1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-29 00:29:34 +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 &; using type = uint32_t &;
}; };
template <> struct Carry<false> { 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 /// 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, 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 { enum class Condition {
EQ, NE, CS, CC, EQ, NE, CS, CC,
MI, PL, VS, VC, MI, PL, VS, VC,
@ -140,9 +63,14 @@ protected:
struct BranchFlags { struct BranchFlags {
constexpr BranchFlags(uint8_t flags) noexcept : flags_(flags) {} 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. /// @returns The operation to apply.
constexpr BranchOperation operation() const { constexpr Operation operation() const {
return flag_bit<24>(flags_) ? BranchOperation::BL : BranchOperation::B; return flag_bit<24>(flags_) ? Operation::BL : Operation::B;
} }
private: private:
@ -162,6 +90,53 @@ private:
// //
// Data processing (i.e. AND to MVN). // 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 { struct DataProcessingFlags {
constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {} 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. /// @c true if the status register should be updated; @c false otherwise.
constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); } 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. /// @returns The operation to apply.
constexpr MultiplyOperation operation() const { constexpr Operation operation() const {
return flag_bit<21>(flags_) ? MultiplyOperation::MLA : MultiplyOperation::MUL; return flag_bit<21>(flags_) ? Operation::MLA : Operation::MUL;
} }
private: private:
@ -243,8 +223,13 @@ private:
struct SingleDataTransferFlags { struct SingleDataTransferFlags {
constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr SingleDataTransferOperation operation() const { enum class Operation {
return flag_bit<20>(flags_) ? SingleDataTransferOperation::LDR : SingleDataTransferOperation::STR; 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_); } constexpr bool offset_is_immediate() const { return flag_bit<25>(flags_); }
@ -279,8 +264,13 @@ struct SingleDataTransfer: public WithShiftControlBits {
struct BlockDataTransferFlags { struct BlockDataTransferFlags {
constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr BlockDataTransferOperation operation() const { enum class Operation {
return flag_bit<20>(flags_) ? BlockDataTransferOperation::LDM : BlockDataTransferOperation::STM; 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_); } constexpr bool pre_index() const { return flag_bit<24>(flags_); }
@ -333,8 +323,13 @@ private:
struct CoprocessorRegisterTransferFlags { struct CoprocessorRegisterTransferFlags {
constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr CoprocessorRegisterTransferOperation operation() const { enum class Operation {
return flag_bit<20>(flags_) ? CoprocessorRegisterTransferOperation::MRC : CoprocessorRegisterTransferOperation::MCR; 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; } constexpr int coprocessor_operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0x7; }
@ -361,8 +356,13 @@ private:
struct CoprocessorDataTransferFlags { struct CoprocessorDataTransferFlags {
constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr CoprocessorDataTransferOperation operation() const { enum class Operation {
return flag_bit<20>(flags_) ? CoprocessorDataTransferOperation::LDC : CoprocessorDataTransferOperation::STC; 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 pre_index() const { return flag_bit<24>(flags_); }
constexpr bool add_offset() const { return flag_bit<23>(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 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 multiplier = fields.multiplier() == 15 ? registers_.pc_status(8) : registers_.active[fields.multiplier()];
const uint32_t accumulator = 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()]); (fields.multiplicand() == 15 ? registers_.pc_status(12) : registers_.active[fields.accumulator()]);
const uint32_t result = multiplicand * multiplier + accumulator; const uint32_t result = multiplicand * multiplier + accumulator;
@ -217,7 +217,7 @@ struct Scheduler {
template <Flags f> void perform(Branch branch) { template <Flags f> void perform(Branch branch) {
constexpr BranchFlags flags(f); constexpr BranchFlags flags(f);
if constexpr (flags.operation() == BranchOperation::BL) { if constexpr (flags.operation() == BranchFlags::Operation::BL) {
registers_.active[14] = registers_.pc(4); registers_.active[14] = registers_.pc(4);
} }
registers_.set_pc(registers_.pc(8) + branch.offset()); registers_.set_pc(registers_.pc(8) + branch.offset());