1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-07 05:30:30 +00:00

Add basic arithmetics.

This commit is contained in:
Thomas Harte 2024-02-26 21:27:58 -05:00
parent def69ce6d5
commit 16e827bb2c
3 changed files with 74 additions and 2 deletions

View File

@ -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

View File

@ -10,6 +10,8 @@
#include "OperationMapper.hpp"
#include <cstdint>
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;

View File

@ -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<true, 31>(operand1, operand2, conditions));
status.set_v(Numeric::overflow<true>(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<false, 31>(operand1, operand2, conditions));
status.set_v(Numeric::overflow<false>(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<false, 31>(operand2, operand1, conditions));
status.set_v(Numeric::overflow<false>(operand2, operand1, conditions));
}
destination = conditions;
break;
}
// Set N and Z in a unified way.