版權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須注明原文網址 http://www.cnblogs.com/Colin-Cai/p/7220107.html 作者:窗戶 QQ:6679072 E-mail:6679072@qq.com
已經很久很久很久,沒有真正在正式工作中設計過數字電路,有的只是在業余的時候玩玩。
想起最早的時候,學習數字電路設計,用的是原理圖。習慣於用原理圖去思考,后來用VHDL,再后來習慣了verilog那和C語言一樣的運算符以及簡潔的表達,不再喜歡VHDL的累贅。之所以用HDL,最初的想法僅僅是因為原理圖畫起來累,理解起來繁瑣且不便於修改罷了,腦子里最開始總是不斷在真實電路和HDL代碼中映射。
現在EDA的技術越來越發達,我一朋友從事IC設計,卻從來不理解原理圖設計,讓我一度匪夷所思,后來想想可能只是因為他沒有經歷過我們以前那個階段罷了。
閑話不多說了,回到這個主題,這其實是數字設計中經常遇到的問題。初學者看到的就是,這還不簡單,直接把這個信號引入當D觸發器的時鍾,結果超復雜的異步設計,陷入萬劫深淵無法自拔,這還沒包括外部信號可能會有干擾而產生毛刺。
首先,我們要先默認,外部輸入的信號頻率要低過主頻,否則無法處理,其次,外部輸入的信號是可能會有毛刺的。
如上所示是一個毛刺,不能當時發生了上升沿。
如上所示,只是上升沿的過程出現了毛刺,不能當成是多個上升沿發生。
那么我們得想辦法把毛刺過濾。毛刺發生的情況並不多,於是我們就想,每次系統時鍾上升沿(或下降沿)的時候都對外部數字信號采樣,當外部真正的電平(也就是去掉毛刺之后)是低電平的時候,采樣也絕大多數都是低電平,采到高電平的毛刺是鳳毛麟角,高電平也同理。
再進一步我們就會想,如果連續采到n個電平是高電平,那么實際電平就是高電平;反之,如果連續采到n個電平是低電平,那么實際電平就是低電平;如果連續抓的n個電平有高有低,則實際電平就是之前保持的。
如此就得到了過濾毛刺之后的真實信號,然后再用真實信號連續兩個系統時鍾的值來判斷上升沿下降沿。
於是有了如下設計
`timescale 1ns / 1ns module top ( nRst, clk, in, en_posedge ); input nRst, clk, in; output en_posedge; parameter W=3; reg [W-1:0]in_reg; always@(negedge nRst or posedge clk) if(!nRst) in_reg <= {W{1'b0}}; else in_reg <= {in_reg[W-2:0], in}; reg in_filter, in_filter_last; always@(negedge nRst or posedge clk) if(!nRst) in_filter <= 1'b0; else case({&in_reg, |in_reg}) 2'b00: in_filter <= 1'b0; 2'b11: in_filter <= 1'b1; default: in_filter <= in_filter; endcase always@(negedge nRst or posedge clk) if(!nRst) in_filter_last <= 1'b0; else in_filter_last <= in_filter; reg en_posedge; always@(negedge nRst or posedge clk) if(!nRst) en_posedge <= 1'b0; else if((!in_filter_last) & in_filter) en_posedge <= 1'b1; else en_posedge <= 1'b0; endmodule
所描述的電路長這樣
再來做一個testbench
`timescale 1ns / 1ns module tb; reg nRst, clk, in; wire en_posedge; top t ( nRst, clk, in, en_posedge ); initial forever begin clk = 0; #10; clk = 1; #10; end initial begin in=0; nRst=1; #5; nRst=0; #20; nRst=1; #1000; in=1; #20; in=0; #1000; repeat(3) begin in=1; #20; in=0; #20; end in=1; #1000; $stop; end endmodule
仿真圖如下
只認出了一次上升沿。抓取下降沿同理。
再來說說設計中的
parameter W=3;
這里的W代表着,設計可以過濾掉小於W-1個系統時鍾周期的毛刺。
另外,in_reg和in_filter、in_filter_last要么全1要么全0,取決於默認情況下(一般是指無通信的時候)外部輸入信號是什么電平。
想起以前工程中真的出現過問題,悲哀的教訓,后來仔細想了很久,雖然看上去不難實現,但的確是吸取教訓之后的設計結果。