VHDL
NCKU
main.s
+ Makefile
: 可以更改指令,改完後make
他即可(助教很貼心的給makefile
了。top_tb.v
: 跑完測試拉波形的時候,自己宣告的register file會在Memory那邊,沒有跟sim放在一起;通常拉i_CPU, register file以及i_DM即可(假設你很順利能讀指令)main.s
裡面已經有答案了,我是使用main.log
debug的,可以兩個對照啊這樣就不用自己算值了
initial begin
#(`MAX*`CYCLE)
$display("Simulation Failed");
$finish;
end
他的意思是,當你時間超過他們規定的時間時,就要算失敗,但是助教給的時間非常充裕,所以問題是出在
在log檔裡,有一個叫做
main_exit
的block,你要跳到那邊
以我來說,我沒辦法跳到是因為我的simm和register file沒有做signed,做了以後就跳到了
如果註解掉後就可以看到DM裡的結果,那問題是第二種;如果還是不行,就是第一種,或是如原文說的初始化不夠正確
補個讓人霧煞煞的LW和SW
注意:給值時候是給類似
x[7]+4
,只要data_addr顯示了這個的值(假設x[7]=3092,那data_addr總共就是3096)就是對的
data_out的值不等於data_addr(data_addr=3096,但data_out會是另外的值,這就要看原本在那裡存了什麼)
進階的部份:data_addr <= x[7] + 13和data_addr <= x[7] +16在DM的addr顯示的是同個東西,但對我們來說,我們要寫入的位置會變得不同,以sb為例
__ __ __ __ | __ __ __ __
16 15 14 13 | 16 15 14 13
差別大概是這種感覺,要用imm的末兩位來判斷,可以直接參考裡面的文章寫,如果出來結果還是不對就調換順序(快速debug方式,概念則是這樣)
基本寫法和data_write差不多,只要注意在data_write是1的地方data_in要對就好,至於其他部份即使是前一時刻的值也沒什麼關係
lb: load byte (8 bit)
lh: load half word (16 bit),這兩個在你分配x[rd]
要做好位置的分配與補0
解決方法:
1.如果是32bit:設成reg signed(或是用$signed個別補充)並在讀取imm的時候要自己sign extend他,讓他依據你讀入的最高位補
2. 12 bit register: 直接設成reg signed(附帶一題:register file設成signed會比較好,不用自己轉),不用補東西
他做加法時會自己幫你補剩下20位,好耶!
Image Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
JAL
那個是故意的,你絕對不可以改x[0]
x[0] <= 0
x[0] <= 0
(模擬電腦不讓給x[0]的情況)JALR
jalr本身是因為要跳到某個地方,必須先把現在位置存到暫存器,然後才能跳過去;存的時候要存的是現在位置+4,因為現在這裡已經做過了,我是要接下一步
問題指令:jalr $t0,$t0,0
原意
x[rd] = pc + 4;
pc = imm + x[rs1];
出問題時的流程:
//pc=912,imm=400,$t0=200
$t0 = pc + 4; //$t0 = 916
pc = imm + $t0; //pc = 1316
實際上我們想要的:
(1)
//pc=912,imm=400,$t0=200
pc = imm + $t0; //pc = 600
$t0 = pc + 4; //$t0 = 916
這樣也能解決問題
(2)
//pc=912,imm=400,$t0=200
$t0 <= pc + 4; //$t0 = 916
pc <= imm + $t0; //pc = 600
//前提,兩個在同個clk一起做,pc不可以比較晚
(3)
//pc=912,imm=400,$t0=200
reg [32:0]temp;
temp = $t0;
$t0 = pc + 4; //$t0 = 916
pc = imm + temp; //pc = 600
也就是,會不會遇到要看程式架構:
errr,去年是44個指令,但今年(112級)是54筆測資,今年多了mul系列,不知道明年會不會又多,郭
所以DM的參考指令不一定準,前面幾個差不多,大概在sw後面開始會不一樣,不一樣的話:
或是可以數已經使用了幾個sw,但指令很多會數到亂掉Q
我本身的程式架構
--------------------------
助教給的input,output(有的output可以自己加reg,這個是從紅綠燈就知道的事情ㄛ)
--------------------------
--------------------------
自己的register
我用到了:
reg [31:0] x [31:0]//register file
reg [11:0]iimm,simm...//只需要12 bit的imm
reg [31:0]jimm...//需要31 bit imm(因為中間一坨0)
reg tmp, flag...//輔助用,依照自己需求加減
---------------------------
---------------------------
parameter implement
我做了兩組parameter宣告,一組是單純FSM,一組是opcode的type
optype其實可有可無,有的話比較好閱讀,因為你可以記你是Rtype或是什麼,
分case處理時很容易閱讀,至少比binary好閱讀
缺點就浪費行數跟空間r
---------------------------
---------------------------
always@(posedge clk)begin
if(rst)begin
大多變數為0的初始化
end
else begin
依據不同state不同狀態改變
end
end
有n個,總之就是一個always block只放一個變數,有幾個我就寫幾個
一開始會先處理parameter變數變化//例如 FSM 和 opcode type
再來處理各種會連到外面的output//data_in,data_addr
各種指令會用到的變數的讀取//rs1,rs2,funct3,imm
x[]和PC等計算//加減乘除會在x[]|beq,bne會在PC
---------------------------
我看過的程式架構
把ALU和decoder獨立出來,R-type另外處理
全部擠在一起
如果不知道如何下手,或許可以
本來就是分這兩部份啦,只是會忘記
然後modelsim有個小技巧是在波形圖左下角有時間,時間可以自己輸入和複製,這樣就不用一直重複拉波形圖了,可以直接跳到那邊,好耶!
這樣de可能會比較踏實,當然,普通的一行一行對也可以,因為通常是小錯誤,修改完後可以多對很多,後面不會差太多