Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sliderules: A dynamic ISA reference table #329

Draft
wants to merge 64 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
001f3a1
Prevent release-based Github Actions from running on forks
raccog Jan 6, 2024
addf38c
Remove unnecessary conditionals
raccog Jan 6, 2024
78f9fb3
Add initial Qt Designer layout for sliderules tab
raccog Nov 13, 2023
05e0b12
Create template table model for instruction decoding
raccog Nov 13, 2023
fbbb97d
Add encoding table
raccog Nov 13, 2023
83cadb0
Fill table with instruction names and extension origin
raccog Nov 13, 2023
1265307
Try to generate initial parts of the encoding table
raccog Nov 13, 2023
34f8eee
Fix column resizing and disable filter input
raccog Nov 13, 2023
c4296ba
Fix column sizes and add some spans
raccog Nov 13, 2023
b74f213
Generate field names for sliderules encoding table
raccog Nov 13, 2023
34a0148
Set opcode bits in the table and mark them with the color red
raccog Nov 13, 2023
0adf51b
Reorganize sliderule table by using a certain structure for each column
raccog Nov 14, 2023
7b178a6
Add fields to bitfields
raccog Nov 14, 2023
d80852f
Fix immediates intersecting with zeroes
raccog Nov 14, 2023
9c8720d
Fix BitRangeSet fold expression
raccog Nov 14, 2023
bbc2441
Give fields shortened names if only using one column
raccog Nov 14, 2023
c7622c9
Blank out instruction bits that are not used (for compressed instrs)
raccog Nov 14, 2023
fd2dc6c
Add splitter between encodings and decodings
raccog Nov 14, 2023
d629d2b
Fix spanning issues
raccog Nov 14, 2023
fd2b947
Move instruction instances from Assembler into ISAInfoBase
raccog Nov 14, 2023
4b838ce
Quick refactor
raccog Nov 14, 2023
bc08d20
Further reduce ISAInfo instantiations by caching all accesses
raccog Nov 14, 2023
acf0526
Show instructions from all supported extensions in sliderules
raccog Nov 14, 2023
8e07d48
Add descriptions to RISC-V instructions and sliderules table
raccog Dec 5, 2023
0911bf3
Add long description for tooltip when hovering over description
raccog Dec 5, 2023
b2e1197
Fix rebase
raccog Dec 6, 2023
bf6d481
Refactor (simplify) encoding table
raccog Dec 13, 2023
604c337
Stretch description column
raccog Dec 13, 2023
d9377e3
Add rows for encoding constructed immediates
raccog Dec 13, 2023
e2fd626
Add some TODO comments
raccog Dec 13, 2023
144b4ae
Add UI selectors for ISA and register width
raccog Dec 13, 2023
eca786d
Add ISA options to combo boxes
raccog Dec 13, 2023
6580ffe
Change grouping of ISA selectors
raccog Dec 13, 2023
7e5e682
Got ISA filtering working properly
raccog Dec 18, 2023
677a9f7
Add main ISA extension selector
raccog Dec 18, 2023
eb4f94d
Get main extensions selector working
raccog Dec 18, 2023
3cd268b
Fix encoding table column stretching when changing ISA options
raccog Dec 28, 2023
4d5d5df
Quick refactor
raccog Dec 28, 2023
380600b
Add UI element for selecting multiple extensions
raccog Dec 28, 2023
2a4f304
Fix rows being hidden when they shouldn't be
raccog Dec 28, 2023
df7bb6f
Remove "Explanation" column
raccog Jan 6, 2024
fec7547
Rewrite parts of the EncodingModel
raccog Jan 6, 2024
4a59ee5
Create EncodingView manually to be more independent from SliderulesTab
raccog Jan 6, 2024
507aff7
Get encoding table filters working again (mostly)
raccog Jan 6, 2024
5e96781
Get main extension selector working (mostly)
raccog Jan 7, 2024
5364305
Remove some unused code
raccog Jan 7, 2024
382e8a0
Get all current filters working properly
raccog Jan 7, 2024
6696b0b
Add checkboxes for selecting additional extensions
raccog Jan 7, 2024
4f7af16
Remove blank extension from MIPS ISAInfo
raccog Jan 7, 2024
58e30a0
Show in UI how many instructions are shown/filtered
raccog Jan 7, 2024
30c3406
Only reset the register width selector when changing ISA families
raccog Jan 7, 2024
c13a65a
Fix clang-format
raccog Jan 7, 2024
45e230a
Separate encoding model (data) from encoding view (UI)
raccog Jan 15, 2024
e4ec45f
Start reworking UI after learning more about Qt
raccog Jan 19, 2024
1f6b9db
Add back ISA register width selector
raccog Jan 19, 2024
4cf3016
Working on flow of data between Qt widgets and models
raccog Feb 3, 2024
204bbde
Redo again
raccog Feb 26, 2024
fed3aaa
Get sliderules filters working
raccog Feb 26, 2024
77fc57d
Start Qt model from scratch
raccog Feb 26, 2024
b195e71
Remove complex code to start with a simple example
raccog Feb 26, 2024
c716784
Get a working model for a QTreeView
raccog Feb 27, 2024
029052c
Add first signal and slot for ISAInstructionsModel
raccog Feb 27, 2024
a68278c
Connect signals/slots so that ISA filters work properly
raccog Feb 27, 2024
7e0a3ac
Update extension filters when model changes
raccog Feb 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/assembler/assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ constructAssemblerDynamic(const std::shared_ptr<const ISAInfoBase> &isa) {

throw std::runtime_error(
std::string("Cannot dynamically construct assembler for isa: ") +
isa->name().toStdString());
isa->fullName().toStdString());
}

} // namespace Assembler
Expand Down
117 changes: 114 additions & 3 deletions src/isa/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ struct BitRangeBase {

const unsigned start, stop, N;

/// Returns true if the index is within the start/stop range
constexpr bool isWithinRange(unsigned idx) const {
return (idx >= start && idx <= stop);
}
constexpr unsigned width() const { return stop - start + 1; }
// TODO(raccog): Decouple from vsrtl library
constexpr Instr_T getMask() const { return vsrtl::generateBitmask(width()); }
Expand Down Expand Up @@ -133,6 +137,9 @@ struct BitRangeSet {
using CombineWith =
typename OtherBitRangeImpl::template CombinedBitRanges<BitRanges...>;

/// Returns all BitRanges in this set as a vector that can be read at runtime
static std::vector<BitRangeBase> getRanges() { return {BitRanges()...}; }

/// Returns the combined width of all BitRanges
constexpr static unsigned width() { return (BitRanges().width() + ... + 0); }

Expand Down Expand Up @@ -182,6 +189,11 @@ struct OpPartBase {
return range < other.range;
}

/// Returns true if the i'th bit is set in this OpPart
constexpr bool bitIsSet(unsigned i) const {
return ((range.apply(value) >> i) & 1) == 1;
}

/// Applies this OpPart's encoding to the instruction.
constexpr void apply(Instr_T &instruction) const {
instruction |= range.apply(value);
Expand Down Expand Up @@ -271,6 +283,9 @@ struct OpcodeSet {
return IndexedOpPart<OpParts...>::getOpPart(partIndex);
}

/// Returns all OpParts in this set as a vector that can be read at runtime
static std::vector<OpPartBase> getParts() { return {OpParts()...}; }

private:
/// Run verifications for all BitRanges
constexpr static BitRanges ranges{};
Expand All @@ -290,16 +305,31 @@ struct InstrRes {

using AssembleRes = Result<InstrRes>;

struct FieldBase {
enum class Type { Reg, Immediate };

FieldBase(Type _type, unsigned _tokenIndex, std::vector<BitRangeBase> _ranges)
: type(_type), tokenIndex(_tokenIndex), ranges(_ranges) {}

const Type type;
const unsigned tokenIndex;
const std::vector<BitRangeBase> ranges;

virtual QString fieldType() const { return "UNKNOWN"; }
};

/** @brief An instruction field defined at compile-time.
* @param _tokenIndex: The index of this field in an assembly instruction
* (starting at 0).
* @param _BitRanges: A set of BitRanges that define which bits contain field in
* the instruction. Must be BitRangesImpl type.
*/
template <unsigned _tokenIndex, typename _BitRanges>
struct Field {
struct Field : public FieldBase {
using BitRanges = _BitRanges;

Field(Type type) : FieldBase(type, _tokenIndex, BitRanges::getRanges()) {}

private:
/// Run verifications for all BitRanges
constexpr static BitRanges ranges{};
Expand All @@ -316,6 +346,7 @@ class FieldSet {
template <unsigned, template <unsigned> typename...>
struct IndexedFieldSet {
using BitRanges = BitRangeSet<>;
static std::vector<std::shared_ptr<FieldBase>> getFields() { return {}; }
};
template <unsigned tokenIndex, template <unsigned> typename FirstField,
template <unsigned> typename... NextFields>
Expand Down Expand Up @@ -354,6 +385,19 @@ class FieldSet {
else
return true;
}

/// Returns all Fields in this set as a vector that can be read at runtime
static std::vector<std::shared_ptr<FieldBase>> getFields() {
auto field = std::make_shared<IndexedField>();
if constexpr (tokenIndex < sizeof...(Fields)) {
std::vector<std::shared_ptr<FieldBase>> vec =
NextIndexedFieldSet::getFields();
vec.insert(vec.begin(), field);
return vec;
} else {
return {field};
}
}
};

using IndexedFields = IndexedFieldSet<0, Fields...>;
Expand Down Expand Up @@ -383,6 +427,14 @@ class FieldSet {
/// Returns the number of Fields in this set.
constexpr static unsigned numFields() { return sizeof...(Fields); }

/// Returns all Fields in this set as a vector that can be read at runtime
static std::vector<std::shared_ptr<FieldBase>> getFields() {
if constexpr (sizeof...(Fields) == 0) {
return {};
}
return IndexedFields::getFields();
}

private:
/// This calls all BitRanges' static assertions
constexpr static BitRanges ranges{};
Expand All @@ -404,7 +456,9 @@ template <typename RegImpl, unsigned tokenIndex, typename BitRange,
struct Reg : public Field<tokenIndex, BitRangeSet<BitRange>> {
static_assert(verifyBitRange<BitRange>(), "Invalid BitRange type");

Reg() : regsd(RegImpl::NAME.data()) {}
Reg()
: Field<tokenIndex, BitRangeSet<BitRange>>(FieldBase::Type::Reg),
regsd(RegImpl::NAME.data()) {}

/// Applies this register's encoding to the instruction.
static Result<> apply(const TokenizedSrcLine &line, Instr_T &instruction,
Expand Down Expand Up @@ -435,6 +489,8 @@ struct Reg : public Field<tokenIndex, BitRangeSet<BitRange>> {
return true;
}

QString fieldType() const override { return regsd; }

const QString regsd = "reg";
};

Expand Down Expand Up @@ -553,6 +609,12 @@ struct ImmBase : public Field<tokenIndex, typename ImmParts::BitRanges> {
using Reg_T_S = typename std::make_signed<Reg_T>::type;
using Reg_T_U = typename std::make_unsigned<Reg_T>::type;

ImmBase()
: Field<tokenIndex, typename ImmParts::BitRanges>(
FieldBase::Type::Immediate) {}

QString fieldType() const override { return "imm"; }

/// Converts a string to its immediate value (if it exists). Success is set to
/// false if this fails.
constexpr static int64_t getImm(const QString &immToken, bool &success,
Expand Down Expand Up @@ -712,8 +774,14 @@ class InstructionBase {
virtual OpPartBase getOpPart(unsigned partIndex) const = 0;
/// Returns the name of this instruction.
virtual const QString &name() const = 0;
/// Returns a description of this instruction.
virtual const QString &description() const = 0;
/// Returns a long description of this instruction.
virtual const QString &longDescription() const = 0;
/// Returns the number of OpParts in this instruction.
virtual unsigned numOpParts() const = 0;
/// Returns the name of the extension that this instruction came from.
virtual QString extensionOrigin() const = 0;

/**
* @brief size
Expand All @@ -730,6 +798,30 @@ class InstructionBase {
[&](const auto &f) { return f(instr); });
}

virtual const std::vector<std::shared_ptr<FieldBase>> &getFields() const = 0;
virtual const std::vector<OpPartBase> &getOpParts() const = 0;

bool opPartBitIsSet(unsigned idx) const {
auto opParts = getOpParts();
// Check each OpPart to see if this bit is set
for (const auto &part : opParts) {
if (part.bitIsSet(idx)) {
return true;
}
}
return false;
}
bool opPartInRange(unsigned idx) const {
auto opParts = getOpParts();
// Check each OpPart to see if this bit is set
for (const auto &part : opParts) {
if (part.range.isWithinRange(idx)) {
return true;
}
}
return false;
}

protected:
/// An optional set of disassembler match conditions, if the default
/// opcode-based matching is insufficient.
Expand Down Expand Up @@ -772,7 +864,13 @@ template <typename InstrImpl>
struct Instruction : public InstructionBase {
Instruction()
: InstructionBase(InstrByteSize<InstrImpl>::byteSize),
m_name(InstrImpl::NAME.data()) {}
m_name(InstrImpl::NAME.data()), m_description(InstrImpl::DESC.data()),
m_longDescription(InstrImpl::LONG_DESC.data()),
m_fields(InstrImpl::Fields::getFields()),
m_opParts(InstrImpl::Opcode::getParts()) {}

constexpr static std::string_view DESC = "TODO: DESCRIPTION";
constexpr static std::string_view LONG_DESC = "TODO: LONG DESCRIPTION";

AssembleRes assemble(const TokenizedSrcLine &tokens) override {
Instr_T instruction = 0;
Expand Down Expand Up @@ -804,10 +902,23 @@ struct Instruction : public InstructionBase {
return InstrImpl::Opcode::getOpPart(partIndex);
}
const QString &name() const override { return m_name; }
const QString &description() const override { return m_description; }
const QString &longDescription() const override { return m_longDescription; }
unsigned numOpParts() const override { return InstrImpl::Opcode::numParts(); }

const std::vector<std::shared_ptr<FieldBase>> &getFields() const override {
return m_fields;
}
const std::vector<OpPartBase> &getOpParts() const override {
return m_opParts;
}

private:
const QString m_name;
const QString m_description;
const QString m_longDescription;
const std::vector<std::shared_ptr<FieldBase>> m_fields;
const std::vector<OpPartBase> m_opParts;
};

using InstrMap = std::map<QString, std::shared_ptr<InstructionBase>>;
Expand Down
34 changes: 34 additions & 0 deletions src/isa/isaconstructor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "isaconstructor.h"

#include "mips32isainfo.h"
#include "rv32isainfo.h"
#include "rv64isainfo.h"

namespace Ripes {

template <ISA... isas>
std::map<ISA,
std::function<std::shared_ptr<const ISAInfoBase>(const QStringList &)>>
_constructConstructors() {
std::map<ISA, std::function<std::shared_ptr<const ISAInfoBase>(
const QStringList &)>>
constructors;
(
[&] {
constructors[isas] = [](const QStringList &extensions) {
return std::make_shared<ISAInfo<isas>>(extensions);
};
}(),
...);
return constructors;
}

std::map<ISA,
std::function<std::shared_ptr<const ISAInfoBase>(const QStringList &)>>
constructConstructors() {
/// NOTE: Ensure that every ISA is used in the `_constructConstructors<...>()`
/// template
return _constructConstructors<ISA::MIPS32I, ISA::RV32I, ISA::RV64I>();
}

} // namespace Ripes
16 changes: 16 additions & 0 deletions src/isa/isaconstructor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <map>

#include <QStringList>

namespace Ripes {

enum class ISA;
class ISAInfoBase;

std::map<ISA,
std::function<std::shared_ptr<const ISAInfoBase>(const QStringList &)>>
constructConstructors();

} // namespace Ripes
Loading
Loading