[Assembler] Modify the temporary assembler namespace
Until the new assembler infrastructure is finished and tested, we shall
keep changes inside the AssemblerTmp namespace to avoid aliasing the
current "Assembler" class.
MODIFY
src/assembler/assembler.cpp
src/assembler/assembler.cpp
@@ -35,8 +35,9 @@ namespace {
} // namespace
namespace Ripes {
+namespace AssemblerTmp {
-Assembler::Result Assembler::assemble(const QString& program) const {
+Result AssemblerBase::assemble(const QString& program) const {
const auto programLines = program.split(QRegExp("[\r\n]"));
Result result;
@@ -53,7 +54,7 @@ Assembler::Result Assembler::assemble(const QString& program) const {
// runPass(unused3, QByteArray, pass3, tokenizedLines, symbols);
}
-std::variant<Assembler::Errors, Assembler::Program> Assembler::pass0(const QStringList& program) const {
+std::variant<Errors, Program> AssemblerBase::pass0(const QStringList& program) const {
Errors errors;
Program tokenizedLines;
tokenizedLines.reserve(program.size());
@@ -71,7 +72,7 @@ std::variant<Assembler::Errors, Assembler::Program> Assembler::pass0(const QStri
}
}
-std::variant<Assembler::Errors, Assembler::Program> Assembler::pass1(const Program& tokenizedLines) const {
+std::variant<Errors, Program> AssemblerBase::pass1(const Program& tokenizedLines) const {
Errors errors;
Program expandedLines;
expandedLines.reserve(tokenizedLines.size());
@@ -96,7 +97,7 @@ std::variant<Assembler::Errors, Assembler::Program> Assembler::pass1(const Progr
}
}
-std::variant<Assembler::Errors, Assembler::NoPassResult> Assembler::pass2(std::vector<SourceLine>& tokenizedLines,
+std::variant<Errors, NoPassResult> AssemblerBase::pass2(std::vector<SourceLine>& tokenizedLines,
Symbols& symbols) const {
Errors errors;
for (auto& line : tokenizedLines) {
@@ -117,8 +118,7 @@ std::variant<Assembler::Errors, Assembler::NoPassResult> Assembler::pass2(std::v
}
}
-std::variant<Assembler::Errors, QByteArray> Assembler::pass3(const Program& tokenizedLines,
- const SymbolMap& symbolMap) const {
+std::variant<Errors, QByteArray> AssemblerBase::pass3(const Program& tokenizedLines, const SymbolMap& symbolMap) const {
QByteArray program;
Errors errors;
for (const auto& line : tokenizedLines) {
@@ -132,17 +132,16 @@ std::variant<Assembler::Errors, QByteArray> Assembler::pass3(const Program& toke
}
}
-std::variant<Assembler::Error, Assembler::LineTokens> Assembler::tokenize(const QString& line) const {
+std::variant<Error, LineTokens> AssemblerBase::tokenize(const QString& line) const {
const static auto splitter = QRegularExpression(
R"(\t|\((?=x(?:[1-2]\d|3[0-1]|\d)|t[0-6]|a[0-7]|s(?:1[0-1]|\d)|[sgt]p|zero)|(?:x(?:[1-2]\d|3[0-1]|\d)|t[0-6]|a[0-7]|s(?:1[0-1]|\d)|[sgt]p|zero)\K\))");
return line.split(splitter);
}
-std::variant<Assembler::Error, std::pair<QString, Assembler::LineTokens>>
-Assembler::splitSymbolFromLine(const SourceLine& line) const {
+std::variant<Error, std::pair<QString, LineTokens>> AssemblerBase::splitSymbolFromLine(const SourceLine& line) const {
if (line.tokens.size() == 0) {
- return std::pair<QString, Assembler::LineTokens>(QString(), line.tokens);
+ return std::pair<QString, LineTokens>(QString(), line.tokens);
}
const bool hasSymbol =
@@ -162,7 +161,8 @@ Assembler::splitSymbolFromLine(const SourceLine& line) const {
remainingTokens.removeFirst();
auto symbol = firstToken;
symbol.remove(':');
- return std::pair<QString, Assembler::LineTokens>(symbol, remainingTokens);
+ return std::pair<QString, LineTokens>(symbol, remainingTokens);
}
+} // namespace AssemblerTmp
} // namespace Ripes

MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
#pragma once
+#include "assembler_defines.h"
#include "isainfo.h"
#include <set>
#include <variant>
namespace Ripes {
+namespace AssemblerTmp {
-class Assembler {
+class AssemblerBase {
public:
- using Symbol = QString;
- using Symbols = std::set<Symbol>;
- using SymbolMap = std::map<Symbol, unsigned>;
- using LineTokens = QStringList;
- struct SourceLine {
- LineTokens tokens;
- unsigned source_line = 0;
- QString symbol;
- };
- using SymbolLinePair = std::pair<Symbol, LineTokens>;
- using Program = std::vector<SourceLine>;
- using NoPassResult = std::monostate;
-
- // An error is defined as a reference to a source line index + an error string
- using Error = std::pair<unsigned, QString>;
- using Errors = std::vector<Error>;
- /**
- * @brief The Result struct
- * An assembly result is determined to be valid iff errors is empty.
- */
- struct Result {
- Errors errors;
- QByteArray program;
- };
-
Result assemble(const QString& program) const;
private:
@@ -72,4 +49,6 @@ protected:
virtual std::variant<Error, SymbolLinePair> splitSymbolFromLine(const SourceLine& line) const = 0;
};
+} // namespace AssemblerTmp
+
} // namespace Ripes

ADD
src/assembler/assembler_defines.h
+#pragma once
+
+#include <QByteArray>
+#include <QStringList>
+
+#include <map>
+#include <set>
+#include <variant>
+
+namespace Ripes {
+
+namespace AssemblerTmp {
+
+using Symbol = QString;
+using Symbols = std::set<Symbol>;
+using SymbolMap = std::map<Symbol, unsigned>;
+using LineTokens = QStringList;
+struct SourceLine {
+ LineTokens tokens;
+ unsigned source_line = 0;
+ QString symbol;
+};
+using SymbolLinePair = std::pair<Symbol, LineTokens>;
+using Program = std::vector<SourceLine>;
+using NoPassResult = std::monostate;
+
+// An error is defined as a reference to a source line index + an error string
+using Error = std::pair<unsigned, QString>;
+using Errors = std::vector<Error>;
+/**
+ * @brief The Result struct
+ * An assembly result is determined to be valid iff errors is empty.
+ */
+struct Result {
+ Errors errors;
+ QByteArray program;
+};
+
+} // namespace AssemblerTmp
+
+} // namespace Ripes

MODIFY
src/assembler/rv32i_assembler.cpp
src/assembler/rv32i_assembler.cpp
#include <algorithm>
namespace Ripes {
+namespace AssemblerTmp {
namespace {
inline QByteArray uint32ToByteArr(uint32_t in) {
@@ -53,9 +54,9 @@ uint32_t getRegisterNumber(const QString& reg, bool& success) {
*/
template <int N, typename T_funct, typename T_ret, typename... Args>
T_funct expectNTokens(const T_funct& functor) {
- return [=](const Assembler::SourceLine& line, Args... others) {
+ return [=](const AssemblerTmp::SourceLine& line, Args... others) {
if (line.tokens.size() != N) {
- return std::variant<Assembler::Error, T_ret>({Assembler::Error(
+ return std::variant<AssemblerTmp::Error, T_ret>({AssemblerTmp::Error(
line.source_line, "Expected " + QString::number(N) + " tokens but got " + line.tokens.size())});
} else {
return functor(line, others...);
@@ -63,18 +64,29 @@ T_funct expectNTokens(const T_funct& functor) {
};
}
-template <uint32_t funct3, uint32_t funct7>
-std::variant<Assembler::Error, QByteArray> assembleOpInstruction(const Assembler::SourceLine& line) {
+std::variant<AssemblerTmp::Error, std::vector<uint32_t>> getRegisters(const AssemblerTmp::SourceLine& line,
+ const std::vector<int>& indicies) {
bool success;
- std::vector<uint32_t> regs(3);
- for (size_t token_idx = 1; token_idx <= regs.size(); token_idx++) {
- const auto& regToken = line.tokens[token_idx];
+ std::vector<uint32_t> regs(indicies.size());
+ for (const int& index : indicies) {
+ const auto& regToken = line.tokens[index];
const uint32_t reg = getRegisterNumber(regToken, success);
if (!success) {
- return {Assembler::Error(line.source_line, "Unknown register '" + regToken + "'")};
+ return {AssemblerTmp::Error(line.source_line, "Unknown register '" + regToken + "'")};
}
regs.push_back(reg);
}
+ return regs;
+}
+
+template <uint32_t funct3, uint32_t funct7>
+std::variant<AssemblerTmp::Error, QByteArray> assembleOpInstruction(const AssemblerTmp::SourceLine& line) {
+ auto regsVariant = getRegisters(line, {1, 2, 3});
+ try {
+ return std::get<AssemblerTmp::Error>(regsVariant);
+ } catch (std::bad_variant_access&) {
+ }
+ auto& regs = std::get<std::vector<uint32_t>>(regsVariant);
return uint32ToByteArr(instrType::OP | funct3 << 12 | funct7 << 25 | regs[0] << 7 | regs[1] << 15 | regs[2] << 20);
}
@@ -96,7 +108,7 @@ RV32I_Assembler::RV32I_Assembler(const std::set<Extensions>& extensions) {
}
}
-std::variant<Assembler::Error, std::optional<std::vector<Assembler::LineTokens>>>
+std::variant<AssemblerTmp::Error, std::optional<std::vector<AssemblerTmp::LineTokens>>>
RV32I_Assembler::expandPseudoOp(const SourceLine& line) const {
if (line.tokens.empty()) {
return {};
@@ -108,8 +120,8 @@ RV32I_Assembler::expandPseudoOp(const SourceLine& line) const {
return m_pseudoOpExpanders.at(opcode)(line);
}
-std::variant<Assembler::Error, QByteArray>
-RV32I_Assembler::assembleInstruction(const SourceLine& line, const Assembler::SymbolMap& symbols) const {
+std::variant<AssemblerTmp::Error, QByteArray>
+RV32I_Assembler::assembleInstruction(const SourceLine& line, const AssemblerTmp::SymbolMap& symbols) const {
if (line.tokens.empty()) {
return {QByteArray()};
}
@@ -137,7 +149,7 @@ void RV32I_Assembler::addAssemblerFunctor(const QString& opcode, AssemblerFuncto
void RV32I_Assembler::enableExtI() {
// Pseudo-op functors
addPseudoOpExpanderFunctor("nop", expectNTokens<1, PseudoOpFunctor, PseudoOpFunctorRetT>([](const SourceLine&) {
- return std::vector<Assembler::LineTokens>{QString("addi x0 x0 0").split(' ')};
+ return std::vector<AssemblerTmp::LineTokens>{QString("addi x0 x0 0").split(' ')};
}));
// Assembler functors
@@ -148,17 +160,19 @@ void RV32I_Assembler::enableExtM() {
// Assembler functors
- addAssemblerFunctor("mul", expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const Assembler::SymbolMap&>(
- [](const SourceLine& line, const Assembler::SymbolMap&) {
+ addAssemblerFunctor("mul", expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const AssemblerTmp::SymbolMap&>(
+ [](const SourceLine& line, const AssemblerTmp::SymbolMap&) {
return assembleOpInstruction<0b000, 0b0000001>(line);
}));
- addAssemblerFunctor("mulh", expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const Assembler::SymbolMap&>(
- [](const SourceLine& line, const Assembler::SymbolMap&) {
+ addAssemblerFunctor("mulh",
+ expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const AssemblerTmp::SymbolMap&>(
+ [](const SourceLine& line, const AssemblerTmp::SymbolMap&) {
return assembleOpInstruction<0b001, 0b0000001>(line);
}));
- addAssemblerFunctor("mulhsu", expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const Assembler::SymbolMap&>(
- [](const SourceLine& line, const Assembler::SymbolMap&) {
+ addAssemblerFunctor("mulhsu",
+ expectNTokens<3, AssemblerFunctor, AssemblerFunctorRetT, const AssemblerTmp::SymbolMap&>(
+ [](const SourceLine& line, const AssemblerTmp::SymbolMap&) {
return assembleOpInstruction<0b011, 0b0000001>(line);
}));
}
@@ -168,4 +182,5 @@ void RV32I_Assembler::enableExtF() {
// Assembler functors
}
+} // namespace AssemblerTmp
} // namespace Ripes

MODIFY
src/assembler/rv32i_assembler.h
src/assembler/rv32i_assembler.h
#include <functional>
namespace Ripes {
+namespace AssemblerTmp {
-class RV32I_Assembler : public Assembler {
+class RV32I_Assembler : public AssemblerBase {
public:
enum class Extensions { M, F };
RV32I_Assembler(const std::set<Extensions>& extensions);
@@ -21,8 +22,8 @@ public:
* @brief m_pseudoOpExpanders
* A map of (pseudo)opcodes => pseudo-op expander functors
*/
- using PseudoOpFunctorRetT = std::optional<std::vector<Assembler::LineTokens>>;
- using PseudoOpFunctor = std::function<std::variant<Assembler::Error, PseudoOpFunctorRetT>(const SourceLine&)>;
+ using PseudoOpFunctorRetT = std::optional<std::vector<LineTokens>>;
+ using PseudoOpFunctor = std::function<std::variant<Error, PseudoOpFunctorRetT>(const SourceLine&)>;
std::map<QString, PseudoOpFunctor> m_pseudoOpExpanders;
void addPseudoOpExpanderFunctor(const QString& opcode, PseudoOpFunctor functor);
@@ -31,8 +32,8 @@ public:
* a map of opcodes => instruction assembler functors
*/
using AssemblerFunctorRetT = QByteArray;
- using AssemblerFunctor = std::function<std::variant<Assembler::Error, AssemblerFunctorRetT>(
- const SourceLine&, const Assembler::SymbolMap&)>;
+ using AssemblerFunctor =
+ std::function<std::variant<Error, AssemblerFunctorRetT>(const SourceLine&, const SymbolMap&)>;
std::map<QString, AssemblerFunctor> m_assemblers;
void addAssemblerFunctor(const QString& opcode, AssemblerFunctor functor);
@@ -46,4 +47,5 @@ public:
void enableExtF();
};
+} // namespace AssemblerTmp
} // namespace Ripes

[Assembler] Modify the temporary assembler namespace

Until the new assembler infrastructure is finished and tested, we shall
keep changes inside the AssemblerTmp namespace to avoid aliasing the
current "Assembler" class.