From 16e827bb2ceb6ee96b61261c6f583d3fe4121564 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 26 Feb 2024 21:27:58 -0500 Subject: [PATCH] Add basic arithmetics. --- InstructionSets/ARM/OperationMapper.hpp | 12 ++++ InstructionSets/ARM/Status.hpp | 7 +++ .../Mac/Clock SignalTests/ARMDecoderTests.mm | 57 ++++++++++++++++++- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index 85fbfae2d..a3adbc0e2 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -51,6 +51,18 @@ constexpr bool is_logical(DataProcessingOperation operation) { } } +constexpr bool is_comparison(DataProcessingOperation operation) { + switch(operation) { + case DataProcessingOperation::TST: + case DataProcessingOperation::TEQ: + case DataProcessingOperation::CMP: + case DataProcessingOperation::CMN: + return true; + + default: return false; + } +} + enum class Operation { MUL, /// Rd = Rm * Rs MLA, /// Rd = Rm * Rs + Rn diff --git a/InstructionSets/ARM/Status.hpp b/InstructionSets/ARM/Status.hpp index 3cf3cba60..de320232d 100644 --- a/InstructionSets/ARM/Status.hpp +++ b/InstructionSets/ARM/Status.hpp @@ -10,6 +10,8 @@ #include "OperationMapper.hpp" +#include + namespace InstructionSet::ARM { namespace ConditionCode { @@ -45,6 +47,11 @@ struct Status { carry_flag_ = value; } + /// @returns @c 1 if carry is set; @c 0 otherwise. + uint32_t c() const { + return carry_flag_ ? 1 : 0; + } + /// Sets V if the highest bit of @c value is set; resets it otherwise. void set_v(uint32_t value) { overflow_flag_ = value; diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index d5bf8dc34..088fe37be 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -10,6 +10,7 @@ #include "../../../InstructionSets/ARM/OperationMapper.hpp" #include "../../../InstructionSets/ARM/Status.hpp" +#include "../../../Numeric/Carry.hpp" using namespace InstructionSet::ARM; @@ -64,7 +65,7 @@ struct Scheduler { constexpr DataProcessingFlags flags(f); auto &destination = registers_[fields.destination()]; - const auto &operand1 = registers_[fields.operand1()]; + const uint32_t operand1 = registers_[fields.operand1()]; uint32_t operand2; uint32_t rotate_carry = 0; @@ -104,7 +105,59 @@ struct Scheduler { case DataProcessingOperation::TST: conditions = operand1 & operand2; break; case DataProcessingOperation::TEQ: conditions = operand1 ^ operand2; break; - default: break; // ETC. + case DataProcessingOperation::ADD: + case DataProcessingOperation::ADC: + case DataProcessingOperation::CMN: + conditions = operand1 + operand2; + + if constexpr (flags.operation() == DataProcessingOperation::ADC) { + conditions += status.c(); + } + + if constexpr (flags.set_condition_codes()) { + status.set_c(Numeric::carried_out(operand1, operand2, conditions)); + status.set_v(Numeric::overflow(operand1, operand2, conditions)); + } + + if constexpr (!is_comparison(flags.operation())) { + destination = conditions; + } + break; + + case DataProcessingOperation::SUB: + case DataProcessingOperation::SBC: + case DataProcessingOperation::CMP: + conditions = operand1 - operand2; + + if constexpr (flags.operation() == DataProcessingOperation::SBC) { + conditions -= status.c(); + } + + if constexpr (flags.set_condition_codes()) { + status.set_c(Numeric::carried_out(operand1, operand2, conditions)); + status.set_v(Numeric::overflow(operand1, operand2, conditions)); + } + + if constexpr (!is_comparison(flags.operation())) { + destination = conditions; + } + break; + + case DataProcessingOperation::RSB: + case DataProcessingOperation::RSC: + conditions = operand2 - operand1; + + if constexpr (flags.operation() == DataProcessingOperation::RSC) { + conditions -= status.c(); + } + + if constexpr (flags.set_condition_codes()) { + status.set_c(Numeric::carried_out(operand2, operand1, conditions)); + status.set_v(Numeric::overflow(operand2, operand1, conditions)); + } + + destination = conditions; + break; } // Set N and Z in a unified way.