#include "pdp6.h" int dotrace = 1; Apr apr; void trace(char *fmt, ...) { va_list ap; if(!dotrace) return; va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); } void decode_ch(void) { int ir6_8; ir6_8 = apr.ir>>9 & 7; apr.ch_inc = apr.ch_inc_op = apr.ch_n_inc_op = 0; apr.ch_load = apr.ch_dep = 0; if((apr.ir & 0770000) == 0130000){ apr.ch_inc = ((ir6_8 & 5) == 4 || ir6_8 == 3) && !apr.chf5; apr.ch_inc_op = apr.ch_inc && !apr.chf7; apr.ch_n_inc_op = (ir6_8 & 5) == 5 && !apr.chf5 || apr.ch_inc && apr.chf7; apr.ch_load = (ir6_8 & 6) == 4 && apr.chf5; apr.ch_dep = (ir6_8 & 6) == 6 && apr.chf5; } if(apr.ch_inc_op || apr.ch_n_inc_op || apr.ch_load) apr.fac_inh = 1; if(apr.ch_n_inc_op || apr.ch_load) apr.fc_e = 1; if(apr.ch_dep || apr.ch_inc_op) apr.fc_e_pse = 1; if(apr.ch_dep) apr.sac_inh = 1; } void decode_2xx(void) { apr.ir_fwt = (apr.inst & 0760) == 0200; apr.ir_fwt_swap = 0; apr.fwt_00 = apr.fwt_01 = apr.fwt_10 = apr.fwt_11 = 0; if(apr.ir_fwt){ apr.ir_fwt_swap = (apr.inst & 0774) == 0204; apr.fwt_00 = (apr.inst & 03) == 0; apr.fwt_01 = (apr.inst & 03) == 1; apr.fwt_10 = (apr.inst & 03) == 2; apr.fwt_11 = (apr.inst & 03) == 3; if(apr.fwt_00 || apr.fwt_01 || apr.fwt_11) apr.fac_inh = 1; if(apr.fwt_00) apr.fc_e = 1; if(apr.fwt_11) apr.fc_e_pse = 1; if(apr.fwt_10) apr.sac_inh = apr.sc_e = 1; } apr.fc_c_acrt = (apr.inst & 0776) == 0262; apr.fc_c_aclt = apr.inst == 0251 || apr.inst == 0267; apr.ir_md = (apr.inst & 0760) == 0220; if(apr.ir_md){ if((apr.inst & 03) != 1) apr.fc_e = 1; if((apr.inst & 03) == 2) apr.sac_inh = 1; if(apr.inst & 02) apr.sc_e = 1; if((apr.inst & 0774) == 0224) apr.fac2 = 1; if(((apr.inst & 0774) == 0224 || (apr.inst & 0770) == 0230) && !apr.sac_inh) apr.sac2 = 1; } apr.shift_op = (apr.inst & 0770) == 0240 && (apr.inst & 03) != 3; if(apr.shift_op && apr.inst & 04) apr.fac2 = apr.sac2 = 1; if(apr.inst == EXCH) apr.fc_e_pse = 1; if((apr.inst & 0774) == 0254) apr.fac_inh = 1; if(apr.inst == XCT) apr.fac_inh = apr.fc_e = 1; apr.ir_jp = (apr.inst & 0770) == 0260; if(apr.ir_jp){ apr.e_long = 1; if(apr.inst == PUSHJ) apr.sc_e = apr.mb_pc_sto = 1; if(apr.inst == PUSH) apr.sc_e = apr.fc_e = 1; if((apr.inst & 0776) == 0264) /* JSR, JSP */ apr.mb_pc_sto = apr.fac_inh = 1; if(apr.inst == POP || apr.inst == JSR || apr.inst == JSA) apr.sc_e = 1; } apr.ir_as = (apr.inst & 0770) == 0270; } void decodeir(void) { bool iot_a, jrst_a, uuo_a; apr.inst = apr.ir>>9 & 0777; apr.fac_inh = 0; apr.fc_e = 0; apr.fc_e_pse = 0; apr.e_long = 0; apr.mb_pc_sto = 0; apr.sc_e = 0; apr.sac_inh = 0; apr.sac2 = 0; decode_ch(); apr.ir_fp = (apr.inst & 0740) == 0140; if(apr.ir_fp){ apr.fc_e = 1; if(apr.inst & 02) /* M, B */ apr.sc_e = 1; if((apr.inst & 03) == 2) apr.sac_inh = 1; if((apr.inst & 03) == 1) apr.sac2 = 1; } decode_2xx(); /* ACCP v MEMAC */ apr.ir_accp = apr.ir_memac = apr.ir_memac_mem = apr.ir_memac_ac = 0; if((apr.inst & 0700) == 0300){ apr.ir_memac = apr.inst & 060; apr.ir_accp = !apr.ir_memac; apr.ir_memac_mem = apr.ir_memac && apr.inst & 010; apr.ir_memac_ac = apr.ir_memac && !apr.ir_memac_mem; if(apr.ir_memac_mem) apr.fac_inh = apr.fc_e_pse = 1; if(apr.ir_accp && apr.inst & 010) apr.fc_e = 1; apr.e_long = 1; if(apr.ir_accp) apr.sac_inh = 1; } /* BOOLE */ apr.boole_as_00 = apr.boole_as_01 = 0; apr.boole_as_10 = apr.boole_as_11 = 0; apr.ir_boole = (apr.inst & 0700) == 0400; if(apr.ir_boole) apr.ir_boole_op = apr.inst>>2 & 017; /* HWT */ apr.hwt_00 = apr.hwt_01 = apr.hwt_10 = apr.hwt_11 = 0; apr.ir_hwt = (apr.inst & 0700) == 0500; if(apr.ir_hwt){ apr.hwt_00 = (apr.inst & 03) == 0; apr.hwt_01 = (apr.inst & 03) == 1; apr.hwt_10 = (apr.inst & 03) == 2; apr.hwt_11 = (apr.inst & 03) == 3; if(apr.hwt_00) apr.fc_e = 1; if(apr.hwt_11) apr.fac_inh = 1; if(apr.hwt_10 || apr.hwt_11) apr.fc_e_pse = 1; if(apr.hwt_10) apr.sac_inh = 1; } if(apr.ir_boole || apr.ir_as){ apr.boole_as_00 = (apr.inst & 03) == 0; apr.boole_as_01 = (apr.inst & 03) == 1; apr.boole_as_10 = (apr.inst & 03) == 2; apr.boole_as_11 = (apr.inst & 03) == 3; if(apr.boole_as_00) apr.fc_e = 1; if(apr.boole_as_10 || apr.boole_as_11) apr.fc_e_pse = 1; if(apr.boole_as_10) apr.sac_inh = 1; } /* ACBM */ apr.ir_acbm = (apr.inst & 0700) == 0600; if(apr.ir_acbm){ if(apr.inst & 010) apr.fc_e = 1; apr.e_long = 1; if(!(apr.inst & 60)) apr.sac_inh = 1; } if(!(apr.ir & 0740) && (apr.fwt_11 || apr.hwt_11 || apr.ir_memac_mem)) apr.sac_inh = 1; uuo_a = (apr.inst & 0700) == 0; iot_a = (apr.inst & 0700) == 0700; jrst_a = apr.inst == 0254; // 5-13 apr.ex_ir_uuo = uuo_a && apr.ex_uuo_sync || iot_a && !apr.ex_pi_sync && apr.ex_user && !apr.cpa_iot_user || jrst_a && (apr.ir & 0000600) && apr.ex_user; apr.ir_jrst = !apr.ex_ir_uuo && jrst_a; apr.ir_iot = !apr.ex_ir_uuo && iot_a; apr.iot_blk = apr.ir_iot && (apr.ir & 0240) == 0; apr.iot_dataio = apr.ir_iot && (apr.ir & 0240) == 0040; if(apr.ir_jrst) apr.mb_pc_sto = 1; if(apr.ex_ir_uuo || apr.ir_iot) apr.fac_inh = 1; if(apr.iot_blk) apr.fc_e_pse = 1; if(apr.iot_dataio && apr.ir & 0100) /* DATAO */ apr.fc_e = 1; /* No need to check PC +1 for E LONG, it's already implied. * We have to wait until ET5 for PC SET */ if(apr.ir_iot && (apr.inst & 0300) == 0300 || /* CONSZ, CONSO */ apr.mb_pc_sto) apr.e_long = 1; if(apr.ir_iot && (apr.ir & 0140) == 040) /* DATAI, CONI */ apr.sc_e = 1; } void swap(word *a, word *b) { word tmp; tmp = *a; *a = *b; *b = tmp; } bool accp_et_al_test(void) { bool lt, cond; // 5-9 lt = !!(apr.ar & SGN) != apr.ar_cry0_xor_cry1; cond = (apr.inst & 2) && apr.ar == 0 || (apr.ir_accp || apr.ir_memac) && (apr.inst & 1) && lt; return cond != !!(apr.inst & 040); } bool selected_flag(void) { // 5-12 return apr.ir & 0400 && apr.ar_ov_flag || apr.ir & 0200 && apr.ar_cry0_flag || apr.ir & 0100 && apr.ar_cry1_flag || apr.ir & 0040 && apr.ar_pc_chg_flag; } void selected_flags_clr(void) { // 6-10 if(apr.ir & 0400) apr.ar_ov_flag = 0; if(apr.ir & 0200) apr.ar_cry0_flag = 0; if(apr.ir & 0100) apr.ar_cry1_flag = 0; if(apr.ir & 0040) apr.ar_pc_chg_flag = 0; } bool pc_set_enable(void) { // 5-12 return apr.inst == AOBJP && !(apr.ar & SGN) || apr.inst == AOBJN && apr.ar & SGN || apr.ir_memac_ac && accp_et_al_test() || apr.inst == JFCL && selected_flag(); } bool pc_inc_enable(void) { // 5-12 return (apr.ir_accp || apr.ir_acbm || apr.ir_memac_mem) && accp_et_al_test() || apr.ir_iot && ((apr.inst & 0340) == 0300 && apr.ar == 0 || (apr.inst & 0340) == 0340 && apr.ar != 0); } void ar_cry(void) { // 6-10 apr.ar_cry0_xor_cry1 = apr.ar_cry0 != apr.ar_cry1 && !((apr.inst & 0700) == 0300 && (apr.inst & 0060) != 0020); } void ar_cry_in(word c) { word a; a = (apr.ar & 0377777777777) + c; apr.ar += c; apr.ar_cry0 = !!(apr.ar & 01000000000000); apr.ar_cry1 = !!(a & 0400000000000); apr.ar &= FW; ar_cry(); } void set_ex_mode_sync(bool value) { apr.ex_mode_sync = value; if(apr.ex_mode_sync) apr.ex_user = 1; // 5-13 } void set_pi_cyc(bool value) { apr.pi_cyc = value; if(!apr.pi_cyc) apr.ex_pi_sync = 1; // 5-13 } void recalc_pi_req(void) { int chan; u8 req; // 8-3 apr.pi_req = 0; if(apr.pi_active){ req = apr.pir & ~apr.pih; for(chan = 0100; chan; chan >>= 1) if(req & chan){ apr.pi_req = chan; break; } } } void set_mc_rq(bool value) { apr.mc_rq = value; // 7-9 if(value && (apr.mc_rd || apr.mc_wr)){ membus0 |= MEMBUS_RQ_CYC; wakemem(); }else membus0 &= ~MEMBUS_RQ_CYC; } void set_mc_wr(bool value) { apr.mc_wr = value; // 7-9 if(value) membus0 |= MEMBUS_WR_RQ; else membus0 &= ~MEMBUS_WR_RQ; set_mc_rq(apr.mc_rq); } void set_mc_rd(bool value) { apr.mc_rd = value; // 7-9 if(value) membus0 |= MEMBUS_RD_RQ; else membus0 &= ~MEMBUS_RD_RQ; set_mc_rq(apr.mc_rq); } void set_key_rim_sbr(bool value) { // not sure if this is correct apr.key_rim_sbr = value | apr.sw_rim_maint; // 5-2 } bool calcaddr(void) { u8 ma18_25; bool ma_ok, ma_fmc_select; // 5-13 apr.ex_inh_rel = !apr.ex_user || apr.ex_pi_sync || (apr.ma & 0777760) == 0 || apr.ex_ill_op; // 7-4 ma18_25 = apr.ma>>10 & 0377; ma_ok = ma18_25 <= apr.pr; // 7-2 ma_fmc_select = !apr.key_rim_sbr && (apr.ma & 0777760) == 0; // 7-5 apr.rla = ma18_25; if(!apr.ex_inh_rel) apr.rla += apr.rlr; membus0 &= ~0007777777761; membus0 |= ma_fmc_select ? MEMBUS_MA_FMC_SEL1 : MEMBUS_MA_FMC_SEL0; membus0 |= (apr.ma&01777) << 4; membus0 |= (apr.rla&017) << 14; membus0 |= apr.rla & 0020 ? MEMBUS_MA21_1|MEMBUS_MA21 : MEMBUS_MA21_0; membus0 |= apr.rla & 0040 ? MEMBUS_MA20_1 : MEMBUS_MA20_0; membus0 |= apr.rla & 0100 ? MEMBUS_MA19_1 : MEMBUS_MA19_0; membus0 |= apr.rla & 0200 ? MEMBUS_MA18_1 : MEMBUS_MA18_0; membus0 |= apr.ma & 01 ? MEMBUS_MA35_1 : MEMBUS_MA35_0; return ma_ok; } pulse(kt4); pulse(it1); pulse(at1); pulse(at0); pulse(iat0); pulse(et10); pulse(mc_wr_rs); pulse(mc_rd_rq_pulse); pulse(mc_wr_rq_pulse); pulse(mc_rdwr_rq_pulse); pulse(mc_rd_wr_rs_pulse); // TODO: find A LONG pulse(pi_reset){ trace("PI RESET\n"); apr.pi_active = 0; // 8-4 apr.pih = 0; // 8-4 apr.pir = 0; // 8-4 recalc_pi_req(); // 8-4 apr.pio = 0; // 8-3 return NULL; } pulse(ar_flag_clr){ trace("AR FLAG CLR\n"); apr.ar_ov_flag = 0; // 6-10 apr.ar_cry0_flag = 0; // 6-10 apr.ar_cry1_flag = 0; // 6-10 apr.ar_pc_chg_flag = 0; // 6-10 ar_cry(); apr.chf7 = 0; // 6-19 return NULL; } pulse(ar_flag_set){ trace("AR FLAG SET\n"); apr.ar_ov_flag = !!(apr.mb & 0400000000000); // 6-10 apr.ar_cry0_flag = !!(apr.mb & 0200000000000); // 6-10 apr.ar_cry1_flag = !!(apr.mb & 0100000000000); // 6-10 apr.ar_pc_chg_flag = !!(apr.mb & 0040000000000); // 6-10 ar_cry(); apr.chf7 = !!(apr.mb & 0020000000000); // 6-19 if(apr.mb & 0010000000000) set_ex_mode_sync(1); // 5-13 return NULL; } // TODO pulse(mp_clr){ apr.chf5 = 0; // 6-19 apr.shf1 = 0; // 6-20 return NULL; } pulse(mr_clr){ trace("MR CLR\n"); apr.ir = 0; // 5-7 apr.mq = 0; // 6-13 apr.sc = 0; // 6-15 apr.fe = 0; // 6-15 apr.mc_rd = 0; // 7-9 apr.mc_wr = 0; // 7-9 apr.mc_rq = 0; // 7-9 apr.mc_stop = 0; // 7-9 apr.mc_stop_sync = 0; // 7-9 apr.mc_split_cyc_sync = 0; // 7-9 set_ex_mode_sync(0); // 5-13 apr.ex_uuo_sync = 0; // 5-13 apr.ex_pi_sync = 0; // 5-13 apr.a_long = 0; // nowhere to be found :( apr.ar_com_cont = 0; // 6-9 mp_clr(); // TODO: DS CLR /* sbr flip-flops */ apr.key_rd_wr = 0; // 5-2 apr.if1a = 0; // 5-3 apr.af0 = 0; // 5-3 apr.af3 = 0; // 5-3 apr.af3a = 0; // 5-3 apr.f1a = 0; // 5-4 apr.f4a = 0; // 5-4 apr.f6a = 0; // 5-4 apr.et4_ar_pse = 0; // 5-5 apr.sf3 = 0; // 5-6 apr.sf5a = 0; // 5-6 apr.sf7 = 0; // 5-6 apr.mc_rst1_ret = NULL; apr.art3_ret = NULL; apr.sct2_ret = NULL; return NULL; } pulse(mr_start){ trace("MR START\n"); // IOB RESET apr.cpa_iot_user = 0; // 8-5 apr.cpa_illeg_op = 0; // 8-5 apr.cpa_non_exist_mem = 0; // 8-5 apr.cpa_clock_en = 0; // 8-5 apr.cpa_clock_flag = 0; // 8-5 apr.cpa_pc_chg_en = 0; // 8-5 apr.cpa_pdl_ov = 0; // 8-5 apr.cpa_arov_en = 0; // 8-5 apr.cpa_pia33 = 0; // 8-5 apr.cpa_pia34 = 0; // 8-5 apr.cpa_pia35 = 0; // 8-5 apr.pi_ov = 0; // 8-4 set_pi_cyc(0); // 8-4 pi_reset(); // 8-4 ar_flag_clr(); // 6-10 apr.ex_user = 0; // 5-13 apr.ex_ill_op = 0; // 5-13 apr.pr = 0; // 5-13, 7-4 apr.rlr = 0; // 5-13, 7-5 apr.rla = 0; return NULL; } pulse(mr_pwr_clr){ trace("MR PWR CLR\n"); apr.run = 0; // 5-1 /* order matters because of EX PI SYNC */ mr_start(); // 5-2 mr_clr(); // 5-2 return NULL; } pulse(st7){ trace("ST7\n"); return NULL; } /* * Shift subroutines */ pulse(ar_sh_lt){ return NULL; } pulse(mq_sh_lt){ return NULL; } pulse(ar_sh_rt){ return NULL; } pulse(mq_sh_rt){ return NULL; } pulse(sct2){ trace("SCT2\n"); return apr.sct2_ret; } pulse(sct1){ trace("SCT1\n"); apr.sc = apr.sc+1 & 0777; // 6-16 // TODO: implement shifts if(apr.shift_op && !(apr.mb & RSGN)){ ar_sh_lt(); mq_sh_lt(); } if(apr.shift_op && (apr.mb & RSGN)){ ar_sh_rt(); mq_sh_rt(); } if(apr.sc == 0777) return sct2; return sct1; } pulse(sct0){ trace("SCT0\n"); if(apr.sc == 0777) return sct2; return sct1; } pulse(sht1a){ trace("SHT1A\n"); apr.shf1 = 0; // 6-20 return et10; } pulse(sht1){ trace("SHT1\n"); if(apr.mb & 0400000) apr.sc = ~apr.sc & 0777; apr.shf1 = 1; // 6-20 apr.sct2_ret = sht1a; return sct0; } pulse(sht0){ trace("SHT0\n"); apr.sc = apr.sc+1 & 0777; // 6-16 return NULL; } /* * AR subroutines */ pulse(art3){ trace("ART3\n"); apr.ar_com_cont = 0; // 6-9 return apr.art3_ret; } pulse(ar_cry_comp){ trace("AR CRY COMP\n"); apr.ar = ~apr.ar & FW; // 6-8 return art3; // 6-9 } pulse(ar_pm1_t1){ trace("AR AR+-1 T1\n"); ar_cry_in(1); if(apr.iot_blk || apr.inst == 0252 || apr.inst == 0253 || apr.ir_jp && !(apr.inst & 0004)) ar_cry_in(01000000); if(apr.ar_com_cont) return ar_cry_comp; return art3; } pulse(ar_pm1_t0){ trace("AR AR+-1 T0\n"); apr.ar = ~apr.ar & FW; // 6-8 apr.ar_com_cont = 1; // 6-9 return ar_pm1_t1; } pulse(ar_negate_t0){ trace("AR NEGATE T0\n"); apr.ar = ~apr.ar & FW; // 6-8 return ar_pm1_t1; } pulse(ar_ast2){ trace("AR2\n"); ar_cry_in((~apr.ar & apr.mb) << 1); if(apr.ar_com_cont) return ar_cry_comp; return art3; } pulse(ar_ast1){ trace("AR AST1\n"); apr.ar ^= apr.mb; return ar_ast2; } pulse(ar_ast0){ trace("AR AST0\n"); apr.ar = ~apr.ar & FW; // 6-8 apr.ar_com_cont = 1; // 6-9 return ar_ast1; } /* * Priority Interrupt */ pulse(pir_stb){ trace("PIR STB\n"); apr.pir |= apr.pio & iobus1; recalc_pi_req(); // 8-3 return NULL; } pulse(pi_sync){ trace("PI SYNC\n"); if(!apr.pi_cyc) pir_stb(); // 5-3 if(apr.pi_req && !apr.pi_cyc) return iat0; // TODO: IA INH/AT INH if(apr.if1a) return it1; return at1; } /* * Store */ pulse(st3){ trace("ST3\n"); apr.sf3 = 0; return NULL; } pulse(st2){ trace("ST2\n"); apr.sf3 = 1; apr.mc_rst1_ret = st3; return mc_rd_wr_rs_pulse; } pulse(st1){ trace("ST1\n"); apr.sf3 = 1; apr.mc_rst1_ret = st3; return mc_wr_rq_pulse; } /* * Execute */ pulse(et10){ trace("ET10\n"); if(apr.pi_hold){ apr.pi_ov = 0; apr.pi_cyc = 0; } if(apr.ir_jrst || apr.inst == PUSHJ || apr.inst == PUSH) apr.ma |= apr.mb & RT; if((apr.fc_e_pse || apr.sc_e) && !(apr.ir_jp || apr.inst == EXCH || apr.ch_dep)) apr.mb = apr.ar; if(apr.ir_jp && !(apr.inst & 04)) swap(&apr.mb, &apr.ar); if(apr.ir_memac || apr.ir_as){ apr.ar_cry0_flag = apr.ar_cry0; apr.ar_cry1_flag = apr.ar_cry1; } if(apr.hwt_10 || apr.hwt_11 || apr.fwt_10 || apr.fwt_11 || apr.ir_memac_mem) apr.mb = apr.ar; if(apr.ir_fwt && !apr.ar_cry0 && apr.ar_cry1 || (apr.ir_memac || apr.ir_as) && apr.ar_cry0 != apr.ar_cry1){ apr.ar_ov_flag = 1; // 6-10 if(apr.cpa_arov_en) ; } if(apr.ir_jp && !(apr.inst & 04) && apr.ar_cry0){ apr.cpa_pdl_ov = 1; ; } if(apr.inst == JFCL) selected_flags_clr(); if(apr.sc_e) return st1; if(apr.fc_e_pse) return st2; return st3; } pulse(et9){ bool pc_inc; trace("ET9\n"); pc_inc = apr.inst == JSR || apr.inst == JSA || pc_inc_enable(); if(pc_inc) apr.pc = apr.pc+1 & FW; if((apr.pc_set || pc_inc) && !(apr.ir_jrst && apr.ir & 0100)){ apr.ar_pc_chg_flag = 1; if(apr.cpa_pc_chg_en) ; } if(apr.ir_acbm || apr.ir_jp && apr.inst != JSR) swap(&apr.mb, &apr.ar); if(apr.ir_jrst || apr.inst == PUSHJ || apr.inst == PUSH) apr.ma = 0; if(apr.inst == JSR) apr.chf7 = 0; return et10; } pulse(et8){ trace("ET8\n"); if(apr.pc_set) apr.pc |= apr.ma; // 5-12 if(apr.inst == JSR) apr.ex_ill_op = 0; return et9; } pulse(et7){ trace("ET7\n"); if(apr.pc_set) apr.pc = 0; // 5-12 if(apr.inst == JSR && (apr.ex_pi_sync || apr.ex_ill_op)) apr.ex_user = 0; // 5-13 if(apr.ir_acbm) apr.ar = ~apr.ar; return et8; } pulse(et6){ trace("ET6\n"); if(apr.mb_pc_sto || apr.inst == JSA) apr.mb |= apr.pc; if(apr.inst == PUSHJ || apr.inst == JSR || apr.inst == JSP){ // 6-4 if(apr.ar_ov_flag) apr.mb |= 0400000000000; if(apr.ar_cry0_flag) apr.mb |= 0200000000000; if(apr.ar_cry1_flag) apr.mb |= 0100000000000; if(apr.ar_pc_chg_flag) apr.mb |= 0040000000000; if(apr.chf7) apr.mb |= 0020000000000; if(apr.ex_user) apr.mb |= 0010000000000; } if(apr.ir_acbm && (apr.inst & 060) == 020) /* Z */ apr.mb &= apr.ar; return et7; } pulse(et5){ trace("ET5\n"); if(apr.mb_pc_sto) apr.mb = 0; if(apr.ir_acbm) apr.ar = ~apr.ar; // 5-12 apr.pc_set = apr.ir_jp && !(apr.inst == PUSH || apr.inst == POP) || apr.ir_jrst || pc_set_enable(); if(apr.e_long | apr.pc_set) return et6; return et10; } pulse(et4){ bool hwt_lt, hwt_rt; trace("ET4\n"); apr.et4_ar_pse = 0; // 5-5 if(apr.ir_boole && (apr.ir_boole_op == 04 || apr.ir_boole_op == 010 || apr.ir_boole_op == 011 || apr.ir_boole_op == 014 || apr.ir_boole_op == 015 || apr.ir_boole_op == 016 || apr.ir_boole_op == 017)) apr.ar = ~apr.ar & FW; // 6-8 hwt_lt = apr.ir_hwt && !(apr.inst & 040); hwt_rt = apr.ir_hwt && apr.inst & 040; if(hwt_rt && apr.inst & 020 && (!(apr.inst & 010) || apr.mb & RSGN)) apr.ar = apr.ar & ~LT | ~apr.ar & LT; if(hwt_lt && apr.inst & 020 && (!(apr.inst & 010) || apr.mb & SGN)) apr.ar = apr.ar & ~RT | ~apr.ar & RT; if(hwt_lt) apr.ar = apr.ar & ~LT | apr.mb & LT; if(hwt_rt) apr.ar = apr.ar & ~RT | apr.mb & RT; if(apr.ir_fwt_swap) swap(&apr.mb, &apr.ar); // 6-3 if(apr.ir_acbm) swap(&apr.mb, &apr.ar); return et5; } pulse(et3){ trace("ET3\n"); if(apr.inst == POPJ || apr.inst == BLT) apr.ma = apr.mb & RT; // 7-3 // 5-9 if(apr.ir_fwt && ((apr.inst & 0774) == 0210 || (apr.inst & 0774) == 0214 && apr.ar & SGN)){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; return ar_negate_t0; } if(apr.ir_as){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; if(apr.inst & 4) return ar_ast0; else return ar_ast1; } if(apr.ir_accp){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; return ar_ast0; } if(apr.ir_memac){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; if((apr.inst & 070) == 040) // +1 return ar_pm1_t1; if((apr.inst & 070) == 060) // -1 return ar_pm1_t0; return et4; } if(apr.inst == AOBJP || apr.inst == AOBJN || apr.inst == PUSHJ || apr.inst == PUSH){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; return ar_pm1_t1; } if(apr.inst == POP || apr.inst == POPJ){ apr.et4_ar_pse = 1; // 5-5 apr.art3_ret = et4; return ar_pm1_t0; } if(apr.shift_op) return sht1; return et4; }; pulse(et1){ trace("ET1\n"); if(apr.ex_ir_uuo) apr.ex_ill_op = 1; // 5-13 if(apr.ir_jrst && apr.ir & 040) apr.ex_mode_sync = 1; // 5-13 if(apr.ir_jrst && apr.ir & 0100) ar_flag_set(); if(apr.ir_jrst && apr.ir & 0400 || apr.iot_dataio && !apr.pi_ov && apr.pi_cyc) if(apr.pi_active){ // TODO: check if this correct apr.pih &= apr.pi_req-1; // 8-3 recalc_pi_req(); } if(apr.ir_boole && (apr.ir_boole_op == 06 || apr.ir_boole_op == 011 || apr.ir_boole_op == 014)) apr.ar ^= apr.mb; // 6-8 if(apr.ir_boole && (apr.ir_boole_op == 01 || apr.ir_boole_op == 02 || apr.ir_boole_op == 015 || apr.ir_boole_op == 016)) apr.ar &= apr.mb; // 6-8 if(apr.ir_boole && (apr.ir_boole_op == 03 || apr.ir_boole_op == 04 || apr.ir_boole_op == 07 || apr.ir_boole_op == 010 || apr.ir_boole_op == 013)) apr.ar |= apr.mb; // 6-8 if(apr.ir_fwt_swap || apr.ir_hwt && apr.inst & 04) apr.mb = apr.mb<<18 & LT | apr.mb>>18 & RT; // 6-3 if(apr.ir_hwt && apr.inst & 030) apr.ar = 0; // 6-8 if(apr.inst == POPJ) apr.ma = 0; if(apr.shift_op && apr.mb & 0400000) sht0(); // 6-20 if(apr.ir_acbm){ apr.mb &= apr.ar; if((apr.inst & 060) == 040) /* C */ apr.ar ^= apr.mb; if((apr.inst & 060) == 060) /* O */ apr.ar |= apr.mb; } return et3; } pulse(et0){ trace("ET0\n"); if(!((apr.ch_inc_op || apr.ch_n_inc_op) && apr.inst != IBP || apr.ex_ir_uuo || apr.iot_blk || apr.inst == BLT || apr.inst == XCT || apr.key_execute && !apr.run || apr.pi_cyc)) apr.pc = apr.pc+1 & RT; // 5-12 apr.ar_cry0 = 0; // 6-10 apr.ar_cry1 = 0; // 6-10 ar_cry(); if(apr.ir_jrst && apr.ir & 0100) ar_flag_clr(); // TODO: subroutines return et1; } pulse(et0a){ trace("ET0A\n"); // 8-4 apr.pi_hold = (!apr.ir_iot || !apr.pi_ov && apr.iot_dataio) && apr.pi_cyc; if(apr.pi_hold){ apr.pih |= apr.pi_req; // 8-3 recalc_pi_req(); } // 5-1 if(apr.key_ex_sync) apr.key_ex_st = 1; if(apr.key_dep_sync) apr.key_dep_st = 1; if(apr.key_inst_stop || apr.ir_jrst && apr.ir & 0200 && !apr.ex_user) apr.run = 0; if(apr.ir_boole && (apr.ir_boole_op == 00 || apr.ir_boole_op == 03 || apr.ir_boole_op == 014 || apr.ir_boole_op == 017)) apr.ar = 0; // 6-8 if(apr.ir_boole && (apr.ir_boole_op == 02 || apr.ir_boole_op == 04 || apr.ir_boole_op == 012 || apr.ir_boole_op == 013 || apr.ir_boole_op == 015)) apr.ar = ~apr.ar & FW; // 6-8 if(apr.fwt_00 || apr.fwt_11 || apr.hwt_11 || apr.ir_memac_mem) apr.ar = apr.mb; // 6-8 if(apr.fwt_01 || apr.fwt_10) apr.mb = apr.ar; // 6-3 if(apr.inst == EXCH || apr.inst == JSP || apr.hwt_10) swap(&apr.mb, &apr.ar); // 6-3 if(apr.inst == POP || apr.inst == POPJ || apr.inst == JRA) apr.mb = apr.mq; // 6-3 if(apr.inst == FSC || apr.shift_op) apr.sc |= ~apr.mb & 0377 | ~apr.mb>>9 & 0400; // 6-15 if(apr.ir_acbm && apr.inst & 1 || apr.inst == JSA) apr.mb = apr.mb<<18 & LT | apr.mb>>18 & RT; // 6-3 return NULL; } /* * Fetch */ pulse(ft6a){ trace("FT6A\n"); apr.f6a = 0; // 5-4 et0a(); // 5-5 return et0; // 5-5 } pulse(ft7){ trace("FT7\n"); apr.f6a = 1; // 5-4 apr.mc_rst1_ret = ft6a; if(apr.mc_split_cyc_sync) return mc_rd_rq_pulse; return mc_rdwr_rq_pulse; } pulse(ft6){ trace("FT6\n"); apr.f6a = 1; // 5-4 apr.mc_rst1_ret = ft6a; return mc_rd_rq_pulse; } pulse(ft5){ trace("FT5\n"); apr.ma = apr.mb & RT; // 7-3 if(apr.fc_e) return ft6; if(apr.fc_e_pse) return ft7; return ft6a; } pulse(ft4a){ trace("FT4A\n"); apr.f4a = 0; // 5-4 apr.ma = 0; // 7-3 swap(&apr.mb, &apr.mq); // 6-3, 6-13 return ft5; // 5-4 } pulse(ft4){ trace("FT4\n"); apr.mq = apr.mb; // 6-13 apr.f4a = 1; // 5-4 apr.mc_rst1_ret = ft4a; return mc_rd_rq_pulse; } pulse(ft3){ trace("FT3\n"); apr.ma = apr.mb & RT; // 7-3 swap(&apr.mb, &apr.ar); // 6-3 return ft4; // 5-4 } pulse(ft1a){ trace("FT1A\n"); apr.f1a = 0; // 5-4 if(apr.fac2) apr.ma = apr.ma+1 & 017; // 7-1, 7-5 else apr.ma = 0; // 7-3 if(!(apr.fc_c_aclt || apr.fc_c_acrt)) swap(&apr.mb, &apr.ar); // 6-3 if(apr.fc_c_aclt) apr.mb = apr.mb<<18 & LT | apr.mb>>18 & RT; // 6-3 if(apr.fac2) return ft4; // 5-4 if(apr.fc_c_aclt || apr.fc_c_acrt) return ft3; // 5-4 return ft5; // 5-4 } pulse(ft1){ trace("FT1\n"); apr.ma = apr.ir>>5 & 017; // 7-3 apr.f1a = 1; // 5-4 apr.mc_rst1_ret = ft1a; return mc_rd_rq_pulse; } pulse(ft0){ trace("FT0\n"); if(apr.fac_inh) return ft5; // 5-4 return ft1; // 5-4 } /* * Address */ pulse(at5){ trace("AT5\n"); apr.a_long = 1; // nowhere to be found :( apr.af0 = 1; // 5-3 apr.ma = apr.mb & RT; // 7-3 apr.ir &= ~037; // 5-7 apr.mc_rst1_ret = at0; return mc_rd_rq_pulse; } pulse(at4){ trace("AT4\n"); apr.ar &= ~LT; // 6-8 // TODO: what is MC DR SPLIT? if(apr.sw_addr_stop || apr.key_mem_stop) apr.mc_split_cyc_sync = 1; // 7-9 if(apr.ir & 020) return at5; // 5-3 return ft0; // 5-4 } pulse(at3a){ trace("AT3A\n"); apr.af3a = 0; // 5-3 apr.mb = apr.ar; // 6-3 return at4; // 5-3 } pulse(at3){ trace("AT3\n"); apr.af3 = 0; // 5-3 apr.ma = 0; // 7-3 apr.af3a = 1; // 5-3 apr.art3_ret = at3a; return ar_ast1; } pulse(at2){ trace("AT2\n"); apr.a_long = 1; // nowhere to be found :( apr.ma = apr.ir & 017; // 7-3 apr.af3 = 1; // 5-3 apr.mc_rst1_ret = at3; return mc_rd_rq_pulse; } pulse(at1){ trace("AT1\n"); apr.ex_uuo_sync = 1; // 5-13 if((apr.ir & 017) == 0) return at4; // 5-3 return at2; // 5-3 } pulse(at0){ trace("AT0\n"); apr.ar &= ~RT; // 6-8 apr.ar |= apr.mb & RT; // 6-8 apr.ir |= apr.mb>>18 & 037; // 5-7 decodeir(); apr.ma = 0; // 7-3 apr.af0 = 0; // 5-3 return pi_sync; // 8-4 } /* * Instruction */ pulse(iat0){ trace("IAT0\n"); mr_clr(); set_pi_cyc(1); return it1; } pulse(it1a){ trace("IT1A\n"); apr.if1a = 0; apr.ir |= apr.mb>>18 & 0777740; // 5-7 if(apr.ma & 0777760) set_key_rim_sbr(0); // 5-2 return at0; } pulse(it1){ trace("IT1\n"); hword n; u8 r; if(apr.pi_cyc){ // 7-3 r = apr.pi_req; for(n = 7; !(r & 1); n--, r >>= 1); apr.ma = 040 | n<<1; }else apr.ma = apr.pc; // 7-3 if(apr.pi_ov) apr.ma = (apr.ma+1)&RT; // 7-3 apr.if1a = 1; apr.mc_rst1_ret = it1a; return mc_rd_rq_pulse; } pulse(it0){ trace("IT0\n"); apr.ma = 0; mr_clr(); apr.if1a = 1; // 5-3 return pi_sync; // 8-4 } /* * Memory Control */ pulse(mc_rs_t1){ trace("MC RS T1\n"); set_mc_rd(0); if(apr.key_ex_next || apr.key_dep_next) apr.mi = apr.mb; // 7-7 return apr.mc_rst1_ret; } pulse(mc_rs_t0){ trace("MC RS T0\n"); apr.mc_stop = 0; return mc_rs_t1; } pulse(mc_wr_rs){ trace("MC WR RS\n"); if(apr.ma == apr.mas) apr.mi = apr.mb; // 7-7 membus1 = apr.mb; membus0 |= MEMBUS_MAI_WR_RS; wakemem(); if(!apr.mc_stop) return mc_rs_t0; return NULL; } pulse(mc_addr_ack){ trace("MC ADDR ACK\n"); set_mc_rq(0); if(!apr.mc_rd && apr.mc_wr) return mc_wr_rs; return NULL; } pulse(mc_non_exist_rd){ trace("MC NON EXIST RD\n"); if(!apr.mc_stop) return mc_rs_t0; return NULL; } pulse(mc_non_exist_mem_rst){ trace("MC NON EXIST MEM RST\n"); if(apr.mc_rd){ /* call directly - no other pulses after it in this case */ mc_addr_ack(); return mc_non_exist_rd; }else return mc_addr_ack(); return NULL; } pulse(mc_non_exist_mem){ trace("MC NON EXIST MEM\n"); apr.cpa_non_exist_mem = 1; // TODO: IOB PI REQ CPA PIA if(!apr.sw_mem_disable) return mc_non_exist_mem_rst; return NULL; } pulse(mc_illeg_address){ trace("MC ILLEG ADDRESS\n"); apr.cpa_illeg_op = 1; // TODO: IOB PI REQ CPA PIA return st7; } pulse(mc_rq_pulse){ trace("MC RQ PULSE\n"); apr.mc_stop = 0; // 7-9 /* catch non-existent memory */ apr.extpulse |= 4; if(calcaddr() == 0 && !apr.ex_inh_rel) return mc_illeg_address; set_mc_rq(1); if(apr.key_mem_stop || apr.ma == apr.mas && apr.sw_addr_stop){ apr.mc_stop = 1; // 7-9 // TODO: what is this? does it make any sense? if(apr.key_mem_cont) return kt4; } return NULL; } pulse(mc_rdwr_rq_pulse){ trace("MC RD/RW RQ PULSE\n"); set_mc_rd(1); // 7-9 set_mc_wr(1); // 7-9 apr.mb = 0; apr.mc_stop_sync = 1; // 7-9 return mc_rq_pulse; } pulse(mc_rd_rq_pulse){ trace("MC RD RQ PULSE\n"); set_mc_rd(1); // 7-9 set_mc_wr(0); // 7-9 apr.mb = 0; return mc_rq_pulse; } pulse(mc_split_rd_rq){ trace("MC SPLIT RD RQ\n"); return mc_rd_rq_pulse; } pulse(mc_wr_rq_pulse){ trace("MC WR RQ PULSE\n"); set_mc_rd(0); // 7-9 set_mc_wr(1); // 7-9 return mc_rq_pulse; } pulse(mc_split_wr_rq){ trace("MC SPLIT WR RQ\n"); return mc_wr_rq_pulse; } pulse(mc_rd_wr_rs_pulse){ trace("MC RD/WR RS PULSE\n"); return apr.mc_split_cyc_sync ? mc_split_wr_rq : mc_wr_rs; } /* * Keys */ pulse(key_rd_wr_ret){ trace("KEY RD WR RET\n"); apr.key_rd_wr = 0; // 5-2 // apr.ex_ill_op = 0; // ?? not found on 5-13 return kt4; // 5-2 } pulse(key_rd){ trace("KEY RD\n"); apr.key_rd_wr = 1; // 5-2 apr.mc_rst1_ret = key_rd_wr_ret; return mc_rd_rq_pulse; } pulse(key_wr){ trace("KEY WR\n"); apr.key_rd_wr = 1; // 5-2 apr.mb = apr.ar; // 6-3 apr.mc_rst1_ret = key_rd_wr_ret; return mc_wr_rq_pulse; } pulse(key_go){ trace("KEY GO\n"); apr.run = 1; apr.key_ex_st = 0; apr.key_dep_st = 0; apr.key_ex_sync = 0; apr.key_dep_sync = 0; return it0; } pulse(kt4){ trace("KT4\n"); if(apr.run && (apr.key_ex || apr.key_ex_next || apr.key_dep || apr.key_dep_next)) return key_go; // 5-2 // TODO check repeat switch return NULL; } pulse(kt3){ trace("KT3\n"); if(apr.key_readin || apr.key_start) apr.pc = apr.ma; // 5-12 if(apr.key_execute && !apr.run){ apr.mb = apr.ar; // 6-3 // TODO: go to KT4 to check repeat (when processor is idle) return it1a; // 5-3 } if(apr.key_ex || apr.key_ex_next) return key_rd; // 5-2 if(apr.key_dep || apr.key_dep_next) return key_wr; // 5-2 if(apr.key_start || apr.key_readin || apr.key_inst_cont) return key_go; // 5-4 return NULL; } #define KEY_MANUAL (apr.key_readin || apr.key_start || apr.key_inst_cont ||\ apr.key_mem_cont || apr.key_ex || apr.key_dep ||\ apr.key_ex_next || apr.key_dep_next || apr.key_execute ||\ apr.key_io_reset) pulse(kt12){ trace("KT1,2\n"); if(apr.key_io_reset) mr_start(); // 5-2 if(KEY_MANUAL && !apr.key_mem_cont) mr_clr(); // 5-2 if(!(apr.key_readin || apr.key_inst_cont || apr.key_mem_cont)) set_key_rim_sbr(0); // 5-2 if(apr.key_readin){ set_key_rim_sbr(1); // 5-2 apr.ma = apr.mas; } if(apr.key_start) apr.ma = apr.mas; if(apr.key_execute && !apr.run) apr.ar = apr.data; if(apr.key_ex) apr.ma = apr.mas; if(apr.key_ex_next) apr.ma = (apr.ma+1)&RT; if(apr.key_dep){ apr.ma = apr.mas; apr.ar = apr.data; } if(apr.key_dep_next){ apr.ma = (apr.ma+1)&RT; apr.ar = apr.data; } if(apr.key_mem_cont && apr.mc_stop) return mc_rs_t0; if(KEY_MANUAL && apr.mc_stop && apr.mc_stop_sync && !apr.key_mem_cont){ /* Finish rd/wr which should stop the processor. * Set flag to continue at KT3 */ apr.extpulse |= 2; return mc_wr_rs; } return kt3; // 5-2 } pulse(kt0a){ trace("KT0A\n"); apr.key_ex_st = 0; // 5-1 apr.key_dep_st = 0; // 5-1 apr.key_ex_sync = apr.key_ex || apr.key_ex_next; // 5-1 apr.key_dep_sync = apr.key_dep || apr.key_dep_next; // 5-1 if(!apr.run || apr.key_mem_cont) return kt12; // 5-2 return NULL; } pulse(kt0){ trace("KT0\n"); return kt0a; // 5-2 } pulse(key_manual){ trace("KEY MANUAL\n"); return kt0; // 5-2 } pulse(mai_addr_ack){ trace("MAI ADDR ACK\n"); return mc_addr_ack; } pulse(mai_rd_rs){ trace("MAI RD RS\n"); apr.mb = membus1; if(apr.ma == apr.mas) apr.mi = apr.mb; // 7-7 if(!apr.mc_stop) return mc_rs_t0; return NULL; } void* aprmain(void *p) { mr_pwr_clr(); while(apr.sw_power){ if(apr.extpulse & 1){ if(apr.nextpulse) printf("whaa: cpu wasn't idle\n"); apr.extpulse &= ~1; apr.nextpulse = key_manual; } if(apr.nextpulse) apr.nextpulse = apr.nextpulse(); else if(membus0 & MEMBUS_MAI_ADDR_ACK){ membus0 &= ~MEMBUS_MAI_ADDR_ACK; apr.extpulse &= ~4; apr.nextpulse = mai_addr_ack; }else if(membus0 & MEMBUS_MAI_RD_RS){ membus0 &= ~MEMBUS_MAI_RD_RS; apr.nextpulse = mai_rd_rs; }else if(apr.extpulse & 2){ /* continue at KT3 after finishing rd/wr from a stop */ apr.extpulse &= ~2; apr.nextpulse = kt3; }else if(apr.extpulse & 4){ apr.extpulse &= ~4; if(apr.mc_rq && !apr.mc_stop) apr.nextpulse = mc_non_exist_mem; } } printf("power off\n"); return NULL; }