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,
|
||||
};
|
||||
|
||||
enum class Operation {
|
||||
enum class DataProcessingOperation {
|
||||
AND, /// Rd = Op1 AND Op2.
|
||||
EOR, /// Rd = Op1 EOR Op2.
|
||||
SUB, /// Rd = Op1 - Op2.
|
||||
@ -33,7 +33,9 @@ enum class Operation {
|
||||
MOV, /// Rd = Op2
|
||||
BIC, /// Rd = Op1 AND NOT Op2.
|
||||
MVN, /// Rd = NOT Op2.
|
||||
};
|
||||
|
||||
enum class Operation {
|
||||
MUL, /// Rd = Rm * Rs
|
||||
MLA, /// Rd = Rm * Rs + Rn
|
||||
B, /// Add offset to PC; programmer allows for PC being two words ahead.
|
||||
@ -120,12 +122,17 @@ private:
|
||||
struct DataProcessingFlags {
|
||||
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;
|
||||
/// @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.
|
||||
constexpr bool set_condition_codes() { return flag_bit<20>(flags_); }
|
||||
constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); }
|
||||
|
||||
private:
|
||||
uint8_t flags_;
|
||||
@ -332,8 +339,7 @@ struct OperationMapper {
|
||||
|
||||
// Data processing; cf. p.17.
|
||||
if constexpr (((partial >> 26) & 0b11) == 0b00) {
|
||||
constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf));
|
||||
scheduler.template perform<operation, i>(
|
||||
scheduler.template perform<i>(
|
||||
condition,
|
||||
DataProcessing(instruction)
|
||||
);
|
||||
@ -444,7 +450,7 @@ struct SampleScheduler {
|
||||
// (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
|
||||
// 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, SingleDataTransfer);
|
||||
template <Operation, Flags> void perform(Condition, BlockDataTransfer);
|
||||
|
@ -15,8 +15,74 @@ using namespace InstructionSet::ARM;
|
||||
|
||||
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 {
|
||||
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, SingleDataTransfer) {}
|
||||
template <Operation, Flags> void perform(Condition, BlockDataTransfer) {}
|
||||
@ -30,6 +96,11 @@ struct Scheduler {
|
||||
|
||||
void software_interrupt(Condition) {}
|
||||
void unknown(uint32_t) {}
|
||||
|
||||
private:
|
||||
Status status;
|
||||
|
||||
uint32_t registers_[16]; // TODO: register swaps with mode.
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user