時序電路
首先來看兩個問題:
1.為什么CPU要用時序電路,時序電路與普通邏輯電路有什么區別。
2.觸發器、鎖存器以及時鐘脈沖對時序電路的作用是什么,它們是如何工作的。
帶著這兩個問題,我們從頭了解一下邏輯電路。要了解邏輯電路,首先我們便要了解組成邏輯電路的基本單位:邏輯門。
邏輯門
邏輯門是數字電路組成的基本單元,它們的輸出是它們輸入位值的布爾函數。最常用的邏輯門便是我們熟知的與、或、非。
對于與門,只有a、b輸入都為1時,輸出才為1。
對于或門,輸入a、b只要有一個為1,輸出便為1。
對于非門,若輸入為1則輸出為0,輸入為0則輸出為1。
以上三種是最基本的邏輯門,我們可以通過它們的組合來實現復雜的邏輯推演,最簡單的比如與或、異或等。再復雜的邏輯,都可以用最基本的邏輯的特定組合實現出來,就像我們應用層工程師靠有限的語法可以創造出近乎無限的應用一樣。
邏輯門總是活動的,一旦一個門的輸入變化了,在很短的時間內,輸出便會相應的變化。
使用很多的邏輯門構建成一張網,便得到了一個實現的復雜邏輯的計算塊(computational Block),稱為組合電路。組合電路的構成遵循以下原則:
1. 每個邏輯門的輸入必須連接了一個系統的輸入、某個存儲單元的輸出或某個邏輯門的輸出(三選一)。
2. 兩個或多個邏輯門的輸出不能連接在一起,否則可能產生互相矛盾的信號造成錯誤或電路故障。
3. 這個網必須是無環的,也就是說不能有回路,否則會使網的計算邏輯有歧義。
了解了基本的邏輯門和組合電路的概念,我們再介紹一下電路中的控制信號是如何實現的。
控制信號
我們說過再復雜的邏輯也可以靠最基本的邏輯組合而成,輸入輸出的控制邏輯也不例外。為了更好的理解控制信號是如何工作的,我們介紹一種非常有用的組合電路:位多路復用器。
其中的 s 輸入控制著兩個與門。其中位于上方的與門的邏輯是 !s && b ,位于下方的與門的邏輯是 s && a 。
也就是說當 s 的輸入為 1 時,b的輸入是無法到達或門的, 0&&b 恒為零。此時 a 的輸入便是整個電路的輸出。
反之當 s 輸入為 0 時,a 的輸入是無法到達或門的 ,0&&a 恒為零。此時 b 的輸入便是整個電路的輸出。
可以看到 s 輸入的電位高低直接決定著 a、b 中哪個輸入有效,這便是控制信號工作的一個典型例子。
看到控制信號是如何工作的,我們來假想一下簡單的寄存器是如何依賴一個時鐘控制信號工作的。一個時鐘信號周期的由低電平變為高電平再由高電平變為低電平。
以該信號作為寄存器的控制信號,寄存器內每一位輸入位都與該信號進行與邏輯后再進入寄存器,那么可以想象,在時鐘周期內的低電平部分,任何信號無法寫入寄存器,等待時鐘信號變為高電平時寄存器才變為可寫入狀態。這就是一個簡單的觸發器了,隨著時鐘信號周而復始的改變著自己的狀態。
當然真正的觸發器的實現比這復雜的多,這里只是方便理解舉了最簡單的例子。
明白了上述基本概念,我們看一下普通組合邏輯電路與時序電路的區別。
普通組合邏輯電路與時序電路的區別
1.毛刺容忍
組合邏輯電路從本質上講,不存儲任何信息。它們只是簡單的響應輸入信號,產生符合輸入的某個邏輯表達式結果的輸出。
而時鐘電路是擁有自己的狀態的,時序電路某一個狀態除了依賴當前的輸入外,還依賴電路的上一個狀態。
而我們想要電路擁有自己的狀態并可以基于這個狀態進行計算,必須在組合邏輯電路中引入存儲設備和控制存儲設備的周期性變化的時鐘信號。
引入存儲設備是容易理解的,沒有存儲設備的電路當然是沒有自己的狀態的,因為它沒有存儲狀態信息的載體,存儲器就是存儲電路狀態信息的載體。
而時鐘周期的作用相對就不是那么容易理解,我們舉個例子來理解時鐘信號的作用:
我們來看一個沒有時鐘信號的組合邏輯電路:
我們前面說過,邏輯門總是活動的,一旦一個邏輯門的輸入改變,則輸出會在很短的時間內發生改變。
但是需要注意的是,這個“很短時間內”的描述。由于元器件的質量/種類不同、路線的長度不同等物理因素的限制,不同的輸入到達輸出的時間是不同的。
比如圖中,c 輸入到達下方的與門與到達上方的與門的兩條路線中,到達下方與門的路線多出了一個非門。那么 c 信號到達上方的與門自然要比到達下方的與門的速度快。
所以當 c 信號發生改變時,有一段時間內,F 端的輸出是錯誤的,因為 A&&C 已經到達 F 端但 B&&!C 還沒有到達,也就是說 F1 是比 F0 到達的慢的,存在延遲,如下圖所示:
我們稱這種情況為“毛刺”。
雖然毛刺出現的時間是很短暫的,但是對于一個電路系統的輸出來說卻是致命的。如果我們在發生毛刺的時間內將錯誤的輸出寫入存儲器,接下來的邏輯會一錯再錯并讓我們摸不到頭腦。
而時序電路則不會出現上述問題,我們將A/B/C的輸入到F的輸出看作一個完整的動作,在一個時鐘周期內完成。那么,A/B/C的輸入將在時鐘沿觸發,F也將在時鐘沿采集結果。而在采集結果時,F的輸出已經跨越了毛刺處于穩定狀態。當然,這樣時一個鐘周期內高電平持續的時間必須足夠使 F 輸出達到穩定狀態。
這樣,下一個動作(發生在下一個時鐘周期)如果基于 F 輸出,將得到正確的結果。這是時序電路與普通邏輯電路的區別之一:對毛刺的容忍。
可以看到,通過時鐘周期,組合邏輯電路中輸入的變化可以看作一個一個的動作。而在一個時鐘周期內,電路完成一個最基本的動作,保證下個時鐘周期的動作可以獲取正確的電路狀態。
如果無法理解電路按動作運轉的意義,我們看一個非常簡單的例子:
int a=0; int b=a;
我們需要將 a=0 執行完后,執行 b=a 才有意義。a=0沒有執行完成或未執行時,b=a 的執行完全沒有意義。這就是程序按指令運轉的重要性,正如電路按動作運轉的重要性。
時鐘周期將一個一個的動作隔離開來,確保每個動作在執行時,上一個動作已經完全執行完成了。而存儲器則記錄電路的狀態,每個動作的執行結果放在存儲器中供下個動作使用。
這正是CPU所需要的,CPU執行一條一條的指令正可以看作一個一個的動作(當然這里并不是指的一條指令,CPU的基本動作是比指令更加細化的單位,尤其是在流水線的引入之后。指令正是由一個個基本的動作構成的,這些基本動作指的是取指令/指令譯碼/指令執行/訪存/寫回/PC增加等等)。
時鐘周期像人類的心跳,CPU隨著時鐘節拍快速又有條不紊的運行。正如前面所說,一個時鐘周期必須足夠CPU完全完成耗時最長的基本動作,時鐘周期對于不同的CPU來說并不是固定的,確定一個CPU的時鐘周期也是一個非常復雜的任務。
2.支持反饋邏輯
如果我們要實現一個計數器,如果用非時序電路實現是這樣的:
上述電路是完全無法使用的,電路的下一個輸出依賴電路現在時刻的狀態,除了上一節所述的毛刺現象會造成結果的不可預計外,電路本身的邏輯存在死循環。
要支持反饋邏輯,必須使用寄存器將結果暫存起來,由時鐘沿控制數據的反饋更新。
說完了時序電路的特性,我們看看時序電路如何組成處理器。
時序電路構成處理器
我們可以看到,一個最基本的處理器是這樣一個電路:
1. 可以完成邏輯的運算。
2. 電路需要有自己的狀態。
3. 每一個輸出除了基于輸入和處理邏輯外,還需要基于當前電路的狀態。
時序電路可以很好的滿足上述特性。對于時序電路來說,時鐘脈沖便是電路的心跳,而寄存器是協同整個電路按心跳節拍運轉的動脈瓣。
大多數時候,寄存器處于一種穩定狀態,產生的輸出等于它的當前狀態。信號沿著寄存器前面的組合電路傳播。這時產生一個新的寄存器輸入,但當當前時鐘脈沖處于低電位時,寄存器的輸出仍保持不變。直到時鐘脈沖變為高電位,輸入信號便寫入到寄存器中,成為下一個狀態。直到下一個時鐘上升沿,寄存器的狀態和輸出都不會發生改變。
電信號暢通無阻的在組合電路中傳播,而寄存器就成為這種傳播的屏障。只有在每個時鐘的上升沿時,信號才可以通過寄存器進入下一個組合電路。
而一個個的組合電路執行著不同的動作,對于整個電路而言,時鐘脈沖與寄存器的配合使得電路在每個動作執行完成后才會執行下一個動作。處理器在一個時鐘周期內,執行完一個動作并把狀態更新到寄存器。直到下一個時鐘周期再執行下一個動作,此時上個動作已經完全執行完成了,而電路的最新狀態也已經通過寄存器傳播到了負責當前動作的電路中來。
換個角度,時鐘周期保證了每個周期結束時,這個周期內的輸入已經完整的轉化為了輸出。而這個輸出保存在寄存器內供下個周期的動作使用。時鐘周期和寄存器的配合將電路要執行的動作與動作之間隔離開來。每個動作的結尾會更新PC寄存器,而這也將成為下一個動作的開始。一個一個動作有條不紊的執行,周而復始。(這種描述僅適用于最簡單的處理器模型,即一個時鐘周期完成一條指令的執行的處理器。當引入流水線后,由于分支、控制指令等原因造成了流水線冒險,PC的更新有著更加完備的機制,而不是固定的在一條指令的最后更新)
上面便是一個最簡單的處理器結構,左邊標識了每部分電路對應的動作。
我們可以使一個時鐘周期內執行完成整個指令執行(上述所有動作),這樣下一個時鐘周期執行下一條指令時可以保證上條指令可以執行完成。雖然這樣時鐘周期會長到讓人難以接受,但它保證了指令流的正常流轉。
我們可以想象,這樣一個完整的過程是從讀PC計數器數值并取指令開始的。PC計數器中的數值造成了后面一系列電路狀態的變化,在PC不改變時,電路處于一個穩定的狀態,也就是完整執行完一個指令的狀態。
而當PC計數器一旦發生改變,將引起整個電路的新一輪的狀態改變。指令執行的最后一個動作便是改變PC計數器,這樣在下一個時鐘周期,整個電路將執行新的指令。
或者我們可以將負責各個動作的電路間用寄存器隔離開來,一個時鐘周期內只執行一個動作而不是一條指令,這樣可以大大加快電路的整體效率。事實上流水線便是這樣做的,為了更高的效率,許多流水線的層級非常深,一個取指/譯碼/執行三個動作可能被拆分成十五個甚至更多個動作。這樣一個時鐘周期內,就可以處理多條指令(當然它們處于不同的動作階段)。
典型的流水線簡圖如下:
我們用寄存器將負責每一個動作的模塊隔離開來,然后將時鐘周期設為每個模塊剛好可以向本模塊寄存器寫入數據的時間(而不是信號從頭傳播到尾的時間)。這樣一個時鐘周期內,每個模塊都執行一次完整的動作。在單個時鐘周期內,每個模塊在服務不同的指令,而不是所有模塊服務同一個指令(如果這樣則每個模塊只在高電平持續時間的一小塊時間內工作)。在單位時間內,整個邏輯電路服務的指令總數大大增加,也就是吞吐量得到了增加。
因為增加了電路的復雜性,對于一條指令而言,從頭走到尾所需的時間變長了,但對整個電路而言,吞吐量增加了。這便是流水線機制的意義。
我們在試圖理解流水線的動作時,不要將關注點放在邏輯電路上,而要將關注點放在寄存器值的變化上。因為組合邏輯電路不受時鐘信號影響,僅負責信號的傳播,真正依賴時鐘信號的是寄存器的寫入行為。我們的目標便是寄存器的值隨著時鐘周期發生正確的變化。當組合邏輯A前的輸入(也就是PC寄存器值)發生變化后,每過一個時鐘周期,該變化便依次傳遞到后面模塊的寄存器中。
流水線聽起來很完美,但也存在一些缺陷。比如我們很難將各個模塊的延遲變為一致的,整個電路的速度將受限于最慢的模塊。時鐘周期必須大于最慢模塊的整體計算時間,這就給其它模塊帶來了延遲。另外,流水線的層級也并非是越深越好。隨著流水線層架的加深,寄存器的增多將導致整體電路延遲的增加,當層級到達一定深度時,該延遲占用總計算時間的比例增大,造成收益的減小。
指令如流水一樣進入處理器,而不是一條指令執行完成后下一條指令才進入處理器。雖然將指令的執行拆分成多個小動作會帶來許多麻煩,比如流水線冒險,但其帶來的吞吐量及縮短時鐘周期的收益是值得我們花費精力來解決這些麻煩的。
一個最基本的處理器的實現需要組合邏輯電路和兩種存儲設備:時鐘寄存器(程序計數器和指令狀態寄存器)和隨機訪問存儲器(指令內存/數據內存和寄存器文件)。
組合邏輯不需要任何時序或控制,只要輸入變化了,值就通過邏輯門網絡傳播。
那么我們還有四個硬件需要用時序控制:程序計數器/指令狀態寄存器/數據內存和寄存器文件。因為時序控制的都是寫入操作,而指令內存不需要寫入操作,所以也不需要時序控制。
時鐘脈沖控制著上述四個元器件的寫入操作。時鐘信號觸發將值寫入到指令狀態寄存器和隨機訪問存儲器。
處理器真的是一個非常宏大的話題,筆者能力極其有限,只能盡量的從非常宏觀的角度上描述一下對處理器的認識(依然很吃力)。
混亂的戰場上,兩個士兵在黑暗的建筑里遇到。 不知道對方是否自己人,只能祈禱對方別沖動。 但如果聽到了槍聲,就已經沒有了選擇的余地。
編輯:hfy
-
寄存器
+關注
關注
31文章
5343瀏覽量
120368 -
計數器
+關注
關注
32文章
2256瀏覽量
94569 -
時序電路
+關注
關注
1文章
114瀏覽量
21700 -
多路復用器
+關注
關注
9文章
873瀏覽量
65300 -
控制信號
+關注
關注
0文章
164瀏覽量
11966
發布評論請先 登錄
相關推薦
評論