mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Move string logic into Preinstruction
.
This commit is contained in:
parent
4ba20132b9
commit
2fa6b2301b
295
InstructionSets/M68k/Instruction.cpp
Normal file
295
InstructionSets/M68k/Instruction.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
//
|
||||
// Instruction.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 12/05/2022.
|
||||
// Copyright © 2022 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Instruction.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace InstructionSet::M68k;
|
||||
|
||||
std::string Preinstruction::operand_description(int index, int opcode) const {
|
||||
switch(mode(index)) {
|
||||
default: assert(false);
|
||||
|
||||
case AddressingMode::None:
|
||||
return "";
|
||||
|
||||
case AddressingMode::DataRegisterDirect:
|
||||
return std::string("D") + std::to_string(reg(index));
|
||||
|
||||
case AddressingMode::AddressRegisterDirect:
|
||||
return std::string("A") + std::to_string(reg(index));
|
||||
case AddressingMode::AddressRegisterIndirect:
|
||||
return std::string("(A") + std::to_string(reg(index)) + ")";
|
||||
case AddressingMode::AddressRegisterIndirectWithPostincrement:
|
||||
return std::string("(A") + std::to_string(reg(index)) + ")+";
|
||||
case AddressingMode::AddressRegisterIndirectWithPredecrement:
|
||||
return std::string("-(A") + std::to_string(reg(index)) + ")";
|
||||
case AddressingMode::AddressRegisterIndirectWithDisplacement:
|
||||
return std::string("(d16, A") + std::to_string(reg(index)) + ")";
|
||||
case AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement:
|
||||
return std::string("(d8, A") + std::to_string(reg(index)) + ", Xn)";
|
||||
|
||||
case AddressingMode::ProgramCounterIndirectWithDisplacement:
|
||||
return "(d16, PC)";
|
||||
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
|
||||
return "(d8, PC, Xn)";
|
||||
|
||||
case AddressingMode::AbsoluteShort:
|
||||
return "(xxx).w";
|
||||
case AddressingMode::AbsoluteLong:
|
||||
return "(xxx).l";
|
||||
|
||||
case AddressingMode::ImmediateData:
|
||||
return "#";
|
||||
|
||||
case AddressingMode::Quick:
|
||||
if(opcode == -1) {
|
||||
return "Q";
|
||||
}
|
||||
return std::to_string(int(quick(uint16_t(opcode), operation)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string Preinstruction::to_string(int opcode) const {
|
||||
bool flip_operands = false;
|
||||
const char *instruction;
|
||||
|
||||
switch(operation) {
|
||||
case Operation::Undefined: instruction = "None"; break;
|
||||
case Operation::NOP: instruction = "NOP"; break;
|
||||
case Operation::ABCD: instruction = "ABCD"; break;
|
||||
case Operation::SBCD: instruction = "SBCD"; break;
|
||||
case Operation::NBCD: instruction = "NBCD"; break;
|
||||
|
||||
case Operation::ADDb: instruction = "ADD.b"; break;
|
||||
case Operation::ADDw: instruction = "ADD.w"; break;
|
||||
case Operation::ADDl: instruction = "ADD.l"; break;
|
||||
|
||||
case Operation::ADDAw:
|
||||
if(mode<0>() == AddressingMode::Quick) {
|
||||
instruction = "ADD.w";
|
||||
} else {
|
||||
instruction = "ADDA.w";
|
||||
}
|
||||
break;
|
||||
case Operation::ADDAl:
|
||||
if(mode<0>() == AddressingMode::Quick) {
|
||||
instruction = "ADD.l";
|
||||
} else {
|
||||
instruction = "ADDA.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::ADDXb: instruction = "ADDX.b"; break;
|
||||
case Operation::ADDXw: instruction = "ADDX.w"; break;
|
||||
case Operation::ADDXl: instruction = "ADDX.l"; break;
|
||||
|
||||
case Operation::SUBb: instruction = "SUB.b"; break;
|
||||
case Operation::SUBw: instruction = "SUB.w"; break;
|
||||
case Operation::SUBl: instruction = "SUB.l"; break;
|
||||
|
||||
case Operation::SUBAw:
|
||||
if(mode<0>() == AddressingMode::Quick) {
|
||||
instruction = "SUB.w";
|
||||
} else {
|
||||
instruction = "SUBA.w";
|
||||
}
|
||||
break;
|
||||
case Operation::SUBAl:
|
||||
if(mode<0>() == AddressingMode::Quick) {
|
||||
instruction = "SUB.l";
|
||||
} else {
|
||||
instruction = "SUBA.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::SUBXb: instruction = "SUBX.b"; break;
|
||||
case Operation::SUBXw: instruction = "SUBX.w"; break;
|
||||
case Operation::SUBXl: instruction = "SUBX.l"; break;
|
||||
|
||||
case Operation::MOVEb: instruction = "MOVE.b"; break;
|
||||
case Operation::MOVEw: instruction = "MOVE.w"; break;
|
||||
case Operation::MOVEl:
|
||||
if(mode<0>() == AddressingMode::Quick) {
|
||||
instruction = "MOVE.q";
|
||||
} else {
|
||||
instruction = "MOVE.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::MOVEAw: instruction = "MOVEA.w"; break;
|
||||
case Operation::MOVEAl: instruction = "MOVEA.l"; break;
|
||||
|
||||
case Operation::LEA: instruction = "LEA"; break;
|
||||
case Operation::PEA: instruction = "PEA"; break;
|
||||
|
||||
case Operation::MOVEtoSR: instruction = "MOVEtoSR"; break;
|
||||
case Operation::MOVEfromSR: instruction = "MOVEfromSR"; break;
|
||||
case Operation::MOVEtoCCR: instruction = "MOVEtoCCR"; break;
|
||||
case Operation::MOVEtoUSP: instruction = "MOVEtoUSP"; break;
|
||||
case Operation::MOVEfromUSP: instruction = "MOVEfromUSP"; break;
|
||||
|
||||
case Operation::ORItoSR: instruction = "ORItoSR"; break;
|
||||
case Operation::ORItoCCR: instruction = "ORItoCCR"; break;
|
||||
case Operation::ANDItoSR: instruction = "ANDItoSR"; break;
|
||||
case Operation::ANDItoCCR: instruction = "ANDItoCCR"; break;
|
||||
case Operation::EORItoSR: instruction = "EORItoSR"; break;
|
||||
case Operation::EORItoCCR: instruction = "EORItoCCR"; break;
|
||||
|
||||
case Operation::BTST: instruction = "BTST"; break;
|
||||
case Operation::BCLR: instruction = "BCLR"; break;
|
||||
case Operation::BCHG: instruction = "BCHG"; break;
|
||||
case Operation::BSET: instruction = "BSET"; break;
|
||||
|
||||
case Operation::CMPb: instruction = "CMP.b"; break;
|
||||
case Operation::CMPw: instruction = "CMP.w"; break;
|
||||
case Operation::CMPl: instruction = "CMP.l"; break;
|
||||
|
||||
case Operation::CMPAw: instruction = "CMPA.w"; break;
|
||||
case Operation::CMPAl: instruction = "CMPA.l"; break;
|
||||
|
||||
case Operation::TSTb: instruction = "TST.b"; break;
|
||||
case Operation::TSTw: instruction = "TST.w"; break;
|
||||
case Operation::TSTl: instruction = "TST.l"; break;
|
||||
|
||||
case Operation::JMP: instruction = "JMP"; break;
|
||||
case Operation::JSR: instruction = "JSR"; break;
|
||||
case Operation::RTS: instruction = "RTS"; break;
|
||||
case Operation::DBcc: instruction = "DBcc"; break;
|
||||
case Operation::Scc: instruction = "Scc"; break;
|
||||
|
||||
case Operation::Bccb:
|
||||
case Operation::Bccl:
|
||||
case Operation::Bccw: instruction = "Bcc"; break;
|
||||
|
||||
case Operation::BSRb:
|
||||
case Operation::BSRl:
|
||||
case Operation::BSRw: instruction = "BSR"; break;
|
||||
|
||||
case Operation::CLRb: instruction = "CLR.b"; break;
|
||||
case Operation::CLRw: instruction = "CLR.w"; break;
|
||||
case Operation::CLRl: instruction = "CLR.l"; break;
|
||||
|
||||
case Operation::NEGXb: instruction = "NEGX.b"; break;
|
||||
case Operation::NEGXw: instruction = "NEGX.w"; break;
|
||||
case Operation::NEGXl: instruction = "NEGX.l"; break;
|
||||
|
||||
case Operation::NEGb: instruction = "NEG.b"; break;
|
||||
case Operation::NEGw: instruction = "NEG.w"; break;
|
||||
case Operation::NEGl: instruction = "NEG.l"; break;
|
||||
|
||||
case Operation::ASLb: instruction = "ASL.b"; break;
|
||||
case Operation::ASLw: instruction = "ASL.w"; break;
|
||||
case Operation::ASLl: instruction = "ASL.l"; break;
|
||||
case Operation::ASLm: instruction = "ASL.w"; break;
|
||||
|
||||
case Operation::ASRb: instruction = "ASR.b"; break;
|
||||
case Operation::ASRw: instruction = "ASR.w"; break;
|
||||
case Operation::ASRl: instruction = "ASR.l"; break;
|
||||
case Operation::ASRm: instruction = "ASR.w"; break;
|
||||
|
||||
case Operation::LSLb: instruction = "LSL.b"; break;
|
||||
case Operation::LSLw: instruction = "LSL.w"; break;
|
||||
case Operation::LSLl: instruction = "LSL.l"; break;
|
||||
case Operation::LSLm: instruction = "LSL.w"; break;
|
||||
|
||||
case Operation::LSRb: instruction = "LSR.b"; break;
|
||||
case Operation::LSRw: instruction = "LSR.w"; break;
|
||||
case Operation::LSRl: instruction = "LSR.l"; break;
|
||||
case Operation::LSRm: instruction = "LSR.w"; break;
|
||||
|
||||
case Operation::ROLb: instruction = "ROL.b"; break;
|
||||
case Operation::ROLw: instruction = "ROL.w"; break;
|
||||
case Operation::ROLl: instruction = "ROL.l"; break;
|
||||
case Operation::ROLm: instruction = "ROL.w"; break;
|
||||
|
||||
case Operation::RORb: instruction = "ROR.b"; break;
|
||||
case Operation::RORw: instruction = "ROR.w"; break;
|
||||
case Operation::RORl: instruction = "ROR.l"; break;
|
||||
case Operation::RORm: instruction = "ROR.w"; break;
|
||||
|
||||
case Operation::ROXLb: instruction = "ROXL.b"; break;
|
||||
case Operation::ROXLw: instruction = "ROXL.w"; break;
|
||||
case Operation::ROXLl: instruction = "ROXL.l"; break;
|
||||
case Operation::ROXLm: instruction = "ROXL.w"; break;
|
||||
|
||||
case Operation::ROXRb: instruction = "ROXR.b"; break;
|
||||
case Operation::ROXRw: instruction = "ROXR.w"; break;
|
||||
case Operation::ROXRl: instruction = "ROXR.l"; break;
|
||||
case Operation::ROXRm: instruction = "ROXR.w"; break;
|
||||
|
||||
case Operation::MOVEMtoMl: instruction = "MOVEM.l"; break;
|
||||
case Operation::MOVEMtoMw: instruction = "MOVEM.w"; break;
|
||||
case Operation::MOVEMtoRl:
|
||||
instruction = "MOVEM.l";
|
||||
flip_operands = true;
|
||||
break;
|
||||
case Operation::MOVEMtoRw:
|
||||
instruction = "MOVEM.w";
|
||||
flip_operands = true;
|
||||
break;
|
||||
|
||||
case Operation::MOVEPl: instruction = "MOVEP.l"; break;
|
||||
case Operation::MOVEPw: instruction = "MOVEP.w"; break;
|
||||
|
||||
case Operation::ANDb: instruction = "AND.b"; break;
|
||||
case Operation::ANDw: instruction = "AND.w"; break;
|
||||
case Operation::ANDl: instruction = "AND.l"; break;
|
||||
|
||||
case Operation::EORb: instruction = "EOR.b"; break;
|
||||
case Operation::EORw: instruction = "EOR.w"; break;
|
||||
case Operation::EORl: instruction = "EOR.l"; break;
|
||||
|
||||
case Operation::NOTb: instruction = "NOT.b"; break;
|
||||
case Operation::NOTw: instruction = "NOT.w"; break;
|
||||
case Operation::NOTl: instruction = "NOT.l"; break;
|
||||
|
||||
case Operation::ORb: instruction = "OR.b"; break;
|
||||
case Operation::ORw: instruction = "OR.w"; break;
|
||||
case Operation::ORl: instruction = "OR.l"; break;
|
||||
|
||||
case Operation::MULU: instruction = "MULU"; break;
|
||||
case Operation::MULS: instruction = "MULS"; break;
|
||||
case Operation::DIVU: instruction = "DIVU"; break;
|
||||
case Operation::DIVS: instruction = "DIVS"; break;
|
||||
|
||||
case Operation::RTE: instruction = "RTE"; break;
|
||||
case Operation::RTR: instruction = "RTR"; break;
|
||||
|
||||
case Operation::TRAP: instruction = "TRAP"; break;
|
||||
case Operation::TRAPV: instruction = "TRAPV"; break;
|
||||
case Operation::CHK: instruction = "CHK"; break;
|
||||
|
||||
case Operation::EXG: instruction = "EXG"; break;
|
||||
case Operation::SWAP: instruction = "SWAP"; break;
|
||||
|
||||
case Operation::TAS: instruction = "TAS"; break;
|
||||
|
||||
case Operation::EXTbtow: instruction = "EXT.w"; break;
|
||||
case Operation::EXTwtol: instruction = "EXT.l"; break;
|
||||
|
||||
case Operation::LINKw: instruction = "LINK"; break;
|
||||
case Operation::UNLINK: instruction = "UNLINK"; break;
|
||||
|
||||
case Operation::STOP: instruction = "STOP"; break;
|
||||
case Operation::RESET: instruction = "RESET"; break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
const std::string operand1 = operand_description(0 ^ int(flip_operands), opcode);
|
||||
const std::string operand2 = operand_description(1 ^ int(flip_operands), opcode);
|
||||
|
||||
std::string result = instruction;
|
||||
if(!operand1.empty()) result += std::string(" ") + operand1;
|
||||
if(!operand2.empty()) result += std::string(", ") + operand2;
|
||||
|
||||
return result;
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace InstructionSet {
|
||||
namespace M68k {
|
||||
@ -308,6 +309,8 @@ class Preinstruction {
|
||||
uint8_t operands_[2] = { uint8_t(AddressingMode::None), uint8_t(AddressingMode::None)};
|
||||
uint8_t flags_ = 0;
|
||||
|
||||
std::string operand_description(int index, int opcode) const;
|
||||
|
||||
public:
|
||||
Preinstruction(
|
||||
Operation operation,
|
||||
@ -327,6 +330,11 @@ class Preinstruction {
|
||||
}
|
||||
|
||||
Preinstruction() {}
|
||||
|
||||
/// Produces a string description of this instruction; if @c opcode
|
||||
/// is supplied then any quick fields in this instruction will be decoded;
|
||||
/// otherwise they'll be printed as just 'Q'.
|
||||
std::string to_string(int opcode = -1) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -131,6 +131,9 @@
|
||||
4B0ACC3223775819008902D0 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0ACC2223775819008902D0 /* Atari2600.cpp */; };
|
||||
4B0ACC3323775819008902D0 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0ACC2223775819008902D0 /* Atari2600.cpp */; };
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
|
||||
4B0DA67B282DCDF100C12F17 /* Instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0DA67A282DCC4200C12F17 /* Instruction.cpp */; };
|
||||
4B0DA67C282DCDF300C12F17 /* Instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0DA67A282DCC4200C12F17 /* Instruction.cpp */; };
|
||||
4B0DA67D282DCDF300C12F17 /* Instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0DA67A282DCC4200C12F17 /* Instruction.cpp */; };
|
||||
4B0E04EA1FC9E5DA00F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; };
|
||||
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; };
|
||||
4B0E04F11FC9EA9500F43484 /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B79A4FF1FC913C900EEDAD5 /* MSX.cpp */; };
|
||||
@ -1166,6 +1169,7 @@
|
||||
4B0ACC2523775819008902D0 /* TIA.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hpp; sourceTree = "<group>"; };
|
||||
4B0CCC421C62D0B3001CAC5F /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRT.cpp; sourceTree = "<group>"; };
|
||||
4B0CCC431C62D0B3001CAC5F /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRT.hpp; sourceTree = "<group>"; };
|
||||
4B0DA67A282DCC4200C12F17 /* Instruction.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Instruction.cpp; sourceTree = "<group>"; };
|
||||
4B0E04E81FC9E5DA00F43484 /* CAS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAS.cpp; sourceTree = "<group>"; };
|
||||
4B0E04E91FC9E5DA00F43484 /* CAS.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CAS.hpp; sourceTree = "<group>"; };
|
||||
4B0E04F81FC9FA3000F43484 /* 9918.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 9918.hpp; sourceTree = "<group>"; };
|
||||
@ -3201,6 +3205,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B79629F2819681F008130F9 /* Decoder.cpp */,
|
||||
4B0DA67A282DCC4200C12F17 /* Instruction.cpp */,
|
||||
4B79629E2819681F008130F9 /* Decoder.hpp */,
|
||||
4B7C79FE282AFA9B002D6C0B /* ExceptionVectors.hpp */,
|
||||
4BB5B99C281C805300522DA9 /* Executor.hpp */,
|
||||
@ -5623,6 +5628,7 @@
|
||||
4B47F6C6241C87A100ED06F7 /* Struct.cpp in Sources */,
|
||||
4B055AE01FAE9B660060FFFF /* CRT.cpp in Sources */,
|
||||
4B894527201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4B0DA67C282DCDF300C12F17 /* Instruction.cpp in Sources */,
|
||||
4BB244D622AABAF600BE20E5 /* z8530.cpp in Sources */,
|
||||
4BAF2B4F2004580C00480230 /* DMK.cpp in Sources */,
|
||||
4B055AD01FAE9B030060FFFF /* Tape.cpp in Sources */,
|
||||
@ -5829,6 +5835,7 @@
|
||||
4BC080D926A25ADA00D03FD8 /* Amiga.cpp in Sources */,
|
||||
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */,
|
||||
4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */,
|
||||
4B0DA67B282DCDF100C12F17 /* Instruction.cpp in Sources */,
|
||||
4B74CF812312FA9C00500CE8 /* HFV.cpp in Sources */,
|
||||
4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */,
|
||||
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,
|
||||
@ -6039,6 +6046,7 @@
|
||||
4B7752B728217EF40073E2C5 /* Chipset.cpp in Sources */,
|
||||
4B778EFB23A5EB7E0000D260 /* HFE.cpp in Sources */,
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */,
|
||||
4B0DA67D282DCDF300C12F17 /* Instruction.cpp in Sources */,
|
||||
4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */,
|
||||
4B778F2223A5EDDD0000D260 /* PulseQueuedTape.cpp in Sources */,
|
||||
4B778EF123A5D6B50000D260 /* 9918.cpp in Sources */,
|
||||
|
@ -15,51 +15,6 @@ using namespace InstructionSet::M68k;
|
||||
@interface M68000DecoderTests : XCTestCase
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
NSString *operand(Preinstruction instruction, uint16_t opcode, int index) {
|
||||
switch(instruction.mode(index)) {
|
||||
default: return [NSString stringWithFormat:@"[Mode %d?]", int(instruction.mode(index))];
|
||||
|
||||
case AddressingMode::None:
|
||||
return @"";
|
||||
|
||||
case AddressingMode::DataRegisterDirect:
|
||||
return [NSString stringWithFormat:@"D%d", instruction.reg(index)];
|
||||
|
||||
case AddressingMode::AddressRegisterDirect:
|
||||
return [NSString stringWithFormat:@"A%d", instruction.reg(index)];
|
||||
case AddressingMode::AddressRegisterIndirect:
|
||||
return [NSString stringWithFormat:@"(A%d)", instruction.reg(index)];
|
||||
case AddressingMode::AddressRegisterIndirectWithPostincrement:
|
||||
return [NSString stringWithFormat:@"(A%d)+", instruction.reg(index)];
|
||||
case AddressingMode::AddressRegisterIndirectWithPredecrement:
|
||||
return [NSString stringWithFormat:@"-(A%d)", instruction.reg(index)];
|
||||
case AddressingMode::AddressRegisterIndirectWithDisplacement:
|
||||
return [NSString stringWithFormat:@"(d16, A%d)", instruction.reg(index)];
|
||||
case AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement:
|
||||
return [NSString stringWithFormat:@"(d8, A%d, Xn)", instruction.reg(index)];
|
||||
|
||||
case AddressingMode::ProgramCounterIndirectWithDisplacement:
|
||||
return @"(d16, PC)";
|
||||
case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
|
||||
return @"(d8, PC, Xn)";
|
||||
|
||||
case AddressingMode::AbsoluteShort:
|
||||
return @"(xxx).w";
|
||||
case AddressingMode::AbsoluteLong:
|
||||
return @"(xxx).l";
|
||||
|
||||
case AddressingMode::ImmediateData:
|
||||
return @"#";
|
||||
|
||||
case AddressingMode::Quick:
|
||||
return [NSString stringWithFormat:@"%d", quick(opcode, instruction.operation)];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@implementation M68000DecoderTests
|
||||
|
||||
- (void)testInstructionSpecs {
|
||||
@ -81,244 +36,7 @@ NSString *operand(Preinstruction instruction, uint16_t opcode, int index) {
|
||||
|
||||
const auto found = decoder.decode(uint16_t(instr));
|
||||
|
||||
NSString *instruction;
|
||||
bool flipOperands = false;
|
||||
switch(found.operation) {
|
||||
case Operation::Undefined: instruction = @"None"; break;
|
||||
case Operation::NOP: instruction = @"NOP"; break;
|
||||
case Operation::ABCD: instruction = @"ABCD"; break;
|
||||
case Operation::SBCD: instruction = @"SBCD"; break;
|
||||
case Operation::NBCD: instruction = @"NBCD"; break;
|
||||
|
||||
case Operation::ADDb: instruction = @"ADD.b"; break;
|
||||
case Operation::ADDw: instruction = @"ADD.w"; break;
|
||||
case Operation::ADDl: instruction = @"ADD.l"; break;
|
||||
|
||||
case Operation::ADDAw:
|
||||
if(found.mode<0>() == AddressingMode::Quick) {
|
||||
instruction = @"ADD.w";
|
||||
} else {
|
||||
instruction = @"ADDA.w";
|
||||
}
|
||||
break;
|
||||
case Operation::ADDAl:
|
||||
if(found.mode<0>() == AddressingMode::Quick) {
|
||||
instruction = @"ADD.l";
|
||||
} else {
|
||||
instruction = @"ADDA.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::ADDXb: instruction = @"ADDX.b"; break;
|
||||
case Operation::ADDXw: instruction = @"ADDX.w"; break;
|
||||
case Operation::ADDXl: instruction = @"ADDX.l"; break;
|
||||
|
||||
case Operation::SUBb: instruction = @"SUB.b"; break;
|
||||
case Operation::SUBw: instruction = @"SUB.w"; break;
|
||||
case Operation::SUBl: instruction = @"SUB.l"; break;
|
||||
|
||||
case Operation::SUBAw:
|
||||
if(found.mode<0>() == AddressingMode::Quick) {
|
||||
instruction = @"SUB.w";
|
||||
} else {
|
||||
instruction = @"SUBA.w";
|
||||
}
|
||||
break;
|
||||
case Operation::SUBAl:
|
||||
if(found.mode<0>() == AddressingMode::Quick) {
|
||||
instruction = @"SUB.l";
|
||||
} else {
|
||||
instruction = @"SUBA.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::SUBXb: instruction = @"SUBX.b"; break;
|
||||
case Operation::SUBXw: instruction = @"SUBX.w"; break;
|
||||
case Operation::SUBXl: instruction = @"SUBX.l"; break;
|
||||
|
||||
case Operation::MOVEb: instruction = @"MOVE.b"; break;
|
||||
case Operation::MOVEw: instruction = @"MOVE.w"; break;
|
||||
case Operation::MOVEl:
|
||||
if(found.mode<0>() == AddressingMode::Quick) {
|
||||
instruction = @"MOVE.q";
|
||||
} else {
|
||||
instruction = @"MOVE.l";
|
||||
}
|
||||
break;
|
||||
|
||||
case Operation::MOVEAw: instruction = @"MOVEA.w"; break;
|
||||
case Operation::MOVEAl: instruction = @"MOVEA.l"; break;
|
||||
|
||||
case Operation::LEA: instruction = @"LEA"; break;
|
||||
case Operation::PEA: instruction = @"PEA"; break;
|
||||
|
||||
case Operation::MOVEtoSR: instruction = @"MOVEtoSR"; break;
|
||||
case Operation::MOVEfromSR: instruction = @"MOVEfromSR"; break;
|
||||
case Operation::MOVEtoCCR: instruction = @"MOVEtoCCR"; break;
|
||||
case Operation::MOVEtoUSP: instruction = @"MOVEtoUSP"; break;
|
||||
case Operation::MOVEfromUSP: instruction = @"MOVEfromUSP"; break;
|
||||
|
||||
case Operation::ORItoSR: instruction = @"ORItoSR"; break;
|
||||
case Operation::ORItoCCR: instruction = @"ORItoCCR"; break;
|
||||
case Operation::ANDItoSR: instruction = @"ANDItoSR"; break;
|
||||
case Operation::ANDItoCCR: instruction = @"ANDItoCCR"; break;
|
||||
case Operation::EORItoSR: instruction = @"EORItoSR"; break;
|
||||
case Operation::EORItoCCR: instruction = @"EORItoCCR"; break;
|
||||
|
||||
case Operation::BTST: instruction = @"BTST"; break;
|
||||
case Operation::BCLR: instruction = @"BCLR"; break;
|
||||
case Operation::BCHG: instruction = @"BCHG"; break;
|
||||
case Operation::BSET: instruction = @"BSET"; break;
|
||||
|
||||
case Operation::CMPb: instruction = @"CMP.b"; break;
|
||||
case Operation::CMPw: instruction = @"CMP.w"; break;
|
||||
case Operation::CMPl: instruction = @"CMP.l"; break;
|
||||
|
||||
case Operation::CMPAw: instruction = @"CMPA.w"; break;
|
||||
case Operation::CMPAl: instruction = @"CMPA.l"; break;
|
||||
|
||||
case Operation::TSTb: instruction = @"TST.b"; break;
|
||||
case Operation::TSTw: instruction = @"TST.w"; break;
|
||||
case Operation::TSTl: instruction = @"TST.l"; break;
|
||||
|
||||
case Operation::JMP: instruction = @"JMP"; break;
|
||||
case Operation::JSR: instruction = @"JSR"; break;
|
||||
case Operation::RTS: instruction = @"RTS"; break;
|
||||
case Operation::DBcc: instruction = @"DBcc"; break;
|
||||
case Operation::Scc: instruction = @"Scc"; break;
|
||||
|
||||
case Operation::Bccb:
|
||||
case Operation::Bccl:
|
||||
case Operation::Bccw: instruction = @"Bcc"; break;
|
||||
|
||||
case Operation::BSRb:
|
||||
case Operation::BSRl:
|
||||
case Operation::BSRw: instruction = @"BSR"; break;
|
||||
|
||||
case Operation::CLRb: instruction = @"CLR.b"; break;
|
||||
case Operation::CLRw: instruction = @"CLR.w"; break;
|
||||
case Operation::CLRl: instruction = @"CLR.l"; break;
|
||||
|
||||
case Operation::NEGXb: instruction = @"NEGX.b"; break;
|
||||
case Operation::NEGXw: instruction = @"NEGX.w"; break;
|
||||
case Operation::NEGXl: instruction = @"NEGX.l"; break;
|
||||
|
||||
case Operation::NEGb: instruction = @"NEG.b"; break;
|
||||
case Operation::NEGw: instruction = @"NEG.w"; break;
|
||||
case Operation::NEGl: instruction = @"NEG.l"; break;
|
||||
|
||||
case Operation::ASLb: instruction = @"ASL.b"; break;
|
||||
case Operation::ASLw: instruction = @"ASL.w"; break;
|
||||
case Operation::ASLl: instruction = @"ASL.l"; break;
|
||||
case Operation::ASLm: instruction = @"ASL.w"; break;
|
||||
|
||||
case Operation::ASRb: instruction = @"ASR.b"; break;
|
||||
case Operation::ASRw: instruction = @"ASR.w"; break;
|
||||
case Operation::ASRl: instruction = @"ASR.l"; break;
|
||||
case Operation::ASRm: instruction = @"ASR.w"; break;
|
||||
|
||||
case Operation::LSLb: instruction = @"LSL.b"; break;
|
||||
case Operation::LSLw: instruction = @"LSL.w"; break;
|
||||
case Operation::LSLl: instruction = @"LSL.l"; break;
|
||||
case Operation::LSLm: instruction = @"LSL.w"; break;
|
||||
|
||||
case Operation::LSRb: instruction = @"LSR.b"; break;
|
||||
case Operation::LSRw: instruction = @"LSR.w"; break;
|
||||
case Operation::LSRl: instruction = @"LSR.l"; break;
|
||||
case Operation::LSRm: instruction = @"LSR.w"; break;
|
||||
|
||||
case Operation::ROLb: instruction = @"ROL.b"; break;
|
||||
case Operation::ROLw: instruction = @"ROL.w"; break;
|
||||
case Operation::ROLl: instruction = @"ROL.l"; break;
|
||||
case Operation::ROLm: instruction = @"ROL.w"; break;
|
||||
|
||||
case Operation::RORb: instruction = @"ROR.b"; break;
|
||||
case Operation::RORw: instruction = @"ROR.w"; break;
|
||||
case Operation::RORl: instruction = @"ROR.l"; break;
|
||||
case Operation::RORm: instruction = @"ROR.w"; break;
|
||||
|
||||
case Operation::ROXLb: instruction = @"ROXL.b"; break;
|
||||
case Operation::ROXLw: instruction = @"ROXL.w"; break;
|
||||
case Operation::ROXLl: instruction = @"ROXL.l"; break;
|
||||
case Operation::ROXLm: instruction = @"ROXL.w"; break;
|
||||
|
||||
case Operation::ROXRb: instruction = @"ROXR.b"; break;
|
||||
case Operation::ROXRw: instruction = @"ROXR.w"; break;
|
||||
case Operation::ROXRl: instruction = @"ROXR.l"; break;
|
||||
case Operation::ROXRm: instruction = @"ROXR.w"; break;
|
||||
|
||||
case Operation::MOVEMtoMl: instruction = @"MOVEM.l"; break;
|
||||
case Operation::MOVEMtoMw: instruction = @"MOVEM.w"; break;
|
||||
case Operation::MOVEMtoRl:
|
||||
instruction = @"MOVEM.l";
|
||||
flipOperands = true;
|
||||
break;
|
||||
case Operation::MOVEMtoRw:
|
||||
instruction = @"MOVEM.w";
|
||||
flipOperands = true;
|
||||
break;
|
||||
|
||||
case Operation::MOVEPl: instruction = @"MOVEP.l"; break;
|
||||
case Operation::MOVEPw: instruction = @"MOVEP.w"; break;
|
||||
|
||||
case Operation::ANDb: instruction = @"AND.b"; break;
|
||||
case Operation::ANDw: instruction = @"AND.w"; break;
|
||||
case Operation::ANDl: instruction = @"AND.l"; break;
|
||||
|
||||
case Operation::EORb: instruction = @"EOR.b"; break;
|
||||
case Operation::EORw: instruction = @"EOR.w"; break;
|
||||
case Operation::EORl: instruction = @"EOR.l"; break;
|
||||
|
||||
case Operation::NOTb: instruction = @"NOT.b"; break;
|
||||
case Operation::NOTw: instruction = @"NOT.w"; break;
|
||||
case Operation::NOTl: instruction = @"NOT.l"; break;
|
||||
|
||||
case Operation::ORb: instruction = @"OR.b"; break;
|
||||
case Operation::ORw: instruction = @"OR.w"; break;
|
||||
case Operation::ORl: instruction = @"OR.l"; break;
|
||||
|
||||
case Operation::MULU: instruction = @"MULU"; break;
|
||||
case Operation::MULS: instruction = @"MULS"; break;
|
||||
case Operation::DIVU: instruction = @"DIVU"; break;
|
||||
case Operation::DIVS: instruction = @"DIVS"; break;
|
||||
|
||||
case Operation::RTE: instruction = @"RTE"; break;
|
||||
case Operation::RTR: instruction = @"RTR"; break;
|
||||
|
||||
case Operation::TRAP: instruction = @"TRAP"; break;
|
||||
case Operation::TRAPV: instruction = @"TRAPV"; break;
|
||||
case Operation::CHK: instruction = @"CHK"; break;
|
||||
|
||||
case Operation::EXG: instruction = @"EXG"; break;
|
||||
case Operation::SWAP: instruction = @"SWAP"; break;
|
||||
|
||||
case Operation::TAS: instruction = @"TAS"; break;
|
||||
|
||||
case Operation::EXTbtow: instruction = @"EXT.w"; break;
|
||||
case Operation::EXTwtol: instruction = @"EXT.l"; break;
|
||||
|
||||
case Operation::LINKw: instruction = @"LINK"; break;
|
||||
case Operation::UNLINK: instruction = @"UNLINK"; break;
|
||||
|
||||
case Operation::STOP: instruction = @"STOP"; break;
|
||||
case Operation::RESET: instruction = @"RESET"; break;
|
||||
|
||||
// For now, skip any unmapped operations.
|
||||
default:
|
||||
XCTAssert(false, @"Operation %d unhandled by test case", int(found.operation));
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString *const operand1 = operand(found, uint16_t(instr), 0 ^ int(flipOperands));
|
||||
NSString *const operand2 = operand(found, uint16_t(instr), 1 ^ int(flipOperands));
|
||||
|
||||
if(operand1.length) instruction = [instruction stringByAppendingFormat:@" %@", operand1];
|
||||
if(operand2.length) instruction = [instruction stringByAppendingFormat:@", %@", operand2];
|
||||
|
||||
XCTAssertFalse(
|
||||
found.mode(0 ^ int(flipOperands)) == AddressingMode::None &&
|
||||
found.mode(1 ^ int(flipOperands)) != AddressingMode::None,
|
||||
@"Decoding of %@ provided a second operand but not a first", instrName);
|
||||
NSString *const instruction = [NSString stringWithUTF8String:found.to_string(instr).c_str()];
|
||||
XCTAssertEqualObjects(instruction, expected, "%@ should decode as %@; got %@", instrName, expected, instruction);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user