1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 03:29:45 +00:00

Localise flags, detect improper carry write.

This commit is contained in:
Thomas Harte 2024-02-28 21:28:19 -05:00
parent 904462b881
commit 93b4008f81
3 changed files with 92 additions and 92 deletions

View File

@ -22,7 +22,7 @@ template <> struct Carry<true> {
using type = uint32_t &;
};
template <> struct Carry<false> {
using type = uint32_t;
using type = const uint32_t;
};
/// Apply a rotation of @c type to @c source of @c amount; @c carry should be either @c 1 or @c 0

View File

@ -17,83 +17,6 @@ enum class Model {
ARM2,
};
enum class DataProcessingOperation {
AND, /// Rd = Op1 AND Op2.
EOR, /// Rd = Op1 EOR Op2.
SUB, /// Rd = Op1 - Op2.
RSB, /// Rd = Op2 - Op1.
ADD, /// Rd = Op1 + Op2.
ADC, /// Rd = Op1 + Ord2 + C.
SBC, /// Rd = Op1 - Op2 + C.
RSC, /// Rd = Op2 - Op1 + C.
TST, /// Set condition codes on Op1 AND Op2.
TEQ, /// Set condition codes on Op1 EOR Op2.
CMP, /// Set condition codes on Op1 - Op2.
CMN, /// Set condition codes on Op1 + Op2.
ORR, /// Rd = Op1 OR Op2.
MOV, /// Rd = Op2
BIC, /// Rd = Op1 AND NOT Op2.
MVN, /// Rd = NOT Op2.
};
constexpr bool is_logical(DataProcessingOperation operation) {
switch(operation) {
case DataProcessingOperation::AND:
case DataProcessingOperation::EOR:
case DataProcessingOperation::TST:
case DataProcessingOperation::TEQ:
case DataProcessingOperation::ORR:
case DataProcessingOperation::MOV:
case DataProcessingOperation::BIC:
case DataProcessingOperation::MVN:
return true;
default: return false;
}
}
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 MultiplyOperation {
MUL, /// Rd = Rm * Rs
MLA, /// Rd = Rm * Rs + Rn
};
enum class BranchOperation {
B, /// Add offset to PC; programmer allows for PC being two words ahead.
BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction.
};
enum class SingleDataTransferOperation {
LDR, /// Read single byte or word from [base + offset], possibly mutating the base.
STR, /// Write a single byte or word to [base + offset], possibly mutating the base.
};
enum class BlockDataTransferOperation {
LDM, /// Read 116 words from [base], possibly mutating it.
STM, /// Write 1-16 words to [base], possibly mutating it.
};
enum class CoprocessorRegisterTransferOperation {
MRC, /// Move from coprocessor register to ARM register.
MCR, /// Move from ARM register to coprocessor register.
};
enum class CoprocessorDataTransferOperation {
LDC, /// Coprocessor data transfer load.
STC, /// Coprocessor data transfer store.
};
enum class Condition {
EQ, NE, CS, CC,
MI, PL, VS, VC,
@ -140,9 +63,14 @@ protected:
struct BranchFlags {
constexpr BranchFlags(uint8_t flags) noexcept : flags_(flags) {}
enum class Operation {
B, /// Add offset to PC; programmer allows for PC being two words ahead.
BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction.
};
/// @returns The operation to apply.
constexpr BranchOperation operation() const {
return flag_bit<24>(flags_) ? BranchOperation::BL : BranchOperation::B;
constexpr Operation operation() const {
return flag_bit<24>(flags_) ? Operation::BL : Operation::B;
}
private:
@ -162,6 +90,53 @@ private:
//
// Data processing (i.e. AND to MVN).
//
enum class DataProcessingOperation {
AND, /// Rd = Op1 AND Op2.
EOR, /// Rd = Op1 EOR Op2.
SUB, /// Rd = Op1 - Op2.
RSB, /// Rd = Op2 - Op1.
ADD, /// Rd = Op1 + Op2.
ADC, /// Rd = Op1 + Ord2 + C.
SBC, /// Rd = Op1 - Op2 + C.
RSC, /// Rd = Op2 - Op1 + C.
TST, /// Set condition codes on Op1 AND Op2.
TEQ, /// Set condition codes on Op1 EOR Op2.
CMP, /// Set condition codes on Op1 - Op2.
CMN, /// Set condition codes on Op1 + Op2.
ORR, /// Rd = Op1 OR Op2.
MOV, /// Rd = Op2
BIC, /// Rd = Op1 AND NOT Op2.
MVN, /// Rd = NOT Op2.
};
constexpr bool is_logical(DataProcessingOperation operation) {
switch(operation) {
case DataProcessingOperation::AND:
case DataProcessingOperation::EOR:
case DataProcessingOperation::TST:
case DataProcessingOperation::TEQ:
case DataProcessingOperation::ORR:
case DataProcessingOperation::MOV:
case DataProcessingOperation::BIC:
case DataProcessingOperation::MVN:
return true;
default: return false;
}
}
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;
}
}
struct DataProcessingFlags {
constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {}
@ -209,9 +184,14 @@ struct MultiplyFlags {
/// @c true if the status register should be updated; @c false otherwise.
constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); }
enum class Operation {
MUL, /// Rd = Rm * Rs
MLA, /// Rd = Rm * Rs + Rn
};
/// @returns The operation to apply.
constexpr MultiplyOperation operation() const {
return flag_bit<21>(flags_) ? MultiplyOperation::MLA : MultiplyOperation::MUL;
constexpr Operation operation() const {
return flag_bit<21>(flags_) ? Operation::MLA : Operation::MUL;
}
private:
@ -243,8 +223,13 @@ private:
struct SingleDataTransferFlags {
constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr SingleDataTransferOperation operation() const {
return flag_bit<20>(flags_) ? SingleDataTransferOperation::LDR : SingleDataTransferOperation::STR;
enum class Operation {
LDR, /// Read single byte or word from [base + offset], possibly mutating the base.
STR, /// Write a single byte or word to [base + offset], possibly mutating the base.
};
constexpr Operation operation() const {
return flag_bit<20>(flags_) ? Operation::LDR : Operation::STR;
}
constexpr bool offset_is_immediate() const { return flag_bit<25>(flags_); }
@ -279,8 +264,13 @@ struct SingleDataTransfer: public WithShiftControlBits {
struct BlockDataTransferFlags {
constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr BlockDataTransferOperation operation() const {
return flag_bit<20>(flags_) ? BlockDataTransferOperation::LDM : BlockDataTransferOperation::STM;
enum class Operation {
LDM, /// Read 116 words from [base], possibly mutating it.
STM, /// Write 1-16 words to [base], possibly mutating it.
};
constexpr Operation operation() const {
return flag_bit<20>(flags_) ? Operation::LDM : Operation::STM;
}
constexpr bool pre_index() const { return flag_bit<24>(flags_); }
@ -333,8 +323,13 @@ private:
struct CoprocessorRegisterTransferFlags {
constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr CoprocessorRegisterTransferOperation operation() const {
return flag_bit<20>(flags_) ? CoprocessorRegisterTransferOperation::MRC : CoprocessorRegisterTransferOperation::MCR;
enum class Operation {
MRC, /// Move from coprocessor register to ARM register.
MCR, /// Move from ARM register to coprocessor register.
};
constexpr Operation operation() const {
return flag_bit<20>(flags_) ? Operation::MRC : Operation::MCR;
}
constexpr int coprocessor_operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0x7; }
@ -361,8 +356,13 @@ private:
struct CoprocessorDataTransferFlags {
constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr CoprocessorDataTransferOperation operation() const {
return flag_bit<20>(flags_) ? CoprocessorDataTransferOperation::LDC : CoprocessorDataTransferOperation::STC;
enum class Operation {
LDC, /// Coprocessor data transfer load.
STC, /// Coprocessor data transfer store.
};
constexpr Operation operation() const {
return flag_bit<20>(flags_) ? Operation::LDC : Operation::STC;
}
constexpr bool pre_index() const { return flag_bit<24>(flags_); }
constexpr bool add_offset() const { return flag_bit<23>(flags_); }

View File

@ -199,7 +199,7 @@ struct Scheduler {
const uint32_t multiplicand = fields.multiplicand() == 15 ? registers_.pc(8) : registers_.active[fields.multiplicand()];
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(8) : registers_.active[fields.multiplier()];
const uint32_t accumulator =
flags.operation() == MultiplyOperation::MUL ? 0 :
flags.operation() == MultiplyFlags::Operation::MUL ? 0 :
(fields.multiplicand() == 15 ? registers_.pc_status(12) : registers_.active[fields.accumulator()]);
const uint32_t result = multiplicand * multiplier + accumulator;
@ -217,7 +217,7 @@ struct Scheduler {
template <Flags f> void perform(Branch branch) {
constexpr BranchFlags flags(f);
if constexpr (flags.operation() == BranchOperation::BL) {
if constexpr (flags.operation() == BranchFlags::Operation::BL) {
registers_.active[14] = registers_.pc(4);
}
registers_.set_pc(registers_.pc(8) + branch.offset());