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;
|
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);
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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
474
bus.cpp
|
@ -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
52
bus.h
|
@ -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; }
|
||||||
|
|
|
@ -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
162
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);
|
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
5
cpu.h
|
@ -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; }
|
||||||
|
|
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 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)
|
||||||
|
|
27
kw11-l.cpp
27
kw11-l.cpp
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
kw11-l.h
4
kw11-l.h
|
@ -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()();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
log.cpp
3
log.cpp
|
@ -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");
|
||||||
|
|
||||||
|
|
40
main.cpp
40
main.cpp
|
@ -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)
|
||||||
|
|
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);
|
|
26
utils.cpp
26
utils.cpp
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue