mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Localise flags, detect improper carry write.
This commit is contained in:
parent
904462b881
commit
93b4008f81
@ -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
|
||||
|
@ -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 1–16 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 1–16 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_); }
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user