---
tags: RISCV, 伴學松, 伴學松活動記錄
---
# 從0到有製作自己的CPU!! 第三周活動記錄 20220721
[TOC]
# 直播紀錄連結
{%youtube A8WBmcLHZuQ%}
## 出席
- [x] KIM_WENG
- [x] 名名
- [x] chuan
- [x] bill503084699
- [x] 楓糖
- [x] 謝祥辰
- [x] 黑貓
- [x] sixkwnp
- [ ] Bonki
- [x] ouo314
- [x] Willwho
- [ ] GYLABA
- [x] mikuthebest
- [x] Penquuin
- [x] 葉子
- [ ] painCake
- [x] EZ4ENCE
- [ ] 頂漿汗腺
- [ ] 角角
- [ ] adam chen
# 討論內容
1. [RV32I指令初步複習與講解](https://gitmind.com/app/doc/fd312032746)、[指令參考表](http://riscvbook.com/chinese/RISC-V-Reader-Chinese-v2p1.pdf)(P.27)
2. 實作Decoder
- R type
```verilog=
module decoder(
input [31:0] instr, // instruction
output reg [6:0] opcode, // opcode + function3 + function7
output reg [4:0] rd,
output reg [4:0] rs1,
output reg [4:0] rs2,
output reg [31:0] imm,
);
always @(*) begin
case(instr[6:0])
7'b011001: begin // R type
case(instr[14:12]) // function3
3'b000: begin // R add or R sub
case(instr[31:25]) // function7
7'b0000000: begin // R add
opcode = {instr[31:25], instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:25];
rs2 = instr[24:20];
end
7'b0100000: begin // R sub
opcode = {instr[31:25], instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:25];
rs2 = instr[24:20];
end
end case
end
3'b001: begin //R sll
opcode = {instr[31:25], instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:25];
rs2 = instr[24:20];
end
...... // the same thing to the decoder
end case
end
end case // opcode
end
```
- ***so we simplify to***
```verilog=
module decoder(
input [31:0] instr, // instruction
output reg [6:0] opcode, // opcode + function3 + function7
output reg [4:0] rd,
output reg [4:0] rs1,
output reg [4:0] rs2,
output reg [31:0] imm,
);
always @(*) begin
case(instr[6:0])
7'b011001: begin // R type
opcode = {instr[31:25], instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:25];
rs2 = instr[24:20];
end
end case // opcode
end
```
- R type & I type
```verilog=
module decoder(
input [31:0] instr, // instruction
output reg [6:0] opcode, // opcode + function3 + function7
output reg [4:0] rd,
output reg [4:0] rs1,
output reg [4:0] rs2,
output reg [31:0] imm,
);
imm = 32'b0;
always @(*) begin
case(instr[6:0])
7'b011001: begin // R type
opcode = {instr[31:25], instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:25];
rs2 = instr[24:20];
end
7'b0010011: begin // I type
case(instr[14:12]) // srli, srai or slli
3'b001, 3'b101: begin
opcode = {instr[31:25, instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:15];
imm[4:0] = instr[24:20]
end
default: begin
opcode = {7'b0000000, instr[14:12], instr[6:0]}; // pass to ALU
rd = instr[11:7];
rs1 = instr[19:15];
imm[11:0] = instr[31:20]
end
end case
end
end case // opcode
end
```
# 本周作業
1. 複習ALU和decode
2. 實現decode(可選)
# 討論重點
1. RV32i介紹[心智圖](https://gitmind.com/app/doc/fd312032746)
2. 今天焦點為R type, I type……等為中心
3. 用計算機介紹imm填的bits數與位置
4. 下週第三組的目標
## 點子 / 撇步
- [指令參考表](http://riscvbook.com/chinese/RISC-V-Reader-Chinese-v2p1.pdf)(P.27)
[name=Willwho]
- 我們寫在ripes左邊的程式指令,右邊會顯示機器代碼(機械碼),翻譯成可以指定成電腦看得懂的代碼。
[name=第二組]
- decode在做機械碼的辨認register是要讀還是再傳到哪個部位的register
[name=第二組]
- 翻譯完機械碼而變成type,但他只是定義出來,不會因為指令格式更新而造成天翻地覆。
[name=第二組]
- deocde看到opcode之後再看後面來辨識是哪個type來分類。
[name=第二組]
- 最基本的code是rv32i,總共47指令,到後面的csr的操作等……偏系統層面的操作不先講。
[name=第二組]
- 逐步講解各種rv32i type,看yt
[name=第二組]
- decode的架構與辨別靠得是function3跟code來辨別type分門別類。
[name=第二組]
- 舉R type 為例
| `指令` | function7 | rs2 | rs1 | function3 | rd | opcode | `ALU_SIGN` |
| ------ |:---------:|:----:|:----:|:---------:|:---:|:-------:| ---------- |
| | 七碼 | 五碼 | 五碼 | 三碼 | | 0110011 | |
- 舉I type 為例
| `指令` | imm | rs1 | function3 | rd | opcode |`ALU_SIGN`|
|:------:|:----:|:---:|:---------:|:---:|:------:|:---:|
| | 七碼 | 五碼 | 三碼 | | 兩種各七碼 | |
- R type比完opcode 再比function3 再比function7來分門別類。
[name=第二組]
- I type 平移特殊情況,當你遇到平移,往左平移都填零,往右也填零但有特殊情況可能動手腳會填一,不管哪個type都是用這方式找。
[name=第二組]
- s type同上述方式,每一個都是你要用switch case下去做的東西。
[name=第二組]
- 極簡化版cpu single circle是一一個勉強能用的cpu,risc v 的特殊平移跟另一種狀況溢位?則是由csr來處理,single cycle沒辦法回頭沒辦法用csr來處理溢位或是?
[name=第二組]
- risc v設計指令,很精簡地安排指令,來安排各個指令,R type(暫存器與暫存器之運算)跟 I type(暫存器與常數的運算)是很成對的。
[name=第二組]
- I type 大部分用function3判斷。
[name=第二組]
- 除了最醜的B type外,risc v盡量在指令格式上對齊,最高位sign bit可以做13bit的跳耀,盡量找imm塞滿空位,register都固定。
[name=第二組]
- Deocde是一個輸入instr四個輸出(wd)rd rs1 rs2跟imm立即數(12bits),處理立即數還是以完整4bytes的資料輸出,但我們我會看指令格式去看說放在哪個type跟哪個位置。
[name=第二組]
- 遇到I type 先填前12個bits,如果是B type 平移一個位數,填中間12個bits,再如果是J/S type先填前20bits
[name=第二組]
- input 32個指令,至少有4+1個output 就不要加加減法,寫一個module的宣告輸入1個輸出5個,至少寫3個輸出rd,rs1,rs2。
[name=第二組]
- kim大輔助做alway begin end,先從opcode開始塞。
[name=第二組]
- 給出黑貓寫的decode.v
[name=名名]
- kim大會把循序邏輯額外寫出來但黑貓是都寫在一起。
[name=第二組]
- case()里頭的數值先改instrution的值。
[name=第二組]
- 之後再分出R type,額外加begin跟end,再加上case來讀function3讀到000又要顯示一層add or sub,然後再開一層begin end case來顯示各一個add跟sub
[name=第二組]
- 如果要儲存完整opcode所以都要存好function3跟function7
[name=第二組]
- 每一個模塊都逐漸組起來,很多程式library收到的輸入再丟出來不曉得之後會不會再用得,因此可以精簡化,但我們還沒搞到alu之後要幹嘛所以一次性全部搞出來再吐回去,沒效率但沒毛病的方法因此我們目前只要寫Decode沒跟ALU串連起來。
[name=第二組]
- 之後的概念都一樣但因為function7不一樣因此只要改成begin前面的數字。
[name=第二組]
- Decode其實只是讀這些instruction,下去拆依照各個type,看到哪個type就是用怎樣子的拆法。
[name=第二組]
- I type 只是差在沒function7
[name=第二組]
- 如果只有一個也可以if做宣告(但最後不行)。
[name=第二組]
- 縮排要對好case, endcase
[name=第二組]
- Decode進到register會先接受rd, rs1,再連到ALU
[name=第二組]
- 如果imm都設為零,那電流到imm那邊就會塞彩蛋register,遇到R type, imm那邊就好塞彩蛋,ALU就不會鳥它。
[name=第二組]
- 讀線然後clock decode,clock ALU,clock data,每個clock都要在一個之間解開。
[name=第二組]
- Decode甩鍋,揭開一個框一個框就丟給register跟ALU
[name=第二組]
- csr最後處理異常處理。
[name=第二組]
# 補充資料
- [Cisen RV32 Decode.v](https://github.com/cisen/32bit_RISC-V/blob/master/src/decode.v)
- [KIM大的 Decode.v](https://github.com/kimweng01/RV32I_KIMWENG_sopc/blob/main/code/id.v)