Merge branch 'master' into psram

This commit is contained in:
folkert van heusden 2024-04-22 20:48:15 +02:00
commit 586d5bffb3
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
11 changed files with 247 additions and 69 deletions

View file

@ -17,8 +17,8 @@ board_build.filesystem = littlefs
lib_deps = greiman/SdFat@^2.1.2
adafruit/Adafruit NeoPixel
bblanchon/ArduinoJson@^6.19.4
build_flags = -std=gnu++17 -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
build_unflags = -std=gnu++11
build_flags = -std=gnu++2a -DESP32=1 -ggdb3 -D_GLIBCXX_USE_C99
build_unflags = -std=gnu++11 -std=gnu++17
extra_scripts = pre:prepare.py
[env:SHA2017-badge]
@ -32,8 +32,8 @@ board_build.filesystem = littlefs
lib_deps = greiman/SdFat@^2.1.2
adafruit/Adafruit NeoPixel
bblanchon/ArduinoJson@^6.19.4
build_flags = -std=gnu++17 -DESP32=1 -DSHA2017 -ggdb3 -D_GLIBCXX_USE_C99 -ISHAdisplay/Arduino/libraries/epd2in9-badge -ISHAdisplay/Arduino/libraries/epdpaint -ISHAdisplay/components/epaper-29-dke
build_unflags = -std=gnu++11
build_flags = -std=gnu++2a -DESP32=1 -DSHA2017 -ggdb3 -D_GLIBCXX_USE_C99 -ISHAdisplay/Arduino/libraries/epd2in9-badge -ISHAdisplay/Arduino/libraries/epdpaint -ISHAdisplay/components/epaper-29-dke
build_unflags = -std=gnu++11 -std=gnu++17
upload_protocol = esptool
[env:ESP32-ttgo-t-beam]

View file

@ -79,7 +79,7 @@ std::pair<breakpoint_register *, std::optional<std::string> > breakpoint_registe
return { nullptr, "register: key or value missing" };
auto values_in = parts.at(1);
auto v_parts = split(values_in, ",");
auto v_parts = split(std::move(values_in), ",");
std::set<uint16_t> values;
for(auto & v: v_parts)
values.insert(std::stoi(v, nullptr, 8));

16
bus.cpp
View file

