1
0
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:
Thomas Harte 2023-10-16 15:40:24 -04:00
parent f1779e6067
commit 89743f0ba0
3 changed files with 66 additions and 20 deletions

View File

@ -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_

View File

@ -165,6 +165,24 @@ IntT *resolve(
namespace Primitive {
template <typename IntT, typename MemoryT, typename RegistersT>
void push(IntT value, MemoryT &memory, RegistersT &registers) {
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 &registers) {
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 Developers 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 &registers, 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 &registers, 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 &registers, 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;

View File

@ -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 &registers, 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];
}
}