Merge branch 'd_i'
This commit is contained in:
commit
c5b603d50c
11 changed files with 606 additions and 383 deletions
|
@ -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
|
||||
|
||||
|
|
244
bus.cpp
244
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)
|
||||
|
|
27
bus.h
27
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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
566
cpu.cpp
566
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<std::mutex> 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);
|
||||
|
|
32
cpu.h
32
cpu.h
|
@ -5,12 +5,27 @@
|
|||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "bus.h"
|
||||
|
||||
typedef struct {
|
||||
bool word_mode;
|
||||
bool prev_mode;
|
||||
bool set;
|
||||
d_i_space_t space;
|
||||
|
||||
union {
|
||||
std::optional<uint16_t> addr;
|
||||
int reg;
|
||||
};
|
||||
|
||||
std::optional<uint16_t> 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<uint8_t, std::set<uint8_t> > 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);
|
||||
};
|
||||
|
|
55
debugger.cpp
55
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)
|
||||
|
|
43
loaders.cpp
43
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<size; i++)
|
||||
b -> writeWord(offset + i * 2, bl[i]);
|
||||
|
||||
c -> setRegister(7, offset);
|
||||
c -> setRegister(7, start);
|
||||
}
|
||||
|
||||
uint16_t loadTape(bus *const b, const std::string & file)
|
||||
|
|
14
log.cpp
14
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);
|
||||
|
|
2
log.h
2
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)
|
||||
|
|
2
main.cpp
2
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");
|
||||
|
|
Loading…
Add table
Reference in a new issue