我曾經說過,電子系的本科課程,可以串成一條宏偉的線索,它們從單個電子的運動規律出發,教你一層又一層地搭建出五彩繽紛的硬體、軟體與網路世界。當我在大四悟到這一點的時候,是心潮澎湃的。但是,在這條線索上,卻有一個關鍵的環節我一直沒搞懂,這是我本科時代的一個遺憾。

  這關鍵的一環,就是「數字電路」課程中的「D 觸發器

」。「D 觸發器」是計算機系統中存儲器的基本組成單元。它有「時鐘」和「數據」兩個輸入,功能是這樣的:

  1. 當時鐘的上升沿到來時[1],根據外界輸入的數據,改變自身的內部狀態;

  2. 在其它時候,保持自身的內部狀態不變。

  「D 觸發器」有多種實現方式。有一種實現方式使用了 8 個與非門

,下面這篇文章言簡意賅地介紹了它的設計思路,十分值得一讀:

三郎:計算機數學小書2-D觸發器的進化之路?

zhuanlan.zhihu.com圖標

但還有一種更加「節省」的實現方式,只用了 6 個與非門,這就是我長久以來沒有搞懂的東西。它的電路圖長這樣:

圖 1:由 6 個與非門組成的 D 觸發器

是不是一看就有一種要暈的感覺呢?我的數字電路課本上,在這個電路圖的旁邊,用了大約 20 行文字,追蹤了信號在電路中傳遞的過程。如果你靜下心來讀的話,不一定讀不懂,但往往會淹沒在細節之中,無法宏觀地掌握上述電路的工作原理與設計思路。

  上週在刷知乎的時候,我又見到了「D 觸發器」這個東西。這讓我又想起了本科時代的遺憾,並讓我下決心真正弄懂圖 1 中的電路。很幸運的是,這次我成功了!這篇文章,就來帶你直觀地弄懂下面三個問題:

  1. 圖 1 中的電路,是怎麼實現「D 觸發器」的功能的?

  2. 圖 1 中的電路,是怎麼設計出來的?  3. 能不能用更少的與非門實現「D 觸發器」?

  咦?超級瑪麗在哪裡?別著急,馬上就來!

一、直觀理解 D 觸發器的工作原理

  圖 1 中的電路之所以看起來亂,是因為「與非門」畫起來很笨重:它的所有輸入端都必須畫在一邊,而輸出端畫在另一邊。於是,各個與非門之間的連線,就只好各種拐彎、交叉了。而下面的圖 2,用超級瑪麗代替與非門,就解開了這一團亂麻:

圖 2:用超級瑪麗直觀表示 D 觸發器

  圖中每個紅色的超級瑪麗(Mario)代表一個與非門,綠色(Luigi)和黃色(Wario)的代表輸入數據和時鐘。如果從一個瑪麗到另一個瑪麗之間有箭頭,則代表前者是後者的一個輸入。讀者不妨檢驗一下,圖 1 和圖 2 的連接關係是一模一樣的。由此也比較容易看出各個瑪麗的功能:1、4 號瑪麗負責接收輸入數據,2、3 號瑪麗直接受時鐘控制,5、6 號瑪麗負責記憶及輸出。

  瑪麗的姿勢代表高低電平,但是注意:蹲著的瑪麗代表 1,站著的瑪麗代表 0。這種設定有點兒繞,不過它可以讓與非門的邏輯很符合直覺:如果箭頭起點處的瑪麗站起來了(輸入為 0),則箭頭終點處的瑪麗必須蹲下(輸出為 1),可以看成是前者「壓制」住了後者;如果一個瑪麗不被任何其他瑪麗「壓制」,那他就會自動站起來。不難看出,1、2 號,3、4 號,5、6 號瑪麗形成了三對「冤家」,每一對中的兩個瑪麗不可能同時站著。其中,5、6 號這一對「冤家」比較好理解,它們不是你壓制我,就是我壓制你,可以形成兩種穩態,代表兩種記憶。至於 1、2 號,3、4 號兩對「冤家」有什麼用,下文中會見分曉。

  現在可以講解 D 觸發器的工作原理了。我們從時鐘為 0 的狀態開始。此時黃色的瑪麗站著,把 2、3 號瑪麗都壓了下去,使得它們無法對 1、4、5、6 號瑪麗施加影響。於是,輸入側的 1、4 號瑪麗就與輸出側的 5、6 號瑪麗隔絕了,不管輸入數據如何變化,5、6 號瑪麗都不受影響,保持著之前的狀態。而在輸入側,1 號瑪麗會與綠色瑪麗保持相同的狀態,4 號瑪麗則相反(如圖 3)。

