###### tags: `108-1_RISC-V` 柏廷 :https://hackmd.io/RIH5iX2cSAGazeXDPS6-mg?both # 109-1 Computer Architecture Final Project #### Outline [TOC] # Final Project :::info Contribute to Ripes: pick up pending issues, work on them, and finally send pull request(s). ::: __Take reference from mortbopet/[Ripes](https://github.com/mortbopet/Ripes)__g ## The problem to be solved :::info For instance, if a user tries to write **```jalr x0 0 (x1)```** the tooltip should also state that **`jalr`** has the format **`jalr [rd][rs][imm]`** ![](https://i.imgur.com/GRkomG2.png) ::: ## Pre-work :::success * Get the Ripes source code * Check the __Cmake__ and __Qt__ environment setting ```shell= $ git clone --recursive https://github.com/mortbopet/Ripes.git $ sudo apt-get install cmake $ sudo apt-get install qt5-default $ sudo apt-get install qttools5-dev $ sudo apt-get install qttools5-dev-tools $ sudo apt-get install qtmultimedia5-dev $ sudo apt-get install libqt5svg5-dev $ sudo apt-get install libqt5webkit5-dev $ sudo apt-get install libqt5charts5-dev ``` * Generate the Make files with Cmake, follow the below command * build ```shell= $ cmake . $ make ``` :::warning * Using the below instruction if the system can not find the CXX compiler identification: ``` sudo apt-get update sudo apt-get install -y build-essential ``` ::: ## Updating and Modifying ### Breakthrough :::success * The author already programmed the tooltip which showed some hint about the syntax error. ![](https://i.imgur.com/i0xBnsk.png) * Therefore, we start to learn more about the code relate to this part. ::: ### Version 1 :::info ![](https://i.imgur.com/w4nXx11.png) * Basing on the Table above, we infer that our work will relate to **Register(rd, rs1, rs2)** and **Immediate(imm)**. So we start to summarize these instruction's type referncing to **[RISC-V card(link)](https://github.com/jameslzhu/riscv-card/blob/master/riscv-card.pdf)**: | Type | Form | | | ------- | ------------------------ | ---------------------------------------------------- | | R-type | [rd], [rs1], [rs2] | add, sub, xor, or, and, sll, srl, sra, sltu | | | | mul, mulh, mulsu, mulu, div, divu, rem, remu | | I-type | [rd], [rs1], [imm] | addi, xori, ori, andi, slli, srli, srai, slti, sltiu | | | [dst], [base], [offset] | lb, lh, lw, lhu | | S-type | [rd], [rs1], [imm] | sb, sw, sh | | SB-type | [rd], [rs1], [imm] | beq, bne, blt, bge, bltu, bgeu | | U-type | [rd], [imm] | lui, auipc | | UJ-type | [rd], [imm] | jal | | | [rd], [rs1], [imm] | jalr | * After tracing the code, we figure out the function that we want to modify is defined in [**instruction.h**(line:***`293~300`***)](https://github.com/mortbopet/Ripes/blob/assembler/src/assembler/instruction.h#L293). ```cpp= AssembleRes assemble (const Assembler::TokenizedSrcLine& line) const { if (line.tokens.length() != m_expectedTokens) { return Assembler::Error(line.sourceLine, "Instruction '" + m_opcode.name + Hint + "' expects " + QString::number(m_expectedTokens - 1) + " arguments, but got " + QString::number(line.tokens.length() - 1)); } return m_assembler(this, line); } ``` * First, we try to add some if statement into the function to test whether function worked or not. * The first modify version of tooltip determination is written as the code below: :::spoiler ```cpp= AssembleRes assemble(const Assembler::TokenizedSrcLine& line) const { if (line.tokens.length() != m_expectedTokens) { //***************************************************************************** QString OpcodeType = QString(); //****************** R Format ****************** if ( m_opcode.name == "add" || m_opcode.name == "sub" || m_opcode.name == "xor" || m_opcode.name == "or" || m_opcode.name == "and" || m_opcode.name == "sll" || m_opcode.name == "srl" || m_opcode.name == "sra" || m_opcode.name == "slt" || m_opcode.name == "sltu"|| m_opcode.name == "mul" || m_opcode.name == "mulh"|| m_opcode.name == "mulsu" || m_opcode.name == "mulu"|| m_opcode.name == "div" || m_opcode.name == "divu"|| m_opcode.name == "rem" || m_opcode.name == "remu"){ OpcodeType = "[rd], [rs1], [rs2]"; } //****************** I Format form 1 ****************** if ( m_opcode.name == "addi" || m_opcode.name == "xori" || m_opcode.name == "ori" || m_opcode.name == "andi" || m_opcode.name == "slli" || m_opcode.name == "srli" || m_opcode.name == "srai" || m_opcode.name == "slti" || m_opcode.name == "sltiu"){ OpcodeType = "[rd], [rs1], [imm(11:0)]"; } //****************** I Format form 2 ****************** if ( m_opcode.name == "lb" || m_opcode.name == "lh" || m_opcode.name == "lw" || m_opcode.name == "lbu" || m_opcode.name == "lhu"){ OpcodeType = "[dst], [base], [offset(11:0)]"; } //****************** S Type Format ****************** if ( m_opcode.name == "sb" || m_opcode.name == "sh" || m_opcode.name == "sw" ){ OpcodeType = "[rd], [imm] ([r1])"; } //****************** SB Type Format ****************** if ( m_opcode.name == "beq" || m_opcode.name == "bne" || m_opcode.name == "blt" || m_opcode.name == "bge" || m_opcode.name == "bltu" || m_opcode.name == "bgeu"){ OpcodeType = "[rd], [rs1], [imm(11:0)]"; } //****************** U Type Format ****************** if ( m_opcode.name == "lui" || m_opcode.name == "auipc" ){ OpcodeType = "[rd], [imm(31:12)]"; } //****************** UJ Type Format ****************** if ( m_opcode.name == "jal"){ OpcodeType = "[rd], [imm(31:12)]"; } if ( m_opcode.name == "jalr"){ OpcodeType = "[rd], [rs], [imm]"; } return Assembler::Error(line.sourceLine, "" + m_opcode.name + " " + OpcodeType + ", expects " + QString::number(m_expectedTokens - 1) + " arguments, but got " + QString::number(line.tokens.length() - 1)); } return m_assembler(this, line); } ``` ::: ### Version 2 :::success Follow the author opinion, we use **dynamic_cast** to change the parameters' type. ``` dynamic_cast < type-id > ( expression ) ``` Instructions are defined in **rv32i_assembler.h**. ```cpp= #define BType(name, funct3) 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)})) ``` And in **instruction.h** all the structs inherit **Field**. ```cpp= struct Opcode : public Field{ ... } struct Reg : public Field{ ... } struct Imm : public Field{ ... } ``` And we could get the information at **m_field** which type is ``` std::vector<std::shared_ptr<Field>> m_fields; ``` Then we use **dynamic_cast** to get what we want ``` dynamic_cast<Imm*>(m_fields[i].get()) dynamic_cast<Reg*>(m_fields[i].get()) ``` Final add parameters at the instruction definition for determining the type (rd, rs1, and rs2) in **rv32i_assembler.cpp**. Beside, we also add some code to represent our desired (Reg or Imm) in **instruction.h**. ```cpp= AssembleRes assemble (const Assembler::TokenizedSrcLine& line) const { QString Hint = ""; for(int i = 0; i < (m_expectedTokens-1); i++){ //Imm if(dynamic_cast<Imm*>(m_fields[i].get())) Hint = Hint + " [Imm]"; //Reg else{ Reg* regField = dynamic_cast<Reg*>(m_fields[i].get()); if(regField->regsd == Reg::Regsd::rs1) Hint = Hint + " [rs1]"; else if(regField->regsd == Reg::Regsd::rs2) Hint = Hint + " [rs2]"; else Hint = Hint + " [rd]"; } } if (line.tokens.length() != m_expectedTokens) { return Assembler::Error(line.sourceLine, "Instruction '" + m_opcode.name + Hint + "' expects " + QString::number(m_expectedTokens - 1) + " arguments, but got " + QString::number(line.tokens.length() - 1)); } return m_assembler(this, line); } ``` * This is the `.diff` file of version 2 comparing with the original code in the assembler branch: ::: spoiler ```diff= diff --git a/external/VSRTL b/external/VSRTL --- a/external/VSRTL +++ b/external/VSRTL @@ -1 +1 @@ -Subproject commit efc10897e5bc9b3e4c72e4e7d34766391c051c49 +Subproject commit efc10897e5bc9b3e4c72e4e7d34766391c051c49-dirty diff --git a/src/assembler/instruction.h b/src/assembler/instruction.h index b734f03..f67e8b4 100644 --- a/src/assembler/instruction.h +++ b/src/assembler/instruction.h @@ -103,14 +103,15 @@ struct Opcode : public Field { }; struct Reg : public Field { + enum class Regsd { rd, rs1, rs2 }; /** * @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(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range) : Field(tokenIndex), m_range(range), m_isa(isa) {} - Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop) - : Field(tokenIndex), m_range({_start, _stop}), m_isa(isa) {} + Reg(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range, Regsd _regsd) : Field(tokenIndex), m_range(range), m_isa(isa), regsd(_regsd) {} + Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop, Regsd _regsd) + : Field(tokenIndex), m_range({_start, _stop}), m_isa(isa), regsd(_regsd) {} std::optional<Assembler::Error> apply(const Assembler::TokenizedSrcLine& line, uint32_t& instruction, FieldLinkRequest&) const override { bool success; @@ -135,6 +136,7 @@ struct Reg : public Field { const BitRange m_range; const ISAInfoBase* m_isa; + const Regsd regsd; }; struct ImmPart { @@ -289,14 +291,51 @@ public: } AssembleRes assemble(const Assembler::TokenizedSrcLine& line) const { + QString Hint = ""; + + for(int i = 0; i < (m_expectedTokens-1); i++){ + //Imm + if(dynamic_cast<Imm*>(m_fields[i].get())) + Hint = Hint + " [Imm]"; + //Reg + else + { + Reg* regField = dynamic_cast<Reg*>(m_fields[i].get()); + + if(regField->regsd == Reg::Regsd::rs1) + Hint = Hint + " [rs1]"; + else if(regField->regsd == Reg::Regsd::rs2) + Hint = Hint + " [rs2]"; + else + Hint = Hint + " [rd]"; + } + } if (line.tokens.length() != m_expectedTokens) { - return Assembler::Error(line.sourceLine, "Instruction '" + m_opcode.name + "' expects " + + return Assembler::Error(line.sourceLine, "Instruction " + m_opcode.name + Hint + " expects " + QString::number(m_expectedTokens - 1) + " arguments, but got " + QString::number(line.tokens.length() - 1)); } return m_assembler(this, line); } + + + DisassembleRes disassemble(const uint32_t instruction, const uint32_t address, const ReverseSymbolMap& symbolMap) const { return m_disassembler(this, instruction, address, symbolMap); diff --git a/src/assembler/pseudoinstruction.h b/src/assembler/pseudoinstruction.h index f1e6c81..99459a9 100644 --- a/src/assembler/pseudoinstruction.h +++ b/src/assembler/pseudoinstruction.h @@ -30,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> reg() { return std::make_shared<Reg>(nullptr, 0, 0, 0); } + static std::shared_ptr<Reg> reg() { return std::make_shared<Reg>(nullptr, 0, 0, 0, Reg::Regsd::rd); } static std::shared_ptr<Imm> imm() { return std::make_shared<Imm>(0, 0, Imm::Repr::Hex, std::vector<ImmPart>{}); } private: diff --git a/src/assembler/rv32i_assembler.cpp b/src/assembler/rv32i_assembler.cpp index b4c750f..a6cc5b0 100644 --- a/src/assembler/rv32i_assembler.cpp +++ b/src/assembler/rv32i_assembler.cpp @@ -41,7 +41,7 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define BType(name, funct3) \ 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<Reg>(isa, 1, 15, 19, Reg::Regsd::rs1), std::make_shared<Reg>(isa, 2, 20, 24, Reg::Regsd::rs2), \ 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)}, \ @@ -50,44 +50,44 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define IType(name, funct3) \ 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<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})})) #define LoadType(name, funct3) \ 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<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 3, 15, 19, Reg::Regsd::rs1), \ std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})})) #define IShiftType(name, funct3, funct7) \ 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<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ std::make_shared<Imm>(3, 5, Imm::Repr::Unsigned, std::vector{ImmPart(0, 20, 24)})})) #define RType(name, funct3, funct7) \ 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)})) + {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ + std::make_shared<Reg>(isa, 3, 20, 24, Reg::Regsd::rs2)})) #define SType(name, funct3) \ std::shared_ptr<Instruction>(new Instruction( \ Opcode(name, {OpPart(0b0100011, 0, 6), OpPart(funct3, 12, 14)}), \ - {std::make_shared<Reg>(isa, 3, 15, 19), \ + {std::make_shared<Reg>(isa, 3, 15, 19, Reg::Regsd::rs1), \ std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(5, 25, 31), ImmPart(0, 7, 11)}), \ - std::make_shared<Reg>(isa, 1, 20, 24)})) + std::make_shared<Reg>(isa, 1, 20, 24, Reg::Regsd::rs2)})) #define UType(name, opcode) \ std::shared_ptr<Instruction>( \ new Instruction(Opcode(name, {OpPart(opcode, 0, 6)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11), \ + {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), \ std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)})})) #define JType(name, opcode) \ std::shared_ptr<Instruction>(new Instruction( \ Opcode(name, {OpPart(opcode, 0, 6)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11), \ + {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), \ std::make_shared<Imm>( \ 2, 21, Imm::Repr::Signed, \ std::vector{ImmPart(20, 31, 31), ImmPart(12, 12, 19), ImmPart(11, 20, 20), ImmPart(1, 21, 30)}, \ @@ -96,7 +96,7 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define JALRType(name) \ 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<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})})) #define RegTok PseudoInstruction::reg() @@ -325,7 +325,7 @@ void RV32I_Assembler::enableExtI(const ISAInfo<ISA::RV32I>* isa, InstrVec& instr auto auipcSymbolModifier = [](uint32_t bareSymbol) { return bareSymbol >> 12; }; 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<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)}, Imm::SymbolType::Absolute, auipcSymbolModifier)}))); ``` ::: ### [Environment Problem in pull request(link)](https://travis-ci.org/github/mortbopet/Ripes/builds/754568916) :::danger **Problem image:** There are some error when the Travis CI testing our code.But according to auther's answer, it because of outdated compiler versions that doesn't fully support **`std::variant`**. ![](https://i.imgur.com/IixTuxx.png) **Author's answer:** ![](https://i.imgur.com/7gyczTn.png) ::: ### Version 3 :::success * According to the author's suggestion, we implemented version 2 with some different parameter type and changing coding style. * Beside that, we also add some instruction to display the [imm]'s bits such as the following picture: ![](https://i.imgur.com/4HOUc8n.png) :::spoiler ```diff= diff --git a/src/assembler/instruction.h b/src/assembler/instruction.h index f67e8b4..643eeb3 100644 --- a/src/assembler/instruction.h +++ b/src/assembler/instruction.h @@ -103,14 +103,16 @@ struct Opcode : public Field { }; struct Reg : public Field { - enum class Regsd { rd, rs1, rs2 }; /** * @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(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range, Regsd _regsd) : Field(tokenIndex), m_range(range), m_isa(isa), regsd(_regsd) {} - Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop, Regsd _regsd) + Reg(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range) : Field(tokenIndex), m_range(range), m_isa(isa) {} + Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop) + : Field(tokenIndex), m_range({_start, _stop}), m_isa(isa) {} + Reg(const ISAInfoBase* isa, unsigned tokenIndex, BitRange range, QString _regsd) : Field(tokenIndex), m_range(range), m_isa(isa), regsd(_regsd) {} + Reg(const ISAInfoBase* isa, unsigned tokenIndex, unsigned _start, unsigned _stop, QString _regsd) : Field(tokenIndex), m_range({_start, _stop}), m_isa(isa), regsd(_regsd) {} std::optional<Assembler::Error> apply(const Assembler::TokenizedSrcLine& line, uint32_t& instruction, FieldLinkRequest&) const override { @@ -136,7 +138,7 @@ struct Reg : public Field { const BitRange m_range; const ISAInfoBase* m_isa; - const Regsd regsd; + const QString regsd = "reg"; }; struct ImmPart { @@ -292,39 +294,14 @@ public: AssembleRes assemble(const Assembler::TokenizedSrcLine& line) const { QString Hint = ""; - for(int i = 0; i < (m_expectedTokens-1); i++){ - //Imm - if(dynamic_cast<Imm*>(m_fields[i].get())) - Hint = Hint + " [Imm]"; - //Reg - else - { - Reg* regField = dynamic_cast<Reg*>(m_fields[i].get()); - - if(regField->regsd == Reg::Regsd::rs1) - Hint = Hint + " [rs1]"; - else if(regField->regsd == Reg::Regsd::rs2) - Hint = Hint + " [rs2]"; - else - Hint = Hint + " [rd]"; + + for(const auto& field : m_fields) { + if(auto* immField = dynamic_cast<Imm*>(field.get())) + Hint = Hint + " [Imm(" + QString::number(immField->width) + ")]"; + else if (auto* regField = dynamic_cast<Reg*>(field.get())) { + Hint = Hint + " [" + regField->regsd +"]"; } } if (line.tokens.length() != m_expectedTokens) { return Assembler::Error(line.sourceLine, "Instruction " + m_opcode.name + Hint + " expects " + QString::number(m_expectedTokens - 1) + diff --git a/src/assembler/pseudoinstruction.h b/src/assembler/pseudoinstruction.h index 99459a9..9f3a847 100644 --- a/src/assembler/pseudoinstruction.h +++ b/src/assembler/pseudoinstruction.h @@ -30,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> reg() { return std::make_shared<Reg>(nullptr, 0, 0, 0, Reg::Regsd::rd); } + static std::shared_ptr<Reg> reg() { return std::make_shared<Reg>(nullptr, 0, 0, 0, "rd"); } static std::shared_ptr<Imm> imm() { return std::make_shared<Imm>(0, 0, Imm::Repr::Hex, std::vector<ImmPart>{}); } private: diff --git a/src/assembler/rv32i_assembler.cpp b/src/assembler/rv32i_assembler.cpp index a6cc5b0..af7f7a3 100644 --- a/src/assembler/rv32i_assembler.cpp +++ b/src/assembler/rv32i_assembler.cpp @@ -41,7 +41,7 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define BType(name, funct3) \ std::shared_ptr<Instruction>(new Instruction( \ Opcode(name, {OpPart(0b1100011, 0, 6), OpPart(funct3, 12, 14)}), \ - {std::make_shared<Reg>(isa, 1, 15, 19, Reg::Regsd::rs1), std::make_shared<Reg>(isa, 2, 20, 24, Reg::Regsd::rs2), \ + {std::make_shared<Reg>(isa, 1, 15, 19, "rs1"), std::make_shared<Reg>(isa, 2, 20, 24, "rs2"), \ 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)}, \ @@ -50,44 +50,44 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define IType(name, funct3) \ std::shared_ptr<Instruction>( \ new Instruction(Opcode(name, {OpPart(0b0010011, 0, 6), OpPart(funct3, 12, 14)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ + {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 2, 15, 19, "rs1"), \ std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})})) #define LoadType(name, funct3) \ std::shared_ptr<Instruction>( \ new Instruction(Opcode(name, {OpPart(0b0000011, 0, 6), OpPart(funct3, 12, 14)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 3, 15, 19, Reg::Regsd::rs1), \ + {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 IShiftType(name, funct3, funct7) \ 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, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ + {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, 24)})})) #define RType(name, funct3, funct7) \ 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, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ - std::make_shared<Reg>(isa, 3, 20, 24, Reg::Regsd::rs2)})) + {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 SType(name, funct3) \ std::shared_ptr<Instruction>(new Instruction( \ Opcode(name, {OpPart(0b0100011, 0, 6), OpPart(funct3, 12, 14)}), \ - {std::make_shared<Reg>(isa, 3, 15, 19, Reg::Regsd::rs1), \ + {std::make_shared<Reg>(isa, 3, 15, 19, "rs1"), \ std::make_shared<Imm>(2, 12, Imm::Repr::Signed, std::vector{ImmPart(5, 25, 31), ImmPart(0, 7, 11)}), \ - std::make_shared<Reg>(isa, 1, 20, 24, Reg::Regsd::rs2)})) + std::make_shared<Reg>(isa, 1, 20, 24, "rs2")})) #define UType(name, opcode) \ std::shared_ptr<Instruction>( \ new Instruction(Opcode(name, {OpPart(opcode, 0, 6)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), \ + {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), \ std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)})})) #define JType(name, opcode) \ std::shared_ptr<Instruction>(new Instruction( \ Opcode(name, {OpPart(opcode, 0, 6)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), \ + {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), \ std::make_shared<Imm>( \ 2, 21, Imm::Repr::Signed, \ std::vector{ImmPart(20, 31, 31), ImmPart(12, 12, 19), ImmPart(11, 20, 20), ImmPart(1, 21, 30)}, \ @@ -96,7 +96,7 @@ RV32I_Assembler::initInstructions(const ISAInfo<ISA::RV32I>* isa) const { #define JALRType(name) \ std::shared_ptr<Instruction>( \ new Instruction(Opcode(name, {OpPart(0b1100111, 0, 6), OpPart(0b000, 12, 14)}), \ - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), std::make_shared<Reg>(isa, 2, 15, 19, Reg::Regsd::rs1), \ + {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Reg>(isa, 2, 15, 19, "rs1"), \ std::make_shared<Imm>(3, 12, Imm::Repr::Signed, std::vector{ImmPart(0, 20, 31)})})) #define RegTok PseudoInstruction::reg() @@ -325,7 +325,7 @@ void RV32I_Assembler::enableExtI(const ISAInfo<ISA::RV32I>* isa, InstrVec& instr auto auipcSymbolModifier = [](uint32_t bareSymbol) { return bareSymbol >> 12; }; instructions.push_back(std::shared_ptr<Instruction>( new Instruction(Opcode("auipc", {OpPart(0b0010111, 0, 6)}), - {std::make_shared<Reg>(isa, 1, 7, 11, Reg::Regsd::rd), + {std::make_shared<Reg>(isa, 1, 7, 11, "rd"), std::make_shared<Imm>(2, 32, Imm::Repr::Hex, std::vector{ImmPart(0, 12, 31)}, Imm::SymbolType::Absolute, auipcSymbolModifier)}))); ``` ::: ### Code flow :::info #### Signal and Slot * Flow chart | Order\Object | Sender | Signal(func) | Receiver | Slot(func) | |:----- |:---------------- |:----------------------------- |:---------------- |:----------------------------- | | 1. | this->document() | QTextDocument::contentsChange | N/A | m_changeTimer->start() | | 2. | m_changeTimer | &QTimer::timeout | this(codeEditor) | &CodeEditor::timedTextChanged | | 3. | m_ui->codeEditor | &CodeEditor::timedTextChanged | this(edittab) | &EditTab::sourceCodeChanged | * Connect function * codeeditor.cpp ```cpp= void CodeEditor::setupChangedTimer() { ... m_changeTimer->setInterval(500); m_changeTimer->setSingleShot(true); ... ... ... connect(this->document(), &QTextDocument::contentsChange, [this](int, int, int) { m_changeTimer->start(); }); connect(m_changeTimer, &QTimer::timeout, this, &CodeEditor::timedTextChanged); } ``` * edittab.cpp ```cpp= EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_ui(new Ui::EditTab) { ... connect(m_ui->codeEditor, &CodeEditor::timedTextChanged, this, &EditTab::sourceCodeChanged); ... } ``` * Description 1. While the file is being edited, the timer is set to start at 0 (The timer is reset each time a change occurs). 2. If no changes on the editor for a while(Timer interval is 500[0.5s]), timeout will trigger function timedTextChanged. 3. Finally, timedTextChanged is just an interface and notify the edittab, Edittab will start at function sourceCodeChanged(). 4. Then there's a series of __syntax check__. #### Syntax check * After getting assembly, next check whether the syntax and format are correct. * Put the assembly line by line into the QStringList ```cpp= AssembleResult assembleRaw(const QString& program) const { const auto programLines = program.split(QRegExp("[\r\n]")); return assemble(programLines); } ``` * Through the runPass(pass0, pass1, pass2, pass3), processing each line content of assembly, and record syntax or format errors. ```cpp= AssembleResult assemble(const QStringList& programLines) const override { AssembleResult result; // Per default, emit to .text until otherwise specified setCurrentSegment(".text"); // Tokenize each source line and separate symbol from remainder of tokens runPass(tokenizedLines, SourceProgram, pass0, programLines); // Pseudo instruction expansion runPass(expandedLines, SourceProgram, pass1, tokenizedLines); /** Assemble. During assembly, we generate: * - symbolMap: Recoding the offset locations in the program of lines adorned with symbols * - linkageMap: Recording offsets of instructions which require linkage with symbols */ SymbolMap symbolMap; LinkRequests needsLinkage; runPass(program, Program, pass2, expandedLines, symbolMap, needsLinkage); // Symbol linkage runPass(unused, NoPassResult, pass3, program, symbolMap, needsLinkage); result.program = program; return result; } ``` * runPass Architecture * pass0 * tokenize * splitCommentFromLine * splitSymbolsFromLine * pass1 * expandPseudoOp * pass2 * assembleDirective * assembleInstruction * pass3 ::: ### comment,reply and pull request #### 2018/10/8 - [Link](https://github.com/mortbopet/Ripes/issues/17#issue-367766297) ![](https://i.imgur.com/e0ZuRQm.png) #### 2021/1/11 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-757637147) ![](https://i.imgur.com/YCNzWpF.png) ![](https://i.imgur.com/zOzVVzS.png) #### 2021/1/12 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-758355003) Because everytime make file have spend so much time. Therefore, we manage to ask the author about the method for debugging. ![](https://i.imgur.com/6hilyPN.png) ![](https://i.imgur.com/IfLH5Cj.png) ![](https://i.imgur.com/Tl8EMHb.png) ![](https://i.imgur.com/ad1VH2j.png) #### 2021/1/13 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-759268548) ![](https://i.imgur.com/NiLKDXO.png) ![](https://i.imgur.com/aiageDN.png) #### 2021/1/15 - [Link](https://github.com/mortbopet/Ripes/pull/68) #### **Pull Request** ![](https://i.imgur.com/L8OEqLR.png) #### 2021/1/18 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-759268548) ![](https://i.imgur.com/Y6OWlf1.png) ### **Pull request** ![](https://i.imgur.com/R45x2BJ.png)