我是靠谱客的博主 单薄水池,最近开发中收集的这篇文章主要介绍1.2.5 D触发器与多路延迟一、时序电路二、数据类型三、带复位的触发器四、锁存器(latch)五、多级延迟的触发器六、计数器七、分频器与门控使能信号,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 一、时序电路
    • 1.D触发器
    • 2.阻塞赋值与非阻塞赋值
  • 二、数据类型
    • 1.线网类型
    • 2.寄存器类型
  • 三、带复位的触发器
  • 四、锁存器(latch)
  • 五、多级延迟的触发器
  • 六、计数器
  • 七、分频器与门控使能信号

一、时序电路

1.D触发器

先来看一个最简单的时序电路:

module D1(
input D,
input CLK,
output reg Q
);

always@(posedge CLK)
	begin
		Q <= D;
	end
	
endmodule		

上面描述了一个最简单的边沿触发的D触发器:输入数据D,在下一时钟周期就输出Q。
其中,数据的存储时刻是时钟信号的上升沿(跳变瞬间),即寄存器Q在时钟上升沿采样到数据D,并更新存储内容;
除了时钟上升沿的其他时刻,无论D如何变化,都不会存储到Q寄存器中。只要理解这一点,就明白了数字电路进行时序电路控制的基础。

2.阻塞赋值与非阻塞赋值

在Verilog中,信号有两种赋值方式:
1.非阻塞(Non-Blocking)赋值方式: b <= a
(1)在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用;
(2)块结束后才能完成这次赋值操作,而所赋的变量值是上一次赋值得到的;
(3)在编写可综合的时序逻辑模块时,是最常用的赋值方法。

always@(posedge CLK)
	begin
		b <= a;
		c <= b;
	end

赋值是在always块结束后进行的,c应为原来b的值。实际电路如图:
在这里插入图片描述
2.阻塞(Blocking)赋值方式:b = a
(1)赋值语句执行完后,块才结束;
(2)b的值在赋值语句执行完后立刻改变;
(3)在时序逻辑中使用时,可能会产生意想不到的后果。

always@(posedge CLK)
	begin
		b = a;
		c = b;
	end

赋值是马上执行的,也就是说执行b=a之后,c=b也立即执行,最后c为a的值,即c=a。实际电路如图:
在这里插入图片描述
3.阻塞赋值与非阻塞赋值是Verilog中专门针对电路行为而特殊设计的赋值语句。

1.对于组合电路,信号传递过来是立即生效的,而且生效的值也将继续传递,直到某个寄存器或存储单元终结;
2.对于D触发器而言,对它们中的任何一个赋值,只要不是在触发沿上,都是无效的,而且输出的值也一直保持稳定不变,直到新的时钟沿到来并更新存储的数据。

因此,对于寄存器的赋值应当是非阻塞赋值,因为寄存器采样数据发生在当前模块执行完毕后。
而对于组合电路赋值,应当采用阻塞赋值。

二、数据类型

在Verilog中,根据电路描述的行为特征,定义了两种数据类型:1.线网类型(net type);2.寄存器类型(reg type)

1.线网类型

线网类型主要有两种:1.wire型2.tri型
1.线网类型用于对结构化器件之间的物理连线建模,如:器件的引脚、内部器件(如与非门的输出)等。

由于线网类型代表的是物理连接线,所以它不存储逻辑值,必须由器件驱动,通常由assign进行赋值。若wire型信号没有被驱动时,默认为Z(高阻态)。当信号没有定义数据类型时,默认为wire型。

2.tri类型主要用于定义三态的线网,不可综合,因此只在仿真测试或功能模型中使用。

2.寄存器类型

1.寄存器类型为reg,是数据存储单元的抽象。reg型数据的默认值为x(不定值)
2.reg类型数据常用于表示always模块内的指定信号,常代表触发器在always模块内被赋值的每一个信号都要被定义成reg型
3.对于reg型数据,其赋值语句的作用就如同改变一组触发器的存储单元的值
4.reg型数据可以赋正值,也可以赋负值。但当一个reg型数据是一个表达式中的操作数时,它的值被当作无符号值,即正值
5.注意:reg型只表示被定义的信号将用于always模块内,并不是说reg型信号一定是寄存器或触发器的输出。

三、带复位的触发器

1.最简单的带异步复位的触发器:

module DFF1(
input clk,
input rst,
input d,
output reg q
);

//negedge表示复位信号低电平有效
always@(posedge clk or negedge rst)
begin
	if(!rst)
		q <= 0;
	else
		q <= d;
end

endmodule

2.最简单的带同步复位的触发器:

module DFF1(
input clk,
input rst,
input d,
output reg q
);

//negedge表示复位信号低电平有效
always@(posedge clk)
begin
	if(!rst)
		q <= 0;
	else
		q <= d;
end

endmodule

3.综上,同步复位与异步复位的区别就在于:always语句的敏感列表中是否添加了复位信号

四、锁存器(latch)

锁存器在同步电路中应该尽量避免(除非做专门的特殊处理),但锁存器也有一定的优点。
一、下面是一个电平敏感型锁存器结构:

// latch
module latch_D #(parameter N = 2) (
input clk,
input [N-1:0] d,
output [N-1:0] q,
);

assign q = clk ? d : q; //锁存器电路描述

endmodule

