Merge branch 'd_i'

This commit is contained in:
folkert van heusden 2023-03-18 19:48:17 +01:00
commit c5b603d50c
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
11 changed files with 606 additions and 383 deletions

View file

@ -11,7 +11,7 @@ framework = arduino
monitor_speed = 115200 monitor_speed = 115200
upload_speed = 1000000 upload_speed = 1000000
lib_deps = greiman/SdFat@^2.1.2 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_flags = -std=gnu++17 -Ofast -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
build_unflags = -std=gnu++11 -Os build_unflags = -std=gnu++11 -Os

240
bus.cpp
View file

@ -17,9 +17,11 @@
// see also https://github.com/espressif/esp-idf/issues/1934 // see also https://github.com/espressif/esp-idf/issues/1934
constexpr int n_pages = 12; constexpr int n_pages = 12;
#else #else
constexpr int n_pages = 16; constexpr int n_pages = 32;
#endif #endif
constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 };
bus::bus() bus::bus()
{ {
m = new memory(n_pages * 8192); 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; 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; 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 if (a == ADDR_PIR) { // PIR
DOLOG(debug, !peek_only, "read PIT"); DOLOG(debug, !peek_only, "read PIR");
return 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 // LO size register field must be all 1s, so subtract 1
constexpr uint32_t system_size = n_pages * 8192 / 64 - 1; constexpr uint32_t system_size = n_pages * 8192 / 64 - 1;
if (a == ADDR_SYSSIZE + 2) // system size HI if (a == ADDR_SYSSIZE + 2) { // system size HI
return system_size >> 16; printf("accessing system size HI\r\n");
return ((system_size >> 6) - 1) >> 16;
}
if (a == ADDR_SYSSIZE) // system size LO if (a == ADDR_SYSSIZE) { // system size LO
return system_size & 65535; printf("accessing system size LO\r\n");
return (system_size >> 6) - 1;
}
if (a & 1) if (a & 1)
DOLOG(debug, !peek_only, "bus::readWord: odd address UNHANDLED %o", a); 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; 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) if (word_mode)
temp = m -> readByte(m_offset); temp = m -> readByte(m_offset);
@ -322,32 +328,164 @@ void bus::setMMR2(const uint16_t value)
MMR2 = 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 const uint8_t apf = a >> 13; // active page field
if ((a & 1) && word_mode == 0 && peek_only == false) { uint32_t physical_instruction = pages[run_mode][0][apf].par * 64;
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_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) if (is_write)
pages[run_mode][0][apf].pdr |= 1 << 7; // TODO: D/I pages[run_mode][is_data][addr.apf].pdr |= 1 << 7;
//MMR0 &= ~14; // add current page
//MMR0 |= apf << 1;
c->schedule_trap(004); // invalid access c->schedule_trap(004); // invalid access
throw 5; 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) { if (MMR0 & 1) {
// TODO: D/I const uint8_t apf = a >> 13; // active page field
m_offset = pages[run_mode][0][apf].par * 64; // memory offset TODO: handle 16b int-s
bool d = is_data & (!!(MMR3 & di_ena_mask[run_mode])) ? is_data : false;
uint16_t p_offset = a & 8191; // page offset 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; m_offset += p_offset;
if ((MMR3 & 16) == 0) // off is 18bit 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 (trap_on_failure) {
if ((MMR0 & (1 << 9)) || c->get_34()) { 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 if (is_write && access_control != 6) { // write
DOLOG(debug, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a); 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 c->schedule_trap(0250); // invalid address
if (is_write) 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) { if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777; 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 c->schedule_trap(0250); // invalid address
if (is_write) 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) { if ((MMR0 & 0160000) == 0) {
MMR0 &= 017777; MMR0 &= 017777;
@ -425,20 +563,19 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
} }
if (is_write) 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); c->schedule_trap(04);
throw 3; 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][d][apf].pdr >> 8) & 127;
uint16_t pdr_len = (pages[run_mode][0][apf].pdr >> 8) & 127;
uint16_t pdr_cmp = (a >> 6) & 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)) { 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); 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) 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; 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; 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; int page = (a >> 1) & 7;
if (word_mode) { 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) : 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); (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); 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) { 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 bool is_data = space == d_space;
pages[run_mode][0][apf].pdr |= 64; // set 'W' (written to) bit
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) { if (a >= 0160000) {
@ -723,7 +865,7 @@ void bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bo
return; 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); 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); 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) uint16_t bus::peekWord(const uint16_t a)

