双边沿触发器

双边沿触发器在时钟的每个上升沿和下降沿都会触发。但是在FPGA中没有双边沿触发器,并且像always @(posedge clk or negedge clk)这样的描述方式并不合法。

建立如下一个类似双边沿触发器的的电路:

Hint:

  • 在FPGA中不能创造双边沿触发器,但是我们可以把上升沿触发器和下降沿触发器都创造出来。
  • 这个题是一个中等难度的电路设计题,但是只需要基础的Verilog语言知识。(这是一个电路设计题,而不是一个编码题。)在编码前手画一个电路草图可能会有帮助。

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


想要对时钟进行双边沿触发主要有三种方法。

一种就是像楼上所说,使用电平敏感触发,能够实现时钟的双边沿触发,但是一般不推荐这种方法触发,这种方法虽然在逻辑上是可行的,但verilog终归不是C一样的高级语言,它的每段代码都需经过综合布线实现的,因此在用verilog实现算法的时候还需考虑代码书写风格的合理性,而对时钟信号使用电平触发,很有可能在某些情况下就不能满足时序。

第二种就是就是将上升沿和下降沿分成两个always快来写,这样子写的缺点就是不能在两个always块中对同一个reg变量做操作,同时这样写总觉得会很蛋疼。

第三种就是利用pll将时钟信号延迟或者滞后180°,分别对上升沿触发,或者干脆将时钟倍频,这样子就不需要考虑太多了。

另外,对于频率不是很快的时钟信号或者是一些异步信号建议采用脉冲形式同步,也就是在一个足够快的时钟下(如50M),可以实时监测输入信号的电平,当两次相邻电平异或之后为1,就表示有上升沿或者下降沿(01表示有上升沿,10表示有下降沿),这样子的好处就是,你的所有模块都可以在同一个工作时钟下工作,而不会因为一些其他时钟信号或异步信号而将电路变成异步电路。

(以上有些是参考网上资料,有些是我实际操作的经验,还望采纳)http://www.openedv.com/posts/list/55917.htm

 使用电平敏感触发方式和将时钟信号翻转或滞后180°,这两种方式都可以正确的实现电路功能,但是编译后会出现不满足时序的要求,可能是因为编译器将这两种方式都认为是组合逻辑电路。

如上图所示,没有产生always过程块在时钟周期结束后才进行赋值的一个周期延时。因此我们把目光放在写两个always过程块这种方法上,一个上升沿触发,一个下降沿触发。

笔者分别手画出了d在上升沿和下降沿产生的q1q2两个信号,在仔细观察后发现这两个信号和原信号d没有任何关系(其实是因为这里第一步就进入了错误思路)。通过观察手画的信号图,发现可以在时钟为正电平时将q1信号赋值给q,在时钟为负电平时,将q2赋值给q,这样就解决了如何将q1q2变为q的问题,也就是将一个信号通过时钟上升沿和下降沿分解后再还原成为原本的信号。跳过了双边沿触发,也满足了时序。

module top_module (
    input clk,
    input d,
    output q
);
    reg q1,q2;
    always@(posedge clk)
        q1 <= d;
    always@(negedge clk)
        q2 <= d ;
    
    always@(clk)
        if(clk)
            q <= q1;
   	else 
            q <= q2;

endmodule

 上面的第三个always块也可以用组合逻辑来描述:assign q = clk ? q1:q2;

上面的主要思路是使用别的方法跳过双边沿触发器这个模块,也就是将d信号包装成两个不同的信号,再将这两个信号还原成d信号。这种思想其实可以用一个很简单的的电路来表达。那就是异或“^”。

module top_module(
	input clk,
	input d,
	output q);
	
	reg p, n;
	
	// A positive-edge triggered flip-flop
    always @(posedge clk)
        p <= d ^ n;
        
    // A negative-edge triggered flip-flop
    always @(negedge clk)
        n <= d ^ p;
    
    // Why does this work? 
    // After posedge clk, p changes to d^n. Thus q = (p^n) = (d^n^n) = d.
    // After negedge clk, n changes to d^p. Thus q = (p^n) = (p^d^p) = d.
    // At each (positive or negative) clock edge, p and n FFs alternately
    // load a value that will cancel out the other and cause the new value of d to remain.
    assign q = p ^ n;
    
    
	// Can't synthesis this.
	/*always @(posedge clk, negedge clk) begin
		q <= d;
	end*/
    
    
endmodule

正如上述代码所示,直接用异或的特性,d^n^n=d。把p和n当做中间量载体,改变了d信号但又很容易就可以还原,甚至p和n的初始值都没有设定,因为实际上都没有用到p和n的值。

  • 12
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值