diff --git a/bus.cpp b/bus.cpp index 14a7cb7..730930b 100644 --- a/bus.cpp +++ b/bus.cpp @@ -237,7 +237,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm { 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, peek_only, space); + uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, !peek_only, false, space); uint32_t io_base = mmu_->get_io_base(); bool is_io = m_offset >= io_base; @@ -553,7 +553,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, false, space); + uint32_t m_offset = mmu_->calculate_physical_address(c, run_mode, addr_in, true, true, space); uint32_t io_base = mmu_->get_io_base(); bool is_io = m_offset >= io_base; diff --git a/console_ncurses.cpp b/console_ncurses.cpp index 8f7fceb..531efee 100644 --- a/console_ncurses.cpp +++ b/console_ncurses.cpp @@ -146,7 +146,7 @@ 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, true, i_space); + uint32_t full_addr = b->getMMU()->calculate_physical_address(c, run_mode, current_PC, false, false, i_space); uint16_t current_instr = b->read_word(current_PC); diff --git a/mmu.cpp b/mmu.cpp index bdf66c7..199ae0e 100644 --- a/mmu.cpp +++ b/mmu.cpp @@ -353,147 +353,152 @@ void mmu::mmudebug(const uint16_t a) } } -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 bool peek_only, const d_i_space_t space) +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) { - uint32_t m_offset = a; + const auto [ trap_action, access_control ] = get_trap_action(run_mode, d, apf, is_write); - if (is_enabled() || (is_write && (getMMR0() & (1 << 8 /* maintenance check */)))) { - uint8_t apf = a >> 13; // active page field + if (trap_action == T_PROCEED) + return; - bool d = space == d_space && get_use_data_space(run_mode); + if (is_write) + set_page_trapped(run_mode, d, apf); - uint16_t p_offset = a & 8191; // page offset + if (is_locked() == false) { + uint16_t temp = getMMR0(); - m_offset = get_physical_memory_offset(run_mode, d, apf); + temp &= ~((1l << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (3 << 5) | (7 << 1) | (1 << 4)); - m_offset += p_offset; + if (is_write && access_control != 6) + temp |= 1 << 13; // read-only + // + if (access_control == 0 || access_control == 4) + temp |= 1l << 15; // not resident + else + temp |= 1 << 13; // read-only - if ((getMMR3() & 16) == 0) // off is 18bit - m_offset &= 0x3ffff; + temp |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode? - uint32_t io_base = get_io_base(); - bool is_io = m_offset >= io_base; + temp |= apf << 1; // add current page - if (trap_on_failure) { - { - const auto [ trap_action, access_control ] = get_trap_action(run_mode, d, apf, is_write); + temp |= d << 4; - if (trap_action != T_PROCEED) [[unlikely]] { - if (is_write) - set_page_trapped(run_mode, d, apf); + setMMR0_as_is(temp); - if (is_locked() == false) { - uint16_t temp = getMMR0(); + TRACE("MMR0: %06o", temp); + } - temp &= ~((1l << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (3 << 5) | (7 << 1) | (1 << 4)); + if (trap_action == T_TRAP_250) { + TRACE("Page access %d (for virtual address %06o): trap 0250", access_control, virt_addr); - if (is_write && access_control != 6) - temp |= 1 << 13; // read-only - // - if (access_control == 0 || access_control == 4) - temp |= 1l << 15; // not resident - else - temp |= 1 << 13; // read-only + c->trap(0250); // trap - temp |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode? + throw 5; + } + else { // T_ABORT_4 + TRACE("Page access %d (for virtual address %06o): trap 004", access_control, virt_addr); - temp |= apf << 1; // add current page + c->trap(004); // abort - temp |= d << 4; + throw 5; + } +} - setMMR0_as_is(temp); +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) +{ + if (m_offset >= m->get_memory_size() && !is_io) [[unlikely]] { + TRACE("TRAP(04) (throw 6) on address %08o", m_offset); - TRACE("MMR0: %06o", temp); - } + if (is_locked() == false) { + uint16_t temp = getMMR0(); - if (trap_action == T_TRAP_250) { - TRACE("Page access %d (for virtual address %06o): trap 0250", access_control, a); + temp &= 017777; + temp |= 1l << 15; // non-resident - c->trap(0250); // trap + temp &= ~14; // add current page + temp |= apf << 1; - throw 5; - } - else { // T_ABORT_4 - TRACE("Page access %d (for virtual address %06o): trap 004", access_control, a); + temp &= ~(3 << 5); + temp |= run_mode << 5; - c->trap(004); // abort + setMMR0_as_is(temp); + } - throw 5; - } - } - } + if (is_write) + set_page_trapped(run_mode, d, apf); - if (m_offset >= m->get_memory_size() && !is_io) [[unlikely]] { - if (!peek_only) - TRACE("mmu::calculate_physical_address %o >= %o", m_offset, m->get_memory_size()); - TRACE("TRAP(04) (throw 6) on address %06o", a); + c->trap(04); - if (is_locked() == false) { - uint16_t temp = getMMR0(); + throw 6; + } +} - temp &= 017777; - temp |= 1l << 15; // non-resident +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) +{ + uint16_t pdr_len = get_pdr_len(run_mode, d, apf); + uint16_t pdr_cmp = (virt_addr >> 6) & 127; - temp &= ~14; // add current page - temp |= apf << 1; + bool direction = get_pdr_direction(run_mode, d, apf); - temp &= ~(3 << 5); - temp |= run_mode << 5; + if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) [[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); - setMMR0_as_is(temp); - } + c->trap(0250); // invalid access - if (is_write) - set_page_trapped(run_mode, d, apf); + if (is_locked() == false) { + uint16_t temp = getMMR0(); - c->trap(04); + temp &= 017777; + temp |= 1 << 14; // length - throw 6; - } + temp &= ~14; // add current page + temp |= apf << 1; - uint16_t pdr_len = get_pdr_len(run_mode, d, apf); - uint16_t pdr_cmp = (a >> 6) & 127; + temp &= ~(3 << 5); + temp |= run_mode << 5; - bool direction = get_pdr_direction(run_mode, d, apf); + temp &= ~(1 << 4); + temp |= d << 4; - // TRACE("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); + setMMR0_as_is(temp); + } - if ((pdr_cmp > pdr_len && direction == false) || (pdr_cmp < pdr_len && direction == true)) [[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", a); - c->trap(0250); // invalid access + if (is_write) + set_page_trapped(run_mode, d, apf); - if (is_locked() == false) { - uint16_t temp = getMMR0(); + throw 7; + } +} + +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 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); - temp &= 017777; - temp |= 1 << 14; // length + uint16_t p_offset = a & 8191; // page offset - temp &= ~14; // add current page - temp |= apf << 1; + m_offset = get_physical_memory_offset(run_mode, d, apf); - temp &= ~(3 << 5); - temp |= run_mode << 5; + m_offset += p_offset; + + if ((getMMR3() & 16) == 0) // off is 18bit + m_offset &= 0x3ffff; - temp &= ~(1 << 4); - temp |= d << 4; + if (trap_on_failure) { + verify_page_access(c, a, run_mode, d, apf, is_write); - setMMR0_as_is(temp); - } + // e.g. ram or i/o, not unmapped + uint32_t io_base = get_io_base(); + bool is_io = m_offset >= io_base; - if (is_write) - set_page_trapped(run_mode, d, apf); + verify_access_valid(c, m_offset, run_mode, d, apf, is_io, is_write); - throw 7; - } + verify_page_length(c, a, run_mode, d, apf, is_write); } - - TRACE("virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d, %s)", a, m_offset, run_mode, apf, - get_physical_memory_offset(run_mode, d, apf), - p_offset, get_access_control(run_mode, d, apf), d ? "D" : "I"); - } - else { - // TRACE("no MMU (read physical address %08o)", m_offset); } return m_offset; diff --git a/mmu.h b/mmu.h index 8c64d51..7c02e49 100644 --- a/mmu.h +++ b/mmu.h @@ -62,6 +62,10 @@ class mmu : public device void set_par_pdr(const json_t *const j_in, const int run_mode, const bool is_d, const std::string & name); #endif + 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); + public: mmu(); virtual ~mmu(); @@ -94,7 +98,7 @@ class mmu : public device 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 bool peek_only, const d_i_space_t space); + 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); uint16_t getMMR0() const { return MMR0; } uint16_t getMMR1() const { return MMR1; }