我的晶元之路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 |