mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-03-10 12:29:22 +00:00
Better integration of CPU20 into UniBone framework
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
|
||||
|
||||
Class hierarchy for UniBone - devices
|
||||
|
||||
|
||||
TODO:
|
||||
devices.cpp -> unibus_device.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// base class, for uniform GUI interface
|
||||
class device_c {
|
||||
parameter_c <vector>
|
||||
|
||||
thread
|
||||
|
||||
name
|
||||
}
|
||||
|
||||
|
||||
// communicates with PRU over "unibusadapter"
|
||||
// - register accesses
|
||||
// - send interrupts
|
||||
// - initiate DMA
|
||||
//
|
||||
|
||||
class unibus_device_c::device_c {
|
||||
// 2nd thread for unibuown thr
|
||||
registers[]
|
||||
}
|
||||
|
||||
|
||||
// storage device. physical drive
|
||||
// simulates slow speed up, track-to-track search
|
||||
class diskdrive_c::device_c {
|
||||
bool attached ;
|
||||
bool readonly ;
|
||||
uint8_t unitnr ;
|
||||
image_filename ;
|
||||
}
|
||||
|
||||
|
||||
class diskcontroller_c::unibus_device {
|
||||
drive_count
|
||||
// list of drives, indexed by unit number
|
||||
diskdrives[]
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
|
||||
Implementation of a drive controeller, event based
|
||||
|
||||
|
||||
1) controller_c acceepts event callbacks
|
||||
|
||||
busevent (from unibusadapter)
|
||||
BUS_INIT, BUS_ACLO, DMA compelte, INTR accepted.
|
||||
|
||||
driveevent (from storage drive)
|
||||
status_change (needs drive status polling then)
|
||||
|
||||
parameter (from user GUI)
|
||||
parameter_changed
|
||||
|
||||
2) drive_c accepts event callbacks
|
||||
|
||||
parameter (from user GUI)
|
||||
parameter_changed
|
||||
|
||||
frontpanel (from lamps&switches logic)
|
||||
|
||||
command (from controeller)
|
||||
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ gpios_c *gpios; // Singleton
|
||||
|
||||
buslatches_t buslatches;
|
||||
|
||||
|
||||
gpios_c::gpios_c() {
|
||||
log_label = "GPIOS";
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ typedef struct {
|
||||
#define ARM_DEBUG_PIN2(n) GPIO_SETVAL(gpios->led[2], !!(n))
|
||||
#define ARM_DEBUG_PIN3(n) GPIO_SETVAL(gpios->led[3], !!(n))
|
||||
|
||||
|
||||
class gpios_c: public logsource_c {
|
||||
private:
|
||||
void bank_map_registers(unsigned bank_idx, unsigned unmapped_start_addr);
|
||||
|
||||
@@ -103,7 +103,7 @@ unibusadapter_c::unibusadapter_c() :
|
||||
|
||||
requests_init();
|
||||
|
||||
the_cpu = NULL;
|
||||
registered_cpu = NULL;
|
||||
}
|
||||
|
||||
bool unibusadapter_c::on_param_changed(parameter_c *param) {
|
||||
@@ -235,8 +235,8 @@ bool unibusadapter_c::register_device(unibusdevice_c& device) {
|
||||
// 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;
|
||||
assert(registered_cpu == NULL); // only one allowed!
|
||||
registered_cpu = cpu;
|
||||
mailbox->cpu_enable = 1 ;
|
||||
mailbox_execute(ARM2PRU_CPU_ENABLE) ;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ void unibusadapter_c::unregister_device(unibusdevice_c& device) {
|
||||
if (cpu) {
|
||||
mailbox->cpu_enable = 0;
|
||||
mailbox_execute(ARM2PRU_CPU_ENABLE);
|
||||
the_cpu = NULL;
|
||||
registered_cpu = NULL;
|
||||
}
|
||||
|
||||
// remove "from backplane"
|
||||
@@ -1159,9 +1159,9 @@ void unibusadapter_c::worker(unsigned instance) {
|
||||
|
||||
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
|
||||
assert(registered_cpu); // if INTR events are enabled, cpu must be instantiated
|
||||
// see register_device()
|
||||
the_cpu->on_interrupt(mailbox->events.intr_slave.vector);
|
||||
registered_cpu->on_interrupt(mailbox->events.intr_slave.vector);
|
||||
// clear SSYN, INTR cycle completes
|
||||
EVENT_ACK(*mailbox, intr_slave);
|
||||
// mailbox->arbitrator.cpu_priority_level now CPU_PRIORITY_LEVEL_FETCHING
|
||||
|
||||
@@ -64,7 +64,7 @@ private:
|
||||
|
||||
pthread_mutex_t requests_mutex;
|
||||
|
||||
unibuscpu_c *the_cpu ; // only one unibuscpu_c may be registered
|
||||
unibuscpu_c *registered_cpu ; // only one unibuscpu_c may be registered
|
||||
|
||||
void worker_init_event(void);
|
||||
void worker_power_event(bool power_down);
|
||||
|
||||
@@ -32,13 +32,13 @@ void unibuscpu_c::on_power_changed(void) {
|
||||
if (power_down) { // power-on defaults
|
||||
INFO("CPU: ACLO failed");
|
||||
power_event = power_event_down;
|
||||
// ka11_pwrdown(&the_cpu->ka11);
|
||||
// ka11_pwrdown(&unibone_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);
|
||||
// ka11_pwrup(&unibone_cpu->ka11);
|
||||
// DCLO restored
|
||||
// CPU loads PC and PSW from vector 24
|
||||
// if HALTed: do nothing, user is expected to setup PC and PSW ?
|
||||
|
||||
@@ -177,12 +177,14 @@ void main(void) {
|
||||
|
||||
if (emulate_cpu) {
|
||||
// Receive INTR from physical or emulated devices, and signal ARM.
|
||||
// Same code loop as for DATA cycle
|
||||
if (!sm_intr_slave_state)
|
||||
sm_intr_slave_state = (statemachine_state_func) &sm_intr_slave_start;
|
||||
sm_intr_slave_state = sm_intr_slave_state() ;
|
||||
/*
|
||||
while ((sm_intr_slave_state = sm_intr_slave_state())
|
||||
&& EVENT_IS_ACKED(mailbox, intr_slave))
|
||||
;
|
||||
*/
|
||||
}
|
||||
|
||||
// process ARM commands in master and slave mode
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "mailbox.h"
|
||||
#include "gpios.hpp" // ARM_DEBUG_PIN*
|
||||
|
||||
#include "unibus.h"
|
||||
|
||||
@@ -36,12 +38,79 @@
|
||||
#include "unibusdevice.hpp" // definition of class device_c
|
||||
#include "cpu.hpp"
|
||||
|
||||
/* Adapter procs to Angelos CPU are not members of cpu_c calss
|
||||
int dbg = 0;
|
||||
|
||||
/*** functions to be used by Angelos CPU emulator ***/
|
||||
|
||||
/* Adapter procs to Angelos CPU are not members of cpu_c class
|
||||
and need one global reference.
|
||||
*/
|
||||
static cpu_c *the_cpu = NULL;
|
||||
static cpu_c *unibone_cpu = NULL;
|
||||
|
||||
int dbg = 0;
|
||||
// route "trace()" to unibone_cpu->logger
|
||||
void unibone_log(unsigned msglevel, const char *srcfilename, unsigned srcline, const char *fmt,
|
||||
...) {
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, fmt);
|
||||
//vprintf(fmt, arg_ptr) ;
|
||||
//va_end(arg_ptr); va_start(arg_ptr, fmt);
|
||||
logger->vlog(unibone_cpu, msglevel, srcfilename, srcline, fmt, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
}
|
||||
|
||||
|
||||
void unibone_logdump(void) {
|
||||
// logger->dump(logger->default_filepath);
|
||||
logger->dump(); // stdout
|
||||
}
|
||||
|
||||
// Result: 1 = OK, 0 = bus timeout
|
||||
int unibone_dato(unsigned addr, unsigned data) {
|
||||
uint16_t wordbuffer = (uint16_t) data;
|
||||
|
||||
dbg = 1;
|
||||
unibusadapter->cpu_DATA_transfer(unibone_cpu->data_transfer_request, UNIBUS_CONTROL_DATO,
|
||||
addr, &wordbuffer);
|
||||
dbg = 0;
|
||||
return unibone_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(unibone_cpu->data_transfer_request, UNIBUS_CONTROL_DATOB,
|
||||
addr, &wordbuffer);
|
||||
dbg = 0;
|
||||
return unibone_cpu->data_transfer_request.success;
|
||||
}
|
||||
|
||||
int unibone_dati(unsigned addr, unsigned *data) {
|
||||
uint16_t wordbuffer;
|
||||
dbg = 1;
|
||||
unibusadapter->cpu_DATA_transfer(unibone_cpu->data_transfer_request, UNIBUS_CONTROL_DATI,
|
||||
addr, &wordbuffer);
|
||||
*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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// CPU executes RESET opcode -> pulses INIT line
|
||||
void unibone_bus_init(unsigned pulsewidth_ms) {
|
||||
unibus->init(pulsewidth_ms);
|
||||
}
|
||||
|
||||
cpu_c::cpu_c() :
|
||||
unibuscpu_c() // super class constructor
|
||||
@@ -67,12 +136,13 @@ cpu_c::cpu_c() :
|
||||
memset(&ka11, 0, sizeof(ka11));
|
||||
ka11.bus = &bus;
|
||||
|
||||
assert(the_cpu == NULL); // only one possible
|
||||
the_cpu = this; // Singleton
|
||||
// link to global instance ptr
|
||||
assert(unibone_cpu == NULL);// only one possible
|
||||
unibone_cpu = this; // Singleton
|
||||
}
|
||||
|
||||
cpu_c::~cpu_c() {
|
||||
the_cpu = NULL;
|
||||
unibone_cpu = NULL;
|
||||
}
|
||||
|
||||
bool cpu_c::on_param_changed(parameter_c *param) {
|
||||
@@ -90,42 +160,47 @@ bool cpu_c::on_param_changed(parameter_c *param) {
|
||||
void cpu_c::worker(unsigned instance) {
|
||||
UNUSED(instance); // only one
|
||||
timeout_c timeout;
|
||||
bool nxm;
|
||||
unsigned pc = 0;
|
||||
unsigned dr = 0760102;
|
||||
// bool nxm;
|
||||
// unsigned pc = 0;
|
||||
//unsigned dr = 0760102;
|
||||
unsigned opcode = 0;
|
||||
(void) opcode;
|
||||
|
||||
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);
|
||||
while (!workers_terminate) {
|
||||
// run full speed!
|
||||
// speed control is diffiuclt, force to use more ARM cycles
|
||||
timeout.wait_us(1);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
||||
// timeout.wait_ms(10);
|
||||
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]);
|
||||
}
|
||||
|
||||
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(&the_cpu->ka11);
|
||||
// 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(&the_cpu->ka11);
|
||||
power_event = power_event_none; // processed
|
||||
}
|
||||
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;
|
||||
if (init.value) {
|
||||
// user wants CPU reset
|
||||
ka11_reset(&ka11);
|
||||
init.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -175,55 +250,6 @@ void cpu_c::on_interrupt(uint16_t vector) {
|
||||
// push PC to stack
|
||||
// PC := *vector
|
||||
// PSW := *(vector+2)
|
||||
ka11_setintr(&the_cpu->ka11, vector);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// functions to be used by Angelos CPU emulator
|
||||
// Result: 1 = OK, 0 = bus timeout
|
||||
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;
|
||||
}
|
||||
|
||||
// CPU executes RESET opcode -> pulses INIT line
|
||||
void unibone_bus_init(unsigned pulsewidth_ms) {
|
||||
unibus->init(pulsewidth_ms);
|
||||
}
|
||||
ka11_setintr(&unibone_cpu->ka11, vector);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,8 @@ using namespace std;
|
||||
//#include "unibusadapter.hpp"
|
||||
//#include "unibusdevice.hpp"
|
||||
#include "unibuscpu.hpp"
|
||||
extern "C" {
|
||||
#include "cpu20/11.h"
|
||||
#include "cpu20/ka11.h"
|
||||
}
|
||||
|
||||
class cpu_c: public unibuscpu_c {
|
||||
private:
|
||||
@@ -58,7 +56,7 @@ public:
|
||||
parameter_bool_c init = parameter_bool_c(this, "init", "i",/*readonly*/
|
||||
false, "1 = CPU initializing");
|
||||
|
||||
struct Bus bus; // UNIBU Sinterface of CPU
|
||||
struct Bus bus; // UNIBUS interface of CPU
|
||||
struct KA11 ka11; // Angelos CPU state
|
||||
|
||||
// background worker function
|
||||
@@ -68,9 +66,8 @@ public:
|
||||
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)
|
||||
override;
|
||||
|
||||
void on_interrupt(uint16_t vector) ;
|
||||
|
||||
void on_interrupt(uint16_t vector);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,12 @@ typedef uint32_t uint32;
|
||||
|
||||
|
||||
//#define trace printf
|
||||
#define trace(...)
|
||||
//#define trace(...)
|
||||
// route "trace()" to unibone_cpu->logger
|
||||
void unibone_log(unsigned msglevel, const char *srcfilename, unsigned srcline, const char *fmt, ...) ;
|
||||
void unibone_logdump(void);
|
||||
#define LL_DEBUG 5 // see logger.hpp
|
||||
#define trace(...) unibone_log(LL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
int hasinput(int fd);
|
||||
int dial(char *host, int port);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "11.h"
|
||||
#include "ka11.h"
|
||||
|
||||
#include "gpios.hpp" // ARM_DEBUG_PIN*
|
||||
|
||||
int unibone_dato(unsigned addr, unsigned data);
|
||||
int unibone_datob(unsigned addr, unsigned data);
|
||||
int unibone_dati(unsigned addr, unsigned *data);
|
||||
@@ -12,7 +14,7 @@ int
|
||||
dati_bus(Bus *bus)
|
||||
{
|
||||
unsigned int data;
|
||||
if(!unibone_dati(bus->addr, &data))
|
||||
if(!unibone_dati(bus->addr, &data))
|
||||
return 1;
|
||||
bus->data = data;
|
||||
return 0;
|
||||
@@ -129,9 +131,12 @@ ka11_reset(KA11 *cpu)
|
||||
int
|
||||
dati(KA11 *cpu, int b)
|
||||
{
|
||||
trace("dati %06o: ", cpu->ba);
|
||||
if(!b && cpu->ba&1)
|
||||
trace("dati %06o:\n", cpu->ba);
|
||||
if(!b && cpu->ba&1) {
|
||||
//ARM_DEBUG_PIN0(1) ;
|
||||
//unibone_logdump() ; // write trace() output to file
|
||||
goto be;
|
||||
}
|
||||
|
||||
/* internal registers */
|
||||
if((cpu->ba&0177400) == 0177400){
|
||||
|
||||
@@ -216,7 +216,7 @@ $(OBJDIR)/cpu.o : $(DEVICE_SRC_DIR)/cpu.cpp $(DEVICE_SRC_DIR)/cpu.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
$(OBJDIR)/ka11.o : $(DEVICE_SRC_DIR)/cpu20/ka11.c $(DEVICE_SRC_DIR)/cpu20/ka11.h
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
$(CC) $(CCFLAGS) -x c++ -Wno-parentheses $< -o $@
|
||||
|
||||
$(OBJDIR)/rl0102.o : $(DEVICE_SRC_DIR)/rl0102.cpp $(DEVICE_SRC_DIR)/rl0102.hpp
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
Reference in New Issue
Block a user