Try   HackMD

CPU 作業說明與心得

tags: assigment sophomore computer organization

檔案架構

[ 先來看看助教到底給了我們多少材料和要做些什麼吧 ]

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

需要編譯的檔案:

  • CPU.v:你的code該寫在這

  • SRAM.v:負責讀 / 寫instruction memory 和data memory (對你沒看錯,這兩條datapath是共用同個檔案)

  • top.v:規範如何連接各個module,這裡你可以看到SRAM被寫了兩次,一條是DM(data memory)和一條是IM(instruction memory)

  • top_tb.v:測試檔,萬惡的龍貓,所有訊號都可以在這裡查看(左邊可以展開喔) (不要跟我一開始一樣把tb檔以外的拿進去看波型,會看不到任何訊號)

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    [ 如果想看暫存器的東西可以從這裡按添加波形 ]

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

指令測試檔案:

  • 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.smain.s翻譯過來的指令 (他把setup.s包在裡面一起編,我就不懂為什麼這麼重要的事情沒講,我當初找了很久找不到setup.hex在哪)
  • golden.hex 這個是答案,會比較這裡面和DM的資料是否一樣

其他有用檔案:

  • main.log:裡面的資料就是他跑測資的記錄檔,也是提供你比較好閱讀而已

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    [ 子揚說他是一個指令一個指令對喇 ]

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    [ 幫大家分解一下 ] <PC Address>: <16進的instr_out> <verilog的指令>

    ​​​​0: 00000093 li ra,0 ​​​​4: 00000113 li sp,0 ​​​​...

    [ li 就是 addi ra 0($zero)喔!複習個!] 這裡可以得出一個結論, setup.smain.s裡用的指令都是用我們實作的, 就算看起來沒有,也會用替代的方式實現

    如果嫌log很難看,main.s裡面也可以看指令, 只是缺少address但好處是後面有算好的數字結果可以參考

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

作要要求

[ 講了那麼多所以這次到底要寫什麼呢? ]

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

!就是紅色以外的部分!

  • 紅色的instruction memory(IM)和data memory(DM)都靠助教給的SRAM處理,只要給出對的控制訊號就行了,等等會介紹控制訊號
  • 所以要自己寫的包含:
    • Progarm counter(PC)
    • register file(管理32個register)
    • 還有各種計算元件(verilog會幫你處理,只要寫對運算式就好)

CPU的I/O訊號

module CPU( input clk, //cpu clock input rst, //reset signal input [31:0] data_out, //data_read = 1時會給你來自DM的資料 input [31:0] instr_out, //當instr_read = 1時會給你來自IM的資料 output reg instr_read, //1bit控制訊號,決定要不要讀instruction進來 output reg data_read, //1bit控制訊號,決定要不要讀data進來 output reg [31:0] instr_addr, //instrunction的address,用來決定拿哪一個指令 output reg [31:0] data_addr, //DM的address,用來決定讀或寫DM上哪一個位置 output reg [3:0] data_write, //4bit控制訊號,決定每8bit要不要寫入DM(處理SW,SH,SB) output reg [31:0] data_in //要寫入DM的資料 );

註:請依自己的需求在output上加上reg,上面的code已經加了跟助教給的不太一樣喔

  • 因為SRAM裡面只靠clk訊號正源觸發,沒有偵測其他訊號 (我當初還天真地以為他們會在always裡檢查data_readinstruction_read)
  • 所以在data_readinstruction_read = 1時並不會馬上改變data_outinstruction_out的值
  • 要等到下一次clk變1時才會拿到,這也是為什麼說拿指令要delay 1個 cycle,而load系列還要再delay 1個 cycle

初始化(結果都是XXXXXXXX有高機率是這個階段出問題)

  • 記得先檢查你有沒有一直拿到新的instruction -> 也就是instr_out要一直變動

  • 再來是前面提到初始化會用到幾個必備的指令

    • jal
    • bgeu
    • addi
    • sw

    還有一些我分析不出來的(la) 這幾個如果有錯初始化失敗,結果就會是XXXXXXXX 而且會因為離不開這個block而進不到main裡

/* Fills memory blocks */ /* 這裡是main.s的內容 */ fill_block: bgeu a0, a1, fb_end sw a2, 0(a0) addi a0, a0, 4 j fill_block fb_end: ret
  • 那如何檢查自己初始成功了沒?

    • setup裡有初始化各個register成00000000(不用自己寫) 如果你連register都沒有全部變0 可能是addi寫錯 或是你的register架構有錯 (我一開始企圖分檔寫register結果接線跟用和什麼訊號觸發的會有很大的挑戰,後來放棄了)

    記得檢查 register[0] 一定要是 0,初始化才會對哦

    • 我是在執行指令時加入$dispaly("")去顯示現在做了什麼指令 去看有沒有進到main 如果都是上面那4個指令 就代表你還卡在初始化裡 (助教你跳個錯誤訊息"setup failed"很難484)

開始測試

如果你的結果不是XXXXXXXX 那可以進到測試指令的部份了

這邊就是按照給的指令表去寫 但有時候有些imm串的方式很奇怪的要特別小心

[ 例如 ]

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
這裡imm串法長的很詭異,而且會後一個沒寫的隱藏bit是0喔

imm =[20 bits signed extention,
               instruction[31],
                instruction[7],
            instruction[30:25],
             instruction[11:8],
                          1'b0] <- 這個被隱藏起來ㄌ

每種 imm 的長度都是 32 位元,文件上沒說明的部分要自己補齊並做好 sign extension

另外提示有幾個實用的東西可以自己查如何使用:$signed(), $unsigned(), >>>

易寫錯或有爭議的指令

  • JAL 早上跟助教說過了,0x0000006f =

    00000000000000000000000011011112 這串指令會去改寫x0(Zero register)

    我們認為是bug ,但助教說不是,所以要想辦法解決

  • JALR : 在作業說明是這麼說的:

    rd = PC + 4 PC = imm + rs1 (Set LSB of PC to 0)

    但是在實作上不能寫成:

    ​​​​regi[rd] = pc + 4;
    ​​​​pc = imm + regi[rs1];
    

    因為在測試的過程中可能會遇到下列的指令

    ​​​​jalr t0, t0, 0
    

    在上述的情況,若使用前者的寫法會導致最後 pc 的結果為 pc = pc + 4 但是 t0 原本不是 pc + 4 而是這個 cycle 結束才會被改為 pc + 4 的數值,所以 pc 數值也不應該被改為 (pc + 4)(t0 的數值) + (0)(imm 的數值) ,而是 pc = t0(未賦值前 t0 的數值) + imm

  • SWSBSHLWLB

    1. SW:就不多解釋了。
    2. SBSH:要特別注意的是你必須要依照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,依此類推。

    • ex: 如果 data_addr 為 0x000ffab3,因為最後兩個 bit 是 11 所以使用 sb 的時候對應的 data_write 為 1000
    1. LBLH一樣ㄏ

結果

花了一點時間去把「結果」和「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
  • 補充說明那兩個困難的指令,code如下:
addi s0, s0, 20 lw t5, -40(s0) # t5 = t4 lw t4, -16(s0) sw t5, -4(s0) sb t5, -8(s0) sh t5, -12(s0) sb t5, -13(s0) <- 問題 sh t5, -18(s0) <- 問題

這邊會看到:明明都是資料的offest應該皆為4的倍數,上面卻出現了13和18!

[ 解釋 ]

  • 助教設計的SRAM裡會去用4bit對齊,會忽略最後2個bit (這個根本挖坑給我們跳)
  • 也就是說寫入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 黃宇衡