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

Add basic multiply.

This commit is contained in:
Thomas Harte 2024-02-28 11:27:27 -05:00
parent 60d1b36e9a
commit 487ade56ed
2 changed files with 38 additions and 8 deletions

View File

@ -63,9 +63,12 @@ constexpr bool is_comparison(DataProcessingOperation operation) {
}
}
enum class Operation {
enum class MultiplyOperation {
MUL, /// Rd = Rm * Rs
MLA, /// Rd = Rm * Rs + Rn
};
enum class Operation {
B, /// Add offset to PC; programmer allows for PC being two words ahead.
BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction.
@ -192,7 +195,12 @@ struct MultiplyFlags {
constexpr MultiplyFlags(uint8_t flags) noexcept : flags_(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_); }
/// @returns The operation to apply.
constexpr MultiplyOperation operation() const {
return flag_bit<21>(flags_) ? MultiplyOperation::MLA : MultiplyOperation::MUL;
}
private:
uint8_t flags_;
@ -388,11 +396,7 @@ struct OperationMapper {
// This implementation provides only eight bits baked into the template parameters so
// an additional dynamic test is required to check whether this is really, really MUL or MLA.
if(((instruction >> 4) & 0b1111) == 0b1001) {
constexpr bool is_mla = partial & (1 << 21);
scheduler.template perform<is_mla ? Operation::MLA : Operation::MUL, i>(
condition,
Multiply(instruction)
);
scheduler.template perform<i>(Multiply(instruction));
return;
}
}

View File

@ -274,7 +274,33 @@ struct Scheduler {
}
}
template <Operation, Flags> void perform(Condition, Multiply) {}
template <Flags f> void perform(Multiply fields) {
constexpr MultiplyFlags flags(f);
// R15 rules:
//
// * Rs: no PSR, 8 bytes ahead;
// * Rn: with PSR, 8 bytes ahead;
// * Rm: with PSR, 12 bytes ahead.
const uint32_t multiplicand = fields.multiplicand() == 15 ? registers_.pc(8) : registers_.active[fields.multiplicand()];
const uint32_t multiplier = fields.multiplier() == 15 ? registers_.pc_status(8) : registers_.active[fields.multiplier()];
const uint32_t accumulator =
flags.operation() == MultiplyOperation::MUL ? 0 :
(fields.multiplicand() == 15 ? registers_.pc_status(12) : registers_.active[fields.accumulator()]);
const uint32_t result = multiplicand * multiplier + accumulator;
if constexpr (flags.set_condition_codes()) {
registers_.set_nz(result);
// V is unaffected; C is undefined.
}
if(fields.destination() != 15) {
registers_.active[fields.destination()] = result;
}
}
template <Operation, Flags> void perform(Condition, SingleDataTransfer) {}
template <Operation, Flags> void perform(Condition, BlockDataTransfer) {}