mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-14 13:33:42 +00:00
Further clean up copy-and-paste mess.
This commit is contained in:
parent
7159366360
commit
a768b101f8
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
|
Loading…
x
Reference in New Issue
Block a user