@ -287,6 +287,11 @@ uint16_t bus::read(const uint16_t addr_in, const word_mode_t word_mode, const rm
return 0;
}
if (a >= 0172100 && a <= 0172137) { // MM11-LP parity
if (!peek_only) DOLOG(debug, false, "READ-I/O MM11-LP parity (%06o): %o", a, 1);
return 1;
}
if (word_mode == wm_byte) {
if (a == ADDR_PSW) { // PSW
uint8_t temp = c->getPSW();
@ -621,6 +626,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
uint32_t io_base = get_io_base();
bool is_io = m_offset >= io_base;
[[unlikely]]
if (trap_on_failure) {
{
auto rc = get_trap_action(run_mode, d, apf, is_write);
@ -652,14 +658,14 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
DOLOG(debug, false, "MMR0: %06o", MMR0);
if (trap_action == T_TRAP_250) {
DOLOG(debug, false, "Page access %d: trap 0250", access_control);
DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 0250", access_control, a);
c->trap(0250); // trap
throw 5;
}
else { // T_ABORT_4
DOLOG(debug, false, "Page access %d: trap 004", access_control);
DOLOG(debug, false, "Page access %d (for virtual address %06o): trap 004", access_control, a);
c->trap(004); // abort
@ -668,6 +674,7 @@ uint32_t bus::calculate_physical_address(const int run_mode, const uint16_t a, c
}
}
[[unlikely]]
if (m_offset >= n_pages * 8192l && !is_io) {
DOLOG(debug, !peek_only, "bus::calculate_physical_address %o >= %o", m_offset, n_pages * 8192l);
DOLOG(debug, false, "TRAP(04) (throw 6) on address %06o", a);
@ -988,6 +995,11 @@ write_rc_t bus::write(const uint16_t addr_in, const word_mode_t word_mode, uint1
return { false };
}
if (a >= 0172100 && a <= 0172137) { // MM11-LP parity
DOLOG(debug, false, "WRITE-I/O MM11-LP parity (%06o): %o", a, value);
return { false };
}
/// MMU ///
// supervisor
if (a >= ADDR_PDR_SV_START && a < ADDR_PDR_SV_END) {

73
cpu.cpp
View file

@ -127,9 +127,9 @@ std::vector<std::pair<uint16_t, std::string> > cpu::get_stack_trace() const
void cpu::reset()
{
memset(regs0_5, 0x00, sizeof regs0_5);
memset(sp, 0x00, sizeof sp);
pc = 0;
psw = 0; // 7 << 5;
memset(sp, 0x00, sizeof sp);
pc = 0;
psw = 0; // 7 << 5;
fpsr = 0;
init_interrupt_queue();
}
@ -149,6 +149,8 @@ uint16_t cpu::getRegister(const int nr, const rm_selection_t mode_selection) con
return sp[getPSW_runmode()];
}
assert(nr == 7);
return pc;
}
@ -166,6 +168,7 @@ void cpu::setRegister(const int nr, const uint16_t value, const rm_selection_t m
sp[getPSW_runmode()] = value;
}
else {
assert(nr == 7);
pc = value;
}
}
@ -210,6 +213,8 @@ uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, con
return sp[getPSW_runmode()] += value;
}
assert(nr == 7);
return pc += value;
}
@ -222,8 +227,10 @@ void cpu::lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint
regs0_5[set][reg] = value;
else if (reg == 6)
sp[set == 0 ? 0 : 3] = value;
else
else {
assert(reg == 7);
pc = value;
}
}
uint16_t cpu::lowlevel_register_get(const uint8_t set, const uint8_t reg)
@ -237,6 +244,8 @@ uint16_t cpu::lowlevel_register_get(const uint8_t set, const uint8_t reg)
if (reg == 6)
return sp[set == 0 ? 0 : 3];
assert(reg == 7);
return pc;
}
@ -337,6 +346,8 @@ bool cpu::check_pending_interrupts() const
for(uint8_t i=start_level; i < 8; i++) {
auto interrupts = queued_interrupts.find(i);
assert(interrupts != queued_interrupts.end());
if (interrupts->second.empty() == false)
return true;
}
@ -372,8 +383,8 @@ bool cpu::execute_any_pending_interrupt()
uint8_t current_level = getPSW_spl();
// uint8_t start_level = current_level <= 3 ? 0 : current_level + 1;
// uint8_t start_level = current_level + 1;
uint8_t start_level = current_level;
// PDP-11_70_Handbook_1977-78.pdf page 1-5, "processor priority"
uint8_t start_level = current_level + 1;
for(uint8_t i=0; i < 8; i++) {
auto interrupts = queued_interrupts.find(i);
@ -381,7 +392,7 @@ bool cpu::execute_any_pending_interrupt()
if (interrupts->second.empty() == false) {
any_queued_interrupts = true;
if (i < start_level)
if (i < start_level) // at leas we know now that there's an interrupt scheduled
continue;
if (can_trigger == false) {
@ -399,6 +410,9 @@ bool cpu::execute_any_pending_interrupt()
trap(v, i, true);
// when there are more interrupts scheduled, invoke them asap
trap_delay = initial_trap_delay;
#if defined(BUILD_FOR_RP2040)
xSemaphoreGive(qi_lock);
#endif
@ -407,6 +421,9 @@ bool cpu::execute_any_pending_interrupt()
}
}
if (any_queued_interrupts && trap_delay.has_value() == false)
trap_delay = initial_trap_delay;
#if defined(BUILD_FOR_RP2040)
xSemaphoreGive(qi_lock);
#endif
@ -789,6 +806,8 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
addToMMR1(g_dst);
uint16_t shift = g_dst.value.value() & 077;
DOLOG(debug, true, "shift %06o with %d", R, shift);
bool sign = SIGN(R, wm_word);
if (shift == 0) {
@ -812,14 +831,14 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
setPSW_v(SIGN(R, wm_word) != SIGN(oldR, wm_word));
}
else {
int shift_n = 64 - shift;
uint32_t sign_extend = sign ? 0x8000 : 0;
int shift_n = 64 - shift;
uint32_t sign_extend = sign ? 0x8000 : 0;
for(int i=0; i<shift_n; i++) {
setPSW_c(R & 1);
R >>= 1;
R |= sign_extend;
}
for(int i=0; i<shift_n; i++) {
setPSW_c(R & 1);
R >>= 1;
R |= sign_extend;
}
setPSW_v(SIGN(R, wm_word) != SIGN(oldR, wm_word));
}
@ -863,8 +882,7 @@ bool cpu::additional_double_operand_instructions(const uint16_t instr)
int shift_n = (64 - shift) - 1;
// extend sign-bit
if (sign) // convert to unsigned 64b int & extend sign
{
if (sign) { // convert to unsigned 64b int & extend sign
R0R1 = (uint64_t(R0R1) | 0xffffffff00000000ll) >> shift_n;
setPSW_c(R0R1 & 1);
@ -1555,8 +1573,11 @@ bool cpu::condition_code_operations(const uint16_t instr)
}
if ((instr & ~7) == 0000230) { // SPLx
int level = instr & 7;
setPSW_spl(level);
if (getPSW_runmode() == 0) { // only in kernel mode
int level = instr & 7;
setPSW_spl(level);
}
// // trap via vector 010 only(?) on an 11/60 and not(?) on an 11/70
// trap(010);
@ -1610,7 +1631,10 @@ bool cpu::misc_operations(const uint16_t instr)
{
switch(instr) {
case 0b0000000000000000: // HALT
*event = EVENT_HALT;
if (getPSW_runmode() == 0) // only in kernel mode
*event = EVENT_HALT;
else
trap(4);
return true;
case 0b0000000000000001: // WAIT
@ -1664,8 +1688,11 @@ bool cpu::misc_operations(const uint16_t instr)
return true;
case 0b0000000000000101: // RESET
b->init();
init_interrupt_queue();
if (getPSW_runmode() == 0) { // only in kernel mode
b->init();
init_interrupt_queue();
}
return true;
}
@ -2041,7 +2068,7 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
}
if (text.empty() && name.empty() == false)
text = name + space + src_text + comma + dst_text.operand;
text = name + space + src_text + comma + dst_text.operand; // TODO: swap for ASH, ASHC
if (text.empty() == false && next_word != -1)
instruction_words.push_back(next_word);
@ -2307,7 +2334,7 @@ std::map<std::string, std::vector<std::string> > cpu::disassemble(const uint16_t
// PSW
std::string psw_str = format("%d%d|%d|%d|%c%c%c%c%c", psw >> 14, (psw >> 12) & 3, (psw >> 11) & 1, (psw >> 5) & 7,
psw & 16?'t':'-', psw & 8?'n':'-', psw & 4?'z':'-', psw & 2 ? 'v':'-', psw & 1 ? 'c':'-');
out.insert({ "psw", { psw_str } });
out.insert({ "psw", { std::move(psw_str) } });
out.insert({ "psw-value", { format("%06o", psw) } });
// values worked with

5
cpu.h
View file

@ -126,8 +126,6 @@ public:
uint64_t get_wait_time() const { return wait_time; }
std::tuple<double, double, uint64_t, uint32_t, double> get_mips_rel_speed(const std::optional<uint64_t> & instruction_count, const std::optional<uint64_t> & t_diff_1s) const;
std::map<uint8_t, std::set<uint8_t> > get_queued_interrupts() const { return queued_interrupts; }
bool get_debug() const { return debug_mode; }
void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); }
std::vector<std::pair<uint16_t, std::string> > get_stack_trace() const;
@ -141,6 +139,9 @@ public:
void init_interrupt_queue();
void queue_interrupt(const uint8_t level, const uint8_t vector);
std::map<uint8_t, std::set<uint8_t> > get_queued_interrupts() const { return queued_interrupts; }
std::optional<int> get_interrupt_delay_left() const { return trap_delay; }
bool check_if_interrupts_pending() const { return any_queued_interrupts; }
void trap(uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
bool is_it_a_trap() const { return it_is_a_trap; }

View file

@ -720,6 +720,14 @@ void show_queued_interrupts(console *const cnsl, cpu *const c)
{
cnsl->put_string_lf(format("Current level: %d", c->getPSW_spl()));
auto delay = c->get_interrupt_delay_left();
if (delay.has_value())
cnsl->put_string_lf(format("Current delay left: %d", delay.value()));
else
cnsl->put_string_lf("No delay");
cnsl->put_string_lf(format("Interrupt pending flag: %d", c->check_if_interrupts_pending()));
auto queued_interrupts = c->get_queued_interrupts();
for(auto & level: queued_interrupts) {
@ -1049,6 +1057,37 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue;
}
else if (parts[0] == "setll" && parts.size() == 2) {
auto ll_parts = split(parts[1], ",");
if (ll_parts.size() != 2)
cnsl->put_string_lf("Loglevel for either screen or file missing");
else {
log_level_t ll_screen = parse_ll(ll_parts[0]);
log_level_t ll_file = parse_ll(ll_parts[1]);
setll(ll_screen, ll_file);
}
}
else if (parts[0] == "setll" && parts.size() == 2) {
auto ll_parts = split(parts[1], ",");
if (ll_parts.size() != 2)
cnsl->put_string_lf("Loglevel for either screen or file missing");
else {
log_level_t ll_screen = parse_ll(ll_parts[0]);
log_level_t ll_file = parse_ll(ll_parts[1]);
setll(ll_screen, ll_file);
}
continue;
}
else if (parts[0] == "setsl" && parts.size() == 3) {
setloghost(parts.at(1).c_str(), parse_ll(parts[2]));
continue;
}
else if (cmd == "qi") {
show_queued_interrupts(cnsl, c);
@ -1087,6 +1126,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
" follows v/p (virtual/physical), all octal values, mmr0-3 and psw are",
" registers",
"trace/t - toggle tracing",
"setll - set loglevel: terminal,file",
"setsl - set syslog target: requires a hostname and a loglevel",
"turbo - toggle turbo mode (cannot be interrupted)",
"debug - enable CPU debug mode",
"bt - show backtrace - need to enable debug first",

View file

@ -119,13 +119,14 @@ bool disk_backend_nbd::connect(const bool retry)
}
}
if (memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) {
if (fd != -1 && memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) {
close(fd);
fd = -1;
DOLOG(warning, true, "disk_backend_nbd::connect: magic invalid");
}
DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size));
if (fd != -1)
DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size));
}
while(fd == -1 && retry);

