時序邏輯(sequential logic)
想想健身房置物櫃上的密碼鎖。把轉盤撥到"12"並不會把鎖打開——接下來會發生什麼,取決於你之前撥過哪些數字。這把鎖記得自己處在序列中的哪一步。普通的門鈴則恰恰相反:一按就響,一鬆就停,根本不記得你一分鐘前是否按過。時序邏輯就是這把密碼鎖的數位版。它的輸出不僅取決於此刻的輸入,還取決於一份對此前發生過什麼的記憶——也就是電路的狀態。與之對照的是組合邏輯,後者的輸出純粹是目前輸入的函數,就像那只門鈴。
讓時序電路得以"記憶"的,是一份保存在正反器或暫存器裡的狀態——一個個微小的一位元(或多位元)儲存單元。而真正讓整套機制"滴答"運轉起來的關鍵在於:這份記憶只在時脈訊號的邊緣才會更新,時脈訊號就是那拍共同的心跳,驅使一個時脈域齊步向前。每逢時脈的正緣(或負緣),每個受時脈驅動的正反器都會把它的輸入拍下一個快照,並把這個值穩定地保持到下一個邊緣。(帶致能端的正反器在未被致能時,只會保留它原來的值。)所以時序電路並不是連續不停地漂移,而是踩著節拍,從一個狀態到下一個狀態,一次只前進一個離散的步子。
在實務中,你會把時序邏輯設計成一個迴路:目前狀態加上目前輸入,一起送進一塊組合邏輯,它計算出兩樣東西——輸出,以及下一個狀態,而下一個狀態會在下一個邊緣被重新鎖存回正反器裡。這個結構正是一個有限狀態機,計數器、紅綠燈控制器、通訊協定和處理器控制單元都是這樣搭出來的。它的另一面是:時脈從此為你定下速度上限——兩個正反器之間所有的組合邏輯,都必須在一個時脈週期內穩定下來,這正是工程師對關鍵路徑和時序如此較真的全部緣由。
// A simple counter: state (count) advances one step on each clock edge. // (count is a 4-bit register, e.g. reg [3:0] count;) always @(posedge clk) if (rst) count <= 4'b0000; // synchronous reset else count <= count + 1;
一個 4 位元計數器——它的輸出取決於前一次的計數值,並在每個時脈邊緣更新,這正是時序邏輯的精髓。
這裡的"時序"(sequential)指的是隨時間推進、穿過一連串狀態,而不是軟體裡指令一條接一條地執行。一個時序電路可以在同一個時脈邊緣上同時更新數百萬個正反器——它在硬體上是平行的,所謂"時序"只是說它一步一步地穿過各個狀態。