mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-22 11:29:20 +00:00
Start dealing with per-instruction fields.
This commit is contained in:
parent
d639dc8bcb
commit
57b45076c5
@ -16,38 +16,47 @@
|
||||
namespace InstructionSet::ARM {
|
||||
|
||||
template <Model model>
|
||||
using OperationTable = std::array<Operation, 128>;
|
||||
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 << 21);
|
||||
const auto opcode = static_cast<uint32_t>(c << 20);
|
||||
|
||||
// Cf. the ARM2 datasheet, p45. Tests below match its ordering
|
||||
// other than that 'undefined' is the fallthrough case.
|
||||
// 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) {
|
||||
result[c] = Operation((c >> 21) & 0xf);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Multiply and multiply-accumulate (MUL, MLA); cf. p.23.
|
||||
if(((opcode >> 22) & 0b111'111) == 0b000'000) {
|
||||
result[c] =
|
||||
((opcode >> 21) & 1) ? Operation::MLA : Operation::MUL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single data transfer (LDR, STR); cf. p.25.
|
||||
if(((opcode >> 26) & 0b11) == 0b01) {
|
||||
result[c] = Operation::SingleDataTransfer;
|
||||
result[c] =
|
||||
((opcode >> 20) & 1) ? Operation::LDR : Operation::STR;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Block data transfer (LDM, STM); cf. p.29.
|
||||
if(((opcode >> 25) & 0b111) == 0b100) {
|
||||
result[c] = Operation::BlockDataTransfer;
|
||||
result[c] =
|
||||
((opcode >> 20) & 1) ? Operation::LDM : Operation::STM;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Branch and branch with link (B, BL); cf. p.15.
|
||||
if(((opcode >> 25) & 0b111) == 0b101) {
|
||||
result[c] =
|
||||
((opcode >> 24) & 1) ? Operation::BL : Operation::B;
|
||||
@ -77,7 +86,19 @@ constexpr OperationTable<model> operation_table() {
|
||||
template <Model model>
|
||||
constexpr Operation operation(uint32_t opcode) {
|
||||
constexpr OperationTable<model> operations = operation_table<model>();
|
||||
return operations[(opcode >> 21) & 0x7f];
|
||||
|
||||
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.
|
||||
if(
|
||||
(op == Operation::MUL || op == Operation::MLA)
|
||||
&& ((opcode >> 4) & 0b1111) != 0b1001
|
||||
) {
|
||||
return Operation::Undefined;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,13 @@
|
||||
|
||||
namespace InstructionSet::ARM {
|
||||
|
||||
enum class ShiftType {
|
||||
LogicalLeft = 0b00,
|
||||
LogicalRight = 0b01,
|
||||
ArithmeticRight = 0b10,
|
||||
RotateRight = 0b11,
|
||||
};
|
||||
|
||||
template <Model model>
|
||||
class Instruction {
|
||||
public:
|
||||
@ -24,8 +31,61 @@ class Instruction {
|
||||
return InstructionSet::ARM::operation<model>(opcode_);
|
||||
}
|
||||
|
||||
//
|
||||
// B and BL.
|
||||
//
|
||||
|
||||
/// Provides a 26-bit offset to add to the program counter for B and BL.
|
||||
uint32_t b_offset() const { return (opcode_ & 0xff'ffff) << 2; }
|
||||
|
||||
//
|
||||
// Data processing (i.e. AND to MVN).
|
||||
//
|
||||
|
||||
/// @returns @c true if this operation should set condition codes; @c false otherwise.
|
||||
/// @note Valid for data processing and multiply/multiply-accumulate.
|
||||
bool set_condition_codes() const { return opcode_ & (1 << 20); }
|
||||
// TODO: could build this into the Operation?
|
||||
|
||||
/// 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_;
|
||||
};
|
||||
|
||||
// TODO: do MUL and MLA really transpose Rd and Rn as per the data sheet?
|
||||
// ARM: Assembly Language Programming by Cockerell thinks not.
|
||||
|
||||
}
|
||||
|
@ -11,16 +11,44 @@
|
||||
namespace InstructionSet::ARM {
|
||||
|
||||
enum class Operation {
|
||||
AND, EOR, SUB, RSB,
|
||||
ADD, ADC, SBC, RSC,
|
||||
TST, TEQ, CMP, CMN,
|
||||
ORR, MOV, BIC, MVN,
|
||||
/// Rd = Op1 AND Op2.
|
||||
AND,
|
||||
/// Rd = Op1 EOR Op2.
|
||||
EOR,
|
||||
/// Rd = Op1 - Op2.
|
||||
SUB,
|
||||
/// Rd = Op2 - Op1.
|
||||
RSB,
|
||||
/// Rd = Op1 + Op2.
|
||||
ADD,
|
||||
/// Rd = Op1 + Ord2 + C.
|
||||
ADC,
|
||||
/// Rd = Op1 - Op2 + C.
|
||||
SBC,
|
||||
/// Rd = Op2 - Op1 + C.
|
||||
RSC,
|
||||
/// Set condition codes on Op1 AND Op2.
|
||||
TST,
|
||||
/// Set condition codes on Op1 EOR Op2.
|
||||
TEQ,
|
||||
/// Set condition codes on Op1 - Op2.
|
||||
CMP,
|
||||
/// Set condition codes on Op1 + Op2.
|
||||
CMN,
|
||||
/// Rd = Op1 OR Op2.
|
||||
ORR,
|
||||
/// Rd = Op2
|
||||
MOV,
|
||||
/// Rd = Op1 AND NOT Op2.
|
||||
BIC,
|
||||
/// Rd = NOT Op2.
|
||||
MVN,
|
||||
|
||||
B, BL,
|
||||
MUL, MLA,
|
||||
|
||||
SingleDataTransfer, // TODO: LDR or STR?
|
||||
BlockDataTransfer, // TODO: LDM or STM?
|
||||
LDR, STR,
|
||||
LDM, STM,
|
||||
SoftwareInterrupt,
|
||||
|
||||
CoprocessorDataOperationOrRegisterTransfer,
|
||||
|
Loading…
x
Reference in New Issue
Block a user