59
log.cpp
View file

@ -1,4 +1,4 @@
// (C) 2018-2023 by Folkert van Heusden
// (C) 2018-2024 by Folkert van Heusden
// Released under MIT license
#include <fcntl.h>
@ -7,6 +7,9 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "error.h"
@ -16,9 +19,11 @@
static const char *logfile = strdup("/tmp/kek.log");
static sockaddr_in syslog_ip_addr = { };
static bool is_file = true;
log_level_t log_level_file = warning;
log_level_t log_level_screen = warning;
FILE *lfh = nullptr;
FILE *lfh = nullptr;
static int lf_uid = -1;
static int lf_gid = -1;
static bool l_timestamp = true;
@ -30,29 +35,58 @@ int gettid()
}
#endif
void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp)
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool timestamp)
{
if (lfh)
fclose(lfh);
free((void *)logfile);
is_file = true;
logfile = lf ? strdup(lf) : nullptr;
log_level_file = ll_file;
log_level_file = ll_file;
log_level_screen = ll_screen;
l_timestamp = timestamp;
l_timestamp = timestamp;
atexit(closelog);
}
void setloghost(const char *const host, const log_level_t ll)
{
inet_aton(host, &syslog_ip_addr.sin_addr);
syslog_ip_addr.sin_port = htons(514);
is_file = false;
log_level_file = ll;
l_timestamp = false;
}
void setll(const log_level_t ll_file, const log_level_t ll_screen)
{
log_level_file = ll_file;
log_level_screen = ll_screen;
}
void setloguid(const int uid, const int gid)
{
lf_uid = uid;
lf_gid = gid;
}
void send_syslog(const int ll, const std::string & what)
{
std::string msg = format("<%d>%s", 16 * 8 + ll, what.c_str());
int s = socket(AF_INET, SOCK_DGRAM, 0);
(void)sendto(s, msg.c_str(), msg.size(), 0, reinterpret_cast<sockaddr *>(&syslog_ip_addr), sizeof syslog_ip_addr);
close(s);
}
void closelog()
{
if (lfh) {
@ -70,7 +104,6 @@ void dolog(const log_level_t ll, const char *fmt, ...)
lfh = fopen(logfile, "a+");
if (!lfh)
error_exit(true, "Cannot access log-file %s", logfile);
#if !defined(_WIN32)
if (lf_uid != -1 && fchown(fileno(lfh), lf_uid, lf_gid) == -1)
error_exit(true, "Cannot change logfile (%s) ownership", logfile);
@ -101,29 +134,33 @@ void dolog(const log_level_t ll, const char *fmt, ...)
#endif
char *ts_str = nullptr;
const char *const ll_names[] = { "debug ", "info ", "warning", "error " };
const char *const ll_names[] = { "emerg ", "alert ", "crit ", "error ", "warning", "notice ", "info ", "debug ", "none " };
asprintf(&ts_str, "%04d-%02d-%02d %02d:%02d:%02d.%06d] %s ",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, int(now % 1000000),
ll_names[ll]);
if (ll <= log_level_file && is_file == false)
send_syslog(ll, str);
#if !defined(ESP32)
if (ll >= log_level_file && lfh != nullptr)
if (ll <= log_level_file && lfh != nullptr)
fprintf(lfh, "%s%s\n", ts_str, str);
#endif
if (ll >= log_level_screen)
if (ll <= log_level_screen)
printf("%s%s\r\n", ts_str, str);
free(ts_str);
}
else {
if (ll <= log_level_file && is_file == false)
send_syslog(ll, str);
#if !defined(ESP32)
if (ll >= log_level_file && lfh != nullptr)
if (ll <= log_level_file && lfh != nullptr)
fprintf(lfh, "%s\n", str);
#endif
if (ll >= log_level_screen)
if (ll <= log_level_screen)
printf("%s\r\n", str);
}

11
log.h
View file

@ -1,4 +1,4 @@
// (C) 2018-2023 by Folkert van Heusden
// (C) 2018-2024 by Folkert van Heusden
// Released under MIT license
#pragma once
@ -8,10 +8,12 @@
#include "config.h"
typedef enum { debug, info, warning, ll_error, none } log_level_t; // TODO ll_ prefix
typedef enum { ll_emerg = 0, ll_alert, ll_critical, ll_error, warning, notice, info, debug, none } log_level_t; // TODO ll_ prefix
log_level_t parse_ll(const std::string & str);
void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp);
void setlogfile(const char *const lf, const log_level_t ll_file, const log_level_t ll_screen, const bool l_timestamp);
void setloghost(const char *const host, const log_level_t ll);
void setll(const log_level_t ll_file, const log_level_t ll_screen);
void setloguid(const int uid, const int gid);
void closelog();
void dolog(const log_level_t ll, const char *fmt, ...);
@ -22,7 +24,8 @@ void dolog(const log_level_t ll, const char *fmt, ...);
#define DOLOG(ll, always, fmt, ...) do { \
extern log_level_t log_level_file, log_level_screen; \
\
if (always || ll >= log_level_file || ll >= log_level_screen) \
[[unlikely]] \
if (always || ll <= log_level_file || ll <= log_level_screen) \
dolog(ll, fmt, ##__VA_ARGS__); \
} while(0)
#endif

