2011年3月25日 星期五

原來D-Flip Flop可以這麼深奧...

強者蕭兄的問題如下:

(1)問題1
我想做出以下這個功能,內附verilog與vhdl模擬的結果timing圖







這是用Verilog的實現
當然我用VHDL可以寫一個很Verilog style的VHDL來實現這個功能沒問題
但我發現VHDL本身就提供rising_edge( )這個函數,
一般都是用來取代if clk'event and clk = '1'
我想利用rising_edge( )來實現我這個需求
以下是我寫的vhdl,但發現模擬結果不正確
若我想用rising_edge來寫,我該怎麼改?
//========== 以上蕭兄的問題1結束 ==========

看到這類問題
我的第一個直覺就是他code寫錯了
果不其然
他犯了全天下男人都會犯的錯(咦???)


我們先來看一下他的code吧

library ieee;
use ieee.std_logic_1164.all;

entity detect_rising_edge is 
  port (
    clk   : in std_logic;
    rst_n : in std_logic;
    d     : in std_logic;
    q     : out std_logic
  );
end entity;

architecture arc of detect_rising_edge is 
begin
  process(clk, rst_n, d) begin
    if (rst_n = '0') then
      q <= '0';
    elsif rising_edge(clk) then
      if rising_edge(d) then
        q <= '1';
      else
        q <= '0';
      end if;
    end if;
  end process;
end arc;

果然, 他的process真的出了問題了
首先, 他希望用一個process來完成兩個d-ff的功能
基本上是不太可能的(應該說是完全不可能)
因為在一個VHDL的process中
它的基本架構是長成下面這個樣子的:

沒錯, 這裡可以看得出來
觸發源只有一個clk
因此在elsif的地方呢
蕭兄用了兩次rising_edge
這個很明顯無法產生正確的結果
因為VHDL會只認第一個rising_edge
下一個rising_edge, 它會認定條件不成立
(本來就沒有的東西, 難不成要叫娘子出來看上帝???)
所以當然只跑 q <= '0' 這個敘述


那麼正確的該怎麼寫呢
我們先來看一下蕭兄的Verilog程式吧!!!
(總是要給人家一點面子, 但面子也是人家湊上來......丟的......)

reg q;
reg d_d1;

always@(posedge clk or negedge rst_n)
  if (~rst_n)
    d_d1 <= 1'b0;
  else
    d_d1 <= d;
    
always@(posedge clk or negedge rst_n)
  if (~rst_n)
    q <= 1'b0;
  else ({d_d1, d} == 2'b01)
    q <= 1'b1;
  else
    q <= 1'b0;

不愧是蕭兄, 連Verilog都寫得很簡潔
那麼VHDL呢??
請看小弟的寫法

architecture arc of detect_rising_edge is 
    signal d_d1    :std_logic;
    signal d_con:std_logic;
begin
    process(clk, rst_n)
    begin
        if(rst_n = '0') then
            d_d1 <= '0';
        elsif rising_edge(clk) then
            d_d1 <= d;
        end if;
    end process;
    
    d_con <= (not d_d1) and d;
    
    process(clk, rst_n, d_con)
    begin
        if(rst_n = '0') then
            q <= '0';
        elsif rising_edge(clk) then
            q <= d_con;
        end if;
    end process;    
end arc;

沒錯, 就是這樣, 兩個是不是很像呢???
兩個always對應到兩個process
再根據先前所提的理論
來驗證一下RTL吧(使用工具: Xilinx ISE 10.1)

rtl_vhdl.PNG

再加上模擬結果

sim_vhdl.PNG

是不是跟蕭兄的結果一模一樣呢???

其實蕭兄原先的想法是
不想用到與Verilog的coding style去寫VHDL
而我也曾試著改過他的code
發現真的不行
我才深入思考數位邏輯內的架構是如何

另外
在simulation時也發現一個好玩的問題
若剛好d的上升源離clk的上升源太近的話
delay的效果就不見囉
這是因為在第二個D-FF前只有一個clock cycle delay
通常這類的設計會使用兩個以上
如下圖

edge_detect.gif

很明顯的, input訊號需要先被同步後再進行delay
這樣才能確保正確的判斷所輸入的資料是否有產生變化
(上圖為雙邊檢測)

以上
是回答蕭兄的"問題1"......
其他的問題會陸續補上解答
(這小子問題還真多 = = )

沒有留言: