mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-01-13 15:27:09 +00:00
CPU20 power start/power fail
This commit is contained in:
parent
6f2adbd216
commit
d058310e53
@ -116,7 +116,7 @@ void unibus_c::init(unsigned pulsewidth_ms) {
|
||||
*/
|
||||
void unibus_c::powercycle(void) {
|
||||
timeout_c timeout;
|
||||
const unsigned delay_ms = 100; // time between phases
|
||||
const unsigned delay_ms = 200; // time between phases
|
||||
mailbox->initializationsignal.id = INITIALIZATIONSIGNAL_ACLO;
|
||||
mailbox->initializationsignal.val = 1;
|
||||
mailbox_execute(ARM2PRU_INITALIZATIONSIGNAL_SET);
|
||||
|
||||
@ -68,6 +68,8 @@ using namespace std;
|
||||
#include "iopageregister.h"
|
||||
#include "priorityrequest.hpp"
|
||||
#include "unibusadapter.hpp"
|
||||
#include "unibuscpu.hpp"
|
||||
|
||||
unibusadapter_c *unibusadapter; // another Singleton
|
||||
// is registered in device_c.list<devices> ... order of static constructor calls ???
|
||||
|
||||
@ -85,11 +87,13 @@ unibusadapter_c::unibusadapter_c() :
|
||||
devices[i] = NULL;
|
||||
line_INIT = false;
|
||||
line_DCLO = false;
|
||||
line_ACLO = false ;
|
||||
line_ACLO = false;
|
||||
|
||||
requests_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
requests_init();
|
||||
|
||||
the_cpu = NULL;
|
||||
}
|
||||
|
||||
bool unibusadapter_c::on_param_changed(parameter_c *param) {
|
||||
@ -214,6 +218,15 @@ bool unibusadapter_c::register_device(unibusdevice_c& device) {
|
||||
register_handle++;
|
||||
}
|
||||
|
||||
// if its a CPU, switch PRU to "with_CPU"
|
||||
unibuscpu_c *cpu = dynamic_cast<unibuscpu_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) ;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -227,6 +240,14 @@ void unibusadapter_c::unregister_device(unibusdevice_c& device) {
|
||||
|
||||
INFO("UnibusAdapter: UnRegistering device %s.", device.name.value.c_str());
|
||||
|
||||
// if its a CPU, disable PRU to "with_CPU"
|
||||
unibuscpu_c *cpu = dynamic_cast<unibuscpu_c*>(&device);
|
||||
if (cpu) {
|
||||
mailbox->cpu_enable = 0;
|
||||
mailbox_execute(ARM2PRU_CPU_ENABLE);
|
||||
the_cpu = NULL;
|
||||
}
|
||||
|
||||
// remove "from backplane"
|
||||
devices[device.handle] = NULL;
|
||||
device.handle = 0;
|
||||
@ -302,8 +323,8 @@ void unibusadapter_c::requests_cancel_scheduled(void) {
|
||||
prl->slot_request[slot] = NULL;
|
||||
// signal to blocking DMA() or INTR()
|
||||
pthread_mutex_lock(&req->complete_mutex);
|
||||
req->complete = true;
|
||||
pthread_cond_signal(&req->complete_cond);
|
||||
req->complete = true;
|
||||
pthread_cond_signal(&req->complete_cond);
|
||||
pthread_mutex_unlock(&req->complete_mutex);
|
||||
}
|
||||
}
|
||||
@ -492,8 +513,8 @@ void unibusadapter_c::request_active_complete(unsigned level_index) {
|
||||
|
||||
// signal to DMA() or INTR()
|
||||
pthread_mutex_lock(&tmprq->complete_mutex);
|
||||
tmprq->complete = true;
|
||||
pthread_cond_signal(&tmprq->complete_cond);
|
||||
tmprq->complete = true;
|
||||
pthread_cond_signal(&tmprq->complete_cond);
|
||||
pthread_mutex_unlock(&tmprq->complete_mutex);
|
||||
|
||||
}
|
||||
@ -525,7 +546,7 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni
|
||||
|
||||
// dma_request.level-index, priority_slot in constructor
|
||||
dma_request.complete = false;
|
||||
dma_request.success = false;
|
||||
dma_request.success = false;
|
||||
dma_request.executing_on_PRU = false;
|
||||
dma_request.unibus_control = unibus_control;
|
||||
dma_request.unibus_start_addr = unibus_addr;
|
||||
@ -551,12 +572,13 @@ void unibusadapter_c::DMA(dma_request_c& dma_request, bool blocking, uint8_t uni
|
||||
// DEBUG("device DMA start: %s @ %06o, len=%d", unibus->control2text(unibus_control), unibus_addr, wordcount);
|
||||
if (blocking) {
|
||||
pthread_mutex_lock(&dma_request.complete_mutex);
|
||||
// DMA() is blocking: Wait for request to finish.
|
||||
// pthread_mutex_lock(&dma_request.mutex);
|
||||
while (!dma_request.complete) {
|
||||
int res = pthread_cond_wait(&dma_request.complete_cond, &dma_request.complete_mutex);
|
||||
assert(!res) ;
|
||||
}
|
||||
// DMA() is blocking: Wait for request to finish.
|
||||
// pthread_mutex_lock(&dma_request.mutex);
|
||||
while (!dma_request.complete) {
|
||||
int res = pthread_cond_wait(&dma_request.complete_cond,
|
||||
&dma_request.complete_mutex);
|
||||
assert(!res);
|
||||
}
|
||||
pthread_mutex_unlock(&dma_request.complete_mutex);
|
||||
}
|
||||
}
|
||||
@ -681,17 +703,18 @@ void unibusadapter_c::cancel_INTR(intr_request_c& intr_request) {
|
||||
// both empty, or both filled
|
||||
assert((prl->slot_request_mask == 0) == (prl->active == NULL));
|
||||
|
||||
pthread_mutex_lock(&intr_request.complete_mutex);
|
||||
pthread_cond_signal(&intr_request.complete_cond);
|
||||
pthread_mutex_lock(&intr_request.complete_mutex);
|
||||
pthread_cond_signal(&intr_request.complete_cond);
|
||||
pthread_mutex_unlock(&intr_request.complete_mutex);
|
||||
|
||||
pthread_mutex_unlock(&requests_mutex); // lock schedule table operations
|
||||
|
||||
}
|
||||
|
||||
|
||||
// do DATO/DATI as master CPU.
|
||||
// no NPR/NPG/SACK request, but waiting for BUS idle
|
||||
// result: success, else BUS TIMOUT
|
||||
// result: success, else BUS TIMEOUT
|
||||
void unibusadapter_c::cpu_DATA_transfer(dma_request_c& dma_request, uint8_t unibus_control,
|
||||
uint32_t unibus_addr, uint16_t *buffer) {
|
||||
timeout_c timeout;
|
||||
@ -721,17 +744,15 @@ void unibusadapter_c::cpu_DATA_transfer(dma_request_c& dma_request, uint8_t unib
|
||||
// then ARM2PRU_DMA is answered with an error
|
||||
// infinite time may have passed after that check above
|
||||
} while (!success);
|
||||
// wait for PRU complete event
|
||||
//pthread_mutex_lock(&cpu_data_transfer_request->complete_mutex);
|
||||
//pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex);
|
||||
pthread_mutex_lock(&cpu_data_transfer_request->complete_mutex);
|
||||
// DMA() is blocking: Wait for request to finish.
|
||||
// pthread_mutex_lock(&dma_request.mutex);
|
||||
while (!cpu_data_transfer_request->complete) {
|
||||
int res = pthread_cond_wait(&cpu_data_transfer_request->complete_cond, &cpu_data_transfer_request->complete_mutex);
|
||||
assert(!res) ;
|
||||
}
|
||||
pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex);
|
||||
// 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.
|
||||
while (!cpu_data_transfer_request->complete) {
|
||||
int res = pthread_cond_wait(&cpu_data_transfer_request->complete_cond,
|
||||
&cpu_data_transfer_request->complete_mutex);
|
||||
assert(!res);
|
||||
}
|
||||
pthread_mutex_unlock(&cpu_data_transfer_request->complete_mutex);
|
||||
|
||||
// Copy incoming data from mailbox DMA buffer
|
||||
if (unibus_control == UNIBUS_CONTROL_DATI)
|
||||
@ -1048,7 +1069,8 @@ void unibusadapter_c::worker(unsigned instance) {
|
||||
"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);
|
||||
init_falling_edge, dclo_raising_edge, dclo_falling_edge,
|
||||
aclo_raising_edge, aclo_falling_edge);
|
||||
|
||||
}
|
||||
if (dclo_raising_edge)
|
||||
@ -1073,15 +1095,28 @@ void unibusadapter_c::worker(unsigned instance) {
|
||||
pthread_mutex_unlock(&requests_mutex);
|
||||
mailbox->events.event_dma = 0; // PRU may re-raise and change mailbox now
|
||||
}
|
||||
if (mailbox->events.event_intr) {
|
||||
// INTRs are granted unpredictable by Arbitrator
|
||||
if (mailbox->events.event_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);
|
||||
pthread_mutex_unlock(&requests_mutex);
|
||||
mailbox->events.event_intr = 0; // PRU may re-raise and change mailbox now
|
||||
mailbox->events.event_intr_master = 0; // PRU may re-raise and change mailbox now
|
||||
}
|
||||
if (mailbox->events.event_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);
|
||||
// clear SSYN, INTR cycle completes
|
||||
mailbox->events.event_intr_slave = 0;
|
||||
// mailbox->arbitrator.cpu_priority_level now CPU_PRIORITY_LEVEL_FETCHING
|
||||
// BG grants blocked
|
||||
|
||||
// PRU may re-raise and change mailbox now
|
||||
}
|
||||
|
||||
if (init_raising_edge) // INIT deasserted -> asserted. DATI/DATO cycle only possible before that.
|
||||
worker_init_event();
|
||||
}
|
||||
|
||||
@ -49,6 +49,9 @@ public:
|
||||
void clear();
|
||||
};
|
||||
|
||||
class unibuscpu_c ;
|
||||
|
||||
|
||||
// is a device_c. need a thread (but no params)
|
||||
class unibusadapter_c: public device_c {
|
||||
private:
|
||||
@ -61,6 +64,8 @@ private:
|
||||
|
||||
pthread_mutex_t requests_mutex;
|
||||
|
||||
unibuscpu_c *the_cpu ; // only one unibuscpu_c may be registered
|
||||
|
||||
void worker_init_event(void);
|
||||
void worker_power_event(bool power_down);
|
||||
void worker_deviceregister_event(void);
|
||||
|
||||
54
10.01_base/2_src/arm/unibuscpu.cpp
Normal file
54
10.01_base/2_src/arm/unibuscpu.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/* unibuscpu.cpp: base class for all CPU implementations
|
||||
|
||||
Copyright (c) 2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
27-aug-2019 JH start
|
||||
*/
|
||||
|
||||
#include "unibuscpu.hpp"
|
||||
|
||||
void unibuscpu_c::on_power_changed(void) {
|
||||
// called within a bus_cycle, and initiates other cycles?!
|
||||
//assert(dbg==0) ;
|
||||
if (power_down) { // power-on defaults
|
||||
INFO("CPU: ACLO failed");
|
||||
power_event = power_event_down;
|
||||
// ka11_pwrdown(&the_cpu->ka11);
|
||||
// ACLO failed.
|
||||
// CPU traps to vector 24 and has 2ms time to execute code
|
||||
} else {
|
||||
INFO("CPU: DCLO restored");
|
||||
power_event = power_event_up;
|
||||
// ka11_pwrup(&the_cpu->ka11);
|
||||
// DCLO restored
|
||||
// CPU loads PC and PSW from vector 24
|
||||
// if HALTed: do nothing, user is expected to setup PC and PSW ?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// UNIBUS INIT: clear all registers
|
||||
void unibuscpu_c::on_init_changed(void) {
|
||||
// a CPU does not react to INIT ... else its own RESET would reset it.
|
||||
}
|
||||
|
||||
|
||||
52
10.01_base/2_src/arm/unibuscpu.hpp
Normal file
52
10.01_base/2_src/arm/unibuscpu.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* unibuscpu.hpp: base class for all CPU implementations
|
||||
|
||||
Copyright (c) 2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
27-aug-2019 JH start
|
||||
*/
|
||||
|
||||
#ifndef _UNIBUSCPU_HPP_
|
||||
#define _UNIBUSCPU_HPP_
|
||||
|
||||
|
||||
#include "unibusdevice.hpp"
|
||||
|
||||
// a CPU is just a device with INTR facilities
|
||||
class unibuscpu_c: public unibusdevice_c {
|
||||
public:
|
||||
unibuscpu_c(): unibusdevice_c() {
|
||||
power_event = power_event_none ;
|
||||
} ;
|
||||
|
||||
enum power_event_enum {power_event_none, power_event_up, power_event_down} ;
|
||||
|
||||
enum power_event_enum power_event ;
|
||||
|
||||
// called by PRU on INTR, returns new priority level
|
||||
virtual void on_interrupt(uint16_t vector) = 0 ;
|
||||
|
||||
|
||||
virtual void on_power_changed(void) ;
|
||||
virtual void on_init_changed(void) ;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -168,4 +168,5 @@ public:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -71,8 +71,9 @@ OBJECTS_COMMON= \
|
||||
$(OBJ_DIR)/pru1_pru_mailbox.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_arbitration.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_dma.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_intr_master.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_data_slave.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_intr_master.object \
|
||||
$(OBJ_DIR)/pru1_statemachine_intr_slave.object \
|
||||
$(OBJ_DIR)/pru1_timeouts.object \
|
||||
$(OBJ_DIR)/pru1_utils.object
|
||||
|
||||
|
||||
@ -54,10 +54,10 @@
|
||||
#include "pru1_statemachine_arbitration.h"
|
||||
#include "pru1_statemachine_dma.h"
|
||||
#include "pru1_statemachine_intr_master.h"
|
||||
#include "pru1_statemachine_slave.h"
|
||||
#include "pru1_statemachine_data_slave.h"
|
||||
|
||||
// Supress warnings about using void * as function pointers
|
||||
// sm_slave_state = (statemachine_state_func)&sm_slave_start;
|
||||
// sm_slave_state = (statemachine_state_func)&sm_data_slave_start;
|
||||
// while (sm_slave_state = sm_slave_state()) << usage
|
||||
#pragma diag_push
|
||||
#pragma diag_remark=515
|
||||
@ -203,7 +203,7 @@ void main(void) {
|
||||
// writing into mailbox.arm2pru_req
|
||||
while (mailbox.arm2pru_req == ARM2PRU_DDR_SLAVE_MEMORY) {
|
||||
statemachine_state_func sm_slave_state =
|
||||
(statemachine_state_func) &sm_slave_start;
|
||||
(statemachine_state_func) &sm_data_slave_start;
|
||||
// do all states of an access, start when MSYN found.
|
||||
while (sm_slave_state = sm_slave_state())
|
||||
;
|
||||
|
||||
@ -58,11 +58,12 @@
|
||||
#include "pru1_buslatches.h"
|
||||
#include "pru1_statemachine_arbitration.h"
|
||||
#include "pru1_statemachine_dma.h"
|
||||
#include "pru1_statemachine_data_slave.h"
|
||||
#include "pru1_statemachine_intr_master.h"
|
||||
#include "pru1_statemachine_slave.h"
|
||||
#include "pru1_statemachine_intr_slave.h"
|
||||
|
||||
// supress warnigns about using void * as function pointers
|
||||
// sm_slave_state = (statemachine_state_func)&sm_slave_start;
|
||||
// sm_slave_state = (statemachine_state_func)&sm_data_slave_start;
|
||||
// while (sm_slave_state = sm_slave_state()) << usage
|
||||
#pragma diag_push
|
||||
#pragma diag_remark=515
|
||||
@ -93,8 +94,11 @@ void main(void) {
|
||||
statemachine_arb_worker_func sm_arb_worker = &sm_arb_worker_client;
|
||||
statemachine_state_func sm_data_slave_state = NULL;
|
||||
statemachine_state_func sm_data_master_state = NULL;
|
||||
statemachine_state_func sm_intr_slave_state = NULL ;
|
||||
// these are function pointers: could be 16bit on PRU?
|
||||
|
||||
bool emulate_cpu = false;
|
||||
|
||||
/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
|
||||
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
|
||||
|
||||
@ -118,16 +122,27 @@ void main(void) {
|
||||
uint8_t arm2pru_req_cached;
|
||||
|
||||
if (sm_data_master_state == NULL) {
|
||||
// State 1 "SLAVE"
|
||||
// State 1 "SLAVE"
|
||||
|
||||
// DATA or INTR for CPU?
|
||||
|
||||
// fast: a complete slave data cycle
|
||||
if (!sm_data_slave_state)
|
||||
sm_data_slave_state = (statemachine_state_func) &sm_slave_start;
|
||||
sm_data_slave_state = (statemachine_state_func) &sm_data_slave_start;
|
||||
while ((sm_data_slave_state = sm_data_slave_state())
|
||||
&& !mailbox.events.event_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
|
||||
|
||||
if (emulate_cpu) {
|
||||
// same code loop as for DATA cycle
|
||||
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) ;
|
||||
}
|
||||
|
||||
// signal INT or PWR FAIL to ARM
|
||||
do_event_initializationsignals();
|
||||
|
||||
@ -160,10 +175,10 @@ void main(void) {
|
||||
// we have been GRANTed bus mastership and are doing DMA or INTR
|
||||
// SACK held here -> no further arbitration
|
||||
// INTR is only 1 cycle, DMA has SACK set all the time, arbitration
|
||||
// prohibited then.
|
||||
// prohibited then.
|
||||
|
||||
sm_data_master_state = sm_data_master_state(); // execute only ONE state ,
|
||||
// else DMA blocks will block prcoessing of other state machines
|
||||
// else DMA blocks will block processing of other state machines
|
||||
// throws signals to ARM, causes may issue mailbox.arm2pru_req
|
||||
}
|
||||
|
||||
@ -193,7 +208,7 @@ void main(void) {
|
||||
if (mailbox.arbitrator.cpu_BBSY) {
|
||||
// ARM CPU emulation did a single word DATA transfer with cpu_DATA_transfer()
|
||||
if (mailbox.arbitrator.device_BBSY) {
|
||||
// ARM started cpu DATA transfer, but arbitration logic
|
||||
// ARM started cpu DATA transfer, but arbitration logic
|
||||
// GRANTed a device request in the mean time. Tell ARM.
|
||||
mailbox.arm2pru_req = PRU2ARM_DMA_CPU_TRANSFER_BLOCKED; // error
|
||||
mailbox.arbitrator.cpu_BBSY = false;
|
||||
@ -227,7 +242,7 @@ void main(void) {
|
||||
// vector of GRANted level is transfered with statemachine sm_intr_master
|
||||
|
||||
// Atomically change state in a device's associates interrupt register.
|
||||
// The Interupt Register is set immediately. No wait for INTR GRANT,
|
||||
// The Interupt Register is set immediately. No wait for INTR GRANT,
|
||||
// INTR level may be blocked.
|
||||
if (mailbox.intr.iopage_register_handle)
|
||||
deviceregisters.registers[mailbox.intr.iopage_register_handle].value =
|
||||
@ -259,7 +274,16 @@ void main(void) {
|
||||
}
|
||||
mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done
|
||||
break;
|
||||
case ARM2PRU_HALT:
|
||||
case ARM2PRU_CPU_ENABLE:
|
||||
// bool flag much faster to access then shared mailbox member.
|
||||
emulate_cpu = mailbox.cpu_enable ;
|
||||
if (emulate_cpu)
|
||||
sm_arb_worker = &sm_arb_worker_master;
|
||||
else
|
||||
sm_arb_worker = &sm_arb_worker_client;
|
||||
mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done
|
||||
break ;
|
||||
case ARM2PRU_HALT:
|
||||
mailbox.arm2pru_req = ARM2PRU_NONE; // ACK: done
|
||||
__halt(); // LA: trigger on timeout of REG_WRITE
|
||||
break;
|
||||
|
||||
@ -238,7 +238,10 @@ PRU_DEBUG_PIN_PULSE_100NS ;
|
||||
uint8_t requested_intr_level = requests_2_highests_intr[intr_request_mask];
|
||||
|
||||
// compare against cpu run level 4..7
|
||||
if (requested_intr_level > mailbox.arbitrator.cpu_priority_level) {
|
||||
// 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) {
|
||||
// GRANT request, set GRANT line:
|
||||
// BG4 is signal bit maskl 0x01, etc ...
|
||||
sm_arb.arbitrator_grant_mask = BIT(requested_intr_level - 4);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* pru1_statemachine_slave.c: state machine for execution of slave DATO* or DATI* cycles
|
||||
/* pru1_statemachine_data_slave.c: state machine for execution of slave DATO* or DATI* cycles
|
||||
|
||||
Copyright (c) 2018, Joerg Hoppe
|
||||
Copyright (c) 2018-2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@ -34,8 +34,6 @@
|
||||
- address is evaluated, ggf mem access
|
||||
*/
|
||||
|
||||
#define _PRU1_STATEMACHINE_SLAVE_C_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@ -46,16 +44,16 @@
|
||||
#include "iopageregister.h"
|
||||
|
||||
#include "pru1_buslatches.h"
|
||||
#include "pru1_statemachine_slave.h"
|
||||
#include "pru1_statemachine_data_slave.h"
|
||||
|
||||
// forwards ;
|
||||
//statemachine_state_func sm_slave_start(void);
|
||||
static statemachine_state_func sm_slave_state_10(void);
|
||||
static statemachine_state_func sm_slave_state_20(void);
|
||||
//static statemachine_state_func sm_slave_state_99(void);
|
||||
//statemachine_state_func sm_data_slave_start(void);
|
||||
static statemachine_state_func sm_data_slave_state_10(void);
|
||||
static statemachine_state_func sm_data_slave_state_20(void);
|
||||
//static statemachine_state_func sm_data_slave_state_99(void);
|
||||
|
||||
// check for MSYN active
|
||||
statemachine_state_func sm_slave_start() {
|
||||
statemachine_state_func sm_data_slave_start() {
|
||||
uint8_t latch2val, latch3val, latch4val;
|
||||
// uint8_t iopage;
|
||||
uint32_t addr;
|
||||
@ -111,11 +109,11 @@ statemachine_state_func sm_slave_start() {
|
||||
buslatches_setbyte(6, data >> 8);
|
||||
// set SSYN = latch[4], bit 5
|
||||
buslatches_setbits(4, BIT(5), BIT(5));
|
||||
return (statemachine_state_func) &sm_slave_state_20;
|
||||
return (statemachine_state_func) &sm_data_slave_state_20;
|
||||
// perhaps PRU2ARM_INTERRUPT now active
|
||||
} else
|
||||
// no address match: wait for MSYN to go inactive
|
||||
// return (statemachine_state_func) &sm_slave_state_99;
|
||||
// return (statemachine_state_func) &sm_data_slave_state_99;
|
||||
return NULL ;
|
||||
case UNIBUS_CONTROL_DATO:
|
||||
// fetch data in any case
|
||||
@ -128,11 +126,11 @@ statemachine_state_func sm_slave_start() {
|
||||
// SSYN = latch[4], bit 5
|
||||
buslatches_setbits(4, BIT(5), BIT(5));
|
||||
// wait for MSYN to go inactive, then SSYN inactive
|
||||
return (statemachine_state_func) &sm_slave_state_10;
|
||||
return (statemachine_state_func) &sm_data_slave_state_10;
|
||||
// perhaps PRU2ARM_INTERRUPT now active
|
||||
} else
|
||||
// no address match: wait for MSYN to go inactive
|
||||
// return (statemachine_state_func) &sm_slave_state_99;
|
||||
// return (statemachine_state_func) &sm_data_slave_state_99;
|
||||
return NULL ;
|
||||
case UNIBUS_CONTROL_DATOB:
|
||||
// A00 = 1, odd address: get upper byte
|
||||
@ -149,11 +147,11 @@ statemachine_state_func sm_slave_start() {
|
||||
// SSYN = latch[4], bit 5
|
||||
buslatches_setbits(4, BIT(5), BIT(5));
|
||||
// wait for MSYN to go inactive, then SSYN inactive
|
||||
return (statemachine_state_func) &sm_slave_state_10;
|
||||
return (statemachine_state_func) &sm_data_slave_state_10;
|
||||
// perhaps PRU2ARM_INTERRUPT now active
|
||||
} else
|
||||
// no address match: wait for MSYN to go inactive
|
||||
// return (statemachine_state_func) &sm_slave_state_99;
|
||||
// return (statemachine_state_func) &sm_data_slave_state_99;
|
||||
return NULL ;
|
||||
}
|
||||
return NULL; // not reached
|
||||
@ -161,14 +159,14 @@ statemachine_state_func sm_slave_start() {
|
||||
|
||||
// End DATO: wait for MSYN to go inactive, then SSYN inactive
|
||||
// also wait for EVENT ACK
|
||||
static statemachine_state_func sm_slave_state_10() {
|
||||
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_slave_state_10; // wait, MSYN still active
|
||||
return (statemachine_state_func) &sm_data_slave_state_10; // wait, MSYN still active
|
||||
if (mailbox.events.event_deviceregister)
|
||||
// unibusadapter.worker() did not yet run on_after_register_access()
|
||||
// => wait, long SSYN delay until ARM acknowledges event
|
||||
return (statemachine_state_func) &sm_slave_state_10;
|
||||
return (statemachine_state_func) &sm_data_slave_state_10;
|
||||
// if ARM was triggered by event and changed the device state,
|
||||
// now an Interrupt arbitration may be pending.
|
||||
|
||||
@ -180,14 +178,14 @@ static statemachine_state_func sm_slave_state_10() {
|
||||
|
||||
// End DATI: wait for MSYN to go inactive, then SSYN and DATA inactive
|
||||
// also wait for EVENT ACK
|
||||
static statemachine_state_func sm_slave_state_20() {
|
||||
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_slave_state_20; // wait, MSYN still active
|
||||
return (statemachine_state_func) &sm_data_slave_state_20; // wait, MSYN still active
|
||||
if (mailbox.events.event_deviceregister)
|
||||
// unibusadapter.worker() did not yet run on_after_register_access()
|
||||
// => wait, long SSYN delay until ARM acknowledges event
|
||||
return (statemachine_state_func) &sm_slave_state_20;
|
||||
return (statemachine_state_func) &sm_data_slave_state_20;
|
||||
// if ARM was triggered by event and changed the device state,
|
||||
// now an Interrupt arbitration may be pending.
|
||||
|
||||
@ -204,10 +202,10 @@ static statemachine_state_func sm_slave_state_20() {
|
||||
|
||||
// end of inactive cycle: wait for MSYN to go inactive
|
||||
// Not necessary, start() state simply checks addr again if MSYN still set.
|
||||
static statemachine_state_func sm_slave_state_99() {
|
||||
static statemachine_state_func sm_data_slave_state_99() {
|
||||
// MSYN = latch[4], bit 4
|
||||
if (buslatches_getbyte(4) & BIT(4)) {
|
||||
return (statemachine_state_func) &sm_slave_state_99; // wait, MSYN still active
|
||||
return (statemachine_state_func) &sm_data_slave_state_99; // wait, MSYN still active
|
||||
}
|
||||
// PRU_DEBUG_PIN(1) ;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* pru1_statemachine_slave.h: state machine for execution of slave DATO* or DATI* cycles
|
||||
|
||||
Copyright (c) 2018, Joerg Hoppe
|
||||
Copyright (c) 2018-2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@ -24,12 +24,12 @@
|
||||
29-jun-2019 JH rework: state returns ptr to next state func
|
||||
12-nov-2018 JH entered beta phase
|
||||
*/
|
||||
#ifndef _PRU1_STATEMACHINE_SLAVE_H_
|
||||
#define _PRU1_STATEMACHINE_SLAVE_H_
|
||||
#ifndef _PRU1_STATEMACHINE_DATA_SLAVE_H_
|
||||
#define _PRU1_STATEMACHINE_DATA_SLAVE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pru1_utils.h" // statemachine_state_func
|
||||
|
||||
statemachine_state_func sm_slave_start(void);
|
||||
statemachine_state_func sm_data_slave_start(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -50,8 +50,6 @@
|
||||
|
||||
! Uses single global timeout, don't run in parallel with other statemachines using timeout !
|
||||
*/
|
||||
#define _PRU1_STATEMACHINE_DMA_C_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -37,9 +37,7 @@ typedef struct {
|
||||
uint16_t cur_wordsleft; // # of words left to transfer
|
||||
} statemachine_dma_t;
|
||||
|
||||
#ifndef _PRU1_STATEMACHINE_DMA_C_
|
||||
extern statemachine_dma_t sm_dma;
|
||||
#endif
|
||||
|
||||
statemachine_state_func sm_dma_start(void);
|
||||
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
Precondition: BBSY already asserted (arbitration got)
|
||||
|
||||
*/
|
||||
#define _PRU1_STATEMACHINE_INTR_C_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@ -86,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)
|
||||
if (mailbox.events.event_intr_master)
|
||||
return (statemachine_state_func) &sm_intr_master_state_2; // wait
|
||||
|
||||
// remove vector
|
||||
@ -106,7 +105,7 @@ 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 = 1;
|
||||
mailbox.events.event_intr_master = 1;
|
||||
// ARM is clearing this, before requesting new interrupt of same level
|
||||
// so no concurrent ARP+PRU access
|
||||
PRU2ARM_INTERRUPT
|
||||
|
||||
93
10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c
Normal file
93
10.01_base/2_src/pru1/pru1_statemachine_intr_slave.c
Normal file
@ -0,0 +1,93 @@
|
||||
/* pru1_statemachine_intr_slave.c: CPU receives interrupt vector
|
||||
|
||||
Copyright (c) 2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
26-aug-2019 JH start
|
||||
|
||||
State machines for CPU emulation to receive INTR vector placed onto bus by device.
|
||||
|
||||
|
||||
All references "PDP11BUS handbook 1979"
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
//#include "devices.h"
|
||||
#include "mailbox.h"
|
||||
#include "pru1_buslatches.h"
|
||||
#include "pru1_utils.h"
|
||||
|
||||
#include "pru1_statemachine_intr_slave.h"
|
||||
|
||||
// states
|
||||
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
|
||||
statemachine_state_func sm_intr_slave_start() {
|
||||
// WAIT for INTR
|
||||
if ((buslatches_getbyte(7) & BIT(0)) == 0)
|
||||
return NULL ; // still idle
|
||||
// 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]
|
||||
uint8_t latch6val = buslatches_getbyte(6) ; // DATA[8..15] = latch[6]
|
||||
|
||||
// set SSYN = latch[4], bit 5
|
||||
buslatches_setbits(4, BIT(5), BIT(5));
|
||||
|
||||
// mark priority level as invalid, block more BG GRANTS until PSW fetched
|
||||
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 ;
|
||||
PRU2ARM_INTERRUPT ;
|
||||
// wait until ARM acked
|
||||
return (statemachine_state_func) &sm_intr_slave_state_1;
|
||||
}
|
||||
|
||||
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 co solved by
|
||||
if (mailbox.events.event_intr_slave)
|
||||
return (statemachine_state_func) &sm_intr_slave_state_1;
|
||||
|
||||
// wait if INTR still active
|
||||
if (buslatches_getbyte(7) & BIT(0)) // check INTR
|
||||
return (statemachine_state_func) &sm_intr_slave_state_1;
|
||||
|
||||
// clear SSYN = latch[4], bit 5
|
||||
buslatches_setbits(4, BIT(5), 0);
|
||||
|
||||
// now CPU may do DATI to fetch PC and PSW
|
||||
|
||||
return NULL; // ready
|
||||
}
|
||||
|
||||
40
10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h
Normal file
40
10.01_base/2_src/pru1/pru1_statemachine_intr_slave.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* pru1_statemachine_intr_slave.h: CPU receives interrupt vector
|
||||
|
||||
Copyright (c) 2018-2019, Joerg Hoppe
|
||||
j_hoppe@t-online.de, www.retrocmp.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
26-aug-2019 JH start
|
||||
*/
|
||||
#ifndef _PRU1_STATEMACHINE_INTR_SLAVE_H_
|
||||
#define _PRU1_STATEMACHINE_INTR_SLAVE_H_
|
||||
|
||||
#include "pru1_utils.h" // statemachine_state_func
|
||||
|
||||
typedef struct {
|
||||
uint16_t vector; // interrupt vector to transfer
|
||||
uint8_t level_index; // 0..3 = BR..BR7. to be returned to ARM on complete
|
||||
} statemachine_intr_slave_t;
|
||||
|
||||
extern statemachine_intr_slave_t sm_intr_slave;
|
||||
|
||||
statemachine_state_func sm_intr_slave_start(void);
|
||||
|
||||
#endif
|
||||
@ -44,12 +44,13 @@
|
||||
#define ARM2PRU_ARB_MODE_NONE 11 // DMA without NPR/NPG/SACK arbitration
|
||||
#define ARM2PRU_ARB_MODE_CLIENT 12 // DMA with arbitration by external Arbitrator
|
||||
#define ARM2PRU_ARB_MODE_MASTER 13 // DMA as Arbitrator
|
||||
#define ARM2PRU_DMA 14 // DMA with selcted arbitration
|
||||
#define ARM2PRU_DMA 14 // DMA with selected arbitration
|
||||
#define PRU2ARM_DMA_CPU_TRANSFER_BLOCKED 15 // possible result of ARM2PRU_DMA
|
||||
#define ARM2PRU_INTR 16 // INTR with arbitration by external Arbitrator
|
||||
#define ARM2PRU_INTR_CANCEL 17 // clear INTR which has been requested
|
||||
#define ARM2PRU_DDR_FILL_PATTERN 18 // fill DDR with test pattern
|
||||
#define ARM2PRU_DDR_SLAVE_MEMORY 19 // use DDR as UNIBUS slave memory
|
||||
#define ARM2PRU_CPU_ENABLE 18 // siwtch CPU master side functions ON/OFF
|
||||
#define ARM2PRU_DDR_FILL_PATTERN 19 // fill DDR with test pattern
|
||||
#define ARM2PRU_DDR_SLAVE_MEMORY 20 // use DDR as UNIBUS slave memory
|
||||
|
||||
|
||||
// signal IDs for ARM2PRU_INITALIZATIONSIGNAL_*
|
||||
@ -76,6 +77,10 @@
|
||||
#define PRIORITY_ARBITRATION_INTR_MASK 0x0f // BR4|BR5|BR6|BR7
|
||||
#define PRIORITY_ARBITRATION_BIT_MASK 0x1f
|
||||
|
||||
// CPU pririty level invalid between INTR receive and fetch of next PSW
|
||||
#define CPU_PRIORITY_LEVEL_FETCHING 0xff
|
||||
|
||||
|
||||
// data for a requested DMA operation
|
||||
#define PRU_MAX_DMA_WORDCOUNT 512
|
||||
|
||||
@ -175,7 +180,7 @@ typedef struct {
|
||||
// differemt events can be raised asynchronically and concurrent,
|
||||
// but a single event type is sequentially raised by PRU and cleared by ARM.
|
||||
|
||||
/* Access to device register ***/
|
||||
/*** Access to device register ***/
|
||||
uint8_t event_deviceregister; // trigger flag
|
||||
// info about register access
|
||||
uint8_t unibus_control; // DATI,DATO,DATOB
|
||||
@ -197,24 +202,28 @@ typedef struct {
|
||||
uint8_t event_dma; // trigger flag
|
||||
uint8_t event_dma_cpu_transfer ; // 1: ARM must process DMa as compelted cpu DATA transfer
|
||||
|
||||
/*** Event priority arbitration data transfer complete
|
||||
/*** 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.
|
||||
*/
|
||||
// ---dword---
|
||||
uint8_t event_intr; // trigger flag: 1 = one of BR4,5,6,7 vector on UNIBUS
|
||||
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 _dummy2, _dummy3;
|
||||
/*** 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 ;
|
||||
// ---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
|
||||
// ---dword---
|
||||
uint8_t initialization_signals_prev; // on event: a signal changed from this ...
|
||||
// ---dword---
|
||||
uint8_t initialization_signals_cur; // ... to this
|
||||
|
||||
// uint8_t dummy[2]; // make record multiple of dword !!!
|
||||
uint8_t _dummy2[2]; // make record multiple of dword !!!
|
||||
} mailbox_events_t;
|
||||
|
||||
typedef struct {
|
||||
@ -242,6 +251,7 @@ typedef struct {
|
||||
mailbox_buslatch_test_t buslatch_test;
|
||||
mailbox_buslatch_exerciser_t buslatch_exerciser;
|
||||
mailbox_initializationsignal_t initializationsignal ;
|
||||
uint32_t cpu_enable;
|
||||
};
|
||||
} mailbox_t;
|
||||
|
||||
|
||||
@ -41,8 +41,10 @@
|
||||
*/
|
||||
static cpu_c *the_cpu = NULL;
|
||||
|
||||
int dbg = 0;
|
||||
|
||||
cpu_c::cpu_c() :
|
||||
unibusdevice_c() // super class constructor
|
||||
unibuscpu_c() // super class constructor
|
||||
{
|
||||
// static config
|
||||
name.value = "CPU20";
|
||||
@ -81,7 +83,7 @@ bool cpu_c::on_param_changed(parameter_c *param) {
|
||||
init.value = false;
|
||||
}
|
||||
}
|
||||
return device_c::on_param_changed(param); // more actions (for enable)
|
||||
return unibusdevice_c::on_param_changed(param); // more actions (for enable)
|
||||
}
|
||||
|
||||
// background worker.
|
||||
@ -93,6 +95,8 @@ void cpu_c::worker(unsigned instance) {
|
||||
unsigned dr = 0760102;
|
||||
unsigned opcode = 0;
|
||||
(void) opcode;
|
||||
|
||||
power_event = power_event_none;
|
||||
while (!workers_terminate) {
|
||||
// run full speed!
|
||||
timeout.wait_us(1);
|
||||
@ -105,6 +109,17 @@ void cpu_c::worker(unsigned instance) {
|
||||
if (runmode.value != (ka11.state != 0))
|
||||
runmode.value = ka11.state != 0;
|
||||
|
||||
// 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(&the_cpu->ka11);
|
||||
// stop stop some time after power down
|
||||
else if (power_event == power_event_up)
|
||||
ka11_pwrup(&the_cpu->ka11);
|
||||
power_event = power_event_none; // processed
|
||||
}
|
||||
|
||||
if (init.value) {
|
||||
// user wants CPU reset
|
||||
ka11_reset(&ka11);
|
||||
@ -146,29 +161,14 @@ void cpu_c::on_after_register_access(unibusdevice_register_t *device_reg,
|
||||
UNUSED(unibus_control);
|
||||
}
|
||||
|
||||
// TODO
|
||||
void cpu_c::on_power_changed(void) {
|
||||
if (power_down) { // power-on defaults
|
||||
INFO("CPU: ACLO failed");
|
||||
ka11_pwrdown(&the_cpu->ka11);
|
||||
// ACLO failed.
|
||||
// CPU traps to vector 24 and has 2ms time to execute code
|
||||
} else {
|
||||
INFO("CPU: DCLO restored");
|
||||
ka11_pwrup(&the_cpu->ka11);
|
||||
// DCLO restored
|
||||
// CPU loads PC and PSW from vector 24
|
||||
}
|
||||
}
|
||||
|
||||
// UNIBUS INIT: clear all registers
|
||||
void cpu_c::on_init_changed(void) {
|
||||
// a CPU does not react to INIT ... else its own RESET would reset it.
|
||||
|
||||
}
|
||||
|
||||
// TODO
|
||||
// CPU received interrupt vector from UNIBUS
|
||||
// PRU triggers this via unibusadapter,
|
||||
// mailbox->arbitrator.cpu_priority_level is CPU_PRIORITY_LEVEL_FETCHING
|
||||
// CPU fetches PSW and calls unibone_prioritylevelchange(), which
|
||||
// sets mailbox->arbitrator.cpu_priority_level and
|
||||
// PRU is allowed now to grant BGs again.
|
||||
void cpu_c::on_interrupt(uint16_t vector) {
|
||||
// CPU sequence:
|
||||
// push PSW to stack
|
||||
@ -184,35 +184,43 @@ extern "C" {
|
||||
int unibone_dato(unsigned addr, unsigned data) {
|
||||
uint16_t wordbuffer = (uint16_t) data;
|
||||
|
||||
dbg = 1;
|
||||
unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATO, addr,
|
||||
&wordbuffer);
|
||||
dbg = 0;
|
||||
return the_cpu->data_transfer_request.success;
|
||||
}
|
||||
|
||||
int unibone_datob(unsigned addr, unsigned data) {
|
||||
uint16_t wordbuffer = (uint16_t) data;
|
||||
// TODO DATOB als 1 byte-DMA !
|
||||
dbg = 1;
|
||||
unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATOB, addr,
|
||||
&wordbuffer);
|
||||
dbg = 0;
|
||||
return the_cpu->data_transfer_request.success;
|
||||
}
|
||||
|
||||
int unibone_dati(unsigned addr, unsigned *data) {
|
||||
uint16_t wordbuffer;
|
||||
dbg = 1;
|
||||
unibusadapter->cpu_DATA_transfer(the_cpu->data_transfer_request, UNIBUS_CONTROL_DATI, addr,
|
||||
&wordbuffer);
|
||||
*data = wordbuffer;
|
||||
dbg = 0;
|
||||
// printf("DATI; ba=%o, data=%o\n", addr, *data) ;
|
||||
|
||||
return the_cpu->data_transfer_request.success;
|
||||
}
|
||||
|
||||
// CPU has changed the arbitration level, just forward
|
||||
// if this is called as result of INTR fector PC and PSW fetch,
|
||||
// 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;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// CPU executes RESET opcode -> pulses INIT line
|
||||
void unibone_bus_init(unsigned pulsewidth_ms) {
|
||||
unibus->init(pulsewidth_ms);
|
||||
|
||||
@ -29,14 +29,15 @@
|
||||
using namespace std;
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "unibusadapter.hpp"
|
||||
#include "unibusdevice.hpp"
|
||||
//#include "unibusadapter.hpp"
|
||||
//#include "unibusdevice.hpp"
|
||||
#include "unibuscpu.hpp"
|
||||
extern "C" {
|
||||
#include "cpu20/11.h"
|
||||
#include "cpu20/ka11.h"
|
||||
}
|
||||
|
||||
class cpu_c: public unibusdevice_c {
|
||||
class cpu_c: public unibuscpu_c {
|
||||
private:
|
||||
|
||||
//unibusdevice_register_t *switch_reg;
|
||||
@ -67,8 +68,6 @@ public:
|
||||
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)
|
||||
override;
|
||||
|
||||
void on_power_changed(void) override;
|
||||
void on_init_changed(void) override;
|
||||
void on_interrupt(uint16_t vector) ;
|
||||
|
||||
};
|
||||
|
||||
@ -111,8 +111,9 @@ OBJECTS = $(OBJDIR)/application.o \
|
||||
$(OBJDIR)/storagecontroller.o \
|
||||
$(OBJDIR)/demo_io.o \
|
||||
$(OBJDIR)/testcontroller.o \
|
||||
$(OBJDIR)/unibusdevice.o \
|
||||
$(OBJDIR)/device.o \
|
||||
$(OBJDIR)/unibusdevice.o \
|
||||
$(OBJDIR)/unibuscpu.o \
|
||||
$(OBJDIR)/parameter.o \
|
||||
$(OBJDIR)/panel.o \
|
||||
$(OBJDIR)/priorityrequest.o \
|
||||
@ -262,6 +263,9 @@ $(OBJDIR)/testcontroller.o : $(DEVICE_SRC_DIR)/testcontroller.cpp $(DEVICE_SRC_
|
||||
$(OBJDIR)/unibusdevice.o : $(BASE_SRC_DIR)/unibusdevice.cpp $(BASE_SRC_DIR)/unibusdevice.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/unibuscpu.o : $(BASE_SRC_DIR)/unibuscpu.cpp $(BASE_SRC_DIR)/unibuscpu.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/device.o : $(BASE_SRC_DIR)/device.cpp $(BASE_SRC_DIR)/device.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
|
||||
@ -14,85 +14,89 @@
|
||||
14
|
||||
15 ; select one type of console at assembly time
|
||||
16 177560 dladr = 177560 ; base addr of DEC DL11 console
|
||||
17 ; dladr = 176500 ; DL11 #0
|
||||
17 ; dladr = 176500 ; DL11 #0
|
||||
18 ; dladr = 176510 ; DL11 #1
|
||||
19 ; dladr = 176520 ; DL11 #2
|
||||
20
|
||||
21
|
||||
22 000000 .=0
|
||||
23 000000 000137 001000 jmp @#start ; early emulation started code execution from 0
|
||||
23 000000 000137 001000 jmp @#start ; early emulation started code execution from 0
|
||||
24
|
||||
25 001000 .=1000
|
||||
26
|
||||
27 000776 stack = . - 2 ; stack growns down from start
|
||||
25 000024 .=24 ; If not HALTed: start on power-up
|
||||
26 000024 001000 .word start ; PC
|
||||
27 000026 000340 .word 340 ; PSW with priority level 7
|
||||
28
|
||||
29 start:
|
||||
30 001000 012706 000776 mov #stack,sp ; init stack
|
||||
31
|
||||
32 ; 1. print "Hello" msg
|
||||
33 001004 012701 001126 mov #shello,r1
|
||||
34 001010 004737 001054 call @#puts
|
||||
29 001000 .=1000
|
||||
30
|
||||
31 000776 stack = . - 2 ; stack growns down from start
|
||||
32
|
||||
33 start:
|
||||
34 001000 012706 000776 mov #stack,sp ; init stack
|
||||
35
|
||||
36 ; 2. echo chars until ^C hit
|
||||
37 1$:
|
||||
38 001014 004737 001110 call @#getc ; wait for char, return in r0
|
||||
39 001020 042700 177600 bic #177600,r0 ; make 7bit: clear bits <15:7>
|
||||
40 001024 120027 000003 cmpb r0,#3 ; break by ^C ?
|
||||
41 001030 001403 beq 2$ ; yes: leave loop
|
||||
42 001032 004737 001070 call @#putc ; no: echo char in r0 and loop
|
||||
43 001036 000766 br 1$
|
||||
44
|
||||
45 2$:
|
||||
46
|
||||
47 ; 3. print "Bye bye" msg and HALT
|
||||
48 001040 012701 001211 mov #sbye,r1
|
||||
49 001044 004737 001054 call @#puts
|
||||
50 001050 000000 halt
|
||||
51
|
||||
52 ; 4. loop on CONT
|
||||
53 001052 000752 br start
|
||||
54
|
||||
36 ; 1. print "Hello" msg
|
||||
37 001004 012701 001126 mov #shello,r1
|
||||
38 001010 004737 001054 call @#puts
|
||||
39
|
||||
40 ; 2. echo chars until ^C hit
|
||||
41 1$:
|
||||
42 001014 004737 001110 call @#getc ; wait for char, return in r0
|
||||
43 001020 042700 177600 bic #177600,r0 ; make 7bit: clear bits <15:7>
|
||||
44 001024 120027 000003 cmpb r0,#3 ; break by ^C ?
|
||||
45 001030 001403 beq 2$ ; yes: leave loop
|
||||
46 001032 004737 001070 call @#putc ; no: echo char in r0 and loop
|
||||
47 001036 000766 br 1$
|
||||
48
|
||||
49 2$:
|
||||
50
|
||||
51 ; 3. print "Bye bye" msg and HALT
|
||||
52 001040 012701 001211 mov #sbye,r1
|
||||
53 001044 004737 001054 call @#puts
|
||||
54 001050 000000 halt
|
||||
55
|
||||
56 ; ----------------------
|
||||
57 ; puts - print a string
|
||||
58 ; r1 = pointer, r0,r1 changed
|
||||
59 puts:
|
||||
60 001054 112100 movb (r1)+,r0 ; load xmt char
|
||||
61 001056 001403 beq 1$ ; string ends with 0
|
||||
62 001060 004737 001070 call @#putc
|
||||
63 001064 000773 br puts ; transmit nxt char of string
|
||||
64 001066 000207 1$: return
|
||||
65
|
||||
66
|
||||
67 ; ----------------------
|
||||
68 ; putc - output a single char
|
||||
69 ; r0 = char, r4 changed
|
||||
70 putc:
|
||||
71 001070 012704 177560 mov #dladr,r4 ; set base addr
|
||||
72 001074 110064 000006 movb r0,6(r4) ; char into transmit buffer
|
||||
73 001100 105764 000004 1$: tstb 4(r4) ; XMT RDY?
|
||||
74 001104 100375 bpl 1$ ; no, loop
|
||||
75 001106 000207 return
|
||||
76
|
||||
77 ; ----------------------
|
||||
78 ; getc - input a single char
|
||||
79 ; result in r0, r4 changed
|
||||
80 getc:
|
||||
81 001110 012704 177560 mov #dladr,r4 ; set base addr
|
||||
82 001114 105714 1$: tstb (r4) ; RCVR DONE?
|
||||
83 001116 100376 bpl 1$ ; no, loop
|
||||
84 001120 016400 000002 mov 2(r4),r0 ; return data
|
||||
85 001124 000207 return
|
||||
86
|
||||
87
|
||||
88 shello:
|
||||
89 001126 110 145 154 .ascii /Hello, World!/
|
||||
56 ; 4. loop on CONT
|
||||
57 001052 000752 br start
|
||||
58
|
||||
59
|
||||
60 ; ----------------------
|
||||
61 ; puts - print a string
|
||||
62 ; r1 = pointer, r0,r1 changed
|
||||
63 puts:
|
||||
64 001054 112100 movb (r1)+,r0 ; load xmt char
|
||||
65 001056 001403 beq 1$ ; string ends with 0
|
||||
66 001060 004737 001070 call @#putc
|
||||
67 001064 000773 br puts ; transmit nxt char of string
|
||||
68 001066 000207 1$: return
|
||||
69
|
||||
70
|
||||
71 ; ----------------------
|
||||
72 ; putc - output a single char
|
||||
73 ; r0 = char, r4 changed
|
||||
74 putc:
|
||||
75 001070 012704 177560 mov #dladr,r4 ; set base addr
|
||||
76 001074 110064 000006 movb r0,6(r4) ; char into transmit buffer
|
||||
77 001100 105764 000004 1$: tstb 4(r4) ; XMT RDY?
|
||||
78 001104 100375 bpl 1$ ; no, loop
|
||||
79 001106 000207 return
|
||||
80
|
||||
81 ; ----------------------
|
||||
82 ; getc - input a single char
|
||||
83 ; result in r0, r4 changed
|
||||
84 getc:
|
||||
85 001110 012704 177560 mov #dladr,r4 ; set base addr
|
||||
86 001114 105714 1$: tstb (r4) ; RCVR DONE?
|
||||
87 001116 100376 bpl 1$ ; no, loop
|
||||
88 001120 016400 000002 mov 2(r4),r0 ; return data
|
||||
89 001124 000207 return
|
||||
90
|
||||
91
|
||||
92 shello:
|
||||
93 001126 110 145 154 .ascii /Hello, World!/
|
||||
001131 154 157 054
|
||||
001134 040 127 157
|
||||
001137 162 154 144
|
||||
001142 041
|
||||
90 001143 015 012 .byte 15,12 ; CR, LF,
|
||||
91 001145 124 171 160 .ascii /Typed chars are echoed, ^C HALTs./
|
||||
94 001143 015 012 .byte 15,12 ; CR, LF,
|
||||
95 001145 124 171 160 .ascii /Typed chars are echoed, ^C HALTs./
|
||||
001150 145 144 040
|
||||
001153 143 150 141
|
||||
001156 162 163 040
|
||||
@ -103,13 +107,13 @@
|
||||
001175 136 103 040
|
||||
001200 110 101 114
|
||||
001203 124 163 056
|
||||
92 001206 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker
|
||||
93 sbye:
|
||||
94 001211 015 012 .byte 15,12
|
||||
95 001213 107 157 157 .ascii /Good bye!/
|
||||
96 001206 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker
|
||||
97 sbye:
|
||||
98 001211 015 012 .byte 15,12
|
||||
99 001213 107 157 157 .ascii /Good bye!/
|
||||
001216 144 040 142
|
||||
001221 171 145 041
|
||||
96 001224 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker
|
||||
97
|
||||
98 .end
|
||||
98
|
||||
100 001224 015 012 000 .byte 15,12,0 ; CR, LF, NUL=end marker
|
||||
101
|
||||
102 .end
|
||||
102
|
||||
|
||||
@ -14,13 +14,17 @@
|
||||
|
||||
; select one type of console at assembly time
|
||||
dladr = 177560 ; base addr of DEC DL11 console
|
||||
; dladr = 176500 ; DL11 #0
|
||||
; dladr = 176500 ; DL11 #0
|
||||
; dladr = 176510 ; DL11 #1
|
||||
; dladr = 176520 ; DL11 #2
|
||||
|
||||
|
||||
.=0
|
||||
jmp @#start ; early emulation started code execution from 0
|
||||
jmp @#start ; early emulation started code execution from 0
|
||||
|
||||
.=24 ; If not HALTed: start on power-up
|
||||
.word start ; PC
|
||||
.word 340 ; PSW with priority level 7
|
||||
|
||||
.=1000
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user