mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Formalise a separate manager of segments.
This commit is contained in:
parent
6c405680f2
commit
ac826f90c3
@ -256,13 +256,13 @@ template <
|
|||||||
case Operation::LDS:
|
case Operation::LDS:
|
||||||
if constexpr (data_size == DataSize::Word) {
|
if constexpr (data_size == DataSize::Word) {
|
||||||
Primitive::ld<Source::DS>(instruction, destination_w(), context);
|
Primitive::ld<Source::DS>(instruction, destination_w(), context);
|
||||||
context.registers.did_update(Source::DS);
|
context.segments.did_update(Source::DS);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case Operation::LES:
|
case Operation::LES:
|
||||||
if constexpr (data_size == DataSize::Word) {
|
if constexpr (data_size == DataSize::Word) {
|
||||||
Primitive::ld<Source::ES>(instruction, destination_w(), context);
|
Primitive::ld<Source::ES>(instruction, destination_w(), context);
|
||||||
context.registers.did_update(Source::ES);
|
context.segments.did_update(Source::ES);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ template <
|
|||||||
case Operation::MOV:
|
case Operation::MOV:
|
||||||
Primitive::mov<IntT>(destination_w(), source_r());
|
Primitive::mov<IntT>(destination_w(), source_r());
|
||||||
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
context.registers.did_update(instruction.destination().source());
|
context.segments.did_update(instruction.destination().source());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ template <
|
|||||||
case Operation::POP:
|
case Operation::POP:
|
||||||
destination_w() = Primitive::pop<IntT, false>(context);
|
destination_w() = Primitive::pop<IntT, false>(context);
|
||||||
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
context.registers.did_update(instruction.destination().source());
|
context.segments.did_update(instruction.destination().source());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Operation::PUSH:
|
case Operation::PUSH:
|
||||||
@ -349,10 +349,26 @@ template <
|
|||||||
// hence PUSH is sometimes read-modify-write.
|
// hence PUSH is sometimes read-modify-write.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Operation::POPF: Primitive::popf(context); return;
|
case Operation::POPF:
|
||||||
case Operation::PUSHF: Primitive::pushf(context); return;
|
if constexpr (std::is_same_v<IntT, uint16_t> || std::is_same_v<IntT, uint32_t>) {
|
||||||
case Operation::POPA: Primitive::popa<IntT>(context); return;
|
Primitive::popf(context);
|
||||||
case Operation::PUSHA: Primitive::pusha<IntT>(context); return;
|
}
|
||||||
|
return;
|
||||||
|
case Operation::PUSHF:
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t> || std::is_same_v<IntT, uint32_t>) {
|
||||||
|
Primitive::pushf(context);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case Operation::POPA:
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t> || std::is_same_v<IntT, uint32_t>) {
|
||||||
|
Primitive::popa<IntT>(context);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case Operation::PUSHA:
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t> || std::is_same_v<IntT, uint32_t>) {
|
||||||
|
Primitive::pusha<IntT>(context);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
case Operation::CMPS:
|
case Operation::CMPS:
|
||||||
Primitive::cmps<IntT, AddressT, Repetition::None>(instruction, eCX(), eSI(), eDI(), context);
|
Primitive::cmps<IntT, AddressT, Repetition::None>(instruction, eCX(), eSI(), eDI(), context);
|
||||||
|
@ -95,7 +95,6 @@ template <typename IntT, typename ContextT>
|
|||||||
void popa(
|
void popa(
|
||||||
ContextT &context
|
ContextT &context
|
||||||
) {
|
) {
|
||||||
if constexpr (!std::is_same_v<IntT, uint8_t>) {
|
|
||||||
context.memory.preauthorise_stack_read(sizeof(IntT) * 8);
|
context.memory.preauthorise_stack_read(sizeof(IntT) * 8);
|
||||||
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
||||||
context.registers.edi() = pop<uint32_t, true>(context);
|
context.registers.edi() = pop<uint32_t, true>(context);
|
||||||
@ -117,13 +116,11 @@ void popa(
|
|||||||
context.registers.ax() = pop<uint16_t, true>(context);
|
context.registers.ax() = pop<uint16_t, true>(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename IntT, typename ContextT>
|
template <typename IntT, typename ContextT>
|
||||||
void pusha(
|
void pusha(
|
||||||
ContextT &context
|
ContextT &context
|
||||||
) {
|
) {
|
||||||
if constexpr (!std::is_same_v<IntT, uint8_t>) {
|
|
||||||
context.memory.preauthorise_stack_read(sizeof(IntT) * 8);
|
context.memory.preauthorise_stack_read(sizeof(IntT) * 8);
|
||||||
IntT initial_sp = context.registers.sp();
|
IntT initial_sp = context.registers.sp();
|
||||||
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
||||||
@ -146,7 +143,6 @@ void pusha(
|
|||||||
push<uint16_t, true>(context.registers.si(), context);
|
push<uint16_t, true>(context.registers.si(), context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,6 @@ struct Registers {
|
|||||||
uint16_t &di() { return di_; }
|
uint16_t &di() { return di_; }
|
||||||
|
|
||||||
uint16_t es_, cs_, ds_, ss_;
|
uint16_t es_, cs_, ds_, ss_;
|
||||||
uint32_t es_base_, cs_base_, ds_base_, ss_base_;
|
|
||||||
|
|
||||||
uint16_t ip_;
|
uint16_t ip_;
|
||||||
uint16_t &ip() { return ip_; }
|
uint16_t &ip() { return ip_; }
|
||||||
@ -78,17 +77,10 @@ struct Registers {
|
|||||||
uint16_t &ds() { return ds_; }
|
uint16_t &ds() { return ds_; }
|
||||||
uint16_t &ss() { return ss_; }
|
uint16_t &ss() { return ss_; }
|
||||||
|
|
||||||
using Source = InstructionSet::x86::Source;
|
const uint16_t es() const { return es_; }
|
||||||
/// Posted by @c perform after any operation which *might* have affected a segment register.
|
const uint16_t cs() const { return cs_; }
|
||||||
void did_update(Source segment) {
|
const uint16_t ds() const { return ds_; }
|
||||||
switch(segment) {
|
const uint16_t ss() const { return ss_; }
|
||||||
default: break;
|
|
||||||
case Source::ES: es_base_ = es_ << 4; break;
|
|
||||||
case Source::CS: cs_base_ = cs_ << 4; break;
|
|
||||||
case Source::DS: ds_base_ = ds_ << 4; break;
|
|
||||||
case Source::SS: ss_base_ = ss_ << 4; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator ==(const Registers &rhs) const {
|
bool operator ==(const Registers &rhs) const {
|
||||||
return
|
return
|
||||||
@ -104,19 +96,52 @@ struct Registers {
|
|||||||
cs_ == rhs.cs_ &&
|
cs_ == rhs.cs_ &&
|
||||||
ds_ == rhs.ds_ &&
|
ds_ == rhs.ds_ &&
|
||||||
si_ == rhs.si_ &&
|
si_ == rhs.si_ &&
|
||||||
ip_ == rhs.ip_ &&
|
ip_ == rhs.ip_;
|
||||||
es_base_ == rhs.es_base_ &&
|
|
||||||
cs_base_ == rhs.cs_base_ &&
|
|
||||||
ds_base_ == rhs.ds_base_ &&
|
|
||||||
ss_base_ == rhs.ss_base_;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
class Segments {
|
||||||
|
public:
|
||||||
|
Segments(const Registers ®isters) : registers_(registers) {}
|
||||||
|
|
||||||
|
using Source = InstructionSet::x86::Source;
|
||||||
|
|
||||||
|
/// Posted by @c perform after any operation which *might* have affected a segment register.
|
||||||
|
void did_update(Source segment) {
|
||||||
|
switch(segment) {
|
||||||
|
default: break;
|
||||||
|
case Source::ES: es_base_ = registers_.es() << 4; break;
|
||||||
|
case Source::CS: cs_base_ = registers_.cs() << 4; break;
|
||||||
|
case Source::DS: ds_base_ = registers_.ds() << 4; break;
|
||||||
|
case Source::SS: ss_base_ = registers_.ss() << 4; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
did_update(Source::ES);
|
||||||
|
did_update(Source::CS);
|
||||||
|
did_update(Source::DS);
|
||||||
|
did_update(Source::SS);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t es_base_, cs_base_, ds_base_, ss_base_;
|
||||||
|
|
||||||
|
bool operator ==(const Segments &rhs) const {
|
||||||
|
return
|
||||||
|
es_base_ != rhs.es_base_ &&
|
||||||
|
cs_base_ != rhs.cs_base_ &&
|
||||||
|
ds_base_ != rhs.ds_base_ &&
|
||||||
|
ss_base_ != rhs.ss_base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Registers ®isters_;
|
||||||
|
};
|
||||||
struct Memory {
|
struct Memory {
|
||||||
public:
|
public:
|
||||||
using AccessType = InstructionSet::x86::AccessType;
|
using AccessType = InstructionSet::x86::AccessType;
|
||||||
|
|
||||||
// Constructor.
|
// Constructor.
|
||||||
Memory(Registers ®isters) : registers_(registers) {
|
Memory(Registers ®isters, const Segments &segments) : registers_(registers), segments_(segments) {
|
||||||
memory.resize(1024*1024);
|
memory.resize(1024*1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +262,7 @@ struct Memory {
|
|||||||
std::unordered_map<uint32_t, Tag> tags;
|
std::unordered_map<uint32_t, Tag> tags;
|
||||||
std::vector<uint8_t> memory;
|
std::vector<uint8_t> memory;
|
||||||
const Registers ®isters_;
|
const Registers ®isters_;
|
||||||
|
const Segments &segments_;
|
||||||
|
|
||||||
void preauthorise(uint32_t address) {
|
void preauthorise(uint32_t address) {
|
||||||
preauthorisations.insert(address);
|
preauthorisations.insert(address);
|
||||||
@ -256,10 +282,10 @@ struct Memory {
|
|||||||
uint32_t segment_base(InstructionSet::x86::Source segment) {
|
uint32_t segment_base(InstructionSet::x86::Source segment) {
|
||||||
using Source = InstructionSet::x86::Source;
|
using Source = InstructionSet::x86::Source;
|
||||||
switch(segment) {
|
switch(segment) {
|
||||||
default: return registers_.ds_base_;
|
default: return segments_.ds_base_;
|
||||||
case Source::ES: return registers_.es_base_;
|
case Source::ES: return segments_.es_base_;
|
||||||
case Source::CS: return registers_.cs_base_;
|
case Source::CS: return segments_.cs_base_;
|
||||||
case Source::SS: return registers_.ss_base_;
|
case Source::SS: return segments_.ss_base_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,8 +365,8 @@ struct IO {
|
|||||||
};
|
};
|
||||||
class FlowController {
|
class FlowController {
|
||||||
public:
|
public:
|
||||||
FlowController(Memory &memory, Registers ®isters, Flags &flags) :
|
FlowController(Memory &memory, Registers ®isters, Segments &segments, Flags &flags) :
|
||||||
memory_(memory), registers_(registers), flags_(flags) {}
|
memory_(memory), registers_(registers), segments_(segments), flags_(flags) {}
|
||||||
|
|
||||||
// Requirements for perform.
|
// Requirements for perform.
|
||||||
void jump(uint16_t address) {
|
void jump(uint16_t address) {
|
||||||
@ -349,7 +375,7 @@ class FlowController {
|
|||||||
|
|
||||||
void jump(uint16_t segment, uint16_t address) {
|
void jump(uint16_t segment, uint16_t address) {
|
||||||
registers_.cs_ = segment;
|
registers_.cs_ = segment;
|
||||||
registers_.did_update(Registers::Source::CS);
|
segments_.did_update(Segments::Source::CS);
|
||||||
registers_.ip_ = address;
|
registers_.ip_ = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,6 +397,7 @@ class FlowController {
|
|||||||
private:
|
private:
|
||||||
Memory &memory_;
|
Memory &memory_;
|
||||||
Registers ®isters_;
|
Registers ®isters_;
|
||||||
|
Segments &segments_;
|
||||||
Flags &flags_;
|
Flags &flags_;
|
||||||
bool should_repeat_ = false;
|
bool should_repeat_ = false;
|
||||||
};
|
};
|
||||||
@ -378,12 +405,16 @@ class FlowController {
|
|||||||
struct ExecutionSupport {
|
struct ExecutionSupport {
|
||||||
Flags flags;
|
Flags flags;
|
||||||
Registers registers;
|
Registers registers;
|
||||||
|
Segments segments;
|
||||||
Memory memory;
|
Memory memory;
|
||||||
FlowController flow_controller;
|
FlowController flow_controller;
|
||||||
IO io;
|
IO io;
|
||||||
static constexpr auto model = InstructionSet::x86::Model::i8086;
|
static constexpr auto model = InstructionSet::x86::Model::i8086;
|
||||||
|
|
||||||
ExecutionSupport(): memory(registers), flow_controller(memory, registers, flags) {}
|
ExecutionSupport():
|
||||||
|
memory(registers, segments),
|
||||||
|
segments(registers),
|
||||||
|
flow_controller(memory, registers, segments, flags) {}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
memory.clear();
|
memory.clear();
|
||||||
@ -560,11 +591,6 @@ struct FailedExecution {
|
|||||||
registers.ss_ = [value[@"ss"] intValue];
|
registers.ss_ = [value[@"ss"] intValue];
|
||||||
registers.ip_ = [value[@"ip"] intValue];
|
registers.ip_ = [value[@"ip"] intValue];
|
||||||
|
|
||||||
registers.did_update(Registers::Source::ES);
|
|
||||||
registers.did_update(Registers::Source::CS);
|
|
||||||
registers.did_update(Registers::Source::DS);
|
|
||||||
registers.did_update(Registers::Source::SS);
|
|
||||||
|
|
||||||
const uint16_t flags_value = [value[@"flags"] intValue];
|
const uint16_t flags_value = [value[@"flags"] intValue];
|
||||||
flags.set(flags_value);
|
flags.set(flags_value);
|
||||||
|
|
||||||
@ -610,6 +636,7 @@ struct FailedExecution {
|
|||||||
[self populate:initial_registers flags:initial_flags value:initial_state[@"regs"]];
|
[self populate:initial_registers flags:initial_flags value:initial_state[@"regs"]];
|
||||||
execution_support.flags = initial_flags;
|
execution_support.flags = initial_flags;
|
||||||
execution_support.registers = initial_registers;
|
execution_support.registers = initial_registers;
|
||||||
|
execution_support.segments.reset();
|
||||||
|
|
||||||
// Execute instruction.
|
// Execute instruction.
|
||||||
//
|
//
|
||||||
@ -657,8 +684,11 @@ struct FailedExecution {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Segments intended_segments(intended_registers);
|
||||||
[self populate:intended_registers flags:intended_flags value:final_state[@"regs"]];
|
[self populate:intended_registers flags:intended_flags value:final_state[@"regs"]];
|
||||||
const bool registersEqual = intended_registers == execution_support.registers;
|
intended_segments.reset();
|
||||||
|
|
||||||
|
const bool registersEqual = intended_registers == execution_support.registers && intended_segments == execution_support.segments;
|
||||||
const bool flagsEqual = (intended_flags.get() & flags_mask) == (execution_support.flags.get() & flags_mask);
|
const bool flagsEqual = (intended_flags.get() & flags_mask) == (execution_support.flags.get() & flags_mask);
|
||||||
|
|
||||||
// Exit if no issues were found.
|
// Exit if no issues were found.
|
||||||
@ -703,7 +733,6 @@ struct FailedExecution {
|
|||||||
non_exception_registers.sp() = execution_support.registers.sp();
|
non_exception_registers.sp() = execution_support.registers.sp();
|
||||||
non_exception_registers.ax() = execution_support.registers.ax();
|
non_exception_registers.ax() = execution_support.registers.ax();
|
||||||
non_exception_registers.cs() = execution_support.registers.cs();
|
non_exception_registers.cs() = execution_support.registers.cs();
|
||||||
non_exception_registers.cs_base_ = execution_support.registers.cs_base_;
|
|
||||||
|
|
||||||
if(non_exception_registers == execution_support.registers) {
|
if(non_exception_registers == execution_support.registers) {
|
||||||
failure_list = &permitted_failures;
|
failure_list = &permitted_failures;
|
||||||
|
Loading…
Reference in New Issue
Block a user