1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-02-27 01:00:00 +00:00

/home/joerg/retrocmp/dec/UniBone/workspace

This commit is contained in:
Joerg Hoppe
2019-09-01 06:47:30 +02:00
parent f13b35bc08
commit 15d22c8e25
11 changed files with 169 additions and 93 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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".

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
;
}

View File

@@ -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 */ \