Merge branch 'rl'
This commit is contained in:
commit
f6824ececf
9 changed files with 425 additions and 138 deletions
|
@ -19,7 +19,7 @@ add_executable(
|
||||||
main.cpp
|
main.cpp
|
||||||
memory.cpp
|
memory.cpp
|
||||||
rk05.cpp
|
rk05.cpp
|
||||||
rx02.cpp
|
rl02.cpp
|
||||||
terminal.cpp
|
terminal.cpp
|
||||||
tests.cpp
|
tests.cpp
|
||||||
tm-11.cpp
|
tm-11.cpp
|
||||||
|
|
13
bus.cpp
13
bus.cpp
|
@ -1,4 +1,4 @@
|
||||||
// (C) 2018 by Folkert van Heusden
|
// (C) 2018-2022 by Folkert van Heusden
|
||||||
// Released under Apache License v2.0
|
// Released under Apache License v2.0
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -19,6 +19,7 @@ constexpr int n_pages = 12;
|
||||||
constexpr int n_pages = 16;
|
constexpr int n_pages = 16;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bus::bus()
|
bus::bus()
|
||||||
{
|
{
|
||||||
m = new memory(n_pages * 8192);
|
m = new memory(n_pages * 8192);
|
||||||
|
@ -33,7 +34,7 @@ bus::~bus()
|
||||||
delete c;
|
delete c;
|
||||||
delete tm11;
|
delete tm11;
|
||||||
delete rk05_;
|
delete rk05_;
|
||||||
delete rx02_;
|
delete rl02_;
|
||||||
delete tty_;
|
delete tty_;
|
||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
@ -280,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)
|
if (rk05_ && a >= RK05_BASE && a < RK05_END)
|
||||||
return word_mode ? rk05_ -> readByte(a) : rk05_ -> readWord(a);
|
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)
|
if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END)
|
||||||
return word_mode ? tty_ -> readByte(a) : tty_ -> readWord(a);
|
return word_mode ? tty_ -> readByte(a) : tty_ -> readWord(a);
|
||||||
|
|
||||||
|
@ -546,6 +550,11 @@ uint16_t bus::write(const uint16_t a, const bool word_mode, uint16_t value, cons
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rl02_ && a >= RL02_BASE && a < RL02_END) {
|
||||||
|
word_mode ? rl02_ -> writeByte(a, value) : rl02_ -> writeWord(a, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) {
|
if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) {
|
||||||
word_mode ? tty_ -> writeByte(a, value) : tty_ -> writeWord(a, value);
|
word_mode ? tty_ -> writeByte(a, value) : tty_ -> writeWord(a, value);
|
||||||
return value;
|
return value;
|
||||||
|
|
6
bus.h
6
bus.h
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "tm-11.h"
|
#include "tm-11.h"
|
||||||
#include "rk05.h"
|
#include "rk05.h"
|
||||||
#include "rx02.h"
|
#include "rl02.h"
|
||||||
|
|
||||||
class cpu;
|
class cpu;
|
||||||
class memory;
|
class memory;
|
||||||
|
@ -24,7 +24,7 @@ private:
|
||||||
cpu *c { nullptr };
|
cpu *c { nullptr };
|
||||||
tm_11 *tm11 { nullptr };
|
tm_11 *tm11 { nullptr };
|
||||||
rk05 *rk05_ { nullptr };
|
rk05 *rk05_ { nullptr };
|
||||||
rx02 *rx02_ { nullptr };
|
rl02 *rl02_ { nullptr };
|
||||||
tty *tty_ { nullptr };
|
tty *tty_ { nullptr };
|
||||||
|
|
||||||
memory *m { nullptr };
|
memory *m { nullptr };
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
void add_cpu(cpu *const c) { this -> c = c; }
|
void add_cpu(cpu *const c) { this -> c = c; }
|
||||||
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; }
|
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; }
|
||||||
void add_rk05(rk05 *rk05_) { this -> rk05_ = rk05_; }
|
void add_rk05(rk05 *rk05_) { this -> rk05_ = rk05_; }
|
||||||
void add_rx02(rx02 *rx02_) { this -> rx02_ = rx02_; }
|
void add_rl02(rl02 *rl02_) { this -> rl02_ = rl02_; }
|
||||||
void add_tty(tty *tty_) { this -> tty_ = tty_; }
|
void add_tty(tty *tty_) { this -> tty_ = tty_; }
|
||||||
|
|
||||||
cpu *getCpu() { return this->c; }
|
cpu *getCpu() { return this->c; }
|
||||||
|
|
166
main.cpp
166
main.cpp
|
@ -21,6 +21,8 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum { BL_NONE, BL_RK05, BL_RL02 } bootloader_t;
|
||||||
|
|
||||||
bool withUI { false };
|
bool withUI { false };
|
||||||
uint32_t event { 0 };
|
uint32_t event { 0 };
|
||||||
std::atomic_bool terminate { false };
|
std::atomic_bool terminate { false };
|
||||||
|
@ -37,32 +39,85 @@ void loadbin(bus *const b, uint16_t base, const char *const file)
|
||||||
fclose(fh);
|
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;
|
uint16_t offset = 0;
|
||||||
constexpr uint16_t bootrom[] = {
|
const uint16_t *bl = nullptr;
|
||||||
0012700,
|
int size = 0;
|
||||||
0177406,
|
|
||||||
0012710,
|
|
||||||
0177400,
|
|
||||||
0012740,
|
|
||||||
0000005,
|
|
||||||
0105710,
|
|
||||||
0100376,
|
|
||||||
0005007
|
|
||||||
};
|
|
||||||
|
|
||||||
FILE *fh = fopen("boot.dat", "wb");
|
if (which == BL_RK05) {
|
||||||
|
offset = 01000;
|
||||||
|
|
||||||
for(size_t i=0; i<sizeof bootrom / 2; i++) {
|
static uint16_t rk05_code[] = {
|
||||||
b -> writeWord(offset + i * 2, bootrom[i]);
|
0012700,
|
||||||
fputc(bootrom[i] & 255, fh);
|
0177406,
|
||||||
fputc(bootrom[i] >> 8, fh);
|
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);
|
c -> setRegister(7, offset);
|
||||||
}
|
}
|
||||||
|
@ -130,6 +185,44 @@ uint16_t loadTape(bus *const b, const char *const file)
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void load_p11_x11(bus *const b, const std::string & file)
|
||||||
|
{
|
||||||
|
FILE *fh = fopen(file.c_str(), "rb");
|
||||||
|
if (!fh)
|
||||||
|
error_exit(true, "Cannot open %s", file.c_str());
|
||||||
|
|
||||||
|
uint16_t addr = 0;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
while(!feof(fh)) {
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
if (!fgets(buffer, sizeof buffer, fh))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
uint8_t byte = strtol(buffer, NULL, 16);
|
||||||
|
|
||||||
|
b->writeByte(addr, byte);
|
||||||
|
|
||||||
|
n--;
|
||||||
|
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::vector<std::string> parts = split(buffer, " ");
|
||||||
|
|
||||||
|
addr = strtol(parts[0].c_str(), NULL, 16);
|
||||||
|
n = strtol(parts[1].c_str(), NULL, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
cpu *const c = b -> getCpu();
|
||||||
|
c -> setRegister(7, 0);
|
||||||
|
}
|
||||||
|
|
||||||
volatile bool sw = false;
|
volatile bool sw = false;
|
||||||
void sw_handler(int s)
|
void sw_handler(int s)
|
||||||
{
|
{
|
||||||
|
@ -150,7 +243,7 @@ void help()
|
||||||
printf("-R d.rk load file as a RK05 disk device\n");
|
printf("-R d.rk load file as a RK05 disk device\n");
|
||||||
printf("-p 123 set CPU start pointer to decimal(!) value\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("-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("-n ncurses UI\n");
|
||||||
printf("-d enable debugger\n");
|
printf("-d enable debugger\n");
|
||||||
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
|
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
|
||||||
|
@ -170,12 +263,16 @@ int main(int argc, char *argv[])
|
||||||
c -> setEmulateMFPT(true);
|
c -> setEmulateMFPT(true);
|
||||||
|
|
||||||
std::vector<std::string> rk05_files;
|
std::vector<std::string> rk05_files;
|
||||||
|
std::vector<std::string> rl02_files;
|
||||||
|
|
||||||
bool testCases = false;
|
bool testCases = false;
|
||||||
bool run_debugger = false;
|
bool run_debugger = false;
|
||||||
bool tracing = false;
|
bool tracing = false;
|
||||||
bool bootloader = false;
|
|
||||||
|
bootloader_t bootloader = BL_NONE;
|
||||||
|
|
||||||
int opt = -1;
|
int opt = -1;
|
||||||
while((opt = getopt(argc, argv, "hm:T:R:p:ndtL:b")) != -1)
|
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:")) != -1)
|
||||||
{
|
{
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
@ -183,7 +280,13 @@ int main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case 'b':
|
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;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -216,6 +319,10 @@ int main(int argc, char *argv[])
|
||||||
rk05_files.push_back(optarg);
|
rk05_files.push_back(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
rl02_files.push_back(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
c->setRegister(7, atoi(optarg));
|
c->setRegister(7, atoi(optarg));
|
||||||
break;
|
break;
|
||||||
|
@ -247,8 +354,11 @@ int main(int argc, char *argv[])
|
||||||
if (rk05_files.empty() == false)
|
if (rk05_files.empty() == false)
|
||||||
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
b->add_rk05(new rk05(rk05_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||||
|
|
||||||
if (bootloader)
|
if (rl02_files.empty() == false)
|
||||||
setBootLoader(b);
|
b->add_rl02(new rl02(rl02_files, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||||
|
|
||||||
|
if (bootloader != BL_NONE)
|
||||||
|
setBootLoader(b, bootloader);
|
||||||
|
|
||||||
running = cnsl->get_running_flag();
|
running = cnsl->get_running_flag();
|
||||||
|
|
||||||
|
@ -275,6 +385,8 @@ int main(int argc, char *argv[])
|
||||||
// loadbin(b, 0, "test.dat");
|
// loadbin(b, 0, "test.dat");
|
||||||
// c->setRegister(7, 0);
|
// c->setRegister(7, 0);
|
||||||
|
|
||||||
|
//load_p11_x11(b, "/home/folkert/Projects/PDP-11/work/p11-2.10i/Tests/mtpi.x11");
|
||||||
|
|
||||||
cnsl->start_thread();
|
cnsl->start_thread();
|
||||||
|
|
||||||
if (run_debugger)
|
if (run_debugger)
|
||||||
|
@ -306,5 +418,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
delete b;
|
delete b;
|
||||||
|
|
||||||
|
delete lf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
2
rk05.cpp
2
rk05.cpp
|
@ -11,7 +11,7 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
const char * const regnames[] = {
|
static const char * const regnames[] = {
|
||||||
"RK05_DS drivestatus",
|
"RK05_DS drivestatus",
|
||||||
"RK05_ERROR ",
|
"RK05_ERROR ",
|
||||||
"RK05_CS ctrlstatus",
|
"RK05_CS ctrlstatus",
|
||||||
|
|
218
rl02.cpp
Normal file
218
rl02.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
// (C) 2022 by Folkert van Heusden
|
||||||
|
// Released under Apache License v2.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bus.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "rl02.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
constexpr int sectors_per_track = 40;
|
||||||
|
constexpr int bytes_per_sector = 256;
|
||||||
|
|
||||||
|
static const char * const regnames[] = {
|
||||||
|
"control status",
|
||||||
|
"bus address ",
|
||||||
|
"disk address ",
|
||||||
|
"multipurpose "
|
||||||
|
};
|
||||||
|
|
||||||
|
rl02::rl02(const std::vector<std::string> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity) :
|
||||||
|
b(b),
|
||||||
|
disk_read_acitivity(disk_read_acitivity),
|
||||||
|
disk_write_acitivity(disk_write_acitivity)
|
||||||
|
{
|
||||||
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
memset(xfer_buffer, 0x00, sizeof xfer_buffer);
|
||||||
|
|
||||||
|
for(auto file : files) {
|
||||||
|
#if defined(ESP32)
|
||||||
|
File32 *fh = new File32();
|
||||||
|
|
||||||
|
if (!fh->open(file.c_str(), O_RDWR)) {
|
||||||
|
delete fh;
|
||||||
|
error_exit(true, "rl02: cannot open \"%s\"", file.c_str());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
FILE *fh = fopen(file.c_str(), "rb");
|
||||||
|
if (!fh)
|
||||||
|
error_exit(true, "rl02: cannot open \"%s\"", file.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fhs.push_back(fh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rl02::~rl02()
|
||||||
|
{
|
||||||
|
for(auto fh : fhs) {
|
||||||
|
#if defined(ESP32)
|
||||||
|
fh->close();
|
||||||
|
delete fh;
|
||||||
|
#else
|
||||||
|
fclose(fh);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rl02::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr & ~1);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t rl02::readWord(const uint16_t addr)
|
||||||
|
{
|
||||||
|
const int reg = (addr - RL02_BASE) / 2;
|
||||||
|
|
||||||
|
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, "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 - RL02_BASE) / 2];
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
vtemp &= ~0xff00;
|
||||||
|
vtemp |= v << 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vtemp &= ~0x00ff;
|
||||||
|
vtemp |= 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);
|
||||||
|
#endif
|
||||||
|
}
|
51
rl02.h
Normal file
51
rl02.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// (C) 2022 by Folkert van Heusden
|
||||||
|
// Released under Apache License v2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
#include "esp32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RL02_CSR 0174400 // control status register
|
||||||
|
#define RL02_BAR 0174402 // bus address register
|
||||||
|
#define RL02_DAR 0174404 // disk address register
|
||||||
|
#define RL02_MPR 0174406 // multi purpose register
|
||||||
|
#define RL02_BASE RL02_CSR
|
||||||
|
#define RL02_END (RL02_MPR + 2)
|
||||||
|
|
||||||
|
class bus;
|
||||||
|
|
||||||
|
class rl02
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
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();
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr);
|
||||||
|
uint16_t readWord(const uint16_t addr);
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v);
|
||||||
|
void writeWord(const uint16_t addr, const uint16_t v);
|
||||||
|
};
|
72
rx02.cpp
72
rx02.cpp
|
@ -1,72 +0,0 @@
|
||||||
// (C) 2018 by Folkert van Heusden
|
|
||||||
// Released under Apache License v2.0
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "rx02.h"
|
|
||||||
#include "gen.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
rx02::rx02(const std::string & file, memory *const m) : m(m)
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
memset(registers, 0x00, sizeof registers);
|
|
||||||
|
|
||||||
fh = fopen(file.c_str(), "rb");
|
|
||||||
}
|
|
||||||
|
|
||||||
rx02::~rx02()
|
|
||||||
{
|
|
||||||
fclose(fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t rx02::readByte(const uint16_t addr)
|
|
||||||
{
|
|
||||||
uint16_t v = readWord(addr & ~1);
|
|
||||||
|
|
||||||
if (addr & 1)
|
|
||||||
return v >> 8;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t rx02::readWord(const uint16_t addr)
|
|
||||||
{
|
|
||||||
const int reg = (addr - RX02_BASE) / 2;
|
|
||||||
uint16_t vtemp = registers[reg];
|
|
||||||
|
|
||||||
D(printf("RX02 read addr %o: ", addr);)
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
|
|
||||||
D(printf("%o\n", vtemp);)
|
|
||||||
|
|
||||||
return vtemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rx02::writeByte(const uint16_t addr, const uint8_t v)
|
|
||||||
{
|
|
||||||
uint16_t vtemp = registers[(addr - RX02_BASE) / 2];
|
|
||||||
|
|
||||||
if (addr & 1) {
|
|
||||||
vtemp &= ~0xff00;
|
|
||||||
vtemp |= v << 8;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vtemp &= ~0x00ff;
|
|
||||||
vtemp |= v;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeWord(addr, vtemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rx02::writeWord(const uint16_t addr, uint16_t v)
|
|
||||||
{
|
|
||||||
D(printf("RX02 write %o: %o\n", addr, v);)
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
|
|
||||||
D(printf("set register %o to %o\n", addr, v);)
|
|
||||||
registers[(addr - RX02_BASE) / 2] = v;
|
|
||||||
}
|
|
33
rx02.h
33
rx02.h
|
@ -1,33 +0,0 @@
|
||||||
// (C) 2018 by Folkert van Heusden
|
|
||||||
// Released under Apache License v2.0
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// FIXME namen van defines
|
|
||||||
#define RX02_BASE 0
|
|
||||||
#define RX02_END (1 + 2)
|
|
||||||
|
|
||||||
class memory;
|
|
||||||
|
|
||||||
class rx02
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
memory *const m;
|
|
||||||
uint16_t registers[7];
|
|
||||||
uint8_t xfer_buffer[512];
|
|
||||||
int offset;
|
|
||||||
FILE *fh;
|
|
||||||
|
|
||||||
public:
|
|
||||||
rx02(const std::string & file, memory *const m);
|
|
||||||
virtual ~rx02();
|
|
||||||
|
|
||||||
uint8_t readByte(const uint16_t addr);
|
|
||||||
uint16_t readWord(const uint16_t addr);
|
|
||||||
|
|
||||||
void writeByte(const uint16_t addr, const uint8_t v);
|
|
||||||
void writeWord(const uint16_t addr, uint16_t v);
|
|
||||||
};
|
|
Loading…
Add table
Reference in a new issue