专栏/HDLBits (98) — 双边触发器

HDLBits (98) — 双边触发器

2022年04月13日 04:00--浏览 · --点赞 · --评论
粉丝:3402文章:240

本题链接:

https://hdlbits.01xz.net/wiki/Dualedge

现在我们已经熟悉了触发器,它们会在时钟的上升沿或时钟的下降沿被触发。而双边触发器会在时钟的上升沿和下降沿上触发。但是,FPGA中没有双边缘触发的触发器,并且always @(posedge clk or negedge clk)并不被认为是合法的敏感列表

请构建一个功能类似于双边触发器的电路:

(注意: 这不一定是完全等价的: 触发器的输出没有报错,但是对于更大的仿真组合电路中执行此操作可能会报错。不过在这里我们可以忽略这些细节。)

题目

module top_module (
    input clk,
    input d,
    output q
);

提示:

  • 不能在FPGA中创建双边触发器。但是可以分别创建上升沿触发器和降沿触发器。

  • 这个问题是一个中等难度的电路设计问题,但只需要基本的Verilog语言功底就可以完成。(这是电路设计问题,不是编程问题。)在尝试编程之前,先手绘电路图可能会有所帮助。

答案

module top_module (
    input clk,
    input d,
    output q
);
    reg [1:0] status;

    always @(posedge clk) begin
        status[0] = d;
    end

    always @(negedge clk) begin
        status[1] = d;
    end

    assign q = clk ? status[0] : status[1];
endmodule
module top_module(
	input clk,
	input d,
	output q);
	reg p, n;
    always @(posedge clk)
        p <= d ^ n;
    always @(negedge clk)
        n <= d ^ p;
    assign q = p ^ n;
endmodule

输出波形

过程结构语句有 2 种,initial 与 always 语句。它们是行为级建模的 2 种基本语句。

一个模块中可以包含多个 initial 和 always 语句,但 2 种语句不能嵌套使用。

这些语句在模块间并行执行,与其在模块的前后顺序没有关系。

但是 initial 语句或 always 语句内部可以理解为是顺序执行的(非阻塞赋值除外)。

每个 initial 语句或 always 语句都会产生一个独立的控制流,执行时间都是从 0 时刻开始。

always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。

由于循环执行的特点,always 语句多用于仿真时钟的产生,信号行为的检测等。

在 Verilog 中,事件是指某一个 reg 或 wire 型变量发生了值的变化。

基于事件触发的时序控制又主要分为以下几种。

一般事件控制

事件控制用符号 @ 表示。

语句执行的条件是信号的值发生特定的变化。

关键字 posedge 指信号发生边沿正向跳变,negedge 指信号发生负向边沿跳变,未指明跳变方向时,则 2 种情况的边沿变化都会触发相关事件。例如:

//信号clk只要发生变化,就执行q<=d,双边沿D触发器模型 always @(clk) q <= d ;                 //在信号clk上升沿时刻,执行q<=d,正边沿D触发器模型 always @(posedge clk) q <= d ;   //在信号clk下降沿时刻,执行q<=d,负边沿D触发器模型 always @(negedge clk) q <= d ; //立刻计算d的值,并在clk上升沿时刻赋值给q,不推荐这种写法 q = @(posedge clk) d ;

命名事件控制

用户可以声明 event(事件)类型的变量,并触发该变量来识别该事件是否发生。命名事件用关键字 event 来声明,触发信号用 -> 表示。例如:

event     start_receiving ; always @( posedge clk_samp) begin         -> start_receiving ;       //采样时钟上升沿作为时间触发时刻 end   always @(start_receiving) begin     data_buf = {data_if[0], data_if[1]} ; //触发时刻,对多维数据整合 end

敏感列表

当多个信号或事件中任意一个发生变化都能够触发语句的执行时,Verilog 中使用"或"表达式来描述这种情况,用关键字 or 连接多个事件或信号。这些事件或信号组成的列表称为"敏感列表"。当然,or 也可以用逗号 , 来代替。例如:

//带有低有效复位端的D触发器模型 always @(posedge clk or negedge rstn)    begin       //always @(posedge clk , negedge rstn)    begin       //也可以使用逗号陈列多个事件触发     if(! rstn)begin         q <= 1'b ;           end     else begin         q <= d ;     end end

当组合逻辑输入变量很多时,那么编写敏感列表会很繁琐。此时,更为简洁的写法是 @* 或 @(*),表示对语句块中的所有输入变量的变化都是敏感的。例如:

always @(*) begin //always @(a, b, c, d, e, f, g, h, i, j, k, l, m) begin //两种写法等价     assign s = a? b+c : d ? e+f : g ? h+i : j ? k+l : m ; end

参考内容:

4.1 Verilog 过程结构 | 菜鸟教程:

https://www.runoob.com/w3cnote/verilog-process-structure.html

4.3 Verilog 时序控制 | 菜鸟教程:

https://www.runoob.com/w3cnote/verilog-timing-control.html


投诉或建议