diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini index c05e4b0..e7d8b97 100644 --- a/ESP32/platformio.ini +++ b/ESP32/platformio.ini @@ -11,7 +11,7 @@ framework = arduino monitor_speed = 115200 upload_speed = 1000000 lib_deps = greiman/SdFat@^2.1.2 - adafruit/Adafruit NeoPixel@^1.10.4 + adafruit/Adafruit NeoPixel build_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 build_unflags = -std=gnu++11 -Os diff --git a/bus.cpp b/bus.cpp index dfe55ed..b0465ae 100644 --- a/bus.cpp +++ b/bus.cpp @@ -17,9 +17,11 @@ // see also https://github.com/espressif/esp-idf/issues/1934 constexpr int n_pages = 12; #else -constexpr int n_pages = 16; +constexpr int n_pages = 32; #endif +constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 }; + bus::bus() { m = new memory(n_pages * 8192); @@ -74,7 +76,7 @@ uint16_t bus::read_par(const uint32_t a, const int run_mode, const bool word_mod return word_mode ? (a & 1 ? t >> 8 : t & 255) : t; } -uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, const bool peek_only) +uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, const bool peek_only, const d_i_space_t space) { uint16_t temp = 0; @@ -99,7 +101,7 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, } if (a == ADDR_PIR) { // PIR - DOLOG(debug, !peek_only, "read PIT"); + DOLOG(debug, !peek_only, "read PIR"); return PIR; } @@ -256,11 +258,15 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, // LO size register field must be all 1s, so subtract 1 constexpr uint32_t system_size = n_pages * 8192 / 64 - 1; - if (a == ADDR_SYSSIZE + 2) // system size HI - return system_size >> 16; + if (a == ADDR_SYSSIZE + 2) { // system size HI + printf("accessing system size HI\r\n"); + return ((system_size >> 6) - 1) >> 16; + } - if (a == ADDR_SYSSIZE) // system size LO - return system_size & 65535; + if (a == ADDR_SYSSIZE) { // system size LO + printf("accessing system size LO\r\n"); + return (system_size >> 6) - 1; + } if (a & 1) DOLOG(debug, !peek_only, "bus::readWord: odd address UNHANDLED %o", a); @@ -272,7 +278,7 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3; - uint32_t m_offset = calculate_physical_address(run_mode, a, !peek_only, false, peek_only, word_mode); + uint32_t m_offset = calculate_physical_address(run_mode, a, !peek_only, false, peek_only, space == d_space); if (word_mode) temp = m -> readByte(m_offset); @@ -322,32 +328,164 @@ void bus::setMMR2(const uint16_t value) MMR2 = value; } -uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const bool peek_only, const bool word_mode) +memory_addresses_t bus::calculate_physical_address(const int run_mode, const uint16_t a) { - uint32_t m_offset = a; - const uint8_t apf = a >> 13; // active page field - if ((a & 1) && word_mode == 0 && peek_only == false) { - DOLOG(debug, true, "TRAP(004) (throw 5) on address %06o, page %d, run mode %d, MMR0 %06o, MMR2 %06o", a, apf, run_mode, MMR0, MMR2); + uint32_t physical_instruction = pages[run_mode][0][apf].par * 64; + uint32_t physical_data = pages[run_mode][1][apf].par * 64; + uint16_t p_offset = a & 8191; // page offset + + physical_instruction += p_offset; + physical_data += p_offset; + + if (MMR0 & 1) { // MMU enabled? + if ((MMR3 & 16) == 0) { // offset is 18bit + physical_instruction &= 0x3ffff; + physical_data &= 0x3ffff; + } + } + + return { a, apf, physical_instruction, physical_data }; +} + +void bus::check_address(const bool trap_on_failure, const bool is_write, const memory_addresses_t & addr, const bool word_mode, const bool is_data, const int run_mode) +{ + // check for odd address access + if ((addr.virtual_address & 1) && word_mode == 0) { if (is_write) - pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I - - //MMR0 &= ~14; // add current page - //MMR0 |= apf << 1; + pages[run_mode][is_data][addr.apf].pdr |= 1 << 7; c->schedule_trap(004); // invalid access throw 5; } + if (!trap_on_failure) + return; + + // check access to page + if ((MMR0 & (1 << 9)) || c->get_34()) { + const int access_control = pages[run_mode][is_data][addr.apf].pdr & 7; + + // write + if (is_write && access_control != 6) { + c->schedule_trap(0250); // invalid address + + if (is_write) + pages[run_mode][is_data][addr.apf].pdr |= 1 << 7; + + if ((MMR0 & 0160000) == 0) { + MMR0 &= 017777; + MMR0 |= 1 << 13; // read-only + + MMR0 &= ~(3 << 5); + MMR0 |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode? + + MMR0 &= ~14; // add current page + MMR0 |= addr.apf << 1; + } + + DOLOG(debug, true, "MMR0: %06o", MMR0); + + throw 1; + } + + // read + if (!is_write) { + if (access_control == 0 || access_control == 1 || access_control == 3 || access_control == 4 || access_control == 7) { + c->schedule_trap(0250); // invalid address + + if (is_write) + pages[run_mode][is_data][addr.apf].pdr |= 1 << 7; // TODO: D/I + + if ((MMR0 & 0160000) == 0) { + MMR0 &= 017777; + + if (access_control == 0 || access_control == 4) + MMR0 |= 1 << 15; // not resident + else + MMR0 |= 1 << 13; // read-only + + MMR0 &= ~(3 << 5); + MMR0 |= run_mode << 5; + + MMR0 &= ~14; // add current page + MMR0 |= addr.apf << 1; + } + + throw 2; + } + } + } + + // beyond physical range? + if ((is_data && addr.physical_data >= n_pages * 8192) || (!is_data && addr.physical_instruction >= n_pages * 8192)) { + if ((MMR0 & 0160000) == 0) { + MMR0 &= 017777; + MMR0 |= 1 << 15; // non-resident + + MMR0 &= ~14; // add current page + MMR0 |= addr.apf << 1; + + MMR0 &= ~(3 << 5); + MMR0 |= run_mode << 5; + } + + if (is_write) + pages[run_mode][is_data][addr.apf].pdr |= 1 << 7; // TODO: D/I + + c->schedule_trap(04); + + throw 3; + } + + // check if invalid access IN a page + uint16_t pdr_len = (pages[run_mode][is_data][addr.apf].pdr >> 8) & 127; + uint16_t pdr_cmp = (addr.virtual_address >> 6) & 127; + + bool direction = pages[run_mode][is_data][addr.apf].pdr & 8; // TODO: D/I + + if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) { + c->schedule_trap(0250); // invalid access + + if ((MMR0 & 0160000) == 0) { + MMR0 &= 017777; + MMR0 |= 1 << 14; // length + + MMR0 &= ~14; // add current page + MMR0 |= addr.apf << 1; + + MMR0 &= ~(3 << 5); + MMR0 |= run_mode << 5; + } + + if (is_write) + pages[run_mode][0][addr.apf].pdr |= 1 << 7; // TODO: D/I + + throw 4; + } +} + +bool bus::get_use_data_space(const int run_mode) +{ + return !!(MMR3 & di_ena_mask[run_mode]); +} + +uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const bool peek_only, const bool is_data) +{ + uint32_t m_offset = a; + if (MMR0 & 1) { - // TODO: D/I - m_offset = pages[run_mode][0][apf].par * 64; // memory offset TODO: handle 16b int-s + const uint8_t apf = a >> 13; // active page field + + bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false; uint16_t p_offset = a & 8191; // page offset + m_offset = pages[run_mode][d][apf].par * 64; // memory offset TODO: handle 16b int-s + m_offset += p_offset; if ((MMR3 & 16) == 0) // off is 18bit @@ -355,7 +493,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c if (trap_on_failure) { if ((MMR0 & (1 << 9)) || c->get_34()) { - const int access_control = pages[run_mode][0][apf].pdr & 7; + const int access_control = pages[run_mode][d][apf].pdr & 7; if (is_write && access_control != 6) { // write DOLOG(debug, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a); @@ -363,7 +501,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c c->schedule_trap(0250); // invalid address if (is_write) - pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I + pages[run_mode][d][apf].pdr |= 1 << 7; if ((MMR0 & 0160000) == 0) { MMR0 &= 017777; @@ -387,7 +525,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c c->schedule_trap(0250); // invalid address if (is_write) - pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I + pages[run_mode][d][apf].pdr |= 1 << 7; if ((MMR0 & 0160000) == 0) { MMR0 &= 017777; @@ -425,20 +563,19 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c } if (is_write) - pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I + pages[run_mode][d][apf].pdr |= 1 << 7; // TODO: D/I c->schedule_trap(04); throw 3; } - // uint16_t pdr_len = ((pages[run_mode][0][apf].pdr >> 8) & 127) * 64; // TODO: D/I - uint16_t pdr_len = (pages[run_mode][0][apf].pdr >> 8) & 127; + uint16_t pdr_len = (pages[run_mode][d][apf].pdr >> 8) & 127; uint16_t pdr_cmp = (a >> 6) & 127; - bool direction = pages[run_mode][0][apf].pdr & 8; // TODO: D/I + bool direction = pages[run_mode][d][apf].pdr & 8; // TODO: D/I - // DOLOG(debug, true, "p_offset %06o pdr_len %06o direction %d, run_mode %d, apf %d, pdr: %06o", p_offset, pdr_len, direction, run_mode, apf, pages[run_mode][0][apf].pdr); + // DOLOG(debug, true, "p_offset %06o pdr_len %06o direction %d, run_mode %d, apf %d, pdr: %06o", p_offset, pdr_len, direction, run_mode, apf, pages[run_mode][d][apf].pdr); if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) { DOLOG(debug, !peek_only, "bus::calculate_physical_address::p_offset %o versus %o direction %d", pdr_cmp, pdr_len, direction); @@ -457,13 +594,13 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c } if (is_write) - pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I + pages[run_mode][d][apf].pdr |= 1 << 7; // TODO: D/I throw 4; } } - DOLOG(debug, !peek_only, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d)", a, m_offset, run_mode, apf, pages[run_mode][0][apf].par * 64, p_offset, pages[run_mode][0][apf].pdr & 7); // TODO: D/I + DOLOG(debug, !peek_only, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d)", a, m_offset, run_mode, apf, pages[run_mode][d][apf].par * 64, p_offset, pages[run_mode][d][apf].pdr & 7); // TODO: D/I } return m_offset; @@ -489,6 +626,8 @@ void bus::write_pdr(const uint32_t a, const int run_mode, const uint16_t value, int page = (a >> 1) & 7; if (word_mode) { + assert(a != 0 || value < 256); + a & 1 ? (pages[run_mode][is_d][page].pdr &= 0xff, pages[run_mode][is_d][page].pdr |= value << 8) : (pages[run_mode][is_d][page].pdr &= 0xff00, pages[run_mode][is_d][page].pdr |= value); } @@ -524,15 +663,18 @@ void bus::write_par(const uint32_t a, const int run_mode, const uint16_t value, DOLOG(debug, true, "write run-mode %d: %c PAR for %d: %o (%07o)", run_mode, is_d ? 'D' : 'I', page, word_mode ? value & 0xff : value, pages[run_mode][is_d][page].par * 64); } -void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev) +void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev, const d_i_space_t space) { - int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3; + int run_mode = (c->getPSW() >> (use_prev ? 12 : 14)) & 3; if ((MMR0 & 1) == 1 && (a & 1) == 0 && a != ADDR_MMR0) { - const uint8_t apf = a >> 13; // active page field + const uint8_t apf = a >> 13; // active page field - // TODO: D/I - pages[run_mode][0][apf].pdr |= 64; // set 'W' (written to) bit + bool is_data = space == d_space; + + bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false; + + pages[run_mode][d][apf].pdr |= 64; // set 'W' (written to) bit } if (a >= 0160000) { @@ -723,7 +865,7 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo return; } - uint32_t m_offset = calculate_physical_address(run_mode, a, true, true, false, word_mode); + uint32_t m_offset = calculate_physical_address(run_mode, a, true, true, false, space == d_space); DOLOG(debug, true, "WRITE to %06o/%07o: %o", a, m_offset, value); @@ -733,9 +875,37 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo m->writeWord(m_offset, value); } -uint16_t bus::readWord(const uint16_t a) +void bus::writePhysical(const uint32_t a, const uint16_t value) { - return read(a, false, false, false); + DOLOG(debug, true, "physicalWRITE %06o to %o", value, a); + + if (a >= n_pages * 8192) { + DOLOG(debug, true, "physicalWRITE to %o: trap 004", a); + c->schedule_trap(004); + } + else { + m->writeWord(a, value); + } +} + +uint16_t bus::readPhysical(const uint32_t a) +{ + if (a >= n_pages * 8192) { + DOLOG(debug, true, "physicalREAD from %o: trap 004", a); + c->schedule_trap(004); + + return 0; + } + else { + uint16_t value = m->readWord(a); + DOLOG(debug, true, "physicalREAD %06o from %o", value, a); + return value; + } +} + +uint16_t bus::readWord(const uint16_t a, const d_i_space_t s) +{ + return read(a, false, false, false, s); } uint16_t bus::peekWord(const uint16_t a) diff --git a/bus.h b/bus.h index cbf5330..7669b89 100644 --- a/bus.h +++ b/bus.h @@ -55,8 +55,16 @@ class cpu; class memory; class tty; -typedef struct -{ +typedef enum { d_space, i_space } d_i_space_t; + +typedef struct { + uint16_t virtual_address; + uint8_t apf; // active page field + uint32_t physical_instruction; + uint32_t physical_data; +} memory_addresses_t; + +typedef struct { uint16_t par, pdr; } page_t; @@ -111,17 +119,20 @@ public: void set_lf_crs_b7(); uint8_t get_lf_crs(); - uint16_t read(const uint16_t a, const bool word_mode, const bool use_prev, const bool peek_only=false); + uint16_t read(const uint16_t a, const bool word_mode, const bool use_prev, const bool peek_only=false, const d_i_space_t s = i_space); uint16_t readByte(const uint16_t a) { return read(a, true, false); } - uint16_t readWord(const uint16_t a); + uint16_t readWord(const uint16_t a, const d_i_space_t s = i_space); uint16_t peekWord(const uint16_t a); uint16_t readUnibusByte(const uint16_t a); - void write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev); + void write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev, const d_i_space_t s = i_space); void writeByte(const uint16_t a, const uint8_t value) { return write(a, true, value, false); } void writeWord(const uint16_t a, const uint16_t value); + uint16_t readPhysical(const uint32_t a); + void writePhysical(const uint32_t a, const uint16_t value); + void writeUnibusByte(const uint16_t a, const uint8_t value); uint16_t getMMR0() { return MMR0; } @@ -137,5 +148,9 @@ public: uint16_t get_switch_register() const { return switch_register; } - uint32_t calculate_physical_address(const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const bool peek_only, const bool word_mode); + uint32_t calculate_physical_address(const int run_mode, const uint16_t a, const bool trap_on_failure, const bool is_write, const bool peek_only, const bool is_data); + + bool get_use_data_space(const int run_mode); + memory_addresses_t calculate_physical_address(const int run_mode, const uint16_t a); + void check_address(const bool trap_on_failure, const bool is_write, const memory_addresses_t & addr, const bool word_mode, const bool is_data, const int run_mode); }; diff --git a/console_ncurses.cpp b/console_ncurses.cpp index 6a3555b..5720b85 100644 --- a/console_ncurses.cpp +++ b/console_ncurses.cpp @@ -139,7 +139,7 @@ void console_ncurses::panel_update_thread() int run_mode = current_PSW >> 14; uint16_t current_PC = c->getPC(); - uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, true); + uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, false); uint16_t current_instr = b->readWord(current_PC); diff --git a/cpu.cpp b/cpu.cpp index cbf9954..b957c87 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -10,6 +10,8 @@ #include "log.h" #include "utils.h" +uint16_t oldpc = 0; + #define SIGN(x, wm) ((wm) ? (x) & 0x80 : (x) & 0x8000) #define IS_0(x, wm) ((wm) ? ((x) & 0xff) == 0 : (x) == 0) @@ -88,9 +90,8 @@ void cpu::reset() memset(regs0_5, 0x00, sizeof regs0_5); memset(sp, 0x00, sizeof sp); pc = 0; - psw = 7 << 5; + psw = 0; // 7 << 5; fpsr = 0; - runMode = false; init_interrupt_queue(); } @@ -152,17 +153,17 @@ void cpu::setRegisterLowByte(const int nr, const bool word_mode, const uint16_t } } -bool cpu::put_result(const uint16_t a, const uint8_t dst_mode, const uint8_t dst_reg, const bool word_mode, const uint16_t value) +bool cpu::put_result(const gam_rc_t & g, const uint16_t value) { - if (dst_mode == 0) { - setRegisterLowByte(dst_reg, word_mode, value); + if (g.addr.has_value() == false) { + setRegisterLowByte(g.reg, g.word_mode, value); return true; } - b->write(a, word_mode, value, false); + b->write(g.addr.value(), g.word_mode, value, false); - return a != ADDR_PSW; + return g.addr.value() != ADDR_PSW; } uint16_t cpu::addRegister(const int nr, const bool prev_mode, const uint16_t value) @@ -259,6 +260,13 @@ void cpu::setPSW(const uint16_t v, const bool limited) } } +void cpu::setPSW_flags_nzv(const uint16_t value, const bool word_mode) +{ + setPSW_n(SIGN(value, word_mode)); + setPSW_z(IS_0(value, word_mode)); + setPSW_v(false); +} + bool cpu::check_queued_interrupts() { std::unique_lock lck(qi_lock); @@ -314,141 +322,86 @@ void cpu::addToMMR1(const uint8_t mode, const uint8_t reg, const bool word_mode) } // GAM = general addressing modes -uint16_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode) +gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode, const bool read_value) { - uint16_t next_word = 0; - uint16_t temp = 0; + gam_rc_t g { false, false, false, i_space, { }, 0 }; + g.word_mode = word_mode; // word/byte + g.prev_mode = prev_mode; // run mode + g.set = getBitPSW(11); - int set = getBitPSW(11); + uint16_t next_word = 0; + + g.space = reg == 7 ? i_space : (b->get_use_data_space(psw >> 14) ? d_space : i_space); switch(mode) { case 0: // 000 - return getRegister(reg, set, prev_mode) & (word_mode ? 0xff : 0xffff); + g.reg = reg; + g.value = getRegister(reg, g.set, prev_mode) & (word_mode ? 0xff : 0xffff); + break; case 1: - return b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode); + g.addr = getRegister(reg, g.set, prev_mode); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, false, g.space); + break; case 2: - temp = b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode); + g.addr = getRegister(reg, g.set, prev_mode); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, false, g.space); addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? 2 : 1); - return temp; + break; case 3: - temp = b -> read(b -> read(getRegister(reg, set, prev_mode), false, prev_mode), word_mode, prev_mode); + g.addr = b->read(getRegister(reg, g.set, prev_mode), false, prev_mode, g.space); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, false, d_space); addRegister(reg, prev_mode, 2); - return temp; + break; case 4: addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? -2 : -1); - return b -> read(getRegister(reg, set, prev_mode), word_mode, prev_mode); + g.addr = getRegister(reg, g.set, prev_mode); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, false, d_space); + break; case 5: addRegister(reg, prev_mode, -2); - return b -> read(b -> read(getRegister(reg, set, prev_mode), false, prev_mode), word_mode, prev_mode); + g.addr = b->read(getRegister(reg, g.set, prev_mode), false, prev_mode, g.space); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, d_space); + break; case 6: next_word = b -> read(getPC(), false, prev_mode); addRegister(7, prev_mode, + 2); - temp = b -> read(getRegister(reg, set, prev_mode) + next_word, word_mode, prev_mode); - return temp; + g.addr = getRegister(reg, g.set, prev_mode) + next_word; + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, d_space); + break; case 7: next_word = b -> read(getPC(), false, prev_mode); addRegister(7, prev_mode, + 2); - return b -> read(b -> read(getRegister(reg, set, prev_mode) + next_word, false, prev_mode), word_mode, prev_mode); + g.addr = b->read(getRegister(reg, g.set, prev_mode) + next_word, false, prev_mode); + if (read_value) + g.value = b->read(g.addr.value(), word_mode, prev_mode, d_space); + break; } - return -1; + return g; } -bool cpu::putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, bool const prev_mode) +bool cpu::putGAM(const gam_rc_t & g, const uint16_t value) { - uint16_t next_word = 0; - int addr = -1; + if (g.addr.has_value()) { + b->write(g.addr.value(), g.word_mode, value, g.prev_mode, g.space); - int set = getBitPSW(11); - - uint16_t dummy = 0; - - switch(mode) { - case 0: - setRegister(reg, prev_mode, value); - break; - case 1: - addr = getRegister(reg, set, prev_mode); - b -> write(addr, word_mode, value, false); - break; - case 2: - addr = getRegister(reg, set, prev_mode); - b -> write(addr, word_mode, value, false); - addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? 2 : 1); - break; - case 3: - addr = b -> readWord(getRegister(reg, set, prev_mode)); - b -> write(addr, word_mode, value, false); - addRegister(reg, prev_mode, 2); - break; - case 4: - dummy = addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? -2 : -1); - b -> write(dummy, word_mode, value, false); - break; - case 5: - addRegister(reg, prev_mode, -2); - addr = b -> readWord(getRegister(reg, set, prev_mode)); - b -> write(addr, word_mode, value, false); - break; - case 6: - next_word = b -> readWord(getPC()); - addRegister(7, prev_mode, 2); - addr = (getRegister(reg, set, prev_mode) + next_word) & 0xffff; - b -> write(addr, word_mode, value, false); - break; - case 7: - next_word = b -> readWord(getPC()); - addRegister(7, prev_mode, 2); - addr = b -> readWord(getRegister(reg, set, prev_mode) + next_word); - b -> write(addr, word_mode, value, false); - break; - - default: - // error - break; + return g.addr.value() != ADDR_PSW; } - return addr == -1 || addr != ADDR_PSW; + setRegister(g.reg, g.set, g.prev_mode, value); + + return true; } -uint16_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode, const bool prev_mode) +gam_rc_t cpu::getGAMAddress(const uint8_t mode, const int reg, const bool word_mode) { - uint16_t next_word = 0; - uint16_t temp = 0; - - int set = getBitPSW(11); - - switch(mode) { - case 0: - // registers are also mapped in memory - return 0177700 + reg; - case 1: - return getRegister(reg, set, prev_mode); - case 2: - temp = getRegister(reg, set, prev_mode); - addRegister(reg, prev_mode, !word_mode || reg == 6 || reg == 7 ? 2 : 1); - return temp; - case 3: - temp = b -> readWord(getRegister(reg, set, prev_mode)); - addRegister(reg, prev_mode, 2); - return temp; - case 4: - addRegister(reg, prev_mode, !word_mode || reg == 6 || reg == 7 ? -2 : -1); - return getRegister(reg, set, prev_mode); - case 5: - addRegister(reg, prev_mode, -2); - return b -> readWord(getRegister(reg, set, prev_mode)); - case 6: - next_word = b -> readWord(getPC()); - addRegister(7, prev_mode, 2); - return getRegister(reg, set, prev_mode) + next_word; - case 7: - next_word = b -> readWord(getPC()); - addRegister(7, prev_mode, 2); - return b -> readWord(getRegister(reg, set, prev_mode) + next_word); - } - - return -1; + return getGAM(mode, reg, word_mode, false, false); } bool cpu::double_operand_instructions(const uint16_t instr) @@ -467,7 +420,10 @@ bool cpu::double_operand_instructions(const uint16_t instr) const uint8_t src_mode = (src >> 3) & 7; const uint8_t src_reg = src & 7; - const uint16_t src_value = operation == 0b110 ? 0 : getGAM(src_mode, src_reg, word_mode, false); + gam_rc_t g_src { false, false, false, i_space, { }, 0 }; + + if (operation != 0b110) + g_src = getGAM(src_mode, src_reg, word_mode, false); const uint8_t dst = instr & 63; const uint8_t dst_mode = (dst >> 3) & 7; @@ -480,17 +436,17 @@ bool cpu::double_operand_instructions(const uint16_t instr) addToMMR1(src_mode, src_reg, word_mode); if (word_mode && dst_mode == 0) - setRegister(dst_reg, false, int8_t(src_value)); // int8_t: sign extension - else - set_flags = putGAM(dst_mode, dst_reg, word_mode, src_value, false); + setRegister(dst_reg, false, int8_t(g_src.value.value())); // int8_t: sign extension + else { + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); + + set_flags = putGAM(g_dst, g_src.value.value()); + } addToMMR1(dst_mode, dst_reg, word_mode); - if (set_flags) { - setPSW_n(SIGN(src_value, word_mode)); - setPSW_z(IS_0(src_value, word_mode)); - setPSW_v(false); - } + if (set_flags) + setPSW_flags_nzv(g_src.value.value(), word_mode); return true; } @@ -498,82 +454,75 @@ bool cpu::double_operand_instructions(const uint16_t instr) case 0b010: { // CMP/CMPB Compare Word/Byte addToMMR1(src_mode, src_reg, word_mode); - uint16_t dst_value = getGAM(dst_mode, dst_reg, word_mode, false); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); - uint16_t temp = (src_value - dst_value) & (word_mode ? 0xff : 0xffff); + uint16_t temp = (g_src.value.value() - g_dst.value.value()) & (word_mode ? 0xff : 0xffff); addToMMR1(dst_mode, dst_reg, word_mode); setPSW_n(SIGN(temp, word_mode)); setPSW_z(IS_0(temp, word_mode)); - setPSW_v(SIGN((src_value ^ dst_value) & (~dst_value ^ temp), word_mode)); - setPSW_c(src_value < dst_value); + setPSW_v(SIGN((g_src.value.value() ^ g_dst.value.value()) & (~g_dst.value.value() ^ temp), word_mode)); + setPSW_c(g_src.value.value() < g_dst.value.value()); return true; } case 0b011: { // BIT/BITB Bit Test Word/Byte - uint16_t dst_value = getGAM(dst_mode, dst_reg, word_mode, false); - uint16_t result = (dst_value & src_value) & (word_mode ? 0xff : 0xffff); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t result = (g_dst.value.value() & g_src.value.value()) & (word_mode ? 0xff : 0xffff); - setPSW_n(SIGN(result, word_mode)); - setPSW_z(IS_0(result, word_mode)); - setPSW_v(false); + setPSW_flags_nzv(result, word_mode); return true; } case 0b100: { // BIC/BICB Bit Clear Word/Byte - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); - uint16_t result = b->read(a, word_mode, false) & ~src_value; + uint16_t result = g_dst.value.value() & ~g_src.value.value(); - if (put_result(a, dst_mode, dst_reg, word_mode, result)) { - setPSW_n(SIGN(result, word_mode)); - setPSW_z(IS_0(result, word_mode)); - setPSW_v(false); - } + if (put_result(g_dst, result)) + setPSW_flags_nzv(result, word_mode); return true; } case 0b101: { // BIS/BISB Bit Set Word/Byte - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); - uint16_t result = b->read(a, word_mode, false) | src_value; + uint16_t result = g_dst.value.value() | g_src.value.value(); - if (put_result(a, dst_mode, dst_reg, word_mode, result)) { - setPSW_n(SIGN(result, word_mode)); - setPSW_z(IS_0(result, word_mode)); - setPSW_v(false); - } + if (put_result(g_dst, result)) + setPSW_flags_nzv(result, word_mode); return true; } case 0b110: { // ADD/SUB Add/Subtract Word - int16_t ssrc_value = getGAM(src_mode, src_reg, false, false); + auto g_ssrc = getGAM(src_mode, src_reg, false, false); - uint16_t dst_addr = getGAMAddress(dst_mode, dst_reg, false, false); - int16_t dst_value = b->readWord(dst_addr); - int16_t result = 0; + auto g_dst = getGAM(dst_mode, dst_reg, false, false); - bool set_flags = dst_addr != ADDR_PSW; + int16_t result = 0; + + bool set_flags = g_dst.addr.has_value() ? g_dst.addr.value() != ADDR_PSW : true; if (instr & 0x8000) { - result = (dst_value - ssrc_value) & 0xffff; + result = (g_dst.value.value() - g_ssrc.value.value()) & 0xffff; if (set_flags) { - setPSW_v(sign(ssrc_value) != sign(dst_value) && sign(ssrc_value) == sign(result)); - setPSW_c(uint16_t(dst_value) < uint16_t(ssrc_value)); + //setPSW_v(sign(g_ssrc.value.value()) != sign(g_dst.value.value()) && sign(g_ssrc.value.value()) == sign(result)); + setPSW_v(((g_ssrc.value.value() ^ g_dst.value.value()) & 0x8000) && !((g_dst.value.value() ^ result) & 0x8000)); + setPSW_c(uint16_t(g_dst.value.value()) < uint16_t(g_ssrc.value.value())); } } else { - result = (dst_value + ssrc_value) & 0xffff; + result = (g_dst.value.value() + g_ssrc.value.value()) & 0xffff; if (set_flags) { - setPSW_v(sign(ssrc_value) == sign(dst_value) && sign(dst_value) != sign(result)); - setPSW_c(uint16_t(result) < uint16_t(ssrc_value)); + setPSW_v(sign(g_ssrc.value.value()) == sign(g_dst.value.value()) && sign(g_dst.value.value()) != sign(result)); + setPSW_c(uint16_t(result) < uint16_t(g_ssrc.value.value())); } } @@ -582,10 +531,7 @@ bool cpu::double_operand_instructions(const uint16_t instr) setPSW_z(result == 0); } - if (dst_mode == 0) - setRegister(dst_reg, false, result); - else - b->writeWord(dst_addr, result); + putGAM(g_dst, result); return true; } @@ -606,8 +552,11 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) switch(operation) { case 0: { // MUL - int16_t R1 = getRegister(reg); - int16_t R2 = getGAM(dst_mode, dst_reg, true, false); + int16_t R1 = getRegister(reg); + + auto R2g = getGAM(dst_mode, dst_reg, false, false); + int16_t R2 = R2g.value.value(); + int32_t result = R1 * R2; setRegister(reg, result >> 16); @@ -621,7 +570,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 1: { // DIV - int16_t divider = getGAM(dst_mode, dst_reg, false, false); + auto R2g = getGAM(dst_mode, dst_reg, false, false); + int16_t divider = R2g.value.value(); if (divider == 0) { // divide by zero setPSW_n(false); @@ -659,7 +609,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) case 2: { // ASH uint32_t R = getRegister(reg), oldR = R; - uint16_t shift = getGAM(dst_mode, dst_reg, false, false) & 077; + + auto g_dst = getGAM(dst_mode, dst_reg, false, false); + uint16_t shift = g_dst.value.value() & 077; + bool sign = SIGN(R, false); // extend sign-bit @@ -701,7 +654,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) case 3: { // ASHC uint32_t R0R1 = (getRegister(reg) << 16) | getRegister(reg | 1); - uint16_t shift = getGAM(dst_mode, dst_reg, false, false) & 077; + + auto g_dst = getGAM(dst_mode, dst_reg, false, false); + uint16_t shift = g_dst.value.value() & 077; + bool sign = R0R1 & 0x80000000; setPSW_v(false); @@ -754,23 +710,13 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr) } case 4: { // XOR (word only) - uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); - uint16_t vl = b->read(a, false, false) ^ getRegister(reg); - bool set_flags = true; + auto g_dst = getGAM(dst_mode, dst_reg, false, false); + uint16_t vl = g_dst.value.value() ^ getRegister(reg); - if (dst_mode == 0) - putGAM(dst_mode, dst_reg, false, vl, false); - else { - b->write(a, false, vl, false); + bool set_flags = putGAM(g_dst, vl); - set_flags = a != ADDR_PSW; - } - - if (set_flags) { - setPSW_n(vl & 0x8000); - setPSW_z(vl == 0); - setPSW_v(false); - } + if (set_flags) + setPSW_flags_nzv(vl, false); return true; } @@ -805,30 +751,16 @@ bool cpu::single_operand_instructions(const uint16_t instr) if (word_mode) // handled elsewhere return false; else { - uint16_t v = 0; + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); - if (dst_mode == 0) { - v = getRegister(dst_reg); + uint16_t v = g_dst.value.value(); - v = ((v & 0xff) << 8) | (v >> 8); + v = ((v & 0xff) << 8) | (v >> 8); - setRegister(dst_reg, false, v); - } - else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - v = b->readWord(a); - - v = ((v & 0xff) << 8) | (v >> 8); - - set_flags = a != ADDR_PSW; - - b->writeWord(a, v); - } + set_flags = putGAM(g_dst, v); if (set_flags) { - setPSW_n(v & 0x80); - setPSW_z((v & 0xff) == 0); - setPSW_v(false); + setPSW_flags_nzv(v, true); setPSW_c(false); } } @@ -837,75 +769,52 @@ bool cpu::single_operand_instructions(const uint16_t instr) } case 0b000101000: { // CLR/CLRB - if (dst_mode == 0) { - uint16_t r = 0; + { + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); + + uint16_t r = 0; // CLRB only clears the least significant byte if (word_mode) - r = getGAM(dst_mode, dst_reg, false, false) & 0xff00; + r = g_dst.value.value() & 0xff00; - putGAM(dst_mode, dst_reg, false, r, false); - } - else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); + bool set_flags = putGAM(g_dst, r); - set_flags = a != ADDR_PSW; - - b -> write(a, word_mode, 0, false); - } - - if (set_flags) { - setPSW_n(false); - setPSW_z(true); - setPSW_v(false); - setPSW_c(false); + if (set_flags) { + setPSW_n(false); + setPSW_z(true); + setPSW_v(false); + setPSW_c(false); + } } break; } case 0b000101001: { // COM/COMB - if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = a.value.value(); - if (word_mode) - v ^= 0xff; - else - v ^= 0xffff; + if (word_mode) + v ^= 0xff; + else + v ^= 0xffff; - setPSW_n(SIGN(v, word_mode)); - setPSW_z(IS_0(v, word_mode)); - setPSW_v(false); + set_flags = putGAM(a, v); + + if (set_flags) { + setPSW_flags_nzv(v, word_mode); setPSW_c(true); - - setRegister(dst_reg, false, v); } - else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t v = b -> read(a, word_mode, false); - if (word_mode) - v ^= 0xff; - else - v ^= 0xffff; - - bool set_flags = a != ADDR_PSW; - - if (set_flags) { - setPSW_n(SIGN(v, word_mode)); - setPSW_z(IS_0(v, word_mode)); - setPSW_v(false); - setPSW_c(true); - } - - b->write(a, word_mode, v, false); - } break; } case 0b000101010: { // INC/INCB + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = a.value.value(); + if (dst_mode == 0) { - uint16_t v = getRegister(dst_reg); uint16_t add = word_mode ? v & 0xff00 : 0; v = (v + 1) & (word_mode ? 0xff : 0xffff); @@ -918,11 +827,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t v = b -> read(a, word_mode, false); - int32_t vl = (v + 1) & (word_mode ? 0xff : 0xffff); + int32_t vl = (a.value.value() + 1) & (word_mode ? 0xff : 0xffff); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(vl, word_mode)); @@ -930,13 +837,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(word_mode ? vl == 0x80 : v == 0x8000); } - b->write(a, word_mode, vl, false); + b->write(a.addr.value(), word_mode, vl, false); } break; } case 0b000101011: { // DEC/DECB + // TODO unify if (dst_mode == 0) { uint16_t v = getRegister(dst_reg); uint16_t add = word_mode ? v & 0xff00 : 0; @@ -951,11 +859,11 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t v = b -> read(a, word_mode, false); - int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = a.value.value(); + int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(vl, word_mode)); @@ -963,7 +871,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(word_mode ? vl == 0x7f : vl == 0x7fff); } - b->write(a, word_mode, vl, false); + b->write(a.addr.value(), word_mode, vl, false); } break; @@ -985,12 +893,12 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t v = -b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = -a.value.value(); - b->write(a, word_mode, v, false); + b->write(a.addr.value(), word_mode, v, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1021,14 +929,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - const uint16_t vo = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + const uint16_t vo = a.value.value(); bool org_c = getPSW_c(); uint16_t v = (vo + org_c) & (word_mode ? 0x00ff : 0xffff); - b->write(a, word_mode, v, false); + b->write(a.addr.value(), word_mode, v, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1063,14 +971,14 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - const uint16_t vo = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + const uint16_t vo = a.value.value(); bool org_c = getPSW_c(); uint16_t v = (vo - org_c) & (word_mode ? 0xff : 0xffff); - b->write(a, word_mode, v, false); + b->write(a.addr.value(), word_mode, v, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1087,11 +995,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) } case 0b000101111: { // TST/TSTB - uint16_t v = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = getGAM(dst_mode, dst_reg, word_mode, false).value.value(); - setPSW_n(SIGN(v, word_mode)); - setPSW_z(IS_0(v, word_mode)); - setPSW_v(false); + setPSW_flags_nzv(v, word_mode); setPSW_c(false); break; @@ -1120,8 +1026,8 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_c() ^ getPSW_n()); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t t = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t t = a.value.value(); bool new_carry = t & 1; uint16_t temp = 0; @@ -1130,9 +1036,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) else temp = (t >> 1) | (getPSW_c() << 15); - b->write(a, word_mode, temp, false); + b->write(a.addr.value(), word_mode, temp, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_c(new_carry); @@ -1167,8 +1073,8 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_c() ^ getPSW_n()); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t t = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t t = a.value.value(); bool new_carry = false; uint16_t temp = 0; @@ -1181,9 +1087,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) temp = (t << 1) | getPSW_c(); } - b->write(a, word_mode, temp, false); + b->write(a.addr.value(), word_mode, temp, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_c(new_carry); @@ -1222,8 +1128,8 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_n() ^ getPSW_c()); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t v = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t v = a.value.value(); uint16_t add = word_mode ? v & 0xff00 : 0; bool hb = word_mode ? v & 128 : v & 32768; @@ -1240,9 +1146,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) v |= hb << 15; } - b->write(a, word_mode, v, false); + b->write(a.addr.value(), word_mode, v, false); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1269,11 +1175,11 @@ bool cpu::single_operand_instructions(const uint16_t instr) setRegister(dst_reg, false, v); } else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - uint16_t vl = b -> read(a, word_mode, false); + auto a = getGAM(dst_mode, dst_reg, word_mode, false); + uint16_t vl = a.value.value(); uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff); - bool set_flags = a != ADDR_PSW; + bool set_flags = a.addr.value() != ADDR_PSW; if (set_flags) { setPSW_n(SIGN(v, word_mode)); @@ -1282,14 +1188,13 @@ bool cpu::single_operand_instructions(const uint16_t instr) setPSW_v(getPSW_n() ^ getPSW_c()); } - b->write(a, word_mode, v, false); + b->write(a.addr.value(), word_mode, v, false); } break; } case 0b00110101: { // MFPD/MFPI // always words: word_mode-bit is to select between MFPI and MFPD - // NOTE: this code does not work for D/I split setups! TODO if ((b->getMMR0() & 0160000) == 0) b->addToMMR1(-2, 6); @@ -1301,19 +1206,28 @@ bool cpu::single_operand_instructions(const uint16_t instr) v = getRegister(dst_reg, getBitPSW(11), true); else { // calculate address in current address space - uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); + auto a = getGAMAddress(dst_mode, dst_reg, false); - set_flags = a != ADDR_PSW; + set_flags = a.addr.value() != ADDR_PSW; - // read from previous space - v = b -> read(a, false, true); + if (a.addr.value() >= 0160000) { + // read from previous space + v = b -> read(a.addr.value(), false, true); + } + else { + auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a.addr.value()); + + //b->check_address(true, true, phys, false, word_mode, (getPSW() >> 12) & 3); + + extern FILE *lfh; + fflush(lfh); + + v = b->readPhysical(word_mode ? phys.physical_data : phys.physical_instruction); + } } - if (set_flags) { - setPSW_n(SIGN(v, false)); - setPSW_z(v == 0); - setPSW_v(false); - } + if (set_flags) + setPSW_flags_nzv(v, false); // put on current stack pushStack(v); @@ -1323,7 +1237,6 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b00110110: { // MTPI/MTPD // always words: word_mode-bit is to select between MTPI and MTPD - // NOTE: this code does not work for D/I split setups! TODO if ((b->getMMR0() & 0160000) == 0) b->addToMMR1(2, 6); @@ -1336,18 +1249,35 @@ bool cpu::single_operand_instructions(const uint16_t instr) if (dst_mode == 0) setRegister(dst_reg, true, v); else { - uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); + auto a = getGAMAddress(dst_mode, dst_reg, false); - set_flags = a != ADDR_PSW; + set_flags = a.addr.value() != ADDR_PSW; - b->write(a, false, v, true); // put in '13/12' address space + if (a.addr.value() >= 0160000) + b->write(a.addr.value(), false, v, true); // put in '13/12' address space + else { + auto phys = b->calculate_physical_address((getPSW() >> 12) & 3, a.addr.value()); + + DOLOG(debug, true, "MTPI/D %06o -> %o / %o", a, phys.physical_instruction, phys.physical_data); + +// FILE *fh = fopen("og2-kek.dat", "a+"); +// fprintf(fh, "%lu %06o MTPI %06o: %06o\n", mtpi_count, oldpc, a, v); +// fclose(fh); + DOLOG(debug, true, "%lu %06o MTPI %06o: %06o", mtpi_count, oldpc, a.addr.value(), v); + + mtpi_count++; + + //b->check_address(true, true, phys, false, word_mode, (getPSW() >> 12) & 3); + + extern FILE *lfh; + fflush(lfh); + + b->writePhysical(word_mode ? phys.physical_data : phys.physical_instruction, v); + } } - if (set_flags) { - setPSW_n(SIGN(v, false)); - setPSW_z(v == 0); - setPSW_v(false); - } + if (set_flags) + setPSW_flags_nzv(v, false); break; } @@ -1355,7 +1285,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) case 0b000110100: // MARK/MTPS (put something in PSW) if (word_mode) { // MTPS psw &= 0xff00; // only alter lower 8 bits - psw |= getGAM(dst_mode, dst_reg, word_mode, false) & 0xef; // can't change bit 4 + psw |= getGAM(dst_mode, dst_reg, word_mode, false).value.value() & 0xef; // can't change bit 4 } else { setRegister(6, getPC() + dst * 2); @@ -1367,7 +1297,9 @@ bool cpu::single_operand_instructions(const uint16_t instr) break; - case 0b000110111: // MFPS (get PSW to something) / SXT + case 0b000110111: { // MFPS (get PSW to something) / SXT + auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false); + if (word_mode) { // MFPS uint16_t temp = psw & 0xff; bool extend_b7 = psw & 128; @@ -1375,7 +1307,7 @@ bool cpu::single_operand_instructions(const uint16_t instr) if (extend_b7 && dst_mode == 0) temp |= 0xff00; - set_flags = putGAM(dst_mode, dst_reg, word_mode, temp, false); + bool set_flags = putGAM(g_dst, temp); if (set_flags) { setPSW_z(temp == 0); @@ -1384,17 +1316,16 @@ bool cpu::single_operand_instructions(const uint16_t instr) } } else { // SXT - uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); - int32_t vl = -getPSW_n(); - if (put_result(a, dst_mode, dst_reg, word_mode, vl)) { + if (put_result(g_dst, vl)) { setPSW_z(getPSW_n() == false); setPSW_v(false); } } + } - break; + break; default: return false; @@ -1600,15 +1531,15 @@ bool cpu::misc_operations(const uint16_t instr) int dst_reg = instr & 7; bool word_mode = false; - setPC(getGAMAddress(dst_mode, dst_reg, word_mode, false)); + setPC(getGAMAddress(dst_mode, dst_reg, word_mode).addr.value()); } return true; } if ((instr & 0b1111111000000000) == 0b0000100000000000) { // JSR - int link_reg = (instr >> 6) & 7; - uint16_t dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false, false); + int link_reg = (instr >> 6) & 7; + auto dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false).addr.value(); // PUSH link pushStack(getRegister(link_reg)); @@ -1717,8 +1648,6 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt) setPSW(before_psw, false); } } - - DOLOG(debug, true, "*** CPU::TRAP FIN, MMR0: %06o, MMR2: %06o ***", b->getMMR0(), b->getMMR2()); } cpu::operand_parameters cpu::addressing_to_string(const uint8_t mode_register, const uint16_t pc, const bool word_mode) const @@ -2222,6 +2151,7 @@ void cpu::step_b() instruction_count++; uint16_t temp_pc = getPC(); + oldpc = temp_pc; if ((b->getMMR0() & 0160000) == 0) b->setMMR2(temp_pc); diff --git a/cpu.h b/cpu.h index 26fb173..1d9bb31 100644 --- a/cpu.h +++ b/cpu.h @@ -5,12 +5,27 @@ #include #include #include +#include #include #include #include #include "bus.h" +typedef struct { + bool word_mode; + bool prev_mode; + bool set; + d_i_space_t space; + + union { + std::optional addr; + int reg; + }; + + std::optional value; +} gam_rc_t; + class cpu { private: @@ -21,12 +36,13 @@ private: uint16_t fpsr { 0 }; uint16_t stackLimitRegister { 0 }; uint8_t scheduled_trap { 0 }; - bool runMode { false }; bool emulateMFPT { false }; uint64_t instruction_count { 0 }; uint64_t running_since { 0 }; bool mode11_70 { true }; + uint64_t mtpi_count { 0 }; + // level, vector std::map > queued_interrupts; std::mutex qi_lock; @@ -42,10 +58,11 @@ private: uint16_t addRegister(const int nr, const bool prev_mode, const uint16_t value); void addToMMR1(const uint8_t mode, const uint8_t reg, const bool word_mode); - uint16_t getGAMAddress(const uint8_t mode, const int reg, const bool word_mode, const bool MF_MT); - uint16_t getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool MF_MT); - // returns false when flag registers should not be updated - bool putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, const bool MF_FT); + + + gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool prev_mode, const bool read_value = true); + gam_rc_t getGAMAddress(const uint8_t mode, const int reg, const bool word_mode); + bool putGAM(const gam_rc_t & g, const uint16_t value); // returns false when flag registers should not be updated bool double_operand_instructions(const uint16_t instr); bool additional_double_operand_instructions(const uint16_t instr); @@ -100,8 +117,6 @@ public: void setEmulateMFPT(const bool v) { emulateMFPT = v; } - bool getRunMode() { return runMode; } - bool getPSW_c() const; bool getPSW_v() const; bool getPSW_z() const; @@ -115,6 +130,7 @@ public: void setPSW_n(const bool v); void setPSW_spl(const int v); void setBitPSW(const int bit, const bool v); + void setPSW_flags_nzv(const uint16_t value, const bool word_mode); uint16_t getPSW() const { return psw; } void setPSW(const uint16_t v, const bool limited); @@ -137,5 +153,5 @@ public: uint16_t getRegister(const int nr, const int mode, const bool sp_prev_mode) const; uint16_t getRegister(const int nr) const; - bool put_result(const uint16_t a, const uint8_t dst_mode, const uint8_t dst_reg, const bool word_mode, const uint16_t value); + bool put_result(const gam_rc_t & g, const uint16_t value); }; diff --git a/debugger.cpp b/debugger.cpp index cdfe0fe..2b17e53 100644 --- a/debugger.cpp +++ b/debugger.cpp @@ -49,6 +49,19 @@ int disassemble(cpu *const c, console *const cnsl, const int pc, const bool inst instruction.c_str(), MMR0.c_str(), MMR2.c_str() ); +#if defined(COMPARE_OUTPUT) + { + std::string temp = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s, instr: %s", + registers[0].c_str(), registers[1].c_str(), registers[2].c_str(), registers[3].c_str(), registers[4].c_str(), registers[5].c_str(), registers[6].c_str(), pc, + psw.c_str(), + data["instruction-values"][0].c_str() + ); + + FILE *fh = fopen("compare.dat", "a+"); + fprintf(fh, "%s\n", temp.c_str()); + fclose(fh); + } +#endif if (cnsl) cnsl->debug(result); @@ -136,8 +149,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto if (parts.empty()) continue; - if (cmd == "go") + if (cmd == "go") { single_step = false; + + *stop_event = EVENT_NONE; + } else if (parts[0] == "single" || parts[0] == "s") { single_step = true; @@ -145,6 +161,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto n_single_step = atoi(parts[1].c_str()); else n_single_step = 1; + + *stop_event = EVENT_NONE; } else if ((parts[0] == "sbp" || parts[0] == "cbp") && parts.size() == 2){ uint16_t pc = std::stoi(parts[1].c_str(), nullptr, 8); @@ -191,6 +209,36 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto continue; } + else if (parts[0] == "setpc") { + if (parts.size() == 2) { + uint16_t new_pc = std::stoi(parts.at(1), nullptr, 8); + c->setPC(new_pc); + + cnsl->put_string_lf(format("Set PC to %06o", new_pc)); + } + else { + cnsl->put_string_lf("setpc requires an (octal address as) parameter"); + } + + continue; + } + else if (parts[0] == "setmem") { + auto a_it = kv.find("a"); + auto v_it = kv.find("v"); + + if (a_it == kv.end() || v_it == kv.end()) + cnsl->put_string_lf("setmem: parameter missing?"); + else { + uint16_t a = std::stoi(a_it->second, nullptr, 8); + uint8_t v = std::stoi(v_it->second, nullptr, 8); + + c->getBus()->writeByte(a, v); + + cnsl->put_string_lf(format("Set %06o to %03o", a, v)); + } + + continue; + } else if (parts[0] == "trace" || parts[0] == "t") { tracing = !tracing; @@ -295,6 +343,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto cnsl->put_string_lf("trace/t - toggle tracing"); cnsl->put_string_lf("strace - start tracing from address - invoke without address to disable"); cnsl->put_string_lf("mmudump - dump MMU settings (PARs/PDRs)"); + cnsl->put_string_lf("setpc - set PC to value"); + cnsl->put_string_lf("setmem - set memory (a=) to value (v=), both in octal, one byte"); continue; } @@ -308,6 +358,9 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto *cnsl->get_running_flag() = true; while(*stop_event == EVENT_NONE) { + if (!single_step) + DOLOG(debug, false, "---"); + c->step_a(); if (trace_start_addr != -1 && c->getPC() == trace_start_addr) diff --git a/loaders.cpp b/loaders.cpp index e6f566b..01079ba 100644 --- a/loaders.cpp +++ b/loaders.cpp @@ -26,11 +26,13 @@ void setBootLoader(bus *const b, const bootloader_t which) cpu *const c = b -> getCpu(); uint16_t offset = 0; + uint16_t start = 0; const uint16_t *bl = nullptr; int size = 0; if (which == BL_RK05) { - offset = 01000; + /* + start = offset = 01000; static uint16_t rk05_code[] = { 0012700, @@ -43,13 +45,44 @@ void setBootLoader(bus *const b, const bootloader_t which) 0100376, 0005007 }; + */ + + // from https://github.com/amakukha/PyPDP11.git + offset = 02000; + start = 02002; + + static uint16_t rk05_code[] = { + 0042113, // "KD" + 0012706, 02000, // MOV #boot_start, SP + 0012700, 0000000, // MOV #unit, R0 ; unit number + 0010003, // MOV R0, R3 + 0000303, // SWAB R3 + 0006303, // ASL R3 + 0006303, // ASL R3 + 0006303, // ASL R3 + 0006303, // ASL R3 + 0006303, // ASL R3 + 0012701, 0177412, // MOV #RKDA, R1 ; csr + 0010311, // MOV R3, (R1) ; load da + 0005041, // CLR -(R1) ; clear ba + 0012741, 0177000, // MOV #-256.*2, -(R1) ; load wc + 0012741, 0000005, // MOV #READ+GO, -(R1) ; read & go + 0005002, // CLR R2 + 0005003, // CLR R3 + 0012704, 02020, // MOV #START+20, R4 + 0005005, // CLR R5 + 0105711, // TSTB (R1) + 0100376, // BPL .-2 + 0105011, // CLRB (R1) + 0005007 // CLR PC + }; bl = rk05_code; - size = 9; + size = sizeof(rk05_code)/sizeof(rk05_code[0]); } else if (which == BL_RL02) { - offset = 01000; + start = offset = 01000; /* from https://www.pdp-11.nl/peripherals/disk/rl-info.html static uint16_t rl02_code[] = { @@ -93,7 +126,7 @@ void setBootLoader(bus *const b, const bootloader_t which) 0005007, }; - size = 10; + size = sizeof(rl02_code)/sizeof(rl02_code[0]); bl = rl02_code; } @@ -101,7 +134,7 @@ void setBootLoader(bus *const b, const bootloader_t which) for(int i=0; i writeWord(offset + i * 2, bl[i]); - c -> setRegister(7, offset); + c -> setRegister(7, start); } uint16_t loadTape(bus *const b, const std::string & file) diff --git a/log.cpp b/log.cpp index e277e41..f7e65a5 100644 --- a/log.cpp +++ b/log.cpp @@ -13,7 +13,7 @@ static const char *logfile = strdup("/tmp/myip.log"); log_level_t log_level_file = warning; log_level_t log_level_screen = warning; -static FILE *lfh = nullptr; +FILE *lfh = nullptr; static int lf_uid = -1; static int lf_gid = -1; @@ -35,6 +35,8 @@ void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_scre log_level_file = ll_file; log_level_screen = ll_screen; + + atexit(closelog); } void setloguid(const int uid, const int gid) @@ -45,9 +47,11 @@ void setloguid(const int uid, const int gid) void closelog() { - fclose(lfh); + if (lfh) { + fclose(lfh); - lfh = nullptr; + lfh = nullptr; + } } void dolog(const log_level_t ll, const char *fmt, ...) @@ -56,11 +60,11 @@ void dolog(const log_level_t ll, const char *fmt, ...) return; if (!lfh) { +#if !defined(ESP32) lfh = fopen(logfile, "a+"); if (!lfh) error_exit(true, "Cannot access log-file %s", logfile); -#if !defined(ESP32) if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1) error_exit(true, "Cannot change logfile (%s) ownership", logfile); @@ -91,8 +95,10 @@ void dolog(const log_level_t ll, const char *fmt, ...) (void)vasprintf(&str, fmt, ap); va_end(ap); +#if !defined(ESP32) if (ll >= log_level_file) fprintf(lfh, "%s%s\n", ts_str, str); +#endif if (ll >= log_level_screen) printf("%s%s\r\n", ts_str, str); diff --git a/log.h b/log.h index 23139fe..db07ebf 100644 --- a/log.h +++ b/log.h @@ -14,6 +14,6 @@ void dolog(const log_level_t ll, const char *fmt, ...); #define DOLOG(ll, always, fmt, ...) do { \ extern log_level_t log_level_file, log_level_screen; \ \ - if (always && (ll >= log_level_file || ll >= log_level_screen)) \ + if (always || ll >= log_level_file || ll >= log_level_screen) \ dolog(ll, fmt, ##__VA_ARGS__); \ } while(0) diff --git a/main.cpp b/main.cpp index 8f3c283..a40ce57 100644 --- a/main.cpp +++ b/main.cpp @@ -44,7 +44,7 @@ void help() printf("-h this help\n"); printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\n"); printf("-R d.rk load file as a RK05 disk device\n"); - printf("-r d.rk load file as a RL02 disk device\n"); + printf("-r d.rl load file as a RL02 disk device\n"); printf("-p 123 set CPU start pointer to decimal(!) value\n"); printf("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n"); printf("-n ncurses UI\n");