1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-11 15:49:38 +00:00
CLK/InstructionSets/6809/OperationMapper.hpp
2024-01-16 23:34:46 -05:00

241 lines
7.1 KiB
C++

//
// 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<Operation,AddressingMode> to describe the instruction
defined by opcode @c i on page @c page.
*/
template <Page page> struct OperationMapper {
template <int i, typename SchedulerT> void dispatch(SchedulerT &scheduler);
};
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page0>::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<operations[lower], modes[lower]>();
} 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<operations[lower], AM::Relative>();
} 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<op, AM::Indexed>();
break;
case 0x4: case 0x5: case 0x6: case 0x7: case 0xc:
s.template schedule<op, AM::Immediate>();
break;
case 0x8:
s.template schedule<op, AM::Illegal>();
break;
default:
s.template schedule<op, AM::Inherent>();
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<op, op == O::None ? AM::Illegal : AM::Inherent>();
} 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<op, op == O::None ? AM::Illegal : AM::Inherent>();
} 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<op, op == O::None ? AM::Illegal : upper == 0 ? AM::Direct : mode>();
} 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<O::BSR, AM::Relative>();
else s.template schedule<operations[lower], mode>();
} 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<operations[lower], mode>();
} break;
}
}
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page1>::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<operations[i - 0x21], AM::Relative>();
} else switch(i) {
default: s.template schedule<O::None, AM::Illegal>(); break;
case 0x3f: s.template schedule<O::SWI2, AM::Inherent>(); break;
case 0x83: case 0x93: case 0xa3: case 0xb3:
s.template schedule<O::CMPD, mode>();
break;
case 0x8c: case 0x9c: case 0xac: case 0xbc:
s.template schedule<O::CMPY, mode>();
break;
case 0x8e: case 0x9e: case 0xae: case 0xbe:
s.template schedule<O::LDY, mode>();
break;
case 0x9f: case 0xaf: case 0xbf:
s.template schedule<O::STY, mode>();
break;
case 0xce: case 0xde: case 0xee: case 0xfe:
s.template schedule<O::LDS, mode>();
break;
case 0xdf: case 0xef: case 0xff:
s.template schedule<O::STS, mode>();
break;
}
}
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page2>::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<O::None, AM::Illegal>(); break;
case 0x3f: s.template schedule<O::SWI3, AM::Inherent>(); break;
case 0x83: case 0x93: case 0xa3: case 0xb3:
s.template schedule<O::CMPU, mode>();
break;
case 0x8c: case 0x9c: case 0xac: case 0xbc:
s.template schedule<O::CMPS, mode>();
break;
}
}
}