1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-14 03:37:04 +00:00

Fix PUSH SP, far call. Further simplify FlowController.

This commit is contained in:
Thomas Harte 2023-11-01 23:39:52 -04:00
parent acb55aa4e2
commit e4fdf09149
2 changed files with 39 additions and 60 deletions

View File

@ -189,13 +189,13 @@ IntT *resolve(
namespace Primitive {
// The below takes a reference in order properly to handle PUSH SP, which should place the value of SP after the
// push onto the stack.
// The below takes a reference in order properly to handle PUSH SP,
// which should place the value of SP after the push onto the stack.
template <typename IntT, bool Preauthorised, typename ContextT>
void push(IntT value, ContextT &context) {
void push(IntT &value, ContextT &context) {
context.registers.sp_ -= sizeof(IntT);
context.memory.template access<IntT, Preauthorised ? AccessType::PreauthorisedWrite : AccessType::Write>(
InstructionSet::x86::Source::SS,
Source::SS,
context.registers.sp_) = value;
context.memory.template write_back<IntT>();
}
@ -203,7 +203,7 @@ void push(IntT value, ContextT &context) {
template <typename IntT, bool Preauthorised, typename ContextT>
IntT pop(ContextT &context) {
const auto value = context.memory.template access<IntT, Preauthorised ? AccessType::PreauthorisedRead : AccessType::Read>(
InstructionSet::x86::Source::SS,
Source::SS,
context.registers.sp_);
context.registers.sp_ += sizeof(IntT);
return value;
@ -597,7 +597,7 @@ void div(IntT &destination_high, IntT &destination_low, IntT source, ContextT &c
The CF, OF, SF, ZF, AF, and PF flags are undefined.
*/
if(!source) {
InstructionSet::x86::interrupt(Interrupt::DivideError, context);
interrupt(Interrupt::DivideError, context);
return;
}
@ -869,12 +869,14 @@ void call_far(InstructionT &instruction, ContextT &context) {
}
context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2);
push<uint16_t, true>(context.registers.cs(), context);
push<uint16_t, true>(context.registers.ip(), context);
const uint16_t offset = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
source_address += 2;
const uint16_t segment = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
// At least on an 8086, the stack writes occur after the target address read.
push<uint16_t, true>(context.registers.cs(), context);
push<uint16_t, true>(context.registers.ip(), context);
context.flow_controller.jump(segment, offset);
}
@ -899,6 +901,7 @@ void jump_far(InstructionT &instruction, ContextT &context) {
}
const Source source_segment = instruction.data_segment();
context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2);
const uint16_t offset = context.memory.template access<uint16_t, AccessType::Read>(source_segment, source_address);
source_address += 2;
@ -1919,7 +1922,8 @@ template <
const uint16_t ip = context.memory.template access<uint16_t, AccessType::Read>(address);
const uint16_t cs = context.memory.template access<uint16_t, AccessType::Read>(address + 2);
Primitive::push<uint16_t, true>(context.status.get(), context);
auto flags = context.status.get();
Primitive::push<uint16_t, true>(flags, context);
context.status.template set_from<Flag::Interrupt, Flag::Trap>(0);
// Push CS and IP.

View File

@ -109,8 +109,6 @@ struct Memory {
Seeded,
AccessExpected,
Accessed,
FlagsL,
FlagsH
};
std::unordered_map<uint32_t, Tag> tags;
@ -239,25 +237,7 @@ class FlowController {
FlowController(Memory &memory, Registers &registers, Status &status) :
memory_(memory), registers_(registers), status_(status) {}
void interrupt(int index) {
// TODO: reauthorise and possibly double fault?
const uint16_t address = static_cast<uint16_t>(index) << 2;
const uint16_t new_ip = memory_.access<uint16_t, Memory::AccessType::Read>(address, Memory::Tag::Accessed);
const uint16_t new_cs = memory_.access<uint16_t, Memory::AccessType::Read>(address + 2, Memory::Tag::Accessed);
push(status_.get(), true);
using Flag = InstructionSet::x86::Flag;
status_.set_from<Flag::Interrupt, Flag::Trap>(0);
// Push CS and IP.
push(registers_.cs_);
push(registers_.ip_);
registers_.cs_ = new_cs;
registers_.ip_ = new_ip;
}
// Requirements for perform.
void jump(uint16_t address) {
registers_.ip_ = address;
}
@ -270,12 +250,14 @@ class FlowController {
void halt() {}
void wait() {}
void begin_instruction() {
should_repeat_ = false;
}
void repeat_last() {
should_repeat_ = true;
}
// Other actions.
void begin_instruction() {
should_repeat_ = false;
}
bool should_repeat() const {
return should_repeat_;
}
@ -285,23 +267,6 @@ class FlowController {
Registers &registers_;
Status &status_;
bool should_repeat_ = false;
void push(uint16_t value, bool is_flags = false) {
// Perform the push in two steps because it's possible for SP to underflow, and so that FlagsL and
// FlagsH can be set separately.
--registers_.sp_;
memory_.access<uint8_t, Memory::AccessType::Write>(
InstructionSet::x86::Source::SS,
registers_.sp_,
is_flags ? Memory::Tag::FlagsH : Memory::Tag::Accessed
) = value >> 8;
--registers_.sp_;
memory_.access<uint8_t, Memory::AccessType::Write>(
InstructionSet::x86::Source::SS,
registers_.sp_,
is_flags ? Memory::Tag::FlagsL : Memory::Tag::Accessed
) = value & 0xff;
}
};
struct ExecutionSupport {
@ -556,21 +521,31 @@ struct FailedExecution {
InstructionSet::x86::Status intended_status;
bool ramEqual = true;
int mask_position = 0;
for(NSArray<NSNumber *> *ram in final_state[@"ram"]) {
const uint32_t address = [ram[0] intValue];
uint8_t mask = 0xff;
if(const auto tag = execution_support.memory.tags.find(address); tag != execution_support.memory.tags.end()) {
switch(tag->second) {
default: break;
case Memory::Tag::FlagsH: mask = flags_mask >> 8; break;
case Memory::Tag::FlagsL: mask = flags_mask & 0xff; break;
}
if((mask_position != 1) && execution_support.memory.memory[address] == [ram[1] intValue]) {
continue;
}
if((execution_support.memory.memory[address] & mask) != ([ram[1] intValue] & mask)) {
ramEqual = false;
// Consider whether this apparent mismatch might be because flags have been written to memory;
// allow only one use of the [16-bit] mask per test.
bool matched_with_mask = false;
while(mask_position < 2) {
const uint8_t mask = mask_position ? (flags_mask >> 8) : (flags_mask & 0xff);
++mask_position;
if((execution_support.memory.memory[address] & mask) == ([ram[1] intValue] & mask)) {
matched_with_mask = true;
break;
}
}
if(matched_with_mask) {
continue;
}
ramEqual = false;
break;
}
[self populate:intended_registers status:intended_status value:final_state[@"regs"]];