View file

@ -493,7 +493,7 @@ int main(int argc, char *argv[])
console *cnsl = nullptr;
setlog(logfile, ll_file, ll_screen, timestamp);
setlogfile(logfile, ll_file, ll_screen, timestamp);
if (validate_json.empty() == false)
return run_cpu_validation(validate_json);
@ -622,11 +622,11 @@ int main(int argc, char *argv[])
delete metrics_thread;
}
delete lf;
delete cnsl;
delete b;
delete lf;
return 0;
}

View file

@ -15,9 +15,9 @@
static const char * const regnames[] = {
"control status",
"bus address ",
"disk address ",
"multipurpose "
"bus address",
"disk address",
"multipurpose"
};
static const char * const commands[] = {
@ -89,7 +89,7 @@ uint16_t rl02::readWord(const uint16_t addr)
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;
}
@ -112,7 +112,7 @@ void rl02::writeByte(const uint16_t addr, const uint8_t v)
uint32_t rl02::get_bus_address() const
{
return registers[(RL02_BAR - RL02_BASE) / 2] | (uint32_t((registers[(RL02_CSR - RL02_BASE) / 2] >> 4) & 3) << 16);
return (registers[(RL02_BAR - RL02_BASE) / 2] | (uint32_t((registers[(RL02_CSR - RL02_BASE) / 2] >> 4) & 3) << 16)) & ~1;
}
void rl02::update_bus_address(const uint32_t a)
@ -137,7 +137,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
{
const int reg = (addr - RL02_BASE) / 2;
DOLOG(debug, false, "RL02 write \"%s\"/%06o: %06o", regnames[reg], addr, v);
DOLOG(debug, false, "RL02: write \"%s\"/%06o: %06o", regnames[reg], addr, v);
registers[reg] = v;
@ -146,16 +146,24 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
const bool do_exec = !(v & 128);
DOLOG(debug, false, "RL02 set command %d, exec: %d (%s)", command, do_exec, commands[command]);
int device = (v >> 8) & 3;
DOLOG(debug, false, "RL02: device %d, set command %d, exec: %d (%s)", device, command, do_exec, commands[command]);
bool do_int = false;
*disk_read_acitivity = true;
if (command == 2) { // get status
registers[(RL02_MPR - RL02_BASE) / 2] = 0;
if (size_t(device) >= fhs.size()) {
DOLOG(info, false, "RL02: PDP11/70 is accessing a not-attached virtual disk %d", device);
registers[(RL02_CSR - RL02_BASE) / 2] |= (1 << 10) | (1 << 15);
do_int = true;
}
else if (command == 2) { // get status
mpr[0] = 5 /* lock on */ | (1 << 3) /* brush home */ | (1 << 4) /* heads over disk */ | (head << 6) | (1 << 7) /* RL02 */;
mpr[1] = mpr[0];
}
else if (command == 3) { // seek
uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2];
@ -169,10 +177,10 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
else if (new_track >= rl02_track_count)
new_track = rl02_track_count - 1;
DOLOG(debug, false, "RL02: seek from cylinder %d to %d (distance: %d, DAR: %06o)", track, new_track, cylinder_count, temp);
DOLOG(debug, false, "RL02: device %d, seek from cylinder %d to %d (distance: %d, DAR: %06o)", device, track, new_track, cylinder_count, temp);
track = new_track;
update_dar();
// update_dar();
do_int = true;
}
@ -181,7 +189,53 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
mpr[1] = 0; // zero
mpr[2] = 0; // TODO: CRC
DOLOG(debug, false, "RL02 read header [cylinder: %d, head: %d, sector: %d] %06o", track, head, sector, mpr[0]);
DOLOG(debug, false, "RL02: device %d, read header [cylinder: %d, head: %d, sector: %d] %06o", device, track, head, sector, mpr[0]);
do_int = true;
}
else if (command == 5) { // write data
uint32_t memory_address = get_bus_address();
uint32_t count = (65536l - registers[(RL02_MPR - RL02_BASE) / 2]) * 2;
if (count == 65536)
count = 0;
uint16_t temp = registers[(RL02_DAR - RL02_BASE) / 2];
sector = temp & 63;
head = (temp >> 6) & 1;
track = temp >> 7;
uint32_t temp_disk_offset = calc_offset();
DOLOG(debug, false, "RL02: device %d, write %d bytes (dec) to %d (dec) from %06o (oct) [cylinder: %d, head: %d, sector: %d]", device, count, temp_disk_offset, memory_address, track, head, sector);
while(count > 0) {
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count);
if (!fhs.at(device)->write(temp_disk_offset, cur, xfer_buffer)) {
DOLOG(ll_error, true, "RL02: write error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector);
break;
}
mpr[0] += count / 2;
temp_disk_offset += cur;
count -= cur;
sector++;
if (sector >= rl02_sectors_per_track) {
sector = 0;
head++;
if (head >= 2) {
head = 0;
track++;
}
}
}
do_int = true;
}
@ -200,7 +254,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
uint32_t temp_disk_offset = calc_offset();
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: device %d, read %d bytes (dec) from %d (dec) to %06o (oct) [cylinder: %d, head: %d, sector: %d]", device, count, temp_disk_offset, memory_address, track, head, sector);
// update_dar();
@ -208,7 +262,7 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
uint32_t cur = std::min(uint32_t(sizeof xfer_buffer), count);
if (!fhs.at(device)->read(temp_disk_offset, cur, xfer_buffer)) {
DOLOG(ll_error, true, "RL02 read error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector);
DOLOG(ll_error, true, "RL02: read error, device %d, disk offset %u, read size %u, cylinder %d, head %d, sector %d", device, temp_disk_offset, cur, track, head, sector);
break;
}
@ -218,6 +272,8 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
b->writeUnibusByte(memory_address++, xfer_buffer[i++]);
// update_bus_address(memory_address);
mpr[0]++;
}
temp_disk_offset += cur;
@ -247,9 +303,9 @@ void rl02::writeWord(const uint16_t addr, uint16_t v)
if (do_int) {
if (registers[(RL02_CSR - RL02_BASE) / 2] & 64) { // interrupt enable?
DOLOG(debug, false, "RL02 triggering interrupt");
DOLOG(debug, false, "RL02: triggering interrupt");
b->getCpu()->queue_interrupt(4, 0160);
b->getCpu()->queue_interrupt(5, 0160);
}
}