CP有效沿到来之前电路的状态称为当前状态,用QnQ^nQn表示。
(相关资料图)
CP有效沿到来后,电路进入的新状态称为次级状态,用Qn+1Q^{n+1}Qn+1表示。
D
QnQ^nQn
Qn+1Q^{n+1}Qn+1
0
0
0
0
1
0
1
0
1
1
1
1
Qn+1=DQ^{n+1}=DQn+1=D
由于直接置位和清除与CP信号无关,因此该置位和清除操作称为异步置位和清除。
直接置1、直接清零的过程如下:
(1) 当SˉD=0\bar{S}_{D}=0SˉD=0时,RˉD=1\bar{R}_{D}=1RˉD=1,令Y1=1Y_{1}=1Y1=1 , Sˉ=Y1CPRˉD=CP\bar{S}=\overline{Y_{1} \cdot C P \cdot \bar{R}_{D}}=\overline{C P}Sˉ=Y1 CPRˉD=CP, Rˉ=SˉCPY4=1\quad \bar{R}=\overline{\bar{S} \cdot C P \cdot Y_{4}}=1Rˉ=Sˉ CPY4=1,所以Q=1Q=1Q=1,Qˉ=0\bar{Q}=0Qˉ=0,即输出Q直接设置为1。
(2) 当SˉD=1\bar{S}_{\mathrm{D}}=1SˉD=1时,RˉD=0\bar{R}_{\mathrm{D}}=0RˉD=0,使得Sˉ=1\bar{S}=1Sˉ=1,所以Q=0Q=0Q=0,Qˉ=1\bar{Q}=1Qˉ=1,即输出Q直接清零。
所谓同步清零,是指只有清零输入信号有效且CP有效沿(如上升沿)到来时,触发器才能被清零。
(a) 实现同步清算的方案之一
(b)第二种实现同步清算的方案
功能:
En=0,Q保持不变。 En=1,在CP作用下,Q=D。 Qn+1=CEQn+CEDQ^{n+1}=\overline{C E} \cdot Q^{n}+C E \cdot DQn +1=CEQn+CED
逻辑符号
示例1. 尝试对具有异步清零和异步设置的边沿D 触发器进行建模,如图所示。
具有异步输入的D 触发器
//版本1:模块Set_Rst_DFF(Q,Q_,D,CP,Rd_,Sd_);输出Q,Q_;输入D、CP、Rd_、Sd_;电线Y1、Y2、Y3、Y4、Y5、Y6;赋值#5 Y1=~(Sd_ Y2 Y4);赋值#5 Y2=~(Rd_ CP Y1);赋值#5 Y3=~(CP Y2 Y4);赋值#5 Y4=~(Rd_ Y3 D );赋值#5 Y5=~ (Sd_ Y2 Y6);赋值#5 Y6=~(Rd_ Y3 Y5);赋值Q=Y5;赋值Q_=Y6; endmodule 复制代码版本1: 使用连续赋值语句按照该图建模,赋值语句中#5表示给每个与非门添加5个单位时间的传输延迟。
//版本2模块Set_Rst_DFF_bh(Q,Q_,D,CP,Rd_,Sd_);输出寄存器Q;输出Q_;输入D、CP、Rd_、Sd_;赋值Q_=~Q;总是@(kedge CP 或negedge Sd_ 或negedge Rd_) if (~Sd_) //相当于: if (Sd_==0) Q=1'b1;否则如果(~Rd_) Q=1'b0;否则Q=D; endmodule 复制了代码版本2 的功能:
采用函数式描述风格,使用always和if-else为输出变量赋值。
negedge Sd_ 是一个异步事件,必须匹配if (~Sd_)。 negedge Rd_ 是另一个异步事件,它必须匹配if (~Rd_)。这是语法要求。
当Sd_为0时,输出Q置1;当Sd_=1且Rd_=0时,输出Q设置为0;当Sd_ 和Rd_ 都不为0,并且时钟CP 的上升沿到达时,输出Q 被设置为0。输入D 被传递到输出Q。请注意,如果设置1 事件、设置0 事件和时钟事件如果同时发生,则设置1 事件的优先级最高,其次是设置0 事件,时钟事件的优先级最低。
示例2 具有同步清零功能的上升沿D 触发器。
模块Sync_rst_DFF(Q,D,CP,Rd_);输出寄存器Q;输入D、CP、Rd_;总是@(posege CP) if ( !Rd_) //也作为(~Rd_) Q=0; else Q=D ;endmodule 复制代码示例4 使用功能描述风格对如图所示的电路(2 分电路)进行建模,并给出仿真结果。
解决方案:(1)设计块:使用always和if-else语句给输出变量赋值。代码如下。
`时间刻度1 ns/1 nsmodule _2Divider (Q,CP,Rd_);输出寄存器Q;输入CP,Rd_;有线;赋值D=~Q;总是@(posege CP 或negedge Rd_) if(~Rd_) Q=1'b0;否则Q=D; endmodule复制代码(2)激励块:为输入变量赋值。
`时间刻度1 ns/1 nsmodule test_2Divider();reg CP, Rd_; wire Q;//调用(实例化)设计block_2Divider U1 (.CP(CP),Q(Q),Rd_(Rd_) ) ;initial begin //生成复位信号Rd_ Rd_=1'b0; rd_=#2000 1'b1;#8000 $stop;end always begin //生成时钟信号CP CP=1'b0; CP=#500 1'b1 ; #500;end endmodule复制代码(3)仿真波形(使用ModelSim)
从图中可以看出,时钟CP的周期为1000ns。在2000ns之前,清零信号Rd_有效,输出Q清零。之后,Rd_=1,2500ns时,CP上升沿到来,Q=1;在下一个CP 上升沿(3500ns),Q=0,在下一个CP 上升沿(4500ns),Q=1,如此重复,直到8000ns,执行系统任务$stop模拟停止。
简而言之,当不考虑清零信号Rd_的作用时,每CP的上升沿到来,触发器状态Q就翻转一次。输出信号Q的频率正好是CP频率的二分之一,因此该电路称为除2电路。所谓分频电路是指能够将输入的高频信号变换为低频信号输出的电路。
例5 尝试对如图所示的电路进行建模并给出仿真结果。
4位异步二进制计数器逻辑图
解决方案: (1)设计块:采用结构描述风格的代码如下。编写了两个模块,可以将其放在一个名为Ripplecounter.v 的文件中。
第一个主模块Ripplecounter 用作设计的顶层。实例化了分频器子模块_2Divider1 4次,第二个分频器子模块_2Divider1作为设计的底层。
`timescale 1 ns/1 ns/*====设计模块:Ripplecounter.v====*/module Ripplecounter (Q,CP,CLR_);输出[3:0] Q;输入CP、CLR_; //实例引用分频器module_2Divider1 _2Divider1 FF0 (Q[0],CP ,CLR_); //注意,引用时端口的顺序- 位置关联_2Divider1 FF1 (Q[1],~Q[0],CLR_) ; _2除法器1 FF2(Q[2],~Q[1],CLR_); _2Divider1 FF3(Q[3],~Q[2],CLR_);endmodule复制代码设计的底层模块_2Divider1
//分频器子模块模块_2Divider1(Q,CP,Rd_);输出寄存器Q;输入CP,Rd_;总是@(posege CP 或negedge Rd_) if(!Rd_) Q=1'b0; else Q=~ Q;endmodule 复制代码(2) 激励块:为输入变量(CLR_和CP)赋值。
/*====激励块:test_Ripplecounter.v====*/module test_Ripplecounter();reg CLR_, CP;wire [3:0] Q;Ripplecounter i1 (.CLR_(CLR_),CP(CP), Q(Q));初始开始//CLR_ CLR_=1'b0; CLR_=#20 1'b1;#400 $stop;end always begin //CPCP=1'b0;CP=#10 1'b1;# 10;end endmodule 复制代码(3) 仿真波形:如图以下。
如图所示,
时钟CP的周期为20ns。开始时,清零信号CLR_有效(0~20ns),输出Q清零。 20ns后,CLR_始终为高电平。 30ns时,CP上升沿到来,Q=0001;在CP 的下一个上升沿(50ns),Q=0010,在CP 的下一个上升沿(70ns),Q=0011,依此类推,直到310ns,Q=1111,在330ns, Q=0000,直到执行系统任务$stop,模拟停止。该电路首先在CLR_的作用下清除输出。此后,当CLR_=1时,每当CP的上升沿到来时,电路状态Q在原来的二进制值的基础上加1,符合二进制递增计数的规则。直到计数值到达1111时,又出现CP的上升沿。计数值返回到0000并重新开始计数。因此,该电路称为4位二进制向上计数器(Ripplecounter:纹波计数器)。
可以看出,计数器实际上是对时钟脉冲进行计数的。每次时钟脉冲触发边沿到达时,计数器都会改变状态。
参考:
Verilog HDL与FPGA数字系统设计,Roger,机械工业出版社,2015年4月Verilog HDL与CPLD/FPGA项目开发教程(第2版),聂章龙,机械工业出版社,2015年12月Verilog HDL数字设计与综合(第2版), Samir Palnitkar 着,夏宇文等译,电子工业出版社,2015 年8 月Verilog HDL 导论(第3 版),J. BHASKER 着,夏宇文、甘伟译,北京航空航天大学学会出版, 2019 年3 月