#include #include "isa/isa.h" instruction_context decode(unsigned int dfifb, unsigned int pc, unsigned int bits, bool interrupt) { auto df = dfifb >> 3; auto ifb = dfifb & 00007; instruction_context inst; inst.next_pc = (pc & ~07777) | ((pc + 1) & 07777); if (interrupt) { bits = 04000; assert(df == 0); assert(ifb == 0); inst.next_pc = pc; } switch (bits >> 9) { case 0: // AND inst.need_exec_load = true; inst.need_read_acc = true; inst.need_write_acc = true; inst.ef = [](auto &ctx) { ctx.acc = ctx.acc.value() & ctx.data.value(); }; break; case 1: // TAD inst.need_exec_load = true; inst.need_read_acc = true; inst.need_read_link = true; inst.need_write_acc = true; inst.need_write_link = true; inst.ef = [](auto &ctx) { unsigned int sum = (ctx.link.value() << 12) + ctx.acc.value() + ctx.data.value(); ctx.link = (sum >> 12) & 1; ctx.acc = sum & 07777; }; break; case 2: // ISZ inst.need_exec_load = true; inst.need_exec_store = true; inst.possibly_redirects = true; inst.ef = [](auto &ctx) { ctx.data = (ctx.data.value() + 1) & 07777; if (*ctx.data) ctx.next_pc = (ctx.next_pc & ~07777) | ((ctx.next_pc + 1) & 07777); }; break; case 3: // DCA inst.need_read_acc = true; inst.need_write_acc = true; inst.need_exec_store = true; inst.ef = [](auto &ctx) { ctx.data = ctx.acc.value(); ctx.acc = 0; }; break; case 4: // JMS inst.need_exec_store = true; inst.possibly_redirects = true; inst.ef = [ifb](auto &ctx) { ctx.data = ctx.next_pc; ctx.next_pc = (ifb << 12) | ((ctx.final_address.value() + 1) & 07777); }; break; case 5: // JMP inst.possibly_redirects = true; inst.ef = [ifb](auto &ctx) { ctx.next_pc = (ifb << 12) | (ctx.final_address.value() & 07777); }; break; case 6: // IOT inst.ef = [](auto &ctx) { assert(false); }; break; case 7: // OPR if ((bits & 0400) == 0000) { bool cla = bits & 0200; bool cll = bits & 0100; bool cma = bits & 0040; bool cml = bits & 0020; bool rar = bits & 0010; bool ral = bits & 0004; bool bsw = bits & 0002; bool iac = bits & 0001; inst.need_read_acc = cma || rar || ral || bsw || iac; 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.ef = [cla, cll, cma, cml, rar, ral, bsw, iac](auto &ctx) { if (cla) ctx.acc = 0; if (cll) ctx.link = 0; if (cma) ctx.acc = ~ctx.acc.value(); if (cml) ctx.link = !ctx.link.value(); if (iac) { if (++ctx.acc.value() == 0) ctx.link = !ctx.link.value(); } if (rar && !ral) { unsigned int x = (ctx.link.value() << 12) | ctx.acc.value(); x = (x >> 1) | ((x & 1) << 12); if (bsw) x = (x >> 1) | ((x & 1) << 12); ctx.link = x >> 12; ctx.acc = x & 07777; } if (ral && !rar) { unsigned int x = (ctx.link.value() << 12) | ctx.acc.value(); x = ((x << 1) & 07777) | (x >> 12); if (bsw) x = ((x << 1) & 07777) | (x >> 12); ctx.link = x >> 12; ctx.acc = x & 07777; } if (bsw && !(rar || ral)) ctx.acc = ((ctx.acc.value() & 00077) << 6) | (ctx.acc.value() >> 6); }; } else if ((bits & 0411) == 0400) { bool cla = bits & 0200; bool sma = bits & 0100; bool sza = bits & 0040; bool snl = bits & 0020; bool osr = bits & 0004; bool hlt = bits & 0002; inst.need_read_acc = sma || sza; inst.need_read_link = snl; inst.need_write_acc = cla; if (hlt) inst.write_ctlreg = HALTED; inst.possibly_redirects = true; inst.ef = [cla, sma, sza, snl, osr, hlt](auto &ctx) { bool skip = false; if (sma && (ctx.acc.value() & 04000)) skip = true; if (sza && (ctx.acc.value() == 0)) skip = true; if (snl && ctx.link.value()) skip = true; if (cla) ctx.acc = 0; assert(!osr); if (hlt) ctx.ctlval = 1; if (skip) ctx.next_pc = (ctx.next_pc & 070000) | ((ctx.next_pc + 1) & 007777); }; } else if ((bits & 0411) == 0410) { bool cla = bits & 0200; bool spa = bits & 0100; bool sna = bits & 0040; bool szl = bits & 0020; bool osr = bits & 0004; bool hlt = bits & 0002; inst.need_read_acc = spa || sna; inst.need_read_link = szl; inst.need_write_acc = cla; if (hlt) inst.write_ctlreg = HALTED; inst.possibly_redirects = true; inst.ef = [cla, spa, sna, szl, osr, hlt](auto &ctx) { bool skip = true; if (spa && (ctx.acc.value() & 04000)) skip = false; if (sna && (ctx.acc.value() == 0)) skip = false; if (szl && ctx.link.value()) skip = false; if (cla) ctx.acc = 0; assert(!osr); if (hlt) ctx.ctlval = 1; if (skip) ctx.next_pc = (ctx.next_pc & 070000) | ((ctx.next_pc + 1) & 007777); }; } else if ((bits & 0401) == 0401) { bool cla = bits & 0200; bool mqa = bits & 0100; bool mql = bits & 0020; bool extended_arith = bits & 0056; inst.need_read_acc = mqa || mql; inst.need_read_mq = mqa; inst.need_write_acc = cla || mqa; inst.need_write_mq = mql; inst.ef = [cla, mqa, mql, extended_arith](auto &ctx) { assert(!extended_arith); if (cla) ctx.acc = 0; auto new_acc = ctx.acc; auto new_mq = ctx.mq; if (mqa) new_acc = ctx.acc.value() | ctx.mq.value(); if (mql) new_mq = ctx.acc.value(); ctx.acc = new_acc; ctx.mq = new_mq; }; } else { assert(false); } break; } // Instructions with memory operands may be direct or indirect if (inst.need_exec_load || inst.need_exec_store || inst.possibly_redirects) { auto addr = (df << 12) | ((bits & 00200) ? (inst.next_pc & 07600) : 0) | (bits & 00177); if (bits & 00400) { inst.need_indirect_load = true; inst.init_address = addr; } else { inst.final_address = addr; } } // Non-jump indirect memory operands may be autoincrementing depending on operand bits if (!inst.possibly_redirects && inst.need_indirect_load && ((bits & 00170) == 00010)) inst.need_autoinc_store = true; return inst; }