Initial commit of RV64I assembler
ADD
src/assembler/rv64i_assembler.cpp
+#include "rv64i_assembler.h"
+#include "gnudirectives.h"
+#include "ripessettings.h"
+#include "rv32i_assembler.h"
+#include "rvassembler_common.h"
+#include "rvrelocations.h"
+
+#include <QByteArray>
+#include <algorithm>
+
+namespace Ripes {
+namespace Assembler {
+
+RV64I_Assembler::RV64I_Assembler(const ISAInfo<ISA::RV64I>* isa) : Assembler(isa) {
+ auto [instrs, pseudos] = initInstructions(isa);
+
+ auto directives = gnuDirectives();
+ auto relocations = rvRelocations();
+ initialize(instrs, pseudos, directives, relocations);
+
+ // Initialize segment pointers
+ setSegmentBase(".text", RipesSettings::value(RIPES_SETTING_ASSEMBLER_TEXTSTART).toUInt());
+ setSegmentBase(".data", RipesSettings::value(RIPES_SETTING_ASSEMBLER_DATASTART).toUInt());
+ setSegmentBase(".bss", RipesSettings::value(RIPES_SETTING_ASSEMBLER_BSSSTART).toUInt());
+
+ // Monitor settings changes to segment pointers
+ connect(RipesSettings::getObserver(RIPES_SETTING_ASSEMBLER_TEXTSTART), &SettingObserver::modified,
+ [this](const QVariant& value) { setSegmentBase(".text", value.toUInt()); });
+ connect(RipesSettings::getObserver(RIPES_SETTING_ASSEMBLER_DATASTART), &SettingObserver::modified,
+ [this](const QVariant& value) { setSegmentBase(".data", value.toUInt()); });
+ connect(RipesSettings::getObserver(RIPES_SETTING_ASSEMBLER_BSSSTART), &SettingObserver::modified,
+ [this](const QVariant& value) { setSegmentBase(".bss", value.toUInt()); });
+}
+
+std::tuple<InstrVec, PseudoInstrVec> RV64I_Assembler::initInstructions(const ISAInfo<ISA::RV64I>* isa) const {
+ InstrVec instructions;
+ PseudoInstrVec pseudoInstructions;
+
+ enableExtI(isa, instructions, pseudoInstructions);
+ for (const auto& extension : isa->enabledExtensions()) {
+ switch (extension.unicode()->toLatin1()) {
+ case 'M':
+ enableExtM(isa, instructions, pseudoInstructions);
+ break;
+ default:
+ assert(false && "Unhandled ISA extension");
+ }
+ }
+ return {instructions, pseudoInstructions};
+}
+
+void RV64I_Assembler::enableExtI(const ISAInfoBase* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) {
+ RV32I_Assembler::enableExtI(isa, instructions, pseudoInstructions, {RV32I_Assembler::Options::shifts64BitVariant});
+
+ instructions.push_back(IType32(Token("addiw"), 0b000));
+
+ instructions.push_back(IShiftType64(Token("slli"), RVISA::OPIMM, 0b001, 0b000000));
+ instructions.push_back(IShiftType64(Token("srli"), RVISA::OPIMM, 0b101, 0b000000));
+ instructions.push_back(IShiftType64(Token("srai"), RVISA::OPIMM, 0b101, 0b010000));
+
+ instructions.push_back(RType32(Token("addw"), 0b000, 0b0000000));
+ instructions.push_back(RType32(Token("subw"), 0b000, 0b0100000));
+ instructions.push_back(RType32(Token("sllw"), 0b001, 0b0000000));
+ instructions.push_back(RType32(Token("srlw"), 0b101, 0b0000000));
+ instructions.push_back(RType32(Token("sraw"), 0b101, 0b0100000));
+}
+
+void RV64I_Assembler::enableExtM(const ISAInfoBase* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions) {
+ RV32I_Assembler::enableExtM(isa, instructions, pseudoInstructions);
+}
+
+} // namespace Assembler
+} // namespace Ripes

