Merge branch 'master' into MMR1
This commit is contained in:
commit
a00226e118
27 changed files with 897 additions and 271 deletions
|
@ -14,6 +14,9 @@ add_executable(
|
|||
console_posix.cpp
|
||||
cpu.cpp
|
||||
debugger.cpp
|
||||
disk_backend.cpp
|
||||
disk_backend_file.cpp
|
||||
disk_backend_nbd.cpp
|
||||
error.cpp
|
||||
kw11-l.cpp
|
||||
loaders.cpp
|
||||
|
|
1
ESP32/disk_backend.cpp
Symbolic link
1
ESP32/disk_backend.cpp
Symbolic link
|
@ -0,0 +1 @@
|
|||
../disk_backend.cpp
|
1
ESP32/disk_backend.h
Symbolic link
1
ESP32/disk_backend.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../disk_backend.h
|
93
ESP32/disk_backend_esp32.cpp
Normal file
93
ESP32/disk_backend_esp32.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "disk_backend_esp32.h"
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
disk_backend_esp32::disk_backend_esp32(const std::string & filename) :
|
||||
filename(filename),
|
||||
fh(new File32())
|
||||
{
|
||||
}
|
||||
|
||||
disk_backend_esp32::~disk_backend_esp32()
|
||||
{
|
||||
fh->close();
|
||||
|
||||
delete fh;
|
||||
}
|
||||
|
||||
bool disk_backend_esp32::begin()
|
||||
{
|
||||
if (!fh->open(filename.c_str(), O_RDWR)) {
|
||||
DOLOG(ll_error, true, "rk05: cannot open \"%s\"", filename.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_esp32::read(const off_t offset, const size_t n, uint8_t *const target)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_esp32::read: read %zu bytes from offset %zu", n, offset);
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
if (!fh->seek(offset))
|
||||
DOLOG(ll_error, true, "seek error %s", strerror(errno));
|
||||
|
||||
yield();
|
||||
|
||||
if (fh->read(target, n) != size_t(n)) {
|
||||
DOLOG(debug, true, "fread error: %s", strerror(errno));
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
yield();
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_esp32::write(const off_t offset, const size_t n, const uint8_t *const from)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_esp32::write: write %zu bytes to offset %zu", n, offset);
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
if (!fh->seek(offset))
|
||||
DOLOG(ll_error, true, "seek error %s", strerror(errno));
|
||||
|
||||
yield();
|
||||
|
||||
if (fh->write(from, n) != n) {
|
||||
DOLOG(ll_error, true, "RK05 fwrite error %s", strerror(errno));
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
yield();
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
22
ESP32/disk_backend_esp32.h
Normal file
22
ESP32/disk_backend_esp32.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <string>
|
||||
|
||||
#include "disk_backend.h"
|
||||
#include "esp32.h"
|
||||
|
||||
|
||||
class disk_backend_esp32 : public disk_backend
|
||||
{
|
||||
private:
|
||||
const std::string filename;
|
||||
File32 *const fh { nullptr };
|
||||
|
||||
public:
|
||||
disk_backend_esp32(const std::string & filename);
|
||||
virtual ~disk_backend_esp32();
|
||||
|
||||
bool begin() override;
|
||||
|
||||
bool read(const off_t offset, const size_t n, uint8_t *const target) override;
|
||||
|
||||
bool write(const off_t offset, const size_t n, const uint8_t *const from) override;
|
||||
};
|
1
ESP32/disk_backend_nbd.cpp
Symbolic link
1
ESP32/disk_backend_nbd.cpp
Symbolic link
|
@ -0,0 +1 @@
|
|||
../disk_backend_nbd.cpp
|
1
ESP32/disk_backend_nbd.h
Symbolic link
1
ESP32/disk_backend_nbd.h
Symbolic link
|
@ -0,0 +1 @@
|
|||
../disk_backend_nbd.h
|
|
@ -1,7 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#define USE_SDFAT
|
||||
#define SD_FAT_TYPE 1
|
||||
#include <SdFat.h>
|
||||
|
|
257
ESP32/main.ino
257
ESP32/main.ino
|
@ -1,4 +1,4 @@
|
|||
// (C) 2018-2022 by Folkert van Heusden
|
||||
// (C) 2018-2023 by Folkert van Heusden
|
||||
// Released under Apache License v2.0
|
||||
#include <atomic>
|
||||
#include <stdio.h>
|
||||
|
@ -12,6 +12,9 @@
|
|||
#include "console_esp32.h"
|
||||
#include "cpu.h"
|
||||
#include "debugger.h"
|
||||
#include "disk_backend.h"
|
||||
#include "disk_backend_esp32.h"
|
||||
#include "disk_backend_nbd.h"
|
||||
#include "error.h"
|
||||
#include "esp32.h"
|
||||
#include "gen.h"
|
||||
|
@ -53,58 +56,87 @@ void console_thread_wrapper_io(void *const c)
|
|||
cnsl->operator()();
|
||||
}
|
||||
|
||||
void setup_wifi_stations()
|
||||
typedef enum { BE_NETWORK, BE_SD } disk_backend_t;
|
||||
std::optional<disk_backend_t> select_disk_backend(console *const c)
|
||||
{
|
||||
#if 0
|
||||
WiFi.mode(WIFI_STA);
|
||||
c->put_string("1. network (NBD), 2. local SD card, 9. abort");
|
||||
|
||||
WiFi.softAP("PDP-11 KEK", nullptr, 5, 0, 4);
|
||||
int ch = -1;
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9')
|
||||
ch = c->wait_char(500);
|
||||
|
||||
#if 0
|
||||
Serial.println(F("Scanning for WiFi access points..."));
|
||||
c->put_string_lf(format("%c", ch));
|
||||
|
||||
int n = WiFi.scanNetworks();
|
||||
if (ch == '9')
|
||||
return { };
|
||||
|
||||
Serial.println(F("scan done"));
|
||||
if (ch == '1')
|
||||
return BE_NETWORK;
|
||||
|
||||
if (n == 0)
|
||||
Serial.println(F("no networks found"));
|
||||
else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// Print SSID and RSSI for each network found
|
||||
Serial.print(i + 1);
|
||||
Serial.print(F(": "));
|
||||
Serial.print(WiFi.SSID(i));
|
||||
Serial.print(F(" ("));
|
||||
Serial.print(WiFi.RSSI(i));
|
||||
Serial.print(F(")"));
|
||||
Serial.println(WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? " " : "*");
|
||||
delay(10);
|
||||
}
|
||||
// if (ch == '2')
|
||||
return BE_SD;
|
||||
}
|
||||
|
||||
typedef enum { DT_RK05, DT_RL02 } disk_type_t;
|
||||
|
||||
std::optional<disk_type_t> select_disk_type(console *const c)
|
||||
{
|
||||
c->put_string("1. RK05, 2. RL02, 9. abort");
|
||||
|
||||
int ch = -1;
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '9')
|
||||
ch = c->wait_char(500);
|
||||
|
||||
c->put_string_lf(format("%c", ch));
|
||||
|
||||
if (ch == '9')
|
||||
return { };
|
||||
|
||||
if (ch == '1')
|
||||
return DT_RK05;
|
||||
|
||||
// if (ch == '2')
|
||||
return DT_RL02;
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::vector<disk_backend *>, std::vector<disk_backend *> > > select_nbd_server(console *const c)
|
||||
{
|
||||
c->flush_input();
|
||||
|
||||
std::string hostname = c->read_line("Enter hostname (or empty to abort): ");
|
||||
|
||||
if (hostname.empty())
|
||||
return { };
|
||||
|
||||
std::string port_str = c->read_line("Enter port number (or empty to abort): ");
|
||||
|
||||
if (port_str.empty())
|
||||
return { };
|
||||
|
||||
auto disk_type = select_disk_type(c);
|
||||
|
||||
if (disk_type.has_value() == false)
|
||||
return { };
|
||||
|
||||
disk_backend *d = new disk_backend_nbd(hostname, atoi(port_str.c_str()));
|
||||
|
||||
if (d->begin() == false) {
|
||||
c->put_string_lf("Cannot initialize NBD client");
|
||||
delete d;
|
||||
return { };
|
||||
}
|
||||
|
||||
std::string ssid = read_terminal_line("SSID: ");
|
||||
std::string password = read_terminal_line("password: ");
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
#else
|
||||
WiFi.begin("www.vanheusden.com", "Ditiseentest31415926");
|
||||
//WiFi.begin("NURDspace-guest", "harkharkhark");
|
||||
#endif
|
||||
if (disk_type.value() == DT_RK05)
|
||||
return { { { d }, { } } };
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print('.');
|
||||
if (disk_type.value() == DT_RL02)
|
||||
return { { { }, { d } } };
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
||||
on_wifi = true;
|
||||
|
||||
Serial.println(WiFi.localIP());
|
||||
#endif
|
||||
return { };
|
||||
}
|
||||
|
||||
// RK05, RL02 files
|
||||
std::pair<std::vector<std::string>, std::vector<std::string> > select_disk_files(console *const c)
|
||||
std::optional<std::pair<std::vector<disk_backend *>, std::vector<disk_backend *> > > select_disk_files(console *const c)
|
||||
{
|
||||
c->debug("MISO: %d", int(MISO));
|
||||
c->debug("MOSI: %d", int(MOSI));
|
||||
|
@ -126,16 +158,10 @@ std::pair<std::vector<std::string>, std::vector<std::string> > select_disk_files
|
|||
if (selected_file.empty())
|
||||
continue;
|
||||
|
||||
c->put_string("1. RK05, 2. RL02, 3. re-select file");
|
||||
auto disk_type = select_disk_type(c);
|
||||
|
||||
int ch = -1;
|
||||
while(ch == -1 && ch != '1' && ch != '2' && ch != '3')
|
||||
ch = c->wait_char(500);
|
||||
|
||||
c->put_string_lf(format("%c", ch));
|
||||
|
||||
if (ch == '3')
|
||||
continue;
|
||||
if (disk_type.has_value() == false)
|
||||
return { };
|
||||
|
||||
c->put_string("Opening file: ");
|
||||
c->put_string_lf(selected_file.c_str());
|
||||
|
@ -145,17 +171,126 @@ std::pair<std::vector<std::string>, std::vector<std::string> > select_disk_files
|
|||
if (fh.open(selected_file.c_str(), O_RDWR)) {
|
||||
fh.close();
|
||||
|
||||
if (ch == '1')
|
||||
return { { selected_file }, { } };
|
||||
disk_backend *temp = new disk_backend_esp32(selected_file);
|
||||
|
||||
if (ch == '2')
|
||||
return { { }, { selected_file } };
|
||||
if (!temp->begin()) {
|
||||
c->put_string("Cannot use: ");
|
||||
c->put_string_lf(selected_file.c_str());
|
||||
|
||||
delete temp;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disk_type.value() == DT_RK05)
|
||||
return { { { temp }, { } } };
|
||||
|
||||
if (disk_type.value() == DT_RL02)
|
||||
return { { { }, { temp } } };
|
||||
}
|
||||
|
||||
c->put_string_lf("open failed");
|
||||
}
|
||||
}
|
||||
|
||||
void configure_disk(console *const c)
|
||||
{
|
||||
for(;;) {
|
||||
Serial.println(F("Load disk"));
|
||||
|
||||
auto backend = select_disk_backend(cnsl);
|
||||
|
||||
if (backend.has_value() == false)
|
||||
break;
|
||||
|
||||
std::optional<std::pair<std::vector<disk_backend *>, std::vector<disk_backend *> > > files;
|
||||
|
||||
if (backend == BE_NETWORK)
|
||||
files = select_nbd_server(cnsl);
|
||||
else // if (backend == BE_SD)
|
||||
files = select_disk_files(cnsl);
|
||||
|
||||
if (files.has_value() == false)
|
||||
break;
|
||||
|
||||
if (files.value().first.empty() == false)
|
||||
b->add_rk05(new rk05(files.value().first, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
|
||||
if (files.value().second.empty() == false)
|
||||
b->add_rl02(new rl02(files.value().second, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
|
||||
// TODO: allow bootloader to be selected
|
||||
if (files.value().first.empty() == false)
|
||||
setBootLoader(b, BL_RK05);
|
||||
else
|
||||
setBootLoader(b, BL_RL02);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_hostname()
|
||||
{
|
||||
WiFi.setHostname("PDP-11");
|
||||
}
|
||||
|
||||
void configure_network(console *const c)
|
||||
{
|
||||
WiFi.persistent(true);
|
||||
|
||||
WiFi.setAutoReconnect(true);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
c->put_string_lf("Scanning for wireless networks...");
|
||||
|
||||
int n_ssids = WiFi.scanNetworks();
|
||||
|
||||
c->put_string_lf("Wireless networks:");
|
||||
|
||||
for(int i=0; i<n_ssids; i++)
|
||||
c->put_string_lf(format("\t%s", WiFi.SSID(i).c_str()));
|
||||
|
||||
c->flush_input();
|
||||
|
||||
std::string wifi_ap = c->read_line("Enter SSID[|PSK]: ");
|
||||
|
||||
auto parts = split(wifi_ap, "|");
|
||||
|
||||
if (parts.size() > 2) {
|
||||
c->put_string_lf("Invalid SSID/PSK: should not contain '|'");
|
||||
return;
|
||||
}
|
||||
|
||||
set_hostname();
|
||||
|
||||
if (parts.size() == 1)
|
||||
WiFi.begin(parts.at(0).c_str());
|
||||
else
|
||||
WiFi.begin(parts.at(0).c_str(), parts.at(1).c_str());
|
||||
}
|
||||
|
||||
void start_network(console *const c)
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
set_hostname();
|
||||
|
||||
WiFi.begin();
|
||||
|
||||
int i = 0;
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED && i < 10 * 3) {
|
||||
c->put_string(".");
|
||||
|
||||
delay(1000 / 3);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
c->put_string_lf("");
|
||||
c->put_string_lf(format("Local IP address: %s", WiFi.localIP().toString().c_str()));
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
|
@ -181,8 +316,6 @@ void setup() {
|
|||
Serial.println(F("Connect CPU to BUS"));
|
||||
b->add_cpu(c);
|
||||
|
||||
c->setEmulateMFPT(true);
|
||||
|
||||
Serial.println(F("Init console"));
|
||||
cnsl = new console_esp32(&stop_event, b);
|
||||
|
||||
|
@ -205,20 +338,6 @@ void setup() {
|
|||
|
||||
// setup_wifi_stations();
|
||||
|
||||
Serial.println(F("Load RK05"));
|
||||
auto disk_files = select_disk_files(cnsl);
|
||||
|
||||
if (disk_files.first.empty() == false)
|
||||
b->add_rk05(new rk05(disk_files.first, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
|
||||
if (disk_files.second.empty() == false)
|
||||
b->add_rl02(new rl02(disk_files.second, b, cnsl->get_disk_read_activity_flag(), cnsl->get_disk_write_activity_flag()));
|
||||
|
||||
if (disk_files.first.empty() == false)
|
||||
setBootLoader(b, BL_RK05);
|
||||
else
|
||||
setBootLoader(b, BL_RL02);
|
||||
|
||||
Serial.print(F("Free RAM after init: "));
|
||||
Serial.println(ESP.getFreeHeap());
|
||||
|
||||
|
|
37
bus.cpp
37
bus.cpp
|
@ -17,7 +17,7 @@
|
|||
// see also https://github.com/espressif/esp-idf/issues/1934
|
||||
constexpr int n_pages = 12;
|
||||
#else
|
||||
constexpr int n_pages = 128; // 1MB
|
||||
constexpr int n_pages = 32; // 32=256kB (for EKBEEx.BIC)
|
||||
#endif
|
||||
|
||||
constexpr uint16_t di_ena_mask[4] = { 4, 2, 0, 1 };
|
||||
|
@ -309,8 +309,11 @@ uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev,
|
|||
uint32_t m_offset = calculate_physical_address(run_mode, a, !peek_only, false, peek_only, space == d_space);
|
||||
|
||||
if (peek_only == false && m_offset >= n_pages * 8192) {
|
||||
if (!peek_only) DOLOG(debug, false, "Read non existing mapped memory (%o >= %o)", m_offset, n_pages * 8192);
|
||||
if (!peek_only) DOLOG(debug, true, "Read non existing mapped memory (%o >= %o)", m_offset, n_pages * 8192);
|
||||
|
||||
c->schedule_trap(004); // no such memory
|
||||
|
||||
throw 6;
|
||||
}
|
||||
|
||||
if (word_mode)
|
||||
|
@ -358,7 +361,8 @@ void bus::clearMMR0Bit(const int bit)
|
|||
|
||||
void bus::setMMR2(const uint16_t value)
|
||||
{
|
||||
MMR2 = value;
|
||||
if ((MMR0 & 0xe000) == 0)
|
||||
MMR2 = value;
|
||||
}
|
||||
|
||||
void bus::check_odd_addressing(const uint16_t a, const int run_mode, const d_i_space_t space, const bool is_write)
|
||||
|
@ -424,19 +428,26 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
|||
|
||||
bool do_trap = false;
|
||||
|
||||
if (access_control == 0)
|
||||
if (is_write && access_control != 6) // write
|
||||
do_trap = true;
|
||||
else if (is_write && access_control != 6) // write
|
||||
do_trap = true;
|
||||
else if (!is_write && (access_control == 0 || access_control == 1 || access_control == 3 || access_control == 4 || access_control == 7)) {
|
||||
else if (!is_write && (access_control == 0 || access_control == 1 || access_control == 3 || access_control == 4 || access_control == 7)) { // read
|
||||
do_trap = true;
|
||||
}
|
||||
|
||||
if (do_trap) {
|
||||
DOLOG(debug, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a);
|
||||
bool do_trap_250 = false;
|
||||
|
||||
if (MMR0 & (1 << 9))
|
||||
c->schedule_trap(0250); // invalid address
|
||||
if ((MMR0 & (1 << 9)) && (MMR0 & 0xf000) == 0) {
|
||||
DOLOG(debug, true, "TRAP(0250) (throw 1) for access_control %d on address %06o", access_control, a);
|
||||
|
||||
do_trap_250 = true;
|
||||
}
|
||||
else {
|
||||
DOLOG(debug, true, "A.C.F. triggger for %d on address %06o", access_control, a);
|
||||
}
|
||||
|
||||
if (access_control == 1 || access_control == 4 || access_control == 5)
|
||||
MMR0 |= 1 << 12; // set trap-flag
|
||||
|
||||
if (is_write)
|
||||
pages[run_mode][d][apf].pdr |= 1 << 7;
|
||||
|
@ -457,7 +468,11 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
|
|||
|
||||
DOLOG(debug, true, "MMR0: %06o", MMR0);
|
||||
|
||||
throw 1;
|
||||
if (do_trap_250) {
|
||||
c->schedule_trap(0250); // invalid address
|
||||
|
||||
throw 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
cpu.cpp
28
cpu.cpp
|
@ -1293,7 +1293,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
psw &= 0xff00; // only alter lower 8 bits
|
||||
psw |= getGAM(dst_mode, dst_reg, word_mode, false).value.value() & 0xef; // can't change bit 4
|
||||
#else
|
||||
schedule_trap(010);
|
||||
trap(010);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@ -1324,7 +1324,7 @@ bool cpu::single_operand_instructions(const uint16_t instr)
|
|||
setPSW_n(extend_b7);
|
||||
}
|
||||
#else
|
||||
schedule_trap(010);
|
||||
trap(010);
|
||||
#endif
|
||||
}
|
||||
else { // SXT
|
||||
|
@ -1438,7 +1438,7 @@ bool cpu::condition_code_operations(const uint16_t instr)
|
|||
setPSW_spl(level);
|
||||
|
||||
// // trap via vector 010 only(?) on an 11/60 and not(?) on an 11/70
|
||||
// schedule_trap(010);
|
||||
// trap(010);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1466,7 +1466,7 @@ void cpu::pushStack(const uint16_t v)
|
|||
if (getRegister(6) == stackLimitRegister) {
|
||||
DOLOG(debug, true, "stackLimitRegister reached %06o while pushing %06o", stackLimitRegister, v);
|
||||
|
||||
schedule_trap(123);
|
||||
trap(123, 7); // TODO
|
||||
}
|
||||
else {
|
||||
uint16_t a = addRegister(6, false, -2);
|
||||
|
@ -1501,11 +1501,11 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
return true;
|
||||
|
||||
case 0b0000000000000011: // BPT
|
||||
schedule_trap(014);
|
||||
trap(014);
|
||||
return true;
|
||||
|
||||
case 0b0000000000000100: // IOT
|
||||
schedule_trap(020);
|
||||
trap(020);
|
||||
return true;
|
||||
|
||||
case 0b0000000000000110: // RTT
|
||||
|
@ -1515,7 +1515,7 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
|
||||
case 0b0000000000000111: // MFPT
|
||||
//setRegister(0, 0);
|
||||
schedule_trap(010); // does not exist on PDP-11/70
|
||||
trap(010); // does not exist on PDP-11/70
|
||||
return true;
|
||||
|
||||
case 0b0000000000000101: // RESET
|
||||
|
@ -1525,12 +1525,12 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
}
|
||||
|
||||
if ((instr >> 8) == 0b10001000) { // EMT
|
||||
schedule_trap(030);
|
||||
trap(030);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((instr >> 8) == 0b10001001) { // TRAP
|
||||
schedule_trap(034);
|
||||
trap(034);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1583,7 @@ bool cpu::misc_operations(const uint16_t instr)
|
|||
|
||||
void cpu::schedule_trap(const uint16_t vector)
|
||||
{
|
||||
DOLOG(debug, false, "schedule_trap @ %06o", pc);
|
||||
DOLOG(debug, true, "schedule_trap @ %06o", pc);
|
||||
|
||||
scheduled_trap = vector;
|
||||
}
|
||||
|
@ -2169,9 +2169,15 @@ void cpu::step_b()
|
|||
|
||||
uint16_t temp_pc = getPC();
|
||||
|
||||
if ((b->getMMR0() & 0160000) == 0)
|
||||
b->setMMR2(temp_pc);
|
||||
|
||||
try {
|
||||
uint16_t instr = b->readWord(temp_pc);
|
||||
|
||||
if (temp_pc == 025250)
|
||||
DOLOG(debug, true, "GREP %06o %06o", temp_pc, instr);
|
||||
|
||||
addRegister(7, false, 2);
|
||||
|
||||
if (double_operand_instructions(instr))
|
||||
|
@ -2188,7 +2194,7 @@ void cpu::step_b()
|
|||
|
||||
DOLOG(warning, true, "UNHANDLED instruction %06o @ %06o", instr, temp_pc);
|
||||
|
||||
schedule_trap(010);
|
||||
trap(010);
|
||||
}
|
||||
catch(const int exception) {
|
||||
DOLOG(debug, true, "bus-trap during execution of command (%d)", exception);
|
||||
|
|
2
cpu.h
2
cpu.h
|
@ -132,7 +132,7 @@ public:
|
|||
void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; }
|
||||
|
||||
uint16_t getStackPointer(const int which) const { assert(which >= 0 && which < 4); return sp[which]; }
|
||||
uint16_t getPC() const { b->setMMR2(pc); return pc; }
|
||||
uint16_t getPC() const { return pc; }
|
||||
|
||||
void setRegister(const int nr, const bool reg_set, const bool prev_mode, const uint16_t value);
|
||||
void setRegister(const int nr, const bool prev_mode, const uint16_t v) { setRegister(nr, (getPSW() >> 11) & 1, prev_mode, v); }
|
||||
|
|
29
debugger.cpp
29
debugger.cpp
|
@ -7,7 +7,14 @@
|
|||
|
||||
|
||||
#if defined(ESP32)
|
||||
#include "esp32.h"
|
||||
|
||||
void setBootLoader(bus *const b);
|
||||
|
||||
void configure_disk(console *const c);
|
||||
|
||||
void configure_network(console *const c);
|
||||
void start_network(console *const c);
|
||||
#endif
|
||||
|
||||
// returns size of instruction (in bytes)
|
||||
|
@ -341,6 +348,23 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
#endif
|
||||
continue;
|
||||
}
|
||||
#if defined(ESP32)
|
||||
else if (cmd == "cfgdisk") {
|
||||
configure_disk(cnsl);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "cfgnet") {
|
||||
configure_network(cnsl);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (cmd == "startnet") {
|
||||
start_network(cnsl);
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
else if (cmd == "quit" || cmd == "q") {
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
|
@ -363,6 +387,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
|
|||
cnsl->put_string_lf("setpc - set PC to value");
|
||||
cnsl->put_string_lf("setmem - set memory (a=) to value (v=), both in octal, one byte");
|
||||
cnsl->put_string_lf("toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)");
|
||||
#if defined(ESP32)
|
||||
cnsl->put_string_lf("cfgnet - configure network (e.g. WiFi)");
|
||||
cnsl->put_string_lf("startnet - start network");
|
||||
cnsl->put_string_lf("cfgdisk - configure disk");
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
9
disk_backend.cpp
Normal file
9
disk_backend.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "disk_backend.h"
|
||||
|
||||
disk_backend::disk_backend()
|
||||
{
|
||||
}
|
||||
|
||||
disk_backend::~disk_backend()
|
||||
{
|
||||
}
|
18
disk_backend.h
Normal file
18
disk_backend.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
class disk_backend
|
||||
{
|
||||
public:
|
||||
disk_backend();
|
||||
virtual ~disk_backend();
|
||||
|
||||
virtual bool begin() = 0;
|
||||
|
||||
virtual bool read(const off_t offset, const size_t n, uint8_t *const target) = 0;
|
||||
|
||||
virtual bool write(const off_t offset, const size_t n, const uint8_t *const from) = 0;
|
||||
};
|
44
disk_backend_file.cpp
Normal file
44
disk_backend_file.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "disk_backend_file.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
disk_backend_file::disk_backend_file(const std::string & filename) :
|
||||
filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
disk_backend_file::~disk_backend_file()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool disk_backend_file::begin()
|
||||
{
|
||||
fd = open(filename.c_str(), O_RDWR);
|
||||
|
||||
if (fd == -1) {
|
||||
DOLOG(ll_error, true, "disk_backend_file: cannot open \"%s\": %s", filename.c_str(), strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_file::read(const off_t offset, const size_t n, uint8_t *const target)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_file::read: read %zu bytes from offset %zu", n, offset);
|
||||
|
||||
return pread(fd, target, n, offset) == ssize_t(n);
|
||||
}
|
||||
|
||||
bool disk_backend_file::write(const off_t offset, const size_t n, const uint8_t *const from)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_file::write: write %zu bytes to offset %zu", n, offset);
|
||||
|
||||
return pwrite(fd, from, n, offset) == ssize_t(n);
|
||||
}
|
22
disk_backend_file.h
Normal file
22
disk_backend_file.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <string>
|
||||
|
||||
#include "disk_backend.h"
|
||||
|
||||
|
||||
class disk_backend_file : public disk_backend
|
||||
{
|
||||
private:
|
||||
const std::string filename;
|
||||
|
||||
int fd { -1 };
|
||||
|
||||
public:
|
||||
disk_backend_file(const std::string & filename);
|
||||
virtual ~disk_backend_file();
|
||||
|
||||
bool begin() override;
|
||||
|
||||
bool read(const off_t offset, const size_t n, uint8_t *const target) override;
|
||||
|
||||
bool write(const off_t offset, const size_t n, const uint8_t *const from) override;
|
||||
};
|
269
disk_backend_nbd.cpp
Normal file
269
disk_backend_nbd.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "disk_backend_nbd.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include <lwip/netdb.h>
|
||||
#include <lwip/sockets.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
|
||||
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))
|
||||
|
||||
|
||||
disk_backend_nbd::disk_backend_nbd(const std::string & host, const int port) :
|
||||
host(host),
|
||||
port(port)
|
||||
{
|
||||
}
|
||||
|
||||
disk_backend_nbd::~disk_backend_nbd()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool disk_backend_nbd::begin()
|
||||
{
|
||||
if (!connect(false)) {
|
||||
DOLOG(ll_error, true, "disk_backend_nbd: cannot connect to NBD server");
|
||||
return false;
|
||||
}
|
||||
|
||||
DOLOG(info, true, "disk_backend_nbd: connected to NBD server");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_nbd::connect(const bool retry)
|
||||
{
|
||||
do {
|
||||
// LOOP until connected, logging message, exponential backoff?
|
||||
addrinfo *res = nullptr;
|
||||
|
||||
addrinfo hints { 0 };
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
char port_str[8] { 0 };
|
||||
snprintf(port_str, sizeof port_str, "%d", port);
|
||||
|
||||
int rc = getaddrinfo(host.c_str(), port_str, &hints, &res);
|
||||
|
||||
if (rc != 0) {
|
||||
#ifdef ESP32
|
||||
DOLOG(ll_error, true, "disk_backend_nbd: cannot resolve \"%s\":%s", host.c_str(), port_str);
|
||||
#else
|
||||
DOLOG(ll_error, true, "disk_backend_nbd: cannot resolve \"%s\":%s: %s", host.c_str(), port_str, gai_strerror(rc));
|
||||
#endif
|
||||
|
||||
sleep(1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for(addrinfo *p = res; p != NULL; p = p->ai_next) {
|
||||
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (::connect(fd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
DOLOG(ll_error, true, "disk_backend_nbd: cannot connect");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t magic1[8];
|
||||
uint8_t magic2[8];
|
||||
uint64_t size;
|
||||
uint32_t flags;
|
||||
uint8_t padding[124];
|
||||
} nbd_hello;
|
||||
|
||||
if (fd != -1) {
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_hello), sizeof nbd_hello) != sizeof nbd_hello) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
DOLOG(debug, false, "disk_backend_nbd::connect: connect short read");
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
DOLOG(debug, false, "disk_backend_nbd::connect: magic invalid");
|
||||
}
|
||||
|
||||
DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size));
|
||||
}
|
||||
while(fd == -1 && retry);
|
||||
|
||||
return fd != -1;
|
||||
}
|
||||
|
||||
bool disk_backend_nbd::read(const off_t offset, const size_t n, uint8_t *const target)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: read %zu bytes from offset %zu", n, offset);
|
||||
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
do {
|
||||
if (fd == -1 && !connect(true)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: (re-)connect");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint64_t handle;
|
||||
uint64_t offset;
|
||||
uint32_t length;
|
||||
} nbd_request { 0 };
|
||||
|
||||
nbd_request.magic = ntohl(0x25609513);
|
||||
nbd_request.type = 0; // READ
|
||||
nbd_request.offset = HTONLL(uint64_t(offset));
|
||||
nbd_request.length = htonl(n);
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(&nbd_request), sizeof nbd_request) != sizeof nbd_request) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem sending request");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t error;
|
||||
uint64_t handle;
|
||||
} nbd_reply;
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_reply), sizeof nbd_reply) != sizeof nbd_reply) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem receiving reply header");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ntohl(nbd_reply.magic) != 0x67446698) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: bad reply header %08x", nbd_reply.magic);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
int error = ntohl(nbd_reply.error);
|
||||
if (error) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: NBD server indicated error: %d", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(target), n) != ssize_t(n)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem receiving payload");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while(fd == -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_nbd::write(const off_t offset, const size_t n, const uint8_t *const from)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: write %zu bytes to offset %zu", n, offset);
|
||||
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
do {
|
||||
if (!connect(true)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: (re-)connect");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint64_t handle;
|
||||
uint64_t offset;
|
||||
uint32_t length;
|
||||
} nbd_request { 0 };
|
||||
|
||||
nbd_request.magic = ntohl(0x25609513);
|
||||
nbd_request.type = 1; // WRITE
|
||||
nbd_request.offset = HTONLL(uint64_t(offset));
|
||||
nbd_request.length = htonl(n);
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(&nbd_request), sizeof nbd_request) != sizeof nbd_request) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem sending request");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(from), n) != ssize_t(n)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem sending payload");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t error;
|
||||
uint64_t handle;
|
||||
} nbd_reply;
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_reply), sizeof nbd_reply) != sizeof nbd_reply) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem receiving reply header");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ntohl(nbd_reply.magic) != 0x67446698) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: bad reply header %08x", nbd_reply.magic);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
int error = ntohl(nbd_reply.error);
|
||||
if (error) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: NBD server indicated error: %d", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while(fd == -1);
|
||||
|
||||
return true;
|
||||
}
|
25
disk_backend_nbd.h
Normal file
25
disk_backend_nbd.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include <string>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "disk_backend.h"
|
||||
|
||||
|
||||
class disk_backend_nbd : public disk_backend
|
||||
{
|
||||
private:
|
||||
const std::string host;
|
||||
const int port { 0 };
|
||||
int fd { -1 };
|
||||
|
||||
bool connect(const bool retry);
|
||||
|
||||
public:
|
||||
disk_backend_nbd(const std::string & host, const int port);
|
||||
virtual ~disk_backend_nbd();
|
||||
|
||||
bool begin() override;
|
||||
|
||||
bool read(const off_t offset, const size_t n, uint8_t *const target) override;
|
||||
|
||||
bool write(const off_t offset, const size_t n, const uint8_t *const from) override;
|
||||
};
|
|
@ -5,6 +5,11 @@
|
|||
#include "kw11-l.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if defined(ESP32)
|
||||
#include "esp32.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(ESP32)
|
||||
void thread_wrapper_kw11(void *p)
|
||||
{
|
||||
|
|
38
main.cpp
38
main.cpp
|
@ -12,6 +12,9 @@
|
|||
#include "console_posix.h"
|
||||
#include "cpu.h"
|
||||
#include "debugger.h"
|
||||
#include "disk_backend.h"
|
||||
#include "disk_backend_file.h"
|
||||
#include "disk_backend_nbd.h"
|
||||
#include "gen.h"
|
||||
#include "kw11-l.h"
|
||||
#include "loaders.h"
|
||||
|
@ -45,6 +48,7 @@ void help()
|
|||
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\n");
|
||||
printf("-R d.rk load file as a RK05 disk device\n");
|
||||
printf("-r d.rl load file as a RL02 disk device\n");
|
||||
printf("-N host:port:type use NBD-server as disk device, type being either \"rk05\" or \"rl02\"\n");
|
||||
printf("-p 123 set CPU start pointer to decimal(!) value\n");
|
||||
printf("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n");
|
||||
printf("-n ncurses UI\n");
|
||||
|
@ -59,8 +63,8 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
//setlocale(LC_ALL, "");
|
||||
|
||||
std::vector<std::string> rk05_files;
|
||||
std::vector<std::string> rl02_files;
|
||||
std::vector<disk_backend *> rk05_files;
|
||||
std::vector<disk_backend *> rl02_files;
|
||||
|
||||
bool run_debugger = false;
|
||||
bool tracing = false;
|
||||
|
@ -80,8 +84,10 @@ int main(int argc, char *argv[])
|
|||
|
||||
std::string test;
|
||||
|
||||
disk_backend *temp_d = nullptr;
|
||||
|
||||
int opt = -1;
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:s:Q:")) != -1)
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:s:Q:N:")) != -1)
|
||||
{
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
|
@ -132,13 +138,35 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
|
||||
case 'R':
|
||||
rk05_files.push_back(optarg);
|
||||
temp_d = new disk_backend_file(optarg);
|
||||
if (!temp_d->begin())
|
||||
error_exit(false, "Cannot use file \"%s\" for RK05", optarg);
|
||||
rk05_files.push_back(temp_d);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
rl02_files.push_back(optarg);
|
||||
temp_d = new disk_backend_file(optarg);
|
||||
if (!temp_d->begin())
|
||||
error_exit(false, "Cannot use file \"%s\" for RL02", optarg);
|
||||
rl02_files.push_back(temp_d);
|
||||
break;
|
||||
|
||||
case 'N': {
|
||||
auto parts = split(optarg, ":");
|
||||
if (parts.size() != 3)
|
||||
error_exit(false, "-N: parameter missing");
|
||||
|
||||
temp_d = new disk_backend_nbd(parts.at(0), atoi(parts.at(1).c_str()));
|
||||
|
||||
if (parts.at(2) == "rk05")
|
||||
rk05_files.push_back(temp_d);
|
||||
else if (parts.at(2) == "rl02")
|
||||
rl02_files.push_back(temp_d);
|
||||
else
|
||||
error_exit(false, "\"%s\" is not recognized as a disk type", parts.at(2).c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
start_addr = atoi(optarg);
|
||||
sa_set = true;
|
||||
|
|
90
rk05.cpp
90
rk05.cpp
|
@ -22,42 +22,21 @@ static const char * const regnames[] = {
|
|||
"RK05_DATABUF "
|
||||
};
|
||||
|
||||
rk05::rk05(const std::vector<std::string> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity) :
|
||||
rk05::rk05(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),
|
||||
disk_read_acitivity(disk_read_acitivity),
|
||||
disk_write_acitivity(disk_write_acitivity)
|
||||
{
|
||||
memset(registers, 0x00, sizeof registers);
|
||||
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, "rk05: cannot open \"%s\"", file.c_str());
|
||||
}
|
||||
#else
|
||||
FILE *fh = fopen(file.c_str(), "rb");
|
||||
if (!fh)
|
||||
error_exit(true, "rk05: cannot open \"%s\"", file.c_str());
|
||||
#endif
|
||||
|
||||
fhs.push_back(fh);
|
||||
}
|
||||
fhs = files;
|
||||
}
|
||||
|
||||
rk05::~rk05()
|
||||
{
|
||||
for(auto fh : fhs) {
|
||||
#if defined(ESP32)
|
||||
fh->close();
|
||||
for(auto fh : fhs)
|
||||
delete fh;
|
||||
#else
|
||||
fclose(fh);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rk05::readByte(const uint16_t addr)
|
||||
|
@ -117,10 +96,6 @@ void rk05::writeByte(const uint16_t addr, const uint8_t v)
|
|||
|
||||
void rk05::writeWord(const uint16_t addr, uint16_t v)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
const int reg = (addr - RK05_BASE) / 2;
|
||||
|
||||
registers[reg] = v;
|
||||
|
@ -158,19 +133,8 @@ void rk05::writeWord(const uint16_t addr, uint16_t v)
|
|||
for(size_t i=0; i<reclen; i++)
|
||||
xfer_buffer[i] = b->readUnibusByte(memoff + i);
|
||||
|
||||
#if defined(ESP32)
|
||||
File32 *fh = fhs.at(device);
|
||||
if (!fh->seek(diskoffb))
|
||||
DOLOG(ll_error, true, "RK05 seek error %s", strerror(errno));
|
||||
if (fh->write(xfer_buffer, reclen) != reclen)
|
||||
DOLOG(ll_error, true, "RK05 fwrite error %s", strerror(errno));
|
||||
#else
|
||||
FILE *fh = fhs.at(device);
|
||||
if (fseek(fh, diskoffb, SEEK_SET) == -1)
|
||||
DOLOG(ll_error, true, "RK05 seek error %s", strerror(errno));
|
||||
if (fwrite(xfer_buffer, 1, reclen, fh) != reclen)
|
||||
DOLOG(ll_error, true, "RK05 fwrite error %s", strerror(errno));
|
||||
#endif
|
||||
if (!fhs.at(device)->write(diskoffb, reclen, xfer_buffer))
|
||||
DOLOG(ll_error, true, "RK05 pwrite error %s", strerror(errno));
|
||||
|
||||
if (v & 2048)
|
||||
DOLOG(debug, true, "RK05 inhibit BA increase");
|
||||
|
@ -194,43 +158,19 @@ void rk05::writeWord(const uint16_t addr, uint16_t v)
|
|||
|
||||
DOLOG(debug, true, "RK05 drive %d position sec %d surf %d cyl %d, reclen %zo, READ from %o, mem: %o", device, sector, surface, cylinder, reclen, diskoffb, memoff);
|
||||
|
||||
bool proceed = true;
|
||||
|
||||
#if defined(ESP32)
|
||||
File32 *fh = fhs.at(device);
|
||||
if (!fh->seek(diskoffb)) {
|
||||
DOLOG(ll_error, true, "RK05 seek error %s", strerror(errno));
|
||||
proceed = false;
|
||||
}
|
||||
#else
|
||||
FILE *fh = nullptr;
|
||||
|
||||
if (device >= fhs.size())
|
||||
proceed = false;
|
||||
else {
|
||||
fh = fhs.at(device);
|
||||
|
||||
if (fseek(fh, diskoffb, SEEK_SET) == -1) {
|
||||
DOLOG(ll_error, true, "RK05 seek error %s", strerror(errno));
|
||||
proceed = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int temp_diskoffb = diskoffb;
|
||||
|
||||
uint32_t temp = reclen;
|
||||
uint32_t p = memoff;
|
||||
while(proceed && temp > 0) {
|
||||
while(temp > 0) {
|
||||
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), temp);
|
||||
|
||||
#if defined(ESP32)
|
||||
yield();
|
||||
if (!fhs.at(device)->read(temp_diskoffb, cur, xfer_buffer)) {
|
||||
DOLOG(ll_error, true, "RK05 read error %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (fh->read(xfer_buffer, cur) != size_t(cur))
|
||||
DOLOG(debug, true, "RK05 fread error: %s", strerror(errno));
|
||||
#else
|
||||
if (fread(xfer_buffer, 1, cur, fh) != size_t(cur))
|
||||
DOLOG(debug, true, "RK05 fread error: %s", strerror(errno));
|
||||
#endif
|
||||
temp_diskoffb += cur;
|
||||
|
||||
for(uint32_t i=0; i<cur; i++) {
|
||||
if (p < 0160000)
|
||||
|
@ -284,8 +224,4 @@ void rk05::writeWord(const uint16_t addr, uint16_t v)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
}
|
||||
|
|
21
rk05.h
21
rk05.h
|
@ -1,4 +1,4 @@
|
|||
// (C) 2018-2022 by Folkert van Heusden
|
||||
// (C) 2018-2023 by Folkert van Heusden
|
||||
// Released under Apache License v2.0
|
||||
#pragma once
|
||||
|
||||
|
@ -8,9 +8,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(ESP32)
|
||||
#include "esp32.h"
|
||||
#endif
|
||||
#include "disk_backend.h"
|
||||
|
||||
|
||||
#define RK05_DS 0177400 // drive status
|
||||
|
@ -28,19 +26,16 @@ class bus;
|
|||
class rk05
|
||||
{
|
||||
private:
|
||||
bus *const b;
|
||||
uint16_t registers[7];
|
||||
uint8_t xfer_buffer[512];
|
||||
#if defined(ESP32)
|
||||
std::vector<File32 *> fhs;
|
||||
#else
|
||||
std::vector<FILE *> fhs;
|
||||
#endif
|
||||
bus *const b { nullptr };
|
||||
uint16_t registers [ 7];
|
||||
uint8_t xfer_buffer[512];
|
||||
std::vector<disk_backend *> fhs;
|
||||
|
||||
std::atomic_bool *const disk_read_acitivity { nullptr };
|
||||
std::atomic_bool *const disk_write_acitivity { nullptr };
|
||||
|
||||
public:
|
||||
rk05(const std::vector<std::string> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||
rk05(const std::vector<disk_backend *> & files, bus *const b, std::atomic_bool *const disk_read_acitivity, std::atomic_bool *const disk_write_acitivity);
|
||||
virtual ~rk05();
|
||||
|
||||
uint8_t readByte(const uint16_t addr);
|
||||
|
|
83
rl02.cpp
83
rl02.cpp
|
@ -22,7 +22,7 @@ static const char * const regnames[] = {
|
|||
"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) :
|
||||
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),
|
||||
disk_read_acitivity(disk_read_acitivity),
|
||||
disk_write_acitivity(disk_write_acitivity)
|
||||
|
@ -30,34 +30,13 @@ rl02::rl02(const std::vector<std::string> & files, bus *const b, std::atomic_boo
|
|||
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);
|
||||
}
|
||||
fhs = files;
|
||||
}
|
||||
|
||||
rl02::~rl02()
|
||||
{
|
||||
for(auto fh : fhs) {
|
||||
#if defined(ESP32)
|
||||
fh->close();
|
||||
for(auto fh : fhs)
|
||||
delete fh;
|
||||
#else
|
||||
fclose(fh);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rl02::readByte(const uint16_t addr)
|
||||
|
@ -116,10 +95,6 @@ uint32_t rl02::calcOffset(const uint16_t da)
|
|||
|
||||
void rl02::writeWord(const uint16_t addr, uint16_t v)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
|
||||
DOLOG(debug, true, "RL02 write %06o: %06o", addr, v);
|
||||
|
||||
const int reg = (addr - RL02_BASE) / 2;
|
||||
|
@ -138,44 +113,13 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
|||
|
||||
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;
|
||||
|
||||
DOLOG(debug, true, "RL02 set MPR for status to %06o", 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)) {
|
||||
DOLOG(ll_error, true, "RL02 seek to %d error %s", 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) {
|
||||
DOLOG(ll_error, true, "RL02 seek error %s", strerror(errno));
|
||||
proceed = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
uint32_t temp_disk_offset = disk_offset;
|
||||
|
||||
uint32_t memory_address = registers[(RL02_BAR - RL02_BASE) / 2];
|
||||
|
||||
|
@ -187,19 +131,16 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
|||
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))
|
||||
DOLOG(info, true, "RL02 fread error: %s", strerror(errno));
|
||||
#else
|
||||
if (fread(xfer_buffer, 1, cur, fh) != size_t(cur))
|
||||
DOLOG(info, true, "RL02 fread error: %s", strerror(errno));
|
||||
#endif
|
||||
if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) {
|
||||
DOLOG(ll_error, true, "RL02 read error %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<cur; i++, p++)
|
||||
b->writeByte(p, xfer_buffer[i]);
|
||||
|
||||
temp_disk_offset += cur;
|
||||
|
||||
count -= cur;
|
||||
}
|
||||
|
||||
|
@ -212,8 +153,4 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
|
|||
*disk_read_acitivity = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ESP32)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
}
|
||||
|
|
16
rl02.h
16
rl02.h
|
@ -1,4 +1,4 @@
|
|||
// (C) 2022 by Folkert van Heusden
|
||||
// (C) 2023 by Folkert van Heusden
|
||||
// Released under Apache License v2.0
|
||||
#pragma once
|
||||
|
||||
|
@ -8,9 +8,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(ESP32)
|
||||
#include "esp32.h"
|
||||
#endif
|
||||
#include "disk_backend.h"
|
||||
|
||||
|
||||
#define RL02_CSR 0174400 // control status register
|
||||
#define RL02_BAR 0174402 // bus address register
|
||||
|
@ -27,12 +26,7 @@ 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::vector<disk_backend *> fhs;
|
||||
|
||||
std::atomic_bool *const disk_read_acitivity { nullptr };
|
||||
std::atomic_bool *const disk_write_acitivity { nullptr };
|
||||
|
@ -40,7 +34,7 @@ private:
|
|||
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);
|
||||
rl02(const std::vector<disk_backend *> & 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);
|
||||
|
|
47
utils.cpp
47
utils.cpp
|
@ -10,6 +10,7 @@
|
|||
#include <string>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -144,3 +145,49 @@ void set_thread_name(std::string name)
|
|||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t WRITE(int fd, const char *whereto, size_t len)
|
||||
{
|
||||
ssize_t cnt=0;
|
||||
|
||||
while(len > 0)
|
||||
{
|
||||
ssize_t rc = write(fd, whereto, len);
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
else if (rc == 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
whereto += rc;
|
||||
len -= rc;
|
||||
cnt += rc;
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ssize_t READ(int fd, char *whereto, size_t len)
|
||||
{
|
||||
ssize_t cnt=0;
|
||||
|
||||
while(len > 0)
|
||||
{
|
||||
ssize_t rc = read(fd, whereto, len);
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
else if (rc == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
whereto += rc;
|
||||
len -= rc;
|
||||
cnt += rc;
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
3
utils.h
3
utils.h
|
@ -18,3 +18,6 @@ uint64_t get_us();
|
|||
void myusleep(uint64_t us);
|
||||
|
||||
void set_thread_name(std::string name);
|
||||
|
||||
ssize_t WRITE(int fd, const char *whereto, size_t len);
|
||||
ssize_t READ(int fd, char *whereto, size_t len);
|
||||
|
|
Loading…
Add table
Reference in a new issue