我的晶元之路3
我的晶元之路3
上回說到write&readnmodule 的FSM化
還是按主代碼FSM順序寫:
l S0:初始化,
always@(posedge sha_clk)
if(sha_reset_bn== 1b0)
begin
//current_state=nS1;
current_state=S0;
end
elsen
*/
begin
case(current_state)
S0:begin
sign0=1b0;//重置延時標記
……
sha_ipen=1b0;
sha_rw_b=1b1;
sha_addr=5b00000;
sha_wdata=8b0;
pre=2b00;
……
current_state=S1;
end
l S1:
以下標註部分為套用counter實現延時的語句模板
S1:
if(startS1==1b0)//標誌字
begin
delaystartn=1b1;//counter控制信號賦值
delayn=16h0040;
if(delaystop==1)//完成延時
begin
delaystart=1b0;//ncounter控制信號重置
delay=1;
startS1=1b1;//延時後操作
sign0=1b1;
counter_reset=1;//清零counter***這個並不是個非常好的做法,應該是不清零也可以的(這句刪除掉也沒事,但沒試過,具體到具體電路不太清楚區別),但是寫上是可以用的
end
end
//信號sign0,對應 #500 nsha_ipen=1b1;
elsenif(sign0==1b1)
begin
counter_reset=0;//=1時reset
begin
delaystart=1b1;
delay=24;
if(delaystop==1)//完成延時
begin
delaystart=1b0;
delay=2;
sha_ipen=1b1;
sign0=1b0;
sign1=1b1;
counter_reset=1;
end
end
end
//信號sign1,對應#500
elsenif(sign1==1b1)
begin
counter_reset=0;
if(reuse==1)
begin
delaystart=1b1;
delay=26;
if(delaystop==1)//完成延時
begin
delaystart=1b0;
delay=3;
sign1=1b0;
current_state=S2;
counter_reset=1;
end
end
l 實現w/r模塊的嘗試
在實現S2過程中出現了以下問題:
n Task中是不可以有時序電路的(實現不了延時);
n S1的實現方法,實際上是一個二叉樹條件,並不是多路選擇器
當面對S2,S3當中
W32(SHADI0,32h61626364); //S3狀態,W32數據
W32(SHADI1,32h62636465);
W32(SHADI2,32h63646566);
W32(SHADI3,32h64656667);//read(SHADI3);
W32(SHADI4,32h65666768);//read(SHADI4);
W32(SHADI5,32h66676869);//read(SHADI5);
W32(SHADI6,32h6768696a);//read(SHADI6);
W32(SHADI7,32h68696a6b);//read(SHADI7);
W32(SHADI8,32h696a6b6c);//read(SHADI8);
W32(SHADI9,32h6a6b6c6d);//read(SHADI9);
W32(SHADIA,32h6b6c6d6e);//read(SHADIA);
W32(SHADIB,32h6c6d6e6f);//read(SHADIB);
W32(SHADIC,32h6d6e6f70);//read(SHADIC);
W32(SHADID,32h6e6f7071);//read(SHADID);
W32(SHADIE,32h80000000);//read(SHADIE);
W32(SHADIF,32h00000000);//read(SHADIF);
read(SHADI0);
read(SHADI1);
read(SHADI2);
read(SHADI3);
read(SHADI4);
read(SHADI5);
read(SHADI6);
read(SHADI7);
read(SHADI8);
read(SHADI9);
read(SHADIA);
read(SHADIB);
read(SHADIC);
read(SHADID);
read(SHADIE);
read(SHADIF);
這些代碼,需要的選擇過多,且不好維護
實現方法我想的第一個思路是多路選擇器,每次always@(posedge sha_clk)時判斷信號進行下一步。
但這種方法的實現貌似和上面一樣,也是多路選擇,或者就是狀態機。
那就不如把read(addr【0:4】)和w32(addr【0:4】,data32『hxxxx)分別封裝為module調用
l 實現w/r module
首先,還是要搞清楚結構,仔細觀察原來的tb代碼,
Write模塊需要什麼input,輸出什麼
Read模塊需要什麼input,輸出什麼
這步我覺得很重要,從原先的代碼並不是那麼容易的一眼可以看出來輸入輸出關係
從原來的task入手
task W32(input [4:0] adr,input [31:0] datan);
nbegin
nW8(2b00,data[7:0]);
nW8(2b01,data[15:8]);
nW8(2b10,data[23:16]);
nW8(2b11,data[31:24]);
n#100;
nsha_rw_b=1b0;
nsha_addr=adr;
n@(posedge sha_clk);
n#100 sha_rw_b=1b1;
nend
endtask
task W32be(input [4:0] adr,input [31:0]ndata );
nbegin
nW8(2b00,data[7:0]);
nW8(2b01,data[15:8]);
nW8(2b10,data[23:16]);
nW8(2b11,data[31:24]);
n#100;
nsha_rw_b=1b0;
nsha_addr=adr;
n@(posedge sha_clk);
//#5 sha_rw_b=1b1;
nend
endtask
tasknW8(input [1:0] adr,input [7:0] data );
nbegin
n#100;
npre=adr;
nsha_wdata=data;
n@(posedge sha_clk);
nend
endtask
ntask read( input [4:0] adr );
nbegin
n#100;
nsha_wdata=8b0;
sha_rw_b=1b1;
nsha_addr=adr;
pre=2b00;//試試
n@(posedge sha_clk);
n#200 pre=2b00;
n#200 pre=2b01;
n#200 pre=2b10;
n#200 pre=2b11;
#200;
nend
nendtask
仔細分析
n 關於sha_reset_b&w32_reset,貌似並不需要sha_reset_b直接控制w32,只要sha_reset_b啟動後在主代碼state.v中將w32_reset,一併打開即可
n 時鐘應該是一直要給的,不考慮功耗等,最好讓w32一直有時鐘
n Pre需要麼,貌似不太需要,不過可以一直留著,和主代碼中pre連接
n sha_rw_b需要麼,只是個使能信號,w32模塊最好像counter那樣有start有stop控制,用狀態機實現,我們只要在S2/S3開始時主代碼中打開sha_rw_b就好
n 也就是說,從sha_statenmodule中給w32模塊data和sha addr就好,可以加上pre,其餘的為時鐘,rst,和其他的start,stop等復用信號。
版本shasha_12
modulenW32be(clk,rst,start,addr,data,pre,sha_wdata,stop,reuse);
inputnclk,rst,start;//clk是給counter用的。rst是自己用的,在state.v中module state中調用復用
inputn[4:0] addr;
inputn[31:0] data;//相比較原本的那個tb(不可綜合的),原來的data 8位要慢一個周期給到sha_wdata,pre也要晚一個周期傳輸到,感覺應該不會出問題
//原來w32be 的task中的#100都有在本文件中狀態機中實現
//output,復用部分信號
outputnwire stop;//stop=1時,本次計時結束
outputnwire reuse;//resure=1時,可以開始下一次計數周期
regnstop_reg=1b0;
regnreuse_reg=1b0;
assignnstop = stop_reg;
assignnreuse = reuse_reg;
//output,正常的信號控制部分
outputnwire [1:0]pre;
outputnwire [7:0]sha_wdata;
regn[1:0]pre_reg=2b00;
regn[7:0]sha_wdata_reg=8b0;
assignnpre=pre_reg;
assignnsha_wdata=sha_wdata_reg;
//給counter的控制信號
regncounter_start=0;
regn[15:0]counter_delay=0;
regncounter_reset=0;
wirencounter_stop;
wirencounter_reuse;
//狀態信號
regnsign0=1b0;
regnsign1=1b0;
regnsign2=1b0;
regnsign3=1b0;
regnsign4=1b0;
regnsign5=1b0;
regn[2:0] state=3b000;
counternw0(.clk(clk),//讀stop,stop=1時結束
.rst(counter_reset),
.start(counter_start),
.delay(counter_delay),
.stop(counter_stop),
.reuse(counter_reuse));
alwaysn@ (posedge clk or posedge rst)//rstè????aé?1?????¨????????????
begin
ifn(rst)//rst=1??????????-£??????rst=0
begin
counter_reset=1;
stop_regn= 1b0;
reuse_reg=n1b1;
staten= 3b000;
counter_start=0;
end
else
begin
case(state)
3b000:
begin
counter_reset=0;
stop_regn=1b0;
reuse_reg=1b1;
if(startn== 1b1)
begin
staten= 3b001;
reuse_reg=1b0;
sign0=1;
end
else
begin
staten= 3b000;
end
end
3b001:
begin
//#100; pre=adr; sha_wdata=data;
if(sign0==1b1)
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h3201;//隨便一個標示
pre_reg=2b00;
sha_wdata_reg=data[7:0];
sign0=1b0;
sign1=1b1;
staten= 3b010;
counter_reset=1;
end
end
end
3b010:
begin
//#100; pre=adr; sha_wdata=data;
if(sign1==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h3302;//隨便一個標示
pre_reg=2b01;
sha_wdata_reg=data[15:8];
sign1=1b0;
sign2=1b1;
counter_reset=1;
staten= 3b011;
end
end
end
end
3b011:
begin
//#100; pre=adr; sha_wdata=data;
if(sign2==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h3203;//隨便一個標示
pre_reg=2b10;
sha_wdata_reg=data[23:16];
sign2=1b0;
sign3=1b1;
counter_reset=1;
staten= 3b100;
end
end
end
end
3b100:
begin
//#100; pre=adr; sha_wdata=data;
if(sign3==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h3204;//隨便一個標示
pre_reg=2b11;
sha_wdata_reg=data[31:24];
sign3=1b0;
sign4=1b1;
counter_reset=1;
staten= 3b101;
end
end
end
end
3b101:
begin
//#100; sha_rw_b=1b0;(這個改交給modulenstate控制,在運行w32be結束後) sha_addr=adr;(這個不用了)
if(sign4==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h3232;//隨便一個標示
sign4=1b0;
sign5=1b1;
counter_reset=1;
staten= 3b110;
end
end
end
end
3b110:
begin
staten<=3b111;
stop_regn<= 1b1;
end
3b111:
begin
staten<=3b000;
end
endcase
end
end
endmodule
W32模塊集成一個counternw0.
Read模塊同上,分析來回信號,比w32少一個data,甚至不需要用(在主代碼中指定就好)
modulenread(clk,rst,start,addr,pre,stop,reuse);
inputnclk,rst,start;//clk是自己用&給counter用的。rst是自己用的,在state.v中module state中調用復用
inputn[4:0] addr;
//output,復用部分信號
outputnwire stop;//stop=1時,本次計時結束
outputnwire reuse;//resure=1時,可以開始下一次計數周期
regnstop_reg=1b0;
regnreuse_reg=1b0;
assignnstop = stop_reg;
assignnreuse = reuse_reg;
//output,正常的信號控制部分
outputnwire [1:0]pre;
regn[1:0]pre_reg=2b00;
assignnpre=pre_reg;
//給counter的控制信號
regncounter_start=0;
regn[15:0]counter_delay=0;
regncounter_reset=0;
wirencounter_stop;
wirencounter_reuse;
//狀態信號
regnsign0=1b0;
regnsign1=1b0;
regnsign2=1b0;
regnsign3=1b0;
regnsign4=1b0;
regnsign5=1b0;
regn[2:0] state=3b000;
counternr0(.clk(clk),//讀stop,stop=1時結束
.rst(counter_reset),
.start(counter_start),
.delay(counter_delay),
.stop(counter_stop),
.reuse(counter_reuse));
//從這開始改20160817
alwaysn@ (posedge clk or posedge rst)//rstè????aé?1?????¨????????????
begin
ifn(rst)//rst=1??????????-£??????rst=0
begin
counter_reset<=1;
stop_regn<= 1b0;
reuse_reg<=n1b1;
staten<= 3b000;
counter_start<=0;
end
else
begin
case(state)
3b000:
begin
counter_reset<=0;
stop_regn<=1b0;
reuse_reg<=1b1;
pre_reg=2b00;
if(startn== 1b1)
begin
staten= 3b001;
reuse_reg=1b0;
sign0=1;
end
else
begin
staten= 3b000;
end
end
3b001:
begin
//#100; sha_addr=addr; pre=2b00;
if(sign0==1b1)
begin
counter_start=1b1;
counter_delay=10;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h4401;//隨便一個標示
pre_reg=2b00;
sign0=1b0;
sign1=1b1;
staten= 3b010;
counter_reset=1;
end
end
end
3b010:
begin
//#200; pre=2b01;
if(sign1==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=10;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h4402;//隨便一個標示
pre_reg=2b01;
sign1=1b0;
sign2=1b1;
counter_reset=1;
staten= 3b011;
end
end
end
end
3b011:
begin
// #200 npre=2b10;//』001狀態
if(sign2==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=10;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h4403;//隨便一個標示
pre_reg=2b10;
sign2=1b0;
sign3=1b1;
counter_reset=1;
staten= 3b100;
end
end
end
end
3b100:
begin
// #200 npre=2b11;
if(sign3==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=5;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h4404;//隨便一個標示
pre_reg=2b11;
sign3=1b0;
sign4=1b1;
counter_reset=1;
staten= 3b101;
end
end
end
end
3b101:
begin
//#200;
if(sign4==1b1)
begin
counter_reset=0;//=1時reset
begin
counter_start=1b1;
counter_delay=10;
if(counter_stop==1)//完成延時
begin
counter_start=1b0;
counter_delay=16h4405;//隨便一個標示
sign4=1b0;
sign5=1b1;
counter_reset=1;
staten= 3b110;
end
end
end
end
3b110:
begin
staten<=3b111;
stop_regn<= 1b1;
end
3b111:
begin
staten<=3b000;
end
endcase
end
end
endmodule
l 在sha_state.v中調用兩模塊/S2,S3等的實現
// S2:W32be(SHACTRL,32h0000000a);#8000;
S2:begin
if(startS2==1b0)//S2控制字
begin
assignnpre=w32be_pre;//初始化控制
assignnsha_wdata=w32be_sha_wdata;
sha_addr=SHACTRL;//w32部分信號處理
w32be_addr=sha_addr;
w32be_start=1b1;
w32be_data=32h0000000a;
if(w32be_stop==1)//瀹屾垚寤舵椂
begin
w32be_start=1b0; //w32和控制字的處理
sha_rw_b=1b0;
startS2=1b1;
sign2_0=1b1;
w32be_reset=1;
end
end
else if(sign2_0==1b1)
begin
w32be_reset=0;
sign2_0=0;
sign2_1=1;
deassign pre;
deassign sha_wdata;
end
//淇″彿sign2_1錛屽搴#8000
else if(sign2_1==1b1)
begin
counter_reset=0;//=1鏃秗eset
begin
counter_start=1b1;
delay=16h0190;//#400;
if(counter_stop==1)//瀹屾垚寤舵椂
begin
counter_start=1b0;
delay=16h2200;
sign2_1=1b0;
sign2_2=1b1;
current_state=S3;
counter_reset=1;
end
end
end
end
S3:begin
//read(SHACTRL);
if(startS3==1b0)
begin
assign pre=read_pre;
sha_rw_b=1b1;
read_start=1b1;
sha_addr=SHACTRL;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
startS3=1b1;
sign3_0=1b1;
read_reset=1;
end
end
// read(SHADO0);
else if(sign3_0==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO0;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_0=1b0;
sign3_1=1b1;
read_reset=1;
end
end
end
// read(SHADO1);
else if(sign3_1==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO1;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_1=1b0;
sign3_2=1b1;
read_reset=1;
end
end
end
// read(SHADO2);
else if(sign3_2==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO2;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_2=1b0;
sign3_3=1b1;
read_reset=1;
end
end
end
// read(SHADO3);
else if(sign3_3==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO3;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_3=1b0;
sign3_4=1b1;
read_reset=1;
end
end
end
// read(SHADO4);
else if(sign3_4==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO4;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_4=1b0;
sign3_5=1b1;
read_reset=1;
end
end
end
// read(SHADO5);
else if(sign3_5==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO5;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_5=1b0;
sign3_6=1b1;
read_reset=1;
end
end
end
// read(SHADO6);
else if(sign3_6==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO6;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_6=1b0;
sign3_7=1b1;
read_reset=1;
end
end
end
// read(SHADO7);
else if(sign3_7==1b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1b1;
sha_addr=SHADO7;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1b0;
sign3_7=1b0;
sign3_8=1b1;
current_state=S4;
deassignnpre;
read_reset=1;
end
end
end
end
實際上,w32和read模塊的sha_addr部分並沒有什麼特別的用(應該是),佔用了寄存器,但是能用,我一直用到了最後,沒有怎麼修改了。
確實模擬時方便看。。。
有看到這的讀者可以試著改改,去掉兩個模塊的input addr【4:0】,應該模擬結果是一樣的。
下期將完成前仿
--------------------------------
微博@georgeuser,一枚很可能要搞硬體的喵控的專業記錄日記。
記錄我所走過的路,願我的分享能予人一些借鑒,也願我某日再回頭時能再拾起細節。
推薦閱讀:
※寫書環境 Gitbook + SourceTree + MarkdownPad
※IC 實現數據收集 - Floorplan
※離職華為創辦「加速雲」,Eric帶你探索FPGA在人工智慧的應用
※數字ic前端和後端等學習路線是什麼?
TAG:数字IC设计 | 现场可编辑逻辑门阵列FPGA |