1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Further clean up copy-and-paste mess.

This commit is contained in:
Thomas Harte 2023-10-11 14:36:42 -04:00
parent 7159366360
commit a768b101f8
4 changed files with 70 additions and 176 deletions

View File

@ -80,7 +80,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
#define Displacement(op, size) \
SetOperation(Operation::op); \
phase_ = Phase::DisplacementOrOperand; \
displacement_size_ = size
operation_size_= displacement_size_ = size
/// Handles PUSH [immediate], etc — anything with only an immediate operand.
#define Immediate(op, size) \
@ -90,11 +90,11 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
operand_size_ = size
/// Handles far CALL and far JMP — fixed four or six byte operand operations.
#define Far(op) \
SetOperation(Operation::op); \
phase_ = Phase::DisplacementOrOperand; \
operand_size_ = DataSize::Word; \
destination_ = Source::Immediate; \
#define Far(op) \
SetOperation(Operation::op); \
phase_ = Phase::DisplacementOrOperand; \
operation_size_ = operand_size_ = DataSize::Word; \
destination_ = Source::Immediate; \
displacement_size_ = data_size(default_address_size_)
/// Handles ENTER — a fixed three-byte operation.
@ -353,7 +353,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0x8e: MemRegReg(MOV, Seg_MemReg, DataSize::Word); break;
case 0x8f: MemRegReg(POP, MemRegSingleOperand, data_size_); break;
case 0x90: Complete(NOP, None, None, DataSize::None); break; // Or XCHG AX, AX?
case 0x90: Complete(NOP, None, None, DataSize::Byte); break; // Could be encoded as XCHG AX, AX if Operation space becomes limited.
case 0x91: Complete(XCHG, eAX, eCX, data_size_); break;
case 0x92: Complete(XCHG, eAX, eDX, data_size_); break;
case 0x93: Complete(XCHG, eAX, eBX, data_size_); break;
@ -365,7 +365,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0x98: Complete(CBW, eAX, AH, data_size_); break;
case 0x99: Complete(CWD, eAX, eDX, data_size_); break;
case 0x9a: Far(CALLfar); break;
case 0x9b: Complete(WAIT, None, None, DataSize::None); break;
case 0x9b: Complete(WAIT, None, None, DataSize::Byte); break;
case 0x9c: Complete(PUSHF, None, None, data_size_); break;
case 0x9d: Complete(POPF, None, None, data_size_); break;
case 0x9e: Complete(SAHF, None, None, DataSize::Byte); break;
@ -421,11 +421,11 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
source_ = Source::Immediate;
operand_size_ = data_size_;
} else {
Complete(RETnear, None, None, DataSize::None);
Complete(RETnear, None, None, DataSize::Byte);
}
break;
case 0xc2: RegData(RETnear, None, data_size_); break;
case 0xc3: Complete(RETnear, None, None, DataSize::None); break;
case 0xc3: Complete(RETnear, None, None, DataSize::Byte); break;
case 0xc4: MemRegReg(LES, Reg_MemReg, data_size_); break;
case 0xc5: MemRegReg(LDS, Reg_MemReg, data_size_); break;
case 0xc6: MemRegReg(MOV, MemRegMOV, DataSize::Byte); break;
@ -440,7 +440,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
break;
case 0xc9:
if constexpr (model >= Model::i80186) {
Complete(LEAVE, None, None, DataSize::None);
Complete(LEAVE, None, None, DataSize::Byte);
} else {
Complete(RETfar, None, None, DataSize::DWord);
}
@ -456,8 +456,8 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
operand_ = 3;
break;
case 0xcd: RegData(INT, None, DataSize::Byte); break;
case 0xce: Complete(INTO, None, None, DataSize::None); break;
case 0xcf: Complete(IRET, None, None, DataSize::None); break;
case 0xce: Complete(INTO, None, None, DataSize::Byte); break;
case 0xcf: Complete(IRET, None, None, DataSize::Byte); break;
case 0xd0: case 0xd1:
ShiftGroup();
@ -505,17 +505,17 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0xf2: repetition_ = Repetition::RepNE; break;
case 0xf3: repetition_ = Repetition::RepE; break;
case 0xf4: Complete(HLT, None, None, DataSize::None); break;
case 0xf5: Complete(CMC, None, None, DataSize::None); break;
case 0xf4: Complete(HLT, None, None, DataSize::Byte); break;
case 0xf5: Complete(CMC, None, None, DataSize::Byte); break;
case 0xf6: MemRegReg(Invalid, MemRegTEST_to_IDIV, DataSize::Byte); break;
case 0xf7: MemRegReg(Invalid, MemRegTEST_to_IDIV, data_size_); break;
case 0xf8: Complete(CLC, None, None, DataSize::None); break;
case 0xf9: Complete(STC, None, None, DataSize::None); break;
case 0xfa: Complete(CLI, None, None, DataSize::None); break;
case 0xfb: Complete(STI, None, None, DataSize::None); break;
case 0xfc: Complete(CLD, None, None, DataSize::None); break;
case 0xfd: Complete(STD, None, None, DataSize::None); break;
case 0xf8: Complete(CLC, None, None, DataSize::Byte); break;
case 0xf9: Complete(STC, None, None, DataSize::Byte); break;
case 0xfa: Complete(CLI, None, None, DataSize::Byte); break;
case 0xfb: Complete(STI, None, None, DataSize::Byte); break;
case 0xfc: Complete(CLD, None, None, DataSize::Byte); break;
case 0xfd: Complete(STD, None, None, DataSize::Byte); break;
case 0xfe: MemRegReg(Invalid, MemRegINC_DEC, DataSize::Byte); break;
case 0xff: MemRegReg(Invalid, MemRegINC_to_PUSH, data_size_); break;
@ -541,7 +541,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0x03: MemRegReg(LSL, Reg_MemReg, data_size_); break;
case 0x05:
Requires(i80286);
Complete(LOADALL, None, None, DataSize::None);
Complete(LOADALL, None, None, DataSize::Byte);
break;
case 0x06: Complete(CLTS, None, None, DataSize::Byte); break;

