使用Verilog语言描述计数器——脉动计数器。
内容说明:
本次设计的计数器属于脉动计数器。使用Verilog语言设计,并且设计方法采用模块设计和简单的行为级设计。会有这两种设计的对比测试。最后,会有对这次设计计数器过程中的一些小心得。
计数器
什么是计数器?
计数是一种最简单基本的运算。计数器就是实现这种运算的逻辑电路。计数器在数字系统中主要是对脉冲的个数进行计数,以实现测量、计数和控制的功能,同时兼有分频功能。(百度)
自己对计数器的理解。
计数器就是一个简简单单具有计数功能的模块(module)。不过,这个原理简单的计数模块在芯片和计算机中却是不可或缺的部分。计数器虽然是对脉冲个数进行计数,但是如果把脉冲个数进行某种运算,而且这种运算可以具有某种含义,那么“计数”便可以统计“某种关键量”的次数(数量)。
计数器分类:
按照触发条件:同步计数器和异步计数器。
按照功能:加法计数器、减法计数器,移位计数器、可以记录固定数值的计数器。
本次设计的脉动计数器属于减法计数器。
脉动计数器
脉动计数器是由4个T触发器组成的计数模块。具体逻辑图如图1
图1:脉动计数器逻辑图
设计思想:
这次设计给出了电路的逻辑图。在这个图中,我们可以看出需要调用4个T触发器,用时钟信号和复位信号把4个T触发器连接起来,4个T触发器的输出组成了最终的输出结果。需要先设计出T触发器,一个T触发器是由一个D触发器和一个非门构成,而D触发器之前设计过。这样设计逻辑就很简单了,先设计D触发器,之后和非门组成T触发器,最后构成脉动计数器。
这次的设计方面继续采用模块化设计。
设计代码:
D触发器设计代码:
这个D触发器功能比较完善,具有复位、置数功能。
module dff (clk,rst,load,d,q);
input clk,rst,load;
input d;
output q;
reg q;
always @ (posedge clk or negedge rst or negedge load)
if(!rst)
q<=0;
else if (!load)
q<=1;
else
q<=d;
endmodule
T触发器设计代码:
module tff (clk,rst,q);
input clk,rst;
output q;
//wire a;
//not (a,q);
//dff u1 (clk,rst,1'b1,a,q);
dff u1 (clk,rst,1'b1,~q,q);
endmodule
T触发器设计时,可以有两种想法。一种是如同注释一样,调用一个非门;另一种是在模块调用总直接取非。两种各自选取。
注:在dff u1 (clk,rst,1'b1,~q,q);
中,1'b1
不可偷懒写成1
。因为,前者代表1位二进制的1;后者代表十进制的1,具体几位看自己的计算机,一般是32位。在赋值的时候,有时会忽略数字的位数和进制,这样只要你自己可以理解不出错误,都可以(开心就好)。但是模块调用是“很严肃”的事情,这样“无所谓”会让模块调用(实例化)出现问题。
顶层模块设计代码:
module counter (clk,rst,q);
input clk,rst;
output [3:0] q;
tff u1 (.clk(clk),.rst(rst),.q(q[0]));
tff u2 (.clk(q[0]),.rst(rst),.q(q[1]));
tff u3 (.clk(q[1]),.rst(rst),.q(q[2]));
tff u4 (.clk(q[2]),.rst(rst),.q(q[3]));
endmodule
在使用模块设计之后,使用行为级编写一个简单的计数器,功能和上面设计的脉动计数器一样。不过,代码长度和难度完全不一样。
代码如下:
module counter_1 (clk,rst,q);
input clk,rst;
output [3:0] q;
reg [3:0] q;
always @ (posedge clk or negedge rst)
begin
if(!rst)
q<=0;
else
q<=q-1;
end
endmodule
测试代码:
module counter_tb;
reg clk,rst;
wire [3:0] q1,q2;
counter t1 (clk,rst,q1);
counter_1 t2 (clk,rst,q2);
initial
begin
clk=0;rst=0;
#10 rst=1;
#50 rst=0;
#10 rst=1;
#200 rst=0;
#10 $stop;
#10 $finish;
end
always #6 clk=~clk;
endmodule
运行结果:
两中不同设计方法的计数器测试结果如图2所示。
十进制输出结果如图3所示。
异步复位部分如图4所示。
图2:两中不同设计方法的计数器测试结果
注:图上显示的数值是把二进制转换为了无符号的数值。就是输出没有负数。但是如果改变输出数值的格式,比如改成十进制,结果如图3所示。
图3:十进制输出结果
对于为什么会有-8后面是7这个现象的解释。
可以这样理解,0000减1,但是减不了。向“远方”借1,最后变成了1111。这种理解方式只是让你“强行”明白减法。这里的标准回答是补码,十进制中的4位二进制数中规定最高一位是标志位。“1”表示负数;“0”表示正数。有关补码的知识之后再说。
这样也可以解释(-8)的下一位为什么是(7)。
图4:异步复位部分
可以看出异步复位不需要等待时钟的到来,就可以把输出结果复位(置零)。但是新的输出的出现需要等待时钟。
总结
本次主要介绍计数器和如何使用Verilog编写一个计数器。两种设计方法的区别,使用分模块(复杂)设计可以控制模块内部功能,自主性强一些,通过修改内部代码可以实现功能的“微调”;但是编写代码难度加大,对设计者素质要求高。使用行为级(容易)设计最大的优点简单、方便;同时缺点无法做到“窥看”内部。
预告
其他计数器的设计。计数器也有新花样。
感想
不入其行,不知其难。
入了其行,方知世界之大!!!