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' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes libncurses-dev
|
||||
sudo apt-get install --yes libncurses-dev libjansson-dev
|
||||
|
||||
- name: Configure (cpp)
|
||||
if: ${{ matrix.language == 'cpp' }}
|
||||
|
|
|
@ -6,8 +6,10 @@ cmake_minimum_required(VERSION 3.9)
|
|||
|
||||
add_compile_options(-Wall -pedantic -Wextra)
|
||||
|
||||
#add_compile_options(-fsanitize=address)
|
||||
#add_link_options(-fsanitize=address)
|
||||
#add_compile_options(-fsanitize=undefined)
|
||||
#add_link_options(-fsanitize=undefined)
|
||||
|
||||
#add_compile_options(-fanalyzer)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
|
|
@ -72,7 +72,6 @@ void console_esp32::panel_update_thread()
|
|||
pixels.begin();
|
||||
|
||||
pixels.clear();
|
||||
|
||||
pixels.show();
|
||||
|
||||
constexpr uint8_t brightness = 16;
|
||||
|
@ -103,7 +102,7 @@ void console_esp32::panel_update_thread()
|
|||
pixels.clear();
|
||||
pixels.show();
|
||||
|
||||
for(;;) {
|
||||
while(!stop_panel) {
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
|
||||
try {
|
||||
|
@ -141,5 +140,10 @@ void console_esp32::panel_update_thread()
|
|||
put_string_lf("Unknown exception in panel thread");
|
||||
}
|
||||
}
|
||||
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
|
||||
Serial.println(F("panel task terminating"));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#include "esp_heap_caps.h"
|
||||
#endif
|
||||
|
||||
#if defined(SHA2017)
|
||||
#include "console_shabadge.h"
|
||||
|
@ -70,14 +73,13 @@ std::atomic_bool *running { nullptr };
|
|||
|
||||
bool trace_output { false };
|
||||
|
||||
std::vector<disk_backend *> rk05_files;
|
||||
std::vector<disk_backend *> rl02_files;
|
||||
|
||||
void console_thread_wrapper_panel(void *const c)
|
||||
{
|
||||
console *const cnsl = reinterpret_cast<console *>(c);
|
||||
|
||||
cnsl->panel_update_thread();
|
||||
|
||||
vTaskSuspend(nullptr);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
#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() {
|
||||
Serial.begin(115200);
|
||||
|
||||
|
@ -222,6 +232,10 @@ void setup() {
|
|||
Serial.print(F("Size of 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)
|
||||
Serial.print(F("CPU clock frequency (MHz): "));
|
||||
Serial.println(getCpuFrequencyMhz());
|
||||
|
@ -296,13 +310,19 @@ void setup() {
|
|||
cnsl = new console_esp32(&stop_event, serial_ports, 80, 25);
|
||||
#endif
|
||||
cnsl->set_bus(b);
|
||||
cnsl->begin();
|
||||
|
||||
running = cnsl->get_running_flag();
|
||||
|
||||
Serial.println(F("Connect RK05 and RL02 to BUS"));
|
||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
Serial.println(F("Connect RK05 and RL02 devices to BUS"));
|
||||
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"));
|
||||
tty_ = new tty(cnsl, b);
|
||||
|
@ -311,7 +331,7 @@ void setup() {
|
|||
|
||||
#if !defined(BUILD_FOR_RP2040) // FIXME: led ring
|
||||
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
|
||||
|
||||
#if !defined(BUILD_FOR_RP2040)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#! /usr/bin/python3
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
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)
|
||||
return ret.stdout.strip() + add
|
||||
|
||||
|
||||
fh = open('version.cpp', 'w')
|
||||
fh.write('const char *version_str = "' + get_git_hash() + '";\n')
|
||||
fh.close()
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../win32.cpp
|
|
@ -1 +0,0 @@
|
|||
../win32.h
|
|
@ -11,6 +11,7 @@ To build for e.g. linux:
|
|||
|
||||
Required:
|
||||
* libncursesw5-dev
|
||||
* libjansson-dev
|
||||
|
||||
To build for e.g. windows:
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ std::optional<std::string> breakpoint_memory::is_triggered() const
|
|||
if (it == values.end())
|
||||
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)
|
||||
|
@ -41,7 +41,7 @@ std::pair<breakpoint_memory *, std::optional<std::string> > breakpoint_memory::p
|
|||
return { nullptr, "memory: key or value missing" };
|
||||
|
||||
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;
|
||||
for(auto & v: v_parts)
|
||||
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") {
|
||||
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';
|
||||
|
||||
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), { } };
|
||||
}
|
||||
|
||||
|
|
30
bus.cpp
30
bus.cpp
|
@ -24,6 +24,7 @@
|
|||
bus::bus()
|
||||
{
|
||||
mmu_ = new mmu();
|
||||
mmu_->begin();
|
||||
|
||||
kw11_l_ = new kw11_l(this);
|
||||
|
||||
|
@ -65,7 +66,10 @@ json_t *bus::serialize() const
|
|||
if (rl02_)
|
||||
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;
|
||||
}
|
||||
|
@ -112,7 +116,13 @@ bus *bus::deserialize(const json_t *const j, console *const cnsl, std::atomic_ui
|
|||
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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
this->n_pages = n_pages;
|
||||
|
||||
uint32_t n_bytes = n_pages * 8192l;
|
||||
|
||||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
if (m_offset >= uint32_t(n_pages * 8192)) {
|
||||
if (m_offset >= m->get_memory_size()) {
|
||||
if (peek_only) {
|
||||
DOLOG(debug, false, "READ from %06o - out of range!", addr_in);
|
||||
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]] {
|
||||
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192l);
|
||||
if (m_offset >= m->get_memory_size() && !is_io) [[unlikely]] {
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (m_offset >= uint32_t(n_pages * 8192)) {
|
||||
if (m_offset >= m->get_memory_size()) {
|
||||
c->trap(004); // no such RAM
|
||||
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);
|
||||
|
||||
if (a >= n_pages * 8192l) {
|
||||
if (a >= m->get_memory_size()) {
|
||||
DOLOG(debug, false, "physicalWRITE to %o: trap 004", a);
|
||||
c->trap(004);
|
||||
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)
|
||||
{
|
||||
if (a >= n_pages * 8192l) {
|
||||
if (a >= m->get_memory_size()) {
|
||||
DOLOG(debug, false, "physicalREAD from %o: trap 004", a);
|
||||
c->trap(004);
|
||||
throw 13;
|
||||
|
|
4
bus.h
4
bus.h
|
@ -75,10 +75,7 @@ private:
|
|||
rl02 *rl02_ { nullptr };
|
||||
tty *tty_ { nullptr };
|
||||
kw11_l *kw11_l_ { nullptr };
|
||||
|
||||
mmu *mmu_ { nullptr };
|
||||
|
||||
int n_pages { DEFAULT_N_PAGES };
|
||||
memory *m { nullptr };
|
||||
|
||||
uint16_t microprogram_break_register { 0 };
|
||||
|
@ -104,7 +101,6 @@ public:
|
|||
void set_debug_mode() { console_switches |= 128; }
|
||||
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 mmudebug(const uint16_t a);
|
||||
|
|
31
console.cpp
31
console.cpp
|
@ -46,6 +46,10 @@ console::~console()
|
|||
delete [] screen_buffer;
|
||||
}
|
||||
|
||||
void console::begin()
|
||||
{
|
||||
}
|
||||
|
||||
void console::start_thread()
|
||||
{
|
||||
assert(b);
|
||||
|
@ -266,33 +270,6 @@ std::string console::read_line(const std::string & prompt)
|
|||
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)
|
||||
{
|
||||
put_char_ll(c);
|
||||
|
|
|
@ -30,6 +30,7 @@ private:
|
|||
|
||||
protected:
|
||||
std::atomic_uint32_t *const stop_event { nullptr };
|
||||
std::atomic_bool stop_panel { false };
|
||||
|
||||
bus *b { nullptr };
|
||||
#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);
|
||||
virtual ~console();
|
||||
|
||||
virtual void begin();
|
||||
|
||||
void set_bus(bus *const b) { this->b = b; }
|
||||
|
||||
void start_thread();
|
||||
|
@ -76,8 +79,6 @@ public:
|
|||
void put_string(const std::string & what);
|
||||
virtual void put_string_lf(const std::string & what) = 0;
|
||||
|
||||
void debug(const std::string fmt, ...);
|
||||
|
||||
virtual void resize_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_write_activity_flag() { return &disk_write_activity_flag; }
|
||||
|
||||
void stop_panel_thread() { stop_panel = true; }
|
||||
virtual void panel_update_thread() = 0;
|
||||
};
|
||||
|
|
|
@ -16,10 +16,6 @@
|
|||
console_ncurses::console_ncurses(std::atomic_uint32_t *const stop_event): console(stop_event)
|
||||
{
|
||||
init_ncurses(true);
|
||||
|
||||
resize_terminal();
|
||||
|
||||
th_panel = new std::thread(&console_ncurses::panel_update_thread, this);
|
||||
}
|
||||
|
||||
console_ncurses::~console_ncurses()
|
||||
|
@ -51,6 +47,13 @@ console_ncurses::~console_ncurses()
|
|||
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)
|
||||
{
|
||||
struct pollfd fds[] = { { STDIN_FILENO, POLLIN, 0 } };
|
||||
|
@ -133,7 +136,7 @@ void console_ncurses::panel_update_thread()
|
|||
|
||||
constexpr int refresh_rate = 50;
|
||||
|
||||
while(*stop_event != EVENT_TERMINATE) {
|
||||
while(*stop_event != EVENT_TERMINATE && stop_panel == false) {
|
||||
myusleep(1000000 / refresh_rate);
|
||||
|
||||
// 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];
|
||||
|
||||
std::string instruction_values;
|
||||
for(auto iv : data["instruction-values"])
|
||||
for(auto & iv : data["instruction-values"])
|
||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||
|
||||
std::string work_values;
|
||||
for(auto wv : data["work-values"])
|
||||
for(auto & wv : data["work-values"])
|
||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||
|
||||
std::string instruction = data["instruction-text"].at(0);
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
console_ncurses(std::atomic_uint32_t *const stop_event);
|
||||
virtual ~console_ncurses();
|
||||
|
||||
void begin() override;
|
||||
|
||||
void put_string_lf(const std::string & what) 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
|
||||
{
|
||||
if (nr < 6) {
|
||||
int set = getBitPSW(11);
|
||||
int set = get_register_set();
|
||||
|
||||
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)
|
||||
{
|
||||
if (nr < 6) {
|
||||
int set = getBitPSW(11);
|
||||
int set = get_register_set();
|
||||
|
||||
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)
|
||||
{
|
||||
if (nr < 6)
|
||||
return regs0_5[getBitPSW(11)][nr] += value;
|
||||
return regs0_5[get_register_set()][nr] += value;
|
||||
|
||||
if (nr == 6) {
|
||||
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_reg = dst & 7;
|
||||
|
||||
bool set_flags = true;
|
||||
|
||||
switch(operation) {
|
||||
case 0b001: { // MOV/MOVB Move Word/Byte
|
||||
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)
|
||||
setRegister(dst_reg, int8_t(g_src.value.value())); // int8_t: sign extension
|
||||
else {
|
||||
|
@ -715,7 +715,7 @@ bool cpu::double_operand_instructions(const uint16_t instr)
|
|||
setPSW_z(result == 0);
|
||||
}
|
||||
|
||||
putGAM(g_dst, result);
|
||||
(void)putGAM(g_dst, result);
|
||||
|
||||
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_reg = dst & 7;
|
||||
const word_mode_t word_mode = instr & 0x8000 ? wm_byte : wm_word;
|
||||
bool set_flags = true;
|
||||
|
||||
switch(opcode) {
|
||||
case 0b00000011: { // SWAB
|
||||
|
@ -959,7 +958,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
|
||||
v = (v << 8) | (v >> 8);
|
||||
|
||||
set_flags = putGAM(g_dst, v);
|
||||
bool set_flags = putGAM(g_dst, v);
|
||||
|
||||
if (set_flags) {
|
||||
setPSW_flags_nzv(v, wm_byte);
|
||||
|
|
1
cpu.h
1
cpu.h
|
@ -160,6 +160,7 @@ public:
|
|||
bool getBitPSW(const int bit) const;
|
||||
int getPSW_runmode() const { return psw >> 14; };
|
||||
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_v(const bool v);
|
||||
|
|
69
debugger.cpp
69
debugger.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "disk_backend_nbd.h"
|
||||
#include "loaders.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "tty.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -37,13 +38,9 @@
|
|||
#include "rp2040.h"
|
||||
#endif
|
||||
|
||||
void set_boot_loader(bus *const b);
|
||||
|
||||
void configure_disk(console *const c);
|
||||
|
||||
void configure_network(console *const c);
|
||||
void check_network(console *const c);
|
||||
void start_network(console *const c);
|
||||
void configure_network(console *const cnsl);
|
||||
void check_network(console *const cnsl);
|
||||
void start_network(console *const cnsl);
|
||||
|
||||
void set_tty_serial_speed(console *const c, const uint32_t bps);
|
||||
#endif
|
||||
|
@ -85,10 +82,10 @@ std::optional<disk_backend *> select_disk_file(console *const c)
|
|||
#if IS_POSIX
|
||||
c->put_string_lf("Files in current directory: ");
|
||||
#else
|
||||
c->debug("MISO: %d", int(MISO));
|
||||
c->debug("MOSI: %d", int(MOSI));
|
||||
c->debug("SCK : %d", int(SCK ));
|
||||
c->debug("SS : %d", int(SS ));
|
||||
c->put_string_lf(format("MISO: %d", int(MISO)));
|
||||
c->put_string_lf(format("MOSI: %d", int(MOSI)));
|
||||
c->put_string_lf(format("SCK : %d", int(SCK )));
|
||||
c->put_string_lf(format("SS : %d", int(SS )));
|
||||
|
||||
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))) {
|
||||
auto err = SD.sdErrorCode();
|
||||
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
|
||||
c->debug("Failed to initialize SD card");
|
||||
c->put_string_lf("Failed to initialize SD card");
|
||||
|
||||
return { };
|
||||
}
|
||||
|
@ -239,20 +236,20 @@ std::optional<disk_backend *> select_disk_backend(console *const cnsl)
|
|||
void configure_disk(bus *const b, console *const cnsl)
|
||||
{
|
||||
// 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;
|
||||
disk_device *dd = nullptr;
|
||||
|
||||
if (ch == '1') {
|
||||
if (type_ch == '1') {
|
||||
dd = b->getRK05();
|
||||
bl = BL_RK05;
|
||||
}
|
||||
else if (ch == '2') {
|
||||
else if (type_ch == '2') {
|
||||
dd = b->getRL02();
|
||||
bl = BL_RL02;
|
||||
}
|
||||
else if (ch == '9') {
|
||||
else if (type_ch == '9') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -289,11 +286,11 @@ void configure_disk(bus *const b, console *const cnsl)
|
|||
int slot = ch - 'A';
|
||||
|
||||
for(;;) {
|
||||
int ch = wait_for_key("Select cartridge action: 1. load, 2. unload, 9. exit", cnsl, { '1', '2', '9' });
|
||||
if (ch == '9')
|
||||
int ch_action = wait_for_key("Select cartridge action: 1. load, 2. unload, 9. exit", cnsl, { '1', '2', '9' });
|
||||
if (ch_action == '9')
|
||||
break;
|
||||
|
||||
if (ch == '1') {
|
||||
if (ch_action == '1') {
|
||||
auto image_file = select_disk_backend(cnsl);
|
||||
|
||||
if (image_file.has_value()) {
|
||||
|
@ -303,7 +300,7 @@ void configure_disk(bus *const b, console *const cnsl)
|
|||
cnsl->put_string_lf("Cartridge loaded");
|
||||
}
|
||||
}
|
||||
else if (ch == '2') {
|
||||
else if (ch_action == '2') {
|
||||
if (cartridge_slots->at(slot)) {
|
||||
delete cartridge_slots->at(slot);
|
||||
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];
|
||||
|
||||
std::string instruction_values;
|
||||
for(auto iv : data["instruction-values"])
|
||||
for(auto & iv : data["instruction-values"])
|
||||
instruction_values += (instruction_values.empty() ? "" : ",") + iv;
|
||||
|
||||
std::string work_values;
|
||||
for(auto wv : data["work-values"])
|
||||
for(auto & wv : data["work-values"])
|
||||
work_values += (work_values.empty() ? "" : ",") + wv;
|
||||
|
||||
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)
|
||||
cnsl->debug(result);
|
||||
cnsl->put_string_lf(result);
|
||||
else
|
||||
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;
|
||||
|
||||
for(auto pair : kv_array) {
|
||||
for(auto & pair : kv_array) {
|
||||
auto kv = split(pair, splitter);
|
||||
|
||||
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:");
|
||||
|
||||
for(auto a : bps)
|
||||
for(auto & a : bps)
|
||||
cnsl->put_string_lf(format("%d: %s", a.first, a.second->emit().c_str()));
|
||||
|
||||
if (bps.empty())
|
||||
|
@ -825,6 +822,12 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
continue;
|
||||
}
|
||||
#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") {
|
||||
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)
|
||||
b->set_memory_size(std::stoi(parts.at(1)));
|
||||
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));
|
||||
}
|
||||
|
@ -942,7 +945,10 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
}
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
@ -951,6 +957,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "dp") {
|
||||
cnsl->stop_panel_thread();
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "bt") {
|
||||
if (c->get_debug() == false)
|
||||
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",
|
||||
// "dser - deserialize state from a file",
|
||||
#endif
|
||||
"dp - disable panel",
|
||||
#if defined(ESP32)
|
||||
"cfgnet - configure network (e.g. WiFi)",
|
||||
"startnet - start network",
|
||||
"chknet - check network status",
|
||||
"serspd - set serial speed in bps (8N1 are default)",
|
||||
"debug - debugging info",
|
||||
#endif
|
||||
"cfgdisk - configure disk",
|
||||
nullptr
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "disk_backend.h"
|
||||
#include "gen.h"
|
||||
#if IS_POSIX
|
||||
#include "disk_backend_file.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++)
|
||||
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;
|
||||
|
|
|
@ -137,7 +137,7 @@ bool disk_backend_nbd::connect(const bool retry)
|
|||
uint64_t size;
|
||||
uint32_t flags;
|
||||
uint8_t padding[124];
|
||||
} nbd_hello;
|
||||
} nbd_hello { };
|
||||
|
||||
if (fd != -1) {
|
||||
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 offset;
|
||||
uint32_t length;
|
||||
} nbd_request { 0 };
|
||||
} nbd_request { };
|
||||
|
||||
nbd_request.magic = ntohl(0x25609513);
|
||||
nbd_request.type = 0; // READ
|
||||
|
|
|
@ -18,5 +18,7 @@ public:
|
|||
virtual ~disk_device() {
|
||||
}
|
||||
|
||||
virtual void begin() = 0;
|
||||
|
||||
std::vector<disk_backend *> * access_disk_backends() { return &fhs; }
|
||||
};
|
||||
|
|
12
loaders.cpp
12
loaders.cpp
|
@ -40,7 +40,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
|||
if (which == BL_RK05) {
|
||||
start = offset = 01000;
|
||||
|
||||
static uint16_t rk05_code[] = {
|
||||
static const uint16_t rk05_code[] = {
|
||||
0012700,
|
||||
0177406,
|
||||
0012710,
|
||||
|
@ -92,7 +92,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
|||
start = offset = 01000;
|
||||
|
||||
/* from https://www.pdp-11.nl/peripherals/disk/rl-info.html
|
||||
static uint16_t rl02_code[] = {
|
||||
static const uint16_t rl02_code[] = {
|
||||
0012701,
|
||||
0174400,
|
||||
0012761,
|
||||
|
@ -120,7 +120,7 @@ void set_boot_loader(bus *const b, const bootloader_t which)
|
|||
*/
|
||||
|
||||
// from http://gunkies.org/wiki/RL11_disk_controller
|
||||
static uint16_t rl02_code[] = {
|
||||
static const uint16_t rl02_code[] = {
|
||||
0012700,
|
||||
0174400,
|
||||
0012760,
|
||||
|
@ -207,7 +207,11 @@ std::optional<uint16_t> load_tape(bus *const b, const std::string & file)
|
|||
break;
|
||||
}
|
||||
|
||||
uint8_t c = fgetc(fh);
|
||||
int c = fgetc(fh);
|
||||
if (c == -1) {
|
||||
DOLOG(warning, true, "read failure");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
csum += c;
|
||||
|
|
71
log.cpp
71
log.cpp
|
@ -15,7 +15,9 @@
|
|||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
#if defined(_WIN32)
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
|
||||
static const char *logfile = strdup("/tmp/kek.log");
|
||||
|
@ -23,10 +25,12 @@ static sockaddr_in syslog_ip_addr = { };
|
|||
static bool is_file = true;
|
||||
log_level_t log_level_file = warning;
|
||||
log_level_t log_level_screen = warning;
|
||||
FILE *lfh = nullptr;
|
||||
static FILE *log_fh = nullptr;
|
||||
static int lf_uid = -1;
|
||||
static int lf_gid = -1;
|
||||
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)
|
||||
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)
|
||||
{
|
||||
if (lfh)
|
||||
fclose(lfh);
|
||||
if (log_fh)
|
||||
fclose(log_fh);
|
||||
|
||||
free((void *)logfile);
|
||||
|
||||
|
@ -54,9 +58,10 @@ void setlogfile(const char *const lf, const log_level_t ll_file, const log_level
|
|||
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;
|
||||
bool ok = inet_aton(host, &syslog_ip_addr.sin_addr) == 1;
|
||||
syslog_ip_addr.sin_port = htons(514);
|
||||
|
||||
is_file = false;
|
||||
|
@ -64,6 +69,8 @@ void setloghost(const char *const host, const log_level_t ll)
|
|||
log_level_file = ll;
|
||||
|
||||
l_timestamp = false;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void setll(const log_level_t ll_screen, const log_level_t ll_file)
|
||||
|
@ -83,44 +90,52 @@ void send_syslog(const int ll, const std::string & what)
|
|||
std::string msg = format("<%d>%s", 16 * 8 + ll, what.c_str());
|
||||
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s != -1) {
|
||||
(void)sendto(s, msg.c_str(), msg.size(), 0, reinterpret_cast<sockaddr *>(&syslog_ip_addr), sizeof syslog_ip_addr);
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
|
||||
void closelog()
|
||||
{
|
||||
if (lfh) {
|
||||
fclose(lfh);
|
||||
if (log_fh) {
|
||||
fclose(log_fh);
|
||||
|
||||
lfh = nullptr;
|
||||
log_fh = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void dolog(const log_level_t ll, const char *fmt, ...)
|
||||
{
|
||||
#if !defined(BUILD_FOR_RP2040)
|
||||
if (!lfh && logfile != nullptr) {
|
||||
if (!log_fh && logfile != nullptr) {
|
||||
#if !defined(ESP32)
|
||||
lfh = fopen(logfile, "a+");
|
||||
if (!lfh)
|
||||
log_fh = fopen(logfile, "a+");
|
||||
if (!log_fh)
|
||||
error_exit(true, "Cannot access log-file %s", logfile);
|
||||
#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);
|
||||
|
||||
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");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
char *str = nullptr;
|
||||
|
||||
for(;;) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(void)vasprintf(&str, fmt, ap);
|
||||
int needed_length = vsnprintf(log_buffer, log_buffer_size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (needed_length < log_buffer_size)
|
||||
break;
|
||||
|
||||
log_buffer_size *= 2;
|
||||
log_buffer = reinterpret_cast<char *>(realloc(log_buffer, log_buffer_size));
|
||||
}
|
||||
|
||||
if (l_timestamp) {
|
||||
uint64_t now = get_us();
|
||||
time_t t_now = now / 1000000;
|
||||
|
@ -132,39 +147,35 @@ void dolog(const log_level_t ll, const char *fmt, ...)
|
|||
if (!localtime_r(&t_now, &tm))
|
||||
error_exit(true, "localtime_r failed");
|
||||
#endif
|
||||
char *ts_str = nullptr;
|
||||
char ts_str[64] { };
|
||||
|
||||
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),
|
||||
ll_names[ll], get_thread_name().c_str());
|
||||
|
||||
if (ll <= log_level_file && is_file == false)
|
||||
send_syslog(ll, str);
|
||||
send_syslog(ll, log_buffer);
|
||||
#if !defined(ESP32)
|
||||
if (ll <= log_level_file && lfh != nullptr)
|
||||
fprintf(lfh, "%s%s\n", ts_str, str);
|
||||
if (ll <= log_level_file && log_fh != nullptr)
|
||||
fprintf(log_fh, "%s%s\n", ts_str, log_buffer);
|
||||
#endif
|
||||
|
||||
if (ll <= log_level_screen)
|
||||
printf("%s%s\r\n", ts_str, str);
|
||||
|
||||
free(ts_str);
|
||||
printf("%s%s\r\n", ts_str, log_buffer);
|
||||
}
|
||||
else {
|
||||
if (ll <= log_level_file && is_file == false)
|
||||
send_syslog(ll, str);
|
||||
send_syslog(ll, log_buffer);
|
||||
#if !defined(ESP32)
|
||||
if (ll <= log_level_file && lfh != nullptr)
|
||||
fprintf(lfh, "%s\n", str);
|
||||
if (ll <= log_level_file && log_fh != nullptr)
|
||||
fprintf(log_fh, "%s\n", log_buffer);
|
||||
#endif
|
||||
|
||||
if (ll <= log_level_screen)
|
||||
printf("%s\r\n", str);
|
||||
printf("%s\r\n", log_buffer);
|
||||
}
|
||||
|
||||
free(str);
|
||||
#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);
|
||||
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 setloguid(const int uid, const int gid);
|
||||
void send_syslog(const int ll, const std::string & what);
|
||||
void closelog();
|
||||
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");
|
||||
size_t array_size = json_array_size(b_sp);
|
||||
assert(array_size == 4);
|
||||
for(size_t i=0; i<array_size; i++) {
|
||||
size_t sp_array_size = json_array_size(b_sp);
|
||||
assert(sp_array_size == 4);
|
||||
for(size_t i=0; i<sp_array_size; i++) {
|
||||
json_t *temp = json_array_get(b_sp, i);
|
||||
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");
|
||||
size_t array_size = json_array_size(a_sp);
|
||||
assert(array_size == 4);
|
||||
for(size_t i=0; i<array_size; i++) {
|
||||
size_t sp_array_size = json_array_size(a_sp);
|
||||
assert(sp_array_size == 4);
|
||||
for(size_t i=0; i<sp_array_size; i++) {
|
||||
json_t *temp = json_array_get(a_sp, i);
|
||||
uint16_t sp = c->lowlevel_register_sp_get(i);
|
||||
if (json_integer_value(temp) != sp) {
|
||||
|
@ -525,18 +525,30 @@ int main(int argc, char *argv[])
|
|||
cpu *c = new cpu(b, &event);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
for(auto & file: rl02_files)
|
||||
rl02_dev->access_disk_backends()->push_back(file);
|
||||
}
|
||||
|
||||
if (enable_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 {
|
||||
FILE *fh = fopen(deserialize.c_str(), "r");
|
||||
|
@ -566,6 +578,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
cnsl->set_bus(b);
|
||||
cnsl->begin();
|
||||
|
||||
running = cnsl->get_running_flag();
|
||||
|
||||
|
|
2
memory.h
2
memory.h
|
@ -21,6 +21,8 @@ public:
|
|||
memory(const uint32_t size);
|
||||
~memory();
|
||||
|
||||
uint32_t get_memory_size() const { return size; }
|
||||
|
||||
void reset();
|
||||
#if IS_POSIX
|
||||
json_t *serialize() const;
|
||||
|
|
19
mmu.cpp
19
mmu.cpp
|
@ -15,6 +15,11 @@ mmu::~mmu()
|
|||
{
|
||||
}
|
||||
|
||||
void mmu::begin()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void mmu::reset()
|
||||
{
|
||||
memset(pages, 0x00, sizeof pages);
|
||||
|
@ -52,8 +57,6 @@ void mmu::setMMR0(uint16_t value)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -102,17 +105,6 @@ void mmu::addToMMR1(const int8_t delta, const uint8_t reg)
|
|||
|
||||
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;
|
||||
|
@ -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 *m = new mmu();
|
||||
m->begin();
|
||||
|
||||
for(int run_mode=0; run_mode<4; run_mode++) {
|
||||
if (run_mode == 2)
|
||||
|
|
2
mmu.h
2
mmu.h
|
@ -50,6 +50,8 @@ public:
|
|||
mmu();
|
||||
virtual ~mmu();
|
||||
|
||||
void begin();
|
||||
|
||||
#if IS_POSIX
|
||||
json_t *serialize() const;
|
||||
static mmu *deserialize(const json_t *const j);
|
||||
|
|
53
rk05.cpp
53
rk05.cpp
|
@ -23,14 +23,11 @@ static const char * const regnames[] = {
|
|||
"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),
|
||||
disk_read_acitivity(disk_read_acitivity),
|
||||
disk_write_acitivity(disk_write_acitivity)
|
||||
{
|
||||
fhs = files;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
rk05::~rk05()
|
||||
|
@ -39,6 +36,11 @@ rk05::~rk05()
|
|||
delete fh;
|
||||
}
|
||||
|
||||
void rk05::begin()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void rk05::reset()
|
||||
{
|
||||
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 = reclen;
|
||||
uint32_t temp_reclen = reclen;
|
||||
uint32_t p = memoff;
|
||||
while(temp > 0) {
|
||||
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp);
|
||||
while(temp_reclen > 0) {
|
||||
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp_reclen);
|
||||
|
||||
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);
|
||||
|
@ -205,7 +207,7 @@ void rk05::writeWord(const uint16_t addr, const uint16_t v)
|
|||
update_bus_address(2);
|
||||
}
|
||||
|
||||
temp -= cur;
|
||||
temp_reclen -= cur;
|
||||
|
||||
if (++sector >= 12) {
|
||||
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_backend.h"
|
||||
#include "gen.h"
|
||||
|
||||
|
||||
#define RK05_DS 0177400 // drive status
|
||||
|
@ -39,11 +40,17 @@ private:
|
|||
void update_bus_address(const uint16_t v);
|
||||
|
||||
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();
|
||||
|
||||
void begin() 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;
|
||||
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"
|
||||
};
|
||||
|
||||
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),
|
||||
disk_read_activity (disk_read_activity ),
|
||||
disk_write_activity(disk_write_activity)
|
||||
{
|
||||
fhs = files;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
rl02::~rl02()
|
||||
|
@ -47,6 +44,11 @@ rl02::~rl02()
|
|||
delete fh;
|
||||
}
|
||||
|
||||
void rl02::begin()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void rl02::reset()
|
||||
{
|
||||
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;
|
||||
|
||||
rl02 *r = new rl02(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++)
|
||||
backends.push_back(disk_backend::deserialize(json_array_get(j_backends, i)));
|
||||
|
||||
rl02 *r = new rl02(backends, b, nullptr, nullptr);
|
||||
r->access_disk_backends()->push_back(disk_backend::deserialize(json_array_get(j_backends, i)));
|
||||
|
||||
for(int regnr=0; regnr<4; regnr++)
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -365,7 +368,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
|||
*disk_read_activity = false;
|
||||
}
|
||||
else {
|
||||
DOLOG(warning, false, "RL02: command %d not implemented", command);
|
||||
DOLOG(debug, false, "RL02: command %d not implemented", command);
|
||||
}
|
||||
|
||||
if (do_int) {
|
||||
|
|
3
rl02.h
3
rl02.h
|
@ -47,9 +47,10 @@ private:
|
|||
uint32_t calc_offset() const;
|
||||
|
||||
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();
|
||||
|
||||
void begin() override;
|
||||
void reset() override;
|
||||
|
||||
#if IS_POSIX
|
||||
|
|
12
tm-11.cpp
12
tm-11.cpp
|
@ -10,11 +10,8 @@
|
|||
#include "memory.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()
|
||||
|
@ -22,6 +19,13 @@ tm_11::~tm_11()
|
|||
fclose(fh);
|
||||
}
|
||||
|
||||
void tm_11::begin()
|
||||
{
|
||||
fh = fopen(file.c_str(), "rb");
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void tm_11::reset()
|
||||
{
|
||||
memset(registers, 0x00, sizeof registers );
|
||||
|
|
3
tm-11.h
3
tm-11.h
|
@ -24,6 +24,7 @@ class memory;
|
|||
class tm_11 : public device
|
||||
{
|
||||
private:
|
||||
std::string file;
|
||||
memory *const m { nullptr };
|
||||
uint16_t registers[6] { 0 };
|
||||
uint8_t xfer_buffer[65536];
|
||||
|
@ -34,6 +35,8 @@ public:
|
|||
tm_11(const std::string & file, memory *const m);
|
||||
virtual ~tm_11();
|
||||
|
||||
void begin();
|
||||
|
||||
void reset() override;
|
||||
|
||||
uint8_t readByte(const uint16_t addr) override;
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
|
||||
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, ...)
|
||||
{
|
||||
#if defined(BUILD_FOR_RP2040)
|
||||
char buffer[128];
|
||||
#if defined(BUILD_FOR_RP2040) || defined(ESP32)
|
||||
char buffer[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
|
Loading…
Add table
Reference in a new issue