27
bus.h
View file

@ -55,8 +55,16 @@ class cpu;
class memory; class memory;
class tty; 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; uint16_t par, pdr;
} page_t; } page_t;
@ -111,17 +119,20 @@ public:
void set_lf_crs_b7(); void set_lf_crs_b7();
uint8_t get_lf_crs(); 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 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 peekWord(const uint16_t a);
uint16_t readUnibusByte(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 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); 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); void writeUnibusByte(const uint16_t a, const uint8_t value);
uint16_t getMMR0() { return MMR0; } uint16_t getMMR0() { return MMR0; }
@ -137,5 +148,9 @@ 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 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);
}; };

View file

@ -139,7 +139,7 @@ void console_ncurses::panel_update_thread()
int run_mode = current_PSW >> 14; int run_mode = current_PSW >> 14;
uint16_t current_PC = c->getPC(); 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); uint16_t current_instr = b->readWord(current_PC);

528
cpu.cpp
View file

@ -10,6 +10,8 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
uint16_t oldpc = 0;
#define SIGN(x, wm) ((wm) ? (x) & 0x80 : (x) & 0x8000) #define SIGN(x, wm) ((wm) ? (x) & 0x80 : (x) & 0x8000)
#define IS_0(x, wm) ((wm) ? ((x) & 0xff) == 0 : (x) == 0) #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(regs0_5, 0x00, sizeof regs0_5);
memset(sp, 0x00, sizeof sp); memset(sp, 0x00, sizeof sp);
pc = 0; pc = 0;
psw = 7 << 5; psw = 0; // 7 << 5;
fpsr = 0; fpsr = 0;
runMode = false;
init_interrupt_queue(); 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) { if (g.addr.has_value() == false) {
setRegisterLowByte(dst_reg, word_mode, value); setRegisterLowByte(g.reg, g.word_mode, value);
return true; 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) 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() bool cpu::check_queued_interrupts()
{ {
std::unique_lock<std::mutex> lck(qi_lock); 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 // 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; gam_rc_t g { false, false, false, i_space, { }, 0 };
uint16_t temp = 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) { switch(mode) {
case 0: // 000 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: 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: 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); addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? 2 : 1);
return temp; break;
case 3: 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); addRegister(reg, prev_mode, 2);
return temp; break;
case 4: case 4:
addRegister(reg, prev_mode, !word_mode || reg == 7 || reg == 6 ? -2 : -1); 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: case 5:
addRegister(reg, prev_mode, -2); 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: case 6:
next_word = b -> read(getPC(), false, prev_mode); next_word = b -> read(getPC(), false, prev_mode);
addRegister(7, prev_mode, + 2); addRegister(7, prev_mode, + 2);
temp = b -> read(getRegister(reg, set, prev_mode) + next_word, word_mode, prev_mode); g.addr = getRegister(reg, g.set, prev_mode) + next_word;
return temp; if (read_value)
g.value = b->read(g.addr.value(), word_mode, prev_mode, d_space);
break;
case 7: case 7:
next_word = b -> read(getPC(), false, prev_mode); next_word = b -> read(getPC(), false, prev_mode);
addRegister(7, prev_mode, + 2); 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; if (g.addr.has_value()) {
int addr = -1; b->write(g.addr.value(), g.word_mode, value, g.prev_mode, g.space);
int set = getBitPSW(11); return g.addr.value() != ADDR_PSW;
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 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; return getGAM(mode, reg, word_mode, false, false);
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;
} }
bool cpu::double_operand_instructions(const uint16_t instr) 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_mode = (src >> 3) & 7;
const uint8_t src_reg = src & 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 = instr & 63;
const uint8_t dst_mode = (dst >> 3) & 7; 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); addToMMR1(src_mode, src_reg, word_mode);
if (word_mode && dst_mode == 0) if (word_mode && dst_mode == 0)
setRegister(dst_reg, false, int8_t(src_value)); // int8_t: sign extension setRegister(dst_reg, false, int8_t(g_src.value.value())); // int8_t: sign extension
else else {
set_flags = putGAM(dst_mode, dst_reg, word_mode, src_value, false); 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); addToMMR1(dst_mode, dst_reg, word_mode);
if (set_flags) { if (set_flags)
setPSW_n(SIGN(src_value, word_mode)); setPSW_flags_nzv(g_src.value.value(), word_mode);
setPSW_z(IS_0(src_value, word_mode));
setPSW_v(false);
}
return true; return true;
} }
@ -498,82 +454,75 @@ bool cpu::double_operand_instructions(const uint16_t instr)
case 0b010: { // CMP/CMPB Compare Word/Byte case 0b010: { // CMP/CMPB Compare Word/Byte
addToMMR1(src_mode, src_reg, word_mode); 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); addToMMR1(dst_mode, dst_reg, word_mode);
setPSW_n(SIGN(temp, word_mode)); setPSW_n(SIGN(temp, word_mode));
setPSW_z(IS_0(temp, word_mode)); setPSW_z(IS_0(temp, word_mode));
setPSW_v(SIGN((src_value ^ dst_value) & (~dst_value ^ temp), word_mode)); setPSW_v(SIGN((g_src.value.value() ^ g_dst.value.value()) & (~g_dst.value.value() ^ temp), word_mode));
setPSW_c(src_value < dst_value); setPSW_c(g_src.value.value() < g_dst.value.value());
return true; return true;
} }
case 0b011: { // BIT/BITB Bit Test Word/Byte case 0b011: { // BIT/BITB Bit Test Word/Byte
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 result = (dst_value & src_value) & (word_mode ? 0xff : 0xffff); uint16_t result = (g_dst.value.value() & g_src.value.value()) & (word_mode ? 0xff : 0xffff);
setPSW_n(SIGN(result, word_mode)); setPSW_flags_nzv(result, word_mode);
setPSW_z(IS_0(result, word_mode));
setPSW_v(false);
return true; return true;
} }
case 0b100: { // BIC/BICB Bit Clear Word/Byte 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)) { if (put_result(g_dst, result))
setPSW_n(SIGN(result, word_mode)); setPSW_flags_nzv(result, word_mode);
setPSW_z(IS_0(result, word_mode));
setPSW_v(false);
}
return true; return true;
} }
case 0b101: { // BIS/BISB Bit Set Word/Byte 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)) { if (put_result(g_dst, result))
setPSW_n(SIGN(result, word_mode)); setPSW_flags_nzv(result, word_mode);
setPSW_z(IS_0(result, word_mode));
setPSW_v(false);
}
return true; return true;
} }
case 0b110: { // ADD/SUB Add/Subtract Word 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);
auto g_dst = getGAM(dst_mode, dst_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; int16_t result = 0;
bool set_flags = dst_addr != ADDR_PSW; bool set_flags = g_dst.addr.has_value() ? g_dst.addr.value() != ADDR_PSW : true;
if (instr & 0x8000) { if (instr & 0x8000) {
result = (dst_value - ssrc_value) & 0xffff; result = (g_dst.value.value() - g_ssrc.value.value()) & 0xffff;
if (set_flags) { if (set_flags) {
setPSW_v(sign(ssrc_value) != sign(dst_value) && sign(ssrc_value) == sign(result)); //setPSW_v(sign(g_ssrc.value.value()) != sign(g_dst.value.value()) && sign(g_ssrc.value.value()) == sign(result));
setPSW_c(uint16_t(dst_value) < uint16_t(ssrc_value)); 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 { else {
result = (dst_value + ssrc_value) & 0xffff; result = (g_dst.value.value() + g_ssrc.value.value()) & 0xffff;
if (set_flags) { if (set_flags) {
setPSW_v(sign(ssrc_value) == sign(dst_value) && sign(dst_value) != sign(result)); 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(ssrc_value)); 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); setPSW_z(result == 0);
} }
if (dst_mode == 0) putGAM(g_dst, result);
setRegister(dst_reg, false, result);
else
b->writeWord(dst_addr, result);
return true; return true;
} }
@ -607,7 +553,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
switch(operation) { switch(operation) {
case 0: { // MUL case 0: { // MUL
int16_t R1 = getRegister(reg); int16_t R1 = getRegister(reg);
int16_t R2 = getGAM(dst_mode, dst_reg, true, false);
auto R2g = getGAM(dst_mode, dst_reg, false, false);
int16_t R2 = R2g.value.value();
int32_t result = R1 * R2; int32_t result = R1 * R2;
setRegister(reg, result >> 16); setRegister(reg, result >> 16);
@ -621,7 +570,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
} }
case 1: { // DIV 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 if (divider == 0) { // divide by zero
setPSW_n(false); setPSW_n(false);
@ -659,7 +609,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
case 2: { // ASH case 2: { // ASH
uint32_t R = getRegister(reg), oldR = R; 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); bool sign = SIGN(R, false);
// extend sign-bit // extend sign-bit
@ -701,7 +654,10 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
case 3: { // ASHC case 3: { // ASHC
uint32_t R0R1 = (getRegister(reg) << 16) | getRegister(reg | 1); 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; bool sign = R0R1 & 0x80000000;
setPSW_v(false); setPSW_v(false);
@ -754,23 +710,13 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
} }
case 4: { // XOR (word only) case 4: { // XOR (word only)
uint16_t a = getGAMAddress(dst_mode, dst_reg, false, false); auto g_dst = getGAM(dst_mode, dst_reg, false, false);
uint16_t vl = b->read(a, false, false) ^ getRegister(reg); uint16_t vl = g_dst.value.value() ^ getRegister(reg);
bool set_flags = true;
if (dst_mode == 0) bool set_flags = putGAM(g_dst, vl);
putGAM(dst_mode, dst_reg, false, vl, false);
else {
b->write(a, false, vl, false);
set_flags = a != ADDR_PSW; if (set_flags)
} setPSW_flags_nzv(vl, false);
if (set_flags) {
setPSW_n(vl & 0x8000);
setPSW_z(vl == 0);
setPSW_v(false);
}
return true; return true;
} }
@ -805,30 +751,16 @@ bool cpu::single_operand_instructions(const uint16_t instr)
if (word_mode) // handled elsewhere if (word_mode) // handled elsewhere
return false; return false;
else { else {
uint16_t v = 0; auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
if (dst_mode == 0) { uint16_t v = g_dst.value.value();
v = getRegister(dst_reg);
v = ((v & 0xff) << 8) | (v >> 8); v = ((v & 0xff) << 8) | (v >> 8);
setRegister(dst_reg, false, v); set_flags = putGAM(g_dst, 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);
}
if (set_flags) { if (set_flags) {
setPSW_n(v & 0x80); setPSW_flags_nzv(v, true);
setPSW_z((v & 0xff) == 0);
setPSW_v(false);
setPSW_c(false); setPSW_c(false);
} }
} }
@ -837,22 +769,16 @@ bool cpu::single_operand_instructions(const uint16_t instr)
} }
case 0b000101000: { // CLR/CLRB case 0b000101000: { // CLR/CLRB
if (dst_mode == 0) { {
auto g_dst = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t r = 0; uint16_t r = 0;
// CLRB only clears the least significant byte // CLRB only clears the least significant byte
if (word_mode) 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); bool set_flags = putGAM(g_dst, r);
}
else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false);
set_flags = a != ADDR_PSW;
b -> write(a, word_mode, 0, false);
}
if (set_flags) { if (set_flags) {
setPSW_n(false); setPSW_n(false);
@ -860,52 +786,35 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setPSW_v(false); setPSW_v(false);
setPSW_c(false); setPSW_c(false);
} }
}
break; break;
} }
case 0b000101001: { // COM/COMB case 0b000101001: { // COM/COMB
if (dst_mode == 0) { auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t v = getRegister(dst_reg); uint16_t v = a.value.value();
if (word_mode) if (word_mode)
v ^= 0xff; v ^= 0xff;
else else
v ^= 0xffff; v ^= 0xffff;
setPSW_n(SIGN(v, word_mode)); set_flags = putGAM(a, v);
setPSW_z(IS_0(v, word_mode));
setPSW_v(false);
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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_flags_nzv(v, word_mode);
setPSW_z(IS_0(v, word_mode));
setPSW_v(false);
setPSW_c(true); setPSW_c(true);
} }
b->write(a, word_mode, v, false);
}
break; break;
} }
case 0b000101010: { // INC/INCB case 0b000101010: { // INC/INCB
auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t v = a.value.value();
if (dst_mode == 0) { if (dst_mode == 0) {
uint16_t v = getRegister(dst_reg);
uint16_t add = word_mode ? v & 0xff00 : 0; uint16_t add = word_mode ? v & 0xff00 : 0;
v = (v + 1) & (word_mode ? 0xff : 0xffff); 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); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); int32_t vl = (a.value.value() + 1) & (word_mode ? 0xff : 0xffff);
uint16_t v = b -> read(a, word_mode, false);
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) { if (set_flags) {
setPSW_n(SIGN(vl, word_mode)); 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); 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; break;
} }
case 0b000101011: { // DEC/DECB case 0b000101011: { // DEC/DECB
// TODO unify
if (dst_mode == 0) { if (dst_mode == 0) {
uint16_t v = getRegister(dst_reg); uint16_t v = getRegister(dst_reg);
uint16_t add = word_mode ? v & 0xff00 : 0; 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); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t v = b -> read(a, word_mode, false); uint16_t v = a.value.value();
int32_t vl = (v - 1) & (word_mode ? 0xff : 0xffff); 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) { if (set_flags) {
setPSW_n(SIGN(vl, word_mode)); 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); 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; break;
@ -985,12 +893,12 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setRegister(dst_reg, false, v); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t v = -b -> read(a, 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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_n(SIGN(v, word_mode));
@ -1021,14 +929,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setRegister(dst_reg, false, v); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
const uint16_t vo = b -> read(a, word_mode, false); const uint16_t vo = a.value.value();
bool org_c = getPSW_c(); bool org_c = getPSW_c();
uint16_t v = (vo + org_c) & (word_mode ? 0x00ff : 0xffff); 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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_n(SIGN(v, word_mode));
@ -1063,14 +971,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setRegister(dst_reg, false, v); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
const uint16_t vo = b -> read(a, word_mode, false); const uint16_t vo = a.value.value();
bool org_c = getPSW_c(); bool org_c = getPSW_c();
uint16_t v = (vo - org_c) & (word_mode ? 0xff : 0xffff); 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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_n(SIGN(v, word_mode));
@ -1087,11 +995,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
} }
case 0b000101111: { // TST/TSTB 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_flags_nzv(v, word_mode);
setPSW_z(IS_0(v, word_mode));
setPSW_v(false);
setPSW_c(false); setPSW_c(false);
break; break;
@ -1120,8 +1026,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setPSW_v(getPSW_c() ^ getPSW_n()); setPSW_v(getPSW_c() ^ getPSW_n());
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t t = b -> read(a, word_mode, false); uint16_t t = a.value.value();
bool new_carry = t & 1; bool new_carry = t & 1;
uint16_t temp = 0; uint16_t temp = 0;
@ -1130,9 +1036,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
else else
temp = (t >> 1) | (getPSW_c() << 15); 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) { if (set_flags) {
setPSW_c(new_carry); setPSW_c(new_carry);
@ -1167,8 +1073,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setPSW_v(getPSW_c() ^ getPSW_n()); setPSW_v(getPSW_c() ^ getPSW_n());
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t t = b -> read(a, word_mode, false); uint16_t t = a.value.value();
bool new_carry = false; bool new_carry = false;
uint16_t temp = 0; uint16_t temp = 0;
@ -1181,9 +1087,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
temp = (t << 1) | getPSW_c(); 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) { if (set_flags) {
setPSW_c(new_carry); setPSW_c(new_carry);
@ -1222,8 +1128,8 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setPSW_v(getPSW_n() ^ getPSW_c()); setPSW_v(getPSW_n() ^ getPSW_c());
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t v = b -> read(a, word_mode, false); uint16_t v = a.value.value();
uint16_t add = word_mode ? v & 0xff00 : 0; uint16_t add = word_mode ? v & 0xff00 : 0;
bool hb = word_mode ? v & 128 : v & 32768; bool hb = word_mode ? v & 128 : v & 32768;
@ -1240,9 +1146,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
v |= hb << 15; 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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); setPSW_n(SIGN(v, word_mode));
@ -1269,11 +1175,11 @@ bool cpu::single_operand_instructions(const uint16_t instr)
setRegister(dst_reg, false, v); setRegister(dst_reg, false, v);
} }
else { else {
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false); auto a = getGAM(dst_mode, dst_reg, word_mode, false);
uint16_t vl = b -> read(a, word_mode, false); uint16_t vl = a.value.value();
uint16_t v = (vl << 1) & (word_mode ? 0xff : 0xffff); 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) { if (set_flags) {
setPSW_n(SIGN(v, word_mode)); 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()); setPSW_v(getPSW_n() ^ getPSW_c());
} }
b->write(a, word_mode, v, false); b->write(a.addr.value(), word_mode, v, false);
} }
break; break;
} }
case 0b00110101: { // MFPD/MFPI case 0b00110101: { // MFPD/MFPI
// always words: word_mode-bit is to select between MFPI and MFPD // 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) if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(-2, 6); b->addToMMR1(-2, 6);
@ -1301,19 +1206,28 @@ bool cpu::single_operand_instructions(const uint16_t instr)
v = getRegister(dst_reg, getBitPSW(11), true); v = getRegister(dst_reg, getBitPSW(11), true);
else { else {
// calculate address in current address space // 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;
if (a.addr.value() >= 0160000) {
// read from previous space // read from previous space
v = b -> read(a, false, true); 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) { if (set_flags)
setPSW_n(SIGN(v, false)); setPSW_flags_nzv(v, false);
setPSW_z(v == 0);
setPSW_v(false);
}
// put on current stack // put on current stack
pushStack(v); pushStack(v);
@ -1323,7 +1237,6 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b00110110: { // MTPI/MTPD case 0b00110110: { // MTPI/MTPD
// always words: word_mode-bit is to select between MTPI and 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) if ((b->getMMR0() & 0160000) == 0)
b->addToMMR1(2, 6); b->addToMMR1(2, 6);
@ -1336,18 +1249,35 @@ bool cpu::single_operand_instructions(const uint16_t instr)
if (dst_mode == 0) if (dst_mode == 0)
setRegister(dst_reg, true, v); setRegister(dst_reg, true, v);
else { 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) { if (set_flags)
setPSW_n(SIGN(v, false)); setPSW_flags_nzv(v, false);
setPSW_z(v == 0);
setPSW_v(false);
}
break; break;
} }
@ -1355,7 +1285,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
case 0b000110100: // MARK/MTPS (put something in PSW) case 0b000110100: // MARK/MTPS (put something in PSW)
if (word_mode) { // MTPS if (word_mode) { // MTPS
psw &= 0xff00; // only alter lower 8 bits 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 { else {
setRegister(6, getPC() + dst * 2); setRegister(6, getPC() + dst * 2);
@ -1367,7 +1297,9 @@ bool cpu::single_operand_instructions(const uint16_t instr)
break; 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 if (word_mode) { // MFPS
uint16_t temp = psw & 0xff; uint16_t temp = psw & 0xff;
bool extend_b7 = psw & 128; bool extend_b7 = psw & 128;
@ -1375,7 +1307,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
if (extend_b7 && dst_mode == 0) if (extend_b7 && dst_mode == 0)
temp |= 0xff00; temp |= 0xff00;
set_flags = putGAM(dst_mode, dst_reg, word_mode, temp, false); bool set_flags = putGAM(g_dst, temp);
if (set_flags) { if (set_flags) {
setPSW_z(temp == 0); setPSW_z(temp == 0);
@ -1384,15 +1316,14 @@ bool cpu::single_operand_instructions(const uint16_t instr)
} }
} }
else { // SXT else { // SXT
uint16_t a = getGAMAddress(dst_mode, dst_reg, word_mode, false);
int32_t vl = -getPSW_n(); 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_z(getPSW_n() == false);
setPSW_v(false); setPSW_v(false);
} }
} }
}
break; break;
@ -1600,7 +1531,7 @@ bool cpu::misc_operations(const uint16_t instr)
int dst_reg = instr & 7; int dst_reg = instr & 7;
bool word_mode = false; 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; return true;
@ -1608,7 +1539,7 @@ bool cpu::misc_operations(const uint16_t instr)
if ((instr & 0b1111111000000000) == 0b0000100000000000) { // JSR if ((instr & 0b1111111000000000) == 0b0000100000000000) { // JSR
int link_reg = (instr >> 6) & 7; int link_reg = (instr >> 6) & 7;
uint16_t dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false, false); auto dst_value = getGAMAddress((instr >> 3) & 7, instr & 7, false).addr.value();
// PUSH link // PUSH link
pushStack(getRegister(link_reg)); 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); 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 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++; instruction_count++;
uint16_t temp_pc = getPC(); uint16_t temp_pc = getPC();
oldpc = temp_pc;
if ((b->getMMR0() & 0160000) == 0) if ((b->getMMR0() & 0160000) == 0)
b->setMMR2(temp_pc); b->setMMR2(temp_pc);

