mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-19 07:31:15 +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 &;
|
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
|
||||||
|
@ -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 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 {
|
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 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_); }
|
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_); }
|
||||||
|
@ -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());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user