ADD
src/assembler/rv64i_assembler.h
+#pragma once
+
+#include "assembler.h"
+
+#include <QObject>
+#include <functional>
+
+namespace Ripes {
+namespace Assembler {
+
+class RV64I_Assembler : public QObject, public Assembler {
+ Q_OBJECT
+public:
+ RV64I_Assembler(const ISAInfo<ISA::RV64I>* isa);
+
+private:
+ std::tuple<InstrVec, PseudoInstrVec> initInstructions(const ISAInfo<ISA::RV64I>* isa) const;
+
+ /**
+ * Extension enablers
+ * Calling an extension enabler will register the appropriate assemblers and pseudo-op expander functors with
+ * the assembler.
+ */
+ static void enableExtI(const ISAInfoBase* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions);
+ static void enableExtM(const ISAInfoBase* isa, InstrVec& instructions, PseudoInstrVec& pseudoInstructions);
+
+protected:
+ QChar commentDelimiter() const override { return '#'; }
+};
+
+} // namespace Assembler
+} // namespace Ripes

MODIFY
src/assembler/rvassembler_common.h
src/assembler/rvassembler_common.h
@@ -30,21 +30,27 @@ namespace Assembler {
{std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 3, 15, 19, "rs1"), \
std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})}))
-#define IShiftTypeCommon(name, opcode, funct3, funct7, immEnd) \
+#define IShiftType32(name, opcode, funct3, funct7) \
std::shared_ptr<Instruction>( \
new Instruction(Opcode(name, {OpPart(opcode, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
{std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 2, 15, 19, "rs1"), \
- std::make_shared<Imm>(3, 5, Imm::Repr::Unsigned, std::vector{ImmPart(0, 20, immEnd)})}))
+ std::make_shared<Imm>(3, 5, Imm::Repr::Unsigned, std::vector{ImmPart(0, 20, 24)})}))
-#define IShiftType32(name, opcode, funct3, funct7) IShiftTypeCommon(name, opcode, funct3, funct7, 24)
-#define IShiftType64(name, opcode, funct3, funct7) IShiftTypeCommon(name, opcode, funct3, funct7, 25)
+#define IShiftType64(name, opcode, funct3, funct6) \
+ std::shared_ptr<Instruction>( \
+ new Instruction(Opcode(name, {OpPart(opcode, 0, 6), OpPart(funct3, 12, 14), OpPart(funct6, 26, 31)}), \
+ {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 2, 15, 19, "rs1"), \
+ std::make_shared<Imm>(3, 5, Imm::Repr::Unsigned, std::vector{ImmPart(0, 20, 25)})}))
-#define RType(name, funct3, funct7) \
+#define RTypeCommon(name, opcode, funct3, funct7) \
std::shared_ptr<Instruction>( \
- new Instruction(Opcode(name, {OpPart(RVISA::OPIMM32, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
+ new Instruction(Opcode(name, {OpPart(opcode, 0, 6), OpPart(funct3, 12, 14), OpPart(funct7, 25, 31)}), \
{std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 2, 15, 19, "rs1"), \
std::make_shared<Reg>(isa, 3, 20, 24, "rs2")}))
+#define RType(name, funct3, funct7) RTypeCommon(name, RVISA::OP, funct3, funct7)
+#define RType32(name, funct3, funct7) RTypeCommon(name, RVISA::OP32, funct3, funct7)
+
#define SType(name, funct3) \
std::shared_ptr<Instruction>(new Instruction( \
Opcode(name, {OpPart(0b0100011, 0, 6), OpPart(funct3, 12, 14)}), \

MODIFY
src/isa/isainfo.h
src/isa/isainfo.h
namespace Ripes {
/// List of currently supported ISAs
-enum class ISA { RV32I };
-const static std::map<ISA, QString> ISAFamilyNames = {{ISA::RV32I, "RISC-V"}};
+enum class ISA { RV32I, RV64I };
+const static std::map<ISA, QString> ISAFamilyNames = {{ISA::RV32I, "RISC-V"}, {ISA::RV64I, "RISC-V"}};
enum class RegisterFileType { GPR, FPR, CSR };
const static std::map<RegisterFileType, QString> s_RegsterFileName = {{RegisterFileType::GPR, "GPR"},
{RegisterFileType::FPR, "FPR"},

ADD
src/isa/rv64isainfo.h
+#pragma once
+
+#include "isainfo.h"
+#include "rvisainfo_common.h"
+
+namespace Ripes {
+
+template <>
+class ISAInfo<ISA::RV64I> : public ISAInfoBase {
+public:
+ ISAInfo<ISA::RV32I>(const QStringList extensions) {
+ // Validate extensions
+ for (const auto& ext : extensions) {
+ if (supportsExtension(ext)) {
+ m_enabledExtensions << ext;
+ } else {
+ assert(false && "Invalid extension specified for ISA");
+ }
+ }
+ }
+
+ QString name() const override { return "RV32I"; }
+ ISA isaID() const override { return ISA::RV64I; }
+
+ unsigned int regCnt() const override { return 32; }
+ QString regName(unsigned i) const override {
+ return RVISA::RegNames.size() > static_cast<int>(i) ? RVISA::RegNames.at(static_cast<int>(i)) : QString();
+ }
+ QString regAlias(unsigned i) const override {
+ return RVISA::RegAliases.size() > static_cast<int>(i) ? RVISA::RegAliases.at(static_cast<int>(i)) : QString();
+ }
+ QString regInfo(unsigned i) const override {
+ return RVISA::RegDescs.size() > static_cast<int>(i) ? RVISA::RegDescs.at(static_cast<int>(i)) : QString();
+ }
+ bool regIsReadOnly(unsigned i) const override { return i == 0; }
+ unsigned int bits() const override { return 32; }
+ int spReg() const override { return 2; }
+ int gpReg() const override { return 3; }
+ int syscallReg() const override { return 17; }
+ unsigned elfMachineId() const override { return EM_RISCV; }
+ unsigned int regNumber(const QString& reg, bool& success) const override {
+ QString regRes = reg;
+ success = true;
+ if (reg[0] == 'x' && (RVISA::RegNames.count(reg) != 0)) {
+ regRes.remove('x');
+ return regRes.toInt(&success, 10);
+ } else if (RVISA::RegAliases.contains(reg)) {
+ return RVISA::RegAliases.indexOf(reg);
+ }
+ success = false;
+ return 0;
+ }
+
+ QString CCmarch() const override {
+ QString march = "rv32i";
+
+ // Proceed in canonical order
+ for (const auto& ext : {"M", "A", "F", "D"}) {
+ if (m_enabledExtensions.contains(ext)) {
+ march += QString(ext).toLower();
+ }
+ }
+
+ return march;
+ }
+ QString CCmabi() const override { return "ilp32"; }
+
+ QString elfSupportsFlags(unsigned flags) const override {
+ /** We expect no flags for RV32IM compiled RISC-V executables.
+ * Refer to: https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-elf-object-files
+ */
+ if (flags == 0)
+ return QString();
+ QString err;
+ for (const auto& flag : RVISA::ELFFlagStrings) {
+ if (flags & flag.first) {
+ err += "ELF flag '" + RVISA::ELFFlagStrings.at(flag.first) + "' unsupported<br/>";
+ }
+ }
+ return err;
+ }
+
+ const QStringList& supportedExtensions() const override { return m_supportedExtensions; }
+ const QStringList& enabledExtensions() const override { return m_enabledExtensions; }
+
+private:
+ QStringList m_enabledExtensions;
+ QStringList m_supportedExtensions = {"M"};
+};
+
+} // namespace Ripes

MODIFY
src/isa/rvisainfo_common.h
src/isa/rvisainfo_common.h
@@ -9,7 +9,21 @@ namespace RVISA {
extern const QStringList RegAliases;
extern const QStringList RegNames;
extern const QStringList RegDescs;
-enum Opcode { OPIMM = 0b0010011, OPIMM32 = 0b0110011 };
+enum Opcode {
+ LUI = 0b0110111,
+ JAL = 0b1101111,
+ JALR = 0b1100111,
+ BRANCH = 0b1100011,
+ LOAD = 0b0000011,
+ STORE = 0b0100011,
+ OPIMM = 0b0010011,
+ OP = 0b0110011,
+ OPIMM32 = 0b0011011,
+ OP32 = 0b0111011,
+ ECALL = 0b1110011,
+ AUIPC = 0b0010111,
+ INVALID = 0b0
+};
} // namespace RVISA

Initial commit of RV64I assembler