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:
parent
def69ce6d5
commit
16e827bb2c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user