diff options
| author | Julian Blake Kongslie | 2022-11-05 16:59:17 -0700 |
|---|---|---|
| committer | Julian Blake Kongslie | 2022-11-05 16:59:31 -0700 |
| commit | 68bdebd8cae39c30acc384664faa136aeaa9bb84 (patch) | |
| tree | 4b0c489accd2eb10af6bc359c9ee0d4b22af64ff /uarch | |
| parent | Support for more line formats in evt reader (diff) | |
| download | biggolf-68bdebd8cae39c30acc384664faa136aeaa9bb84.tar.xz | |
Add initial uarch model
Diffstat (limited to '')
| -rw-r--r-- | uarch/core.cpp | 140 | ||||
| -rw-r--r-- | uarch/core.h | 74 |
2 files changed, 214 insertions, 0 deletions
diff --git a/uarch/core.cpp b/uarch/core.cpp new file mode 100644 index 0000000..34f422a --- /dev/null +++ b/uarch/core.cpp | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | #include <fmt/format.h> | ||
| 2 | #include <iostream> | ||
| 3 | |||
| 4 | #include "uarch/core.h" | ||
| 5 | |||
| 6 | fetch_stage::fetch_stage(core &c) | ||
| 7 | : c(c) | ||
| 8 | , pc(c.checker.pc) | ||
| 9 | { } | ||
| 10 | |||
| 11 | decode_stage::decode_stage(core &c) | ||
| 12 | : c(c) | ||
| 13 | , acc(c.checker.acc) | ||
| 14 | , link(c.checker.link) | ||
| 15 | , mq(c.checker.mq) | ||
| 16 | , pc(c.checker.pc) | ||
| 17 | , ctlregs(c.checker.ctlregs) | ||
| 18 | , icount(c.checker.icount) | ||
| 19 | { } | ||
| 20 | |||
| 21 | void fetch_stage::clock() { | ||
| 22 | if (c.fetch_restarto.has_value()) { | ||
| 23 | auto &r = *c.fetch_restarto; | ||
| 24 | pte(r.tr, "!"); | ||
| 25 | gen = r.new_gen; | ||
| 26 | pc = r.new_pc; | ||
| 27 | didrestart = true; | ||
| 28 | c.fetch_restarto.reset(); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (c.fetch_bundlep.can_write()) { | ||
| 32 | fetch_bundle b; | ||
| 33 | b.tr = infra::pt::toplevel(); | ||
| 34 | b.gen = gen; | ||
| 35 | b.pc = pc; | ||
| 36 | b.word = c.mem.fetch(pc); | ||
| 37 | if (didrestart) | ||
| 38 | infra::pt::event(b.tr, ">", now-1, ""); | ||
| 39 | pte(b.tr, "F"); | ||
| 40 | c.fetch_bundlep.write(std::move(b)); | ||
| 41 | pc = (pc & 070000) | ((pc + 1) & 007777); | ||
| 42 | didrestart = false; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | void decode_stage::clock() { | ||
| 47 | bool progress = ctlregs[HALTED]; | ||
| 48 | |||
| 49 | if (!ctlregs[HALTED] && c.fetch_bundlep.can_read()) { | ||
| 50 | auto b = c.fetch_bundlep.read(); | ||
| 51 | |||
| 52 | if (b.gen != gen) | ||
| 53 | goto bail_out; | ||
| 54 | |||
| 55 | if (b.pc != pc) { | ||
| 56 | pte(b.tr, "~"); | ||
| 57 | fetch_restart r; | ||
| 58 | r.tr = b.tr; | ||
| 59 | r.new_gen = ++gen; | ||
| 60 | r.new_pc = pc; | ||
| 61 | c.fetch_restarto = std::move(r); | ||
| 62 | goto bail_out; | ||
| 63 | } | ||
| 64 | |||
| 65 | progress = true; | ||
| 66 | |||
| 67 | pte(b.tr, "E"); | ||
| 68 | |||
| 69 | inst = decode(ctlregs[FLAGS], | ||
| 70 | pc, | ||
| 71 | c.mem.fetch(pc), | ||
| 72 | interrupt); | ||
| 73 | auto next_pc = inst.next_pc; | ||
| 74 | |||
| 75 | if (inst.need_indirect_load) { | ||
| 76 | auto addr = c.mem.fetch(inst.init_address.value()); | ||
| 77 | if (inst.need_autoinc_store) { | ||
| 78 | addr = (addr + 1) & 07777; | ||
| 79 | c.mem.store(*inst.init_address, addr); | ||
| 80 | } | ||
| 81 | auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; | ||
| 82 | inst.final_address = (df << 12) | addr; | ||
| 83 | } else { | ||
| 84 | assert(!inst.need_autoinc_store); | ||
| 85 | } | ||
| 86 | |||
| 87 | pte(b.tr, "", inst.disasm()); | ||
| 88 | |||
| 89 | if (inst.need_exec_load) | ||
| 90 | inst.data = c.mem.fetch(inst.final_address.value()); | ||
| 91 | |||
| 92 | if (inst.need_read_acc) | ||
| 93 | inst.acc = acc; | ||
| 94 | if (inst.need_read_link) | ||
| 95 | inst.link = link; | ||
| 96 | if (inst.need_read_mq) | ||
| 97 | inst.mq = mq; | ||
| 98 | if (inst.read_ctlreg.has_value()) | ||
| 99 | inst.ctlval = ctlregs[*inst.read_ctlreg]; | ||
| 100 | |||
| 101 | inst.execute(); | ||
| 102 | |||
| 103 | if (inst.need_write_acc) | ||
| 104 | acc = inst.acc.value(); | ||
| 105 | if (inst.need_write_link) | ||
| 106 | link = inst.link.value(); | ||
| 107 | if (inst.need_write_mq) | ||
| 108 | mq = inst.mq.value(); | ||
| 109 | if (inst.write_ctlreg.has_value()) | ||
| 110 | ctlregs[*inst.write_ctlreg] = inst.ctlval.value(); | ||
| 111 | |||
| 112 | if (inst.need_exec_store) | ||
| 113 | c.mem.store(inst.final_address.value(), inst.data.value()); | ||
| 114 | |||
| 115 | assert(inst.next_pc == next_pc || inst.possibly_redirects); | ||
| 116 | pc = inst.next_pc; | ||
| 117 | } | ||
| 118 | bail_out: | ||
| 119 | |||
| 120 | if (progress) | ||
| 121 | interrupt = c.system.interact(icount++, ctlregs); | ||
| 122 | |||
| 123 | if (c.checker.icount != icount) { | ||
| 124 | assert(c.checker.icount + 1 == icount); | ||
| 125 | |||
| 126 | c.checker.execute(); | ||
| 127 | assert(c.checker.icount == icount); | ||
| 128 | std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", icount, pc, c.checker.pc); | ||
| 129 | assert(pc == c.checker.pc); | ||
| 130 | assert(acc == c.checker.acc); | ||
| 131 | assert(link == c.checker.link); | ||
| 132 | assert(mq == c.checker.mq); | ||
| 133 | assert(ctlregs == c.checker.ctlregs); | ||
| 134 | if (inst.init_address.has_value()) | ||
| 135 | assert(c.mem.fetch(*inst.init_address) == c.checker.mem.fetch(*inst.init_address)); | ||
| 136 | if (inst.final_address.has_value()) | ||
| 137 | assert(c.mem.fetch(*inst.final_address) == c.checker.mem.fetch(*inst.final_address)); | ||
| 138 | assert(c.mem.fetch(pc) == c.checker.mem.fetch(pc)); | ||
| 139 | } | ||
| 140 | } | ||
diff --git a/uarch/core.h b/uarch/core.h new file mode 100644 index 0000000..0f9be74 --- /dev/null +++ b/uarch/core.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <array> | ||
| 4 | |||
| 5 | #include "infra/pipetrace.h" | ||
| 6 | #include "infra/port.h" | ||
| 7 | #include "io/model.h" | ||
| 8 | #include "isa/checker.h" | ||
| 9 | #include "isa/isa.h" | ||
| 10 | |||
| 11 | struct core; | ||
| 12 | |||
| 13 | struct fetch_bundle { | ||
| 14 | infra::transaction tr; | ||
| 15 | unsigned int gen; | ||
| 16 | unsigned int pc; | ||
| 17 | unsigned int word; | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct fetch_restart { | ||
| 21 | infra::transaction tr; | ||
| 22 | unsigned int new_gen; | ||
| 23 | unsigned int new_pc; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct fetch_stage : public infra::sim { | ||
| 27 | core &c; | ||
| 28 | |||
| 29 | unsigned int gen = 0; | ||
| 30 | unsigned int pc; | ||
| 31 | bool didrestart = false; | ||
| 32 | |||
| 33 | fetch_stage(core &c); | ||
| 34 | |||
| 35 | void clock(); | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct decode_stage : public infra::sim { | ||
| 39 | core &c; | ||
| 40 | |||
| 41 | unsigned int gen = 0; | ||
| 42 | |||
| 43 | bool interrupt = false; | ||
| 44 | |||
| 45 | unsigned int acc; | ||
| 46 | unsigned int link; | ||
| 47 | unsigned int mq; | ||
| 48 | unsigned int pc; | ||
| 49 | std::array<uint_fast32_t, NUM_CTLREGS> ctlregs; | ||
| 50 | std::uint64_t icount; | ||
| 51 | instruction_context inst; | ||
| 52 | |||
| 53 | decode_stage(core &c); | ||
| 54 | |||
| 55 | void clock(); | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct core { | ||
| 59 | iomodel &system; | ||
| 60 | funcchecker checker; | ||
| 61 | funcmem mem; | ||
| 62 | |||
| 63 | infra::port<fetch_bundle> fetch_bundlep; | ||
| 64 | std::optional<fetch_restart> fetch_restarto; | ||
| 65 | |||
| 66 | // Construction order is execution order within a cycle, so this list should be back-to-front (for zero-cycle restarts) | ||
| 67 | decode_stage decode{*this}; | ||
| 68 | fetch_stage fetch{*this}; | ||
| 69 | |||
| 70 | core(iomodel &model) | ||
| 71 | : system(model) | ||
| 72 | , checker(model) | ||
| 73 | { } | ||
| 74 | }; | ||
