diff --git a/10.01_base/2_src/arm/unibus.cpp b/10.01_base/2_src/arm/unibus.cpp index e358615..a31a100 100644 --- a/10.01_base/2_src/arm/unibus.cpp +++ b/10.01_base/2_src/arm/unibus.cpp @@ -94,14 +94,14 @@ char *unibus_c::control2text(uint8_t control) { return buffer; } -/* pulse INIT cycle for 50 milliseconds ... source? +/* pulse INIT cycle for some milliseconds */ -void unibus_c::init(void) { +void unibus_c::init(unsigned pulsewidth_ms) { timeout_c timeout; mailbox->initializationsignal.id = INITIALIZATIONSIGNAL_INIT; mailbox->initializationsignal.val = 1; mailbox_execute(ARM2PRU_INITALIZATIONSIGNAL_SET); - timeout.wait_ms(50); + timeout.wait_ms(pulsewidth_ms); mailbox->initializationsignal.id = INITIALIZATIONSIGNAL_INIT; mailbox->initializationsignal.val = 0; mailbox_execute(ARM2PRU_INITALIZATIONSIGNAL_SET); diff --git a/10.01_base/2_src/shared/unibus.h b/10.01_base/2_src/shared/unibus.h index bfdcece..2b238e5 100644 --- a/10.01_base/2_src/shared/unibus.h +++ b/10.01_base/2_src/shared/unibus.h @@ -85,7 +85,7 @@ public: static char *control2text(uint8_t control); static char *data2text(unsigned val); - void init(void); + void init(unsigned pulsewidth_ms); static void set_arbitration_mode(enum arbitration_mode_enum arbitration_mode); void powercycle(void); diff --git a/10.02_devices/2_src/cpu.cpp b/10.02_devices/2_src/cpu.cpp index b3669e1..afcea06 100644 --- a/10.02_devices/2_src/cpu.cpp +++ b/10.02_devices/2_src/cpu.cpp @@ -84,33 +84,6 @@ bool cpu_c::on_param_changed(parameter_c *param) { return device_c::on_param_changed(param); // more actions (for enable) } -extern "C" { -// functions to be used by Angelos CPU emulator -// Result: 1 = OK, 0 = bus timeout -int cpu_dato(unsigned addr, unsigned data) { - uint16_t wordbuffer = (uint16_t) data; - - unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATO, addr, &wordbuffer); - return the_cpu->data_transfer_request.success ; -} - -int cpu_datob(unsigned addr, unsigned data) { - uint16_t wordbuffer = (uint16_t) data; - // TODO DATOB als 1 byte-DMA ! - unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATOB, addr, &wordbuffer); - return the_cpu->data_transfer_request.success ; -} - -int cpu_dati(unsigned addr, unsigned *data) { - uint16_t wordbuffer; -unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATI, addr, &wordbuffer); - *data = wordbuffer; - // printf("DATI; ba=%o, data=%o\n", addr, *data) ; - - return the_cpu->data_transfer_request.success ; -} -} - // background worker. void cpu_c::worker(unsigned instance) { UNUSED(instance); // only one @@ -128,27 +101,27 @@ void cpu_c::worker(unsigned instance) { if (runmode.value != (ka11.state != 0)) ka11.state = runmode.value; - condstep(&ka11); + ka11_condstep(&ka11); if (runmode.value != (ka11.state != 0)) runmode.value = ka11.state != 0; if (init.value) { // user wants CPU reset - reset(&ka11); + ka11_reset(&ka11); init.value = 0; } #if 0 if (runmode.value) { // simulate a fetch - nxm = !cpu_dati(pc, &opcode); + nxm = !unibone_dati(pc, &opcode); if (nxm) { printf("Bus timeout at PC = %06o. HALT.\n", pc); runmode.value = false; } pc = (pc + 2) % 0100; // loop around // set LEDS - nxm = !cpu_dato(dr, pc & 0xf); + nxm = !unibone_dato(dr, pc & 0xf); if (nxm) { printf("Bus timeout at DR = %06o. HALT.\n", dr); runmode.value = false; @@ -173,17 +146,76 @@ void cpu_c::on_after_register_access(unibusdevice_register_t *device_reg, UNUSED(unibus_control); } +// TODO void cpu_c::on_power_changed(void) { if (power_down) { // power-on defaults + INFO("CPU: ACLO failed"); + ka11_pwrdown(&the_cpu->ka11); + // ACLO failed. + // CPU traps to vector 24 and has 2ms time to execute code + } else { + INFO("CPU: DCLO restored"); + ka11_pwrup(&the_cpu->ka11); + // DCLO restored + // CPU loads PC and PSW from vector 24 } } // UNIBUS INIT: clear all registers void cpu_c::on_init_changed(void) { - // write all registers to "reset-values" - if (init_asserted) { - reset_unibus_registers(); - INFO("cpu::on_init()"); - } +// a CPU does not react to INIT ... else its own RESET would reset it. + +} + +// TODO +// CPU received interrupt vector from UNIBUS +void cpu_c::on_interrupt(uint16_t vector) { + // CPU sequence: + // push PSW to stack + // push PC to stack + // PC := *vector + // PSW := *(vector+2) + ka11_setintr(&the_cpu->ka11, vector); +} + +extern "C" { +// functions to be used by Angelos CPU emulator +// Result: 1 = OK, 0 = bus timeout +int unibone_dato(unsigned addr, unsigned data) { + uint16_t wordbuffer = (uint16_t) data; + + unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATO, addr, + &wordbuffer); + return the_cpu->data_transfer_request.success; +} + +int unibone_datob(unsigned addr, unsigned data) { + uint16_t wordbuffer = (uint16_t) data; + // TODO DATOB als 1 byte-DMA ! + unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATOB, addr, + &wordbuffer); + return the_cpu->data_transfer_request.success; +} + +int unibone_dati(unsigned addr, unsigned *data) { + uint16_t wordbuffer; + unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATI, addr, + &wordbuffer); + *data = wordbuffer; + // printf("DATI; ba=%o, data=%o\n", addr, *data) ; + + return the_cpu->data_transfer_request.success; +} + +// CPU has changed the arbitration level, just forward +void unibone_prioritylevelchange(uint8_t level) { + mailbox->arbitrator.cpu_priority_level = level; +} + +// TODO +// CPU executes RESET opcode -> pulses INIT line +void unibone_bus_init(unsigned pulsewidth_ms) { + unibus->init(pulsewidth_ms); +} } diff --git a/10.02_devices/2_src/cpu.hpp b/10.02_devices/2_src/cpu.hpp index 802bd85..210f36e 100644 --- a/10.02_devices/2_src/cpu.hpp +++ b/10.02_devices/2_src/cpu.hpp @@ -69,6 +69,9 @@ public: void on_power_changed(void) override; void on_init_changed(void) override; + void on_interrupt(uint16_t vector) ; + }; + #endif diff --git a/10.02_devices/2_src/cpu20/ka11.c b/10.02_devices/2_src/cpu20/ka11.c index fa4fb48..fdc8e35 100644 --- a/10.02_devices/2_src/cpu20/ka11.c +++ b/10.02_devices/2_src/cpu20/ka11.c @@ -1,15 +1,18 @@ #include "11.h" #include "ka11.h" -int cpu_dato(unsigned addr, unsigned data); -int cpu_datob(unsigned addr, unsigned data); -int cpu_dati(unsigned addr, unsigned *data); +int unibone_dato(unsigned addr, unsigned data); +int unibone_datob(unsigned addr, unsigned data); +int unibone_dati(unsigned addr, unsigned *data); +void unibone_prioritylevelchange(uint8_t level); +void unibone_bus_init(unsigned pulsewidth_ms) ; + int dati_bus(Bus *bus) { unsigned int data; - if(!cpu_dati(bus->addr, &data)) + if(!unibone_dati(bus->addr, &data)) return 1; bus->data = data; return 0; @@ -18,15 +21,20 @@ dati_bus(Bus *bus) int dato_bus(Bus *bus) { - return !cpu_dato(bus->addr, bus->data); + return !unibone_dato(bus->addr, bus->data); } int datob_bus(Bus *bus) { - return !cpu_datob(bus->addr, bus->data); + return !unibone_datob(bus->addr, bus->data); } +void +levelchange(word psw) +{ + unibone_prioritylevelchange(psw>>5); +} @@ -42,11 +50,12 @@ enum { enum { TRAP_STACK = 1, - TRAP_PWR = 2, // can't happen + TRAP_PWR = 2, TRAP_BR7 = 4, TRAP_BR6 = 010, TRAP_BR5 = 040, TRAP_BR4 = 0100, + TRAP_BRX = 0200, // for unibone TRAP_CSTOP = 01000 // can't happen? }; @@ -107,7 +116,7 @@ printstate(KA11 *cpu) } void -reset(KA11 *cpu) +ka11_reset(KA11 *cpu) { Busdev *bd; @@ -171,6 +180,7 @@ trace("dato %06o %06o %d\n", cpu->ba, cpu->bus->data, b); /* writes 0 for the odd byte. I think this is correct. */ cpu->psw = cpu->bus->data; + levelchange(cpu->psw); goto ok; } } @@ -546,7 +556,7 @@ step(KA11 *cpu) SVC; case 3: TR(BPT); TRAP(014); case 4: TR(IOT); TRAP(020); - case 5: TR(RESET); reset(cpu); SVC; + case 5: TR(RESET); ka11_reset(cpu); unibone_bus_init(10) ; SVC; } // All other instructions should be reserved now @@ -567,6 +577,7 @@ trap: PUSH; OUT(SP, PC); INA(TV, PC); INA(TV+2, PSW); + levelchange(PSW); /* no trace trap after a trap */ oldpsw = PSW; @@ -586,6 +597,9 @@ service: }else if(cpu->traps & TRAP_PWR){ cpu->traps &= ~TRAP_PWR; TRAP(024); + }else if(cpu->traps & TRAP_BRX){ + cpu->traps &= ~TRAP_BRX; + TRAP(cpu->trapvec); }else if(c < 7 && cpu->traps & TRAP_BR7){ cpu->traps &= ~TRAP_BR7; TRAP(cpu->br[3].bg(cpu->br[3].dev)); @@ -605,7 +619,31 @@ service: } void -condstep(KA11 *cpu) +ka11_setintr(KA11 *cpu, unsigned vec) +{ + cpu->traps |= TRAP_BRX; + cpu->trapvec = vec; +} + +void +ka11_pwrdown(KA11 *cpu) +{ + cpu->traps |= TRAP_PWR; +} + +void +ka11_pwrup(KA11 *cpu) +{ + INA(024, PC); + INA(024+2, PSW); + return ; +be: + trace("BE\n"); + cpu->be++ ; +} + +void +ka11_condstep(KA11 *cpu) { if((cpu->state == STATE_RUNNING) || (cpu->state == STATE_WAITING && cpu->traps)){ @@ -621,7 +659,7 @@ run(KA11 *cpu) while(cpu->state != STATE_HALTED){ svc(cpu, cpu->bus); - condstep(cpu); + ka11_condstep(cpu); } printstate(cpu); diff --git a/10.02_devices/2_src/cpu20/ka11.h b/10.02_devices/2_src/cpu20/ka11.h index ec0a65d..b709d89 100644 --- a/10.02_devices/2_src/cpu20/ka11.h +++ b/10.02_devices/2_src/cpu20/ka11.h @@ -1,4 +1,4 @@ -// 11/20 cpu - TODO +// Interface of 11/20 PCU emulator to UniBone typedef struct KA11 KA11; struct KA11 { @@ -16,9 +16,14 @@ struct KA11 int (*bg)(void *dev); void *dev; } br[4]; + word trapvec; // for unibone word sw; }; -//void run(KA11 *cpu); -void reset(KA11 *cpu); -void condstep(KA11 *cpu); + +void ka11_reset(KA11 *cpu); +void ka11_setintr(KA11 *cpu, unsigned vec); +void ka11_pwrdown(KA11 *cpu); +void ka11_pwrup(KA11 *cpu); +void ka11_condstep(KA11 *cpu); + diff --git a/10.03_app_demo/2_src/menu_device_exercisers.cpp b/10.03_app_demo/2_src/menu_device_exercisers.cpp index 827965b..9746536 100644 --- a/10.03_app_demo/2_src/menu_device_exercisers.cpp +++ b/10.03_app_demo/2_src/menu_device_exercisers.cpp @@ -121,7 +121,7 @@ void application_c::menu_device_exercisers(void) { if (!strcasecmp(s_opcode, "q")) { ready = true; } else if (!strcasecmp(s_opcode, "init")) { - unibus->init(); + unibus->init(50); } else if (!strcasecmp(s_opcode, "pwr")) { unibus->powercycle(); } else if (!strcasecmp(s_opcode, "dbg") && n_fields == 2) { diff --git a/10.03_app_demo/2_src/menu_devices.cpp b/10.03_app_demo/2_src/menu_devices.cpp index a78f3a4..adcb84e 100644 --- a/10.03_app_demo/2_src/menu_devices.cpp +++ b/10.03_app_demo/2_src/menu_devices.cpp @@ -140,7 +140,7 @@ void application_c::menu_devices(bool with_CPU) { // without PDP-11 CPU no INIT after power ON was generated. // Devices may trash the bus lines. - unibus->init(); + unibus->init(50); unibusadapter->enabled.set(true); @@ -262,7 +262,7 @@ void application_c::menu_devices(bool with_CPU) { if (!strcasecmp(s_opcode, "q")) { ready = true; } else if (!strcasecmp(s_opcode, "init")) { - unibus->init(); + unibus->init(50); } else if (!strcasecmp(s_opcode, "pwr")) { unibus->powercycle(); } else if (!strcasecmp(s_opcode, "dbg") && n_fields == 2) { diff --git a/10.03_app_demo/2_src/menu_masterslave.cpp b/10.03_app_demo/2_src/menu_masterslave.cpp index 2a009d2..f093558 100644 --- a/10.03_app_demo/2_src/menu_masterslave.cpp +++ b/10.03_app_demo/2_src/menu_masterslave.cpp @@ -155,7 +155,7 @@ void application_c::menu_masterslave(enum unibus_c::arbitration_mode_enum arbitr else printf("%s\n", fileErrorText("Error opening command file \"%s\"!", s_param[0])); } else if (!strcasecmp(s_opcode, "init")) { - unibus->init(); + unibus->init(50); } else if (!strcasecmp(s_opcode, "i")) { iopageregisters_print_tables(); } else if (!strcasecmp(s_opcode, "pwr")) {