mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Start poking at implementation.
This commit is contained in:
parent
cd21b39f44
commit
030dda34f0
@ -16,7 +16,7 @@ enum class Model {
|
|||||||
ARM2,
|
ARM2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Operation {
|
enum class DataProcessingOperation {
|
||||||
AND, /// Rd = Op1 AND Op2.
|
AND, /// Rd = Op1 AND Op2.
|
||||||
EOR, /// Rd = Op1 EOR Op2.
|
EOR, /// Rd = Op1 EOR Op2.
|
||||||
SUB, /// Rd = Op1 - Op2.
|
SUB, /// Rd = Op1 - Op2.
|
||||||
@ -33,7 +33,9 @@ enum class Operation {
|
|||||||
MOV, /// Rd = Op2
|
MOV, /// Rd = Op2
|
||||||
BIC, /// Rd = Op1 AND NOT Op2.
|
BIC, /// Rd = Op1 AND NOT Op2.
|
||||||
MVN, /// Rd = NOT Op2.
|
MVN, /// Rd = NOT Op2.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Operation {
|
||||||
MUL, /// Rd = Rm * Rs
|
MUL, /// Rd = Rm * Rs
|
||||||
MLA, /// Rd = Rm * Rs + Rn
|
MLA, /// Rd = Rm * Rs + Rn
|
||||||
B, /// Add offset to PC; programmer allows for PC being two words ahead.
|
B, /// Add offset to PC; programmer allows for PC being two words ahead.
|
||||||
@ -120,12 +122,17 @@ private:
|
|||||||
struct DataProcessingFlags {
|
struct DataProcessingFlags {
|
||||||
constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {}
|
constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||||
|
|
||||||
|
/// @returns The operation to apply.
|
||||||
|
constexpr DataProcessingOperation operation() const {
|
||||||
|
return DataProcessingOperation((flags_ >> 21) & 0xf);
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns @c true if operand 2 is defined by the @c rotate() and @c immediate() fields;
|
/// @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.
|
/// @c false if it is defined by the @c shift_*() and @c operand2() fields.
|
||||||
constexpr bool operand2_is_immediate() { return flag_bit<25>(flags_); }
|
constexpr bool operand2_is_immediate() const { return flag_bit<25>(flags_); }
|
||||||
|
|
||||||
/// @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() { return flag_bit<20>(flags_); }
|
constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t flags_;
|
uint8_t flags_;
|
||||||
@ -332,8 +339,7 @@ struct OperationMapper {
|
|||||||
|
|
||||||
// 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));
|
scheduler.template perform<i>(
|
||||||
scheduler.template perform<operation, i>(
|
|
||||||
condition,
|
condition,
|
||||||
DataProcessing(instruction)
|
DataProcessing(instruction)
|
||||||
);
|
);
|
||||||
@ -444,7 +450,7 @@ struct SampleScheduler {
|
|||||||
// (1) Condition, indicating the condition code associated with this operation; and
|
// (1) Condition, indicating the condition code associated with this operation; and
|
||||||
// (2) An operation-specific encapsulation of the operation code for decoding of fields that didn't
|
// (2) An operation-specific encapsulation of the operation code for decoding of fields that didn't
|
||||||
// fit into the template parameters.
|
// fit into the template parameters.
|
||||||
template <Operation, Flags> void perform(Condition, DataProcessing);
|
template <Flags> void perform(Condition, DataProcessing);
|
||||||
template <Operation, Flags> void perform(Condition, Multiply);
|
template <Operation, Flags> void perform(Condition, Multiply);
|
||||||
template <Operation, Flags> void perform(Condition, SingleDataTransfer);
|
template <Operation, Flags> void perform(Condition, SingleDataTransfer);
|
||||||
template <Operation, Flags> void perform(Condition, BlockDataTransfer);
|
template <Operation, Flags> void perform(Condition, BlockDataTransfer);
|
||||||
|
@ -15,8 +15,74 @@ using namespace InstructionSet::ARM;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
template <ShiftType type>
|
||||||
|
void shift(uint32_t &source, uint32_t &carry, uint32_t amount) {
|
||||||
|
switch(type) {
|
||||||
|
case ShiftType::LogicalLeft:
|
||||||
|
if(amount > 32) {
|
||||||
|
source = carry = 0;
|
||||||
|
} else if(amount == 32) {
|
||||||
|
carry = source & 1;
|
||||||
|
source = 0;
|
||||||
|
} else {
|
||||||
|
carry = source & (0x8000'0000 >> amount);
|
||||||
|
source <<= amount;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shift(ShiftType type, uint32_t &source, uint32_t &carry, uint32_t amount) {
|
||||||
|
switch(type) {
|
||||||
|
case ShiftType::LogicalLeft: shift<ShiftType::LogicalLeft>(source, carry, amount); break;
|
||||||
|
case ShiftType::LogicalRight: shift<ShiftType::LogicalRight>(source, carry, amount); break;
|
||||||
|
case ShiftType::ArithmeticRight: shift<ShiftType::ArithmeticRight>(source, carry, amount); break;
|
||||||
|
case ShiftType::RotateRight: shift<ShiftType::RotateRight>(source, carry, amount); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Scheduler {
|
struct Scheduler {
|
||||||
template <Operation, Flags> void perform(Condition, DataProcessing) {}
|
template <Flags f> void perform(Condition condition, DataProcessing fields) {
|
||||||
|
if(!status.test(condition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr DataProcessingFlags flags(f);
|
||||||
|
auto &destination = registers_[fields.destination()];
|
||||||
|
const auto &operand1 = registers_[fields.operand1()];
|
||||||
|
uint32_t operand2;
|
||||||
|
uint32_t rotate_carry = 0;
|
||||||
|
|
||||||
|
if constexpr (flags.operand2_is_immediate()) {
|
||||||
|
if(!fields.rotate()) {
|
||||||
|
operand2 = fields.immediate();
|
||||||
|
} else {
|
||||||
|
operand2 = fields.immediate() >> fields.rotate();
|
||||||
|
operand2 |= fields.immediate() << (32 - fields.rotate());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t shift_amount;
|
||||||
|
if(fields.shift_count_is_register()) {
|
||||||
|
shift_amount = registers_[fields.shift_register()];
|
||||||
|
} else {
|
||||||
|
shift_amount = fields.shift_amount();
|
||||||
|
}
|
||||||
|
|
||||||
|
operand2 = registers_[fields.operand2()];
|
||||||
|
shift(fields.shift_type(), operand2, rotate_carry, shift_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(flags.operation()) {
|
||||||
|
case DataProcessingOperation::AND:
|
||||||
|
destination = operand1 & operand2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break; // ETC.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <Operation, Flags> void perform(Condition, Multiply) {}
|
template <Operation, Flags> void perform(Condition, Multiply) {}
|
||||||
template <Operation, Flags> void perform(Condition, SingleDataTransfer) {}
|
template <Operation, Flags> void perform(Condition, SingleDataTransfer) {}
|
||||||
template <Operation, Flags> void perform(Condition, BlockDataTransfer) {}
|
template <Operation, Flags> void perform(Condition, BlockDataTransfer) {}
|
||||||
@ -30,6 +96,11 @@ struct Scheduler {
|
|||||||
|
|
||||||
void software_interrupt(Condition) {}
|
void software_interrupt(Condition) {}
|
||||||
void unknown(uint32_t) {}
|
void unknown(uint32_t) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Status status;
|
||||||
|
|
||||||
|
uint32_t registers_[16]; // TODO: register swaps with mode.
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user