1.当时钟信号为高电平时,将输入端信号打入锁存器
当时钟信号为低电平时,锁存原来已打入的数据
2.通常锁存器数据有效,滞后于控制信号有效

二、锁存器结构也可以用always结构来描述:

module latch_D #(parameter N = 2) (
input clk,
input [N-1:0] d,
output reg [N-1:0] q
);

always@(clk or d)  //always@(*)
begin
	if(clk)
		q = d;
end

endmodule

由于if语句的不完整,缺少else分支,导致q变为锁存器。

三、锁存器结构用case语句也可以表示:

module latch_D #(parameter N = 2) (
input clk,
input [N-1:0] d,
output reg [N-1:0] q 
);

always@(clk or d)  //always@(*)
begin
	case(clk)
	1 : q = d;
	endcase
end

endmodule

由于case语句中没有default项,导致q成为锁存器。

五、多级延迟的触发器

1.对输入信号进行多级延迟:

always@(posedge clk or negedge rst)
	begin
		d0 <= d;
		d1 <= d0;
		q <= d1;
	end

其中:d0是d的延迟一级采样,或者称为d的延迟一拍信号;同样d1是d的延迟2拍信号,q是d的延迟3拍信号。
此电路的主要用法:
(1)若d信号相对于clk属于不稳定信号,则q和d1输出相对于clk属于稳定信号;
(2)可以通过d1和q信号来获取d信号的上升沿和下降沿;
(3)单纯地对d信号进行延迟操作。

2.可以发现:原始信号d与延迟1拍的信号d0的反向信号相与就是上升沿脉冲;而下降沿脉冲则是原始信号d取反,与延迟1拍信号d0相与的结果。代码如下:

assign D_rising_edge = d & ~d0;
assign D_falling_edge = ~d & d0;

六、计数器

计数器电路的主要用途有:1计数;2看门狗;3特殊的有限状态机描述。
1.最简单的N位计数器,默认范围为[0 : 2^N-1]的写法为:

module count #(parameter N = 8) (
input clk,
input rst,
output [N-1:0] cnt_Q
);

reg [N-1:0] cnt;   //临时变量,用于防止其他调用者误认为输出锁存
assign cnt_Q = cnt;

always@(posedge)
	begin
		if(rst)
			cnt <= 0;
		else
			cnt <= cnt + 1;
	end

endmodule

通过rst信号清除计数器的数值,然后在下一周期开始加1计数。当计数器达到能够存储的最大数值时,本例为8个1,即8’1111_1111时就回自动回到0,然后开始下一轮计数。

2.若实现[0 : K]范围内的计数,其中K ≠ 2^N,则可以将上面程序进行修改:

always@(posedge clk)
	begin
		if(rst)
			cnt <= 0;
		else if(cnt == K)
			cnt <= 0;
		else
			cnt <= cnt + 1;
	end

七、分频器与门控使能信号

1.计数器实质上是对输入的驱动时钟进行计数,因此在某种意义上讲,计数器等同于对时钟进行分频。
2.一个最大计数位宽为N的计数器,将其最高位作为时钟输出(占空比不一定为1:1),则工作频率为输入频率的1/2N。
3.通常在ASIC和FPGA中,时钟都是全局信号,需要通过PLL处理才能使用,但在某些简易场合,计数器输出时钟也是能够使用的,只是需要注意时序约束罢了。

1.下面的例子是一个基于计数器的通用时钟分频器,能够支持任意整数倍分IP你,占空比尽量接近于1:1。

module clock_div #(parameter cdfactor = 2) (
input clk_in,  //标准参考时钟输入
input rst_x,   //复位信号
output clk_out //分频时钟输出
);

reg clk_loc;   //分频时钟的内部变量
//reg [15:0] cnt;  //最大支持65536分频
reg [7:0] cnt;   //最大支持256分频

//根据分频因子cd_factor选择输入等于输出还是分频
assign clk_out = (cdfactor == 1) ? clk_in : clk_out;

always@(posedge clk or negedge rst_x)
begin
	if(!rst_x)
		begin
			cnt <= 0;
			clk_loc <= 1;
		end
	else
		begin
			cnt <= cnt + 1;
			if(cnt == cdfactor/2 - 1)
				clk_loc <= 0;
			else if(cnt == cdfactor - 1)
				begin
					cnt <= 0;
					clk_loc <= 1;
				end
		end
end

endmodule

2.此外,还可以通过对计数器状态的判断,给出使能信号指示,从而间接达到门控时钟的目的。
例如下面的Q寄存器,若enable信号不为高,则无法更新内容,并一直保持现有的工作状态。这与Q输入时钟为clk&enable的组合信号没有太多区别。而enable信号可以通过cnt的某一个计数区间或状态来获得。

assign enable = (cnt[N-1] == 1'b1) ? 1'b1 : 1'b0;
always@(posedge clk)
	begin
		if(enable)
			Q <= D;
	end

最后

以上就是单薄水池为你收集整理的1.2.5 D触发器与多路延迟一、时序电路二、数据类型三、带复位的触发器四、锁存器(latch)五、多级延迟的触发器六、计数器七、分频器与门控使能信号的全部内容,希望文章能够帮你解决1.2.5 D触发器与多路延迟一、时序电路二、数据类型三、带复位的触发器四、锁存器(latch)五、多级延迟的触发器六、计数器七、分频器与门控使能信号所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部