From 15d22c8e259ca38ff9d84448c0c5eb025bef0ec3 Mon Sep 17 00:00:00 2001 From: Joerg Hoppe Date: Sun, 1 Sep 2019 06:47:30 +0200 Subject: [PATCH] /home/joerg/retrocmp/dec/UniBone/workspace --- 10.01_base/2_src/arm/unibusadapter.cpp | 114 ++++++++++++------ 10.01_base/2_src/arm/unibusadapter.hpp | 4 + 10.01_base/2_src/arm/unibusdevice.cpp | 16 +-- 10.01_base/2_src/arm/unibusdevice.hpp | 5 +- 10.01_base/2_src/pru1/pru1_main_unibus.c | 6 +- .../2_src/pru1/pru1_statemachine_data_slave.c | 4 +- 10.01_base/2_src/pru1/pru1_statemachine_dma.c | 5 +- .../pru1/pru1_statemachine_intr_master.c | 6 +- .../2_src/pru1/pru1_statemachine_intr_slave.c | 8 +- 10.01_base/2_src/pru1/pru1_utils.c | 10 +- 10.01_base/2_src/shared/mailbox.h | 84 ++++++++----- 11 files changed, 169 insertions(+), 93 deletions(-) diff --git a/10.01_base/2_src/arm/unibusadapter.cpp b/10.01_base/2_src/arm/unibusadapter.cpp index ab9b81f..c209ca3 100644 --- a/10.01_base/2_src/arm/unibusadapter.cpp +++ b/10.01_base/2_src/arm/unibusadapter.cpp @@ -419,8 +419,11 @@ void unibusadapter_c::request_execute_active_on_PRU(unsigned level_index) { // Start the PRU: // signal still not cleared in worker() while processing this // assert(mailbox->events.event_dma == 0); // previous signal must have been processed - // DEBUG("request_execute_active_on_PRU() DMA: ->active = dma_request %p, start = 0%06o, control=%u, wordcount=%u, data=0%06o ...", dmareq, - // mailbox->dma.startaddr, (unsigned)mailbox->dma.control, (unsigned)mailbox->dma.wordcount, (unsigned)mailbox->dma.words[0]); + _DEBUG( + "request_execute_active_on_PRU() DMA: dev %s, ->active = dma_request %p, start = 0%06o, control=%u, wordcount=%u, data=0%06o ...", + dmareq->device ? dmareq->device->name.value.c_str() : "none", dmareq, + mailbox->dma.startaddr, (unsigned) mailbox->dma.control, + (unsigned) mailbox->dma.wordcount, (unsigned) mailbox->dma.words[0]); mailbox->dma.cur_status = 0; // device DMA, not by CPU mailbox_execute(ARM2PRU_DMA); // scheduling is fast, on complete there's a signal. @@ -555,7 +558,9 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni dma_request.buffer = buffer; dma_request.wordcount = wordcount; dma_request.chunk_max_words = PRU_MAX_DMA_WORDCOUNT; // PRU limit, maybe less - // DEBUG("DMA(): initialized dma_request %p",&dma_request); + _DEBUG("DMA() req: dev %s, %s @ %06o, wordcount %d", + dma_request.device ? dma_request.device->name.value.c_str() : "none", + unibus_c::control2text(unibus_control), unibus_addr, wordcount); // put into schedule tables @@ -600,6 +605,10 @@ void unibusadapter_c::INTR(intr_request_c& intr_request, priority_request_level_c *prl = &request_levels[intr_request.level_index]; pthread_mutex_lock(&requests_mutex); // lock schedule table operations + _DEBUG("INTR() req: dev %s, slot/level/vector= %d/%d/%03o", + intr_request.device->name.value.c_str(), (unsigned) intr_request.slot, + intr_request.level_index + 4, intr_request.vector); + // Is an INTR with same slot and level already executed on PRU // or waiting in the schedule table? // If yes: do not re-raise, will be completed at some time later. @@ -622,9 +631,12 @@ void unibusadapter_c::INTR(intr_request_c& intr_request, // scheduled and request_active_complete() not called pthread_mutex_unlock(&requests_mutex); if (interrupt_register) { + _DEBUG("INTR() delayed with IR"); // if device re-raises a blocked INTR, CSR must complete immediately intr_request.device->set_register_dati_value(interrupt_register, interrupt_register_value, __func__); + } else { + _DEBUG("INTR() delayed without IR"); } return; // do not schedule a 2nd time @@ -639,12 +651,14 @@ void unibusadapter_c::INTR(intr_request_c& intr_request, // The associated device interrupt register (if any) should be updated // atomically with raising the INTR signal line by PRU. if (interrupt_register && request_is_blocking_active(intr_request.level_index)) { + _DEBUG("INTR() delayed, IR now"); // one or more another requests are handled by PRU: INTR signal delayed by Arbitrator, // write intr register asynchronically here. intr_request.device->set_register_dati_value(interrupt_register, interrupt_register_value, __func__); intr_request.interrupt_register = NULL; // don't do a 2nd time } else { // forward to PRU + _DEBUG("INTR() IR forward to PRU"); // intr_request.level_index, priority_slot, vector in constructor intr_request.interrupt_register = interrupt_register; intr_request.interrupt_register_value = interrupt_register_value; @@ -711,7 +725,6 @@ void unibusadapter_c::cancel_INTR(intr_request_c& intr_request) { } - // do DATO/DATI as master CPU. // no NPR/NPG/SACK request, but waiting for BUS idle // result: success, else BUS TIMEOUT @@ -800,16 +813,16 @@ void unibusadapter_c::worker_power_event(bool power_down) { void unibusadapter_c::worker_deviceregister_event() { unsigned device_handle; unibusdevice_c *device; - device_handle = mailbox->events.device_handle; + device_handle = mailbox->events.deviceregister_device_handle; assert(device_handle); device = devices[device_handle]; unsigned evt_idx = mailbox->events.device_register_idx; - uint32_t evt_addr = mailbox->events.addr; + uint32_t evt_addr = mailbox->events.deviceregister_addr; // normally evt_data == device_reg->shared_register->value // but shared value gets desorted if INIT in same event clears the registers before DATO - uint16_t evt_data = mailbox->events.data; + uint16_t evt_data = mailbox->events.deviceregister_data; unibusdevice_register_t *device_reg = &(device->registers[evt_idx]); - uint8_t unibus_control = mailbox->events.unibus_control; + uint8_t unibus_control = mailbox->events.deviceregister_unibus_control; /* call device event callback @@ -876,6 +889,7 @@ void unibusadapter_c::worker_deviceregister_event() { // Called for device DMA() chunk, // or cpu_DATA_transfer() void unibusadapter_c::worker_dma_chunk_complete_event(bool cpu_DATA_transfer) { + dbg_dma_event_count++; if (cpu_DATA_transfer) { // cpu_DATA_transfer() started independent of request_levels table, @@ -921,6 +935,13 @@ void unibusadapter_c::worker_dma_chunk_complete_event(bool cpu_DATA_transfer) { dmareq->chunk_unibus_start_addr = mailbox->dma.cur_addr + 2; // dmarequest remains prl->active and ->busy + _DEBUG( + "DMA chunk complete: dev %s, %s @ %06o..%06o, wordcount %d, data=%06o, %06o, ... %s", + prl->active->device ? prl->active->device->name.value.c_str() : "none", + unibus->control2text(mailbox->dma.control), mailbox->dma.startaddr, + mailbox->dma.cur_addr, mailbox->dma.wordcount, mailbox->dma.words[0], + mailbox->dma.words[1], dmareq->success ? "OK" : "TIMEOUT"); + // re-activate this request, or choose another with higher slot priority, // inserted in parallel (interrupt this DMA) prl->active = NULL; @@ -928,14 +949,10 @@ void unibusadapter_c::worker_dma_chunk_complete_event(bool cpu_DATA_transfer) { request_execute_active_on_PRU(PRIORITY_LEVEL_INDEX_NPR); more_chunks = true; - // DEBUG("DMA chunk: %s @ %06o..%06o, wordcount %d, data=%06o, %06o, ... %s", - // unibus->control2text(mailbox->dma.control), mailbox->dma.startaddr, - // mailbox->dma.cur_addr, mailbox->dma.wordcount, mailbox->dma.words[0], - // mailbox->dma.words[1], dmareq->success ? "OK" : "TIMEOUT"); } if (!more_chunks) { - DEBUG("DMA ready: %s @ %06o..%06o, wordcount %d, data=%06o, %06o, ... %s", + _DEBUG("DMA ready: %s @ %06o..%06o, wordcount %d, data=%06o, %06o, ... %s", unibus->control2text(dmareq->unibus_control), dmareq->unibus_start_addr, dmareq->unibus_end_addr, dmareq->wordcount, dmareq->buffer[0], dmareq->buffer[1], dmareq->success ? "OK" : "TIMEOUT"); @@ -967,8 +984,12 @@ void unibusadapter_c::worker_intr_complete_event(uint8_t level_index) { // activate next request of this level on PRU for priority arbitration request_activate_lowest_slot(level_index); - if (prl->active) + if (prl->active) { + _DEBUG("INTR() complete, next scheduled"); request_execute_active_on_PRU(level_index); + } else { + _DEBUG("INTR() complete, no next scheduled"); + } // else INTRs for all slots of this level completed } @@ -1029,11 +1050,11 @@ void unibusadapter_c::worker(unsigned instance) { bool aclo_raising_edge = false; bool aclo_falling_edge = false; // DEBUG("mailbox->events: mask=0x%x", mailbox->events.eventmask); - if (mailbox->events.event_init) { + if (!EVENT_IS_ACKED(*mailbox, init)) { any_event = true; // robust: any change in ACLO/DCL=INIT updates state of all 3. // Initial DCLO-cycle to PDP_11 initialize these states - if (mailbox->events.initialization_signals_cur & INITIALIZATIONSIGNAL_INIT) { + if (mailbox->events.init_signals_cur & INITIALIZATIONSIGNAL_INIT) { if (!line_INIT) init_raising_edge = true; line_INIT = true; @@ -1042,11 +1063,11 @@ void unibusadapter_c::worker(unsigned instance) { init_falling_edge = true; line_INIT = false; } - mailbox->events.event_init = 0; // PRU may re-raise and change mailbox now + EVENT_ACK(*mailbox, init); // PRU may re-raise and change mailbox now } - if (mailbox->events.event_power) { + if (!EVENT_IS_ACKED(*mailbox, power)) { any_event = true; - if (mailbox->events.initialization_signals_cur & INITIALIZATIONSIGNAL_DCLO) { + if (mailbox->events.init_signals_cur & INITIALIZATIONSIGNAL_DCLO) { if (!line_DCLO) dclo_raising_edge = true; line_DCLO = true; @@ -1055,7 +1076,7 @@ void unibusadapter_c::worker(unsigned instance) { dclo_falling_edge = true; line_DCLO = false; } - if (mailbox->events.initialization_signals_cur & INITIALIZATIONSIGNAL_ACLO) { + if (mailbox->events.init_signals_cur & INITIALIZATIONSIGNAL_ACLO) { if (!line_ACLO) aclo_raising_edge = true; line_ACLO = true; @@ -1064,13 +1085,12 @@ void unibusadapter_c::worker(unsigned instance) { aclo_falling_edge = true; line_ACLO = false; } - mailbox->events.event_power = 0; // PRU may re-raise and change mailbox now + EVENT_ACK(*mailbox, power); // PRU may re-raise and change mailbox now DEBUG( "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); + mailbox->events.init_signals_prev, mailbox->events.init_signals_cur, + init_raising_edge, init_falling_edge, dclo_raising_edge, + dclo_falling_edge, aclo_raising_edge, aclo_falling_edge); } if (dclo_raising_edge) @@ -1079,38 +1099,42 @@ void unibusadapter_c::worker(unsigned instance) { worker_power_event(false); // power signal power change if (init_falling_edge) // INIT asserted -> deasserted. DATI/DATO cycle only possible after that. worker_init_event(); - if (mailbox->events.event_deviceregister) { + if (!EVENT_IS_ACKED(*mailbox, deviceregister)) { any_event = true; // DATI/DATO // DEBUG("EVENT_DEVICEREGISTER: control=%d, addr=%06o", (int)mailbox->events.unibus_control, mailbox->events.addr); worker_deviceregister_event(); // ARM2PRU opcodes raised by device logic are processed in midst of bus cycle - mailbox->events.event_deviceregister = 0; // PRU continues bus cycle with SSYN now + EVENT_ACK(*mailbox, deviceregister); // PRU continues bus cycle with SSYN now } - if (mailbox->events.event_dma) { + if (!EVENT_IS_ACKED(*mailbox, dma)) { any_event = true; pthread_mutex_lock(&requests_mutex); - worker_dma_chunk_complete_event(mailbox->events.event_dma_cpu_transfer); + worker_dma_chunk_complete_event(mailbox->events.dma_cpu_transfer); pthread_mutex_unlock(&requests_mutex); - mailbox->events.event_dma = 0; // PRU may re-raise and change mailbox now + // rpu may have set again event_dma again, if this is called before EVENT signal?? + // call this only on singal, not on timeout! + + // this may clear reraised PRU event flag! + EVENT_ACK(*mailbox, dma); // PRU may re-raise and change mailbox now } - if (mailbox->events.event_intr_master) { + if (!EVENT_IS_ACKED(*mailbox, 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); + worker_intr_complete_event(mailbox->events.intr_level_index); pthread_mutex_unlock(&requests_mutex); - mailbox->events.event_intr_master = 0; // PRU may re-raise and change mailbox now + EVENT_ACK(*mailbox, intr_master); // PRU may re-raise and change mailbox now } - if (mailbox->events.event_intr_slave) { + if (!EVENT_IS_ACKED(*mailbox, 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); + the_cpu->on_interrupt(mailbox->events.intr_vector); // clear SSYN, INTR cycle completes - mailbox->events.event_intr_slave = 0; + EVENT_ACK(*mailbox, intr_slave); // mailbox->arbitrator.cpu_priority_level now CPU_PRIORITY_LEVEL_FETCHING // BG grants blocked @@ -1182,3 +1206,21 @@ void unibusadapter_c::print_shared_register_map() { } } +// diag: access to internal state of DMA and interupt request handling +mailbox_t mailbox_snapshot; + +// reset measurements and timeouts +void unibusadapter_c::debug_init() { + // count events both on ARM and PRU, must be same! + dbg_dma_event_count = 0; + mailbox->events.dma_dbg_count = 0; +} + +// look into data strucures +void unibusadapter_c::debug_snapshot(void) { + // copy PRU mailbox state to space visible in Debugger (why necessary?) + memcpy(&mailbox_snapshot, (void *) mailbox, sizeof(mailbox_t)); + break_here(); // pos for breakpoint + +} + diff --git a/10.01_base/2_src/arm/unibusadapter.hpp b/10.01_base/2_src/arm/unibusadapter.hpp index 3c095ba..3fd1e1b 100644 --- a/10.01_base/2_src/arm/unibusadapter.hpp +++ b/10.01_base/2_src/arm/unibusadapter.hpp @@ -114,6 +114,10 @@ public: void print_shared_register_map(void); + void debug_init(void) ; + void debug_snapshot(void) ; + uint32_t dbg_dma_event_count ; // count dba evets on ARM side + }; extern unibusadapter_c *unibusadapter; // another Singleton diff --git a/10.01_base/2_src/arm/unibusdevice.cpp b/10.01_base/2_src/arm/unibusdevice.cpp index ed3c57a..f4e1d59 100644 --- a/10.01_base/2_src/arm/unibusdevice.cpp +++ b/10.01_base/2_src/arm/unibusdevice.cpp @@ -81,17 +81,18 @@ bool unibusdevice_c::on_param_changed(parameter_c *param) { } // define default values for device BASE address and INTR -void unibusdevice_c::set_default_bus_params(uint32_t default_base_addr, unsigned default_priority_slot, - unsigned default_intr_vector, unsigned default_intr_level) { +void unibusdevice_c::set_default_bus_params(uint32_t default_base_addr, + unsigned default_priority_slot, unsigned default_intr_vector, + unsigned default_intr_level) { assert(default_priority_slot <= PRIORITY_SLOT_COUNT); // bitmask! this->default_base_addr = default_base_addr; this->default_priority_slot = default_priority_slot; this->default_intr_vector = this->intr_vector.new_value = default_intr_vector; this->default_intr_level = this->intr_level.new_value = default_intr_level; - base_addr.set(default_base_addr) ; - priority_slot.set(default_priority_slot) ; - intr_vector.set(default_intr_vector) ; - intr_level.set(default_intr_level) ; + base_addr.set(default_base_addr); + priority_slot.set(default_priority_slot); + intr_vector.set(default_intr_vector); + intr_level.set(default_intr_level); } void unibusdevice_c::install(void) { @@ -251,7 +252,8 @@ char *unibusdevice_c::get_unibus_resource_info(void) { else if (register_count == 1) sprintf(tmpbuff, "addr %06o", base_addr.value); else - sprintf(tmpbuff, "addr %06o-%06o (%d regs)", base_addr.value, base_addr.value+2*(register_count-1), register_count) ; + sprintf(tmpbuff, "addr %06o-%06o (%d regs)", base_addr.value, + base_addr.value + 2 * (register_count - 1), register_count); strcat(buffer, tmpbuff); // get priority slot range from DMA request and intr_requests diff --git a/10.01_base/2_src/arm/unibusdevice.hpp b/10.01_base/2_src/arm/unibusdevice.hpp index 1aaf674..4c9f51c 100644 --- a/10.01_base/2_src/arm/unibusdevice.hpp +++ b/10.01_base/2_src/arm/unibusdevice.hpp @@ -81,7 +81,7 @@ typedef struct unibusdevice_register_struct { class unibusdevice_c: public device_c { public: - static unibusdevice_c *find_by_request_slot(uint8_t priority_slot) ; + static unibusdevice_c *find_by_request_slot(uint8_t priority_slot); private: // setup address tables, also in shared memory @@ -164,9 +164,8 @@ public: void log_register_event(const char *change_info, unibusdevice_register_t *changed_reg); - char *get_unibus_resource_info(void) ; + char *get_unibus_resource_info(void); }; - #endif 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 5105544..bab5606 100644 --- a/10.01_base/2_src/pru1/pru1_main_unibus.c +++ b/10.01_base/2_src/pru1/pru1_main_unibus.c @@ -130,7 +130,7 @@ void main(void) { if (!sm_data_slave_state) sm_data_slave_state = (statemachine_state_func) &sm_data_slave_start; while ((sm_data_slave_state = sm_data_slave_state()) - && !mailbox.events.event_deviceregister) + && EVENT_IS_ACKED(mailbox,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 @@ -140,7 +140,7 @@ void main(void) { 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) ; + && EVENT_IS_ACKED(mailbox,intr_slave)) ; } // signal INT or PWR FAIL to ARM @@ -149,7 +149,7 @@ void main(void) { // Priority Arbitration // Delay INTR or DMA while BUS halted via SSYN. // ARM may start DMA within deviceregister event! - if (!mailbox.events.event_deviceregister) { + if (EVENT_IS_ACKED(mailbox,deviceregister)) { // execute one of the arbitration workers uint8_t grant_mask = sm_arb_worker(); // sm_arb_worker()s include State 2 "BBSYWAIT". 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 876b9b2..c66f92a 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 @@ -163,7 +163,7 @@ 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_data_slave_state_10; // wait, MSYN still active - if (mailbox.events.event_deviceregister) + if (! EVENT_IS_ACKED(mailbox,deviceregister)) // unibusadapter.worker() did not yet run on_after_register_access() // => wait, long SSYN delay until ARM acknowledges event return (statemachine_state_func) &sm_data_slave_state_10; @@ -182,7 +182,7 @@ 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_data_slave_state_20; // wait, MSYN still active - if (mailbox.events.event_deviceregister) + if (! EVENT_IS_ACKED(mailbox,deviceregister)) // unibusadapter.worker() did not yet run on_after_register_access() // => wait, long SSYN delay until ARM acknowledges event return (statemachine_state_func) &sm_data_slave_state_20; 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 fe800b9..daae265 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_dma.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_dma.c @@ -332,7 +332,7 @@ static statemachine_state_func sm_dma_state_99() { timeout_cleanup(TIMEOUT_DMA); // device or cpu cycle ended: now CPU may become UNIBUS master again - mailbox.events.event_dma_cpu_transfer = mailbox.arbitrator.cpu_BBSY ; + mailbox.events.dma_cpu_transfer = mailbox.arbitrator.cpu_BBSY ; mailbox.arbitrator.device_BBSY = false; mailbox.arbitrator.cpu_BBSY = false; @@ -340,7 +340,8 @@ static statemachine_state_func sm_dma_state_99() { mailbox.dma.cur_status = final_dma_state; // signal to ARM // signal to ARM - mailbox.events.event_dma = 1; +mailbox.events.dma_dbg_count++ ; //DBG + EVENT_SIGNAL(mailbox,dma) ; // ARM is clearing this, before requesting new DMA. // no concurrent ARM+PRU access PRU2ARM_INTERRUPT 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 aae997e..d80ac3c 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 @@ -85,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_master) + if (! EVENT_IS_ACKED(mailbox,intr_master)) return (statemachine_state_func) &sm_intr_master_state_2; // wait // remove vector @@ -104,8 +104,8 @@ 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_master = 1; + mailbox.events.intr_level_index = sm_intr_master.level_index; + EVENT_SIGNAL(mailbox,intr_master); // 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 index a4b3605..8cd986f 100644 --- a/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c +++ b/10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c @@ -64,7 +64,7 @@ statemachine_state_func sm_intr_slave_start() { 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 ; + mailbox.events.intr_vector = (uint16_t) latch6val << 8 | latch5val ; PRU2ARM_INTERRUPT ; // wait until ARM acked return (statemachine_state_func) &sm_intr_slave_state_1; @@ -73,10 +73,10 @@ statemachine_state_func sm_intr_slave_start() { 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 ACK is delayed 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) + if (! EVENT_IS_ACKED(mailbox,intr_slave)) return (statemachine_state_func) &sm_intr_slave_state_1; // wait if INTR still active diff --git a/10.01_base/2_src/pru1/pru1_utils.c b/10.01_base/2_src/pru1/pru1_utils.c index a681e1d..19b4e14 100644 --- a/10.01_base/2_src/pru1/pru1_utils.c +++ b/10.01_base/2_src/pru1/pru1_utils.c @@ -39,7 +39,7 @@ // Assume this events come so slow, no one gets raised until // prev event processed. void do_event_initializationsignals() { - uint8_t mb_cur = mailbox.events.initialization_signals_cur; // as saved + uint8_t mb_cur = mailbox.events.init_signals_cur; // as saved uint8_t bus_cur = buslatches_getbyte(7) & 0x38; // now sampled if (bus_cur & INITIALIZATIONSIGNAL_INIT) @@ -48,15 +48,15 @@ void do_event_initializationsignals() { if (bus_cur != mb_cur) { // save old state, so ARM can detect what changed - mailbox.events.initialization_signals_prev = mb_cur; - mailbox.events.initialization_signals_cur = bus_cur; + mailbox.events.init_signals_prev = mb_cur; + mailbox.events.init_signals_cur = bus_cur; // trigger the correct event: power and/or INIT if ((mb_cur ^ bus_cur) & (INITIALIZATIONSIGNAL_DCLO | INITIALIZATIONSIGNAL_ACLO)) // AC_LO or DC_LO changed - mailbox.events.event_power = 1; + EVENT_SIGNAL(mailbox,power) ; if ((mb_cur ^ bus_cur) & INITIALIZATIONSIGNAL_INIT) // INIT changed - mailbox.events.event_init = 1; + EVENT_SIGNAL(mailbox,init); PRU2ARM_INTERRUPT ; } diff --git a/10.01_base/2_src/shared/mailbox.h b/10.01_base/2_src/shared/mailbox.h index 4473839..11f3607 100644 --- a/10.01_base/2_src/shared/mailbox.h +++ b/10.01_base/2_src/shared/mailbox.h @@ -175,55 +175,83 @@ typedef struct { // multiple of 32 bit now } mailbox_intr_t; +/* PRU->ARM event signaling is a signal/acknowledge protocoll. + There are no shared mutexes for PRU / ARM mailbox protection. + So protocol must be implmeneted with the "single writer -multiple reader" pattern, + where only a single writer modifes shared variables. + For each event source there are 2 channels (variables) + - signal: PRU arites, ARM reads + - acknowledge: ARM writes, PRU reads. + Both variables are rollaround-counters, which are simply updated on event. + PRU raises event with "signaled++", and checks for ARM ack with + "if (signaled != acked) ..." + ARM checks for pending signals with + "if (signaled != acked) ..." + and acknowledees an event with "acked++". +*/ +#define EVENT_SIGNAL(mailbox,source) ((mailbox).events.source##_signaled++) +#define EVENT_ACK(mailbox,source) ((mailbox).events.source##_acked++) +#define EVENT_IS_ACKED(mailbox,source) ((mailbox).events.source##_signaled == (mailbox).events.source##_acked) + typedef struct { - // trigger flags raised by PRU, reset by ARM - // differemt events can be raised asynchronically and concurrent, - // but a single event type is sequentially raised by PRU and cleared by ARM. + // different events can be raised asynchronically and concurrent, + // but a single event type is sequentially signaled by PRU and acked by ARM. /*** Access to device register ***/ - uint8_t event_deviceregister; // trigger flag + uint8_t deviceregister_signaled; // PRU->ARM + uint8_t deviceregister_acked; // ARM->PRU // info about register access - uint8_t unibus_control; // DATI,DATO,DATOB + uint8_t deviceregister_unibus_control; // DATI,DATO,DATOB // handle of controller - uint8_t device_handle; + uint8_t deviceregister_device_handle; + // ---dword--- // # of register in device space uint8_t device_register_idx; + uint8_t _dummy1 ; + uint16_t deviceregister_data; // deviceregister_data value for DATO event // ---dword--- // UNIBUS address accessed - uint32_t addr; // accessed address: odd/even important for DATOB - // ---dword--- - uint16_t data; // data value for DATO event + uint32_t deviceregister_addr; // accessed address: odd/even important for DATOB /*** DMA transfer complete After ARM2PRU_DMA_*, NPR/NPG/SACK protocll was executed and Data trasnfered accoring to mailbox_dma_t. After that, mailbox_dma_t is updated and signal raised. */ - uint8_t event_dma; // trigger flag - uint8_t event_dma_cpu_transfer ; // 1: ARM must process DMa as compelted cpu DATA transfer + uint8_t dma_signaled; // PRU->ARM + uint8_t dma_acked; // ARM->PRU + uint8_t dma_cpu_transfer ; // 1: ARM must process DMA as completed cpu DATA transfer + uint8_t _dummy2 ; + // ---dword--- + uint32_t dma_dbg_count ; //DBG + /*** 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. + granted, and the deviceregister_data transfer was handled as bus master. */ // ---dword--- - 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 intr_master_signaled; // PRU->ARM, one of BR4,5,6,7 vector on UNIBUS + uint8_t intr_master_acked; // ARM->PRU + uint8_t intr_level_index; // 0..3 -> BR4..BR7 /*** 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 ; + uint8_t intr_slave_signaled; // PRU->ARM, one of BR4,5,6,7 vector on UNIBUS + // ---dword--- + uint8_t intr_slave_acked; // ARM->PRU + uint8_t _dummy3 ; + uint16_t intr_vector ; // received vector // ---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 + uint8_t init_signaled; // PRU->ARM + uint8_t init_acked; // ARM->PRU + uint8_t power_signaled; // PRU->ARM + uint8_t power_acked; // ARM->PRU // ---dword--- - uint8_t initialization_signals_prev; // on event: a signal changed from this ... - // ---dword--- - uint8_t initialization_signals_cur; // ... to this + uint8_t init_signals_prev; // on event: a signal changed from this ... + uint8_t init_signals_cur; // ... to this - uint8_t _dummy2[2]; // make record multiple of dword !!! + uint8_t _dummy9[2]; // make record multiple of dword !!! } mailbox_events_t; typedef struct { @@ -283,12 +311,12 @@ extern volatile far mailbox_t mailbox; // iopageregister_t *reg #define DO_EVENT_DEVICEREGISTER(_reg,_unibus_control,_addr,_data) do { \ /* register read changes device state: signal to ARM */ \ - mailbox.events.unibus_control = _unibus_control ; \ - mailbox.events.device_handle = _reg->event_device_handle ;\ + mailbox.events.deviceregister_unibus_control = _unibus_control ; \ + mailbox.events.deviceregister_device_handle = _reg->event_device_handle ;\ mailbox.events.device_register_idx = _reg->event_device_register_idx ; \ - mailbox.events.addr = _addr ; \ - mailbox.events.data = _data ; \ - mailbox.events.event_deviceregister = 1 ; \ + mailbox.events.deviceregister_addr = _addr ; \ + mailbox.events.deviceregister_data = _data ; \ + EVENT_SIGNAL(mailbox,deviceregister) ; \ /* data for ARM valid now*/ \ PRU2ARM_INTERRUPT ; \ /* leave SSYN asserted until mailbox.event.signal ACKEd to 0 */ \