Merge branch 'master' into psram
This commit is contained in:
commit
b353d6b99c
51 changed files with 726 additions and 1625 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,5 +7,5 @@ tests/*.lst
|
||||||
tests/*.bin
|
tests/*.bin
|
||||||
*.log
|
*.log
|
||||||
work/
|
work/
|
||||||
tests/
|
tests-work/
|
||||||
build/
|
build/
|
||||||
|
|
BIN
BIC/ZRKJE0.BIC
Normal file
BIN
BIC/ZRKJE0.BIC
Normal file
Binary file not shown.
BIN
BIC/ZRKKF2.BIC
Normal file
BIN
BIC/ZRKKF2.BIC
Normal file
Binary file not shown.
|
@ -37,6 +37,7 @@ add_executable(
|
||||||
log.cpp
|
log.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
memory.cpp
|
memory.cpp
|
||||||
|
mmu.cpp
|
||||||
rk05.cpp
|
rk05.cpp
|
||||||
rl02.cpp
|
rl02.cpp
|
||||||
terminal.cpp
|
terminal.cpp
|
||||||
|
|
1
ESP32/device.h
Symbolic link
1
ESP32/device.h
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../device.h
|
|
@ -48,16 +48,16 @@ std::optional<std::string> breakpoint_register::is_triggered() const
|
||||||
|
|
||||||
switch(reg) {
|
switch(reg) {
|
||||||
case hr_mmr0:
|
case hr_mmr0:
|
||||||
v = b->getMMR0();
|
v = b->getMMU()->getMMR0();
|
||||||
break;
|
break;
|
||||||
case hr_mmr1:
|
case hr_mmr1:
|
||||||
v = b->getMMR1();
|
v = b->getMMU()->getMMR1();
|
||||||
break;
|
break;
|
||||||
case hr_mmr2:
|
case hr_mmr2:
|
||||||
v = b->getMMR2();
|
v = b->getMMU()->getMMR2();
|
||||||
break;
|
break;
|
||||||
case hr_mmr3:
|
case hr_mmr3:
|
||||||
v = b->getMMR3();
|
v = b->getMMU()->getMMR3();
|
||||||
break;
|
break;
|
||||||
case hr_psw:
|
case hr_psw:
|
||||||
v = c->getPSW();
|
v = c->getPSW();
|
||||||
|
|
353
bus.cpp
353
bus.cpp
|
@ -10,6 +10,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "mmu.h"
|
||||||
#include "tm-11.h"
|
#include "tm-11.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -18,12 +19,13 @@
|
||||||
#include <esp_debug_helpers.h>
|
#include <esp_debug_helpers.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr const int di_ena_mask[4] = { 4, 2, 0, 1 };
|
|
||||||
|
|
||||||
bus::bus()
|
bus::bus()
|
||||||
{
|
{
|
||||||
m = new memory(n_pages * 8192l);
|
m = new memory(n_pages * 8192l);
|
||||||
|
|
||||||
|
mmu_ = new mmu();
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
#if defined(BUILD_FOR_RP2040)
|
#if defined(BUILD_FOR_RP2040)
|
||||||
|
@ -38,6 +40,7 @@ bus::~bus()
|
||||||
delete rk05_;
|
delete rk05_;
|
||||||
delete rl02_;
|
delete rl02_;
|
||||||
delete tty_;
|
delete tty_;
|
||||||
|
delete mmu_;
|
||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +60,7 @@ void bus::reset()
|
||||||
{
|
{
|
||||||
m->reset();
|
m->reset();
|
||||||
|
|
||||||
memset(pages, 0x00, sizeof pages);
|
mmu_->reset();
|
||||||
|
|
||||||
CPUERR = MMR0 = MMR1 = MMR2 = MMR3 = PIR = CSR = 0;
|
|
||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
c->reset();
|
c->reset();
|
||||||
|
@ -105,38 +106,18 @@ void bus::add_tty(tty *const tty_)
|
||||||
|
|
||||||
void bus::init()
|
void bus::init()
|
||||||
{
|
{
|
||||||
MMR0 = 0;
|
mmu_->setMMR0(0);
|
||||||
MMR3 = 0;
|
mmu_->setMMR3(0);
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t bus::read_pdr(const uint32_t a, const int run_mode, const word_mode_t word_mode, const bool peek_only)
|
|
||||||
{
|
|
||||||
int page = (a >> 1) & 7;
|
|
||||||
bool is_d = a & 16;
|
|
||||||
uint16_t t = pages[run_mode][is_d][page].pdr;
|
|
||||||
|
|
||||||
if (!peek_only)
|
|
||||||
DOLOG(debug, false, "READ-I/O PDR run-mode %d: %c for %d: %o", run_mode, is_d ? 'D' : 'I', page, t);
|
|
||||||
|
|
||||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t bus::read_par(const uint32_t a, const int run_mode, const word_mode_t word_mode, const bool peek_only)
|
|
||||||
{
|
|
||||||
int page = (a >> 1) & 7;
|
|
||||||
bool is_d = a & 16;
|
|
||||||
uint16_t t = pages[run_mode][is_d][page].par;
|
|
||||||
|
|
||||||
if (!peek_only)
|
|
||||||
DOLOG(debug, false, "READ-I/O PAR run-mode %d: %c for %d: %o (phys: %07o)", run_mode, is_d ? 'D' : 'I', page, t, t * 64);
|
|
||||||
|
|
||||||
return word_mode ? (a & 1 ? t >> 8 : t & 255) : t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus::trap_odd(const uint16_t a)
|
void bus::trap_odd(const uint16_t a)
|
||||||
{
|
{
|
||||||
MMR0 &= ~(7 << 1);
|
uint16_t temp = mmu_->getMMR0();
|
||||||
MMR0 |= (a >> 13) << 1;
|
|
||||||
|
temp &= ~(7 << 1);
|
||||||
|
temp |= (a >> 13) << 1;
|
||||||
|
|
||||||
|
mmu_->setMMR0(temp);
|
||||||
|
|
||||||
c->trap(004); // invalid access
|
c->trap(004); // invalid access
|
||||||
}
|
}
|
||||||
|
@ -196,7 +177,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||||
uint16_t temp = CPUERR & 0xff;
|
uint16_t temp = mmu_->getCPUERR() & 0xff;
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O CPU error: %03o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O CPU error: %03o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +203,8 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
if (a == ADDR_PIR || a == ADDR_PIR + 1) { // PIR
|
if (a == ADDR_PIR || a == ADDR_PIR + 1) { // PIR
|
||||||
uint16_t temp = 0;
|
uint16_t temp = 0;
|
||||||
|
|
||||||
|
uint16_t PIR = mmu_->getPIR();
|
||||||
|
|
||||||
if (word_mode == wm_word)
|
if (word_mode == wm_word)
|
||||||
temp = PIR;
|
temp = PIR;
|
||||||
else
|
else
|
||||||
|
@ -261,18 +244,17 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MMU ///
|
/// MMU ///
|
||||||
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
|
if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) ||
|
||||||
return read_pdr(a, 1, word_mode, peek_only);
|
(a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) ||
|
||||||
else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
|
(a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) ||
|
||||||
return read_par(a, 1, word_mode, peek_only);
|
(a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) ||
|
||||||
else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
|
(a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) ||
|
||||||
return read_pdr(a, 0, word_mode, peek_only);
|
(a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) {
|
||||||
else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
|
if (word_mode == wm_word)
|
||||||
return read_par(a, 0, word_mode, peek_only);
|
return mmu_->readWord(a);
|
||||||
else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
|
|
||||||
return read_pdr(a, 3, word_mode, peek_only);
|
return mmu_->readByte(a);
|
||||||
else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
|
}
|
||||||
return read_par(a, 3, word_mode, peek_only);
|
|
||||||
///////////
|
///////////
|
||||||
|
|
||||||
if (a >= 0177740 && a <= 0177753) { // cache control register and others
|
if (a >= 0177740 && a <= 0177753) { // cache control register and others
|
||||||
|
@ -327,37 +309,37 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR0) {
|
if (a == ADDR_MMR0) {
|
||||||
uint8_t temp = MMR0;
|
uint8_t temp = mmu_->getMMR0();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0 LO: %03o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0 LO: %03o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
if (a == ADDR_MMR0 + 1) {
|
if (a == ADDR_MMR0 + 1) {
|
||||||
uint8_t temp = MMR0 >> 8;
|
uint8_t temp = mmu_->getMMR0() >> 8;
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0 HI: %03o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0 HI: %03o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (a == ADDR_MMR0) {
|
if (a == ADDR_MMR0) {
|
||||||
uint16_t temp = MMR0;
|
uint16_t temp = mmu_->getMMR0();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0: %06o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR0: %06o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR1) { // MMR1
|
if (a == ADDR_MMR1) { // MMR1
|
||||||
uint16_t temp = MMR1;
|
uint16_t temp = mmu_->getMMR1();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR1: %06o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR1: %06o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR2) { // MMR2
|
if (a == ADDR_MMR2) { // MMR2
|
||||||
uint16_t temp = MMR2;
|
uint16_t temp = mmu_->getMMR2();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR2: %06o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR2: %06o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR3) { // MMR3
|
if (a == ADDR_MMR3) { // MMR3
|
||||||
uint16_t temp = MMR3;
|
uint16_t temp = mmu_->getMMR3();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR3: %06o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O MMR3: %06o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -375,7 +357,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||||
uint16_t temp = CPUERR;
|
uint16_t temp = mmu_->getCPUERR();
|
||||||
if (!peek_only) DOLOG(debug, false, "READ-I/O CPUERR: %06o", temp);
|
if (!peek_only) DOLOG(debug, false, "READ-I/O CPUERR: %06o", temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -464,49 +446,11 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus::setMMR0(uint16_t value)
|
|
||||||
{
|
|
||||||
value &= ~(3 << 10); // bit 10 & 11 always read as 0
|
|
||||||
|
|
||||||
if (value & 1)
|
|
||||||
value &= ~(7l << 13); // reset error bits
|
|
||||||
|
|
||||||
if (MMR0 & 0160000) {
|
|
||||||
if ((value & 1) == 0)
|
|
||||||
value &= 254; // bits 7...1 are protected
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO if bit 15/14/13 are set (either of them), then do not modify bit 1...7
|
|
||||||
|
|
||||||
MMR0 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::setMMR0Bit(const int bit)
|
|
||||||
{
|
|
||||||
assert(bit != 10 && bit != 11);
|
|
||||||
assert(bit < 16 && bit >= 0);
|
|
||||||
|
|
||||||
MMR0 |= 1 << bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::clearMMR0Bit(const int bit)
|
|
||||||
{
|
|
||||||
assert(bit != 10 && bit != 11);
|
|
||||||
assert(bit < 16 && bit >= 0);
|
|
||||||
|
|
||||||
MMR0 &= ~(1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::setMMR2(const uint16_t value)
|
|
||||||
{
|
|
||||||
MMR2 = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::check_odd_addressing(const uint16_t a, const int run_mode, const d_i_space_t space, const bool is_write)
|
void bus::check_odd_addressing(const uint16_t a, const int run_mode, const d_i_space_t space, const bool is_write)
|
||||||
{
|
{
|
||||||
if (a & 1) {
|
if (a & 1) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
pages[run_mode][space == d_space][a >> 13].pdr |= 1 << 7;
|
mmu_->set_page_trapped(run_mode, space == d_space, a >> 13);
|
||||||
|
|
||||||
trap_odd(a);
|
trap_odd(a);
|
||||||
|
|
||||||
|
@ -518,25 +462,25 @@ memory_addresses_t bus::calculate_physical_address(const int run_mode, const uin
|
||||||
{
|
{
|
||||||
const uint8_t apf = a >> 13; // active page field
|
const uint8_t apf = a >> 13; // active page field
|
||||||
|
|
||||||
if ((MMR0 & 1) == 0) {
|
if (mmu_->is_enabled() == false) {
|
||||||
bool is_psw = a == ADDR_PSW;
|
bool is_psw = a == ADDR_PSW;
|
||||||
return { a, apf, a, is_psw, a, is_psw };
|
return { a, apf, a, is_psw, a, is_psw };
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t physical_instruction = pages[run_mode][0][apf].par * 64;
|
uint32_t physical_instruction = mmu_->get_physical_memory_offset(run_mode, 0, apf);
|
||||||
uint32_t physical_data = pages[run_mode][1][apf].par * 64;
|
uint32_t physical_data = mmu_->get_physical_memory_offset(run_mode, 1, apf);
|
||||||
|
|
||||||
uint16_t p_offset = a & 8191; // page offset
|
uint16_t p_offset = a & 8191; // page offset
|
||||||
|
|
||||||
physical_instruction += p_offset;
|
physical_instruction += p_offset;
|
||||||
physical_data += p_offset;
|
physical_data += p_offset;
|
||||||
|
|
||||||
if ((MMR3 & 16) == 0) { // offset is 18bit
|
if ((mmu_->getMMR3() & 16) == 0) { // offset is 18bit
|
||||||
physical_instruction &= 0x3ffff;
|
physical_instruction &= 0x3ffff;
|
||||||
physical_data &= 0x3ffff;
|
physical_data &= 0x3ffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_use_data_space(run_mode) == false)
|
if (mmu_->get_use_data_space(run_mode) == false)
|
||||||
physical_data = physical_instruction;
|
physical_data = physical_instruction;
|
||||||
|
|
||||||
uint32_t io_base = get_io_base();
|
uint32_t io_base = get_io_base();
|
||||||
|
@ -568,14 +512,9 @@ void bus::mmudebug(const uint16_t a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bus::get_use_data_space(const int run_mode) const
|
|
||||||
{
|
|
||||||
return !!(MMR3 & di_ena_mask[run_mode]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<trap_action_t, int> bus::get_trap_action(const int run_mode, const bool d, const int apf, const bool is_write)
|
std::pair<trap_action_t, int> bus::get_trap_action(const int run_mode, const bool d, const int apf, const bool is_write)
|
||||||
{
|
{
|
||||||
const int access_control = pages[run_mode][d][apf].pdr & 7;
|
const int access_control = mmu_->get_access_control(run_mode, d, apf);
|
||||||
|
|
||||||
trap_action_t trap_action = T_PROCEED;
|
trap_action_t trap_action = T_PROCEED;
|
||||||
|
|
||||||
|
@ -609,25 +548,24 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
{
|
{
|
||||||
uint32_t m_offset = a;
|
uint32_t m_offset = a;
|
||||||
|
|
||||||
if ((MMR0 & 1 /* mmu enabled */) || (is_write && (MMR0 & (1 << 8 /* maintenance check */)))) {
|
if (mmu_->is_enabled() || (is_write && (mmu_->getMMR0() & (1 << 8 /* maintenance check */)))) {
|
||||||
const uint8_t apf = a >> 13; // active page field
|
const uint8_t apf = a >> 13; // active page field
|
||||||
|
|
||||||
bool d = space == d_space && get_use_data_space(run_mode) ? space == d_space : false;
|
bool d = space == d_space && mmu_->get_use_data_space(run_mode) ? space == d_space : 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
|
m_offset = mmu_->get_physical_memory_offset(run_mode, d, apf);
|
||||||
|
|
||||||
m_offset += p_offset;
|
m_offset += p_offset;
|
||||||
|
|
||||||
if ((MMR3 & 16) == 0) // off is 18bit
|
if ((mmu_->getMMR3() & 16) == 0) // off is 18bit
|
||||||
m_offset &= 0x3ffff;
|
m_offset &= 0x3ffff;
|
||||||
|
|
||||||
uint32_t io_base = get_io_base();
|
uint32_t io_base = get_io_base();
|
||||||
bool is_io = m_offset >= io_base;
|
bool is_io = m_offset >= io_base;
|
||||||
|
|
||||||
[[unlikely]]
|
if (trap_on_failure) [[unlikely]] {
|
||||||
if (trap_on_failure) {
|
|
||||||
{
|
{
|
||||||
auto rc = get_trap_action(run_mode, d, apf, is_write);
|
auto rc = get_trap_action(run_mode, d, apf, is_write);
|
||||||
auto trap_action = rc.first;
|
auto trap_action = rc.first;
|
||||||
|
@ -635,28 +573,32 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
|
|
||||||
if (trap_action != T_PROCEED) {
|
if (trap_action != T_PROCEED) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
mmu_->set_page_trapped(run_mode, d, apf);
|
||||||
|
|
||||||
if ((MMR0 & 0160000) == 0) {
|
if (mmu_->is_locked() == false) {
|
||||||
MMR0 &= ~((1l << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (3 << 5) | (7 << 1) | (1 << 4));
|
uint16_t temp = mmu_->getMMR0();
|
||||||
|
|
||||||
|
temp &= ~((1l << 15) | (1 << 14) | (1 << 13) | (1 << 12) | (3 << 5) | (7 << 1) | (1 << 4));
|
||||||
|
|
||||||
if (is_write && access_control != 6)
|
if (is_write && access_control != 6)
|
||||||
MMR0 |= 1 << 13; // read-only
|
temp |= 1 << 13; // read-only
|
||||||
//
|
//
|
||||||
if (access_control == 0 || access_control == 4)
|
if (access_control == 0 || access_control == 4)
|
||||||
MMR0 |= 1l << 15; // not resident
|
temp |= 1l << 15; // not resident
|
||||||
else
|
else
|
||||||
MMR0 |= 1 << 13; // read-only
|
temp |= 1 << 13; // read-only
|
||||||
|
|
||||||
MMR0 |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode?
|
temp |= run_mode << 5; // TODO: kernel-mode or user-mode when a trap occurs in user-mode?
|
||||||
|
|
||||||
MMR0 |= apf << 1; // add current page
|
temp |= apf << 1; // add current page
|
||||||
|
|
||||||
MMR0 |= d << 4;
|
temp |= d << 4;
|
||||||
|
|
||||||
|
mmu_->setMMR0(temp);
|
||||||
|
|
||||||
|
DOLOG(debug, false, "MMR0: %06o", temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
DOLOG(debug, false, "MMR0: %06o", MMR0);
|
|
||||||
|
|
||||||
if (trap_action == T_TRAP_250) {
|
if (trap_action == T_TRAP_250) {
|
||||||
DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 0250", access_control, a);
|
DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 0250", access_control, a);
|
||||||
|
|
||||||
|
@ -674,34 +616,37 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[unlikely]]
|
if (m_offset >= n_pages * 8192l && !is_io) [[unlikely]] {
|
||||||
if (m_offset >= n_pages * 8192l && !is_io) {
|
|
||||||
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192l);
|
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192l);
|
||||||
DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a);
|
DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a);
|
||||||
|
|
||||||
if ((MMR0 & 0160000) == 0) {
|
if (mmu_->is_locked() == false) {
|
||||||
MMR0 &= 017777;
|
uint16_t temp = mmu_->getMMR0();
|
||||||
MMR0 |= 1l << 15; // non-resident
|
|
||||||
|
|
||||||
MMR0 &= ~14; // add current page
|
temp &= 017777;
|
||||||
MMR0 |= apf << 1;
|
temp |= 1l << 15; // non-resident
|
||||||
|
|
||||||
MMR0 &= ~(3 << 5);
|
temp &= ~14; // add current page
|
||||||
MMR0 |= run_mode << 5;
|
temp |= apf << 1;
|
||||||
|
|
||||||
|
temp &= ~(3 << 5);
|
||||||
|
temp |= run_mode << 5;
|
||||||
|
|
||||||
|
mmu_->setMMR0(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_write)
|
if (is_write)
|
||||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
mmu_->set_page_trapped(run_mode, d, apf);
|
||||||
|
|
||||||
c->trap(04);
|
c->trap(04);
|
||||||
|
|
||||||
throw 6;
|
throw 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t pdr_len = (pages[run_mode][d][apf].pdr >> 8) & 127;
|
uint16_t pdr_len = mmu_->get_pdr_len(run_mode, d, apf);
|
||||||
uint16_t pdr_cmp = (a >> 6) & 127;
|
uint16_t pdr_cmp = (a >> 6) & 127;
|
||||||
|
|
||||||
bool direction = pages[run_mode][d][apf].pdr & 8;
|
bool direction = mmu_->get_pdr_direction(run_mode, d, apf);
|
||||||
|
|
||||||
// DOLOG(debug, false, "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);
|
// DOLOG(debug, false, "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);
|
||||||
|
|
||||||
|
@ -710,28 +655,34 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
DOLOG(debug, false, "TRAP(0250) (throw 7) on address %06o", a);
|
DOLOG(debug, false, "TRAP(0250) (throw 7) on address %06o", a);
|
||||||
c->trap(0250); // invalid access
|
c->trap(0250); // invalid access
|
||||||
|
|
||||||
if ((MMR0 & 0160000) == 0) {
|
if (mmu_->is_locked() == false) {
|
||||||
MMR0 &= 017777;
|
uint16_t temp = mmu_->getMMR0();
|
||||||
MMR0 |= 1 << 14; // length
|
|
||||||
|
|
||||||
MMR0 &= ~14; // add current page
|
temp &= 017777;
|
||||||
MMR0 |= apf << 1;
|
temp |= 1 << 14; // length
|
||||||
|
|
||||||
MMR0 &= ~(3 << 5);
|
temp &= ~14; // add current page
|
||||||
MMR0 |= run_mode << 5;
|
temp |= apf << 1;
|
||||||
|
|
||||||
MMR0 &= ~(1 << 4);
|
temp &= ~(3 << 5);
|
||||||
MMR0 |= d << 4;
|
temp |= run_mode << 5;
|
||||||
|
|
||||||
|
temp &= ~(1 << 4);
|
||||||
|
temp |= d << 4;
|
||||||
|
|
||||||
|
mmu_->setMMR0(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_write)
|
if (is_write)
|
||||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
mmu_->set_page_trapped(run_mode, d, apf);
|
||||||
|
|
||||||
throw 7;
|
throw 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DOLOG(debug, false, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d, %s)", a, m_offset, run_mode, apf, pages[run_mode][d][apf].par * 64, p_offset, pages[run_mode][d][apf].pdr & 7, d ? "D" : "I");
|
DOLOG(debug, false, "virtual address %06o maps to physical address %08o (run_mode: %d, apf: %d, par: %08o, poff: %o, AC: %d, %s)", a, m_offset, run_mode, apf,
|
||||||
|
mmu_->get_physical_memory_offset(run_mode, d, apf),
|
||||||
|
p_offset, mmu_->get_access_control(run_mode, d, apf), d ? "D" : "I");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// DOLOG(debug, false, "no MMU (read physical address %08o)", m_offset);
|
// DOLOG(debug, false, "no MMU (read physical address %08o)", m_offset);
|
||||||
|
@ -740,69 +691,6 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
return m_offset;
|
return m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus::clearMMR1()
|
|
||||||
{
|
|
||||||
MMR1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::addToMMR1(const int8_t delta, const uint8_t reg)
|
|
||||||
{
|
|
||||||
assert(reg >= 0 && reg <= 7);
|
|
||||||
assert(delta >= -2 && delta <= 2);
|
|
||||||
|
|
||||||
assert((getMMR0() & 0160000) == 0); // MMR1 should not be locked
|
|
||||||
|
|
||||||
#if defined(ESP32)
|
|
||||||
// if (MMR1 > 255)
|
|
||||||
// esp_backtrace_print(32);
|
|
||||||
#else
|
|
||||||
if (MMR1 > 255) {
|
|
||||||
extern FILE *lfh;
|
|
||||||
fflush(lfh);
|
|
||||||
}
|
|
||||||
assert(MMR1 < 256);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MMR1 <<= 8;
|
|
||||||
|
|
||||||
MMR1 |= (delta & 31) << 3;
|
|
||||||
MMR1 |= reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode)
|
|
||||||
{
|
|
||||||
bool is_d = a & 16;
|
|
||||||
int page = (a >> 1) & 7;
|
|
||||||
|
|
||||||
if (word_mode == wm_byte) {
|
|
||||||
assert(a != 0 || value < 256);
|
|
||||||
|
|
||||||
update_word(&pages[run_mode][is_d][page].pdr, a & 1, value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pages[run_mode][is_d][page].pdr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pages[run_mode][is_d][page].pdr &= ~(32768 + 128 /*A*/ + 64 /*W*/ + 32 + 16); // set bit 4, 5 & 15 to 0 as they are unused and A/W are set to 0 by writes
|
|
||||||
|
|
||||||
DOLOG(debug, false, "WRITE-I/O PDR run-mode %d: %c for %d: %o [%d]", run_mode, is_d ? 'D' : 'I', page, value, word_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bus::write_par(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode)
|
|
||||||
{
|
|
||||||
bool is_d = a & 16;
|
|
||||||
int page = (a >> 1) & 7;
|
|
||||||
|
|
||||||
if (word_mode == wm_byte)
|
|
||||||
update_word(&pages[run_mode][is_d][page].par, a & 1, value);
|
|
||||||
else
|
|
||||||
pages[run_mode][is_d][page].par = value;
|
|
||||||
|
|
||||||
pages[run_mode][is_d][page].pdr &= ~(128 /*A*/ + 64 /*W*/); // reset PDR A/W when PAR is written to
|
|
||||||
|
|
||||||
DOLOG(debug, false, "WRITE-I/O PAR run-mode %d: %c for %d: %o (%07o)", run_mode, is_d ? 'D' : 'I', page, word_mode == wm_byte ? value & 0xff : value, pages[run_mode][is_d][page].par * 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t space)
|
write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t space)
|
||||||
{
|
{
|
||||||
int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode();
|
int run_mode = mode_selection == rm_cur ? c->getPSW_runmode() : c->getPSW_prev_runmode();
|
||||||
|
@ -811,10 +699,10 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
|
|
||||||
bool is_data = space == d_space;
|
bool is_data = space == d_space;
|
||||||
|
|
||||||
bool d = is_data && get_use_data_space(run_mode) ? is_data : false;
|
bool d = is_data && mmu_->get_use_data_space(run_mode) ? is_data : false;
|
||||||
|
|
||||||
if ((MMR0 & 1) == 1 && (addr_in & 1) == 0 && addr_in != ADDR_MMR0)
|
if (mmu_->is_enabled() && (addr_in & 1) == 0 /* TODO remove this? */ && addr_in != ADDR_MMR0)
|
||||||
pages[run_mode][d][apf].pdr |= 64; // set 'W' (written to) bit
|
mmu_->set_page_written_to(run_mode, d, apf);
|
||||||
|
|
||||||
uint32_t m_offset = calculate_physical_address(run_mode, addr_in, true, true, false, space);
|
uint32_t m_offset = calculate_physical_address(run_mode, addr_in, true, true, false, space);
|
||||||
|
|
||||||
|
@ -864,7 +752,9 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
if (a == ADDR_MMR0 || a == ADDR_MMR0 + 1) { // MMR0
|
if (a == ADDR_MMR0 || a == ADDR_MMR0 + 1) { // MMR0
|
||||||
DOLOG(debug, false, "WRITE-I/O MMR0 register %s: %03o", a & 1 ? "MSB" : "LSB", value);
|
DOLOG(debug, false, "WRITE-I/O MMR0 register %s: %03o", a & 1 ? "MSB" : "LSB", value);
|
||||||
|
|
||||||
update_word(&MMR0, a & 1, value);
|
uint16_t temp = mmu_->getMMR0();
|
||||||
|
update_word(&temp, a & 1, value);
|
||||||
|
mmu_->setMMR0(temp);
|
||||||
|
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
|
@ -924,19 +814,19 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
|
|
||||||
if (a == ADDR_CPU_ERR) { // cpu error register
|
if (a == ADDR_CPU_ERR) { // cpu error register
|
||||||
DOLOG(debug, false, "WRITE-I/O CPUERR: %06o", value);
|
DOLOG(debug, false, "WRITE-I/O CPUERR: %06o", value);
|
||||||
CPUERR = 0;
|
mmu_->setCPUERR(0);
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR3) { // MMR3
|
if (a == ADDR_MMR3) { // MMR3
|
||||||
DOLOG(debug, false, "WRITE-I/O set MMR3: %06o", value);
|
DOLOG(debug, false, "WRITE-I/O set MMR3: %06o", value);
|
||||||
MMR3 = value;
|
mmu_->setMMR3(value);
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == ADDR_MMR0) { // MMR0
|
if (a == ADDR_MMR0) { // MMR0
|
||||||
DOLOG(debug, false, "WRITE-I/O set MMR0: %06o", value);
|
DOLOG(debug, false, "WRITE-I/O set MMR0: %06o", value);
|
||||||
setMMR0(value);
|
mmu_->setMMR0(value);
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,7 +842,8 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
bits >>= 1;
|
bits >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIR = value;
|
mmu_->setPIR(value);
|
||||||
|
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,35 +893,19 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
|
|
||||||
/// MMU ///
|
/// MMU ///
|
||||||
// supervisor
|
// supervisor
|
||||||
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) {
|
if ((a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) ||
|
||||||
write_pdr(a, 1, value, word_mode);
|
(a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) ||
|
||||||
return { false };
|
(a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) ||
|
||||||
}
|
(a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) ||
|
||||||
if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END) {
|
(a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) ||
|
||||||
write_par(a, 1, value, word_mode);
|
(a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)) {
|
||||||
return { false };
|
if (word_mode == wm_word)
|
||||||
}
|
mmu_->writeWord(a, value);
|
||||||
|
else
|
||||||
|
mmu_->writeByte(a, value);
|
||||||
|
|
||||||
// kernel
|
|
||||||
if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END) {
|
|
||||||
write_pdr(a, 0, value, word_mode);
|
|
||||||
return { false };
|
return { false };
|
||||||
}
|
}
|
||||||
if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END) {
|
|
||||||
write_par(a, 0, value, word_mode);
|
|
||||||
return { false };
|
|
||||||
}
|
|
||||||
|
|
||||||
// user
|
|
||||||
if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END) {
|
|
||||||
write_pdr(a, 3, value, word_mode);
|
|
||||||
return { false };
|
|
||||||
}
|
|
||||||
if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END) {
|
|
||||||
write_par(a, 3, value, word_mode);
|
|
||||||
return { false };
|
|
||||||
}
|
|
||||||
////
|
|
||||||
|
|
||||||
if (a >= 0177740 && a <= 0177753) { // cache control register and others
|
if (a >= 0177740 && a <= 0177753) { // cache control register and others
|
||||||
// TODO
|
// TODO
|
||||||
|
|
68
bus.h
68
bus.h
|
@ -8,9 +8,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "tm-11.h"
|
#include "gen.h"
|
||||||
|
#include "mmu.h"
|
||||||
#include "rk05.h"
|
#include "rk05.h"
|
||||||
#include "rl02.h"
|
#include "rl02.h"
|
||||||
|
#include "tm-11.h"
|
||||||
|
|
||||||
#if defined(BUILD_FOR_RP2040)
|
#if defined(BUILD_FOR_RP2040)
|
||||||
#include "rp2040.h"
|
#include "rp2040.h"
|
||||||
|
@ -36,21 +38,6 @@
|
||||||
#define ADDR_KW11P 0172540
|
#define ADDR_KW11P 0172540
|
||||||
#define ADDR_LP11CSR 0177514 // printer
|
#define ADDR_LP11CSR 0177514 // printer
|
||||||
|
|
||||||
#define ADDR_PDR_SV_START 0172200
|
|
||||||
#define ADDR_PDR_SV_END 0172240
|
|
||||||
#define ADDR_PAR_SV_START 0172240
|
|
||||||
#define ADDR_PAR_SV_END 0172300
|
|
||||||
|
|
||||||
#define ADDR_PDR_K_START 0172300
|
|
||||||
#define ADDR_PDR_K_END 0172340
|
|
||||||
#define ADDR_PAR_K_START 0172340
|
|
||||||
#define ADDR_PAR_K_END 0172400
|
|
||||||
|
|
||||||
#define ADDR_PDR_U_START 0177600
|
|
||||||
#define ADDR_PDR_U_END 0177640
|
|
||||||
#define ADDR_PAR_U_START 0177640
|
|
||||||
#define ADDR_PAR_U_END 0177700
|
|
||||||
|
|
||||||
#define ADDR_PSW 0177776
|
#define ADDR_PSW 0177776
|
||||||
#define ADDR_STACKLIM 0177774
|
#define ADDR_STACKLIM 0177774
|
||||||
#define ADDR_KERNEL_R 0177700
|
#define ADDR_KERNEL_R 0177700
|
||||||
|
@ -70,12 +57,6 @@ class cpu;
|
||||||
class memory;
|
class memory;
|
||||||
class tty;
|
class tty;
|
||||||
|
|
||||||
typedef enum { d_space, i_space } d_i_space_t;
|
|
||||||
|
|
||||||
typedef enum { wm_word = 0, wm_byte = 1 } word_mode_t;
|
|
||||||
|
|
||||||
typedef enum { rm_prev, rm_cur } rm_selection_t;
|
|
||||||
|
|
||||||
typedef enum { T_PROCEED, T_ABORT_4, T_TRAP_250 } trap_action_t;
|
typedef enum { T_PROCEED, T_ABORT_4, T_TRAP_250 } trap_action_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -87,10 +68,6 @@ typedef struct {
|
||||||
bool physical_data_is_psw;
|
bool physical_data_is_psw;
|
||||||
} memory_addresses_t;
|
} memory_addresses_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t par, pdr;
|
|
||||||
} page_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool is_psw;
|
bool is_psw;
|
||||||
} write_rc_t;
|
} write_rc_t;
|
||||||
|
@ -104,14 +81,11 @@ private:
|
||||||
rl02 *rl02_ { nullptr };
|
rl02 *rl02_ { nullptr };
|
||||||
tty *tty_ { nullptr };
|
tty *tty_ { nullptr };
|
||||||
|
|
||||||
|
mmu *mmu_ { nullptr };
|
||||||
|
|
||||||
int n_pages { DEFAULT_N_PAGES };
|
int n_pages { DEFAULT_N_PAGES };
|
||||||
memory *m { nullptr };
|
memory *m { nullptr };
|
||||||
|
|
||||||
// 8 pages, D/I, 3 modes and 1 invalid mode
|
|
||||||
page_t pages[4][2][8];
|
|
||||||
|
|
||||||
uint16_t MMR0 { 0 }, MMR1 { 0 }, MMR2 { 0 }, MMR3 { 0 }, CPUERR { 0 }, PIR { 0 }, CSR { 0 };
|
|
||||||
|
|
||||||
#if defined(BUILD_FOR_RP2040)
|
#if defined(BUILD_FOR_RP2040)
|
||||||
SemaphoreHandle_t lf_csr_lock { xSemaphoreCreateBinary() };
|
SemaphoreHandle_t lf_csr_lock { xSemaphoreCreateBinary() };
|
||||||
#else
|
#else
|
||||||
|
@ -124,11 +98,6 @@ private:
|
||||||
uint16_t console_switches { 0 };
|
uint16_t console_switches { 0 };
|
||||||
uint16_t console_leds { 0 };
|
uint16_t console_leds { 0 };
|
||||||
|
|
||||||
uint16_t read_pdr (const uint32_t a, const int run_mode, const word_mode_t word_mode, const bool peek_only);
|
|
||||||
uint16_t read_par (const uint32_t a, const int run_mode, const word_mode_t word_mode, const bool peek_only);
|
|
||||||
void write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode);
|
|
||||||
void write_par(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bus();
|
bus();
|
||||||
~bus();
|
~bus();
|
||||||
|
@ -153,9 +122,11 @@ public:
|
||||||
void add_rl02(rl02 *const rl02_);
|
void add_rl02(rl02 *const rl02_);
|
||||||
void add_tty (tty *const tty_);
|
void add_tty (tty *const tty_);
|
||||||
|
|
||||||
cpu *getCpu() { return this->c; }
|
cpu *getCpu() { return c; }
|
||||||
|
|
||||||
tty *getTty() { return this->tty_; }
|
tty *getTty() { return tty_; }
|
||||||
|
|
||||||
|
mmu *getMMU() { return mmu_; }
|
||||||
|
|
||||||
void init(); // invoked by 'RESET' command
|
void init(); // invoked by 'RESET' command
|
||||||
|
|
||||||
|
@ -168,39 +139,24 @@ public:
|
||||||
uint16_t peekWord(const uint16_t a);
|
uint16_t peekWord(const uint16_t a);
|
||||||
|
|
||||||
uint8_t readUnibusByte(const uint32_t a);
|
uint8_t readUnibusByte(const uint32_t a);
|
||||||
|
void writeUnibusByte(const uint32_t a, const uint8_t value);
|
||||||
|
|
||||||
write_rc_t write (const uint16_t a, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t s = i_space);
|
write_rc_t write (const uint16_t a, const word_mode_t word_mode, uint16_t value, const rm_selection_t mode_selection, const d_i_space_t s = i_space);
|
||||||
void writeByte(const uint16_t a, const uint8_t value) { write(a, wm_byte, value, rm_cur); }
|
void writeByte(const uint16_t a, const uint8_t value) { write(a, wm_byte, value, rm_cur); }
|
||||||
void writeWord(const uint16_t a, const uint16_t value, const d_i_space_t s = i_space);
|
void writeWord(const uint16_t a, const uint16_t value, const d_i_space_t s = i_space);
|
||||||
|
|
||||||
uint16_t readPhysical(const uint32_t a);
|
uint16_t readPhysical(const uint32_t a);
|
||||||
void writePhysical(const uint32_t a, const uint16_t value);
|
void writePhysical(const uint32_t a, const uint16_t value);
|
||||||
|
|
||||||
void writeUnibusByte(const uint32_t a, const uint8_t value);
|
|
||||||
|
|
||||||
uint16_t getMMR0() const { return MMR0; }
|
|
||||||
uint16_t getMMR1() const { return MMR1; }
|
|
||||||
uint16_t getMMR2() const { return MMR2; }
|
|
||||||
uint16_t getMMR3() const { return MMR3; }
|
|
||||||
uint16_t getMMR(int nr) const { const uint16_t *const mmrs[] { &MMR0, &MMR1, &MMR2, &MMR3 }; return *mmrs[nr]; }
|
|
||||||
bool isMMR1Locked() const { return !!(MMR0 & 0160000); }
|
|
||||||
void clearMMR1();
|
|
||||||
void addToMMR1(const int8_t delta, const uint8_t reg);
|
|
||||||
void setMMR0(const uint16_t value);
|
|
||||||
void setMMR0Bit(const int bit);
|
|
||||||
void clearMMR0Bit(const int bit);
|
|
||||||
void setMMR2(uint16_t value);
|
|
||||||
|
|
||||||
void check_odd_addressing(const uint16_t a, const int run_mode, const d_i_space_t space, const bool is_write);
|
void check_odd_addressing(const uint16_t a, const int run_mode, const d_i_space_t space, const bool is_write);
|
||||||
void trap_odd(const uint16_t a);
|
void trap_odd(const uint16_t a);
|
||||||
|
|
||||||
uint32_t get_io_base() const { return MMR0 & 1 ? (MMR3 & 16 ? 017760000 : 0760000) : 0160000; }
|
uint32_t get_io_base() const { return mmu_->getMMR0() & 1 ? (mmu_->getMMR3() & 16 ? 017760000 : 0760000) : 0160000; }
|
||||||
bool is_psw(const uint16_t addr, const int run_mode, const d_i_space_t space) const;
|
bool is_psw(const uint16_t addr, const int run_mode, const d_i_space_t space) const;
|
||||||
|
|
||||||
std::pair<trap_action_t, int> get_trap_action(const int run_mode, const bool d, const int apf, const bool is_write);
|
std::pair<trap_action_t, int> get_trap_action(const int run_mode, const bool d, const int apf, const bool is_write);
|
||||||
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 d_i_space_t space);
|
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 d_i_space_t space);
|
||||||
|
|
||||||
bool get_use_data_space(const int run_mode) const;
|
|
||||||
memory_addresses_t calculate_physical_address(const int run_mode, const uint16_t a) const;
|
memory_addresses_t calculate_physical_address(const int run_mode, const uint16_t a) const;
|
||||||
void check_address(const bool trap_on_failure, const bool is_write, const memory_addresses_t & addr, const word_mode_t word_mode, const bool is_data, const int run_mode);
|
void check_address(const bool trap_on_failure, const bool is_write, const memory_addresses_t & addr, const word_mode_t word_mode, const bool is_data, const int run_mode);
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,7 +72,7 @@ int console_ncurses::wait_for_char_ll(const short timeout)
|
||||||
|
|
||||||
void console_ncurses::put_char_ll(const char c)
|
void console_ncurses::put_char_ll(const char c)
|
||||||
{
|
{
|
||||||
if (c >= 32 || (c != 12 && c != 27 && c != 13)) {
|
if ((c >= 32 && c < 127) || c == 10) {
|
||||||
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
||||||
|
|
||||||
wprintw(w_main->win, "%c", c);
|
wprintw(w_main->win, "%c", c);
|
||||||
|
@ -213,22 +213,28 @@ void console_ncurses::panel_update_thread()
|
||||||
werase(w_panel->win);
|
werase(w_panel->win);
|
||||||
}
|
}
|
||||||
|
|
||||||
// speed
|
{
|
||||||
uint64_t cur_instr_cnt = c->get_instructions_executed_count();
|
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
||||||
|
|
||||||
mvwprintw(w_panel->win, 1, 1 + 39, "%8ld", (cur_instr_cnt - prev_instr_cnt) * refresh_rate);
|
// speed
|
||||||
|
uint64_t cur_instr_cnt = c->get_instructions_executed_count();
|
||||||
|
|
||||||
prev_instr_cnt = cur_instr_cnt;
|
mvwprintw(w_panel->win, 1, 1 + 39, "%8ld", (cur_instr_cnt - prev_instr_cnt) * refresh_rate);
|
||||||
|
|
||||||
// ncurses
|
prev_instr_cnt = cur_instr_cnt;
|
||||||
wmove(w_main->win, ty, tx);
|
|
||||||
|
|
||||||
mydoupdate();
|
// ncurses
|
||||||
|
wmove(w_main->win, ty, tx);
|
||||||
|
|
||||||
|
mydoupdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void console_ncurses::refresh_virtual_terminal()
|
void console_ncurses::refresh_virtual_terminal()
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> lck(ncurses_mutex);
|
||||||
|
|
||||||
wclear(w_main->win);
|
wclear(w_main->win);
|
||||||
|
|
||||||
for(int row=0; row<t_height; row++)
|
for(int row=0; row<t_height; row++)
|
||||||
|
|
32
cpu.cpp
32
cpu.cpp
|
@ -460,10 +460,10 @@ void cpu::queue_interrupt(const uint8_t level, const uint8_t vector)
|
||||||
|
|
||||||
void cpu::addToMMR1(const gam_rc_t & g)
|
void cpu::addToMMR1(const gam_rc_t & g)
|
||||||
{
|
{
|
||||||
if (!b->isMMR1Locked() && g.mmr1_update.has_value()) {
|
if (!b->getMMU()->isMMR1Locked() && g.mmr1_update.has_value()) {
|
||||||
assert(g.mmr1_update.value().delta);
|
assert(g.mmr1_update.value().delta);
|
||||||
|
|
||||||
b->addToMMR1(g.mmr1_update.value().delta, g.mmr1_update.value().reg);
|
b->getMMU()->addToMMR1(g.mmr1_update.value().delta, g.mmr1_update.value().reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ gam_rc_t cpu::getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t wo
|
||||||
{
|
{
|
||||||
gam_rc_t g { word_mode, mode_selection, i_space, mode, { }, { }, { }, { } };
|
gam_rc_t g { word_mode, mode_selection, i_space, mode, { }, { }, { }, { } };
|
||||||
|
|
||||||
d_i_space_t isR7_space = reg == 7 ? i_space : (b->get_use_data_space(getPSW_runmode()) ? d_space : i_space);
|
d_i_space_t isR7_space = reg == 7 ? i_space : (b->getMMU()->get_use_data_space(getPSW_runmode()) ? d_space : i_space);
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ always d_space here? TODO
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ always d_space here? TODO
|
||||||
|
|
||||||
g.space = isR7_space;
|
g.space = isR7_space;
|
||||||
|
@ -1737,8 +1737,8 @@ bool cpu::misc_operations(const uint16_t instr)
|
||||||
|
|
||||||
// PUSH link
|
// PUSH link
|
||||||
pushStack(getRegister(link_reg));
|
pushStack(getRegister(link_reg));
|
||||||
if (!b->isMMR1Locked()) {
|
if (!b->getMMU()->isMMR1Locked()) {
|
||||||
b->addToMMR1(-2, 6);
|
b->getMMU()->addToMMR1(-2, 6);
|
||||||
|
|
||||||
addToMMR1(a);
|
addToMMR1(a);
|
||||||
}
|
}
|
||||||
|
@ -1806,7 +1806,7 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
|
||||||
setRegister(6, 04);
|
setRegister(6, 04);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b->clearMMR1();
|
b->getMMU()->clearMMR1();
|
||||||
|
|
||||||
before_psw = getPSW();
|
before_psw = getPSW();
|
||||||
|
|
||||||
|
@ -2343,10 +2343,10 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
|
||||||
work_values_str.push_back(format("%06o", v));
|
work_values_str.push_back(format("%06o", v));
|
||||||
out.insert({ "work-values", work_values_str });
|
out.insert({ "work-values", work_values_str });
|
||||||
|
|
||||||
out.insert({ "MMR0", { format("%06o", b->getMMR0()) } });
|
out.insert({ "MMR0", { format("%06o", b->getMMU()->getMMR0()) } });
|
||||||
out.insert({ "MMR1", { format("%06o", b->getMMR1()) } });
|
out.insert({ "MMR1", { format("%06o", b->getMMU()->getMMR1()) } });
|
||||||
out.insert({ "MMR2", { format("%06o", b->getMMR2()) } });
|
out.insert({ "MMR2", { format("%06o", b->getMMU()->getMMR2()) } });
|
||||||
out.insert({ "MMR3", { format("%06o", b->getMMR3()) } });
|
out.insert({ "MMR3", { format("%06o", b->getMMU()->getMMR3()) } });
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -2355,12 +2355,12 @@ void cpu::step()
|
||||||
{
|
{
|
||||||
it_is_a_trap = false;
|
it_is_a_trap = false;
|
||||||
|
|
||||||
if (!b->isMMR1Locked())
|
if (!b->getMMU()->isMMR1Locked())
|
||||||
b->clearMMR1();
|
b->getMMU()->clearMMR1();
|
||||||
|
|
||||||
if (any_queued_interrupts && execute_any_pending_interrupt()) {
|
if (any_queued_interrupts && execute_any_pending_interrupt()) {
|
||||||
if (!b->isMMR1Locked())
|
if (!b->getMMU()->isMMR1Locked())
|
||||||
b->clearMMR1();
|
b->getMMU()->clearMMR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
instruction_count++;
|
instruction_count++;
|
||||||
|
@ -2368,8 +2368,8 @@ void cpu::step()
|
||||||
try {
|
try {
|
||||||
instruction_start = getPC();
|
instruction_start = getPC();
|
||||||
|
|
||||||
if (!b->isMMR1Locked())
|
if (!b->getMMU()->isMMR1Locked())
|
||||||
b->setMMR2(instruction_start);
|
b->getMMU()->setMMR2(instruction_start);
|
||||||
|
|
||||||
uint16_t instr = b->readWord(instruction_start);
|
uint16_t instr = b->readWord(instruction_start);
|
||||||
|
|
||||||
|
|
32
debugger.cpp
32
debugger.cpp
|
@ -499,27 +499,13 @@ int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool
|
||||||
work_values.c_str()
|
work_values.c_str()
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s (%s), instr: %s: %s - MMR0/1/2/3: %s/%s/%s/%s",
|
result = format("R0: %s, R1: %s, R2: %s, R3: %s, R4: %s, R5: %s, SP: %s, PC: %06o, PSW: %s (%s), instr: %s: %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[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,
|
registers[6].c_str(), pc,
|
||||||
psw.c_str(), data["psw-value"][0].c_str(),
|
psw.c_str(), data["psw-value"][0].c_str(),
|
||||||
instruction_values.c_str(),
|
instruction_values.c_str(),
|
||||||
instruction.c_str(),
|
instruction.c_str()
|
||||||
MMR0.c_str(), MMR1.c_str(), MMR2.c_str(), MMR3.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);
|
||||||
|
@ -530,7 +516,7 @@ int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool
|
||||||
for(auto sp_val : data["sp"])
|
for(auto sp_val : data["sp"])
|
||||||
sp += (sp.empty() ? "" : ",") + sp_val;
|
sp += (sp.empty() ? "" : ",") + sp_val;
|
||||||
|
|
||||||
DOLOG(debug, false, "SP: %s", sp.c_str());
|
DOLOG(debug, false, "SP: %s, MMR0/1/2/3: %s/%s/%s/%s", sp.c_str(), MMR0.c_str(), MMR1.c_str(), MMR2.c_str(), MMR3.c_str());
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (c->getPSW_runmode() == 3) {
|
if (c->getPSW_runmode() == 3) {
|
||||||
|
@ -602,10 +588,10 @@ void dump_range_as_instructions(console *const cnsl, bus *const b, const uint16_
|
||||||
|
|
||||||
void mmu_dump(console *const cnsl, bus *const b, const bool verbose)
|
void mmu_dump(console *const cnsl, bus *const b, const bool verbose)
|
||||||
{
|
{
|
||||||
uint16_t mmr0 = b->getMMR0();
|
uint16_t mmr0 = b->getMMU()->getMMR0();
|
||||||
uint16_t mmr1 = b->getMMR1();
|
uint16_t mmr1 = b->getMMU()->getMMR1();
|
||||||
uint16_t mmr2 = b->getMMR2();
|
uint16_t mmr2 = b->getMMU()->getMMR2();
|
||||||
uint16_t mmr3 = b->getMMR3();
|
uint16_t mmr3 = b->getMMU()->getMMR3();
|
||||||
|
|
||||||
cnsl->put_string_lf(mmr0 & 1 ? "MMU enabled" : "MMU NOT enabled");
|
cnsl->put_string_lf(mmr0 & 1 ? "MMU enabled" : "MMU NOT enabled");
|
||||||
|
|
||||||
|
@ -653,7 +639,7 @@ const char *trap_action_to_str(const trap_action_t ta)
|
||||||
void mmu_resolve(console *const cnsl, bus *const b, const uint16_t va)
|
void mmu_resolve(console *const cnsl, bus *const b, const uint16_t va)
|
||||||
{
|
{
|
||||||
int run_mode = b->getCpu()->getPSW_runmode();
|
int run_mode = b->getCpu()->getPSW_runmode();
|
||||||
cnsl->put_string_lf(format("Run mode: %d, use data space: %d", run_mode, b->get_use_data_space(run_mode)));
|
cnsl->put_string_lf(format("Run mode: %d, use data space: %d", run_mode, b->getMMU()->get_use_data_space(run_mode)));
|
||||||
|
|
||||||
auto data = b->calculate_physical_address(run_mode, va);
|
auto data = b->calculate_physical_address(run_mode, va);
|
||||||
|
|
||||||
|
@ -662,7 +648,7 @@ void mmu_resolve(console *const cnsl, bus *const b, const uint16_t va)
|
||||||
cnsl->put_string_lf(format("Phys. addr. instruction: %08o (psw: %d)", data.physical_instruction, data.physical_instruction_is_psw));
|
cnsl->put_string_lf(format("Phys. addr. instruction: %08o (psw: %d)", data.physical_instruction, data.physical_instruction_is_psw));
|
||||||
cnsl->put_string_lf(format("Phys. addr. data: %08o (psw: %d)", data.physical_data, data.physical_data_is_psw));
|
cnsl->put_string_lf(format("Phys. addr. data: %08o (psw: %d)", data.physical_data, data.physical_data_is_psw));
|
||||||
|
|
||||||
uint16_t mmr3 = b->getMMR3();
|
uint16_t mmr3 = b->getMMU()->getMMR3();
|
||||||
|
|
||||||
if (run_mode == 0) {
|
if (run_mode == 0) {
|
||||||
dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0, data.apf);
|
dump_par_pdr(cnsl, b, ADDR_PDR_K_START, ADDR_PAR_K_START, "kernel i-space", 0, data.apf);
|
||||||
|
|
20
device.h
Normal file
20
device.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
class device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
device() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~device() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
virtual uint8_t readByte(const uint16_t addr) = 0;
|
||||||
|
virtual uint16_t readWord(const uint16_t addr) = 0;
|
||||||
|
|
||||||
|
virtual void writeByte(const uint16_t addr, const uint8_t v) = 0;
|
||||||
|
virtual void writeWord(const uint16_t addr, const uint16_t v) = 0;
|
||||||
|
};
|
6
gen.h
6
gen.h
|
@ -6,3 +6,9 @@
|
||||||
typedef enum { EVENT_NONE = 0, EVENT_HALT, EVENT_INTERRUPT, EVENT_TERMINATE } stop_event_t;
|
typedef enum { EVENT_NONE = 0, EVENT_HALT, EVENT_INTERRUPT, EVENT_TERMINATE } stop_event_t;
|
||||||
|
|
||||||
typedef enum { DT_RK05, DT_RL02, DT_TAPE } disk_type_t;
|
typedef enum { DT_RK05, DT_RL02, DT_TAPE } disk_type_t;
|
||||||
|
|
||||||
|
typedef enum { d_space, i_space } d_i_space_t;
|
||||||
|
|
||||||
|
typedef enum { wm_word = 0, wm_byte = 1 } word_mode_t;
|
||||||
|
|
||||||
|
typedef enum { rm_prev, rm_cur } rm_selection_t;
|
||||||
|
|
|
@ -47,6 +47,8 @@ kw11_l::~kw11_l()
|
||||||
|
|
||||||
void kw11_l::operator()()
|
void kw11_l::operator()()
|
||||||
{
|
{
|
||||||
|
set_thread_name("kek:kw-11l");
|
||||||
|
|
||||||
DOLOG(debug, true, "Starting KW11-L thread");
|
DOLOG(debug, true, "Starting KW11-L thread");
|
||||||
|
|
||||||
while(!stop_flag) {
|
while(!stop_flag) {
|
||||||
|
|
6
log.cpp
6
log.cpp
|
@ -66,7 +66,7 @@ void setloghost(const char *const host, const log_level_t ll)
|
||||||
l_timestamp = false;
|
l_timestamp = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setll(const log_level_t ll_file, const log_level_t ll_screen)
|
void setll(const log_level_t ll_screen, const log_level_t ll_file)
|
||||||
{
|
{
|
||||||
log_level_file = ll_file;
|
log_level_file = ll_file;
|
||||||
log_level_screen = ll_screen;
|
log_level_screen = ll_screen;
|
||||||
|
@ -136,9 +136,9 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
||||||
|
|
||||||
const char *const ll_names[] = { "emerg ", "alert ", "crit ", "error ", "warning", "notice ", "info ", "debug ", "none " };
|
const char *const ll_names[] = { "emerg ", "alert ", "crit ", "error ", "warning", "notice ", "info ", "debug ", "none " };
|
||||||
|
|
||||||
asprintf(&ts_str, "%04d-%02d-%02d %02d:%02d:%02d.%06d] %s ",
|
asprintf(&ts_str, "%04d-%02d-%02d %02d:%02d:%02d.%06d %s|%s] ",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, int(now % 1000000),
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, int(now % 1000000),
|
||||||
ll_names[ll]);
|
ll_names[ll], get_thread_name().c_str());
|
||||||
|
|
||||||
if (ll <= log_level_file && is_file == false)
|
if (ll <= log_level_file && is_file == false)
|
||||||
send_syslog(ll, str);
|
send_syslog(ll, str);
|
||||||
|
|
14
log.h
14
log.h
|
@ -13,7 +13,7 @@ typedef enum { ll_emerg = 0, ll_alert, ll_critical, ll_error, warning, notice, i
|
||||||
log_level_t parse_ll(const std::string & str);
|
log_level_t parse_ll(const std::string & str);
|
||||||
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp);
|
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp);
|
||||||
void setloghost(const char *const host, const log_level_t ll);
|
void setloghost(const char *const host, const log_level_t ll);
|
||||||
void setll(const log_level_t ll_file, const log_level_t ll_screen);
|
void setll(const log_level_t ll_screen, const log_level_t ll_file);
|
||||||
void setloguid(const int uid, const int gid);
|
void setloguid(const int uid, const int gid);
|
||||||
void closelog();
|
void closelog();
|
||||||
void dolog(const log_level_t ll, const char *fmt, ...);
|
void dolog(const log_level_t ll, const char *fmt, ...);
|
||||||
|
@ -21,11 +21,19 @@ void dolog(const log_level_t ll, const char *fmt, ...);
|
||||||
#ifdef TURBO
|
#ifdef TURBO
|
||||||
#define DOLOG(ll, always, fmt, ...) do { } while(0)
|
#define DOLOG(ll, always, fmt, ...) do { } while(0)
|
||||||
#else
|
#else
|
||||||
|
#if defined(ESP32)
|
||||||
#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; \
|
||||||
\
|
\
|
||||||
[[unlikely]] \
|
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)
|
||||||
|
#else
|
||||||
|
#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) [[unlikely]] \
|
||||||
dolog(ll, fmt, ##__VA_ARGS__); \
|
dolog(ll, fmt, ##__VA_ARGS__); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
6
main.cpp
6
main.cpp
|
@ -122,7 +122,7 @@ int run_cpu_validation(const std::string & filename)
|
||||||
{
|
{
|
||||||
json_t *a_mmr0 = json_object_get(test, "mmr0-before");
|
json_t *a_mmr0 = json_object_get(test, "mmr0-before");
|
||||||
assert(a_mmr0);
|
assert(a_mmr0);
|
||||||
b->setMMR0(json_integer_value(a_mmr0));
|
b->getMMU()->setMMR0(json_integer_value(a_mmr0));
|
||||||
}
|
}
|
||||||
|
|
||||||
disassemble(c, nullptr, start_pc, false);
|
disassemble(c, nullptr, start_pc, false);
|
||||||
|
@ -209,7 +209,7 @@ int run_cpu_validation(const std::string & filename)
|
||||||
json_t *a_mmr = json_object_get(test, format("mmr%d-after", r).c_str());
|
json_t *a_mmr = json_object_get(test, format("mmr%d-after", r).c_str());
|
||||||
assert(a_mmr);
|
assert(a_mmr);
|
||||||
uint16_t should_be_mmr = json_integer_value(a_mmr);
|
uint16_t should_be_mmr = json_integer_value(a_mmr);
|
||||||
uint16_t is_mmr = b->getMMR(r);
|
uint16_t is_mmr = b->getMMU()->getMMR(r);
|
||||||
if (should_be_mmr != is_mmr) {
|
if (should_be_mmr != is_mmr) {
|
||||||
int is_d1 = is_mmr >> 11;
|
int is_d1 = is_mmr >> 11;
|
||||||
if (is_d1 & 16)
|
if (is_d1 & 16)
|
||||||
|
@ -263,6 +263,8 @@ int run_cpu_validation(const std::string & filename)
|
||||||
|
|
||||||
void get_metrics(cpu *const c)
|
void get_metrics(cpu *const c)
|
||||||
{
|
{
|
||||||
|
set_thread_name("kek:metrics");
|
||||||
|
|
||||||
uint64_t previous_instruction_count = c->get_instructions_executed_count();
|
uint64_t previous_instruction_count = c->get_instructions_executed_count();
|
||||||
uint64_t previous_ts = get_us();
|
uint64_t previous_ts = get_us();
|
||||||
uint64_t previous_idle_time = c->get_wait_time();
|
uint64_t previous_idle_time = c->get_wait_time();
|
||||||
|
|
222
mmu.cpp
Normal file
222
mmu.cpp
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "gen.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
mmu::mmu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
mmu::~mmu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::reset()
|
||||||
|
{
|
||||||
|
memset(pages, 0x00, sizeof pages);
|
||||||
|
|
||||||
|
CPUERR = MMR0 = MMR1 = MMR2 = MMR3 = PIR = CSR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t mmu::read_pdr(const uint32_t a, const int run_mode)
|
||||||
|
{
|
||||||
|
int page = (a >> 1) & 7;
|
||||||
|
bool is_d = a & 16;
|
||||||
|
uint16_t t = pages[run_mode][is_d][page].pdr;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t mmu::read_par(const uint32_t a, const int run_mode)
|
||||||
|
{
|
||||||
|
int page = (a >> 1) & 7;
|
||||||
|
bool is_d = a & 16;
|
||||||
|
uint16_t t = pages[run_mode][is_d][page].par;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::setMMR0(uint16_t value)
|
||||||
|
{
|
||||||
|
value &= ~(3 << 10); // bit 10 & 11 always read as 0
|
||||||
|
|
||||||
|
if (value & 1)
|
||||||
|
value &= ~(7l << 13); // reset error bits
|
||||||
|
|
||||||
|
if (MMR0 & 0160000) {
|
||||||
|
if ((value & 1) == 0)
|
||||||
|
value &= 254; // bits 7...1 are protected
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO if bit 15/14/13 are set (either of them), then do not modify bit 1...7
|
||||||
|
|
||||||
|
MMR0 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::setMMR0Bit(const int bit)
|
||||||
|
{
|
||||||
|
assert(bit != 10 && bit != 11);
|
||||||
|
assert(bit < 16 && bit >= 0);
|
||||||
|
|
||||||
|
MMR0 |= 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::clearMMR0Bit(const int bit)
|
||||||
|
{
|
||||||
|
assert(bit != 10 && bit != 11);
|
||||||
|
assert(bit < 16 && bit >= 0);
|
||||||
|
|
||||||
|
MMR0 &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::setMMR2(const uint16_t value)
|
||||||
|
{
|
||||||
|
MMR2 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::setMMR3(const uint16_t value)
|
||||||
|
{
|
||||||
|
MMR3 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mmu::get_use_data_space(const int run_mode) const
|
||||||
|
{
|
||||||
|
constexpr const int di_ena_mask[4] = { 4, 2, 0, 1 };
|
||||||
|
|
||||||
|
return !!(MMR3 & di_ena_mask[run_mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::clearMMR1()
|
||||||
|
{
|
||||||
|
MMR1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::addToMMR1(const int8_t delta, const uint8_t reg)
|
||||||
|
{
|
||||||
|
assert(reg >= 0 && reg <= 7);
|
||||||
|
assert(delta >= -2 && delta <= 2);
|
||||||
|
|
||||||
|
assert((getMMR0() & 0160000) == 0); // MMR1 should not be locked
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
// if (MMR1 > 255)
|
||||||
|
// esp_backtrace_print(32);
|
||||||
|
#else
|
||||||
|
if (MMR1 > 255) {
|
||||||
|
extern FILE *lfh;
|
||||||
|
fflush(lfh);
|
||||||
|
}
|
||||||
|
assert(MMR1 < 256);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MMR1 <<= 8;
|
||||||
|
|
||||||
|
MMR1 |= (delta & 31) << 3;
|
||||||
|
MMR1 |= reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode)
|
||||||
|
{
|
||||||
|
bool is_d = a & 16;
|
||||||
|
int page = (a >> 1) & 7;
|
||||||
|
|
||||||
|
if (word_mode == wm_byte) {
|
||||||
|
assert(a != 0 || value < 256);
|
||||||
|
|
||||||
|
update_word(&pages[run_mode][is_d][page].pdr, a & 1, value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pages[run_mode][is_d][page].pdr = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pages[run_mode][is_d][page].pdr &= ~(32768 + 128 /*A*/ + 64 /*W*/ + 32 + 16); // set bit 4, 5 & 15 to 0 as they are unused and A/W are set to 0 by writes
|
||||||
|
|
||||||
|
DOLOG(debug, false, "mmu WRITE-I/O PDR run-mode %d: %c for %d: %o [%d]", run_mode, is_d ? 'D' : 'I', page, value, word_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::write_par(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode)
|
||||||
|
{
|
||||||
|
bool is_d = a & 16;
|
||||||
|
int page = (a >> 1) & 7;
|
||||||
|
|
||||||
|
if (word_mode == wm_byte)
|
||||||
|
update_word(&pages[run_mode][is_d][page].par, a & 1, value);
|
||||||
|
else
|
||||||
|
pages[run_mode][is_d][page].par = value;
|
||||||
|
|
||||||
|
pages[run_mode][is_d][page].pdr &= ~(128 /*A*/ + 64 /*W*/); // reset PDR A/W when PAR is written to
|
||||||
|
|
||||||
|
DOLOG(debug, false, "mmu WRITE-I/O PAR run-mode %d: %c for %d: %o (%07o)", run_mode, is_d ? 'D' : 'I', page, word_mode == wm_byte ? value & 0xff : value, pages[run_mode][is_d][page].par * 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t mmu::readWord(const uint16_t a)
|
||||||
|
{
|
||||||
|
uint16_t v = 0;
|
||||||
|
|
||||||
|
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
|
||||||
|
v = read_pdr(a, 1);
|
||||||
|
else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
|
||||||
|
v = read_par(a, 1);
|
||||||
|
else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
|
||||||
|
v = read_pdr(a, 0);
|
||||||
|
else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
|
||||||
|
v = read_par(a, 0);
|
||||||
|
else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
|
||||||
|
v = read_pdr(a, 3);
|
||||||
|
else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
|
||||||
|
v = read_par(a, 3);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mmu::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::writeWord(const uint16_t a, const uint16_t value)
|
||||||
|
{
|
||||||
|
// supervisor
|
||||||
|
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
|
||||||
|
write_pdr(a, 1, value, wm_word);
|
||||||
|
else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
|
||||||
|
write_par(a, 1, value, wm_word);
|
||||||
|
// kernel
|
||||||
|
else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
|
||||||
|
write_pdr(a, 0, value, wm_word);
|
||||||
|
else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
|
||||||
|
write_par(a, 0, value, wm_word);
|
||||||
|
// user
|
||||||
|
else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
|
||||||
|
write_pdr(a, 3, value, wm_word);
|
||||||
|
else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
|
||||||
|
write_par(a, 3, value, wm_word);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu::writeByte(const uint16_t a, const uint8_t value)
|
||||||
|
{
|
||||||
|
// supervisor
|
||||||
|
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END)
|
||||||
|
write_pdr(a, 1, value, wm_byte);
|
||||||
|
else if (a >= ADDR_PAR_SV_START && a < ADDR_PAR_SV_END)
|
||||||
|
write_par(a, 1, value, wm_byte);
|
||||||
|
// kernel
|
||||||
|
else if (a >= ADDR_PDR_K_START && a < ADDR_PDR_K_END)
|
||||||
|
write_pdr(a, 0, value, wm_byte);
|
||||||
|
else if (a >= ADDR_PAR_K_START && a < ADDR_PAR_K_END)
|
||||||
|
write_par(a, 0, value, wm_byte);
|
||||||
|
// user
|
||||||
|
else if (a >= ADDR_PDR_U_START && a < ADDR_PDR_U_END)
|
||||||
|
write_pdr(a, 3, value, wm_byte);
|
||||||
|
else if (a >= ADDR_PAR_U_START && a < ADDR_PAR_U_END)
|
||||||
|
write_par(a, 3, value, wm_byte);
|
||||||
|
}
|
94
mmu.h
Normal file
94
mmu.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#define ADDR_PDR_SV_START 0172200
|
||||||
|
#define ADDR_PDR_SV_END 0172240
|
||||||
|
#define ADDR_PAR_SV_START 0172240
|
||||||
|
#define ADDR_PAR_SV_END 0172300
|
||||||
|
|
||||||
|
#define ADDR_PDR_K_START 0172300
|
||||||
|
#define ADDR_PDR_K_END 0172340
|
||||||
|
#define ADDR_PAR_K_START 0172340
|
||||||
|
#define ADDR_PAR_K_END 0172400
|
||||||
|
|
||||||
|
#define ADDR_PDR_U_START 0177600
|
||||||
|
#define ADDR_PDR_U_END 0177640
|
||||||
|
#define ADDR_PAR_U_START 0177640
|
||||||
|
#define ADDR_PAR_U_END 0177700
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t par;
|
||||||
|
uint16_t pdr;
|
||||||
|
} page_t;
|
||||||
|
|
||||||
|
class mmu : public device
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// 8 pages, D/I, 3 modes and 1 invalid mode
|
||||||
|
page_t pages[4][2][8];
|
||||||
|
|
||||||
|
uint16_t MMR0 { 0 };
|
||||||
|
uint16_t MMR1 { 0 };
|
||||||
|
uint16_t MMR2 { 0 };
|
||||||
|
uint16_t MMR3 { 0 };
|
||||||
|
uint16_t CPUERR { 0 };
|
||||||
|
uint16_t PIR { 0 };
|
||||||
|
uint16_t CSR { 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
mmu();
|
||||||
|
virtual ~mmu();
|
||||||
|
|
||||||
|
void reset() override;
|
||||||
|
|
||||||
|
bool is_enabled() const { return MMR0 & 1; }
|
||||||
|
bool is_locked() const { return !!(MMR0 & 0160000); }
|
||||||
|
|
||||||
|
void set_page_trapped (const int run_mode, const bool d, const int apf) { pages[run_mode][d][apf].pdr |= 1 << 7; }
|
||||||
|
void set_page_written_to(const int run_mode, const bool d, const int apf) { pages[run_mode][d][apf].pdr |= 1 << 6; }
|
||||||
|
int get_access_control (const int run_mode, const bool d, const int apf) { return pages[run_mode][d][apf].pdr & 7; }
|
||||||
|
int get_pdr_len (const int run_mode, const bool d, const int apf) { return (pages[run_mode][d][apf].pdr >> 8) & 127; }
|
||||||
|
int get_pdr_direction (const int run_mode, const bool d, const int apf) { return pages[run_mode][d][apf].pdr & 8; }
|
||||||
|
uint32_t get_physical_memory_offset(const int run_mode, const bool d, const int apf) const { return pages[run_mode][d][apf].par * 64; }
|
||||||
|
bool get_use_data_space(const int run_mode) const;
|
||||||
|
|
||||||
|
uint16_t getMMR0() const { return MMR0; }
|
||||||
|
uint16_t getMMR1() const { return MMR1; }
|
||||||
|
uint16_t getMMR2() const { return MMR2; }
|
||||||
|
uint16_t getMMR3() const { return MMR3; }
|
||||||
|
uint16_t getMMR(int nr) const { const uint16_t *const mmrs[] { &MMR0, &MMR1, &MMR2, &MMR3 }; return *mmrs[nr]; }
|
||||||
|
|
||||||
|
void setMMR0(const uint16_t value);
|
||||||
|
void setMMR1(const uint16_t value);
|
||||||
|
void setMMR2(const uint16_t value);
|
||||||
|
void setMMR3(const uint16_t value);
|
||||||
|
|
||||||
|
bool isMMR1Locked() const { return !!(MMR0 & 0160000); }
|
||||||
|
void clearMMR1();
|
||||||
|
void addToMMR1(const int8_t delta, const uint8_t reg);
|
||||||
|
|
||||||
|
void setMMR0Bit(const int bit);
|
||||||
|
void clearMMR0Bit(const int bit);
|
||||||
|
|
||||||
|
uint16_t getCPUERR() const { return CPUERR; }
|
||||||
|
void setCPUERR(const uint16_t v) { CPUERR = v; }
|
||||||
|
|
||||||
|
uint16_t getPIR() const { return PIR; };
|
||||||
|
void setPIR(const uint16_t v) { PIR = v; }
|
||||||
|
|
||||||
|
uint16_t read_par(const uint32_t a, const int run_mode);
|
||||||
|
uint16_t read_pdr(const uint32_t a, const int run_mode);
|
||||||
|
|
||||||
|
void write_pdr(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode);
|
||||||
|
void write_par(const uint32_t a, const int run_mode, const uint16_t value, const word_mode_t word_mode);
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
|
uint16_t readWord(const uint16_t addr) override;
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v) override;
|
||||||
|
void writeWord(const uint16_t addr, uint16_t v) override;
|
||||||
|
};
|
2
rk05.cpp
2
rk05.cpp
|
@ -109,7 +109,7 @@ void rk05::writeByte(const uint16_t addr, const uint8_t v)
|
||||||
writeWord(addr, vtemp);
|
writeWord(addr, vtemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rk05::writeWord(const uint16_t addr, uint16_t v)
|
void rk05::writeWord(const uint16_t addr, const uint16_t v)
|
||||||
{
|
{
|
||||||
const int reg = (addr - RK05_BASE) / 2;
|
const int reg = (addr - RK05_BASE) / 2;
|
||||||
|
|
||||||
|
|
15
rk05.h
15
rk05.h
|
@ -9,6 +9,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
#include "disk_backend.h"
|
#include "disk_backend.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@
|
||||||
|
|
||||||
class bus;
|
class bus;
|
||||||
|
|
||||||
class rk05
|
class rk05 : public device
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bus *const b { nullptr };
|
bus *const b { nullptr };
|
||||||
|
@ -36,17 +37,17 @@ private:
|
||||||
std::atomic_bool *const disk_write_acitivity { nullptr };
|
std::atomic_bool *const disk_write_acitivity { nullptr };
|
||||||
|
|
||||||
uint32_t get_bus_address() const;
|
uint32_t get_bus_address() const;
|
||||||
void update_bus_address(const uint16_t v);
|
void update_bus_address(const uint16_t v);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
rk05(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
rk05(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||||
virtual ~rk05();
|
virtual ~rk05();
|
||||||
|
|
||||||
void reset();
|
void reset() override;
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr);
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
uint16_t readWord(const uint16_t addr);
|
uint16_t readWord(const uint16_t addr) override;
|
||||||
|
|
||||||
void writeByte(const uint16_t addr, const uint8_t v);
|
void writeByte(const uint16_t addr, const uint8_t v) override;
|
||||||
void writeWord(const uint16_t addr, uint16_t v);
|
void writeWord(const uint16_t addr, const uint16_t v) override;
|
||||||
};
|
};
|
||||||
|
|
9
rl02.cpp
9
rl02.cpp
|
@ -213,6 +213,15 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
||||||
while(count > 0) {
|
while(count > 0) {
|
||||||
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count);
|
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<cur;) {
|
||||||
|
// BA and MPR are increased by 2
|
||||||
|
xfer_buffer[i++] = b->readUnibusByte(memory_address++);
|
||||||
|
xfer_buffer[i++] = b->readUnibusByte(memory_address++);
|
||||||
|
|
||||||
|
// update_bus_address(memory_address);
|
||||||
|
mpr[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer)) {
|
if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer)) {
|
||||||
DOLOG(ll_error, true, "RL02: write error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector);
|
DOLOG(ll_error, true, "RL02: write error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector);
|
||||||
break;
|
break;
|
||||||
|
|
13
rl02.h
13
rl02.h
|
@ -9,6 +9,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
#include "disk_backend.h"
|
#include "disk_backend.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ constexpr const int rl02_bytes_per_sector = 256;
|
||||||
|
|
||||||
class bus;
|
class bus;
|
||||||
|
|
||||||
class rl02
|
class rl02 : public device
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bus *const b;
|
bus *const b;
|
||||||
|
@ -49,11 +50,11 @@ public:
|
||||||
rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||||
virtual ~rl02();
|
virtual ~rl02();
|
||||||
|
|
||||||
void reset();
|
void reset() override;
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr);
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
uint16_t readWord(const uint16_t addr);
|
uint16_t readWord(const uint16_t addr) override;
|
||||||
|
|
||||||
void writeByte(const uint16_t addr, const uint8_t v);
|
void writeByte(const uint16_t addr, const uint8_t v) override;
|
||||||
void writeWord(const uint16_t addr, const uint16_t v);
|
void writeWord(const uint16_t addr, const uint16_t v) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
.LINK 3326
|
|
||||||
MOV #1000,SP
|
|
||||||
start: MOV #177564,016327
|
|
||||||
|
|
||||||
TRAP 7
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,65 +0,0 @@
|
||||||
; make sure current run-mode is kernel and previous is user
|
|
||||||
MOV #0177776,R0
|
|
||||||
MOV #030000,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; initialize kernel- and user stackpointers
|
|
||||||
; kernel
|
|
||||||
MOV #1000,R6
|
|
||||||
;; user
|
|
||||||
; MOV #0177717,R0
|
|
||||||
; MOV #1000,(R0)
|
|
||||||
|
|
||||||
; user: 060000-080000 will be mapped to physical address 020000
|
|
||||||
MOV #0177646,R0
|
|
||||||
; 020000 / 0100 (0100 => 64 decimal)
|
|
||||||
MOV #0200,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; user: make sure write- and read-access is possible
|
|
||||||
MOV #0177606,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
|
|
||||||
; kernel: flat mapping
|
|
||||||
; 0-010000 -> 0
|
|
||||||
MOV #0172340,R0
|
|
||||||
MOV #0000,(R0)
|
|
||||||
; 060000-0100000 -> 060000
|
|
||||||
MOV #0172346,R0
|
|
||||||
MOV #0600,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; kernel: make sure write- and read-access is possible
|
|
||||||
; 0-010000
|
|
||||||
MOV #0172300,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
; 060000-0100000
|
|
||||||
MOV #0172306,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
|
|
||||||
; place a value at 020000 kernelspace which is
|
|
||||||
; 060000 in userspace
|
|
||||||
MOV #020000,R0
|
|
||||||
MOV #01234,(R0)
|
|
||||||
|
|
||||||
; MRR0
|
|
||||||
MOV #0177572,R0
|
|
||||||
; enable MMU traps
|
|
||||||
BIS #512,(R0)
|
|
||||||
; enable MMU
|
|
||||||
BIS #1,(R0)
|
|
||||||
|
|
||||||
; get word from 060000 in userspace and put that on
|
|
||||||
; the kernel stack
|
|
||||||
MOV #060000,R0
|
|
||||||
MFPI (R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; check for 01234
|
|
||||||
MOV (SP)+,R0
|
|
||||||
CMP #01234,R0
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,62 +0,0 @@
|
||||||
; make sure current run-mode is kernel and previous is user
|
|
||||||
MOV #0177776,R0
|
|
||||||
MOV #030000,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; initialize kernel- and user stackpointers
|
|
||||||
; kernel
|
|
||||||
MOV #1000,R6
|
|
||||||
;; user
|
|
||||||
; MOV #0177717,R0
|
|
||||||
; MOV #1000,(R0)
|
|
||||||
|
|
||||||
; user: 020000-040000 will be mapped to physical address 060000
|
|
||||||
MOV #0177642,R0
|
|
||||||
; 060000 / 0100 (0100 => 64 decimal)
|
|
||||||
MOV #0600,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; user: make sure write- and read-access is possible
|
|
||||||
MOV #0177602,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
|
|
||||||
; kernel: flat mapping
|
|
||||||
; 0-010000 -> 0
|
|
||||||
MOV #0172340,R0
|
|
||||||
MOV #0000,(R0)
|
|
||||||
; 060000-0100000 -> 060000
|
|
||||||
MOV #0172346,R0
|
|
||||||
MOV #0600,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; kernel: make sure write- and read-access is possible
|
|
||||||
; 0-010000
|
|
||||||
MOV #0172300,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
; 060000-0100000
|
|
||||||
MOV #0172306,R0
|
|
||||||
MOV #077406,(R0)
|
|
||||||
|
|
||||||
; MRR0
|
|
||||||
MOV #0177572,R0
|
|
||||||
; enable MMU traps
|
|
||||||
BIS #512,(R0)
|
|
||||||
; enable MMU
|
|
||||||
BIS #1,(R0)
|
|
||||||
|
|
||||||
; write word on stack that will be checked for to be at the
|
|
||||||
; remapped address
|
|
||||||
MOV #01234,-(SP)
|
|
||||||
; this address in kernel space should be 060000 in userspace
|
|
||||||
MOV #020000,R0
|
|
||||||
MTPI (R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
; check for 01234 at 060000 in kernel space
|
|
||||||
MOV #060000,R0
|
|
||||||
CMP #01234,(R0)
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
142
tests/rl02test.mac
Normal file
142
tests/rl02test.mac
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
; this is part of KEK, the PDP11/70 emulator
|
||||||
|
|
||||||
|
.link 1000
|
||||||
|
start:
|
||||||
|
mov #start, sp
|
||||||
|
|
||||||
|
clr r1 ; cyl
|
||||||
|
clr r2 ; head
|
||||||
|
clr r3 ; sector
|
||||||
|
|
||||||
|
write_loop:
|
||||||
|
jsr pc,reg_to_r0
|
||||||
|
jsr pc,set_buffer
|
||||||
|
jsr pc,write_sector
|
||||||
|
jsr pc,next_sector
|
||||||
|
cmp #1,r0
|
||||||
|
beq init_check_loop
|
||||||
|
jmp write_loop
|
||||||
|
|
||||||
|
init_check_loop:
|
||||||
|
clr r1
|
||||||
|
clr r2
|
||||||
|
clr r3
|
||||||
|
|
||||||
|
check_loop:
|
||||||
|
jsr pc,reg_to_r0
|
||||||
|
jsr pc,read_sector
|
||||||
|
jsr pc,chk_buffer
|
||||||
|
cmp #0, r0
|
||||||
|
bne finished_failure
|
||||||
|
jsr pc,next_sector
|
||||||
|
cmp #1, r0
|
||||||
|
beq finished_success
|
||||||
|
jmp check_loop
|
||||||
|
|
||||||
|
finished_success:
|
||||||
|
mov #123,R0
|
||||||
|
halt
|
||||||
|
|
||||||
|
finished_failure:
|
||||||
|
clr R0
|
||||||
|
halt
|
||||||
|
|
||||||
|
write_sector:
|
||||||
|
mov #buffer,0174402 ; bus address
|
||||||
|
mov r0,0174404 ; disk address
|
||||||
|
mov #-0200,0174406 ; word count (128 = 256 bytes)
|
||||||
|
mov #012,0174400 ; go!
|
||||||
|
write_wait:
|
||||||
|
bit #0200,0174400
|
||||||
|
beq write_wait
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
read_sector:
|
||||||
|
mov #buffer,0174402 ; bus address
|
||||||
|
mov r0,0174404 ; disk address
|
||||||
|
mov #-0200,0174406 ; word count (128)
|
||||||
|
mov #014,0174400 ; go!
|
||||||
|
read_wait:
|
||||||
|
bit #0200,0174400
|
||||||
|
beq read_wait
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
set_buffer:
|
||||||
|
; fill allmost all bytes with a pattern unique for this sector
|
||||||
|
mov R0,-(SP)
|
||||||
|
mov R5,-(SP)
|
||||||
|
mov #0125,R0
|
||||||
|
mov #buffer,R5
|
||||||
|
sb_loop:
|
||||||
|
movb r1,(r5)+
|
||||||
|
movb r2,(r5)+
|
||||||
|
movb r3,(r5)+
|
||||||
|
sob r0, sb_loop
|
||||||
|
mov (SP)+,R5
|
||||||
|
mov (SP)+,R0
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
; see if the pattern is (still) there
|
||||||
|
; return 0 if ok, else !0
|
||||||
|
chk_buffer:
|
||||||
|
mov R5,-(SP)
|
||||||
|
mov #0125,R0
|
||||||
|
mov #buffer,R5
|
||||||
|
cb_loop:
|
||||||
|
cmpb r1,(r5)+
|
||||||
|
bne fail
|
||||||
|
cmpb r2,(r5)+
|
||||||
|
bne fail
|
||||||
|
cmpb r3,(r5)+
|
||||||
|
bne fail
|
||||||
|
sob r0, cb_loop
|
||||||
|
fail:
|
||||||
|
mov (SP)+,R5
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
reg_to_r0:
|
||||||
|
mov r4,-(sp)
|
||||||
|
; cylinder
|
||||||
|
mov r1,r4
|
||||||
|
bic #0177000,r4
|
||||||
|
ash #7,r4
|
||||||
|
mov r4,r0
|
||||||
|
; head
|
||||||
|
mov r2,r4
|
||||||
|
bic #0177776,r4
|
||||||
|
ash #6,r4
|
||||||
|
add r4,r0
|
||||||
|
; sector
|
||||||
|
mov r3,r4
|
||||||
|
bic #0177700,r4
|
||||||
|
add r4,r0
|
||||||
|
mov (sp)+,r4
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
; sets r0 to 1 for wrap, else 0
|
||||||
|
next_sector:
|
||||||
|
clr r0
|
||||||
|
; inc sector
|
||||||
|
inc r3
|
||||||
|
; sector 40(dec)?
|
||||||
|
cmp r3,#050
|
||||||
|
blt ns_finished
|
||||||
|
; sector wrap
|
||||||
|
clr r3
|
||||||
|
; next head
|
||||||
|
inc r2
|
||||||
|
cmp r2,#02
|
||||||
|
blt ns_finished
|
||||||
|
clr r2
|
||||||
|
; next track
|
||||||
|
inc r1
|
||||||
|
cmp r1,#01000
|
||||||
|
blt ns_finished
|
||||||
|
clr r1
|
||||||
|
mov #1,r0
|
||||||
|
ns_finished:
|
||||||
|
rts pc
|
||||||
|
|
||||||
|
buffer:
|
||||||
|
; 256 bytes(!) buffer
|
||||||
|
.blkw 0200
|
|
@ -1,50 +0,0 @@
|
||||||
; in simh:
|
|
||||||
; simh> set console telnet=3333
|
|
||||||
; then invoke telnet to port 3333 on the simh systm
|
|
||||||
; simh> load test.bin
|
|
||||||
; simh> run
|
|
||||||
|
|
||||||
|
|
||||||
; initialize stack pointer
|
|
||||||
start: MOV #1000, R6
|
|
||||||
|
|
||||||
; store pointer to text in R0
|
|
||||||
loop: MOV #text, R0
|
|
||||||
CALL printstart
|
|
||||||
JMP loop
|
|
||||||
|
|
||||||
; store copy of R0 on the stack
|
|
||||||
printstart: MOV R0,-(SP)
|
|
||||||
; store PSW (status register) on stack
|
|
||||||
MOV R1,-(SP)
|
|
||||||
MFPS R1
|
|
||||||
MOV R1,-(SP)
|
|
||||||
|
|
||||||
; string ends with 0x00
|
|
||||||
print: TSTB (R0)
|
|
||||||
BEQ pdone
|
|
||||||
|
|
||||||
; put character in tty buffer
|
|
||||||
MOVB (R0), @#TTYTX
|
|
||||||
|
|
||||||
; wait for it to be transmitted
|
|
||||||
waittx: TSTB @#TTYST
|
|
||||||
BPL waittx
|
|
||||||
|
|
||||||
INC R0
|
|
||||||
JMP print
|
|
||||||
|
|
||||||
; retrieve stored r0, r1 and psw from stack
|
|
||||||
pdone: MOV (SP)+,R1
|
|
||||||
MTPS R1
|
|
||||||
MOV (SP)+,R1
|
|
||||||
|
|
||||||
MOV (SP)+,R0
|
|
||||||
RET
|
|
||||||
|
|
||||||
make_raw
|
|
||||||
|
|
||||||
text: .ASCII "test\r\n\x00"
|
|
||||||
|
|
||||||
TTYST = 177564
|
|
||||||
TTYTX = 177566
|
|
|
@ -1,33 +0,0 @@
|
||||||
label: CLC
|
|
||||||
MOV #0.,R0
|
|
||||||
ASR R0 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #0,R1
|
|
||||||
ASRB R1 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #117400,R2
|
|
||||||
ASR R2 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #117400,R3
|
|
||||||
ASRB R3 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #77776,R4
|
|
||||||
ASR R4 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #77776,R5
|
|
||||||
ASRB R5 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,33 +0,0 @@
|
||||||
label: CLC
|
|
||||||
MOV #0.,R0
|
|
||||||
ASL R0 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #0,R1
|
|
||||||
ASLB R1 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #117400,R2
|
|
||||||
ASL R2 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #117400,R3
|
|
||||||
ASLB R3 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #77776,R4
|
|
||||||
ASL R4 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
CLC
|
|
||||||
MOV #77776,R5
|
|
||||||
ASLB R5 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,16 +0,0 @@
|
||||||
mov #1000,SP
|
|
||||||
|
|
||||||
mov #trapfunc, @#034
|
|
||||||
|
|
||||||
traploop: SEC
|
|
||||||
SEN
|
|
||||||
SEV
|
|
||||||
TRAP 0
|
|
||||||
JMP traploop
|
|
||||||
|
|
||||||
trapfunc:
|
|
||||||
NOP
|
|
||||||
NOP
|
|
||||||
RTT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,33 +0,0 @@
|
||||||
label: SEC
|
|
||||||
MOV #0.,R0
|
|
||||||
ROR R0 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #0,R1
|
|
||||||
RORB R1 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #117400,R2
|
|
||||||
ROR R2 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #117400,R3
|
|
||||||
RORB R3 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #1,R4
|
|
||||||
ROR R4 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #1,R5
|
|
||||||
RORB R5 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,33 +0,0 @@
|
||||||
label: SEC
|
|
||||||
MOV #0.,R0
|
|
||||||
ROL R0 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #0,R1
|
|
||||||
ROLB R1 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #117400,R2
|
|
||||||
ROL R2 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #117400,R3
|
|
||||||
ROLB R3 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #1,R4
|
|
||||||
ROL R4 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
SEC
|
|
||||||
MOV #1,R5
|
|
||||||
ROLB R5 ;
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,27 +0,0 @@
|
||||||
label: MOV #0.,R0
|
|
||||||
NEG R0 ; 0
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #0,R1
|
|
||||||
NEGB R1 ; 0
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R2
|
|
||||||
NEG R2 ; 060400
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R3
|
|
||||||
NEGB R3 ; 117400
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #1,R4
|
|
||||||
NEG R4 ; 177777
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #1,R5
|
|
||||||
NEGB R5 ; 000377
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,19 +0,0 @@
|
||||||
label: MOV #0.,R0
|
|
||||||
INC R0
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #0,R1
|
|
||||||
INCB R1
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R2
|
|
||||||
INC R2
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R3
|
|
||||||
INCB R3
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,19 +0,0 @@
|
||||||
label: MOV #0.,R0
|
|
||||||
DEC R0
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #0,R1
|
|
||||||
DECB R1
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R2
|
|
||||||
DEC R2
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R3
|
|
||||||
DECB R3
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,19 +0,0 @@
|
||||||
label: MOV #0.,R0
|
|
||||||
COM R0 ; 65535
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #0,R1
|
|
||||||
COMB R1 ; 255
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R2
|
|
||||||
COM R2 ; 24831
|
|
||||||
NOP
|
|
||||||
|
|
||||||
MOV #117400,R3
|
|
||||||
COMB R3 ; 40959
|
|
||||||
NOP
|
|
||||||
|
|
||||||
HALT
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,8 +0,0 @@
|
||||||
label: MOV #2000,SP
|
|
||||||
NOP
|
|
||||||
INC SP
|
|
||||||
NOP
|
|
||||||
DEC SP
|
|
||||||
NOP
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,5 +0,0 @@
|
||||||
NOP
|
|
||||||
label: .DW 077700
|
|
||||||
NOP
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,4 +0,0 @@
|
||||||
.DW 072527
|
|
||||||
.DW 000000
|
|
||||||
|
|
||||||
make_raw
|
|
|
@ -1,110 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
test_adc:
|
|
||||||
MOV #what_adc,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
; initial value
|
|
||||||
MOV #32769.,R0
|
|
||||||
; number of additions
|
|
||||||
MOV #257.,R1
|
|
||||||
|
|
||||||
test_adc_loop:
|
|
||||||
ADD #1003.,R0
|
|
||||||
ADC R0
|
|
||||||
|
|
||||||
MFPS R2
|
|
||||||
BIC #65520.,R2
|
|
||||||
ADD R2,R0
|
|
||||||
|
|
||||||
DEC R1
|
|
||||||
TST R1
|
|
||||||
BNE test_adc_loop
|
|
||||||
|
|
||||||
CMP #29424.,R0
|
|
||||||
BNE test_adc_failed
|
|
||||||
|
|
||||||
; test 8 bit
|
|
||||||
MOV #32769.,R0
|
|
||||||
MOV #257.,R1
|
|
||||||
|
|
||||||
test_adc_loop8b:
|
|
||||||
ADD #13.,R0
|
|
||||||
ADCB R0
|
|
||||||
|
|
||||||
MFPS R2
|
|
||||||
BIC #65520.,R2
|
|
||||||
ADD R2,R0
|
|
||||||
|
|
||||||
DEC R1
|
|
||||||
TST R1
|
|
||||||
BNE test_adc_loop8b
|
|
||||||
|
|
||||||
CMP #36878.,R0
|
|
||||||
BNE test_adc_failed
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_adc_failed:
|
|
||||||
MOV #adc_fail_text,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
adc_fail_text:
|
|
||||||
.ASCII "ADC handling FAIL\r\n\x00"
|
|
||||||
.EVEN
|
|
||||||
|
|
||||||
test_sbc:
|
|
||||||
; initial value
|
|
||||||
MOV #32769.,R0
|
|
||||||
; number of additions
|
|
||||||
MOV #257.,R1
|
|
||||||
|
|
||||||
test_sbc_loop:
|
|
||||||
SUB #1003.,R0
|
|
||||||
SBC R0
|
|
||||||
|
|
||||||
MFPS R2
|
|
||||||
BIC #65520.,R2
|
|
||||||
SUB R2,R0
|
|
||||||
|
|
||||||
DEC R1
|
|
||||||
TST R1
|
|
||||||
BNE test_sbc_loop
|
|
||||||
|
|
||||||
CMP #36106.,R0
|
|
||||||
BNE test_sbc_failed
|
|
||||||
|
|
||||||
; test 8 bit
|
|
||||||
MOV #32769.,R0
|
|
||||||
MOV #257.,R1
|
|
||||||
|
|
||||||
test_sbc_loop8b:
|
|
||||||
SUB #13.,R0
|
|
||||||
SBCB R0
|
|
||||||
|
|
||||||
MFPS R2
|
|
||||||
BIC #65520.,R2
|
|
||||||
SUB R2,R0
|
|
||||||
|
|
||||||
DEC R1
|
|
||||||
TST R1
|
|
||||||
BNE test_sbc_loop8b
|
|
||||||
|
|
||||||
CMP #28652.,R0
|
|
||||||
BNE test_sbc_failed
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_sbc_failed:
|
|
||||||
MOV #sbc_fail_text,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
sbc_fail_text:
|
|
||||||
.ASCII "SBC handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
what_adc:
|
|
||||||
.ASCII "ADC/SBC test\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
|
@ -1,195 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
test_addr_0:
|
|
||||||
MOV #what_address,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
; address mode 0
|
|
||||||
; b1010101001010101
|
|
||||||
; 16 bit put/get
|
|
||||||
MOV #43605.,R0
|
|
||||||
CMP #43605.,R0
|
|
||||||
BEQ test_addr_0a_ok
|
|
||||||
MOV #1.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_0a_ok:
|
|
||||||
; 8 bit put / 16 bit get, should sign extend
|
|
||||||
MOVB #240.,R0
|
|
||||||
CMP #65520.,R0
|
|
||||||
BEQ test_addr_0b_ok
|
|
||||||
MOV #2.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_0b_ok:
|
|
||||||
; 8 bit put / 16 bit get, should sign extend
|
|
||||||
MOVB #127.,R0
|
|
||||||
CMP #127.,R0
|
|
||||||
BEQ test_addr_0c_ok
|
|
||||||
MOV #3.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_0c_ok:
|
|
||||||
test_addr_1:
|
|
||||||
; address mode 1
|
|
||||||
; indirect get 16 bit
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOV (R0),R1
|
|
||||||
CMP #1234.,R1
|
|
||||||
BEQ test_addr_1a_ok
|
|
||||||
MOV #4.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_1a_ok:
|
|
||||||
; indirect get 8 bit, sign extended
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOVB (R0),R1
|
|
||||||
CMP #65490.,R1
|
|
||||||
BEQ test_addr_1b_ok
|
|
||||||
MOV #5.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_1b_ok:
|
|
||||||
; indirect get 16 bit
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOVB (R0),R1
|
|
||||||
CMP #1234.,R1
|
|
||||||
BNE test_addr_1c_ok
|
|
||||||
MOV #6.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_1c_ok:
|
|
||||||
test_addr_2:
|
|
||||||
; address mode 2
|
|
||||||
; value did not change
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOV (R0)+,R1
|
|
||||||
CMP #1234.,R1
|
|
||||||
BEQ test_addr_2a1_ok
|
|
||||||
MOV #7.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
;
|
|
||||||
test_addr_2a1_ok:
|
|
||||||
; address increased 2 bytes
|
|
||||||
MOV #v1234after,R2
|
|
||||||
CMP R0,R2
|
|
||||||
BEQ test_addr_2a2_ok
|
|
||||||
MOV #8.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_2a2_ok:
|
|
||||||
; value did not change
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOVB (R0)+,R1
|
|
||||||
CMPB #210.,R1
|
|
||||||
BEQ test_addr_2b1_ok
|
|
||||||
MOV #9.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_2b1_ok:
|
|
||||||
; test if this pdp-11 has the hw-bug
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOV (R0)+,R0
|
|
||||||
CMP #1234.,R0
|
|
||||||
BEQ test_addr_2b2_ok
|
|
||||||
MOV #10.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_2b2_ok:
|
|
||||||
test_addr_3:
|
|
||||||
; verify contents of addr1234 first
|
|
||||||
MOV addr1234,r0
|
|
||||||
CMP #1234.,(R0)
|
|
||||||
BEQ test_addr_3b_verify_ok
|
|
||||||
MOV #12.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_3b_verify_ok:
|
|
||||||
MOV @(R0)+,R1
|
|
||||||
MOV #v1234after,R2
|
|
||||||
CMP R0,R2
|
|
||||||
BEQ test_addr_3b2_ok
|
|
||||||
MOV #13.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_3b2_ok:
|
|
||||||
test_addr_4:
|
|
||||||
|
|
||||||
; TODO
|
|
||||||
; address mode 4
|
|
||||||
; value did not change
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOV -(R0),R1
|
|
||||||
CMP #4455.,R1
|
|
||||||
BEQ test_addr_4a1_ok
|
|
||||||
MOV #14.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
;
|
|
||||||
test_addr_4a1_ok:
|
|
||||||
; address drecreased 2 bytes
|
|
||||||
MOV #v4455before,R2
|
|
||||||
CMP R0,R2
|
|
||||||
BEQ test_addr_4a2_ok
|
|
||||||
MOV #15.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_4a2_ok:
|
|
||||||
; value did not change
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOVB -(R0),R1
|
|
||||||
CMPB #17.,R1
|
|
||||||
BEQ test_addr_4a3_ok
|
|
||||||
MOV #16.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_4a3_ok:
|
|
||||||
test_addr_5:
|
|
||||||
; TODO
|
|
||||||
|
|
||||||
|
|
||||||
test_addr_6:
|
|
||||||
MOV #v1234,R0
|
|
||||||
MOV 2(R0),R1
|
|
||||||
CMP #4321.,R1
|
|
||||||
BEQ test_addr_6_ok
|
|
||||||
MOV #17.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_6_ok:
|
|
||||||
test_addr_7:
|
|
||||||
; index deferred
|
|
||||||
MOV #addr1234,R0
|
|
||||||
MOV @2(R0),R1
|
|
||||||
CMP #4321.,R1
|
|
||||||
BEQ test_addr_7_ok
|
|
||||||
MOV #18.,R0
|
|
||||||
JMP test_addr_fail
|
|
||||||
|
|
||||||
test_addr_7_ok:
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_addr_fail:
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
MOV #test_addr_fail_txt,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_addr_fail_txt:
|
|
||||||
.ASCII "addressing handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
what_address:
|
|
||||||
.ASCII "addressing tests\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
||||||
|
|
||||||
v4455before: DW 4455.
|
|
||||||
v1234: DW 1234.
|
|
||||||
v1234after: DW 4321.
|
|
||||||
|
|
||||||
addr1234: DW v1234
|
|
||||||
addr1234after: DW v1234after
|
|
||||||
|
|
||||||
test_addr:
|
|
||||||
CALL test_addr_0
|
|
||||||
RET
|
|
|
@ -1,50 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
test_bge:
|
|
||||||
MOV #what_bge,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
test_bge_1:
|
|
||||||
; initialize flags
|
|
||||||
MOV #8.,R0
|
|
||||||
MTPS R0
|
|
||||||
|
|
||||||
; should not jump
|
|
||||||
BGE test_bge_1_fail
|
|
||||||
JMP test_bge_2
|
|
||||||
|
|
||||||
test_bge_1_fail:
|
|
||||||
MOV #1.,R0
|
|
||||||
JMP test_bge_fail
|
|
||||||
|
|
||||||
test_bge_2:
|
|
||||||
MOV #10.,R0
|
|
||||||
MTPS R0
|
|
||||||
BGE test_bge_2_ok
|
|
||||||
|
|
||||||
MOV #2.,R0
|
|
||||||
JMP test_bge_fail
|
|
||||||
|
|
||||||
test_bge_2_ok:
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_bge_fail:
|
|
||||||
; print test number
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
; flags are always (for this tester) in R2
|
|
||||||
MOV R2,R0
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
MOV #test_bge_fail_txt,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_bge_fail_txt:
|
|
||||||
.ASCII "BGE handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
|
|
||||||
what_bge:
|
|
||||||
.ASCII "BGE test\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
|
@ -1,66 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
test_mov:
|
|
||||||
MOV #what_mov,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
; test if flags are set when moving value
|
|
||||||
|
|
||||||
; clear N, Z, set V and C
|
|
||||||
MOV #3,R0
|
|
||||||
MTPS R0
|
|
||||||
|
|
||||||
MOV #0,R0
|
|
||||||
; get flag-register
|
|
||||||
MFPS R1
|
|
||||||
; mask off upper bits of byte
|
|
||||||
BIC #65520.,R1
|
|
||||||
; only Z and CARRY must be set
|
|
||||||
CMP #5.,R1
|
|
||||||
BEQ test_mov_t1_ok
|
|
||||||
; test 1 failed
|
|
||||||
MOV #1.,R0
|
|
||||||
JMP test_mov_fail
|
|
||||||
|
|
||||||
test_mov_t1_ok:
|
|
||||||
test_mov_t2:
|
|
||||||
; clear all flags
|
|
||||||
MOV #0,R0
|
|
||||||
MTPS R0
|
|
||||||
|
|
||||||
MOV #32768.,R0
|
|
||||||
; get flag-register
|
|
||||||
MFPS R1
|
|
||||||
; mask off upper bits of byte
|
|
||||||
BIC #65520.,R1
|
|
||||||
; only N must be set
|
|
||||||
CMPB #8.,R1
|
|
||||||
BEQ test_mov_t2_ok
|
|
||||||
; test 2 failed
|
|
||||||
MOV #2.,R0
|
|
||||||
JMP test_mov_fail
|
|
||||||
|
|
||||||
test_mov_t2_ok:
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_mov_fail:
|
|
||||||
; print test number
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
; flags are always in R1
|
|
||||||
MOV R1,R0
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
MOV #test_mov_fail_txt,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_mov_fail_txt:
|
|
||||||
.ASCII "MOV handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
|
|
||||||
what_mov:
|
|
||||||
.ASCII "MOV flag test\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
|
@ -1,208 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
psw_store_retrieve:
|
|
||||||
MOV #what_psw,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
; set PSW to all bits set
|
|
||||||
MOV #65535,R1
|
|
||||||
MTPS R1
|
|
||||||
; clear PSW status bits
|
|
||||||
CLC
|
|
||||||
CLV
|
|
||||||
CLZ
|
|
||||||
CLN
|
|
||||||
; retrieve PSW and verify the flags are 0
|
|
||||||
MFPS R2
|
|
||||||
|
|
||||||
; clear currently non-relevant psw-bits
|
|
||||||
BIC #240.,R2
|
|
||||||
|
|
||||||
TSTB R2
|
|
||||||
BNE psw_store_retrieve_fail
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
psw_store_retrieve_fail:
|
|
||||||
MOV R2,R0
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
MOV #psw_store_retrieve_fail_text, R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
clear_flags:
|
|
||||||
CLC
|
|
||||||
CLV
|
|
||||||
CLZ
|
|
||||||
CLN
|
|
||||||
RET
|
|
||||||
|
|
||||||
psw_flags_trigger:
|
|
||||||
; test zero bit
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #32768.,R1
|
|
||||||
TSTB R1
|
|
||||||
BEQ psw_trigger_1_next
|
|
||||||
; store test number
|
|
||||||
MOV #1.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_1_next:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #128.,R1
|
|
||||||
TSTB R1
|
|
||||||
BNE psw_trigger_2_next
|
|
||||||
MOV #2.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_2_next:
|
|
||||||
CALL clear_flags
|
|
||||||
; test overflow bit (overflow)
|
|
||||||
MOV #127.,R1
|
|
||||||
INCB R1
|
|
||||||
BVS psw_trigger_3_next
|
|
||||||
MOV #3.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
; test overflow bit (underflow)
|
|
||||||
psw_trigger_3_next:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #-128.,R1
|
|
||||||
DECB R1
|
|
||||||
BVS psw_trigger_4_next
|
|
||||||
MOV #4.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_4_next:
|
|
||||||
CALL clear_flags
|
|
||||||
; test minus bit
|
|
||||||
MOV #127.,R1
|
|
||||||
INCB R1
|
|
||||||
BMI psw_trigger_5_next
|
|
||||||
MOV #5.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_5_next:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #128.,R1
|
|
||||||
DECB R1
|
|
||||||
BPL psw_trigger_6_next
|
|
||||||
MOV #6.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_6_next:
|
|
||||||
CALL clear_flags
|
|
||||||
; carry flag test
|
|
||||||
MOV #128.,R1
|
|
||||||
ASLB R1
|
|
||||||
BCS psw_trigger_7_next
|
|
||||||
MOV #7.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_7_next:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #64.,R1
|
|
||||||
ASLB R1
|
|
||||||
BCC psw_trigger_8_next
|
|
||||||
MOV #8.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_8_next:
|
|
||||||
; 16 bit tests
|
|
||||||
|
|
||||||
; test zero bit
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #0,R1
|
|
||||||
TST R1
|
|
||||||
BEQ psw_trigger_1_next16b
|
|
||||||
; store test number
|
|
||||||
MOV #9.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_1_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #32768.,R1
|
|
||||||
TST R1
|
|
||||||
BNE psw_trigger_2_next16b
|
|
||||||
MOV #10.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_2_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
; test overflow bit (overflow)
|
|
||||||
MOV #32767.,R1
|
|
||||||
INC R1
|
|
||||||
BVS psw_trigger_3_next16b
|
|
||||||
MOV #11.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
; test overflow bit (underflow)
|
|
||||||
psw_trigger_3_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #-32768.,R1
|
|
||||||
DEC R1
|
|
||||||
BVS psw_trigger_4_next16b
|
|
||||||
MOV #12.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_4_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
; test minus bit
|
|
||||||
MOV #32767.,R1
|
|
||||||
INC R1
|
|
||||||
BMI psw_trigger_5_next16b
|
|
||||||
MOV #13.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_5_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #32768.,R1
|
|
||||||
DEC R1
|
|
||||||
BPL psw_trigger_6_next16b
|
|
||||||
MOV #14.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_6_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
; carry flag test
|
|
||||||
MOV #32768.,R1
|
|
||||||
ASL R1
|
|
||||||
BCS psw_trigger_7_next16b
|
|
||||||
MOV #15.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_7_next16b:
|
|
||||||
CALL clear_flags
|
|
||||||
MOV #16384.,R1
|
|
||||||
ASL R1
|
|
||||||
BCC psw_trigger_8_next16b
|
|
||||||
MOV #16.,R2
|
|
||||||
JMP psw_trigger_fail
|
|
||||||
|
|
||||||
psw_trigger_8_next16b:
|
|
||||||
RET
|
|
||||||
|
|
||||||
psw_trigger_fail:
|
|
||||||
CALL clear_flags
|
|
||||||
; emit test number
|
|
||||||
MOV R2,R0
|
|
||||||
CALL print_binary
|
|
||||||
; emit flags
|
|
||||||
MFPS R0
|
|
||||||
CALL print_binary
|
|
||||||
; emit text
|
|
||||||
MOV #psw_trigger_fail_text,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
psw_store_retrieve_fail_text:
|
|
||||||
.ASCII "MFPS / MTPS handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
psw_trigger_fail_text:
|
|
||||||
.ASCII "PSW trigger fail\r\n\x00"
|
|
||||||
|
|
||||||
what_psw:
|
|
||||||
.ASCII "PSW handling test\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
|
@ -1,66 +0,0 @@
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
test_tst:
|
|
||||||
MOV #what_tst,R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
test_tst_1:
|
|
||||||
; initialize flags
|
|
||||||
MOV #15.,R0
|
|
||||||
MTPS R0
|
|
||||||
|
|
||||||
; test TST when value is 0
|
|
||||||
MOV #0,R1
|
|
||||||
TST R1
|
|
||||||
; retrieve flags
|
|
||||||
MFPS R2
|
|
||||||
; mask off upper bits of byte
|
|
||||||
BIC #65520.,R2
|
|
||||||
CMP #4.,R2
|
|
||||||
BEQ test_tst_1_ok
|
|
||||||
|
|
||||||
MOV #1.,R0
|
|
||||||
JMP test_tst_fail
|
|
||||||
|
|
||||||
test_tst_1_ok:
|
|
||||||
test_tst_2:
|
|
||||||
; initialize flags
|
|
||||||
MOV #15.,R0
|
|
||||||
MTPS R0
|
|
||||||
|
|
||||||
; test TST when value is !0
|
|
||||||
MOV #32768.,R1
|
|
||||||
TST R1
|
|
||||||
; retrieve flags
|
|
||||||
MFPS R2
|
|
||||||
; mask off upper bits of byte
|
|
||||||
BIC #65520.,R2
|
|
||||||
CMP #8.,R2
|
|
||||||
BEQ test_tst_2_ok
|
|
||||||
|
|
||||||
MOV #2.,R0
|
|
||||||
JMP test_tst_fail
|
|
||||||
|
|
||||||
test_tst_2_ok:
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_tst_fail:
|
|
||||||
; print test number
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
; flags are always (for this tester) in R2
|
|
||||||
MOV R2,R0
|
|
||||||
CALL print_binary
|
|
||||||
|
|
||||||
MOV #test_tst_fail_txt,R0
|
|
||||||
CALL print_start
|
|
||||||
RET
|
|
||||||
|
|
||||||
test_tst_fail_txt:
|
|
||||||
.ASCII "TST handling FAIL\r\n\x00"
|
|
||||||
|
|
||||||
|
|
||||||
what_tst:
|
|
||||||
.ASCII "TST test\r\n\x00"
|
|
||||||
|
|
||||||
.EVEN
|
|
121
tests/tester.mac
121
tests/tester.mac
|
@ -1,121 +0,0 @@
|
||||||
; in simh:
|
|
||||||
; simh> set console telnet=3333
|
|
||||||
; then invoke telnet to port 3333 on the simh systm
|
|
||||||
; simh> load test.bin
|
|
||||||
; simh> run
|
|
||||||
|
|
||||||
.EXTERN ALL
|
|
||||||
|
|
||||||
; initialize stack pointer
|
|
||||||
start: MOV #1000, R6
|
|
||||||
JMP go
|
|
||||||
|
|
||||||
.INCLUDE "tester-psw.mac"
|
|
||||||
.INCLUDE "tester-adc-sbc.mac"
|
|
||||||
.INCLUDE "tester-addressing.mac"
|
|
||||||
.INCLUDE "tester-mov.mac"
|
|
||||||
.INCLUDE "tester-tst.mac"
|
|
||||||
.INCLUDE "tester-bge.mac"
|
|
||||||
|
|
||||||
go: MOV #textstart, R0
|
|
||||||
CALL print_start
|
|
||||||
|
|
||||||
CALL psw_store_retrieve
|
|
||||||
|
|
||||||
CALL psw_flags_trigger
|
|
||||||
|
|
||||||
CALL test_adc
|
|
||||||
|
|
||||||
CALL test_sbc
|
|
||||||
|
|
||||||
CALL test_addr
|
|
||||||
|
|
||||||
CALL test_mov
|
|
||||||
|
|
||||||
CALL test_tst
|
|
||||||
|
|
||||||
CALL test_bge
|
|
||||||
|
|
||||||
MOV #textfin, R0
|
|
||||||
CALL print_start
|
|
||||||
TRAP 7
|
|
||||||
|
|
||||||
; store copy of R0 on the stack
|
|
||||||
print_start: MOV R0,-(SP)
|
|
||||||
; store PSW (status register) on stack
|
|
||||||
MFPS -(SP)
|
|
||||||
|
|
||||||
; string ends with 0x00
|
|
||||||
print: TSTB (R0)
|
|
||||||
BEQ pdone
|
|
||||||
|
|
||||||
; put character in tty buffer
|
|
||||||
MOVB (R0), @#TTYTX
|
|
||||||
|
|
||||||
; wait for it to be transmitted
|
|
||||||
waittx: TSTB @#TTYST
|
|
||||||
BPL waittx
|
|
||||||
|
|
||||||
INC R0
|
|
||||||
JMP print
|
|
||||||
|
|
||||||
; retrieve stored r0, r1 and psw from stack
|
|
||||||
pdone: MTPS (SP)+
|
|
||||||
|
|
||||||
MOV (SP)+,R0
|
|
||||||
RET
|
|
||||||
|
|
||||||
print_binary:
|
|
||||||
MFPS -(SP)
|
|
||||||
MOV R0,-(SP)
|
|
||||||
MOV R1,-(SP)
|
|
||||||
; 16 bits in a word
|
|
||||||
MOV #16.,R1
|
|
||||||
|
|
||||||
print_bit:
|
|
||||||
ASL R0
|
|
||||||
BCS print_1
|
|
||||||
waittx0:
|
|
||||||
TSTB @#TTYST
|
|
||||||
BPL waittx0
|
|
||||||
MOVB #48., @#TTYTX
|
|
||||||
BR print_next_bit
|
|
||||||
print_1:
|
|
||||||
waittx1:
|
|
||||||
TSTB @#TTYST
|
|
||||||
BPL waittx1
|
|
||||||
MOVB #49., @#TTYTX
|
|
||||||
BR print_next_bit
|
|
||||||
|
|
||||||
print_next_bit:
|
|
||||||
; keep track of the number of bits emitted
|
|
||||||
DEC R1
|
|
||||||
TST R1
|
|
||||||
BNE print_bit
|
|
||||||
|
|
||||||
; emit seperator
|
|
||||||
bit_seperator:
|
|
||||||
TSTB @#TTYST
|
|
||||||
BPL bit_seperator
|
|
||||||
MOVB #32., @#TTYTX
|
|
||||||
; for some reason the last character is not printed in simh unless repeated
|
|
||||||
bit_seperator2:
|
|
||||||
TSTB @#TTYST
|
|
||||||
BPL bit_seperator2
|
|
||||||
MOVB #32., @#TTYTX
|
|
||||||
|
|
||||||
MOV (SP)+,R1
|
|
||||||
MOV (SP)+,R0
|
|
||||||
MTPS (SP)+
|
|
||||||
RET
|
|
||||||
|
|
||||||
make_raw
|
|
||||||
|
|
||||||
textstart: .ASCII "tester running...\r\n\x00"
|
|
||||||
textfin: .ASCII "tester finished\r\n\x00"
|
|
||||||
.EVEN
|
|
||||||
|
|
||||||
textbuffer: .BLKB 256.
|
|
||||||
|
|
||||||
TTYST = 177564
|
|
||||||
TTYTX = 177566
|
|
17
tm-11.h
17
tm-11.h
|
@ -1,4 +1,4 @@
|
||||||
// (C) 2018-2023 by Folkert van Heusden
|
// (C) 2018-2024 by Folkert van Heusden
|
||||||
// Released under MIT license
|
// Released under MIT license
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -7,6 +7,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
#define TM_11_MTS 0172520 // status register
|
#define TM_11_MTS 0172520 // status register
|
||||||
#define TM_11_MTC 0172522 // command register
|
#define TM_11_MTC 0172522 // command register
|
||||||
#define TM_11_MTBRC 0172524 // byte record counter
|
#define TM_11_MTBRC 0172524 // byte record counter
|
||||||
|
@ -16,9 +18,10 @@
|
||||||
#define TM_11_BASE TM_11_MTS
|
#define TM_11_BASE TM_11_MTS
|
||||||
#define TM_11_END (TM_11_MTRD + 2)
|
#define TM_11_END (TM_11_MTRD + 2)
|
||||||
|
|
||||||
|
|
||||||
class memory;
|
class memory;
|
||||||
|
|
||||||
class tm_11
|
class tm_11 : public device
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
memory *const m { nullptr };
|
memory *const m { nullptr };
|
||||||
|
@ -31,11 +34,11 @@ public:
|
||||||
tm_11(const std::string & file, memory *const m);
|
tm_11(const std::string & file, memory *const m);
|
||||||
virtual ~tm_11();
|
virtual ~tm_11();
|
||||||
|
|
||||||
void reset();
|
void reset() override;
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr);
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
uint16_t readWord(const uint16_t addr);
|
uint16_t readWord(const uint16_t addr) override;
|
||||||
|
|
||||||
void writeByte(const uint16_t addr, const uint8_t v);
|
void writeByte(const uint16_t addr, const uint8_t v) override;
|
||||||
void writeWord(const uint16_t addr, uint16_t v);
|
void writeWord(const uint16_t addr, uint16_t v) override;
|
||||||
};
|
};
|
||||||
|
|
2
tty.cpp
2
tty.cpp
|
@ -130,6 +130,8 @@ uint16_t tty::readWord(const uint16_t addr)
|
||||||
|
|
||||||
void tty::operator()()
|
void tty::operator()()
|
||||||
{
|
{
|
||||||
|
set_thread_name("kek:tty");
|
||||||
|
|
||||||
while(!stop_flag) {
|
while(!stop_flag) {
|
||||||
if (c->poll_char()) {
|
if (c->poll_char()) {
|
||||||
#if defined(BUILD_FOR_RP2040)
|
#if defined(BUILD_FOR_RP2040)
|
||||||
|
|
12
utils.cpp
12
utils.cpp
|
@ -163,6 +163,18 @@ void set_thread_name(std::string name)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_thread_name()
|
||||||
|
{
|
||||||
|
#ifdef linux
|
||||||
|
char buffer[16 + 1] { };
|
||||||
|
pthread_getname_np(pthread_self(), buffer, sizeof buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
#else
|
||||||
|
return pcTaskGetName(xTaskGetCurrentTaskHandle());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t WRITE(int fd, const char *whereto, size_t len)
|
ssize_t WRITE(int fd, const char *whereto, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t cnt=0;
|
ssize_t cnt=0;
|
||||||
|
|
1
utils.h
1
utils.h
|
@ -18,6 +18,7 @@ unsigned long get_ms();
|
||||||
uint64_t get_us();
|
uint64_t get_us();
|
||||||
void myusleep(uint64_t us);
|
void myusleep(uint64_t us);
|
||||||
|
|
||||||
|
std::string get_thread_name();
|
||||||
void set_thread_name(std::string name);
|
void set_thread_name(std::string name);
|
||||||
|
|
||||||
ssize_t WRITE(int fd, const char *whereto, size_t len);
|
ssize_t WRITE(int fd, const char *whereto, size_t len);
|
||||||
|
|
Loading…
Add table
Reference in a new issue