1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-18 16:30:29 +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); 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 < template <
@ -1569,6 +1635,11 @@ template <
case Operation::PUSH: Primitive::push<IntT>(source(), memory, registers); break; case Operation::PUSH: Primitive::push<IntT>(source(), memory, registers); break;
case Operation::POPF: Primitive::popf(memory, registers, status); break; case Operation::POPF: Primitive::popf(memory, registers, status); break;
case Operation::PUSHF: Primitive::pushf(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. // Write to memory if required to complete this operation.

View File

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

View File

@ -230,6 +230,10 @@ class FlowController {
void halt() {} void halt() {}
void wait() {} void wait() {}
void repeat_last() {
// TODO.
}
private: private:
Memory &memory_; Memory &memory_;
Registers &registers_; Registers &registers_;
@ -390,8 +394,11 @@ struct FailedExecution {
@"C4.json.gz", // LES @"C4.json.gz", // LES
@"8D.json.gz", // LEA @"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 @"E0.json.gz", // LOOPNE
@"E1.json.gz", // LOOPE @"E1.json.gz", // LOOPE
@"E2.json.gz", // LOOP @"E2.json.gz", // LOOP
@ -426,7 +433,7 @@ struct FailedExecution {
// NOP // NOP
@"90.json.gz", @"90.json.gz",
*/
// POP // POP
@"07.json.gz", @"0F.json.gz", @"17.json.gz", @"1F.json.gz", @"07.json.gz", @"0F.json.gz", @"17.json.gz", @"1F.json.gz",
@"58.json.gz", @"59.json.gz", @"5A.json.gz", @"5B.json.gz", @"58.json.gz", @"59.json.gz", @"5A.json.gz", @"5B.json.gz",
@ -444,7 +451,7 @@ struct FailedExecution {
// PUSHF // PUSHF
@"9C.json.gz", @"9C.json.gz",
/*
// RCL // RCL
@"D0.2.json.gz", @"D2.2.json.gz", @"D0.2.json.gz", @"D2.2.json.gz",
@"D1.2.json.gz", @"D3.2.json.gz", @"D1.2.json.gz", @"D3.2.json.gz",
@ -653,7 +660,26 @@ struct FailedExecution {
registers.ss_ = [value[@"ss"] intValue]; registers.ss_ = [value[@"ss"] intValue];
registers.ip_ = [value[@"ip"] 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 { - (void)applyExecutionTest:(NSDictionary *)test metadata:(NSDictionary *)metadata {