1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-02-14 11:55:28 +00:00

DMA/INTR arbitration rework, emulated CPU20 with DMA&INTR, runs XXDP

This commit is contained in:
Joerg Hoppe
2019-10-04 12:45:26 +02:00
parent 73b9d2f9fb
commit f314317e2a
57 changed files with 2498 additions and 1795 deletions

View File

@@ -58,12 +58,27 @@ void unibone_log(unsigned msglevel, const char *srcfilename, unsigned srcline, c
va_end(arg_ptr);
}
void unibone_logdump(void) {
// logger->dump(logger->default_filepath);
logger->dump(); // stdout
}
// called before opcode fetch of next instruction
// This is the point in time were INTR requests are checked and GRANTed
// (PRU implementation may limit NPR GRANTs also to this time)
void unibone_on_before_instruction(void) {
// after that the CPU should check for received INTR vectors
// in its microcode service() step.c
// allow PRU do to produce GRANT for device requests
mailbox_execute (ARM2PRU_ARB_GRANT_INTR_REQUESTS);
// Block CPU thread
while (mailbox->arbitrator.ifs_intr_arbitration_pending) {
// often 60-80 us, So just idle loop the CPU thread
// timeout_c::wait_us(1);
}
}
// Result: 1 = OK, 0 = bus timeout
int unibone_dato(unsigned addr, unsigned data) {
uint16_t wordbuffer = (uint16_t) data;
@@ -93,8 +108,6 @@ int unibone_dati(unsigned addr, unsigned *data) {
*data = wordbuffer;
dbg = 0;
// printf("DATI; ba=%o, data=%o\n", addr, *data) ;
//if (!unibone_cpu->data_transfer_request.success)
// ARM_DEBUG_PIN0(1) ;
return unibone_cpu->data_transfer_request.success;
}
@@ -104,7 +117,7 @@ int unibone_dati(unsigned addr, unsigned *data) {
// mailbox->arbitrator.cpu_priority_level was CPU_PRIORITY_LEVEL_FETCHING
// In that case, PRU is allowed now to grant BGs again.
void unibone_prioritylevelchange(uint8_t level) {
mailbox->arbitrator.cpu_priority_level = level;
mailbox->arbitrator.ifs_priority_level = level;
}
// CPU executes RESET opcode -> pulses INIT line
@@ -148,15 +161,43 @@ cpu_c::~cpu_c() {
bool cpu_c::on_param_changed(parameter_c *param) {
if (param == &enabled) {
if (!enabled.new_value) {
// HALT disabled CPU
runmode.value = false;
init.value = false;
// HALT disabled CPU
stop();
} else {
// enable active: assert CPU starts stopped
stop();
}
} else if (param == &runmode) {
if (runmode.new_value) {
start();
} else {
stop();
}
}
return unibusdevice_c::on_param_changed(param); // more actions (for enable)
}
// start CPU logic on PRU and switch arbitration mode
void cpu_c::start() {
runmode.value = true;
mailbox->cpu_enable = 1;
mailbox_execute(ARM2PRU_CPU_ENABLE);
unibus->set_arbitrator_active(true);
}
// stop CPU logic on PRU and switch arbitration mode
void cpu_c::stop() {
ka11.state = 0;
runmode.value = false;
mailbox->cpu_enable = 0;
mailbox_execute(ARM2PRU_CPU_ENABLE);
unibus->set_arbitrator_active(false);
}
// background worker.
// Started/stopped on param "enable"
void cpu_c::worker(unsigned instance) {
UNUSED(instance); // only one
timeout_c timeout;
@@ -169,58 +210,45 @@ void cpu_c::worker(unsigned instance) {
power_event = power_event_none;
// run with lowest priority, but without wait()
// => get all remainingn CPU power
// worker_init_realtime_priority(none_rt);
//worker_init_realtime_priority(device_rt);
// => get all remaining CPU power
worker_init_realtime_priority(none_rt);
//worker_init_realtime_priority(device_rt);
timeout.wait_us(1);
while (!workers_terminate) {
// speed control is diffiuclt, force to use more ARM cycles
timeout.wait_us(1);
for (int i = 0; i < 10; i++) {
if (runmode.value != (ka11.state != 0))
ka11.state = runmode.value;
ka11_condstep(&ka11);
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) {
// don't call power traps if HALTed. Also not on CONT.
if (power_event == power_event_down)
ka11_pwrdown(&unibone_cpu->ka11);
// stop stop some time after power down
else if (power_event == power_event_up)
ka11_pwrup(&unibone_cpu->ka11);
power_event = power_event_none; // processed
}
if (init.value) {
// user wants CPU reset
ka11_reset(&ka11);
init.value = 0;
}
// speed control is difficult, force to use more ARM cycles
// if (runmode.value != (ka11.state != 0))
// ka11.state = runmode.value;
if (runmode.value && (ka11.state == 0))
ka11.state = 1; // HALTED -> RUNNING
else if (!runmode.value)
// HALT position inside instructions !!!
ka11.state = 0; // WAITING|RUNNING =- HALTED
int prev_ka11_state = ka11.state;
ka11_condstep(&ka11);
if (prev_ka11_state > 0 && ka11.state == 0) {
// CPU run on HALT, sync runmode
runmode.value = false;
printf("CPU HALT at %06o.\n", ka11.r[7]);
}
#if 0
// serialize asynchronous power events
if (runmode.value) {
// simulate a fetch
nxm = !unibone_dati(pc, &opcode);
if (nxm) {
printf("Bus timeout at PC = %06o. HALT.\n", pc);
runmode.value = false;
}
pc = (pc + 2) % 0100; // loop around
// set LEDS
nxm = !unibone_dato(dr, pc & 0xf);
if (nxm) {
printf("Bus timeout at DR = %06o. HALT.\n", dr);
runmode.value = false;
}
// don't call power traps if HALTed. Also not on CONT.
if (power_event == power_event_down)
ka11_pwrdown(&unibone_cpu->ka11);
// stop stop some time after power down
else if (power_event == power_event_up)
ka11_pwrup(&unibone_cpu->ka11);
power_event = power_event_none; // processed
}
#endif
if (init.value) {
// user wants CPU reset
ka11_reset(&ka11);
init.value = 0;
}
}
}