圖 3:時鐘為 0 時,輸入與輸出隔絕

  當時鐘上升沿來臨時,黃色的瑪麗就蹲下去了,2、3 號瑪麗終於有機會伸伸懶腰了。但它們還受 1、4 號瑪麗控制。如果綠色的瑪麗站著(輸入為 0),則 4 號瑪麗會受壓制,而 1 號瑪麗站起來。此時 2 號瑪麗會被 1 號瑪麗壓制,而 3 號瑪麗會因無人壓制而站起來。3 號瑪麗進一步壓制住 6 號瑪麗,從而讓 5 號瑪麗站起來(如圖 4)。反之,如果綠色的瑪麗蹲著(輸入為 1),那麼 4 號瑪麗就會站著,並把 1、3 號瑪麗壓制住,2 號瑪麗則會沒有人壓制而站起來。站起來的 2 號瑪麗會把 5 號瑪麗壓制住,於是 6 號瑪麗會站起來(如圖 5)。總而言之,奇數號瑪麗會與綠色的瑪麗採取同樣的姿勢,偶數號的瑪麗則相反。這就達到了把輸入數據保存到 5 號瑪麗的目的。

圖 4:時鐘上升沿來臨時,輸入數據 0 覆蓋原有數據 1

圖 5:時鐘上升沿來臨時,輸入數據 1 覆蓋原有數據 0

  數據存到 5 號瑪麗以後,時鐘仍會保持為 1 一段時間。這段時間內輸入數據仍可能發生變化,但輸出側不應受其影響。但是黃色的瑪麗在這段時間內是蹲著的,失去了黃色瑪麗壓制的 2、3 號瑪麗,如何把輸入側與輸出側隔絕呢?這就要靠 1、2 號以及 3、4 號兩對「冤家」了!原來,2 號或 3 號瑪麗在時鐘上升沿的瞬間站起來後,會立即反過來對 1 號或 4 號瑪麗形成壓制。如果 3 號瑪麗站著,它就會以一己之力壓制住 4 號瑪麗,讓它不再聽從綠色瑪麗的命令(如圖 6)。如果 2 號瑪麗站著,它就會把 1、3 號瑪麗都壓制住。此時,雖然 4 號瑪麗還能聽從綠色瑪麗的命令,但它只能自己玩,無法對其它瑪麗造成影響(如圖 7)。於是,在時鐘保持為 1 的期間,5、6 號瑪麗也可以維持記憶。

圖 6:時鐘為 1 時,剛存入的數據 0 不再受輸入影響

圖 7:時鐘為 1 時,剛存入的數據 1 不再受輸入影響

  時鐘下降沿來臨時,黃色瑪麗站起來,把 2、3 號瑪麗都壓下去,開始一個新的週期。

二、D 觸發器的設計思路

  看懂了 D 觸發器精妙的工作原理,下一個問題自然就是:這個電路是怎麼設計出來的呢?具體來說,為什麼各個瑪麗要像圖 2 那樣佈局,它們之間的線要那麼連呢?在這一節,我們就從右往左設計 D 觸發器的電路。

  先看最右邊 5、6 號兩個瑪麗。它們其實組成了一個「SR 鎖存器」:

  ● 當兩個輸入一個為 0 一個為 1 時寫入數據,寫入後兩個瑪麗的狀態與輸入相反;

  ● 當兩個輸入均為 1(即 2、3 號瑪麗都蹲下)時,保持狀態;  ● 當兩個輸入均為 0(即 2、3 號瑪麗都站起)時,兩個輸出均為 1(即 5、6 號瑪麗都蹲下)。

其中第三種情況是沒有用的,在 D 觸發器裏也不會出現。

圖 8:5、6 號瑪麗組成 SR 鎖存器

  鎖存器存儲的內容可以隨時由外界輸入修改。我們下面要做的事情,就是用時鐘把 SR 鎖存器的輸入端「保護」起來,由時鐘來控制什麼時候寫入,什麼時候保持。於是就有了 2、3 號瑪麗。

圖 9:2、3 號瑪麗接受時鐘控制,保護 SR 鎖存器的輸入

  當時鐘為 0(黃色瑪麗站著)時,2、3 號瑪麗均被壓制,所以 5、6 號瑪麗可以保持狀態。當時鐘上升沿來臨(黃色瑪麗蹲下)時,2、3 號瑪麗就變成了非門的作用,把輸入取反後送給 5、6 號瑪麗。於是就知道,2 號瑪麗的輸入應當就是要存入的數據,而 3 號瑪麗的輸入應當與之相反。於是就有了 4 號瑪麗:

