mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-15 17:54:49 +00:00
Merge pull request #1202 from TomHarte/8088SegmentRegisters
Add means for tracking segment register changes.
This commit is contained in:
commit
03a2d4df80
@ -30,6 +30,8 @@ void aaas(
|
|||||||
--ax.halves.high;
|
--ax.halves.high;
|
||||||
}
|
}
|
||||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||||
|
} else {
|
||||||
|
context.flags.template set_from<Flag::Carry>(0);
|
||||||
}
|
}
|
||||||
ax.halves.low &= 0x0f;
|
ax.halves.low &= 0x0f;
|
||||||
}
|
}
|
||||||
|
@ -246,14 +246,25 @@ template <
|
|||||||
case Operation::LAHF: Primitive::lahf(context.registers.ah(), context); return;
|
case Operation::LAHF: Primitive::lahf(context.registers.ah(), context); return;
|
||||||
|
|
||||||
case Operation::LDS:
|
case Operation::LDS:
|
||||||
if constexpr (data_size == DataSize::Word) Primitive::ld<Source::DS>(instruction, destination_w(), context);
|
if constexpr (data_size == DataSize::Word) {
|
||||||
|
Primitive::ld<Source::DS>(instruction, destination_w(), context);
|
||||||
|
context.registers.did_update(Source::DS);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case Operation::LES:
|
case Operation::LES:
|
||||||
if constexpr (data_size == DataSize::Word) Primitive::ld<Source::ES>(instruction, destination_w(), context);
|
if constexpr (data_size == DataSize::Word) {
|
||||||
|
Primitive::ld<Source::ES>(instruction, destination_w(), context);
|
||||||
|
context.registers.did_update(Source::ES);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case Operation::LEA: Primitive::lea<IntT>(instruction, destination_w(), context); return;
|
case Operation::LEA: Primitive::lea<IntT>(instruction, destination_w(), context); return;
|
||||||
case Operation::MOV: Primitive::mov<IntT>(destination_w(), source_r()); break;
|
case Operation::MOV:
|
||||||
|
Primitive::mov<IntT>(destination_w(), source_r());
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
|
context.registers.did_update(instruction.destination().source());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Operation::JO: jcc(context.flags.template condition<Condition::Overflow>()); return;
|
case Operation::JO: jcc(context.flags.template condition<Condition::Overflow>()); return;
|
||||||
case Operation::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); return;
|
case Operation::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); return;
|
||||||
@ -319,7 +330,12 @@ template <
|
|||||||
|
|
||||||
case Operation::XLAT: Primitive::xlat<AddressT>(instruction, context); return;
|
case Operation::XLAT: Primitive::xlat<AddressT>(instruction, context); return;
|
||||||
|
|
||||||
case Operation::POP: destination_w() = Primitive::pop<IntT, false>(context); break;
|
case Operation::POP:
|
||||||
|
destination_w() = Primitive::pop<IntT, false>(context);
|
||||||
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
|
context.registers.did_update(instruction.destination().source());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Operation::PUSH:
|
case Operation::PUSH:
|
||||||
Primitive::push<IntT, false>(source_rmw(), context); // PUSH SP modifies SP before pushing it;
|
Primitive::push<IntT, false>(source_rmw(), context); // PUSH SP modifies SP before pushing it;
|
||||||
// hence PUSH is sometimes read-modify-write.
|
// hence PUSH is sometimes read-modify-write.
|
||||||
|
@ -444,7 +444,7 @@ enum class Source: uint8_t {
|
|||||||
T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5, T6 = 6, T7 = 7,
|
T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5, T6 = 6, T7 = 7,
|
||||||
D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7,
|
D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7,
|
||||||
|
|
||||||
// Selectors.
|
// Segment registers.
|
||||||
ES, CS, SS, DS, FS, GS,
|
ES, CS, SS, DS, FS, GS,
|
||||||
|
|
||||||
/// @c None can be treated as a source that produces 0 when encountered;
|
/// @c None can be treated as a source that produces 0 when encountered;
|
||||||
@ -473,6 +473,9 @@ enum class Source: uint8_t {
|
|||||||
constexpr bool is_register(Source source) {
|
constexpr bool is_register(Source source) {
|
||||||
return source < Source::None;
|
return source < Source::None;
|
||||||
}
|
}
|
||||||
|
constexpr bool is_segment_register(Source source) {
|
||||||
|
return is_register(source) && source >= Source::ES;
|
||||||
|
}
|
||||||
|
|
||||||
enum class Repetition: uint8_t {
|
enum class Repetition: uint8_t {
|
||||||
None, RepE, RepNE, Rep,
|
None, RepE, RepNE, Rep,
|
||||||
|
@ -68,6 +68,7 @@ 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_; }
|
||||||
@ -77,6 +78,18 @@ 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;
|
||||||
|
/// 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_ = 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
|
||||||
ax_.full == rhs.ax_.full &&
|
ax_.full == rhs.ax_.full &&
|
||||||
@ -91,7 +104,11 @@ 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_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
struct Memory {
|
struct Memory {
|
||||||
@ -237,15 +254,13 @@ struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t segment_base(InstructionSet::x86::Source segment) {
|
uint32_t segment_base(InstructionSet::x86::Source segment) {
|
||||||
uint32_t physical_address;
|
|
||||||
using Source = InstructionSet::x86::Source;
|
using Source = InstructionSet::x86::Source;
|
||||||
switch(segment) {
|
switch(segment) {
|
||||||
default: physical_address = registers_.ds_; break;
|
default: return registers_.ds_base_;
|
||||||
case Source::ES: physical_address = registers_.es_; break;
|
case Source::ES: return registers_.es_base_;
|
||||||
case Source::CS: physical_address = registers_.cs_; break;
|
case Source::CS: return registers_.cs_base_;
|
||||||
case Source::SS: physical_address = registers_.ss_; break;
|
case Source::SS: return registers_.ss_base_;
|
||||||
}
|
}
|
||||||
return physical_address << 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t address(InstructionSet::x86::Source segment, uint16_t offset) {
|
uint32_t address(InstructionSet::x86::Source segment, uint16_t offset) {
|
||||||
@ -271,7 +286,7 @@ struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An additional entry point for the flow controller; on the original 8086 interrupt vectors aren't relative
|
// An additional entry point for the flow controller; on the original 8086 interrupt vectors aren't relative
|
||||||
// to a selector, they're just at an absolute location.
|
// to a segment, they're just at an absolute location.
|
||||||
template <typename IntT, AccessType type>
|
template <typename IntT, AccessType type>
|
||||||
typename InstructionSet::x86::Accessor<IntT, type>::type access(uint32_t address, Tag tag) {
|
typename InstructionSet::x86::Accessor<IntT, type>::type access(uint32_t address, Tag tag) {
|
||||||
if constexpr (type == AccessType::PreauthorisedRead) {
|
if constexpr (type == AccessType::PreauthorisedRead) {
|
||||||
@ -334,6 +349,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);
|
||||||
registers_.ip_ = address;
|
registers_.ip_ = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,9 +411,9 @@ struct FailedExecution {
|
|||||||
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
NSString *path = [NSString stringWithUTF8String:TestSuiteHome];
|
||||||
NSSet *allowList = [NSSet setWithArray:@[
|
NSSet *allowList = [NSSet setWithArray:@[
|
||||||
// Current execution failures, albeit all permitted:
|
// Current execution failures, albeit all permitted:
|
||||||
@"D4.json.gz", // AAM
|
// @"D4.json.gz", // AAM
|
||||||
@"F6.7.json.gz", // IDIV byte
|
// @"F6.7.json.gz", // IDIV byte
|
||||||
@"F7.7.json.gz", // IDIV word
|
// @"F7.7.json.gz", // IDIV word
|
||||||
]];
|
]];
|
||||||
|
|
||||||
NSSet *ignoreList = nil;
|
NSSet *ignoreList = nil;
|
||||||
@ -544,6 +560,11 @@ 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);
|
||||||
|
|
||||||
@ -682,6 +703,7 @@ 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;
|
||||||
@ -694,10 +716,6 @@ struct FailedExecution {
|
|||||||
failure_list = &permitted_failures;
|
failure_list = &permitted_failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(failure_list == &execution_failures) {
|
|
||||||
printf("Fail: %d\n", int(decoded.second.operation()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record a failure.
|
// Record a failure.
|
||||||
FailedExecution failure;
|
FailedExecution failure;
|
||||||
failure.instruction = decoded.second;
|
failure.instruction = decoded.second;
|
||||||
|
Loading…
Reference in New Issue
Block a user