diff --git a/ESP32/console_esp32.cpp b/ESP32/console_esp32.cpp
index f63c22f..ba5912c 100644
--- a/ESP32/console_esp32.cpp
+++ b/ESP32/console_esp32.cpp
@@ -110,7 +110,7 @@ void console_esp32::panel_update_thread()
int run_mode = current_PSW >> 14;
uint16_t current_PC = c->getPC();
- uint32_t full_addr = b->calculate_physical_address(run_mode, current_PC, false, false, true, i_space);
+ uint32_t full_addr = b->getMMU()->calculate_physical_address(c, run_mode, current_PC, false, false, true, i_space);
uint16_t current_instr = b->read_word(current_PC);
diff --git a/ESP32/main.ino b/ESP32/main.ino
index 890003f..d935d5d 100644
--- a/ESP32/main.ino
+++ b/ESP32/main.ino
@@ -44,6 +44,7 @@
#include "kw11-l.h"
#include "loaders.h"
#include "memory.h"
+#include "tm-11.h"
#include "tty.h"
#include "utils.h"
#include "version.h"
@@ -364,6 +365,9 @@ void setup() {
tty_ = new tty(cnsl, b);
b->add_tty(tty_);
+ Serial.println(F("* Adding TM-11"));
+ b->add_tm11(new tm_11(b));
+
Serial.println(F("* Starting KW11-L"));
b->getKW11_L()->begin(cnsl);
diff --git a/ESP32/platformio.ini b/ESP32/platformio.ini
index 7b310ee..890e60c 100644
--- a/ESP32/platformio.ini
+++ b/ESP32/platformio.ini
@@ -65,3 +65,18 @@ lib_deps = greiman/SdFat@^2.1.2
build_flags = -std=gnu++17 -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_USE_MALLOC
build_unflags = -std=gnu++11
extra_scripts = pre:prepare.py
+
+[env:lolin_s2_mini]
+platform = espressif32
+board = lolin_s2_mini
+build_src_filter = +<*> -<.git/> -<.svn/> - - - - - - - -
+framework = arduino
+monitor_speed = 115200
+upload_speed = 1000000
+board_build.filesystem = littlefs
+lib_deps = greiman/SdFat@^2.1.2
+ adafruit/Adafruit NeoPixel
+ bblanchon/ArduinoJson@^6.19.4
+build_flags = -std=gnu++17 -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_USE_MALLOC
+build_unflags = -std=gnu++11
+extra_scripts = pre:prepare.py
diff --git a/RP2040/breakpoint.cpp b/RP2040/breakpoint.cpp
new file mode 120000
index 0000000..f2da141
--- /dev/null
+++ b/RP2040/breakpoint.cpp
@@ -0,0 +1 @@
+../breakpoint.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint.h b/RP2040/breakpoint.h
new file mode 120000
index 0000000..7375cc3
--- /dev/null
+++ b/RP2040/breakpoint.h
@@ -0,0 +1 @@
+../breakpoint.h
\ No newline at end of file
diff --git a/RP2040/breakpoint_and.cpp b/RP2040/breakpoint_and.cpp
new file mode 120000
index 0000000..a852384
--- /dev/null
+++ b/RP2040/breakpoint_and.cpp
@@ -0,0 +1 @@
+../breakpoint_and.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint_and.h b/RP2040/breakpoint_and.h
new file mode 120000
index 0000000..f2dd9b4
--- /dev/null
+++ b/RP2040/breakpoint_and.h
@@ -0,0 +1 @@
+../breakpoint_and.h
\ No newline at end of file
diff --git a/RP2040/breakpoint_memory.cpp b/RP2040/breakpoint_memory.cpp
new file mode 120000
index 0000000..d828241
--- /dev/null
+++ b/RP2040/breakpoint_memory.cpp
@@ -0,0 +1 @@
+../breakpoint_memory.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint_memory.h b/RP2040/breakpoint_memory.h
new file mode 120000
index 0000000..c5b08ad
--- /dev/null
+++ b/RP2040/breakpoint_memory.h
@@ -0,0 +1 @@
+../breakpoint_memory.h
\ No newline at end of file
diff --git a/RP2040/breakpoint_or.cpp b/RP2040/breakpoint_or.cpp
new file mode 120000
index 0000000..3790a41
--- /dev/null
+++ b/RP2040/breakpoint_or.cpp
@@ -0,0 +1 @@
+../breakpoint_or.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint_or.h b/RP2040/breakpoint_or.h
new file mode 120000
index 0000000..196a64e
--- /dev/null
+++ b/RP2040/breakpoint_or.h
@@ -0,0 +1 @@
+../breakpoint_or.h
\ No newline at end of file
diff --git a/RP2040/breakpoint_parser.cpp b/RP2040/breakpoint_parser.cpp
new file mode 120000
index 0000000..881330e
--- /dev/null
+++ b/RP2040/breakpoint_parser.cpp
@@ -0,0 +1 @@
+../breakpoint_parser.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint_parser.h b/RP2040/breakpoint_parser.h
new file mode 120000
index 0000000..f409493
--- /dev/null
+++ b/RP2040/breakpoint_parser.h
@@ -0,0 +1 @@
+../breakpoint_parser.h
\ No newline at end of file
diff --git a/RP2040/breakpoint_register.cpp b/RP2040/breakpoint_register.cpp
new file mode 120000
index 0000000..711d9b4
--- /dev/null
+++ b/RP2040/breakpoint_register.cpp
@@ -0,0 +1 @@
+../breakpoint_register.cpp
\ No newline at end of file
diff --git a/RP2040/breakpoint_register.h b/RP2040/breakpoint_register.h
new file mode 120000
index 0000000..29e0d15
--- /dev/null
+++ b/RP2040/breakpoint_register.h
@@ -0,0 +1 @@
+../breakpoint_register.h
\ No newline at end of file
diff --git a/RP2040/mmu.cpp b/RP2040/mmu.cpp
new file mode 120000
index 0000000..b83d63b
--- /dev/null
+++ b/RP2040/mmu.cpp
@@ -0,0 +1 @@
+../mmu.cpp
\ No newline at end of file
diff --git a/RP2040/mmu.h b/RP2040/mmu.h
new file mode 120000
index 0000000..cc56dfb
--- /dev/null
+++ b/RP2040/mmu.h
@@ -0,0 +1 @@
+../mmu.h
\ No newline at end of file
diff --git a/cpu.cpp b/cpu.cpp
index 103dc01..6eca7c0 100644
--- a/cpu.cpp
+++ b/cpu.cpp
@@ -18,6 +18,12 @@
#define IS_0(x, wm) ((wm) == wm_byte ? ((x) & 0xff) == 0 : (x) == 0)
+// see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11
+constexpr const double pdp11_clock_cycle = 150; // ns, for the 11/70
+constexpr const double pdp11_MHz = 1000.0 / pdp11_clock_cycle;
+constexpr const double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0;
+constexpr const double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction;
+
cpu::cpu(bus *const b, std::atomic_uint32_t *const event) : b(b), event(event)
{
reset();
@@ -97,15 +103,15 @@ std::tuple cpu::get_mips_rel_speed(c
double mips = t_diff ? instr_count / double(t_diff) : 0;
- // see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11
- constexpr double pdp11_clock_cycle = 150; // ns, for the 11/70
- constexpr double pdp11_MHz = 1000.0 / pdp11_clock_cycle;
- constexpr double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0;
- constexpr double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction;
-
return { mips, mips * 100 / pdp11_estimated_mips, instr_count, t_diff, wait_time };
}
+uint32_t cpu::get_effective_run_time(const uint64_t instruction_count) const
+{
+ // division is to go from ns to ms
+ return instruction_count * pdp11_avg_cycles_per_instruction * pdp11_clock_cycle / 1000000l;
+}
+
void cpu::add_to_stack_trace(const uint16_t p)
{
auto da = disassemble(p);
diff --git a/cpu.h b/cpu.h
index 9c5c40f..56e37eb 100644
--- a/cpu.h
+++ b/cpu.h
@@ -133,6 +133,8 @@ public:
uint64_t get_instructions_executed_count() const;
uint64_t get_wait_time() const { return wait_time; }
std::tuple get_mips_rel_speed(const std::optional & instruction_count, const std::optional & t_diff_1s) const;
+ // how many ms would've really passed when executing `instruction_count` instructions
+ uint32_t get_effective_run_time(const uint64_t instruction_count) const;
bool get_debug() const { return debug_mode; }
void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); }
diff --git a/debugger.cpp b/debugger.cpp
index cf57419..d751945 100644
--- a/debugger.cpp
+++ b/debugger.cpp
@@ -78,55 +78,102 @@ std::optional select_nbd_server(console *const cnsl)
}
#endif
-std::optional select_host_file(console *const c)
+void start_disk(console *const cnsl)
{
- for(;;) {
-#if defined(linux)
- DIR *dir = opendir(".");
- if (!dir) {
- c->put_string_lf("Cannot access directory");
- return { };
- }
-
- dirent *dr = nullptr;
- while((dr = readdir(dir))) {
- struct stat st { };
-
- if (stat(dr->d_name, &st) == 0)
- c->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size));
- }
-
- closedir(dir);
-#elif defined(BUILD_FOR_RP2040)
- File root = SD.open("/");
-
- for(;;) {
- auto entry = root.openNextFile();
- if (!entry)
- break;
-
- if (!entry.isDirectory()) {
- c->put_string(entry.name());
- c->put_string("\t\t");
- c->put_string_lf(format("%ld", entry.size()));
- }
-
- entry.close();
- }
-#elif defined(_WIN32)
+#if IS_POSIX
+ return;
#else
- SD.ls("/", LS_DATE | LS_SIZE | LS_R);
+ static bool disk_started = false;
+ if (disk_started)
+ return;
+
+#if defined(ESP32)
+ cnsl->put_string_lf(format("MISO: %d", int(MISO)));
+ cnsl->put_string_lf(format("MOSI: %d", int(MOSI)));
+ cnsl->put_string_lf(format("SCK : %d", int(SCK )));
+ cnsl->put_string_lf(format("SS : %d", int(SS )));
+
#endif
- c->flush_input();
+#if defined(SHA2017)
+ if (SD.begin(21, SD_SCK_MHZ(10)))
+ disk_started = true;
+ else
+ SD.initErrorHalt();
+#elif !defined(BUILD_FOR_RP2040)
+ if (SD.begin(SS, SD_SCK_MHZ(15)))
+ disk_started = true;
+ else {
+ auto err = SD.sdErrorCode();
+ if (err)
+ cnsl->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData()));
+ else
+ cnsl->put_string_lf("Failed to initialize SD card");
+ }
+#endif
+#endif
+}
- std::string selected_file = c->read_line("Enter filename (or empty to abort): ");
+void ls_l(console *const cnsl)
+{
+ start_disk(cnsl);
+
+#if IS_POSIX || defined(_WIN32)
+ cnsl->put_string_lf("Files in current directory: ");
+#else
+ cnsl->put_string_lf("Files on SD-card:");
+#endif
+
+#if defined(linux)
+ DIR *dir = opendir(".");
+ if (!dir) {
+ cnsl->put_string_lf("Cannot access directory");
+ return;
+ }
+
+ dirent *dr = nullptr;
+ while((dr = readdir(dir))) {
+ struct stat st { };
+
+ if (stat(dr->d_name, &st) == 0)
+ cnsl->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size));
+ }
+
+ closedir(dir);
+#elif defined(BUILD_FOR_RP2040)
+ File root = SD.open("/");
+
+ for(;;) {
+ auto entry = root.openNextFile();
+ if (!entry)
+ break;
+
+ if (!entry.isDirectory()) {
+ cnsl->put_string(entry.name());
+ cnsl->put_string("\t\t");
+ cnsl->put_string_lf(format("%ld", entry.size()));
+ }
+
+ entry.close();
+ }
+#elif defined(_WIN32)
+#else
+ SD.ls("/", LS_DATE | LS_SIZE | LS_R);
+#endif
+}
+
+std::optional select_host_file(console *const cnsl)
+{
+ for(;;) {
+ cnsl->flush_input();
+
+ std::string selected_file = cnsl->read_line("Enter filename (or empty to abort): ");
if (selected_file.empty())
return { };
- c->put_string("Opening file: ");
- c->put_string_lf(selected_file.c_str());
+ cnsl->put_string("Opening file: ");
+ cnsl->put_string_lf(selected_file.c_str());
bool can_open_file = false;
@@ -143,41 +190,19 @@ std::optional select_host_file(console *const c)
if (can_open_file)
return selected_file;
- c->put_string_lf("open failed");
+ cnsl->put_string_lf("open failed");
+
+ ls_l(cnsl);
}
}
// disk image files
-std::optional select_disk_file(console *const c)
+std::optional select_disk_file(console *const cnsl)
{
-#if IS_POSIX || defined(_WIN32)
- c->put_string_lf("Files in current directory: ");
-#else
- 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:");
-
-#if defined(SHA2017)
- if (!SD.begin(21, SD_SCK_MHZ(10)))
- SD.initErrorHalt();
-#elif !defined(BUILD_FOR_RP2040)
- if (!SD.begin(SS, SD_SCK_MHZ(15))) {
- auto err = SD.sdErrorCode();
- if (err)
- c->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData()));
- else
- c->put_string_lf("Failed to initialize SD card");
-
- return { };
- }
-#endif
-#endif
+ start_disk(cnsl);
for(;;) {
- auto selected_file = select_host_file(c);
+ auto selected_file = select_host_file(cnsl);
if (selected_file.has_value() == false)
break;
@@ -189,8 +214,8 @@ std::optional select_disk_file(console *const c)
#endif
if (!temp->begin(false)) {
- c->put_string("Cannot use: ");
- c->put_string_lf(selected_file.value().c_str());
+ cnsl->put_string("Cannot use: ");
+ cnsl->put_string_lf(selected_file.value().c_str());
delete temp;
@@ -987,6 +1012,19 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue;
}
+ else if (parts[0] == "bic" && parts.size() == 2) {
+ auto rc = load_tape(b, parts[1].c_str());
+ if (rc.has_value()) {
+ c->setPC(rc.value());
+
+ cnsl->put_string_lf("BIC/LDA file loaded");
+ }
+ else {
+ cnsl->put_string_lf("BIC/LDA failed to load");
+ }
+
+ continue;
+ }
else if (parts[0] == "lt") {
if (parts.size() == 2)
tm11_load_tape(cnsl, b, parts[1]);
@@ -995,6 +1033,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue;
}
+ else if (cmd == "dir" || cmd == "ls") {
+ ls_l(cnsl);
+
+ continue;
+ }
else if (cmd == "ult") {
tm11_unload_tape(b);
@@ -1038,28 +1081,30 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
" follows v/p (virtual/physical), all octal values, mmr0-3 and psw are",
" registers",
"trace/t - toggle tracing",
- "setll - set loglevel: terminal,file",
- "setsl - set syslog target: requires a hostname and a loglevel",
+ "setll x,y - set loglevel: terminal,file",
+ "setsl x,y - set syslog target: requires a hostname and a loglevel",
"turbo - toggle turbo mode (cannot be interrupted)",
"debug - enable CPU debug mode",
"bt - show backtrace - need to enable debug first",
- "strace - start tracing from address - invoke without address to disable",
- "trl - set trace run-level (0...3), empty for all",
+ "strace x - start tracing from address - invoke without address to disable",
+ "trl x - set trace run-level (0...3), empty for all",
"regdump - dump register contents",
"mmudump - dump MMU settings (PARs/PDRs)",
- "mmures - resolve a virtual address",
+ "mmures x - resolve a virtual address",
"qi - show queued interrupts",
- "setpc - set PC to value",
- "setmem - set memory (a=) to value (v=), both in octal, one byte",
- "toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)",
+ "setpc x - set PC to value",
+ "setmem ... - set memory (a=) to value (v=), both in octal, one byte",
+ "toggle ... - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)",
"cls - clear screen",
- "lt - load tape (parameter is filename)",
+ "dir - list files",
+ "bic x - run BIC/LDA file",
+ "lt x - load tape (parameter is filename)",
"ult - unload tape",
"stats - show run statistics",
- "ramsize - set ram size (page count (8 kB))",
- "bl - set bootload (rl02 or rk05)",
+ "ramsize x - set ram size (page count (8 kB), decimal)",
+ "bl - set bootloader (rl02 or rk05)",
#if IS_POSIX
- "ser - serialize state to a file",
+ "ser x - serialize state to a file",
// "dser - deserialize state from a file",
#endif
"dp - disable panel",
@@ -1068,11 +1113,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
"startnet - start network",
"chknet - check network status",
#if defined(CONSOLE_SERIAL_RX)
- "serspd - set serial speed in bps (8N1 are default)",
+ "serspd x - set serial speed in bps (8N1 are default)",
#endif
#endif
"cfgdisk - configure disk",
- "log - log a message to the logfile",
+ "log ... - log a message to the logfile",
nullptr
};
diff --git a/kw11-l.cpp b/kw11-l.cpp
index 2d23054..8a102a1 100644
--- a/kw11-l.cpp
+++ b/kw11-l.cpp
@@ -62,28 +62,40 @@ void kw11_l::reset()
lf_csr = 0;
}
+void kw11_l::do_interrupt()
+{
+ set_lf_crs_b7();
+
+ if (get_lf_crs() & 64)
+ b->getCpu()->queue_interrupt(6, 0100);
+}
+
void kw11_l::operator()()
{
set_thread_name("kek:kw-11l");
TRACE("Starting KW11-L thread");
+ uint64_t prev_cycle_count = b->getCpu()->get_instructions_executed_count();
+ uint64_t interval_prev_cycle_count = prev_cycle_count;
+
while(!stop_flag) {
if (*cnsl->get_running_flag()) {
- set_lf_crs_b7();
-
- if (get_lf_crs() & 64)
- b->getCpu()->queue_interrupt(6, 0100);
+ myusleep(1000000 / 100); // 100 Hz
- // TODO: depending on cpu cycles processed
-#if defined(ESP32)
- myusleep(1000000 / 20); // 50ms
-#else
- myusleep(1000000 / 50); // 20ms
-#endif
+ uint64_t current_cycle_count = b->getCpu()->get_instructions_executed_count();
+ uint32_t took_ms = b->getCpu()->get_effective_run_time(current_cycle_count - prev_cycle_count);
+
+ if (took_ms >= 1000 / 50 || current_cycle_count - interval_prev_cycle_count == 0) {
+ do_interrupt();
+
+ prev_cycle_count = current_cycle_count;
+ }
+
+ interval_prev_cycle_count = current_cycle_count;
}
else {
- myusleep(1000000 / 10); // 100ms
+ myusleep(1000000 / 10); // 10 Hz
}
}
diff --git a/kw11-l.h b/kw11-l.h
index 8c2f8f7..a0398b4 100644
--- a/kw11-l.h
+++ b/kw11-l.h
@@ -28,6 +28,8 @@ private:
uint8_t get_lf_crs();
void set_lf_crs_b7();
+ void do_interrupt();
+
public:
kw11_l(bus *const b);
virtual ~kw11_l();
diff --git a/mmu.cpp b/mmu.cpp
index a4d64c8..65c341a 100644
--- a/mmu.cpp
+++ b/mmu.cpp
@@ -48,6 +48,11 @@ uint16_t mmu::read_par(const uint32_t a, const int run_mode)
return t;
}
+void mmu::setMMR0_as_is(uint16_t value)
+{
+ MMR0 = value;
+}
+
void mmu::setMMR0(uint16_t value)
{
value &= ~(3 << 10); // bit 10 & 11 always read as 0
@@ -350,7 +355,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const
temp |= d << 4;
- setMMR0(temp);
+ setMMR0_as_is(temp);
TRACE("MMR0: %06o", temp);
}
@@ -389,7 +394,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const
temp &= ~(3 << 5);
temp |= run_mode << 5;
- setMMR0(temp);
+ setMMR0_as_is(temp);
}
if (is_write)
@@ -427,7 +432,7 @@ uint32_t mmu::calculate_physical_address(cpu *const c, const int run_mode, const
temp &= ~(1 << 4);
temp |= d << 4;
- setMMR0(temp);
+ setMMR0_as_is(temp);
}
if (is_write)
diff --git a/mmu.h b/mmu.h
index d79b8dc..27074cf 100644
--- a/mmu.h
+++ b/mmu.h
@@ -99,6 +99,7 @@ public:
uint16_t getMMR3() const { return MMR3; }
uint16_t getMMR(int nr) const { const uint16_t *const mmrs[] { &MMR0, &MMR1, &MMR2, &MMR3 }; return *mmrs[nr]; }
+ void setMMR0_as_is(uint16_t value);
void setMMR0(const uint16_t value);
void setMMR1(const uint16_t value);
void setMMR2(const uint16_t value);
diff --git a/rk05.cpp b/rk05.cpp
index a30d407..1cd9e22 100644
--- a/rk05.cpp
+++ b/rk05.cpp
@@ -62,17 +62,17 @@ uint16_t rk05::read_word(const uint16_t addr)
if (addr == RK05_DS) { // 0177400
setBit(registers[reg], 11, true); // disk on-line
- setBit(registers[reg], 8, true); // sector ok
- setBit(registers[reg], 7, true); // drive ready
- setBit(registers[reg], 6, true); // seek ready
- setBit(registers[reg], 4, true); // heads in position
+ setBit(registers[reg], 8, true); // sector ok
+ setBit(registers[reg], 7, true); // drive ready
+ setBit(registers[reg], 6, true); // seek ready
+ setBit(registers[reg], 4, true); // heads in position
}
else if (addr == RK05_ERROR) // 0177402
registers[reg] = 0;
else if (addr == RK05_CS) { // 0177404
setBit(registers[reg], 15, false); // clear error
setBit(registers[reg], 14, false); // clear hard error
- setBit(registers[reg], 7, true); // controller ready
+ setBit(registers[reg], 7, true); // controller ready
}
uint16_t vtemp = registers[reg];
@@ -139,45 +139,56 @@ void rk05::write_word(const uint16_t addr, const uint16_t v)
if (func == 0) { // controller reset
TRACE("RK05 invoke %d (controller reset)", func);
+ registers[(RK05_ERROR - RK05_BASE) / 2] = 0;
}
else if (func == 1) { // write
*disk_write_acitivity = true;
TRACE("RK05 drive %d position sec %d surf %d cyl %d, reclen %zo, WRITE to %o, mem: %o", device, sector, surface, cylinder, reclen, diskoffb, memoff);
- uint32_t work_reclen = reclen;
- uint32_t work_memoff = memoff;
- uint32_t work_diskoffb = diskoffb;
+ if (device >= fhs.size()) {
+ registers[(RK05_ERROR - RK05_BASE) / 2] |= 128; // non existing disk
+ registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured
+ }
+ else {
+ uint32_t work_reclen = reclen;
+ uint32_t work_memoff = memoff;
+ uint32_t work_diskoffb = diskoffb;
- assert(sizeof(xfer_buffer) == 512);
+ assert(sizeof(xfer_buffer) == 512);
- while(work_reclen > 0) {
- uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), work_reclen);
- work_reclen -= cur;
+ while(work_reclen > 0) {
+ uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), work_reclen);
+ work_reclen -= cur;
- for(size_t i=0; ireadUnibusByte(work_memoff++);
+ for(size_t i=0; ireadUnibusByte(work_memoff++);
- if (!fhs.at(device)->write(work_diskoffb, cur, xfer_buffer, 512))
- DOLOG(ll_error, true, "RK05(%d) write error %s to %u len %u", device, strerror(errno), work_diskoffb, cur);
+ if (!fhs.at(device)->write(work_diskoffb, cur, xfer_buffer, 512)) {
+ DOLOG(ll_error, true, "RK05(%d) write error %s to %u len %u", device, strerror(errno), work_diskoffb, cur);
+ registers[(RK05_ERROR - RK05_BASE) / 2] |= 32; // non existing sector
+ registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured
+ break;
+ }
- work_diskoffb += cur;
+ work_diskoffb += cur;
- if (v & 2048)
- TRACE("RK05 inhibit BA increase");
- else
- update_bus_address(cur);
+ if (v & 2048)
+ TRACE("RK05 inhibit BA increase");
+ else
+ update_bus_address(cur);
- if (++sector >= 12) {
- sector = 0;
- if (++surface >= 2) {
- surface = 0;
- cylinder++;
+ if (++sector >= 12) {
+ sector = 0;
+ if (++surface >= 2) {
+ surface = 0;
+ cylinder++;
+ }
}
}
- }
- registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
+ registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
+ }
*disk_write_acitivity = false;
}
@@ -186,40 +197,48 @@ void rk05::write_word(const uint16_t addr, const uint16_t v)
TRACE("RK05 drive %d position sec %d surf %d cyl %d, reclen %zo, READ from %o, mem: %o", device, sector, surface, cylinder, reclen, diskoffb, memoff);
- uint32_t temp_diskoffb = diskoffb;
+ if (device >= fhs.size()) {
+ registers[(RK05_ERROR - RK05_BASE) / 2] |= 128; // non existing disk
+ registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured
+ }
+ else {
+ uint32_t temp_diskoffb = diskoffb;
- uint32_t temp_reclen = reclen;
- uint32_t p = memoff;
- while(temp_reclen > 0) {
- uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp_reclen);
+ uint32_t temp_reclen = reclen;
+ uint32_t p = memoff;
+ 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);
- break;
- }
+ 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);
+ registers[(RK05_ERROR - RK05_BASE) / 2] |= 32; // non existing sector
+ registers[(RK05_CS - RK05_BASE) / 2] |= 3 << 14; // an error occured
+ break;
+ }
- temp_diskoffb += cur;
+ temp_diskoffb += cur;
- for(uint32_t i=0; iwriteUnibusByte(p++, xfer_buffer[i]);
+ for(uint32_t i=0; iwriteUnibusByte(p++, xfer_buffer[i]);
- if ((v & 2048) == 0)
- update_bus_address(2);
- }
+ if ((v & 2048) == 0)
+ update_bus_address(2);
+ }
- temp_reclen -= cur;
+ temp_reclen -= cur;
- if (++sector >= 12) {
- sector = 0;
+ if (++sector >= 12) {
+ sector = 0;
- if (++surface >= 2) {
- surface = 0;
- cylinder++;
+ if (++surface >= 2) {
+ surface = 0;
+ cylinder++;
+ }
}
}
- }
- registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
+ registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
+ }
*disk_read_acitivity = false;
}
diff --git a/tm-11.cpp b/tm-11.cpp
index e41eb67..20eba66 100644
--- a/tm-11.cpp
+++ b/tm-11.cpp
@@ -1,4 +1,4 @@
-// (C) 2018-2023 by Folkert van Heusden
+// (C) 2018-2024 by Folkert van Heusden
// Released under MIT license
#include