1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Introduce/extend 68k enums to cover 68020 instruction set.

This commit is contained in:
Thomas Harte 2022-10-22 15:20:30 -04:00
parent cb0e259339
commit 9a56d053f8
9 changed files with 145 additions and 57 deletions

View File

@ -154,6 +154,7 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
constexpr auto d8PCXn = Mask< AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement >::value; constexpr auto d8PCXn = Mask< AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement >::value;
constexpr auto Imm = Mask< AddressingMode::ImmediateData >::value; constexpr auto Imm = Mask< AddressingMode::ImmediateData >::value;
constexpr auto Quick = Mask< AddressingMode::Quick >::value; constexpr auto Quick = Mask< AddressingMode::Quick >::value;
constexpr auto Ext = Mask< AddressingMode::ExtensionWord >::value;
// A few recurring combinations; terminology is directly from // A few recurring combinations; terminology is directly from
// the Programmers' Reference Manual. // the Programmers' Reference Manual.
@ -191,11 +192,11 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
case ADDtoRb: case ADDtoRb:
case ANDtoRb: case ANDtoRw: case ANDtoRl: case ANDtoRb: case ANDtoRw: case ANDtoRl:
case OpT(Operation::CHK): case OpT(Operation::CHKw):
case OpT(Operation::CMPb): case OpT(Operation::CMPb):
case OpT(Operation::DIVU): case OpT(Operation::DIVS): case OpT(Operation::DIVUw): case OpT(Operation::DIVSw):
case ORtoRb: case ORtoRw: case ORtoRl: case ORtoRb: case ORtoRw: case ORtoRl:
case OpT(Operation::MULU): case OpT(Operation::MULS): case OpT(Operation::MULUw): case OpT(Operation::MULSw):
case SUBtoRb: case SUBtoRb:
return ~TwoOperandMask< return ~TwoOperandMask<
AllModesNoAn, AllModesNoAn,
@ -473,6 +474,11 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
case OpT(Operation::RESET): case OpT(Operation::RESET):
return ~NoOperandMask::value; return ~NoOperandMask::value;
case OpT(Operation::RTM):
return ~OneOperandMask<
An | Dn
>::value;
case OpT(Operation::UNLINK): case OpT(Operation::UNLINK):
case OpT(Operation::MOVEtoUSP): case OpT(Operation::MOVEtoUSP):
case OpT(Operation::MOVEfromUSP): case OpT(Operation::MOVEfromUSP):
@ -482,13 +488,13 @@ template <uint8_t op> uint32_t Predecoder<model>::invalid_operands() {
case OpT(Operation::MOVEMtoMw): case OpT(Operation::MOVEMtoMl): case OpT(Operation::MOVEMtoMw): case OpT(Operation::MOVEMtoMl):
return ~TwoOperandMask< return ~TwoOperandMask<
Imm, Ext,
Ind | PreDec | d16An | d8AnXn | XXXw | XXXl Ind | PreDec | d16An | d8AnXn | XXXw | XXXl
>::value; >::value;
case OpT(Operation::MOVEMtoRw): case OpT(Operation::MOVEMtoRl): case OpT(Operation::MOVEMtoRw): case OpT(Operation::MOVEMtoRl):
return ~TwoOperandMask< return ~TwoOperandMask<
Imm, Ext,
Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn Ind | PostInc | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn
>::value; >::value;
@ -664,7 +670,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// Implicitly: destination is a register; // Implicitly: destination is a register;
// b0b2 and b3b5: source effective address. // b0b2 and b3b5: source effective address.
// //
case OpT(Operation::CHK): case OpT(Operation::CHKw):
return validated<op, validate>( return validated<op, validate>(
combined_mode(ea_mode, ea_register), ea_register, combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register); AddressingMode::DataRegisterDirect, data_register);
@ -697,12 +703,23 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
// b9b11: destination data register; // b9b11: destination data register;
// b0b2 and b3b5: source effective address. // b0b2 and b3b5: source effective address.
// //
case OpT(Operation::DIVU): case OpT(Operation::DIVS): case OpT(Operation::DIVUw): case OpT(Operation::DIVSw):
case OpT(Operation::MULU): case OpT(Operation::MULS): case OpT(Operation::MULUw): case OpT(Operation::MULSw):
return validated<op, validate>( return validated<op, validate>(
combined_mode(ea_mode, ea_register), ea_register, combined_mode(ea_mode, ea_register), ea_register,
AddressingMode::DataRegisterDirect, data_register); AddressingMode::DataRegisterDirect, data_register);
//
// MARK: DIVSl.
//
// b0b2 and b3b5: source effective address.
// Plus an immediate word operand
//
case OpT(Operation::DIVSl):
return validated<op, validate>(
AddressingMode::ExtensionWord, 0,
combined_mode(ea_mode, ea_register), ea_register);
// //
// MARK: LEA // MARK: LEA
// //
@ -823,7 +840,7 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::MOVEMtoMl): case OpT(Operation::MOVEMtoMw): case OpT(Operation::MOVEMtoMl): case OpT(Operation::MOVEMtoMw):
case OpT(Operation::MOVEMtoRl): case OpT(Operation::MOVEMtoRw): case OpT(Operation::MOVEMtoRl): case OpT(Operation::MOVEMtoRw):
return validated<op, validate>( return validated<op, validate>(
AddressingMode::ImmediateData, 0, AddressingMode::ExtensionWord, 0,
combined_mode(ea_mode, ea_register), ea_register); combined_mode(ea_mode, ea_register), ea_register);
// //
@ -943,6 +960,24 @@ template <uint8_t op, bool validate> Preinstruction Predecoder<model>::decode(ui
case OpT(Operation::RTD): case OpT(Operation::RTD):
return validated<op, validate>(AddressingMode::ImmediateData); return validated<op, validate>(AddressingMode::ImmediateData);
//
// MARK: RTM
//
// b0b2: a register number;
// b3: address/data register selection.
//
case OpT(Operation::RTM): {
const auto addressing_mode = (instruction & 8) ?
AddressingMode::AddressRegisterDirect : AddressingMode::DataRegisterDirect;
return validated<op, validate>(addressing_mode, ea_register);
}
//
// MARK: DIVl
//
//
// //
// MARK: Impossible error case. // MARK: Impossible error case.
// //
@ -969,6 +1004,16 @@ Preinstruction Predecoder<model>::decode0(uint16_t instruction) {
case 0xa3c: Decode(Op::EORItoCCR); // 4-104 (p208) case 0xa3c: Decode(Op::EORItoCCR); // 4-104 (p208)
case 0xa7c: Decode(Op::EORItoSR); // 6-10 (p464) case 0xa7c: Decode(Op::EORItoSR); // 6-10 (p464)
// 4-68 (p172)
case 0xcfc: DecodeReq(model >= Model::M68020, Op::CAS2w);
case 0xefc: DecodeReq(model >= Model::M68020, Op::CAS2l);
default: break;
}
switch(instruction & 0xff0) {
case 0x6c0: DecodeReq(model == Model::M68020, Op::RTM); // 4-167 (p271)
default: break; default: break;
} }
@ -1015,7 +1060,23 @@ Preinstruction Predecoder<model>::decode0(uint16_t instruction) {
case 0xc40: Decode(CMPIw); case 0xc40: Decode(CMPIw);
case 0xc80: Decode(CMPIl); case 0xc80: Decode(CMPIl);
case 0x6c0: DecodeReq(model == Model::M68020, Op::CALLM); // 4-64 (p168) // 4-64 (p168)
case 0x6c0: DecodeReq(model == Model::M68020, Op::CALLM);
// 4-67 (p171)
case 0xac0: DecodeReq(model >= Model::M68020, Op::CASb);
case 0xcc0: DecodeReq(model >= Model::M68020, Op::CASw);
case 0xec0: DecodeReq(model >= Model::M68020, Op::CASl);
// 4-72 (p176)
case 0x0c0: DecodeReq(model >= Model::M68020, Op::CHK2b);
case 0x2c0: DecodeReq(model >= Model::M68020, Op::CHK2w);
case 0x4c0: DecodeReq(model >= Model::M68020, Op::CHK2l);
// 4-83 (p187)
case 0x00c: DecodeReq(model >= Model::M68020, Op::CMP2b);
case 0x02c: DecodeReq(model >= Model::M68020, Op::CMP2w);
case 0x04c: DecodeReq(model >= Model::M68020, Op::CMP2l);
default: break; default: break;
} }
@ -1163,12 +1224,15 @@ Preinstruction Predecoder<model>::decode4(uint16_t instruction) {
// 4-108 (p212) // 4-108 (p212)
case 0xec0: Decode(Op::JMP); case 0xec0: Decode(Op::JMP);
// 4-94 (p198)
case 0xc40: Decode(Op::DIVSl);
default: break; default: break;
} }
switch(instruction & 0x1c0) { switch(instruction & 0x1c0) {
case 0x1c0: Decode(Op::LEA); // 4-110 (p214) case 0x1c0: Decode(Op::LEA); // 4-110 (p214)
case 0x180: Decode(Op::CHK); // 4-69 (p173) case 0x180: Decode(Op::CHKw); // 4-69 (p173)
default: break; default: break;
} }
@ -1292,8 +1356,8 @@ Preinstruction Predecoder<model>::decode8(uint16_t instruction) {
if((instruction & 0x1f0) == 0x100) Decode(Op::SBCD); if((instruction & 0x1f0) == 0x100) Decode(Op::SBCD);
switch(instruction & 0x1c0) { switch(instruction & 0x1c0) {
case 0x0c0: Decode(Op::DIVU); // 4-97 (p201) case 0x0c0: Decode(Op::DIVUw); // 4-97 (p201)
case 0x1c0: Decode(Op::DIVS); // 4-93 (p197) case 0x1c0: Decode(Op::DIVSw); // 4-93 (p197)
// 4-150 (p254) // 4-150 (p254)
case 0x000: Decode(ORtoRb); case 0x000: Decode(ORtoRb);
@ -1398,8 +1462,8 @@ Preinstruction Predecoder<model>::decodeC(uint16_t instruction) {
} }
switch(instruction & 0x1c0) { switch(instruction & 0x1c0) {
case 0x0c0: Decode(Op::MULU); // 4-139 (p243) case 0x0c0: Decode(Op::MULUw); // 4-139 (p243)
case 0x1c0: Decode(Op::MULS); // 4-136 (p240) case 0x1c0: Decode(Op::MULSw); // 4-136 (p240)
// 4-15 (p119) // 4-15 (p119)
case 0x000: Decode(ANDtoRb); case 0x000: Decode(ANDtoRb);

View File

@ -81,7 +81,7 @@ template <Model model, Operation t_operation> constexpr uint8_t operand_flags(Op
// //
case Operation::CMPb: case Operation::CMPw: case Operation::CMPl: case Operation::CMPb: case Operation::CMPw: case Operation::CMPl:
case Operation::CMPAw: case Operation::CMPAl: case Operation::CMPAw: case Operation::CMPAl:
case Operation::CHK: case Operation::CHKw:
case Operation::BTST: case Operation::BTST:
case Operation::LINKw: case Operation::LINKw:
return FetchOp1 | FetchOp2; return FetchOp1 | FetchOp2;
@ -106,8 +106,8 @@ template <Model model, Operation t_operation> constexpr uint8_t operand_flags(Op
case Operation::ORb: case Operation::ORw: case Operation::ORl: case Operation::ORb: case Operation::ORw: case Operation::ORl:
case Operation::ANDb: case Operation::ANDw: case Operation::ANDl: case Operation::ANDb: case Operation::ANDw: case Operation::ANDl:
case Operation::EORb: case Operation::EORw: case Operation::EORl: case Operation::EORb: case Operation::EORw: case Operation::EORl:
case Operation::DIVU: case Operation::DIVS: case Operation::DIVUw: case Operation::DIVSw:
case Operation::MULU: case Operation::MULS: case Operation::MULUw: case Operation::MULSw:
case Operation::ASLb: case Operation::ASLw: case Operation::ASLl: case Operation::ASLb: case Operation::ASLw: case Operation::ASLl:
case Operation::ASRb: case Operation::ASRw: case Operation::ASRl: case Operation::ASRb: case Operation::ASRw: case Operation::ASRl:
case Operation::LSLb: case Operation::LSLw: case Operation::LSLl: case Operation::LSLb: case Operation::LSLw: case Operation::LSLl:

View File

@ -80,11 +80,11 @@ constexpr DataSize operand_size(Operation r_operation) {
case Operation::MOVEPw: case Operation::MOVEPw:
case Operation::ANDw: case Operation::EORw: case Operation::ANDw: case Operation::EORw:
case Operation::NOTw: case Operation::ORw: case Operation::NOTw: case Operation::ORw:
case Operation::DIVU: case Operation::DIVS: case Operation::DIVUw: case Operation::DIVSw:
case Operation::MULU: case Operation::MULS: case Operation::MULUw: case Operation::MULSw:
case Operation::EXTbtow: case Operation::EXTbtow:
case Operation::LINKw: case Operation::LINKw:
case Operation::CHK: case Operation::CHKw:
return DataSize::Word; return DataSize::Word;
case Operation::ADDl: case Operation::ADDAl: case Operation::ADDl: case Operation::ADDAl:

View File

@ -742,15 +742,15 @@ template <
Multiplications. Multiplications.
*/ */
case Operation::MULU: Primitive::multiply<true>(src.w, dest.l, status, flow_controller); break; case Operation::MULUw: Primitive::multiply<true>(src.w, dest.l, status, flow_controller); break;
case Operation::MULS: Primitive::multiply<false>(src.w, dest.l, status, flow_controller); break; case Operation::MULSw: Primitive::multiply<false>(src.w, dest.l, status, flow_controller); break;
/* /*
Divisions. Divisions.
*/ */
case Operation::DIVU: Primitive::divide<true, uint16_t, uint32_t>(src.w, dest.l, status, flow_controller); break; case Operation::DIVUw: Primitive::divide<true, uint16_t, uint32_t>(src.w, dest.l, status, flow_controller); break;
case Operation::DIVS: Primitive::divide<false, int16_t, int32_t>(src.w, dest.l, status, flow_controller); break; case Operation::DIVSw: Primitive::divide<false, int16_t, int32_t>(src.w, dest.l, status, flow_controller); break;
// TRAP, which is a nicer form of ILLEGAL. // TRAP, which is a nicer form of ILLEGAL.
case Operation::TRAP: case Operation::TRAP:
@ -763,7 +763,7 @@ template <
} }
} break; } break;
case Operation::CHK: { case Operation::CHKw: {
const bool is_under = s_extend16(dest.w) < 0; const bool is_under = s_extend16(dest.w) < 0;
const bool is_over = s_extend16(dest.w) > s_extend16(src.w); const bool is_over = s_extend16(dest.w) > s_extend16(src.w);

View File

@ -217,17 +217,17 @@ const char *_to_string(Operation operation, bool is_quick) {
case Operation::ORw: return "OR.w"; case Operation::ORw: return "OR.w";
case Operation::ORl: return "OR.l"; case Operation::ORl: return "OR.l";
case Operation::MULU: return "MULU"; case Operation::MULUw: return "MULU";
case Operation::MULS: return "MULS"; case Operation::MULSw: return "MULS";
case Operation::DIVU: return "DIVU"; case Operation::DIVUw: return "DIVU";
case Operation::DIVS: return "DIVS"; case Operation::DIVSw: return "DIVS";
case Operation::RTE: return "RTE"; case Operation::RTE: return "RTE";
case Operation::RTR: return "RTR"; case Operation::RTR: return "RTR";
case Operation::TRAP: return "TRAP"; case Operation::TRAP: return "TRAP";
case Operation::TRAPV: return "TRAPV"; case Operation::TRAPV: return "TRAPV";
case Operation::CHK: return "CHK"; case Operation::CHKw: return "CHK";
case Operation::EXG: return "EXG"; case Operation::EXG: return "EXG";
case Operation::SWAP: return "SWAP"; case Operation::SWAP: return "SWAP";

View File

@ -61,8 +61,8 @@ enum class Operation: uint8_t {
DBcc, DBcc,
Scc, Scc,
Bccb, Bccw, Bccl, Bccb, Bccw,
BSRb, BSRw, BSRl, BSRb, BSRw,
CLRb, CLRw, CLRl, CLRb, CLRw, CLRl,
NEGXb, NEGXw, NEGXl, NEGXb, NEGXw, NEGXl,
@ -87,13 +87,13 @@ enum class Operation: uint8_t {
NOTb, NOTw, NOTl, NOTb, NOTw, NOTl,
ORb, ORw, ORl, ORb, ORw, ORl,
MULU, MULS, MULUw, MULSw,
DIVU, DIVS, DIVUw, DIVSw,
RTE, RTR, RTE, RTR,
TRAP, TRAPV, TRAP, TRAPV,
CHK, CHKw,
EXG, SWAP, EXG, SWAP,
@ -108,23 +108,30 @@ enum class Operation: uint8_t {
// //
// 68020 additions. // 68020 additions.
// //
BKPT, BKPT, TRAPcc,
CALLM, RTD, RTM,
BFCHG, BFCLR, BFCHG, BFCLR,
BFEXTS, BFEXTU, BFEXTS, BFEXTU,
BFFFO, BFINS, BFFFO, BFINS,
BFSET, BFTST, BFSET, BFTST,
CALLM, RTD, RTM,
CAS, CAS2,
CHK2, CMP2,
DIVSL,
EXTbtol,
PACK, UNPK, PACK, UNPK,
TRAPcc, CASb, CASw, CASl,
CAS2w, CAS2l,
CHK2b, CHK2w, CHK2l,
CMP2b, CMP2w, CMP2l,
DIVSl, DIVUl,
MULSl, MULUl,
Bccl, BSRl,
LINKl, CHKl,
EXTbtol,
cpBcc, cpDBcc, cpGEN, cpBcc, cpDBcc, cpGEN,
cpScc, cpTRAPcc, cpRESTORE, cpScc, cpTRAPcc, cpRESTORE,
@ -285,6 +292,10 @@ enum class AddressingMode: uint8_t {
/// # /// #
ImmediateData = 0b01'100, ImmediateData = 0b01'100,
/// An additional word of data. Differs from ImmediateData by being
/// a fixed size, rather than the @c operand_size of the operation.
ExtensionWord = 0b01'111,
/// .q; value is embedded in the opcode. /// .q; value is embedded in the opcode.
Quick = 0b01'110, Quick = 0b01'110,
}; };

View File

@ -438,8 +438,8 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
// For DIVU and DIVS, for now, test only the well-defined flags. // For DIVU and DIVS, for now, test only the well-defined flags.
if( if(
instruction.operation != InstructionSet::M68k::Operation::DIVS && instruction.operation != InstructionSet::M68k::Operation::DIVSw &&
instruction.operation != InstructionSet::M68k::Operation::DIVU instruction.operation != InstructionSet::M68k::Operation::DIVUw
) { ) {
[_failures addObject:name]; [_failures addObject:name];
} else { } else {

View File

@ -540,17 +540,17 @@ void print_transactions(FILE *target, const std::vector<Transaction> &transactio
InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An) InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An)
InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning. InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning.
InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning. InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning.
InstructionSet::M68k::Operation::CHK, // Old implementation pauses four cycles too long. InstructionSet::M68k::Operation::CHKw, // Old implementation pauses four cycles too long.
InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts.
// //
// Operations with timing discrepancies between the two 68000 implementations // Operations with timing discrepancies between the two 68000 implementations
// that I think are _more_ accurate now, but possibly still need work: // that I think are _more_ accurate now, but possibly still need work:
// //
InstructionSet::M68k::Operation::MULU, InstructionSet::M68k::Operation::MULUw,
InstructionSet::M68k::Operation::MULS, InstructionSet::M68k::Operation::MULSw,
InstructionSet::M68k::Operation::DIVU, InstructionSet::M68k::Operation::DIVUw,
InstructionSet::M68k::Operation::DIVS, InstructionSet::M68k::Operation::DIVSw,
}; };
int testsRun = 0; int testsRun = 0;

View File

@ -826,7 +826,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
MoveToStateSpecific(TwoOp_Predec_bw); MoveToStateSpecific(TwoOp_Predec_bw);
} }
StdCASE(CHK, perform_state_ = CHK); StdCASE(CHKw, perform_state_ = CHK);
Duplicate(SUBb, ADDb) StdCASE(ADDb, perform_state_ = Perform_np) Duplicate(SUBb, ADDb) StdCASE(ADDb, perform_state_ = Perform_np)
Duplicate(SUBw, ADDw) StdCASE(ADDw, perform_state_ = Perform_np) Duplicate(SUBw, ADDw) StdCASE(ADDw, perform_state_ = Perform_np)
@ -1002,10 +1002,10 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
StdCASE(TSTw, perform_state_ = Perform_np); StdCASE(TSTw, perform_state_ = Perform_np);
StdCASE(TSTl, perform_state_ = Perform_np); StdCASE(TSTl, perform_state_ = Perform_np);
StdCASE(DIVU, perform_state_ = DIVU_DIVS); StdCASE(DIVUw, perform_state_ = DIVU_DIVS);
StdCASE(DIVS, perform_state_ = DIVU_DIVS); StdCASE(DIVSw, perform_state_ = DIVU_DIVS);
StdCASE(MULU, perform_state_ = Perform_idle_dyamic_Dn); StdCASE(MULUw, perform_state_ = Perform_idle_dyamic_Dn);
StdCASE(MULS, perform_state_ = Perform_idle_dyamic_Dn); StdCASE(MULSw, perform_state_ = Perform_idle_dyamic_Dn);
StdCASE(LEA, { StdCASE(LEA, {
post_ea_state_ = LEA; post_ea_state_ = LEA;
@ -1833,6 +1833,19 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
Prefetch(); // np Prefetch(); // np
MoveToNextOperand(FetchOperand_l); MoveToNextOperand(FetchOperand_l);
//
// ExtensionWord; always the same size.
//
BeginStateMode(FetchOperand_bw, ExtensionWord):
operand_[next_operand_].w = prefetch_.w;
Prefetch(); // np
MoveToNextOperand(FetchOperand_bw);
BeginStateMode(FetchOperand_l, ExtensionWord):
operand_[next_operand_].w = prefetch_.w;
Prefetch(); // np
MoveToNextOperand(FetchOperand_l);
#undef MoveToNextOperand #undef MoveToNextOperand
// MARK: - Store. // MARK: - Store.
@ -2033,7 +2046,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// //
BeginState(CHK): BeginState(CHK):
Prefetch(); // np Prefetch(); // np
PerformSpecific(CHK); PerformSpecific(CHKw);
// Proper next state will have been set by the flow controller // Proper next state will have been set by the flow controller
// call-in; just allow dispatch to whatever it was. // call-in; just allow dispatch to whatever it was.