Merge branch 'master' into d_i
This commit is contained in:
commit
2fd1da58bb
17 changed files with 541 additions and 377 deletions
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
github: [folkertvanheusden]
|
||||
patreon: folkertvanheusden
|
|
@ -102,7 +102,7 @@ void console_esp32::panel_update_thread()
|
|||
int run_mode = current_PSW >> 14;
|
||||
|
||||
uint16_t current_PC = c->getPC();
|
||||
uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true);
|
||||
uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, false);
|
||||
|
||||
uint16_t current_instr = b->readWord(current_PC);
|
||||
|
||||
|
|
|
@ -181,14 +181,14 @@ void setup() {
|
|||
Serial.println(F("Connect CPU to BUS"));
|
||||
b->add_cpu(c);
|
||||
|
||||
Serial.println(F("Start line-frequency interrupt"));
|
||||
kw11_l *lf = new kw11_l(b);
|
||||
|
||||
c->setEmulateMFPT(true);
|
||||
|
||||
Serial.println(F("Init console"));
|
||||
cnsl = new console_esp32(&stop_event, b);
|
||||
|
||||
Serial.println(F("Start line-frequency interrupt"));
|
||||
kw11_l *lf = new kw11_l(b, cnsl);
|
||||
|
||||
running = cnsl->get_running_flag();
|
||||
|
||||
Serial.println(F("Init TTY"));
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[platformio]
|
||||
default_envs = serial32
|
||||
default_envs = ESP32
|
||||
src_dir = .
|
||||
|
||||
[env:serial32]
|
||||
[env:ESP32]
|
||||
lib_ldf_mode = deep+
|
||||
src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
|
||||
platform = espressif32
|
||||
board = wemos_d1_mini32
|
||||
framework = arduino
|
||||
|
@ -14,3 +14,16 @@ lib_deps = greiman/SdFat@^2.1.2
|
|||
adafruit/Adafruit NeoPixel@^1.10.4
|
||||
build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
|
||||
build_unflags = -std=gnu++11 -Os
|
||||
|
||||
#[env:PICO]
|
||||
#lib_ldf_mode = deep+
|
||||
#src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
|
||||
#platform = raspberrypi
|
||||
#board = pico
|
||||
#framework = arduino
|
||||
#monitor_speed = 115200
|
||||
#upload_speed = 1000000
|
||||
#lib_deps = greiman/SdFat@^2.1.2
|
||||
# adafruit/Adafruit NeoPixel@^1.10.4
|
||||
#build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
|
||||
#build_unflags = -std=gnu++11 -Os
|
||||
|
|
514
bus.cpp
514
bus.cpp
|
@ -20,6 +20,7 @@ constexpr int n_pages = 12;
|
|||
constexpr int n_pages = 16;
|
||||
#endif
|
||||
|
||||
constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 };
|
||||
|
||||
bus::bus()
|
||||
{
|
||||
|
@ -51,198 +52,188 @@ void bus::init()
|
|||
MMR3 = 0;
|
||||
}
|
||||
|
||||
uint16_t bus::read_pdr(const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only)
|
||||
{
|
||||
bool is_11_34 = c->get_34();
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[run_mode][is_d][page].pdr;
|
||||
|
||||
DOLOG(debug, !peek_only, "read run-mode %d: %c PDR for %d: %o", run_mode, is_d ? 'D' : 'I', page, t);
|
||||
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
|
||||
uint16_t bus::read_par(const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only)
|
||||
{
|
||||
bool is_11_34 = c->get_34();
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[run_mode][is_d][page].par;
|
||||
|
||||
DOLOG(debug, !peek_only, "read run-mode %d: %c PAR for %d: %o (phys: %07o)", run_mode, is_d ? 'D' : 'I', page, t, t * 64);
|
||||
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
|
||||
uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, const bool peek_only, const d_i_space_t space)
|
||||
{
|
||||
uint16_t temp = 0;
|
||||
|
||||
if (a >= 0160000) {
|
||||
bool is_11_34 = c->get_34();
|
||||
|
||||
if (word_mode)
|
||||
DOLOG(debug, false, "READ I/O %06o in byte mode", a);
|
||||
|
||||
if (a == 0177750) { // MAINT
|
||||
if (a == ADDR_MAINT) { // MAINT
|
||||
DOLOG(debug, !peek_only, "read MAINT");
|
||||
return 1; // POWER OK
|
||||
}
|
||||
|
||||
if (a == 0177570) { // console switch & display register
|
||||
DOLOG(debug, !peek_only, "read console switch");
|
||||
if (a == ADDR_CONSW) { // console switch & display register
|
||||
DOLOG(debug, !peek_only, "read console switch (%06o)", console_switches);
|
||||
|
||||
return debug_mode ? 128 : 0;
|
||||
return console_switches;
|
||||
}
|
||||
|
||||
if (a == 0172540) { // KW11P programmable clock
|
||||
if (a == ADDR_KW11P) { // KW11P programmable clock
|
||||
DOLOG(debug, !peek_only, "read programmable clock");
|
||||
return 128;
|
||||
}
|
||||
|
||||
if (a == 0177772) { // PIR
|
||||
if (a == ADDR_PIR) { // PIR
|
||||
DOLOG(debug, !peek_only, "read PIT");
|
||||
return PIR;
|
||||
}
|
||||
|
||||
if (a == 0177546) { // line frequency clock and status register
|
||||
if (a == ADDR_LFC) { // line frequency clock and status register
|
||||
DOLOG(debug, !peek_only, "read line freq clock");
|
||||
return lf_csr;
|
||||
}
|
||||
|
||||
if (a == 0177514) { // printer, CSR register, LP11
|
||||
if (a == ADDR_LP11CSR) { // printer, CSR register, LP11
|
||||
DOLOG(debug, !peek_only, "read LP11 CSR");
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
/// MMU ///
|
||||
if (a >= 0172200 && a < 0172240) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[001][is_d][page].pdr;
|
||||
DOLOG(debug, !peek_only, "read supervisor %c PDR for %d: %o", is_d ? 'D' : 'I', page, t);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
else if (a >= 0172240 && a < 0172300) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[001][is_d][page].par;
|
||||
DOLOG(debug, !peek_only, "read supervisor %c PAR for %d: %o (phys: %07o)", is_d ? 'D' : 'I', page, t, t * 64);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
else if (a >= 0172300 && a < 0172340) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[000][is_d][page].pdr;
|
||||
DOLOG(debug, !peek_only, "read kernel %c PDR for %d: %o", is_d ? 'D' : 'I', page, t);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
else if (a >= 0172340 && a < 0172400) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[000][is_d][page].par;
|
||||
DOLOG(debug, !peek_only, "read kernel %c PAR for %d: %o (phys: %07o)", is_d ? 'D' : 'I', page, t, t * 64);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
else if (a >= 0177600 && a < 0177640) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[003][is_d][page].pdr;
|
||||
DOLOG(debug, !peek_only, "read userspace %c PDR for %d: %o", is_d ? 'D' : 'I', page, t);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
else if (a >= 0177640 && a < 0177700) {
|
||||
int page = (a >> 1) & 7;
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
uint16_t t = pages[003][is_d][page].par;
|
||||
DOLOG(debug, !peek_only, "read userspace %c PAR for %d: %o (phys: %07o)", is_d ? 'D' : 'I', page, t, t * 64);
|
||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
||||
}
|
||||
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
|
||||
return read_pdr(a, 1, word_mode, peek_only);
|
||||
else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
|
||||
return read_par(a, 1, word_mode, peek_only);
|
||||
else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
|
||||
return read_pdr(a, 0, word_mode, peek_only);
|
||||
else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
|
||||
return read_par(a, 0, word_mode, peek_only);
|
||||
else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
|
||||
return read_pdr(a, 3, word_mode, peek_only);
|
||||
else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
|
||||
return read_par(a, 3, word_mode, peek_only);
|
||||
///////////
|
||||
|
||||
if (word_mode) {
|
||||
if (a == 0177776) { // PSW
|
||||
if (a == ADDR_PSW) { // PSW
|
||||
DOLOG(debug, !peek_only, "readb PSW LSB");
|
||||
return c -> getPSW() & 255;
|
||||
}
|
||||
|
||||
if (a == 0177777) {
|
||||
if (a == ADDR_PSW + 1) {
|
||||
DOLOG(debug, !peek_only, "readb PSW MSB");
|
||||
return c -> getPSW() >> 8;
|
||||
}
|
||||
|
||||
if (a == 0177774) { // stack limit register
|
||||
if (a == ADDR_STACKLIM) { // stack limit register
|
||||
DOLOG(debug, !peek_only, "readb stack limit register");
|
||||
return c -> getStackLimitRegister() & 0xff;
|
||||
}
|
||||
if (a == 0177775) { // stack limit register
|
||||
if (a == ADDR_STACKLIM + 1) { // stack limit register
|
||||
DOLOG(debug, !peek_only, "readb stack limit register");
|
||||
return c -> getStackLimitRegister() >> 8;
|
||||
}
|
||||
|
||||
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||
DOLOG(debug, !peek_only, "readb kernel R%d", a - 0177700);
|
||||
return c -> getRegister(a - 0177700, 0, false) & 0xff;
|
||||
if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
|
||||
DOLOG(debug, !peek_only, "readb kernel R%d", a - ADDR_KERNEL_R);
|
||||
return c -> getRegister(a - ADDR_KERNEL_R, 0, false) & 0xff;
|
||||
}
|
||||
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||
DOLOG(debug, !peek_only, "readb user R%d", a - 0177710);
|
||||
return c -> getRegister(a - 0177710, 3, false) & 0xff;
|
||||
if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
|
||||
DOLOG(debug, !peek_only, "readb user R%d", a - ADDR_USER_R);
|
||||
return c -> getRegister(a - ADDR_USER_R, 3, false) & 0xff;
|
||||
}
|
||||
if (a == 0177706) { // kernel SP
|
||||
if (a == ADDR_KERNEL_SP) { // kernel SP
|
||||
DOLOG(debug, !peek_only, "readb kernel sp");
|
||||
return c -> getStackPointer(0) & 0xff;
|
||||
}
|
||||
if (a == 0177707) { // PC
|
||||
if (a == ADDR_PC) { // PC
|
||||
DOLOG(debug, !peek_only, "readb pc");
|
||||
return c -> getPC() & 0xff;
|
||||
}
|
||||
if (a == 0177716) { // supervisor SP
|
||||
if (a == ADDR_SV_SP) { // supervisor SP
|
||||
DOLOG(debug, !peek_only, "readb supervisor sp");
|
||||
return c -> getStackPointer(1) & 0xff;
|
||||
}
|
||||
if (a == 0177717) { // user SP
|
||||
if (a == ADDR_USER_SP) { // user SP
|
||||
DOLOG(debug, !peek_only, "readb user sp");
|
||||
return c -> getStackPointer(3) & 0xff;
|
||||
}
|
||||
|
||||
if (a == 0177766) { // cpu error register
|
||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||
DOLOG(debug, !peek_only, "readb cpuerr");
|
||||
return CPUERR & 0xff;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (a == 0177572) {
|
||||
if (a == ADDR_MMR0) {
|
||||
DOLOG(debug, !peek_only, "read MMR0");
|
||||
return MMR0;
|
||||
}
|
||||
|
||||
if (a == 0177574) { // MMR1
|
||||
if (a == ADDR_MMR1) { // MMR1
|
||||
DOLOG(debug, !peek_only, "read MMR1");
|
||||
return MMR1;
|
||||
}
|
||||
|
||||
if (a == 0177576) { // MMR2
|
||||
if (a == ADDR_MMR2) { // MMR2
|
||||
DOLOG(debug, !peek_only, "read MMR2");
|
||||
return MMR2;
|
||||
}
|
||||
|
||||
if (a == 0172516) { // MMR3
|
||||
if (a == ADDR_MMR3) { // MMR3
|
||||
DOLOG(debug, !peek_only, "read MMR3");
|
||||
return MMR3;
|
||||
}
|
||||
|
||||
if (a == 0177776) { // PSW
|
||||
if (a == ADDR_PSW) { // PSW
|
||||
DOLOG(debug, !peek_only, "read PSW");
|
||||
return c -> getPSW();
|
||||
}
|
||||
|
||||
if (a == 0177774) { // stack limit register
|
||||
if (a == ADDR_STACKLIM) { // stack limit register
|
||||
return c -> getStackLimitRegister();
|
||||
}
|
||||
|
||||
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||
DOLOG(debug, !peek_only, "read kernel R%d", a - 0177700);
|
||||
return c -> getRegister(a - 0177700, 0, false);
|
||||
if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
|
||||
DOLOG(debug, !peek_only, "read kernel R%d", a - ADDR_KERNEL_R);
|
||||
return c -> getRegister(a - ADDR_KERNEL_R, 0, false);
|
||||
}
|
||||
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||
DOLOG(debug, !peek_only, "read user R%d", a - 0177710);
|
||||
return c -> getRegister(a - 0177710, 3, false);
|
||||
if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
|
||||
DOLOG(debug, !peek_only, "read user R%d", a - ADDR_USER_R);
|
||||
return c -> getRegister(a - ADDR_USER_R, 3, false);
|
||||
}
|
||||
if (a == 0177706) { // kernel SP
|
||||
if (a == ADDR_KERNEL_SP) { // kernel SP
|
||||
DOLOG(debug, !peek_only, "read kernel sp");
|
||||
return c -> getStackPointer(0);
|
||||
}
|
||||
if (a == 0177707) { // PC
|
||||
if (a == ADDR_PC) { // PC
|
||||
DOLOG(debug, !peek_only, "read pc");
|
||||
return c -> getPC();
|
||||
}
|
||||
if (a == 0177716) { // supervisor SP
|
||||
if (a == ADDR_SV_SP) { // supervisor SP
|
||||
DOLOG(debug, !peek_only, "read supervisor sp");
|
||||
return c -> getStackPointer(1);
|
||||
}
|
||||
if (a == 0177717) { // user SP
|
||||
if (a == ADDR_USER_SP) { // user SP
|
||||
DOLOG(debug, !peek_only, "read user sp");
|
||||
return c -> getStackPointer(3);
|
||||
}
|
||||
|
||||
if (a == 0177766) { // cpu error register
|
||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||
DOLOG(debug, !peek_only, "read CPUERR");
|
||||
return CPUERR;
|
||||
}
|
||||
|
@ -267,10 +258,10 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev,
|
|||
// LO size register field must be all 1s, so subtract 1
|
||||
constexpr uint32_t system_size = n_pages * 8192 / 64 - 1;
|
||||
|
||||
if (a == 0177762) // system size HI
|
||||
if (a == ADDR_SYSSIZE + 2) // system size HI
|
||||
return system_size >> 16;
|
||||
|
||||
if (a == 0177760) // system size LO
|
||||
if (a == ADDR_SYSSIZE) // system size LO
|
||||
return system_size & 65535;
|
||||
|
||||
if (a & 1)
|
||||
|
@ -278,12 +269,10 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev,
|
|||
|
||||
DOLOG(debug, !peek_only, "UNHANDLED read %o(%c)", a, word_mode ? 'B' : ' ');
|
||||
|
||||
// c -> busError();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3;
|
||||
int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3;
|
||||
|
||||
uint32_t m_offset = calculate_physical_address(run_mode, a, !peek_only, false, peek_only, space == d_space);
|
||||
|
||||
|
@ -322,6 +311,14 @@ void bus::setMMR0Bit(const int bit)
|
|||
MMR0 |= 1 << bit;
|
||||
}
|
||||
|
||||
void bus::clearMMR0Bit(const int bit)
|
||||
{
|
||||
assert(bit != 10 && bit != 11);
|
||||
assert(bit < 16 && bit >= 0);
|
||||
|
||||
MMR0 &= ~(1 << bit);
|
||||
}
|
||||
|
||||
void bus::setMMR2(const uint16_t value)
|
||||
{
|
||||
MMR2 = value;
|
||||
|
@ -329,12 +326,11 @@ void bus::setMMR2(const uint16_t value)
|
|||
|
||||
uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const bool peek_only, const bool is_data)
|
||||
{
|
||||
uint32_t m_offset = 0;
|
||||
uint32_t m_offset = a;
|
||||
|
||||
if (MMR0 & 1) {
|
||||
const uint8_t apf = a >> 13; // active page field
|
||||
|
||||
constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 };
|
||||
bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false;
|
||||
|
||||
uint16_t p_offset = a & 8191; // page offset
|
||||
|
@ -343,88 +339,119 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
|||
|
||||
m_offset += p_offset;
|
||||
|
||||
if ((MMR3 & 16) == 0) // off is 18bit
|
||||
m_offset &= 0x3ffff;
|
||||
|
||||
if (trap_on_failure) {
|
||||
if ((MMR0 & (1 << 9)) || c->get_34()) {
|
||||
const int access_control = pages[run_mode][0][apf].pdr & 7;
|
||||
const int access_control = pages[run_mode][d][apf].pdr & 7;
|
||||
|
||||
if (is_write && access_control != 6) { // write
|
||||
DOLOG(info, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a);
|
||||
DOLOG(debug, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a);
|
||||
|
||||
c->schedule_trap(0250); // invalid address
|
||||
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
||||
if (is_write)
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
||||
|
||||
MMR0 |= 1 << 13; // read-only
|
||||
if ((MMR0 & 0160000) == 0) {
|
||||
MMR0 &= 017777;
|
||||
MMR0 |= 1 << 13; // read-only
|
||||
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode?
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode?
|
||||
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
}
|
||||
|
||||
DOLOG(debug, true, "MMR0: %06o", MMR0);
|
||||
|
||||
throw 1;
|
||||
}
|
||||
else if (!is_write) { // read
|
||||
if (access_control == 0 || access_control == 1 || access_control == 3 || access_control == 4 || access_control == 7) {
|
||||
DOLOG(info, true, "TRAP(4) (throw 2) for access_control %d on address %06o", access_control, a);
|
||||
DOLOG(debug, true, "TRAP(4) (throw 2) for access_control %d on address %06o", access_control, a);
|
||||
|
||||
c->schedule_trap(0250); // invalid address
|
||||
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
||||
if (is_write)
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
||||
|
||||
MMR0 |= 1 << 13; // read-only
|
||||
if ((MMR0 & 0160000) == 0) {
|
||||
MMR0 &= 017777;
|
||||
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5;
|
||||
if (access_control == 0 || access_control == 4)
|
||||
MMR0 |= 1 << 15; // not resident
|
||||
else
|
||||
MMR0 |= 1 << 13; // read-only
|
||||
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5;
|
||||
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
}
|
||||
|
||||
throw 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t pdr_len = (((pages[run_mode][d][apf].pdr >> 8) & 127) + 1) * 64;
|
||||
|
||||
bool direction = pages[run_mode][d][apf].pdr & 8;
|
||||
|
||||
if (m_offset >= n_pages * 8192) {
|
||||
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192);
|
||||
DOLOG(info, true, "TRAP(04) (throw 3) on address %06o", a);
|
||||
DOLOG(debug, true, "TRAP(04) (throw 3) on address %06o", a);
|
||||
|
||||
MMR0 |= 1 << 15; // non-resident
|
||||
if ((MMR0 & 0160000) == 0) {
|
||||
MMR0 &= 017777;
|
||||
MMR0 |= 1 << 15; // non-resident
|
||||
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5;
|
||||
}
|
||||
|
||||
if (is_write)
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7; // TODO: D/I
|
||||
|
||||
pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I
|
||||
//
|
||||
c->schedule_trap(04);
|
||||
|
||||
throw 3;
|
||||
}
|
||||
|
||||
if ((p_offset > pdr_len && direction == false) || (p_offset < pdr_len && direction == true)) {
|
||||
DOLOG(debug, !peek_only, "bus::calculate_physical_address::p_offset %o >= %o", p_offset, pdr_len);
|
||||
DOLOG(info, true, "TRAP(0250) (throw 4) on address %06o", a);
|
||||
uint16_t pdr_len = (pages[run_mode][d][apf].pdr >> 8) & 127;
|
||||
uint16_t pdr_cmp = (a >> 6) & 127;
|
||||
|
||||
bool direction = pages[run_mode][d][apf].pdr & 8; // TODO: D/I
|
||||
|
||||
// DOLOG(debug, true, "p_offset %06o pdr_len %06o direction %d, run_mode %d, apf %d, pdr: %06o", p_offset, pdr_len, direction, run_mode, apf, pages[run_mode][d][apf].pdr);
|
||||
|
||||
if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) {
|
||||
DOLOG(debug, !peek_only, "bus::calculate_physical_address::p_offset %o versus %o direction %d", pdr_cmp, pdr_len, direction);
|
||||
DOLOG(debug, true, "TRAP(0250) (throw 4) on address %06o", a);
|
||||
c->schedule_trap(0250); // invalid access
|
||||
|
||||
MMR0 |= 1 << 14; // length
|
||||
if ((MMR0 & 0160000) == 0) {
|
||||
MMR0 &= 017777;
|
||||
MMR0 |= 1 << 14; // length
|
||||
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
MMR0 &= ~14; // add current page
|
||||
MMR0 |= apf << 1;
|
||||
|
||||
pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I
|
||||
MMR0 &= ~(3 << 5);
|
||||
MMR0 |= run_mode << 5;
|
||||
}
|
||||
|
||||
if (is_write)
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7; // TODO: D/I
|
||||
|
||||
throw 4;
|
||||
}
|
||||
}
|
||||
|
||||
DOLOG(debug, !peek_only, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d)", a, m_offset, run_mode, apf, pages[run_mode][0][apf].par * 64, p_offset, pages[run_mode][0][apf].pdr & 7); // TODO: D/I
|
||||
}
|
||||
else {
|
||||
m_offset = a;
|
||||
DOLOG(debug, !peek_only, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d)", a, m_offset, run_mode, apf, pages[run_mode][d][apf].par * 64, p_offset, pages[run_mode][d][apf].pdr & 7); // TODO: D/I
|
||||
}
|
||||
|
||||
return m_offset;
|
||||
|
@ -443,27 +470,70 @@ void bus::addToMMR1(const int8_t delta, const uint8_t reg)
|
|||
MMR1 |= reg;
|
||||
}
|
||||
|
||||
void bus::write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode)
|
||||
{
|
||||
bool is_11_34 = c->get_34();
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[run_mode][is_d][page].pdr &= 0xff, pages[run_mode][is_d][page].pdr |= value << 8) :
|
||||
(pages[run_mode][is_d][page].pdr &= 0xff00, pages[run_mode][is_d][page].pdr |= value);
|
||||
}
|
||||
else {
|
||||
pages[run_mode][is_d][page].pdr = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has no cache bit
|
||||
pages[run_mode][is_d][page].pdr &= 077416;
|
||||
else
|
||||
pages[run_mode][is_d][page].pdr &= ~(128 + 64 + 32 + 16); // set bit 4 & 5 to 0 as they are unused and A/W are set to 0 by writes
|
||||
|
||||
DOLOG(debug, true, "write run-mode %d: %c PDR for %d: %o [%d]", run_mode, is_d ? 'D' : 'I', page, value, word_mode);
|
||||
}
|
||||
|
||||
void bus::write_par(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode)
|
||||
{
|
||||
bool is_11_34 = c->get_34();
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[run_mode][is_d][page].par &= 0xff, pages[run_mode][is_d][page].par |= value << 8) :
|
||||
(pages[run_mode][is_d][page].par &= 0xff00, pages[run_mode][is_d][page].par |= value);
|
||||
}
|
||||
else {
|
||||
pages[run_mode][is_d][page].par = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has 12 bit PARs
|
||||
pages[run_mode][is_d][page].par &= 4095;
|
||||
|
||||
DOLOG(debug, true, "write run-mode %d: %c PAR for %d: %o (%07o)", run_mode, is_d ? 'D' : 'I', page, word_mode ? value & 0xff : value, pages[run_mode][is_d][page].par * 64);
|
||||
}
|
||||
|
||||
void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev, const d_i_space_t space)
|
||||
{
|
||||
int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3;
|
||||
|
||||
if ((MMR0 & 1) == 1 && (a & 1) == 0 && a != 0177572) {
|
||||
const uint8_t apf = a >> 13; // active page field
|
||||
if ((MMR0 & 1) == 1 && (a & 1) == 0 && a != ADDR_MMR0) {
|
||||
const uint8_t apf = a >> 13; // active page field
|
||||
|
||||
// TODO: D/I
|
||||
pages[run_mode][0][apf].pdr |= 64; // set 'W' (written to) bit
|
||||
bool is_data = space == d_space;
|
||||
|
||||
bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false;
|
||||
|
||||
pages[run_mode][d][apf].pdr |= 64; // set 'W' (written to) bit
|
||||
}
|
||||
|
||||
if (a >= 0160000) {
|
||||
bool is_11_34 = c->get_34();
|
||||
|
||||
if (word_mode) {
|
||||
assert(value < 256);
|
||||
DOLOG(debug, true, "WRITE I/O %06o in byte mode", a);
|
||||
}
|
||||
|
||||
if (word_mode) {
|
||||
if (a == 0177776 || a == 0177777) { // PSW
|
||||
if (a == ADDR_PSW || a == ADDR_PSW + 1) { // PSW
|
||||
DOLOG(debug, true, "writeb PSW %s", a & 1 ? "MSB" : "LSB");
|
||||
uint16_t vtemp = c -> getPSW();
|
||||
|
||||
|
@ -479,7 +549,7 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
|
|||
return;
|
||||
}
|
||||
|
||||
if (a == 0177774 || a == 0177775) { // stack limit register
|
||||
if (a == ADDR_STACKLIM || a == ADDR_STACKLIM + 1) { // stack limit register
|
||||
DOLOG(debug, true, "writeb Set stack limit register: %o", value);
|
||||
uint16_t v = c -> getStackLimitRegister();
|
||||
|
||||
|
@ -493,67 +563,67 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (a == 0177776) { // PSW
|
||||
if (a == ADDR_PSW) { // PSW
|
||||
DOLOG(debug, true, "write PSW %o", value);
|
||||
c -> setPSW(value & ~16, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0177774) { // stack limit register
|
||||
if (a == ADDR_STACKLIM) { // stack limit register
|
||||
DOLOG(debug, true, "write Set stack limit register: %o", value);
|
||||
c -> setStackLimitRegister(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||
DOLOG(debug, true, "write kernel R%d: %o", a - 01777700, value);
|
||||
c -> setRegister(a - 0177700, false, false, value);
|
||||
if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
|
||||
DOLOG(debug, true, "write kernel R%d: %o", a - ADDR_KERNEL_R, value);
|
||||
c -> setRegister(a - ADDR_KERNEL_R, false, false, value);
|
||||
return;
|
||||
}
|
||||
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||
DOLOG(debug, true, "write user R%d: %o", a - 01777710, value);
|
||||
c -> setRegister(a - 0177710, true, false, value);
|
||||
if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
|
||||
DOLOG(debug, true, "write user R%d: %o", a - ADDR_USER_R, value);
|
||||
c -> setRegister(a - ADDR_USER_R, true, false, value);
|
||||
return;
|
||||
}
|
||||
if (a == 0177706) { // kernel SP
|
||||
if (a == ADDR_KERNEL_SP) { // kernel SP
|
||||
DOLOG(debug, true, "write kernel SP: %o", value);
|
||||
c -> setStackPointer(0, value);
|
||||
return;
|
||||
}
|
||||
if (a == 0177707) { // PC
|
||||
if (a == ADDR_PC) { // PC
|
||||
DOLOG(debug, true, "write PC: %o", value);
|
||||
c -> setPC(value);
|
||||
return;
|
||||
}
|
||||
if (a == 0177716) { // supervisor SP
|
||||
if (a == ADDR_SV_SP) { // supervisor SP
|
||||
DOLOG(debug, true, "write supervisor sp: %o", value);
|
||||
c -> setStackPointer(1, value);
|
||||
return;
|
||||
}
|
||||
if (a == 0177717) { // user SP
|
||||
if (a == ADDR_USER_SP) { // user SP
|
||||
DOLOG(debug, true, "write user sp: %o", value);
|
||||
c -> setStackPointer(3, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0177770) { // microprogram break register
|
||||
if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (a == 0177766) { // cpu error register
|
||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||
DOLOG(debug, true, "write CPUERR: %o", value);
|
||||
CPUERR = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0172516) { // MMR3
|
||||
if (a == ADDR_MMR3) { // MMR3
|
||||
DOLOG(debug, true, "write set MMR3: %o", value);
|
||||
MMR3 = value & 067;
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0177572) { // MMR0
|
||||
if (a == ADDR_MMR0) { // MMR0
|
||||
DOLOG(debug, true, "write set MMR0: %o", value);
|
||||
|
||||
setMMR0(value);
|
||||
|
@ -561,13 +631,13 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
|
|||
return;
|
||||
}
|
||||
|
||||
if (a == 0177772) { // PIR
|
||||
if (a == ADDR_PIR) { // PIR
|
||||
DOLOG(debug, true, "write set PIR: %o", value);
|
||||
PIR = value; // TODO
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0177546) { // line frequency clock and status register
|
||||
if (a == ADDR_LFC) { // line frequency clock and status register
|
||||
DOLOG(debug, true, "write set LFC/SR: %o", value);
|
||||
lf_csr = value;
|
||||
return;
|
||||
|
@ -595,153 +665,49 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
|
|||
|
||||
/// MMU ///
|
||||
// supervisor
|
||||
if (a >= 0172200 && a < 0172240) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[001][is_d][page].pdr &= 0xff, pages[001][is_d][page].pdr |= value << 8) :
|
||||
(pages[001][is_d][page].pdr &= 0xff00, pages[001][is_d][page].pdr |= value);
|
||||
}
|
||||
else {
|
||||
pages[001][is_d][page].pdr = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has no cache bit
|
||||
pages[001][is_d][page].pdr &= 077416;
|
||||
else
|
||||
pages[001][is_d][page].pdr &= ~(128 + 64 + 32 + 16); // set bit 4 & 5 to 0 as they are unused and A/W are set to 0 by writes
|
||||
|
||||
DOLOG(debug, true, "write supervisor %c PDR for %d: %o [%d]", is_d ? 'D' : 'I', page, value, word_mode);
|
||||
|
||||
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) {
|
||||
write_pdr(a, 1, value, word_mode);
|
||||
return;
|
||||
}
|
||||
if (a >= 0172240 && a < 0172300) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[001][is_d][page].par &= 0xff, pages[001][is_d][page].par |= value << 8) :
|
||||
(pages[001][is_d][page].par &= 0xff00, pages[001][is_d][page].par |= value);
|
||||
}
|
||||
else {
|
||||
pages[001][is_d][page].par = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has 12 bit PARs
|
||||
pages[001][is_d][page].par &= 4095;
|
||||
|
||||
DOLOG(debug, true, "write supervisor %c PAR for %d: %o (%07o)", is_d ? 'D' : 'I', page, word_mode ? value & 0xff : value, pages[001][is_d][page].par * 64);
|
||||
|
||||
if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) {
|
||||
write_par(a, 1, value, word_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
// kernel
|
||||
if (a >= 0172300 && a < 0172340) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[000][is_d][page].pdr &= 0xff, pages[000][is_d][page].pdr |= value << 8) :
|
||||
(pages[000][is_d][page].pdr &= 0xff00, pages[000][is_d][page].pdr |= value);
|
||||
}
|
||||
else {
|
||||
pages[000][is_d][page].pdr = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has no cache bit
|
||||
pages[000][is_d][page].pdr &= 077416;
|
||||
else
|
||||
pages[000][is_d][page].pdr &= ~(128 + 64 + 32 + 16); // set bit 4 & 5 to 0 as they are unused and A/W are set to 0 by writes
|
||||
|
||||
DOLOG(debug, true, "write kernel %c PDR for %d: %o [%d]", is_d ? 'D' : 'I', page, value, word_mode);
|
||||
|
||||
if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) {
|
||||
write_pdr(a, 0, value, word_mode);
|
||||
return;
|
||||
}
|
||||
if (a >= 0172340 && a < 0172400) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[000][is_d][page].par &= 0xff, pages[000][is_d][page].par |= value << 8) :
|
||||
(pages[000][is_d][page].par &= 0xff00, pages[000][is_d][page].par |= value);
|
||||
}
|
||||
else {
|
||||
pages[000][is_d][page].par = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has 12 bit PARs
|
||||
pages[000][is_d][page].par &= 4095;
|
||||
|
||||
DOLOG(debug, true, "write kernel %c PAR for %d: %o (%07o)", is_d ? 'D' : 'I', page, word_mode ? value & 0xff : value, pages[000][is_d][page].par * 64);
|
||||
|
||||
if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) {
|
||||
write_par(a, 0, value, word_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
// user
|
||||
if (a >= 0177600 && a < 0177640) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[003][is_d][page].pdr &= 0xff, pages[003][is_d][page].pdr |= value << 8) :
|
||||
(pages[003][is_d][page].pdr &= 0xff00, pages[003][is_d][page].pdr |= value);
|
||||
}
|
||||
else {
|
||||
pages[003][is_d][page].pdr = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has no cache bit
|
||||
pages[003][is_d][page].pdr &= 077416;
|
||||
else
|
||||
pages[003][is_d][page].pdr &= ~(128 + 64 + 32 + 16); // set bit 4 & 5 to 0 as they are unused and A/W are set to 0 by writes
|
||||
|
||||
DOLOG(debug, true, "write user %c PDR for %d: %o [%d]", is_d ? 'D' : 'I', page, value, word_mode);
|
||||
|
||||
if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) {
|
||||
write_pdr(a, 3, value, word_mode);
|
||||
return;
|
||||
}
|
||||
if (a >= 0177640 && a < 0177700) {
|
||||
bool is_d = is_11_34 ? false : (a & 16);
|
||||
int page = (a >> 1) & 7;
|
||||
|
||||
if (word_mode) {
|
||||
a & 1 ? (pages[003][is_d][page].par &= 0xff, pages[003][is_d][page].par |= value << 8) :
|
||||
(pages[003][is_d][page].par &= 0xff00, pages[003][is_d][page].par |= value);
|
||||
}
|
||||
else {
|
||||
pages[003][is_d][page].par = value;
|
||||
}
|
||||
|
||||
if (is_11_34) // 11/34 has 12 bit PARs
|
||||
pages[003][is_d][page].par &= 4095;
|
||||
|
||||
DOLOG(debug, true, "write user %c PAR for %d: %o (%07o)", is_d ? 'D' : 'I', page, word_mode ? value & 0xff : value, pages[003][is_d][page].par * 64);
|
||||
|
||||
if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END) {
|
||||
write_par(a, 3, value, word_mode);
|
||||
return;
|
||||
}
|
||||
////
|
||||
|
||||
if (a == 0177746) { // cache control register
|
||||
if (a == ADDR_CCR) { // cache control register
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
if (a == 0177570) { // switch register
|
||||
if (a == ADDR_CONSW) { // switch register
|
||||
switch_register = value;
|
||||
return;
|
||||
}
|
||||
|
||||
///////////
|
||||
|
||||
if (a == 0177374) { // TODO
|
||||
DOLOG(debug, true, "char: %c", value & 127);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a & 1)
|
||||
DOLOG(info, true, "bus::writeWord: odd address UNHANDLED");
|
||||
|
||||
DOLOG(info, true, "UNHANDLED write %o(%c): %o", a, word_mode ? 'B' : ' ', value);
|
||||
DOLOG(debug, true, "UNHANDLED write %o(%c): %o", a, word_mode ? 'B' : 'W', value);
|
||||
|
||||
// c -> busError();
|
||||
|
||||
|
|
52
bus.h
52
bus.h
|
@ -10,6 +10,47 @@
|
|||
#include "rk05.h"
|
||||
#include "rl02.h"
|
||||
|
||||
#define ADDR_MMR0 0177572
|
||||
#define ADDR_MMR1 0177574
|
||||
#define ADDR_MMR2 0177576
|
||||
#define ADDR_MMR3 0172516
|
||||
|
||||
#define ADDR_PIR 0177772
|
||||
#define ADDR_LFC 0177546 // line frequency
|
||||
#define ADDR_MAINT 0177750
|
||||
#define ADDR_CONSW 0177570
|
||||
#define ADDR_KW11P 0172540
|
||||
#define ADDR_LP11CSR 0177514 // printer
|
||||
|
||||
#define ADDR_PDR_SV_START 0172200
|
||||
#define ADDR_PDR_SV_END 0172240
|
||||
#define ADDR_PAR_SV_START 0172240
|
||||
#define ADDR_PAR_SV_END 0172300
|
||||
|
||||
#define ADDR_PDR_K_START 0172300
|
||||
#define ADDR_PDR_K_END 0172340
|
||||
#define ADDR_PAR_K_START 0172340
|
||||
#define ADDR_PAR_K_END 0172400
|
||||
|
||||
#define ADDR_PDR_U_START 0177600
|
||||
#define ADDR_PDR_U_END 0177640
|
||||
#define ADDR_PAR_U_START 0177640
|
||||
#define ADDR_PAR_U_END 0177700
|
||||
|
||||
#define ADDR_PSW 0177776
|
||||
#define ADDR_STACKLIM 0177774
|
||||
#define ADDR_KERNEL_R 0177700
|
||||
#define ADDR_USER_R 0177710
|
||||
#define ADDR_KERNEL_SP 0177706
|
||||
#define ADDR_PC 0177707
|
||||
#define ADDR_SV_SP 0177716
|
||||
#define ADDR_USER_SP 0177717
|
||||
|
||||
#define ADDR_CPU_ERR 0177766
|
||||
#define ADDR_SYSSIZE 0177760
|
||||
#define ADDR_MICROPROG_BREAK_REG 0177770
|
||||
#define ADDR_CCR 0177746
|
||||
|
||||
class cpu;
|
||||
class memory;
|
||||
class tty;
|
||||
|
@ -41,7 +82,12 @@ private:
|
|||
|
||||
uint16_t lf_csr { 0 };
|
||||
|
||||
bool debug_mode { false };
|
||||
uint16_t console_switches { 0 };
|
||||
|
||||
uint16_t read_pdr (const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only);
|
||||
uint16_t read_par (const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only);
|
||||
void write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode);
|
||||
void write_par(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode);
|
||||
|
||||
public:
|
||||
bus();
|
||||
|
@ -49,7 +95,8 @@ public:
|
|||
|
||||
void clearmem();
|
||||
|
||||
void set_debug_mode(const bool state) { debug_mode = state; }
|
||||
void set_console_switches(const uint16_t new_state) { console_switches = new_state; }
|
||||
void set_debug_mode() { console_switches |= 128; }
|
||||
|
||||
void add_cpu(cpu *const c) { this -> c = c; }
|
||||
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; }
|
||||
|
@ -87,6 +134,7 @@ public:
|
|||
void addToMMR1(const int8_t delta, const uint8_t reg);
|
||||
void setMMR0(int value);
|
||||
void setMMR0Bit(const int bit);
|
||||
void clearMMR0Bit(const int bit);
|
||||
void setMMR2(const uint16_t value);
|
||||
|
||||
uint16_t get_switch_register() const { return switch_register; }
|
||||
|
|
|
@ -32,7 +32,7 @@ int console_posix::wait_for_char_ll(const short timeout)
|
|||
{
|
||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } };
|
||||
|
||||
if (poll(fds, 1, 0) == 1 && fds[0].revents)
|
||||
if (poll(fds, 1, timeout) == 1 && fds[0].revents)
|
||||
return getchar();
|
||||
|
||||
return -1;
|
||||
|
|
170
cpu.cpp
170
cpu.cpp
|
@ -162,7 +162,7 @@ bool cpu::put_result(const uint16_t a, const uint8_t dst_mode, const uint8_t dst
|
|||
|
||||
b->write(a, word_mode, value, false);
|
||||
|
||||
return a != 0177776;
|
||||
return a != ADDR_PSW;
|
||||
}
|
||||
|
||||
uint16_t cpu::addRegister(const int nr, const bool prev_mode, const uint16_t value)
|
||||
|
@ -246,17 +246,15 @@ int cpu::getPSW_spl() const
|
|||
return (psw >> 5) & 7;
|
||||
}
|
||||
|
||||
void cpu::setPSW(const uint16_t v, const bool limited)
|
||||
void cpu::setPSW(uint16_t v, const bool limited)
|
||||
{
|
||||
if (limited) {
|
||||
psw |= v & 0174000; // current & previous mode can only be increased, 11 can only be set
|
||||
v &= 0174037;
|
||||
|
||||
psw &= 0174000; // retain upper 5 bit
|
||||
psw |= v & ~0174000;
|
||||
}
|
||||
else {
|
||||
psw = v;
|
||||
v |= psw & 0174340;
|
||||
}
|
||||
|
||||
psw = v;
|
||||
}
|
||||
|
||||
bool cpu::check_queued_interrupts()
|
||||
|
@ -406,7 +404,7 @@ bool cpu::putGAM(const uint8_t mode, const int reg, const bool word_mode, const
|
|||
break;
|
||||
}
|
||||
|
||||
return addr == -1 || addr != 0177776;
|
||||
return addr == -1 || addr != ADDR_PSW;
|
||||
}
|
||||
|
||||
uint16_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode, const bool prev_mode)
|
||||
|
@ -556,7 +554,7 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
int16_t dst_value = b->readWord(dst_addr);
|
||||
int16_t result = 0;
|
||||
|
||||
bool set_flags = dst_addr != 0177776;
|
||||
bool set_flags = dst_addr != ADDR_PSW;
|
||||
|
||||
if (instr & 0x8000) {
|
||||
result = (dst_value - ssrc_value) & 0xffff;
|
||||
|
@ -761,7 +759,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
|
|||
else {
|
||||
b->write(a, false, vl, false);
|
||||
|
||||
set_flags = a != 0177776;
|
||||
set_flags = a != ADDR_PSW;
|
||||
}
|
||||
|
||||
if (set_flags) {
|
||||
|
@ -818,7 +816,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
v = ((v & 0xff) << 8) | (v >> 8);
|
||||
|
||||
set_flags = a != 0177776;
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
b->writeWord(a, v);
|
||||
}
|
||||
|
@ -847,7 +845,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false);
|
||||
|
||||
set_flags = a != 0177776;
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
b -> write(a, word_mode, 0, false);
|
||||
}
|
||||
|
@ -887,7 +885,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
else
|
||||
v ^= 0xffff;
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -920,7 +918,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
uint16_t v = b -> read(a, word_mode, false);
|
||||
int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(vl, word_mode));
|
||||
|
@ -953,7 +951,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
uint16_t v = b -> read(a, word_mode, false);
|
||||
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(vl, word_mode));
|
||||
|
@ -988,7 +986,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, v, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1026,7 +1024,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, v, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1068,7 +1066,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, v, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1130,7 +1128,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, temp, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_c(new_carry);
|
||||
|
@ -1181,7 +1179,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, temp, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_c(new_carry);
|
||||
|
@ -1240,7 +1238,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
b->write(a, word_mode, v, false);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1271,7 +1269,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
uint16_t vl = b -> read(a, word_mode, false);
|
||||
uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff);
|
||||
|
||||
bool set_flags = a != 0177776;
|
||||
bool set_flags = a != ADDR_PSW;
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_n(SIGN(v, word_mode));
|
||||
|
@ -1287,7 +1285,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
case 0b00110101: { // MFPD/MFPI
|
||||
// always words: word_mode-bit is to select between MFPI and MFPD
|
||||
assert(!word_mode); // TODO
|
||||
// NOTE: this code does not work for D/I split setups! TODO
|
||||
|
||||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->addToMMR1(-2, 6);
|
||||
|
@ -1301,7 +1299,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
// calculate address in current address space
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false);
|
||||
|
||||
set_flags = a != 0177776;
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
// read from previous space
|
||||
v = b -> read(a, false, true);
|
||||
|
@ -1321,7 +1319,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
case 0b00110110: { // MTPI/MTPD
|
||||
// always words: word_mode-bit is to select between MTPI and MTPD
|
||||
assert(!word_mode); // TODO
|
||||
// NOTE: this code does not work for D/I split setups! TODO
|
||||
|
||||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->addToMMR1(2, 6);
|
||||
|
@ -1336,7 +1334,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
else {
|
||||
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false);
|
||||
|
||||
set_flags = a != 0177776;
|
||||
set_flags = a != ADDR_PSW;
|
||||
|
||||
b -> write(a, false, v, true); // put in '13/12' address space
|
||||
}
|
||||
|
@ -1517,7 +1515,7 @@ bool cpu::condition_code_operations(const uint16_t instr)
|
|||
void cpu::pushStack(const uint16_t v)
|
||||
{
|
||||
if (getRegister(6) == stackLimitRegister) {
|
||||
DOLOG(debug, true, "stackLimitRegister reached");
|
||||
DOLOG(debug, true, "stackLimitRegister reached %06o while pushing %06o", stackLimitRegister, v);
|
||||
|
||||
trap(123, 7); // TODO
|
||||
}
|
||||
|
@ -1548,10 +1546,15 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
case 0b0000000000000001: // WAIT
|
||||
return true;
|
||||
|
||||
case 0b0000000000000010: // RTI
|
||||
case 0b0000000000000010: { // RTI
|
||||
setPC(popStack());
|
||||
setPSW(popStack(), !!((getPSW() >> 12) & 3));
|
||||
|
||||
uint16_t replacement_psw = popStack();
|
||||
|
||||
setPSW(replacement_psw, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0b0000000000000011: // BPT
|
||||
trap(014);
|
||||
|
@ -1561,10 +1564,15 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
trap(020);
|
||||
return true;
|
||||
|
||||
case 0b0000000000000110: // RTT
|
||||
case 0b0000000000000110: { // RTT
|
||||
setPC(popStack());
|
||||
setPSW(popStack(), !!((getPSW() >> 12) & 3));
|
||||
|
||||
uint16_t replacement_psw = popStack();
|
||||
|
||||
setPSW(replacement_psw, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case 0b0000000000000111: // MFPT
|
||||
if (emulateMFPT)
|
||||
|
@ -1637,28 +1645,83 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
return false;
|
||||
}
|
||||
|
||||
void cpu::busError()
|
||||
{
|
||||
trap(4);
|
||||
}
|
||||
|
||||
void cpu::schedule_trap(const uint16_t vector)
|
||||
{
|
||||
scheduled_trap = vector;
|
||||
}
|
||||
|
||||
void cpu::trap(const uint16_t vector, const int new_ipl, const bool is_interrupt)
|
||||
// 'is_interrupt' is not correct naming; it is true for mmu faults and interrupts
|
||||
void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
|
||||
{
|
||||
uint16_t before_psw = getPSW();
|
||||
uint16_t before_pc = getPC();
|
||||
DOLOG(debug, true, "*** CPU::TRAP, MMR0: %06o, MMR2: %06o ***", b->getMMR0(), b->getMMR2());
|
||||
|
||||
// make sure the trap vector is retrieved from kernel space
|
||||
psw &= 037777; // mask off 14/15
|
||||
int processing_trap_depth = 0;
|
||||
uint16_t before_psw = 0;
|
||||
uint16_t before_pc = 0;
|
||||
|
||||
if ((b->getMMR0() & 0160000) == 0) {
|
||||
b->setMMR2(vector);
|
||||
b->addToMMR1(-2, 6);
|
||||
b->addToMMR1(-2, 6);
|
||||
for(;;) {
|
||||
try {
|
||||
processing_trap_depth++;
|
||||
|
||||
bool kernel_mode = psw >> 14;
|
||||
|
||||
if (processing_trap_depth >= 2) {
|
||||
DOLOG(debug, true, "Trap depth %d", processing_trap_depth);
|
||||
|
||||
if (kernel_mode)
|
||||
vector = 4;
|
||||
|
||||
setRegister(6, 04);
|
||||
|
||||
if (processing_trap_depth >= 3) {
|
||||
// TODO: halt?
|
||||
}
|
||||
}
|
||||
else {
|
||||
before_psw = getPSW();
|
||||
before_pc = getPC();
|
||||
|
||||
if ((b->getMMR0() & 0160000) == 0 && vector != 4) {
|
||||
b->setMMR2(vector);
|
||||
b->addToMMR1(-2, 6);
|
||||
b->addToMMR1(-2, 6);
|
||||
}
|
||||
|
||||
if (is_interrupt)
|
||||
b->clearMMR0Bit(12);
|
||||
else
|
||||
b->setMMR0Bit(12); // it's a trap
|
||||
}
|
||||
|
||||
// make sure the trap vector is retrieved from kernel space
|
||||
psw &= 037777; // mask off 14/15
|
||||
|
||||
setPC(b->readWord(vector + 0));
|
||||
|
||||
// switch to kernel mode & update 'previous mode'
|
||||
uint16_t new_psw = b->readWord(vector + 2) & 0147777; // mask off old 'previous mode'
|
||||
if (new_ipl != -1)
|
||||
new_psw = (new_psw & ~0xe0) | (new_ipl << 5);
|
||||
new_psw |= (before_psw >> 2) & 030000; // apply new 'previous mode'
|
||||
setPSW(new_psw, false);
|
||||
|
||||
// DOLOG(info, true, "R6: %06o, before PSW: %06o, new PSW: %06o", getRegister(6), before_psw, new_psw);
|
||||
//
|
||||
if (processing_trap_depth >= 2 && kernel_mode)
|
||||
setRegister(6, 04);
|
||||
|
||||
pushStack(before_psw);
|
||||
pushStack(before_pc);
|
||||
|
||||
// if we reach this point then the trap was processed without causing
|
||||
// another trap
|
||||
break;
|
||||
}
|
||||
catch(const int exception) {
|
||||
DOLOG(debug, true, "trap during execution of trap (%d)", exception);
|
||||
|
||||
setPSW(before_psw, false);
|
||||
}
|
||||
}
|
||||
|
||||
setPC(b->readWord(vector + 0, d_space));
|
||||
|
@ -1772,7 +1835,8 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
|
|||
// single_operand_instructions
|
||||
switch(so_opcode) {
|
||||
case 0b00000011:
|
||||
text = "SWAB " + dst_text.operand;
|
||||
if (!word_mode)
|
||||
text = "SWAB " + dst_text.operand;
|
||||
break;
|
||||
|
||||
case 0b000101000:
|
||||
|
@ -2147,6 +2211,9 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
|
|||
work_values_str.push_back(format("%06o", v));
|
||||
out.insert({ "work-values", work_values_str });
|
||||
|
||||
out.insert({ "MMR0", { format("%06o", b->getMMR0()) } });
|
||||
out.insert({ "MMR2", { format("%06o", b->getMMR2()) } });
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -2156,7 +2223,7 @@ void cpu::step_a()
|
|||
b->clearMMR1();
|
||||
|
||||
if (scheduled_trap) {
|
||||
trap(scheduled_trap, 7);
|
||||
trap(scheduled_trap, 7, true);
|
||||
|
||||
scheduled_trap = 0;
|
||||
|
||||
|
@ -2176,12 +2243,13 @@ void cpu::step_b()
|
|||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->setMMR2(temp_pc);
|
||||
|
||||
if (temp_pc & 1)
|
||||
busError();
|
||||
|
||||
try {
|
||||
uint16_t instr = b->readWord(temp_pc);
|
||||
|
||||
// FILE *fh = fopen("/home/folkert/kek.dat", "a+");
|
||||
// fprintf(fh, "%06o %06o\n", temp_pc, instr);
|
||||
// fclose(fh);
|
||||
|
||||
addRegister(7, false, 2);
|
||||
|
||||
if (double_operand_instructions(instr))
|
||||
|
|
5
cpu.h
5
cpu.h
|
@ -95,8 +95,7 @@ public:
|
|||
void init_interrupt_queue();
|
||||
void queue_interrupt(const uint8_t level, const uint8_t vector);
|
||||
|
||||
void busError();
|
||||
void trap(const uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
|
||||
void trap(uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
|
||||
void schedule_trap(const uint16_t vector);
|
||||
|
||||
void setEmulateMFPT(const bool v) { emulateMFPT = v; }
|
||||
|
@ -118,7 +117,7 @@ public:
|
|||
void setBitPSW(const int bit, const bool v);
|
||||
|
||||
uint16_t getPSW() const { return psw; }
|
||||
void setPSW(const uint16_t v, const bool limited);
|
||||
void setPSW(uint16_t v, const bool limited);
|
||||
|
||||
uint16_t getStackLimitRegister() { return stackLimitRegister; }
|
||||
void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; }
|
||||
|
|
29
debugger.cpp
29
debugger.cpp
|
@ -28,6 +28,9 @@ int disassemble(cpu *const c, console *const cnsl, const int pc, const bool inst
|
|||
|
||||
std::string instruction = data["instruction-text"].at(0);
|
||||
|
||||
std::string MMR0 = data["MMR0"].at(0);
|
||||
std::string MMR2 = data["MMR2"].at(0);
|
||||
|
||||
std::string result;
|
||||
|
||||
if (instruction_only)
|
||||
|
@ -38,13 +41,13 @@ int disassemble(cpu *const c, console *const cnsl, const int pc, const bool inst
|
|||
work_values.c_str()
|
||||
);
|
||||
else
|
||||
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s: %s - %s",
|
||||
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s: %s - MMR0/2: %s/%s",
|
||||
registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(),
|
||||
registers[6].c_str(), pc,
|
||||
psw.c_str(),
|
||||
instruction_values.c_str(),
|
||||
instruction.c_str(),
|
||||
work_values.c_str()
|
||||
MMR0.c_str(), MMR2.c_str()
|
||||
);
|
||||
|
||||
if (cnsl)
|
||||
|
@ -103,14 +106,14 @@ void mmu_dump(console *const cnsl, bus *const b)
|
|||
cnsl->put_string_lf(format("MMR2: %06o", b->getMMR2()));
|
||||
cnsl->put_string_lf(format("MMR3: %06o", mmr3));
|
||||
|
||||
dump_par_pdr(cnsl, b, 0172200, 0172240, "supervisor i-space", 0);
|
||||
dump_par_pdr(cnsl, b, 0172220, 0172260, "supervisor d-space", 1 + (!!(mmr3 & 2)));
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_SV_START, ADDR_PAR_SV_START, "supervisor i-space", 0);
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_SV_START + 020, ADDR_PAR_SV_START + 020, "supervisor d-space", 1 + (!!(mmr3 & 2)));
|
||||
|
||||
dump_par_pdr(cnsl, b, 0172300, 0172340, "kernel i-space", 0);
|
||||
dump_par_pdr(cnsl, b, 0172320, 0172360, "kernel d-space", 1 + (!!(mmr3 & 4)));
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0);
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_K_START + 020, ADDR_PAR_K_START + 020, "kernel d-space", 1 + (!!(mmr3 & 4)));
|
||||
|
||||
dump_par_pdr(cnsl, b, 0177600, 0177640, "user i-space", 0);
|
||||
dump_par_pdr(cnsl, b, 0177620, 0177660, "user d-space", 1 + (!!(mmr3 & 1)));
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_U_START, ADDR_PAR_U_START, "user i-space", 0);
|
||||
dump_par_pdr(cnsl, b, ADDR_PDR_U_START + 020, ADDR_PAR_U_START + 020, "user d-space", 1 + (!!(mmr3 & 1)));
|
||||
}
|
||||
|
||||
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing_in)
|
||||
|
@ -120,7 +123,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
|
||||
cpu *const c = b->getCpu();
|
||||
|
||||
b->set_debug_mode(true);
|
||||
b->set_debug_mode();
|
||||
|
||||
bool single_step = false;
|
||||
|
||||
|
@ -157,10 +160,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
|
||||
cnsl->put_string_lf("Breakpoints:");
|
||||
|
||||
for(auto pc : bps) {
|
||||
cnsl->put_string_lf(format(" %06o", pc));
|
||||
for(auto a : bps) {
|
||||
cnsl->put_string(format(" %06o> ", a));
|
||||
|
||||
pc += disassemble(c, cnsl, pc, true);
|
||||
disassemble(c, cnsl, a, true);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -224,6 +227,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
if (val != -1)
|
||||
cnsl->put_string_lf(format("value at %06o, octal: %o, hex: %x, dec: %d\n", addr, val, val, val));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "reset" || cmd == "r") {
|
||||
#if defined(ESP32)
|
||||
|
|
33
kw11-l.cpp
33
kw11-l.cpp
|
@ -1,19 +1,35 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "cpu.h"
|
||||
#include "kw11-l.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
kw11_l::kw11_l(bus *const b) : b(b)
|
||||
#if defined(ESP32)
|
||||
void thread_wrapper_kw11(void *p)
|
||||
{
|
||||
kw11_l *const kw11l = reinterpret_cast<kw11_l *>(p);
|
||||
|
||||
kw11l->operator()();
|
||||
}
|
||||
#endif
|
||||
|
||||
kw11_l::kw11_l(bus *const b, console *const cnsl) : b(b), cnsl(cnsl)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
xTaskCreatePinnedToCore(&thread_wrapper_kw11, "kw11-l", 2048, this, 1, nullptr, 0);
|
||||
#else
|
||||
th = new std::thread(std::ref(*this));
|
||||
#endif
|
||||
}
|
||||
|
||||
kw11_l::~kw11_l()
|
||||
{
|
||||
stop_flag = true;
|
||||
|
||||
#if !defined(ESP32)
|
||||
th->join();
|
||||
#endif
|
||||
|
||||
delete th;
|
||||
}
|
||||
|
@ -21,11 +37,16 @@ kw11_l::~kw11_l()
|
|||
void kw11_l::operator()()
|
||||
{
|
||||
while(!stop_flag) {
|
||||
b->set_lf_crs_b7();
|
||||
if (*cnsl->get_running_flag()) {
|
||||
b->set_lf_crs_b7();
|
||||
|
||||
if (b->get_lf_crs() & 64)
|
||||
b->getCpu()->queue_interrupt(6, 0100);
|
||||
if (b->get_lf_crs() & 64)
|
||||
b->getCpu()->queue_interrupt(6, 0100);
|
||||
|
||||
usleep(1000000 / 50);
|
||||
myusleep(1000000 / 50); // 20ms
|
||||
}
|
||||
else {
|
||||
myusleep(1000000 / 10); // 100ms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
kw11-l.h
4
kw11-l.h
|
@ -8,11 +8,13 @@ class kw11_l
|
|||
{
|
||||
private:
|
||||
bus *const b { nullptr };
|
||||
console *const cnsl { nullptr };
|
||||
|
||||
std::thread * th { nullptr };
|
||||
std::atomic_bool stop_flag { false };
|
||||
|
||||
public:
|
||||
kw11_l(bus *const b);
|
||||
kw11_l(bus *const b, console *const cnsl);
|
||||
virtual ~kw11_l();
|
||||
|
||||
void operator()();
|
||||
|
|
|
@ -178,7 +178,7 @@ void load_p11_x11(bus *const b, const std::string & file)
|
|||
break;
|
||||
|
||||
if (n) {
|
||||
uint8_t byte = strtol(buffer, NULL, 16);
|
||||
uint8_t byte = strtol(buffer, nullptr, 16);
|
||||
|
||||
b->writeByte(addr, byte);
|
||||
|
||||
|
@ -189,8 +189,8 @@ void load_p11_x11(bus *const b, const std::string & file)
|
|||
else {
|
||||
std::vector<std::string> parts = split(buffer, " ");
|
||||
|
||||
addr = strtol(parts[0].c_str(), NULL, 16);
|
||||
n = strtol(parts[1].c_str(), NULL, 16);
|
||||
addr = strtol(parts[0].c_str(), nullptr, 16);
|
||||
n = strtol(parts[1].c_str(), nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
3
log.cpp
3
log.cpp
|
@ -2,6 +2,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "error.h"
|
||||
|
@ -71,7 +72,7 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
|||
uint64_t now = get_us();
|
||||
time_t t_now = now / 1000000;
|
||||
|
||||
struct tm tm { 0 };
|
||||
tm tm { 0 };
|
||||
if (!localtime_r(&t_now, &tm))
|
||||
error_exit(true, "localtime_r failed");
|
||||
|
||||
|
|
40
main.cpp
40
main.cpp
|
@ -44,10 +44,12 @@ void help()
|
|||
printf("-h this help\n");
|
||||
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\n");
|
||||
printf("-R d.rk load file as a RK05 disk device\n");
|
||||
printf("-r d.rk load file as a RL02 disk device\n");
|
||||
printf("-p 123 set CPU start pointer to decimal(!) value\n");
|
||||
printf("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n");
|
||||
printf("-n ncurses UI\n");
|
||||
printf("-d enable debugger\n");
|
||||
printf("-s x set console switches state - octal number\n");
|
||||
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
|
||||
printf("-l x log to file x\n");
|
||||
printf("-L x,y set log level for screen (x) and file (y)\n");
|
||||
|
@ -60,7 +62,6 @@ int main(int argc, char *argv[])
|
|||
std::vector<std::string> rk05_files;
|
||||
std::vector<std::string> rl02_files;
|
||||
|
||||
bool testCases = false;
|
||||
bool run_debugger = false;
|
||||
bool tracing = false;
|
||||
|
||||
|
@ -77,14 +78,26 @@ int main(int argc, char *argv[])
|
|||
|
||||
std::string tape;
|
||||
|
||||
uint16_t console_switches = 0;
|
||||
|
||||
std::string test;
|
||||
|
||||
int opt = -1;
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:3")) != -1)
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:3s:Q:")) != -1)
|
||||
{
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
help();
|
||||
return 1;
|
||||
|
||||
case 'Q':
|
||||
test = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
console_switches = strtol(optarg, NULL, 8);
|
||||
break;
|
||||
|
||||
case '3':
|
||||
mode_34 = true; // switch from 11/70 to 11/34
|
||||
break;
|
||||
|
@ -155,13 +168,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
bus *b = new bus();
|
||||
|
||||
b->set_console_switches(console_switches);
|
||||
|
||||
cpu *c = new cpu(b, &event);
|
||||
b->add_cpu(c);
|
||||
|
||||
c->set_34(mode_34);
|
||||
|
||||
kw11_l *lf = new kw11_l(b);
|
||||
|
||||
c->setEmulateMFPT(true);
|
||||
|
||||
std::atomic_bool interrupt_emulation { false };
|
||||
|
@ -182,11 +195,19 @@ int main(int argc, char *argv[])
|
|||
cnsl = new console_posix(&event, b);
|
||||
}
|
||||
|
||||
if (rk05_files.empty() == false)
|
||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
if (rk05_files.empty() == false) {
|
||||
if (bootloader != BL_RK05)
|
||||
DOLOG(warning, true, "Note: loading RK05 with no RK05 bootloader selected");
|
||||
|
||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
}
|
||||
|
||||
if (rl02_files.empty() == false) {
|
||||
if (bootloader != BL_RL02)
|
||||
DOLOG(warning, true, "Note: loading RL02 with no RL02 bootloader selected");
|
||||
|
||||
if (rl02_files.empty() == false)
|
||||
b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
}
|
||||
|
||||
if (bootloader != BL_NONE)
|
||||
setBootLoader(b, bootloader);
|
||||
|
@ -210,6 +231,9 @@ int main(int argc, char *argv[])
|
|||
sigaction(SIGTERM, &sa, nullptr);
|
||||
sigaction(SIGINT , &sa, nullptr);
|
||||
|
||||
if (test.empty() == false)
|
||||
load_p11_x11(b, test);
|
||||
|
||||
#if 0
|
||||
// loadbin(b, 0, "test.dat");
|
||||
// c->setRegister(7, 0);
|
||||
|
@ -227,6 +251,8 @@ int main(int argc, char *argv[])
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
kw11_l *lf = new kw11_l(b, cnsl);
|
||||
|
||||
cnsl->start_thread();
|
||||
|
||||
if (run_debugger)
|
||||
|
|
3
tests.h
3
tests.h
|
@ -1,3 +0,0 @@
|
|||
// (C) 2018 by Folkert van Heusden
|
||||
// Released under Apache License v2.0
|
||||
void tests(cpu *const c);
|
28
utils.cpp
28
utils.cpp
|
@ -4,10 +4,12 @@
|
|||
#include <Arduino.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -41,7 +43,7 @@ unsigned long get_ms()
|
|||
#if defined(ESP32)
|
||||
return millis();
|
||||
#else
|
||||
struct timeval tv;
|
||||
timeval tv;
|
||||
|
||||
// TODO replace gettimeofday by clock_gettime
|
||||
gettimeofday(&tv, NULL);
|
||||
|
@ -55,7 +57,7 @@ uint64_t get_us()
|
|||
#if defined(ESP32)
|
||||
return micros();
|
||||
#else
|
||||
struct timeval tv;
|
||||
timeval tv;
|
||||
|
||||
// TODO replace gettimeofday by clock_gettime
|
||||
gettimeofday(&tv, NULL);
|
||||
|
@ -72,21 +74,35 @@ int parity(int v)
|
|||
void myusleep(uint64_t us)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
delayMicroseconds(us);
|
||||
for(;;) {
|
||||
uint64_t n_ms = us / 1000;
|
||||
|
||||
if (n_ms >= portTICK_RATE_MS) {
|
||||
vTaskDelay(n_ms / portTICK_RATE_MS);
|
||||
|
||||
us -= n_ms * 1000;
|
||||
}
|
||||
else {
|
||||
delayMicroseconds(us);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct timespec req;
|
||||
timespec req;
|
||||
|
||||
req.tv_sec = us / 1000000l;
|
||||
req.tv_nsec = (us % 1000000l) * 1000l;
|
||||
|
||||
for(;;) {
|
||||
struct timespec rem { 0, 0 };
|
||||
timespec rem { 0, 0 };
|
||||
|
||||
int rc = nanosleep(&req, &rem);
|
||||
|
||||
if (rc == 0 || (rc == -1 && errno != EINTR))
|
||||
break;
|
||||
|
||||
memcpy(&req, &rem, sizeof(struct timespec));
|
||||
memcpy(&req, &rem, sizeof(timespec));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue