mirror of
https://github.com/aap/pdp6.git
synced 2026-01-29 21:31:11 +00:00
612 lines
11 KiB
C
612 lines
11 KiB
C
#include "pdp6.h"
|
|
|
|
typedef void *Pulse(void);
|
|
#define pulse(p) void *p(void)
|
|
|
|
/* external pulses:
|
|
* KEY MANUAL
|
|
* MAI-CMC ADDR ACK
|
|
* MAI RD RS
|
|
*/
|
|
|
|
Apr apr;
|
|
int extpulse;
|
|
Pulse *nextpulse;
|
|
Pulse *mc_rst1_ret;
|
|
|
|
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
|
|
set_pir(u8 value)
|
|
{
|
|
int chan;
|
|
u8 req;
|
|
// 8-3
|
|
apr.pir = value;
|
|
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;
|
|
}
|
|
}
|
|
apr.pi_rq = !!apr.pi_req; // 8-4
|
|
}
|
|
|
|
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(iat0);
|
|
pulse(mc_wr_rs);
|
|
pulse(mc_rd_rq_pulse);
|
|
|
|
// TODO: find A LONG
|
|
|
|
pulse(pi_reset){
|
|
printf("PI RESET\n");
|
|
apr.pi_active = 0; // 8-4
|
|
apr.pih = 0; // 8-4
|
|
set_pir(0); // 8-4
|
|
apr.pio = 0; // 8-3
|
|
return NULL;
|
|
}
|
|
|
|
pulse(ar_flag_clr){
|
|
printf("AR FLAG CLR\n");
|
|
apr.pc_chg_flag = 0; // 6-10
|
|
apr.ar_ov_flag = 0; // 6-10
|
|
apr.ar_cry0_flag = 0; // 6-10
|
|
apr.ar_cry1_flag = 0; // 6-10
|
|
apr.chf7 = 0; // 6-19
|
|
return NULL;
|
|
}
|
|
|
|
pulse(mr_clr){
|
|
printf("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 :(
|
|
// TODO: MP CLR, DS CLR
|
|
|
|
/* sbr flip-flops */
|
|
apr.key_rd_wr = 0; // 5-2
|
|
apr.if1a = 0; // 5-3
|
|
mc_rst1_ret = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
pulse(mr_start){
|
|
printf("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;
|
|
|
|
// apr.ex_user = 1;
|
|
// apr.rlr = 2;
|
|
// apr.pr = 1;
|
|
return NULL;
|
|
}
|
|
|
|
pulse(mr_pwr_clr){
|
|
printf("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){
|
|
printf("ST7\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Priority Interrupt
|
|
*/
|
|
|
|
pulse(pir_stb){
|
|
printf("PIR STB\n");
|
|
set_pir(apr.pir | apr.pio & iobus1); // 8-3
|
|
return NULL;
|
|
}
|
|
|
|
pulse(pi_sync){
|
|
printf("PI SYNC\n");
|
|
if(!apr.pi_cyc)
|
|
pir_stb();
|
|
// 5-3
|
|
if(apr.pi_rq && !apr.pi_cyc)
|
|
return iat0;
|
|
// TODO: IA INH/AT INH
|
|
if(apr.if1a)
|
|
return it1;
|
|
return at1;
|
|
}
|
|
|
|
/*
|
|
* Address
|
|
*/
|
|
|
|
pulse(at1){
|
|
printf("AT1\n");
|
|
return NULL;
|
|
}
|
|
|
|
pulse(at0){
|
|
printf("AT0\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Instruction
|
|
*/
|
|
|
|
pulse(iat0){
|
|
printf("IAT0\n");
|
|
mr_clr();
|
|
set_pi_cyc(1);
|
|
return it1;
|
|
}
|
|
|
|
pulse(it1a){
|
|
printf("IT1A\n");
|
|
apr.if1a = 0;
|
|
apr.ir |= (apr.mb & 0777740000000) >> 18; // 5-7
|
|
if(apr.ma & 0777760)
|
|
set_key_rim_sbr(0); // 5-2
|
|
return at0;
|
|
}
|
|
|
|
pulse(it1){
|
|
printf("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)&0777777; // 7-3
|
|
apr.if1a = 1;
|
|
mc_rst1_ret = it1a;
|
|
return mc_rd_rq_pulse;
|
|
}
|
|
|
|
pulse(it0){
|
|
printf("IT0\n");
|
|
apr.ma = 0;
|
|
mr_clr();
|
|
apr.if1a = 1; // 5-3
|
|
return pi_sync;
|
|
}
|
|
|
|
/*
|
|
* Memory Control
|
|
*/
|
|
|
|
pulse(mc_rs_t1){
|
|
printf("MC RS T1\n");
|
|
set_mc_rd(0);
|
|
if(apr.key_ex_next || apr.key_dep_next)
|
|
apr.mi = apr.mb; // 7-7
|
|
return mc_rst1_ret;
|
|
}
|
|
|
|
pulse(mc_rs_t0){
|
|
printf("MC RS T0\n");
|
|
apr.mc_stop = 0;
|
|
return mc_rs_t1;
|
|
}
|
|
|
|
pulse(mc_wr_rs){
|
|
printf("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){
|
|
printf("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){
|
|
printf("MC NON EXIST RD\n");
|
|
if(!apr.mc_stop)
|
|
return mc_rs_t0;
|
|
return NULL;
|
|
}
|
|
|
|
pulse(mc_non_exist_mem_rst){
|
|
printf("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){
|
|
printf("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){
|
|
printf("MC ILLEG ADDRESS\n");
|
|
apr.cpa_illeg_op = 1;
|
|
// TODO: IOB PI REQ CPA PIA
|
|
return st7;
|
|
}
|
|
|
|
pulse(mc_rq_pulse){
|
|
printf("MC RQ PULSE\n");
|
|
apr.mc_stop = 0; // 7-9
|
|
/* catch non-existent memory */
|
|
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){
|
|
printf("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){
|
|
printf("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){
|
|
printf("MC SPLIT RD RQ\n");
|
|
return mc_rd_rq_pulse;
|
|
}
|
|
|
|
pulse(mc_wr_rq_pulse){
|
|
printf("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){
|
|
printf("MC SPLIT WR RQ\n");
|
|
return mc_wr_rq_pulse;
|
|
}
|
|
|
|
pulse(mc_rd_wr_rs_pulse){
|
|
printf("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){
|
|
printf("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){
|
|
printf("KEY RD\n");
|
|
apr.key_rd_wr = 1; // 5-2
|
|
mc_rst1_ret = key_rd_wr_ret;
|
|
return mc_rd_rq_pulse;
|
|
}
|
|
|
|
pulse(key_wr){
|
|
printf("KEY WR\n");
|
|
apr.key_rd_wr = 1; // 5-2
|
|
apr.mb = apr.ar; // 6-3
|
|
mc_rst1_ret = key_rd_wr_ret;
|
|
return mc_wr_rq_pulse;
|
|
}
|
|
|
|
pulse(key_go){
|
|
printf("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){
|
|
printf("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){
|
|
printf("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){
|
|
printf("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)&0777777;
|
|
if(apr.key_dep){
|
|
apr.ma = apr.mas;
|
|
apr.ar = apr.data;
|
|
}
|
|
if(apr.key_dep_next){
|
|
apr.ma = (apr.ma+1)&0777777;
|
|
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 */
|
|
extpulse |= 2;
|
|
return mc_wr_rs;
|
|
}
|
|
return kt3; // 5-2
|
|
}
|
|
|
|
pulse(kt0a){
|
|
printf("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){
|
|
printf("KT0\n");
|
|
return kt0a; // 5-2
|
|
}
|
|
|
|
pulse(key_manual){
|
|
printf("KEY MANUAL\n");
|
|
return kt0; // 5-2
|
|
}
|
|
|
|
pulse(mai_addr_ack){
|
|
printf("MAI ADDR ACK\n");
|
|
return mc_addr_ack;
|
|
}
|
|
|
|
pulse(mai_rd_rs){
|
|
printf("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(extpulse & 1){
|
|
if(nextpulse)
|
|
printf("whaa: cpu wasn't idle\n");
|
|
extpulse &= ~1;
|
|
nextpulse = key_manual;
|
|
}
|
|
if(nextpulse)
|
|
nextpulse = nextpulse();
|
|
else if(membus0 & MEMBUS_MAI_ADDR_ACK){
|
|
membus0 &= ~MEMBUS_MAI_ADDR_ACK;
|
|
extpulse &= ~4;
|
|
nextpulse = mai_addr_ack;
|
|
}else if(membus0 & MEMBUS_MAI_RD_RS){
|
|
membus0 &= ~MEMBUS_MAI_RD_RS;
|
|
nextpulse = mai_rd_rs;
|
|
}else if(extpulse & 2){
|
|
/* continue at KT3 after finishing rd/wr from a stop */
|
|
extpulse &= ~2;
|
|
nextpulse = kt3;
|
|
}else if(extpulse & 4){
|
|
extpulse &= ~4;
|
|
if(apr.mc_rq && !apr.mc_stop)
|
|
nextpulse = mc_non_exist_mem;
|
|
}
|
|
}
|
|
printf("power off\n");
|
|
return NULL;
|
|
}
|