From 3ef8bd930dda3eb70b9d8c1fc313ebf0680722fb Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Sat, 11 Mar 2023 21:13:46 +0100 Subject: [PATCH] Added: * calculate data/instruction physical addresses from a virtual address memory_addresses_t calculate_physical_address(const int run_mode, const uint16_t a); * check if a 'memory_address_t'-address would cause a fault 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); --- bus.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus.h | 13 +++++- 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/bus.cpp b/bus.cpp index 84c968f..668c9db 100644 --- a/bus.cpp +++ b/bus.cpp @@ -324,6 +324,146 @@ void bus::setMMR2(const uint16_t value) MMR2 = value; } +memory_addresses_t bus::calculate_physical_address(const int run_mode, const uint16_t a) +{ + const uint8_t apf = a >> 13; // active page field + + 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][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; + } +} + 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; diff --git a/bus.h b/bus.h index a6dd170..4670622 100644 --- a/bus.h +++ b/bus.h @@ -57,8 +57,14 @@ class tty; typedef enum { d_space, i_space } d_i_space_t; -typedef struct -{ +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; @@ -140,4 +146,7 @@ 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 is_data); + + 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); };