1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-20 10:17:05 +00:00

Eliminate need for intermediate storage.

This commit is contained in:
Thomas Harte
2026-02-25 12:47:38 -05:00
parent e6b55fa954
commit 65c6222a56
4 changed files with 82 additions and 80 deletions
+52 -49
View File
@@ -71,11 +71,12 @@ enum class Page {
defined by opcode @c i on page @c page.
*/
template <Page page> struct OperationMapper {
template <int i, typename SchedulerT> void dispatch(SchedulerT &scheduler);
template <int i, typename SchedulerT> auto dispatch(SchedulerT &scheduler);
};
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page0>::dispatch(SchedulerT &s) {
template <int i, typename SchedulerT>
auto OperationMapper<Page::Page0>::dispatch(SchedulerT &s) {
using AM = AddressingMode;
using O = Operation;
@@ -101,15 +102,15 @@ template <int i, typename SchedulerT> void OperationMapper<Page::Page0>::dispatc
AM::Illegal, AM::Inherent, AM::Immediate, AM::Illegal,
AM::Immediate, AM::Inherent, AM::Inherent, AM::Inherent,
};
s.template schedule<operations[lower], modes[lower]>();
} break;
return s.template schedule<operations[lower], modes[lower]>();
}
case 0x2: {
static 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;
return s.template schedule<operations[lower], AM::Relative>();
}
case 0x3: {
static constexpr Operation operations[] = {
O::LEAX, O::LEAY, O::LEAS, O::LEAU, O::PSHS, O::PULS, O::PSHU, O::PULU,
@@ -118,63 +119,64 @@ template <int i, typename SchedulerT> void OperationMapper<Page::Page0>::dispatc
static constexpr auto op = operations[lower];
switch(lower) {
case 0x0: case 0x1: case 0x2: case 0x3:
s.template schedule<op, AM::Indexed>();
break;
return s.template schedule<op, AM::Indexed>();
case 0x4: case 0x5: case 0x6: case 0x7: case 0xc:
s.template schedule<op, AM::Immediate>();
break;
return s.template schedule<op, AM::Immediate>();
case 0x8:
s.template schedule<op, AM::Illegal>();
break;
return s.template schedule<op, AM::Illegal>();
default:
s.template schedule<op, AM::Inherent>();
break;
return s.template schedule<op, AM::Inherent>();
}
} break;
}
case 0x4: {
static 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,
};
static constexpr auto op = operations[lower];
s.template schedule<op, op == O::None ? AM::Illegal : AM::Inherent>();
} break;
return s.template schedule<op, op == O::None ? AM::Illegal : AM::Inherent>();
}
case 0x5: {
static 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,
};
static constexpr auto op = operations[lower];
s.template schedule<op, op == O::None ? AM::Illegal : AM::Inherent>();
} break;
return s.template schedule<op, op == O::None ? AM::Illegal : AM::Inherent>();
}
case 0x0: case 0x6: case 0x7: {
static 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,
};
static constexpr auto op = operations[lower];
s.template schedule<op, op == O::None ? AM::Illegal : upper == 0 ? AM::Direct : mode>();
} break;
return s.template schedule<op, op == O::None ? AM::Illegal : upper == 0 ? AM::Direct : mode>();
}
case 0x8: case 0x9: case 0xa: case 0xb: {
static 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;
if(i == 0x8d) return s.template schedule<O::BSR, AM::Relative>();
else return s.template schedule<operations[lower], mode>();
}
case 0xc: case 0xd: case 0xe: case 0xf: {
static 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;
return s.template schedule<operations[lower], mode>();
}
}
__builtin_unreachable();
}
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page1>::dispatch(SchedulerT &s) {
template <int i, typename SchedulerT>
auto OperationMapper<Page::Page1>::dispatch(SchedulerT &s) {
using AM = AddressingMode;
using O = Operation;
@@ -188,34 +190,35 @@ template <int i, typename SchedulerT> void OperationMapper<Page::Page1>::dispatc
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>();
return 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;
default: return s.template schedule<O::None, AM::Illegal>();
case 0x3f: return s.template schedule<O::SWI2, AM::Inherent>();
case 0x83: case 0x93: case 0xa3: case 0xb3:
s.template schedule<O::CMPD, mode>();
break;
return s.template schedule<O::CMPD, mode>();
case 0x8c: case 0x9c: case 0xac: case 0xbc:
s.template schedule<O::CMPY, mode>();
break;
return s.template schedule<O::CMPY, mode>();
case 0x8e: case 0x9e: case 0xae: case 0xbe:
s.template schedule<O::LDY, mode>();
break;
return s.template schedule<O::LDY, mode>();
case 0x9f: case 0xaf: case 0xbf:
s.template schedule<O::STY, mode>();
break;
return s.template schedule<O::STY, mode>();
case 0xce: case 0xde: case 0xee: case 0xfe:
s.template schedule<O::LDS, mode>();
break;
return s.template schedule<O::LDS, mode>();
case 0xdf: case 0xef: case 0xff:
s.template schedule<O::STS, mode>();
break;
return s.template schedule<O::STS, mode>();
}
__builtin_unreachable();
}
template <>
template <int i, typename SchedulerT> void OperationMapper<Page::Page2>::dispatch(SchedulerT &s) {
template <int i, typename SchedulerT>
auto OperationMapper<Page::Page2>::dispatch(SchedulerT &s) {
using AM = AddressingMode;
using O = Operation;
@@ -225,16 +228,16 @@ template <int i, typename SchedulerT> void OperationMapper<Page::Page2>::dispatc
static 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;
default: return s.template schedule<O::None, AM::Illegal>();
case 0x3f: return s.template schedule<O::SWI3, AM::Inherent>();
case 0x83: case 0x93: case 0xa3: case 0xb3:
s.template schedule<O::CMPU, mode>();
break;
return s.template schedule<O::CMPU, mode>();
case 0x8c: case 0x9c: case 0xac: case 0xbc:
s.template schedule<O::CMPS, mode>();
break;
return s.template schedule<O::CMPS, mode>();
}
__builtin_unreachable();
}
}
@@ -757,7 +757,6 @@
4B96DECC2EBEE7D100505298 /* SID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96DECA2EBEE7D100505298 /* SID.cpp */; };
4B96DECD2EBEE7D100505298 /* SID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96DECA2EBEE7D100505298 /* SID.cpp */; };
4B96DECE2EBEE7D100505298 /* SID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96DECA2EBEE7D100505298 /* SID.cpp */; };
4B96DED32EC3ECDA00505298 /* SIDTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B96DED22EC3ECDA00505298 /* SIDTests.mm */; };
4B96F7CE263E33B10092AEE1 /* DSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96F7CC263E33B10092AEE1 /* DSK.cpp */; };
4B96F7CF263E33B10092AEE1 /* DSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96F7CC263E33B10092AEE1 /* DSK.cpp */; };
4B98A05E1FFAD3F600ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
@@ -1980,7 +1979,6 @@
4B96DEC32EBEA88C00505298 /* TubeProcessor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TubeProcessor.hpp; sourceTree = "<group>"; };
4B96DEC92EBEE7D100505298 /* SID.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SID.hpp; sourceTree = "<group>"; };
4B96DECA2EBEE7D100505298 /* SID.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SID.cpp; sourceTree = "<group>"; };
4B96DED22EC3ECDA00505298 /* SIDTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SIDTests.mm; sourceTree = "<group>"; };
4B96DED42EC53BC300505298 /* BiquadFilter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = BiquadFilter.hpp; sourceTree = "<group>"; };
4B96F7CB263E30B00092AEE1 /* RawSectorDump.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RawSectorDump.hpp; sourceTree = "<group>"; };
4B96F7CC263E33B10092AEE1 /* DSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DSK.cpp; sourceTree = "<group>"; };
@@ -4968,7 +4966,6 @@
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
4B3F76B825A1635300178AEC /* PowerPCDecoderTests.mm */,
4BE76CF822641ED300ACD6FA /* QLTests.mm */,
4B96DED22EC3ECDA00505298 /* SIDTests.mm */,
4B8DD3672633B2D400B3C866 /* SpectrumVideoContentionTests.mm */,
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
4B1D08051E0F7A1100763741 /* TimeTests.mm */,
@@ -6931,7 +6928,6 @@
4B778F4623A5F1D80000D260 /* StaticAnalyser.cpp in Sources */,
4B778F1323A5EC890000D260 /* Z80Base.cpp in Sources */,
4B778F2923A5EF030000D260 /* CommodoreROM.cpp in Sources */,
4B96DED32EC3ECDA00505298 /* SIDTests.mm in Sources */,
4B06AADC2C645F720034D014 /* BD500.cpp in Sources */,
4B778F4823A5F1E70000D260 /* StaticAnalyser.cpp in Sources */,
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */,
@@ -17,19 +17,15 @@ using namespace InstructionSet::M6809;
namespace {
struct OperationCapture {
template <Operation operation, AddressingMode mode> void schedule() {
this->operation = operation;
this->mode = mode;
template <Operation operation, AddressingMode mode> auto schedule() {
return std::make_pair(operation, mode);
}
Operation operation;
AddressingMode mode;
};
template <Page page> OperationCapture capture(uint8_t opcode) {
template <Page page> std::pair<Operation, AddressingMode> capture(const uint8_t opcode) {
OperationCapture catcher;
OperationMapper<page> mapper;
Reflection::dispatch(mapper, opcode, catcher);
return catcher;
return Reflection::dispatch(mapper, opcode, catcher);
}
}
@@ -39,17 +35,21 @@ template <Page page> OperationCapture capture(uint8_t opcode) {
@implementation M6809OperationMapperTests
- (void)testOpcode:(uint8_t)opcode page:(Page)page isOperation:(Operation)operation addressingMode:(AddressingMode)mode {
OperationCapture catcher;
switch(page) {
case Page::Page0: catcher = capture<Page::Page0>(opcode); break;
case Page::Page1: catcher = capture<Page::Page1>(opcode); break;
case Page::Page2: catcher = capture<Page::Page2>(opcode); break;
}
XCTAssertEqual(catcher.operation, operation, "Operation didn't match for opcode 0x%02x in page %d", opcode, int(page));
XCTAssertEqual(catcher.mode, mode, "Mode didn't match for opcode 0x%02x in page %d", opcode, int(page));
- (void)
testOpcode:(uint8_t)opcode
page:(Page)page
isOperation:(Operation)expectedOperation
addressingMode:(AddressingMode)expectedMode
{
const auto &[operation, mode] = [&]() {
switch(page) {
case Page::Page0: return capture<Page::Page0>(opcode);
case Page::Page1: return capture<Page::Page1>(opcode);
case Page::Page2: return capture<Page::Page2>(opcode);
}
} ();
XCTAssertEqual(expectedOperation, operation, "Operation didn't match for opcode 0x%02x in page %d", opcode, int(page));
XCTAssertEqual(expectedMode, mode, "Mode didn't match for opcode 0x%02x in page %d", opcode, int(page));
}
- (void)testMap {
+11 -8
View File
@@ -16,8 +16,9 @@ namespace Reflection {
/*!
Calls @c t.dispatch<c>(args...) as efficiently as possible.
*/
template <typename TargetT, typename... Args> void dispatch(TargetT &t, uint8_t c, Args &&... args) {
#define Opt(x) case x: t.template dispatch<x>(std::forward<Args>(args)...); break
template <typename TargetT, typename... Args>
auto dispatch(TargetT &t, const uint8_t c, Args &&... args) {
#define Opt(x) case x: return t.template dispatch<x>(std::forward<Args>(args)...);
#define Opt4(x) Opt(x + 0x00); Opt(x + 0x01); Opt(x + 0x02); Opt(x + 0x03)
#define Opt16(x) Opt4(x + 0x00); Opt4(x + 0x04); Opt4(x + 0x08); Opt4(x + 0x0c)
#define Opt64(x) Opt16(x + 0x00); Opt16(x + 0x10); Opt16(x + 0x20); Opt16(x + 0x30)
@@ -26,6 +27,7 @@ template <typename TargetT, typename... Args> void dispatch(TargetT &t, uint8_t
switch(c) {
Opt256(0);
}
__builtin_unreachable();
#undef Opt256
#undef Opt64
@@ -68,20 +70,21 @@ struct RangeDispatcher {
/// Perform @c target.perform<n>() for the input range `begin <= n < end`.
template <typename... Args>
static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
static auto dispatch(SequencerT &target, const int begin, const int end, Args&&... args) {
// Minor optimisation: do a comparison with end once outside the loop and if it implies so
// then do no further comparisons within the loop. This is somewhat targetted at expected
// use cases.
if(end < SequencerT::max) {
dispatch<true>(target, begin, end, args...);
return dispatch<true>(target, begin, end, args...);
} else {
dispatch<false>(target, begin, end, args...);
return dispatch<false>(target, begin, end, args...);
}
}
private:
template <bool use_end, typename... Args> static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
template <bool use_end, typename... Args>
static auto dispatch(SequencerT &target, const int begin, const int end, Args&&... args) {
#define index(n) \
case n: \
if constexpr (n <= SequencerT::max) { \
@@ -141,13 +144,13 @@ struct SubrangeDispatcher {
}
private:
static constexpr int find_begin(int n) {
static consteval int find_begin(int n) {
const auto type = ClassifierT::region(n);
while(n && ClassifierT::region(n - 1) == type) --n;
return n;
}
static constexpr int find_end(int n) {
static consteval int find_end(int n) {
const auto type = ClassifierT::region(n);
while(n < ClassifierT::max && ClassifierT::region(n) == type) ++n;
return n;