View File

@ -826,7 +826,7 @@ template <
// Establish source() and destination() shorthand to fetch data if necessary.
IntT immediate;
auto source = [&]() -> IntT& {
const auto source = [&]() -> IntT& {
return *resolve<model, IntT>(
instruction,
instruction.source().template source<false>(),
@ -836,7 +836,7 @@ template <
nullptr,
&immediate);
};
auto destination = [&]() -> IntT& {
const auto destination = [&]() -> IntT& {
return *resolve<model, IntT>(
instruction,
instruction.destination().template source<false>(),
@ -847,6 +847,25 @@ template <
&immediate);
};
const auto jcc = [&](bool condition) {
Primitive::jump(
condition,
instruction.displacement(),
registers,
flow_controller);
};
const auto muldiv_high = [&]() -> IntT& {
if constexpr (data_size == DataSize::Byte) return registers.ah();
else if constexpr (data_size == DataSize::Word) return registers.dx();
else if constexpr (data_size == DataSize::DWord) return registers.edx();
};
const auto muldiv_low = [&]() -> IntT& {
if constexpr (data_size == DataSize::Byte) return registers.al();
else if constexpr (data_size == DataSize::Word) return registers.ax();
else if constexpr (data_size == DataSize::DWord) return registers.eax();
};
// Guide to the below:
//
// * use hard-coded register names where appropriate;
@ -891,43 +910,10 @@ template <
case Operation::CMP: Primitive::sub<false, false>(destination(), source(), status); break;
case Operation::TEST: Primitive::test(destination(), source(), status); break;
// TODO: all the below could call a common registers getter?
case Operation::MUL:
if constexpr (data_size == DataSize::Byte) {
Primitive::mul(registers.ah(), registers.al(), source(), status);
} else if constexpr (data_size == DataSize::Word) {
Primitive::mul(registers.dx(), registers.ax(), source(), status);
} else if constexpr (data_size == DataSize::DWord) {
Primitive::mul(registers.edx(), registers.eax(), source(), status);
}
return;
case Operation::IMUL_1:
if constexpr (data_size == DataSize::Byte) {
Primitive::imul(registers.ah(), registers.al(), source(), status);
} else if constexpr (data_size == DataSize::Word) {
Primitive::imul(registers.dx(), registers.ax(), source(), status);
} else if constexpr (data_size == DataSize::DWord) {
Primitive::imul(registers.edx(), registers.eax(), source(), status);
}
return;
case Operation::DIV:
if constexpr (data_size == DataSize::Byte) {
Primitive::div(registers.ah(), registers.al(), source(), flow_controller);
} else if constexpr (data_size == DataSize::Word) {
Primitive::div(registers.dx(), registers.ax(), source(), flow_controller);
} else if constexpr (data_size == DataSize::DWord) {
Primitive::div(registers.edx(), registers.eax(), source(), flow_controller);
}
return;
case Operation::IDIV:
if constexpr (data_size == DataSize::Byte) {
Primitive::idiv(registers.ah(), registers.al(), source(), flow_controller);
} else if constexpr (data_size == DataSize::Word) {
Primitive::idiv(registers.dx(), registers.ax(), source(), flow_controller);
} else if constexpr (data_size == DataSize::DWord) {
Primitive::idiv(registers.edx(), registers.eax(), source(), flow_controller);
}
return;
case Operation::MUL: Primitive::mul(muldiv_high(), muldiv_low(), source(), status); return;
case Operation::IMUL_1: Primitive::imul(muldiv_high(), muldiv_low(), source(), status); return;
case Operation::DIV: Primitive::div(muldiv_high(), muldiv_low(), source(), flow_controller); return;
case Operation::IDIV: Primitive::idiv(muldiv_high(), muldiv_low(), source(), flow_controller); return;
case Operation::INC: Primitive::inc(destination(), status); break;
case Operation::DEC: Primitive::dec(destination(), status); break;
@ -948,118 +934,22 @@ template <
Primitive::call_far<model>(instruction, flow_controller, registers, memory);
return;
case Operation::JO:
Primitive::jump(
status.condition<Condition::Overflow>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNO:
Primitive::jump(
!status.condition<Condition::Overflow>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JB:
Primitive::jump(
status.condition<Condition::Below>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNB:
Primitive::jump(
!status.condition<Condition::Below>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JZ:
Primitive::jump(
status.condition<Condition::Zero>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNZ:
Primitive::jump(
!status.condition<Condition::Zero>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JBE:
Primitive::jump(
status.condition<Condition::BelowOrEqual>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNBE:
Primitive::jump(
!status.condition<Condition::BelowOrEqual>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JS:
Primitive::jump(
status.condition<Condition::Sign>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNS:
Primitive::jump(
!status.condition<Condition::Sign>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JP:
Primitive::jump(
!status.condition<Condition::ParityOdd>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNP:
Primitive::jump(
status.condition<Condition::ParityOdd>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JL:
Primitive::jump(
status.condition<Condition::Less>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNL:
Primitive::jump(
!status.condition<Condition::Less>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JLE:
Primitive::jump(
status.condition<Condition::LessOrEqual>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JNLE:
Primitive::jump(
!status.condition<Condition::LessOrEqual>(),
instruction.displacement(),
registers,
flow_controller);
return;
case Operation::JO: jcc(status.condition<Condition::Overflow>()); return;
case Operation::JNO: jcc(!status.condition<Condition::Overflow>()); return;
case Operation::JB: jcc(status.condition<Condition::Below>()); return;
case Operation::JNB: jcc(!status.condition<Condition::Below>()); return;
case Operation::JZ: jcc(status.condition<Condition::Zero>()); return;
case Operation::JNZ: jcc(!status.condition<Condition::Zero>()); return;
case Operation::JBE: jcc(status.condition<Condition::BelowOrEqual>()); return;
case Operation::JNBE: jcc(!status.condition<Condition::BelowOrEqual>()); return;
case Operation::JS: jcc(status.condition<Condition::Sign>()); return;
case Operation::JNS: jcc(!status.condition<Condition::Sign>()); return;
case Operation::JP: jcc(!status.condition<Condition::ParityOdd>()); return;
case Operation::JNP: jcc(status.condition<Condition::ParityOdd>()); return;
case Operation::JL: jcc(status.condition<Condition::Less>()); return;
case Operation::JNL: jcc(!status.condition<Condition::Less>()); return;
case Operation::JLE: jcc(status.condition<Condition::LessOrEqual>()); return;
case Operation::JNLE: jcc(!status.condition<Condition::LessOrEqual>()); return;
case Operation::CLC: Primitive::clc(status); return;
case Operation::CLD: Primitive::cld(status); return;
@ -1105,9 +995,9 @@ template <
if constexpr (is_32bit(model)) {
perform<model, DataSize::DWord>(instruction, status, flow_controller, registers, memory, io);
}
break;
[[fallthrough]];
case DataSize::None:
perform<model, DataSize::None>(instruction, status, flow_controller, registers, memory, io);
assert(false);
break;
}
}

View File

@ -789,6 +789,10 @@ template<bool is_32bit> class Instruction {
if(!has_length_extension()) return Repetition::None;
return Repetition((length_extension() >> 4) & 3);
}
/// @returns The data size of this operation — e.g. `MOV AX, BX` has a data size of `::Word` but `MOV EAX, EBX` has a data size of
/// `::DWord`. This value is guaranteed never to be `DataSize::None` even for operations such as `CLI` that don't have operands and operate
/// on data that is not a byte, word or double word.
DataSize operation_size() const {
return DataSize(source_data_dest_sib_ >> 14);
}

View File

@ -23,7 +23,7 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"