32
cpu.h
View file

@ -5,12 +5,27 @@
#include <assert.h> #include <assert.h>
#include <map> #include <map>
#include <mutex> #include <mutex>
#include <optional>
#include <set> #include <set>
#include <stdint.h> #include <stdint.h>
#include <vector> #include <vector>
#include "bus.h" #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 class cpu
{ {
private: private:
@ -21,12 +36,13 @@ private:
uint16_t fpsr { 0 }; uint16_t fpsr { 0 };
uint16_t stackLimitRegister { 0 }; uint16_t stackLimitRegister { 0 };
uint8_t scheduled_trap { 0 }; uint8_t scheduled_trap { 0 };
bool runMode { false };
bool emulateMFPT { false }; bool emulateMFPT { false };
uint64_t instruction_count { 0 }; uint64_t instruction_count { 0 };
uint64_t running_since { 0 }; uint64_t running_since { 0 };
bool mode11_70 { true }; bool mode11_70 { true };
uint64_t mtpi_count { 0 };
// level, vector // level, vector
std::map<uint8_t, std::set<uint8_t> > queued_interrupts; std::map<uint8_t, std::set<uint8_t> > queued_interrupts;
std::mutex qi_lock; std::mutex qi_lock;
@ -42,10 +58,11 @@ private:
uint16_t addRegister(const int nr, const bool prev_mode, const uint16_t value); 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); 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 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);
bool putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, const bool MF_FT); 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 double_operand_instructions(const uint16_t instr);
bool additional_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; } void setEmulateMFPT(const bool v) { emulateMFPT = v; }
bool getRunMode() { return runMode; }
bool getPSW_c() const; bool getPSW_c() const;
bool getPSW_v() const; bool getPSW_v() const;
bool getPSW_z() const; bool getPSW_z() const;
@ -115,6 +130,7 @@ public:
void setPSW_n(const bool v); void setPSW_n(const bool v);
void setPSW_spl(const int v); void setPSW_spl(const int v);
void setBitPSW(const int bit, const bool 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; } uint16_t getPSW() const { return psw; }
void setPSW(const uint16_t v, const bool limited); 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 int mode, const bool sp_prev_mode) const;
uint16_t getRegister(const int nr) 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);
}; };

