summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Blake Kongslie2022-10-29 18:18:26 -0700
committerJulian Blake Kongslie2022-10-29 18:18:26 -0700
commit9f4aa97822adc791f700670ef0fc7636849563b7 (patch)
tree0b9d6c1bb1d7d596501df3b77ab3d7b9f191aa4f
parentControl register values should not be "unsigned int" (diff)
downloadbiggolf-9f4aa97822adc791f700670ef0fc7636849563b7.tar.xz
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
-rw-r--r--Bugs2
-rw-r--r--evts/foobar.evt22
-rw-r--r--io/event.h2
-rw-r--r--io/model.cpp44
-rw-r--r--io/model.h4
-rw-r--r--isa/checker.h3
-rw-r--r--isa/ctlreg.def8
-rw-r--r--isa/decode.cpp22
-rw-r--r--isa/isa.h37
-rw-r--r--main.cpp16
-rw-r--r--programs/echo.pal6
-rw-r--r--programs/echo_int.pal58
-rw-r--r--programs/echo_optimal.pal67
-rw-r--r--programs/fib_mike.pal (renamed from programs/mike_fib.pal)2
14 files changed, 263 insertions, 30 deletions
diff --git a/Bugs b/Bugs
new file mode 100644
index 0000000..2681d88
--- /dev/null
+++ b/Bugs
@@ -0,0 +1,2 @@
1TAD should do AC+[mem] and invert the link bit if the result carries
2IF 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 @@
1+100
2TT_BITS=0x6601/0xFF01
3+100
4TT_BITS=0x6F01/0xFF01
5+100
6TT_BITS=0x6F01/0xFF01
7+100
8TT_BITS=0x0A01/0xFF01
9+1000
10HALTED=1
11+10000
12HALTED=0
13+100
14TT_BITS=0x6201/0xFF01
15+100
16TT_BITS=0x6101/0xFF01
17+100
18TT_BITS=0x7201/0xFF01
19+100
20TT_BITS=0x0A01/0xFF01
21+1000
22HALTED=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 {
9 ctlreg reg; 9 ctlreg reg;
10 std::uint_fast32_t mask; 10 std::uint_fast32_t mask;
11 std::uint_fast32_t value; 11 std::uint_fast32_t value;
12 event(ctlreg reg, std::uint_fast32_t value, std::uint_fast32_t mask=~0) 12 event(ctlreg reg, std::uint_fast32_t value, std::uint_fast32_t mask=~(std::uint_fast32_t)0)
13 : reg(reg) 13 : reg(reg)
14 , mask(mask) 14 , mask(mask)
15 , value(value) 15 , 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 @@
1#include <array> 1#include <array>
2#include <cassert>
2#include <cstdint> 3#include <cstdint>
3#include <iostream> 4#include <iostream>
4#include <utility> 5#include <utility>
@@ -17,8 +18,7 @@ bool iomodel::interact(std::array<std::uint_fast32_t, NUM_CTLREGS> &ctlregs) {
17 ++time; 18 ++time;
18 19
19 if (ctlregs[TT_BITS] & TTO_TX) { 20 if (ctlregs[TT_BITS] & TTO_TX) {
20 // PDP-8 doesn't really have support for 8-bit output, this is Jules' contribution 21 std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) & 0x7f) << std::flush;
21 std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) ^ 0x80) << std::flush;
22 ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA; 22 ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA;
23 log.emplace(time + TT_OUTPUT_DELAY, event(TT_BITS, TTO_FLAG, 0)); 23 log.emplace(time + TT_OUTPUT_DELAY, event(TT_BITS, TTO_FLAG, 0));
24 } 24 }
@@ -46,4 +46,42 @@ bool iomodel::interact(std::array<std::uint_fast32_t, NUM_CTLREGS> &ctlregs) {
46 } 46 }
47 47
48 return interrupt; 48 return interrupt;
49}; 49}
50
51void iomodel::load_evt(std::istream &fh) {
52 // File format:
53 // +time advances time by relative increment
54 // regname=value/mask adds event that sets regname = (regname & ~mask) | value
55 // regname=value adds event that sets regname = value
56 // FIXME: add assertions
57 // FIXME: add DMA
58 for (std::string line; std::getline(fh, line); ) {
59 if (line.size() == 0)
60 continue;
61 if (line[0] == '+') {
62 char *end = nullptr;
63 auto step = std::strtoull(line.c_str(), &end, 0);
64 assert(end && *end == '\0');
65 load_time += step;
66 } else {
67 auto eqpos = line.find('=');
68 assert(eqpos != std::string::npos);
69 auto regname = line.substr(0, eqpos);
70 ctlreg reg = ctlreg_map.at(regname);
71 std::uint_fast32_t value, mask;
72 auto slashpos = line.find('/', eqpos);
73 auto valuestr = line.substr(eqpos + 1, slashpos - (eqpos + 1));
74 char *end = nullptr;
75 value = std::strtoull(valuestr.c_str(), &end, 0);
76 assert(end && *end == '\0');
77 if (slashpos == std::string::npos) {
78 mask = ~(std::uint_fast32_t)0;
79 } else {
80 auto maskstr = line.substr(slashpos + 1);
81 mask = std::strtoull(maskstr.c_str(), &end, 0);
82 assert(end && *end == '\0');
83 }
84 log.emplace(load_time, event(reg, value, mask));
85 }
86 }
87}
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 {
13 event_log log; 13 event_log log;
14 std::uint64_t time = 0; 14 std::uint64_t time = 0;
15 bool interact(std::array<std::uint_fast32_t, NUM_CTLREGS> &ctlregs); 15 bool interact(std::array<std::uint_fast32_t, NUM_CTLREGS> &ctlregs);
16 bool done() {
17 return log.lower_bound(time) == log.end();
18 }
16 19
20 std::uint64_t load_time = 0;
17 void load_evt(std::istream &fh); 21 void load_evt(std::istream &fh);
18}; 22};
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 {
52 ctlregs.fill(0); 52 ctlregs.fill(0);
53 } 53 }
54 void execute(); 54 void execute();
55 bool done() {
56 return ctlregs[HALTED] && system.done();
57 }
55}; 58};
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 @@
1REG(DATA_INSTRUCTION_FIELD_BUFFER) // (df << 3) | if_buffer
2REG(DATA_INSTRUCTION_FIELD_SAVED) // (df_saved << 3) | if_saved
3REG(HALTED)
4REG(INT_ENABLE) // (int_enable_delay << 1) | int_enable
5REG(INT_PENDING) // only meaningful if interrupts disabled
6REG(TT_BITS) // see TT[IO]_* consts in isa/isa.h
7REG(TT_INPUT_INT_ENABLE) // (status_enable << 1) | (int_enable)
8REG(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
152 ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); 152 ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777);
153 }; 153 };
154 break; 154 break;
155 case 5:
156 // KIE set TT_INPUT_INT_ENABLE to the low bit of the accumulator
157 inst.need_read_acc = true;
158 inst.write_ctlreg = TT_INPUT_INT_ENABLE;
159 inst.ef = [](auto &ctx) {
160 ctx.ctlval = ctx.acc.value() & 3;
161 };
162 break;
163 case 6:
164 // KRB transfer keyboard buffer to accumulator and clear TTI flag
165 inst.read_ctlreg = TT_BITS;
166 inst.need_write_acc = true;
167 inst.write_ctlreg = TT_BITS;
168 inst.ef = [](auto &ctx) {
169 ctx.acc = (ctx.ctlval.value() & TTI_DATA) >> TTI_DATA_SHIFT;
170 ctx.ctlval.value() &= ~TTI_FLAG;
171 };
172 break;
155 default: 173 default:
156 inst.ef = [bits](auto &ctx) { 174 inst.ef = [bits](auto &ctx) {
157 std::cerr << "unimplemented IOT KB suboperation " << (bits & 07) << "\n"; 175 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
194 inst.write_ctlreg = TT_BITS; 212 inst.write_ctlreg = TT_BITS;
195 inst.ef = [](auto &ctx) { 213 inst.ef = [](auto &ctx) {
196 auto &x = ctx.ctlval.value(); 214 auto &x = ctx.ctlval.value();
197 auto chr = ctx.acc.value() ^ 0x80; 215 auto chr = ctx.acc.value();
198 x &= ~TTO_DATA; 216 x &= ~TTO_DATA;
199 x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; 217 x |= (chr << TTO_DATA_SHIFT) & TTO_DATA;
200 x |= TTO_TX; 218 x |= TTO_TX;
@@ -216,7 +234,7 @@ instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bit
216 inst.write_ctlreg = TT_BITS; 234 inst.write_ctlreg = TT_BITS;
217 inst.ef = [](auto &ctx) { 235 inst.ef = [](auto &ctx) {
218 auto &x = ctx.ctlval.value(); 236 auto &x = ctx.ctlval.value();
219 auto chr = ctx.acc.value() ^ 0x80; 237 auto chr = ctx.acc.value();
220 x &= ~TTO_FLAG & ~TTO_FLAG_OLD & ~TTO_DATA; 238 x &= ~TTO_FLAG & ~TTO_FLAG_OLD & ~TTO_DATA;
221 x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; 239 x |= (chr << TTO_DATA_SHIFT) & TTO_DATA;
222 x |= TTO_TX; 240 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 @@
2 2
3#include <cstdint> 3#include <cstdint>
4#include <functional> 4#include <functional>
5#include <map>
5#include <optional> 6#include <optional>
7#include <string>
6 8
7enum ctlreg { 9enum ctlreg {
8 DATA_INSTRUCTION_FIELD_BUFFER, // (df << 3) | if_buffer 10#define REG(N) N,
9 DATA_INSTRUCTION_FIELD_SAVED, // (df_saved << 3) | if_saved 11#include "ctlreg.def"
10 HALTED, 12#undef REG
11 INT_ENABLE, // (int_enable_delay << 1) | int_enable
12 INT_PENDING, // only meaningful if interrupts disabled
13 TT_BITS, // see below TT[IO]_* consts
14 TT_INPUT_INT_ENABLE,
15 TT_OUTPUT_INT_ENABLE,
16 13
17 NUM_CTLREGS, 14 NUM_CTLREGS,
18}; 15};
19 16
17const char * const ctlreg_names[] = {
18#define REG(N) #N,
19#include "ctlreg.def"
20#undef REG
21};
22
23const std::map<std::string, ctlreg> ctlreg_map = {
24#define REG(N) { #N, N },
25#include "ctlreg.def"
26#undef REG
27};
28
20// TT_BITS 29// TT_BITS
21static constexpr unsigned int TTI_FLAG = 1 << 0; 30static constexpr std::uint_fast32_t TTI_FLAG = 1 << 0;
22static constexpr unsigned int TTO_TX = 1 << 1; 31static constexpr std::uint_fast32_t TTO_TX = 1 << 1;
23static constexpr unsigned int TTO_FLAG = 1 << 2; 32static constexpr std::uint_fast32_t TTO_FLAG = 1 << 2;
24static constexpr unsigned int TTO_FLAG_OLD = 1 << 3; 33static constexpr std::uint_fast32_t TTO_FLAG_OLD = 1 << 3;
25static constexpr unsigned int TTI_DATA_SHIFT = 8; 34static constexpr unsigned int TTI_DATA_SHIFT = 8;
26static constexpr unsigned int TTO_DATA_SHIFT = 16; 35static constexpr unsigned int TTO_DATA_SHIFT = 16;
27static constexpr unsigned int TTI_DATA = 0xff << TTI_DATA_SHIFT; 36static constexpr std::uint_fast32_t TTI_DATA = 0xff << TTI_DATA_SHIFT;
28static constexpr unsigned int TTO_DATA = 0xff << TTO_DATA_SHIFT; 37static constexpr std::uint_fast32_t TTO_DATA = 0xff << TTO_DATA_SHIFT;
29 38
30struct instruction_context { 39struct instruction_context {
31 // Known statically at decode time 40 // 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 @@
1#include <arpa/inet.h> 1#include <arpa/inet.h>
2#include <cstdint> 2#include <cstdint>
3#include <fmt/format.h> 3#include <fmt/format.h>
4#include <fstream>
4#include <iostream> 5#include <iostream>
5#include <optional> 6#include <optional>
6#include <utility> 7#include <utility>
@@ -60,13 +61,18 @@ int main(int argc, const char *argv[]) {
60 checker checker(system); 61 checker checker(system);
61 62
62 for (--argc, ++argv; argc; --argc, ++argv) { 63 for (--argc, ++argv; argc; --argc, ++argv) {
63 auto program = programs.at(argv[0]); 64 if (auto program = programs.find(*argv); program != programs.end()) {
64 if (auto err = load_program(checker, program)) 65 if (auto err = load_program(checker, program->second))
65 return err; 66 return err;
67 } else {
68 std::ifstream fh(*argv);
69 system.load_evt(fh);
70 }
66 } 71 }
67 72
68 while (true) { 73 while (!checker.done()) {
69 //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]); 74// if (!checker.ctlregs[HALTED])
75// std::cout << fmt::format("\t{:9} {:04o}\n", system.time, checker.pc);
70 checker.execute(); 76 checker.execute();
71 } 77 }
72 78
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 @@
1/ vim: set sw=8 noexpandtab : 1/ vim: set sw=8 noexpandtab :
2 2
3*200 3*200
4 TFL
4LOOP, TSF 5LOOP, TSF
5 JMS ECHO
6 JMP LOOP 6 JMP LOOP
7
8ECHO, 0
9WAIT, KSF 7WAIT, KSF
10 JMP WAIT 8 JMP WAIT
11 KRB 9 KRB
12 TLS 10 TLS
13 JMP I ECHO 11 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 @@
1/ vim: set sw=8 noexpandtab :
2
3*000
4
5INTRET, 0
6 JMP GOTINT
7
8*010
9
10HEAD, 7777 / because preincrement
11TAIL, 7777
12
13*200
14
15 CLA IAC
16 KIE
17 ION
18 CLA
19LOOP, TAD TAIL
20 CMA IAC
21 TAD HEAD
22 SNA
23 JMP LOOP
24 CLA
25 CDF 0010
26 TAD I TAIL
27 CDF 0000
28 IOF / critical section
29 TLS
30BUSY, TSF / FIXME: remove busy wait inside IOF (see echo_optimal.pal)
31 JMP BUSY
32 TCF
33 ION
34 CLA / end critical section
35 JMP LOOP
36
37*400
38
39SAVEA, 0
40SAVEF, 0
41
42GOTINT, DCA SAVEA
43 GTF
44 AND (7577)
45 DCA SAVEF
46 KSF
47 JMP RETINT
48 KRB
49 CDF 0010
50 DCA I HEAD
51 CDF 0000
52RETINT, CLA
53 TAD SAVEF
54 RTF
55 CLA
56 TAD SAVEA
57 ION
58 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 @@
1/ vim: set sw=8 noexpandtab :
2
3*000
4
5INTRET, 0
6 JMP GOTINT
7
8*010
9
10HEAD, 7777 / because preincrement
11TAIL, 7777
12
13*100
14
15TTBUSY, 0 / FIXME: sometimes we get wedged with TTBUSY=1, but TT flag is clear (no TT interrupt occurs)
16
17*200
18
19 CLA IAC
20 KIE
21 ION
22 CLA
23LOOP, TAD TTBUSY
24 SZA
25 JMP LOOP
26 TAD TAIL
27 CMA IAC
28 TAD HEAD
29 SNA
30 JMP LOOP
31 CLA
32 CDF 0010
33 TAD I TAIL
34 CDF 0000
35 IOF / critical section
36 TPC
37 CLA IAC
38 ION
39 DCA TTBUSY / end critical section
40 JMP LOOP
41
42*400
43
44SAVEA, 0
45SAVEF, 0
46
47GOTINT, DCA SAVEA
48 GTF
49 AND (7577)
50 DCA SAVEF
51 TSF
52 JMP KBIN
53 DCA TTBUSY
54 TCF
55KBIN, KSF
56 JMP RETINT
57 KRB
58 CDF 0010
59 DCA I HEAD
60 CDF 0000
61RETINT, CLA
62 TAD SAVEF
63 RTF
64 CLA
65 TAD SAVEA
66 ION
67 JMP I INTRET
diff --git a/programs/mike_fib.pal b/programs/fib_mike.pal
index 6f56109..a20a843 100644
--- a/programs/mike_fib.pal
+++ b/programs/fib_mike.pal
@@ -9,7 +9,7 @@ LOOP, CLA
9 TAD FIB0 9 TAD FIB0
10 JMS PUTN 10 JMS PUTN
11 CLA 11 CLA
12 TAD (054) 12 TAD (012)
13 JMS PUTC 13 JMS PUTC
14 CLA 14 CLA
15 TAD FIB0 15 TAD FIB0