1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-27 02:55:07 +00:00

Attempt CMPS, changing storage of direction; add flags check.

This commit is contained in:
Thomas Harte 2023-10-19 14:07:59 -04:00
parent 617be7cba7
commit f715cd89a9
3 changed files with 160 additions and 59 deletions

View File

@ -1354,6 +1354,72 @@ void pushf(MemoryT &memory, RegistersT &registers, Status &status) {
push<uint16_t>(value, memory, registers);
}
template <typename AddressT, typename InstructionT, typename RegistersT>
bool repetition_over(const InstructionT &instruction, RegistersT &registers) {
if(instruction.repetition() == Repetition::None) {
return false;
}
if constexpr (std::is_same_v<AddressT, uint16_t>) {
return !registers.cx();
} else {
return !registers.ecx();
}
}
template <typename AddressT, typename InstructionT, typename RegistersT, typename FlowControllerT>
void repeat(const InstructionT &instruction, Status &status, RegistersT &registers, FlowControllerT &flow_controller) {
if(instruction.repetition() == Repetition::None) {
return;
}
bool count_exhausted = false;
if constexpr (std::is_same_v<AddressT, uint16_t>) {
count_exhausted = !(--registers.cx());
} else {
count_exhausted = !(--registers.ecx());
}
if(count_exhausted) {
return;
}
const bool zero = status.flag<Flag::Zero>();
if(instruction.repetition() == Repetition::RepE && !zero) {
return;
} else if(instruction.repetition() == Repetition::RepNE && zero) {
return;
}
flow_controller.repeat_last();
}
template <typename IntT, typename AddressT, typename InstructionT, typename MemoryT, typename RegistersT, typename FlowControllerT>
void cmps(const InstructionT &instruction, MemoryT &memory, RegistersT &registers, Status &status, FlowControllerT &flow_controller) {
if(repetition_over<AddressT>(instruction, registers)) {
return;
}
Source source_segment = instruction.segment_override();
if(source_segment == Source::None) source_segment = Source::DS;
if constexpr (std::is_same_v<AddressT, uint16_t>) {
IntT source = memory.template access<IntT>(source_segment, registers.si());
IntT destination = memory.template access<IntT>(Source::ES, registers.di());
Primitive::sub<false, false>(destination, source, status);
registers.si() += status.direction<AddressT>();
registers.di() += status.direction<AddressT>();
} else {
IntT source = memory.template access<IntT>(source_segment, registers.esi());
IntT destination = memory.template access<IntT>(Source::ES, registers.edi());
Primitive::sub<false, false>(destination, source, status);
registers.esi() += status.direction<AddressT>();
registers.edi() += status.direction<AddressT>();
}
repeat<AddressT>(instruction, status, registers, flow_controller);
}
}
template <
@ -1569,6 +1635,11 @@ template <
case Operation::PUSH: Primitive::push<IntT>(source(), memory, registers); break;
case Operation::POPF: Primitive::popf(memory, registers, status); break;
case Operation::PUSHF: Primitive::pushf(memory, registers, status); break;
// TODO: don't assume address size below.
case Operation::CMPS:
Primitive::cmps<IntT, uint16_t>(instruction, memory, registers, status, flow_controller);
break;
}
// Write to memory if required to complete this operation.

View File

