From 9f4aa97822adc791f700670ef0fc7636849563b7 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 29 Oct 2022 18:18:26 -0700 Subject: Understanding interrupt handling within SIMH (see echo_int.pal) Add list of Bugs Add event log file parser More changes associated with widening the ctlregs (FIXME add a typedef) Add some keyboard instructions --- Bugs | 2 + evts/foobar.evt | 22 +++++++++ io/event.h | 2 +- io/model.cpp | 44 +++++++++++++++-- io/model.h | 4 ++ isa/checker.h | 3 ++ isa/ctlreg.def | 8 ++++ isa/decode.cpp | 22 ++++++++- isa/isa.h | 37 +++++++++------ main.cpp | 16 +++++-- programs/echo.pal | 6 +-- programs/echo_int.pal | 58 +++++++++++++++++++++++ programs/echo_optimal.pal | 67 ++++++++++++++++++++++++++ programs/fib_mike.pal | 117 ++++++++++++++++++++++++++++++++++++++++++++++ programs/mike_fib.pal | 117 ---------------------------------------------- 15 files changed, 379 insertions(+), 146 deletions(-) create mode 100644 Bugs create mode 100644 evts/foobar.evt create mode 100644 isa/ctlreg.def create mode 100644 programs/echo_int.pal create mode 100644 programs/echo_optimal.pal create mode 100644 programs/fib_mike.pal delete mode 100644 programs/mike_fib.pal diff --git a/Bugs b/Bugs new file mode 100644 index 0000000..2681d88 --- /dev/null +++ b/Bugs @@ -0,0 +1,2 @@ +TAD should do AC+[mem] and invert the link bit if the result carries +IF is used for same-page and zero-page memory accesses (including the first access of an indirect) diff --git a/evts/foobar.evt b/evts/foobar.evt new file mode 100644 index 0000000..556692a --- /dev/null +++ b/evts/foobar.evt @@ -0,0 +1,22 @@ ++100 +TT_BITS=0x6601/0xFF01 ++100 +TT_BITS=0x6F01/0xFF01 ++100 +TT_BITS=0x6F01/0xFF01 ++100 +TT_BITS=0x0A01/0xFF01 ++1000 +HALTED=1 ++10000 +HALTED=0 ++100 +TT_BITS=0x6201/0xFF01 ++100 +TT_BITS=0x6101/0xFF01 ++100 +TT_BITS=0x7201/0xFF01 ++100 +TT_BITS=0x0A01/0xFF01 ++1000 +HALTED=1 diff --git a/io/event.h b/io/event.h index 2da3323..e17c333 100644 --- a/io/event.h +++ b/io/event.h @@ -9,7 +9,7 @@ struct event { ctlreg reg; std::uint_fast32_t mask; std::uint_fast32_t value; - event(ctlreg reg, std::uint_fast32_t value, std::uint_fast32_t mask=~0) + event(ctlreg reg, std::uint_fast32_t value, std::uint_fast32_t mask=~(std::uint_fast32_t)0) : reg(reg) , mask(mask) , value(value) diff --git a/io/model.cpp b/io/model.cpp index 4b37be4..e9caba0 100644 --- a/io/model.cpp +++ b/io/model.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,8 +18,7 @@ bool iomodel::interact(std::array &ctlregs) { ++time; if (ctlregs[TT_BITS] & TTO_TX) { - // PDP-8 doesn't really have support for 8-bit output, this is Jules' contribution - std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) ^ 0x80) << std::flush; + std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) & 0x7f) << std::flush; ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA; log.emplace(time + TT_OUTPUT_DELAY, event(TT_BITS, TTO_FLAG, 0)); } @@ -46,4 +46,42 @@ bool iomodel::interact(std::array &ctlregs) { } return interrupt; -}; +} + +void iomodel::load_evt(std::istream &fh) { + // File format: + // +time advances time by relative increment + // regname=value/mask adds event that sets regname = (regname & ~mask) | value + // regname=value adds event that sets regname = value + // FIXME: add assertions + // FIXME: add DMA + for (std::string line; std::getline(fh, line); ) { + if (line.size() == 0) + continue; + if (line[0] == '+') { + char *end = nullptr; + auto step = std::strtoull(line.c_str(), &end, 0); + assert(end && *end == '\0'); + load_time += step; + } else { + auto eqpos = line.find('='); + assert(eqpos != std::string::npos); + auto regname = line.substr(0, eqpos); + ctlreg reg = ctlreg_map.at(regname); + std::uint_fast32_t value, mask; + auto slashpos = line.find('/', eqpos); + auto valuestr = line.substr(eqpos + 1, slashpos - (eqpos + 1)); + char *end = nullptr; + value = std::strtoull(valuestr.c_str(), &end, 0); + assert(end && *end == '\0'); + if (slashpos == std::string::npos) { + mask = ~(std::uint_fast32_t)0; + } else { + auto maskstr = line.substr(slashpos + 1); + mask = std::strtoull(maskstr.c_str(), &end, 0); + assert(end && *end == '\0'); + } + log.emplace(load_time, event(reg, value, mask)); + } + } +} diff --git a/io/model.h b/io/model.h index 8758a43..2826170 100644 --- a/io/model.h +++ b/io/model.h @@ -13,6 +13,10 @@ struct iomodel { event_log log; std::uint64_t time = 0; bool interact(std::array &ctlregs); + bool done() { + return log.lower_bound(time) == log.end(); + } + std::uint64_t load_time = 0; void load_evt(std::istream &fh); }; diff --git a/isa/checker.h b/isa/checker.h index 571bbc8..96460cf 100644 --- a/isa/checker.h +++ b/isa/checker.h @@ -52,4 +52,7 @@ struct checker { ctlregs.fill(0); } void execute(); + bool done() { + return ctlregs[HALTED] && system.done(); + } }; diff --git a/isa/ctlreg.def b/isa/ctlreg.def new file mode 100644 index 0000000..c9eab05 --- /dev/null +++ b/isa/ctlreg.def @@ -0,0 +1,8 @@ +REG(DATA_INSTRUCTION_FIELD_BUFFER) // (df << 3) | if_buffer +REG(DATA_INSTRUCTION_FIELD_SAVED) // (df_saved << 3) | if_saved +REG(HALTED) +REG(INT_ENABLE) // (int_enable_delay << 1) | int_enable +REG(INT_PENDING) // only meaningful if interrupts disabled +REG(TT_BITS) // see TT[IO]_* consts in isa/isa.h +REG(TT_INPUT_INT_ENABLE) // (status_enable << 1) | (int_enable) +REG(TT_OUTPUT_INT_ENABLE) diff --git a/isa/decode.cpp b/isa/decode.cpp index 9563327..c35118b 100644 --- a/isa/decode.cpp +++ b/isa/decode.cpp @@ -152,6 +152,24 @@ instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bit ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); }; break; + case 5: + // KIE set TT_INPUT_INT_ENABLE to the low bit of the accumulator + inst.need_read_acc = true; + inst.write_ctlreg = TT_INPUT_INT_ENABLE; + inst.ef = [](auto &ctx) { + ctx.ctlval = ctx.acc.value() & 3; + }; + break; + case 6: + // KRB transfer keyboard buffer to accumulator and clear TTI flag + inst.read_ctlreg = TT_BITS; + inst.need_write_acc = true; + inst.write_ctlreg = TT_BITS; + inst.ef = [](auto &ctx) { + ctx.acc = (ctx.ctlval.value() & TTI_DATA) >> TTI_DATA_SHIFT; + ctx.ctlval.value() &= ~TTI_FLAG; + }; + break; default: inst.ef = [bits](auto &ctx) { std::cerr << "unimplemented IOT KB suboperation " << (bits & 07) << "\n"; @@ -194,7 +212,7 @@ instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bit inst.write_ctlreg = TT_BITS; inst.ef = [](auto &ctx) { auto &x = ctx.ctlval.value(); - auto chr = ctx.acc.value() ^ 0x80; + auto chr = ctx.acc.value(); x &= ~TTO_DATA; x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; x |= TTO_TX; @@ -216,7 +234,7 @@ instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bit inst.write_ctlreg = TT_BITS; inst.ef = [](auto &ctx) { auto &x = ctx.ctlval.value(); - auto chr = ctx.acc.value() ^ 0x80; + auto chr = ctx.acc.value(); x &= ~TTO_FLAG & ~TTO_FLAG_OLD & ~TTO_DATA; x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; x |= TTO_TX; diff --git a/isa/isa.h b/isa/isa.h index 84a783c..6484cd8 100644 --- a/isa/isa.h +++ b/isa/isa.h @@ -2,30 +2,39 @@ #include #include +#include #include +#include enum ctlreg { - DATA_INSTRUCTION_FIELD_BUFFER, // (df << 3) | if_buffer - DATA_INSTRUCTION_FIELD_SAVED, // (df_saved << 3) | if_saved - HALTED, - INT_ENABLE, // (int_enable_delay << 1) | int_enable - INT_PENDING, // only meaningful if interrupts disabled - TT_BITS, // see below TT[IO]_* consts - TT_INPUT_INT_ENABLE, - TT_OUTPUT_INT_ENABLE, +#define REG(N) N, +#include "ctlreg.def" +#undef REG NUM_CTLREGS, }; +const char * const ctlreg_names[] = { +#define REG(N) #N, +#include "ctlreg.def" +#undef REG +}; + +const std::map ctlreg_map = { +#define REG(N) { #N, N }, +#include "ctlreg.def" +#undef REG +}; + // TT_BITS -static constexpr unsigned int TTI_FLAG = 1 << 0; -static constexpr unsigned int TTO_TX = 1 << 1; -static constexpr unsigned int TTO_FLAG = 1 << 2; -static constexpr unsigned int TTO_FLAG_OLD = 1 << 3; +static constexpr std::uint_fast32_t TTI_FLAG = 1 << 0; +static constexpr std::uint_fast32_t TTO_TX = 1 << 1; +static constexpr std::uint_fast32_t TTO_FLAG = 1 << 2; +static constexpr std::uint_fast32_t TTO_FLAG_OLD = 1 << 3; static constexpr unsigned int TTI_DATA_SHIFT = 8; static constexpr unsigned int TTO_DATA_SHIFT = 16; -static constexpr unsigned int TTI_DATA = 0xff << TTI_DATA_SHIFT; -static constexpr unsigned int TTO_DATA = 0xff << TTO_DATA_SHIFT; +static constexpr std::uint_fast32_t TTI_DATA = 0xff << TTI_DATA_SHIFT; +static constexpr std::uint_fast32_t TTO_DATA = 0xff << TTO_DATA_SHIFT; struct instruction_context { // Known statically at decode time diff --git a/main.cpp b/main.cpp index 46be782..62926a5 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -60,13 +61,18 @@ int main(int argc, const char *argv[]) { checker checker(system); for (--argc, ++argv; argc; --argc, ++argv) { - auto program = programs.at(argv[0]); - if (auto err = load_program(checker, program)) - return err; + if (auto program = programs.find(*argv); program != programs.end()) { + if (auto err = load_program(checker, program->second)) + return err; + } else { + std::ifstream fh(*argv); + system.load_evt(fh); + } } - while (true) { - //std::cout << fmt::format("{:9} @{:04o} {:01o}:{:04o}:{:04o} TTO={:x}\n", system.time, checker.pc, checker.link, checker.acc, checker.mq, checker.ctlregs[TT_OUTPUT]); + while (!checker.done()) { +// if (!checker.ctlregs[HALTED]) +// std::cout << fmt::format("\t{:9} {:04o}\n", system.time, checker.pc); checker.execute(); } diff --git a/programs/echo.pal b/programs/echo.pal index 4e59623..83b46e8 100644 --- a/programs/echo.pal +++ b/programs/echo.pal @@ -1,13 +1,11 @@ / vim: set sw=8 noexpandtab : *200 + TFL LOOP, TSF - JMS ECHO JMP LOOP - -ECHO, 0 WAIT, KSF JMP WAIT KRB TLS - JMP I ECHO + JMP LOOP diff --git a/programs/echo_int.pal b/programs/echo_int.pal new file mode 100644 index 0000000..62886ff --- /dev/null +++ b/programs/echo_int.pal @@ -0,0 +1,58 @@ +/ vim: set sw=8 noexpandtab : + +*000 + +INTRET, 0 + JMP GOTINT + +*010 + +HEAD, 7777 / because preincrement +TAIL, 7777 + +*200 + + CLA IAC + KIE + ION + CLA +LOOP, TAD TAIL + CMA IAC + TAD HEAD + SNA + JMP LOOP + CLA + CDF 0010 + TAD I TAIL + CDF 0000 + IOF / critical section + TLS +BUSY, TSF / FIXME: remove busy wait inside IOF (see echo_optimal.pal) + JMP BUSY + TCF + ION + CLA / end critical section + JMP LOOP + +*400 + +SAVEA, 0 +SAVEF, 0 + +GOTINT, DCA SAVEA + GTF + AND (7577) + DCA SAVEF + KSF + JMP RETINT + KRB + CDF 0010 + DCA I HEAD + CDF 0000 +RETINT, CLA + TAD SAVEF + RTF + CLA + TAD SAVEA + ION + JMP I INTRET diff --git a/programs/echo_optimal.pal b/programs/echo_optimal.pal new file mode 100644 index 0000000..1281309 --- /dev/null +++ b/programs/echo_optimal.pal @@ -0,0 +1,67 @@ +/ vim: set sw=8 noexpandtab : + +*000 + +INTRET, 0 + JMP GOTINT + +*010 + +HEAD, 7777 / because preincrement +TAIL, 7777 + +*100 + +TTBUSY, 0 / FIXME: sometimes we get wedged with TTBUSY=1, but TT flag is clear (no TT interrupt occurs) + +*200 + + CLA IAC + KIE + ION + CLA +LOOP, TAD TTBUSY + SZA + JMP LOOP + TAD TAIL + CMA IAC + TAD HEAD + SNA + JMP LOOP + CLA + CDF 0010 + TAD I TAIL + CDF 0000 + IOF / critical section + TPC + CLA IAC + ION + DCA TTBUSY / end critical section + JMP LOOP + +*400 + +SAVEA, 0 +SAVEF, 0 + +GOTINT, DCA SAVEA + GTF + AND (7577) + DCA SAVEF + TSF + JMP KBIN + DCA TTBUSY + TCF +KBIN, KSF + JMP RETINT + KRB + CDF 0010 + DCA I HEAD + CDF 0000 +RETINT, CLA + TAD SAVEF + RTF + CLA + TAD SAVEA + ION + JMP I INTRET diff --git a/programs/fib_mike.pal b/programs/fib_mike.pal new file mode 100644 index 0000000..a20a843 --- /dev/null +++ b/programs/fib_mike.pal @@ -0,0 +1,117 @@ + *200 +MAIN, CLA + TAD (-26) + DCA FIBN + DCA FIB0 + IAC + DCA FIB1 +LOOP, CLA + TAD FIB0 + JMS PUTN + CLA + TAD (012) + JMS PUTC + CLA + TAD FIB0 + TAD FIB1 + DCA FIB2 + TAD FIB1 + DCA FIB0 + TAD FIB2 + DCA FIB1 + ISZ FIBN + JMP LOOP +EXIT, HLT + CLA IAC + DCA FIB1 + DCA FIB0 + JMP MAIN +PUTN, 0 + JMS ITOA + CMA IAC + IAC + CMA IAC + DCA 10 +PUTNL, CLA + TAD I 10 + SPA + JMP I PUTN + TAD (60) + JMS PUTC + JMP PUTNL +PUTC, 0 + TLS + TSF + JMP .-1 + JMP I PUTC +ITOA, 0 + DCA ITOAV + DCA ITOAD + DCA ITOAD+1 + DCA ITOAD+2 + DCA ITOAD+3 + TAD (-14) + DCA ITOAN +ITOAL, CLL / LOOP OVER BINARY INPUT BITS + TAD ITOAD+3 + JMS ITOA2X + DCA ITOAD+3 + TAD ITOAD+2 + JMS ITOA2X + DCA ITOAD+2 + TAD ITOAD+1 + JMS ITOA2X + DCA ITOAD+1 + TAD ITOAD + JMS ITOA2X + DCA ITOAD + CLL + TAD ITOAV / SHIFT MSB OUT OF INPUT VALUE + RAL + DCA ITOAV + RAL + TAD ITOAD+3 / ADD SHIFTED-OUT MSB TO DECIMAL LSD + DCA ITOAD+3 + ISZ ITOAN + JMP ITOAL / NEXT LOOP ITERATION + TAD (ITOAD) + DCA ITOAR +ITOAJ, TAD I ITOAR + SZA + JMP ITOAX + ISZ ITOAR + TAD I ITOAR + SZA + JMP ITOAX + ISZ ITOAR + TAD I ITOAR + SZA + JMP ITOAX + ISZ ITOAR +ITOAX, CLA + TAD ITOAR + JMP I ITOA +ITOA2X, 0 + RAL / PUTS 0 IN LINK + DCA ITOAT + TAD (-12) + TAD ITOAT / PUTS 1 IN LINK IF WRAPPED + SMA + DCA ITOAT + CLA + TAD ITOAT + JMP I ITOA2X +FIB0, 0 +FIB1, 1 +FIB2, 0 +FIBN, -27 +ITOAD, 0 / OUTPUT DIGITS (MSD FIRST) + 0 + 0 + 0 + 4000 / OUTPUT SENTINEL +ITOAN, 0 / INPUT BITS LOOP COUNTER +ITOAR, 0 / POINTER TO FIRST NONZERO DIGIT +ITOAT, 0 / SCRATCHPAD FOR ITOA2X +ITOAV, 0 / VALUE BEING CONVERTED (TEMPORARY) +$ diff --git a/programs/mike_fib.pal b/programs/mike_fib.pal deleted file mode 100644 index 6f56109..0000000 --- a/programs/mike_fib.pal +++ /dev/null @@ -1,117 +0,0 @@ - *200 -MAIN, CLA - TAD (-26) - DCA FIBN - DCA FIB0 - IAC - DCA FIB1 -LOOP, CLA - TAD FIB0 - JMS PUTN - CLA - TAD (054) - JMS PUTC - CLA - TAD FIB0 - TAD FIB1 - DCA FIB2 - TAD FIB1 - DCA FIB0 - TAD FIB2 - DCA FIB1 - ISZ FIBN - JMP LOOP -EXIT, HLT - CLA IAC - DCA FIB1 - DCA FIB0 - JMP MAIN -PUTN, 0 - JMS ITOA - CMA IAC - IAC - CMA IAC - DCA 10 -PUTNL, CLA - TAD I 10 - SPA - JMP I PUTN - TAD (60) - JMS PUTC - JMP PUTNL -PUTC, 0 - TLS - TSF - JMP .-1 - JMP I PUTC -ITOA, 0 - DCA ITOAV - DCA ITOAD - DCA ITOAD+1 - DCA ITOAD+2 - DCA ITOAD+3 - TAD (-14) - DCA ITOAN -ITOAL, CLL / LOOP OVER BINARY INPUT BITS - TAD ITOAD+3 - JMS ITOA2X - DCA ITOAD+3 - TAD ITOAD+2 - JMS ITOA2X - DCA ITOAD+2 - TAD ITOAD+1 - JMS ITOA2X - DCA ITOAD+1 - TAD ITOAD - JMS ITOA2X - DCA ITOAD - CLL - TAD ITOAV / SHIFT MSB OUT OF INPUT VALUE - RAL - DCA ITOAV - RAL - TAD ITOAD+3 / ADD SHIFTED-OUT MSB TO DECIMAL LSD - DCA ITOAD+3 - ISZ ITOAN - JMP ITOAL / NEXT LOOP ITERATION - TAD (ITOAD) - DCA ITOAR -ITOAJ, TAD I ITOAR - SZA - JMP ITOAX - ISZ ITOAR - TAD I ITOAR - SZA - JMP ITOAX - ISZ ITOAR - TAD I ITOAR - SZA - JMP ITOAX - ISZ ITOAR -ITOAX, CLA - TAD ITOAR - JMP I ITOA -ITOA2X, 0 - RAL / PUTS 0 IN LINK - DCA ITOAT - TAD (-12) - TAD ITOAT / PUTS 1 IN LINK IF WRAPPED - SMA - DCA ITOAT - CLA - TAD ITOAT - JMP I ITOA2X -FIB0, 0 -FIB1, 1 -FIB2, 0 -FIBN, -27 -ITOAD, 0 / OUTPUT DIGITS (MSD FIRST) - 0 - 0 - 0 - 4000 / OUTPUT SENTINEL -ITOAN, 0 / INPUT BITS LOOP COUNTER -ITOAR, 0 / POINTER TO FIRST NONZERO DIGIT -ITOAT, 0 / SCRATCHPAD FOR ITOA2X -ITOAV, 0 / VALUE BEING CONVERTED (TEMPORARY) -$ -- cgit v1.2.3