* 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);
This commit is contained in:
folkert van heusden 2023-03-11 21:13:46 +01:00
parent 6f20ce864f
commit 3ef8bd930d
2 changed files with 151 additions and 2 deletions

140
bus.cpp
View file

@ -324,6 +324,146 @@ void bus::setMMR2(const uint16_t value)
MMR2 = 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 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; uint32_t m_offset = a;

13
bus.h
View file

@ -57,8 +57,14 @@ class tty;
typedef enum { d_space, i_space } d_i_space_t; 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; uint16_t par, pdr;
} page_t; } page_t;
@ -140,4 +146,7 @@ public:
uint16_t get_switch_register() const { return switch_register; } 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); 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);
}; };