1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-03-29 10:55:55 +00:00

First successful iNTR on emulated CPU20

This commit is contained in:
Joerg Hoppe
2019-09-23 13:42:47 +02:00
parent 47bf827c52
commit b2d944f9cd
11 changed files with 127 additions and 110 deletions

View File

@@ -237,9 +237,8 @@ bool unibusadapter_c::register_device(unibusdevice_c& 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) ;
mailbox->cpu_enable = 1 ;
mailbox_execute(ARM2PRU_CPU_ENABLE) ;
}
return true;
}
@@ -765,14 +764,21 @@ void unibusadapter_c::cpu_DATA_transfer(dma_request_c& dma_request, uint8_t unib
// do the transfer. Wait until concurrent device DMA/INTR complete
do {
while (mailbox->arbitrator.device_BBSY)
timeout.wait_us(100);
while (mailbox->arbitrator.device_BBSY) {
timeout.wait_us(10);
// This blocks the CPU thread.
// Device threads continue and are waiting for End of DMA/INTR
// PRU performs DMA/INTR) and master_arbitrator clears device_BBSY.
// PRU cpu logic responds as INTR_slave
}
mailbox->arbitrator.cpu_BBSY = true; // mark as "initiated by CPU, not by device"
success = mailbox_execute(ARM2PRU_DMA);
// a device may have acquired the bus concurrently,
// then ARM2PRU_DMA is answered with an error
// then ARM2PRU_DMA is answered with error PRU2ARM_DMA_CPU_TRANSFER_BLOCKED.
// infinite time may have passed after that check above
} while (!success);
// 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.
@@ -1068,7 +1074,6 @@ void unibusadapter_c::worker(unsigned instance) {
bool dclo_falling_edge = false;
bool aclo_raising_edge = false;
bool aclo_falling_edge = false;
// DEBUG("mailbox->events: mask=0x%x", mailbox->events.eventmask);
if (!EVENT_IS_ACKED(*mailbox, init)) {
any_event = true;
// robust: any change in ACLO/DCL=INIT updates state of all 3.

View File

@@ -79,7 +79,7 @@
other GRANTS
- monitoring INIT and AC_LO/DC_LO
- watching fpr AMR2PRU commands
2. "BBSYWAIT": UNibone got PRIORITY GRAMT, has set SACK and released BR/NPR
2. "BBSYWAIT": UniBone got PRIORITY GRAMT, has set SACK and released BR/NPR
waits for current BUS master to relaeasy BBSY (ony DATI/DATO cycle max)
- SACK active: no GRANT forward necessary, no arbitration necessary
- INIT is monitored by DMA statemachine: no DC_LO/INIT monitoring necessary
@@ -219,7 +219,7 @@ void main(void) {
} else {
// Emulated device: raise request for emulated or physical Arbitrator.
// request DMA, arbitrator must've been selected with ARM2PRU_ARB_MODE_*
sm_arb.request_mask |= PRIORITY_ARBITRATION_BIT_NP;
sm_arb.device_request_mask |= PRIORITY_ARBITRATION_BIT_NP;
// sm_arb_worker() evaluates this,extern Arbitrator raises Grant, excution starts in future loop
// end of DMA is signaled to ARM with signal
@@ -238,7 +238,7 @@ void main(void) {
// request INTR, arbitrator must've been selected with ARM2PRU_ARB_MODE_*
// start one INTR cycle. May be raised in midst of slave cycle
// by ARM, if access to "active" register triggers INTR.
sm_arb.request_mask |= mailbox.intr.priority_arbitration_bit;
sm_arb.device_request_mask |= mailbox.intr.priority_arbitration_bit;
// sm_arb_worker() evaluates this, extern Arbitrator raises Grant,
// vector of GRANted level is transfered with statemachine sm_intr_master
@@ -254,7 +254,7 @@ void main(void) {
case ARM2PRU_INTR_CANCEL:
// cancels one or more INTR requests. If already Granted, the GRANT is forwarded,
// and canceled by reaching a "SACK turnaround terminator" or "No SACK TIMEOUT" in the arbitrator.
sm_arb.request_mask &= ~mailbox.intr.priority_arbitration_bit;
sm_arb.device_request_mask &= ~mailbox.intr.priority_arbitration_bit;
// no completion event, could interfer with other INTRs?
mailbox.arm2pru_req = ARM2PRU_NONE; // done
break;

View File

@@ -99,7 +99,7 @@ statemachine_arbitration_t sm_arb;
void sm_arb_reset() {
// cleanup: clear all REQUESTS and SACK
buslatches_setbits(1, PRIORITY_ARBITRATION_BIT_MASK | BIT(5), 0);
sm_arb.request_mask = 0;
sm_arb.device_request_mask = 0;
sm_arb.bbsy_wait_grant_mask = 0;
sm_arb.arbitrator_grant_mask = 0;
@@ -123,13 +123,56 @@ uint8_t sm_arb_worker_none() {
;
// ignore BR* INTR requests, only ack DMA.
if (sm_arb.request_mask & PRIORITY_ARBITRATION_BIT_NP) {
sm_arb.request_mask &= ~PRIORITY_ARBITRATION_BIT_NP;
if (sm_arb.device_request_mask & PRIORITY_ARBITRATION_BIT_NP) {
sm_arb.device_request_mask &= ~PRIORITY_ARBITRATION_BIT_NP;
return PRIORITY_ARBITRATION_BIT_NP;
} else
return 0;
}
/* Helper:
Wait for GRANTs requested by emulated devices,
then raise SACK,
then wait for BBSY deasserted.
Calling this is only 2*5 ns extra.
"grant_mask": all GRANT lines received from physical or emulated CPU.
result: 0 if busy, else bitmask with one bit set for GRANTed and SACKEd request.
*/
static uint8_t sm_arb_worker_device_grant_sack_bbsy(uint8_t grant_mask) {
if (sm_arb.bbsy_wait_grant_mask == 0) {
// State 1: Wait For GRANT:
// process the requested grant for an open requests.
grant_mask &= sm_arb.device_request_mask;
if (grant_mask) {
// one of our requests was granted:
// set SACK
// AND simultaneously clear granted requests BR*/NPR
// BIT(5): SACK mask and level
buslatches_setbits(1, (PRIORITY_ARBITRATION_BIT_MASK & sm_arb.device_request_mask) | BIT(5),
~grant_mask | BIT(5))
;
// clear granted requests internally
sm_arb.device_request_mask &= ~grant_mask;
// UNIBUS DATA section is indepedent: MSYN, SSYN, BBSY may still be active.
// -> DMA and INTR statemachine must wait for BBSY.
// Arbitrator should remove GRANT now. Data section on Bus still BBSY
sm_arb.bbsy_wait_grant_mask = grant_mask; // next is State 2: wait for BBSY clear
}
return 0; // no GRANT for us, or wait for BBSY
} else {
// State 2: wait for BBSY to clear
if (buslatches_getbyte(1) & BIT(6))
return 0; // BBSY still set
grant_mask = sm_arb.bbsy_wait_grant_mask;
sm_arb.bbsy_wait_grant_mask = 0; // Next State is 1
return grant_mask; // signal what request we got granted.
}
}
/* worker_client:
Issue request to extern Arbitrator (PDP-11 CPU).
Watch for GRANTs on the bus signal lines, then raise SACK.
@@ -139,52 +182,25 @@ uint8_t sm_arb_worker_none() {
But it guarantees caller may now issue an DMA or INTR.
*/
uint8_t sm_arb_worker_client() {
uint8_t grant_mask;
// Always update UNIBUS BR/NPR lines, are ORed with requests from other devices.
buslatches_setbits(1, PRIORITY_ARBITRATION_BIT_MASK, sm_arb.request_mask)
buslatches_setbits(1, PRIORITY_ARBITRATION_BIT_MASK, sm_arb.device_request_mask)
;
// read GRANT IN lines from CPU (Arbitrator). Only one at a time may be active
// read GRANT IN lines from CPU (Arbitrator).
// Only one at a time may be active, else arbitrator malfucntion.
// Arbitrator asserts SACK is inactive
// latch[0]: BG signals are inverted, "get" is non-inverting: bit = active signal.
// "set" is inverting!
grant_mask = buslatches_getbyte(0) & PRIORITY_ARBITRATION_BIT_MASK; // read GRANT IN
uint8_t grant_mask = buslatches_getbyte(0) & PRIORITY_ARBITRATION_BIT_MASK; // read GRANT IN
// forward un-requested GRANT IN to GRANT OUT for other cards on neighbor slots
buslatches_setbits(0, PRIORITY_ARBITRATION_BIT_MASK & ~sm_arb.request_mask, ~grant_mask)
buslatches_setbits(0, PRIORITY_ARBITRATION_BIT_MASK & ~sm_arb.device_request_mask, ~grant_mask)
;
if (sm_arb.bbsy_wait_grant_mask == 0) {
// State 1: Wait For GRANT:
// process the requested grant for an open requests.
grant_mask &= sm_arb.request_mask;
if (grant_mask) {
// one of our requests was granted:
// set SACK
// AND simultaneously Clear granted requests BR*/NPR
// BIT(5): SACK mask and level
buslatches_setbits(1, (PRIORITY_ARBITRATION_BIT_MASK & sm_arb.request_mask) | BIT(5),
~grant_mask | BIT(5))
;
// clear granted requests internally
sm_arb.request_mask &= ~grant_mask;
// Arbitrator should remove GRANT now. Data section on Bus still BBSY
sm_arb.bbsy_wait_grant_mask = grant_mask; // next is State 2: wait for BBSY clear
}
return 0; // no GRANT for us, or wait for BBSY
} else {
// wait for BBSY to clear
if (buslatches_getbyte(1) & BIT(6))
return 0; // BBSY still set
grant_mask = sm_arb.bbsy_wait_grant_mask;
sm_arb.bbsy_wait_grant_mask = 0; // Next State is 1
return grant_mask; // signal what request we got granted.
}
// UNIBUS DATA section is indepedent: MSYN, SSYN, BBSY may still be active.
// -> DMA and INTR statemachine must wait for BBSY.
// GRANT forwarding complete,
// handle GRANT/SACK/BBSY for emulated devices
return sm_arb_worker_device_grant_sack_bbsy(grant_mask);
}
/* "worker_master"
@@ -198,28 +214,38 @@ uint8_t sm_arb_worker_client() {
- GRANT BR* in descending priority, when CPU execution level allows .
- Cancel GRANT, if no device responds with SACK within timeout period
*/
#if 0
// decode set of requests lines to highest INTR level
// BR4 = 0x01 -> 4, BR5 = 0x02 -> 5, etc.
// Index only PRIORITY_ARBITRATION_INTR_MASK, [0] invalid.
static const uint8_t requests_2_highests_intr[16] = { //
static uint8_t requests_2_highests_intr[16] = { //
/*0000*/9, /*0001*/4, /*0010*/5, /*0011*/5,
/*0100*/6, /*0101*/6, /*0110*/6, /*0111*/6,
/*1000*/7, /*1001*/7, /*1010*/7, /*0011*/7,
/*1100*/7, /*1101*/7, /*1110*/7, /*0111*/7 };
/*1000*/7, /*1001*/7, /*1010*/7, /*1011*/7,
/*1100*/7, /*1101*/7, /*1110*/7, /*1111*/7 };
#endif
uint8_t sm_arb_worker_master() {
/******* arbitrator logic *********/
uint8_t intr_request_mask;
uint8_t latch1val = buslatches_getbyte(1);
// monitor BBSY
if (!(latch1val & BIT(5)) && !(latch1val & BIT(6))) {
// neither SACK nor BBSY: bus is not used by device.
// exclude "SACK and NOT BBSY": device has not yet raised BBSY
mailbox.arbitrator.device_BBSY = false ;
}
if (latch1val & BIT(5)) {
// SACK set by a device
// priority arbitration disabled, remove GRANT.
sm_arb.arbitrator_grant_mask = 0;
// CPU looses now access to UNIBUS after current cycle
mailbox.arbitrator.device_BBSY = 1; // DATA section used by device now
mailbox.arbitrator.device_BBSY = true; // DATA section used by device now
//NONO: BBSY ! No SACK for parts of DMA cycle .
timeout_cleanup(TIMEOUT_SACK);
} else if (latch1val & PRIORITY_ARBITRATION_BIT_NP) {
@@ -229,76 +255,52 @@ uint8_t sm_arb_worker_master() {
sm_arb.arbitrator_grant_mask = PRIORITY_ARBITRATION_BIT_NP;
timeout_set(TIMEOUT_SACK, MILLISECS(ARB_MASTER_SACK_TIMOUT_MS));
}
} else if ((intr_request_mask = latch1val & PRIORITY_ARBITRATION_INTR_MASK)) {
} else if ((intr_request_mask = (latch1val & PRIORITY_ARBITRATION_INTR_MASK))) {
// device BR4,BR5,BR6 or BR7
if (sm_arb.arbitrator_grant_mask == 0) {
// no 2nd device's request may modify GRANT before 1st device acks with SACK
// GRANT request depending on CPU priority level
// find highest request line
uint8_t requested_intr_level = requests_2_highests_intr[intr_request_mask];
// find level # of highest request in bitmask
// lmbd() = LeftMostBitDetect(0x01)-> 0 (0x03) -> 1, (0x07) -> 2, 0x0f -> 3
// BR4 = 0x01 -> 4, BR5 = 0x02 -> 5, etc.
uint8_t requested_intr_level = __lmbd(intr_request_mask,1) + 4 ;
// compare against cpu run level 4..7
// 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) {
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 ...
// BG4 is signal bit mask 0x01, 0x02, etc ...
//requested_intr_level = 4 ;
sm_arb.arbitrator_grant_mask = BIT(requested_intr_level - 4);
// 320 ns ???
timeout_set(TIMEOUT_SACK, MILLISECS(ARB_MASTER_SACK_TIMOUT_MS));
}
}
} else if (sm_arb.arbitrator_grant_mask && timeout_reached(TIMEOUT_SACK)) {
// no SACK, no requests, but GRANTs: SACK timeout?
sm_arb.arbitrator_grant_mask = 0;
mailbox.arbitrator.device_BBSY = 0; // started by SACK, but UNIBUS DATA section not used by device
mailbox.arbitrator.device_BBSY = false; // started by SACK, but UNIBUS DATA section not used by device
timeout_cleanup(TIMEOUT_SACK);
}
// put the single BR/NPR GRANT onto BUS lines. BGOUT inverted.
buslatches_setbits(0, PRIORITY_ARBITRATION_BIT_MASK, ~sm_arb.arbitrator_grant_mask ) ;
/***** client device logic *****/
// Always update UNIBUS BR/NPR lines, are ORed with requests from other devices.
buslatches_setbits(1, PRIORITY_ARBITRATION_BIT_MASK, sm_arb.request_mask)
buslatches_setbits(1, PRIORITY_ARBITRATION_BIT_MASK, sm_arb.device_request_mask)
;
// read GRANT IN lines from CPU (Arbitrator). Only one at a time may be active
// Arbitrator asserts SACK is inactive
uint8_t grant_mask = sm_arb.arbitrator_grant_mask;
// forward GRANTs not requested by UniBone devices to other cards on neighbor slots
buslatches_setbits(0, PRIORITY_ARBITRATION_BIT_MASK & ~sm_arb.request_mask, ~grant_mask)
;
// Do not forward GRANT IN to GRANT OUT: we, the arbitrator, do not have GRANT IN.
// GRANTs for UniBone internal devices are not visible on UNIBUS
// (emualted GRANT OUT - GRANT IN connections)
if (sm_arb.bbsy_wait_grant_mask == 0) {
// State 1: Wait For GRANT:
// process the requested grant for an open requests.
grant_mask &= sm_arb.request_mask;
if (grant_mask) {
// one of our requests was granted:
// set SACK
// AND simultaneously Clear granted requests BR*/NPR
// BIT(5): SACK mask and level
buslatches_setbits(1, (PRIORITY_ARBITRATION_BIT_MASK & sm_arb.request_mask) | BIT(5),
~grant_mask | BIT(5))
;
// clear granted requests internally
sm_arb.request_mask &= ~grant_mask;
// Arbitrator should remove GRANT now. Data section on Bus still BBSY
sm_arb.bbsy_wait_grant_mask = grant_mask; // next is State 2: wait for BBSY clear
}
return 0; // no GRANT for us, or wait for BBSY
} else {
// wait for BBSY to clear
if (buslatches_getbyte(1) & BIT(6))
return 0; // BBSY still set
grant_mask = sm_arb.bbsy_wait_grant_mask;
sm_arb.bbsy_wait_grant_mask = 0; // Next State is 1
return grant_mask; // signal what request we got granted.
}
// UNIBUS DATA section is indepedent: MSYN, SSYN, BBSY may still be active.
// -> DMA and INTR statemachine must wait for BBSY.
// Arbitration master stuff complete,
// handle GRANT/SACK/BBSY for emulated devices
return sm_arb_worker_device_grant_sack_bbsy(sm_arb.arbitrator_grant_mask);
}

View File

@@ -40,7 +40,7 @@ typedef struct {
// There are 5 request/grant signals (BR4,5,6,7 and NPR).
// These are encoded as bitmask fitting the buslatch[0] or[1]
// BR/NPR lines = set of _PRIORITY_ARBITRATION_BIT_*
uint8_t request_mask;
uint8_t device_request_mask;
// sm_arb has 2 states: State 1 "Wait for GRANT" and State 2 "wait for BBSY"
// When arbitrator GRANts a request, we set SACK, GRAMT is cleared and we wait
@@ -53,7 +53,7 @@ typedef struct {
// only used wif working as Arbitrator/Interupt Fielding Processor
uint8_t ifs_priority_level; // priority level of Interrupt Fielding processor (CPU)
uint8_t arbitrator_grant_mask; // GRANT line set by master
uint8_t arbitrator_grant_mask; // single GRANT line set by master
} statemachine_arbitration_t;

View File

@@ -83,6 +83,10 @@ statemachine_state_func sm_data_slave_start() {
// addr8..15 = latch[3]
// addr 16,17 = latch[4].0,1
addr = latch2val | ((uint32_t) latch3val << 8) | ((uint32_t) (latch4val & 3) << 16);
//if (addr == 0777546) // LTC
// PRU_DEBUG_PIN0(1) ; // trigger to LA.
// make bool of a17..a13. iopage, if a17..a13 all 1's
// iopage = ((latch3val & 0xe0) | (latch4val & 3)) == 0xe3;

View File

@@ -333,7 +333,7 @@ static statemachine_state_func sm_dma_state_99() {
// device or cpu cycle ended: now CPU may become UNIBUS master again
mailbox.events.dma.cpu_transfer = mailbox.arbitrator.cpu_BBSY ;
mailbox.arbitrator.device_BBSY = false;
// device_BBSY monitored by sm_arbitration (physical devices).
mailbox.arbitrator.cpu_BBSY = false;
// SACK already de-asserted at wordcount==1

View File

@@ -98,7 +98,7 @@ static statemachine_state_func sm_intr_master_state_2() {
// deassert BBSY
buslatches_setbits(1, BIT(6), 0);
// device cycle ended: now CPU may become UNIBUS master again
mailbox.arbitrator.device_BBSY = false ;
// device_BBSY monitored by sm_arbitration (physical devices).
// SACK already removed

View File

@@ -47,11 +47,11 @@ 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
// WAIT for INTR.
// Master holds BBSY and SACK
statemachine_state_func sm_intr_slave_start() {
// WAIT for INTR
if ((buslatches_getbyte(7) & BIT(0)) == 0)
return NULL ; // still idle
return NULL ; // INTR still deasserted
// 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]
@@ -65,7 +65,11 @@ statemachine_state_func sm_intr_slave_start() {
// signal ARM, wait for event to be processed
mailbox.events.intr_slave.vector = (uint16_t) latch6val << 8 | latch5val ;
EVENT_SIGNAL(mailbox,intr_slave) ; // signal to ARM
PRU2ARM_INTERRUPT ;
PRU_DEBUG_PIN0(1);
// wait until ARM acked
return (statemachine_state_func) &sm_intr_slave_state_1;
}

View File

@@ -44,7 +44,7 @@ void do_event_initializationsignals() {
uint8_t bus_cur = buslatches_getbyte(7) & 0x38; // now sampled
if (bus_cur & INITIALIZATIONSIGNAL_INIT) {
sm_arb.request_mask = 0 ; // INIT clears all PRIORITY request signals
sm_arb.device_request_mask = 0 ; // INIT clears all PRIORITY request signals
// SACK cleared later on end of INTR/DMA transaction
}

View File

@@ -123,9 +123,9 @@ typedef struct {
// data for bus arbitrator
typedef struct {
// arbitrator.device_BBSY indicates a device wants or has acquired the UNIBUS
// cpu DATA transfer must be delayed until == 00
// set by arbitration logic
// arbitrator.device_BBSY indicates a device wants or has acquired the UNIBUS.
// cpu DATA transfer must be delayed until device_BBSY == 0
// set when arbitration logic detects SACK!
uint8_t device_BBSY;
// Command by ARM on DMA start: DATA transfer as CPU, else as device

View File

@@ -106,8 +106,10 @@ void cpu_c::worker(unsigned instance) {
if (runmode.value != (ka11.state != 0))
ka11.state = runmode.value;
ka11_condstep(&ka11);
if (runmode.value != (ka11.state != 0))
if (runmode.value != (ka11.state != 0)) {
runmode.value = ka11.state != 0;
printf("CPU HALT at %06o.\n", ka11.r[7]) ;
}
// serialize asynchronous power events
if (runmode.value) {