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:
@@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
;
|
||||
}
|
||||
|
||||
@@ -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 */ \
|
||||
|
||||
Reference in New Issue
Block a user