#ifndef MICROCODELONG_HPP #define MICROCODELONG_HPP #include "instructions.hpp" #define KBLIB_DEF_MACROS 1 #include namespace mc_long { struct record_field { u64 _data; BITFIELD(0u, 5, rsrc, _data) // 0-3: A-D BITFIELD(5u, 2, rdest, _data) BITFIELD(7u, 1, rindexed, _data) BITFIELD(0u, 8, r, _data) BITFIELD(0u, 2, wsrc, _data) BITFIELD(2u, 5, wdest, _data) BITFIELD(0u, 7, w, _data) BITFIELD(0u, 1, Do_RW, _data) BITFIELD(1u, 2, RW_src, _data) BITFIELD(3u, 2, RW_dest, _data) BITFIELD(0u, 5, RW, _data) enum act : decltype(_data) { nil = 0, // input // registers rr0 = set_rsrc_v<0>, rr1 = set_rsrc_v<1>, rr2 = set_rsrc_v<2>, rr3 = set_rsrc_v<3>, rr4 = set_rsrc_v<4>, rr5 = set_rsrc_v<5>, rr6 = set_rsrc_v<6>, rr7 = set_rsrc_v<7>, rr8 = set_rsrc_v<8>, rr9 = set_rsrc_v<9>, rr10 = set_rsrc_v<10>, rr11 = set_rsrc_v<11>, rr12 = set_rsrc_v<12>, rr13 = set_rsrc_v<13>, rr14 = set_rsrc_v<14>, rr15 = set_rsrc_v<15>, // stacks rPS = set_rsrc_v<16>, rHS = set_rsrc_v<17>, rCS = set_rsrc_v<18>, rNS = set_rsrc_v<19>, // operands rL = set_rsrc_v<20>, rR = set_rsrc_v<21>, // nothing (?) rsA = set_rsrc_v<22>, // internal registers rA = set_rdest_v<0>, rB = set_rdest_v<1>, rC = set_rdest_v<2>, rD = set_rdest_v<3>, rno = rsA | rA, ri = set_rindexed_v<1>, // output // internal registers wA = set_wsrc_v<0>, wB = set_wsrc_v<1>, wC = set_wsrc_v<2>, wD = set_wsrc_v<3>, // registers wr0 = set_wdest_v<0>, wr1 = set_wdest_v<1>, wr2 = set_wdest_v<2>, wr3 = set_wdest_v<3>, wr4 = set_wdest_v<4>, wr5 = set_wdest_v<5>, wr6 = set_wdest_v<6>, wr7 = set_wdest_v<7>, wr8 = set_wdest_v<8>, wr9 = set_wdest_v<9>, wr10 = set_wdest_v<10>, wr11 = set_wdest_v<11>, wr12 = set_wdest_v<12>, wr13 = set_wdest_v<13>, wr14 = set_wdest_v<14>, wr15 = set_wdest_v<15>, // stacks wPS = set_wdest_v<16>, wHS = set_wdest_v<17>, wCS = set_wdest_v<18>, wNS = set_wdest_v<19>, // operands wL = set_wdest_v<20>, wR = set_wdest_v<21>, // nothing (?) wsA = set_wdest_v<22>, wno = 0, // RW do_RW = set_Do_RW_v<1>, RWno = 0, // address selector RWsA = set_RW_src_v<0>, RWsB = set_RW_src_v<1>, RWsC = set_RW_src_v<2>, RWsD = set_RW_src_v<3>, // internal register destination RWdA = set_RW_dest_v<0>, RWdB = set_RW_dest_v<1>, RWdC = set_RW_dest_v<2>, RWdD = set_RW_dest_v<3>, RWAA = do_RW | RWsA | RWdA, RWAB = do_RW | RWsA | RWdB, RWAC = do_RW | RWsA | RWdC, RWAD = do_RW | RWsA | RWdD, RWBA = do_RW | RWsB | RWdA, RWBB = do_RW | RWsB | RWdB, RWBC = do_RW | RWsB | RWdC, RWBD = do_RW | RWsB | RWdD, RWCA = do_RW | RWsC | RWdA, RWCB = do_RW | RWsC | RWdB, RWCC = do_RW | RWsC | RWdC, RWCD = do_RW | RWsC | RWdD, RWDA = do_RW | RWsD | RWdA, RWDB = do_RW | RWsD | RWdB, RWDC = do_RW | RWsD | RWdC, RWDD = do_RW | RWsD | RWdD, }; }; struct instruction_record { struct subcycle { u64 _data; // 0-15: r0-r15 // 16-18: stack, hstack, cstack // 19: no effect // 20-21: L, R operands // 22-31: no effect BITFIELD(0u, 5, r1src, _data) // 0-3: A-D BITFIELD(5u, 2, r1dest, _data) BITFIELD(7u, 1, r1indexed, _data) BITFIELD(0u, 8, r1, _data) BITFIELD(8u, 5, r2src, _data) BITFIELD(13u, 2, r2dest, _data) BITFIELD(15u, 1, r2indexed, _data) BITFIELD(8u, 8, r2, _data) BITFIELD(16u, 1, do_read, _data) BITFIELD(17u, 2, read_src, _data) BITFIELD(19u, 2, read_dest, _data) BITFIELD(16u, 5, R, _data) BITFIELD(21u, 8, computation, _data) BITFIELD(29u, 2, w1src, _data) BITFIELD(31u, 5, w1dest, _data) BITFIELD(29u, 7, w1, _data) BITFIELD(36u, 2, w2src, _data) BITFIELD(38u, 5, w2dest, _data) BITFIELD(36u, 7, w2, _data) BITFIELD(43u, 1, do_write, _data) BITFIELD(44u, 2, write_src, _data) BITFIELD(46u, 2, write_dest, _data) BITFIELD(43u, 5, W, _data) BITFIELD(48u, 16, remainder, _data) /* // r1: 4 bits // BITFIELD(0u, 1, read_type1, _data) BITFIELD(1u, 1, indexed1, _data) BITFIELD(2u, 2, dest1, _data) BITFIELD(0u, 2, no_read1, _data) // r2: 4 bits (8) // BITFIELD(4u, 1, read_type2, _data) BITFIELD(5u, 1, indexed2, _data) BITFIELD(6u, 2, dest2, _data) BITFIELD(4u, 2, no_read2, _data) // R: 5 bits (13) BITFIELD(8u, 1, do_read, _data) BITFIELD(9u, 2, read_src, _data) BITFIELD(11u, 2, read_dest, _data) // C: 8 bits (21) BITFIELD(13u, 8, computation, _data) // w1: 3 bits (24) // BITFIELD(21u, 1, write_type1, _data) BITFIELD(22u, 2, src1, _data) // w2: 3 bits (27) // BITFIELD(24u, 1, write_type2, _data) BITFIELD(25u, 2, src2, _data) // W: 5 bits (32) BITFIELD(27u, 1, do_write, _data) BITFIELD(28u, 2, write_src, _data) BITFIELD(30u, 2, write_dest, _data) */ [[nodiscard]] constexpr friend auto operator==(subcycle lhs, subcycle rhs) { return lhs._data == rhs._data; } }; detail::str_type name; private: constexpr static unsigned char subcycle_bits = 2; public: constexpr static unsigned char max_subcycles = 1u << subcycle_bits; unsigned char cyclecount : subcycle_bits; subcycle subcycles[max_subcycles]; [[nodiscard]] constexpr friend auto operator==(const instruction_record& lhs, const instruction_record& rhs) -> bool { return lhs.name == rhs.name and lhs.cyclecount == rhs.cyclecount and kblib::equal(lhs.subcycles, lhs.subcycles + lhs.cyclecount, rhs.subcycles); } }; namespace actions { using ISC = instruction_record::subcycle; enum act : decltype(ISC::_data) { nil = 0, // nothing (?) r1sA = ISC::set_r1src_v<22>, // registers r1r0 = ISC::set_r1src_v<0>, r1r1 = ISC::set_r1src_v<1>, r1r2 = ISC::set_r1src_v<2>, r1r3 = ISC::set_r1src_v<3>, r1r4 = ISC::set_r1src_v<4>, r1r5 = ISC::set_r1src_v<5>, r1r6 = ISC::set_r1src_v<6>, r1r7 = ISC::set_r1src_v<7>, r1r8 = ISC::set_r1src_v<8>, r1r9 = ISC::set_r1src_v<9>, r1r10 = ISC::set_r1src_v<10>, r1r11 = ISC::set_r1src_v<11>, r1r12 = ISC::set_r1src_v<12>, r1r13 = ISC::set_r1src_v<13>, r1r14 = ISC::set_r1src_v<14>, r1r15 = ISC::set_r1src_v<15>, // stacks r1PS = ISC::set_r1src_v<16>, r1HS = ISC::set_r1src_v<17>, r1CS = ISC::set_r1src_v<18>, r1NS = ISC::set_r1src_v<19>, // operands r1L = ISC::set_r1src_v<20>, r1R = ISC::set_r1src_v<21>, // internal registers r1A = ISC::set_r1dest_v<0>, r1B = ISC::set_r1dest_v<1>, r1C = ISC::set_r1dest_v<2>, r1D = ISC::set_r1dest_v<3>, r1no = r1sA | r1A, r1i = ISC::set_r1indexed_v<1>, r2r0 = ISC::set_r2src_v<0>, r2r1 = ISC::set_r2src_v<1>, r2r2 = ISC::set_r2src_v<2>, r2r3 = ISC::set_r2src_v<3>, r2r4 = ISC::set_r2src_v<4>, r2r5 = ISC::set_r2src_v<5>, r2r6 = ISC::set_r2src_v<6>, r2r7 = ISC::set_r2src_v<7>, r2r8 = ISC::set_r2src_v<8>, r2r9 = ISC::set_r2src_v<9>, r2r10 = ISC::set_r2src_v<10>, r2r11 = ISC::set_r2src_v<11>, r2r12 = ISC::set_r2src_v<12>, r2r13 = ISC::set_r2src_v<13>, r2r14 = ISC::set_r2src_v<14>, r2r15 = ISC::set_r2src_v<15>, r2PS = ISC::set_r2src_v<16>, r2HS = ISC::set_r2src_v<17>, r2CS = ISC::set_r2src_v<18>, r2NS = ISC::set_r2src_v<19>, r2L = ISC::set_r2src_v<20>, r2R = ISC::set_r2src_v<21>, r2sA = ISC::set_r2src_v<22>, r2A = ISC::set_r2dest_v<0>, r2B = ISC::set_r2dest_v<1>, r2C = ISC::set_r2dest_v<2>, r2D = ISC::set_r2dest_v<3>, r2no = r2sA | r2A, r2i = ISC::set_r2indexed_v<1>, // reading from memory R = ISC::set_do_read_v<1>, Rno = 0, // address selector RsA = ISC::set_read_src_v<0>, RsB = ISC::set_read_src_v<1>, RsC = ISC::set_read_src_v<2>, RsD = ISC::set_read_src_v<3>, // internal register destination RdA = ISC::set_read_dest_v<0>, RdB = ISC::set_read_dest_v<1>, RdC = ISC::set_read_dest_v<2>, RdD = ISC::set_read_dest_v<3>, RAA = R | RsA | RdA, RAB = R | RsA | RdB, RAC = R | RsA | RdC, RAD = R | RsA | RdD, RBA = R | RsB | RdA, RBB = R | RsB | RdB, RBC = R | RsB | RdC, RBD = R | RsB | RdD, RCA = R | RsC | RdA, RCB = R | RsC | RdB, RCC = R | RsC | RdC, RCD = R | RsC | RdD, RDA = R | RsD | RdA, RDB = R | RsD | RdB, RDC = R | RsD | RdC, RDD = R | RsD | RdD, // complex computations Cno = ISC::set_computation_v<0>, // output // internal registers w1A = ISC::set_w1src_v<0>, w1B = ISC::set_w1src_v<1>, w1C = ISC::set_w1src_v<2>, w1D = ISC::set_w1src_v<3>, // registers w1r0 = ISC::set_w1dest_v<0>, w1r1 = ISC::set_w1dest_v<1>, w1r2 = ISC::set_w1dest_v<2>, w1r3 = ISC::set_w1dest_v<3>, w1r4 = ISC::set_w1dest_v<4>, w1r5 = ISC::set_w1dest_v<5>, w1r6 = ISC::set_w1dest_v<6>, w1r7 = ISC::set_w1dest_v<7>, w1r8 = ISC::set_w1dest_v<8>, w1r9 = ISC::set_w1dest_v<9>, w1r10 = ISC::set_w1dest_v<10>, w1r11 = ISC::set_w1dest_v<11>, w1r12 = ISC::set_w1dest_v<12>, w1r13 = ISC::set_w1dest_v<13>, w1r14 = ISC::set_w1dest_v<14>, w1r15 = ISC::set_w1dest_v<15>, // stacks w1PS = ISC::set_w1dest_v<16>, w1HS = ISC::set_w1dest_v<17>, w1CS = ISC::set_w1dest_v<18>, w1NS = ISC::set_w1dest_v<19>, // operands w1L = ISC::set_w1dest_v<20>, w1R = ISC::set_w1dest_v<21>, // nothing (?) w1sA = ISC::set_w1dest_v<22>, w1no = 0, w2A = ISC::set_w2src_v<0>, w2B = ISC::set_w2src_v<1>, w2C = ISC::set_w2src_v<2>, w2D = ISC::set_w2src_v<3>, w2r0 = ISC::set_w2dest_v<0>, w2r1 = ISC::set_w2dest_v<1>, w2w2 = ISC::set_w2dest_v<2>, w2r3 = ISC::set_w2dest_v<3>, w2r4 = ISC::set_w2dest_v<4>, w2r5 = ISC::set_w2dest_v<5>, w2r6 = ISC::set_w2dest_v<6>, w2r7 = ISC::set_w2dest_v<7>, w2r8 = ISC::set_w2dest_v<8>, w2r9 = ISC::set_w2dest_v<9>, w2r10 = ISC::set_w2dest_v<10>, w2r11 = ISC::set_w2dest_v<11>, w2r12 = ISC::set_w2dest_v<12>, w2r13 = ISC::set_w2dest_v<13>, w2r14 = ISC::set_w2dest_v<14>, w2r15 = ISC::set_w2dest_v<15>, w2PS = ISC::set_w2dest_v<16>, w2HS = ISC::set_w2dest_v<17>, w2CS = ISC::set_w2dest_v<18>, w2NS = ISC::set_w2dest_v<19>, w2L = ISC::set_w2dest_v<20>, w2R = ISC::set_w2dest_v<21>, w2sA = ISC::set_w2dest_v<22>, w2no = 0, // writing to memory W = ISC::set_do_write_v<1>, Wno = 0, // internal register source WsA = ISC::set_write_src_v<0>, WsB = ISC::set_write_src_v<1>, WsC = ISC::set_write_src_v<2>, WsD = ISC::set_write_src_v<3>, // address selector WdA = ISC::set_write_dest_v<0>, WdB = ISC::set_write_dest_v<1>, WdC = ISC::set_write_dest_v<2>, WdD = ISC::set_write_dest_v<3>, WAA = W | WsA | WdA, WAB = W | WsA | WdB, WAC = W | WsA | WdC, WAD = W | WsA | WdD, WBA = W | WsB | WdA, WBB = W | WsB | WdB, WBC = W | WsB | WdC, WBD = W | WsB | WdD, WCA = W | WsC | WdA, WCB = W | WsC | WdB, WCC = W | WsC | WdC, WCD = W | WsC | WdD, WDA = W | WsD | WdA, WDB = W | WsD | WdB, WDC = W | WsD | WdC, WDD = W | WsD | WdD, }; constexpr act operator|(act lhs, act rhs) { return act(kblib::etoi(lhs) | kblib::etoi(rhs)); } } // namespace actions using computation = void (*)(computer_state& state, unsigned char cycle, const instruction_record& instr); constexpr std::array, 256> computation_table{{ {"NOP", nullptr}, {"INC", // increment with wrapping [](computer_state& state, unsigned char cycle, const instruction_record& instr) { ++state.internal[instr.subcycles[cycle].remainder() % 4]; return; }}, {"DEC", // decrement with wrapping [](computer_state& state, unsigned char cycle, const instruction_record& instr) { --state.internal[instr.subcycles[cycle].remainder() % 4]; return; }}, {"INCS", // increment with saturation [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I = state.internal[instr.subcycles[cycle].remainder() % 4]; if (I != kblib::max) { ++I; } return; }}, {"DECS", // decrement with saturation [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I = state.internal[instr.subcycles[cycle].remainder() % 4]; if (I != kblib::min) { --I; } return; }}, {"SICS", // signed increment with saturation [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I = state.internal[instr.subcycles[cycle].remainder() % 4]; auto s = kblib::signed_cast(I); if (s != kblib::max) { I++; } return; }}, {"SDCS", // signed decrement with saturation [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I = state.internal[instr.subcycles[cycle].remainder() % 4]; auto s = kblib::signed_cast(I); if (s != kblib::min) { I--; } return; }}, {"ADD", [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I1 = state.internal[instr.subcycles[cycle].remainder() % 4]; auto& I2 = state .internal[(instr.subcycles[cycle].remainder() >> 2u) % 4]; auto& O = state .internal[(instr.subcycles[cycle].remainder() >> 4u) % 4]; O = I1 + I2; return; }}, {"SUB", [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I1 = state.internal[instr.subcycles[cycle].remainder() % 4]; auto& I2 = state .internal[(instr.subcycles[cycle].remainder() >> 2u) % 4]; auto& O = state .internal[(instr.subcycles[cycle].remainder() >> 4u) % 4]; O = I1 - I2; return; }}, {"ADDS", [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I1 = state.internal[instr.subcycles[cycle].remainder() % 4]; auto& I2 = state .internal[(instr.subcycles[cycle].remainder() >> 2u) % 4]; auto& O = state .internal[(instr.subcycles[cycle].remainder() >> 4u) % 4]; O = saturating_add(I1, I2); return; }}, {"SUBS", [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I1 = state.internal[instr.subcycles[cycle].remainder() % 4]; auto& I2 = state .internal[(instr.subcycles[cycle].remainder() >> 2u) % 4]; auto& O = state .internal[(instr.subcycles[cycle].remainder() >> 4u) % 4]; O = saturating_add(I1, -I2); return; }}, {"FMA", [](computer_state& state, unsigned char cycle, const instruction_record& instr) { auto& I1 = state.internal[instr.subcycles[cycle].remainder() % 4]; auto& I2 = state .internal[(instr.subcycles[cycle].remainder() >> 2u) % 4]; auto& I3 = state .internal[(instr.subcycles[cycle].remainder() >> 4u) % 4]; auto& O = state .internal[(instr.subcycles[cycle].remainder() >> 6u) % 4]; O = I1 * I2 + I3; return; }}, }}; static_assert(sizeof(instruction_record) == sizeof(u64) * 2 + sizeof(u64) * (instruction_record::max_subcycles)); [[nodiscard]] constexpr auto parse_microcode_name(std::string_view in, std::size_t& read) { decltype(instruction_record::name) ret{}; read = 0; if (in[0] == '"') { auto working = in; working.remove_prefix(1); bool is_escape{}; bool found_colon{}; for (auto i : kblib::range(working.size())) { auto c = working[i]; if (not is_escape and c == '\\') { is_escape = true; } else if (c == '"') { if (i + 1 > ret.size()) { throw "name too long"; } else { kblib::copy_n(working.begin(), i, ret.begin()); working.remove_prefix(i + 1); if (working.empty()) { throw "no data"; } else if (working.front() != ':') { throw "invalid name"; } else { working.remove_prefix(1); found_colon = true; read = in.size() - working.size(); break; } } } } if (not found_colon) { throw "unterminated quotation"; } if (is_escape) { throw "escape at end of string"; } return ret; } else { for (auto i : kblib::range(in.size())) { if (in[i] != ':') { ret[i] = in[i]; } else { read = i + 1; // +1 for colon return ret; } } } return ret; } template constexpr inline auto get_iospec_elem(std::string_view in, std::size_t& read) -> std::string_view { std::size_t prefix_len{}; bool found_text{}; for (auto [c, i] : kblib::enumerate(in)) { if (not found_text and kblib::isAspace(c)) { ++prefix_len; } if (c == ',') { read = i + 1; return in.substr(prefix_len, i - prefix_len); } else if (c == ';') { throw "invalid iospec"; } } throw "no terminator"; } [[nodiscard]] constexpr auto parse_microcode_iospec(std::string_view in, std::size_t& read, bool& term) -> actions::act { auto working = [&] { std::size_t prefix_len{}; bool found_text{}; for (auto [c, i] : kblib::enumerate(in)) { if (not found_text and kblib::isAspace(c)) { ++prefix_len; } if (c == ';' or c == ',') { read = i + 1; term = (c == ';'); return in.substr(prefix_len, i - prefix_len); } } throw "no terminator"; }(); constexpr std::pair table[]{ {"-", actions::act::nil}, {"r1r0", actions::act::r1r0}, {"r1r1", actions::act::r1r1}, {"r1r2", actions::act::r1r2}, {"r1r3", actions::act::r1r3}, {"r1r4", actions::act::r1r4}, {"r1r5", actions::act::r1r5}, {"r1r6", actions::act::r1r6}, {"r1r7", actions::act::r1r7}, {"r1r8", actions::act::r1r8}, {"r1r9", actions::act::r1r9}, {"r1r10", actions::act::r1r10}, {"r1r11", actions::act::r1r11}, {"r1r12", actions::act::r1r12}, {"r1r13", actions::act::r1r13}, {"r1r14", actions::act::r1r14}, {"r1r15", actions::act::r1r15}, {"r1PS", actions::act::r1PS}, {"r1HS", actions::act::r1HS}, {"r1CS", actions::act::r1CS}, {"r1NS", actions::act::r1NS}, {"r1L", actions::act::r1L}, {"r1R", actions::act::r1R}, {"r1sA", actions::act::r1sA}, {"r1A", actions::act::r1A}, {"r1B", actions::act::r1B}, {"r1C", actions::act::r1C}, {"r1D", actions::act::r1D}, {"r1no", actions::act::r1no}, {"r1i", actions::act::r1i}, {"r2r0", actions::act::r2r0}, {"r2r1", actions::act::r2r1}, {"r2r2", actions::act::r2r2}, {"r2r3", actions::act::r2r3}, {"r2r4", actions::act::r2r4}, {"r2r5", actions::act::r2r5}, {"r2r6", actions::act::r2r6}, {"r2r7", actions::act::r2r7}, {"r2r8", actions::act::r2r8}, {"r2r9", actions::act::r2r9}, {"r2r10", actions::act::r2r10}, {"r2r11", actions::act::r2r11}, {"r2r12", actions::act::r2r12}, {"r2r13", actions::act::r2r13}, {"r2r14", actions::act::r2r14}, {"r2r15", actions::act::r2r15}, {"r2PS", actions::act::r2PS}, {"r2HS", actions::act::r2HS}, {"r2CS", actions::act::r2CS}, {"r2NS", actions::act::r2NS}, {"r2L", actions::act::r2L}, {"r2R", actions::act::r2R}, {"r2sA", actions::act::r2sA}, {"r2A", actions::act::r2A}, {"r2B", actions::act::r2B}, {"r2C", actions::act::r2C}, {"r2D", actions::act::r2D}, {"r2no", actions::act::r2no}, {"r2i", actions::act::r2i}, {"R", actions::act::R}, {"RsA", actions::act::RsA}, {"RsB", actions::act::RsB}, {"RsC", actions::act::RsC}, {"RsD", actions::act::RsD}, {"RdA", actions::act::RdA}, {"RdB", actions::act::RdB}, {"RdC", actions::act::RdC}, {"RdD", actions::act::RdD}, {"RAA", actions::act::RAA}, {"RAB", actions::act::RAB}, {"RAC", actions::act::RAC}, {"RAD", actions::act::RAD}, {"RBA", actions::act::RBA}, {"RBB", actions::act::RBB}, {"RBC", actions::act::RBC}, {"RBD", actions::act::RBD}, {"RCA", actions::act::RCA}, {"RCB", actions::act::RCB}, {"RCC", actions::act::RCC}, {"RCD", actions::act::RCD}, {"RDA", actions::act::RDA}, {"RDB", actions::act::RDB}, {"RDC", actions::act::RDC}, {"RDD", actions::act::RDD}, {"Cno", actions::act::Cno}, {"w1A", actions::act::w1A}, {"w1B", actions::act::w1B}, {"w1C", actions::act::w1C}, {"w1D", actions::act::w1D}, {"w1r0", actions::act::w1r0}, {"w1r1", actions::act::w1r1}, {"w1r2", actions::act::w1r2}, {"w1r3", actions::act::w1r3}, {"w1r4", actions::act::w1r4}, {"w1r5", actions::act::w1r5}, {"w1r6", actions::act::w1r6}, {"w1r7", actions::act::w1r7}, {"w1r8", actions::act::w1r8}, {"w1r9", actions::act::w1r9}, {"w1r10", actions::act::w1r10}, {"w1r11", actions::act::w1r11}, {"w1r12", actions::act::w1r12}, {"w1r13", actions::act::w1r13}, {"w1r14", actions::act::w1r14}, {"w1r15", actions::act::w1r15}, {"w1PS", actions::act::w1PS}, {"w1HS", actions::act::w1HS}, {"w1CS", actions::act::w1CS}, {"w1NS", actions::act::w1NS}, {"w1L", actions::act::w1L}, {"w1R", actions::act::w1R}, {"w1sA", actions::act::w1sA}, {"w2A", actions::act::w2A}, {"w2B", actions::act::w2B}, {"w2C", actions::act::w2C}, {"w2D", actions::act::w2D}, {"w2r0", actions::act::w2r0}, {"w2r1", actions::act::w2r1}, {"w2w2", actions::act::w2w2}, {"w2r3", actions::act::w2r3}, {"w2r4", actions::act::w2r4}, {"w2r5", actions::act::w2r5}, {"w2r6", actions::act::w2r6}, {"w2r7", actions::act::w2r7}, {"w2r8", actions::act::w2r8}, {"w2r9", actions::act::w2r9}, {"w2r10", actions::act::w2r10}, {"w2r11", actions::act::w2r11}, {"w2r12", actions::act::w2r12}, {"w2r13", actions::act::w2r13}, {"w2r14", actions::act::w2r14}, {"w2r15", actions::act::w2r15}, {"w2PS", actions::act::w2PS}, {"w2HS", actions::act::w2HS}, {"w2CS", actions::act::w2CS}, {"w2NS", actions::act::w2NS}, {"w2L", actions::act::w2L}, {"w2R", actions::act::w2R}, {"w2sA", actions::act::w2sA}, {"W", actions::act::W}, {"WsA", actions::act::WsA}, {"WsB", actions::act::WsB}, {"WsC", actions::act::WsC}, {"WsD", actions::act::WsD}, {"WdA", actions::act::WdA}, {"WdB", actions::act::WdB}, {"WdC", actions::act::WdC}, {"WdD", actions::act::WdD}, {"WAA", actions::act::WAA}, {"WAB", actions::act::WAB}, {"WAC", actions::act::WAC}, {"WAD", actions::act::WAD}, {"WBA", actions::act::WBA}, {"WBB", actions::act::WBB}, {"WBC", actions::act::WBC}, {"WBD", actions::act::WBD}, {"WCA", actions::act::WCA}, {"WCB", actions::act::WCB}, {"WCC", actions::act::WCC}, {"WCD", actions::act::WCD}, {"WDA", actions::act::WDA}, {"WDB", actions::act::WDB}, {"WDC", actions::act::WDC}, {"WDD", actions::act::WDD}, }; const auto key_comp = [&](auto& el) { return el.first == working; }; if (working.starts_with("!")) { auto comp = kblib::find_if(computation_table.begin(), computation_table.end(), key_comp); if (comp != computation_table.end()) { return actions::act{ actions::ISC{}.computation(comp - computation_table.begin())}; } } else if (auto el = kblib::find_if(std::begin(table), std::end(table), key_comp); el != std::end(table)) { return el->second; } throw "invalid iospec"; } template [[nodiscard]] constexpr auto generic_parser(auto& table, std::string_view in, std::size_t& read) -> actions::act { const std::size_t initial_size = in.size(); std::size_t shift_amount = -1; if (in.starts_with(A)) { shift_amount = shift_A; } else if (in.starts_with(B)) { shift_amount = shift_B; } else { throw "invalid iospec"; } in.remove_prefix(1); record_field r{}; while (not in.empty()) { if (in.starts_with(' ')) { in.remove_prefix(1); continue; } else if (in.starts_with(',') or in.starts_with(';')) { in.remove_prefix(1); break; } [&r, &table](std::string_view& in) { for (auto& f : table) { if (in.starts_with(f.first)) { in.remove_prefix(f.first.size()); r.r(r.r() | f.second); return; } } throw "invalid iospec"; }(in); } read += initial_size - in.size(); return actions::act{r._data << shift_amount}; } [[nodiscard]] constexpr auto parse_microcode_iospec_c(std::string_view in, std::size_t& read) -> actions::act { if (in.empty()) { return actions::act::nil; } else { constexpr std::pair read_table[]{ {"-", record_field::act::rno}, {"r0", record_field::act::rr0}, {"r1", record_field::act::rr1}, {"r2", record_field::act::rr2}, {"r3", record_field::act::rr3}, {"r4", record_field::act::rr4}, {"r5", record_field::act::rr5}, {"r6", record_field::act::rr6}, {"r7", record_field::act::rr7}, {"r8", record_field::act::rr8}, {"r9", record_field::act::rr9}, {"r10", record_field::act::rr10}, {"r11", record_field::act::rr11}, {"r12", record_field::act::rr12}, {"r13", record_field::act::rr13}, {"r14", record_field::act::rr14}, {"r15", record_field::act::rr15}, {"P", record_field::act::rPS}, {"H", record_field::act::rHS}, {"C", record_field::act::rCS}, {"N", record_field::act::rNS}, {"L", record_field::act::rL}, {"R", record_field::act::rR}, {"A", record_field::act::rA}, {"B", record_field::act::rB}, {"C", record_field::act::rC}, {"D", record_field::act::rD}, {"sA", record_field::act::rsA}, {"no", record_field::act::rno}, {"i", record_field::act::ri}, }; constexpr std::pair write_table[]{ {"-", record_field::act::wno}, {"A", record_field::act::wA}, {"B", record_field::act::wB}, {"C", record_field::act::wC}, {"D", record_field::act::wD}, {"r0", record_field::act::wr0}, {"r1", record_field::act::wr1}, {"r2", record_field::act::wr2}, {"r3", record_field::act::wr3}, {"r4", record_field::act::wr4}, {"r5", record_field::act::wr5}, {"r6", record_field::act::wr6}, {"r7", record_field::act::wr7}, {"r8", record_field::act::wr8}, {"r9", record_field::act::wr9}, {"r10", record_field::act::wr10}, {"r11", record_field::act::wr11}, {"r12", record_field::act::wr12}, {"r13", record_field::act::wr13}, {"r14", record_field::act::wr14}, {"r15", record_field::act::wr15}, {"P", record_field::act::wPS}, {"H", record_field::act::wHS}, {"C", record_field::act::wCS}, {"N", record_field::act::wNS}, {"L", record_field::act::wL}, {"R", record_field::act::wR}, {"sA", record_field::act::wsA}, {"no", record_field::act::wno}, }; constexpr std::pair RW_table[]{ {"-", record_field::act::RWno}, {"no", record_field::act::RWno}, {"sA", record_field::act::RWsA}, {"sB", record_field::act::RWsB}, {"sC", record_field::act::RWsC}, {"sD", record_field::act::RWsD}, {"dA", record_field::act::RWdA}, {"dB", record_field::act::RWdB}, {"dC", record_field::act::RWdC}, {"dD", record_field::act::RWdD}, {"AA", record_field::act::RWAA}, {"AB", record_field::act::RWAB}, {"AC", record_field::act::RWAC}, {"AD", record_field::act::RWAD}, {"BA", record_field::act::RWBA}, {"BB", record_field::act::RWBB}, {"BC", record_field::act::RWBC}, {"BD", record_field::act::RWBD}, {"CA", record_field::act::RWCA}, {"CB", record_field::act::RWCB}, {"CC", record_field::act::RWCC}, {"CD", record_field::act::RWCD}, {"DA", record_field::act::RWDA}, {"DB", record_field::act::RWDB}, {"DC", record_field::act::RWDC}, {"DD", record_field::act::RWDD}, }; switch (in.front()) { case 'r': in.remove_prefix(1); read += 1; return actions::act{ generic_parser<'1', instruction_record::subcycle::r1_shift_v, '2', instruction_record::subcycle::r2_shift_v>( read_table, in, read)}; break; case 'w': in.remove_prefix(1); read += 1; return actions::act{ generic_parser<'1', instruction_record::subcycle::w1_shift_v, '2', instruction_record::subcycle::w2_shift_v>( write_table, in, read)}; break; case 'R': case 'W': return actions::act{ generic_parser<'R', instruction_record::subcycle::R_shift_v, 'W', instruction_record::subcycle::W_shift_v>(RW_table, in, read)}; break; case 'C': in.remove_prefix(1); read += 1; if (in.starts_with('!')) { in.remove_prefix(1); read += 1; const auto key_comp = [&](auto& el) { return in == el.first; }; auto comp = kblib::find_if(computation_table.begin(), computation_table.end(), key_comp); if (comp != computation_table.end()) { return actions::act{actions::ISC{}.computation( comp - computation_table.begin())}; } else { throw "invalid C name"; } } else { read += in.size(); return actions::act::Cno; } break; default: throw "invalid iospec"; } } } [[nodiscard]] constexpr auto parse_microcode_iospec_c(std::string_view in) { std::size_t read{}; return parse_microcode_iospec_c(in, read); } static_assert(parse_microcode_iospec_c("r1R,") == actions::act::r1R); static_assert(parse_microcode_iospec_c("r1A,") == actions::act::r1A); static_assert(parse_microcode_iospec_c("r1i,") == actions::act::r1i); static_assert(parse_microcode_iospec_c("r2L,") == actions::act::r2L); static_assert(parse_microcode_iospec_c("r2B,") == actions::act::r2B); static_assert(parse_microcode_iospec_c("r2i,") == actions::act::r2i); static_assert(parse_microcode_iospec_c("RAA,") == actions::act::RAA); static_assert(parse_microcode_iospec_c("WBA,") == actions::act::WBA); [[nodiscard]] constexpr auto wrap_parse_microcode_iospec(std::string_view in) { std::size_t read{}; bool term{}; return parse_microcode_iospec(in, read, term); } static_assert(wrap_parse_microcode_iospec("-,") == actions::act::nil); static_assert(wrap_parse_microcode_iospec("r1R,") == actions::act::r1R); static_assert(wrap_parse_microcode_iospec("r1A,") == actions::act::r1A); static_assert(wrap_parse_microcode_iospec("r1i,") == actions::act::r1i); static_assert(wrap_parse_microcode_iospec("r2L,") == actions::act::r2L); static_assert(wrap_parse_microcode_iospec("r2B,") == actions::act::r2B); static_assert(wrap_parse_microcode_iospec("r2i,") == actions::act::r2i); static_assert(wrap_parse_microcode_iospec("RAA,") == actions::act::RAA); static_assert(wrap_parse_microcode_iospec("WBA;") == actions::act::WBA); static_assert(wrap_parse_microcode_iospec(" -,") == actions::act::nil); [[nodiscard]] constexpr auto remove_leading_ws(std::string_view in) -> std::string_view { using namespace std::literals; if (in.empty()) { return in; } while (" \r\n\t\v"sv.find(in.front()) != std::string_view::npos) { in.remove_prefix(1); } return in; } [[nodiscard]] constexpr auto parse_microcode_spec(std::string_view in) -> instruction_record { instruction_record instr{}; // format: "name":r1,r2,R,C,w1,w2,W; if (in.empty()) { return instr; } else { { in = remove_leading_ws(in); std::size_t read{}; instr.name = parse_microcode_name(in, read); in.remove_prefix(read); } for (auto& subcycle : instr.subcycles) { do { in = remove_leading_ws(in); if (in.empty()) { throw "unexpected end of spec"; } std::size_t read{}; subcycle._data |= parse_microcode_iospec_c( in.substr(0, in.find_first_of(",;")), read); in.remove_prefix(read); if (in.starts_with(';')) { in.remove_prefix(1); break; } if (in.starts_with(',')) { in.remove_prefix(1); } } while (not in.empty()); ++instr.cyclecount; in = remove_leading_ws(in); if (in.empty()) { break; } } } return instr; } // R = register; F = register adjusted; O = indexed register; S = any stack alignas(alignof(std::max_align_t)) constexpr instruction_record instr_table[]{ {detail::str("nop"), 0, {}}, parse_microcode_spec(R"("SET 00": r1, r2RA, w1AL;)"), parse_microcode_spec(R"("SET 01": r1, r2RAi, w1AL;)"), parse_microcode_spec(R"("SET 02": r1, r2RA, RAA, w1AL;)"), parse_microcode_spec(R"("SET 03": r1, r2RAi, RAA, w1AL;)"), parse_microcode_spec(R"("SET 20": r1RA, r2LA, WBA;)"), parse_microcode_spec(R"("SET 21": r1RAi, r2LA, WBA;)"), parse_microcode_spec(R"("SET 22": r1RA, r2LA, RAA, WBA;)"), parse_microcode_spec(R"("SET 23": r1RAi, r2LA, RAA, WBA;)"), parse_microcode_spec(R"("SET 30": r1RA, r2LBi, WBA;)"), parse_microcode_spec(R"("SET 31": r1RAi, r2LBi, WBA;)"), parse_microcode_spec(R"("SET 32": r1RA, r2LBi, RAA, WBA;)"), parse_microcode_spec(R"("SET 33": r1RAi, r2LBi, RAA, WBA;)"), parse_microcode_spec(R"("SWAP 00": r1RA,r2LB,w1AL,w2BR;)"), parse_microcode_spec(R"("SWAP 02": r1RA,r2LB,RAC,w1CL,WBA;)"), parse_microcode_spec(R"("SWAP 03": r1RAi,r2LB,RAC,w1CL,WBA;)"), parse_microcode_spec(R"("SWAP 22": r1RA,r2LB,RAC; r1no,r2no,RBD,WCB; r1no,r2no,WDA; )"), parse_microcode_spec(R"("SWAP 23": r1RAi,r2LB,RAC; r1no,r2no,RBD,WCB; r1no,r2no,WDA; )"), parse_microcode_spec(R"("SWAP 33": r1RAi,r2LBi,RAC; r1no,r2no,RBD,WCB; r1no,r2no,WDA; )"), parse_microcode_spec(R"("XCHG 00": r1LA,r2RB,w1AP,w2BL;)"), parse_microcode_spec(R"("XCHG 01": r1LA,r2RBi,w1AP,w2BL;)"), parse_microcode_spec(R"("XCHG 02": ;)"), parse_microcode_spec(R"("XCHG 03": ;)"), }; alignas(alignof(std::max_align_t)) constexpr instruction_record instr_table2[]{ {detail::str("nop"), 0, {}}, {detail::str("set00"), 1, { {actions::act::r2R | actions::act::r2A | actions::act::w1A | actions::act::w1L}, }}, {detail::str("set 01"), 1, { {actions::act::r2R | actions::act::r2A | actions::act::r2i | actions::act::w1A | actions::act::w1L}, }}, {detail::str("set 02"), 1, { {actions::act::r2R | actions::act::r2A | actions::act::RAA | actions::act::w1A | actions::act::w1L}, }}, {detail::str("set 03"), 1, { {actions::act::r2R | actions::act::r2A | actions::act::r2i | actions::act::RAA | actions::act::w1A | actions::act::w1L}, }}, {detail::str("set 20"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::WBA}, }}, {detail::str("set 21"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::WBA}, }}, {detail::str("set 30"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::r2i | actions::act::WBA}, }}, {detail::str("set 31"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::r2i | actions::act::WBA}, }}, {detail::str("set 22"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::RAA | actions::act::WBA}, }}, {detail::str("set 23"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::RAA | actions::act::WBA}, }}, {detail::str("set 32"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::r2i | actions::act::RAA | actions::act::WBA}, }}, {detail::str("set 33"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::r2i | actions::act::RAA | actions::act::WBA}, }}, {detail::str("swap 00"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::w1A | actions::act::w1L | actions::act::w2B | actions::act::w2R}, }}, {detail::str("swap 02"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::RAC | actions::act::w1C | actions::act::w1L | actions::act::WBA}, }}, {detail::str("swap 03"), 1, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::RAC | actions::act::w1C | actions::act::w1L | actions::act::WBA}, }}, {detail::str("swap 22"), 3, { {actions::act::r1R | actions::act::r1A | actions::act::r2L | actions::act::r2B | actions::act::RAC}, {actions::act::r1no | actions::act::r2no | actions::act::RBD | actions::act::WCB}, {actions::act::r1no | actions::act::r2no | actions::act::WDA}, }}, {detail::str("swap 23"), 3, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::RAC}, {actions::act::r1no | actions::act::r2no | actions::act::RBD | actions::act::WCB}, {actions::act::r1no | actions::act::r2no | actions::act::WDA}, }}, {detail::str("swap 33"), 3, { {actions::act::r1R | actions::act::r1A | actions::act::r1i | actions::act::r2L | actions::act::r2B | actions::act::r2i | actions::act::RAC}, {actions::act::r1no | actions::act::r2no | actions::act::RBD | actions::act::WCB}, {actions::act::r1no | actions::act::r2no | actions::act::WDA}, }}, }; /* Instructions: addrmode name:number R/F : 0 I : 1 *F : 2 *I : 3 "name":r1,r2,R,C,w1,w2,W; "SET 00": -,RA,-,-,AL,-,-; "SET 01": -,RAi,-,-,AL,-,-; "SET 02": -,RA,AA,-,AL,-,-; "SET 03": -,RAi,AA,-,AL,-,-; "SET 20": RA,LB,-,-,-,-,BA; "SET 21": RAi,LB,-,-,-,-,BA; "SET 30": RA,LBi,-,-,-,-,BA; "SET 31": RAi,LBi,-,-,-,-,BA; "SET 22": RA,LB,AA,-,-,-,BA; "SET 23": RAi,LB,AA,-,-,-,BA; "SET 32": RA,LBi,AA,-,-,-,BA; "SET 33": RAi,LBi,AA,-,-,-,BA; "SWAP 00": RA,LB,-,-,AL,BR,-; "SWAP 02": RA,LB,AC,-,CL,-,BA; "SWAP 03": RAi,LB,AC,-,CL,-,BA; "SWAP 22": RA,LB,AC,-,-,-,-; -,-,BD,-,-,-,CB; -,-,-,-,-,-,DA; "SWAP 23": RAi,LB,AC,-,-,-,-; -,-,BD,-,-,-,CB; -,-,-,-,-,-,DA; "SWAP 33": RAi,LBi,AC,-,-,-,-; -,-,BD,-,-,-,CB; -,-,-,-,-,-,DA; "XCHG 00": LA,RB,-,-,AP,BL,-; "XCHG 01": LA,RBi,-,-,AP,BL,-; "XCHG 02": "XCHG 03": set: R(L) O(i, R, O): 1: r.a: R+(i ? index << 20 | O : SE(O)) -> A r.a: zero -> C R: no C: no w.a: A -> L w.a: no W: no set: R(L) {PH}(R, O): 1: r.b: R+O -> A r.a: no R: no C: no w.a: A -> L w.a: no W: no set: {PH}(L) O(i, R, O): 1: r.a: R+(i ? index << 20 | O : SE(O)) -> A r.a: no R: no C: no w.b: A -> L w.a: no W: no set: {PH}(L) {PH}(R, O) 1: r.b: R+O -> A r.a: no R: no C: no w.b: A -> L w.a: no W: no set: R(L) *O(i, R, O): 1: r.a: R+(i ? index << 20 | O : SE(O)) -> A r.a: no R: (LP = A) *A -> A C: no w.a: A -> L w.a: no W: no set: R(L) *{PH}(R, O): 1: r.b: R+O -> A r.a: no R: (LP = A) *A -> A C: no w.a: A -> L w.a: no W: no set: {PH}(L) *O(i, R, O): 1: r.a: R+(i ? index << 20 | O : SE(O)) -> A r.a: no R: (LP = A) *A -> A C: no w.b: A -> L w.a: no W: no set: {PH}(L) *{PH}(R, O) 1: r.b: R+O -> A r.a: no R: (LP = A) *A -> A C: no w.b: A -> L w.a: no W: no set: *O(il, L, Ol) O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: no C: no w.a: no w.a: no W: (LP = A) A -> *B set: *O(il, L, Ol) {PH}(R, Or): 1: r.b: R+Or -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: no C: no w.a: no w.a: no W: (LP = A) A -> *B set: *O(il, L, Ol) *O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: *A -> A C: no w.a: no w.a: no W: (LP = A) A -> *B set: *O(il, L, Ol) *{PH}(R, Or): 1: r.b: R+Or -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: *A -> A C: no w.a: no w.a: no W: (LP = A) A -> *B swap R(L) R(R): (R != L) 1: r.a: R -> A r.a: L -> B R: no C: no w.a: A -> L w.a: B -> R W: no swap R(L) *O(i, R, O): 1: r.a: R+(i ? index << 20 | O : SE(O)) -> A r.a: L -> B R: *A -> C C: no w.a: C -> L w.a: no W: B -> *A swap *O(i, L, O) R(R): // symmetry swap R(L) *{PH}(R, O): 1: r.a: L -> B r.b: R+O -> A R: *A -> C C: no w.a: C -> L w.a: no W: B -> *A swap *{PH}(L, O) R(R): // symmetry swap *O(il, L, Ol) *O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: *A -> C C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *B -> D C: no w.a: no w.a: no W: C -> *B 3: r.a: no r.a: no R: no C: no w.a: no w.a: no W: D -> *A swap *O(il, L, Ol) *{PH}(R, Or): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A r.b: R+Or -> B R: *A -> C C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *B -> D C: no w.a: no w.a: no W: C -> *B 3: r.a: no r.a: no R: no C: no w.a: no w.a: no W: D -> *A swap *{PH}(L, Ol) *{PH}(R, Or): 1: r.b: R+Or -> A r.b: L+Ol -> B R: *A -> C C: no w.a: no w.a: no W:no 2: r.a: no r.a: no R: *B -> D C: no w.a: no w.a: no W: C -> *B 3: r.a: no r.a: no R: no C: no w.a: no w.a: no W: D -> *A xchg R(L) O(ir, R, Or): 1: r.a: L -> A r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B R: no C: no w.b: A -> stack w.a: B -> L W: no xchg R(L) {PH}(R, Or): // Optimized to swap xchg R(L) *O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B r.a: L -> A R: *B -> B C: no w.b: A -> stack w.a: B -> L W: no xchg *O(il, L, Ol) O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: *B -> C C: no w.b: C -> stack w.a: no W: no 2: r.a: no r.a: no R: *A -> A C: no w.a: no w.a: no W: A -> *B load_ua O(il, L, Ol) O(ir, R, Or): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A // src r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B // c_o R: *A -> C C: ++A w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> A C: call shift_ua(A,B,C,D) w.b: A -> stack w.a: no W: no load_ua O(il, L, Ol) {PH}(R, Or): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A // src r.a: R+Or -> B // c_o R: *A -> C C: ++A w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> A C: call shift_ua w.b: A -> stack w.a: no W: no load_ua {PH}(L, Ol) O(ir, R, Or): 1: r.a: L+Ol -> A // src r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B // c_o R: *A -> C C: ++A w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> A C: call shift_ua w.b: A -> stack w.a: no W: no load_ua {PH}(L, Ol) {PH}(R, Or): 1: r.a: L+Ol -> A // src r.a: R+Or -> B // c_o R: *A -> C C: ++C w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> A C: call shift_ua w.b: A -> stack w.a: no W: no load_ua *O(il, L, Ol) O(ir, R, Or): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A // src r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B // c_o R: *A -> A C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> C C: ++A w.a: no w.a: no W: no 3: r.a: no r.a: no R: *A -> A C: call shift_ua(A,B,C,D) w.b: A -> stack w.a: no W: no load_ua *O(il, L, Ol) {PH}(R, Or): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A // src r.a: R+Or -> B // c_o R: *A -> A C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> C C: ++A w.a: no w.a: no W: no 3: r.a: no r.a: no R: *A -> A C: call shift_ua(A,B,C,D) w.b: A -> stack w.a: no W: no load_ua *{PH}(il, L, Ol) O(ir, R, Or): 1: r.a: L+Ol -> A // src r.a: R+(ir ? index << 20 | Or : SE(Or)) -> B // c_o R: *A -> A C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> C C: ++A w.a: no w.a: no W: no 3: r.a: no r.a: no R: *A -> A C: call shift_ua(A,B,C,D) w.b: A -> stack w.a: no W: no load_ua *{PH}(il, L, Ol) {PH}(R, Or): 1: r.a: L+Ol -> A // src r.a: R+Or -> B // c_o R: *A -> A C: no w.a: no w.a: no W: no 2: r.a: no r.a: no R: *A -> C C: ++A w.a: no w.a: no W: no 3: r.a: no r.a: no R: *A -> A C: call shift_ua(A,B,C,D) w.b: A -> stack w.a: no W: no load_ua_se: w.a: no w.a: no W: no 3: r.a: r.a: R: no C: B&7 -> B w.a: w.a: W: 4: r.a: no r.a: no R: no C: B+1 -> B w.a: no w.a: no W: no 5: r.a: no r.a: no R: no C: call signextend store_ua: mcpy: mset: fma O(il, L, Ol) O(ir, R, Or): 1: r.a: R+(ir ? index << 20 | Or : SE(Or)) -> A r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> B R: no C: no w.a: no w.a: no W: no 2: r.b: stack -> C r.a: no R: no C: call fma w.b: A -> stack w.a: no W: no jmp O(il, L, Ol): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A r.a: no R: no C: no w.a: A -> CP w.a: no W: no reljmp (O(il, L, Ol): 1: r.a: L+(il ? index << 20 | Ol : SE(Ol)) -> A r.a: CP -> B R: no C: A + B -> A w.a: A -> CP w.a: no W: no transfer: 1: r.a: CP -> A r.a: FP -> B R: no C: no w.b: A -> cstack w.b: B -> cstack W: no 2: r.a: jump -> A r.a: SP -> B R: no C: no w.a: B -> FP w.a: A -> CP W: no return: 1: r.b: cstack -> A r.b: cstack -> B R: no C: no w.a: A -> FP w.a: B -> CP "name":r1,r2,R,C,w1,w2,W; "xchg,*F,F":RA,LB,BC,-,CS,Ar0,-;-,-,AA,-,-,-,AB; "xchg,*O,F":RiA,LB,BC,-,CS,Ar0,-;-,-,AA,-,-,-,AB; "xchg,*F,O":RA,LiB,BC,-,CS,Ar0,-;-,-,AA,-,-,-,AB; "xchg,*O,O":RiA,LiB,BC,-,CS,Ar0,-;-,-,AA,-,-,-,AB; */ /* vertical microcode: move: 26 from/to: Fixed Operands 18A, 18B, 36L 3 // 3 Index 1 // 4 Registers 0-15 16 // 20 Stacks P, H, C, N 4 // 24 Internal registers A-D 4 // 28 load: 26 move indirect->direct store: 26 => 78 move direct->indirect Computations: 128? => 206 */ } // namespace mc_long #endif // MICROCODELONG_HPP