亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Verilog

always 的顺序逻辑

上一篇文章展示了使用 always 的不同示例 块来实现组合逻辑。一个 always block 也主要用于实现 sequential 具有存储元件的逻辑,例如可以保存值的触发器。

JK 人字拖

JK 触发器是用于存储值的多种触发器之一,它有两个数据输入 j 和 k,一个用于复位 rstn,另一个用于时钟 clk。 JK 触发器的真值表如下所示,通常使用 NAND 门实现。

rstn j k q 评论
0 0 0 0 置位复位时,输出始终为零
1 0 0 保持值 当j和k都为0时,输出和之前一样
1 0 1 1 当k=1时,输出变为1
1 1 0 0 当k=0时,输出变为0
1 1 1 切换值 当 j=1,k=1 输出切换当前值

JK触发器的行为Verilog代码可以写成如下所示

  
  
module jk_ff ( input 			j, 				// Input J
               input 			k, 				// Input K
               input 			rstn, 		// Active-low async reset
               input 			clk, 			// Input clk
               output reg q); 			// Output Q

	always @ (posedge clk or negedge rstn) begin
		if (!rstn) begin
			q <= 0;
		end else begin
	  	q <= (j & ~q) | (~k & q);
	  end
  end
endmodule

  

测试台

首先声明测试台中使用的所有变量并使用简单的 always 启动时钟 可以驱动到设计的块。然后实例化设计并将其端口与相应的测试平台变量连接起来。注意 q 的类型是 wire 因为它连接到将主动驱动它的设计输出。设计的所有其他输入都是类型 reg 以便它们可以在诸如 initial 之类的程序块内驱动 .

激励首先将设计的所有输入初始化为零,然后在一段时间后取消断言复位。 for 循环用于将不同的值驱动到随机时间驱动的 j 和 k。循环完成后,再等待一段时间并完成模拟。

  
  
module tb;
	// Declare testbench variables
	reg j, k, rstn, clk;
	wire q;
	integer i;
	reg [2:0] dly;
	
	// Start the clock 
	always #10 clk = ~clk;
	
	// Instantiate the design
	jk_ff 	u0 (	.j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
	
	// Write the stimulus
	initial begin
		{j, k, rstn, clk} <= 0;
		#10 rstn <= 1;
		
		for (i = 0; i < 10; i = i+1) begin
			dly = $random;
			#(dly) j <= $random;
			#(dly) k <= $random;
		end
		
		#20 $finish;
	end
endmodule

  

从仿真波形中可以看出,在时钟的位姿下,输出 q 会根据输入 j 和 k 的状态而改变值,如真值表所示。

<无脚本>

模 10 计数器

模数 (MOD) 计数器在回滚到零之前简单地计数到某个数字。 MOD-N 计数器将从 0 计数到 N-1,然后回滚到零并重新开始计数。这样的计数器通常需要 log2N 个触发器来保存计数值。下面显示的是一个 MOD-10 计数器的 Verilog 代码,只要复位 rstn 被取消断言,它就会在每个时钟 clk 保持计数。

Verilog 参数可用于制作更具扩展性的 MOD-N 计数器。

  
  
module mod10_counter ( 	input		clk,
												input 	rstn,
												output	reg[3:0] out);
												
	always @ (posedge clk) begin
		if (!rstn) begin
			out <= 0;
		end else begin
			if (out == 10) 
				out <= 0;
			else
				out <= out + 1;
		end
	end
endmodule

  

测试台

测试台首先声明了一些变量,这些变量可以分配一些值并驱动到设计输入。然后计数器模块被实例化并与测试台信号连接,这些信号随后被激励中的一些值驱动。由于计数器还需要时钟,因此测试台时钟使用 always 建模 堵塞。激励只是在时间 0ns 设置默认值,然后在 10ns 后取消置位复位,并允许设计运行一段时间。

  
  
module tb;
	reg clk, rstn;
	reg [3:0] out;
	
	mod10_counter u0 ( .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
		{clk, rstn} <= 0;
		
		#10 rstn <= 1;
		#450 $finish;
	end
endmodule

  

看到计数器模块从零计数到九,翻转到零,重新开始计数。

<无脚本>

4位左移寄存器

下图是一个 4 位左移寄存器,它接受一个输入 d 到 LSB,所有其他位将左移 1。例如,如果 d 等于 0 并且寄存器的初始值为 0011,它将变为 0110 在时钟 clk 的下一个边沿。

  
  
module lshift_4b_reg (  input d,                      
                        input clk,                    
                        input rstn,                   
                        output reg [3:0] out
                     );
 
   always @ (posedge clk) begin
      if (!rstn) begin
         out <= 0;
      end else begin
         out <= {out[2:0], d};
      end
   end
endmodule

  

测试台

测试平台遵循与之前所示类似的模板,其中声明了一些变量,设计模块被实例化并与测试平台信号连接。然后启动时钟并使用 initial 将激励驱动到设计中 堵塞。在这个测试台示例中,必须执行不同的 d 值,因此 for 循环用于迭代 20 次并将随机值应用于设计。

  
  
module tb;
	reg clk, rstn, d;
	wire [3:0] out;
  integer i;
	
  lshift_4b_reg u0 (  .d(d), .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
    {clk, rstn, d} <= 0;
    
    #10 rstn <= 1;
	
    for (i = 0; i < 20; i=i+1) begin
      @(posedge clk) d <= $random; 
    end
    
    #10 $finish;
	end  
endmodule

  

请注意,每个位都向左移动 1,并将 d 的新值应用于 LSB。

<无脚本>

Verilog

  1. 教程 - 编写组合和顺序代码
  2. 带开关的电路
  3. 集成电路
  4. 可编程逻辑控制器 (PLC)
  5. 布尔代数简介
  6. 卡诺图的逻辑简化
  7. 带反馈的数字逻辑
  8. 通过纯 CMOS 逻辑工艺具有自抑制电阻开关负载的 RRAM 集成 4T SRAM
  9. 具有低工作电压的基于原子层沉积的 HfAlOx 的 RRAM,用于计算内存应用
  10. Verilog Mod-N 计数器
  11. Verilog 灰色计数器
  12. 冈本磨床始终保持光滑表面