Merge branch 'master' into d_i

This commit is contained in:
folkert van heusden 2022-11-10 09:13:22 +01:00
commit 2fd1da58bb
17 changed files with 541 additions and 377 deletions

2
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,2 @@
github: [folkertvanheusden]
patreon: folkertvanheusden

View file

@ -102,7 +102,7 @@ void console_esp32::panel_update_thread()
int run_mode = current_PSW >> 14; int run_mode = current_PSW >> 14;
uint16_t current_PC = c->getPC(); 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); uint16_t current_instr = b->readWord(current_PC);

View file

@ -181,14 +181,14 @@ void setup() {
Serial.println(F("Connect CPU to BUS")); Serial.println(F("Connect CPU to BUS"));
b->add_cpu(c); b->add_cpu(c);
Serial.println(F("Start line-frequency interrupt"));
kw11_l *lf = new kw11_l(b);
c->setEmulateMFPT(true); c->setEmulateMFPT(true);
Serial.println(F("Init console")); Serial.println(F("Init console"));
cnsl = new console_esp32(&stop_event, b); 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(); running = cnsl->get_running_flag();
Serial.println(F("Init TTY")); Serial.println(F("Init TTY"));

View file

@ -1,10 +1,10 @@
[platformio] [platformio]
default_envs = serial32 default_envs = ESP32
src_dir = . src_dir = .
[env:serial32] [env:ESP32]
lib_ldf_mode = deep+ 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 platform = espressif32
board = wemos_d1_mini32 board = wemos_d1_mini32
framework = arduino framework = arduino
@ -14,3 +14,16 @@ lib_deps = greiman/SdFat@^2.1.2
adafruit/Adafruit NeoPixel@^1.10.4 adafruit/Adafruit NeoPixel@^1.10.4
build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
build_unflags = -std=gnu++11 -Os 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

474
bus.cpp
View file

@ -20,6 +20,7 @@ constexpr int n_pages = 12;
constexpr int n_pages = 16; constexpr int n_pages = 16;
#endif #endif
constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 };
bus::bus() bus::bus()
{ {
@ -51,198 +52,188 @@ void bus::init()
MMR3 = 0; 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 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; uint16_t temp = 0;
if (a >= 0160000) { if (a >= 0160000) {
bool is_11_34 = c->get_34();
if (word_mode) if (word_mode)
DOLOG(debug, false, "READ I/O %06o in byte mode", a); 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"); DOLOG(debug, !peek_only, "read MAINT");
return 1; // POWER OK return 1; // POWER OK
} }
if (a == 0177570) { // console switch & display register if (a == ADDR_CONSW) { // console switch & display register
DOLOG(debug, !peek_only, "read console switch"); 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"); DOLOG(debug, !peek_only, "read programmable clock");
return 128; return 128;
} }
if (a == 0177772) { // PIR if (a == ADDR_PIR) { // PIR
DOLOG(debug, !peek_only, "read PIT"); DOLOG(debug, !peek_only, "read PIT");
return PIR; 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"); DOLOG(debug, !peek_only, "read line freq clock");
return lf_csr; 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"); DOLOG(debug, !peek_only, "read LP11 CSR");
return 0x80; return 0x80;
} }
/// MMU /// /// MMU ///
if (a >= 0172200 && a < 0172240) { if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
int page = (a >> 1) & 7; return read_pdr(a, 1, word_mode, peek_only);
bool is_d = is_11_34 ? false : (a & 16); else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
uint16_t t = pages[001][is_d][page].pdr; return read_par(a, 1, word_mode, peek_only);
DOLOG(debug, !peek_only, "read supervisor %c PDR for %d: %o", is_d ? 'D' : 'I', page, t); else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t; return read_pdr(a, 0, word_mode, peek_only);
} else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
else if (a >= 0172240 && a < 0172300) { return read_par(a, 0, word_mode, peek_only);
int page = (a >> 1) & 7; else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
bool is_d = is_11_34 ? false : (a & 16); return read_pdr(a, 3, word_mode, peek_only);
uint16_t t = pages[001][is_d][page].par; else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
DOLOG(debug, !peek_only, "read supervisor %c PAR for %d: %o (phys: %07o)", is_d ? 'D' : 'I', page, t, t * 64); return read_par(a, 3, word_mode, peek_only);
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 (word_mode) { if (word_mode) {
if (a == 0177776) { // PSW if (a == ADDR_PSW) { // PSW
DOLOG(debug, !peek_only, "readb PSW LSB"); DOLOG(debug, !peek_only, "readb PSW LSB");
return c -> getPSW() & 255; return c -> getPSW() & 255;
} }
if (a == 0177777) { if (a == ADDR_PSW + 1) {
DOLOG(debug, !peek_only, "readb PSW MSB"); DOLOG(debug, !peek_only, "readb PSW MSB");
return c -> getPSW() >> 8; return c -> getPSW() >> 8;
} }
if (a == ADDR_STACKLIM) { // stack limit register
if (a == 0177774) { // stack limit register
DOLOG(debug, !peek_only, "readb stack limit register"); DOLOG(debug, !peek_only, "readb stack limit register");
return c -> getStackLimitRegister() & 0xff; 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"); DOLOG(debug, !peek_only, "readb stack limit register");
return c -> getStackLimitRegister() >> 8; return c -> getStackLimitRegister() >> 8;
} }
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5 if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
DOLOG(debug, !peek_only, "readb kernel R%d", a - 0177700); DOLOG(debug, !peek_only, "readb kernel R%d", a - ADDR_KERNEL_R);
return c -> getRegister(a - 0177700, 0, false) & 0xff; return c -> getRegister(a - ADDR_KERNEL_R, 0, false) & 0xff;
} }
if (a >= 0177710 && a <= 0177715) { // user R0-R5 if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
DOLOG(debug, !peek_only, "readb user R%d", a - 0177710); DOLOG(debug, !peek_only, "readb user R%d", a - ADDR_USER_R);
return c -> getRegister(a - 0177710, 3, false) & 0xff; 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"); DOLOG(debug, !peek_only, "readb kernel sp");
return c -> getStackPointer(0) & 0xff; return c -> getStackPointer(0) & 0xff;
} }
if (a == 0177707) { // PC if (a == ADDR_PC) { // PC
DOLOG(debug, !peek_only, "readb pc"); DOLOG(debug, !peek_only, "readb pc");
return c -> getPC() & 0xff; return c -> getPC() & 0xff;
} }
if (a == 0177716) { // supervisor SP if (a == ADDR_SV_SP) { // supervisor SP
DOLOG(debug, !peek_only, "readb supervisor sp"); DOLOG(debug, !peek_only, "readb supervisor sp");
return c -> getStackPointer(1) & 0xff; return c -> getStackPointer(1) & 0xff;
} }
if (a == 0177717) { // user SP if (a == ADDR_USER_SP) { // user SP
DOLOG(debug, !peek_only, "readb user sp"); DOLOG(debug, !peek_only, "readb user sp");
return c -> getStackPointer(3) & 0xff; return c -> getStackPointer(3) & 0xff;
} }
if (a == ADDR_CPU_ERR) { // cpu error register
if (a == 0177766) { // cpu error register
DOLOG(debug, !peek_only, "readb cpuerr"); DOLOG(debug, !peek_only, "readb cpuerr");
return CPUERR & 0xff; return CPUERR & 0xff;
} }
} }
else { else {
if (a == 0177572) { if (a == ADDR_MMR0) {
DOLOG(debug, !peek_only, "read MMR0"); DOLOG(debug, !peek_only, "read MMR0");
return MMR0; return MMR0;
} }
if (a == 0177574) { // MMR1 if (a == ADDR_MMR1) { // MMR1
DOLOG(debug, !peek_only, "read MMR1"); DOLOG(debug, !peek_only, "read MMR1");
return MMR1; return MMR1;
} }
if (a == 0177576) { // MMR2 if (a == ADDR_MMR2) { // MMR2
DOLOG(debug, !peek_only, "read MMR2"); DOLOG(debug, !peek_only, "read MMR2");
return MMR2; return MMR2;
} }
if (a == 0172516) { // MMR3 if (a == ADDR_MMR3) { // MMR3
DOLOG(debug, !peek_only, "read MMR3"); DOLOG(debug, !peek_only, "read MMR3");
return MMR3; return MMR3;
} }
if (a == 0177776) { // PSW if (a == ADDR_PSW) { // PSW
DOLOG(debug, !peek_only, "read PSW"); DOLOG(debug, !peek_only, "read PSW");
return c -> getPSW(); return c -> getPSW();
} }
if (a == 0177774) { // stack limit register if (a == ADDR_STACKLIM) { // stack limit register
return c -> getStackLimitRegister(); return c -> getStackLimitRegister();
} }
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5 if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
DOLOG(debug, !peek_only, "read kernel R%d", a - 0177700); DOLOG(debug, !peek_only, "read kernel R%d", a - ADDR_KERNEL_R);
return c -> getRegister(a - 0177700, 0, false); return c -> getRegister(a - ADDR_KERNEL_R, 0, false);
} }
if (a >= 0177710 && a <= 0177715) { // user R0-R5 if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
DOLOG(debug, !peek_only, "read user R%d", a - 0177710); DOLOG(debug, !peek_only, "read user R%d", a - ADDR_USER_R);
return c -> getRegister(a - 0177710, 3, false); 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"); DOLOG(debug, !peek_only, "read kernel sp");
return c -> getStackPointer(0); return c -> getStackPointer(0);
} }
if (a == 0177707) { // PC if (a == ADDR_PC) { // PC
DOLOG(debug, !peek_only, "read pc"); DOLOG(debug, !peek_only, "read pc");
return c -> getPC(); return c -> getPC();
} }
if (a == 0177716) { // supervisor SP if (a == ADDR_SV_SP) { // supervisor SP
DOLOG(debug, !peek_only, "read supervisor sp"); DOLOG(debug, !peek_only, "read supervisor sp");
return c -> getStackPointer(1); return c -> getStackPointer(1);
} }
if (a == 0177717) { // user SP if (a == ADDR_USER_SP) { // user SP
DOLOG(debug, !peek_only, "read user sp"); DOLOG(debug, !peek_only, "read user sp");
return c -> getStackPointer(3); return c -> getStackPointer(3);
} }
if (a == 0177766) { // cpu error register if (a == ADDR_CPU_ERR) { // cpu error register
DOLOG(debug, !peek_only, "read CPUERR"); DOLOG(debug, !peek_only, "read CPUERR");
return 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 // LO size register field must be all 1s, so subtract 1
constexpr uint32_t system_size = n_pages * 8192 / 64 - 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; return system_size >> 16;
if (a == 0177760) // system size LO if (a == ADDR_SYSSIZE) // system size LO
return system_size & 65535; return system_size & 65535;
if (a & 1) if (a & 1)
@ -278,8 +269,6 @@ 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' : ' '); DOLOG(debug, !peek_only, "UNHANDLED read %o(%c)", a, word_mode ? 'B' : ' ');
// c -> busError();
return -1; return -1;
} }
@ -322,6 +311,14 @@ void bus::setMMR0Bit(const int bit)
MMR0 |= 1 << 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) void bus::setMMR2(const uint16_t value)
{ {
MMR2 = 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 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) { if (MMR0 & 1) {
const uint8_t apf = a >> 13; // active page field 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; bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false;
uint16_t p_offset = a & 8191; // page offset uint16_t p_offset = a & 8191; // page offset
@ -343,17 +339,23 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
m_offset += p_offset; m_offset += p_offset;
if ((MMR3 & 16) == 0) // off is 18bit
m_offset &= 0x3ffff;
if (trap_on_failure) { if (trap_on_failure) {
if ((MMR0 & (1 << 9)) || c->get_34()) { 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 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 c->schedule_trap(0250); // invalid address
if (is_write)
pages[run_mode][d][apf].pdr |= 1 << 7; pages[run_mode][d][apf].pdr |= 1 << 7;
if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777;
MMR0 |= 1 << 13; // read-only MMR0 |= 1 << 13; // read-only
MMR0 &= ~(3 << 5); MMR0 &= ~(3 << 5);
@ -361,17 +363,27 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
MMR0 &= ~14; // add current page MMR0 &= ~14; // add current page
MMR0 |= apf << 1; MMR0 |= apf << 1;
}
DOLOG(debug, true, "MMR0: %06o", MMR0);
throw 1; throw 1;
} }
else if (!is_write) { // read else if (!is_write) { // read
if (access_control == 0 || access_control == 1 || access_control == 3 || access_control == 4 || access_control == 7) { 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 c->schedule_trap(0250); // invalid address
if (is_write)
pages[run_mode][d][apf].pdr |= 1 << 7; pages[run_mode][d][apf].pdr |= 1 << 7;
if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777;
if (access_control == 0 || access_control == 4)
MMR0 |= 1 << 15; // not resident
else
MMR0 |= 1 << 13; // read-only MMR0 |= 1 << 13; // read-only
MMR0 &= ~(3 << 5); MMR0 &= ~(3 << 5);
@ -379,52 +391,67 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
MMR0 &= ~14; // add current page MMR0 &= ~14; // add current page
MMR0 |= apf << 1; MMR0 |= apf << 1;
}
throw 2; 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) { if (m_offset >= n_pages * 8192) {
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", 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);
if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777;
MMR0 |= 1 << 15; // non-resident MMR0 |= 1 << 15; // non-resident
MMR0 &= ~14; // add current page MMR0 &= ~14; // add current page
MMR0 |= apf << 1; 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
c->schedule_trap(04); c->schedule_trap(04);
throw 3; throw 3;
} }
if ((p_offset > pdr_len && direction == false) || (p_offset < pdr_len && direction == true)) { uint16_t pdr_len = (pages[run_mode][d][apf].pdr >> 8) & 127;
DOLOG(debug, !peek_only, "bus::calculate_physical_address::p_offset %o >= %o", p_offset, pdr_len); uint16_t pdr_cmp = (a >> 6) & 127;
DOLOG(info, true, "TRAP(0250) (throw 4) on address %06o", a);
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 c->schedule_trap(0250); // invalid access
if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777;
MMR0 |= 1 << 14; // length MMR0 |= 1 << 14; // length
MMR0 &= ~14; // add current page MMR0 &= ~14; // add current page
MMR0 |= apf << 1; 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; 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 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
}
else {
m_offset = a;
} }
return m_offset; return m_offset;
@ -443,27 +470,70 @@ void bus::addToMMR1(const int8_t delta, const uint8_t reg)
MMR1 |= 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) 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; int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3;
if ((MMR0 & 1) == 1 && (a & 1) == 0 && a != 0177572) { if ((MMR0 & 1) == 1 && (a & 1) == 0 && a != ADDR_MMR0) {
const uint8_t apf = a >> 13; // active page field const uint8_t apf = a >> 13; // active page field
// TODO: D/I bool is_data = space == d_space;
pages[run_mode][0][apf].pdr |= 64; // set 'W' (written to) bit
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) { if (a >= 0160000) {
bool is_11_34 = c->get_34();
if (word_mode) { if (word_mode) {
assert(value < 256); assert(value < 256);
DOLOG(debug, true, "WRITE I/O %06o in byte mode", a); DOLOG(debug, true, "WRITE I/O %06o in byte mode", a);
} }
if (word_mode) { 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"); DOLOG(debug, true, "writeb PSW %s", a & 1 ? "MSB" : "LSB");
uint16_t vtemp = c -> getPSW(); 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; 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); DOLOG(debug, true, "writeb Set stack limit register: %o", value);
uint16_t v = c -> getStackLimitRegister(); 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 { else {
if (a == 0177776) { // PSW if (a == ADDR_PSW) { // PSW
DOLOG(debug, true, "write PSW %o", value); DOLOG(debug, true, "write PSW %o", value);
c -> setPSW(value & ~16, false); c -> setPSW(value & ~16, false);
return; return;
} }
if (a == 0177774) { // stack limit register if (a == ADDR_STACKLIM) { // stack limit register
DOLOG(debug, true, "write Set stack limit register: %o", value); DOLOG(debug, true, "write Set stack limit register: %o", value);
c -> setStackLimitRegister(value); c -> setStackLimitRegister(value);
return; return;
} }
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5 if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5
DOLOG(debug, true, "write kernel R%d: %o", a - 01777700, value); DOLOG(debug, true, "write kernel R%d: %o", a - ADDR_KERNEL_R, value);
c -> setRegister(a - 0177700, false, false, value); c -> setRegister(a - ADDR_KERNEL_R, false, false, value);
return; return;
} }
if (a >= 0177710 && a <= 0177715) { // user R0-R5 if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5
DOLOG(debug, true, "write user R%d: %o", a - 01777710, value); DOLOG(debug, true, "write user R%d: %o", a - ADDR_USER_R, value);
c -> setRegister(a - 0177710, true, false, value); c -> setRegister(a - ADDR_USER_R, true, false, value);
return; return;
} }
if (a == 0177706) { // kernel SP if (a == ADDR_KERNEL_SP) { // kernel SP
DOLOG(debug, true, "write kernel SP: %o", value); DOLOG(debug, true, "write kernel SP: %o", value);
c -> setStackPointer(0, value); c -> setStackPointer(0, value);
return; return;
} }
if (a == 0177707) { // PC if (a == ADDR_PC) { // PC
DOLOG(debug, true, "write PC: %o", value); DOLOG(debug, true, "write PC: %o", value);
c -> setPC(value); c -> setPC(value);
return; return;
} }
if (a == 0177716) { // supervisor SP if (a == ADDR_SV_SP) { // supervisor SP
DOLOG(debug, true, "write supervisor sp: %o", value); DOLOG(debug, true, "write supervisor sp: %o", value);
c -> setStackPointer(1, value); c -> setStackPointer(1, value);
return; return;
} }
if (a == 0177717) { // user SP if (a == ADDR_USER_SP) { // user SP
DOLOG(debug, true, "write user sp: %o", value); DOLOG(debug, true, "write user sp: %o", value);
c -> setStackPointer(3, value); c -> setStackPointer(3, value);
return; return;
} }
if (a == 0177770) { // microprogram break register if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register
return; return;
} }
} }
if (a == 0177766) { // cpu error register if (a == ADDR_CPU_ERR) { // cpu error register
DOLOG(debug, true, "write CPUERR: %o", value); DOLOG(debug, true, "write CPUERR: %o", value);
CPUERR = 0; CPUERR = 0;
return; return;
} }
if (a == 0172516) { // MMR3 if (a == ADDR_MMR3) { // MMR3
DOLOG(debug, true, "write set MMR3: %o", value); DOLOG(debug, true, "write set MMR3: %o", value);
MMR3 = value & 067; MMR3 = value & 067;
return; return;
} }
if (a == 0177572) { // MMR0 if (a == ADDR_MMR0) { // MMR0
DOLOG(debug, true, "write set MMR0: %o", value); DOLOG(debug, true, "write set MMR0: %o", value);
setMMR0(value); setMMR0(value);
@ -561,13 +631,13 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
return; return;
} }
if (a == 0177772) { // PIR if (a == ADDR_PIR) { // PIR
DOLOG(debug, true, "write set PIR: %o", value); DOLOG(debug, true, "write set PIR: %o", value);
PIR = value; // TODO PIR = value; // TODO
return; 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); DOLOG(debug, true, "write set LFC/SR: %o", value);
lf_csr = value; lf_csr = value;
return; return;
@ -595,153 +665,49 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
/// MMU /// /// MMU ///
// supervisor // supervisor
if (a >= 0172200 && a < 0172240) { if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) {
bool is_d = is_11_34 ? false : (a & 16); write_pdr(a, 1, value, word_mode);
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);
return; return;
} }
if (a >= 0172240 && a < 0172300) { if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) {
bool is_d = is_11_34 ? false : (a & 16); write_par(a, 1, value, word_mode);
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);
return; return;
} }
// kernel // kernel
if (a >= 0172300 && a < 0172340) { if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) {
bool is_d = is_11_34 ? false : (a & 16); write_pdr(a, 0, value, word_mode);
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);
return; return;
} }
if (a >= 0172340 && a < 0172400) { if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) {
bool is_d = is_11_34 ? false : (a & 16); write_par(a, 0, value, word_mode);
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);
return; return;
} }
// user // user
if (a >= 0177600 && a < 0177640) { if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) {
bool is_d = is_11_34 ? false : (a & 16); write_pdr(a, 3, value, word_mode);
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);
return; return;
} }
if (a >= 0177640 && a < 0177700) { if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END) {
bool is_d = is_11_34 ? false : (a & 16); write_par(a, 3, value, word_mode);
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);
return; return;
} }
//// ////
if (a == 0177746) { // cache control register if (a == ADDR_CCR) { // cache control register
// TODO // TODO
return; return;
} }
if (a == 0177570) { // switch register if (a == ADDR_CONSW) { // switch register
switch_register = value; switch_register = value;
return; return;
} }
/////////// ///////////
if (a == 0177374) { // TODO DOLOG(debug, true, "UNHANDLED write %o(%c): %o", a, word_mode ? 'B' : 'W', value);
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);
// c -> busError(); // c -> busError();

