mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Implement RET, IRET.
This commit is contained in:
parent
f1779e6067
commit
89743f0ba0
@ -442,12 +442,12 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
||||
if constexpr (model >= Model::i80186) {
|
||||
Complete(LEAVE, None, None, DataSize::Byte);
|
||||
} else {
|
||||
Complete(RETfar, None, None, DataSize::DWord);
|
||||
Complete(RETfar, None, None, DataSize::Word);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xca: RegData(RETfar, None, data_size_); break;
|
||||
case 0xcb: Complete(RETfar, None, None, DataSize::DWord); break;
|
||||
case 0xcb: Complete(RETfar, None, None, DataSize::Word); break;
|
||||
|
||||
case 0xcc:
|
||||
// Encode INT3 as though it were INT with an
|
||||
@ -1065,7 +1065,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
||||
address_size_,
|
||||
segment_override_,
|
||||
repetition_,
|
||||
DataSize(operation_size_),
|
||||
operation_size_,
|
||||
static_cast<typename InstructionT::DisplacementT>(displacement_),
|
||||
static_cast<typename InstructionT::ImmediateT>(operand_),
|
||||
consumed_
|
||||
|
@ -165,6 +165,24 @@ IntT *resolve(
|
||||
|
||||
namespace Primitive {
|
||||
|
||||
template <typename IntT, typename MemoryT, typename RegistersT>
|
||||
void push(IntT value, MemoryT &memory, RegistersT ®isters) {
|
||||
registers.sp_ -= sizeof(IntT);
|
||||
memory.template access<IntT>(
|
||||
InstructionSet::x86::Source::SS,
|
||||
registers.sp_) = value;
|
||||
memory.template write_back<IntT>();
|
||||
}
|
||||
|
||||
template <typename IntT, typename MemoryT, typename RegistersT>
|
||||
IntT pop(MemoryT &memory, RegistersT ®isters) {
|
||||
const auto value = memory.template access<IntT>(
|
||||
InstructionSet::x86::Source::SS,
|
||||
registers.sp_);
|
||||
registers.sp_ += sizeof(IntT);
|
||||
return value;
|
||||
}
|
||||
|
||||
//
|
||||
// Comments below on intended functioning of each operation come from the 1997 edition of the
|
||||
// Intel Architecture Software Developer’s Manual; that year all such definitions still fitted within a
|
||||
@ -793,6 +811,30 @@ void call_far(InstructionT &instruction,
|
||||
flow_controller.call(segment, offset);
|
||||
}
|
||||
|
||||
template <typename FlowControllerT, typename RegistersT, typename MemoryT>
|
||||
void iret(RegistersT ®isters, FlowControllerT &flow_controller, MemoryT &memory, Status &status) {
|
||||
// TODO: all modes other than 16-bit real mode.
|
||||
registers.ip() = pop<uint16_t>(memory, registers);
|
||||
registers.cs() = pop<uint16_t>(memory, registers);
|
||||
status.set(pop<uint16_t>(memory, registers));
|
||||
flow_controller.did_iret();
|
||||
}
|
||||
|
||||
template <typename InstructionT, typename FlowControllerT, typename RegistersT, typename MemoryT>
|
||||
void ret_near(InstructionT instruction, RegistersT ®isters, FlowControllerT &flow_controller, MemoryT &memory) {
|
||||
registers.ip() = pop<uint16_t>(memory, registers);
|
||||
registers.sp() += instruction.operand();
|
||||
flow_controller.did_near_ret();
|
||||
}
|
||||
|
||||
template <typename InstructionT, typename FlowControllerT, typename RegistersT, typename MemoryT>
|
||||
void ret_far(InstructionT instruction, RegistersT ®isters, FlowControllerT &flow_controller, MemoryT &memory) {
|
||||
registers.ip() = pop<uint16_t>(memory, registers);
|
||||
registers.cs() = pop<uint16_t>(memory, registers);
|
||||
registers.sp() += instruction.operand();
|
||||
flow_controller.did_far_ret();
|
||||
}
|
||||
|
||||
template <Model model, Source selector, typename InstructionT, typename MemoryT, typename RegistersT>
|
||||
void ld(
|
||||
InstructionT &instruction,
|
||||
@ -1370,6 +1412,10 @@ template <
|
||||
Primitive::call_far<model>(instruction, flow_controller, registers, memory);
|
||||
return;
|
||||
|
||||
case Operation::IRET: Primitive::iret(registers, flow_controller, memory, status); return;
|
||||
case Operation::RETnear: Primitive::ret_near(instruction, registers, flow_controller, memory); return;
|
||||
case Operation::RETfar: Primitive::ret_far(instruction, registers, flow_controller, memory); return;
|
||||
|
||||
case Operation::INT: Primitive::int_(instruction.operand(), flow_controller); return;
|
||||
case Operation::INTO: Primitive::into(status, flow_controller); return;
|
||||
|
||||
|
@ -66,7 +66,7 @@ struct Registers {
|
||||
uint16_t es_, cs_, ds_, ss_;
|
||||
|
||||
uint16_t ip_;
|
||||
uint16_t ip() { return ip_; }
|
||||
uint16_t &ip() { return ip_; }
|
||||
|
||||
uint16_t &es() { return es_; }
|
||||
uint16_t &cs() { return cs_; }
|
||||
@ -190,6 +190,10 @@ class FlowController {
|
||||
FlowController(Memory &memory, Registers ®isters, Status &status) :
|
||||
memory_(memory), registers_(registers), status_(status) {}
|
||||
|
||||
void did_iret() {}
|
||||
void did_near_ret() {}
|
||||
void did_far_ret() {}
|
||||
|
||||
void interrupt(int index) {
|
||||
const uint16_t address = static_cast<uint16_t>(index) << 2;
|
||||
const uint16_t new_ip = memory_.access<uint16_t>(address, Memory::Tag::Accessed);
|
||||
@ -361,9 +365,13 @@ struct FailedExecution {
|
||||
// CALL
|
||||
@"E8.json.gz", @"FF.2.json.gz",
|
||||
@"9A.json.gz", @"FF.3.json.gz",
|
||||
*/
|
||||
// IRET
|
||||
@"CF.json.gz",
|
||||
|
||||
// TODO: IRET
|
||||
// TODO: RET
|
||||
@"C3.json.gz", @"C2.json.gz", // near RET
|
||||
@"CB.json.gz", @"CA.json.gz", // far RET
|
||||
/*
|
||||
// TODO: JMP
|
||||
// TODO: JCXZ
|
||||
|
||||
@ -379,13 +387,11 @@ struct FailedExecution {
|
||||
@"C5.json.gz", // LDS
|
||||
@"C4.json.gz", // LES
|
||||
@"8D.json.gz", // LEA
|
||||
*/
|
||||
|
||||
// TODO: CMPS, LODS, MOVS, SCAS, STOS
|
||||
|
||||
// TODO: LOOP, LOOPE, LOOPNE
|
||||
|
||||
/*
|
||||
// MOV
|
||||
@"88.json.gz", @"89.json.gz", @"8A.json.gz", @"8B.json.gz",
|
||||
@"8C.json.gz", @"8E.json.gz",
|
||||
@ -434,21 +440,19 @@ struct FailedExecution {
|
||||
// ROR
|
||||
@"D0.1.json.gz", @"D2.1.json.gz",
|
||||
@"D1.1.json.gz", @"D3.1.json.gz",
|
||||
*/
|
||||
|
||||
// SAL
|
||||
// @"D0.4.json.gz", @"D2.4.json.gz",
|
||||
// @"D1.4.json.gz", @"D3.4.json.gz",
|
||||
@"D0.4.json.gz", @"D2.4.json.gz",
|
||||
@"D1.4.json.gz", @"D3.4.json.gz",
|
||||
|
||||
// SAR
|
||||
// @"D0.7.json.gz", @"D2.7.json.gz",
|
||||
// @"D1.7.json.gz", @"D3.7.json.gz",
|
||||
@"D0.7.json.gz", @"D2.7.json.gz",
|
||||
@"D1.7.json.gz", @"D3.7.json.gz",
|
||||
|
||||
// SHR
|
||||
@"D0.5.json.gz", @"D2.5.json.gz",
|
||||
@"D1.5.json.gz", @"D3.5.json.gz",
|
||||
|
||||
/*
|
||||
@"F8.json.gz", // CLC
|
||||
@"FC.json.gz", // CLD
|
||||
@"FA.json.gz", // CLI
|
||||
@ -632,7 +636,7 @@ struct FailedExecution {
|
||||
status.set([value[@"flags"] intValue]);
|
||||
}
|
||||
|
||||
- (void)applyExecutionTest:(NSDictionary *)test file:(NSString *)file metadata:(NSDictionary *)metadata {
|
||||
- (void)applyExecutionTest:(NSDictionary *)test metadata:(NSDictionary *)metadata {
|
||||
InstructionSet::x86::Decoder<InstructionSet::x86::Model::i8086> decoder;
|
||||
const auto data = [self bytes:test[@"bytes"]];
|
||||
const auto decoded = decoder.decode(data.data(), data.size());
|
||||
@ -656,10 +660,6 @@ struct FailedExecution {
|
||||
execution_support.status = initial_status;
|
||||
execution_support.registers = initial_registers;
|
||||
|
||||
if([test[@"name"] isEqual:@"rol byte ss:[bp+si+CF11h], cl"]) {
|
||||
printf("");
|
||||
}
|
||||
|
||||
// Execute instruction.
|
||||
execution_support.registers.ip_ += decoded.first;
|
||||
InstructionSet::x86::perform<InstructionSet::x86::Model::i8086>(
|
||||
@ -760,7 +760,7 @@ struct FailedExecution {
|
||||
}
|
||||
|
||||
for(NSDictionary *test in [self testsInFile:file]) {
|
||||
[self applyExecutionTest:test file:file metadata:test_metadata];
|
||||
[self applyExecutionTest:test metadata:test_metadata];
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user