Menu Close

Verilog 计数器设计及触发器模型深度分析

计数器是时序电路中比较简单的模型,但对于Verilog语法的训练和复习起到不可或缺的作用。计数器设计中有16进制计数器,10进制计数器(BCD码计数器),60进制计数器,30进制计数器等不同的模型,这些模型在数字电路中学习中已经有较为详细的介绍。本节内容主要是利用Verilog描述语言对这些计数器进行描述,从而学会Verilog基础语法在时序电路设计中的应用。

 

 1.二进制计数器

二进制计数器是指将reg类型的向量按照整体使用,向量的权值都是2的幂次方。对于4位二进制组成的向量可以表达的范围0-9 a,b,c,d,e,f 总共16个数值,因此也把二进制计数器称为16进制计数器。

例1:

module count16
(
    input             rst,
    input             clk,
    output reg [15:0] count_hex
);
 
always@(posedge clk or posedge rst)
if(rst) 
begin   //  异步复位
    count_hex <= 0;
end
else        //同步释放
    count_hex <= count_hex + 1;
 
endmodule

在时钟的使用及触发器模型 中我们介绍了在时钟边沿的驱动下,reg型变量可以通过触发器模型来分析。对于D触发器,有D端,Q端,时钟端。如图1:

图 1

(1)  触发器的时钟端

时钟端比较好理解,因为在always过程中有posedge 关键字,所以我们知道所有寄存器(count_hex[15:0])对应触发器的clk端全部连在一起组成同步时序电路。

(2)  触发器的D端和Q端

对于count_hex<=count_hex+1; 这样的赋值语句,左边和右边都有寄存器变量,到底哪一边是触发器的D端,哪一边是Q端?

我们可以这样分析,在赋值语句的左边count_hex是被赋值变量,而触发器的Q端是输出端,如果左端是Q,就会给输出端赋值,这不合理,因此赋值语句左边的count_hex只能是触发器的D端。赋值语句右边希望能在稳定输出的前提下评估组合逻辑运算,将运算的结果赋给D端,从这一点看赋值语句右边count_hex只能是Q端,这和数字电路中现态次态分析是一致的。

因次结论如下:对于类似的count_hex<=count_hex+1;赋值语句,赋值语句左边对应的触发器的D端,赋值语句右边对应的是触发器的Q端的现态。

另外,如果在仿真波形上或signal_tap,ILA等调试工具上看到的寄存器的值(触发器模型),都是触发器的Q端的值。

因此例1的程序可以用图2-1的模型来理解。在Vivado中经过analysis & elaboration 后的模型如图2-2所示。

图2-1

图2-2

2.十进制计数器(BCD码计数器)

十进制计数器就是逢9进1,当多位十进制计数器级联时,处在不同位置的寄存器向量的权值不同。如例2中的向量a,b,c,d, a代表个位,b为十位,c为百位,d为千位。因此如果b要实现加1,a需要产生进位,即当a==9时,如果a再出现加1的情况下,a将回归到0,而b将实现加1操作。b到c,c到d的计数及进位操作与a到b的情况类似。与2进制计数器不同,进位按照2进制的规律(16进制的规律)可以自动实现,因此各级的回归于进位需要if或case等分支判断语句帮助实现。

例2:

十进制计数器程序

module BCD_counter
(
    input            clk,
    input            rst,
    output reg [3:0] a,
    output reg [3:0] b,
    output reg [3:0] c,
    output reg [3:0] d
);
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    a <= 0;
    b <= 0;
    c <= 0;
    d <= 0;
end
else 
begin
    if(a == 9)
    begin
        a <= 0;
        if(b == 9)
        begin
            b <= 0;
            if(c == 9)
            begin
                c <= 0;
                if(d == 9)  d <= 0;
                else      d <= d + 1;
            end
            else  c <= c + 1;
        end
        else
            b <= b + 1;
    end
    else
        a <= a + 1;
end
 
endmodule

 

testbench 仿真程序 tb.v

`timescale  1ns/1ps
 
 
module tb
(
);
 
parameter PERIOD = 10;
 
reg clk;
 
initial 
begin
    clk = 1'b0;
    # (PERIOD/2)
  
    forever 
        # (PERIOD/2) 
        clk=~clk;
end
 
wire [3:0] a, b, c, d;
 
reg         rst;
 
initial 
begin
    rst = 1;
    #20
 
    rst = 0;
end
 
 
BCD_counter BCD_counter_inst
(
    .rst  (rst),
    .clk  (clk),
    .a    (a),
    .b    (b),
    .c    (c),
    .d    (d)
);
 
endmodule

 

仿真波形如下:

图3

图4

在10进制计数器中,if(a==9)的语句中,a的模型如果为D触发器,那么这里a是D端还是Q端?由于D端接收的是组合逻辑,在整个周期内D的是不稳定的。而Q值在上升沿后到下一个上升沿之前都是稳定的,因此这里的a指的是a的Q端。

 

3.        60进制计数器

上面解决了D触发器模型的问题后,60进制计数器就显得比较简单了。

例4:

module counter60
(
    input            clk,
    input            rst,
    output reg [3:0] a,
    output reg [3:0] b
);
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    a <= 0;
    b <= 0;
end
else 
begin
    if(a == 9)
    begin
        a <= 0;
        if(b == 5) b <= 0; 
        else     b <= b + 1;
    end
    else
        a <= a + 1;          
end
 
endmodule

 

4.     12进制计数器

12进制计数器由两个部分构成:

  1. 在a, b 组合中不满足十进制的12,即不满足(a==2)&&(b==1)的情况下,a,b组合仍然满足10进制的计数规律。
  2. 当满足(a==2)&&(b==1)条件时,高位清零,低位置1。即b<=0; a<=1;

12进制的Verilog程序如下:

module counter12
(
    input            clk,
    input            rst,
    output reg [3:0] a,
    output reg [3:0] b
);
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    a <= 1;
    b <= 0;
end
else 
begin
    if((a == 2)&&(b == 1))
    begin
        a <= 1;
        b <= 0; 
    end
    else if(a == 9)
    begin
       a <= 0;
       b <= b + 1;
    end
    else
        a <= a + 1;          
end
 
endmodule

 

图5

 

5.       24进制计数器

24进制计数器与12进制计数器非常相似,可以直接12进制的方式进行分析和设计,24进制的Verilog程序如下:

module counter24
(
    input            clk,
    input            rst,
    output reg [3:0] a,
    output reg [3:0] b
);
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    a <= 0;
    b <= 0;
end
else 
begin
    if((a == 3)&&(b == 2))
    begin
        a <= 0;
        b <= 0; 
    end
    else if(a == 9)
    begin
        a <= 0;
        b <= b + 1;
    end
    else
        a <= a + 1;          
end
 
endmodule

 

图6

 

其它的计数器如30进制,31进制,28进制,29进制,7进制等,这里就不一一介绍了,可以参照复杂数字钟设计部分内容。

思考题:试分析以下语句有何区别?(a为4位 reg类型)

a <= a + 1;

a <= a + 1’b1;

a <= a + 4’b1;

a <= a + 4’h1;

a <= a + 32’b1;

a <= a + ‘b1;

a <= a + ‘h1;

 

Posted in FPGA, FPGA 教材教案, Verilog, Verilog

发表回复

相关链接