@ -84,14 +84,14 @@ class Status {
// Flag getters.
template <Flag flag> bool flag() const {
switch(flag) {
case Flag::Carry: return carry;
case Flag::AuxiliaryCarry: return auxiliary_carry;
case Flag::Sign: return sign;
case Flag::Overflow: return overflow;
case Flag::Trap: return trap;
case Flag::Interrupt: return interrupt;
case Flag::Direction: return direction;
case Flag::Zero: return !zero;
case Flag::Carry: return carry_;
case Flag::AuxiliaryCarry: return auxiliary_carry_;
case Flag::Sign: return sign_;
case Flag::Overflow: return overflow_;
case Flag::Trap: return trap_;
case Flag::Interrupt: return interrupt_;
case Flag::Direction: return direction_ < 0;
case Flag::Zero: return !zero_;
case Flag::ParityOdd: return not_parity_bit();
}
}
@ -126,15 +126,15 @@ class Status {
for(const auto flag: {flags...}) {
switch(flag) {
default: break;
case Flag::Zero: zero = value; break;
case Flag::Sign: sign = value & Numeric::top_bit<IntT>(); break;
case Flag::ParityOdd: parity = value; break;
case Flag::Carry: carry = value; break;
case Flag::AuxiliaryCarry: auxiliary_carry = value; break;
case Flag::Overflow: overflow = value; break;
case Flag::Interrupt: interrupt = value; break;
case Flag::Trap: trap = value; break;
case Flag::Direction: direction = value; break;
case Flag::Zero: zero_ = value; break;
case Flag::Sign: sign_ = value & Numeric::top_bit<IntT>(); break;
case Flag::ParityOdd: parity_ = value; break;
case Flag::Carry: carry_ = value; break;
case Flag::AuxiliaryCarry: auxiliary_carry_ = value; break;
case Flag::Overflow: overflow_ = value; break;
case Flag::Interrupt: interrupt_ = value; break;
case Flag::Trap: trap_ = value; break;
case Flag::Direction: direction_ = value ? -1 : 1; break;
}
}
}
@ -142,44 +142,45 @@ class Status {
set_from<FlagT, flags...>(value);
}
template <typename IntT> IntT carry_bit() const { return carry ? 1 : 0; }
template <typename IntT> IntT carry_bit() const { return carry_ ? 1 : 0; }
bool not_parity_bit() const {
// x86 parity always considers the lowest 8-bits only.
auto result = static_cast<uint8_t>(parity);
auto result = static_cast<uint8_t>(parity_);
result ^= result >> 4;
result ^= result >> 2;
result ^= result >> 1;
return result & 1;
}
template <typename IntT> IntT direction() const { return static_cast<IntT>(direction_); }
// Complete value get and set.
void set(uint16_t value) {
carry = value & ConditionCode::Carry;
auxiliary_carry = value & ConditionCode::AuxiliaryCarry;
sign = value & ConditionCode::Sign;
overflow = value & ConditionCode::Overflow;
trap = value & ConditionCode::Trap;
interrupt = value & ConditionCode::Interrupt;
direction = value & ConditionCode::Direction;
carry_ = value & ConditionCode::Carry;
auxiliary_carry_ = value & ConditionCode::AuxiliaryCarry;
sign_ = value & ConditionCode::Sign;
overflow_ = value & ConditionCode::Overflow;
trap_ = value & ConditionCode::Trap;
interrupt_ = value & ConditionCode::Interrupt;
direction_ = (value & ConditionCode::Direction) ? -1 : 1;
zero = (~value) & ConditionCode::Zero;
zero_ = (~value) & ConditionCode::Zero;
parity = (~value) & ConditionCode::Parity;
parity_ = (~value) & ConditionCode::Parity;
}
uint16_t get() const {
return
0xf002 |
(carry ? ConditionCode::Carry : 0) |
(auxiliary_carry ? ConditionCode::AuxiliaryCarry : 0) |
(sign ? ConditionCode::Sign : 0) |
(overflow ? ConditionCode::Overflow : 0) |
(trap ? ConditionCode::Trap : 0) |
(interrupt ? ConditionCode::Interrupt : 0) |
(direction ? ConditionCode::Direction : 0) |
(zero ? 0 : ConditionCode::Zero) |
(flag<Flag::Carry>() ? ConditionCode::Carry : 0) |
(flag<Flag::AuxiliaryCarry>() ? ConditionCode::AuxiliaryCarry : 0) |
(flag<Flag::Sign>() ? ConditionCode::Sign : 0) |
(flag<Flag::Overflow>() ? ConditionCode::Overflow : 0) |
(flag<Flag::Trap>() ? ConditionCode::Trap : 0) |
(flag<Flag::Interrupt>() ? ConditionCode::Interrupt : 0) |
(flag<Flag::Direction>() ? ConditionCode::Direction : 0) |
(flag<Flag::Zero>() ? ConditionCode::Zero : 0) |
(not_parity_bit() ? 0 : ConditionCode::Parity);
}
@ -187,18 +188,18 @@ class Status {
std::string to_string() const {
std::string result;
if(overflow) result += "O"; else result += "-";
if(direction) result += "D"; else result += "-";
if(interrupt) result += "I"; else result += "-";
if(trap) result += "T"; else result += "-";
if(sign) result += "S"; else result += "-";
if(!zero) result += "S"; else result += "-";
if(overflow_) result += "O"; else result += "-";
if(direction_) result += "D"; else result += "-";
if(interrupt_) result += "I"; else result += "-";
if(trap_) result += "T"; else result += "-";
if(sign_) result += "S"; else result += "-";
if(!zero_) result += "Z"; else result += "-";
result += "-";
if(auxiliary_carry) result += "A"; else result += "-";
if(auxiliary_carry_) result += "A"; else result += "-";
result += "-";
if(!not_parity_bit()) result += "P"; else result += "-";
result += "-";
if(carry) result += "C"; else result += "-";
if(carry_) result += "C"; else result += "-";
return result;
}
@ -209,19 +210,22 @@ class Status {
private:
// Non-zero => set; zero => unset.
uint32_t carry;
uint32_t auxiliary_carry;
uint32_t sign;
uint32_t overflow;
uint32_t trap;
uint32_t interrupt;
uint32_t direction;
uint32_t carry_;
uint32_t auxiliary_carry_;
uint32_t sign_;
uint32_t overflow_;
uint32_t trap_;
uint32_t interrupt_;
// +1 = direction flag not set;
// -1 = direction flag set.
int32_t direction_;
// Zero => set; non-zero => unset.
uint32_t zero;
uint32_t zero_;
// Odd number of bits => set; even => unset.
uint32_t parity;
uint32_t parity_;
};
}

View File

@ -230,6 +230,10 @@ class FlowController {
void halt() {}
void wait() {}
void repeat_last() {
// TODO.
}
private:
Memory &memory_;
Registers &registers_;
@ -390,8 +394,11 @@ struct FailedExecution {
@"C4.json.gz", // LES
@"8D.json.gz", // LEA
// TODO: CMPS, LODS, MOVS, SCAS, STOS
// TODO: LODS, MOVS, SCAS, STOS
*/
// CMPS
@"A6.json.gz", //@"A7.json.gz",
/*
@"E0.json.gz", // LOOPNE
@"E1.json.gz", // LOOPE
@"E2.json.gz", // LOOP
@ -426,7 +433,7 @@ struct FailedExecution {
// NOP
@"90.json.gz",
*/
// POP
@"07.json.gz", @"0F.json.gz", @"17.json.gz", @"1F.json.gz",
@"58.json.gz", @"59.json.gz", @"5A.json.gz", @"5B.json.gz",
@ -444,7 +451,7 @@ struct FailedExecution {
// PUSHF
@"9C.json.gz",
/*
// RCL
@"D0.2.json.gz", @"D2.2.json.gz",
@"D1.2.json.gz", @"D3.2.json.gz",
@ -653,7 +660,26 @@ struct FailedExecution {
registers.ss_ = [value[@"ss"] intValue];
registers.ip_ = [value[@"ip"] intValue];
status.set([value[@"flags"] intValue]);
const uint16_t flags = [value[@"flags"] intValue];
status.set(flags);
// Apply a quick test of flag packing/unpacking.
constexpr auto defined_flags = static_cast<uint16_t>(
InstructionSet::x86::ConditionCode::Carry |
InstructionSet::x86::ConditionCode::Parity |
InstructionSet::x86::ConditionCode::AuxiliaryCarry |
InstructionSet::x86::ConditionCode::Zero |
InstructionSet::x86::ConditionCode::Sign |
InstructionSet::x86::ConditionCode::Trap |
InstructionSet::x86::ConditionCode::Interrupt |
InstructionSet::x86::ConditionCode::Direction |
InstructionSet::x86::ConditionCode::Overflow
);
XCTAssert((status.get() & defined_flags) == (flags & defined_flags),
"Set status of %04x was returned as %04x",
flags & defined_flags,
(status.get() & defined_flags)
);
}
- (void)applyExecutionTest:(NSDictionary *)test metadata:(NSDictionary *)metadata {