1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Formalise a separate manager of segments.

This commit is contained in:
Thomas Harte 2023-11-14 10:56:00 -05:00
parent 6c405680f2
commit ac826f90c3
3 changed files with 125 additions and 84 deletions

View File

@ -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);

View File

@ -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);
@ -116,14 +115,12 @@ void popa(
context.registers.cx() = pop<uint16_t, true>(context); context.registers.cx() = pop<uint16_t, true>(context);
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>) {
@ -145,7 +142,6 @@ void pusha(
push<uint16_t, true>(context.registers.si(), context); push<uint16_t, true>(context.registers.si(), context);
push<uint16_t, true>(context.registers.si(), context); push<uint16_t, true>(context.registers.si(), context);
} }
}
} }
} }

View File

@ -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 &registers) : 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 &registers_;
};
struct Memory { struct Memory {
public: public:
using AccessType = InstructionSet::x86::AccessType; using AccessType = InstructionSet::x86::AccessType;
// Constructor. // Constructor.
Memory(Registers &registers) : registers_(registers) { Memory(Registers &registers, 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 &registers_; const Registers &registers_;
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 &registers, Flags &flags) : FlowController(Memory &memory, Registers &registers, 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 &registers_; Registers &registers_;
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;