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