###### 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]`**

:::
## 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.

* Therefore, we start to learn more about the code relate to this part.
:::
### Version 1
:::info

* 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`**.

**Author's answer:**

:::
### 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:

:::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)

#### 2021/1/11 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-757637147)


#### 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.




#### 2021/1/13 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-759268548)


#### 2021/1/15 - [Link](https://github.com/mortbopet/Ripes/pull/68)
#### **Pull Request**

#### 2021/1/18 - [Link](https://github.com/mortbopet/Ripes/issues/17#issuecomment-759268548)

### **Pull request**
