-
Notifications
You must be signed in to change notification settings - Fork 0
fpga项目:计数器的3种不同写法
minichao9901 edited this page Mar 9, 2024
·
2 revisions
- 我们希望由一个start_pulse去触发一个counter,去产生一个特定的序列或者延时。一共有3种实现方案,我们逐一分析。
- 注意是每来一个start_pulse,就会触发一次这样的序列。
这个方案中fsm其实就是一个最简单的cnt_valid信号。cnt_valid信号是一个辅助信号,它是一个reg类型,能够实现one-time counter
/*********************************************************************************/
/* 1) counter+fsm */
/*********************************************************************************/
parameter CNT_MAX=6;
reg [5:0] div_cnt;
reg cnt_valid;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt<=0;
else if(add_div_cnt) begin
if(end_div_cnt)
div_cnt<=0;
else
div_cnt<=div_cnt+1;
end
assign add_div_cnt=cnt_valid;
assign end_div_cnt=add_div_cnt && (div_cnt==CNT_MAX-1);
always @(posedge clk or negedge rst_n)
if(rst_n==0)
cnt_valid<=0;
else case(cnt_valid)
0: if(start_pulse) cnt_valid<=1;
1: if(end_div_cnt) cnt_valid<=0; //comment this line, becomes free running counter
endcase
/*********************************************************************************/
这个方案代码很比较长,适合于计数值比较小的情况。不太适合于计数长度为变量的情况。
/*********************************************************************************/
/* 2) pure fsm */
/*********************************************************************************/
reg [5:0] div_cnt2;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt2<=0;
else case(div_cnt2)
0: if(start_pulse) div_cnt2<=1;
1: div_cnt2<=2;
2: div_cnt2<=3;
3: div_cnt2<=4;
4: div_cnt2<=5;
5: div_cnt2<=0;
default: div_cnt2<=0;
endcase
assign cnt_valid2=(div_cnt2>=1) && (div_cnt2<=5);
assign end_div_cnt2=(div_cnt2==5);
/*********************************************************************************/
这个方案代码短,适合于计数长度为任意值的情况。从代码看,这个很类似于计数器,但其实不是计数器,其实是状态机写法。
/*********************************************************************************/
/* 3) rewrite fsm, result is counter-like fsm */
/*********************************************************************************/
reg [5:0] div_cnt3;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt3<=0;
else if(div_cnt3==0 && start_pulse)
div_cnt3<=1;
else if(div_cnt3>=1 && div_cnt3<5)
div_cnt3<=div_cnt3+1;
else if(div_cnt3==5)
div_cnt3<=0;
assign cnt_valid3=(div_cnt3>=1) && (div_cnt3<=5);
assign end_div_cnt3=(div_cnt3==5);
/*********************************************************************************/
可以看到,都实现了相应的功能。注意到方案1会多一个计数值,也就是0,也就是当start_pulse来的时候,我们让计数值清零了。其余2个方案,计数值范围是1-5。 从代码长度看,方案3最短。这是状态机的if...else写法,请仔细品味一下。它的特点是,在if()条件中,会根据当前state的值和外部的条件,决定下一个state值。
module counter_or_fsm;
reg clk, rst_n;
initial clk=0;
always #10 clk=~clk;
initial begin
rst_n=0;
#1000;
rst_n=1;
end
reg start_pulse;
initial begin
start_pulse=0;
wait(rst_n==1);
#1000;
@(posedge clk)
#1 start_pulse=1;
@(posedge clk)
#1 start_pulse=0;
end
/*********************************************************************************/
/* 1) counter+fsm */
/*********************************************************************************/
parameter CNT_MAX=6;
reg [5:0] div_cnt;
reg cnt_valid;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt<=0;
else if(add_div_cnt) begin
if(end_div_cnt)
div_cnt<=0;
else
div_cnt<=div_cnt+1;
end
assign add_div_cnt=cnt_valid;
assign end_div_cnt=add_div_cnt && (div_cnt==CNT_MAX-1);
always @(posedge clk or negedge rst_n)
if(rst_n==0)
cnt_valid<=0;
else case(cnt_valid)
0: if(start_pulse) cnt_valid<=1;
1: if(end_div_cnt) cnt_valid<=0; //comment this line, becomes free running counter
endcase
/*********************************************************************************/
/*********************************************************************************/
/* 2) pure fsm */
/*********************************************************************************/
reg [5:0] div_cnt2;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt2<=0;
else case(div_cnt2)
0: if(start_pulse) div_cnt2<=1;
1: div_cnt2<=2;
2: div_cnt2<=3;
3: div_cnt2<=4;
4: div_cnt2<=5;
5: div_cnt2<=0;
default: div_cnt2<=0;
endcase
assign cnt_valid2=(div_cnt2>=1) && (div_cnt2<=5);
assign end_div_cnt2=(div_cnt2==5);
/*********************************************************************************/
/*********************************************************************************/
/* 3) rewrite fsm, result is counter-like fsm */
/*********************************************************************************/
reg [5:0] div_cnt3;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
div_cnt3<=0;
else if(div_cnt3==0 && start_pulse)
div_cnt3<=1;
else if(div_cnt3>=1 && div_cnt3<5)
div_cnt3<=div_cnt3+1;
else if(div_cnt3==5)
div_cnt3<=0;
assign cnt_valid3=(div_cnt3>=1) && (div_cnt3<=5);
assign end_div_cnt3=(div_cnt3==5);
/*********************************************************************************/
endmodule