本篇文章介绍时序逻辑的设计,以设计一个计数器来讲解时序逻辑,同时扩展verilog语法知识

一、时序逻辑

  时序逻辑是Verilog HDL 设计中另一类重要应用。从电路特征上看来,其特点为任意时刻的输出不仅取决于该时刻的输入,而且还和电路原来的状态有关。

  从电路行为上讲,不管输入如何变化,仅当时钟的沿(上升沿或下降沿)到达时,才有可能使输出发生变化。
  1、在描述时序电路的always块中的reg型信号都会被综合成寄存器,这是和组合逻辑电路所不同的。
  2、时序逻辑中推荐使用非阻塞赋值“<=”。
  3、时序逻辑的敏感信号列表只需要加入所用的时钟触发沿即可,其余所有的输入和条件判断信号都不用加入,这是因为时序逻辑是通过时钟信号的跳变沿来控制的。

二、时序逻辑在FPGA里RTL实现

  我们写一个简单的寄存器,看看fpga是怎样实现时序逻辑的

module	counter(
	input 			a,
	input				clk,
	
	output	reg 	q
);

	always@(posedge clk)begin
		q <= a;
	end

endmodule

  我们看一下fpga的芯片规划器

  

FPGA SEM ip时序图_加法器

   从芯片规划器,可以看出来几个细节。

  1、我们用了一个查找表、一个寄存器。对FPGA来说,这个寄存器你就算不使用他也是在那里的

  2、我么的输出信号是与clk同步的,必须要等到clk的上升沿到来是,输出才会更新,因此就实现了寄存器的功能

三、同步复位、异步复位

  1、同步复位:其实就是你的操作和时钟的上升沿同步

    举个例子,你要将q设置为0,下面这代码就是同步复位,q <= 0,是在时钟上升沿到来时执行的,所以是同步复位

module	counter(
	input 			a,
	input				clk,
	
	output	reg 	q
);

	always@(posedge clk)begin
		q <= 0;
	end

endmodule

  2、异步复位:其实就是你的操作和时钟没有关系

    举个例子,你要将q设置为0,下面这代码就是异步复位,q <= 0,无论时钟是什么状态,只有rst_n到来就执行清零

module	counter(
	input 					a,
	input						clk,
	input						rst_n,
	output	reg [7:0]	q
);

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			q <= 0;
		else	
			q <= q + 1'b1;
	end
endmodule

四、竞争冒险

  竞争冒险:意思是,在我时钟的上升沿进行采样时,输入信号处于不稳定状态,这个会给电路带来亚稳态的问题

    

FPGA SEM ip时序图_上升沿_02

     为了解决竞争冒险,我们只要满足信号的建立时间和保持时间即可

      

FPGA SEM ip时序图_上升沿_03

 五、verilog语法补充

   1、parameter 定义全局变量

parameter	T = 	26'd49_000_000;

      2、defparam 重新定义参数,这个主要是在仿真脚本修改例化的模块的内部参数

defparam counter_inst.T = 26'd49;
	
	counter counter_inst(
	.clk		(clk),
	.rst_n	(rst_n),	
	.flag		(flag)

 六、计数器设计

  设计一个1秒的计数器,当时间到一秒后给出一个flag信号

  1、代码实现 verilog.v

module	counter(
	input				clk,
	input				rst_n,
	output	reg 	flag
);

	reg	[25:0] count;
	
	parameter	T = 	26'd49_000_000;
	
	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)begin
			flag <= 1'b0;
			count <= 0;
			end
		else	if(count == T)begin
				flag <= 1'b1;
				count <= 0;
			end
		else 
			begin
				count <= count + 1'b1;
				flag <= 1'b0;
			end
	end

endmodule

  2、仿真脚本

    我在仿真脚本将时间参数改为T改为 T=26‘d49;方便仿真

`timescale 1ns/1ps


module counter_tb;

	reg				clk;
	reg				rst_n;
	wire				flag;
	
	defparam counter_inst.T = 26'd49;
	
	counter counter_inst(
	.clk		(clk),
	.rst_n	(rst_n),	
	.flag		(flag)
);

	always #10 clk = ~clk;

	initial begin
		clk = 0;
		rst_n = 0;
		#20;
		rst_n = 1;
		#5000000;
		$stop;
	end

endmodule

  3、仿真结果

    1、可以看出脉冲flag只持续了一个周期

      

FPGA SEM ip时序图_FPGA SEM ip时序图_04

     2、可以看出脉冲的触发是50个计数值

      

FPGA SEM ip时序图_寄存器_05

七、计数器里隐藏的加法器问题

  我们设计的这个计数器,里面其实用了一个加法器,加法器是组合逻辑(因为组合逻辑只取决于输入)

  当我们给加法器一个初值0的时候,加法器的输出立即就输出1,这就是仿真的时候,开始复位拉高后,count在第一个clk上升沿就为1的原因

    

FPGA SEM ip时序图_FPGA SEM ip时序图_06