打印

Verilog中计数器的正确写法和错误写法

[复制链接]
2090|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xjsxjtu|  楼主 | 2012-10-8 22:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
计数器是Verilog中最基本的时序电路,在计数器的基础上可以设计时钟分频器
module counter10(clk,clr,load,en,data,q,count_flag);
  input clk;
  input clr;
  input load;
  input en;
  input[3:0] data;
  output reg[3:0] q;
  output reg count_flag;
  
  
always@(posedge clk)
    if(clr)
       q  <= 0;
     else if(load == 1'b1)
       q  <= data;
    else if(en == 1'b1) begin
       if(q == 9 )
          q  <= 0;
       else
          q  <= q + 1;
     end
  
always@(q) begin                        //该电路将时序逻辑部分和组合逻辑部分分开设计,是一种很正规的写法
     if(q == 9)                           // 第一个always块中是时序逻辑,在第二个always块中是组合逻辑,
       count_flag  <= 1;                  //这样的写法有利于综合
     else
       count_flag  <= 0;
   end
endmodule

以下内容为testbench内容:
`timescale 1ns/1ns
module count10_tb;
  reg clk;
  reg clr;
  reg load;
  reg en;
  reg[3:0] data;
  wire[3:0]  q;
  wire     count_flag;
  
  counter10 count(clk,clr,load,en,data,q,count_flag);
  initial clk  = 0 ;
  always #5 clk  = ~clk;                     
  
  initial begin
      clr  = 0;
      load = 1;
      en   = 1;
      data = 4'b0101;
  end
   
  initial  #100  load  = 0;
  initial  #20   load  = 1;              // 这里的initial各条语句是并发执行的,基准的时间点是0;
  initial  #20   load  = 0;
  initial  #40   clr   = 1;
  initial  #80   clr   = 0;
endmodule

modelsim6.5 b 中的仿真波形:


在设计中会想到将两个always模块进行合并写到一个always模块中,程序代码如下:
module counter10_2(clk,clr,load,en,data,q,count);
  input clk;
  input clr;
  input load;
  input en;
  input[3:0] data;
  output reg[3:0] q;
  output reg count;
  
  
always@(posedge clk) begin
    if(clr)
       q <= 0 ;
    else if(load)
       q  <= data;
    else if(en) begin
        if(q == 9) begin
           q <= 0;
           count  <= 1;
         end
        else begin
           q  <= q + 1;
           count  <= 0;
         end
      end
  end
endmodule  

程序代码看上去没有问题,当q ==9 时,q  再次变为0 ,count_flag变为1,然而在仿真中出现的问题一目了然:
这里count_flag会延迟一个时钟得到
但在循时序电路内,就有两个要考虑:
1.使用的是non-blocking,所以q <= 0和cout_flag <= 1一起执行。
2.因为是循序电路,所以q <= 0和 cout <_flag= 1并不会马上有结果,必须等到下一个clock才出现。
所以在ModelSim的模拟,我们看到{q等于0和cout_flag等于1}同时在下一个clock时出现,所以若要cout_flag马上等于1,就不能用循序电路,而要改用组合电路,这样就会马上等于1,所以用另外一个always block来表示这个组合电路的结果才正确。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

328

主题

1073

帖子

2

粉丝