View file

@ -49,6 +49,19 @@ int disassemble(cpu *const c, console *const cnsl, const int pc, const bool inst
instruction.c_str(), instruction.c_str(),
MMR0.c_str(), MMR2.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) if (cnsl)
cnsl->debug(result); cnsl->debug(result);
@ -136,8 +149,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
if (parts.empty()) if (parts.empty())
continue; continue;
if (cmd == "go") if (cmd == "go") {
single_step = false; single_step = false;
*stop_event = EVENT_NONE;
}
else if (parts[0] == "single" || parts[0] == "s") { else if (parts[0] == "single" || parts[0] == "s") {
single_step = true; 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()); n_single_step = atoi(parts[1].c_str());
else else
n_single_step = 1; n_single_step = 1;
*stop_event = EVENT_NONE;
} }
else if ((parts[0] == "sbp" || parts[0] == "cbp") && parts.size() == 2){ else if ((parts[0] == "sbp" || parts[0] == "cbp") && parts.size() == 2){
uint16_t pc = std::stoi(parts[1].c_str(), nullptr, 8); 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; 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") { else if (parts[0] == "trace" || parts[0] == "t") {
tracing = !tracing; 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("trace/t - toggle tracing");
cnsl->put_string_lf("strace - start tracing from address - invoke without address to disable"); 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("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; continue;
} }
@ -308,6 +358,9 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
*cnsl->get_running_flag() = true; *cnsl->get_running_flag() = true;
while(*stop_event == EVENT_NONE) { while(*stop_event == EVENT_NONE) {
if (!single_step)
DOLOG(debug, false, "---");
c->step_a(); c->step_a();
if (trace_start_addr != -1 && c->getPC() == trace_start_addr) if (trace_start_addr != -1 && c->getPC() == trace_start_addr)

View file

@ -26,11 +26,13 @@ void setBootLoader(bus *const b, const bootloader_t which)
cpu *const c = b -> getCpu(); cpu *const c = b -> getCpu();
uint16_t offset = 0; uint16_t offset = 0;
uint16_t start = 0;
const uint16_t *bl = nullptr; const uint16_t *bl = nullptr;
int size = 0; int size = 0;
if (which == BL_RK05) { if (which == BL_RK05) {
offset = 01000; /*
start = offset = 01000;
static uint16_t rk05_code[] = { static uint16_t rk05_code[] = {
0012700, 0012700,
@ -43,13 +45,44 @@ void setBootLoader(bus *const b, const bootloader_t which)
0100376, 0100376,
0005007 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; bl = rk05_code;
size = 9; size = sizeof(rk05_code)/sizeof(rk05_code[0]);
} }
else if (which == BL_RL02) { else if (which == BL_RL02) {
offset = 01000; start = offset = 01000;
/* from https://www.pdp-11.nl/peripherals/disk/rl-info.html /* from https://www.pdp-11.nl/peripherals/disk/rl-info.html
static uint16_t rl02_code[] = { static uint16_t rl02_code[] = {
@ -93,7 +126,7 @@ void setBootLoader(bus *const b, const bootloader_t which)
0005007, 0005007,
}; };
size = 10; size = sizeof(rl02_code)/sizeof(rl02_code[0]);
bl = rl02_code; bl = rl02_code;
} }
@ -101,7 +134,7 @@ void setBootLoader(bus *const b, const bootloader_t which)
for(int i=0; i<size; i++) for(int i=0; i<size; i++)
b -> writeWord(offset + i * 2, bl[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) uint16_t loadTape(bus *const b, const std::string & file)

10
log.cpp
View file

@ -13,7 +13,7 @@
static const char *logfile = strdup("/tmp/myip.log"); static const char *logfile = strdup("/tmp/myip.log");
log_level_t log_level_file = warning; log_level_t log_level_file = warning;
log_level_t log_level_screen = warning; log_level_t log_level_screen = warning;
static FILE *lfh = nullptr; FILE *lfh = nullptr;
static int lf_uid = -1; static int lf_uid = -1;
static int lf_gid = -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_file = ll_file;
log_level_screen = ll_screen; log_level_screen = ll_screen;
atexit(closelog);
} }
void setloguid(const int uid, const int gid) void setloguid(const int uid, const int gid)
@ -45,9 +47,11 @@ void setloguid(const int uid, const int gid)
void closelog() void closelog()
{ {
if (lfh) {
fclose(lfh); fclose(lfh);
lfh = nullptr; lfh = nullptr;
}
} }
void dolog(const log_level_t ll, const char *fmt, ...) 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; return;
if (!lfh) { if (!lfh) {
#if !defined(ESP32)
lfh = fopen(logfile, "a+"); lfh = fopen(logfile, "a+");
if (!lfh) if (!lfh)
error_exit(true, "Cannot access log-file %s", logfile); error_exit(true, "Cannot access log-file %s", logfile);
#if !defined(ESP32)
if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1) if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1)
error_exit(true, "Cannot change logfile (%s) ownership", logfile); 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); (void)vasprintf(&str, fmt, ap);
va_end(ap); va_end(ap);
#if !defined(ESP32)
if (ll >= log_level_file) if (ll >= log_level_file)
fprintf(lfh, "%s%s\n", ts_str, str); fprintf(lfh, "%s%s\n", ts_str, str);
#endif
if (ll >= log_level_screen) if (ll >= log_level_screen)
printf("%s%s\r\n", ts_str, str); printf("%s%s\r\n", ts_str, str);

2
log.h
View file

@ -14,6 +14,6 @@ void dolog(const log_level_t ll, const char *fmt, ...);
#define DOLOG(ll, always, fmt, ...) do { \ #define DOLOG(ll, always, fmt, ...) do { \
extern log_level_t log_level_file, log_level_screen; \ 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__); \ dolog(ll, fmt, ##__VA_ARGS__); \
} while(0) } while(0)

View file

@ -44,7 +44,7 @@ void help()
printf("-h this help\n"); printf("-h this help\n");
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\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 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("-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("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n");
printf("-n ncurses UI\n"); printf("-n ncurses UI\n");