mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-26 08:29:33 +00:00
Add coprocessor data operations and register transfers.
This commit is contained in:
parent
b2696450d5
commit
e986ae2878
@ -47,7 +47,6 @@ struct WithShiftControlBits {
|
||||
/// The amount to shift by if @c shift_count_is_register() is @c false; meaningless otherwise.
|
||||
int shift_amount() const { return (opcode_ >> 7) & 0x1f; }
|
||||
|
||||
|
||||
protected:
|
||||
uint32_t opcode_;
|
||||
};
|
||||
@ -150,10 +149,69 @@ struct SingleDataTransfer: public WithShiftControlBits {
|
||||
int immediate() const { return opcode_ & 0xfff; }
|
||||
};
|
||||
|
||||
//
|
||||
// Block data transfer (LDR, STR).
|
||||
//
|
||||
struct BlockDataTransferFlags {
|
||||
constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
constexpr bool pre_index() { return flag_bit<24>(flags_); }
|
||||
constexpr bool add_offset() { return flag_bit<23>(flags_); }
|
||||
constexpr bool load_psr() { return flag_bit<22>(flags_); }
|
||||
constexpr bool write_back_address() { return flag_bit<21>(flags_); }
|
||||
|
||||
private:
|
||||
uint8_t flags_;
|
||||
};
|
||||
|
||||
struct BlockDataTransfer: public WithShiftControlBits {
|
||||
using WithShiftControlBits::WithShiftControlBits;
|
||||
|
||||
/// The base register index. i.e. 'Rn'.
|
||||
int base() const { return (opcode_ >> 16) & 0xf; }
|
||||
|
||||
/// A bitfield indicating which registers to load or store.
|
||||
int register_list() const { return opcode_ & 0xffff; }
|
||||
};
|
||||
|
||||
//
|
||||
// Coprocessor data operation and register transfer.
|
||||
//
|
||||
struct CoprocessorDataOperationFlags {
|
||||
constexpr CoprocessorDataOperationFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0xf; }
|
||||
|
||||
private:
|
||||
uint8_t flags_;
|
||||
};
|
||||
|
||||
struct CoprocessorRegisterTransferFlags {
|
||||
constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0x7; }
|
||||
|
||||
private:
|
||||
uint8_t flags_;
|
||||
};
|
||||
|
||||
struct CoprocessorOperationOrRegisterTransfer {
|
||||
constexpr CoprocessorOperationOrRegisterTransfer(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
int operand1() { return (opcode_ >> 16) & 0xf; }
|
||||
int operand2() { return opcode_ & 0xf; }
|
||||
int destination() { return (opcode_ >> 12) & 0xf; }
|
||||
int coprocessor() { return (opcode_ >> 8) & 0xf; }
|
||||
int information() { return (opcode_ >> 5) & 0x7; }
|
||||
|
||||
protected:
|
||||
uint32_t opcode_;
|
||||
};
|
||||
|
||||
struct OperationMapper {
|
||||
template <int i, typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
||||
constexpr auto partial = static_cast<uint32_t>(i << 20);
|
||||
constexpr auto partial = uint32_t(i << 20);
|
||||
const auto condition = Condition(instruction >> 28);
|
||||
|
||||
// Cf. the ARM2 datasheet, p.45. Tests below match its ordering
|
||||
// other than that 'undefined' is the fallthrough case. More specific
|
||||
@ -165,6 +223,7 @@ struct OperationMapper {
|
||||
constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf));
|
||||
constexpr auto flags = DataProcessingFlags(i);
|
||||
scheduler.template data_processing<operation, flags>(
|
||||
condition,
|
||||
DataProcessing(instruction)
|
||||
);
|
||||
}
|
||||
@ -179,6 +238,7 @@ struct OperationMapper {
|
||||
constexpr bool is_mla = partial & (1 << 21);
|
||||
constexpr auto flags = MultiplyFlags(i);
|
||||
scheduler.template multiply<is_mla ? Operation::MLA : Operation::MUL, flags>(
|
||||
condition,
|
||||
Multiply(instruction)
|
||||
);
|
||||
}
|
||||
@ -189,9 +249,61 @@ struct OperationMapper {
|
||||
constexpr bool is_ldr = partial & (1 << 20);
|
||||
constexpr auto flags = SingleDataTransferFlags(i);
|
||||
scheduler.template single_data_transfer<is_ldr ? Operation::LDR : Operation::STR, flags>(
|
||||
condition,
|
||||
SingleDataTransfer(instruction)
|
||||
);
|
||||
}
|
||||
|
||||
// Block data transfer (LDM, STM); cf. p.29.
|
||||
if constexpr (((partial >> 25) & 0b111) == 0b100) {
|
||||
constexpr bool is_ldm = partial & (1 << 20);
|
||||
constexpr auto flags = BlockDataTransferFlags(i);
|
||||
scheduler.template block_data_transfer<is_ldm ? Operation::LDM : Operation::STM, flags>(
|
||||
condition,
|
||||
BlockDataTransfer(instruction)
|
||||
);
|
||||
}
|
||||
|
||||
// Branch and branch with link (B, BL); cf. p.15.
|
||||
if constexpr (((partial >> 25) & 0b111) == 0b101) {
|
||||
constexpr bool is_bl = partial & (1 << 24);
|
||||
scheduler.template branch<is_bl ? Operation::BL : Operation::B>(
|
||||
condition,
|
||||
(instruction & 0xf'ffff) << 2
|
||||
);
|
||||
}
|
||||
|
||||
// Software interreupt; cf. p.35.
|
||||
if constexpr (((partial >> 24) & 0b1111) == 0b1111) {
|
||||
scheduler.software_interrupt(condition);
|
||||
}
|
||||
|
||||
|
||||
// Both:
|
||||
// Coprocessor data operation; cf. p. 37; and
|
||||
// Coprocessor register transfers; cf. p. 42.
|
||||
if constexpr (((partial >> 24) & 0b1111) == 0b1110) {
|
||||
const auto parameters = CoprocessorOperationOrRegisterTransfer(instruction);
|
||||
|
||||
// TODO: parameters should probably vary.
|
||||
|
||||
if(instruction & (1 << 4)) {
|
||||
// Register transfer.
|
||||
constexpr auto flags = CoprocessorRegisterTransferFlags(i);
|
||||
constexpr bool is_mrc = partial & (1 << 20);
|
||||
scheduler.template coprocessor_register_transfer<is_mrc ? Operation::MRC : Operation::MCR, flags>(
|
||||
condition,
|
||||
parameters
|
||||
);
|
||||
} else {
|
||||
// Data operation.
|
||||
constexpr auto flags = CoprocessorDataOperationFlags(i);
|
||||
scheduler.template coprocessor_data_operation<flags>(
|
||||
condition,
|
||||
parameters
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -202,40 +314,11 @@ template <typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &s
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
// Block data transfer (LDM, STM); cf. p.29.
|
||||
if(((opcode >> 25) & 0b111) == 0b100) {
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(((opcode >> 25) & 0b111) == 0b110) {
|
||||
result[c] = Operation::CoprocessorDataTransfer;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(((opcode >> 24) & 0b1111) == 0b1110) {
|
||||
result[c] = Operation::CoprocessorDataOperationOrRegisterTransfer;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(((opcode >> 24) & 0b1111) == 0b1111) {
|
||||
result[c] = Operation::SoftwareInterrupt;
|
||||
continue;
|
||||
}
|
||||
|
||||
result[c] = Operation::Undefined;
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
//
|
||||
// Instruction.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/02/2024.
|
||||
// Copyright © 2024 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Decoder.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "Operation.hpp"
|
||||
|
||||
namespace InstructionSet::ARM {
|
||||
|
||||
/*
|
||||
|
||||
//
|
||||
// LDR and STR.
|
||||
//
|
||||
struct SingleDataTransfer {
|
||||
constexpr SingleDataTransfer(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
/// The destination register index. i.e. 'Rd' for LDR.
|
||||
int destination() const { return (opcode_ >> 12) & 0xf; }
|
||||
|
||||
/// The destination register index. i.e. 'Rd' for STR.
|
||||
int source() const { return (opcode_ >> 12) & 0xf; }
|
||||
|
||||
/// The base register index. i.e. 'Rn'.
|
||||
int base() const { return (opcode_ >> 16) & 0xf; }
|
||||
|
||||
///
|
||||
int offset() const { return opcode_ & 0xfff; }
|
||||
|
||||
// TODO: P, U, B, W, L, I.
|
||||
*/
|
||||
|
||||
}
|
@ -49,9 +49,10 @@ enum class Operation {
|
||||
|
||||
LDR, STR,
|
||||
LDM, STM,
|
||||
SoftwareInterrupt,
|
||||
SWI,
|
||||
|
||||
CoprocessorDataOperationOrRegisterTransfer,
|
||||
CDP,
|
||||
MRC, MCR,
|
||||
CoprocessorDataTransfer,
|
||||
|
||||
Undefined,
|
||||
|
@ -1333,7 +1333,6 @@
|
||||
4B1EC714255398B000A1F44B /* Sound.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sound.cpp; sourceTree = "<group>"; };
|
||||
4B1EC715255398B000A1F44B /* Sound.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sound.hpp; sourceTree = "<group>"; };
|
||||
4B1EDB431E39A0AC009D6819 /* chip.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chip.png; sourceTree = "<group>"; };
|
||||
4B20053E2B804A4F00420C5C /* Instruction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Instruction.hpp; sourceTree = "<group>"; };
|
||||
4B2005402B804AA300420C5C /* Decoder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Decoder.hpp; sourceTree = "<group>"; };
|
||||
4B2005422B804D6400420C5C /* ARMDecoderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ARMDecoderTests.mm; sourceTree = "<group>"; };
|
||||
4B2005442B804DC900420C5C /* Model.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Model.hpp; sourceTree = "<group>"; };
|
||||
@ -2762,7 +2761,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B2005402B804AA300420C5C /* Decoder.hpp */,
|
||||
4B20053E2B804A4F00420C5C /* Instruction.hpp */,
|
||||
4B2005442B804DC900420C5C /* Model.hpp */,
|
||||
4B2005452B804DF600420C5C /* Operation.hpp */,
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user