owned this note
owned this note
Published
Linked with GitHub
# Rework Assignment 3 : SoftCPU
###### tags: `Computer Architecture` `Term Project` `RISC-V`
contributed by <`mingjii`>
## Set up the Environment
#### Prerequisites
- Use pre-built GNU Toolchain via [xPack GNU RISC-V Embedded GCC](https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/), release [versions](https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/)
```
$ mkdir /tmp && cd /tmp
$ wget https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v10.2.0-1.2/xpack-riscv-none-embed-gcc-10.2.0-1.2-linux-x64.tar.gz
$ tar xvf /tmp/xpack-riscv-none-embed-gcc-10.2.0-1.2-linux-x64.tar.gz
$ sudo chmod -R -w /tmp/xpack-riscv-none-embed-gcc-10.2.0-1.2/bin/riscv-none-embed-gcc-10.2.0
```
- Install required packages
```
$ sudo apt install build-essential ccache
$ sudo apt install lcov
$ sudo apt install gtkwave
```
#### Clone the Simulator
- Clone from [SRV32](https://github.com/sysprog21/srv32)
```
$ git clone https://github.com/sysprog21/srv32.git
$ cd srv32
```
- Edit the file `Makefile`, and set the riscv path to `CROSS_COMPILE` at the second line
```
export CROSS_COMPILE = /tmp/xpack-riscv-none-embed-gcc-10.2.0-1.2/bin/riscv-none-embed-
```
- Run
```
$ make all
```
## Requirements 1 : Run on both simulator in [srv32](https://github.com/sysprog21/srv32)
#### C code in [Assignment 1](/_gFpDYgLQg6YVvTMU2zy-Q)
```c
#include <stdio.h>
volatile int hammingDistance(volatile int x, volatile int y)
{
// XOR operation will output 1 if two bit are different.
volatile int cmpResult = x ^ y;
// Counting the bits of the compared result.
volatile int dis = 0;
while (cmpResult)
{
if (cmpResult & 1)
{
++dis; // If the right most bit is 1, result value + 1
}
cmpResult >>= 1; // Shift right one bit on every loop.
}
return dis;
}
volatile int main()
{
// Take x = 1, y = 4 for example
volatile int x = 1, y = 4;
// Print the result
printf("The Hamming Distance is %d\n", hammingDistance(x, y));
return 0;
}
```
#### RTL SIM Result
```
Excuting 1629 instructions, 2127 cycles, 1.305 CPI
Program terminate
- ../rtl/../testbench/testbench.v:418: Verilog $finish
Simulation statistics
=====================
Simulation time : 0.016 s
Simulation cycles: 2138
Simulation speed : 0.133625 MHz
```
#### ISS Result
```
Excuting 1629 instructions, 2127 cycles, 1.306 CPI
Program terminate
Simulation statistics
=====================
Simulation time : 0.000 s
Simulation cycles: 2127
Simulation speed : 5.028 MHz
```
## Requirements 2 : Analyze Datapath
### Disassembly Code (format: elf32-littleriscv)
This is the Disassembly Code from obove program, in `sw` directory.
:::spoiler
```
0000009c <main>:
9c: fe010113 addi sp,sp,-32
a0: 00100793 li a5,1
a4: 00f12023 sw a5,0(sp)
a8: 00400793 li a5,4
ac: 00f12223 sw a5,4(sp)
b0: 00012783 lw a5,0(sp)
b4: 00412703 lw a4,4(sp)
b8: 00112e23 sw ra,28(sp)
bc: 00e7c7b3 xor a5,a5,a4
c0: 00f12423 sw a5,8(sp)
c4: 00012623 sw zero,12(sp)
c8: 00812783 lw a5,8(sp)
cc: 02078863 beqz a5,fc <main+0x60>
d0: 00812783 lw a5,8(sp)
d4: 0017f793 andi a5,a5,1
d8: 00078863 beqz a5,e8 <main+0x4c>
dc: 00c12783 lw a5,12(sp)
e0: 00178793 addi a5,a5,1
e4: 00f12623 sw a5,12(sp)
e8: 00812783 lw a5,8(sp)
ec: 4017d793 srai a5,a5,0x1
f0: 00f12423 sw a5,8(sp)
f4: 00812783 lw a5,8(sp)
f8: fc079ce3 bnez a5,d0 <main+0x34>
fc: 00c12583 lw a1,12(sp)
100: 00020537 lui a0,0x20
104: 03c50513 addi a0,a0,60 # 2003c <__malloc_trim_threshold+0x4>
108: 054000ef jal ra,15c <printf>
10c: 01c12083 lw ra,28(sp)
110: 00000513 li a0,0
114: 02010113 addi sp,sp,32
118: 00008067 ret
```
:::

### R-type

:::spoiler
#### `xor` For Example
```
bc: 00e7c7b3 xor a5,a5,a4
```
- 
- The address of the instruction is `0x000000bc`
- And its content is `0x00e7c7b3` = `0b 0000000 01110 01111 100 01111 0110011`
- `opcode`: `0110011`
- `function code`: `0000000100`
- `rd`: `01111` = `x15` (a5)
- `rs1`: `01111` = `x15` (a5)
- `rs2`: `01110` = `x14` (a4)
##### IF/ID stage


1. `fetch_pc`: `0x000000bc`
2. Get the address's content from **I-MEM**, `imem_rdata`: `0x00e7c7b3`
3. The content is the instruction execute in pipline, `inst` = `imem_rdata` (`0x00e7c7b3`)
- `is_compressed`: `0`, this is not compressed instruciton.
- `imm`: don't care, **R-type** has no immediate
##### EX stage


1. `ex_src1_sel` : `0x0F`, refer to register `x15`, the content of `x15`: `0x00000001` (`reg_rdata1`)
2. `ex_src2_sel` : `0x0E`, refer to register `x14`, the content of `x14`: `0x00000004` (`reg_rdata2`)
3. `ex_imm`: don't care
- According to `rtl/riscv.v`:
- `alu_op1` = `reg_rdata1` : `0x00000001`
- `alu_op2` = `reg_rdata2` : `0x00000004`
```
assign alu_op1[31: 0] = reg_rdata1;
assign alu_op2[31: 0] = (ex_imm_sel) ? ex_imm : reg_rdata2;
```
4. Execute `xor` operation: `alu_op1 XOR alu_op2`
- $1\oplus 4 = 5$
- `ex_result`: `0x0000005`
##### WB stage


1. **R-type** instruction need to write back to register, `wb_alu2reg`: `1`
2. Write the result to destinate register
- `wb_dst_sel` : `0x0F`, refer to register `x15`
- `wb_result`: `0x00000005`
- the content of `x15` will be set to `0x00000005` at next clock
3. However, the instruction in **EX** stage ( `sw a5,24(sp)` ) also access the register `a5 (x15)` at same clock
- Have to forward `wb_result` to `reg_rdata2`, while `x15` hasn't set the right value `0x00000005`
|Instruction|cycle 1|c2|c3|c4|
|-|-|-|-|-|
|`xor a5,a5,a4`|IF/ID|EX|WB $\searrow$||
|`sw a5,24(sp)`||IF/ID|EX$\swarrow$|WB|
:::
### I-type

:::spoiler
#### `addi` For Example
```
d4: 0017f793 andi a5,a5,1
```
- 
- The address of the instruction is `0x000000d4`
- And its content is `0017f793` = `0b 000000000001 01111 111 01111 0010011`
- `opcode`: `0010011`
- `function code`: `111`
- `rd`: `01111` = `x15` (a5)
- `rs1`: `01111` = `x15` (a5)
- `immediate`: `0b000000000001`
##### IF/ID stage


1. `fetch_pc`: `0x000000d4`
2. Get the address's content from **I-MEM**, `imem_rdata`: `0x0017f793`
3. The content is the instruction execute in pipline, `inst` = `imem_rdata` (`0x0017f793`)
- `is_compressed`: `0`, this is not compressed instruciton.
- `imm`: `0x00000001`
##### EX stage


1. `ex_src1_sel` : `0x0F`, refer to register `x15`, the content of `x15`: `0x00000005` (`reg_rdata1`)
2. `ex_src2_sel` : don't care
3. `ex_imm` = `imm` : `0x00000001`
- According to `rtl/riscv.v`:
- `alu_op1` = `reg_rdata1` : `0x00000005`
- `alu_op2` = `ex_imm` : `0x00000001`
```
assign alu_op1[31: 0] = reg_rdata1;
assign alu_op2[31: 0] = (ex_imm_sel) ? ex_imm : reg_rdata2;
```
4. Execute `and` operation: `alu_op1 and alu_op2`
- $101_2 \cdot 001_2 = 001_2$
- `ex_result`: `0x0000001`
##### WB stage


1. `andi` instruction need to write back to register, `wb_alu2reg`: `1`
2. Write the result to destinate register
- `wb_dst_sel` : `0x0F`, refer to register `x15`
- `wb_result`: `0x00000001`
- the content of `x15` will be set to `0x00000001` at next clock
3. However, the instruction in **EX** stage ( `beqz a5,e8` ) also access the register `a5 (x15)` at same clock
- Have to forward `wb_result` to `reg_rdata1`, while `x15` hasn't set the right value `0x00000005`
|Instruction|cycle 1|c2|c3|c4|
|-|-|-|-|-|
|`andi a5,a5,1`|IF/ID|EX|WB $\searrow$||
|`beqz a5,e8`||IF/ID|EX$\swarrow$|WB|
:::
### S-type

::: spoiler
#### `sw` For Example
```
ac: 00f12223 sw a5,4(sp)
```
- 
- The address of the instruction is `0x000000ac`
- And its content is `00f12223` = `0b 0000000 01111 00010 010 00100 0100011`
- `opcode`: `0100011`
- `function code`: `010`
- `rs1`: `00010` = `x2` (sp)
- `rs2`: `01111` = `x15` (a5)
- `immediate`: `0b 0000000 00100`
##### IF/ID stage


1. `fetch_pc`: `0x000000ac`
2. Get the address's content from **I-MEM**, `imem_rdata`: `0x00f12223`
3. The content is the instruction execute in pipline, `inst` = `imem_rdata` (`0x00f12223`)
- `is_compressed`: `0`, this is not compressed instruciton.
- `imm`: `0b 0000000 00100`
##### EX stage


1. `ex_src1_sel` : `0x02`, refer to register `x2`, the content of `x2`: `0x00003FFE0` (`reg_rdata1`)
2. `ex_src1_se2` : `0x0F`, refer to register `x15`, the content of `x15`: `0x00000004` (`reg_rdata2`)
3. `ex_imm`: `0x00000004`
- According to `rtl/riscv.v`:
- `alu_op1` = `reg_rdata1` : `0x00003FFE0`
- `alu_op2` = `ex_imm` : `0x00000004`
```
assign alu_op1[31: 0] = reg_rdata1;
assign alu_op2[31: 0] = (ex_imm_sel) ? ex_imm : reg_rdata2;
```
4. Execute `add` operation: `alu_op1 add alu_op2`
- `0x00003FFE0 + 0x00000004 = 0x00003FFE4`
- `ex_memaddr`: `0x00003FFE4`
5. `ex_memwr` = `1`
##### WB stage


1. `sw` instruction don't need to write back to register, `wb_alu2reg`: `0`
2. `wb_dst_sel`: don't care, `wb_result`: don't care
3. Write the value to the specific address at **D-MEM**
- address (`wb_waddr` = `ex_memaddr`): `0x0003FFE4`
- value (`wb_wdata` = `reg_rdata2`): `0x00000004`
:::
### B-type

::: spoiler
#### `BEQ` For Example
```
f8: fc079ce3 bnez a5,d0
```
- 
- The address of the instruction is `0x000000f8`
- And its content is `fc079ce3` = `0b 1111110 00000 01111 001 11001 1100011`
- `opcode`: `1100011`
- `function code`: `000`
- `rs1`: `01111` = `x15` (a5)
- `rs2`: `00000` = `x0` (zero)
- `immediate`: `0b 1111111011000` = `0xFFFFFD8`
##### IF/ID stage


1. `fetch_pc`: `0x000000f8`
2. Get the address's content from **I-MEM**, `imem_rdata`: `0xfc079ce3`
3. The content is the instruction execute in pipline, `inst` = `imem_rdata` (`0xfc079ce3`)
- `is_compressed`: `0`, this is not compressed instruciton.
- `imm`: `0xFFFFFD8`
##### EX stage


1. `ex_src1_sel` : `0x0F`, refer to register `x15`, the content of `x15`: `0x000000002` (`reg_rdata1`)
2. `ex_src1_se2` : `0x00`, refer to register `x0`, the content of `x0`: always `0` (`reg_rdata2`)
3. `ex_imm`: `0xFFFFFD8`
```
assign alu_op1[31: 0] = reg_rdata1;
assign alu_op2[31: 0] = (ex_imm_sel) ? ex_imm : reg_rdata2;
assign result_subs[32: 0] = {alu_op1[31], alu_op1} - {alu_op2[31], alu_op2};
```
- According to `rtl/riscv.v`:
- `alu_op1` = `reg_rdata1` : `0x00000002`
- `alu_op2` = `reg_rdata2` : `0x00000000`
- `result_subs` = `0x00000002`
```
OP_BNE : begin
next_pc = (result_subs[32: 0] != 'd0) ?
ex_pc + ex_imm : fetch_pc + `IF_NEXT_PC;
if (result_subs[32: 0] == 'd0) branch_taken = 1'b0;
end
```
4. `next_pc` = `ex_pc` + `ex_imm` = `0x000000f8` + `0xFFFFFD8` = `0x000000D0`
- `branch_taken` = `ex_branch` = `1`
:::
## Reference
[Lab3](https://hackmd.io/wGBlfjb0RiOT1XLneqP9Kw?view): srv32 - RISCV RV32IM Soft CPU
[Assignment3](https://hackmd.io/@sysprog/2021-arch-homework3): SoftCPU