From 57aca63db05b915b01d9215c5e39cae3f832e123 Mon Sep 17 00:00:00 2001 From: folkert van heusden Date: Fri, 10 Jun 2022 09:48:02 +0200 Subject: [PATCH] Implemented RL02 read command --- bus.cpp | 3 ++ main.cpp | 114 +++++++++++++++++++++++++++++++++++++++++------------ rl02.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- rl02.h | 10 +++-- 4 files changed, 212 insertions(+), 33 deletions(-) diff --git a/bus.cpp b/bus.cpp index b1fad88..4730419 100644 --- a/bus.cpp +++ b/bus.cpp @@ -281,6 +281,9 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev, if (rk05_ && a >= RK05_BASE && a < RK05_END) return word_mode ? rk05_ -> readByte(a) : rk05_ -> readWord(a); + if (rl02_ && a >= RL02_BASE && a < RL02_END) + return word_mode ? rl02_ -> readByte(a) : rl02_ -> readWord(a); + if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) return word_mode ? tty_ -> readByte(a) : tty_ -> readWord(a); diff --git a/main.cpp b/main.cpp index 195bb27..85d564e 100644 --- a/main.cpp +++ b/main.cpp @@ -21,6 +21,8 @@ #include "utils.h" +typedef enum { BL_NONE, BL_RK05, BL_RL02 } bootloader_t; + bool withUI { false }; uint32_t event { 0 }; std::atomic_bool terminate { false }; @@ -37,32 +39,85 @@ void loadbin(bus *const b, uint16_t base, const char *const file) fclose(fh); } -void setBootLoader(bus *const b) +void setBootLoader(bus *const b, const bootloader_t which) { - cpu *const c = b -> getCpu(); + cpu *const c = b -> getCpu(); - const uint16_t offset = 01000; - constexpr uint16_t bootrom[] = { - 0012700, - 0177406, - 0012710, - 0177400, - 0012740, - 0000005, - 0105710, - 0100376, - 0005007 - }; + uint16_t offset = 0; + const uint16_t *bl = nullptr; + int size = 0; - FILE *fh = fopen("boot.dat", "wb"); + if (which == BL_RK05) { + offset = 01000; - for(size_t i=0; i writeWord(offset + i * 2, bootrom[i]); - fputc(bootrom[i] & 255, fh); - fputc(bootrom[i] >> 8, fh); + static uint16_t rk05_code[] = { + 0012700, + 0177406, + 0012710, + 0177400, + 0012740, + 0000005, + 0105710, + 0100376, + 0005007 + }; + + bl = rk05_code; + + size = 9; + } + else if (which == BL_RL02) { + offset = 01000; + + /* from https://www.pdp-11.nl/peripherals/disk/rl-info.html + static uint16_t rl02_code[] = { + 0012701, + 0174400, + 0012761, + 0000013, + 0000004, + 0012711, + 0000004, + 0105711, + 0100376, + 0005061, + 0000002, + 0005061, + 0000004, + 0012761, + 0177400, + 0000006, + 0012711, + 0000014, + 0105711, + 0100376, + 0005007 + }; + + size = 21; + */ + + // from http://gunkies.org/wiki/RL11_disk_controller + static uint16_t rl02_code[] = { + 0012700, + 0174400, + 0012760, + 0177400, + 0000006, + 0012710, + 0000014, + 0105710, + 0100376, + 0005007, + }; + + size = 10; + + bl = rl02_code; } - fclose(fh); + for(int i=0; i writeWord(offset + i * 2, bl[i]); c -> setRegister(7, offset); } @@ -150,7 +205,7 @@ void help() printf("-R d.rk load file as a RK05 disk device\n"); printf("-p 123 set CPU start pointer to decimal(!) value\n"); printf("-L f.bin load file into memory at address given by -p (and run it)\n"); - printf("-b enable bootloader (build-in)\n"); + printf("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n"); printf("-n ncurses UI\n"); printf("-d enable debugger\n"); printf("-t enable tracing (disassemble to stderr, requires -d as well)\n"); @@ -175,10 +230,11 @@ int main(int argc, char *argv[]) bool testCases = false; bool run_debugger = false; bool tracing = false; - bool bootloader = false; + + bootloader_t bootloader = BL_NONE; int opt = -1; - while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b")) != -1) + while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:")) != -1) { switch(opt) { case 'h': @@ -186,7 +242,13 @@ int main(int argc, char *argv[]) return 1; case 'b': - bootloader = true; + if (strcasecmp(optarg, "rk05") == 0) + bootloader = BL_RK05; + else if (strcasecmp(optarg, "rl02") == 0) + bootloader = BL_RL02; + else + error_exit(false, "Bootload \"%s\" not recognized", optarg); + break; case 'd': @@ -257,8 +319,8 @@ int main(int argc, char *argv[]) if (rl02_files.empty() == false) b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag())); - if (bootloader) - setBootLoader(b); + if (bootloader != BL_NONE) + setBootLoader(b, bootloader); running = cnsl->get_running_flag(); diff --git a/rl02.cpp b/rl02.cpp index 52e80ac..9048057 100644 --- a/rl02.cpp +++ b/rl02.cpp @@ -11,6 +11,9 @@ #include "utils.h" +constexpr int sectors_per_track = 40; +constexpr int bytes_per_sector = 256; + static const char * const regnames[] = { "control status", "bus address ", @@ -68,20 +71,25 @@ uint8_t rl02::readByte(const uint16_t addr) uint16_t rl02::readWord(const uint16_t addr) { - const int reg = (addr - RK05_BASE) / 2; + const int reg = (addr - RL02_BASE) / 2; - uint16_t value = 0; + if (addr == RL02_CSR) { // control status + setBit(registers[reg], 0, true); // drive ready (DRDY) + setBit(registers[reg], 7, true); // controller ready (CRDY) + } + + uint16_t value = registers[reg]; // TODO - D(fprintf(stderr, "RK05 read %s/%o: %06o\n", reg[regnames], addr, value);) + D(fprintf(stderr, "RL02 read %s/%o: %06o\n", regnames[reg], addr, value);) return value; } void rl02::writeByte(const uint16_t addr, const uint8_t v) { - uint16_t vtemp = registers[(addr - RK05_BASE) / 2]; + uint16_t vtemp = registers[(addr - RL02_BASE) / 2]; if (addr & 1) { vtemp &= ~0xff00; @@ -95,12 +103,114 @@ void rl02::writeByte(const uint16_t addr, const uint8_t v) writeWord(addr, vtemp); } +uint32_t rl02::calcOffset(const uint16_t da) +{ + int sector = da & 63; + int track = (da >> 6) & 1023; + + uint32_t offset = (sectors_per_track * track + sector) * bytes_per_sector; + + return offset; +} + void rl02::writeWord(const uint16_t addr, uint16_t v) { #if defined(ESP32) digitalWrite(LED_BUILTIN, LOW); #endif + fprintf(stderr, "RL02 write %06o: %06o\n", addr, v); + + const int reg = (addr - RL02_BASE) / 2; + + registers[reg] = v; + + if (addr == RL02_CSR) { // control status + const uint8_t command = (v >> 1) & 7; + + const bool do_exec = !(v & 128); + + fprintf(stderr, "RL02 set command %d, exec: %d\n", command, do_exec); + + uint32_t disk_offset = calcOffset(registers[(RL02_DAR - RL02_BASE) / 2] & ~1); + int device = 0; // TODO + + if (command == 2) { // get status + registers[(RL02_MPR - RL02_BASE) / 2] = 0; +#if 0 + if (registers[(RL02_DAR - RL02_BASE) / 2] & 2) { // get status -> load status word in MPR + registers[(RL02_MPR - RL02_BASE) / 2] = 5 | // lock on + (1 << 3) | // brushes are home + (1 << 7) | // this is an RL02 + 0; + + fprintf(stderr, "RL02 set MPR for status to %06o\n", registers[(RL02_MPR - RL02_BASE) / 2]); + } +#endif + } + else if (command == 6 || command == 7) { // read data / read data without header check + *disk_read_acitivity = true; + + bool proceed = true; + +#if defined(ESP32) + File32 *fh = fhs.at(device); + + if (!fh->seek(disk_offset)) { + fprintf(stderr, "RL02 seek to %d error %s\n", disk_offset, strerror(errno)); + + proceed = false; + } +#else + FILE *fh = nullptr; + + if (size_t(device) >= fhs.size()) + proceed = false; + else { + fh = fhs.at(device); + + if (fseek(fh, disk_offset, SEEK_SET) == -1) { + fprintf(stderr, "RL02 seek error %s\n", strerror(errno)); + proceed = false; + } + } +#endif + + uint32_t memory_address = registers[(RL02_BAR - RL02_BASE) / 2]; + + uint32_t count = (65536 - registers[(RL02_MPR - RL02_BASE) / 2]) * 2; + + fprintf(stderr, "RL02 read %d bytes (dec) from %d (dec) to %06o (oct)\n", count, disk_offset, memory_address); + + uint32_t p = memory_address; + while(proceed && count > 0) { + uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); + +#if defined(ESP32) + yield(); + + if (fh->read(xfer_buffer, cur) != size_t(cur)) + D(fprintf(stderr, "RL02 fread error: %s\n", strerror(errno));) +#else + if (fread(xfer_buffer, 1, cur, fh) != size_t(cur)) + D(fprintf(stderr, "RL02 fread error: %s\n", strerror(errno));) +#endif + + for(uint32_t i=0; iwriteByte(p, xfer_buffer[i]); + + count -= cur; + } + + if (registers[(RL02_CSR - RL02_BASE) / 2] & 64) { // interrupt enable? + fprintf(stderr, "RL02 triggering interrupt\n"); + + b->getCpu()->queue_interrupt(5, 0254); + } + + *disk_read_acitivity = false; + } + } #if defined(ESP32) digitalWrite(LED_BUILTIN, HIGH); diff --git a/rl02.h b/rl02.h index d25e96a..d0da43e 100644 --- a/rl02.h +++ b/rl02.h @@ -24,17 +24,21 @@ class bus; class rl02 { private: - bus *const b; - uint16_t registers[7]; - uint8_t xfer_buffer[512]; + bus *const b; + uint16_t registers[4]; + uint8_t xfer_buffer[512]; + #if defined(ESP32) std::vector fhs; #else std::vector fhs; #endif + std::atomic_bool *const disk_read_acitivity { nullptr }; std::atomic_bool *const disk_write_acitivity { nullptr }; + uint32_t calcOffset(uint16_t); + public: rl02(const std::vector & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity); virtual ~rl02();