mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-16 19:08:08 +00:00
241 lines
7.1 KiB
C++
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;
|
|
}
|
|
}
|
|
|
|
}
|