1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 03:29:45 +00:00

Start poking at implementation.

This commit is contained in:
Thomas Harte 2024-02-26 14:30:26 -05:00
parent cd21b39f44
commit 030dda34f0
2 changed files with 84 additions and 7 deletions

View File

@ -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);

View File

@ -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.
};
}