我的芯片之路3
我的芯片之路3
上回说到write&read module 的FSM化
还是按主代码FSM顺序写:
l S0:初始化,
always@(posedge sha_clk)
if(sha_reset_b == 1’b0)
begin
//current_state= S1;
current_state=S0;
end
else
*/
begin
case(current_state)
S0:begin
sign0=1’b0;//重置延时标记
……
sha_ipen=1’b0;
sha_rw_b=1’b1;
sha_addr=5’b00000;
sha_wdata=8’b0;
pre=2’b00;
……
current_state=S1;
end
l S1:
以下标注部分为套用counter实现延时的语句模板
S1:
if(startS1==1’b0)//标志字
begin
delaystart =1’b1;//counter控制信号赋值
delay =16’h0040;
if(delaystop==1)//完成延时
begin
delaystart=1’b0;// counter控制信号重置
delay=1;
startS1=1’b1;//延时后操作
sign0=1’b1;
counter_reset=1;//清零counter***这个并不是个非常好的做法,应该是不清零也可以的(这句删除掉也没事,但没试过,具体到具体电路不太清楚区别),但是写上是可以用的
end
end
//信号sign0,对应 #500 sha_ipen=1’b1;
else if(sign0==1’b1)
begin
counter_reset=0;//=1时reset
begin
delaystart=1’b1;
delay=24;
if(delaystop==1)//完成延时
begin
delaystart=1’b0;
delay=2;
sha_ipen=1’b1;
sign0=1’b0;
sign1=1’b1;
counter_reset=1;
end
end
end
//信号sign1,对应#500
else if(sign1==1’b1)
begin
counter_reset=0;
if(reuse==1)
begin
delaystart=1’b1;
delay=26;
if(delaystop==1)//完成延时
begin
delaystart=1’b0;
delay=3;
sign1=1’b0;
current_state=S2;
counter_reset=1;
end
end
l 实现w/r模块的尝试
在实现S2过程中出现了以下问题:
n Task中是不可以有时序电路的(实现不了延时);
n S1的实现方法,实际上是一个二叉树条件,并不是多路选择器

当面对S2,S3当中
W32(SHADI0,32’h61626364); //S3状态,W32数据
W32(SHADI1,32’h62636465);
W32(SHADI2,32’h63646566);
W32(SHADI3,32’h64656667);//read(SHADI3);
W32(SHADI4,32’h65666768);//read(SHADI4);
W32(SHADI5,32’h66676869);//read(SHADI5);
W32(SHADI6,32’h6768696a);//read(SHADI6);
W32(SHADI7,32’h68696a6b);//read(SHADI7);
W32(SHADI8,32’h696a6b6c);//read(SHADI8);
W32(SHADI9,32’h6a6b6c6d);//read(SHADI9);
W32(SHADIA,32’h6b6c6d6e);//read(SHADIA);
W32(SHADIB,32’h6c6d6e6f);//read(SHADIB);
W32(SHADIC,32’h6d6e6f70);//read(SHADIC);
W32(SHADID,32’h6e6f7071);//read(SHADID);
W32(SHADIE,32’h80000000);//read(SHADIE);
W32(SHADIF,32’h00000000);//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] data );
begin
W8(2’b00,data[7:0]);
W8(2’b01,data[15:8]);
W8(2’b10,data[23:16]);
W8(2’b11,data[31:24]);
#100;
sha_rw_b=1’b0;
sha_addr=adr;
@(posedge sha_clk);
#100 sha_rw_b=1’b1;
end
endtask
task W32be(input [4:0] adr,input [31:0] data );
begin
W8(2’b00,data[7:0]);
W8(2’b01,data[15:8]);
W8(2’b10,data[23:16]);
W8(2’b11,data[31:24]);
#100;
sha_rw_b=1’b0;
sha_addr=adr;
@(posedge sha_clk);
//#5 sha_rw_b=1’b1;
end
endtask
task W8(input [1:0] adr,input [7:0] data );
begin
#100;
pre=adr;
sha_wdata=data;
@(posedge sha_clk);
end
endtask
task read( input [4:0] adr );
begin
#100;
sha_wdata=8’b0;
sha_rw_b=1’b1;
sha_addr=adr;
pre=2’b00;//试试
@(posedge sha_clk);
#200 pre=2’b00;
#200 pre=2’b01;
#200 pre=2’b10;
#200 pre=2’b11;
#200;
end
endtask

