[Assembler] Assembler is no longer templated by ISA
The ISA is anyways accessed through a static pointer, so we gain no
performance benefits through templating. Simplifies things a bit
as well.
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -235,19 +235,10 @@ protected:
mutable Section m_currentSection;
};
-template <typename ISA>
class Assembler : public AssemblerBase {
- static_assert(std::is_base_of<ISAInfoBase, ISA>::value, "Provided ISA type must derive from ISAInfoBase");
-
public:
- using Instr = Instruction<ISA>;
- using InstrMap = std::map<QString, std::shared_ptr<Instr>>;
- using InstrVec = std::vector<std::shared_ptr<Instr>>;
- using PseudoInstr = PseudoInstruction<ISA>;
- using PseudoInstrMap = std::map<QString, std::shared_ptr<PseudoInstr>>;
- using PseudoInstrVec = std::vector<std::shared_ptr<PseudoInstr>>;
+ Assembler(const ISAInfoBase* isa) : m_isa(isa) {}
-public:
AssembleResult assemble(const QStringList& programLines) const override {
AssembleResult result;
@@ -288,7 +279,7 @@ public:
res.program << "unknown instruction";
} catch (const std::bad_variant_access&) {
// Got match, disassemble
- auto tokens = std::get<const Instruction<ISA>*>(match)->disassemble(instructionWord, baseAddress + i,
+ auto tokens = std::get<const Instruction*>(match)->disassemble(instructionWord, baseAddress + i,
ReverseSymbolMap());
try {
auto& error = std::get<Error>(match);
@@ -303,7 +294,7 @@ public:
return res;
}
- const Matcher<ISA>& getMatcher() { return *m_matcher; }
+ const Matcher& getMatcher() { return *m_matcher; }
std::set<QString> getOpcodes() const override {
std::set<QString> opcodes;
@@ -472,7 +463,7 @@ protected:
currentSection = &program.sections.at(m_currentSection).data;
addr_offset = currentSection->size();
if (!wasDirective) {
- std::weak_ptr<Instr> assembledWith;
+ std::weak_ptr<Instruction> assembledWith;
runOperation(machineCode, InstrRes, assembleInstruction, line, assembledWith);
if (!machineCode.linksWithSymbol.symbol.isEmpty()) {
@@ -578,7 +569,8 @@ protected:
return {res};
}
- virtual AssembleRes assembleInstruction(const TokenizedSrcLine& line, std::weak_ptr<Instr>& assembledWith) const {
+ virtual AssembleRes assembleInstruction(const TokenizedSrcLine& line,
+ std::weak_ptr<Instruction>& assembledWith) const {
if (line.tokens.empty()) {
return {Error(line.sourceLine, "Empty source lines should be impossible at this point")};
}
@@ -590,13 +582,11 @@ protected:
return m_instructionMap.at(opcode)->assemble(line);
};
- Assembler<ISA>() {}
-
void initialize(InstrVec& instructions, PseudoInstrVec& pseudoinstructions, DirectiveVec& directives) {
setInstructions(instructions);
setPseudoInstructions(pseudoinstructions);
setDirectives(directives);
- m_matcher = std::make_unique<Matcher<ISA>>(m_instructions);
+ m_matcher = std::make_unique<Matcher>(m_instructions);
}
void setPseudoInstructions(PseudoInstrVec& pseudoInstructions) {
@@ -645,7 +635,9 @@ protected:
PseudoInstrVec m_pseudoInstructions;
PseudoInstrMap m_pseudoInstructionMap;
- std::unique_ptr<Matcher<ISA>> m_matcher;
+ std::unique_ptr<Matcher> m_matcher;
+
+ const ISAInfoBase* m_isa;
};
} // namespace AssemblerTmp

MODIFY
src/assembler/instruction.h
src/assembler/instruction.h
@@ -99,21 +99,21 @@ struct Opcode : public Field {
const std::vector<OpPart> opParts;
};
-template <typename ISA>
struct Reg : public Field {
- static_assert(std::is_base_of<ISAInfoBase, ISA>::value, "Provided ISA type must derive from ISAInfoBase");
/**
* @brief Reg
* @param tokenIndex: Index within a list of decoded instruction tokens that corresponds to the register index
* @param range: range in instruction field containing register index value
*/
- Reg(unsigned tokenIndex, BitRange range) : m_tokenIndex(tokenIndex), m_range(range) {}
- Reg(unsigned tokenIndex, unsigned _start, unsigned _stop) : m_tokenIndex(tokenIndex), m_range({_start, _stop}) {}
+ Reg(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range)
+ : m_tokenIndex(tokenIndex), m_range(range), m_isa(isa) {}
+ Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop)
+ : m_tokenIndex(tokenIndex), m_range({_start, _stop}), m_isa(isa) {}
std::optional<AssemblerTmp::Error> apply(const AssemblerTmp::TokenizedSrcLine& line, uint32_t& instruction,
FieldLinkRequest&) const override {
bool success;
const QString& regToken = line.tokens[m_tokenIndex];
- const uint32_t reg = ISA::instance()->regNumber(regToken, success);
+ const uint32_t reg = m_isa->regNumber(regToken, success);
if (!success) {
return AssemblerTmp::Error(line.sourceLine, "Unknown register '" + regToken + "'");
}
@@ -123,7 +123,7 @@ struct Reg : public Field {
std::optional<AssemblerTmp::Error> decode(const uint32_t instruction, const uint32_t, const ReverseSymbolMap&,
AssemblerTmp::LineTokens& line) const override {
const unsigned regNumber = m_range.decode(instruction);
- const QString registerName = ISA::instance()->regName(regNumber);
+ const QString registerName = m_isa->regName(regNumber);
if (registerName.isEmpty()) {
return AssemblerTmp::Error(0, "Unknown register number '" + QString::number(regNumber) + "'");
}
@@ -133,6 +133,7 @@ struct Reg : public Field {
const unsigned m_tokenIndex;
const BitRange m_range;
+ const ISAInfoBase* m_isa;
};
struct ImmPart {
@@ -253,14 +254,11 @@ struct Imm : public Field {
const std::function<uint32_t(uint32_t)> symbolTransformer;
};
-template <typename ISA>
class Instruction {
- static_assert(std::is_base_of<ISAInfoBase, ISA>::value, "Provided ISA type must derive from ISAInfoBase");
-
public:
Instruction(Opcode opcode, const std::vector<std::shared_ptr<Field>>& fields)
: m_opcode(opcode), m_expectedTokens(1 /*opcode*/ + fields.size()), m_fields(fields) {
- m_assembler = [](const Instruction<ISA>* _this, const AssemblerTmp::TokenizedSrcLine& line) {
+ m_assembler = [](const Instruction* _this, const AssemblerTmp::TokenizedSrcLine& line) {
InstrRes res;
_this->m_opcode.apply(line, res.instruction, res.linksWithSymbol);
for (const auto& field : _this->m_fields) {
@@ -271,7 +269,7 @@ public:
}
return AssembleRes(res);
};
- m_disassembler = [](const Instruction<ISA>* _this, const uint32_t instruction, const uint32_t address,
+ m_disassembler = [](const Instruction* _this, const uint32_t instruction, const uint32_t address,
const ReverseSymbolMap& symbolMap) {
AssemblerTmp::LineTokens line;
_this->m_opcode.decode(instruction, address, symbolMap, line);
@@ -307,8 +305,8 @@ public:
const unsigned& size() const { return 4; }
private:
- std::function<AssembleRes(const Instruction<ISA>*, const AssemblerTmp::TokenizedSrcLine&)> m_assembler;
- std::function<DisassembleRes(const Instruction<ISA>*, const uint32_t, const uint32_t, const ReverseSymbolMap&)>
+ std::function<AssembleRes(const Instruction*, const AssemblerTmp::TokenizedSrcLine&)> m_assembler;
+ std::function<DisassembleRes(const Instruction*, const uint32_t, const uint32_t, const ReverseSymbolMap&)>
m_disassembler;
const Opcode m_opcode;
@@ -316,6 +314,9 @@ private:
const std::vector<std::shared_ptr<Field>> m_fields;
};
+using InstrMap = std::map<QString, std::shared_ptr<Instruction>>;
+using InstrVec = std::vector<std::shared_ptr<Instruction>>;
+
} // namespace AssemblerTmp
} // namespace Ripes

MODIFY
src/assembler/matcher.h
src/assembler/matcher.h
namespace Ripes {
namespace AssemblerTmp {
-template <typename ISA>
class Matcher {
- static_assert(std::is_base_of<ISAInfoBase, ISA>::value, "Provided ISA type must derive from ISAInfoBase");
-
struct MatchNode {
MatchNode(OpPart _matcher) : matcher(_matcher) {}
OpPart matcher;
std::vector<MatchNode> children;
- std::shared_ptr<Instruction<ISA>> instruction;
+ std::shared_ptr<Instruction> instruction;
void print(unsigned depth = 0) const {
if (depth == 0) {
@@ -43,11 +40,11 @@ class Matcher {
};
public:
- Matcher(const std::vector<std::shared_ptr<Instruction<ISA>>>& instructions)
+ Matcher(const std::vector<std::shared_ptr<Instruction>>& instructions)
: m_matchRoot(buildMatchTree(instructions, 1)) {}
void print() const { m_matchRoot.print(); }
- std::variant<Error, const Instruction<ISA>*> matchInstruction(uint32_t instruction) const {
+ std::variant<Error, const Instruction*> matchInstruction(uint32_t instruction) const {
auto match = matchInstructionRec(instruction, m_matchRoot, true);
if (match == nullptr) {
return Error(0, "Unknown instruction");
@@ -56,7 +53,7 @@ public:
}
private:
- const Instruction<ISA>* matchInstructionRec(uint32_t instruction, const MatchNode& node, bool isRoot) const {
+ const Instruction* matchInstructionRec(uint32_t instruction, const MatchNode& node, bool isRoot) const {
if (isRoot || node.matcher.matches(instruction)) {
if (node.children.size() > 0) {
for (const auto& child : node.children) {
@@ -71,9 +68,9 @@ private:
return nullptr;
}
- MatchNode buildMatchTree(const std::vector<std::shared_ptr<Instruction<ISA>>>& instructions,
+ MatchNode buildMatchTree(const std::vector<std::shared_ptr<Instruction>>& instructions,
const unsigned fieldDepth = 1, OpPart matcher = OpPart(0, BitRange(0, 0, 2))) {
- using InstrVec = std::vector<std::shared_ptr<Instruction<ISA>>>;
+ using InstrVec = std::vector<std::shared_ptr<Instruction>>;
std::map<OpPart, InstrVec> instrsWithEqualOpPart;
for (const auto& instr : instructions) {

MODIFY
src/assembler/pseudoinstruction.h
src/assembler/pseudoinstruction.h
namespace Ripes {
namespace AssemblerTmp {
-template <typename ISA>
class PseudoInstruction {
- static_assert(std::is_base_of<ISAInfoBase, ISA>::value, "Provided ISA type must derive from ISAInfoBase");
-
public:
PseudoInstruction(
const QString& opcode, const std::vector<std::shared_ptr<Field>>& fields,
@@ -33,7 +30,7 @@ public:
* Does not relate to actual regs/imms in an instruction word, but solely used for a pseudoinstruction to
* be used within the instruction token checking system.
*/
- static std::shared_ptr<Reg<ISA>> reg() { return std::make_shared<Reg<ISA>>(0, 0, 0); }
+ static std::shared_ptr<Reg> reg() { return std::make_shared<Reg>(nullptr, 0, 0, 0); }
static std::shared_ptr<Imm> imm() { return std::make_shared<Imm>(0, 0, Imm::Repr::Hex, std::vector<ImmPart>{}); }
private:
@@ -44,5 +41,8 @@ private:
const std::vector<std::shared_ptr<Field>> m_fields;
};
+using PseudoInstrVec = std::vector<std::shared_ptr<PseudoInstruction>>;
+using PseudoInstrMap = std::map<QString, std::shared_ptr<PseudoInstruction>>;
+
} // namespace AssemblerTmp
} // namespace Ripes

MODIFY
src/assembler/rv32i_assembler.cpp
src/assembler/rv32i_assembler.cpp
namespace Ripes {
namespace AssemblerTmp {
-RV32I_Assembler::RV32I_Assembler(const std::set<Extensions> extensions) : Assembler<ISAInfo<ISA::RV32IM>>() {
- auto [instrs, pseudos, directives] = initInstructions(extensions);
+RV32I_Assembler::RV32I_Assembler(const ISAInfo<ISA::RV32I>* isa) : Assembler(isa) {
+ auto [instrs, pseudos, directives] = initInstructions(isa);
initialize(instrs, pseudos, directives);
// Initialize segment pointers
@@ -17,19 +17,19 @@ RV32I_Assembler::RV32I_Assembler(const std::set<Extensions> extensions) : Assemb
setSegmentBase(".bss", 0x11000000);
}
-std::tuple<RV32I_Assembler::RVInstrVec, RV32I_Assembler::RVPseudoInstrVec, DirectiveVec>
-RV32I_Assembler::initInstructions(const std::set<Extensions>& extensions) const {
- RVInstrVec instructions;
- RVPseudoInstrVec pseudoInstructions;
+std::tuple<InstrVec, PseudoInstrVec, DirectiveVec>
+RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const {
+ InstrVec instructions;
+ PseudoInstrVec pseudoInstructions;
- enableExtI(instructions, pseudoInstructions);
- for (const auto& extension : extensions) {
- switch (extension) {
- case Extensions::M:
- enableExtM(instructions, pseudoInstructions);
+ enableExtI(isa, instructions, pseudoInstructions);
+ for (auto extension : isa->enabledExtensions()) {
+ switch (extension.unicode()->toLatin1()) {
+ case 'M':
+ enableExtM(isa, instructions, pseudoInstructions);
break;
- case Extensions::F:
- enableExtF(instructions, pseudoInstructions);
+ case 'F':
+ enableExtF(isa, instructions, pseudoInstructions);
break;
default:
assert(false && "Unhandled ISA extension");
@@ -39,70 +39,73 @@ RV32I_Assembler::initInstructions(const std::set<Extensions>& extensions) const
}
#define BType(name, funct3) \
- std::shared_ptr<RVInstr>(new RVInstr(Opcode(name, {OpPart(0b1100011, 0, 6), OpPart(funct3, 12, 14)}), \
- {std::make_shared<RVReg>(1, 15, 19), std::make_shared<RVReg>(2, 20, 24), \
- std::make_shared<Imm>(3, 13, Imm::Repr::Signed, \
- std::vector{ImmPart(12, 31, 31), ImmPart(11, 7, 7), \
- ImmPart(5, 25, 30), ImmPart(1, 8, 11)}, \
+ std::shared_ptr<Instruction>(new Instruction( \
+ Opcode(name, {OpPart(0b1100011, 0, 6), OpPart(funct3, 12, 14)}), \
+ {std::make_shared<Reg>(isa, 1, 15, 19), std::make_shared<Reg>(isa, 2, 20, 24), \
+ std::make_shared<Imm>( \
+ 3, 13, Imm::Repr::Signed, \
+ std::vector{ImmPart(12, 31, 31), ImmPart(11, 7, 7), ImmPart(5, 25, 30), ImmPart(1, 8, 11)}, \
Imm::SymbolType::Relative)}))
#define IType(name, funct3) \
- std::shared_ptr<RVInstr>( \
- new RVInstr(Opcode(name, {OpPart(0b0010011, 0, 6), OpPart(funct3, 12, 14)}), \
- {std::make_shared<RVReg>(1, 7, 11), std::make_shared<RVReg>(2, 15, 19), \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(0b0010011, 0, 6), OpPart(funct3, 12, 14)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), std::make_shared<Reg>(isa, 2, 15, 19), \
std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})}))
#define LoadType(name, funct3) \
- std::shared_ptr<RVInstr>( \
- new RVInstr(Opcode(name, {OpPart(0b0000011, 0, 6), OpPart(funct3, 12, 14)}), \
- {std::make_shared<RVReg>(1, 7, 11), std::make_shared<RVReg>(3, 15, 19), \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(0b0000011, 0, 6), OpPart(funct3, 12, 14)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), std::make_shared<Reg>(isa, 3, 15, 19), \
std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})}))
#define IShiftType(name, funct3, funct7) \
- std::shared_ptr<RVInstr>( \
- new RVInstr(Opcode(name, {OpPart(0b0010011, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
- {std::make_shared<RVReg>(1, 7, 11), std::make_shared<RVReg>(2, 15, 19), \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(0b0010011, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), std::make_shared<Reg>(isa, 2, 15, 19), \
std::make_shared<Imm>(3, 5, Imm::Repr::Unsigned, std::vector{ImmPart(0, 20, 24)})}))
#define RType(name, funct3, funct7) \
- std::shared_ptr<RVInstr>(new RVInstr( \
- Opcode(name, {OpPart(0b0110011, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
- {std::make_shared<RVReg>(1, 7, 11), std::make_shared<RVReg>(2, 15, 19), std::make_shared<RVReg>(3, 20, 24)}))
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(0b0110011, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), std::make_shared<Reg>(isa, 2, 15, 19), \
+ std::make_shared<Reg>(isa, 3, 20, 24)}))
#define SType(name, funct3) \
- std::shared_ptr<RVInstr>(new RVInstr( \
+ std::shared_ptr<Instruction>(new Instruction( \
Opcode(name, {OpPart(0b0100011, 0, 6), OpPart(funct3, 12, 14)}), \
- {std::make_shared<RVReg>(3, 15, 19), \
+ {std::make_shared<Reg>(isa, 3, 15, 19), \
std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(5, 25, 31), ImmPart(0, 7, 11)}), \
- std::make_shared<RVReg>(1, 20, 24)}))
+ std::make_shared<Reg>(isa, 1, 20, 24)}))
#define UType(name, opcode) \
- std::shared_ptr<RVInstr>( \
- new RVInstr(Opcode(name, {OpPart(opcode, 0, 6)}), \
- {std::make_shared<RVReg>(1, 7, 11), \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(opcode, 0, 6)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), \
std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)})}))
#define JType(name, opcode) \
- std::shared_ptr<RVInstr>(new RVInstr(Opcode(name, {OpPart(opcode, 0, 6)}), \
- {std::make_shared<RVReg>(1, 7, 11), \
- std::make_shared<Imm>(2, 21, Imm::Repr::Hex, \
- std::vector{ImmPart(20, 31, 31), ImmPart(12, 12, 19), \
- ImmPart(11, 20, 20), ImmPart(1, 21, 30)}, \
+ std::shared_ptr<Instruction>(new Instruction( \
+ Opcode(name, {OpPart(opcode, 0, 6)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), \
+ std::make_shared<Imm>( \
+ 2, 21, Imm::Repr::Hex, \
+ std::vector{ImmPart(20, 31, 31), ImmPart(12, 12, 19), ImmPart(11, 20, 20), ImmPart(1, 21, 30)}, \
Imm::SymbolType::Relative)}))
#define JALRType(name) \
- std::shared_ptr<RVInstr>( \
- new RVInstr(Opcode(name, {OpPart(0b1100111, 0, 6), OpPart(0b000, 12, 14)}), \
- {std::make_shared<RVReg>(1, 7, 11), std::make_shared<RVReg>(2, 15, 19), \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(0b1100111, 0, 6), OpPart(0b000, 12, 14)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11), std::make_shared<Reg>(isa, 2, 15, 19), \
std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})}))
-#define RegTok RVPseudoInstr::reg()
-#define ImmTok RVPseudoInstr::imm()
+#define RegTok PseudoInstruction::reg()
+#define ImmTok PseudoInstruction::imm()
#define CreatePseudoInstruction
-#define PseudoExpandFunc(line) [](const RVPseudoInstr&, const AssemblerTmp::TokenizedSrcLine& line)
+#define PseudoExpandFunc(line) [](const PseudoInstruction&, const AssemblerTmp::TokenizedSrcLine& line)
#define PseudoLoad(name) \
- std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr( \
+ std::shared_ptr<PseudoInstruction>(new PseudoInstruction( \
name, {RegTok, ImmTok}, PseudoExpandFunc(line) { \
LineTokensVec v; \
v.push_back(QStringList() << "auipc" << line.tokens.at(1) << line.tokens.at(2)); \
@@ -115,7 +118,7 @@ RV32I_Assembler::initInstructions(const std::set<Extensions>& extensions) const
// The sw is a pseudo-op if a symbol is given as the immediate token. Thus, if we detect that
// a number has been provided, then abort the pseudo-op handling.
#define PseudoStore(name) \
- std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr( \
+ std::shared_ptr<PseudoInstruction>(new PseudoInstruction( \
name, {RegTok, ImmTok, RegTok}, PseudoExpandFunc(line) { \
bool canConvert; \
getImmediate(line.tokens.at(2), canConvert); \
@@ -130,7 +133,8 @@ RV32I_Assembler::initInstructions(const std::set<Extensions>& extensions) const
return PseudoExpandRes(v); \
}))
-void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pseudoInstructions) const {
+void RV32I_Assembler::enableExtI(const ISAInfo<ISA::RV32I>* isa, InstrVec& instructions,
+ PseudoInstrVec& pseudoInstructions) const {
// Pseudo-op functors
pseudoInstructions.push_back(PseudoLoad("lb"));
pseudoInstructions.push_back(PseudoLoad("lh"));
@@ -140,50 +144,50 @@ void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pse
pseudoInstructions.push_back(PseudoStore("sw"));
// clang-format off
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"la", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "auipc" << line.tokens.at(1) << line.tokens.at(2),
QStringList() << "addi" << line.tokens.at(1) << line.tokens.at(1) << QString("((%1&0xfff)-(__address__-4))").arg(line.tokens.at(2))};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"call", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{LineTokens() << "auipc" << "x6" << line.tokens.at(1),
LineTokens() << "jalr" << "x1" << "x6" << line.tokens.at(1)};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"tail", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "auipc" << "x6" << line.tokens.at(1),
QStringList() << "jalr" << "x0" << "x6" << line.tokens.at(1)};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"j", {ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "jal" << "x0" << line.tokens.at(1)};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"jr", {RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "jalr" << "x0" << line.tokens.at(1) << "0"};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"jalr", {RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "jalr" << "x1" << line.tokens.at(1) << "0"};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
- "ret", {}, [](const RVPseudoInstr&, const AssemblerTmp::TokenizedSrcLine&) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
+ "ret", {}, [](const PseudoInstruction&, const AssemblerTmp::TokenizedSrcLine&) {
return LineTokensVec{QStringList() << "jalr" << "x0" << "x1" << "0"};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"jal", {ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList() << "jal" << "x1" << line.tokens.at(1)};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"li", {RegTok, ImmTok},
PseudoExpandFunc(line) {
LineTokensVec v;
@@ -213,101 +217,101 @@ void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pse
return PseudoExpandRes{v};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("nop", {}, [](const RVPseudoInstr&, const AssemblerTmp::TokenizedSrcLine&) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("nop", {}, [](const PseudoInstruction&, const AssemblerTmp::TokenizedSrcLine&) {
return LineTokensVec{QString("addi x0 x0 0").split(' ')};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(new RVPseudoInstr(
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(new PseudoInstruction(
"mv", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"addi", line.tokens.at(1), line.tokens.at(2), "0"}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("not", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("not", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"xori", line.tokens.at(1), line.tokens.at(2), "-1"}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("neg", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("neg", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"sub", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("seqz", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("seqz", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"sltiu", line.tokens.at(1), line.tokens.at(2), "1"}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("snez", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("snez", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{ QStringList{"sltu", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("sltz", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("sltz", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"slt", line.tokens.at(1), line.tokens.at(2), "x0"}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("sgtz", {RegTok, RegTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("sgtz", {RegTok, RegTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"slt", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("beqz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("beqz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"beq", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bnez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bnez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bne", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("blez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("blez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bge", "x0", line.tokens.at(1), line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bgez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bgez", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bge", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bltz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bltz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"blt", line.tokens.at(1), "x0", line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bgtz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bgtz", {RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"blt", "x0", line.tokens.at(1), line.tokens.at(2)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bgt", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bgt", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"blt", line.tokens.at(2), line.tokens.at(1), line.tokens.at(3)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("ble", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("ble", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bge", line.tokens.at(2), line.tokens.at(1), line.tokens.at(3)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bgtu", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bgtu", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bltu", line.tokens.at(2), line.tokens.at(2), line.tokens.at(3)}};
})));
- pseudoInstructions.push_back(std::shared_ptr<RVPseudoInstr>(
- new RVPseudoInstr("bleu", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
+ pseudoInstructions.push_back(std::shared_ptr<PseudoInstruction>(
+ new PseudoInstruction("bleu", {RegTok, RegTok, ImmTok}, PseudoExpandFunc(line) {
return LineTokensVec{QStringList{"bgeu", line.tokens.at(2), line.tokens.at(2), line.tokens.at(3)}};
})));
// clang-format on
// Assembler functors
- instructions.push_back(
- std::shared_ptr<RVInstr>(new RVInstr(Opcode("ecall", {OpPart(0b1110011, 0, 6), OpPart(0, 7, 31)}), {})));
+ instructions.push_back(std::shared_ptr<Instruction>(
+ new Instruction(Opcode("ecall", {OpPart(0b1110011, 0, 6), OpPart(0, 7, 31)}), {})));
instructions.push_back(UType("lui", 0b0110111));
@@ -319,9 +323,9 @@ void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pse
* provided symbol.
*/
auto auipcSymbolModifier = [](uint32_t bareSymbol) { return bareSymbol >> 12; };
- instructions.push_back(std::shared_ptr<RVInstr>(
- new RVInstr(Opcode("auipc", {OpPart(0b0010111, 0, 6)}),
- {std::make_shared<RVReg>(1, 7, 11),
+ instructions.push_back(std::shared_ptr<Instruction>(
+ new Instruction(Opcode("auipc", {OpPart(0b0010111, 0, 6)}),
+ {std::make_shared<Reg>(isa, 1, 7, 11),
std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)},
Imm::SymbolType::Absolute, auipcSymbolModifier)})));
@@ -369,7 +373,7 @@ void RV32I_Assembler::enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pse
instructions.push_back(BType("bgeu", 0b111));
}
-void RV32I_Assembler::enableExtM(RVInstrVec& instructions, RVPseudoInstrVec&) const {
+void RV32I_Assembler::enableExtM(const ISAInfo<ISA::RV32I>* isa, InstrVec& instructions, PseudoInstrVec&) const {
// Pseudo-op functors
// --
@@ -384,7 +388,7 @@ void RV32I_Assembler::enableExtM(RVInstrVec& instructions, RVPseudoInstrVec&) co
instructions.push_back(RType("remu", 0b111, 0b0000001));
}
-void RV32I_Assembler::enableExtF(RVInstrVec&, RVPseudoInstrVec&) const {
+void RV32I_Assembler::enableExtF(const ISAInfo<ISA::RV32I>* isa, InstrVec&, PseudoInstrVec&) const {
// Pseudo-op functors
// Assembler functors

MODIFY
src/assembler/rv32i_assembler.h
src/assembler/rv32i_assembler.h
namespace Ripes {
namespace AssemblerTmp {
-class RV32I_Assembler : public Assembler<ISAInfo<ISA::RV32IM>> {
-private:
- using RVInstr = Instruction<ISAInfo<ISA::RV32IM>>;
- using RVInstrVec = std::vector<std::shared_ptr<RVInstr>>;
- using RVPseudoInstr = PseudoInstruction<ISAInfo<ISA::RV32IM>>;
- using RVPseudoInstrVec = std::vector<std::shared_ptr<RVPseudoInstr>>;
- using RVReg = Reg<ISAInfo<ISA::RV32IM>>;
-
+class RV32I_Assembler : public Assembler {
public:
- enum class Extensions { M, F };
- RV32I_Assembler(const std::set<Extensions> extensions = std::set<Extensions>());
+ RV32I_Assembler(const ISAInfo<ISA::RV32I>* isa);
-public:
- std::tuple<RVInstrVec, RVPseudoInstrVec, DirectiveVec>
- initInstructions(const std::set<Extensions>& extensions) const;
+private:
+ std::tuple<InstrVec, PseudoInstrVec, DirectiveVec> initInstructions(const ISAInfo<ISA::RV32I>* isa) const;
/**
* Extension enablers
* Calling an extension enabler will register the appropriate assemblers and pseudo-op expander functors with
* the assembler.
*/
- void enableExtI(RVInstrVec& instructions, RVPseudoInstrVec& pseudoInstructions) const;
- void enableExtM(RVInstrVec& instructions, RVPseudoInstrVec& pseudoInstructions) const;
- void enableExtF(RVInstrVec& instructions, RVPseudoInstrVec& pseudoInstructions) const;
+ void enableExtI(const ISAInfo<ISA::RV32I>* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) const;
+ void enableExtM(const ISAInfo<ISA::RV32I>* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) const;
+ void enableExtF(const ISAInfo<ISA::RV32I>* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) const;
protected:
QChar commentDelimiter() const override { return '#'; }

MODIFY
test/tst_assembler.cpp
test/tst_assembler.cpp
@@ -10,7 +10,7 @@ const QString s_testdir = VSRTL_RISCV_TEST_DIR;
using namespace Ripes;
using namespace AssemblerTmp;
-using RVISA = ISAInfo<ISA::RV32IM>;
+using RVISA = ISAInfo<ISA::RV32I>;
class tst_Assembler : public QObject {
Q_OBJECT
@@ -32,7 +32,7 @@ private slots:
void tst_invalidLabel();
private:
- std::vector<std::shared_ptr<Instruction<RVISA>>> createInstructions();
+ std::vector<std::shared_ptr<Instruction>> createInstructions();
QString createProgram(int entries) {
QString out;
@@ -51,7 +51,8 @@ private:
enum class Expect { Fail, Success };
void testAssemble(const QStringList& program, Expect expect) {
- auto assembler = RV32I_Assembler();
+ auto isa = std::make_unique<ISAInfo<ISA::RV32I>>(QStringList());
+ auto assembler = RV32I_Assembler(isa.get());
auto res = assembler.assemble(program);
if ((res.errors.size() != 0) ^ (expect == Expect::Fail)) {
res.errors.print();
@@ -70,7 +71,8 @@ void tst_Assembler::tst_riscv() {
const auto testFiles = dir.entryList({"*.s"});
auto testFunct = [](const QString& filename) {
- auto assembler = RV32I_Assembler({RV32I_Assembler::Extensions::M});
+ auto isa = std::make_unique<ISAInfo<ISA::RV32I>>(QStringList());
+ auto assembler = RV32I_Assembler(isa.get());
auto f = QFile(filename);
f.open(QIODevice::ReadOnly | QIODevice::Text);
auto program = QString(f.readAll());
@@ -113,9 +115,10 @@ void tst_Assembler::tst_invalidLabel() {
}
void tst_Assembler::tst_benchmarkNew() {
- auto newassembler = RV32I_Assembler();
+ auto isa = std::make_unique<ISAInfo<ISA::RV32I>>(QStringList());
+ auto assembler = RV32I_Assembler(isa.get());
auto program = createProgram(1000);
- QBENCHMARK { newassembler.assembleRaw(program); }
+ QBENCHMARK { assembler.assembleRaw(program); }
}
void tst_Assembler::tst_simpleprogram() {
@@ -194,7 +197,8 @@ void tst_Assembler::tst_labelWithPseudo() {
}
void tst_Assembler::tst_matcher() {
- auto assembler = RV32I_Assembler();
+ auto isa = std::make_unique<ISAInfo<ISA::RV32I>>(QStringList());
+ auto assembler = RV32I_Assembler(isa.get());
assembler.getMatcher().print();
std::vector<std::pair<QString, unsigned>> toMatch = {
@@ -210,7 +214,7 @@ void tst_Assembler::tst_matcher() {
QFAIL(error.second.toStdString().c_str());
} catch (const std::bad_variant_access&) {
}
- auto matchInstr = std::get<const Instruction<RVISA>*>(match);
+ auto matchInstr = std::get<const Instruction*>(match);
if (matchInstr->name() != iter.first) {
QString error =
"Incorrect instruction decoded; got '" + matchInstr->name() + "' but expected '" + iter.first + "'";

[Assembler] Assembler is no longer templated by ISA

The ISA is anyways accessed through a static pointer, so we gain no
performance benefits through templating. Simplifies things a bit
as well.