assigment
sophomore
computer organization
[ 先來看看助教到底給了我們多少材料和要做些什麼吧 ]
CPU.v
:你的code該寫在這
SRAM.v
:負責讀 / 寫instruction memory 和data memory
(對你沒看錯,這兩條datapath是共用同個檔案)
top.v
:規範如何連接各個module,這裡你可以看到SRAM被寫了兩次,一條是DM(data memory)和一條是IM(instruction memory)
top_tb.v
:測試檔,萬惡的龍貓,所有訊號都可以在這裡查看(左邊可以展開喔)
(不要跟我一開始一樣把tb檔以外的拿進去看波型,會看不到任何訊號)
[ 如果想看暫存器的東西可以從這裡按添加波形 ]
setup.s
:程式最開始要先執行的部分,會初始化所有register和memory區段main.s
:程式真正開始測試指令的部分這兩個檔案並不會真的被「執行」到,它是把裡面的內容編成16進制的.hex
,翻譯指令成我們寫的cpu可以解讀的樣子,主要是給你看裡面到底有什麼指令(但註解沒很清楚有夠難懂),真正被執行的是.hex
這裡衍伸出一個問題,也就是說如果你setup.s
裡面用到的指令(jal
, begu
, addi
, sw
, auipc
)有寫錯,你一輩子都不能開始進到main.s
測其他指令,等等後面會談到
main0.hex
, main1.hex
, main2.hex
, main3.hex
:
這四個檔就是setup.s
和main.s
翻譯過來的指令
(他把setup.s
包在裡面一起編,我就不懂為什麼這麼重要的事情沒講,我當初找了很久找不到setup.hex
在哪)golden.hex
:
這個是答案,會比較這裡面和DM的資料是否一樣main.log
:裡面的資料就是他跑測資的記錄檔,也是提供你比較好閱讀而已
[ 子揚說他是一個指令一個指令對喇 ]
[ 幫大家分解一下 ] <PC Address>: <16進的instr_out> <verilog的指令>
[ li
就是 addi ra 0($zero)
喔!複習個!]
這裡可以得出一個結論,
從setup.s
到main.s
裡用的指令都是用我們實作的,
就算看起來沒有,也會用替代的方式實現
如果嫌log很難看,main.s
裡面也可以看指令,
只是缺少address但好處是後面有算好的數字結果可以參考
[ 講了那麼多所以這次到底要寫什麼呢? ]
!就是紅色以外的部分!
PC
)註:請依自己的需求在output上加上reg,上面的code已經加了跟助教給的不太一樣喔
clk
訊號正源觸發,沒有偵測其他訊號
(我當初還天真地以為他們會在always裡檢查data_read
和instruction_read
)data_read
和instruction_read
= 1時並不會馬上改變data_out
和instruction_out
的值clk
變1時才會拿到,這也是為什麼說拿指令要delay 1個 cycle,而load系列還要再delay 1個 cycle記得先檢查你有沒有一直拿到新的instruction
-> 也就是instr_out
要一直變動
再來是前面提到初始化會用到幾個必備的指令
jal
bgeu
addi
sw
還有一些我分析不出來的(la) 這幾個如果有錯初始化失敗,結果就會是XXXXXXXX 而且會因為離不開這個block而進不到main裡
那如何檢查自己初始成功了沒?
addi
寫錯
或是你的register架構有錯
(我一開始企圖分檔寫register結果接線跟用和什麼訊號觸發的會有很大的挑戰,後來放棄了)記得檢查 register[0] 一定要是 0,初始化才會對哦
$dispaly("")
去顯示現在做了什麼指令
去看有沒有進到main
如果都是上面那4個指令
就代表你還卡在初始化裡
(助教你跳個錯誤訊息"setup failed"很難484)如果你的結果不是XXXXXXXX 那可以進到測試指令的部份了
這邊就是按照給的指令表去寫 但有時候有些imm串的方式很奇怪的要特別小心
[ 例如 ] 這裡imm串法長的很詭異,而且會後一個沒寫的隱藏bit是0喔
每種 imm 的長度都是 32 位元,文件上沒說明的部分要自己補齊並做好 sign extension
另外提示有幾個實用的東西可以自己查如何使用:
$signed()
,$unsigned()
,>>>
JAL
:
早上跟助教說過了,0x0000006f =
這串指令會去改寫x0
(Zero register)
我們認為是bug ,但助教說不是,所以要想辦法解決
JALR
:
在作業說明是這麼說的:
rd = PC + 4 PC = imm + rs1 (Set LSB of PC to 0)
但是在實作上不能寫成:
因為在測試的過程中可能會遇到下列的指令
在上述的情況,若使用前者的寫法會導致最後 pc 的結果為 pc = pc + 4
但是 t0
原本不是 pc + 4 而是這個 cycle 結束才會被改為 pc + 4 的數值,所以 pc 數值也不應該被改為 (pc + 4)(t0 的數值) + (0)(imm 的數值) ,而是 pc = t0(未賦值前 t0 的數值) + imm
SW
、SB
、SH
、LW
、LB
…:
SW
:就不多解釋了。SB
、SH
:要特別注意的是你必須要依照data_addr[1:0]
作為寫入的依據。
自己看因為在使用 sh
, sb
時,不一定是寫在 data_addr 是 4 的倍數上,但是 memory 在讀取資料的時候會以 4 為單位讀取或寫入。
就像是 data memory 讀寫的指針永遠都只在 4 的倍數上,但是我們實際使用時可能會需要寫的 data_addr
是 13, 17, 5 等等不是 4 的倍數的位置上,這時候就需要透過 data_write
來指定正確的寫入位置。
因為 data memory 的指針指在 4 的倍數的 addr 上,所以實際上我們要決定的是要寫入的 byte (或是 half-word) 應該要放在這 4 byte 中的哪幾個 byte 上,如果是 sb
指令且需要寫在 LSB (Least significant byte) 上,就指定 data_write
為 0001; 如果寫在 MSB 上對應的 data_write
就是 1000,依此類推。
0x000ffab3
,因為最後兩個 bit 是 11 所以使用 sb
的時候對應的 data_write 為 1000
LB
、LH
一樣ㄏ花了一點時間去把「結果」和「main.s
」裡面區塊的位置對應(就是所有SW的位置)
可以快速對應哪個指令可能有問題
結果如下:
DM | value | instr |
---|---|---|
DM[8192] | fffffff0 | addi |
DM[8193] | fffffff8 | sub |
DM[8194] | 00000008 | sll |
DM[8195] | 00000001 | slti |
DM[8196] | 00000001 | sltu |
DM[8197] | 78787878 | xor |
DM[8198] | 000091a2 | srl |
DM[8199] | 00000003 | sra |
DM[8200] | fefcfefd | or |
DM[8201] | 10305070 | and |
DM[8202] | cccccccc | lw |
DM[8203] | ffffffcc | lb |
DM[8204] | ffffcccc | lh |
DM[8205] | 000000cc | lbu |
DM[8206] | 0000cccc | lhu |
DM[8207] | 00000d9d | addi |
DM[8208] | 00000004 | slti |
DM[8209] | 00000003 | sltiu |
DM[8210] | 000001a6 | xori |
DM[8211] | 00000ec6 | ori |
DM[8212] | 2468b7a8 | andi |
DM[8213] | 5dbf9f00 | slli |
DM[8214] | 00012b38 | srli |
DM[8215] | fa2817b7 | srai |
DM[8216] | ff000000 | jalr |
DM[8217] | 12345678 | sw |
DM[8218] | 0000f000 | sw |
DM[8219] | 00000f00 | sw |
DM[8220] | 000000f0 | sw |
DM[8221] | 0000000f | sw |
DM[8222] | 56780000 | sh(困難) |
DM[8223] | 78000000 | sb(困難) |
DM[8224] | 00005678 | sh |
DM[8225] | 00000078 | sb |
DM[8226] | 12345678 | sw |
DM[8227] | ce780000 | sh && sb |
DM[8228] | fffff000 | beq |
DM[8229] | fffff000 | bne |
DM[8230] | fffff000 | blt |
DM[8231] | fffff000 | bge |
DM[8232] | fffff000 | bltu |
DM[8233] | fffff000 | bgeu |
DM[8234] | 1357a064 | aupic |
DM[8235] | 13578000 | lui |
DM[8236] | fffff004 | jal |
這邊會看到:明明都是資料的offest應該皆為4的倍數,上面卻出現了13和18!
[ 解釋 ]
13(0000_1101)
和18(0001_0010)
位置的時候,其實是在寫12(0000_1100)
和16(0001_0000)
若沒有考慮直接把值寫入,就會出現問題(寫進錯誤的值)data_write
去偏移到正確的位置了(但寫入的資料也要調整)
所以data_write
訊號是可以出現0010,0100,0110等組合喔這次作業真的不容易 作業說明又很模糊 (因為這份作業是每年一直傳下來進化的,所以有時候助教根本不知道之前是怎麼做的) 常常坐在電腦前4個小時但0進度 (我跟子揚都寫到看日出了QQ) 希望這些心得有助大家在期中前趕快把這份作業生出來 有時間救救學分
打個預防針 裡面可能有些小錯 多半都是我們作者的心得和推論 不是100%正確 但也有寫信騷擾助教後得到的答案 所以要麻煩大家一起debug 有寫錯的地方請多多包涵並私訊我 我會跟你討論討論再更正 也歡迎想加入協作提供建議或心得讓大家寫作業順利的人來找我 我會把權限開給你 祝大家寫作業順利! _(:3 」∠ )_
特別感謝其他協作者:111 沈子揚、111 張祐誠、111 向景亘 特別感謝心靈導師:110 王聖中 作者:111 黃宇衡