diff --git a/ESP32/console_esp32.cpp b/ESP32/console_esp32.cpp index 3505dce..28e70b3 100644 --- a/ESP32/console_esp32.cpp +++ b/ESP32/console_esp32.cpp @@ -121,7 +121,7 @@ void console_esp32::panel_update_thread() if (panel_mode == PM_BITS) { memory_addresses_t rc = b->getMMU()->calculate_physical_address(run_mode, current_PC); - uint16_t current_instr = b->peek_word(current_PC); + auto current_instr = b->peek_word(run_mode, current_PC); int pixel_offset = 0; @@ -140,8 +140,14 @@ void console_esp32::panel_update_thread() for(uint8_t b=0; b<16; b++) pixels.setPixelColor(pixel_offset++, current_PSW & (1l << b) ? magenta : 0); - for(uint8_t b=0; b<16; b++) - pixels.setPixelColor(pixel_offset++, current_instr & (1l << b) ? red : 0); + if (current_instr.has_value()) { + for(uint8_t b=0; b<16; b++) + pixels.setPixelColor(pixel_offset++, current_instr.value() & (1l << b) ? red : 0); + } + else { + for(uint8_t b=0; b<16; b++) + pixels.setPixelColor(pixel_offset++, 0); + } pixels.setPixelColor(pixel_offset++, running_flag ? white : 0); diff --git a/breakpoint_memory.cpp b/breakpoint_memory.cpp index 7adfa48..dea0644 100644 --- a/breakpoint_memory.cpp +++ b/breakpoint_memory.cpp @@ -22,10 +22,16 @@ std::optional breakpoint_memory::is_triggered() const { uint16_t v = 0; - if (is_virtual) - v = b->read(addr, word_mode, rm_cur, true, i_space); - else + if (is_virtual) { + auto temp = b->peek_word(rm_cur, addr); // FIXME rm_cur + if (temp.has_value() == false) + return { }; + + v = temp.value(); + } + else { v = b->read_physical(addr); + } auto it = values.find(v); if (it == values.end()) diff --git a/breakpoint_register.cpp b/breakpoint_register.cpp index 832aef0..698686b 100644 --- a/breakpoint_register.cpp +++ b/breakpoint_register.cpp @@ -42,7 +42,7 @@ std::optional breakpoint_register::is_triggered() const uint16_t v = 0; if (register_nr < 8) - v = c->getRegister(register_nr); // TODO run-mode + v = c->get_register(register_nr); // TODO run-mode else { hwreg_t reg = hwreg_t(register_nr); diff --git a/bus.cpp b/bus.cpp index f69becb..d72f38c 100644 --- a/bus.cpp +++ b/bus.cpp @@ -95,11 +95,14 @@ bus *bus::deserialize(const JsonDocument j, console *const cnsl, std::atomic_uin if (j.containsKey("tty")) b->add_tty(tty::deserialize(j["tty"], b, cnsl)); - if (j.containsKey("mmu")) - b->add_mmu(mmu::deserialize(j["mmu"], m)); + cpu *c = nullptr; + if (j.containsKey("cpu")) { + c = cpu::deserialize(j["cpu"], b, event); + b->add_cpu(c); + } - if (j.containsKey("cpu")) - b->add_cpu(cpu::deserialize(j["cpu"], b, event)); + if (j.containsKey("mmu")) + b->add_mmu(mmu::deserialize(j["mmu"], m, c)); if (j.containsKey("rl02")) b->add_rl02(rl02::deserialize(j["rl02"], b)); @@ -135,7 +138,7 @@ void bus::set_memory_size(const int n_pages) delete m; m = new memory(n_bytes); - mmu_->begin(m); + mmu_->begin(m, c); TRACE("Memory is now %u kB in size", n_bytes / 1024); } @@ -181,19 +184,24 @@ void bus::add_ram(memory *const m) delete this->m; this->m = m; - mmu_->begin(m); + mmu_->begin(m, c); } void bus::add_mmu(mmu *const mmu_) { delete this->mmu_; this->mmu_ = mmu_; + + mmu_->begin(m, c); } void bus::add_cpu(cpu *const c) { delete this->c; this->c = c; + + if (mmu_) + mmu_->begin(m, c); } void bus::add_tm11(tm_11 *const tm11) @@ -238,11 +246,11 @@ void bus::init() mmu_->setMMR3(0); } -uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool peek_only, const d_i_space_t space) +uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm_selection_t mode_selection, const d_i_space_t space) { int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode(); - uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, !peek_only, false, space); + uint32_t m_offset = mmu_->calculate_physical_address(run_mode, addr_in, false, space); uint32_t io_base = mmu_->get_io_base(); bool is_io = m_offset >= io_base; @@ -252,61 +260,59 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm //// REGISTERS //// if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5 - uint16_t temp = c->getRegister(a - ADDR_KERNEL_R) & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O kernel R%d: %06o", a - ADDR_KERNEL_R, temp); + uint16_t temp = c->get_register(a - ADDR_KERNEL_R) & (word_mode == wm_byte ? 0xff : 0xffff); + TRACE("READ-I/O kernel R%d: %06o", a - ADDR_KERNEL_R, temp); return temp; } if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5 - uint16_t temp = c->getRegister(a - ADDR_USER_R) & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O user R%d: %06o", a - ADDR_USER_R, temp); + uint16_t temp = c->get_register(a - ADDR_USER_R) & (word_mode == wm_byte ? 0xff : 0xffff); + TRACE("READ-I/O user R%d: %06o", a - ADDR_USER_R, temp); return temp; } if (a == ADDR_KERNEL_SP) { // kernel SP uint16_t temp = c->getStackPointer(0) & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O kernel SP: %06o", temp); + TRACE("READ-I/O kernel SP: %06o", temp); return temp; } if (a == ADDR_PC) { // PC uint16_t temp = c->getPC() & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O PC: %06o", temp); + TRACE("READ-I/O PC: %06o", temp); return temp; } if (a == ADDR_SV_SP) { // supervisor SP uint16_t temp = c->getStackPointer(1) & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O supervisor SP: %06o", temp); + TRACE("READ-I/O supervisor SP: %06o", temp); return temp; } if (a == ADDR_USER_SP) { // user SP uint16_t temp = c->getStackPointer(3) & (word_mode == wm_byte ? 0xff : 0xffff); - if (!peek_only) TRACE("READ-I/O user SP: %06o", temp); + TRACE("READ-I/O user SP: %06o", temp); return temp; } ///^ registers ^/// - if (!peek_only) { - if ((a & 1) && word_mode == wm_word) [[unlikely]] { - TRACE("READ-I/O odd address %06o UNHANDLED", a); - mmu_->trap_if_odd(addr_in, run_mode, space, false); - throw 0; - return 0; - } + if ((a & 1) && word_mode == wm_word) [[unlikely]] { + TRACE("READ-I/O odd address %06o UNHANDLED", a); + mmu_->trap_if_odd(addr_in, run_mode, space, false); + throw 0; + return 0; } if (a == ADDR_CPU_ERR) { // cpu error register uint16_t temp = mmu_->getCPUERR() & 0xff; - if (!peek_only) TRACE("READ-I/O CPU error: %03o", temp); + TRACE("READ-I/O CPU error: %03o", temp); return temp; } if (a == ADDR_MAINT) { // MAINT uint16_t temp = 1; // POWER OK - if (!peek_only) TRACE("READ-I/O MAINT: %o", temp); + TRACE("READ-I/O MAINT: %o", temp); return temp; } if (a == ADDR_CONSW) { // console switch & display register uint16_t temp = console_switches; - if (!peek_only) TRACE("READ-I/O console switch: %o", temp); + TRACE("READ-I/O console switch: %o", temp); return temp; } @@ -320,13 +326,13 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm else temp = a == ADDR_PIR ? PIR & 255 : PIR >> 8; - if (!peek_only) TRACE("READ-I/O PIR: %o", temp); + TRACE("READ-I/O PIR: %o", temp); return temp; } if (a == ADDR_SYSTEM_ID) { uint16_t temp = 011064; - if (!peek_only) TRACE("READ-I/O system id: %o", temp); + TRACE("READ-I/O system id: %o", temp); return temp; } @@ -335,17 +341,14 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm if (a == ADDR_LP11CSR) { // printer, CSR register, LP11 uint16_t temp = 0x80; - if (!peek_only) TRACE("READ-I/O LP11 CSR: %o", temp); + TRACE("READ-I/O LP11 CSR: %o", temp); return temp; } /// MMU /// - if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) || - (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) || - (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) || - (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) || - (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) || - (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) { + if ((a >= ADDR_PDR_SV_START && a < ADDR_PAR_SV_END) || + (a >= ADDR_PDR_K_START && a < ADDR_PAR_K_END) || + (a >= ADDR_PDR_U_START && a < ADDR_PAR_U_END)) { if (word_mode == wm_word) return mmu_->read_word(a); @@ -354,133 +357,133 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm /////////// if (a >= 0177740 && a <= 0177753) { // cache control register and others - if (!peek_only) TRACE("READ-I/O cache control register/others (%06o): %o", a, 0); + TRACE("READ-I/O cache control register/others (%06o): %o", a, 0); // TODO return 0; } if (a >= 0170200 && a <= 0170377) { // unibus map - if (!peek_only) TRACE("READ-I/O unibus map (%06o): %o", a, 0); + TRACE("READ-I/O unibus map (%06o): %o", a, 0); // TODO return 0; } if (a >= 0172100 && a <= 0172137) { // MM11-LP parity - if (!peek_only) TRACE("READ-I/O MM11-LP parity (%06o): %o", a, 1); + TRACE("READ-I/O MM11-LP parity (%06o): %o", a, 1); return 1; } if (word_mode == wm_byte) { if (a == ADDR_PSW) { // PSW uint8_t temp = c->getPSW(); - if (!peek_only) TRACE("READ-I/O PSW LSB: %03o", temp); + TRACE("READ-I/O PSW LSB: %03o", temp); return temp; } if (a == ADDR_PSW + 1) { uint8_t temp = c->getPSW() >> 8; - if (!peek_only) TRACE("READ-I/O PSW MSB: %03o", temp); + TRACE("READ-I/O PSW MSB: %03o", temp); return temp; } if (a == ADDR_STACKLIM) { // stack limit register uint8_t temp = c->getStackLimitRegister(); - if (!peek_only) TRACE("READ-I/O stack limit register (low): %03o", temp); + TRACE("READ-I/O stack limit register (low): %03o", temp); return temp; } if (a == ADDR_STACKLIM + 1) { // stack limit register uint8_t temp = c->getStackLimitRegister() >> 8; - if (!peek_only) TRACE("READ-I/O stack limit register (high): %03o", temp); + TRACE("READ-I/O stack limit register (high): %03o", temp); return temp; } if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register uint8_t temp = microprogram_break_register; - if (!peek_only) TRACE("READ-I/O microprogram break register (low): %03o", temp); + TRACE("READ-I/O microprogram break register (low): %03o", temp); return temp; } if (a == ADDR_MICROPROG_BREAK_REG + 1) { // microprogram break register uint8_t temp = microprogram_break_register >> 8; - if (!peek_only) TRACE("READ-I/O microprogram break register (high): %03o", temp); + TRACE("READ-I/O microprogram break register (high): %03o", temp); return temp; } if (a == ADDR_MMR0) { uint8_t temp = mmu_->getMMR0(); - if (!peek_only) TRACE("READ-I/O MMR0 LO: %03o", temp); + TRACE("READ-I/O MMR0 LO: %03o", temp); return temp; } if (a == ADDR_MMR0 + 1) { uint8_t temp = mmu_->getMMR0() >> 8; - if (!peek_only) TRACE("READ-I/O MMR0 HI: %03o", temp); + TRACE("READ-I/O MMR0 HI: %03o", temp); return temp; } } else { if (a == ADDR_MMR0) { uint16_t temp = mmu_->getMMR0(); - if (!peek_only) TRACE("READ-I/O MMR0: %06o", temp); + TRACE("READ-I/O MMR0: %06o", temp); return temp; } if (a == ADDR_MMR1) { // MMR1 uint16_t temp = mmu_->getMMR1(); - if (!peek_only) TRACE("READ-I/O MMR1: %06o", temp); + TRACE("READ-I/O MMR1: %06o", temp); return temp; } if (a == ADDR_MMR2) { // MMR2 uint16_t temp = mmu_->getMMR2(); - if (!peek_only) TRACE("READ-I/O MMR2: %06o", temp); + TRACE("READ-I/O MMR2: %06o", temp); return temp; } if (a == ADDR_MMR3) { // MMR3 uint16_t temp = mmu_->getMMR3(); - if (!peek_only) TRACE("READ-I/O MMR3: %06o", temp); + TRACE("READ-I/O MMR3: %06o", temp); return temp; } if (a == ADDR_PSW) { // PSW uint16_t temp = c->getPSW(); - if (!peek_only) TRACE("READ-I/O PSW: %06o", temp); + TRACE("READ-I/O PSW: %06o", temp); return temp; } if (a == ADDR_STACKLIM) { // stack limit register uint16_t temp = c->getStackLimitRegister(); - if (!peek_only) TRACE("READ-I/O stack limit register: %06o", temp); + TRACE("READ-I/O stack limit register: %06o", temp); return temp; } if (a == ADDR_CPU_ERR) { // cpu error register uint16_t temp = mmu_->getCPUERR(); - if (!peek_only) TRACE("READ-I/O CPUERR: %06o", temp); + TRACE("READ-I/O CPUERR: %06o", temp); return temp; } if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register uint16_t temp = microprogram_break_register; - if (!peek_only) TRACE("READ-I/O microprogram break register: %06o", temp); + TRACE("READ-I/O microprogram break register: %06o", temp); return temp; } } - if (tm11 && a >= TM_11_BASE && a < TM_11_END && !peek_only) + if (tm11 && a >= TM_11_BASE && a < TM_11_END) return word_mode == wm_byte ? tm11->read_byte(a) : tm11->read_word(a); - if (rk05_ && a >= RK05_BASE && a < RK05_END && !peek_only) + if (rk05_ && a >= RK05_BASE && a < RK05_END) return word_mode == wm_byte ? rk05_->read_byte(a) : rk05_->read_word(a); - if (rl02_ && a >= RL02_BASE && a < RL02_END && !peek_only) + if (rl02_ && a >= RL02_BASE && a < RL02_END) return word_mode == wm_byte ? rl02_->read_byte(a) : rl02_->read_word(a); - if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END && !peek_only) + if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) return word_mode == wm_byte ? tty_->read_byte(a) : tty_->read_word(a); - if (dc11_ && a >= DC11_BASE && a < DC11_END && !peek_only) + if (dc11_ && a >= DC11_BASE && a < DC11_END) return word_mode == wm_byte ? dc11_->read_byte(a) : dc11_->read_word(a); - if (rp06_ && a >= RP06_BASE && a < RP06_END && !peek_only) + if (rp06_ && a >= RP06_BASE && a < RP06_END) return word_mode == wm_byte ? rp06_->read_byte(a) : rp06_->read_word(a); // LO size register field must be all 1s, so subtract 1 @@ -488,27 +491,25 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm if (a == ADDR_SYSSIZE + 2) { // system size HI uint16_t temp = system_size >> 16; - if (!peek_only) TRACE("READ-I/O accessing system size HI: %06o", temp); + TRACE("READ-I/O accessing system size HI: %06o", temp); return temp; } if (a == ADDR_SYSSIZE) { // system size LO uint16_t temp = system_size; - if (!peek_only) TRACE("READ-I/O accessing system size LO: %06o", temp); + TRACE("READ-I/O accessing system size LO: %06o", temp); return temp; } - if (!peek_only) { - TRACE("READ-I/O UNHANDLED read %08o (%c), (base: %o)", m_offset, word_mode == wm_byte ? 'B' : ' ', mmu_->get_io_base()); + TRACE("READ-I/O UNHANDLED read %08o (%c), (base: %o)", m_offset, word_mode == wm_byte ? 'B' : ' ', mmu_->get_io_base()); - c->trap(004); // no such i/o - throw 1; - } + c->trap(004); // no such i/o + throw 1; return -1; } - if (peek_only == false && word_mode == wm_word && (addr_in & 1)) { + if ((addr_in & 1) && word_mode == wm_word) { TRACE("READ from %06o - odd address!", addr_in); mmu_->trap_if_odd(addr_in, run_mode, space, false); throw 2; @@ -516,11 +517,6 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm } if (m_offset >= m->get_memory_size()) { - if (peek_only) { - TRACE("READ from %06o - out of range!", addr_in); - return 0; - } - c->trap(004); // no such RAM throw 1; } @@ -531,7 +527,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm else temp = m->read_word(m_offset); - if (!peek_only) TRACE("READ from %06o/%07o %c %c: %06o (%s)", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', temp, mode_selection == rm_prev ? "prev" : "cur"); + TRACE("READ from %06o/%07o %c %c: %06o (%s)", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', temp, mode_selection == rm_prev ? "prev" : "cur"); return temp; } @@ -549,7 +545,7 @@ bool bus::is_psw(const uint16_t addr, const int run_mode, const d_i_space_t spac return false; } -write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t space) +bool bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t space) { int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode(); @@ -561,7 +557,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 if (mmu_->is_enabled() && (addr_in & 1) == 0 /* TODO remove this? */ && addr_in != ADDR_MMR0) mmu_->set_page_written_to(run_mode, d, apf); - uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, true, true, space); + uint32_t m_offset = mmu_->calculate_physical_address(run_mode, addr_in, true, space); uint32_t io_base = mmu_->get_io_base(); bool is_io = m_offset >= io_base; @@ -581,7 +577,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 c->setPSW(vtemp, false); - return { true }; + return true; } if (a == ADDR_STACKLIM || a == ADDR_STACKLIM + 1) { // stack limit register @@ -595,7 +591,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 c->setStackLimitRegister(v); - return { false }; + return false; } if (a == ADDR_MICROPROG_BREAK_REG || a == ADDR_MICROPROG_BREAK_REG + 1) { // microprogram break register @@ -603,7 +599,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 update_word(µprogram_break_register, a & 1, value); - return { false }; + return false; } if (a == ADDR_MMR0 || a == ADDR_MMR0 + 1) { // MMR0 @@ -613,7 +609,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 update_word(&temp, a & 1, value); mmu_->setMMR0(temp); - return { false }; + return false; } } else { @@ -626,65 +622,65 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 if (a == ADDR_STACKLIM) { // stack limit register TRACE("WRITE-I/O stack limit register: %06o", value); c->setStackLimitRegister(value & 0xff00); - return { false }; + return false; } if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5 int reg = a - ADDR_KERNEL_R; TRACE("WRITE-I/O kernel R%d: %06o", reg, value); - c->setRegister(reg, value); - return { false }; + c->set_register(reg, value); + return false; } if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5 int reg = a - ADDR_USER_R; TRACE("WRITE-I/O user R%d: %06o", reg, value); - c->setRegister(reg, value); - return { false }; + c->set_register(reg, value); + return false; } if (a == ADDR_KERNEL_SP) { // kernel SP TRACE("WRITE-I/O kernel SP: %06o", value); c->setStackPointer(0, value); - return { false }; + return false; } if (a == ADDR_PC) { // PC TRACE("WRITE-I/O PC: %06o", value); c->setPC(value); - return { false }; + return false; } if (a == ADDR_SV_SP) { // supervisor SP TRACE("WRITE-I/O supervisor sp: %06o", value); c->setStackPointer(1, value); - return { false }; + return false; } if (a == ADDR_USER_SP) { // user SP TRACE("WRITE-I/O user sp: %06o", value); c->setStackPointer(3, value); - return { false }; + return false; } if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register TRACE("WRITE-I/O microprogram break register: %06o", value); microprogram_break_register = value & 0xff; // only 8b on 11/70? - return { false }; + return false; } } if (a == ADDR_CPU_ERR) { // cpu error register TRACE("WRITE-I/O CPUERR: %06o", value); mmu_->setCPUERR(0); - return { false }; + return false; } if (a == ADDR_MMR3) { // MMR3 TRACE("WRITE-I/O set MMR3: %06o", value); mmu_->setMMR3(value); - return { false }; + return false; } if (a == ADDR_MMR0) { // MMR0 TRACE("WRITE-I/O set MMR0: %06o", value); mmu_->setMMR0(value); - return { false }; + return false; } if (a == ADDR_PIR) { // PIR @@ -701,91 +697,88 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 mmu_->setPIR(value); - return { false }; + return false; } if (a == ADDR_LFC) { // line frequency clock and status register kw11_l_->write_word(a, value); - return { false }; + return false; } if (tm11 && a >= TM_11_BASE && a < TM_11_END) { TRACE("WRITE-I/O TM11 register %d: %06o", (a - TM_11_BASE) / 2, value); word_mode == wm_byte ? tm11->write_byte(a, value) : tm11->write_word(a, value); - return { false }; + return false; } if (rk05_ && a >= RK05_BASE && a < RK05_END) { TRACE("WRITE-I/O RK05 register %d: %06o", (a - RK05_BASE) / 2, value); word_mode == wm_byte ? rk05_->write_byte(a, value) : rk05_->write_word(a, value); - return { false }; + return false; } if (rl02_ && a >= RL02_BASE && a < RL02_END) { TRACE("WRITE-I/O RL02 register %d: %06o", (a - RL02_BASE) / 2, value); word_mode == wm_byte ? rl02_->write_byte(a, value) : rl02_->write_word(a, value); - return { false }; + return false; } if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) { TRACE("WRITE-I/O TTY register %d: %06o", (a - PDP11TTY_BASE) / 2, value); word_mode == wm_byte ? tty_->write_byte(a, value) : tty_->write_word(a, value); - return { false }; + return false; } if (dc11_ && a >= DC11_BASE && a < DC11_END) { word_mode == wm_byte ? dc11_->write_byte(a, value) : dc11_->write_word(a, value); - return { false }; + return false; } if (rp06_ && a >= RP06_BASE && a < RP06_END) { word_mode == wm_byte ? rp06_->write_byte(a, value) : rp06_->write_word(a, value); - return { false }; + return false; } if (a >= 0172100 && a <= 0172137) { // MM11-LP parity TRACE("WRITE-I/O MM11-LP parity (%06o): %o", a, value); - return { false }; + return false; } /// MMU /// - // supervisor - if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) || - (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) || - (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) || - (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) || - (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) || - (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) { + if ((a >= ADDR_PDR_SV_START && a < ADDR_PAR_SV_END) || + (a >= ADDR_PDR_K_START && a < ADDR_PAR_K_END) || + (a >= ADDR_PDR_U_START && a < ADDR_PAR_U_END)) { if (word_mode == wm_word) mmu_->write_word(a, value); else mmu_->write_byte(a, value); - return { false }; + return false; } + /////////// if (a >= 0177740 && a <= 0177753) { // cache control register and others // TODO - return { false }; + return false; } if (a >= 0170200 && a <= 0170377) { // unibus map TRACE("writing %06o to unibus map (%06o)", value, a); // TODO - return { false }; + return false; } if (a == ADDR_CONSW) { // switch register console_leds = value; - return { false }; + return false; } if (a == ADDR_SYSSIZE || a == ADDR_SYSSIZE + 2) // system size (is read-only) - return { false }; + return false; if (a == ADDR_SYSTEM_ID) // is r/o - return { false }; + return false; /////////// @@ -804,7 +797,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 throw 9; } - if (word_mode == wm_word && (addr_in & 1)) [[unlikely]] { + if ( (addr_in & 1) && word_mode == wm_word) [[unlikely]] { TRACE("WRITE to %06o (value: %06o) - odd address!", addr_in, value); mmu_->trap_if_odd(addr_in, run_mode, space, true); @@ -824,7 +817,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1 else m->write_word(m_offset, value); - return { false }; + return false; } void bus::write_physical(const uint32_t a, const uint16_t value) @@ -858,12 +851,18 @@ uint16_t bus::read_physical(const uint32_t a) uint16_t bus::read_word(const uint16_t a, const d_i_space_t s) { - return read(a, wm_word, rm_cur, false, s); + return read(a, wm_word, rm_cur, s); } -uint16_t bus::peek_word(const uint16_t a) +std::optional bus::peek_word(const int run_mode, const uint16_t a) { - return read(a, wm_word, rm_cur, true); + auto meta = mmu_->calculate_physical_address(run_mode, a); + + uint32_t io_base = mmu_->get_io_base(); + if (meta.physical_instruction >= io_base) + return { }; + + return m->read_word(meta.physical_instruction); } void bus::write_word(const uint16_t a, const uint16_t value, const d_i_space_t s) @@ -883,7 +882,6 @@ uint8_t bus::read_unibus_byte(const uint32_t a) void bus::write_unibus_byte(const uint32_t a, const uint8_t v) { TRACE("write_unibus_byte[%08o]=%03o", a, v); - if (a < m->get_memory_size()) m->write_byte(a, v); } diff --git a/bus.cpp- b/bus.cpp- new file mode 100644 index 0000000..e509bbe --- /dev/null +++ b/bus.cpp- @@ -0,0 +1,891 @@ +// (C) 2018-2024 by Folkert van Heusden +// Released under MIT license + +#include "gen.h" +#include +#include +#include +#include + +#include "bus.h" +#include "cpu.h" +#include "dc11.h" +#include "kw11-l.h" +#include "log.h" +#include "memory.h" +#include "mmu.h" +#include "tm-11.h" +#include "tty.h" +#include "utils.h" + +#if defined(ESP32) +#include +#endif + + +bus::bus() +{ + mmu_ = new mmu(); + + kw11_l_ = new kw11_l(this); + + reset(); +} + +bus::~bus() +{ + delete kw11_l_; + delete c; + delete tm11; + delete rk05_; + delete rl02_; + delete tty_; + delete mmu_; + delete m; + delete dc11_; + delete rp06_; +} + +JsonDocument bus::serialize() const +{ + JsonDocument j_out; + + if (m) + j_out["memory"] = m->serialize(); + + if (kw11_l_) + j_out["kw11-l"] = kw11_l_->serialize(); + + if (tty_) + j_out["tty"] = tty_->serialize(); + + if (mmu_) + j_out["mmu"] = mmu_->serialize(); + + if (c) + j_out["cpu"] = c->serialize(); + + if (rl02_) + j_out["rl02"] = rl02_->serialize(); + + if (rk05_) + j_out["rk05"] = rk05_->serialize(); + + if (dc11_) + j_out["dc11"] = dc11_->serialize(); + + if (rp06_) + j_out["rp06"] = rp06_->serialize(); + + // TODO: tm11 + + return j_out; +} + +bus *bus::deserialize(const JsonDocument j, console *const cnsl, std::atomic_uint32_t *const event) +{ + bus *b = new bus(); + + memory *m = nullptr; + if (j.containsKey("memory")) { + m = memory::deserialize(j["memory"]); + b->add_ram(m); + } + + if (j.containsKey("tty")) + b->add_tty(tty::deserialize(j["tty"], b, cnsl)); + + if (j.containsKey("mmu")) + b->add_mmu(mmu::deserialize(j["mmu"], m)); + + if (j.containsKey("cpu")) + b->add_cpu(cpu::deserialize(j["cpu"], b, event)); + + if (j.containsKey("rl02")) + b->add_rl02(rl02::deserialize(j["rl02"], b)); + + if (j.containsKey("rk05")) + b->add_rk05(rk05::deserialize(j["rk05"], b)); + + if (j.containsKey("kw11-l")) + b->add_KW11_L(kw11_l::deserialize(j["kw11-l"], b, cnsl)); + + if (j.containsKey("dc11")) + b->add_DC11(dc11::deserialize(j["dc11"], b)); + + if (j.containsKey("rp06")) + b->add_RP06(rp06::deserialize(j["rp06"], b)); + + // TODO: tm11 + + return b; +} + +void bus::show_state(console *const cnsl) const +{ + cnsl->put_string_lf(format("Microprogram break register: %06o", microprogram_break_register)); + cnsl->put_string_lf(format("Console switches: %06o", console_switches)); + cnsl->put_string_lf(format("Console LEDs: %06o", console_leds)); +} + +void bus::set_memory_size(const int n_pages) +{ + uint32_t n_bytes = n_pages * 8192l; + + delete m; + m = new memory(n_bytes); + + mmu_->begin(m); + + TRACE("Memory is now %u kB in size", n_bytes / 1024); +} + +void bus::reset() +{ + if (m) + m->reset(); + if (mmu_) + mmu_->reset(); + if (c) + c->reset(); + if (tm11) + tm11->reset(); + if (rk05_) + rk05_->reset(); + if (rl02_) + rl02_->reset(); + if (tty_) + tty_->reset(); + if (kw11_l_) + kw11_l_->reset(); + if (dc11_) + dc11_->reset(); + if (rp06_) + rp06_->reset(); +} + +void bus::add_RP06(rp06 *const rp06_) +{ + delete this->rp06_; + this->rp06_ = rp06_; +} + +void bus::add_KW11_L(kw11_l *const kw11_l_) +{ + delete this->kw11_l_; + this->kw11_l_ = kw11_l_; +} + +void bus::add_ram(memory *const m) +{ + delete this->m; + this->m = m; + + mmu_->begin(m); +} + +void bus::add_mmu(mmu *const mmu_) +{ + delete this->mmu_; + this->mmu_ = mmu_; +} + +void bus::add_cpu(cpu *const c) +{ + delete this->c; + this->c = c; +} + +void bus::add_tm11(tm_11 *const tm11) +{ + delete this->tm11; + this->tm11= tm11; +} + +void bus::add_rk05(rk05 *const rk05_) +{ + delete this->rk05_; + this->rk05_ = rk05_; +} + +void bus::add_rl02(rl02 *const rl02_) +{ + delete this->rl02_; + this->rl02_ = rl02_; +} + +void bus::add_tty(tty *const tty_) +{ + delete this->tty_; + this->tty_ = tty_; +} + +void bus::add_DC11(dc11 *const dc11_) +{ + delete this->dc11_; + this->dc11_ = dc11_; +} + +void bus::del_DC11() +{ + delete dc11_; + dc11_ = nullptr; +} + +void bus::init() +{ + mmu_->setMMR0(0); + mmu_->setMMR3(0); +} + +uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool peek_only, const d_i_space_t space) +{ + int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode(); + + uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, !peek_only, false, space); + + if (m_offset >= m->get_memory_size()) { + uint32_t io_base = mmu_->get_io_base(); + bool is_io = m_offset >= io_base; + + if (is_io) { + uint16_t a = m_offset - io_base + 0160000; // TODO + + //// REGISTERS //// + if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5 + uint16_t temp = c->getRegister(a - ADDR_KERNEL_R) & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O kernel R%d: %06o", a - ADDR_KERNEL_R, temp); + return temp; + } + if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5 + uint16_t temp = c->getRegister(a - ADDR_USER_R) & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O user R%d: %06o", a - ADDR_USER_R, temp); + return temp; + } + if (a == ADDR_KERNEL_SP) { // kernel SP + uint16_t temp = c->getStackPointer(0) & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O kernel SP: %06o", temp); + return temp; + } + if (a == ADDR_PC) { // PC + uint16_t temp = c->getPC() & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O PC: %06o", temp); + return temp; + } + if (a == ADDR_SV_SP) { // supervisor SP + uint16_t temp = c->getStackPointer(1) & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O supervisor SP: %06o", temp); + return temp; + } + if (a == ADDR_USER_SP) { // user SP + uint16_t temp = c->getStackPointer(3) & (word_mode == wm_byte ? 0xff : 0xffff); + if (!peek_only) TRACE("READ-I/O user SP: %06o", temp); + return temp; + } + ///^ registers ^/// + + if ((a & 1) && word_mode == wm_word) [[unlikely]] { + if (!peek_only) { + TRACE("READ-I/O odd address %06o UNHANDLED", a); + mmu_->trap_if_odd(addr_in, run_mode, space, false); + throw 0; + return 0; + } + } + + if (a == ADDR_CPU_ERR) { // cpu error register + uint16_t temp = mmu_->getCPUERR() & 0xff; + if (!peek_only) TRACE("READ-I/O CPU error: %03o", temp); + return temp; + } + + if (a == ADDR_MAINT) { // MAINT + uint16_t temp = 1; // POWER OK + if (!peek_only) TRACE("READ-I/O MAINT: %o", temp); + return temp; + } + + if (a == ADDR_CONSW) { // console switch & display register + uint16_t temp = console_switches; + if (!peek_only) TRACE("READ-I/O console switch: %o", temp); + return temp; + } + + if (a == ADDR_PIR || a == ADDR_PIR + 1) { // PIR + uint16_t temp = 0; + + uint16_t PIR = mmu_->getPIR(); + + if (word_mode == wm_word) + temp = PIR; + else + temp = a == ADDR_PIR ? PIR & 255 : PIR >> 8; + + if (!peek_only) TRACE("READ-I/O PIR: %o", temp); + return temp; + } + + if (a == ADDR_SYSTEM_ID) { + uint16_t temp = 011064; + if (!peek_only) TRACE("READ-I/O system id: %o", temp); + return temp; + } + + if (a == ADDR_LFC) // line frequency clock and status register + return kw11_l_->read_word(a); + + if (a == ADDR_LP11CSR) { // printer, CSR register, LP11 + uint16_t temp = 0x80; + if (!peek_only) TRACE("READ-I/O LP11 CSR: %o", temp); + return temp; + } + + /// MMU /// + if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) || + (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) || + (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) || + (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) || + (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) || + (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) { + if (word_mode == wm_word) + return mmu_->read_word(a); + + return mmu_->read_byte(a); + } + /////////// + + if (a >= 0177740 && a <= 0177753) { // cache control register and others + if (!peek_only) TRACE("READ-I/O cache control register/others (%06o): %o", a, 0); + // TODO + return 0; + } + + if (a >= 0170200 && a <= 0170377) { // unibus map + if (!peek_only) TRACE("READ-I/O unibus map (%06o): %o", a, 0); + // TODO + return 0; + } + + if (a >= 0172100 && a <= 0172137) { // MM11-LP parity + if (!peek_only) TRACE("READ-I/O MM11-LP parity (%06o): %o", a, 1); + return 1; + } + + if (word_mode == wm_byte) { + if (a == ADDR_PSW) { // PSW + uint8_t temp = c->getPSW(); + if (!peek_only) TRACE("READ-I/O PSW LSB: %03o", temp); + return temp; + } + + if (a == ADDR_PSW + 1) { + uint8_t temp = c->getPSW() >> 8; + if (!peek_only) TRACE("READ-I/O PSW MSB: %03o", temp); + return temp; + } + if (a == ADDR_STACKLIM) { // stack limit register + uint8_t temp = c->getStackLimitRegister(); + if (!peek_only) TRACE("READ-I/O stack limit register (low): %03o", temp); + return temp; + } + if (a == ADDR_STACKLIM + 1) { // stack limit register + uint8_t temp = c->getStackLimitRegister() >> 8; + if (!peek_only) TRACE("READ-I/O stack limit register (high): %03o", temp); + return temp; + } + + if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register + uint8_t temp = microprogram_break_register; + if (!peek_only) TRACE("READ-I/O microprogram break register (low): %03o", temp); + return temp; + } + if (a == ADDR_MICROPROG_BREAK_REG + 1) { // microprogram break register + uint8_t temp = microprogram_break_register >> 8; + if (!peek_only) TRACE("READ-I/O microprogram break register (high): %03o", temp); + return temp; + } + + if (a == ADDR_MMR0) { + uint8_t temp = mmu_->getMMR0(); + if (!peek_only) TRACE("READ-I/O MMR0 LO: %03o", temp); + return temp; + } + if (a == ADDR_MMR0 + 1) { + uint8_t temp = mmu_->getMMR0() >> 8; + if (!peek_only) TRACE("READ-I/O MMR0 HI: %03o", temp); + return temp; + } + } + else { + if (a == ADDR_MMR0) { + uint16_t temp = mmu_->getMMR0(); + if (!peek_only) TRACE("READ-I/O MMR0: %06o", temp); + return temp; + } + + if (a == ADDR_MMR1) { // MMR1 + uint16_t temp = mmu_->getMMR1(); + if (!peek_only) TRACE("READ-I/O MMR1: %06o", temp); + return temp; + } + + if (a == ADDR_MMR2) { // MMR2 + uint16_t temp = mmu_->getMMR2(); + if (!peek_only) TRACE("READ-I/O MMR2: %06o", temp); + return temp; + } + + if (a == ADDR_MMR3) { // MMR3 + uint16_t temp = mmu_->getMMR3(); + if (!peek_only) TRACE("READ-I/O MMR3: %06o", temp); + return temp; + } + + if (a == ADDR_PSW) { // PSW + uint16_t temp = c->getPSW(); + if (!peek_only) TRACE("READ-I/O PSW: %06o", temp); + return temp; + } + + if (a == ADDR_STACKLIM) { // stack limit register + uint16_t temp = c->getStackLimitRegister(); + if (!peek_only) TRACE("READ-I/O stack limit register: %06o", temp); + return temp; + } + + if (a == ADDR_CPU_ERR) { // cpu error register + uint16_t temp = mmu_->getCPUERR(); + if (!peek_only) TRACE("READ-I/O CPUERR: %06o", temp); + return temp; + } + + if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register + uint16_t temp = microprogram_break_register; + if (!peek_only) TRACE("READ-I/O microprogram break register: %06o", temp); + return temp; + } + } + + if (tm11 && a >= TM_11_BASE && a < TM_11_END && !peek_only) + return word_mode == wm_byte ? tm11->read_byte(a) : tm11->read_word(a); + + if (rk05_ && a >= RK05_BASE && a < RK05_END && !peek_only) + return word_mode == wm_byte ? rk05_->read_byte(a) : rk05_->read_word(a); + + if (rl02_ && a >= RL02_BASE && a < RL02_END && !peek_only) + return word_mode == wm_byte ? rl02_->read_byte(a) : rl02_->read_word(a); + + if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END && !peek_only) + return word_mode == wm_byte ? tty_->read_byte(a) : tty_->read_word(a); + + if (dc11_ && a >= DC11_BASE && a < DC11_END && !peek_only) + return word_mode == wm_byte ? dc11_->read_byte(a) : dc11_->read_word(a); + + if (rp06_ && a >= RP06_BASE && a < RP06_END && !peek_only) + return word_mode == wm_byte ? rp06_->read_byte(a) : rp06_->read_word(a); + + // LO size register field must be all 1s, so subtract 1 + uint32_t system_size = m->get_memory_size() / 64 - 1; + + if (a == ADDR_SYSSIZE + 2) { // system size HI + uint16_t temp = system_size >> 16; + if (!peek_only) TRACE("READ-I/O accessing system size HI: %06o", temp); + return temp; + } + + if (a == ADDR_SYSSIZE) { // system size LO + uint16_t temp = system_size; + if (!peek_only) TRACE("READ-I/O accessing system size LO: %06o", temp); + return temp; + } + + if (!peek_only) { + TRACE("READ-I/O UNHANDLED read %08o (%c), (base: %o)", m_offset, word_mode == wm_byte ? 'B' : ' ', mmu_->get_io_base()); + + c->trap(004); // no such i/o + throw 1; + } + + return -1; + } + + if (peek_only) { + TRACE("READ from %06o - out of range!", addr_in); + return 0; + } + + c->trap(004); // no such RAM + throw 1; + } + + if ((addr_in & 1) && word_mode == wm_word) { + if (peek_only == false) { + TRACE("READ from %06o - odd address!", addr_in); + mmu_->trap_if_odd(addr_in, run_mode, space, false); + throw 2; + return 0; + } + } + + uint16_t temp = 0; + if (word_mode == wm_byte) + temp = m->read_byte(m_offset); + else + temp = m->read_word(m_offset); + + if (!peek_only) TRACE("READ from %06o/%07o %c %c: %06o (%s)", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', temp, mode_selection == rm_prev ? "prev" : "cur"); + + return temp; +} + +bool bus::is_psw(const uint16_t addr, const int run_mode, const d_i_space_t space) const +{ + auto meta = mmu_->calculate_physical_address(run_mode, addr); + + if (space == d_space && meta.physical_data_is_psw) + return true; + + if (space == i_space && meta.physical_instruction_is_psw) + return true; + + return false; +} + +write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t space) +{ + int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode(); + + const uint8_t apf = addr_in >> 13; // active page field + + bool is_data = space == d_space; + bool d = is_data && mmu_->get_use_data_space(run_mode); + + if (mmu_->is_enabled() && (addr_in & 1) == 0 /* TODO remove this? */ && addr_in != ADDR_MMR0) + mmu_->set_page_written_to(run_mode, d, apf); + + uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, true, true, space); + + if (m_offset >= m->get_memory_size()) { + uint32_t io_base = mmu_->get_io_base(); + bool is_io = m_offset >= io_base; + + if (is_io) { + uint16_t a = m_offset - io_base + 0160000; // TODO + + if (word_mode == wm_byte) { + if (a == ADDR_PSW || a == ADDR_PSW + 1) { // PSW + TRACE("WRITE-I/O PSW %s: %03o", a & 1 ? "MSB" : "LSB", value); + + uint16_t vtemp = c->getPSW(); + + update_word(&vtemp, a & 1, value); + + vtemp &= ~16; // cannot set T bit via this + + c->setPSW(vtemp, false); + + return { true }; + } + + if (a == ADDR_STACKLIM || a == ADDR_STACKLIM + 1) { // stack limit register + TRACE("WRITE-I/O stack limit register %s: %03o", a & 1 ? "MSB" : "LSB", value); + + uint16_t v = c->getStackLimitRegister(); + + update_word(&v, a & 1, value); + + v |= 0377; + + c->setStackLimitRegister(v); + + return { false }; + } + + if (a == ADDR_MICROPROG_BREAK_REG || a == ADDR_MICROPROG_BREAK_REG + 1) { // microprogram break register + TRACE("WRITE-I/O micropram break register %s: %03o", a & 1 ? "MSB" : "LSB", value); + + update_word(µprogram_break_register, a & 1, value); + + return { false }; + } + + if (a == ADDR_MMR0 || a == ADDR_MMR0 + 1) { // MMR0 + TRACE("WRITE-I/O MMR0 register %s: %03o", a & 1 ? "MSB" : "LSB", value); + + uint16_t temp = mmu_->getMMR0(); + update_word(&temp, a & 1, value); + mmu_->setMMR0(temp); + + return { false }; + } + } + else { + if (a == ADDR_PSW) { // PSW + TRACE("WRITE-I/O PSW: %06o", value); + c->setPSW(value & ~16, false); + return { true }; + } + + if (a == ADDR_STACKLIM) { // stack limit register + TRACE("WRITE-I/O stack limit register: %06o", value); + c->setStackLimitRegister(value & 0xff00); + return { false }; + } + + if (a >= ADDR_KERNEL_R && a <= ADDR_KERNEL_R + 5) { // kernel R0-R5 + int reg = a - ADDR_KERNEL_R; + TRACE("WRITE-I/O kernel R%d: %06o", reg, value); + c->setRegister(reg, value); + return { false }; + } + if (a >= ADDR_USER_R && a <= ADDR_USER_R + 5) { // user R0-R5 + int reg = a - ADDR_USER_R; + TRACE("WRITE-I/O user R%d: %06o", reg, value); + c->setRegister(reg, value); + return { false }; + } + if (a == ADDR_KERNEL_SP) { // kernel SP + TRACE("WRITE-I/O kernel SP: %06o", value); + c->setStackPointer(0, value); + return { false }; + } + if (a == ADDR_PC) { // PC + TRACE("WRITE-I/O PC: %06o", value); + c->setPC(value); + return { false }; + } + if (a == ADDR_SV_SP) { // supervisor SP + TRACE("WRITE-I/O supervisor sp: %06o", value); + c->setStackPointer(1, value); + return { false }; + } + if (a == ADDR_USER_SP) { // user SP + TRACE("WRITE-I/O user sp: %06o", value); + c->setStackPointer(3, value); + return { false }; + } + + if (a == ADDR_MICROPROG_BREAK_REG) { // microprogram break register + TRACE("WRITE-I/O microprogram break register: %06o", value); + microprogram_break_register = value & 0xff; // only 8b on 11/70? + return { false }; + } + } + + if (a == ADDR_CPU_ERR) { // cpu error register + TRACE("WRITE-I/O CPUERR: %06o", value); + mmu_->setCPUERR(0); + return { false }; + } + + if (a == ADDR_MMR3) { // MMR3 + TRACE("WRITE-I/O set MMR3: %06o", value); + mmu_->setMMR3(value); + return { false }; + } + + if (a == ADDR_MMR0) { // MMR0 + TRACE("WRITE-I/O set MMR0: %06o", value); + mmu_->setMMR0(value); + return { false }; + } + + if (a == ADDR_PIR) { // PIR + TRACE("WRITE-I/O set PIR: %06o", value); + + value &= 0177000; + + int bits = value >> 9; + + while(bits) { + value += 042; // bit 1...3 and 5...7 + bits >>= 1; + } + + mmu_->setPIR(value); + + return { false }; + } + + if (a == ADDR_LFC) { // line frequency clock and status register + kw11_l_->write_word(a, value); + + return { false }; + } + + if (tm11 && a >= TM_11_BASE && a < TM_11_END) { + TRACE("WRITE-I/O TM11 register %d: %06o", (a - TM_11_BASE) / 2, value); + word_mode == wm_byte ? tm11->write_byte(a, value) : tm11->write_word(a, value); + return { false }; + } + + if (rk05_ && a >= RK05_BASE && a < RK05_END) { + TRACE("WRITE-I/O RK05 register %d: %06o", (a - RK05_BASE) / 2, value); + word_mode == wm_byte ? rk05_->write_byte(a, value) : rk05_->write_word(a, value); + return { false }; + } + + if (rl02_ && a >= RL02_BASE && a < RL02_END) { + TRACE("WRITE-I/O RL02 register %d: %06o", (a - RL02_BASE) / 2, value); + word_mode == wm_byte ? rl02_->write_byte(a, value) : rl02_->write_word(a, value); + return { false }; + } + + if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) { + TRACE("WRITE-I/O TTY register %d: %06o", (a - PDP11TTY_BASE) / 2, value); + word_mode == wm_byte ? tty_->write_byte(a, value) : tty_->write_word(a, value); + return { false }; + } + + if (dc11_ && a >= DC11_BASE && a < DC11_END) { + word_mode == wm_byte ? dc11_->write_byte(a, value) : dc11_->write_word(a, value); + return { false }; + } + + if (rp06_ && a >= RP06_BASE && a < RP06_END) { + word_mode == wm_byte ? rp06_->write_byte(a, value) : rp06_->write_word(a, value); + return { false }; + } + + if (a >= 0172100 && a <= 0172137) { // MM11-LP parity + TRACE("WRITE-I/O MM11-LP parity (%06o): %o", a, value); + return { false }; + } + + /// MMU /// + // supervisor + if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) || + (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) || + (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) || + (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) || + (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) || + (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) { + if (word_mode == wm_word) + mmu_->write_word(a, value); + else + mmu_->write_byte(a, value); + + return { false }; + } + + if (a >= 0177740 && a <= 0177753) { // cache control register and others + // TODO + return { false }; + } + + if (a >= 0170200 && a <= 0170377) { // unibus map + TRACE("writing %06o to unibus map (%06o)", value, a); + // TODO + return { false }; + } + + if (a == ADDR_CONSW) { // switch register + console_leds = value; + return { false }; + } + + if (a == ADDR_SYSSIZE || a == ADDR_SYSSIZE + 2) // system size (is read-only) + return { false }; + + if (a == ADDR_SYSTEM_ID) // is r/o + return { false }; + + /////////// + + TRACE("WRITE-I/O UNHANDLED %08o(%c): %06o (base: %o)", m_offset, word_mode == wm_byte ? 'B' : 'W', value, mmu_->get_io_base()); + + if (word_mode == wm_word && (a & 1)) [[unlikely]] { + TRACE("WRITE-I/O to %08o (value: %06o) - odd address!", m_offset, value); + + mmu_->trap_if_odd(a, run_mode, space, true); + + throw 8; + } + + c->trap(004); // no such i/o + + throw 9; + } + + c->trap(004); // no such RAM + throw 1; + } + + if (word_mode == wm_word && (addr_in & 1)) [[unlikely]] { + TRACE("WRITE to %06o (value: %06o) - odd address!", addr_in, value); + + mmu_->trap_if_odd(addr_in, run_mode, space, true); + + throw 10; + } + + TRACE("WRITE to %06o/%07o %c %c: %06o", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', value); + + if (word_mode == wm_byte) + m->write_byte(m_offset, value); + else + m->write_word(m_offset, value); + + return { false }; +} + +void bus::write_physical(const uint32_t a, const uint16_t value) +{ + TRACE("physicalWRITE %06o to %o", value, a); + + if (a >= m->get_memory_size()) { + TRACE("physicalWRITE to %o: trap 004", a); + c->trap(004); + throw 12; + } + else { + m->write_word(a, value); + } +} + +uint16_t bus::read_physical(const uint32_t a) +{ + if (a >= m->get_memory_size()) { + TRACE("physicalREAD from %o: trap 004", a); + c->trap(004); + throw 13; + } + + uint16_t value = m->read_word(a); + + TRACE("physicalREAD %06o from %o", value, a); + + return value; +} + +uint16_t bus::read_word(const uint16_t a, const d_i_space_t s) +{ + return read(a, wm_word, rm_cur, false, s); +} + +uint16_t bus::peek_word(const uint16_t a) +{ + return read(a, wm_word, rm_cur, true); +} + +void bus::write_word(const uint16_t a, const uint16_t value, const d_i_space_t s) +{ + write(a, wm_word, value, rm_cur, s); +} + +uint8_t bus::read_unibus_byte(const uint32_t a) +{ + uint8_t v = 0; + if (a < m->get_memory_size()) + v = m->read_byte(a); + TRACE("read_unibus_byte[%08o]=%03o", a, v); + return v; +} + +void bus::write_unibus_byte(const uint32_t a, const uint8_t v) +{ + TRACE("write_unibus_byte[%08o]=%03o", a, v); + + if (a < m->get_memory_size()) + m->write_byte(a, v); +} diff --git a/bus.h b/bus.h index 43cb2f3..016aa3a 100644 --- a/bus.h +++ b/bus.h @@ -122,15 +122,15 @@ public: tm_11 *getTM11() { return tm11; } rp06 *getRP06() { return rp06_; } - uint16_t read(const uint16_t a, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool peek_only=false, const d_i_space_t s = i_space); + uint16_t read(const uint16_t a, const word_mode_t word_mode, const rm_selection_t mode_selection, const d_i_space_t s = i_space); uint8_t read_byte(const uint16_t a) override { return read(a, wm_byte, rm_cur); } uint16_t read_word(const uint16_t a, const d_i_space_t s); uint16_t read_word(const uint16_t a) override { return read_word(a, i_space); } - uint16_t peek_word(const uint16_t a); + std::optional peek_word(const int run_mode, const uint16_t a); uint8_t read_unibus_byte(const uint32_t a); uint16_t read_physical(const uint32_t a); - write_rc_t write(const uint16_t a, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t s = i_space); + bool write(const uint16_t a, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t s = i_space); void write_unibus_byte(const uint32_t a, const uint8_t value); void write_byte(const uint16_t a, const uint8_t value) override { write(a, wm_byte, value, rm_cur); } void write_word(const uint16_t a, const uint16_t value, const d_i_space_t s); diff --git a/console_ncurses.cpp b/console_ncurses.cpp index 531efee..4f7ef4b 100644 --- a/console_ncurses.cpp +++ b/console_ncurses.cpp @@ -146,9 +146,9 @@ void console_ncurses::panel_update_thread() int run_mode = current_PSW >> 14; uint16_t current_PC = c->getPC(); - uint32_t full_addr = b->getMMU()->calculate_physical_address(c, run_mode, current_PC, false, false, i_space); + memory_addresses_t rc = b->getMMU()->calculate_physical_address(run_mode, current_PC); - uint16_t current_instr = b->read_word(current_PC); + auto current_instr = b->peek_word(run_mode, current_PC); auto data = c->disassemble(current_PC); @@ -160,15 +160,21 @@ void console_ncurses::panel_update_thread() wattron(w_panel->win, COLOR_PAIR(1 + run_mode)); for(uint8_t b=0; b<22; b++) - mvwprintw(w_panel->win, 0, 1 + 22 - b, "%c", full_addr & (1 << b) ? '1' : '0'); + mvwprintw(w_panel->win, 0, 1 + 22 - b, "%c", rc.physical_instruction & (1 << b) ? '1' : '0'); wattron(w_panel->win, COLOR_PAIR(1)); for(uint8_t b=0; b<16; b++) mvwprintw(w_panel->win, 1, 1 + 16 - b, "%c", current_PSW & (1 << b) ? '1' : '0'); - for(uint8_t b=0; b<16; b++) - mvwprintw(w_panel->win, 1, 1 + 16 - b + 17, "%c", current_instr & (1 << b) ? '1' : '0'); + if (current_instr.has_value()) { + for(uint8_t b=0; b<16; b++) + mvwprintw(w_panel->win, 1, 1 + 16 - b + 17, "%c", current_instr.value() & (1 << b) ? '1' : '0'); + } + else { + for(uint8_t b=0; b<16; b++) + mvwprintw(w_panel->win, 1, 1 + 16 - b + 17, "-"); + } mvwprintw(w_panel->win, 4, 1, "LEDs:"); diff --git a/cpu.cpp b/cpu.cpp index 1d02c24..1ed12d4 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -143,7 +143,7 @@ void cpu::reset() init_interrupt_queue(); } -uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) const +uint16_t cpu::get_register(const int nr) const { if (nr < 6) { int set = get_register_set(); @@ -151,76 +151,64 @@ uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) con return regs0_5[set][nr]; } - if (nr == 6) { - if (mode_selection == rm_prev) - return sp[getPSW_prev_runmode()]; - + if (nr == 6) return sp[getPSW_runmode()]; - } assert(nr == 7); return pc; } -void cpu::setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection) +void cpu::set_register(const int nr, const uint16_t value) { if (nr < 6) { int set = get_register_set(); regs0_5[set][nr] = value; } - else if (nr == 6) { - if (mode_selection == rm_prev) - sp[getPSW_prev_runmode()] = value; - else - sp[getPSW_runmode()] = value; - } + else if (nr == 6) + sp[getPSW_runmode()] = value; else { assert(nr == 7); pc = value; } } -void cpu::setRegisterLowByte(const int nr, const word_mode_t word_mode, const uint16_t value) +void cpu::set_registerLowByte(const int nr, const word_mode_t word_mode, const uint16_t value) { if (word_mode == wm_byte) { - uint16_t v = getRegister(nr); + uint16_t v = get_register(nr); v &= 0xff00; assert(value < 256); v |= value; - setRegister(nr, v); + set_register(nr, v); } else { - setRegister(nr, value); + set_register(nr, value); } } bool cpu::put_result(const gam_rc_t & g, const uint16_t value) { if (g.addr.has_value() == false) { - setRegisterLowByte(g.reg.value(), g.word_mode, value); + set_registerLowByte(g.reg.value(), g.word_mode, value); return true; } - return b->write(g.addr.value(), g.word_mode, value, g.mode_selection, g.space).is_psw == false; + return b->write(g.addr.value(), g.word_mode, value, g.mode_selection, g.space) == false; } -uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, const uint16_t value) +uint16_t cpu::add_register(const int nr, const uint16_t value) { if (nr < 6) return regs0_5[get_register_set()][nr] += value; - if (nr == 6) { - if (mode_selection == rm_prev) - return sp[getPSW_prev_runmode()] += value; - + if (nr == 6) return sp[getPSW_runmode()] += value; - } assert(nr == 7); @@ -477,9 +465,9 @@ void cpu::addToMMR1(const gam_rc_t & g) } // GAM = general addressing modes -gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool read_value) +gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const bool read_value) { - gam_rc_t g { word_mode, mode_selection, i_space, mode, { }, { }, { }, { } }; + gam_rc_t g { word_mode, rm_cur, i_space, mode, { }, { }, { }, { } }; d_i_space_t isR7_space = reg == 7 ? i_space : (b->getMMU()->get_use_data_space(getPSW_runmode()) ? d_space : i_space); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ always d_space here? TODO @@ -491,60 +479,60 @@ gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t wo switch(mode) { case 0: // Rn g.reg = reg; - g.value = getRegister(reg, mode_selection) & (word_mode == wm_byte ? 0xff : 0xffff); + g.value = get_register(reg) & (word_mode == wm_byte ? 0xff : 0xffff); break; case 1: // (Rn) - g.addr = getRegister(reg, mode_selection); + g.addr = get_register(reg); if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, isR7_space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, isR7_space); break; case 2: // (Rn)+ / #n - g.addr = getRegister(reg, mode_selection); + g.addr = get_register(reg); if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, isR7_space); - addRegister(reg, mode_selection, word_mode == wm_word || reg == 7 || reg == 6 ? 2 : 1); + g.value = b->read(g.addr.value(), word_mode, rm_cur, isR7_space); + add_register(reg, word_mode == wm_word || reg == 7 || reg == 6 ? 2 : 1); g.mmr1_update = { word_mode == wm_word || reg == 7 || reg == 6 ? 2 : 1, reg }; break; case 3: // @(Rn)+ / @#a - g.addr = b->read(getRegister(reg, mode_selection), wm_word, mode_selection, false, isR7_space); + g.addr = b->read(get_register(reg), wm_word, rm_cur, isR7_space); // might be wrong: the adds should happen when the read is really performed, because of traps - addRegister(reg, mode_selection, 2); + add_register(reg, 2); g.mmr1_update = { 2, reg }; g.space = d_space; if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, g.space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, g.space); break; case 4: // -(Rn) - addRegister(reg, mode_selection, word_mode == wm_word || reg == 7 || reg == 6 ? -2 : -1); + add_register(reg, word_mode == wm_word || reg == 7 || reg == 6 ? -2 : -1); g.mmr1_update = { word_mode == wm_word || reg == 7 || reg == 6 ? -2 : -1, reg }; g.space = d_space; - g.addr = getRegister(reg, mode_selection); + g.addr = get_register(reg); if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, isR7_space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, isR7_space); break; case 5: // @-(Rn) - addRegister(reg, mode_selection, -2); + add_register(reg, -2); g.mmr1_update = { -2, reg }; - g.addr = b->read(getRegister(reg, mode_selection), wm_word, mode_selection, false, isR7_space); + g.addr = b->read(get_register(reg), wm_word, rm_cur, isR7_space); g.space = d_space; if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, g.space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, g.space); break; case 6: // x(Rn) / a - next_word = b->read(getPC(), wm_word, mode_selection, false, i_space); - addRegister(7, mode_selection, + 2); - g.addr = getRegister(reg, mode_selection) + next_word; + next_word = b->read(getPC(), wm_word, rm_cur, i_space); + add_register(7, + 2); + g.addr = get_register(reg) + next_word; g.space = d_space; if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, g.space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, g.space); break; case 7: // @x(Rn) / @a - next_word = b->read(getPC(), wm_word, mode_selection, false, i_space); - addRegister(7, mode_selection, + 2); - g.addr = b->read(getRegister(reg, mode_selection) + next_word, wm_word, mode_selection, false, d_space); + next_word = b->read(getPC(), wm_word, rm_cur, i_space); + add_register(7, + 2); + g.addr = b->read(get_register(reg) + next_word, wm_word, rm_cur, d_space); g.space = d_space; if (read_value) - g.value = b->read(g.addr.value(), word_mode, mode_selection, false, g.space); + g.value = b->read(g.addr.value(), word_mode, rm_cur, g.space); break; } @@ -560,17 +548,23 @@ bool cpu::putGAM(const gam_rc_t & g, const uint16_t value) if (g.addr.has_value()) { auto rc = b->write(g.addr.value(), g.word_mode, value, g.mode_selection, g.space); - return rc.is_psw == false; + return rc == false; } - setRegister(g.reg.value(), value, g.mode_selection); + if (g.mode_selection == rm_prev) { + assert(g.reg.value() == 6); + sp[getPSW_prev_runmode()] = value; + } + else { + set_register(g.reg.value(), value); + } return true; } gam_rc_t cpu::getGAMAddress(const uint8_t mode, const int reg, const word_mode_t word_mode) { - return getGAM(mode, reg, word_mode, rm_cur, false); + return getGAM(mode, reg, word_mode, false); } bool cpu::double_operand_instructions(const uint16_t instr) @@ -599,14 +593,14 @@ bool cpu::double_operand_instructions(const uint16_t instr) switch(operation) { case 0b001: { // MOV/MOVB Move Word/Byte - gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur); + gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode); bool set_flags = true; if (word_mode == wm_byte && dst_mode == 0) - setRegister(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension + set_register(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension else { - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur, false); + auto g_dst = getGAMAddress(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); set_flags = putGAM(g_dst, g_src.value.value()); @@ -621,9 +615,9 @@ bool cpu::double_operand_instructions(const uint16_t instr) } case 0b010: { // CMP/CMPB Compare Word/Byte - gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur); + gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode); - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); addToMMR1(g_src); @@ -639,9 +633,9 @@ bool cpu::double_operand_instructions(const uint16_t instr) } case 0b011: { // BIT/BITB Bit Test Word/Byte - gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur); + gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode); - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); addToMMR1(g_src); @@ -654,20 +648,20 @@ bool cpu::double_operand_instructions(const uint16_t instr) } case 0b100: { // BIC/BICB Bit Clear Word/Byte - gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur); + gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode); if (dst_mode == 0) { addToMMR1(g_src); // keep here because of order of updates - uint16_t v = getRegister(dst_reg); // need the full word + uint16_t v = get_register(dst_reg); // need the full word uint16_t result = v & ~g_src.value.value(); - setRegister(dst_reg, result); + set_register(dst_reg, result); setPSW_flags_nzv(result, word_mode); } else { - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); addToMMR1(g_src); @@ -682,22 +676,22 @@ bool cpu::double_operand_instructions(const uint16_t instr) } case 0b101: { // BIS/BISB Bit Set Word/Byte - gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur); + gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode); if (dst_mode == 0) { addToMMR1(g_src); // keep here because of order of updates - uint16_t v = getRegister(dst_reg); // need the full word + uint16_t v = get_register(dst_reg); // need the full word uint16_t result = v | g_src.value.value(); - setRegister(dst_reg, result); + set_register(dst_reg, result); setPSW_n(SIGN(result, word_mode)); setPSW_z(IS_0(result, word_mode)); setPSW_v(false); } else { - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); addToMMR1(g_src); @@ -715,9 +709,9 @@ bool cpu::double_operand_instructions(const uint16_t instr) } case 0b110: { // ADD/SUB Add/Subtract Word - auto g_ssrc = getGAM(src_mode, src_reg, wm_word, rm_cur); + auto g_ssrc = getGAM(src_mode, src_reg, wm_word); - auto g_dst = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); addToMMR1(g_ssrc); @@ -774,16 +768,16 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) switch(operation) { case 0: { // MUL - int16_t R1 = getRegister(reg); + int16_t R1 = get_register(reg); - auto R2g = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + auto R2g = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(R2g); int16_t R2 = R2g.value.value(); int32_t result = R1 * R2; - setRegister(reg, result >> 16); - setRegister(reg | 1, result & 65535); + set_register(reg, result >> 16); + set_register(reg | 1, result & 65535); setPSW_n(result < 0); setPSW_z(result == 0); @@ -793,11 +787,11 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 1: { // DIV - auto R2g = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + auto R2g = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(R2g); int16_t divider = R2g.value.value(); - int32_t R0R1 = (uint32_t(getRegister(reg)) << 16) | getRegister(reg | 1); + int32_t R0R1 = (uint32_t(get_register(reg)) << 16) | get_register(reg | 1); if (divider == 0) { // divide by zero setPSW_n(false); @@ -829,8 +823,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) return true; } - setRegister(reg, quot); - setRegister(reg | 1, rem); + set_register(reg, quot); + set_register(reg | 1, rem); setPSW_v(false); @@ -838,9 +832,9 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 2: { // ASH - uint32_t R = getRegister(reg), oldR = R; + uint32_t R = get_register(reg), oldR = R; - auto g_dst = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); uint16_t shift = g_dst.value.value() & 077; @@ -886,15 +880,15 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) setPSW_n(SIGN(R, wm_word)); setPSW_z(R == 0); - setRegister(reg, R); + set_register(reg, R); return true; } case 3: { // ASHC - uint32_t R0R1 = (uint32_t(getRegister(reg)) << 16) | getRegister(reg | 1); + uint32_t R0R1 = (uint32_t(get_register(reg)) << 16) | get_register(reg | 1); - auto g_dst = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); uint16_t shift = g_dst.value.value() & 077; @@ -939,8 +933,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) bool new_sign = R0R1 & 0x80000000; setPSW_v(sign != new_sign); - setRegister(reg, R0R1 >> 16); - setRegister(reg | 1, R0R1 & 65535); + set_register(reg, R0R1 >> 16); + set_register(reg | 1, R0R1 & 65535); setPSW_n(R0R1 & 0x80000000); setPSW_z(R0R1 == 0); @@ -949,8 +943,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 4: { // XOR (word only) - uint16_t reg_v = getRegister(reg); // in case it is R7 - auto g_dst = getGAM(dst_mode, dst_reg, wm_word, rm_cur); + uint16_t reg_v = get_register(reg); // in case it is R7 + auto g_dst = getGAM(dst_mode, dst_reg, wm_word); addToMMR1(g_dst); uint16_t vl = g_dst.value.value() ^ reg_v; @@ -963,7 +957,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 7: { // SOB - if (addRegister(reg, rm_cur, -1)) { + if (add_register(reg, -1)) { uint16_t newPC = getPC() - dst * 2; setPC(newPC); @@ -989,7 +983,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) if (word_mode == wm_byte) // handled elsewhere return false; - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); uint16_t v = g_dst.value.value(); @@ -1010,14 +1004,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) bool set_flags = false; if (word_mode == wm_byte && dst_mode == 0) { - uint16_t v = getRegister(dst_reg) & 0xff00; + uint16_t v = get_register(dst_reg) & 0xff00; - setRegister(dst_reg, v); + set_register(dst_reg, v); set_flags = true; } else { - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur, false); + auto g_dst = getGAMAddress(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); set_flags = putGAM(g_dst, 0); @@ -1038,14 +1032,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) uint16_t v = 0; if (word_mode == wm_byte && dst_mode == 0) { - v = getRegister(dst_reg) ^ 0xff; + v = get_register(dst_reg) ^ 0xff; - setRegister(dst_reg, v); + set_register(dst_reg, v); set_flags = true; } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); v = a.value.value(); @@ -1067,7 +1061,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000101010: { // INC/INCB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); uint16_t add = word_mode == wm_byte ? v & 0xff00 : 0; v = (v + 1) & (word_mode == wm_byte ? 0xff : 0xffff); @@ -1077,14 +1071,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_z(IS_0(v, word_mode)); setPSW_v(word_mode == wm_byte ? (v & 0xff) == 0x80 : v == 0x8000); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); int32_t vl = (a.value.value() + 1) & (word_mode == wm_byte ? 0xff : 0xffff); - bool set_flags = b->write(a.addr.value(), a.word_mode, vl, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, vl, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(vl, word_mode)); @@ -1099,7 +1093,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000101011: { // DEC/DECB // TODO unify if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); uint16_t add = word_mode == wm_byte ? v & 0xff00 : 0; v = (v - 1) & (word_mode == wm_byte ? 0xff : 0xffff); @@ -1109,14 +1103,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_z(IS_0(v, word_mode)); setPSW_v(word_mode == wm_byte ? (v & 0xff) == 0x7f : v == 0x7fff); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); int32_t vl = (a.value.value() - 1) & (word_mode == wm_byte ? 0xff : 0xffff); - bool set_flags = b->write(a.addr.value(), a.word_mode, vl, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, vl, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(vl, word_mode)); @@ -1130,7 +1124,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000101100: { // NEG/NEGB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); uint16_t add = word_mode == wm_byte ? v & 0xff00 : 0; v = (-v) & (word_mode == wm_byte ? 0xff : 0xffff); @@ -1141,14 +1135,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(word_mode == wm_byte ? (v & 0xff) == 0x80 : v == 0x8000); setPSW_c(v); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); uint16_t v = -a.value.value(); - bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1163,7 +1157,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000101101: { // ADC/ADCB if (dst_mode == 0) { - const uint16_t vo = getRegister(dst_reg); + const uint16_t vo = get_register(dst_reg); uint16_t v = vo; uint16_t add = word_mode == wm_byte ? v & 0xff00 : 0; bool org_c = getPSW_c(); @@ -1176,16 +1170,16 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v((word_mode == wm_byte ? (vo & 0xff) == 0x7f : vo == 0x7fff) && org_c); setPSW_c((word_mode == wm_byte ? (vo & 0xff) == 0xff : vo == 0xffff) && org_c); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); const uint16_t vo = a.value.value(); bool org_c = getPSW_c(); uint16_t v = (vo + org_c) & (word_mode == wm_byte ? 0x00ff : 0xffff); - bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1200,7 +1194,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000101110: { // SBC/SBCB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); const uint16_t vo = v; uint16_t add = word_mode == wm_byte ? v & 0xff00 : 0; bool org_c = getPSW_c(); @@ -1213,16 +1207,16 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v((word_mode == wm_byte ? (vo & 0xff) == 0x80 : vo == 0x8000) && org_c); setPSW_c(IS_0(vo, word_mode) && org_c); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); const uint16_t vo = a.value.value(); bool org_c = getPSW_c(); uint16_t v = (vo - org_c) & (word_mode == wm_byte ? 0xff : 0xffff); - bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1235,7 +1229,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) } case 0b000101111: { // TST/TSTB - auto g = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g = getGAM(dst_mode, dst_reg, word_mode); uint16_t v = g.value.value(); addToMMR1(g); @@ -1247,7 +1241,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000110000: { // ROR/RORB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); bool new_carry = v & 1; uint16_t temp = 0; @@ -1256,7 +1250,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) else temp = (v >> 1) | (getPSW_c() << 15); - setRegister(dst_reg, temp); + set_register(dst_reg, temp); setPSW_c(new_carry); setPSW_n(SIGN(temp, word_mode)); @@ -1264,7 +1258,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_c() ^ getPSW_n()); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); uint16_t t = a.value.value(); bool new_carry = t & 1; @@ -1275,7 +1269,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) else temp = (t >> 1) | (getPSW_c() << 15); - bool set_flags = b->write(a.addr.value(), a.word_mode, temp, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, temp, a.mode_selection, a.space) == false; if (set_flags) { setPSW_c(new_carry); @@ -1289,7 +1283,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000110001: { // ROL/ROLB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); bool new_carry = false; uint16_t temp = 0; @@ -1302,7 +1296,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) temp = (v << 1) | getPSW_c(); } - setRegister(dst_reg, temp); + set_register(dst_reg, temp); setPSW_c(new_carry); setPSW_n(SIGN(temp, word_mode)); @@ -1310,7 +1304,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_c() ^ getPSW_n()); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); uint16_t t = a.value.value(); bool new_carry = false; @@ -1325,7 +1319,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) temp = (t << 1) | getPSW_c(); } - bool set_flags = b->write(a.addr.value(), a.word_mode, temp, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, temp, a.mode_selection, a.space) == false; if (set_flags) { setPSW_c(new_carry); @@ -1339,7 +1333,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000110010: { // ASR/ASRB if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + uint16_t v = get_register(dst_reg); uint16_t hb = word_mode == wm_byte ? v & 128 : v & 32768; setPSW_c(v & 1); @@ -1350,14 +1344,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) v >>= 1; v |= hb; - setRegister(dst_reg, v); + set_register(dst_reg, v); setPSW_n(SIGN(v, word_mode)); setPSW_z(IS_0(v, word_mode)); setPSW_v(getPSW_n() ^ getPSW_c()); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); uint16_t v = a.value.value(); @@ -1371,7 +1365,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) v >>= 1; v |= hb; - bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1384,7 +1378,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b00110011: { // ASL/ASLB if (dst_mode == 0) { - uint16_t vl = getRegister(dst_reg); + uint16_t vl = get_register(dst_reg); uint16_t v = ((vl << 1) & (word_mode == wm_byte ? 0xff : 0xffff)); if (word_mode == wm_byte) @@ -1395,15 +1389,15 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_c(SIGN(vl, word_mode)); setPSW_v(getPSW_n() ^ getPSW_c()); - setRegister(dst_reg, v); + set_register(dst_reg, v); } else { - auto a = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto a = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(a); uint16_t vl = a.value.value(); uint16_t v = (vl << 1) & (word_mode == wm_byte ? 0xff : 0xffff); - bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space).is_psw == false; + bool set_flags = b->write(a.addr.value(), a.word_mode, v, a.mode_selection, a.space) == false; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1419,15 +1413,19 @@ bool cpu::single_operand_instructions(const uint16_t instr) // always words: word_mode-bit is to select between MFPI and MFPD uint16_t v = 0xffff; - if (dst_mode == 0) - v = getRegister(dst_reg, rm_prev); + if (dst_mode == 0) { + if (dst_reg == 6) + v = sp[getPSW_prev_runmode()]; + else + v = get_register(dst_reg); + } else { // calculate address in current address space auto a = getGAMAddress(dst_mode, dst_reg, wm_word); addToMMR1(a); // read from previous space - v = b->read(a.addr.value(), wm_word, rm_prev, false, word_mode == wm_byte ? d_space : i_space); + v = b->read(a.addr.value(), wm_word, rm_prev, word_mode == wm_byte ? d_space : i_space); } setPSW_flags_nzv(v, wm_word); @@ -1444,8 +1442,12 @@ bool cpu::single_operand_instructions(const uint16_t instr) uint16_t v = popStack(); bool set_flags = true; - if (dst_mode == 0) - setRegister(dst_reg, v, rm_prev); + if (dst_mode == 0) { + if (dst_reg == 6) + sp[getPSW_prev_runmode()] = v; + else + set_register(dst_reg, v); + } else { auto a = getGAMAddress(dst_mode, dst_reg, wm_word); addToMMR1(a); @@ -1467,24 +1469,24 @@ bool cpu::single_operand_instructions(const uint16_t instr) if (word_mode == wm_byte) { // MTPS #if 0 // not in the PDP-11/70 psw &= 0xff00; // only alter lower 8 bits - psw |= getGAM(dst_mode, dst_reg, word_mode, rm_cur).value.value() & 0xef; // can't change bit 4 + psw |= getGAM(dst_mode, dst_reg, word_mode).value.value() & 0xef; // can't change bit 4 #else trap(010); #endif } else { - setRegister(6, getPC() + dst * 2); + set_register(6, getPC() + dst * 2); - setPC(getRegister(5)); + setPC(get_register(5)); - setRegister(5, popStack()); + set_register(5, popStack()); } break; case 0b000110111: { // MFPS (get PSW to something) / SXT if (word_mode == wm_byte) { // MFPS #if 0 // not in the PDP-11/70 - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); uint16_t temp = psw & 0xff; bool extend_b7 = psw & 128; @@ -1504,7 +1506,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) #endif } else { // SXT - auto g_dst = getGAM(dst_mode, dst_reg, word_mode, rm_cur); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode); addToMMR1(g_dst); uint16_t vl = -getPSW_n(); @@ -1597,7 +1599,7 @@ bool cpu::conditional_branch_instructions(const uint16_t instr) } if (take) - addRegister(7, rm_cur, offset * 2); + add_register(7, offset * 2); return true; } @@ -1643,13 +1645,13 @@ bool cpu::condition_code_operations(const uint16_t instr) void cpu::pushStack(const uint16_t v) { - if (getRegister(6) == stackLimitRegister) { + if (get_register(6) == stackLimitRegister) { TRACE("stackLimitRegister reached %06o while pushing %06o", stackLimitRegister, v); trap(04, 7); } else { - uint16_t a = addRegister(6, rm_cur, -2); + uint16_t a = add_register(6, -2); b->write_word(a, v, d_space); } @@ -1657,10 +1659,10 @@ void cpu::pushStack(const uint16_t v) uint16_t cpu::popStack() { - uint16_t a = getRegister(6); + uint16_t a = get_register(6); uint16_t temp = b->read_word(a, d_space); - addRegister(6, rm_cur, 2); + add_register(6, 2); return temp; } @@ -1721,7 +1723,7 @@ bool cpu::misc_operations(const uint16_t instr) return true; case 0b0000000000000111: // MFPT - //setRegister(0, 0); + //set_register(0, 0); trap(010); // does not exist on PDP-11/70 return true; @@ -1774,7 +1776,7 @@ bool cpu::misc_operations(const uint16_t instr) int link_reg = (instr >> 6) & 7; // PUSH link - pushStack(getRegister(link_reg)); + pushStack(get_register(link_reg)); if (!b->getMMU()->isMMR1Locked()) { b->getMMU()->addToMMR1(-2, 6); @@ -1782,7 +1784,7 @@ bool cpu::misc_operations(const uint16_t instr) } // MOVE PC,link - setRegister(link_reg, getPC()); + set_register(link_reg, getPC()); // JMP dst setPC(dst_value); @@ -1797,16 +1799,16 @@ bool cpu::misc_operations(const uint16_t instr) const int link_reg = instr & 7; // MOVE link, PC - setPC(getRegister(link_reg)); + setPC(get_register(link_reg)); // POP link - uint16_t word_on_stack = b->read_word(getRegister(6), d_space); + uint16_t word_on_stack = b->read_word(get_register(6), d_space); - setRegister(link_reg, word_on_stack); + set_register(link_reg, word_on_stack); // do not overwrite SP when it was just set if (link_reg != 6) - addRegister(6, rm_cur, 2); + add_register(6, 2); return true; } @@ -1841,7 +1843,7 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt) if (kernel_mode) vector = 4; - setRegister(6, 04); + set_register(6, 04); } else { b->getMMU()->clearMMR1(); @@ -1869,16 +1871,16 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt) setPSW(new_psw, false); if (processing_trap_depth >= 2 && kernel_mode) - setRegister(6, 04); + set_register(6, 04); - uint16_t prev_sp = getRegister(6); + uint16_t prev_sp = get_register(6); try { pushStack(before_psw); pushStack(before_pc); } catch(const int exception) { // recover stack - setRegister(6, prev_sp); + set_register(6, prev_sp); } processing_trap_depth = 0; @@ -1896,16 +1898,20 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt) while(0); } -cpu::operand_parameters cpu::addressing_to_string(const uint8_t mode_register, const uint16_t pc, const word_mode_t word_mode) const +std::optional cpu::addressing_to_string(const uint8_t mode_register, const uint16_t pc, const word_mode_t word_mode) const { assert(mode_register < 64); - uint16_t next_word = b->peek_word(pc & 65535); - + int run_mode = getPSW_runmode(); + auto temp = b->peek_word(run_mode, pc & 65535); + if (temp.has_value() == false) + return { }; + uint16_t next_word = temp.value(); int reg = mode_register & 7; - uint16_t mask = word_mode == wm_byte ? 0xff : 0xffff; + std::optional temp2; + std::string reg_name; if (reg == 6) reg_name = "SP"; @@ -1916,49 +1922,111 @@ cpu::operand_parameters cpu::addressing_to_string(const uint8_t mode_register, c switch(mode_register >> 3) { case 0: - return { reg_name, 2, -1, uint16_t(getRegister(reg) & mask) }; + return { { reg_name, 2, -1, uint16_t(get_register(reg) & mask) } }; case 1: - return { format("(%s)", reg_name.c_str()), 2, -1, uint16_t(b->peek_word(getRegister(reg)) & mask) }; + temp2 = b->peek_word(run_mode, get_register(reg)); + if (temp2.has_value() == false) + return { }; + + return { { format("(%s)", reg_name.c_str()), 2, -1, uint16_t(temp2.value() & mask) } }; case 2: if (reg == 7) - return { format("#%06o", next_word), 4, int(next_word), uint16_t(next_word & mask) }; + return { { format("#%06o", next_word), 4, int(next_word), uint16_t(next_word & mask) } }; - return { format("(%s)+", reg_name.c_str()), 2, -1, uint16_t(b->peek_word(getRegister(reg)) & mask) }; + temp2 = b->peek_word(run_mode, get_register(reg)); + if (temp2.has_value() == false) + return { }; + + return { { format("(%s)+", reg_name.c_str()), 2, -1, uint16_t(temp2.value() & mask) } }; case 3: - if (reg == 7) - return { format("@#%06o", next_word), 4, int(next_word), uint16_t(b->peek_word(next_word) & mask) }; + if (reg == 7) { + temp2 = b->peek_word(run_mode, next_word); + if (temp2.has_value() == false) + return { }; - return { format("@(%s)+", reg_name.c_str()), 2, -1, uint16_t(b->peek_word(b->peek_word(getRegister(reg))) & mask) }; + return { { format("@#%06o", next_word), 4, int(next_word), uint16_t(temp2.value() & mask) } }; + } + + temp2 = b->peek_word(run_mode, get_register(reg)); + if (temp2.has_value() == false) + return { }; + + temp2 = b->peek_word(run_mode, temp2.value()); + if (temp2.has_value() == false) + return { }; + + return { { format("@(%s)+", reg_name.c_str()), 2, -1, uint16_t(temp2.value() & mask) } }; case 4: - return { format("-(%s)", reg_name.c_str()), 2, -1, uint16_t(b->peek_word(getRegister(reg) - (word_mode == wm_word || reg >= 6 ? 2 : 1)) & mask) }; + temp2 = b->peek_word(run_mode, get_register(reg) - (word_mode == wm_word || reg >= 6 ? 2 : 1)); + if (temp2.has_value() == false) + return { }; + + return { { format("-(%s)", reg_name.c_str()), 2, -1, uint16_t(temp2.value() & mask) } }; case 5: - return { format("@-(%s)", reg_name.c_str()), 2, -1, uint16_t(b->peek_word(b->peek_word(getRegister(reg) - 2)) & mask) }; + temp2 = b->peek_word(run_mode, get_register(reg) - 2); + if (temp2.has_value() == false) + return { }; + + temp2 = b->peek_word(run_mode, temp2.value()); + if (temp2.has_value() == false) + return { }; + + return { { format("@-(%s)", reg_name.c_str()), 2, -1, uint16_t(temp2.value() & mask) } }; case 6: - if (reg == 7) - return { format("%06o", (pc + next_word + 2) & 65535), 4, int(next_word), uint16_t(b->peek_word(getRegister(reg) + next_word) & mask) }; + if (reg == 7) { + temp2 = b->peek_word(run_mode, get_register(reg) + next_word); + if (temp2.has_value() == false) + return { }; - return { format("%o(%s)", next_word, reg_name.c_str()), 4, int(next_word), uint16_t(b->peek_word(getRegister(reg) + next_word) & mask) }; + return { { format("%06o", (pc + next_word + 2) & 65535), 4, int(next_word), uint16_t(temp2.value() & mask) } }; + } + + temp2 = b->peek_word(run_mode, get_register(reg) + next_word); + if (temp2.has_value() == false) + return { }; + + return { { format("%o(%s)", next_word, reg_name.c_str()), 4, int(next_word), uint16_t(temp2.value() & mask) } }; case 7: - if (reg == 7) - return { format("@%06o", next_word), 4, int(next_word), uint16_t(b->peek_word(b->peek_word(getRegister(reg) + next_word)) & mask) }; + if (reg == 7) { + temp2 = b->peek_word(run_mode, get_register(reg) + next_word); + if (temp2.has_value() == false) + return { }; - return { format("@%o(%s)", next_word, reg_name.c_str()), 4, int(next_word), uint16_t(b->peek_word(b->peek_word(getRegister(reg) + next_word)) & mask) }; + temp2 = b->peek_word(run_mode, temp2.value()); + if (temp2.has_value() == false) + return { }; + + return { { format("@%06o", next_word), 4, int(next_word), uint16_t(temp2.value() & mask) } }; + } + + temp2 = b->peek_word(run_mode, get_register(reg) + next_word); + if (temp2.has_value() == false) + return { }; + + temp2 = b->peek_word(run_mode, temp2.value()); + if (temp2.has_value() == false) + return { }; + + return { { format("@%o(%s)", next_word, reg_name.c_str()), 4, int(next_word), uint16_t(temp2.value() & mask) } }; } - return { "??", 0, -1, 0123456 }; + return { }; } std::map > cpu::disassemble(const uint16_t addr) const { - uint16_t instruction = b->peek_word(addr); + auto temp = b->peek_word(getPSW_runmode(), addr); + if (temp.has_value() == false) + return { }; + uint16_t instruction = temp.value(); word_mode_t word_mode = instruction & 0x8000 ? wm_byte : wm_word; std::string word_mode_str = word_mode == wm_byte ? "B" : ""; uint8_t ado_opcode = (instruction >> 9) & 7; // additional double operand @@ -1980,7 +2048,10 @@ std::map > cpu::disassemble(const uint16_t // TODO: 100000011 if (do_opcode == 0b000) { - auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; + auto addressing = addressing_to_string(dst_register, (addr + 2) & 65535, word_mode); + if (addressing.has_value() == false) + return { }; + auto dst_text { addressing.value() }; auto next_word = dst_text.instruction_part; @@ -2073,7 +2144,10 @@ std::map > cpu::disassemble(const uint16_t name = "?"; else { std::string src_text = format("R%d", (instruction >> 6) & 7); - auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; + auto addressing = addressing_to_string(dst_register, (addr + 2) & 65535, word_mode); + if (addressing.has_value() == false) + return { }; + auto dst_text { addressing.value() }; auto next_word = dst_text.instruction_part; @@ -2143,7 +2217,10 @@ std::map > cpu::disassemble(const uint16_t } // source - auto src_text { addressing_to_string(src_register, (addr + 2) & 65535, word_mode) }; + auto addressing_src = addressing_to_string(src_register, (addr + 2) & 65535, word_mode); + if (addressing_src.has_value() == false) + return { }; + auto src_text { addressing_src.value() }; auto next_word_src = src_text.instruction_part; if (next_word_src != -1) @@ -2152,7 +2229,10 @@ std::map > cpu::disassemble(const uint16_t work_values.push_back(src_text.work_value); // destination - auto dst_text { addressing_to_string(dst_register, (addr + src_text.length) & 65535, word_mode) }; + auto addressing_dst = addressing_to_string(dst_register, (addr + src_text.length) & 65535, word_mode); + if (addressing_dst.has_value() == false) + return { }; + auto dst_text { addressing_dst.value() }; auto next_word_dst = dst_text.instruction_part; if (next_word_dst != -1) @@ -2303,7 +2383,10 @@ std::map > cpu::disassemble(const uint16_t text = format("TRAP %o", instruction & 255); if ((instruction & ~0b111111) == 0b0000000001000000) { - auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; + auto addressing = addressing_to_string(dst_register, (addr + 2) & 65535, word_mode); + if (addressing.has_value() == false) + return { }; + auto dst_text { addressing.value() }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -2315,7 +2398,10 @@ std::map > cpu::disassemble(const uint16_t } if ((instruction & 0b1111111000000000) == 0b0000100000000000) { - auto dst_text { addressing_to_string(dst_register, (addr + 2) & 65535, word_mode) }; + auto addressing = addressing_to_string(dst_register, (addr + 2) & 65535, word_mode); + if (addressing.has_value() == false) + return { }; + auto dst_text { addressing.value() }; auto next_word = dst_text.instruction_part; if (next_word != -1) @@ -2353,7 +2439,7 @@ std::map > cpu::disassemble(const uint16_t for(int i=0; i<8; i++) { if (i < 6) - registers.push_back(format("%06o", getRegister(i))); + registers.push_back(format("%06o", get_register(i))); else if (i == 6) registers.push_back(format("%06o", sp[psw >> 14])); else @@ -2411,7 +2497,7 @@ void cpu::step() uint16_t instr = b->read_word(instruction_start); - addRegister(7, rm_cur, 2); + add_register(7, 2); if (double_operand_instructions(instr)) return; diff --git a/cpu.h b/cpu.h index deaa2d9..1d5ce10 100644 --- a/cpu.h +++ b/cpu.h @@ -83,11 +83,11 @@ private: bool check_pending_interrupts() const; // needs the 'qi_lock'-lock bool execute_any_pending_interrupt(); - uint16_t addRegister(const int nr, const rm_selection_t mode_selection, const uint16_t value); + uint16_t add_register(const int nr, const uint16_t value); void addToMMR1(const gam_rc_t & g); - gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool read_value = true); + gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const bool read_value = true); gam_rc_t getGAMAddress(const uint8_t mode, const int reg, const word_mode_t word_mode); bool putGAM(const gam_rc_t & g, const uint16_t value); // returns false when flag registers should not be updated @@ -105,7 +105,7 @@ private: uint16_t work_value; }; - operand_parameters addressing_to_string(const uint8_t mode_register, const uint16_t pc, const word_mode_t word_mode) const; + std::optional addressing_to_string(const uint8_t mode_register, const uint16_t pc, const word_mode_t word_mode) const; void add_to_stack_trace(const uint16_t p); void pop_from_stack_trace(); @@ -181,8 +181,8 @@ public: uint16_t getStackPointer(const int which) const { assert(which >= 0 && which < 4); return sp[which]; } uint16_t getPC() const { return pc; } - void setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection = rm_cur); - void setRegisterLowByte(const int nr, const word_mode_t word_mode, const uint16_t value); + void set_register(const int nr, const uint16_t value); + void set_registerLowByte(const int nr, const word_mode_t word_mode, const uint16_t value); // used by 'main' for json-validation void lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint16_t value); void lowlevel_register_sp_set(const uint8_t set, const uint16_t value); @@ -193,7 +193,7 @@ public: void setStackPointer(const int which, const uint16_t value) { assert(which >= 0 && which < 4); sp[which] = value; } void setPC(const uint16_t value) { pc = value; } - uint16_t getRegister(const int nr, const rm_selection_t mode_selection = rm_cur) const; + uint16_t get_register(const int nr) const; bool put_result(const gam_rc_t & g, const uint16_t value); }; diff --git a/debugger.cpp b/debugger.cpp index 53058c1..be9f612 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -431,6 +431,8 @@ void configure_disk(bus *const b, console *const cnsl) int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool instruction_only) { auto data = c->disassemble(pc); + if (data.empty()) + return 2; // problem! auto registers = data["registers"]; auto psw = data["psw"][0]; @@ -933,11 +935,20 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto for(int i=0; iread(cur_addr, wm_word, rm_cur, true) : b->read_physical(cur_addr); + uint16_t val = 0; - if (val == -1) { - cnsl->put_string_lf(format("Can't read from %06o\n", cur_addr)); - break; + if (parts[2] == "v") { + auto v = b->peek_word(c->getPSW_runmode(), cur_addr); + + if (v.has_value() == false) { + cnsl->put_string_lf(format("Can't read from %06o\n", cur_addr)); + break; + } + + val = v.value(); + } + else { + val = b->read_physical(cur_addr); } if (n == 1) @@ -1310,7 +1321,7 @@ void run_bic(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop { cpu *const c = b->getCpu(); - c->setRegister(7, start_addr); + c->set_register(7, start_addr); *cnsl->get_running_flag() = true; diff --git a/loaders.cpp b/loaders.cpp index 340cebb..dca3fd4 100644 --- a/loaders.cpp +++ b/loaders.cpp @@ -156,7 +156,7 @@ void set_boot_loader(bus *const b, const bootloader_t which) for(uint16_t i=0; iwrite_word(uint16_t(offset + i * 2), bl[i]); - c->setRegister(7, start); + c->set_register(7, start); } std::optional load_tape(bus *const b, const std::string & file) @@ -291,5 +291,5 @@ void load_p11_x11(bus *const b, const std::string & file) fclose(fh); cpu *const c = b->getCpu(); - c->setRegister(7, 0); + c->set_register(7, 0); } diff --git a/main.cpp b/main.cpp index e4be40c..7ed75b7 100644 --- a/main.cpp +++ b/main.cpp @@ -633,13 +633,13 @@ int main(int argc, char *argv[]) if (bic_start.has_value() == false) return 1; // fail - b->getCpu()->setRegister(7, bic_start.value()); + b->getCpu()->set_register(7, bic_start.value()); } if (sa_set) - b->getCpu()->setRegister(7, start_addr); + b->getCpu()->set_register(7, start_addr); - DOLOG(info, true, "Start running at %06o", b->getCpu()->getRegister(7)); + DOLOG(info, true, "Start running at %06o", b->getCpu()->get_register(7)); #if !defined(_WIN32) struct sigaction sa { }; diff --git a/mmu.cpp b/mmu.cpp index 587a7b3..c47ea63 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -17,9 +17,10 @@ mmu::~mmu() { } -void mmu::begin(memory *const m) +void mmu::begin(memory *const m, cpu *const c) { this->m = m; + this->c = c; reset(); } @@ -139,7 +140,7 @@ bool mmu::get_use_data_space(const int run_mode) const { constexpr const int di_ena_mask[4] = { 4, 2, 0, 1 }; - return !!(MMR3 & di_ena_mask[run_mode]); + return MMR3 & di_ena_mask[run_mode]; } void mmu::clearMMR1() @@ -347,17 +348,18 @@ std::pair mmu::get_trap_action(const int run_mode, const boo void mmu::mmudebug(const uint16_t a) { +#if !defined(TURBO) for(int rm=0; rm<4; rm++) { auto ma = calculate_physical_address(rm, a); TRACE("RM %d, a: %06o, apf: %d, PI: %08o (PSW: %d), PD: %08o (PSW: %d)", rm, ma.virtual_address, ma.apf, ma.physical_instruction, ma.physical_instruction_is_psw, ma.physical_data, ma.physical_data_is_psw); } +#endif } -void mmu::verify_page_access(cpu *const c, const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write) +void mmu::verify_page_access(const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write) { const auto [ trap_action, access_control ] = get_trap_action(run_mode, d, apf, is_write); - if (trap_action == T_PROCEED) return; @@ -404,7 +406,7 @@ void mmu::verify_page_access(cpu *const c, const uint16_t virt_addr, const int r } } -void mmu::verify_access_valid(cpu *const c, const uint32_t m_offset, const int run_mode, const bool d, const int apf, const bool is_io, const bool is_write) +void mmu::verify_access_valid(const uint32_t m_offset, const int run_mode, const bool d, const int apf, const bool is_io, const bool is_write) { if (m_offset >= m->get_memory_size() && !is_io) [[unlikely]] { TRACE("TRAP(04) (throw 6) on address %08o", m_offset); @@ -433,14 +435,17 @@ void mmu::verify_access_valid(cpu *const c, const uint32_t m_offset, const int r } } -void mmu::verify_page_length(cpu *const c, const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write) +void mmu::verify_page_length(const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write) { uint16_t pdr_len = get_pdr_len(run_mode, d, apf); + if (pdr_len == 127) + return; + uint16_t pdr_cmp = (virt_addr >> 6) & 127; bool direction = get_pdr_direction(run_mode, d, apf); - if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) [[unlikely]] { + if (direction == false ? pdr_cmp > pdr_len : pdr_cmp < pdr_len) [[unlikely]] { TRACE("mmu::calculate_physical_address::p_offset %o versus %o direction %d", pdr_cmp, pdr_len, direction); TRACE("TRAP(0250) (throw 7) on address %06o", virt_addr); @@ -471,35 +476,32 @@ void mmu::verify_page_length(cpu *const c, const uint16_t virt_addr, const int r } } -uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const d_i_space_t space) +uint32_t mmu::calculate_physical_address(const int run_mode, const uint16_t a, const bool is_write, const d_i_space_t space) { uint32_t m_offset = a; if (is_enabled() || (is_write && (getMMR0() & (1 << 8 /* maintenance check */)))) { - uint8_t apf = a >> 13; // active page field - bool d = space == d_space && get_use_data_space(run_mode); uint16_t p_offset = a & 8191; // page offset - m_offset = get_physical_memory_offset(run_mode, d, apf); + uint8_t apf = a >> 13; // active page field + m_offset = get_physical_memory_offset(run_mode, d, apf); m_offset += p_offset; if ((getMMR3() & 16) == 0) // off is 18bit m_offset &= 0x3ffff; - if (trap_on_failure) { - verify_page_access(c, a, run_mode, d, apf, is_write); + verify_page_access(a, run_mode, d, apf, is_write); - // e.g. ram or i/o, not unmapped - uint32_t io_base = get_io_base(); - bool is_io = m_offset >= io_base; + // e.g. ram or i/o, not unmapped + uint32_t io_base = get_io_base(); + bool is_io = m_offset >= io_base; - verify_access_valid(c, m_offset, run_mode, d, apf, is_io, is_write); + verify_access_valid(m_offset, run_mode, d, apf, is_io, is_write); - verify_page_length(c, a, run_mode, d, apf, is_write); - } + verify_page_length(a, run_mode, d, apf, is_write); } return m_offset; @@ -560,10 +562,10 @@ void mmu::set_par_pdr(const JsonVariantConst j_in, const int run_mode, const boo pages[run_mode][is_d][i_pdr++].pdr = v; } -mmu *mmu::deserialize(const JsonVariantConst j, memory *const mem) +mmu *mmu::deserialize(const JsonVariantConst j, memory *const mem, cpu *const c) { mmu *m = new mmu(); - m->begin(mem); + m->begin(mem, c); for(int run_mode=0; run_mode<4; run_mode++) { if (run_mode == 2) diff --git a/mmu.h b/mmu.h index c1316d4..6f4e92a 100644 --- a/mmu.h +++ b/mmu.h @@ -56,22 +56,23 @@ private: uint16_t CSR { 0 }; memory *m { nullptr }; + cpu *c { nullptr }; JsonDocument add_par_pdr(const int run_mode, const bool is_d) const; void set_par_pdr(const JsonVariantConst j_in, const int run_mode, const bool is_d); - void verify_page_access (cpu *const c, const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write); - void verify_access_valid(cpu *const c, const uint32_t m_offset, const int run_mode, const bool d, const int apf, const bool is_io, const bool is_write); - void verify_page_length (cpu *const c, const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write); + void verify_page_access (const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write); + void verify_access_valid(const uint32_t m_offset, const int run_mode, const bool d, const int apf, const bool is_io, const bool is_write); + void verify_page_length (const uint16_t virt_addr, const int run_mode, const bool d, const int apf, const bool is_write); public: mmu(); virtual ~mmu(); - void begin(memory *const m); + void begin(memory *const m, cpu *const c); JsonDocument serialize() const; - static mmu *deserialize(const JsonVariantConst j, memory *const m); + static mmu *deserialize(const JsonVariantConst j, memory *const m, cpu *const c); void mmudebug(const uint16_t a); @@ -81,7 +82,7 @@ public: void show_state(console *const cnsl) const override; bool is_enabled() const { return MMR0 & 1; } - bool is_locked() const { return !!(MMR0 & 0160000); } + bool is_locked() const { return MMR0 & 0160000; } void set_page_trapped (const int run_mode, const bool d, const int apf) { pages[run_mode][d][apf].pdr |= 1 << 7; } void set_page_written_to(const int run_mode, const bool d, const int apf) { pages[run_mode][d][apf].pdr |= 1 << 6; } @@ -94,7 +95,7 @@ public: memory_addresses_t calculate_physical_address(const int run_mode, const uint16_t a) const; std::pair get_trap_action(const int run_mode, const bool d, const int apf, const bool is_write); - uint32_t calculate_physical_address(cpu *const c, const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const d_i_space_t space); + uint32_t calculate_physical_address(const int run_mode, const uint16_t a, const bool is_write, const d_i_space_t space); uint16_t getMMR0() const { return MMR0; } uint16_t getMMR1() const { return MMR1; } diff --git a/rp06.cpp b/rp06.cpp index 25804e6..f603860 100644 --- a/rp06.cpp +++ b/rp06.cpp @@ -191,7 +191,7 @@ void rp06::write_word(const uint16_t addr, uint16_t v) uint32_t cur_n = std::min(end_offset - cur_offset, SECTOR_SIZE); if (function_code == 070) { - DOLOG(debug, false, "RP06: reading %u bytes from %u (dec) to %06o (oct)", cur_n, offs, addr); + DOLOG(debug, false, "RP06: reading %u bytes from %u (dec) to %06o (oct)", cur_n, cur_offset, addr); if (!fhs.at(0)->read(cur_offset, cur_n, xfer_buffer, SECTOR_SIZE)) { DOLOG(ll_error, true, "RP06 read error %s from %u", strerror(errno), cur_offset); @@ -204,7 +204,7 @@ void rp06::write_word(const uint16_t addr, uint16_t v) b->write_unibus_byte(addr++, xfer_buffer[i]); } else { - DOLOG(debug, false, "RP06: writing %u bytes to %u (dec) from %06o (oct)", cur_n, offs, addr); + DOLOG(debug, false, "RP06: writing %u bytes to %u (dec) from %06o (oct)", cur_n, cur_offset, addr); for(uint32_t i=0; iread_unibus_byte(addr++); diff --git a/work/werkend-mu/run.sh b/work/werkend-mu/run.sh index b7d758c..f858396 100755 --- a/work/werkend-mu/run.sh +++ b/work/werkend-mu/run.sh @@ -6,9 +6,9 @@ echo 'rl(0,0)unix' rm ~/temp/ramdisk/test2.log if [ "$1" = "fast" ] ; then -./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -S 256 -L error,info -l ~/temp/ramdisk/test2.log -P +./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -S 256 -L error,info -l ~/temp/ramdisk/test2.log -P -R rl02 elif [ "$1" = "medium" ] ; then -./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -L error,info -l ~/temp/ramdisk/test2.log -d -S 256 -P +./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -L error,info -l ~/temp/ramdisk/test2.log -d -S 256 -P -R rl02 else -./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -L error,debug -l ~/temp/ramdisk/test2.log -d -t -X -S 256 -P +./build/kek -r work/werkend-mu/unix_v7m_rl0.dsk -r work/werkend-mu/unix_v7m_rl1.dsk -b -L error,debug -l ~/temp/ramdisk/test2.log -d -t -X -S 256 -P -R rl02 fi