// // OperationMapper.hpp // Clock Signal // // Created by Thomas Harte on 17/03/2023. // Copyright © 2023 Thomas Harte. All rights reserved. // #pragma once // Cf. https://techheap.packetizer.com/processors/6809/6809Instructions.html // // Subject to corrections: // // * CWAI and the pushes and pulls at 0x3x are immediate, not inherent. namespace InstructionSet::M6809 { enum class AddressingMode { Illegal, Inherent, Immediate, Direct, Relative, // TODO: is it worth breaking this into 8- and 16-bit versions? Variant, Indexed, Extended, }; enum class Operation { None, SUBB, CMPB, SBCB, ADDD, ANDB, BITB, LDB, STB, EORB, ADCB, ORB, ADDB, LDD, STD, LDU, STU, SUBA, CMPA, SBCA, SUBD, ANDA, BITA, LDA, STA, EORA, ADCA, ORA, ADDA, CMPX, JSR, LDX, STX, BSR, NEG, COM, LSR, ROR, ASR, LSL, ROL, DEC, INC, TST, JMP, CLR, NEGA, COMA, LSRA, RORA, ASRA, LSLA, ROLA, DECA, INCA, TSTA, CLRA, NEGB, COMB, LSRB, RORB, ASRB, LSLB, ROLB, DECB, INCB, TSTB, CLRB, LEAX, LEAY, LEAS, LEAU, PSHS, PULS, PSHU, PULU, RTS, ABX, RTI, CWAI, MUL, RESET, SWI, BRA, BRN, BHI, BLS, BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE, Page1, Page2, NOP, SYNC, LBRA, LBSR, DAA, ORCC, ANDCC, SEX, EXG, TFR, LBRN, LBHI, LBLS, LBCC, LBCS, LBNE, LBEQ, LBVC, LBVS, LBPL, LBMI, LBGE, LBLT, LBGT, LBLE, SWI2, CMPD, CMPY, LDY, STY, LDS, STS, SWI3, CMPU, CMPS, }; enum class Page { Page0, Page1, Page2, }; /*! Calls @c scheduler.schedule to describe the instruction defined by opcode @c i on page @c page. */ template struct OperationMapper { template void dispatch(SchedulerT &scheduler); }; template <> template void OperationMapper::dispatch(SchedulerT &s) { using AM = AddressingMode; using O = Operation; constexpr auto upper = (i >> 4) & 0xf; constexpr auto lower = (i >> 0) & 0xf; constexpr AddressingMode modes[] = { AM::Immediate, AM::Direct, AM::Indexed, AM::Extended }; constexpr AddressingMode mode = modes[(i >> 4) & 3]; switch(upper) { default: break; case 0x1: { constexpr Operation operations[] = { O::Page1, O::Page2, O::NOP, O::SYNC, O::None, O::None, O::LBRA, O::LBSR, O::None, O::DAA, O::ORCC, O::None, O::ANDCC, O::SEX, O::EXG, O::TFR, }; constexpr AddressingMode modes[] = { AM::Variant, AM::Variant, AM::Inherent, AM::Inherent, AM::Illegal, AM::Illegal, AM::Relative, AM::Relative, AM::Illegal, AM::Inherent, AM::Immediate, AM::Illegal, AM::Immediate, AM::Inherent, AM::Inherent, AM::Inherent, }; s.template schedule(); } break; case 0x2: { constexpr Operation operations[] = { O::BRA, O::BRN, O::BHI, O::BLS, O::BCC, O::BCS, O::BNE, O::BEQ, O::BVC, O::BVS, O::BPL, O::BMI, O::BGE, O::BLT, O::BGT, O::BLE, }; s.template schedule(); } break; case 0x3: { constexpr Operation operations[] = { O::LEAX, O::LEAY, O::LEAS, O::LEAU, O::PSHS, O::PULS, O::PSHU, O::PULU, O::None, O::RTS, O::ABX, O::RTI, O::CWAI, O::MUL, O::RESET, O::SWI, }; constexpr auto op = operations[lower]; switch(lower) { case 0x0: case 0x1: case 0x2: case 0x3: s.template schedule(); break; case 0x4: case 0x5: case 0x6: case 0x7: case 0xc: s.template schedule(); break; case 0x8: s.template schedule(); break; default: s.template schedule(); break; } } break; case 0x4: { constexpr Operation operations[] = { O::NEGA, O::None, O::None, O::COMA, O::LSRA, O::None, O::RORA, O::ASRA, O::LSLA, O::ROLA, O::DECA, O::None, O::INCA, O::TSTA, O::None, O::CLRA, }; constexpr auto op = operations[lower]; s.template schedule(); } break; case 0x5: { constexpr Operation operations[] = { O::NEGB, O::None, O::None, O::COMB, O::LSRB, O::None, O::RORB, O::ASRB, O::LSLB, O::ROLB, O::DECB, O::None, O::INCB, O::TSTB, O::None, O::CLRB, }; constexpr auto op = operations[lower]; s.template schedule(); } break; case 0x0: case 0x6: case 0x7: { constexpr Operation operations[] = { O::NEG, O::None, O::None, O::COM, O::LSR, O::None, O::ROR, O::ASR, O::LSL, O::ROL, O::DEC, O::None, O::INC, O::TST, O::JMP, O::CLR, }; constexpr auto op = operations[lower]; s.template schedule(); } break; case 0x8: case 0x9: case 0xa: case 0xb: { constexpr Operation operations[] = { O::SUBA, O::CMPA, O::SBCA, O::SUBD, O::ANDA, O::BITA, O::LDA, O::STA, O::EORA, O::ADCA, O::ORA, O::ADDA, O::CMPX, O::JSR, O::LDX, O::STX, }; if(i == 0x8d) s.template schedule(); else s.template schedule(); } break; case 0xc: case 0xd: case 0xe: case 0xf: { constexpr Operation operations[] = { O::SUBB, O::CMPB, O::SBCB, O::ADDD, O::ANDB, O::BITB, O::LDB, O::STB, O::EORB, O::ADCB, O::ORB, O::ADDB, O::LDD, O::STD, O::LDU, O::STU, }; s.template schedule(); } break; } } template <> template void OperationMapper::dispatch(SchedulerT &s) { using AM = AddressingMode; using O = Operation; constexpr AddressingMode modes[] = { AM::Immediate, AM::Direct, AM::Indexed, AM::Extended }; constexpr auto mode = modes[(i >> 4) & 3]; if constexpr (i >= 0x21 && i < 0x30) { constexpr Operation operations[] = { O::LBRN, O::LBHI, O::LBLS, O::LBCC, O::LBCS, O::LBNE, O::LBEQ, O::LBVC, O::LBVS, O::LBPL, O::LBMI, O::LBGE, O::LBLT, O::LBGT, O::LBLE, }; s.template schedule(); } else switch(i) { default: s.template schedule(); break; case 0x3f: s.template schedule(); break; case 0x83: case 0x93: case 0xa3: case 0xb3: s.template schedule(); break; case 0x8c: case 0x9c: case 0xac: case 0xbc: s.template schedule(); break; case 0x8e: case 0x9e: case 0xae: case 0xbe: s.template schedule(); break; case 0x9f: case 0xaf: case 0xbf: s.template schedule(); break; case 0xce: case 0xde: case 0xee: case 0xfe: s.template schedule(); break; case 0xdf: case 0xef: case 0xff: s.template schedule(); break; } } template <> template void OperationMapper::dispatch(SchedulerT &s) { using AM = AddressingMode; using O = Operation; constexpr AddressingMode modes[] = { AM::Immediate, AM::Direct, AM::Indexed, AM::Extended }; constexpr auto mode = modes[(i >> 4) & 3]; switch(i) { default: s.template schedule(); break; case 0x3f: s.template schedule(); break; case 0x83: case 0x93: case 0xa3: case 0xb3: s.template schedule(); break; case 0x8c: case 0x9c: case 0xac: case 0xbc: s.template schedule(); break; } } }