/******************** MODULE INFO ****************************/ /* * File name : core.sfl * * AUTHOR : Yoshihiro Iida (3aepm001@keyaki.cc.u-tokai.ac.jp) * VERSION : 1.0 * DATE : Oct 16, 2003 * * Compiler : sfl2vl * Project : POP-11: PDP-11 compatible On Programmable chip * Functions : Processor core of POP-11 * * Copyright (c) Yoshihiro Iida, Tokai University, Shimizu Lab., Japan. (http://shimizu-lab.dt.u-tokai.ac.jp) This software is the property of Tokai University, Shimizu Lab., Japan. The POP-11 is free set of files; you can use it, redistribute it and/or modify it under the following terms: 1. You are not allowed to remove or modify this copyright notice and License paragraphs, even if parts of the software is used. 2. The improvements and/or extentions you make SHALL be available for the community under THIS license, source code included. Improvements or extentions, including adaptions to new architectures/languages, SHALL be reported and transmitted to Tokai University, Shimizu Lab., Japan. 3. You must cause the modified files to carry prominent notices stating that you changed the files, what you did and the date of changes. 4. You may NOT distribute this set of files under another license without explisit permission from Tokai University, Shimizu Lab., Japan. 5. This set of files is free, and distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You SHALL NOT use this software unless you accept to carry all risk and cost of defects or limitations. * * ------------ CHANGE RECORD ---------------- * Yoshihiro Iida (3aepm001@keyaki.cc.u-tokai.ac.jp) Sep 21, 2004: * First free version of this software published. * */ %i "arbiter.sfl" %i "pop11.sfl" %i "rs232c/RS232C_IF.sfl" %i "inc18.sfl" %i "timer.sfl" %i "rk.sfl" %i "cla12.sfl" /* %d BUS_ERROR 0b0 */ %d BUS_ERROR (PA<17:16> == 0b10) declare segment_reg { instrin seg_read; instrin writePAR; instrin writePDR; input mode; input page<3>; input PARin<12>; input PDRin<11>; output PARout<12>; output PDRout<11>; instr_arg seg_read(mode,page); instr_arg writePAR(mode,page,PARin); instr_arg writePDR(mode,page,PDRin); } declare core { instrout rd, wt; instrout erd, ewt; input in<16>; output out<16>; output adr<18>; output byte; instrout dsk_rd, dsk_wt; input dsk_in<16>; output dsk_out<16>; output dsk_adr<21>; instrin rdy; input rts,txd; output cts,rxd; output RST; output CS<2>; output DA<3>; input DDI<16>; output DDO<16>; output DIOR; output DIOW; } module core { instrout rd, wt; instrout erd, ewt; input in<16>; output out<16>; output adr<18>; output byte; instrout dsk_rd, dsk_wt; input dsk_in<16>; output dsk_out<16>; output dsk_adr<21>; instrin rdy; input rts,txd; output cts,rxd; output RST; output CS<2>; output DA<3>; input DDI<16>; output DDO<16>; output DIOR; output DIOW; instrself done; /* For MMU */ instrself mrd, mwt; instrself access_err, length_err, bus_err; sel in_sel<16>, out_sel<16>, adr_sel<18>; reg mmu_buf<16>, PA<18>; reg SSR2<16>; reg_wr ssr0_mode<2>, ssr0_page<3>, ssr0_sw, non_resident, readonly_error, length_error; pop11 cpu; RS232C_IF rs232; timer Timer; arbiter Arbiter; cla12 mmu_adder; segment_reg seg; rk Rk; reg_ws rs232_sw; reg_wr timer_irq_enable; reg_wr send_irq_enable, recv_irq_enable; reg_wr send_s0, send_s1, recv_s0, recv_s1; sel APF<3>, BN<7>, nBN<7>, DIB<6>, ACF<2>, ED, AIB, PLF<7>; instr_arg rd(adr, byte); instr_arg wt(adr, out, byte); instr_arg erd(adr, byte); instr_arg ewt(adr, out, byte); instr_arg dsk_rd(dsk_adr); instr_arg dsk_wt(dsk_adr, dsk_out); instr_arg mrd(adr_sel); instr_arg mwt(adr_sel, out_sel); stage_name mmunit { task run(); } par { generate mmunit.run(); /* Interruput Control */ Arbiter.cpu_pri = cpu.pswout<7:5>; if(Arbiter.int) cpu.irq_in(); if(cpu.int_ack) par { Arbiter.ack(); cpu.dati = 0x00||Arbiter.vector; } /* Serial Interface Control */ rs232.do(); cts = rs232.cts; rxd = rs232.rxd; rs232.txd = txd; rs232.rts = rts; /* Timer Interruput Logic */ if(Timer.irq & timer_irq_enable) Arbiter.irq0(); /* Serial Interface Interrupts Logic */ send_s0 := rs232.sv; send_s1 := send_s0; recv_s0 := rs232.rv; recv_s1 := recv_s0; if(send_s0 & ^send_s1 & send_irq_enable) Arbiter.irq3(); if(recv_s0 & ^recv_s1 & recv_irq_enable) Arbiter.irq2(); if(Rk.irq) Arbiter.irq1(); RST = Rk.RST; CS = Rk.CS; DA = Rk.DA; DDO = Rk.DDO; Rk.DDI = DDI; DIOR = Rk.DIOR; DIOW = Rk.DIOW; APF = cpu.adrs<15:13>; BN = cpu.adrs<12:06>; nBN = ^cpu.adrs<12:06>; DIB = cpu.adrs<05:00>; ACF = seg.PDRout<1:0>; ED = seg.PDRout<2>; AIB = seg.PDRout<3>; PLF = seg.PDRout<10:04>; } /* * RK Disk Drive */ instruct Rk.mem_write par { wt(Rk.mem_adr, Rk.mem_out, WORD); Rk.mem_ack(); } instruct Rk.mem_read par { Rk.mem_in = rd(Rk.mem_adr, WORD).in; Rk.mem_ack(); } /* * Memory Map Controller */ %d NO_MAPPED (^(adr_sel<17:13> == 0b11111)) %d MAPPED ((adr_sel<17:13> == 0b11111)&( adr_sel<12>)) %d EABMAP ((adr_sel<17:13> == 0b11111)&(^adr_sel<12>)) %d MAPPING adr_sel<11:00> %d SEGMENT adr_sel<11:05> %d PDR_READ (0b0||seg.PDRout<10:04>||0b0||seg.PDRout<3>||0b00||seg.PDRout<2:0>||0b0) %d PAR_READ (0b0000||seg.PARout) instruct mrd any { /* Physical memory read */ NO_MAPPED: par { done(); in_sel = rd(adr_sel, cpu.byte).in; } EABMAP: par { done(); in_sel = erd(0o00||adr_sel<11:00>, cpu.byte).in; } MAPPED: any { /* Processor Status Word */ MAPPING == 0o7776: par { done(); in_sel = cpu.pswout; } /* Segment Registers */ MAPPING == 0o7576: par { done(); in_sel = SSR2; } /* SSR2 */ MAPPING == 0o7572: par { done(); in_sel = non_resident||length_error||readonly_error||(0b000000)||ssr0_mode||0b0||ssr0_page||ssr0_sw; } /* SSR0 */ SEGMENT == 0o23||0b1: par { done(); in_sel = PAR_READ; seg.seg_read(0b0,adr_sel<3:1>); } /* KISA0-7 */ SEGMENT == 0o23||0b0: par { done(); in_sel = PDR_READ; seg.seg_read(0b0,adr_sel<3:1>); } /* KISD0-7 */ SEGMENT == 0o76||0b1: par { done(); in_sel = PAR_READ; seg.seg_read(0b1,adr_sel<3:1>); } /* UISA0-7 */ SEGMENT == 0o76||0b0: par { done(); in_sel = PDR_READ; seg.seg_read(0b1,adr_sel<3:1>); } /* UISD0-7 */ /* Timer */ MAPPING == 0o7546: par { done(); in_sel = (0o000)||timer_irq_enable||(0o00); } MAPPING == 0o7544: par { done(); in_sel = 0x0000; } /* RS-232C interface */ MAPPING == 0o7570: par { done(); in_sel = (0o00000)||rs232_sw; } MAPPING == 0o7566: par { done(); in_sel = 0x0000; } MAPPING == 0o7564: par { done(); in_sel = (0x00)||rs232.sv||send_irq_enable||(0o00); } MAPPING == 0o7562: par { done(); in_sel = (0x00)||rs232.get().out; } MAPPING == 0o7560: par { done(); in_sel = (0x00)||rs232.rv||recv_irq_enable||(0o00); } /* RK Disk Drive */ MAPPING == 0o7404: par { done(); in_sel = Rk.rkcs_rd().rk_out; } MAPPING == 0o7406: par { done(); in_sel = Rk.rkwc_rd().rk_out; } MAPPING == 0o7410: par { done(); in_sel = Rk.rkba_rd().rk_out; } MAPPING == 0o7412: par { done(); in_sel = Rk.rkda_rd().rk_out; } } ^done: in_sel = 0xffff; } %d PDR_WRITE (out_sel<14:08>||out_sel<6>||out_sel<3:1>) %d PAR_WRITE (out_sel<11:0>) instruct mwt any { /* Physical memory write */ NO_MAPPED: par { wt(adr_sel, out_sel, cpu.byte); } EABMAP: par { ewt(0o00||adr_sel<11:00>, out_sel, cpu.byte); } MAPPED: any { /* Processor Status Word */ MAPPING == 0o7776: cpu.pswt( out_sel ); /* Segment Registers */ MAPPING == 0o7572: par { non_resident := out_sel<15>; length_error := out_sel<14>; readonly_error := out_sel<13>; ssr0_mode := out_sel<6:5>; ssr0_page := out_sel<3:1>; ssr0_sw := out_sel<0>; } /* SSR0 */ SEGMENT == 0o23||0b1: par { seg.writePAR(0b0,adr_sel<3:1>,PAR_WRITE); } /* KISA0-7 */ SEGMENT == 0o23||0b0: par { seg.writePDR(0b0,adr_sel<3:1>,PDR_WRITE); } /* KISD0-7 */ SEGMENT == 0o76||0b1: par { seg.writePAR(0b1,adr_sel<3:1>,PAR_WRITE); } /* UISA0-7 */ SEGMENT == 0o76||0b0: par { seg.writePDR(0b1,adr_sel<3:1>,PDR_WRITE); } /* UISD0-7 */ /* Timer */ MAPPING == 0o7546: timer_irq_enable := out_sel<6>; /* RS-232C interface */ MAPPING == 0o7570: rs232_sw := out_sel<0>; MAPPING == 0o7566: rs232.put( out_sel<7:0> ); MAPPING == 0o7564: send_irq_enable := out_sel<6>; MAPPING == 0o7562: ; MAPPING == 0o7560: par { recv_irq_enable := out_sel<6>; if(out_sel<0>) rs232.get(); } /* RK Disk Drive */ MAPPING == 0o7404: Rk.rkcs_wt(out_sel); MAPPING == 0o7406: Rk.rkwc_wt(out_sel); MAPPING == 0o7410: Rk.rkba_wt(out_sel); MAPPING == 0o7412: Rk.rkda_wt(out_sel); } } /* * Memory Management Unit */ %d CPU_MODE /&cpu.pswout<15:14> %d SSR2_LOCK (non_resident | readonly_error | length_error) stage mmunit { state_name s0,s1,s2,s3; first_state s0; state s0 par { /* Virtual Address 160000 to 177777 is mapped from 760000 to 777777 */ if(^ssr0_sw) if(^Rk.active) par { if(cpu.rd) mmu_buf := mrd( (/&APF)||(/&APF)||cpu.adrs ).in_sel; if(cpu.wt) mwt( (/&APF)||(/&APF)||cpu.adrs, cpu.dato ); if(cpu.rd | cpu.wt) goto s3; } /* Compute Physical Address */ if(ssr0_sw & (cpu.rd | cpu.wt)) par { seg.seg_read(CPU_MODE, APF); PA := mmu_adder.do(0b00000||BN, seg.PARout, 0b0).out||DIB; goto s1; } if(cpu.rd & cpu.inst & ^SSR2_LOCK) SSR2 := cpu.adrs; } state s1 par { /* Read PAR from segment reg */ seg.seg_read(CPU_MODE, APF); /* set W reg of PDR */ if(cpu.wt) seg.writePDR(CPU_MODE, APF, PLF||0b1||ED||ACF); /* Access Control Error Detection */ if( (ACF == 0b00) | (ACF == 0b10) | (/@cpu.pswout<15:14>)) par { non_resident := 0b1; access_err(); } if( (ACF == 0b01) & cpu.wt) par { readonly_error := 0b1; access_err(); } /* Page Length Error Detection */ mmu_adder.do(12#PLF, 12#nBN, 0b1); if(^ED &^mmu_adder.c &^mmu_adder.z ) par { length_error := 0b1; length_err(); } if( ED & mmu_adder.c &^mmu_adder.z ) par { length_error := 0b1; length_err(); } /* If any error was detected ... */ if(BUS_ERROR) par { bus_err(); cpu.error(); goto s0; } if(access_err | length_err) par { if(^SSR2_LOCK) par { ssr0_mode := cpu.pswout<15:14>; ssr0_page := APF; } cpu.fault(); goto s0; } /* If All Green */ if(^access_err & ^length_err & ^bus_err) par { goto s2; } } state s2 if(^Rk.active) par { if(cpu.rd) mmu_buf := mrd(PA).in_sel; if(cpu.wt) mwt(PA, cpu.dato); goto s3; } state s3 par { cpu.rdy(); if(cpu.rd) cpu.dati = mmu_buf; goto s0; } } /* end of mmu */ } /* end of core */ module segment_reg { instrin seg_read; instrin writePAR; instrin writePDR; input mode; input page<3>; input PARin<12>; input PDRin<11>; output PARout<12>; output PDRout<11>; /* Kernel Mode Page Address Reg and Page Discription Reg */ reg_wr k_par0<12>, k_pdr0<11>; reg_wr k_par1<12>, k_pdr1<11>; reg_wr k_par2<12>, k_pdr2<11>; reg_wr k_par3<12>, k_pdr3<11>; reg_wr k_par4<12>, k_pdr4<11>; reg_wr k_par5<12>, k_pdr5<11>; reg_wr k_par6<12>, k_pdr6<11>; reg_wr k_par7<12>, k_pdr7<11>; /* User Mode Page Address Reg and Page Discription Reg */ reg_wr u_par0<12>, u_pdr0<11>; reg_wr u_par1<12>, u_pdr1<11>; reg_wr u_par2<12>, u_pdr2<11>; reg_wr u_par3<12>, u_pdr3<11>; reg_wr u_par4<12>, u_pdr4<11>; reg_wr u_par5<12>, u_pdr5<11>; reg_wr u_par6<12>, u_pdr6<11>; reg_wr u_par7<12>, u_pdr7<11>; instruct seg_read any { (^mode)&(page == 0o0): par { PARout = k_par0; PDRout = k_pdr0; } (^mode)&(page == 0o1): par { PARout = k_par1; PDRout = k_pdr1; } (^mode)&(page == 0o2): par { PARout = k_par2; PDRout = k_pdr2; } (^mode)&(page == 0o3): par { PARout = k_par3; PDRout = k_pdr3; } (^mode)&(page == 0o4): par { PARout = k_par4; PDRout = k_pdr4; } (^mode)&(page == 0o5): par { PARout = k_par5; PDRout = k_pdr5; } (^mode)&(page == 0o6): par { PARout = k_par6; PDRout = k_pdr6; } (^mode)&(page == 0o7): par { PARout = k_par7; PDRout = k_pdr7; } ( mode)&(page == 0o0): par { PARout = u_par0; PDRout = u_pdr0; } ( mode)&(page == 0o1): par { PARout = u_par1; PDRout = u_pdr1; } ( mode)&(page == 0o2): par { PARout = u_par2; PDRout = u_pdr2; } ( mode)&(page == 0o3): par { PARout = u_par3; PDRout = u_pdr3; } ( mode)&(page == 0o4): par { PARout = u_par4; PDRout = u_pdr4; } ( mode)&(page == 0o5): par { PARout = u_par5; PDRout = u_pdr5; } ( mode)&(page == 0o6): par { PARout = u_par6; PDRout = u_pdr6; } ( mode)&(page == 0o7): par { PARout = u_par7; PDRout = u_pdr7; } } instruct writePAR any { (^mode)&(page == 0o0): k_par0 := PARin; (^mode)&(page == 0o1): k_par1 := PARin; (^mode)&(page == 0o2): k_par2 := PARin; (^mode)&(page == 0o3): k_par3 := PARin; (^mode)&(page == 0o4): k_par4 := PARin; (^mode)&(page == 0o5): k_par5 := PARin; (^mode)&(page == 0o6): k_par6 := PARin; (^mode)&(page == 0o7): k_par7 := PARin; ( mode)&(page == 0o0): u_par0 := PARin; ( mode)&(page == 0o1): u_par1 := PARin; ( mode)&(page == 0o2): u_par2 := PARin; ( mode)&(page == 0o3): u_par3 := PARin; ( mode)&(page == 0o4): u_par4 := PARin; ( mode)&(page == 0o5): u_par5 := PARin; ( mode)&(page == 0o6): u_par6 := PARin; ( mode)&(page == 0o7): u_par7 := PARin; } instruct writePDR any { (^mode)&(page == 0o0): k_pdr0 := PDRin; (^mode)&(page == 0o1): k_pdr1 := PDRin; (^mode)&(page == 0o2): k_pdr2 := PDRin; (^mode)&(page == 0o3): k_pdr3 := PDRin; (^mode)&(page == 0o4): k_pdr4 := PDRin; (^mode)&(page == 0o5): k_pdr5 := PDRin; (^mode)&(page == 0o6): k_pdr6 := PDRin; (^mode)&(page == 0o7): k_pdr7 := PDRin; ( mode)&(page == 0o0): u_pdr0 := PDRin; ( mode)&(page == 0o1): u_pdr1 := PDRin; ( mode)&(page == 0o2): u_pdr2 := PDRin; ( mode)&(page == 0o3): u_pdr3 := PDRin; ( mode)&(page == 0o4): u_pdr4 := PDRin; ( mode)&(page == 0o5): u_pdr5 := PDRin; ( mode)&(page == 0o6): u_pdr6 := PDRin; ( mode)&(page == 0o7): u_pdr7 := PDRin; } }/* end of segment */