圖 10:2 號瑪麗接收數據,3 號瑪麗接收取反的數據

  到了現在,還缺的功能就是在時鐘為 1(黃色瑪麗蹲著,不起作用)時,保護好剛剛存入的數據,不讓它受輸入影響了。上圖中的電路做不到這一點:當黃色瑪麗蹲著時,綠色瑪麗可以長驅直入地控制所有紅色瑪麗。為了保護 5、6 號瑪麗的狀態,就需要 2、3 號瑪麗結成一對「冤家」(即組成 SR 鎖存器),並向輸入側提供反饋,讓輸入不至於翻轉 2、3 號瑪麗的狀態。這時我們發現,表示輸入數據的綠色瑪麗是不可以直接連到 2 號瑪麗上的,因為綠色瑪麗不受控制,它只要一站起來,就可以輕而易舉地讓本該站著的 2 號瑪麗蹲下。於是就只好再增設一個 1 號瑪麗,作為綠色瑪麗的傀儡。只要讓 4 號瑪麗控制 1 號瑪麗,1 號瑪麗就可以與綠色瑪麗亦步亦趨了。

圖 11:2、3 號瑪麗結成「冤家」,1 號瑪麗作為綠色瑪麗的傀儡

  下一步就是要設計 2、3 號瑪麗對 1、4 號瑪麗的反饋。不妨把四個箭頭全部連上,這樣 不管是 2 號瑪麗還是 3 號瑪麗站著,就都可以把 1、4 號瑪麗壓製得服服帖帖,不再受綠色瑪麗影響:

圖 12:2、3 號瑪麗全力壓制 1、4 號瑪麗

但其實沒必要費這麼大力氣。不難看出,2 號瑪麗怕的就是自己站著時,1 號瑪麗站起來把自己壓下去;同樣,3 號瑪麗怕的就是自己站著時,4 號瑪麗站起來把自己壓下去。於是隻要 2、3 號瑪麗分別控制 1、4 號瑪麗就行了(又形成兩對「冤家」),中間兩個交叉的箭頭可以去掉:

圖 13:2、3 號瑪麗分別控制 1、4 號瑪麗

  最後檢查一下電路,發現從 3 號瑪麗到 2 號瑪麗的連線可以去掉。這是因為,3 號瑪麗站著時,1 號瑪麗必然也站著,它可以代替 3 號瑪麗壓制 2 號瑪麗。但反過來,2 號瑪麗到 3 號瑪麗的連線不能去掉,因為 4 號瑪麗不能代替 2 號瑪麗壓制 3 號瑪麗 —— 4 號瑪麗本身還受綠色瑪麗控制呢。

圖 14:去掉 2 號瑪麗到 3 號瑪麗的連線,得到最終電路

三、能不能用少於六個與非門搭出 D 觸發器?

  還剩最後一個問題:能不能使用少於 6 個與非門搭出 D 觸發器呢?

  在上面的設計過程中我們發現,5、6 號瑪麗作為記憶的載體,是必不可少的;2、3 號瑪麗要保護 5、6 號瑪麗的輸入,也是必不可少的。那麼 1、4 號瑪麗能不能去掉呢?首先,它們不能都去掉,因為輸入數據不可以直接連到 2、3 號瑪麗上。那麼去掉一個行不行呢?注意到 1 號瑪麗是角色是輸入數據的傀儡,而在時鐘為 1(黃色瑪麗蹲下)時,3 號瑪麗的狀態也是始終跟 1 號瑪麗一致的。既然這樣,何不讓 3 號瑪麗直接作為輸入數據的傀儡,去掉 1 號瑪麗呢!(當然,要恢復 3 號瑪麗對 2 號瑪麗的控制)

圖 14:去掉 1 號瑪麗(同時恢復 3 號瑪麗到 2 號瑪麗的連線)

  很不幸,這個電路是有問題的。問題出在時鐘上升沿的瞬間:如果輸入數據為 0(綠色瑪麗站著),那麼 4 號瑪麗蹲著,當黃色瑪麗蹲下時,2、3 號瑪麗都不受壓制,會爭相站起來,不能保證站起來的一定是 3 號瑪麗。此時就顯示出 1 號瑪麗的必要性了:3 號瑪麗只能在時鐘上升沿之後擔任綠色瑪麗的傀儡,但在時鐘上升沿的瞬間,還是需要 1 號瑪麗把輸入數據傳遞給 2 號瑪麗的。

  由此,我們就說明瞭六個紅色瑪麗(與非門)都是必要的。當然,這並不算嚴格的證明。不過,由五個以內與非門組成的電路種類是很有限的,可以用計算機來枚舉。有興趣的讀者不妨自行編程驗證,只使用五個以內與非門無法搭建出 D 觸發器。

參考

  1. ^本文中的「D 觸發器」,特指邊沿觸髮型(僅在時鐘上升沿接收數據),不包括電平觸髮型(在時鐘為高電平時一直接收數據)。

推薦閱讀:

相關文章