Merge branch 'master' into psram
This commit is contained in:
commit
586d5bffb3
11 changed files with 247 additions and 69 deletions
|
@ -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]
|
||||
|
|
|
@ -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
16
bus.cpp
|
@ -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
73
cpu.cpp
|
@ -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
5
cpu.h
|
@ -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; }
|
||||
|
|
41
debugger.cpp
41
debugger.cpp
|
@ -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",
|
||||
|
|
|
@ -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
59
log.cpp
|
@ -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
11
log.h
|
@ -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
|
||||
|
|
6
main.cpp
6
main.cpp
|
@ -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;
|
||||
}
|
||||
|
|
90
rl02.cpp
90
rl02.cpp
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue