diff --git a/rp06.cpp b/rp06.cpp index b9066fd..00761cc 100644 --- a/rp06.cpp +++ b/rp06.cpp @@ -1,5 +1,6 @@ // (C) 2024 by Folkert van Heusden // Released under MIT license +// Some of the code is translated from Neil Webber's PDP11/70 emulator #include #include @@ -13,7 +14,11 @@ #include "utils.h" -const char *regnames[] { "Control", "Status", "Error register 1", "Maintenance", "Attention summary", "Desired sector/track address", "Look ahead", "Drive type", "Serial no", "Offset", "Desired cylinder address", "Current cylinder address", "Error register 2", "Error register 3", "ECC position", "ECC pattern" }; +constexpr const int NSECT = 22; // sectors per track +constexpr const int NTRAC = 19; // tracks per cylinder +constexpr const int SECTOR_SIZE = 512; + +constexpr const char *regnames[] { "Control", "Status", "Error register 1", "Maintenance", "Attention summary", "Desired sector/track address", "Look ahead", "Drive type", "Serial no", "Offset", "Desired cylinder address", "Current cylinder address", "Error register 2", "Error register 3", "ECC position", "ECC pattern" }; rp06::rp06(bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity) : b(b), @@ -76,9 +81,14 @@ uint16_t rp06::read_word(const uint16_t addr) return value; } +int rp06::reg_num(uint16_t addr) const +{ + return (addr - RP06_BASE) / 2; +} + void rp06::write_byte(const uint16_t addr, const uint8_t v) { - uint16_t vtemp = registers[(addr - RP06_BASE) / 2]; + uint16_t vtemp = registers[reg_num(addr)]; if (addr & 1) { vtemp &= ~0xff00; @@ -92,19 +102,61 @@ void rp06::write_byte(const uint16_t addr, const uint8_t v) write_word(addr, vtemp); } +uint32_t rp06::compute_offset() const +{ + // cyl num, track num, sector num, which were written like this: + uint16_t cn = registers[reg_num(RP06_DC)]; + uint16_t tn = (registers[reg_num(RP06_DA)] >> 8) & 0377; + uint16_t sn = registers[reg_num(RP06_DA)] & 0377; + + // each cylinder is NSECT*NTRAC sectors + // each track is NSECT sectors + uint32_t offs = cn * NSECT * NTRAC; + offs += tn * NSECT; + offs += sn; + offs *= SECTOR_SIZE; + + return offs; +} + +uint32_t rp06::getphysaddr() const +{ + constexpr const uint16_t A16 = 0400; + constexpr const uint16_t A17 = 01000; + + // low 16 bits in UBA, and tack on A16/A17 + bool cur_A16 = registers[reg_num(RP06_CS1)] & A16; + bool cur_A17 = registers[reg_num(RP06_CS1)] & A17; + + uint16_t cur_A1621 = 0; + + // but also bits may be found in bae... the assumption here is + // if these bits are non-zero they override A16/A17 but they + // really need to be consistent... + if (registers[reg_num(RP06_BAE)]) { + cur_A16 = false; // subsumed in A1621 + cur_A17 = false; // subsumed + cur_A1621 = registers[reg_num(RP06_BAE)] & 077; + } + + return registers[reg_num(RP06_UBA)] | (cur_A16 << 16) | (cur_A17 << 17) | (cur_A1621 << 16); +} + void rp06::write_word(const uint16_t addr, uint16_t v) { - const int reg = (addr - RP06_BASE) / 2; + const int reg = reg_num(addr); TRACE("RP06: write \"%s\"/%06o: %06o", regnames[reg], addr, v); registers[reg] = v; - if (reg == RP06_CR) { + if (reg == RP06_CS1) { if (v & 1) { - int function_code = (v >> 1) & 31; + int function_code = v & 63; + if (function_code == 070) { + } } } } diff --git a/rp06.h b/rp06.h index 6c6015c..724e1ae 100644 --- a/rp06.h +++ b/rp06.h @@ -1,5 +1,6 @@ // (C) 2024 by Folkert van Heusden // Released under MIT license +// Some of the code is translated from Neil Webber's PDP11/70 emulator #pragma once @@ -15,9 +16,20 @@ #include "disk_backend.h" -#define RP06_CR 0176700 // control register -#define RP06_BASE RP06_CSR -#define RP06_END (RP06_MPR + 2) +#define RP06_CS1 0176700 // control register +#define RP06_WC 0176702 // word count +#define RP06_UBA 0176704 // UNIBUS address +#define RP06_DA 0176706 // desired address +#define RP06_CS2 0176710 // control/status register 2 +#define RP06_DS 0176712 // drive status +#define RP06_AS 0176716 // unified attention status +#define RP06_RMLA 0176720 // lookahead (sector under head!!) +#define RP06_OFR 0176732 // heads offset +#define RP06_DC 0176734 // desired cylinder +#define RP06_CC 0176736 // "current cylinder" and/or holding register +#define RP06_BAE 0176750 // address extension (pdp11/70 extra phys bits) +#define RP06_BASE RP06_CS1 +#define RP06_END (RP06_BAE + 2) class bus; @@ -27,11 +39,15 @@ class rp06: public disk_device private: bus *const b; - uint16_t registers[20] { }; + uint16_t registers[32] { }; std::atomic_bool *const disk_read_activity { nullptr }; std::atomic_bool *const disk_write_activity { nullptr }; + int reg_num(uint16_t addr) const; + uint32_t getphysaddr() const; + uint32_t compute_offset() const; + public: rp06(bus *const b, std::atomic_bool *const disk_read_activity, std::atomic_bool *const disk_write_activity); virtual ~rp06();