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;
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);

View file

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

View file

@ -1,10 +1,10 @@
[platformio]
default_envs = serial32
default_envs = ESP32
src_dir = .
[env:serial32]
[env:ESP32]
lib_ldf_mode = deep+
src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
build_src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
platform = espressif32
board = wemos_d1_mini32
framework = arduino
@ -14,3 +14,16 @@ lib_deps = greiman/SdFat@^2.1.2
adafruit/Adafruit NeoPixel@^1.10.4
build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
build_unflags = -std=gnu++11 -Os
#[env:PICO]
#lib_ldf_mode = deep+
#src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<build> -<player.cpp>
#platform = raspberrypi
#board = pico
#framework = arduino
#monitor_speed = 115200
#upload_speed = 1000000
#lib_deps = greiman/SdFat@^2.1.2
# adafruit/Adafruit NeoPixel@^1.10.4
#build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
#build_unflags = -std=gnu++11 -Os

514
bus.cpp
View file

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

52
bus.h
View file

@ -10,6 +10,47 @@
#include "rk05.h"
#include "rl02.h"
#define ADDR_MMR0 0177572
#define ADDR_MMR1 0177574
#define ADDR_MMR2 0177576
#define ADDR_MMR3 0172516
#define ADDR_PIR 0177772
#define ADDR_LFC 0177546 // line frequency
#define ADDR_MAINT 0177750
#define ADDR_CONSW 0177570
#define ADDR_KW11P 0172540
#define ADDR_LP11CSR 0177514 // printer
#define ADDR_PDR_SV_START 0172200
#define ADDR_PDR_SV_END 0172240
#define ADDR_PAR_SV_START 0172240
#define ADDR_PAR_SV_END 0172300
#define ADDR_PDR_K_START 0172300
#define ADDR_PDR_K_END 0172340
#define ADDR_PAR_K_START 0172340
#define ADDR_PAR_K_END 0172400
#define ADDR_PDR_U_START 0177600
#define ADDR_PDR_U_END 0177640
#define ADDR_PAR_U_START 0177640
#define ADDR_PAR_U_END 0177700
#define ADDR_PSW 0177776
#define ADDR_STACKLIM 0177774
#define ADDR_KERNEL_R 0177700
#define ADDR_USER_R 0177710
#define ADDR_KERNEL_SP 0177706
#define ADDR_PC 0177707
#define ADDR_SV_SP 0177716
#define ADDR_USER_SP 0177717
#define ADDR_CPU_ERR 0177766
#define ADDR_SYSSIZE 0177760
#define ADDR_MICROPROG_BREAK_REG 0177770
#define ADDR_CCR 0177746
class cpu;
class memory;
class tty;
@ -41,7 +82,12 @@ private:
uint16_t lf_csr { 0 };
bool debug_mode { false };
uint16_t console_switches { 0 };
uint16_t read_pdr (const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only);
uint16_t read_par (const uint32_t a, const int run_mode, const bool word_mode, const bool peek_only);
void write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode);
void write_par(const uint32_t a, const int run_mode, const uint16_t value, const bool word_mode);
public:
bus();
@ -49,7 +95,8 @@ public:
void clearmem();
void set_debug_mode(const bool state) { debug_mode = state; }
void set_console_switches(const uint16_t new_state) { console_switches = new_state; }
void set_debug_mode() { console_switches |= 128; }
void add_cpu(cpu *const c) { this -> c = c; }
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; }
@ -87,6 +134,7 @@ public:
void addToMMR1(const int8_t delta, const uint8_t reg);
void setMMR0(int value);
void setMMR0Bit(const int bit);
void clearMMR0Bit(const int bit);
void setMMR2(const uint16_t value);
uint16_t get_switch_register() const { return switch_register; }

View file

@ -32,7 +32,7 @@ int console_posix::wait_for_char_ll(const short timeout)
{
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, timeout } };
if (poll(fds, 1, 0) == 1 && fds[0].revents)
if (poll(fds, 1, timeout) == 1 && fds[0].revents)
return getchar();
return -1;

