owned this note
owned this note
Published
Linked with GitHub
# 計算機組織_RISCV 實作
###### tags: `Homework` `Computer Organization`,`CPU`,`Sophomore`
[TOC]
## 簡介
利用Verilog實作出RISC-V指令,每年的東西可能稍稍會有不一樣,不過大同小異啦。
### 名詞解釋
若你跟我一樣大腦一開始轉不過來,甚至看不懂縮寫,可以看一下這邊。阿若你都
知道功課在說啥,就跳過這裡吧~(下面廢話有點多)
- RISC-V : 類似MIPS但是是另一個「指令集架構」,有些指令在MIPS中會以不一樣的縮寫呈現。
- IM : Instruction Memory,儲存所有的指令,只要告訴他我需要資料,位置在哪裡,他就會回傳一個32-bit的指令
- DM : Data Memory,就是你的 main memory,而且可以讀跟寫,只要告訴他Data位置與任務(讀或寫)他就會作相對應的動作。
- Mem : Memory
- imm : immediate 常數
- addr: address
- PC : Program Counter(就是指 instr_addr)
### 作業要求

就是除了 DM、IM 以外的東西,都要自己實作。QAQ(PC、register管理、instrucion實作)
但其實我也沒有特別管他的線路,而且我都寫在同一個module裡,硬刻出來就對了!!
### 檔案架構
總共有17的檔案
:::success
**simulate前,只有下面編號1~4的檔案要compile**
:::
1. **`CPU.v`** : ***唯一要實作的部分,其他檔案都不會動到!!!***
2. **`SRAM.v`**: 一檔包辦所有的IM跟DM
3. **`top.v`**:將 CPU 與 SRAM 連接起來
4. **`top_tb.v`**: **執行程式**、並且做有沒有 pass 判斷的檔案(**是simulate這個檔案喔~不要弄錯檔案**),而且波形圖也是從這個檔案 add wave,add 錯會看不到波形
7. **`setup.s`**: 式最開始要先執行的部分,會初始化所有 register 和 memory 區段
8. **`main.s`**:程式真正開始測試所有指令的部分(每行後面還會附註 register 的值)
6. **`golden.hex`**: 答案小本本
7. **`main.log`**: `setup.s`、`main.s`中所有的指令(但後面沒有附註 register 的值)
9. **`main0.hex` `main1.hex` `main2.hex` `main3.hex`**:這四個檔就是setup.s和main.s翻譯成verilog可以用的指令 (他把setup.s包在裡面一起編)
其他檔案不太確定要幹嘛,但不知道也不會怎樣。
### `CPU.v`
因為是實作這個,所以只介紹這個檔案內容(雖然他剛拿到實看起來很空)。但是東西還算不少QAQ。
```verilog=
module CPU(
input clk,
input rst,
input [31:0] data_out,
input [31:0] instr_out,
output reg instr_read,
output reg data_read,
output reg [31:0] instr_addr,
output reg [31:0] data_addr,
output reg [3:0] data_write,
output reg [31:0] data_in
);
```
- `clk` : clock 應該不用說甚麼吧 ><
- `rst` : reset 這次是 posedge rst
- `data_out` : 從 DM 拿到的 Data
- `instr_out` : 從 IM 拿到的 Instruction
- `instr_read` : `1` 則是要讀IM,`0` 則是不要讀(`1` 的話,**下一個cycle** `instr_out` 就會給你32-bit指令)
- `instr_addr` : 你要讀的 instruction 位置(地一個指令是在 `0x00000000`)
- `data_read` : `1` 則是要讀DM,`0` 則是不要讀(`1` 的話,**下一個cycle** `data_out` 就會給你 Data)
- `data_write` : 若是 = `4'b0000` 則不會寫入 DM。反之則會寫入 DM
- `data_write[3]` (第1個bit) : 控制 Memory 的 31 ~ 24 bit
- `data_write[2]` (第2個bit) : 控制 Memory 的 23 ~ 16 bit
- `data_write[1]` (第3個bit) : 控制 Memory 的 15 ~ 8 bit
- `data_write[0]` (第4個bit) : 控制 Memory 的 7 ~ 0 bit
> < Example > 若`data_write <= 4'b0011`表示要寫入 Memory 的 15 ~ 0 bit
- `data_in` : 要寫入 Memory 的資料
- `data_addr` : 你要讀或寫的 data 位置
:::danger
- 再次強調若你這個 cycle 向 IM 要了 instrction,<b>下一個 cycle 才會收到喔</b>,DM 也一樣
- Register 是自己管理的喔,自己要建立32個 registers 像是下面一樣
:::
`reg [31:0] register [0:31];`(32-bit的 register 32個)
>`[31:0]`代表有32個bits `[0:31]`代表32個register
### Register
方便你debug時對照
| Register | Name | 備註 |
| -------- | ----------- |----- |
| x0 |`$Zero` | 要一直保持`0x00000000`喔
| x1 |`$ra` | `jalr`如果跳位置對,但是`ret`的時候錯了,應該是這個register寫入錯東西、`jalr`指令有部分錯了
| x2 |`$sp` |
| x3 |`$gp` |
| x4 |`$tp` |
| x5 |`$t0` |
| x6-x7 |`$t1`~`$t2` |
| x8 |`$s0,$fp` |
| x9 |`$s1` |
| x10-11 |`$a0`~`$a1` |
| x12-17 |`$a2`~`$a7` |
| x18-27 |`$s2`~`$s11` |
| x28-31 |`$t3`~`$t6` |
## Start Coding
:::success
**那一開始要幹嘛呢 ?? 我會推薦以下方式**
>
1. 先能夠讀指令(控制instr_addr每個cycle+4得到每個指令)
2. 打好架構(像是`rst`、各個`case`等等先設計好)
3. 撰寫`addi`(一開始會大量執行的指令)
4. 等這以上部分都OK了(且你也會看波形圖了),再繼續做下去吧!
(若你所有的register能夠變成`0x00000000`就表示成功了!)
:::
### 好用的東西
好用的東西放最前面才會看的到 :+1:
但自己去研究
1. `$signed()`、`$unsigned()`、`$display()`、`>>>`之類的
(`$display()` 我都用來看指令做到哪裡用,用法跟c裡面的`printf("%d,%b",Fuck_CPU,Register[1])`差不多)
2. **所有** imm 都要 **signed-extension**,是**所有**喔!阿接法很亂,要小心,還有的imm沒有imm[0],要補0給他喔,像是:

```
imm = { 20bits signed-extention,
instr_out[31],
instr_out[7],
instr_out[30:25],
instr_out[11:8],
1'b0} <- 這個被隱藏起來ㄌ (超級調皮)
```
3. 還有sign-extension方式,下面是範例,請根據imm接法實作
`{{20{instr_out[31]}},instr_out[31:20]}`
4. 每個指令在幹嘛🙃 [Jim's Dev Blog](https://tclin914.github.io/16df19b4/)
5. `LB、LH`讀進來的也要 signed-extension 喔
### Setup
setup.s 若執行成功,他會將所有 register 設成`0x00000000`,並初始化 DM
#### setup所需的指令
`addi`、`jal`、`sw`、`bgeu`、`jalr`、`auipc`
若以上指令沒完成,可能連死掉的龍貓都不會出現喔~
(`setup`裡的`li`其實就是`addi`)
* 附註 : auipc 的 imm 是 [31:12],是前 20 bit,不要像我一樣白癡,看成他是後20 bit
### Main
若有進入到 main,那就可以慢慢的刻指令了。
阿有些指令的測試可能會先用到另一個指令,所以若不確定哪個出問題,可以去看`main.log`裡面
|DM|Answer|Instruction |data_addr(每年可能不一樣)|備註|
|--|------|------------ |-----------|------|
0| ` = fffffff0 ` | ADD |0x8004|
1| ` = fffffff8 ` | SUB |0x8008|
2| ` = 00000008 ` | SLL |0x800c|
3| ` = 00000001 ` | SLT |0x8010|
4| ` = 00000001 ` | SLTU |0x8014|
5| ` = 78787878 ` | XOR |0x8018|
6| ` = 000091a2 ` | SRL |0x801c|
7| ` = 00000003 ` | SRA |0x8020|
8| ` = fefcfefd ` | OR |0x8024|
9| ` = 10305070 ` | AND |0x8028|
10| ` = cccccccc ` | LW |0x802c|
11| ` = ffffffcc ` | LB |0x8030|
12| ` = ffffcccc ` | LH |0x8034|
13| ` = 000000cc ` | LBU |0x8038|
14| ` = 0000cccc ` | LHU |0x803c|
15| ` = 00000d9d ` | ADDI |0x8040|
16| ` = 00000004 ` | SLTI |0x8044|
17| ` = 00000003 ` | SLTIU |0x8048|
18| ` = 000001a6 ` | XORI |0x804c|
19| ` = 00000ec6 ` | ORI |0x8050|
20| ` = 2468b7a8 ` | ANDI |0x8054|
21| ` = 5dbf9f00 ` | SLLI |0x8058|
22| ` = 00012b38 ` | SRLI |0x805c|
23| ` = fa2817b7 ` | SRAI |0x8060|
24| ` = ff000000 ` | JALR |0x8064|
25| ` = 12345678 ` | SW |0x8068|t4,-20(s0)
26| ` = 0000f000 ` | SW |0x806c|t3,-16(s0)
27| ` = 00000f00 ` | SW |0x8070|t2,-12(s0)
28| ` = 000000f0 ` | SW |0x8074|t1,-8(s0)
29| ` = 0000000f ` | SW |0x8078|t0,-4(s0)
30| ` = 56780000 ` | SH |0x807c|t5,-18(s0) (HARD!!!)
31| ` = 78000000 ` | SB |0x8080|t5,-13(s0) (HARD!!!)
32| ` = 00005678 ` | SH |0x8084|t5,-12(s0)
33| ` = 00000078 ` | SB |0x8088|t5,-8(s0)
34| ` = 12345678 ` | SW |0x808c|t5,-4(s0)
35| ` = ce780000 ` | SW |0x8090|跟DM[31]、[32]有關
36| ` = fffff000 ` | BEQ |0x8094|
37| ` = fffff000 ` | BNE |0x8098|
38| ` = fffff000 ` | BLT |0x809c|
39| ` = fffff000 ` | BGE |0x8100|
40| ` = fffff000 ` | BLTU |0x8104|
41| ` = fffff000 ` | BGEU |0x8108|
42| ` = 1357a064 ` | AUIPC |0x810c|
43| ` = 13578000 ` | LUI |0x8110|
44| ` = fffff004 ` | JAL |0x8114|
45| ` = 000174a8 ` | MUL |0x8118|
46| ` = fffffb37 ` | MUL |0x811c|
47| ` = 00007740 ` | MUL |0x8120|
48| ` = 00005af3 ` | MULH |0x8124|
49| ` = ffffff17 ` | MULH |0x8128|
50| ` = 000000e8 ` | MULH |0x812c|
51| ` = 00005af3 ` | MULHU |0x8130|
52| ` = 000f405f ` | MULHU |0x8134|
53| ` = ffe17e1e ` | MULHU |0x8138|
### 陷阱
1. `DM[30]、[31]`要小心
他利用非4倍數的數字表示數字存的位置,對照答案你大概就知道他想要你怎麼做儲存了(寫死也沒關係,答案對了就好)
2. `$zero` 絕對不能更改到!!!有些指令很ㄐㄧㄢˋ會偷改,不能讓他改到,要保持`0x00000000`。
3. signed-extension 很重要所以再說一遍,還有`LB、LH`也都要signed-extension喔!
4. 記得,你的clock如果比較多才完成一個指令,需要把data_in <= 'hx; data_write <= 0;不然會一直去存東西,我自己是也會把`data_addr <= 'hx`,因為這樣沒有要用他的時候是紅線比較好找到你錯在哪(PO)
#### 補個
如果你是要對波型Debug 你的`setup.S`成功後,main操作的地方大蓋在進度條80%那邊
DM不是按照順序塞進去 Debug請小心(by 博)
(`main.log`中一個store(SW、SB、SH)就是1個DM答案,而且`main.log`每個block都會告訴你他在測試什麼 by昀)
## 後記
個人覺得 sb、sh最難,再來是load跟branch或jump,但自己耍智障次數更多啦QAQ,然後有一個"(PO)"在句子結尾表示是 112陳彥博 補上的 感謝他 :love_letter:
### 補一個後記 (by 博)
他很機掰的會有一些你沒看過的指令在裡面調皮
(他好像是用MIPS的指令,所以對到RISCV會長不一樣by昀)
會有一個指令叫做
1. ``` bleu t1,t0,a90```

他其實是跟```bgeu``` 有關喔
2. ```ret```

文獻在這邊 [RISC-V 手冊](http://crva.ict.ac.cn/documents/RISC-V-Reader-Chinese-v2p1.pdf)
:::info
- 感謝筆記的協作者 112陳彥博 :smirk:
:::