建立時間與保持時間(setup & hold time)
想像你在旋轉的旋轉木馬上遞一張紙條給朋友——你得在他們轉過來之前就把紙條穩穩地舉好,轉過去之後還得再舉一會兒,否則交接就會失手。正反器在時脈邊緣上抓取資料,道理完全一樣。它的資料輸入在時脈跳變的那一刻不能正在變化;它需要一個安靜的視窗,讓數值在邊緣之前穩定保持一小段時間(建立時間),並在邊緣之後再穩定保持一小段時間(保持時間)。
更精確地說,建立時間是資料必須在有效時脈邊緣到來之前就已穩定下來的最短時長,保持時間則是邊緣過去之後資料必須維持不動的最短時長。兩者合起來,在邊緣周圍圈出一小塊禁飛區,在這段時間裡輸入不得變動。這些數值非常小——在現代製程中往往只有幾十皮秒,保持時間甚至可能略為負值——它們源自負責擷取並鎖存數值的取樣單元的內部延遲。
一旦越過任一邊界,正反器可能鎖存到錯誤的邏輯位準,更糟的是,會半途卡在 0 與 1 之間,進入亞穩態——一種不穩定的平衡,要花上無法預測的時間才會朝某一側倒下,這可能把壞資料一路傳播到下游。讓每一條路徑都落在這兩個邊界之內,正是靜態時序分析所檢查的內容。建立檢查是最大延遲測試:資料必須足夠早地到達,因此它給時脈頻率定下了上限。保持檢查是最小延遲測試:資料不能到得太早,以致賽跑般竄過去、被它所發出的那同一個邊緣誤擷取——而關鍵在於,它根本不取決於時脈週期。兩項檢查各自剩下的迴旋餘地就是時序餘量(slack)。
always @(posedge clk) q <= d; // d must be stable around this edge in silicon
在 HDL 模型裡,這項要求是隱含的——你只是描述了暫存器,時序則由工具事後去保證。RTL 對皮秒隻字未提;建立與保持是物理限制,由 STA 在合成後的網表上校驗,而不是這行程式碼的模擬所能看到的東西。
建立違例通常可以靠放慢時脈來解決,保持違例卻不行——保持失敗是單個時脈週期之內的一場賽跑,與頻率無關,所以放慢時脈毫無幫助。補救之道是給跑得太快的資料路徑添加延遲(通常是插入緩衝器)。正是這種不對稱,讓保持違例成為兩者中更令人頭疼的一個:你沒法只靠把時脈調慢就逃脫它。