mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Attempt CMPS, changing storage of direction; add flags check.
This commit is contained in:
parent
617be7cba7
commit
f715cd89a9
@ -1354,6 +1354,72 @@ void pushf(MemoryT &memory, RegistersT ®isters, Status &status) {
|
||||
push<uint16_t>(value, memory, registers);
|
||||
}
|
||||
|
||||
template <typename AddressT, typename InstructionT, typename RegistersT>
|
||||
bool repetition_over(const InstructionT &instruction, RegistersT ®isters) {
|
||||
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 ®isters, 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 ®isters, 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.
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -230,6 +230,10 @@ class FlowController {
|
||||
void halt() {}
|
||||
void wait() {}
|
||||
|
||||
void repeat_last() {
|
||||
// TODO.
|
||||
}
|
||||
|
||||
private:
|
||||
Memory &memory_;
|
||||
Registers ®isters_;
|
||||
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user