From c56dfb2b97a5b8ca61a77536b671d8b6f1c289ee Mon Sep 17 00:00:00 2001 From: Stelios Karagiorgis <108999173+SteliosKaragiorgis@users.noreply.github.com> Date: Thu, 28 Sep 2023 12:16:44 +0300 Subject: [PATCH] Add MIPS ISA (#290) Add MIPS32 to isainfo.h --- src/isa/CMakeLists.txt | 6 + src/isa/isainfo.h | 6 +- src/isa/mips32isainfo.h | 33 ++++++ src/isa/mipsisainfo_common.cpp | 61 ++++++++++ src/isa/mipsisainfo_common.h | 211 +++++++++++++++++++++++++++++++++ 5 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 src/isa/mips32isainfo.h create mode 100644 src/isa/mipsisainfo_common.cpp create mode 100644 src/isa/mipsisainfo_common.h diff --git a/src/isa/CMakeLists.txt b/src/isa/CMakeLists.txt index bd24cb686..4649502b6 100644 --- a/src/isa/CMakeLists.txt +++ b/src/isa/CMakeLists.txt @@ -1 +1,7 @@ create_ripes_lib(isa LINK_TO_RIPES_LIB) + +target_sources(isa_lib + PRIVATE + mipsisainfo_common.h mipsisainfo_common.cpp + mips32isainfo.h +) diff --git a/src/isa/isainfo.h b/src/isa/isainfo.h index 5aa0f54c1..cba8a9b1f 100644 --- a/src/isa/isainfo.h +++ b/src/isa/isainfo.h @@ -12,9 +12,9 @@ namespace Ripes { /// List of currently supported ISAs. -enum class ISA { RV32I, RV64I }; -const static std::map ISAFamilyNames = {{ISA::RV32I, "RISC-V"}, - {ISA::RV64I, "RISC-V"}}; +enum class ISA { RV32I, RV64I, MIPS32I }; +const static std::map ISAFamilyNames = { + {ISA::RV32I, "RISC-V"}, {ISA::RV64I, "RISC-V"}, {ISA::MIPS32I, "MIPS"}}; enum class RegisterFileType { GPR, FPR, CSR }; struct RegisterFileName { QString shortName; diff --git a/src/isa/mips32isainfo.h b/src/isa/mips32isainfo.h new file mode 100644 index 000000000..2ade3f7c6 --- /dev/null +++ b/src/isa/mips32isainfo.h @@ -0,0 +1,33 @@ +#pragma once + +#include "isainfo.h" +#include "mipsisainfo_common.h" + +namespace Ripes { + +template <> +class ISAInfo : public MIPSISAInfoBase { +public: + ISAInfo(const QStringList extensions) { + // Validate extensions + for (const auto &ext : extensions) { + if (supportsExtension(ext)) { + m_enabledExtensions << ext; + } + } + } + + ISA isaID() const override { return ISA::MIPS32I; } + + unsigned int bits() const override { return 32; } + unsigned elfMachineId() const override { return EM_MIPS; } + QString CCmarch() const override { + QString march = "mips32i"; + return march; + } + QString CCmabi() const override { return "ilp32"; } + + unsigned instrByteAlignment() const override { return 4; }; +}; + +} // namespace Ripes diff --git a/src/isa/mipsisainfo_common.cpp b/src/isa/mipsisainfo_common.cpp new file mode 100644 index 000000000..18260feaa --- /dev/null +++ b/src/isa/mipsisainfo_common.cpp @@ -0,0 +1,61 @@ +#include "mipsisainfo_common.h" + +namespace Ripes { +namespace MIPSISA { + +// clang-format off +const QStringList RegAliases = QStringList() << "zero" + << "at" << "v0" << "v1" << "a0" << "a1" << "a2" << "a3" << "t0" << "t1" << "t2" + << "t3" << "t4" << "t5" << "t6" << "t7" << "s0" << "s1" << "s2" << "s3" << "s4" + << "s5" << "s6" << "s7" << "t8" << "t9" << "k0" << "k1" << "gp" << "sp" << "fp" + << "ra" << "hi" << "lo"; + +const QStringList RegNames = QStringList() << "$0" + << "$1" << "$2" << "$3" << "$4" << "$5" << "$6" << "$7" << "$8" + << "$9" << "$10" << "$11" << "$12" << "$13" << "$14" << "$15" + << "$16" << "$17" << "$18" << "$19" << "$20" << "$21" << "$22" << "$23" + << "$24" << "$25" << "$26" << "$27" << "$28" << "$29" << "$30" << "$31" << "$32" << "$33"; + +const QStringList RegDescs = QStringList() << "Hard-Wired zero" + << "Assembler Temporary" + << "Return value from function call" + << "Return value from function call" + << "Argument 1" + << "Argument 2" + << "Argument 3" + << "Argument 4" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Saved Temporary\nPreserved across call" + << "Temporary\nNot preserved across call" + << "Temporary\nNot preserved across call" + << "Kernel use register" + << "Kernel use register" + << "Global pointer" + << "Stack pointer" + << "Frame pointer" + << "Return Address" + << "Multiplication/Division register" + << "Multiplication/Division register"; +// clang-format on +} // namespace MIPSISA + +namespace MIPSABI { +const std::map ELFFlagStrings{ + {NOREORDER, "NOREORDER"}, {PIC, "PIC"}, {CPIC, "CPIC"}, {ARCH, "ARCH"}}; +} + +} // namespace Ripes diff --git a/src/isa/mipsisainfo_common.h b/src/isa/mipsisainfo_common.h new file mode 100644 index 000000000..f5a7f5dc9 --- /dev/null +++ b/src/isa/mipsisainfo_common.h @@ -0,0 +1,211 @@ +#pragma once + +#include "isainfo.h" +#include + +namespace Ripes { + +template +constexpr ISA XLenToMIPSISA() { + static_assert(XLEN == 32, "Only supports 32-bit variants"); + return ISA::MIPS32I; +} + +namespace MIPSISA { + +extern const QStringList RegAliases; +extern const QStringList RegNames; +extern const QStringList RegDescs; +enum Opcode { + ADDI = 0b001000, + ADDIU = 0b001001, + ANDI = 0b001100, + RTYPE = 0b000000, + ORI = 0b001101, + XORI = 0b001110, + LHI = 0b011001, + LLO = 0b011000, + SLTI = 0b001010, + SLTIU = 0b001011, + BEQ = 0b000100, + BGEZ = 0b000001, + BGTZ = 0b000111, + BLEZ = 0b000110, + BLTZ = 0b000001, + BNE = 0b000101, + J = 0b000010, + JAL = 0b000011, + LB = 0b100000, + LBU = 0b100100, + LH = 0b100001, + LHU = 0b100101, + LUI = 0b001111, + LW = 0b100011, + LWC1 = 0b110001, + SB = 0b101000, + SH = 0b101001, + SW = 0b101011, + SWC1 = 0b111001, + TRAP = 0b011010 +}; + +enum Function { + ADD = 0b100000, + ADDU = 0b100001, + AND = 0b100100, + DIV = 0b011010, + DIVU = 0b011011, + MULT = 0b011000, + MULTU = 0b011001, + NOR = 0b100111, + OR = 0b100101, + SLL = 0b000000, + SLLV = 0b000100, + SRA = 0b000011, + SRAV = 0b000111, + SRL = 0b000010, + SRLV = 0b000110, + SUB = 0b100010, + SUBU = 0b100011, + XOR = 0b100110, + SLT = 0b101010, + SLTU = 0b101001, + JALR = 0b001001, + JR = 0b001000, + MFHI = 0b010000, + MFLO = 0b010010, + MTHI = 0b010001, + MTLO = 0b010011, + BREAK = 0b001101, + SYSCALL = 0b001100 +}; + +} // namespace MIPSISA + +namespace MIPSABI { +// MIPS ELF info +// Elf flag masks +enum MIPSElfFlags { NOREORDER = 0b1, PIC = 0b10, CPIC = 0b100, ARCH = 0b0 }; +extern const std::map ELFFlagStrings; + +enum SysCall { + None = 0, + PrintInt = 1, + PrintFloat = 2, + PrintDouble = 3, + PrintStr = 4, + ReadInt = 5, + ReadFloat = 6, + ReadDouble = 7, + ReadString = 8, + Sbrk = 9, + Exit = 10, + PrintChar = 11, + ReadChar = 12, + Open = 13, + Read = 14, + Write = 15, + Close = 16, + Exit2 = 17, + Time = 30, + MIDIout = 31, + Sleep = 32, + MIDIoutSynchronous = 33, + PrintIntHex = 34, + PrintIntBinary = 35, + PrintIntUnsigned = 36, + SetSeed = 40, + RandomInt = 41, + RandomIntRange = 42, + RandomFloat = 43, + RandomDouble = 44, + ConfirmDialog = 50, + InputDialogInt = 51, + InputDialogFloat = 52, + InputDialogDouble = 53, + InutDialogString = 54, + MessageDialog = 55, + MessageDialogInt = 56, + MessageDialogFloat = 57, + MessageDialogDouble = 58, + MessageDialogString = 59 + +}; + +} // namespace MIPSABI + +class MIPSISAInfoBase : public ISAInfoBase { +public: + unsigned int regCnt() const override { return 34; } + QString regName(unsigned i) const override { + return (MIPSISA::RegNames.size() > static_cast(i) + ? MIPSISA::RegNames.at(static_cast(i)) + : QString()); + } + QString regAlias(unsigned i) const override { + return MIPSISA::RegAliases.size() > static_cast(i) + ? MIPSISA::RegAliases.at(static_cast(i)) + : QString(); + } + QString regInfo(unsigned i) const override { + return MIPSISA::RegDescs.size() > static_cast(i) + ? MIPSISA::RegDescs.at(static_cast(i)) + : QString(); + } + QString name() const override { return CCmarch().toUpper(); } + bool regIsReadOnly(unsigned i) const override { return i == 0; } + int spReg() const override { return 29; } + int gpReg() const override { return 28; } + int syscallReg() const override { return 2; } + unsigned instrBits() const override { return 32; } + unsigned elfMachineId() const override { return EM_MIPS; } + unsigned int regNumber(const QString ®, bool &success) const override { + QString regRes = reg; + success = true; + if (reg[0] != '$') { + success = false; + return 0; + } + + QString regNoDollar = regRes.remove('$'); + + if (MIPSISA::RegNames.count(reg) != 0) { + regRes.remove('$'); + return regRes.toInt(&success, 10); + } else if (int idx = MIPSISA::RegAliases.indexOf(regNoDollar); idx != -1) { + return idx; + } + success = false; + return 0; + } + virtual int syscallArgReg(unsigned argIdx) const override { + assert(argIdx < 2 && "MIPS only implements argument registers a0-a7"); + return argIdx + 4; + } + + QString elfSupportsFlags(unsigned flags) const override { + if (flags == 0) + return QString(); + for (const auto &flag : MIPSABI::ELFFlagStrings) + flags &= ~flag.first; + + if (flags != 0) { + return "ELF flag '0b" + QString::number(flags, 2) + "' unsupported"; + } + return QString(); + } + + const QStringList &supportedExtensions() const override { + return m_supportedExtensions; + } + const QStringList &enabledExtensions() const override { + return m_enabledExtensions; + } + QString extensionDescription(const QString &ext) const override { return ""; } + +protected: + QStringList m_enabledExtensions; + QStringList m_supportedExtensions = {""}; +}; + +} // namespace Ripes