mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-18 01:30:56 +00:00
Delete was is now duplicated.
This commit is contained in:
parent
0fe2c1406b
commit
2bbaf73aa2
@ -123,6 +123,11 @@ struct OperationMapper {
|
|||||||
template <int i, typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
template <int i, typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
||||||
constexpr auto partial = static_cast<uint32_t>(i << 20);
|
constexpr auto partial = static_cast<uint32_t>(i << 20);
|
||||||
|
|
||||||
|
// Cf. the ARM2 datasheet, p.45. Tests below match its ordering
|
||||||
|
// other than that 'undefined' is the fallthrough case. More specific
|
||||||
|
// page references are provided were more detailed versions of the
|
||||||
|
// decoding are depicted.
|
||||||
|
|
||||||
// Data processing; cf. p.17.
|
// Data processing; cf. p.17.
|
||||||
if constexpr (((partial >> 26) & 0b11) == 0b00) {
|
if constexpr (((partial >> 26) & 0b11) == 0b00) {
|
||||||
constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf));
|
constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf));
|
||||||
@ -150,47 +155,15 @@ struct OperationMapper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Decodes @c instruction, making an appropriate call into @c scheduler.
|
||||||
template <typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
template <typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
||||||
OperationMapper mapper;
|
OperationMapper mapper;
|
||||||
Reflection::dispatch(mapper, (instruction >> 20) & 0xff, instruction, scheduler);
|
Reflection::dispatch(mapper, (instruction >> 20) & 0xff, instruction, scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
template <Model model>
|
|
||||||
using OperationTable = std::array<Operation, 256>;
|
|
||||||
|
|
||||||
template <Model model>
|
|
||||||
constexpr OperationTable<model> operation_table() {
|
|
||||||
OperationTable<model> result{};
|
|
||||||
for(std::size_t c = 0; c < result.size(); c++) {
|
|
||||||
const auto opcode = static_cast<uint32_t>(c << 20);
|
|
||||||
|
|
||||||
// Cf. the ARM2 datasheet, p.45. Tests below match its ordering
|
|
||||||
// other than that 'undefined' is the fallthrough case. More specific
|
|
||||||
// page references are provided were more detailed versions of the
|
|
||||||
// decoding are depicted.
|
|
||||||
|
|
||||||
// Data processing; cf. p.17.
|
|
||||||
if(((opcode >> 26) & 0b11) == 0b00) {
|
|
||||||
const auto operation = (c >> 21) & 0xf;
|
|
||||||
if((opcode >> 20) & 1) {
|
|
||||||
result[c] = Operation(int(Operation::ANDS) + operation);
|
|
||||||
} else {
|
|
||||||
result[c] = Operation(int(Operation::AND) + operation);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiply and multiply-accumulate (MUL, MLA); cf. p.23.
|
|
||||||
if(((opcode >> 22) & 0b111'111) == 0b000'000) {
|
|
||||||
switch((opcode >> 20) & 3) {
|
|
||||||
case 0: result[c] = Operation::MUL; break;
|
|
||||||
case 1: result[c] = Operation::MULS; break;
|
|
||||||
case 2: result[c] = Operation::MLA; break;
|
|
||||||
case 3: result[c] = Operation::MLAS; break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single data transfer (LDR, STR); cf. p.25.
|
// Single data transfer (LDR, STR); cf. p.25.
|
||||||
if(((opcode >> 26) & 0b11) == 0b01) {
|
if(((opcode >> 26) & 0b11) == 0b01) {
|
||||||
@ -229,30 +202,6 @@ constexpr OperationTable<model> operation_table() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result[c] = Operation::Undefined;
|
result[c] = Operation::Undefined;
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <Model model>
|
|
||||||
constexpr Operation operation(uint32_t opcode) {
|
|
||||||
constexpr OperationTable<model> operations = operation_table<model>();
|
|
||||||
|
|
||||||
const auto op = operations[(opcode >> 21) & 0x7f];
|
|
||||||
|
|
||||||
// MUL and MLA have an extra constraint that doesn't fit the neat
|
|
||||||
// 256-entry table format as above.
|
|
||||||
//
|
|
||||||
// Hope: most instructions aren't MUL/MLA so relying on the branch predictor
|
|
||||||
// here is fine.
|
|
||||||
if(
|
|
||||||
is_multiply(op)
|
|
||||||
&& ((opcode >> 4) & 0b1111) != 0b1001
|
|
||||||
) {
|
|
||||||
return Operation::Undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return op;
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -14,104 +14,7 @@
|
|||||||
|
|
||||||
namespace InstructionSet::ARM {
|
namespace InstructionSet::ARM {
|
||||||
|
|
||||||
/*enum class ShiftType {
|
/*
|
||||||
LogicalLeft = 0b00,
|
|
||||||
LogicalRight = 0b01,
|
|
||||||
ArithmeticRight = 0b10,
|
|
||||||
RotateRight = 0b11,
|
|
||||||
};
|
|
||||||
|
|
||||||
template <Model model>
|
|
||||||
class Instruction {
|
|
||||||
public:
|
|
||||||
constexpr Instruction(uint32_t opcode) noexcept : opcode_(opcode) {}
|
|
||||||
|
|
||||||
constexpr Condition condition() const { return Condition(opcode_ >> 28); }
|
|
||||||
constexpr Operation operation() const {
|
|
||||||
return InstructionSet::ARM::operation<model>(opcode_);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// B and BL.
|
|
||||||
//
|
|
||||||
struct Branch {
|
|
||||||
constexpr Branch(uint32_t opcode) noexcept : opcode_(opcode) {}
|
|
||||||
|
|
||||||
/// Provides a 26-bit offset to add to the program counter for B and BL.
|
|
||||||
uint32_t offset() const { return (opcode_ & 0xff'ffff) << 2; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t opcode_;
|
|
||||||
};
|
|
||||||
Branch branch() const { return Branch(opcode_); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Data processing (i.e. AND to MVN).
|
|
||||||
//
|
|
||||||
struct DataProcessing {
|
|
||||||
constexpr DataProcessing(uint32_t opcode) noexcept : opcode_(opcode) {}
|
|
||||||
|
|
||||||
/// The destination register index.
|
|
||||||
int destination() const { return (opcode_ >> 12) & 0xf; }
|
|
||||||
|
|
||||||
/// The operand 1 register index.
|
|
||||||
int operand1() const { return (opcode_ >> 16) & 0xf; }
|
|
||||||
|
|
||||||
/// @returns @c true if operand 2 is defined by the @c rotate() and @c immediate() fields;
|
|
||||||
/// @c false if it is defined by the @c shift_*() and @c operand2() fields.
|
|
||||||
bool operand2_is_immediate() const { return opcode_ & (1 << 25); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Register values for operand 2.
|
|
||||||
//
|
|
||||||
|
|
||||||
/// The operand 2 register index if @c operand2_is_immediate() is @c false; meaningless otherwise.
|
|
||||||
int operand2() const { return opcode_ & 0xf; }
|
|
||||||
/// The type of shift to apply to operand 2 if @c operand2_is_immediate() is @c false; meaningless otherwise.
|
|
||||||
ShiftType shift_type() const { return ShiftType((opcode_ >> 5) & 3); }
|
|
||||||
/// @returns @c true if the amount to shift by should be taken from a register; @c false if it is an immediate value.
|
|
||||||
bool shift_count_is_register() const { return opcode_ & (1 << 4); }
|
|
||||||
/// The shift amount register index if @c shift_count_is_register() is @c true; meaningless otherwise.
|
|
||||||
int shift_register() const { return (opcode_ >> 8) & 0xf; }
|
|
||||||
/// The amount to shift by if @c shift_count_is_register() is @c false; meaningless otherwise.
|
|
||||||
int shift_amount() const { return (opcode_ >> 7) & 0x1f; }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Immediate values for operand 2.
|
|
||||||
//
|
|
||||||
|
|
||||||
/// An 8-bit value to rotate right @c rotate() places if @c operand2_is_immediate() is @c true; meaningless otherwise.
|
|
||||||
int immediate() const { return opcode_ & 0xff; }
|
|
||||||
/// The number of bits to rotate @c immediate() by if @c operand2_is_immediate() is @c true; meaningless otherwise.
|
|
||||||
int rotate() const { return (opcode_ >> 7) & 0x1e; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t opcode_;
|
|
||||||
};
|
|
||||||
DataProcessing data_processing() const { return DataProcessing(opcode_); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// MUL and MLA.
|
|
||||||
//
|
|
||||||
struct Multiply {
|
|
||||||
constexpr Multiply(uint32_t opcode) noexcept : opcode_(opcode) {}
|
|
||||||
|
|
||||||
/// The destination register index. i.e. 'Rd'.
|
|
||||||
int destination() const { return (opcode_ >> 16) & 0xf; }
|
|
||||||
|
|
||||||
/// The accumulator register index for multiply-add. i.e. 'Rn'.
|
|
||||||
int accumulator() const { return (opcode_ >> 12) & 0xf; }
|
|
||||||
|
|
||||||
/// The multiplicand register index. i.e. 'Rs'.
|
|
||||||
int multiplicand() const { return (opcode_ >> 8) & 0xf; }
|
|
||||||
|
|
||||||
/// The multiplier register index. i.e. 'Rm'.
|
|
||||||
int multiplier() const { return opcode_ & 0xf; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t opcode_;
|
|
||||||
};
|
|
||||||
Multiply multiply() const { return Multiply(opcode_); }
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// LDR and STR.
|
// LDR and STR.
|
||||||
@ -132,17 +35,6 @@ class Instruction {
|
|||||||
int offset() const { return opcode_ & 0xfff; }
|
int offset() const { return opcode_ & 0xfff; }
|
||||||
|
|
||||||
// TODO: P, U, B, W, L, I.
|
// TODO: P, U, B, W, L, I.
|
||||||
|
*/
|
||||||
private:
|
|
||||||
uint32_t opcode_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t opcode_;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
// TODO: do MUL and MLA really transpose Rd and Rn as per the data sheet?
|
|
||||||
// ARM: Assembly Language Programming by Cockerell thinks not.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user