Merge branch 'master' into psram
This commit is contained in:
commit
b1c1a75208
36 changed files with 316 additions and 205 deletions
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
||||||
if: ${{ matrix.language == 'cpp' }}
|
if: ${{ matrix.language == 'cpp' }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install --yes libncurses-dev
|
sudo apt-get install --yes libncurses-dev libjansson-dev
|
||||||
|
|
||||||
- name: Configure (cpp)
|
- name: Configure (cpp)
|
||||||
if: ${{ matrix.language == 'cpp' }}
|
if: ${{ matrix.language == 'cpp' }}
|
||||||
|
|
|
@ -6,8 +6,10 @@ cmake_minimum_required(VERSION 3.9)
|
||||||
|
|
||||||
add_compile_options(-Wall -pedantic -Wextra)
|
add_compile_options(-Wall -pedantic -Wextra)
|
||||||
|
|
||||||
#add_compile_options(-fsanitize=address)
|
#add_compile_options(-fsanitize=undefined)
|
||||||
#add_link_options(-fsanitize=address)
|
#add_link_options(-fsanitize=undefined)
|
||||||
|
|
||||||
|
#add_compile_options(-fanalyzer)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
|
@ -72,7 +72,6 @@ void console_esp32::panel_update_thread()
|
||||||
pixels.begin();
|
pixels.begin();
|
||||||
|
|
||||||
pixels.clear();
|
pixels.clear();
|
||||||
|
|
||||||
pixels.show();
|
pixels.show();
|
||||||
|
|
||||||
constexpr uint8_t brightness = 16;
|
constexpr uint8_t brightness = 16;
|
||||||
|
@ -103,7 +102,7 @@ void console_esp32::panel_update_thread()
|
||||||
pixels.clear();
|
pixels.clear();
|
||||||
pixels.show();
|
pixels.show();
|
||||||
|
|
||||||
for(;;) {
|
while(!stop_panel) {
|
||||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -141,5 +140,10 @@ void console_esp32::panel_update_thread()
|
||||||
put_string_lf("Unknown exception in panel thread");
|
put_string_lf("Unknown exception in panel thread");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixels.clear();
|
||||||
|
pixels.show();
|
||||||
|
|
||||||
|
Serial.println(F("panel task terminating"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ESP32)
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SHA2017)
|
#if defined(SHA2017)
|
||||||
#include "console_shabadge.h"
|
#include "console_shabadge.h"
|
||||||
|
@ -70,14 +73,13 @@ std::atomic_bool *running { nullptr };
|
||||||
|
|
||||||
bool trace_output { false };
|
bool trace_output { false };
|
||||||
|
|
||||||
std::vector<disk_backend *> rk05_files;
|
|
||||||
std::vector<disk_backend *> rl02_files;
|
|
||||||
|
|
||||||
void console_thread_wrapper_panel(void *const c)
|
void console_thread_wrapper_panel(void *const c)
|
||||||
{
|
{
|
||||||
console *const cnsl = reinterpret_cast<console *>(c);
|
console *const cnsl = reinterpret_cast<console *>(c);
|
||||||
|
|
||||||
cnsl->panel_update_thread();
|
cnsl->panel_update_thread();
|
||||||
|
|
||||||
|
vTaskSuspend(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t load_serial_speed_configuration()
|
uint32_t load_serial_speed_configuration()
|
||||||
|
@ -208,6 +210,14 @@ void set_tty_serial_speed(console *const c, const uint32_t bps)
|
||||||
c->put_string_lf("Failed to store configuration file with serial settings");
|
c->put_string_lf("Failed to store configuration file with serial settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name)
|
||||||
|
{
|
||||||
|
printf("%s was called but failed to allocate %d bytes with 0x%X capabilities\r\n", function_name, requested_size, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
@ -222,6 +232,10 @@ void setup() {
|
||||||
Serial.print(F("Size of int: "));
|
Serial.print(F("Size of int: "));
|
||||||
Serial.println(sizeof(int));
|
Serial.println(sizeof(int));
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
heap_caps_register_failed_alloc_callback(heap_caps_alloc_failed_hook);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_FOR_RP2040)
|
#if !defined(BUILD_FOR_RP2040)
|
||||||
Serial.print(F("CPU clock frequency (MHz): "));
|
Serial.print(F("CPU clock frequency (MHz): "));
|
||||||
Serial.println(getCpuFrequencyMhz());
|
Serial.println(getCpuFrequencyMhz());
|
||||||
|
@ -296,13 +310,19 @@ void setup() {
|
||||||
cnsl = new console_esp32(&stop_event, serial_ports, 80, 25);
|
cnsl = new console_esp32(&stop_event, serial_ports, 80, 25);
|
||||||
#endif
|
#endif
|
||||||
cnsl->set_bus(b);
|
cnsl->set_bus(b);
|
||||||
|
cnsl->begin();
|
||||||
|
|
||||||
running = cnsl->get_running_flag();
|
running = cnsl->get_running_flag();
|
||||||
|
|
||||||
Serial.println(F("Connect RK05 and RL02 to BUS"));
|
Serial.println(F("Connect RK05 and RL02 devices to BUS"));
|
||||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
auto rk05_dev = new rk05(b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag());
|
||||||
|
rk05_dev->begin();
|
||||||
|
b->add_rk05(rk05_dev);
|
||||||
|
|
||||||
|
auto rl02_dev = new rl02(b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag());
|
||||||
|
rl02_dev->begin();
|
||||||
|
b->add_rl02(rl02_dev);
|
||||||
|
|
||||||
b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
|
||||||
|
|
||||||
Serial.println(F("Init TTY"));
|
Serial.println(F("Init TTY"));
|
||||||
tty_ = new tty(cnsl, b);
|
tty_ = new tty(cnsl, b);
|
||||||
|
@ -311,7 +331,7 @@ void setup() {
|
||||||
|
|
||||||
#if !defined(BUILD_FOR_RP2040) // FIXME: led ring
|
#if !defined(BUILD_FOR_RP2040) // FIXME: led ring
|
||||||
Serial.println(F("Starting panel"));
|
Serial.println(F("Starting panel"));
|
||||||
xTaskCreate(&console_thread_wrapper_panel, "panel", 2048, cnsl, 1, nullptr);
|
xTaskCreate(&console_thread_wrapper_panel, "panel", 3072, cnsl, 1, nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BUILD_FOR_RP2040)
|
#if !defined(BUILD_FOR_RP2040)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
|
|
||||||
import json
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def get_git_hash():
|
def get_git_hash():
|
||||||
|
@ -12,6 +10,7 @@ def get_git_hash():
|
||||||
ret = subprocess.run(["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE, text=True)
|
ret = subprocess.run(["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE, text=True)
|
||||||
return ret.stdout.strip() + add
|
return ret.stdout.strip() + add
|
||||||
|
|
||||||
|
|
||||||
fh = open('version.cpp', 'w')
|
fh = open('version.cpp', 'w')
|
||||||
fh.write('const char *version_str = "' + get_git_hash() + '";\n')
|
fh.write('const char *version_str = "' + get_git_hash() + '";\n')
|
||||||
fh.close()
|
fh.close()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../win32.cpp
|
|
|
@ -1 +0,0 @@
|
||||||
../win32.h
|
|
|
@ -11,6 +11,7 @@ To build for e.g. linux:
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
* libncursesw5-dev
|
* libncursesw5-dev
|
||||||
|
* libjansson-dev
|
||||||
|
|
||||||
To build for e.g. windows:
|
To build for e.g. windows:
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ std::optional<std::string> breakpoint_memory::is_triggered() const
|
||||||
if (it == values.end())
|
if (it == values.end())
|
||||||
return { };
|
return { };
|
||||||
|
|
||||||
return format("MEM%c%c[%08a]=%06o", word_mode == wm_byte ? 'B' : 'W', is_virtual ? 'V' : 'P', addr, v);
|
return format("MEM%c%c[%08o]=%06o", word_mode == wm_byte ? 'B' : 'W', is_virtual ? 'V' : 'P', addr, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<breakpoint_memory *, std::optional<std::string> > breakpoint_memory::parse(bus *const b, const std::string & in)
|
std::pair<breakpoint_memory *, std::optional<std::string> > breakpoint_memory::parse(bus *const b, const std::string & in)
|
||||||
|
@ -41,7 +41,7 @@ std::pair<breakpoint_memory *, std::optional<std::string> > breakpoint_memory::p
|
||||||
return { nullptr, "memory: key or value missing" };
|
return { nullptr, "memory: key or value missing" };
|
||||||
|
|
||||||
auto values_in = parts.at(1);
|
auto values_in = parts.at(1);
|
||||||
auto v_parts = split(values_in, ",");
|
auto v_parts = split(std::move(values_in), ",");
|
||||||
std::set<uint16_t> values;
|
std::set<uint16_t> values;
|
||||||
for(auto & v: v_parts)
|
for(auto & v: v_parts)
|
||||||
values.insert(std::stoi(v, nullptr, 8));
|
values.insert(std::stoi(v, nullptr, 8));
|
||||||
|
|
|
@ -101,12 +101,12 @@ std::pair<breakpoint_register *, std::optional<std::string> > breakpoint_registe
|
||||||
else if (key == "PC" || key == "pc") {
|
else if (key == "PC" || key == "pc") {
|
||||||
return { new breakpoint_register(b, 7, values), { } };
|
return { new breakpoint_register(b, 7, values), { } };
|
||||||
}
|
}
|
||||||
else if (key.substr(0, 3) == "MMR" or key.substr(0, 3) == "mmr") {
|
else if (key.substr(0, 3) == "MMR" || key.substr(0, 3) == "mmr") {
|
||||||
int which = key[3] - '0';
|
int which = key[3] - '0';
|
||||||
|
|
||||||
return { new breakpoint_register(b, hr_mmr0 + which, values), { } };
|
return { new breakpoint_register(b, hr_mmr0 + which, values), { } };
|
||||||
}
|
}
|
||||||
else if (key.substr(0, 3) == "PSW" or key.substr(0, 3) == "psw") {
|
else if (key.substr(0, 3) == "PSW" || key.substr(0, 3) == "psw") {
|
||||||
return { new breakpoint_register(b, hr_psw, values), { } };
|
return { new breakpoint_register(b, hr_psw, values), { } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
bus.cpp
30
bus.cpp
|
@ -24,6 +24,7 @@
|
||||||
bus::bus()
|
bus::bus()
|
||||||
{
|
{
|
||||||
mmu_ = new mmu();
|
mmu_ = new mmu();
|
||||||
|
mmu_->begin();
|
||||||
|
|
||||||
kw11_l_ = new kw11_l(this);
|
kw11_l_ = new kw11_l(this);
|
||||||
|
|
||||||
|
@ -65,7 +66,10 @@ json_t *bus::serialize() const
|
||||||
if (rl02_)
|
if (rl02_)
|
||||||
json_object_set(j_out, "rl02", rl02_->serialize());
|
json_object_set(j_out, "rl02", rl02_->serialize());
|
||||||
|
|
||||||
// TODO: rk05, tm11
|
if (rk05_)
|
||||||
|
json_object_set(j_out, "rk05", rk05_->serialize());
|
||||||
|
|
||||||
|
// TODO: tm11
|
||||||
|
|
||||||
return j_out;
|
return j_out;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +116,13 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_ui
|
||||||
b->add_rl02(rl02_);
|
b->add_rl02(rl02_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rk05, tm11
|
temp = json_object_get(j, "rk05");
|
||||||
|
if (temp) {
|
||||||
|
rk05 *rk05_ = rk05::deserialize(temp, b);
|
||||||
|
b->add_rk05(rk05_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: tm11
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
@ -120,8 +130,6 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_ui
|
||||||
|
|
||||||
void bus::set_memory_size(const int n_pages)
|
void bus::set_memory_size(const int n_pages)
|
||||||
{
|
{
|
||||||
this->n_pages = n_pages;
|
|
||||||
|
|
||||||
uint32_t n_bytes = n_pages * 8192l;
|
uint32_t n_bytes = n_pages * 8192l;
|
||||||
|
|
||||||
delete m;
|
delete m;
|
||||||
|
@ -474,7 +482,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
}
|
}
|
||||||
|
|
||||||
// LO size register field must be all 1s, so subtract 1
|
// LO size register field must be all 1s, so subtract 1
|
||||||
uint32_t system_size = n_pages * 8192l / 64 - 1;
|
uint32_t system_size = m->get_memory_size() / 64 - 1;
|
||||||
|
|
||||||
if (a == ADDR_SYSSIZE + 2) { // system size HI
|
if (a == ADDR_SYSSIZE + 2) { // system size HI
|
||||||
uint16_t temp = system_size >> 16;
|
uint16_t temp = system_size >> 16;
|
||||||
|
@ -505,7 +513,7 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_offset >= uint32_t(n_pages * 8192)) {
|
if (m_offset >= m->get_memory_size()) {
|
||||||
if (peek_only) {
|
if (peek_only) {
|
||||||
DOLOG(debug, false, "READ from %06o - out of range!", addr_in);
|
DOLOG(debug, false, "READ from %06o - out of range!", addr_in);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -696,8 +704,8 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_offset >= n_pages * 8192l && !is_io) [[unlikely]] {
|
if (m_offset >= m->get_memory_size() && !is_io) [[unlikely]] {
|
||||||
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, m->get_memory_size());
|
||||||
DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a);
|
DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a);
|
||||||
|
|
||||||
if (mmu_->is_locked() == false) {
|
if (mmu_->is_locked() == false) {
|
||||||
|
@ -1025,7 +1033,7 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
|
||||||
|
|
||||||
DOLOG(debug, false, "WRITE to %06o/%07o %c %c: %06o", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', value);
|
DOLOG(debug, false, "WRITE to %06o/%07o %c %c: %06o", addr_in, m_offset, space == d_space ? 'D' : 'I', word_mode == wm_byte ? 'B' : 'W', value);
|
||||||
|
|
||||||
if (m_offset >= uint32_t(n_pages * 8192)) {
|
if (m_offset >= m->get_memory_size()) {
|
||||||
c->trap(004); // no such RAM
|
c->trap(004); // no such RAM
|
||||||
throw 1;
|
throw 1;
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1050,7 @@ void bus::writePhysical(const uint32_t a, const uint16_t value)
|
||||||
{
|
{
|
||||||
DOLOG(debug, false, "physicalWRITE %06o to %o", value, a);
|
DOLOG(debug, false, "physicalWRITE %06o to %o", value, a);
|
||||||
|
|
||||||
if (a >= n_pages * 8192l) {
|
if (a >= m->get_memory_size()) {
|
||||||
DOLOG(debug, false, "physicalWRITE to %o: trap 004", a);
|
DOLOG(debug, false, "physicalWRITE to %o: trap 004", a);
|
||||||
c->trap(004);
|
c->trap(004);
|
||||||
throw 12;
|
throw 12;
|
||||||
|
@ -1054,7 +1062,7 @@ void bus::writePhysical(const uint32_t a, const uint16_t value)
|
||||||
|
|
||||||
uint16_t bus::readPhysical(const uint32_t a)
|
uint16_t bus::readPhysical(const uint32_t a)
|
||||||
{
|
{
|
||||||
if (a >= n_pages * 8192l) {
|
if (a >= m->get_memory_size()) {
|
||||||
DOLOG(debug, false, "physicalREAD from %o: trap 004", a);
|
DOLOG(debug, false, "physicalREAD from %o: trap 004", a);
|
||||||
c->trap(004);
|
c->trap(004);
|
||||||
throw 13;
|
throw 13;
|
||||||
|
|
4
bus.h
4
bus.h
|
@ -75,10 +75,7 @@ private:
|
||||||
rl02 *rl02_ { nullptr };
|
rl02 *rl02_ { nullptr };
|
||||||
tty *tty_ { nullptr };
|
tty *tty_ { nullptr };
|
||||||
kw11_l *kw11_l_ { nullptr };
|
kw11_l *kw11_l_ { nullptr };
|
||||||
|
|
||||||
mmu *mmu_ { nullptr };
|
mmu *mmu_ { nullptr };
|
||||||
|
|
||||||
int n_pages { DEFAULT_N_PAGES };
|
|
||||||
memory *m { nullptr };
|
memory *m { nullptr };
|
||||||
|
|
||||||
uint16_t microprogram_break_register { 0 };
|
uint16_t microprogram_break_register { 0 };
|
||||||
|
@ -104,7 +101,6 @@ public:
|
||||||
void set_debug_mode() { console_switches |= 128; }
|
void set_debug_mode() { console_switches |= 128; }
|
||||||
uint16_t get_console_leds() { return console_leds; }
|
uint16_t get_console_leds() { return console_leds; }
|
||||||
|
|
||||||
int get_memory_size() const { return n_pages; }
|
|
||||||
void set_memory_size(const int n_pages);
|
void set_memory_size(const int n_pages);
|
||||||
|
|
||||||
void mmudebug(const uint16_t a);
|
void mmudebug(const uint16_t a);
|
||||||
|
|
31
console.cpp
31
console.cpp
|
@ -46,6 +46,10 @@ console::~console()
|
||||||
delete [] screen_buffer;
|
delete [] screen_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void console::begin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void console::start_thread()
|
void console::start_thread()
|
||||||
{
|
{
|
||||||
assert(b);
|
assert(b);
|
||||||
|
@ -266,33 +270,6 @@ std::string console::read_line(const std::string & prompt)
|
||||||
return edit_lines_hist.at(line_nr);
|
return edit_lines_hist.at(line_nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void console::debug(const std::string fmt, ...)
|
|
||||||
{
|
|
||||||
#if defined(BUILD_FOR_RP2040)
|
|
||||||
char buffer[128];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vsnprintf(buffer, sizeof buffer, fmt.c_str(), ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
put_string_lf(buffer);
|
|
||||||
#else
|
|
||||||
char *buffer = nullptr;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
|
|
||||||
vasprintf(&buffer, fmt.c_str(), ap);
|
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
put_string_lf(buffer);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void console::put_char(const char c)
|
void console::put_char(const char c)
|
||||||
{
|
{
|
||||||
put_char_ll(c);
|
put_char_ll(c);
|
||||||
|
|
|
@ -29,7 +29,8 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::atomic_uint32_t *const stop_event { nullptr };
|
std::atomic_uint32_t *const stop_event { nullptr };
|
||||||
|
std::atomic_bool stop_panel { false };
|
||||||
|
|
||||||
bus *b { nullptr };
|
bus *b { nullptr };
|
||||||
#if !defined(BUILD_FOR_RP2040)
|
#if !defined(BUILD_FOR_RP2040)
|
||||||
|
@ -60,6 +61,8 @@ public:
|
||||||
console(std::atomic_uint32_t *const stop_event, const int t_width = 80, const int t_height = 25);
|
console(std::atomic_uint32_t *const stop_event, const int t_width = 80, const int t_height = 25);
|
||||||
virtual ~console();
|
virtual ~console();
|
||||||
|
|
||||||
|
virtual void begin();
|
||||||
|
|
||||||
void set_bus(bus *const b) { this->b = b; }
|
void set_bus(bus *const b) { this->b = b; }
|
||||||
|
|
||||||
void start_thread();
|
void start_thread();
|
||||||
|
@ -76,8 +79,6 @@ public:
|
||||||
void put_string(const std::string & what);
|
void put_string(const std::string & what);
|
||||||
virtual void put_string_lf(const std::string & what) = 0;
|
virtual void put_string_lf(const std::string & what) = 0;
|
||||||
|
|
||||||
void debug(const std::string fmt, ...);
|
|
||||||
|
|
||||||
virtual void resize_terminal() = 0;
|
virtual void resize_terminal() = 0;
|
||||||
|
|
||||||
virtual void refresh_virtual_terminal() = 0;
|
virtual void refresh_virtual_terminal() = 0;
|
||||||
|
@ -88,5 +89,6 @@ public:
|
||||||
std::atomic_bool * get_disk_read_activity_flag() { return &disk_read_activity_flag; }
|
std::atomic_bool * get_disk_read_activity_flag() { return &disk_read_activity_flag; }
|
||||||
std::atomic_bool * get_disk_write_activity_flag() { return &disk_write_activity_flag; }
|
std::atomic_bool * get_disk_write_activity_flag() { return &disk_write_activity_flag; }
|
||||||
|
|
||||||
|
void stop_panel_thread() { stop_panel = true; }
|
||||||
virtual void panel_update_thread() = 0;
|
virtual void panel_update_thread() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
console_ncurses::console_ncurses(std::atomic_uint32_t *const stop_event): console(stop_event)
|
console_ncurses::console_ncurses(std::atomic_uint32_t *const stop_event): console(stop_event)
|
||||||
{
|
{
|
||||||
init_ncurses(true);
|
init_ncurses(true);
|
||||||
|
|
||||||
resize_terminal();
|
|
||||||
|
|
||||||
th_panel = new std::thread(&console_ncurses::panel_update_thread, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console_ncurses::~console_ncurses()
|
console_ncurses::~console_ncurses()
|
||||||
|
@ -51,6 +47,13 @@ console_ncurses::~console_ncurses()
|
||||||
endwin();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void console_ncurses::begin()
|
||||||
|
{
|
||||||
|
resize_terminal();
|
||||||
|
|
||||||
|
th_panel = new std::thread(&console_ncurses::panel_update_thread, this);
|
||||||
|
}
|
||||||
|
|
||||||
int console_ncurses::wait_for_char_ll(const short timeout)
|
int console_ncurses::wait_for_char_ll(const short timeout)
|
||||||
{
|
{
|
||||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } };
|
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } };
|
||||||
|
@ -133,7 +136,7 @@ void console_ncurses::panel_update_thread()
|
||||||
|
|
||||||
constexpr int refresh_rate = 50;
|
constexpr int refresh_rate = 50;
|
||||||
|
|
||||||
while(*stop_event != EVENT_TERMINATE) {
|
while(*stop_event != EVENT_TERMINATE && stop_panel == false) {
|
||||||
myusleep(1000000 / refresh_rate);
|
myusleep(1000000 / refresh_rate);
|
||||||
|
|
||||||
// note that these are approximately as there's no mutex on the emulation
|
// note that these are approximately as there's no mutex on the emulation
|
||||||
|
@ -187,11 +190,11 @@ void console_ncurses::panel_update_thread()
|
||||||
auto psw = data["psw"][0];
|
auto psw = data["psw"][0];
|
||||||
|
|
||||||
std::string instruction_values;
|
std::string instruction_values;
|
||||||
for(auto iv : data["instruction-values"])
|
for(auto & iv : data["instruction-values"])
|
||||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||||
|
|
||||||
std::string work_values;
|
std::string work_values;
|
||||||
for(auto wv : data["work-values"])
|
for(auto & wv : data["work-values"])
|
||||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||||
|
|
||||||
std::string instruction = data["instruction-text"].at(0);
|
std::string instruction = data["instruction-text"].at(0);
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
console_ncurses(std::atomic_uint32_t *const stop_event);
|
console_ncurses(std::atomic_uint32_t *const stop_event);
|
||||||
virtual ~console_ncurses();
|
virtual ~console_ncurses();
|
||||||
|
|
||||||
|
void begin() override;
|
||||||
|
|
||||||
void put_string_lf(const std::string & what) override;
|
void put_string_lf(const std::string & what) override;
|
||||||
|
|
||||||
void resize_terminal() override;
|
void resize_terminal() override;
|
||||||
|
|
15
cpu.cpp
15
cpu.cpp
|
@ -137,7 +137,7 @@ void cpu::reset()
|
||||||
uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) const
|
uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) const
|
||||||
{
|
{
|
||||||
if (nr < 6) {
|
if (nr < 6) {
|
||||||
int set = getBitPSW(11);
|
int set = get_register_set();
|
||||||
|
|
||||||
return regs0_5[set][nr];
|
return regs0_5[set][nr];
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) con
|
||||||
void cpu::setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection)
|
void cpu::setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection)
|
||||||
{
|
{
|
||||||
if (nr < 6) {
|
if (nr < 6) {
|
||||||
int set = getBitPSW(11);
|
int set = get_register_set();
|
||||||
|
|
||||||
regs0_5[set][nr] = value;
|
regs0_5[set][nr] = value;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ bool cpu::put_result(const gam_rc_t & g, const uint16_t value)
|
||||||
uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, const uint16_t value)
|
uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, const uint16_t value)
|
||||||
{
|
{
|
||||||
if (nr < 6)
|
if (nr < 6)
|
||||||
return regs0_5[getBitPSW(11)][nr] += value;
|
return regs0_5[get_register_set()][nr] += value;
|
||||||
|
|
||||||
if (nr == 6) {
|
if (nr == 6) {
|
||||||
if (mode_selection == rm_prev)
|
if (mode_selection == rm_prev)
|
||||||
|
@ -584,12 +584,12 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
||||||
const uint8_t dst_mode = (dst >> 3) & 7;
|
const uint8_t dst_mode = (dst >> 3) & 7;
|
||||||
const uint8_t dst_reg = dst & 7;
|
const uint8_t dst_reg = dst & 7;
|
||||||
|
|
||||||
bool set_flags = true;
|
|
||||||
|
|
||||||
switch(operation) {
|
switch(operation) {
|
||||||
case 0b001: { // MOV/MOVB Move Word/Byte
|
case 0b001: { // MOV/MOVB Move Word/Byte
|
||||||
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
gam_rc_t g_src = getGAM(src_mode, src_reg, word_mode, rm_cur);
|
||||||
|
|
||||||
|
bool set_flags = true;
|
||||||
|
|
||||||
if (word_mode == wm_byte && dst_mode == 0)
|
if (word_mode == wm_byte && dst_mode == 0)
|
||||||
setRegister(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension
|
setRegister(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension
|
||||||
else {
|
else {
|
||||||
|
@ -715,7 +715,7 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
||||||
setPSW_z(result == 0);
|
setPSW_z(result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
putGAM(g_dst, result);
|
(void)putGAM(g_dst, result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -945,7 +945,6 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
||||||
const uint8_t dst_mode = (dst >> 3) & 7;
|
const uint8_t dst_mode = (dst >> 3) & 7;
|
||||||
const uint8_t dst_reg = dst & 7;
|
const uint8_t dst_reg = dst & 7;
|
||||||
const word_mode_t word_mode = instr & 0x8000 ? wm_byte : wm_word;
|
const word_mode_t word_mode = instr & 0x8000 ? wm_byte : wm_word;
|
||||||
bool set_flags = true;
|
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case 0b00000011: { // SWAB
|
case 0b00000011: { // SWAB
|
||||||
|
@ -959,7 +958,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
||||||
|
|
||||||
v = (v << 8) | (v >> 8);
|
v = (v << 8) | (v >> 8);
|
||||||
|
|
||||||
set_flags = putGAM(g_dst, v);
|
bool set_flags = putGAM(g_dst, v);
|
||||||
|
|
||||||
if (set_flags) {
|
if (set_flags) {
|
||||||
setPSW_flags_nzv(v, wm_byte);
|
setPSW_flags_nzv(v, wm_byte);
|
||||||
|
|
1
cpu.h
1
cpu.h
|
@ -160,6 +160,7 @@ public:
|
||||||
bool getBitPSW(const int bit) const;
|
bool getBitPSW(const int bit) const;
|
||||||
int getPSW_runmode() const { return psw >> 14; };
|
int getPSW_runmode() const { return psw >> 14; };
|
||||||
int getPSW_prev_runmode() const { return (psw >> 12) & 3; };
|
int getPSW_prev_runmode() const { return (psw >> 12) & 3; };
|
||||||
|
bool get_register_set() const { return !!(psw & 04000); }
|
||||||
|
|
||||||
void setPSW_c(const bool v);
|
void setPSW_c(const bool v);
|
||||||
void setPSW_v(const bool v);
|
void setPSW_v(const bool v);
|
||||||
|
|
69
debugger.cpp
69
debugger.cpp
|
@ -26,6 +26,7 @@
|
||||||
#include "disk_backend_nbd.h"
|
#include "disk_backend_nbd.h"
|
||||||
#include "loaders.h"
|
#include "loaders.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
@ -37,13 +38,9 @@
|
||||||
#include "rp2040.h"
|
#include "rp2040.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void set_boot_loader(bus *const b);
|
void configure_network(console *const cnsl);
|
||||||
|
void check_network(console *const cnsl);
|
||||||
void configure_disk(console *const c);
|
void start_network(console *const cnsl);
|
||||||
|
|
||||||
void configure_network(console *const c);
|
|
||||||
void check_network(console *const c);
|
|
||||||
void start_network(console *const c);
|
|
||||||
|
|
||||||
void set_tty_serial_speed(console *const c, const uint32_t bps);
|
void set_tty_serial_speed(console *const c, const uint32_t bps);
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,10 +82,10 @@ std::optional<disk_backend *> select_disk_file(console *const c)
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
c->put_string_lf("Files in current directory: ");
|
c->put_string_lf("Files in current directory: ");
|
||||||
#else
|
#else
|
||||||
c->debug("MISO: %d", int(MISO));
|
c->put_string_lf(format("MISO: %d", int(MISO)));
|
||||||
c->debug("MOSI: %d", int(MOSI));
|
c->put_string_lf(format("MOSI: %d", int(MOSI)));
|
||||||
c->debug("SCK : %d", int(SCK ));
|
c->put_string_lf(format("SCK : %d", int(SCK )));
|
||||||
c->debug("SS : %d", int(SS ));
|
c->put_string_lf(format("SS : %d", int(SS )));
|
||||||
|
|
||||||
c->put_string_lf("Files on SD-card:");
|
c->put_string_lf("Files on SD-card:");
|
||||||
|
|
||||||
|
@ -99,9 +96,9 @@ std::optional<disk_backend *> select_disk_file(console *const c)
|
||||||
if (!SD.begin(SS, SD_SCK_MHZ(15))) {
|
if (!SD.begin(SS, SD_SCK_MHZ(15))) {
|
||||||
auto err = SD.sdErrorCode();
|
auto err = SD.sdErrorCode();
|
||||||
if (err)
|
if (err)
|
||||||
c->debug("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData());
|
c->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData()));
|
||||||
else
|
else
|
||||||
c->debug("Failed to initialize SD card");
|
c->put_string_lf("Failed to initialize SD card");
|
||||||
|
|
||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
|
@ -239,20 +236,20 @@ std::optional<disk_backend *> select_disk_backend(console *const cnsl)
|
||||||
void configure_disk(bus *const b, console *const cnsl)
|
void configure_disk(bus *const b, console *const cnsl)
|
||||||
{
|
{
|
||||||
// TODO tape
|
// TODO tape
|
||||||
int ch = wait_for_key("1. RK05, 2. RL02, 9. abort", cnsl, { '1', '2', '3', '9' });
|
int type_ch = wait_for_key("1. RK05, 2. RL02, 9. abort", cnsl, { '1', '2', '3', '9' });
|
||||||
|
|
||||||
bootloader_t bl = BL_NONE;
|
bootloader_t bl = BL_NONE;
|
||||||
disk_device *dd = nullptr;
|
disk_device *dd = nullptr;
|
||||||
|
|
||||||
if (ch == '1') {
|
if (type_ch == '1') {
|
||||||
dd = b->getRK05();
|
dd = b->getRK05();
|
||||||
bl = BL_RK05;
|
bl = BL_RK05;
|
||||||
}
|
}
|
||||||
else if (ch == '2') {
|
else if (type_ch == '2') {
|
||||||
dd = b->getRL02();
|
dd = b->getRL02();
|
||||||
bl = BL_RL02;
|
bl = BL_RL02;
|
||||||
}
|
}
|
||||||
else if (ch == '9') {
|
else if (type_ch == '9') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +286,11 @@ void configure_disk(bus *const b, console *const cnsl)
|
||||||
int slot = ch - 'A';
|
int slot = ch - 'A';
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
int ch = wait_for_key("Select cartridge action: 1. load, 2. unload, 9. exit", cnsl, { '1', '2', '9' });
|
int ch_action = wait_for_key("Select cartridge action: 1. load, 2. unload, 9. exit", cnsl, { '1', '2', '9' });
|
||||||
if (ch == '9')
|
if (ch_action == '9')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ch == '1') {
|
if (ch_action == '1') {
|
||||||
auto image_file = select_disk_backend(cnsl);
|
auto image_file = select_disk_backend(cnsl);
|
||||||
|
|
||||||
if (image_file.has_value()) {
|
if (image_file.has_value()) {
|
||||||
|
@ -303,7 +300,7 @@ void configure_disk(bus *const b, console *const cnsl)
|
||||||
cnsl->put_string_lf("Cartridge loaded");
|
cnsl->put_string_lf("Cartridge loaded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ch == '2') {
|
else if (ch_action == '2') {
|
||||||
if (cartridge_slots->at(slot)) {
|
if (cartridge_slots->at(slot)) {
|
||||||
delete cartridge_slots->at(slot);
|
delete cartridge_slots->at(slot);
|
||||||
cartridge_slots->at(slot) = nullptr;
|
cartridge_slots->at(slot) = nullptr;
|
||||||
|
@ -325,11 +322,11 @@ int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool
|
||||||
auto psw = data["psw"][0];
|
auto psw = data["psw"][0];
|
||||||
|
|
||||||
std::string instruction_values;
|
std::string instruction_values;
|
||||||
for(auto iv : data["instruction-values"])
|
for(auto & iv : data["instruction-values"])
|
||||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||||
|
|
||||||
std::string work_values;
|
std::string work_values;
|
||||||
for(auto wv : data["work-values"])
|
for(auto & wv : data["work-values"])
|
||||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||||
|
|
||||||
std::string instruction = data["instruction-text"].at(0);
|
std::string instruction = data["instruction-text"].at(0);
|
||||||
|
@ -358,7 +355,7 @@ int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cnsl)
|
if (cnsl)
|
||||||
cnsl->debug(result);
|
cnsl->put_string_lf(result);
|
||||||
else
|
else
|
||||||
DOLOG(debug, false, "%s", result.c_str());
|
DOLOG(debug, false, "%s", result.c_str());
|
||||||
|
|
||||||
|
@ -391,7 +388,7 @@ std::map<std::string, std::string> split(const std::vector<std::string> & kv_arr
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> out;
|
std::map<std::string, std::string> out;
|
||||||
|
|
||||||
for(auto pair : kv_array) {
|
for(auto & pair : kv_array) {
|
||||||
auto kv = split(pair, splitter);
|
auto kv = split(pair, splitter);
|
||||||
|
|
||||||
if (kv.size() == 1)
|
if (kv.size() == 1)
|
||||||
|
@ -663,7 +660,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
|
|
||||||
cnsl->put_string_lf("Breakpoints:");
|
cnsl->put_string_lf("Breakpoints:");
|
||||||
|
|
||||||
for(auto a : bps)
|
for(auto & a : bps)
|
||||||
cnsl->put_string_lf(format("%d: %s", a.first, a.second->emit().c_str()));
|
cnsl->put_string_lf(format("%d: %s", a.first, a.second->emit().c_str()));
|
||||||
|
|
||||||
if (bps.empty())
|
if (bps.empty())
|
||||||
|
@ -825,6 +822,12 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
|
else if (cmd == "debug") {
|
||||||
|
if (heap_caps_check_integrity_all(true) == false)
|
||||||
|
cnsl->put_string_lf("HEAP corruption!");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (cmd == "cfgnet") {
|
else if (cmd == "cfgnet") {
|
||||||
configure_network(cnsl);
|
configure_network(cnsl);
|
||||||
|
|
||||||
|
@ -863,7 +866,7 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
if (parts.size() == 2)
|
if (parts.size() == 2)
|
||||||
b->set_memory_size(std::stoi(parts.at(1)));
|
b->set_memory_size(std::stoi(parts.at(1)));
|
||||||
else {
|
else {
|
||||||
int n_pages = b->get_memory_size();
|
int n_pages = b->getRAM()->get_memory_size();
|
||||||
|
|
||||||
cnsl->put_string_lf(format("Memory size: %u pages or %u kB (decimal)", n_pages, n_pages * 8192 / 1024));
|
cnsl->put_string_lf(format("Memory size: %u pages or %u kB (decimal)", n_pages, n_pages * 8192 / 1024));
|
||||||
}
|
}
|
||||||
|
@ -942,7 +945,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (parts[0] == "setsl" && parts.size() == 3) {
|
else if (parts[0] == "setsl" && parts.size() == 3) {
|
||||||
setloghost(parts.at(1).c_str(), parse_ll(parts[2]));
|
if (setloghost(parts.at(1).c_str(), parse_ll(parts[2])) == false)
|
||||||
|
cnsl->put_string_lf("Failed parsing IP address");
|
||||||
|
else
|
||||||
|
send_syslog(info, "Hello, world!");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -951,6 +957,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (cmd == "dp") {
|
||||||
|
cnsl->stop_panel_thread();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else if (cmd == "bt") {
|
else if (cmd == "bt") {
|
||||||
if (c->get_debug() == false)
|
if (c->get_debug() == false)
|
||||||
cnsl->put_string_lf("Debug mode is disabled!");
|
cnsl->put_string_lf("Debug mode is disabled!");
|
||||||
|
@ -1006,11 +1017,13 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
||||||
"ser - serialize state to a file",
|
"ser - serialize state to a file",
|
||||||
// "dser - deserialize state from a file",
|
// "dser - deserialize state from a file",
|
||||||
#endif
|
#endif
|
||||||
|
"dp - disable panel",
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
"cfgnet - configure network (e.g. WiFi)",
|
"cfgnet - configure network (e.g. WiFi)",
|
||||||
"startnet - start network",
|
"startnet - start network",
|
||||||
"chknet - check network status",
|
"chknet - check network status",
|
||||||
"serspd - set serial speed in bps (8N1 are default)",
|
"serspd - set serial speed in bps (8N1 are default)",
|
||||||
|
"debug - debugging info",
|
||||||
#endif
|
#endif
|
||||||
"cfgdisk - configure disk",
|
"cfgdisk - configure disk",
|
||||||
nullptr
|
nullptr
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "disk_backend.h"
|
#include "disk_backend.h"
|
||||||
|
#include "gen.h"
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
#include "disk_backend_file.h"
|
#include "disk_backend_file.h"
|
||||||
#include "disk_backend_nbd.h"
|
#include "disk_backend_nbd.h"
|
||||||
|
@ -68,7 +69,7 @@ json_t *disk_backend::serialize_overlay() const
|
||||||
for(size_t i=0; i<id.second.size(); i++)
|
for(size_t i=0; i<id.second.size(); i++)
|
||||||
json_array_append(j_data, json_integer(id.second.at(i)));
|
json_array_append(j_data, json_integer(id.second.at(i)));
|
||||||
|
|
||||||
json_object_set(out, format("%u", id.first).c_str(), j_data);
|
json_object_set(out, format("%lu", id.first).c_str(), j_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
@ -91,10 +91,10 @@ bool disk_backend_nbd::connect(const bool retry)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
// LOOP until connected, logging message, exponential backoff?
|
// LOOP until connected, logging message, exponential backoff?
|
||||||
addrinfo *res = nullptr;
|
addrinfo *res = nullptr;
|
||||||
|
|
||||||
addrinfo hints { 0 };
|
addrinfo hints { 0 };
|
||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
char port_str[8] { 0 };
|
char port_str[8] { 0 };
|
||||||
|
@ -137,7 +137,7 @@ bool disk_backend_nbd::connect(const bool retry)
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint8_t padding[124];
|
uint8_t padding[124];
|
||||||
} nbd_hello;
|
} nbd_hello { };
|
||||||
|
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
if (READ(fd, reinterpret_cast<char *>(&nbd_hello), sizeof nbd_hello) != sizeof nbd_hello) {
|
if (READ(fd, reinterpret_cast<char *>(&nbd_hello), sizeof nbd_hello) != sizeof nbd_hello) {
|
||||||
|
@ -194,7 +194,7 @@ bool disk_backend_nbd::read(const off_t offset_in, const size_t n, uint8_t *cons
|
||||||
uint64_t handle;
|
uint64_t handle;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
} nbd_request { 0 };
|
} nbd_request { };
|
||||||
|
|
||||||
nbd_request.magic = ntohl(0x25609513);
|
nbd_request.magic = ntohl(0x25609513);
|
||||||
nbd_request.type = 0; // READ
|
nbd_request.type = 0; // READ
|
||||||
|
|
|
@ -18,5 +18,7 @@ public:
|
||||||
virtual ~disk_device() {
|
virtual ~disk_device() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void begin() = 0;
|
||||||
|
|
||||||
std::vector<disk_backend *> * access_disk_backends() { return &fhs; }
|
std::vector<disk_backend *> * access_disk_backends() { return &fhs; }
|
||||||
};
|
};
|
||||||
|
|
14
loaders.cpp
14
loaders.cpp
|
@ -30,7 +30,7 @@ void loadbin(bus *const b, uint16_t base, const char *const file)
|
||||||
|
|
||||||
void set_boot_loader(bus *const b, const bootloader_t which)
|
void set_boot_loader(bus *const b, const bootloader_t which)
|
||||||
{
|
{
|
||||||
cpu *const c = b->getCpu();
|
cpu *const c = b->getCpu();
|
||||||
|
|
||||||
uint16_t offset = 0;
|
uint16_t offset = 0;
|
||||||
uint16_t start = 0;
|
uint16_t start = 0;
|
||||||
|
@ -40,7 +40,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
||||||
if (which == BL_RK05) {
|
if (which == BL_RK05) {
|
||||||
start = offset = 01000;
|
start = offset = 01000;
|
||||||
|
|
||||||
static uint16_t rk05_code[] = {
|
static const uint16_t rk05_code[] = {
|
||||||
0012700,
|
0012700,
|
||||||
0177406,
|
0177406,
|
||||||
0012710,
|
0012710,
|
||||||
|
@ -92,7 +92,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
||||||
start = offset = 01000;
|
start = offset = 01000;
|
||||||
|
|
||||||
/* from https://www.pdp-11.nl/peripherals/disk/rl-info.html
|
/* from https://www.pdp-11.nl/peripherals/disk/rl-info.html
|
||||||
static uint16_t rl02_code[] = {
|
static const uint16_t rl02_code[] = {
|
||||||
0012701,
|
0012701,
|
||||||
0174400,
|
0174400,
|
||||||
0012761,
|
0012761,
|
||||||
|
@ -120,7 +120,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// from http://gunkies.org/wiki/RL11_disk_controller
|
// from http://gunkies.org/wiki/RL11_disk_controller
|
||||||
static uint16_t rl02_code[] = {
|
static const uint16_t rl02_code[] = {
|
||||||
0012700,
|
0012700,
|
||||||
0174400,
|
0174400,
|
||||||
0012760,
|
0012760,
|
||||||
|
@ -207,7 +207,11 @@ std::optional<uint16_t> load_tape(bus *const b, const std::string & file)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t c = fgetc(fh);
|
int c = fgetc(fh);
|
||||||
|
if (c == -1) {
|
||||||
|
DOLOG(warning, true, "read failure");
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
csum += c;
|
csum += c;
|
||||||
|
|
81
log.cpp
81
log.cpp
|
@ -15,7 +15,9 @@
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#if defined(_WIN32)
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const char *logfile = strdup("/tmp/kek.log");
|
static const char *logfile = strdup("/tmp/kek.log");
|
||||||
|
@ -23,10 +25,12 @@ static sockaddr_in syslog_ip_addr = { };
|
||||||
static bool is_file = true;
|
static bool is_file = true;
|
||||||
log_level_t log_level_file = warning;
|
log_level_t log_level_file = warning;
|
||||||
log_level_t log_level_screen = warning;
|
log_level_t log_level_screen = warning;
|
||||||
FILE *lfh = nullptr;
|
static FILE *log_fh = nullptr;
|
||||||
static int lf_uid = -1;
|
static int lf_uid = -1;
|
||||||
static int lf_gid = -1;
|
static int lf_gid = -1;
|
||||||
static bool l_timestamp = true;
|
static bool l_timestamp = true;
|
||||||
|
static thread_local int log_buffer_size = 128;
|
||||||
|
static thread_local char *log_buffer = reinterpret_cast<char *>(malloc(log_buffer_size));
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
int gettid()
|
int gettid()
|
||||||
|
@ -37,8 +41,8 @@ int gettid()
|
||||||
|
|
||||||
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp)
|
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp)
|
||||||
{
|
{
|
||||||
if (lfh)
|
if (log_fh)
|
||||||
fclose(lfh);
|
fclose(log_fh);
|
||||||
|
|
||||||
free((void *)logfile);
|
free((void *)logfile);
|
||||||
|
|
||||||
|
@ -54,16 +58,19 @@ void setlogfile(const char *const lf, const log_level_t ll_file, const log_level
|
||||||
atexit(closelog);
|
atexit(closelog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setloghost(const char *const host, const log_level_t ll)
|
bool setloghost(const char *const host, const log_level_t ll)
|
||||||
{
|
{
|
||||||
inet_aton(host, &syslog_ip_addr.sin_addr);
|
syslog_ip_addr.sin_family = AF_INET;
|
||||||
syslog_ip_addr.sin_port = htons(514);
|
bool ok = inet_aton(host, &syslog_ip_addr.sin_addr) == 1;
|
||||||
|
syslog_ip_addr.sin_port = htons(514);
|
||||||
|
|
||||||
is_file = false;
|
is_file = false;
|
||||||
|
|
||||||
log_level_file = ll;
|
log_level_file = ll;
|
||||||
|
|
||||||
l_timestamp = false;
|
l_timestamp = false;
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setll(const log_level_t ll_screen, const log_level_t ll_file)
|
void setll(const log_level_t ll_screen, const log_level_t ll_file)
|
||||||
|
@ -83,43 +90,51 @@ void send_syslog(const int ll, const std::string & what)
|
||||||
std::string msg = format("<%d>%s", 16 * 8 + ll, what.c_str());
|
std::string msg = format("<%d>%s", 16 * 8 + ll, what.c_str());
|
||||||
|
|
||||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
(void)sendto(s, msg.c_str(), msg.size(), 0, reinterpret_cast<sockaddr *>(&syslog_ip_addr), sizeof syslog_ip_addr);
|
if (s != -1) {
|
||||||
close(s);
|
(void)sendto(s, msg.c_str(), msg.size(), 0, reinterpret_cast<sockaddr *>(&syslog_ip_addr), sizeof syslog_ip_addr);
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closelog()
|
void closelog()
|
||||||
{
|
{
|
||||||
if (lfh) {
|
if (log_fh) {
|
||||||
fclose(lfh);
|
fclose(log_fh);
|
||||||
|
|
||||||
lfh = nullptr;
|
log_fh = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dolog(const log_level_t ll, const char *fmt, ...)
|
void dolog(const log_level_t ll, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
#if !defined(BUILD_FOR_RP2040)
|
#if !defined(BUILD_FOR_RP2040)
|
||||||
if (!lfh && logfile != nullptr) {
|
if (!log_fh && logfile != nullptr) {
|
||||||
#if !defined(ESP32)
|
#if !defined(ESP32)
|
||||||
lfh = fopen(logfile, "a+");
|
log_fh = fopen(logfile, "a+");
|
||||||
if (!lfh)
|
if (!log_fh)
|
||||||
error_exit(true, "Cannot access log-file %s", logfile);
|
error_exit(true, "Cannot access log-file %s", logfile);
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1)
|
if (lf_uid != -1 && fchown(fileno(log_fh), lf_uid, lf_gid) == -1)
|
||||||
error_exit(true, "Cannot change logfile (%s) ownership", logfile);
|
error_exit(true, "Cannot change logfile (%s) ownership", logfile);
|
||||||
|
|
||||||
if (fcntl(fileno(lfh), F_SETFD, FD_CLOEXEC) == -1)
|
if (fcntl(fileno(log_fh), F_SETFD, FD_CLOEXEC) == -1)
|
||||||
error_exit(true, "fcntl(FD_CLOEXEC) failed");
|
error_exit(true, "fcntl(FD_CLOEXEC) failed");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
char *str = nullptr;
|
for(;;) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int needed_length = vsnprintf(log_buffer, log_buffer_size, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
va_list ap;
|
if (needed_length < log_buffer_size)
|
||||||
va_start(ap, fmt);
|
break;
|
||||||
(void)vasprintf(&str, fmt, ap);
|
|
||||||
va_end(ap);
|
log_buffer_size *= 2;
|
||||||
|
log_buffer = reinterpret_cast<char *>(realloc(log_buffer, log_buffer_size));
|
||||||
|
}
|
||||||
|
|
||||||
if (l_timestamp) {
|
if (l_timestamp) {
|
||||||
uint64_t now = get_us();
|
uint64_t now = get_us();
|
||||||
|
@ -132,39 +147,35 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
||||||
if (!localtime_r(&t_now, &tm))
|
if (!localtime_r(&t_now, &tm))
|
||||||
error_exit(true, "localtime_r failed");
|
error_exit(true, "localtime_r failed");
|
||||||
#endif
|
#endif
|
||||||
char *ts_str = nullptr;
|
char ts_str[64] { };
|
||||||
|
|
||||||
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|%s] ",
|
snprintf(ts_str, sizeof 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], get_thread_name().c_str());
|
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, log_buffer);
|
||||||
#if !defined(ESP32)
|
#if !defined(ESP32)
|
||||||
if (ll <= log_level_file && lfh != nullptr)
|
if (ll <= log_level_file && log_fh != nullptr)
|
||||||
fprintf(lfh, "%s%s\n", ts_str, str);
|
fprintf(log_fh, "%s%s\n", ts_str, log_buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ll <= log_level_screen)
|
if (ll <= log_level_screen)
|
||||||
printf("%s%s\r\n", ts_str, str);
|
printf("%s%s\r\n", ts_str, log_buffer);
|
||||||
|
|
||||||
free(ts_str);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ll <= log_level_file && is_file == false)
|
if (ll <= log_level_file && is_file == false)
|
||||||
send_syslog(ll, str);
|
send_syslog(ll, log_buffer);
|
||||||
#if !defined(ESP32)
|
#if !defined(ESP32)
|
||||||
if (ll <= log_level_file && lfh != nullptr)
|
if (ll <= log_level_file && log_fh != nullptr)
|
||||||
fprintf(lfh, "%s\n", str);
|
fprintf(log_fh, "%s\n", log_buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ll <= log_level_screen)
|
if (ll <= log_level_screen)
|
||||||
printf("%s\r\n", str);
|
printf("%s\r\n", log_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(str);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
log.h
3
log.h
|
@ -12,9 +12,10 @@ 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);
|
bool setloghost(const char *const host, const log_level_t ll);
|
||||||
void setll(const log_level_t ll_screen, const log_level_t ll_file);
|
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 send_syslog(const int ll, const std::string & what);
|
||||||
void closelog();
|
void closelog();
|
||||||
void dolog(const log_level_t ll, const char *fmt, ...);
|
void dolog(const log_level_t ll, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
37
main.cpp
37
main.cpp
|
@ -111,9 +111,9 @@ int run_cpu_validation(const std::string & filename)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
json_t *b_sp = json_object_get(registers_before, "sp");
|
json_t *b_sp = json_object_get(registers_before, "sp");
|
||||||
size_t array_size = json_array_size(b_sp);
|
size_t sp_array_size = json_array_size(b_sp);
|
||||||
assert(array_size == 4);
|
assert(sp_array_size == 4);
|
||||||
for(size_t i=0; i<array_size; i++) {
|
for(size_t i=0; i<sp_array_size; i++) {
|
||||||
json_t *temp = json_array_get(b_sp, i);
|
json_t *temp = json_array_get(b_sp, i);
|
||||||
c->lowlevel_register_sp_set(i, json_integer_value(temp));
|
c->lowlevel_register_sp_set(i, json_integer_value(temp));
|
||||||
}
|
}
|
||||||
|
@ -183,9 +183,9 @@ int run_cpu_validation(const std::string & filename)
|
||||||
|
|
||||||
{
|
{
|
||||||
json_t *a_sp = json_object_get(registers_after, "sp");
|
json_t *a_sp = json_object_get(registers_after, "sp");
|
||||||
size_t array_size = json_array_size(a_sp);
|
size_t sp_array_size = json_array_size(a_sp);
|
||||||
assert(array_size == 4);
|
assert(sp_array_size == 4);
|
||||||
for(size_t i=0; i<array_size; i++) {
|
for(size_t i=0; i<sp_array_size; i++) {
|
||||||
json_t *temp = json_array_get(a_sp, i);
|
json_t *temp = json_array_get(a_sp, i);
|
||||||
uint16_t sp = c->lowlevel_register_sp_get(i);
|
uint16_t sp = c->lowlevel_register_sp_get(i);
|
||||||
if (json_integer_value(temp) != sp) {
|
if (json_integer_value(temp) != sp) {
|
||||||
|
@ -525,18 +525,30 @@ int main(int argc, char *argv[])
|
||||||
cpu *c = new cpu(b, &event);
|
cpu *c = new cpu(b, &event);
|
||||||
b->add_cpu(c);
|
b->add_cpu(c);
|
||||||
|
|
||||||
if (rk05_files.empty() == false)
|
auto rk05_dev = new rk05(b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag());
|
||||||
|
rk05_dev->begin();
|
||||||
|
b->add_rk05(rk05_dev);
|
||||||
|
|
||||||
|
auto rl02_dev = new rl02(b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag());
|
||||||
|
rl02_dev->begin();
|
||||||
|
b->add_rl02(rl02_dev);
|
||||||
|
|
||||||
|
if (rk05_files.empty() == false) {
|
||||||
bootloader = BL_RK05;
|
bootloader = BL_RK05;
|
||||||
|
|
||||||
if (rl02_files.empty() == false)
|
for(auto & file: rk05_files)
|
||||||
|
rk05_dev->access_disk_backends()->push_back(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rl02_files.empty() == false) {
|
||||||
bootloader = BL_RL02;
|
bootloader = BL_RL02;
|
||||||
|
|
||||||
|
for(auto & file: rl02_files)
|
||||||
|
rl02_dev->access_disk_backends()->push_back(file);
|
||||||
|
}
|
||||||
|
|
||||||
if (enable_bootloader)
|
if (enable_bootloader)
|
||||||
set_boot_loader(b, bootloader);
|
set_boot_loader(b, bootloader);
|
||||||
|
|
||||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
|
||||||
|
|
||||||
b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
FILE *fh = fopen(deserialize.c_str(), "r");
|
FILE *fh = fopen(deserialize.c_str(), "r");
|
||||||
|
@ -566,6 +578,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
cnsl->set_bus(b);
|
cnsl->set_bus(b);
|
||||||
|
cnsl->begin();
|
||||||
|
|
||||||
running = cnsl->get_running_flag();
|
running = cnsl->get_running_flag();
|
||||||
|
|
||||||
|
|
2
memory.h
2
memory.h
|
@ -21,6 +21,8 @@ public:
|
||||||
memory(const uint32_t size);
|
memory(const uint32_t size);
|
||||||
~memory();
|
~memory();
|
||||||
|
|
||||||
|
uint32_t get_memory_size() const { return size; }
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
json_t *serialize() const;
|
json_t *serialize() const;
|
||||||
|
|
19
mmu.cpp
19
mmu.cpp
|
@ -15,6 +15,11 @@ mmu::~mmu()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mmu::begin()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
void mmu::reset()
|
void mmu::reset()
|
||||||
{
|
{
|
||||||
memset(pages, 0x00, sizeof pages);
|
memset(pages, 0x00, sizeof pages);
|
||||||
|
@ -52,8 +57,6 @@ void mmu::setMMR0(uint16_t value)
|
||||||
value &= 254; // bits 7...1 are protected
|
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;
|
MMR0 = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,17 +105,6 @@ void mmu::addToMMR1(const int8_t delta, const uint8_t reg)
|
||||||
|
|
||||||
assert((getMMR0() & 0160000) == 0); // MMR1 should not be locked
|
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 <<= 8;
|
||||||
|
|
||||||
MMR1 |= (delta & 31) << 3;
|
MMR1 |= (delta & 31) << 3;
|
||||||
|
@ -277,6 +269,7 @@ void mmu::set_par_pdr(const json_t *const j_in, const int run_mode, const bool i
|
||||||
mmu *mmu::deserialize(const json_t *const j)
|
mmu *mmu::deserialize(const json_t *const j)
|
||||||
{
|
{
|
||||||
mmu *m = new mmu();
|
mmu *m = new mmu();
|
||||||
|
m->begin();
|
||||||
|
|
||||||
for(int run_mode=0; run_mode<4; run_mode++) {
|
for(int run_mode=0; run_mode<4; run_mode++) {
|
||||||
if (run_mode == 2)
|
if (run_mode == 2)
|
||||||
|
|
2
mmu.h
2
mmu.h
|
@ -50,6 +50,8 @@ public:
|
||||||
mmu();
|
mmu();
|
||||||
virtual ~mmu();
|
virtual ~mmu();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
json_t *serialize() const;
|
json_t *serialize() const;
|
||||||
static mmu *deserialize(const json_t *const j);
|
static mmu *deserialize(const json_t *const j);
|
||||||
|
|
55
rk05.cpp
55
rk05.cpp
|
@ -23,14 +23,11 @@ static const char * const regnames[] = {
|
||||||
"RK05_DATABUF "
|
"RK05_DATABUF "
|
||||||
};
|
};
|
||||||
|
|
||||||
rk05::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::rk05(bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity) :
|
||||||
b(b),
|
b(b),
|
||||||
disk_read_acitivity(disk_read_acitivity),
|
disk_read_acitivity(disk_read_acitivity),
|
||||||
disk_write_acitivity(disk_write_acitivity)
|
disk_write_acitivity(disk_write_acitivity)
|
||||||
{
|
{
|
||||||
fhs = files;
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rk05::~rk05()
|
rk05::~rk05()
|
||||||
|
@ -39,6 +36,11 @@ rk05::~rk05()
|
||||||
delete fh;
|
delete fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rk05::begin()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
void rk05::reset()
|
void rk05::reset()
|
||||||
{
|
{
|
||||||
memset(registers, 0x00, sizeof registers);
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
@ -186,10 +188,10 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v)
|
||||||
|
|
||||||
uint32_t temp_diskoffb = diskoffb;
|
uint32_t temp_diskoffb = diskoffb;
|
||||||
|
|
||||||
uint32_t temp = reclen;
|
uint32_t temp_reclen = reclen;
|
||||||
uint32_t p = memoff;
|
uint32_t p = memoff;
|
||||||
while(temp > 0) {
|
while(temp_reclen > 0) {
|
||||||
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp);
|
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp_reclen);
|
||||||
|
|
||||||
if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer, 512)) {
|
if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer, 512)) {
|
||||||
DOLOG(ll_error, true, "RK05 read error %s from %u len %u", strerror(errno), temp_diskoffb, cur);
|
DOLOG(ll_error, true, "RK05 read error %s from %u len %u", strerror(errno), temp_diskoffb, cur);
|
||||||
|
@ -205,7 +207,7 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v)
|
||||||
update_bus_address(2);
|
update_bus_address(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
temp -= cur;
|
temp_reclen -= cur;
|
||||||
|
|
||||||
if (++sector >= 12) {
|
if (++sector >= 12) {
|
||||||
sector = 0;
|
sector = 0;
|
||||||
|
@ -248,3 +250,38 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_POSIX
|
||||||
|
json_t *rk05::serialize() const
|
||||||
|
{
|
||||||
|
json_t *j = json_object();
|
||||||
|
|
||||||
|
json_t *j_backends = json_array();
|
||||||
|
for(auto & dbe: fhs)
|
||||||
|
json_array_append(j_backends, dbe->serialize());
|
||||||
|
|
||||||
|
json_object_set(j, "backends", j_backends);
|
||||||
|
|
||||||
|
for(int regnr=0; regnr<7; regnr++)
|
||||||
|
json_object_set(j, format("register-%d", regnr).c_str(), json_integer(registers[regnr]));
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
rk05 *rk05::deserialize(const json_t *const j, bus *const b)
|
||||||
|
{
|
||||||
|
std::vector<disk_backend *> backends;
|
||||||
|
|
||||||
|
rk05 *r = new rk05(b, nullptr, nullptr);
|
||||||
|
r->begin();
|
||||||
|
|
||||||
|
json_t *j_backends = json_object_get(j, "backends");
|
||||||
|
for(size_t i=0; i<json_array_size(j_backends); i++)
|
||||||
|
r->access_disk_backends()->push_back(disk_backend::deserialize(json_array_get(j_backends, i)));
|
||||||
|
|
||||||
|
for(int regnr=0; regnr<7; regnr++)
|
||||||
|
r->registers[regnr] = json_integer_value(json_object_get(j, format("register-%d", regnr).c_str()));
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
9
rk05.h
9
rk05.h
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "disk_device.h"
|
#include "disk_device.h"
|
||||||
#include "disk_backend.h"
|
#include "disk_backend.h"
|
||||||
|
#include "gen.h"
|
||||||
|
|
||||||
|
|
||||||
#define RK05_DS 0177400 // drive status
|
#define RK05_DS 0177400 // drive status
|
||||||
|
@ -39,11 +40,17 @@ private:
|
||||||
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(bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||||
virtual ~rk05();
|
virtual ~rk05();
|
||||||
|
|
||||||
|
void begin() override;
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
|
||||||
|
#if IS_POSIX
|
||||||
|
json_t *serialize() const;
|
||||||
|
static rk05 *deserialize(const json_t *const j, bus *const b);
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr) override;
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
uint16_t readWord(const uint16_t addr) override;
|
uint16_t readWord(const uint16_t addr) override;
|
||||||
|
|
||||||
|
|
21
rl02.cpp
21
rl02.cpp
|
@ -31,14 +31,11 @@ static const char * const commands[] = {
|
||||||
"read data w/o header check"
|
"read data w/o header check"
|
||||||
};
|
};
|
||||||
|
|
||||||
rl02::rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity) :
|
rl02::rl02(bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity) :
|
||||||
b(b),
|
b(b),
|
||||||
disk_read_activity (disk_read_activity ),
|
disk_read_activity (disk_read_activity ),
|
||||||
disk_write_activity(disk_write_activity)
|
disk_write_activity(disk_write_activity)
|
||||||
{
|
{
|
||||||
fhs = files;
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rl02::~rl02()
|
rl02::~rl02()
|
||||||
|
@ -47,6 +44,11 @@ rl02::~rl02()
|
||||||
delete fh;
|
delete fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rl02::begin()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
void rl02::reset()
|
void rl02::reset()
|
||||||
{
|
{
|
||||||
memset(registers, 0x00, sizeof registers );
|
memset(registers, 0x00, sizeof registers );
|
||||||
|
@ -86,11 +88,12 @@ rl02 *rl02::deserialize(const json_t *const j, bus *const b)
|
||||||
{
|
{
|
||||||
std::vector<disk_backend *> backends;
|
std::vector<disk_backend *> backends;
|
||||||
|
|
||||||
|
rl02 *r = new rl02(b, nullptr, nullptr);
|
||||||
|
r->begin();
|
||||||
|
|
||||||
json_t *j_backends = json_object_get(j, "backends");
|
json_t *j_backends = json_object_get(j, "backends");
|
||||||
for(size_t i=0; i<json_array_size(j_backends); i++)
|
for(size_t i=0; i<json_array_size(j_backends); i++)
|
||||||
backends.push_back(disk_backend::deserialize(json_array_get(j_backends, i)));
|
r->access_disk_backends()->push_back(disk_backend::deserialize(json_array_get(j_backends, i)));
|
||||||
|
|
||||||
rl02 *r = new rl02(backends, b, nullptr, nullptr);
|
|
||||||
|
|
||||||
for(int regnr=0; regnr<4; regnr++)
|
for(int regnr=0; regnr<4; regnr++)
|
||||||
r->registers[regnr] = json_integer_value(json_object_get(j, format("register-%d", regnr).c_str()));
|
r->registers[regnr] = json_integer_value(json_object_get(j, format("register-%d", regnr).c_str()));
|
||||||
|
@ -201,7 +204,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
||||||
bool do_int = false;
|
bool do_int = false;
|
||||||
|
|
||||||
if (size_t(device) >= fhs.size()) {
|
if (size_t(device) >= fhs.size()) {
|
||||||
DOLOG(info, false, "RL02: PDP11/70 is accessing a not-attached virtual disk %d", device);
|
DOLOG(info, false, "RL02: PDP11/70 is accessing virtual disk %d which is not attached", device);
|
||||||
|
|
||||||
registers[(RL02_CSR - RL02_BASE) / 2] |= (1 << 10) | (1 << 15);
|
registers[(RL02_CSR - RL02_BASE) / 2] |= (1 << 10) | (1 << 15);
|
||||||
|
|
||||||
|
@ -365,7 +368,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
||||||
*disk_read_activity = false;
|
*disk_read_activity = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DOLOG(warning, false, "RL02: command %d not implemented", command);
|
DOLOG(debug, false, "RL02: command %d not implemented", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_int) {
|
if (do_int) {
|
||||||
|
|
3
rl02.h
3
rl02.h
|
@ -47,9 +47,10 @@ private:
|
||||||
uint32_t calc_offset() const;
|
uint32_t calc_offset() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity);
|
rl02(bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity);
|
||||||
virtual ~rl02();
|
virtual ~rl02();
|
||||||
|
|
||||||
|
void begin() override;
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
|
||||||
#if IS_POSIX
|
#if IS_POSIX
|
||||||
|
|
12
tm-11.cpp
12
tm-11.cpp
|
@ -10,11 +10,8 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
tm_11::tm_11(const std::string & file, memory *const m) : m(m)
|
tm_11::tm_11(const std::string & file, memory *const m): file(file), m(m)
|
||||||
{
|
{
|
||||||
fh = fopen(file.c_str(), "rb");
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tm_11::~tm_11()
|
tm_11::~tm_11()
|
||||||
|
@ -22,6 +19,13 @@ tm_11::~tm_11()
|
||||||
fclose(fh);
|
fclose(fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tm_11::begin()
|
||||||
|
{
|
||||||
|
fh = fopen(file.c_str(), "rb");
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
void tm_11::reset()
|
void tm_11::reset()
|
||||||
{
|
{
|
||||||
memset(registers, 0x00, sizeof registers );
|
memset(registers, 0x00, sizeof registers );
|
||||||
|
|
3
tm-11.h
3
tm-11.h
|
@ -24,6 +24,7 @@ class memory;
|
||||||
class tm_11 : public device
|
class tm_11 : public device
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
std::string file;
|
||||||
memory *const m { nullptr };
|
memory *const m { nullptr };
|
||||||
uint16_t registers[6] { 0 };
|
uint16_t registers[6] { 0 };
|
||||||
uint8_t xfer_buffer[65536];
|
uint8_t xfer_buffer[65536];
|
||||||
|
@ -34,6 +35,8 @@ 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 begin();
|
||||||
|
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr) override;
|
uint8_t readByte(const uint16_t addr) override;
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void setBit(uint16_t & v, const int bit, const bool vb)
|
void setBit(uint16_t & v, const int bit, const bool vb)
|
||||||
|
@ -34,8 +36,8 @@ void setBit(uint16_t & v, const int bit, const bool vb)
|
||||||
|
|
||||||
std::string format(const char *const fmt, ...)
|
std::string format(const char *const fmt, ...)
|
||||||
{
|
{
|
||||||
#if defined(BUILD_FOR_RP2040)
|
#if defined(BUILD_FOR_RP2040) || defined(ESP32)
|
||||||
char buffer[128];
|
char buffer[256];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
Loading…
Add table
Reference in a new issue