mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Merge pull request #1195 from TomHarte/8088Flags
Commute: Status -> Flags as per usual x86 naming.
This commit is contained in:
commit
7f4fa914dd
@ -1,19 +1,19 @@
|
||||
//
|
||||
// Status.hpp
|
||||
// Flags.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 05/10/2023.
|
||||
// Copyright © 2023 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef InstructionSets_x86_Status_hpp
|
||||
#define InstructionSets_x86_Status_hpp
|
||||
#ifndef InstructionSets_x86_Flags_hpp
|
||||
#define InstructionSets_x86_Flags_hpp
|
||||
|
||||
#include "../../Numeric/Carry.hpp"
|
||||
|
||||
namespace InstructionSet::x86 {
|
||||
|
||||
namespace ConditionCode {
|
||||
namespace FlagValue {
|
||||
|
||||
//
|
||||
// Standard flags.
|
||||
@ -77,7 +77,7 @@ enum class Condition {
|
||||
LessOrEqual
|
||||
};
|
||||
|
||||
class Status {
|
||||
class Flags {
|
||||
public:
|
||||
using FlagT = uint32_t;
|
||||
|
||||
@ -156,33 +156,33 @@ class Status {
|
||||
|
||||
// Complete value get and set.
|
||||
void set(uint16_t value) {
|
||||
set_from<Flag::Carry>(value & ConditionCode::Carry);
|
||||
set_from<Flag::AuxiliaryCarry>(value & ConditionCode::AuxiliaryCarry);
|
||||
set_from<Flag::Overflow>(value & ConditionCode::Overflow);
|
||||
set_from<Flag::Trap>(value & ConditionCode::Trap);
|
||||
set_from<Flag::Interrupt>(value & ConditionCode::Interrupt);
|
||||
set_from<Flag::Direction>(value & ConditionCode::Direction);
|
||||
set_from<Flag::Carry>(value & FlagValue::Carry);
|
||||
set_from<Flag::AuxiliaryCarry>(value & FlagValue::AuxiliaryCarry);
|
||||
set_from<Flag::Overflow>(value & FlagValue::Overflow);
|
||||
set_from<Flag::Trap>(value & FlagValue::Trap);
|
||||
set_from<Flag::Interrupt>(value & FlagValue::Interrupt);
|
||||
set_from<Flag::Direction>(value & FlagValue::Direction);
|
||||
|
||||
set_from<uint8_t, Flag::Sign>(value);
|
||||
|
||||
set_from<Flag::Zero>((~value) & ConditionCode::Zero);
|
||||
set_from<Flag::ParityOdd>((~value) & ConditionCode::Parity);
|
||||
set_from<Flag::Zero>((~value) & FlagValue::Zero);
|
||||
set_from<Flag::ParityOdd>((~value) & FlagValue::Parity);
|
||||
}
|
||||
|
||||
uint16_t get() const {
|
||||
return
|
||||
0xf002 |
|
||||
|
||||
(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) |
|
||||
(flag<Flag::Carry>() ? FlagValue::Carry : 0) |
|
||||
(flag<Flag::AuxiliaryCarry>() ? FlagValue::AuxiliaryCarry : 0) |
|
||||
(flag<Flag::Sign>() ? FlagValue::Sign : 0) |
|
||||
(flag<Flag::Overflow>() ? FlagValue::Overflow : 0) |
|
||||
(flag<Flag::Trap>() ? FlagValue::Trap : 0) |
|
||||
(flag<Flag::Interrupt>() ? FlagValue::Interrupt : 0) |
|
||||
(flag<Flag::Direction>() ? FlagValue::Direction : 0) |
|
||||
(flag<Flag::Zero>() ? FlagValue::Zero : 0) |
|
||||
|
||||
(flag<Flag::ParityOdd>() ? 0 : ConditionCode::Parity);
|
||||
(flag<Flag::ParityOdd>() ? 0 : FlagValue::Parity);
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
@ -204,7 +204,7 @@ class Status {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator ==(const Status &rhs) const {
|
||||
bool operator ==(const Flags &rhs) const {
|
||||
return get() == rhs.get();
|
||||
}
|
||||
|
||||
@ -230,4 +230,4 @@ class Status {
|
||||
|
||||
}
|
||||
|
||||
#endif /* InstructionSets_x86_Status_hpp */
|
||||
#endif /* InstructionSets_x86_Flags_hpp */
|
@ -191,18 +191,18 @@ 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.
|
||||
template <typename IntT, bool Preauthorised, typename ContextT>
|
||||
template <typename IntT, bool preauthorised, typename ContextT>
|
||||
void push(IntT &value, ContextT &context) {
|
||||
context.registers.sp_ -= sizeof(IntT);
|
||||
context.memory.template access<IntT, Preauthorised ? AccessType::PreauthorisedWrite : AccessType::Write>(
|
||||
context.memory.template access<IntT, preauthorised ? AccessType::PreauthorisedWrite : AccessType::Write>(
|
||||
Source::SS,
|
||||
context.registers.sp_) = value;
|
||||
context.memory.template write_back<IntT>();
|
||||
}
|
||||
|
||||
template <typename IntT, bool Preauthorised, typename ContextT>
|
||||
template <typename IntT, bool preauthorised, typename ContextT>
|
||||
IntT pop(ContextT &context) {
|
||||
const auto value = context.memory.template access<IntT, Preauthorised ? AccessType::PreauthorisedRead : AccessType::Read>(
|
||||
const auto value = context.memory.template access<IntT, preauthorised ? AccessType::PreauthorisedRead : AccessType::Read>(
|
||||
Source::SS,
|
||||
context.registers.sp_);
|
||||
context.registers.sp_ += sizeof(IntT);
|
||||
@ -236,12 +236,12 @@ void aaa(CPU::RegisterPair16 &ax, ContextT &context) { // P. 313
|
||||
The AF and CF flags are set to 1 if the adjustment results in a decimal carry;
|
||||
otherwise they are cleared to 0. The OF, SF, ZF, and PF flags are undefined.
|
||||
*/
|
||||
if((ax.halves.low & 0x0f) > 9 || context.status.template flag<Flag::AuxiliaryCarry>()) {
|
||||
if((ax.halves.low & 0x0f) > 9 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
ax.halves.low += 6;
|
||||
++ax.halves.high;
|
||||
context.status.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
ax.halves.low &= 0x0f;
|
||||
}
|
||||
@ -260,7 +260,7 @@ void aad(CPU::RegisterPair16 &ax, uint8_t imm, ContextT &context) {
|
||||
*/
|
||||
ax.halves.low = ax.halves.low + (ax.halves.high * imm);
|
||||
ax.halves.high = 0;
|
||||
context.status.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(ax.halves.low);
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(ax.halves.low);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
@ -284,7 +284,7 @@ void aam(CPU::RegisterPair16 &ax, uint8_t imm, ContextT &context) {
|
||||
|
||||
ax.halves.high = ax.halves.low / imm;
|
||||
ax.halves.low = ax.halves.low % imm;
|
||||
context.status.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(ax.halves.low);
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(ax.halves.low);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
@ -306,12 +306,12 @@ void aas(CPU::RegisterPair16 &ax, ContextT &context) {
|
||||
The AF and CF flags are set to 1 if there is a decimal borrow;
|
||||
otherwise, they are cleared to 0. The OF, SF, ZF, and PF flags are undefined.
|
||||
*/
|
||||
if((ax.halves.low & 0x0f) > 9 || context.status.template flag<Flag::AuxiliaryCarry>()) {
|
||||
if((ax.halves.low & 0x0f) > 9 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
ax.halves.low -= 6;
|
||||
--ax.halves.high;
|
||||
context.status.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
ax.halves.low &= 0x0f;
|
||||
}
|
||||
@ -347,25 +347,25 @@ void daa(uint8_t &al, ContextT &context) {
|
||||
The SF, ZF, and PF flags are set according to the result. The OF flag is undefined.
|
||||
*/
|
||||
const uint8_t old_al = al;
|
||||
const auto old_carry = context.status.template flag<Flag::Carry>();
|
||||
context.status.template set_from<Flag::Carry>(0);
|
||||
const auto old_carry = context.flags.template flag<Flag::Carry>();
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
|
||||
if((al & 0x0f) > 0x09 || context.status.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.status.template set_from<Flag::Carry>(old_carry | (al > 0xf9));
|
||||
if((al & 0x0f) > 0x09 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.flags.template set_from<Flag::Carry>(old_carry | (al > 0xf9));
|
||||
al += 0x06;
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
|
||||
if(old_al > 0x99 || old_carry) {
|
||||
al += 0x60;
|
||||
context.status.template set_from<Flag::Carry>(1);
|
||||
context.flags.template set_from<Flag::Carry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::Carry>(0);
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
}
|
||||
|
||||
context.status.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
@ -399,25 +399,25 @@ void das(uint8_t &al, ContextT &context) {
|
||||
The SF, ZF, and PF flags are set according to the result. The OF flag is undefined.
|
||||
*/
|
||||
const uint8_t old_al = al;
|
||||
const auto old_carry = context.status.template flag<Flag::Carry>();
|
||||
context.status.template set_from<Flag::Carry>(0);
|
||||
const auto old_carry = context.flags.template flag<Flag::Carry>();
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
|
||||
if((al & 0x0f) > 0x09 || context.status.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.status.template set_from<Flag::Carry>(old_carry | (al < 0x06));
|
||||
if((al & 0x0f) > 0x09 || context.flags.template flag<Flag::AuxiliaryCarry>()) {
|
||||
context.flags.template set_from<Flag::Carry>(old_carry | (al < 0x06));
|
||||
al -= 0x06;
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(0);
|
||||
}
|
||||
|
||||
if(old_al > 0x99 || old_carry) {
|
||||
al -= 0x60;
|
||||
context.status.template set_from<Flag::Carry>(1);
|
||||
context.flags.template set_from<Flag::Carry>(1);
|
||||
} else {
|
||||
context.status.template set_from<Flag::Carry>(0);
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
}
|
||||
|
||||
context.status.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
context.flags.template set_from<uint8_t, Flag::Zero, Flag::Sign, Flag::ParityOdd>(al);
|
||||
}
|
||||
|
||||
template <bool with_carry, typename IntT, typename ContextT>
|
||||
@ -428,16 +428,16 @@ void add(IntT &destination, IntT source, ContextT &context) {
|
||||
/*
|
||||
The OF, SF, ZF, AF, CF, and PF flags are set according to the result.
|
||||
*/
|
||||
const IntT result = destination + source + (with_carry ? context.status.template carry_bit<IntT>() : 0);
|
||||
const IntT result = destination + source + (with_carry ? context.flags.template carry_bit<IntT>() : 0);
|
||||
|
||||
context.status.template set_from<Flag::Carry>(
|
||||
context.flags.template set_from<Flag::Carry>(
|
||||
Numeric::carried_out<true, Numeric::bit_size<IntT>() - 1>(destination, source, result));
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(
|
||||
Numeric::carried_in<4>(destination, source, result));
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
Numeric::overflow<true, IntT>(destination, source, result));
|
||||
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
|
||||
destination = result;
|
||||
}
|
||||
@ -450,16 +450,16 @@ void sub(IntT &destination, IntT source, ContextT &context) {
|
||||
/*
|
||||
The OF, SF, ZF, AF, CF, and PF flags are set according to the result.
|
||||
*/
|
||||
const IntT result = destination - source - (with_borrow ? context.status.template carry_bit<IntT>() : 0);
|
||||
const IntT result = destination - source - (with_borrow ? context.flags.template carry_bit<IntT>() : 0);
|
||||
|
||||
context.status.template set_from<Flag::Carry>(
|
||||
context.flags.template set_from<Flag::Carry>(
|
||||
Numeric::carried_out<false, Numeric::bit_size<IntT>() - 1>(destination, source, result));
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(
|
||||
Numeric::carried_in<4>(destination, source, result));
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
Numeric::overflow<false, IntT>(destination, source, result));
|
||||
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
|
||||
if constexpr (write_back) {
|
||||
destination = result;
|
||||
@ -486,8 +486,8 @@ void test(IntT &destination, IntT source, ContextT &context) {
|
||||
*/
|
||||
const IntT result = destination & source;
|
||||
|
||||
context.status.template set_from<Flag::Carry, Flag::Overflow>(0);
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
context.flags.template set_from<Flag::Carry, Flag::Overflow>(0);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||
}
|
||||
|
||||
template <typename IntT>
|
||||
@ -519,7 +519,7 @@ void mul(IntT &destination_high, IntT &destination_low, IntT source, ContextT &c
|
||||
*/
|
||||
destination_high = (destination_low * source) >> (8 * sizeof(IntT));
|
||||
destination_low *= source;
|
||||
context.status.template set_from<Flag::Overflow, Flag::Carry>(destination_high);
|
||||
context.flags.template set_from<Flag::Overflow, Flag::Carry>(destination_high);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -554,7 +554,7 @@ void imul(IntT &destination_high, IntT &destination_low, IntT source, ContextT &
|
||||
destination_low = IntT(sIntT(destination_low) * sIntT(source));
|
||||
|
||||
const auto sign_extension = (destination_low & Numeric::top_bit<IntT>()) ? IntT(~0) : 0;
|
||||
context.status.template set_from<Flag::Overflow, Flag::Carry>(destination_high != sign_extension);
|
||||
context.flags.template set_from<Flag::Overflow, Flag::Carry>(destination_high != sign_extension);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -681,9 +681,9 @@ void inc(IntT &destination, ContextT &context) {
|
||||
*/
|
||||
++destination;
|
||||
|
||||
context.status.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(((destination - 1) ^ destination) & 0x10);
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(((destination - 1) ^ destination) & 0x10);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -716,7 +716,7 @@ void loop(IntT &counter, OffsetT displacement, ContextT &context) {
|
||||
template <typename IntT, typename OffsetT, typename ContextT>
|
||||
void loope(IntT &counter, OffsetT displacement, ContextT &context) {
|
||||
--counter;
|
||||
if(counter && context.status.template flag<Flag::Zero>()) {
|
||||
if(counter && context.flags.template flag<Flag::Zero>()) {
|
||||
context.flow_controller.jump(context.registers.ip() + displacement);
|
||||
}
|
||||
}
|
||||
@ -724,7 +724,7 @@ void loope(IntT &counter, OffsetT displacement, ContextT &context) {
|
||||
template <typename IntT, typename OffsetT, typename ContextT>
|
||||
void loopne(IntT &counter, OffsetT displacement, ContextT &context) {
|
||||
--counter;
|
||||
if(counter && !context.status.template flag<Flag::Zero>()) {
|
||||
if(counter && !context.flags.template flag<Flag::Zero>()) {
|
||||
context.flow_controller.jump(context.registers.ip() + displacement);
|
||||
}
|
||||
}
|
||||
@ -738,12 +738,12 @@ void dec(IntT &destination, ContextT &context) {
|
||||
The CF flag is not affected.
|
||||
The OF, SF, ZF, AF, and PF flags are set according to the result.
|
||||
*/
|
||||
context.status.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
context.flags.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
|
||||
--destination;
|
||||
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(((destination + 1) ^ destination) & 0x10);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(((destination + 1) ^ destination) & 0x10);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -757,8 +757,8 @@ void and_(IntT &destination, IntT source, ContextT &context) {
|
||||
*/
|
||||
destination &= source;
|
||||
|
||||
context.status.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -772,8 +772,8 @@ void or_(IntT &destination, IntT source, ContextT &context) {
|
||||
*/
|
||||
destination |= source;
|
||||
|
||||
context.status.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -787,8 +787,8 @@ void xor_(IntT &destination, IntT source, ContextT &context) {
|
||||
*/
|
||||
destination ^= source;
|
||||
|
||||
context.status.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Overflow, Flag::Carry>(0);
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -804,13 +804,13 @@ void neg(IntT &destination, ContextT &context) {
|
||||
The CF flag cleared to 0 if the source operand is 0; otherwise it is set to 1.
|
||||
The OF, SF, ZF, AF, and PF flags are set according to the result.
|
||||
*/
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(Numeric::carried_in<4>(IntT(0), destination, IntT(-destination)));
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(Numeric::carried_in<4>(IntT(0), destination, IntT(-destination)));
|
||||
|
||||
destination = -destination;
|
||||
|
||||
context.status.template set_from<Flag::Carry>(destination);
|
||||
context.status.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
context.status.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Carry>(destination);
|
||||
context.flags.template set_from<Flag::Overflow>(destination == Numeric::top_bit<IntT>());
|
||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT>
|
||||
@ -915,7 +915,7 @@ void iret(ContextT &context) {
|
||||
context.memory.preauthorise_stack_read(sizeof(uint16_t) * 3);
|
||||
const auto ip = pop<uint16_t, true>(context);
|
||||
const auto cs = pop<uint16_t, true>(context);
|
||||
context.status.set(pop<uint16_t, true>(context));
|
||||
context.flags.set(pop<uint16_t, true>(context));
|
||||
context.flow_controller.jump(cs, ip);
|
||||
}
|
||||
|
||||
@ -984,7 +984,7 @@ void mov(IntT &destination, IntT source) {
|
||||
|
||||
template <typename ContextT>
|
||||
void into(ContextT &context) {
|
||||
if(context.status.template flag<Flag::Overflow>()) {
|
||||
if(context.flags.template flag<Flag::Overflow>()) {
|
||||
interrupt(Interrupt::OnOverflow, context);
|
||||
}
|
||||
}
|
||||
@ -994,11 +994,11 @@ void sahf(uint8_t &ah, ContextT &context) {
|
||||
/*
|
||||
EFLAGS(SF:ZF:0:AF:0:PF:1:CF) ← AH;
|
||||
*/
|
||||
context.status.template set_from<uint8_t, Flag::Sign>(ah);
|
||||
context.status.template set_from<Flag::Zero>(!(ah & 0x40));
|
||||
context.status.template set_from<Flag::AuxiliaryCarry>(ah & 0x10);
|
||||
context.status.template set_from<Flag::ParityOdd>(!(ah & 0x04));
|
||||
context.status.template set_from<Flag::Carry>(ah & 0x01);
|
||||
context.flags.template set_from<uint8_t, Flag::Sign>(ah);
|
||||
context.flags.template set_from<Flag::Zero>(!(ah & 0x40));
|
||||
context.flags.template set_from<Flag::AuxiliaryCarry>(ah & 0x10);
|
||||
context.flags.template set_from<Flag::ParityOdd>(!(ah & 0x04));
|
||||
context.flags.template set_from<Flag::Carry>(ah & 0x01);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
@ -1007,12 +1007,12 @@ void lahf(uint8_t &ah, ContextT &context) {
|
||||
AH ← EFLAGS(SF:ZF:0:AF:0:PF:1:CF);
|
||||
*/
|
||||
ah =
|
||||
(context.status.template flag<Flag::Sign>() ? 0x80 : 0x00) |
|
||||
(context.status.template flag<Flag::Zero>() ? 0x40 : 0x00) |
|
||||
(context.status.template flag<Flag::AuxiliaryCarry>() ? 0x10 : 0x00) |
|
||||
(context.status.template flag<Flag::ParityOdd>() ? 0x00 : 0x04) |
|
||||
(context.flags.template flag<Flag::Sign>() ? 0x80 : 0x00) |
|
||||
(context.flags.template flag<Flag::Zero>() ? 0x40 : 0x00) |
|
||||
(context.flags.template flag<Flag::AuxiliaryCarry>() ? 0x10 : 0x00) |
|
||||
(context.flags.template flag<Flag::ParityOdd>() ? 0x00 : 0x04) |
|
||||
0x02 |
|
||||
(context.status.template flag<Flag::Carry>() ? 0x01 : 0x00);
|
||||
(context.flags.template flag<Flag::Carry>() ? 0x01 : 0x00);
|
||||
}
|
||||
|
||||
template <typename IntT>
|
||||
@ -1034,32 +1034,32 @@ void cwd(IntT &dx, IntT ax) {
|
||||
|
||||
// TODO: changes to the interrupt flag do quite a lot more in protected mode.
|
||||
template <typename ContextT>
|
||||
void clc(ContextT &context) { context.status.template set_from<Flag::Carry>(0); }
|
||||
void clc(ContextT &context) { context.flags.template set_from<Flag::Carry>(0); }
|
||||
template <typename ContextT>
|
||||
void cld(ContextT &context) { context.status.template set_from<Flag::Direction>(0); }
|
||||
void cld(ContextT &context) { context.flags.template set_from<Flag::Direction>(0); }
|
||||
template <typename ContextT>
|
||||
void cli(ContextT &context) { context.status.template set_from<Flag::Interrupt>(0); }
|
||||
void cli(ContextT &context) { context.flags.template set_from<Flag::Interrupt>(0); }
|
||||
template <typename ContextT>
|
||||
void stc(ContextT &context) { context.status.template set_from<Flag::Carry>(1); }
|
||||
void stc(ContextT &context) { context.flags.template set_from<Flag::Carry>(1); }
|
||||
template <typename ContextT>
|
||||
void std(ContextT &context) { context.status.template set_from<Flag::Direction>(1); }
|
||||
void std(ContextT &context) { context.flags.template set_from<Flag::Direction>(1); }
|
||||
template <typename ContextT>
|
||||
void sti(ContextT &context) { context.status.template set_from<Flag::Interrupt>(1); }
|
||||
void sti(ContextT &context) { context.flags.template set_from<Flag::Interrupt>(1); }
|
||||
template <typename ContextT>
|
||||
void cmc(ContextT &context) {
|
||||
context.status.template set_from<Flag::Carry>(!context.status.template flag<Flag::Carry>());
|
||||
context.flags.template set_from<Flag::Carry>(!context.flags.template flag<Flag::Carry>());
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void salc(uint8_t &al, ContextT &context) {
|
||||
al = context.status.template flag<Flag::Carry>() ? 0xff : 0x00;
|
||||
al = context.flags.template flag<Flag::Carry>() ? 0xff : 0x00;
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
void setmo(IntT &destination, ContextT &context) {
|
||||
destination = ~0;
|
||||
context.status.template set_from<Flag::Carry, Flag::AuxiliaryCarry, Flag::Overflow>(0);
|
||||
context.status.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Carry, Flag::AuxiliaryCarry, Flag::Overflow>(0);
|
||||
context.flags.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -1094,7 +1094,7 @@ void rcl(IntT &destination, uint8_t count, ContextT &context) {
|
||||
it is undefined for multi-bit rotates. The SF, ZF, AF, and PF flags are not affected.
|
||||
*/
|
||||
const auto temp_count = count % (Numeric::bit_size<IntT>() + 1);
|
||||
auto carry = context.status.template carry_bit<IntT>();
|
||||
auto carry = context.flags.template carry_bit<IntT>();
|
||||
switch(temp_count) {
|
||||
case 0: break;
|
||||
case Numeric::bit_size<IntT>(): {
|
||||
@ -1112,8 +1112,8 @@ void rcl(IntT &destination, uint8_t count, ContextT &context) {
|
||||
} break;
|
||||
}
|
||||
|
||||
context.status.template set_from<Flag::Carry>(carry);
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Carry>(carry);
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
((destination >> (Numeric::bit_size<IntT>() - 1)) & 1) ^ carry
|
||||
);
|
||||
}
|
||||
@ -1134,8 +1134,8 @@ void rcr(IntT &destination, uint8_t count, ContextT &context) {
|
||||
tempCOUNT ← tempCOUNT – 1;
|
||||
OD;
|
||||
*/
|
||||
auto carry = context.status.template carry_bit<IntT>();
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
auto carry = context.flags.template carry_bit<IntT>();
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
((destination >> (Numeric::bit_size<IntT>() - 1)) & 1) ^ carry
|
||||
);
|
||||
|
||||
@ -1157,7 +1157,7 @@ void rcr(IntT &destination, uint8_t count, ContextT &context) {
|
||||
} break;
|
||||
}
|
||||
|
||||
context.status.template set_from<Flag::Carry>(carry);
|
||||
context.flags.template set_from<Flag::Carry>(carry);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -1201,8 +1201,8 @@ void rol(IntT &destination, uint8_t count, ContextT &context) {
|
||||
(destination >> (Numeric::bit_size<IntT>() - temp_count));
|
||||
}
|
||||
|
||||
context.status.template set_from<Flag::Carry>(destination & 1);
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Carry>(destination & 1);
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
((destination >> (Numeric::bit_size<IntT>() - 1)) ^ destination) & 1
|
||||
);
|
||||
}
|
||||
@ -1248,8 +1248,8 @@ void ror(IntT &destination, uint8_t count, ContextT &context) {
|
||||
(destination << (Numeric::bit_size<IntT>() - temp_count));
|
||||
}
|
||||
|
||||
context.status.template set_from<Flag::Carry>(destination & Numeric::top_bit<IntT>());
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Carry>(destination & Numeric::top_bit<IntT>());
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
(destination ^ (destination << 1)) & Numeric::top_bit<IntT>()
|
||||
);
|
||||
}
|
||||
@ -1315,26 +1315,26 @@ void sal(IntT &destination, uint8_t count, ContextT &context) {
|
||||
switch(count) {
|
||||
case 0: return;
|
||||
case Numeric::bit_size<IntT>():
|
||||
context.status.template set_from<Flag::Carry, Flag::Overflow>(destination & 1);
|
||||
context.flags.template set_from<Flag::Carry, Flag::Overflow>(destination & 1);
|
||||
destination = 0;
|
||||
break;
|
||||
default:
|
||||
if(count > Numeric::bit_size<IntT>()) {
|
||||
context.status.template set_from<Flag::Carry, Flag::Overflow>(0);
|
||||
context.flags.template set_from<Flag::Carry, Flag::Overflow>(0);
|
||||
destination = 0;
|
||||
} else {
|
||||
const auto mask = (Numeric::top_bit<IntT>() >> (count - 1));
|
||||
context.status.template set_from<Flag::Carry>(
|
||||
context.flags.template set_from<Flag::Carry>(
|
||||
destination & mask
|
||||
);
|
||||
context.status.template set_from<Flag::Overflow>(
|
||||
context.flags.template set_from<Flag::Overflow>(
|
||||
(destination ^ (destination << 1)) & mask
|
||||
);
|
||||
destination <<= count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
context.status.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -1346,14 +1346,14 @@ void sar(IntT &destination, uint8_t count, ContextT &context) {
|
||||
const IntT sign = Numeric::top_bit<IntT>() & destination;
|
||||
if(count >= Numeric::bit_size<IntT>()) {
|
||||
destination = sign ? IntT(~0) : IntT(0);
|
||||
context.status.template set_from<Flag::Carry>(sign);
|
||||
context.flags.template set_from<Flag::Carry>(sign);
|
||||
} else {
|
||||
const IntT mask = 1 << (count - 1);
|
||||
context.status.template set_from<Flag::Carry>(destination & mask);
|
||||
context.flags.template set_from<Flag::Carry>(destination & mask);
|
||||
destination = (destination >> count) | (sign ? ~(IntT(~0) >> count) : 0);
|
||||
}
|
||||
context.status.template set_from<Flag::Overflow>(0);
|
||||
context.status.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<Flag::Overflow>(0);
|
||||
context.flags.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
@ -1362,29 +1362,29 @@ void shr(IntT &destination, uint8_t count, ContextT &context) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.status.template set_from<Flag::Overflow>(Numeric::top_bit<IntT>() & destination);
|
||||
context.flags.template set_from<Flag::Overflow>(Numeric::top_bit<IntT>() & destination);
|
||||
if(count == Numeric::bit_size<IntT>()) {
|
||||
context.status.template set_from<Flag::Carry>(Numeric::top_bit<IntT>() & destination);
|
||||
context.flags.template set_from<Flag::Carry>(Numeric::top_bit<IntT>() & destination);
|
||||
destination = 0;
|
||||
} else if(count > Numeric::bit_size<IntT>()) {
|
||||
context.status.template set_from<Flag::Carry>(0);
|
||||
context.flags.template set_from<Flag::Carry>(0);
|
||||
destination = 0;
|
||||
} else {
|
||||
const IntT mask = 1 << (count - 1);
|
||||
context.status.template set_from<Flag::Carry>(destination & mask);
|
||||
context.flags.template set_from<Flag::Carry>(destination & mask);
|
||||
destination >>= count;
|
||||
}
|
||||
context.status.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
context.flags.template set_from<IntT, Flag::Sign, Flag::Zero, Flag::ParityOdd>(destination);
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void popf(ContextT &context) {
|
||||
context.status.set(pop<uint16_t, false>(context));
|
||||
context.flags.set(pop<uint16_t, false>(context));
|
||||
}
|
||||
|
||||
template <typename ContextT>
|
||||
void pushf(ContextT &context) {
|
||||
uint16_t value = context.status.get();
|
||||
uint16_t value = context.flags.get();
|
||||
push<uint16_t, false>(value, context);
|
||||
}
|
||||
|
||||
@ -1403,7 +1403,7 @@ void repeat(AddressT &eCX, ContextT &context) {
|
||||
}
|
||||
if constexpr (repetition != Repetition::Rep) {
|
||||
// If this is RepE or RepNE, also test the zero flag.
|
||||
if((repetition == Repetition::RepNE) == context.status.template flag<Flag::Zero>()) {
|
||||
if((repetition == Repetition::RepNE) == context.flags.template flag<Flag::Zero>()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1418,8 +1418,8 @@ void cmps(const InstructionT &instruction, AddressT &eCX, AddressT &eSI, Address
|
||||
|
||||
IntT lhs = context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
|
||||
const IntT rhs = context.memory.template access<IntT, AccessType::Read>(Source::ES, eDI);
|
||||
eSI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
Primitive::sub<false, false>(lhs, rhs, context);
|
||||
|
||||
@ -1433,7 +1433,7 @@ void scas(AddressT &eCX, AddressT &eDI, IntT &eAX, ContextT &context) {
|
||||
}
|
||||
|
||||
const IntT rhs = context.memory.template access<IntT, AccessType::Read>(Source::ES, eDI);
|
||||
eDI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
Primitive::sub<false, false>(eAX, rhs, context);
|
||||
|
||||
@ -1447,7 +1447,7 @@ void lods(const InstructionT &instruction, AddressT &eCX, AddressT &eSI, IntT &e
|
||||
}
|
||||
|
||||
eAX = context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
|
||||
eSI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
repeat<AddressT, repetition>(eCX, context);
|
||||
}
|
||||
@ -1461,8 +1461,8 @@ void movs(const InstructionT &instruction, AddressT &eCX, AddressT &eSI, Address
|
||||
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) =
|
||||
context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
|
||||
|
||||
eSI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
repeat<AddressT, repetition>(eCX, context);
|
||||
}
|
||||
@ -1474,7 +1474,7 @@ void stos(AddressT &eCX, AddressT &eDI, IntT &eAX, ContextT &context) {
|
||||
}
|
||||
|
||||
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) = eAX;
|
||||
eDI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
repeat<AddressT, repetition>(eCX, context);
|
||||
}
|
||||
@ -1489,7 +1489,7 @@ void outs(const InstructionT &instruction, AddressT &eCX, uint16_t port, Address
|
||||
port,
|
||||
context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI)
|
||||
);
|
||||
eSI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
repeat<AddressT, repetition>(eCX, context);
|
||||
}
|
||||
@ -1501,7 +1501,7 @@ void ins(AddressT &eCX, uint16_t port, AddressT &eDI, ContextT &context) {
|
||||
}
|
||||
|
||||
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) = context.io.template in<IntT>(port);
|
||||
eDI += context.status.template direction<AddressT>() * sizeof(IntT);
|
||||
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
|
||||
|
||||
repeat<AddressT, repetition>(eCX, context);
|
||||
}
|
||||
@ -1722,22 +1722,22 @@ template <
|
||||
case Operation::LEA: Primitive::lea(instruction, destination_w(), context); return;
|
||||
case Operation::MOV: Primitive::mov(destination_w(), source_r()); break;
|
||||
|
||||
case Operation::JO: jcc(context.status.template condition<Condition::Overflow>()); return;
|
||||
case Operation::JNO: jcc(!context.status.template condition<Condition::Overflow>()); return;
|
||||
case Operation::JB: jcc(context.status.template condition<Condition::Below>()); return;
|
||||
case Operation::JNB: jcc(!context.status.template condition<Condition::Below>()); return;
|
||||
case Operation::JZ: jcc(context.status.template condition<Condition::Zero>()); return;
|
||||
case Operation::JNZ: jcc(!context.status.template condition<Condition::Zero>()); return;
|
||||
case Operation::JBE: jcc(context.status.template condition<Condition::BelowOrEqual>()); return;
|
||||
case Operation::JNBE: jcc(!context.status.template condition<Condition::BelowOrEqual>()); return;
|
||||
case Operation::JS: jcc(context.status.template condition<Condition::Sign>()); return;
|
||||
case Operation::JNS: jcc(!context.status.template condition<Condition::Sign>()); return;
|
||||
case Operation::JP: jcc(!context.status.template condition<Condition::ParityOdd>()); return;
|
||||
case Operation::JNP: jcc(context.status.template condition<Condition::ParityOdd>()); return;
|
||||
case Operation::JL: jcc(context.status.template condition<Condition::Less>()); return;
|
||||
case Operation::JNL: jcc(!context.status.template condition<Condition::Less>()); return;
|
||||
case Operation::JLE: jcc(context.status.template condition<Condition::LessOrEqual>()); return;
|
||||
case Operation::JNLE: jcc(!context.status.template condition<Condition::LessOrEqual>()); return;
|
||||
case Operation::JO: jcc(context.flags.template condition<Condition::Overflow>()); return;
|
||||
case Operation::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); return;
|
||||
case Operation::JB: jcc(context.flags.template condition<Condition::Below>()); return;
|
||||
case Operation::JNB: jcc(!context.flags.template condition<Condition::Below>()); return;
|
||||
case Operation::JZ: jcc(context.flags.template condition<Condition::Zero>()); return;
|
||||
case Operation::JNZ: jcc(!context.flags.template condition<Condition::Zero>()); return;
|
||||
case Operation::JBE: jcc(context.flags.template condition<Condition::BelowOrEqual>()); return;
|
||||
case Operation::JNBE: jcc(!context.flags.template condition<Condition::BelowOrEqual>()); return;
|
||||
case Operation::JS: jcc(context.flags.template condition<Condition::Sign>()); return;
|
||||
case Operation::JNS: jcc(!context.flags.template condition<Condition::Sign>()); return;
|
||||
case Operation::JP: jcc(!context.flags.template condition<Condition::ParityOdd>()); return;
|
||||
case Operation::JNP: jcc(context.flags.template condition<Condition::ParityOdd>()); return;
|
||||
case Operation::JL: jcc(context.flags.template condition<Condition::Less>()); return;
|
||||
case Operation::JNL: jcc(!context.flags.template condition<Condition::Less>()); return;
|
||||
case Operation::JLE: jcc(context.flags.template condition<Condition::LessOrEqual>()); return;
|
||||
case Operation::JNLE: jcc(!context.flags.template condition<Condition::LessOrEqual>()); return;
|
||||
|
||||
case Operation::RCL: Primitive::rcl(destination_rmw(), shift_count(), context); break;
|
||||
case Operation::RCR: Primitive::rcr(destination_rmw(), shift_count(), context); break;
|
||||
@ -1923,9 +1923,9 @@ template <
|
||||
const uint16_t ip = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(address);
|
||||
const uint16_t cs = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(address + 2);
|
||||
|
||||
auto flags = context.status.get();
|
||||
auto flags = context.flags.get();
|
||||
Primitive::push<uint16_t, true>(flags, context);
|
||||
context.status.template set_from<Flag::Interrupt, Flag::Trap>(0);
|
||||
context.flags.template set_from<Flag::Interrupt, Flag::Trap>(0);
|
||||
|
||||
// Push CS and IP.
|
||||
Primitive::push<uint16_t, true>(context.registers.cs(), context);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "Instruction.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "Status.hpp"
|
||||
#include "Flags.hpp"
|
||||
|
||||
namespace InstructionSet::x86 {
|
||||
|
||||
@ -44,7 +44,7 @@ template <
|
||||
typename IOT
|
||||
> struct ExecutionContext {
|
||||
FlowControllerT flow_controller;
|
||||
Status status;
|
||||
Flags flags;
|
||||
RegistersT registers;
|
||||
MemoryT memory;
|
||||
IOT io;
|
||||
|
@ -1125,7 +1125,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
423BDC492AB24699008E37B6 /* 8088Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 8088Tests.mm; sourceTree = "<group>"; };
|
||||
42437B342ACF02A9006DFED1 /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = "<group>"; };
|
||||
42437B342ACF02A9006DFED1 /* Flags.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Flags.hpp; sourceTree = "<group>"; };
|
||||
42437B352ACF0AA2006DFED1 /* Perform.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Perform.hpp; sourceTree = "<group>"; };
|
||||
42437B382ACF2798006DFED1 /* PerformImplementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PerformImplementation.hpp; sourceTree = "<group>"; };
|
||||
42437B392AD07465006DFED1 /* Interrupts.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Interrupts.hpp; sourceTree = "<group>"; };
|
||||
@ -4999,11 +4999,11 @@
|
||||
4B69DEB52AB79E4F0055B217 /* Instruction.cpp */,
|
||||
4BEDA3B825B25563000C2DBD /* Decoder.hpp */,
|
||||
4BEDA3DB25B2588F000C2DBD /* Instruction.hpp */,
|
||||
42437B392AD07465006DFED1 /* Interrupts.hpp */,
|
||||
4BE3C69527CBC540000EAD28 /* Model.hpp */,
|
||||
42437B352ACF0AA2006DFED1 /* Perform.hpp */,
|
||||
42437B342ACF02A9006DFED1 /* Status.hpp */,
|
||||
42437B342ACF02A9006DFED1 /* Flags.hpp */,
|
||||
42437B372ACF2798006DFED1 /* Implementation */,
|
||||
42437B392AD07465006DFED1 /* Interrupts.hpp */,
|
||||
);
|
||||
path = x86;
|
||||
sourceTree = "<group>";
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "../../../InstructionSets/x86/Decoder.hpp"
|
||||
#include "../../../InstructionSets/x86/Perform.hpp"
|
||||
#include "../../../InstructionSets/x86/Flags.hpp"
|
||||
#include "../../../Numeric/RegisterSizes.hpp"
|
||||
|
||||
namespace {
|
||||
@ -29,7 +30,7 @@ namespace {
|
||||
// provide their real path here.
|
||||
constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1";
|
||||
|
||||
using Status = InstructionSet::x86::Status;
|
||||
using Flags = InstructionSet::x86::Flags;
|
||||
struct Registers {
|
||||
CPU::RegisterPair16 ax_;
|
||||
uint8_t &al() { return ax_.halves.low; }
|
||||
@ -287,8 +288,8 @@ struct IO {
|
||||
};
|
||||
class FlowController {
|
||||
public:
|
||||
FlowController(Memory &memory, Registers ®isters, Status &status) :
|
||||
memory_(memory), registers_(registers), status_(status) {}
|
||||
FlowController(Memory &memory, Registers ®isters, Flags &flags) :
|
||||
memory_(memory), registers_(registers), flags_(flags) {}
|
||||
|
||||
// Requirements for perform.
|
||||
void jump(uint16_t address) {
|
||||
@ -318,19 +319,19 @@ class FlowController {
|
||||
private:
|
||||
Memory &memory_;
|
||||
Registers ®isters_;
|
||||
Status &status_;
|
||||
Flags &flags_;
|
||||
bool should_repeat_ = false;
|
||||
};
|
||||
|
||||
struct ExecutionSupport {
|
||||
InstructionSet::x86::Status status;
|
||||
Flags flags;
|
||||
Registers registers;
|
||||
Memory memory;
|
||||
FlowController flow_controller;
|
||||
IO io;
|
||||
static constexpr auto model = InstructionSet::x86::Model::i8086;
|
||||
|
||||
ExecutionSupport(): memory(registers), flow_controller(memory, registers, status) {}
|
||||
ExecutionSupport(): memory(registers), flow_controller(memory, registers, flags) {}
|
||||
|
||||
void clear() {
|
||||
memory.clear();
|
||||
@ -494,7 +495,7 @@ struct FailedExecution {
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
- (void)populate:(Registers &)registers status:(InstructionSet::x86::Status &)status value:(NSDictionary *)value {
|
||||
- (void)populate:(Registers &)registers flags:(Flags &)flags value:(NSDictionary *)value {
|
||||
registers.ax_.full = [value[@"ax"] intValue];
|
||||
registers.bx_.full = [value[@"bx"] intValue];
|
||||
registers.cx_.full = [value[@"cx"] intValue];
|
||||
@ -510,25 +511,25 @@ struct FailedExecution {
|
||||
registers.ss_ = [value[@"ss"] intValue];
|
||||
registers.ip_ = [value[@"ip"] intValue];
|
||||
|
||||
const uint16_t flags = [value[@"flags"] intValue];
|
||||
status.set(flags);
|
||||
const uint16_t flags_value = [value[@"flags"] intValue];
|
||||
flags.set(flags_value);
|
||||
|
||||
// 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
|
||||
InstructionSet::x86::FlagValue::Carry |
|
||||
InstructionSet::x86::FlagValue::Parity |
|
||||
InstructionSet::x86::FlagValue::AuxiliaryCarry |
|
||||
InstructionSet::x86::FlagValue::Zero |
|
||||
InstructionSet::x86::FlagValue::Sign |
|
||||
InstructionSet::x86::FlagValue::Trap |
|
||||
InstructionSet::x86::FlagValue::Interrupt |
|
||||
InstructionSet::x86::FlagValue::Direction |
|
||||
InstructionSet::x86::FlagValue::Overflow
|
||||
);
|
||||
XCTAssert((status.get() & defined_flags) == (flags & defined_flags),
|
||||
"Set status of %04x was returned as %04x",
|
||||
flags & defined_flags,
|
||||
(status.get() & defined_flags)
|
||||
XCTAssert((flags.get() & defined_flags) == (flags_value & defined_flags),
|
||||
"Set flags of %04x was returned as %04x",
|
||||
flags_value & defined_flags,
|
||||
(flags.get() & defined_flags)
|
||||
);
|
||||
}
|
||||
|
||||
@ -544,7 +545,7 @@ struct FailedExecution {
|
||||
NSDictionary *const final_state = test[@"final"];
|
||||
|
||||
// Apply initial state.
|
||||
InstructionSet::x86::Status initial_status;
|
||||
Flags initial_flags;
|
||||
for(NSArray<NSNumber *> *ram in initial_state[@"ram"]) {
|
||||
execution_support.memory.seed([ram[0] intValue], [ram[1] intValue]);
|
||||
}
|
||||
@ -552,8 +553,8 @@ struct FailedExecution {
|
||||
execution_support.memory.touch([ram[0] intValue]);
|
||||
}
|
||||
Registers initial_registers;
|
||||
[self populate:initial_registers status:initial_status value:initial_state[@"regs"]];
|
||||
execution_support.status = initial_status;
|
||||
[self populate:initial_registers flags:initial_flags value:initial_state[@"regs"]];
|
||||
execution_support.flags = initial_flags;
|
||||
execution_support.registers = initial_registers;
|
||||
|
||||
// Execute instruction.
|
||||
@ -571,7 +572,7 @@ struct FailedExecution {
|
||||
|
||||
// Compare final state.
|
||||
Registers intended_registers;
|
||||
InstructionSet::x86::Status intended_status;
|
||||
InstructionSet::x86::Flags intended_flags;
|
||||
|
||||
bool ramEqual = true;
|
||||
int mask_position = 0;
|
||||
@ -602,21 +603,21 @@ struct FailedExecution {
|
||||
break;
|
||||
}
|
||||
|
||||
[self populate:intended_registers status:intended_status value:final_state[@"regs"]];
|
||||
[self populate:intended_registers flags:intended_flags value:final_state[@"regs"]];
|
||||
const bool registersEqual = intended_registers == execution_support.registers;
|
||||
const bool statusEqual = (intended_status.get() & flags_mask) == (execution_support.status.get() & flags_mask);
|
||||
const bool flagsEqual = (intended_flags.get() & flags_mask) == (execution_support.flags.get() & flags_mask);
|
||||
|
||||
if(!statusEqual || !registersEqual || !ramEqual) {
|
||||
if(!flagsEqual || !registersEqual || !ramEqual) {
|
||||
FailedExecution failure;
|
||||
failure.instruction = decoded.second;
|
||||
failure.test_name = std::string([test[@"name"] UTF8String]);
|
||||
|
||||
NSMutableArray<NSString *> *reasons = [[NSMutableArray alloc] init];
|
||||
if(!statusEqual) {
|
||||
Status difference;
|
||||
difference.set((intended_status.get() ^ execution_support.status.get()) & flags_mask);
|
||||
if(!flagsEqual) {
|
||||
Flags difference;
|
||||
difference.set((intended_flags.get() ^ execution_support.flags.get()) & flags_mask);
|
||||
[reasons addObject:
|
||||
[NSString stringWithFormat:@"status differs; errors in %s",
|
||||
[NSString stringWithFormat:@"flags differs; errors in %s",
|
||||
difference.to_string().c_str()]];
|
||||
}
|
||||
if(!registersEqual) {
|
||||
|
Loading…
Reference in New Issue
Block a user