diff options
| -rw-r--r-- | io/model.cpp | 14 | ||||
| -rw-r--r-- | isa/decode.cpp | 48 | ||||
| -rw-r--r-- | isa/isa.h | 13 |
3 files changed, 48 insertions, 27 deletions
diff --git a/io/model.cpp b/io/model.cpp index eaa6ca8..e1b59ea 100644 --- a/io/model.cpp +++ b/io/model.cpp | |||
| @@ -16,21 +16,21 @@ bool iomodel::interact(std::array<unsigned int, NUM_CTLREGS> &ctlregs) { | |||
| 16 | 16 | ||
| 17 | ++time; | 17 | ++time; |
| 18 | 18 | ||
| 19 | if (ctlregs[TT_OUTPUT] & 0x100) { | 19 | if (ctlregs[TT_BITS] & TTO_TX) { |
| 20 | // PDP-8 doesn't really have support for 8-bit output, this is Jules' contribution | 20 | // PDP-8 doesn't really have support for 8-bit output, this is Jules' contribution |
| 21 | std::cout << (char)((ctlregs[TT_OUTPUT] & 0xff) ^ 0x80) << std::flush; | 21 | std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) ^ 0x80) << std::flush; |
| 22 | ctlregs[TT_OUTPUT] &= ~0x1ff; | 22 | ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA; |
| 23 | log.emplace(time + TT_OUTPUT_DELAY, event(TT_OUTPUT, 0x200, 0)); | 23 | log.emplace(time + TT_OUTPUT_DELAY, event(TT_BITS, TTO_FLAG, 0)); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | bool interrupt = false; | 26 | bool interrupt = false; |
| 27 | if (ctlregs[INT_ENABLE] & 1) { | 27 | if (ctlregs[INT_ENABLE] & 1) { |
| 28 | if (ctlregs[TT_INPUT_INT_ENABLE]) { | 28 | if (ctlregs[TT_INPUT_INT_ENABLE]) { |
| 29 | if (ctlregs[TT_INPUT] & 0x100) | 29 | if (ctlregs[TT_BITS] & TTI_FLAG) |
| 30 | interrupt = true; | 30 | interrupt = true; |
| 31 | } | 31 | } |
| 32 | if (ctlregs[TT_OUTPUT_INT_ENABLE]) { | 32 | if (ctlregs[TT_OUTPUT_INT_ENABLE]) { |
| 33 | if (!(ctlregs[TT_OUTPUT] & 0x400) && (ctlregs[TT_OUTPUT] & 0x200)) | 33 | if ((ctlregs[TT_BITS] & (TTO_FLAG|TTO_FLAG_OLD)) == TTO_FLAG) |
| 34 | interrupt = true; | 34 | interrupt = true; |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| @@ -40,7 +40,7 @@ bool iomodel::interact(std::array<unsigned int, NUM_CTLREGS> &ctlregs) { | |||
| 40 | ctlregs[DATA_INSTRUCTION_FIELD_BUFFER] = 0; | 40 | ctlregs[DATA_INSTRUCTION_FIELD_BUFFER] = 0; |
| 41 | ctlregs[HALTED] = 0; | 41 | ctlregs[HALTED] = 0; |
| 42 | ctlregs[INT_ENABLE] = 0; | 42 | ctlregs[INT_ENABLE] = 0; |
| 43 | ctlregs[TT_OUTPUT] = (ctlregs[TT_OUTPUT] & 0x200) * 3; | 43 | ctlregs[TT_BITS] |= (ctlregs[TT_BITS] & TTO_FLAG) ? TTO_FLAG_OLD : 0; |
| 44 | } else { | 44 | } else { |
| 45 | ctlregs[INT_ENABLE] = (ctlregs[INT_ENABLE] >> 1) * 3; | 45 | ctlregs[INT_ENABLE] = (ctlregs[INT_ENABLE] >> 1) * 3; |
| 46 | } | 46 | } |
diff --git a/isa/decode.cpp b/isa/decode.cpp index dde5b74..41d125d 100644 --- a/isa/decode.cpp +++ b/isa/decode.cpp | |||
| @@ -74,54 +74,66 @@ instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bit | |||
| 74 | case 6: // IOT | 74 | case 6: // IOT |
| 75 | switch ((bits >> 3) & 077) { | 75 | switch ((bits >> 3) & 077) { |
| 76 | case 004: | 76 | case 004: |
| 77 | // TELETYPE TELEPRINTER/PUNCH | ||
| 77 | switch (bits & 07) { | 78 | switch (bits & 07) { |
| 78 | case 0: | 79 | case 0: |
| 79 | inst.write_ctlreg = TT_OUTPUT; | 80 | // Set TTO flag |
| 81 | inst.read_ctlreg = TT_BITS; | ||
| 82 | inst.write_ctlreg = TT_BITS; | ||
| 80 | inst.ef = [](auto &ctx) { | 83 | inst.ef = [](auto &ctx) { |
| 81 | ctx.ctlval = 0x600; | 84 | ctx.ctlval.value() |= TTO_FLAG | TTO_FLAG_OLD; |
| 82 | }; | 85 | }; |
| 83 | break; | 86 | break; |
| 84 | case 1: | 87 | case 1: |
| 85 | inst.read_ctlreg = TT_OUTPUT; | 88 | // Skip if TTO flag is set |
| 89 | inst.read_ctlreg = TT_BITS; | ||
| 86 | inst.possibly_redirects = true; | 90 | inst.possibly_redirects = true; |
| 87 | inst.ef = [](auto &ctx) { | 91 | inst.ef = [](auto &ctx) { |
| 88 | if (ctx.ctlval.value() & 0x200) | 92 | if (ctx.ctlval.value() & TTO_FLAG) |
| 89 | ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); | 93 | ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); |
| 90 | }; | 94 | }; |
| 91 | break; | 95 | break; |
| 92 | case 2: | 96 | case 2: |
| 93 | inst.write_ctlreg = TT_OUTPUT; | 97 | // Clear TTO flag |
| 98 | inst.read_ctlreg = TT_BITS; | ||
| 99 | inst.write_ctlreg = TT_BITS; | ||
| 94 | inst.ef = [](auto &ctx) { | 100 | inst.ef = [](auto &ctx) { |
| 95 | ctx.ctlval = 0; | 101 | ctx.ctlval.value() &= ~TTO_FLAG & ~TTO_FLAG_OLD; |
| 96 | }; | 102 | }; |
| 97 | break; | 103 | break; |
| 98 | case 4: | 104 | case 4: |
| 105 | // Print to TTO | ||
| 99 | inst.need_read_acc = true; | 106 | inst.need_read_acc = true; |
| 100 | inst.read_ctlreg = TT_OUTPUT; | 107 | inst.read_ctlreg = TT_BITS; |
| 101 | inst.write_ctlreg = TT_OUTPUT; | 108 | inst.write_ctlreg = TT_BITS; |
| 102 | inst.ef = [](auto &ctx) { | 109 | inst.ef = [](auto &ctx) { |
| 103 | auto &x = ctx.ctlval.value(); | 110 | auto &x = ctx.ctlval.value(); |
| 104 | x &= ~0x1ff; | 111 | auto chr = ctx.acc.value() ^ 0x80; |
| 105 | x |= (ctx.acc.value() & 0xff) ^ 0x80; // 0x7f instead of 0xff for real PDP-8 IO | 112 | x &= ~TTO_DATA; |
| 106 | x |= 0x100; | 113 | x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; |
| 114 | x |= TTO_TX; | ||
| 107 | }; | 115 | }; |
| 108 | break; | 116 | break; |
| 109 | case 5: | 117 | case 5: |
| 118 | // Skip if TTO flag is set or TTI flag is set | ||
| 119 | inst.read_ctlreg = TT_BITS; | ||
| 110 | inst.possibly_redirects = true; | 120 | inst.possibly_redirects = true; |
| 111 | // FIXME this instruction wants to read both TT_OUTPUT and TT_INPUT | ||
| 112 | inst.ef = [](auto &ctx) { | 121 | inst.ef = [](auto &ctx) { |
| 113 | assert(false); | 122 | if (ctx.ctlval.value() & (TTI_FLAG | TTO_FLAG)) |
| 123 | ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); | ||
| 114 | }; | 124 | }; |
| 115 | break; | 125 | break; |
| 116 | case 6: | 126 | case 6: |
| 127 | // Print to TTO and clear TTO flag | ||
| 117 | inst.need_read_acc = true; | 128 | inst.need_read_acc = true; |
| 118 | inst.read_ctlreg = TT_OUTPUT; | 129 | inst.read_ctlreg = TT_BITS; |
| 119 | inst.write_ctlreg = TT_OUTPUT; | 130 | inst.write_ctlreg = TT_BITS; |
| 120 | inst.ef = [](auto &ctx) { | 131 | inst.ef = [](auto &ctx) { |
| 121 | auto &x = ctx.ctlval.value(); | 132 | auto &x = ctx.ctlval.value(); |
| 122 | x &= ~0x7ff; | 133 | auto chr = ctx.acc.value() ^ 0x80; |
| 123 | x |= (ctx.acc.value() & 0xff) ^ 0x80; | 134 | x &= ~TTO_FLAG & ~TTO_FLAG_OLD & ~TTO_DATA; |
| 124 | x |= 0x100; | 135 | x |= (chr << TTO_DATA_SHIFT) & TTO_DATA; |
| 136 | x |= TTO_TX; | ||
| 125 | }; | 137 | }; |
| 126 | break; | 138 | break; |
| 127 | default: | 139 | default: |
| @@ -8,14 +8,23 @@ enum ctlreg { | |||
| 8 | DATA_INSTRUCTION_FIELD_SAVED, // (df_saved << 3) | if_saved | 8 | DATA_INSTRUCTION_FIELD_SAVED, // (df_saved << 3) | if_saved |
| 9 | HALTED, | 9 | HALTED, |
| 10 | INT_ENABLE, // (int_enable_delay << 1) | int_enable | 10 | INT_ENABLE, // (int_enable_delay << 1) | int_enable |
| 11 | TT_INPUT, // (tti_flag << 8) | tti_buffer | 11 | TT_BITS, // see below TT[IO]_* consts |
| 12 | TT_INPUT_INT_ENABLE, | 12 | TT_INPUT_INT_ENABLE, |
| 13 | TT_OUTPUT, // {tto_flag_old, tto_flag, tto_tx, tto_data} | ||
| 14 | TT_OUTPUT_INT_ENABLE, | 13 | TT_OUTPUT_INT_ENABLE, |
| 15 | 14 | ||
| 16 | NUM_CTLREGS, | 15 | NUM_CTLREGS, |
| 17 | }; | 16 | }; |
| 18 | 17 | ||
| 18 | // TT_BITS | ||
| 19 | static constexpr unsigned int TTI_FLAG = 1 << 0; | ||
| 20 | static constexpr unsigned int TTO_TX = 1 << 1; | ||
| 21 | static constexpr unsigned int TTO_FLAG = 1 << 2; | ||
| 22 | static constexpr unsigned int TTO_FLAG_OLD = 1 << 3; | ||
| 23 | static constexpr unsigned int TTI_DATA_SHIFT = 8; | ||
| 24 | static constexpr unsigned int TTO_DATA_SHIFT = 16; | ||
| 25 | static constexpr unsigned int TTI_DATA = 0xff << TTI_DATA_SHIFT; | ||
| 26 | static constexpr unsigned int TTO_DATA = 0xff << TTO_DATA_SHIFT; | ||
| 27 | |||
| 19 | struct instruction_context { | 28 | struct instruction_context { |
| 20 | // Known statically at decode time | 29 | // Known statically at decode time |
| 21 | bool need_indirect_load = false; // final_address = mem[init_address] | 30 | bool need_indirect_load = false; // final_address = mem[init_address] |