52
bus.h
View file

@ -10,6 +10,47 @@
#include "rk05.h" #include "rk05.h"
#include "rl02.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 cpu;
class memory; class memory;
class tty; class tty;
@ -41,7 +82,12 @@ private:
uint16_t lf_csr { 0 }; 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: public:
bus(); bus();
@ -49,7 +95,8 @@ public:
void clearmem(); 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_cpu(cpu *const c) { this -> c = c; }
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; } 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 addToMMR1(const int8_t delta, const uint8_t reg);
void setMMR0(int value); void setMMR0(int value);
void setMMR0Bit(const int bit); void setMMR0Bit(const int bit);
void clearMMR0Bit(const int bit);
void setMMR2(const uint16_t value); void setMMR2(const uint16_t value);
uint16_t get_switch_register() const { return switch_register; } uint16_t get_switch_register() const { return switch_register; }

View file

@ -32,7 +32,7 @@ int console_posix::wait_for_char_ll(const short timeout)
{ {
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 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 getchar();
return -1; return -1;

162
cpu.cpp
View file

@ -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); 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) uint16_t cpu::addRegister(const int nr, const bool prev_mode, const uint16_t value)
@ -246,18 +246,16 @@ int cpu::getPSW_spl() const
return (psw >> 5) & 7; 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) { 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 v |= psw & 0174340;
psw |= v & ~0174000;
} }
else {
psw = v; psw = v;
} }
}
bool cpu::check_queued_interrupts() 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; 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) 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 dst_value = b->readWord(dst_addr);
int16_t result = 0; int16_t result = 0;
bool set_flags = dst_addr != 0177776; bool set_flags = dst_addr != ADDR_PSW;
if (instr & 0x8000) { if (instr & 0x8000) {
result = (dst_value - ssrc_value) & 0xffff; result = (dst_value - ssrc_value) & 0xffff;
@ -761,7 +759,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
else { else {
b->write(a, false, vl, false); b->write(a, false, vl, false);
set_flags = a != 0177776; set_flags = a != ADDR_PSW;
} }
if (set_flags) { if (set_flags) {
@ -818,7 +816,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
v = ((v & 0xff) << 8) | (v >> 8); v = ((v & 0xff) << 8) | (v >> 8);
set_flags = a != 0177776; set_flags = a != ADDR_PSW;
b->writeWord(a, v); b->writeWord(a, v);
} }
@ -847,7 +845,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); 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); b -> write(a, word_mode, 0, false);
} }
@ -887,7 +885,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else else
v ^= 0xffff; v ^= 0xffff;
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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); uint16_t v = b -> read(a, word_mode, false);
int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff); int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(vl, word_mode)); 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); uint16_t v = b -> read(a, word_mode, false);
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff); int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(vl, word_mode)); 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); b->write(a, word_mode, v, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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); b->write(a, word_mode, v, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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); b->write(a, word_mode, v, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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); b->write(a, word_mode, temp, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_c(new_carry); setPSW_c(new_carry);
@ -1181,7 +1179,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, temp, false); b->write(a, word_mode, temp, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_c(new_carry); setPSW_c(new_carry);
@ -1240,7 +1238,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, v, false); b->write(a, word_mode, v, false);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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 vl = b -> read(a, word_mode, false);
uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff); uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776; bool set_flags = a != ADDR_PSW;
if (set_flags) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_n(SIGN(v, word_mode));
@ -1287,7 +1285,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b00110101: { // MFPD/MFPI case 0b00110101: { // MFPD/MFPI
// always words: word_mode-bit is to select between MFPI and MFPD // 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) if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(-2, 6); b->addToMMR1(-2, 6);
@ -1301,7 +1299,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
// calculate address in current address space // calculate address in current address space
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false);
set_flags = a != 0177776; set_flags = a != ADDR_PSW;
// read from previous space // read from previous space
v = b -> read(a, false, true); v = b -> read(a, false, true);
@ -1321,7 +1319,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b00110110: { // MTPI/MTPD case 0b00110110: { // MTPI/MTPD
// always words: word_mode-bit is to select between MTPI and 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) if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(2, 6); b->addToMMR1(2, 6);
@ -1336,7 +1334,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); 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 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) void cpu::pushStack(const uint16_t v)
{ {
if (getRegister(6) == stackLimitRegister) { if (getRegister(6) == stackLimitRegister) {
DOLOG(debug, true, "stackLimitRegister reached"); DOLOG(debug, true, "stackLimitRegister reached %06o while pushing %06o", stackLimitRegister, v);
trap(123, 7); // TODO trap(123, 7); // TODO
} }
@ -1548,10 +1546,15 @@ bool cpu::misc_operations(const uint16_t instr)
case 0b0000000000000001: // WAIT case 0b0000000000000001: // WAIT
return true; return true;
case 0b0000000000000010: // RTI case 0b0000000000000010: { // RTI
setPC(popStack()); setPC(popStack());
setPSW(popStack(), !!((getPSW() >> 12) & 3));
uint16_t replacement_psw = popStack();
setPSW(replacement_psw, true);
return true; return true;
}
case 0b0000000000000011: // BPT case 0b0000000000000011: // BPT
trap(014); trap(014);
@ -1561,10 +1564,15 @@ bool cpu::misc_operations(const uint16_t instr)
trap(020); trap(020);
return true; return true;
case 0b0000000000000110: // RTT case 0b0000000000000110: { // RTT
setPC(popStack()); setPC(popStack());
setPSW(popStack(), !!((getPSW() >> 12) & 3));
uint16_t replacement_psw = popStack();
setPSW(replacement_psw, true);
return true; return true;
}
case 0b0000000000000111: // MFPT case 0b0000000000000111: // MFPT
if (emulateMFPT) if (emulateMFPT)
@ -1637,28 +1645,83 @@ bool cpu::misc_operations(const uint16_t instr)
return false; return false;
} }
void cpu::busError()
{
trap(4);
}
void cpu::schedule_trap(const uint16_t vector) void cpu::schedule_trap(const uint16_t vector)
{ {
scheduled_trap = 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(); DOLOG(debug, true, "*** CPU::TRAP, MMR0: %06o, MMR2: %06o ***", b->getMMR0(), b->getMMR2());
uint16_t before_pc = getPC();
int processing_trap_depth = 0;
uint16_t before_psw = 0;
uint16_t before_pc = 0;
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 // make sure the trap vector is retrieved from kernel space
psw &= 037777; // mask off 14/15 psw &= 037777; // mask off 14/15
if ((b->getMMR0() & 0160000) == 0) { setPC(b->readWord(vector + 0));
b->setMMR2(vector);
b->addToMMR1(-2, 6); // switch to kernel mode & update 'previous mode'
b->addToMMR1(-2, 6); 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)); setPC(b->readWord(vector + 0, d_space));
@ -1772,6 +1835,7 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
// single_operand_instructions // single_operand_instructions
switch(so_opcode) { switch(so_opcode) {
case 0b00000011: case 0b00000011:
if (!word_mode)
text = "SWAB " + dst_text.operand; text = "SWAB " + dst_text.operand;
break; break;
@ -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)); work_values_str.push_back(format("%06o", v));
out.insert({ "work-values", work_values_str }); out.insert({ "work-values", work_values_str });
out.insert({ "MMR0", { format("%06o", b->getMMR0()) } });
out.insert({ "MMR2", { format("%06o", b->getMMR2()) } });
return out; return out;
} }
@ -2156,7 +2223,7 @@ void cpu::step_a()
b->clearMMR1(); b->clearMMR1();
if (scheduled_trap) { if (scheduled_trap) {
trap(scheduled_trap, 7); trap(scheduled_trap, 7, true);
scheduled_trap = 0; scheduled_trap = 0;
@ -2176,12 +2243,13 @@ void cpu::step_b()
if ((b->getMMR0() & 0160000) == 0) if ((b->getMMR0() & 0160000) == 0)
b->setMMR2(temp_pc); b->setMMR2(temp_pc);
if (temp_pc & 1)
busError();
try { try {
uint16_t instr = b->readWord(temp_pc); 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); addRegister(7, false, 2);
if (double_operand_instructions(instr)) if (double_operand_instructions(instr))

5
cpu.h
View file

@ -95,8 +95,7 @@ public:
void init_interrupt_queue(); void init_interrupt_queue();
void queue_interrupt(const uint8_t level, const uint8_t vector); void queue_interrupt(const uint8_t level, const uint8_t vector);
void busError(); void trap(uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
void trap(const uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
void schedule_trap(const uint16_t vector); void schedule_trap(const uint16_t vector);
void setEmulateMFPT(const bool v) { emulateMFPT = v; } void setEmulateMFPT(const bool v) { emulateMFPT = v; }
@ -118,7 +117,7 @@ public:
void setBitPSW(const int bit, const bool v); void setBitPSW(const int bit, const bool v);
uint16_t getPSW() const { return psw; } 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; } uint16_t getStackLimitRegister() { return stackLimitRegister; }
void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; } void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; }

View file

@ -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 instruction = data["instruction-text"].at(0);
std::string MMR0 = data["MMR0"].at(0);
std::string MMR2 = data["MMR2"].at(0);
std::string result; std::string result;
if (instruction_only) 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() work_values.c_str()
); );
else 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[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, registers[6].c_str(), pc,
psw.c_str(), psw.c_str(),
instruction_values.c_str(), instruction_values.c_str(),
instruction.c_str(), instruction.c_str(),
work_values.c_str() MMR0.c_str(), MMR2.c_str()
); );
if (cnsl) 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("MMR2: %06o", b->getMMR2()));
cnsl->put_string_lf(format("MMR3: %06o", mmr3)); cnsl->put_string_lf(format("MMR3: %06o", mmr3));
dump_par_pdr(cnsl, b, 0172200, 0172240, "supervisor i-space", 0); dump_par_pdr(cnsl, b, ADDR_PDR_SV_START, ADDR_PAR_SV_START, "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 + 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, ADDR_PDR_K_START, ADDR_PAR_K_START, "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 + 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, ADDR_PDR_U_START, ADDR_PAR_U_START, "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 + 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) 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(); cpu *const c = b->getCpu();
b->set_debug_mode(true); b->set_debug_mode();
bool single_step = false; 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:"); cnsl->put_string_lf("Breakpoints:");
for(auto pc : bps) { for(auto a : bps) {
cnsl->put_string_lf(format(" %06o", pc)); cnsl->put_string(format(" %06o> ", a));
pc += disassemble(c, cnsl, pc, true); disassemble(c, cnsl, a, true);
} }
continue; continue;
@ -224,6 +227,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
if (val != -1) if (val != -1)
cnsl->put_string_lf(format("value at %06o, octal: %o, hex: %x, dec: %d\n", addr, val, val, val)); 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") { else if (cmd == "reset" || cmd == "r") {
#if defined(ESP32) #if defined(ESP32)

View file

@ -1,19 +1,35 @@
#include <unistd.h> #include <unistd.h>
#include "console.h"
#include "cpu.h" #include "cpu.h"
#include "kw11-l.h" #include "kw11-l.h"
#include "utils.h"
#if defined(ESP32)
kw11_l::kw11_l(bus *const b) : b(b) 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)); th = new std::thread(std::ref(*this));
#endif
} }
kw11_l::~kw11_l() kw11_l::~kw11_l()
{ {
stop_flag = true; stop_flag = true;
#if !defined(ESP32)
th->join(); th->join();
#endif
delete th; delete th;
} }
@ -21,11 +37,16 @@ kw11_l::~kw11_l()
void kw11_l::operator()() void kw11_l::operator()()
{ {
while(!stop_flag) { while(!stop_flag) {
if (*cnsl->get_running_flag()) {
b->set_lf_crs_b7(); b->set_lf_crs_b7();
if (b->get_lf_crs() & 64) if (b->get_lf_crs() & 64)
b->getCpu()->queue_interrupt(6, 0100); b->getCpu()->queue_interrupt(6, 0100);
usleep(1000000 / 50); myusleep(1000000 / 50); // 20ms
}
else {
myusleep(1000000 / 10); // 100ms
}
} }
} }

