RL02: read header

This commit is contained in:
folkert van heusden 2024-04-18 14:33:33 +02:00
parent fd8bb6a60b
commit a623c0ab67
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
2 changed files with 54 additions and 26 deletions

View file

@ -20,6 +20,17 @@ static const char * const regnames[] = {
"multipurpose " "multipurpose "
}; };
static const char * const commands[] = {
"no-op",
"write check",
"get status",
"seek",
"read header",
"write data",
"read data",
"read data w/o header check"
};
rl02::rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity) : rl02::rl02(const std::vector<disk_backend *> & files, 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),
@ -70,13 +81,15 @@ uint16_t rl02::readWord(const uint16_t addr)
if (addr == RL02_MPR) { // multi purpose register if (addr == RL02_MPR) { // multi purpose register
value = mpr[0]; value = mpr[0];
memcpy(&mpr[0], &mpr[1], sizeof(mpr[0]) * 2); mpr[0] = mpr[1];
mpr[1] = mpr[2];
mpr[2] = 0;
} }
else { else {
value = registers[reg]; value = registers[reg];
} }
DOLOG(debug, false, "RL02 read %s/%o: %06o", regnames[reg], addr, value); DOLOG(debug, false, "RL02 read \"%s\"/%o: %06o", regnames[reg], addr, value);
return value; return value;
} }
@ -110,17 +123,22 @@ void rl02::update_bus_address(const uint32_t a)
registers[(RL02_CSR - RL02_BASE) / 2] |= ((a >> 16) & 3) << 4; registers[(RL02_CSR - RL02_BASE) / 2] |= ((a >> 16) & 3) << 4;
} }
uint32_t rl02::calcOffset() const uint32_t rl02::calc_offset() const
{ {
return (rl02_sectors_per_track * track * 2 + head * rl02_sectors_per_track + sector) * rl02_bytes_per_sector; return (rl02_sectors_per_track * track * 2 + head * rl02_sectors_per_track + sector) * rl02_bytes_per_sector;
} }
void rl02::update_dar()
{
registers[(RL02_DAR - RL02_BASE) / 2] = (sector & 63) | (head << 6) | (track << 7);
}
void rl02::writeWord(const uint16_t addr, uint16_t v) void rl02::writeWord(const uint16_t addr, uint16_t v)
{ {
DOLOG(debug, false, "RL02 write %06o: %06o", addr, v);
const int reg = (addr - RL02_BASE) / 2; const int reg = (addr - RL02_BASE) / 2;
DOLOG(debug, false, "RL02 write \"%s\"/%06o: %06o", regnames[reg], addr, v);
registers[reg] = v; registers[reg] = v;
if (addr == RL02_CSR) { // control status if (addr == RL02_CSR) { // control status
@ -128,7 +146,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
const bool do_exec = !(v & 128); const bool do_exec = !(v & 128);
DOLOG(debug, false, "RL02 set command %d, exec: %d", command, do_exec); DOLOG(debug, false, "RL02 set command %d, exec: %d (%s)", command, do_exec, commands[command]);
int device = 0; // TODO int device = 0; // TODO
@ -142,33 +160,31 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
else if (command == 3) { // seek else if (command == 3) { // seek
uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2]; uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2];
int cylinder_count = (((temp >> 7) & 255) + 1) * (temp & 4 ? 1 : -1); int cylinder_count = (temp >> 7) * (temp & 4 ? 1 : -1);
int32_t new_track = 0; // when bit 4 is set, a reset is performed int16_t new_track = track + cylinder_count;
if ((temp & 8) == 0) { if (new_track < 0)
new_track = track + cylinder_count; new_track = 0;
else if (new_track >= rl02_track_count)
if (new_track < 0) new_track = rl02_track_count - 1;
new_track = 0;
else if (new_track >= rl02_track_count)
new_track = rl02_track_count;
}
DOLOG(debug, false, "RL02: seek from cylinder %d to %d (distance: %d, DAR: %06o)", track, new_track, cylinder_count, temp); DOLOG(debug, false, "RL02: seek from cylinder %d to %d (distance: %d, DAR: %06o)", track, new_track, cylinder_count, temp);
track = new_track; track = new_track;
update_dar();
do_int = true; do_int = true;
} }
else if (command == 4) { // read header else if (command == 4) { // read header
mpr[0] = (sector & 63) | (head << 6) | (track << 7);
mpr[1] = 0; // zero
mpr[2] = 0; // TODO: CRC
do_int = true;
} }
else if (command == 6 || command == 7) { // read data / read data without header check else if (command == 6 || command == 7) { // read data / read data without header check
uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2]; uint32_t temp_disk_offset = calc_offset();
sector = temp & 63;
head = !!(temp & 64);
track = temp >> 7;
uint32_t temp_disk_offset = calcOffset();
uint32_t memory_address = get_bus_address(); uint32_t memory_address = get_bus_address();
@ -176,18 +192,24 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
DOLOG(debug, false, "RL02 read %d bytes (dec) from %d (dec) to %06o (oct) [cylinder: %d, head: %d, sector: %d]", count, temp_disk_offset, memory_address, track, head, sector); DOLOG(debug, false, "RL02 read %d bytes (dec) from %d (dec) to %06o (oct) [cylinder: %d, head: %d, sector: %d]", count, temp_disk_offset, memory_address, track, head, sector);
update_dar();
while(count > 0) { while(count > 0) {
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count); uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count);
if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) { if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) {
DOLOG(ll_error, true, "RL02 read error %s", strerror(errno)); DOLOG(ll_error, true, "RL02 read error %s, disk offset %u, read size %u, cylinder %d, head %d, sector %d", strerror(errno), temp_disk_offset, cur, track, head, sector);
break; break;
} }
for(uint32_t i=0; i<cur; i++, memory_address++) { for(uint32_t i=0; i<cur;) {
b->writeUnibusByte(memory_address, xfer_buffer[i]); // BA and MPR are increased by 2
b->writeUnibusByte(memory_address++, xfer_buffer[i++]);
b->writeUnibusByte(memory_address++, xfer_buffer[i++]);
update_bus_address(memory_address); update_bus_address(memory_address);
(*reinterpret_cast<int16_t *>(&registers[(RL02_MPR - RL02_BASE) / 2]))++;
} }
temp_disk_offset += cur; temp_disk_offset += cur;
@ -205,8 +227,13 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
track++; track++;
} }
} }
update_dar();
} }
if (registers[(RL02_MPR - RL02_BASE) / 2])
DOLOG(warning, false, "RL02: unexpected MPR value after read (%06o)", registers[(RL02_MPR - RL02_BASE) / 2]);
do_int = true; do_int = true;
} }

3
rl02.h
View file

@ -42,7 +42,8 @@ private:
uint32_t get_bus_address() const; uint32_t get_bus_address() const;
void update_bus_address(const uint32_t a); void update_bus_address(const uint32_t a);
uint32_t calcOffset() const; void update_dar();
uint32_t calc_offset() const;
public: public:
rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity); rl02(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);