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:
parent
617be7cba7
commit
f715cd89a9
@ -1354,6 +1354,72 @@ void pushf(MemoryT &memory, RegistersT ®isters, 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 ®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 <
|
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.
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 ®isters_;
|
Registers ®isters_;
|
||||||
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user