仔细分析
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_state module中给w32模块data和sha addr就好,可以加上pre,其余的为时钟,rst,和其他的start,stop等复用信号。
版本shasha_12
module W32be(clk,rst,start,addr,data,pre,sha_wdata,stop,reuse);
input clk,rst,start;//clk是给counter用的。rst是自己用的,在state.v中module state中调用复用
input [4:0] addr;
input [31:0] data;//相比较原本的那个tb(不可综合的),原来的data 8位要慢一个周期给到sha_wdata,pre也要晚一个周期传输到,感觉应该不会出问题
//原来w32be 的task中的#100都有在本文件中状态机中实现
//output,复用部分信号
output wire stop;//stop=1时,本次计时结束
output wire reuse;//resure=1时,可以开始下一次计数周期
reg stop_reg=1’b0;
reg reuse_reg=1’b0;
assign stop = stop_reg;
assign reuse = reuse_reg;
//output,正常的信号控制部分
output wire [1:0]pre;
output wire [7:0]sha_wdata;
reg [1:0]pre_reg=2’b00;
reg [7:0]sha_wdata_reg=8’b0;
assign pre=pre_reg;
assign sha_wdata=sha_wdata_reg;
//给counter的控制信号
reg counter_start=0;
reg [15:0]counter_delay=0;
reg counter_reset=0;
wire counter_stop;
wire counter_reuse;
//状态信号
reg sign0=1’b0;
reg sign1=1’b0;
reg sign2=1’b0;
reg sign3=1’b0;
reg sign4=1’b0;
reg sign5=1’b0;
reg [2:0] state=3’b000;
counter w0(.clk(clk),//读stop,stop=1时结束
.rst(counter_reset),
.start(counter_start),
.delay(counter_delay),
.stop(counter_stop),
.reuse(counter_reuse));
always @ (posedge clk or posedge rst)//rstè¿ä¸ªé¡¹ç®ç¨ä¸ä¸ãã
begin
if (rst)//rst=1ç½®ä½ãæ£å¸¸ä¸rst=0
begin
counter_reset=1;
stop_reg = 1’b0;
reuse_reg= 1’b1;
state = 3’b000;
counter_start=0;
end
else
begin
case(state)
3’b000:
begin
counter_reset=0;
stop_reg =1’b0;
reuse_reg=1’b1;
if(start == 1’b1)
begin
state = 3’b001;
reuse_reg=1’b0;
sign0=1;
end
else
begin
state = 3’b000;
end
end
3’b001:
begin
//#100; pre=adr; sha_wdata=data;
if(sign0==1’b1)
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h3201;//随便一个标示
pre_reg=2’b00;
sha_wdata_reg=data[7:0];
sign0=1’b0;
sign1=1’b1;
state = 3’b010;
counter_reset=1;
end
end
end
3’b010:
begin
//#100; pre=adr; sha_wdata=data;
if(sign1==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h3302;//随便一个标示
pre_reg=2’b01;
sha_wdata_reg=data[15:8];
sign1=1’b0;
sign2=1’b1;
counter_reset=1;
state = 3’b011;
end
end
end
end
3’b011:
begin
//#100; pre=adr; sha_wdata=data;
if(sign2==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h3203;//随便一个标示
pre_reg=2’b10;
sha_wdata_reg=data[23:16];
sign2=1’b0;
sign3=1’b1;
counter_reset=1;
state = 3’b100;
end
end
end
end
3’b100:
begin
//#100; pre=adr; sha_wdata=data;
if(sign3==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h3204;//随便一个标示
pre_reg=2’b11;
sha_wdata_reg=data[31:24];
sign3=1’b0;
sign4=1’b1;
counter_reset=1;
state = 3’b101;
end
end
end
end
3’b101:
begin
//#100; sha_rw_b=1’b0;(这个改交给module state控制,在运行w32be结束后) sha_addr=adr;(这个不用了)
if(sign4==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h3232;//随便一个标示
sign4=1’b0;
sign5=1’b1;
counter_reset=1;
state = 3’b110;
end
end
end
end
3’b110:
begin
state <=3’b111;
stop_reg <= 1’b1;
end
3’b111:
begin
state <=3’b000;
end
endcase
end
end
endmodule
W32模块集成一个counter w0.
Read模块同上,分析来回信号,比w32少一个data,甚至不需要用(在主代码中指定就好)
module read(clk,rst,start,addr,pre,stop,reuse);
input clk,rst,start;//clk是自己用&给counter用的。rst是自己用的,在state.v中module state中调用复用
input [4:0] addr;
//output,复用部分信号
output wire stop;//stop=1时,本次计时结束
output wire reuse;//resure=1时,可以开始下一次计数周期
reg stop_reg=1’b0;
reg reuse_reg=1’b0;
assign stop = stop_reg;
assign reuse = reuse_reg;
//output,正常的信号控制部分
output wire [1:0]pre;
reg [1:0]pre_reg=2’b00;
assign pre=pre_reg;
//给counter的控制信号
reg counter_start=0;
reg [15:0]counter_delay=0;
reg counter_reset=0;
wire counter_stop;
wire counter_reuse;
//状态信号
reg sign0=1’b0;
reg sign1=1’b0;
reg sign2=1’b0;
reg sign3=1’b0;
reg sign4=1’b0;
reg sign5=1’b0;
reg [2:0] state=3’b000;
counter r0(.clk(clk),//读stop,stop=1时结束
.rst(counter_reset),
.start(counter_start),
.delay(counter_delay),
.stop(counter_stop),
.reuse(counter_reuse));
//从这开始改20160817
always @ (posedge clk or posedge rst)//rstè¿ä¸ªé¡¹ç®ç¨ä¸ä¸ãã
begin
if (rst)//rst=1ç½®ä½ãæ£å¸¸ä¸rst=0
begin
counter_reset<=1;
stop_reg <= 1’b0;
reuse_reg<= 1’b1;
state <= 3’b000;
counter_start<=0;
end
else
begin
case(state)
3’b000:
begin
counter_reset<=0;
stop_reg <=1’b0;
reuse_reg<=1’b1;
pre_reg=2’b00;
if(start == 1’b1)
begin
state = 3’b001;
reuse_reg=1’b0;
sign0=1;
end
else
begin
state = 3’b000;
end
end
3’b001:
begin
//#100; sha_addr=addr; pre=2’b00;
if(sign0==1’b1)
begin
counter_start=1’b1;
counter_delay=10;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h4401;//随便一个标示
pre_reg=2’b00;
sign0=1’b0;
sign1=1’b1;
state = 3’b010;
counter_reset=1;
end
end
end
3’b010:
begin
//#200; pre=2’b01;
if(sign1==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=10;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h4402;//随便一个标示
pre_reg=2’b01;
sign1=1’b0;
sign2=1’b1;
counter_reset=1;
state = 3’b011;
end
end
end
end
3’b011:
begin
// #200 pre=2’b10;//’001状态
if(sign2==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=10;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h4403;//随便一个标示
pre_reg=2’b10;
sign2=1’b0;
sign3=1’b1;
counter_reset=1;
state = 3’b100;
end
end
end
end
3’b100:
begin
// #200 pre=2’b11;
if(sign3==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=5;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h4404;//随便一个标示
pre_reg=2’b11;
sign3=1’b0;
sign4=1’b1;
counter_reset=1;
state = 3’b101;
end
end
end
end
3’b101:
begin
//#200;
if(sign4==1’b1)
begin
counter_reset=0;//=1时reset
begin
counter_start=1’b1;
counter_delay=10;
if(counter_stop==1)//完成延时
begin
counter_start=1’b0;
counter_delay=16’h4405;//随便一个标示
sign4=1’b0;
sign5=1’b1;
counter_reset=1;
state = 3’b110;
end
end
end
end
3’b110:
begin
state <=3’b111;
stop_reg <= 1’b1;
end
3’b111:
begin
state <=3’b000;
end
endcase
end
end
endmodule
l 在sha_state.v中调用两模块/S2,S3等的实现
// S2:W32be(SHACTRL,32’h0000000a);#8000;
S2:begin
if(startS2==1’b0)//S2控制字
begin
assign pre=w32be_pre;//初始化控制
assign sha_wdata=w32be_sha_wdata;
sha_addr=SHACTRL;//w32部分信号处理
w32be_addr=sha_addr;
w32be_start=1’b1;
w32be_data=32’h0000000a;
if(w32be_stop==1)//瀹屾垚寤舵椂
begin
w32be_start=1’b0; //w32和控制字的处理
sha_rw_b=1’b0;
startS2=1’b1;
sign2_0=1’b1;
w32be_reset=1;
end
end
else if(sign2_0==1’b1)
begin
w32be_reset=0;
sign2_0=0;
sign2_1=1;
deassign pre;
deassign sha_wdata;
end
//淇″彿sign2_1锛屽搴#8000
else if(sign2_1==1’b1)
begin
counter_reset=0;//=1鏃秗eset
begin
counter_start=1’b1;
delay=16’h0190;//#400;
if(counter_stop==1)//瀹屾垚寤舵椂
begin
counter_start=1’b0;
delay=16’h2200;
sign2_1=1’b0;
sign2_2=1’b1;
current_state=S3;
counter_reset=1;
end
end
end
end
S3:begin
//read(SHACTRL);
if(startS3==1’b0)
begin
assign pre=read_pre;
sha_rw_b=1’b1;
read_start=1’b1;
sha_addr=SHACTRL;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
startS3=1’b1;
sign3_0=1’b1;
read_reset=1;
end
end
// read(SHADO0);
else if(sign3_0==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO0;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_0=1’b0;
sign3_1=1’b1;
read_reset=1;
end
end
end
// read(SHADO1);
else if(sign3_1==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO1;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_1=1’b0;
sign3_2=1’b1;
read_reset=1;
end
end
end
// read(SHADO2);
else if(sign3_2==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO2;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_2=1’b0;
sign3_3=1’b1;
read_reset=1;
end
end
end
// read(SHADO3);
else if(sign3_3==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO3;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_3=1’b0;
sign3_4=1’b1;
read_reset=1;
end
end
end
// read(SHADO4);
else if(sign3_4==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO4;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_4=1’b0;
sign3_5=1’b1;
read_reset=1;
end
end
end
// read(SHADO5);
else if(sign3_5==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO5;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_5=1’b0;
sign3_6=1’b1;
read_reset=1;
end
end
end
// read(SHADO6);
else if(sign3_6==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO6;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_6=1’b0;
sign3_7=1’b1;
read_reset=1;
end
end
end
// read(SHADO7);
else if(sign3_7==1’b1)
begin
read_reset=0;//=1鏃秗eset
begin
read_start=1’b1;
sha_addr=SHADO7;
read_addr=sha_addr;
if(read_stop==1)//瀹屾垚寤舵椂
begin
read_start=1’b0;
sign3_7=1’b0;
sign3_8=1’b1;
current_state=S4;
deassign pre;
read_reset=1;
end
end
end
end
实际上,w32和read模块的sha_addr部分并没有什么特别的用(应该是),占用了寄存器,但是能用,我一直用到了最后,没有怎么修改了。
确实仿真时方便看。。。
有看到这的读者可以试着改改,去掉两个模块的input addr【4:0】,应该仿真结果是一样的。
下期将完成前仿
——————————–
微博@georgeuser,一枚很可能要搞硬件的喵控的专业记录日记。
记录我所走过的路,愿我的分享能予人一些借鉴,也愿我某日再回头时能再拾起细节。