170
cpu.cpp
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);
return a != 0177776;
return a != ADDR_PSW;
}
uint16_t cpu::addRegister(const int nr, const bool prev_mode, const uint16_t value)
@ -246,17 +246,15 @@ int cpu::getPSW_spl() const
return (psw >> 5) & 7;
}
void cpu::setPSW(const uint16_t v, const bool limited)
void cpu::setPSW(uint16_t v, const bool limited)
{
if (limited) {
psw |= v & 0174000; // current & previous mode can only be increased, 11 can only be set
v &= 0174037;
psw &= 0174000; // retain upper 5 bit
psw |= v & ~0174000;
}
else {
psw = v;
v |= psw & 0174340;
}
psw = v;
}
bool cpu::check_queued_interrupts()
@ -406,7 +404,7 @@ bool cpu::putGAM(const uint8_t mode, const int reg, const bool word_mode, const
break;
}
return addr == -1 || addr != 0177776;
return addr == -1 || addr != ADDR_PSW;
}
uint16_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode, const bool prev_mode)
@ -556,7 +554,7 @@ bool cpu::double_operand_instructions(const uint16_t instr)
int16_t dst_value = b->readWord(dst_addr);
int16_t result = 0;
bool set_flags = dst_addr != 0177776;
bool set_flags = dst_addr != ADDR_PSW;
if (instr & 0x8000) {
result = (dst_value - ssrc_value) & 0xffff;
@ -761,7 +759,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
else {
b->write(a, false, vl, false);
set_flags = a != 0177776;
set_flags = a != ADDR_PSW;
}
if (set_flags) {
@ -818,7 +816,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
v = ((v & 0xff) << 8) | (v >> 8);
set_flags = a != 0177776;
set_flags = a != ADDR_PSW;
b->writeWord(a, v);
}
@ -847,7 +845,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false);
set_flags = a != 0177776;
set_flags = a != ADDR_PSW;
b -> write(a, word_mode, 0, false);
}
@ -887,7 +885,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else
v ^= 0xffff;
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -920,7 +918,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
uint16_t v = b -> read(a, word_mode, false);
int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(vl, word_mode));
@ -953,7 +951,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
uint16_t v = b -> read(a, word_mode, false);
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(vl, word_mode));
@ -988,7 +986,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, v, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -1026,7 +1024,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, v, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -1068,7 +1066,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, v, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -1130,7 +1128,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, temp, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_c(new_carry);
@ -1181,7 +1179,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, temp, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_c(new_carry);
@ -1240,7 +1238,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
b->write(a, word_mode, v, false);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -1271,7 +1269,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
uint16_t vl = b -> read(a, word_mode, false);
uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff);
bool set_flags = a != 0177776;
bool set_flags = a != ADDR_PSW;
if (set_flags) {
setPSW_n(SIGN(v, word_mode));
@ -1287,7 +1285,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b00110101: { // MFPD/MFPI
// always words: word_mode-bit is to select between MFPI and MFPD
assert(!word_mode); // TODO
// NOTE: this code does not work for D/I split setups! TODO
if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(-2, 6);
@ -1301,7 +1299,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
// calculate address in current address space
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false);
set_flags = a != 0177776;
set_flags = a != ADDR_PSW;
// read from previous space
v = b -> read(a, false, true);
@ -1321,7 +1319,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b00110110: { // MTPI/MTPD
// always words: word_mode-bit is to select between MTPI and MTPD
assert(!word_mode); // TODO
// NOTE: this code does not work for D/I split setups! TODO
if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(2, 6);
@ -1336,7 +1334,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false);
set_flags = a != 0177776;
set_flags = a != ADDR_PSW;
b -> write(a, false, v, true); // put in '13/12' address space
}
@ -1517,7 +1515,7 @@ bool cpu::condition_code_operations(const uint16_t instr)
void cpu::pushStack(const uint16_t v)
{
if (getRegister(6) == stackLimitRegister) {
DOLOG(debug, true, "stackLimitRegister reached");
DOLOG(debug, true, "stackLimitRegister reached %06o while pushing %06o", stackLimitRegister, v);
trap(123, 7); // TODO
}
@ -1548,10 +1546,15 @@ bool cpu::misc_operations(const uint16_t instr)
case 0b0000000000000001: // WAIT
return true;
case 0b0000000000000010: // RTI
case 0b0000000000000010: { // RTI
setPC(popStack());
setPSW(popStack(), !!((getPSW() >> 12) & 3));
uint16_t replacement_psw = popStack();
setPSW(replacement_psw, true);
return true;
}
case 0b0000000000000011: // BPT
trap(014);
@ -1561,10 +1564,15 @@ bool cpu::misc_operations(const uint16_t instr)
trap(020);
return true;
case 0b0000000000000110: // RTT
case 0b0000000000000110: { // RTT
setPC(popStack());
setPSW(popStack(), !!((getPSW() >> 12) & 3));
uint16_t replacement_psw = popStack();
setPSW(replacement_psw, true);
return true;
}
case 0b0000000000000111: // MFPT
if (emulateMFPT)
@ -1637,28 +1645,83 @@ bool cpu::misc_operations(const uint16_t instr)
return false;
}
void cpu::busError()
{
trap(4);
}
void cpu::schedule_trap(const uint16_t vector)
{
scheduled_trap = vector;
}
void cpu::trap(const uint16_t vector, const int new_ipl, const bool is_interrupt)
// 'is_interrupt' is not correct naming; it is true for mmu faults and interrupts
void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
{
uint16_t before_psw = getPSW();
uint16_t before_pc = getPC();
DOLOG(debug, true, "*** CPU::TRAP, MMR0: %06o, MMR2: %06o ***", b->getMMR0(), b->getMMR2());
// make sure the trap vector is retrieved from kernel space
psw &= 037777; // mask off 14/15
int processing_trap_depth = 0;
uint16_t before_psw = 0;
uint16_t before_pc = 0;
if ((b->getMMR0() & 0160000) == 0) {
b->setMMR2(vector);
b->addToMMR1(-2, 6);
b->addToMMR1(-2, 6);
for(;;) {
try {
processing_trap_depth++;
bool kernel_mode = psw >> 14;
if (processing_trap_depth >= 2) {
DOLOG(debug, true, "Trap depth %d", processing_trap_depth);
if (kernel_mode)
vector = 4;
setRegister(6, 04);
if (processing_trap_depth >= 3) {
// TODO: halt?
}
}
else {
before_psw = getPSW();
before_pc = getPC();
if ((b->getMMR0() & 0160000) == 0 && vector != 4) {
b->setMMR2(vector);
b->addToMMR1(-2, 6);
b->addToMMR1(-2, 6);
}
if (is_interrupt)
b->clearMMR0Bit(12);
else
b->setMMR0Bit(12); // it's a trap
}
// make sure the trap vector is retrieved from kernel space
psw &= 037777; // mask off 14/15
setPC(b->readWord(vector + 0));
// switch to kernel mode & update 'previous mode'
uint16_t new_psw = b->readWord(vector + 2) & 0147777; // mask off old 'previous mode'
if (new_ipl != -1)
new_psw = (new_psw & ~0xe0) | (new_ipl << 5);
new_psw |= (before_psw >> 2) & 030000; // apply new 'previous mode'
setPSW(new_psw, false);
// DOLOG(info, true, "R6: %06o, before PSW: %06o, new PSW: %06o", getRegister(6), before_psw, new_psw);
//
if (processing_trap_depth >= 2 && kernel_mode)
setRegister(6, 04);
pushStack(before_psw);
pushStack(before_pc);
// if we reach this point then the trap was processed without causing
// another trap
break;
}
catch(const int exception) {
DOLOG(debug, true, "trap during execution of trap (%d)", exception);
setPSW(before_psw, false);
}
}
setPC(b->readWord(vector + 0, d_space));
@ -1772,7 +1835,8 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
// single_operand_instructions
switch(so_opcode) {
case 0b00000011:
text = "SWAB " + dst_text.operand;
if (!word_mode)
text = "SWAB " + dst_text.operand;
break;
case 0b000101000:
@ -2147,6 +2211,9 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
work_values_str.push_back(format("%06o", v));
out.insert({ "work-values", work_values_str });
out.insert({ "MMR0", { format("%06o", b->getMMR0()) } });
out.insert({ "MMR2", { format("%06o", b->getMMR2()) } });
return out;
}
@ -2156,7 +2223,7 @@ void cpu::step_a()
b->clearMMR1();
if (scheduled_trap) {
trap(scheduled_trap, 7);
trap(scheduled_trap, 7, true);
scheduled_trap = 0;
@ -2176,12 +2243,13 @@ void cpu::step_b()
if ((b->getMMR0() & 0160000) == 0)
b->setMMR2(temp_pc);
if (temp_pc & 1)
busError();
try {
uint16_t instr = b->readWord(temp_pc);
// FILE *fh = fopen("/home/folkert/kek.dat", "a+");
// fprintf(fh, "%06o %06o\n", temp_pc, instr);
// fclose(fh);
addRegister(7, false, 2);
if (double_operand_instructions(instr))

5
cpu.h
View file

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

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 MMR0 = data["MMR0"].at(0);
std::string MMR2 = data["MMR2"].at(0);
std::string result;
if (instruction_only)
@ -38,13 +41,13 @@ int disassemble(cpu *const c, console *const cnsl, const int pc, const bool inst
work_values.c_str()
);
else
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s: %s - %s",
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s: %s - MMR0/2: %s/%s",
registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(),
registers[6].c_str(), pc,
psw.c_str(),
instruction_values.c_str(),
instruction.c_str(),
work_values.c_str()
MMR0.c_str(), MMR2.c_str()
);
if (cnsl)
@ -103,14 +106,14 @@ void mmu_dump(console *const cnsl, bus *const b)
cnsl->put_string_lf(format("MMR2: %06o", b->getMMR2()));
cnsl->put_string_lf(format("MMR3: %06o", mmr3));
dump_par_pdr(cnsl, b, 0172200, 0172240, "supervisor i-space", 0);
dump_par_pdr(cnsl, b, 0172220, 0172260, "supervisor d-space", 1 + (!!(mmr3 & 2)));
dump_par_pdr(cnsl, b, ADDR_PDR_SV_START, ADDR_PAR_SV_START, "supervisor i-space", 0);
dump_par_pdr(cnsl, b, ADDR_PDR_SV_START + 020, ADDR_PAR_SV_START + 020, "supervisor d-space", 1 + (!!(mmr3 & 2)));
dump_par_pdr(cnsl, b, 0172300, 0172340, "kernel i-space", 0);
dump_par_pdr(cnsl, b, 0172320, 0172360, "kernel d-space", 1 + (!!(mmr3 & 4)));
dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0);
dump_par_pdr(cnsl, b, ADDR_PDR_K_START + 020, ADDR_PAR_K_START + 020, "kernel d-space", 1 + (!!(mmr3 & 4)));
dump_par_pdr(cnsl, b, 0177600, 0177640, "user i-space", 0);
dump_par_pdr(cnsl, b, 0177620, 0177660, "user d-space", 1 + (!!(mmr3 & 1)));
dump_par_pdr(cnsl, b, ADDR_PDR_U_START, ADDR_PAR_U_START, "user i-space", 0);
dump_par_pdr(cnsl, b, ADDR_PDR_U_START + 020, ADDR_PAR_U_START + 020, "user d-space", 1 + (!!(mmr3 & 1)));
}
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing_in)
@ -120,7 +123,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
cpu *const c = b->getCpu();
b->set_debug_mode(true);
b->set_debug_mode();
bool single_step = false;
@ -157,10 +160,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
cnsl->put_string_lf("Breakpoints:");
for(auto pc : bps) {
cnsl->put_string_lf(format(" %06o", pc));
for(auto a : bps) {
cnsl->put_string(format(" %06o> ", a));
pc += disassemble(c, cnsl, pc, true);
disassemble(c, cnsl, a, true);
}
continue;
@ -224,6 +227,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
if (val != -1)
cnsl->put_string_lf(format("value at %06o, octal: %o, hex: %x, dec: %d\n", addr, val, val, val));
}
continue;
}
else if (cmd == "reset" || cmd == "r") {
#if defined(ESP32)

View file

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

View file

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

View file

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

View file

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

View file

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

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