From d058310e538f64b639dd83faedbf93a0a91a1ea5 Mon Sep 17 00:00:00 2001 From: Joerg Hoppe Date: Tue, 27 Aug 2019 19:05:41 +0200 Subject: [PATCH] CPU20 power start/power fail --- 10.01_base/2_src/arm/unibus.cpp | 2 +- 10.01_base/2_src/arm/unibusadapter.cpp | 95 +++++++---- 10.01_base/2_src/arm/unibusadapter.hpp | 5 + 10.01_base/2_src/arm/unibuscpu.cpp | 54 +++++++ 10.01_base/2_src/arm/unibuscpu.hpp | 52 ++++++ 10.01_base/2_src/arm/unibusdevice.hpp | 1 + 10.01_base/2_src/pru1/Makefile | 3 +- 10.01_base/2_src/pru1/pru1_main_test.c | 6 +- 10.01_base/2_src/pru1/pru1_main_unibus.c | 42 +++-- .../pru1/pru1_statemachine_arbitration.c | 5 +- .../2_src/pru1/pru1_statemachine_data_slave.c | 46 +++--- .../2_src/pru1/pru1_statemachine_data_slave.h | 8 +- 10.01_base/2_src/pru1/pru1_statemachine_dma.c | 2 - 10.01_base/2_src/pru1/pru1_statemachine_dma.h | 2 - .../pru1/pru1_statemachine_intr_master.c | 5 +- .../2_src/pru1/pru1_statemachine_intr_slave.c | 93 +++++++++++ .../2_src/pru1/pru1_statemachine_intr_slave.h | 40 +++++ 10.01_base/2_src/shared/mailbox.h | 26 ++- 10.02_devices/2_src/cpu.cpp | 54 ++++--- 10.02_devices/2_src/cpu.hpp | 9 +- 10.03_app_demo/2_src/makefile | 6 +- 10.03_app_demo/5_applications/cpu/serial.lst | 152 +++++++++--------- 10.03_app_demo/5_applications/cpu/serial.mac | 8 +- 23 files changed, 523 insertions(+), 193 deletions(-) create mode 100644 10.01_base/2_src/arm/unibuscpu.cpp create mode 100644 10.01_base/2_src/arm/unibuscpu.hpp create mode 100644 10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c create mode 100644 10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h diff --git a/10.01_base/2_src/arm/unibus.cpp b/10.01_base/2_src/arm/unibus.cpp index a31a100..e3fdcc9 100644 --- a/10.01_base/2_src/arm/unibus.cpp +++ b/10.01_base/2_src/arm/unibus.cpp @@ -116,7 +116,7 @@ void unibus_c::init(unsigned pulsewidth_ms) { */ void unibus_c::powercycle(void) { timeout_c timeout; - const unsigned delay_ms = 100; // time between phases + const unsigned delay_ms = 200; // time between phases mailbox->initializationsignal.id = INITIALIZATIONSIGNAL_ACLO; mailbox->initializationsignal.val = 1; mailbox_execute(ARM2PRU_INITALIZATIONSIGNAL_SET); diff --git a/10.01_base/2_src/arm/unibusadapter.cpp b/10.01_base/2_src/arm/unibusadapter.cpp index e8c86c7..ab9b81f 100644 --- a/10.01_base/2_src/arm/unibusadapter.cpp +++ b/10.01_base/2_src/arm/unibusadapter.cpp @@ -68,6 +68,8 @@ using namespace std; #include "iopageregister.h" #include "priorityrequest.hpp" #include "unibusadapter.hpp" +#include "unibuscpu.hpp" + unibusadapter_c *unibusadapter; // another Singleton // is registered in device_c.list ... order of static constructor calls ??? @@ -85,11 +87,13 @@ unibusadapter_c::unibusadapter_c() : devices[i] = NULL; line_INIT = false; line_DCLO = false; - line_ACLO = false ; + line_ACLO = false; requests_mutex = PTHREAD_MUTEX_INITIALIZER; requests_init(); + + the_cpu = NULL; } bool unibusadapter_c::on_param_changed(parameter_c *param) { @@ -214,6 +218,15 @@ bool unibusadapter_c::register_device(unibusdevice_c& device) { register_handle++; } + // if its a CPU, switch PRU to "with_CPU" + unibuscpu_c *cpu = dynamic_cast(&device); + if (cpu) { + assert(the_cpu == NULL); // only one allowed! + the_cpu = cpu; + // TODO: PRU code debuggen + //mailbox->cpu_enable = 1 ; + //mailbox_execute(ARM2PRU_CPU_ENABLE) ; + } return true; } @@ -227,6 +240,14 @@ void unibusadapter_c::unregister_device(unibusdevice_c& device) { INFO("UnibusAdapter: UnRegistering device %s.", device.name.value.c_str()); + // if its a CPU, disable PRU to "with_CPU" + unibuscpu_c *cpu = dynamic_cast(&device); + if (cpu) { + mailbox->cpu_enable = 0; + mailbox_execute(ARM2PRU_CPU_ENABLE); + the_cpu = NULL; + } + // remove "from backplane" devices[device.handle] = NULL; device.handle = 0; @@ -302,8 +323,8 @@ void unibusadapter_c::requests_cancel_scheduled(void) { prl->slot_request[slot] = NULL; // signal to blocking DMA() or INTR() pthread_mutex_lock(&req->complete_mutex); - req->complete = true; - pthread_cond_signal(&req->complete_cond); + req->complete = true; + pthread_cond_signal(&req->complete_cond); pthread_mutex_unlock(&req->complete_mutex); } } @@ -492,8 +513,8 @@ void unibusadapter_c::request_active_complete(unsigned level_index) { // signal to DMA() or INTR() pthread_mutex_lock(&tmprq->complete_mutex); - tmprq->complete = true; - pthread_cond_signal(&tmprq->complete_cond); + tmprq->complete = true; + pthread_cond_signal(&tmprq->complete_cond); pthread_mutex_unlock(&tmprq->complete_mutex); } @@ -525,7 +546,7 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni // dma_request.level-index, priority_slot in constructor dma_request.complete = false; - dma_request.success = false; + dma_request.success = false; dma_request.executing_on_PRU = false; dma_request.unibus_control = unibus_control; dma_request.unibus_start_addr = unibus_addr; @@ -551,12 +572,13 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni // DEBUG("device DMA start: %s @ %06o, len=%d", unibus->control2text(unibus_control), unibus_addr, wordcount); if (blocking) { pthread_mutex_lock(&dma_request.complete_mutex); - // DMA() is blocking: Wait for request to finish. - // pthread_mutex_lock(&dma_request.mutex); - while (!dma_request.complete) { - int res = pthread_cond_wait(&dma_request.complete_cond, &dma_request.complete_mutex); - assert(!res) ; - } + // DMA() is blocking: Wait for request to finish. + // pthread_mutex_lock(&dma_request.mutex); + while (!dma_request.complete) { + int res = pthread_cond_wait(&dma_request.complete_cond, + &dma_request.complete_mutex); + assert(!res); + } pthread_mutex_unlock(&dma_request.complete_mutex); } } @@ -681,17 +703,18 @@ void unibusadapter_c::cancel_INTR(intr_request_c& intr_request) { // both empty, or both filled assert((prl->slot_request_mask == 0) == (prl->active == NULL)); - pthread_mutex_lock(&intr_request.complete_mutex); - pthread_cond_signal(&intr_request.complete_cond); + pthread_mutex_lock(&intr_request.complete_mutex); + pthread_cond_signal(&intr_request.complete_cond); pthread_mutex_unlock(&intr_request.complete_mutex); pthread_mutex_unlock(&requests_mutex); // lock schedule table operations } + // do DATO/DATI as master CPU. // no NPR/NPG/SACK request, but waiting for BUS idle -// result: success, else BUS TIMOUT +// result: success, else BUS TIMEOUT void unibusadapter_c::cpu_DATA_transfer(dma_request_c& dma_request, uint8_t unibus_control, uint32_t unibus_addr, uint16_t *buffer) { timeout_c timeout; @@ -721,17 +744,15 @@ void unibusadapter_c::cpu_DATA_transfer(dma_request_c& dma_request, uint8_t unib // then ARM2PRU_DMA is answered with an error // infinite time may have passed after that check above } while (!success); - // wait for PRU complete event - //pthread_mutex_lock(&cpu_data_transfer_request->complete_mutex); - //pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex); - pthread_mutex_lock(&cpu_data_transfer_request->complete_mutex); - // DMA() is blocking: Wait for request to finish. - // pthread_mutex_lock(&dma_request.mutex); - while (!cpu_data_transfer_request->complete) { - int res = pthread_cond_wait(&cpu_data_transfer_request->complete_cond, &cpu_data_transfer_request->complete_mutex); - assert(!res) ; - } - pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex); + // wait for PRU complete event, no clear why that double lock() is working anyhow! + pthread_mutex_lock(&cpu_data_transfer_request->complete_mutex); + // DMA() is blocking: Wait for request to finish. + while (!cpu_data_transfer_request->complete) { + int res = pthread_cond_wait(&cpu_data_transfer_request->complete_cond, + &cpu_data_transfer_request->complete_mutex); + assert(!res); + } + pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex); // Copy incoming data from mailbox DMA buffer if (unibus_control == UNIBUS_CONTROL_DATI) @@ -1048,7 +1069,8 @@ void unibusadapter_c::worker(unsigned instance) { "EVENT_INITIALIZATIONSIGNALS: (sigprev=0x%x,) cur=0x%x, init_raise=%d, init_fall=%d, dclo_raise/fall=%d%/d, aclo_raise/fall=%d/%d", mailbox->events.initialization_signals_prev, mailbox->events.initialization_signals_cur, init_raising_edge, - init_falling_edge, dclo_raising_edge, dclo_falling_edge, aclo_raising_edge, aclo_falling_edge); + init_falling_edge, dclo_raising_edge, dclo_falling_edge, + aclo_raising_edge, aclo_falling_edge); } if (dclo_raising_edge) @@ -1073,15 +1095,28 @@ void unibusadapter_c::worker(unsigned instance) { pthread_mutex_unlock(&requests_mutex); mailbox->events.event_dma = 0; // PRU may re-raise and change mailbox now } - if (mailbox->events.event_intr) { - // INTRs are granted unpredictable by Arbitrator + if (mailbox->events.event_intr_master) { + // Device INTR was transmitted. INTRs are granted unpredictable by Arbitrator any_event = true; // INTR of which level? the .active rquest of the" pthread_mutex_lock(&requests_mutex); worker_intr_complete_event(mailbox->events.event_intr_level_index); pthread_mutex_unlock(&requests_mutex); - mailbox->events.event_intr = 0; // PRU may re-raise and change mailbox now + mailbox->events.event_intr_master = 0; // PRU may re-raise and change mailbox now } + if (mailbox->events.event_intr_slave) { + // If CPU emulation enabled: a device INTR was detected on bus, + assert(the_cpu); // if INTR events are enabled, cpu must be instantiated + // see register_device() + the_cpu->on_interrupt(mailbox->events.event_intr_vector); + // clear SSYN, INTR cycle completes + mailbox->events.event_intr_slave = 0; + // mailbox->arbitrator.cpu_priority_level now CPU_PRIORITY_LEVEL_FETCHING + // BG grants blocked + + // PRU may re-raise and change mailbox now + } + if (init_raising_edge) // INIT deasserted -> asserted. DATI/DATO cycle only possible before that. worker_init_event(); } diff --git a/10.01_base/2_src/arm/unibusadapter.hpp b/10.01_base/2_src/arm/unibusadapter.hpp index 420e3fa..3c095ba 100644 --- a/10.01_base/2_src/arm/unibusadapter.hpp +++ b/10.01_base/2_src/arm/unibusadapter.hpp @@ -49,6 +49,9 @@ public: void clear(); }; +class unibuscpu_c ; + + // is a device_c. need a thread (but no params) class unibusadapter_c: public device_c { private: @@ -61,6 +64,8 @@ private: pthread_mutex_t requests_mutex; + unibuscpu_c *the_cpu ; // only one unibuscpu_c may be registered + void worker_init_event(void); void worker_power_event(bool power_down); void worker_deviceregister_event(void); diff --git a/10.01_base/2_src/arm/unibuscpu.cpp b/10.01_base/2_src/arm/unibuscpu.cpp new file mode 100644 index 0000000..3e4d32f --- /dev/null +++ b/10.01_base/2_src/arm/unibuscpu.cpp @@ -0,0 +1,54 @@ +/* unibuscpu.cpp: base class for all CPU implementations + + Copyright (c) 2019, Joerg Hoppe + j_hoppe@t-online.de, www.retrocmp.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +27-aug-2019 JH start + */ + +#include "unibuscpu.hpp" + +void unibuscpu_c::on_power_changed(void) { +// called within a bus_cycle, and initiates other cycles?! +//assert(dbg==0) ; + if (power_down) { // power-on defaults + INFO("CPU: ACLO failed"); + power_event = power_event_down; +// ka11_pwrdown(&the_cpu->ka11); + // ACLO failed. + // CPU traps to vector 24 and has 2ms time to execute code + } else { + INFO("CPU: DCLO restored"); + power_event = power_event_up; +// ka11_pwrup(&the_cpu->ka11); + // DCLO restored + // CPU loads PC and PSW from vector 24 + // if HALTed: do nothing, user is expected to setup PC and PSW ? + } + +} + +// UNIBUS INIT: clear all registers +void unibuscpu_c::on_init_changed(void) { +// a CPU does not react to INIT ... else its own RESET would reset it. +} + + diff --git a/10.01_base/2_src/arm/unibuscpu.hpp b/10.01_base/2_src/arm/unibuscpu.hpp new file mode 100644 index 0000000..4d89c4b --- /dev/null +++ b/10.01_base/2_src/arm/unibuscpu.hpp @@ -0,0 +1,52 @@ +/* unibuscpu.hpp: base class for all CPU implementations + + Copyright (c) 2019, Joerg Hoppe + j_hoppe@t-online.de, www.retrocmp.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +27-aug-2019 JH start + */ + +#ifndef _UNIBUSCPU_HPP_ +#define _UNIBUSCPU_HPP_ + + +#include "unibusdevice.hpp" + +// a CPU is just a device with INTR facilities +class unibuscpu_c: public unibusdevice_c { + public: + unibuscpu_c(): unibusdevice_c() { + power_event = power_event_none ; + } ; + + enum power_event_enum {power_event_none, power_event_up, power_event_down} ; + + enum power_event_enum power_event ; + + // called by PRU on INTR, returns new priority level + virtual void on_interrupt(uint16_t vector) = 0 ; + + + virtual void on_power_changed(void) ; + virtual void on_init_changed(void) ; +}; + +#endif diff --git a/10.01_base/2_src/arm/unibusdevice.hpp b/10.01_base/2_src/arm/unibusdevice.hpp index 09498cd..1aaf674 100644 --- a/10.01_base/2_src/arm/unibusdevice.hpp +++ b/10.01_base/2_src/arm/unibusdevice.hpp @@ -168,4 +168,5 @@ public: }; + #endif diff --git a/10.01_base/2_src/pru1/Makefile b/10.01_base/2_src/pru1/Makefile index 22788d5..ffbe6e6 100644 --- a/10.01_base/2_src/pru1/Makefile +++ b/10.01_base/2_src/pru1/Makefile @@ -71,8 +71,9 @@ OBJECTS_COMMON= \ $(OBJ_DIR)/pru1_pru_mailbox.object \ $(OBJ_DIR)/pru1_statemachine_arbitration.object \ $(OBJ_DIR)/pru1_statemachine_dma.object \ - $(OBJ_DIR)/pru1_statemachine_intr_master.object \ $(OBJ_DIR)/pru1_statemachine_data_slave.object \ + $(OBJ_DIR)/pru1_statemachine_intr_master.object \ + $(OBJ_DIR)/pru1_statemachine_intr_slave.object \ $(OBJ_DIR)/pru1_timeouts.object \ $(OBJ_DIR)/pru1_utils.object diff --git a/10.01_base/2_src/pru1/pru1_main_test.c b/10.01_base/2_src/pru1/pru1_main_test.c index e85cd26..35ca702 100644 --- a/10.01_base/2_src/pru1/pru1_main_test.c +++ b/10.01_base/2_src/pru1/pru1_main_test.c @@ -54,10 +54,10 @@ #include "pru1_statemachine_arbitration.h" #include "pru1_statemachine_dma.h" #include "pru1_statemachine_intr_master.h" -#include "pru1_statemachine_slave.h" +#include "pru1_statemachine_data_slave.h" // Supress warnings about using void * as function pointers -// sm_slave_state = (statemachine_state_func)&sm_slave_start; +// sm_slave_state = (statemachine_state_func)&sm_data_slave_start; // while (sm_slave_state = sm_slave_state()) << usage #pragma diag_push #pragma diag_remark=515 @@ -203,7 +203,7 @@ void main(void) { // writing into mailbox.arm2pru_req while (mailbox.arm2pru_req == ARM2PRU_DDR_SLAVE_MEMORY) { statemachine_state_func sm_slave_state = - (statemachine_state_func) &sm_slave_start; + (statemachine_state_func) &sm_data_slave_start; // do all states of an access, start when MSYN found. while (sm_slave_state = sm_slave_state()) ; diff --git a/10.01_base/2_src/pru1/pru1_main_unibus.c b/10.01_base/2_src/pru1/pru1_main_unibus.c index bfc4251..5105544 100644 --- a/10.01_base/2_src/pru1/pru1_main_unibus.c +++ b/10.01_base/2_src/pru1/pru1_main_unibus.c @@ -58,11 +58,12 @@ #include "pru1_buslatches.h" #include "pru1_statemachine_arbitration.h" #include "pru1_statemachine_dma.h" +#include "pru1_statemachine_data_slave.h" #include "pru1_statemachine_intr_master.h" -#include "pru1_statemachine_slave.h" +#include "pru1_statemachine_intr_slave.h" // supress warnigns about using void * as function pointers -// sm_slave_state = (statemachine_state_func)&sm_slave_start; +// sm_slave_state = (statemachine_state_func)&sm_data_slave_start; // while (sm_slave_state = sm_slave_state()) << usage #pragma diag_push #pragma diag_remark=515 @@ -93,8 +94,11 @@ void main(void) { statemachine_arb_worker_func sm_arb_worker = &sm_arb_worker_client; statemachine_state_func sm_data_slave_state = NULL; statemachine_state_func sm_data_master_state = NULL; + statemachine_state_func sm_intr_slave_state = NULL ; // these are function pointers: could be 16bit on PRU? + bool emulate_cpu = false; + /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; @@ -118,16 +122,27 @@ void main(void) { uint8_t arm2pru_req_cached; if (sm_data_master_state == NULL) { - // State 1 "SLAVE" + // State 1 "SLAVE" + + // DATA or INTR for CPU? + // fast: a complete slave data cycle if (!sm_data_slave_state) - sm_data_slave_state = (statemachine_state_func) &sm_slave_start; + sm_data_slave_state = (statemachine_state_func) &sm_data_slave_start; while ((sm_data_slave_state = sm_data_slave_state()) && !mailbox.events.event_deviceregister) // throws signals to ARM, // Acess to internal registers may may issue AMR2PRU opcode, so exit loop then ;// execute complete slave cycle, then check NPR/INTR + if (emulate_cpu) { + // same code loop as for DATA cycle + if (!sm_intr_slave_state) + sm_intr_slave_state = (statemachine_state_func) &sm_intr_slave_start; + while ((sm_intr_slave_state = sm_intr_slave_state()) + && !mailbox.events.event_intr_slave) ; + } + // signal INT or PWR FAIL to ARM do_event_initializationsignals(); @@ -160,10 +175,10 @@ void main(void) { // we have been GRANTed bus mastership and are doing DMA or INTR // SACK held here -> no further arbitration // INTR is only 1 cycle, DMA has SACK set all the time, arbitration - // prohibited then. + // prohibited then. sm_data_master_state = sm_data_master_state(); // execute only ONE state , - // else DMA blocks will block prcoessing of other state machines + // else DMA blocks will block processing of other state machines // throws signals to ARM, causes may issue mailbox.arm2pru_req } @@ -193,7 +208,7 @@ void main(void) { if (mailbox.arbitrator.cpu_BBSY) { // ARM CPU emulation did a single word DATA transfer with cpu_DATA_transfer() if (mailbox.arbitrator.device_BBSY) { - // ARM started cpu DATA transfer, but arbitration logic + // ARM started cpu DATA transfer, but arbitration logic // GRANTed a device request in the mean time. Tell ARM. mailbox.arm2pru_req = PRU2ARM_DMA_CPU_TRANSFER_BLOCKED; // error mailbox.arbitrator.cpu_BBSY = false; @@ -227,7 +242,7 @@ void main(void) { // vector of GRANted level is transfered with statemachine sm_intr_master // Atomically change state in a device's associates interrupt register. - // The Interupt Register is set immediately. No wait for INTR GRANT, + // The Interupt Register is set immediately. No wait for INTR GRANT, // INTR level may be blocked. if (mailbox.intr.iopage_register_handle) deviceregisters.registers[mailbox.intr.iopage_register_handle].value = @@ -259,7 +274,16 @@ void main(void) { } mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done break; - case ARM2PRU_HALT: + case ARM2PRU_CPU_ENABLE: + // bool flag much faster to access then shared mailbox member. + emulate_cpu = mailbox.cpu_enable ; + if (emulate_cpu) + sm_arb_worker = &sm_arb_worker_master; + else + sm_arb_worker = &sm_arb_worker_client; + mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done + break ; + case ARM2PRU_HALT: mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done __halt(); // LA: trigger on timeout of REG_WRITE break; diff --git a/10.01_base/2_src/pru1/pru1_statemachine_arbitration.c b/10.01_base/2_src/pru1/pru1_statemachine_arbitration.c index bd7cfe9..0305584 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_arbitration.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_arbitration.c @@ -238,7 +238,10 @@ PRU_DEBUG_PIN_PULSE_100NS ; uint8_t requested_intr_level = requests_2_highests_intr[intr_request_mask]; // compare against cpu run level 4..7 - if (requested_intr_level > mailbox.arbitrator.cpu_priority_level) { + // but do not GRANT anything if emulated CPU did not fetch new PSW yet, + // then cpu_priority_level is invalid + if (requested_intr_level > mailbox.arbitrator.cpu_priority_level + && requested_intr_level != CPU_PRIORITY_LEVEL_FETCHING) { // GRANT request, set GRANT line: // BG4 is signal bit maskl 0x01, etc ... sm_arb.arbitrator_grant_mask = BIT(requested_intr_level - 4); diff --git a/10.01_base/2_src/pru1/pru1_statemachine_data_slave.c b/10.01_base/2_src/pru1/pru1_statemachine_data_slave.c index 8fbff5d..876b9b2 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_data_slave.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_data_slave.c @@ -1,6 +1,6 @@ -/* pru1_statemachine_slave.c: state machine for execution of slave DATO* or DATI* cycles +/* pru1_statemachine_data_slave.c: state machine for execution of slave DATO* or DATI* cycles - Copyright (c) 2018, Joerg Hoppe + Copyright (c) 2018-2019, Joerg Hoppe j_hoppe@t-online.de, www.retrocmp.com Permission is hereby granted, free of charge, to any person obtaining a @@ -34,8 +34,6 @@ - address is evaluated, ggf mem access */ -#define _PRU1_STATEMACHINE_SLAVE_C_ - #include #include @@ -46,16 +44,16 @@ #include "iopageregister.h" #include "pru1_buslatches.h" -#include "pru1_statemachine_slave.h" +#include "pru1_statemachine_data_slave.h" // forwards ; -//statemachine_state_func sm_slave_start(void); -static statemachine_state_func sm_slave_state_10(void); -static statemachine_state_func sm_slave_state_20(void); -//static statemachine_state_func sm_slave_state_99(void); +//statemachine_state_func sm_data_slave_start(void); +static statemachine_state_func sm_data_slave_state_10(void); +static statemachine_state_func sm_data_slave_state_20(void); +//static statemachine_state_func sm_data_slave_state_99(void); // check for MSYN active -statemachine_state_func sm_slave_start() { +statemachine_state_func sm_data_slave_start() { uint8_t latch2val, latch3val, latch4val; // uint8_t iopage; uint32_t addr; @@ -111,11 +109,11 @@ statemachine_state_func sm_slave_start() { buslatches_setbyte(6, data >> 8); // set SSYN = latch[4], bit 5 buslatches_setbits(4, BIT(5), BIT(5)); - return (statemachine_state_func) &sm_slave_state_20; + return (statemachine_state_func) &sm_data_slave_state_20; // perhaps PRU2ARM_INTERRUPT now active } else // no address match: wait for MSYN to go inactive - // return (statemachine_state_func) &sm_slave_state_99; + // return (statemachine_state_func) &sm_data_slave_state_99; return NULL ; case UNIBUS_CONTROL_DATO: // fetch data in any case @@ -128,11 +126,11 @@ statemachine_state_func sm_slave_start() { // SSYN = latch[4], bit 5 buslatches_setbits(4, BIT(5), BIT(5)); // wait for MSYN to go inactive, then SSYN inactive - return (statemachine_state_func) &sm_slave_state_10; + return (statemachine_state_func) &sm_data_slave_state_10; // perhaps PRU2ARM_INTERRUPT now active } else // no address match: wait for MSYN to go inactive - // return (statemachine_state_func) &sm_slave_state_99; + // return (statemachine_state_func) &sm_data_slave_state_99; return NULL ; case UNIBUS_CONTROL_DATOB: // A00 = 1, odd address: get upper byte @@ -149,11 +147,11 @@ statemachine_state_func sm_slave_start() { // SSYN = latch[4], bit 5 buslatches_setbits(4, BIT(5), BIT(5)); // wait for MSYN to go inactive, then SSYN inactive - return (statemachine_state_func) &sm_slave_state_10; + return (statemachine_state_func) &sm_data_slave_state_10; // perhaps PRU2ARM_INTERRUPT now active } else // no address match: wait for MSYN to go inactive - // return (statemachine_state_func) &sm_slave_state_99; + // return (statemachine_state_func) &sm_data_slave_state_99; return NULL ; } return NULL; // not reached @@ -161,14 +159,14 @@ statemachine_state_func sm_slave_start() { // End DATO: wait for MSYN to go inactive, then SSYN inactive // also wait for EVENT ACK -static statemachine_state_func sm_slave_state_10() { +static statemachine_state_func sm_data_slave_state_10() { // MSYN = latch[4], bit 4 if (buslatches_getbyte(4) & BIT(4)) - return (statemachine_state_func) &sm_slave_state_10; // wait, MSYN still active + return (statemachine_state_func) &sm_data_slave_state_10; // wait, MSYN still active if (mailbox.events.event_deviceregister) // unibusadapter.worker() did not yet run on_after_register_access() // => wait, long SSYN delay until ARM acknowledges event - return (statemachine_state_func) &sm_slave_state_10; + return (statemachine_state_func) &sm_data_slave_state_10; // if ARM was triggered by event and changed the device state, // now an Interrupt arbitration may be pending. @@ -180,14 +178,14 @@ static statemachine_state_func sm_slave_state_10() { // End DATI: wait for MSYN to go inactive, then SSYN and DATA inactive // also wait for EVENT ACK -static statemachine_state_func sm_slave_state_20() { +static statemachine_state_func sm_data_slave_state_20() { // MSYN = latch[4], bit 4 if (buslatches_getbyte(4) & BIT(4)) - return (statemachine_state_func) &sm_slave_state_20; // wait, MSYN still active + return (statemachine_state_func) &sm_data_slave_state_20; // wait, MSYN still active if (mailbox.events.event_deviceregister) // unibusadapter.worker() did not yet run on_after_register_access() // => wait, long SSYN delay until ARM acknowledges event - return (statemachine_state_func) &sm_slave_state_20; + return (statemachine_state_func) &sm_data_slave_state_20; // if ARM was triggered by event and changed the device state, // now an Interrupt arbitration may be pending. @@ -204,10 +202,10 @@ static statemachine_state_func sm_slave_state_20() { // end of inactive cycle: wait for MSYN to go inactive // Not necessary, start() state simply checks addr again if MSYN still set. -static statemachine_state_func sm_slave_state_99() { +static statemachine_state_func sm_data_slave_state_99() { // MSYN = latch[4], bit 4 if (buslatches_getbyte(4) & BIT(4)) { - return (statemachine_state_func) &sm_slave_state_99; // wait, MSYN still active + return (statemachine_state_func) &sm_data_slave_state_99; // wait, MSYN still active } // PRU_DEBUG_PIN(1) ; diff --git a/10.01_base/2_src/pru1/pru1_statemachine_data_slave.h b/10.01_base/2_src/pru1/pru1_statemachine_data_slave.h index 9e9bfd6..39ae8a5 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_data_slave.h +++ b/10.01_base/2_src/pru1/pru1_statemachine_data_slave.h @@ -1,6 +1,6 @@ /* pru1_statemachine_slave.h: state machine for execution of slave DATO* or DATI* cycles - Copyright (c) 2018, Joerg Hoppe + Copyright (c) 2018-2019, Joerg Hoppe j_hoppe@t-online.de, www.retrocmp.com Permission is hereby granted, free of charge, to any person obtaining a @@ -24,12 +24,12 @@ 29-jun-2019 JH rework: state returns ptr to next state func 12-nov-2018 JH entered beta phase */ -#ifndef _PRU1_STATEMACHINE_SLAVE_H_ -#define _PRU1_STATEMACHINE_SLAVE_H_ +#ifndef _PRU1_STATEMACHINE_DATA_SLAVE_H_ +#define _PRU1_STATEMACHINE_DATA_SLAVE_H_ #include #include "pru1_utils.h" // statemachine_state_func -statemachine_state_func sm_slave_start(void); +statemachine_state_func sm_data_slave_start(void); #endif diff --git a/10.01_base/2_src/pru1/pru1_statemachine_dma.c b/10.01_base/2_src/pru1/pru1_statemachine_dma.c index f9d62f5..fe800b9 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_dma.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_dma.c @@ -50,8 +50,6 @@ ! Uses single global timeout, don't run in parallel with other statemachines using timeout ! */ -#define _PRU1_STATEMACHINE_DMA_C_ - #include #include #include diff --git a/10.01_base/2_src/pru1/pru1_statemachine_dma.h b/10.01_base/2_src/pru1/pru1_statemachine_dma.h index 4a1a432..ae1b660 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_dma.h +++ b/10.01_base/2_src/pru1/pru1_statemachine_dma.h @@ -37,9 +37,7 @@ typedef struct { uint16_t cur_wordsleft; // # of words left to transfer } statemachine_dma_t; -#ifndef _PRU1_STATEMACHINE_DMA_C_ extern statemachine_dma_t sm_dma; -#endif statemachine_state_func sm_dma_start(void); diff --git a/10.01_base/2_src/pru1/pru1_statemachine_intr_master.c b/10.01_base/2_src/pru1/pru1_statemachine_intr_master.c index 92f9fd4..aae997e 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_intr_master.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_intr_master.c @@ -29,7 +29,6 @@ Precondition: BBSY already asserted (arbitration got) */ -#define _PRU1_STATEMACHINE_INTR_C_ #include #include @@ -86,7 +85,7 @@ static statemachine_state_func sm_intr_master_state_2() { // Complete and signal this INTR transaction only after ARM has processed the previous event. // INTR may come faster than ARM Linux can process, // especially if Arbitrator grants INTRs of multiple levels almost simultaneaously in parallel. - if (mailbox.events.event_intr) + if (mailbox.events.event_intr_master) return (statemachine_state_func) &sm_intr_master_state_2; // wait // remove vector @@ -106,7 +105,7 @@ static statemachine_state_func sm_intr_master_state_2() { // signal to ARM which INTR was completed // change mailbox only after ARM has ack'ed mailbox.events.event_intr mailbox.events.event_intr_level_index = sm_intr_master.level_index; - mailbox.events.event_intr = 1; + mailbox.events.event_intr_master = 1; // ARM is clearing this, before requesting new interrupt of same level // so no concurrent ARP+PRU access PRU2ARM_INTERRUPT diff --git a/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c b/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c new file mode 100644 index 0000000..a4b3605 --- /dev/null +++ b/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c @@ -0,0 +1,93 @@ +/* pru1_statemachine_intr_slave.c: CPU receives interrupt vector + + Copyright (c) 2019, Joerg Hoppe + j_hoppe@t-online.de, www.retrocmp.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + 26-aug-2019 JH start + + State machines for CPU emulation to receive INTR vector placed onto bus by device. + + + All references "PDP11BUS handbook 1979" + + */ + +#include +#include +#include + +//#include "devices.h" +#include "mailbox.h" +#include "pru1_buslatches.h" +#include "pru1_utils.h" + +#include "pru1_statemachine_intr_slave.h" + +// states +statemachine_intr_slave_t sm_intr_slave; + +// forwards +static statemachine_state_func sm_intr_slave_state_1(void); + +// Wait for BBSY deasserted, then assert, SACK already held asserted +statemachine_state_func sm_intr_slave_start() { + // WAIT for INTR + if ((buslatches_getbyte(7) & BIT(0)) == 0) + return NULL ; // still idle + // device has put vector onto DATA lines, fetch after 150ns + __delay_cycles(NANOSECS(150)); + uint8_t latch5val = buslatches_getbyte(5) ;// DATA[0..7] = latch[5] + uint8_t latch6val = buslatches_getbyte(6) ; // DATA[8..15] = latch[6] + + // set SSYN = latch[4], bit 5 + buslatches_setbits(4, BIT(5), BIT(5)); + + // mark priority level as invalid, block more BG GRANTS until PSW fetched + mailbox.arbitrator.cpu_priority_level = CPU_PRIORITY_LEVEL_FETCHING ; + + // signal ARM, wait for event to be processed + mailbox.events.event_intr_vector = (uint16_t) latch6val << 8 | latch5val ; + PRU2ARM_INTERRUPT ; + // wait until ARM acked + return (statemachine_state_func) &sm_intr_slave_state_1; +} + +static statemachine_state_func sm_intr_slave_state_1() { + + // wait until ARM acked the INTR vector + // event_intr_slave is hold until the CPU + //CPU has read the new PSW and new abritration level + // event_intr_slave co solved by + if (mailbox.events.event_intr_slave) + return (statemachine_state_func) &sm_intr_slave_state_1; + + // wait if INTR still active + if (buslatches_getbyte(7) & BIT(0)) // check INTR + return (statemachine_state_func) &sm_intr_slave_state_1; + + // clear SSYN = latch[4], bit 5 + buslatches_setbits(4, BIT(5), 0); + + // now CPU may do DATI to fetch PC and PSW + + return NULL; // ready +} + diff --git a/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h b/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h new file mode 100644 index 0000000..33f46c5 --- /dev/null +++ b/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h @@ -0,0 +1,40 @@ +/* pru1_statemachine_intr_slave.h: CPU receives interrupt vector + + Copyright (c) 2018-2019, Joerg Hoppe + j_hoppe@t-online.de, www.retrocmp.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + 26-aug-2019 JH start + */ +#ifndef _PRU1_STATEMACHINE_INTR_SLAVE_H_ +#define _PRU1_STATEMACHINE_INTR_SLAVE_H_ + +#include "pru1_utils.h" // statemachine_state_func + +typedef struct { + uint16_t vector; // interrupt vector to transfer + uint8_t level_index; // 0..3 = BR..BR7. to be returned to ARM on complete +} statemachine_intr_slave_t; + +extern statemachine_intr_slave_t sm_intr_slave; + +statemachine_state_func sm_intr_slave_start(void); + +#endif diff --git a/10.01_base/2_src/shared/mailbox.h b/10.01_base/2_src/shared/mailbox.h index 0cee708..4473839 100644 --- a/10.01_base/2_src/shared/mailbox.h +++ b/10.01_base/2_src/shared/mailbox.h @@ -44,12 +44,13 @@ #define ARM2PRU_ARB_MODE_NONE 11 // DMA without NPR/NPG/SACK arbitration #define ARM2PRU_ARB_MODE_CLIENT 12 // DMA with arbitration by external Arbitrator #define ARM2PRU_ARB_MODE_MASTER 13 // DMA as Arbitrator -#define ARM2PRU_DMA 14 // DMA with selcted arbitration +#define ARM2PRU_DMA 14 // DMA with selected arbitration #define PRU2ARM_DMA_CPU_TRANSFER_BLOCKED 15 // possible result of ARM2PRU_DMA #define ARM2PRU_INTR 16 // INTR with arbitration by external Arbitrator #define ARM2PRU_INTR_CANCEL 17 // clear INTR which has been requested -#define ARM2PRU_DDR_FILL_PATTERN 18 // fill DDR with test pattern -#define ARM2PRU_DDR_SLAVE_MEMORY 19 // use DDR as UNIBUS slave memory +#define ARM2PRU_CPU_ENABLE 18 // siwtch CPU master side functions ON/OFF +#define ARM2PRU_DDR_FILL_PATTERN 19 // fill DDR with test pattern +#define ARM2PRU_DDR_SLAVE_MEMORY 20 // use DDR as UNIBUS slave memory // signal IDs for ARM2PRU_INITALIZATIONSIGNAL_* @@ -76,6 +77,10 @@ #define PRIORITY_ARBITRATION_INTR_MASK 0x0f // BR4|BR5|BR6|BR7 #define PRIORITY_ARBITRATION_BIT_MASK 0x1f +// CPU pririty level invalid between INTR receive and fetch of next PSW +#define CPU_PRIORITY_LEVEL_FETCHING 0xff + + // data for a requested DMA operation #define PRU_MAX_DMA_WORDCOUNT 512 @@ -175,7 +180,7 @@ typedef struct { // differemt events can be raised asynchronically and concurrent, // but a single event type is sequentially raised by PRU and cleared by ARM. - /* Access to device register ***/ + /*** Access to device register ***/ uint8_t event_deviceregister; // trigger flag // info about register access uint8_t unibus_control; // DATI,DATO,DATOB @@ -197,24 +202,28 @@ typedef struct { uint8_t event_dma; // trigger flag uint8_t event_dma_cpu_transfer ; // 1: ARM must process DMa as compelted cpu DATA transfer - /*** Event priority arbitration data transfer complete + /*** Event priority arbitration INTR transfer complete After ARM2PRU_INTR, one of BR4/5/6/7 NP was requested, granted, and the data transfer was handled as bus master. */ // ---dword--- - uint8_t event_intr; // trigger flag: 1 = one of BR4,5,6,7 vector on UNIBUS + uint8_t event_intr_master; // trigger flag: 1 = one of BR4,5,6,7 vector on UNIBUS uint8_t event_intr_level_index; // 0..3 -> BR4..BR7 - uint8_t _dummy2, _dummy3; + /*** INTR transmitted by devices as master was received by CPU as slave ***/ + uint8_t event_intr_slave; // trigger flag: 1 = one of BR4,5,6,7 vector on UNIBUS + uint8_t _dummy1 ; // ---dword--- + uint16_t event_intr_vector ; // received vector /*** INIT or Power cycle seen on UNIBUS ***/ uint8_t event_init; // trigger flag uint8_t event_power; // trigger flag + // ---dword--- uint8_t initialization_signals_prev; // on event: a signal changed from this ... // ---dword--- uint8_t initialization_signals_cur; // ... to this - // uint8_t dummy[2]; // make record multiple of dword !!! + uint8_t _dummy2[2]; // make record multiple of dword !!! } mailbox_events_t; typedef struct { @@ -242,6 +251,7 @@ typedef struct { mailbox_buslatch_test_t buslatch_test; mailbox_buslatch_exerciser_t buslatch_exerciser; mailbox_initializationsignal_t initializationsignal ; + uint32_t cpu_enable; }; } mailbox_t; diff --git a/10.02_devices/2_src/cpu.cpp b/10.02_devices/2_src/cpu.cpp index afcea06..c170f33 100644 --- a/10.02_devices/2_src/cpu.cpp +++ b/10.02_devices/2_src/cpu.cpp @@ -41,8 +41,10 @@ */ static cpu_c *the_cpu = NULL; +int dbg = 0; + cpu_c::cpu_c() : - unibusdevice_c() // super class constructor + unibuscpu_c() // super class constructor { // static config name.value = "CPU20"; @@ -81,7 +83,7 @@ bool cpu_c::on_param_changed(parameter_c *param) { init.value = false; } } - return device_c::on_param_changed(param); // more actions (for enable) + return unibusdevice_c::on_param_changed(param); // more actions (for enable) } // background worker. @@ -93,6 +95,8 @@ void cpu_c::worker(unsigned instance) { unsigned dr = 0760102; unsigned opcode = 0; (void) opcode; + + power_event = power_event_none; while (!workers_terminate) { // run full speed! timeout.wait_us(1); @@ -105,6 +109,17 @@ void cpu_c::worker(unsigned instance) { if (runmode.value != (ka11.state != 0)) runmode.value = ka11.state != 0; + // serialize asynchronous power events + if (runmode.value) { + // don't call power traps if HALTed. Also not on CONT. + if (power_event == power_event_down) + ka11_pwrdown(&the_cpu->ka11); + // stop stop some time after power down + else if (power_event == power_event_up) + ka11_pwrup(&the_cpu->ka11); + power_event = power_event_none; // processed + } + if (init.value) { // user wants CPU reset ka11_reset(&ka11); @@ -146,29 +161,14 @@ 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) { -// a CPU does not react to INIT ... else its own RESET would reset it. -} - -// TODO // CPU received interrupt vector from UNIBUS +// PRU triggers this via unibusadapter, +// mailbox->arbitrator.cpu_priority_level is CPU_PRIORITY_LEVEL_FETCHING +// CPU fetches PSW and calls unibone_prioritylevelchange(), which +// sets mailbox->arbitrator.cpu_priority_level and +// PRU is allowed now to grant BGs again. void cpu_c::on_interrupt(uint16_t vector) { // CPU sequence: // push PSW to stack @@ -184,35 +184,43 @@ extern "C" { int unibone_dato(unsigned addr, unsigned data) { uint16_t wordbuffer = (uint16_t) data; + dbg = 1; unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATO, addr, &wordbuffer); + dbg = 0; 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 ! + dbg = 1; unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATOB, addr, &wordbuffer); + dbg = 0; return the_cpu->data_transfer_request.success; } int unibone_dati(unsigned addr, unsigned *data) { uint16_t wordbuffer; + dbg = 1; unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATI, addr, &wordbuffer); *data = wordbuffer; + dbg = 0; // printf("DATI; ba=%o, data=%o\n", addr, *data) ; return the_cpu->data_transfer_request.success; } // CPU has changed the arbitration level, just forward +// if this is called as result of INTR fector PC and PSW fetch, +// mailbox->arbitrator.cpu_priority_level was CPU_PRIORITY_LEVEL_FETCHING +// In that case, PRU is allowed now to grant BGs again. 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 210f36e..ec2ef15 100644 --- a/10.02_devices/2_src/cpu.hpp +++ b/10.02_devices/2_src/cpu.hpp @@ -29,14 +29,15 @@ using namespace std; #include "utils.hpp" -#include "unibusadapter.hpp" -#include "unibusdevice.hpp" +//#include "unibusadapter.hpp" +//#include "unibusdevice.hpp" +#include "unibuscpu.hpp" extern "C" { #include "cpu20/11.h" #include "cpu20/ka11.h" } -class cpu_c: public unibusdevice_c { +class cpu_c: public unibuscpu_c { private: //unibusdevice_register_t *switch_reg; @@ -67,8 +68,6 @@ public: void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control) override; - void on_power_changed(void) override; - void on_init_changed(void) override; void on_interrupt(uint16_t vector) ; }; diff --git a/10.03_app_demo/2_src/makefile b/10.03_app_demo/2_src/makefile index dbfdcda..1c547f9 100644 --- a/10.03_app_demo/2_src/makefile +++ b/10.03_app_demo/2_src/makefile @@ -111,8 +111,9 @@ OBJECTS = $(OBJDIR)/application.o \ $(OBJDIR)/storagecontroller.o \ $(OBJDIR)/demo_io.o \ $(OBJDIR)/testcontroller.o \ - $(OBJDIR)/unibusdevice.o \ $(OBJDIR)/device.o \ + $(OBJDIR)/unibusdevice.o \ + $(OBJDIR)/unibuscpu.o \ $(OBJDIR)/parameter.o \ $(OBJDIR)/panel.o \ $(OBJDIR)/priorityrequest.o \ @@ -262,6 +263,9 @@ $(OBJDIR)/testcontroller.o : $(DEVICE_SRC_DIR)/testcontroller.cpp $(DEVICE_SRC_ $(OBJDIR)/unibusdevice.o : $(BASE_SRC_DIR)/unibusdevice.cpp $(BASE_SRC_DIR)/unibusdevice.hpp $(CC) $(CCFLAGS) $< -o $@ +$(OBJDIR)/unibuscpu.o : $(BASE_SRC_DIR)/unibuscpu.cpp $(BASE_SRC_DIR)/unibuscpu.hpp + $(CC) $(CCFLAGS) $< -o $@ + $(OBJDIR)/device.o : $(BASE_SRC_DIR)/device.cpp $(BASE_SRC_DIR)/device.hpp $(CC) $(CCFLAGS) $< -o $@ diff --git a/10.03_app_demo/5_applications/cpu/serial.lst b/10.03_app_demo/5_applications/cpu/serial.lst index 08f0b11..dc6635c 100644 --- a/10.03_app_demo/5_applications/cpu/serial.lst +++ b/10.03_app_demo/5_applications/cpu/serial.lst @@ -14,85 +14,89 @@ 14 15 ; select one type of console at assembly time 16 177560 dladr = 177560 ; base addr of DEC DL11 console - 17 ; dladr = 176500 ; DL11 #0 + 17 ; dladr = 176500 ; DL11 #0 18 ; dladr = 176510 ; DL11 #1 19 ; dladr = 176520 ; DL11 #2 20 21 22 000000 .=0 - 23 000000 000137 001000 jmp @#start ; early emulation started code execution from 0 + 23 000000 000137 001000 jmp @#start ; early emulation started code execution from 0 24 - 25 001000 .=1000 - 26 - 27 000776 stack = . - 2 ; stack growns down from start + 25 000024 .=24 ; If not HALTed: start on power-up + 26 000024 001000 .word start ; PC + 27 000026 000340 .word 340 ; PSW with priority level 7 28 - 29 start: - 30 001000 012706 000776 mov #stack,sp ; init stack - 31 - 32 ; 1. print "Hello" msg - 33 001004 012701 001126 mov #shello,r1 - 34 001010 004737 001054 call @#puts + 29 001000 .=1000 + 30 + 31 000776 stack = . - 2 ; stack growns down from start + 32 + 33 start: + 34 001000 012706 000776 mov #stack,sp ; init stack 35 - 36 ; 2. echo chars until ^C hit - 37 1$: - 38 001014 004737 001110 call @#getc ; wait for char, return in r0 - 39 001020 042700 177600 bic #177600,r0 ; make 7bit: clear bits <15:7> - 40 001024 120027 000003 cmpb r0,#3 ; break by ^C ? - 41 001030 001403 beq 2$ ; yes: leave loop - 42 001032 004737 001070 call @#putc ; no: echo char in r0 and loop - 43 001036 000766 br 1$ - 44 - 45 2$: - 46 - 47 ; 3. print "Bye bye" msg and HALT - 48 001040 012701 001211 mov #sbye,r1 - 49 001044 004737 001054 call @#puts - 50 001050 000000 halt - 51 - 52 ; 4. loop on CONT - 53 001052 000752 br start - 54 + 36 ; 1. print "Hello" msg + 37 001004 012701 001126 mov #shello,r1 + 38 001010 004737 001054 call @#puts + 39 + 40 ; 2. echo chars until ^C hit + 41 1$: + 42 001014 004737 001110 call @#getc ; wait for char, return in r0 + 43 001020 042700 177600 bic #177600,r0 ; make 7bit: clear bits <15:7> + 44 001024 120027 000003 cmpb r0,#3 ; break by ^C ? + 45 001030 001403 beq 2$ ; yes: leave loop + 46 001032 004737 001070 call @#putc ; no: echo char in r0 and loop + 47 001036 000766 br 1$ + 48 + 49 2$: + 50 + 51 ; 3. print "Bye bye" msg and HALT + 52 001040 012701 001211 mov #sbye,r1 + 53 001044 004737 001054 call @#puts + 54 001050 000000 halt 55 - 56 ; ---------------------- - 57 ; puts - print a string - 58 ; r1 = pointer, r0,r1 changed - 59 puts: - 60 001054 112100 movb (r1)+,r0 ; load xmt char - 61 001056 001403 beq 1$ ; string ends with 0 - 62 001060 004737 001070 call @#putc - 63 001064 000773 br puts ; transmit nxt char of string - 64 001066 000207 1$: return - 65 - 66 - 67 ; ---------------------- - 68 ; putc - output a single char - 69 ; r0 = char, r4 changed - 70 putc: - 71 001070 012704 177560 mov #dladr,r4 ; set base addr - 72 001074 110064 000006 movb r0,6(r4) ; char into transmit buffer - 73 001100 105764 000004 1$: tstb 4(r4) ; XMT RDY? - 74 001104 100375 bpl 1$ ; no, loop - 75 001106 000207 return - 76 - 77 ; ---------------------- - 78 ; getc - input a single char - 79 ; result in r0, r4 changed - 80 getc: - 81 001110 012704 177560 mov #dladr,r4 ; set base addr - 82 001114 105714 1$: tstb (r4) ; RCVR DONE? - 83 001116 100376 bpl 1$ ; no, loop - 84 001120 016400 000002 mov 2(r4),r0 ; return data - 85 001124 000207 return - 86 - 87 - 88 shello: - 89 001126 110 145 154 .ascii /Hello, World!/ + 56 ; 4. loop on CONT + 57 001052 000752 br start + 58 + 59 + 60 ; ---------------------- + 61 ; puts - print a string + 62 ; r1 = pointer, r0,r1 changed + 63 puts: + 64 001054 112100 movb (r1)+,r0 ; load xmt char + 65 001056 001403 beq 1$ ; string ends with 0 + 66 001060 004737 001070 call @#putc + 67 001064 000773 br puts ; transmit nxt char of string + 68 001066 000207 1$: return + 69 + 70 + 71 ; ---------------------- + 72 ; putc - output a single char + 73 ; r0 = char, r4 changed + 74 putc: + 75 001070 012704 177560 mov #dladr,r4 ; set base addr + 76 001074 110064 000006 movb r0,6(r4) ; char into transmit buffer + 77 001100 105764 000004 1$: tstb 4(r4) ; XMT RDY? + 78 001104 100375 bpl 1$ ; no, loop + 79 001106 000207 return + 80 + 81 ; ---------------------- + 82 ; getc - input a single char + 83 ; result in r0, r4 changed + 84 getc: + 85 001110 012704 177560 mov #dladr,r4 ; set base addr + 86 001114 105714 1$: tstb (r4) ; RCVR DONE? + 87 001116 100376 bpl 1$ ; no, loop + 88 001120 016400 000002 mov 2(r4),r0 ; return data + 89 001124 000207 return + 90 + 91 + 92 shello: + 93 001126 110 145 154 .ascii /Hello, World!/ 001131 154 157 054 001134 040 127 157 001137 162 154 144 001142 041 - 90 001143 015 012 .byte 15,12 ; CR, LF, - 91 001145 124 171 160 .ascii /Typed chars are echoed, ^C HALTs./ + 94 001143 015 012 .byte 15,12 ; CR, LF, + 95 001145 124 171 160 .ascii /Typed chars are echoed, ^C HALTs./ 001150 145 144 040 001153 143 150 141 001156 162 163 040 @@ -103,13 +107,13 @@ 001175 136 103 040 001200 110 101 114 001203 124 163 056 - 92 001206 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker - 93 sbye: - 94 001211 015 012 .byte 15,12 - 95 001213 107 157 157 .ascii /Good bye!/ + 96 001206 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker + 97 sbye: + 98 001211 015 012 .byte 15,12 + 99 001213 107 157 157 .ascii /Good bye!/ 001216 144 040 142 001221 171 145 041 - 96 001224 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker - 97 - 98 .end - 98 + 100 001224 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker + 101 + 102 .end + 102 diff --git a/10.03_app_demo/5_applications/cpu/serial.mac b/10.03_app_demo/5_applications/cpu/serial.mac index b262fae..99250a1 100644 --- a/10.03_app_demo/5_applications/cpu/serial.mac +++ b/10.03_app_demo/5_applications/cpu/serial.mac @@ -14,13 +14,17 @@ ; select one type of console at assembly time dladr = 177560 ; base addr of DEC DL11 console - ; dladr = 176500 ; DL11 #0 + ; dladr = 176500 ; DL11 #0 ; dladr = 176510 ; DL11 #1 ; dladr = 176520 ; DL11 #2 .=0 - jmp @#start ; early emulation started code execution from 0 + jmp @#start ; early emulation started code execution from 0 + + .=24 ; If not HALTed: start on power-up + .word start ; PC + .word 340 ; PSW with priority level 7 .=1000