View file

@ -8,11 +8,13 @@ class kw11_l
{ {
private: private:
bus *const b { nullptr }; bus *const b { nullptr };
console *const cnsl { nullptr };
std::thread * th { nullptr }; std::thread * th { nullptr };
std::atomic_bool stop_flag { false }; std::atomic_bool stop_flag { false };
public: public:
kw11_l(bus *const b); kw11_l(bus *const b, console *const cnsl);
virtual ~kw11_l(); virtual ~kw11_l();
void operator()(); void operator()();

View file

@ -178,7 +178,7 @@ void load_p11_x11(bus *const b, const std::string & file)
break; break;
if (n) { if (n) {
uint8_t byte = strtol(buffer, NULL, 16); uint8_t byte = strtol(buffer, nullptr, 16);
b->writeByte(addr, byte); b->writeByte(addr, byte);
@ -189,8 +189,8 @@ void load_p11_x11(bus *const b, const std::string & file)
else { else {
std::vector<std::string> parts = split(buffer, " "); std::vector<std::string> parts = split(buffer, " ");
addr = strtol(parts[0].c_str(), NULL, 16); addr = strtol(parts[0].c_str(), nullptr, 16);
n = strtol(parts[1].c_str(), NULL, 16); n = strtol(parts[1].c_str(), nullptr, 16);
} }
} }

View file

@ -2,6 +2,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "error.h" #include "error.h"
@ -71,7 +72,7 @@ void dolog(const log_level_t ll, const char *fmt, ...)
uint64_t now = get_us(); uint64_t now = get_us();
time_t t_now = now / 1000000; time_t t_now = now / 1000000;
struct tm tm { 0 }; tm tm { 0 };
if (!localtime_r(&t_now, &tm)) if (!localtime_r(&t_now, &tm))
error_exit(true, "localtime_r failed"); error_exit(true, "localtime_r failed");

View file

@ -44,10 +44,12 @@ void help()
printf("-h this help\n"); printf("-h this help\n");
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\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 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("-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("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n");
printf("-n ncurses UI\n"); printf("-n ncurses UI\n");
printf("-d enable debugger\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("-t enable tracing (disassemble to stderr, requires -d as well)\n");
printf("-l x log to file x\n"); printf("-l x log to file x\n");
printf("-L x,y set log level for screen (x) and file (y)\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> rk05_files;
std::vector<std::string> rl02_files; std::vector<std::string> rl02_files;
bool testCases = false;
bool run_debugger = false; bool run_debugger = false;
bool tracing = false; bool tracing = false;
@ -77,14 +78,26 @@ int main(int argc, char *argv[])
std::string tape; std::string tape;
uint16_t console_switches = 0;
std::string test;
int opt = -1; 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) { switch(opt) {
case 'h': case 'h':
help(); help();
return 1; return 1;
case 'Q':
test = optarg;
break;
case 's':
console_switches = strtol(optarg, NULL, 8);
break;
case '3': case '3':
mode_34 = true; // switch from 11/70 to 11/34 mode_34 = true; // switch from 11/70 to 11/34
break; break;
@ -155,13 +168,13 @@ int main(int argc, char *argv[])
bus *b = new bus(); bus *b = new bus();
b->set_console_switches(console_switches);
cpu *c = new cpu(b, &event); cpu *c = new cpu(b, &event);
b->add_cpu(c); b->add_cpu(c);
c->set_34(mode_34); c->set_34(mode_34);
kw11_l *lf = new kw11_l(b);
c->setEmulateMFPT(true); c->setEmulateMFPT(true);
std::atomic_bool interrupt_emulation { false }; std::atomic_bool interrupt_emulation { false };
@ -182,11 +195,19 @@ int main(int argc, char *argv[])
cnsl = new console_posix(&event, b); cnsl = new console_posix(&event, b);
} }
if (rk05_files.empty() == false) 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 (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())); b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
}
if (bootloader != BL_NONE) if (bootloader != BL_NONE)
setBootLoader(b, bootloader); setBootLoader(b, bootloader);
@ -210,6 +231,9 @@ int main(int argc, char *argv[])
sigaction(SIGTERM, &sa, nullptr); sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT , &sa, nullptr); sigaction(SIGINT , &sa, nullptr);
if (test.empty() == false)
load_p11_x11(b, test);
#if 0 #if 0
// loadbin(b, 0, "test.dat"); // loadbin(b, 0, "test.dat");
// c->setRegister(7, 0); // c->setRegister(7, 0);
@ -227,6 +251,8 @@ int main(int argc, char *argv[])
return 0; return 0;
#endif #endif
kw11_l *lf = new kw11_l(b, cnsl);
cnsl->start_thread(); cnsl->start_thread();
if (run_debugger) if (run_debugger)

View file

@ -1,3 +0,0 @@
// (C) 2018 by Folkert van Heusden
// Released under Apache License v2.0
void tests(cpu *const c);

View file

@ -4,10 +4,12 @@
#include <Arduino.h> #include <Arduino.h>
#endif #endif
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <string.h> #include <string.h>
#include <time.h>
#include <vector> #include <vector>
#include <sys/time.h> #include <sys/time.h>
@ -41,7 +43,7 @@ unsigned long get_ms()
#if defined(ESP32) #if defined(ESP32)
return millis(); return millis();
#else #else
struct timeval tv; timeval tv;
// TODO replace gettimeofday by clock_gettime // TODO replace gettimeofday by clock_gettime
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@ -55,7 +57,7 @@ uint64_t get_us()
#if defined(ESP32) #if defined(ESP32)
return micros(); return micros();
#else #else
struct timeval tv; timeval tv;
// TODO replace gettimeofday by clock_gettime // TODO replace gettimeofday by clock_gettime
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@ -72,21 +74,35 @@ int parity(int v)
void myusleep(uint64_t us) void myusleep(uint64_t us)
{ {
#if defined(ESP32) #if defined(ESP32)
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); delayMicroseconds(us);
break;
}
}
#else #else
struct timespec req; timespec req;
req.tv_sec = us / 1000000l; req.tv_sec = us / 1000000l;
req.tv_nsec = (us % 1000000l) * 1000l; req.tv_nsec = (us % 1000000l) * 1000l;
for(;;) { for(;;) {
struct timespec rem { 0, 0 }; timespec rem { 0, 0 };
int rc = nanosleep(&req, &rem); int rc = nanosleep(&req, &rem);
if (rc == 0 || (rc == -1 && errno != EINTR)) if (rc == 0 || (rc == -1 && errno != EINTR))
break; break;
memcpy(&req, &rem, sizeof(struct timespec)); memcpy(&req, &rem, sizeof(timespec));
} }
#endif #endif
} }