Implemented RL02 read command
This commit is contained in:
parent
160ffe5c26
commit
57aca63db0
4 changed files with 212 additions and 33 deletions
3
bus.cpp
3
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);
|
||||
|
||||
|
|
114
main.cpp
114
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<sizeof bootrom / 2; i++) {
|
||||
b -> 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<size; i++)
|
||||
b -> 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();
|
||||
|
||||
|
|
118
rl02.cpp
118
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; i<cur; i++, p++)
|
||||
b->writeByte(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);
|
||||
|
|
10
rl02.h
10
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<File32 *> fhs;
|
||||
#else
|
||||
std::vector<FILE *> 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<std::string> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||
virtual ~rl02();
|
||||
|
|
Loading…
Add table
Reference in a new issue