From 68bdebd8cae39c30acc384664faa136aeaa9bb84 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 5 Nov 2022 16:59:17 -0700 Subject: Add initial uarch model --- isa/checker.cpp | 97 +++++++++++++++++----------------- isa/checker.h | 10 ++-- isa/decode.cpp | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++- isa/isa.h | 10 ++++ main.cpp | 33 ++++++++---- nanosim | 2 +- programs/queue.pal | 45 ++++++++++------ uarch/core.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ uarch/core.h | 74 ++++++++++++++++++++++++++ 9 files changed, 482 insertions(+), 79 deletions(-) create mode 100644 uarch/core.cpp create mode 100644 uarch/core.h diff --git a/isa/checker.cpp b/isa/checker.cpp index c6ab161..70b0f88 100644 --- a/isa/checker.cpp +++ b/isa/checker.cpp @@ -3,56 +3,55 @@ #include "isa/checker.h" #include "isa/isa.h" -void checker::execute() { - bool interrupt = system.interact(ctlregs); - - if (ctlregs[HALTED]) - return; - - inst = decode(ctlregs[FLAGS], - pc, - mem.fetch(pc), - interrupt); - auto next_pc = inst.next_pc; - - if (inst.need_indirect_load) { - auto addr = mem.fetch(inst.init_address.value()); - if (inst.need_autoinc_store) { - addr = (addr + 1) & 07777; - mem.store(*inst.init_address, addr); +void funcchecker::execute() { + if (!ctlregs[HALTED]) { + inst = decode(ctlregs[FLAGS], + pc, + mem.fetch(pc), + interrupt); + auto next_pc = inst.next_pc; + + if (inst.need_indirect_load) { + auto addr = mem.fetch(inst.init_address.value()); + if (inst.need_autoinc_store) { + addr = (addr + 1) & 07777; + mem.store(*inst.init_address, addr); + } + auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; + inst.final_address = (df << 12) | addr; + } else { + assert(!inst.need_autoinc_store); } - auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; - inst.final_address = (df << 12) | addr; - } else { - assert(!inst.need_autoinc_store); + + if (inst.need_exec_load) + inst.data = mem.fetch(inst.final_address.value()); + + if (inst.need_read_acc) + inst.acc = acc; + if (inst.need_read_link) + inst.link = link; + if (inst.need_read_mq) + inst.mq = mq; + if (inst.read_ctlreg.has_value()) + inst.ctlval = ctlregs[*inst.read_ctlreg]; + + inst.execute(); + + if (inst.need_write_acc) + acc = inst.acc.value(); + if (inst.need_write_link) + link = inst.link.value(); + if (inst.need_write_mq) + mq = inst.mq.value(); + if (inst.write_ctlreg.has_value()) + ctlregs[*inst.write_ctlreg] = inst.ctlval.value(); + + if (inst.need_exec_store) + mem.store(inst.final_address.value(), inst.data.value()); + + assert(inst.next_pc == next_pc || inst.possibly_redirects); + pc = inst.next_pc; } - if (inst.need_exec_load) - inst.data = mem.fetch(inst.final_address.value()); - - if (inst.need_read_acc) - inst.acc = acc; - if (inst.need_read_link) - inst.link = link; - if (inst.need_read_mq) - inst.mq = mq; - if (inst.read_ctlreg.has_value()) - inst.ctlval = ctlregs[*inst.read_ctlreg]; - - inst.execute(); - - if (inst.need_write_acc) - acc = inst.acc.value(); - if (inst.need_write_link) - link = inst.link.value(); - if (inst.need_write_mq) - mq = inst.mq.value(); - if (inst.write_ctlreg.has_value()) - ctlregs[*inst.write_ctlreg] = inst.ctlval.value(); - - if (inst.need_exec_store) - mem.store(inst.final_address.value(), inst.data.value()); - - assert(inst.next_pc == next_pc || inst.possibly_redirects); - pc = inst.next_pc; + interrupt = system.interact(icount++, ctlregs, true); } diff --git a/isa/checker.h b/isa/checker.h index 65ef8c9..30a8356 100644 --- a/isa/checker.h +++ b/isa/checker.h @@ -37,16 +37,18 @@ struct funcmem { } }; -struct checker { +struct funcchecker { unsigned int acc = 0; unsigned int link = 0; unsigned int mq = 0; - unsigned int pc = 00200; + unsigned int pc = 000200; std::array ctlregs; + std::uint64_t icount = 0; + bool interrupt = false; iomodel &system; instruction_context inst; funcmem mem; - checker(iomodel &system) + funcchecker(iomodel &system) : system(system) { ctlregs.fill(0); @@ -54,6 +56,6 @@ struct checker { } void execute(); bool done() { - return ctlregs[HALTED] && system.done(); + return ctlregs[HALTED] && system.done(icount); } }; diff --git a/isa/decode.cpp b/isa/decode.cpp index 745e529..2151e2b 100644 --- a/isa/decode.cpp +++ b/isa/decode.cpp @@ -1,9 +1,78 @@ #include #include +#include #include +#include #include "isa/isa.h" +void init_disasm_tables() +{ + for (unsigned int i = 0; i < 0377; ++i) { + auto &s = opr_disasm_group1[i]; + bool cla = i & 0200; + bool cll = i & 0100; + bool cma = i & 0040; + bool cml = i & 0020; + bool rar = i & 0010; + bool ral = i & 0004; + bool bsw = i & 0002; + bool iac = i & 0001; + if (cla) s += "CLA "; + if (cll) s += "CLL "; + if (cma) s += "CMA "; + if (cml) s += "CML "; + if (iac) s += "IAC "; + if (rar) s += "RAR "; + if (ral) s += "RAL "; + if (bsw) s += "BSW "; + if (s.size()) + s = s.substr(0, s.size() - 1); + else + s = "NOP"; + } + + for (unsigned int i = 0; i < 0366; ++i) { + auto &s = opr_disasm_group2_pos[i]; + bool cla = i & 0200; + bool sma = i & 0100; + bool sza = i & 0040; + bool snl = i & 0020; + bool osr = i & 0004; + bool hlt = i & 0002; + if (sma) s += "SMA "; + if (sza) s += "SZA "; + if (snl) s += "SNL "; + if (cla) s += "CLA "; + if (osr) s += "OSR "; + if (hlt) s += "HLT "; + if (s.size()) + s = s.substr(0, s.size() - 1); + else + s = "NOP"; + } + + for (unsigned int i = 0; i < 0366; ++i) { + auto &s = opr_disasm_group2_neg[i]; + bool cla = i & 0200; + bool spa = i & 0100; + bool sna = i & 0040; + bool szl = i & 0020; + bool osr = i & 0004; + bool hlt = i & 0002; + if (spa) s += "SPA "; + if (sna) s += "SNA "; + if (szl) s += "SZL "; + if (cla) s += "CLA "; + if (osr) s += "OSR "; + if (hlt) s += "HLT "; + if (s.size()) + s = s.substr(0, s.size() - 1); + else + s = "SKP"; + } +} + instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned int bits, bool interrupt) { #pragma GCC diagnostic push @@ -19,6 +88,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i #pragma GCC diagnostic pop instruction_context inst; + inst.bits = bits; inst.next_pc = (pc & ~07777) | ((pc + 1) & 07777); if (interrupt) { @@ -34,6 +104,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_exec_load = true; inst.need_read_acc = true; inst.need_write_acc = true; + inst.df = "AND %a"; inst.ef = [](auto &ctx) { ctx.acc = ctx.acc.value() & ctx.data.value() & 07777; }; @@ -44,6 +115,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_link = true; inst.need_write_acc = true; inst.need_write_link = true; + inst.df = "TAD %a"; inst.ef = [](auto &ctx) { unsigned int sum = ctx.acc.value() + ctx.data.value(); ctx.link = ctx.link.value() ^ (sum >> 12); @@ -54,6 +126,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_exec_load = true; inst.need_exec_store = true; inst.possibly_redirects = true; + inst.df = "ISZ %a"; inst.ef = [](auto &ctx) { ctx.data = (ctx.data.value() + 1) & 07777; if (*ctx.data == 0) @@ -64,6 +137,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_acc = true; inst.need_write_acc = true; inst.need_exec_store = true; + inst.df = "DCA %a"; inst.ef = [](auto &ctx) { ctx.data = ctx.acc.value(); ctx.acc = 0; @@ -72,6 +146,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 4: // JMS jump subroutine inst.need_exec_store = true; inst.possibly_redirects = true; + inst.df = "JMS %a"; inst.ef = [ifb](auto &ctx) { ctx.data = ctx.next_pc; ctx.next_pc = (ifb << 12) | ((ctx.final_address.value() + 1) & 07777); @@ -79,6 +154,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i break; case 5: // JMP jump inst.possibly_redirects = true; + inst.df = "JMP %a"; inst.ef = [ifb](auto &ctx) { ctx.next_pc = (ifb << 12) | (ctx.final_address.value() & 07777); }; @@ -91,6 +167,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 0: // SKON skip if interrupts enabled inst.possibly_redirects = true; + inst.df = "SKON"; inst.ef = [ie](auto &ctx) { if (ie) ctx.next_pc = (ctx.next_pc & 07777) | ((ctx.next_pc + 1) & 07777); @@ -99,6 +176,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 1: // ION set int_enable_delay inst.write_ctlreg = FLAGS; + inst.df = "ION"; inst.ef = [flags](auto &ctx) { ctx.ctlval = flags | FLAG_INT_ENABLE_DELAY; }; @@ -106,6 +184,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 2: // IOF clear int_enable and int_enable_delay inst.write_ctlreg = FLAGS; + inst.df = "IOF"; inst.ef = [flags](auto &ctx) { ctx.ctlval = flags & ~FLAG_INT_ENABLE_DELAY & ~FLAG_INT_ENABLE; }; @@ -113,6 +192,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 3: // SRQ skip if pending interrupt inst.possibly_redirects = true; + inst.df = "SRQ"; inst.ef = [ir](auto &ctx) { if (ir) ctx.next_pc = (ctx.next_pc & 07777) | ((ctx.next_pc + 1) & 07777); @@ -122,6 +202,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // GTF get flags inst.read_ctlreg = FLAGS_SAVED; inst.need_read_link = true; + inst.df = "GTF"; inst.ef = [](auto &ctx) { auto flags = ctx.ctlval.value(); flags |= (unsigned int)ctx.link.value() << 11; @@ -133,6 +214,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_acc = true; inst.need_write_link = true; inst.write_ctlreg = FLAGS; + inst.df = "RTF"; inst.ef = [ie](auto &ctx) { if (ie && (ctx.acc.value() & FLAG_INT_ENABLE)) { ctx.ctlval = ctx.acc.value() | FLAG_INT_ENABLE_DELAY; @@ -147,6 +229,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i break; case 6: // SGT skip if greater than + inst.df = "SGT"; inst.ef = [](auto &ctx) { std::cerr << "unimplemented SGT\n"; assert(false); @@ -154,6 +237,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i break; case 7: // CAF clear all flags + inst.df = "CAF"; inst.ef = [](auto &ctx) { std::cerr << "unimplemented CAF\n"; assert(false); @@ -168,6 +252,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // KSF skip if TTI flag is set inst.read_ctlreg = TT_BITS; inst.possibly_redirects = true; + inst.df = "KSF"; inst.ef = [](auto &ctx) { if (ctx.ctlval.value() & TTI_FLAG) ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); @@ -177,6 +262,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // KIE set TT_FLAGS from the accumulator inst.need_read_acc = true; inst.write_ctlreg = TT_FLAGS; + inst.df = "KIE"; inst.ef = [](auto &ctx) { ctx.ctlval = ctx.acc.value(); }; @@ -186,12 +272,14 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.read_ctlreg = TT_BITS; inst.need_write_acc = true; inst.write_ctlreg = TT_BITS; + inst.df = "KRB"; inst.ef = [](auto &ctx) { ctx.acc = (ctx.ctlval.value() & TTI_DATA) >> TTI_DATA_SHIFT; ctx.ctlval.value() &= ~TTI_FLAG; }; break; default: + inst.df = "IOT %b"; inst.ef = [bits](auto &ctx) { std::cerr << "unimplemented IOT KB suboperation " << (bits & 07) << "\n"; assert(false); @@ -205,6 +293,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // TFL set TTO flag inst.read_ctlreg = TT_BITS; inst.write_ctlreg = TT_BITS; + inst.df = "TFL"; inst.ef = [](auto &ctx) { ctx.ctlval.value() |= TTO_FLAG; }; @@ -213,6 +302,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // TSF skip if TTO flag is set inst.read_ctlreg = TT_BITS; inst.possibly_redirects = true; + inst.df = "TSF"; inst.ef = [](auto &ctx) { if (ctx.ctlval.value() & TTO_FLAG) ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); @@ -222,6 +312,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // TCF clear TTO flag inst.read_ctlreg = TT_BITS; inst.write_ctlreg = TT_BITS; + inst.df = "TCF"; inst.ef = [](auto &ctx) { ctx.ctlval.value() &= ~TTO_FLAG; }; @@ -231,6 +322,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_acc = true; inst.read_ctlreg = TT_BITS; inst.write_ctlreg = TT_BITS; + inst.df = "TPC"; inst.ef = [](auto &ctx) { auto &x = ctx.ctlval.value(); auto chr = ctx.acc.value(); @@ -243,6 +335,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // TSK skip if TTO flag is set or TTI flag is set inst.read_ctlreg = TT_BITS; inst.possibly_redirects = true; + inst.df = "TSK"; inst.ef = [](auto &ctx) { if (ctx.ctlval.value() & (TTI_FLAG | TTO_FLAG)) ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); @@ -253,6 +346,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_acc = true; inst.read_ctlreg = TT_BITS; inst.write_ctlreg = TT_BITS; + inst.df = "TLS"; inst.ef = [](auto &ctx) { auto &x = ctx.ctlval.value(); auto chr = ctx.acc.value(); @@ -262,6 +356,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i }; break; default: + inst.df = "IOT %b"; inst.ef = [bits](auto &ctx) { std::cerr << "unimplemented IOT TT suboperation " << (bits & 07) << "\n"; assert(false); @@ -283,6 +378,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i case 01: // CDF change data field inst.write_ctlreg = FLAGS; + inst.df = "CDF %f"; inst.ef = [flags, field](auto &ctx) { ctx.ctlval = (flags & ~FLAG_DF) | (field << FLAG_DF_SHIFT); }; @@ -293,12 +389,14 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i // RMF restore memory field inst.read_ctlreg = FLAGS_SAVED; inst.write_ctlreg = FLAGS; + inst.df = "RMF"; inst.ef = [flags](auto &ctx) { ctx.ctlval.value() &= FLAG_DF | FLAG_IF | FLAG_USER_MODE; ctx.ctlval.value() |= flags & ~(FLAG_DF | FLAG_IF | FLAG_USER_MODE); }; break; default: + inst.df = "IOT %b"; inst.ef = [bits, field](auto &ctx) { std::cerr << "unimplemented IOT MEMORY suboperation " << (bits & 07) << " upon field " << field << "\n"; assert(false); @@ -306,6 +404,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i } break; default: + inst.df = "IOT %b"; inst.ef = [bits, field](auto &ctx) { std::cerr << "unimplemented IOT MEMORY suboperation " << (bits & 07) << " upon field " << field << "\n"; assert(false); @@ -314,6 +413,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i } break; default: + inst.df = "IOT %b"; inst.ef = [bits](auto &ctx) { std::cerr << "warning: unimplemented IOT device " << ((bits >> 6) & 07) << ((bits >> 3) & 07) << " suboperation " << (bits & 07) << "\n"; }; @@ -333,6 +433,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_link = cml || rar || ral || iac; inst.need_write_acc = cla || cma || rar || ral || bsw || iac; inst.need_write_link = cll || cml || rar || ral || iac; + inst.df = opr_disasm_group1[bits & 0377].c_str(); inst.ef = [cla, cll, cma, cml, rar, ral, bsw, iac](auto &ctx) { if (cla) ctx.acc = 0; if (cll) ctx.link = 0; @@ -374,6 +475,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i if (hlt) inst.write_ctlreg = HALTED; inst.possibly_redirects = true; + inst.df = opr_disasm_group2_pos[bits & 0366].c_str(); inst.ef = [cla, sma, sza, snl, osr, hlt](auto &ctx) { bool skip = false; if (sma && (ctx.acc.value() & 04000)) skip = true; @@ -398,6 +500,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i if (hlt) inst.write_ctlreg = HALTED; inst.possibly_redirects = true; + inst.df = opr_disasm_group2_neg[bits & 0366].c_str(); inst.ef = [cla, spa, sna, szl, osr, hlt](auto &ctx) { bool skip = true; if (spa && (ctx.acc.value() & 04000)) skip = false; @@ -418,6 +521,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i inst.need_read_mq = mqa; inst.need_write_acc = cla || mqa; inst.need_write_mq = mql; + inst.df = opr_disasm_extended_arith[bits & 0376].c_str(); inst.ef = [cla, mqa, mql, extended_arith](auto &ctx) { assert(!extended_arith); if (cla) ctx.acc = 0; @@ -429,6 +533,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i ctx.mq = new_mq; }; } else { + inst.df = "OPR %b"; inst.ef = [bits](auto &ctx) { std::cerr << "unimplemented OPR " << ((bits >> 6) & 07) << ((bits >> 3) & 07) << (bits & 07) << "\n"; assert(false); @@ -438,7 +543,7 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i } // Instructions with memory operands may be direct or indirect - if (inst.need_exec_load || inst.need_exec_store || inst.possibly_redirects) { + if (inst.need_exec_load || inst.need_exec_store || (bits & 06000) == 04000 /* JMS and JMP */) { auto addr = (pc & 070000) | ((bits & 00200) ? (pc & 07600) : 0) | (bits & 00177); if (bits & 00400) { inst.need_indirect_load = true; @@ -454,3 +559,46 @@ instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned i return inst; } + +std::string instruction_context::disasm() const +{ + if (!df) + return ""; + + std::ostringstream s; + for (const char *p = df; *p; ++p) { + if (*p != '%') { + s << *p; + continue; + } + switch (*++p) { + case '\0': + case '%': + s << '%'; + break; + case 'a': + if (bits & 00400) + s << "I "; + if (~bits & 00200) + s << "Z "; + s << fmt::format("{:03o}", bits & 00177); + break; + case 'b': + s << fmt::format("{:04o}", bits); + break; + case 'f': + s << fmt::format("{:01o}", (bits & 00070) >> 3); + break; + default: + s << '%' << *p; + break; + } + } + + if (init_address.has_value()) + s << fmt::format(" [{:05o}] ->", *init_address); + if (final_address.has_value()) + s << fmt::format(" [{:05o}]", *final_address); + + return s.str(); +} diff --git a/isa/isa.h b/isa/isa.h index 8156c08..4083e16 100644 --- a/isa/isa.h +++ b/isa/isa.h @@ -51,6 +51,11 @@ static constexpr std::uint_fast32_t TTO_DATA = 0xff << TTO_DATA_SHIFT; static constexpr std::uint_fast32_t TTF_INT_ENABLE = 1 << 0; static constexpr std::uint_fast32_t TTF_STATUS_ENABLE = 1 << 1; +static std::string opr_disasm_group1[0377]; +static std::string opr_disasm_group2_pos[0366]; +static std::string opr_disasm_group2_neg[0366]; +static std::string opr_disasm_extended_arith[0376]; + struct instruction_context { // Known statically at decode time bool need_indirect_load = false; // final_address = mem[init_address] @@ -67,10 +72,14 @@ struct instruction_context { bool need_exec_store = false; // mem[final_address] = data bool possibly_redirects = false; // %pc = next_pc + const char *df = nullptr; + std::string disasm() const; + std::function ef; void execute() { ef(*this); } // May change over the lifetime of the instruction execution + unsigned int bits; unsigned int next_pc; // includes IF std::optional init_address; // includes DF std::optional final_address; // includes DF @@ -81,4 +90,5 @@ struct instruction_context { std::optional mq; }; +void init_disasm_tables(); instruction_context decode(std::uint_fast32_t flags, unsigned int pc, unsigned int bits, bool interrupt); diff --git a/main.cpp b/main.cpp index 7a8d161..4fec1f4 100644 --- a/main.cpp +++ b/main.cpp @@ -6,10 +6,12 @@ #include #include +#include "infra/sim.h" #include "isa/checker.h" #include "programs/programs.h" +#include "uarch/core.h" -int load_program(checker &checker, const std::uint8_t *program) { +int load_program(core &core, const std::uint8_t *program) { bool seen_non_leader = false; bool comment = false; unsigned int field = 0; @@ -31,8 +33,10 @@ int load_program(checker &checker, const std::uint8_t *program) { address = ((b1 & 0077) << 6) | *program++; } else if ((b1 & 0300) == 0000) { seen_non_leader = true; - if (data.has_value()) - checker.mem.store(data->first, data->second); + if (data.has_value()) { + core.checker.mem.store(data->first, data->second); + core.mem.store(data->first, data->second); + } auto a = field | address++; auto d = ((b1 & 0077) << 6) | *program++; data = std::make_pair(a, d); @@ -57,12 +61,14 @@ int main(int argc, const char *argv[]) { return 1; } + init_disasm_tables(); + iomodel system; - checker checker(system); + core core(system); for (--argc, ++argv; argc; --argc, ++argv) { if (auto program = programs.find(*argv); program != programs.end()) { - if (auto err = load_program(checker, program->second)) + if (auto err = load_program(core, program->second)) return err; } else { std::ifstream fh(*argv); @@ -70,12 +76,21 @@ int main(int argc, const char *argv[]) { } } - while (!checker.done()) { -// if (!checker.ctlregs[HALTED]) -// std::cout << fmt::format("\t{:9} {:04o}\n", system.time, checker.pc); - checker.execute(); + std::ofstream pt("bug.pt"); + infra::pt::ptfile = &pt; + + while (!core.checker.done()) { +// if (!checker.ctlregs[HALTED]) { +// if (checker.inst.final_address.has_value()) +// std::cout << fmt::format("{:05o} {:01o} {:04o} {:04o} {:005o}\n", checker.pc, checker.link, checker.acc, checker.mq, *checker.inst.final_address); +// else +// std::cout << fmt::format("{:05o} {:01o} {:04o} {:04o} \n", checker.pc, checker.link, checker.acc, checker.mq); +// } + infra::sim::advance(); } + pt << fmt::format("# icount={} cycles={} ipc={:.04}\n", core.checker.icount, infra::sim::now, (float)core.checker.icount / (float)infra::sim::now); + // std::ofstream fh("trace.evt"); // system.write_evt(fh); diff --git a/nanosim b/nanosim index f795e6c..3c43115 160000 --- a/nanosim +++ b/nanosim @@ -1 +1 @@ -Subproject commit f795e6c7224c0cdeedb0c2a7bccc8cae89913153 +Subproject commit 3c43115056a1622d97de05fbc56c38e2013cfc1f diff --git a/programs/queue.pal b/programs/queue.pal index 89a1fea..7d4cce7 100644 --- a/programs/queue.pal +++ b/programs/queue.pal @@ -7,12 +7,15 @@ INTRET, 0 *010 -HEAD, 7777 / because preincrement -TAIL, 7777 +IHEAD, 7777 / because preincrement +ITAIL, 7777 + +OHEAD, 7777 / because preincrement +OTAIL, 7777 *100 -TTBUSY, 0 +OBUSY, 0 *200 @@ -20,24 +23,23 @@ TTBUSY, 0 KIE ION LOOP, CLA - TAD TTBUSY - SZA - JMP LOOP - TAD TAIL + TAD ITAIL CMA IAC - TAD HEAD + TAD IHEAD SNA JMP LOOP CLA CDF 0010 - TAD I TAIL + TAD I ITAIL + CDF 0020 + DCA I OHEAD CDF 0000 IOF / critical section - TPC - CLA IAC + TAD OBUSY + SNA + TFL ION - DCA TTBUSY / end critical section - JMP LOOP + JMP LOOP / end critical section *400 @@ -47,13 +49,26 @@ GOTINT, DCA SAVEA DCA SAVEF TSF JMP KBIN - DCA TTBUSY TCF + CLA + DCA OBUSY + TAD OTAIL + CMA IAC + TAD OHEAD + SNA + JMP KBIN + CLA + CDF 0020 + TAD I OTAIL + CDF 0000 + TPC + CLA IAC + DCA OBUSY KBIN, KSF JMP RETINT KRB CDF 0010 - DCA I HEAD + DCA I IHEAD CDF 0000 RETINT, CLA TAD SAVEF 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 @@ +#include +#include + +#include "uarch/core.h" + +fetch_stage::fetch_stage(core &c) + : c(c) + , pc(c.checker.pc) +{ } + +decode_stage::decode_stage(core &c) + : c(c) + , acc(c.checker.acc) + , link(c.checker.link) + , mq(c.checker.mq) + , pc(c.checker.pc) + , ctlregs(c.checker.ctlregs) + , icount(c.checker.icount) +{ } + +void fetch_stage::clock() { + if (c.fetch_restarto.has_value()) { + auto &r = *c.fetch_restarto; + pte(r.tr, "!"); + gen = r.new_gen; + pc = r.new_pc; + didrestart = true; + c.fetch_restarto.reset(); + } + + if (c.fetch_bundlep.can_write()) { + fetch_bundle b; + b.tr = infra::pt::toplevel(); + b.gen = gen; + b.pc = pc; + b.word = c.mem.fetch(pc); + if (didrestart) + infra::pt::event(b.tr, ">", now-1, ""); + pte(b.tr, "F"); + c.fetch_bundlep.write(std::move(b)); + pc = (pc & 070000) | ((pc + 1) & 007777); + didrestart = false; + } +} + +void decode_stage::clock() { + bool progress = ctlregs[HALTED]; + + if (!ctlregs[HALTED] && c.fetch_bundlep.can_read()) { + auto b = c.fetch_bundlep.read(); + + if (b.gen != gen) + goto bail_out; + + if (b.pc != pc) { + pte(b.tr, "~"); + fetch_restart r; + r.tr = b.tr; + r.new_gen = ++gen; + r.new_pc = pc; + c.fetch_restarto = std::move(r); + goto bail_out; + } + + progress = true; + + pte(b.tr, "E"); + + inst = decode(ctlregs[FLAGS], + pc, + c.mem.fetch(pc), + interrupt); + auto next_pc = inst.next_pc; + + if (inst.need_indirect_load) { + auto addr = c.mem.fetch(inst.init_address.value()); + if (inst.need_autoinc_store) { + addr = (addr + 1) & 07777; + c.mem.store(*inst.init_address, addr); + } + auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; + inst.final_address = (df << 12) | addr; + } else { + assert(!inst.need_autoinc_store); + } + + pte(b.tr, "", inst.disasm()); + + if (inst.need_exec_load) + inst.data = c.mem.fetch(inst.final_address.value()); + + if (inst.need_read_acc) + inst.acc = acc; + if (inst.need_read_link) + inst.link = link; + if (inst.need_read_mq) + inst.mq = mq; + if (inst.read_ctlreg.has_value()) + inst.ctlval = ctlregs[*inst.read_ctlreg]; + + inst.execute(); + + if (inst.need_write_acc) + acc = inst.acc.value(); + if (inst.need_write_link) + link = inst.link.value(); + if (inst.need_write_mq) + mq = inst.mq.value(); + if (inst.write_ctlreg.has_value()) + ctlregs[*inst.write_ctlreg] = inst.ctlval.value(); + + if (inst.need_exec_store) + c.mem.store(inst.final_address.value(), inst.data.value()); + + assert(inst.next_pc == next_pc || inst.possibly_redirects); + pc = inst.next_pc; + } +bail_out: + + if (progress) + interrupt = c.system.interact(icount++, ctlregs); + + if (c.checker.icount != icount) { + assert(c.checker.icount + 1 == icount); + + c.checker.execute(); + assert(c.checker.icount == icount); + std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", icount, pc, c.checker.pc); + assert(pc == c.checker.pc); + assert(acc == c.checker.acc); + assert(link == c.checker.link); + assert(mq == c.checker.mq); + assert(ctlregs == c.checker.ctlregs); + if (inst.init_address.has_value()) + assert(c.mem.fetch(*inst.init_address) == c.checker.mem.fetch(*inst.init_address)); + if (inst.final_address.has_value()) + assert(c.mem.fetch(*inst.final_address) == c.checker.mem.fetch(*inst.final_address)); + assert(c.mem.fetch(pc) == c.checker.mem.fetch(pc)); + } +} 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 @@ +#pragma once + +#include + +#include "infra/pipetrace.h" +#include "infra/port.h" +#include "io/model.h" +#include "isa/checker.h" +#include "isa/isa.h" + +struct core; + +struct fetch_bundle { + infra::transaction tr; + unsigned int gen; + unsigned int pc; + unsigned int word; +}; + +struct fetch_restart { + infra::transaction tr; + unsigned int new_gen; + unsigned int new_pc; +}; + +struct fetch_stage : public infra::sim { + core &c; + + unsigned int gen = 0; + unsigned int pc; + bool didrestart = false; + + fetch_stage(core &c); + + void clock(); +}; + +struct decode_stage : public infra::sim { + core &c; + + unsigned int gen = 0; + + bool interrupt = false; + + unsigned int acc; + unsigned int link; + unsigned int mq; + unsigned int pc; + std::array ctlregs; + std::uint64_t icount; + instruction_context inst; + + decode_stage(core &c); + + void clock(); +}; + +struct core { + iomodel &system; + funcchecker checker; + funcmem mem; + + infra::port fetch_bundlep; + std::optional fetch_restarto; + + // Construction order is execution order within a cycle, so this list should be back-to-front (for zero-cycle restarts) + decode_stage decode{*this}; + fetch_stage fetch{*this}; + + core(iomodel &model) + : system(model) + , checker(model) + { } +}; -- cgit v1.2.3