- VLSI設計教程
- VLSI設計 - 首頁
- VLSI設計 - 數字系統
- VLSI設計 - FPGA技術
- VLSI設計 - MOS電晶體
- VLSI設計 - MOS反相器
- 組合MOS邏輯電路
- 時序MOS邏輯電路
- VHDL程式設計
- VHDL - 簡介
- VHDL - 組合電路
- VHDL - 時序電路
- Verilog
- Verilog - 簡介
- 行為建模與時序
- VLSI設計有用資源
- VLSI設計 - 快速指南
- VLSI設計 - 有用資源
- VLSI設計 - 討論
Verilog中的行為建模與時序
Verilog中的行為模型包含過程語句,這些語句控制模擬並操作資料型別的變數。所有這些語句都包含在過程中。每個過程都與其關聯的活動流。
在行為模型的模擬過程中,由“always”和“initial”語句定義的所有流程在模擬時間“零”時同時開始。initial語句執行一次,always語句重複執行。在此模型中,暫存器變數a和b分別在模擬時間“零”時初始化為二進位制1和0。然後initial語句完成,並且在該模擬執行期間不再執行。此initial語句包含一個begin-end塊(也稱為順序塊)的語句。在此begin-end型別塊中,a先初始化,然後是b。
行為建模示例
module behave; reg [1:0]a,b; initial begin a = ’b1; b = ’b0; end always begin #50 a = ~a; end always begin #100 b = ~b; end End module
過程賦值
過程賦值用於更新reg、integer、time和memory變數。過程賦值和連續賦值之間存在顯著差異,如下所述:
連續賦值驅動net變數,並在任何輸入運算元的值發生變化時進行評估和更新。
過程賦值在圍繞它們的程式流程構造的控制下更新暫存器變數的值。
過程賦值的右側可以是任何計算為值的表示式。但是,右側的部分選擇必須具有常量索引。左側指示從右側接收賦值的變數。過程賦值的左側可以採用以下形式之一:
暫存器、整數、實數或時間變數 - 對這些資料型別之一的名稱引用進行賦值。
暫存器、整數、實數或時間變數的位選擇 - 對單個位進行賦值,同時保持其他位不變。
暫存器、整數、實數或時間變數的部分選擇 - 兩個或多個連續位的部分選擇,同時保持其餘位不變。對於部分選擇形式,僅允許常量表達式。
儲存器元素 - 儲存器的一個字。請注意,儲存器元素引用不允許位選擇和部分選擇。
上述任何一種的連線 - 可以指定上述四種形式的任何一種的連線,這有效地將右側表示式的結果進行分割槽,並按順序將分割槽部分分配給連線的各個部分。
賦值中的延遲(不適用於綜合)
在延遲賦值中,在執行語句並進行左側賦值之前,會經過Δt個時間單位。使用賦值內延遲,右側會立即計算,但結果會在Δt之後放置到左側賦值。如果另一個過程在Δt期間更改右側訊號,則不會影響輸出。綜合工具不支援延遲。
語法
過程賦值變數 = 表示式
延遲賦值#Δt 變數 = 表示式;
賦值內延遲變數 = #Δt 表示式;
示例
reg [6:0] sum; reg h, ziltch; sum[7] = b[7] ^ c[7]; // execute now. ziltch = #15 ckz&h; /* ckz&a evaluated now; ziltch changed after 15 time units. */ #10 hat = b&c; /* 10 units after ziltch changes, b&c is evaluated and hat changes. */
阻塞賦值
阻塞過程賦值語句必須在順序塊中跟隨它的語句執行之前執行。阻塞過程賦值語句不會阻止順序塊中跟隨它的語句的執行。
語法
阻塞過程賦值的語法如下:
<lvalue> = <timing_control> <expression>
其中,lvalue是過程賦值語句有效的某種資料型別,=是賦值運算子,timing control是可選的賦值內延遲。timing control延遲可以是延遲控制(例如,#6)或事件控制(例如,@(posedge clk))。表示式是模擬器分配給左側的右側值。阻塞過程賦值使用的=賦值運算子也用於過程連續賦值和連續賦值。
示例
rega = 0;
rega[3] = 1; // a bit-select
rega[3:5] = 7; // a part-select
mema[address] = 8’hff; // assignment to a memory element
{carry, acc} = rega + regb; // a concatenation
非阻塞(RTL)賦值
非阻塞過程賦值允許您計劃賦值,而不會阻塞過程流。當您希望在同一時間步長內進行多個暫存器賦值而無需考慮順序或相互依賴關係時,可以使用非阻塞過程語句。
語法
非阻塞過程賦值的語法如下:
<lvalue> <= <timing_control> <expression>
其中lvalue是過程賦值語句有效的某種資料型別,<=是非阻塞賦值運算子,timing control是可選的賦值內timing control。timing control延遲可以是延遲控制或事件控制(例如,@(posedge clk))。表示式是模擬器分配給左側的右側值。非阻塞賦值運算子與模擬器用於小於或等於關係運算符的運算子相同。當您在表示式中使用<=運算子時,模擬器將其解釋為關係運算符,當您在非阻塞過程賦值構造中使用<=運算子時,模擬器將其解釋為賦值運算子。
模擬器如何評估非阻塞過程賦值 當模擬器遇到非阻塞過程賦值時,它會分兩步評估和執行非阻塞過程賦值,如下所示:
模擬器評估右側並計劃在由過程timing control指定的時間進行新值的賦值。模擬器評估右側並計劃在由過程timing control指定的時間進行新值的賦值。
在給定延遲到期或發生適當事件的時間步長的末尾,模擬器透過將值分配給左側來執行賦值。
示例
module evaluates2(out); output out; reg a, b, c; initial begin a = 0; b = 1; c = 0; end always c = #5 ~c; always @(posedge c) begin a <= b; b <= a; end endmodule
條件
條件語句(或if-else語句)用於決定是否執行語句。
形式上,語法如下:
<statement> ::= if ( <expression> ) <statement_or_null> ||= if ( <expression> ) <statement_or_null> else <statement_or_null> <statement_or_null> ::= <statement> ||= ;
<expression>被評估;如果為真(即,具有非零的已知值),則執行第一個語句。如果為假(具有零值或值為x或z),則第一個語句不執行。如果存在else語句並且<expression>為假,則執行else語句。由於測試if表示式的數值是否為零,因此可以進行某些捷徑。
例如,以下兩個語句表達相同的邏輯:
if (expression) if (expression != 0)
由於if-else的else部分是可選的,因此當從巢狀的if序列中省略else時可能會產生混淆。這是透過始終將else與缺少else的最接近的前一個if關聯來解決的。
示例
if (index > 0) if (rega > regb) result = rega; else // else applies to preceding if result = regb; If that association is not what you want, use a begin-end block statement to force the proper association if (index > 0) begin if (rega > regb) result = rega; end else result = regb;
if-else-if的構造
以下構造經常出現,值得單獨討論。
示例
if (<expression>) <statement> else if (<expression>) <statement> else if (<expression>) <statement> else <statement>
此if序列(稱為if-else-if構造)是編寫多路決策的最通用方法。表示式按順序評估;如果任何表示式為真,則執行與其關聯的語句,這將終止整個鏈。每個語句要麼是單個語句,要麼是語句塊。
if-else-if構造的最後一個else部分處理“以上皆非”或預設情況,即沒有滿足其他條件。有時沒有預設的顯式操作;在這種情況下,可以省略尾隨的else,也可以將其用於錯誤檢查以捕獲不可能的條件。
Case語句
case語句是一種特殊的多分支決策語句,它測試表達式是否與多個其他表示式之一匹配,並相應地分支。例如,case語句對於描述微處理器指令的解碼很有用。case語句具有以下語法:
示例
<statement> ::= case ( <expression> ) <case_item>+ endcase ||= casez ( <expression> ) <case_item>+ endcase ||= casex ( <expression> ) <case_item>+ endcase <case_item> ::= <expression> <,<expression>>* : <statement_or_null> ||= default : <statement_or_null> ||= default <statement_or_null>
case表示式按給定的確切順序進行評估和比較。線上性搜尋期間,如果其中一個case項表示式與括號中的表示式匹配,則執行與該case項關聯的語句。如果所有比較都失敗,並且給出了default項,則執行default項語句。如果沒有給出default語句,並且所有比較都失敗,則不執行任何case項語句。
除了語法之外,case語句在兩個重要方面與多分支if-else-if構造不同:
if-else-if構造中的條件表示式比將一個表示式與多個其他表示式進行比較(如case語句中)更通用。
當表示式中存在x和z值時,case語句提供了確定的結果。
迴圈語句
有四種類型的迴圈語句。它們提供了一種控制語句執行零次、一次或多次的方法。
forever連續執行語句。
repeat執行語句固定次數。
while執行語句,直到表示式變為假。如果表示式一開始為假,則語句根本不執行。
for透過以下三步過程控制其關聯語句的執行:
執行通常用於初始化控制執行迴圈次數的變數的賦值
評估表示式——如果結果為零,則for迴圈退出,如果結果不為零,則for迴圈執行其關聯語句,然後執行步驟3
執行通常用於修改迴圈控制變數值的賦值,然後重複步驟2
以下是迴圈語句的語法規則:
示例
<statement> ::= forever <statement> ||=forever begin <statement>+ end <Statement> ::= repeat ( <expression> ) <statement> ||=repeat ( <expression> ) begin <statement>+ end <statement> ::= while ( <expression> ) <statement> ||=while ( <expression> ) begin <statement>+ end <statement> ::= for ( <assignment> ; <expression> ; <assignment> ) <statement> ||=for ( <assignment> ; <expression> ; <assignment> ) begin <statement>+ end
延遲控制
延遲控制
可以透過使用以下語法來延遲控制過程語句的執行:
<statement> ::= <delay_control> <statement_or_null> <delay_control> ::= # <NUMBER> ||= # <identifier> ||= # ( <mintypmax_expression> )
以下示例將賦值的執行延遲10個時間單位:
#10 rega = regb;
接下來的三個示例在數字符號(#)之後提供一個表示式。賦值的執行延遲由表示式的值指定的時間量決定。
事件控制
可以透過使用以下事件控制語法,將過程語句的執行與net或暫存器上的值變化或已宣告事件的發生同步:
示例
<statement> ::= <event_control> <statement_or_null> <event_control> ::= @ <identifier> ||= @ ( <event_expression> ) <event_expression> ::= <expression> ||= posedge <SCALAR_EVENT_EXPRESSION> ||= negedge <SCALAR_EVENT_EXPRESSION> ||= <event_expression> <or <event_expression>>
*<SCALAR_EVENT_EXPRESSION> 是一個表示式,其結果為一位的值。
網路和暫存器上的值變化可以用作事件來觸發語句的執行。這被稱為檢測隱式事件。Verilog 語法還允許您根據變化的方向檢測變化——即,朝向值 1(posedge)或朝向值 0(negedge)。posedge 和 negedge 對未知表示式值的處理如下:
- 當從 1 轉換到未知,以及從未知轉換到 0 時,會檢測到 negedge。
- 當從 0 轉換到未知,以及從未知轉換到 1 時,會檢測到 posedge。
過程:Always 和 Initial 塊
Verilog 中的所有過程都指定在以下四個塊之一中:1) Initial 塊 2) Always 塊 3) 任務 4) 函式
initial 和 always 語句在模擬開始時啟用。initial 塊只執行一次,並且當語句執行完後其活動結束。相反,always 塊重複執行。其活動只有在模擬終止時才會結束。在一個模組中可以定義任意數量的 initial 和 always 塊。任務和函式是從其他過程中的一個或多個位置啟用的過程。
Initial 塊
initial 語句的語法如下:
<initial_statement> ::= initial <statement>
以下示例說明了在模擬開始時使用 initial 語句初始化變數。
Initial Begin Areg = 0; // initialize a register For (index = 0; index < size; index = index + 1) Memory [index] = 0; //initialize a memory Word End
initial 塊的另一個典型用法是指定波形描述,這些描述執行一次以向被模擬的電路的主要部分提供激勵。
Initial Begin Inputs = ’b000000; // initialize at time zero #10 inputs = ’b011001; // first pattern #10 inputs = ’b011011; // second pattern #10 inputs = ’b011000; // third pattern #10 inputs = ’b001000; // last pattern End
Always 塊
‘always’ 語句在整個模擬執行過程中持續重複。always 語句的語法如下所示
<always_statement> ::= always <statement>
由於 ‘always’ 語句的迴圈特性,只有在與某種形式的時序控制結合使用時才有用。如果 ‘always’ 語句不提供時間推進的方法,則 ‘always’ 語句會產生模擬死鎖情況。例如,以下程式碼建立了一個無限的零延遲迴圈:
Always areg = ~areg;
為上述程式碼提供時序控制可以建立一個可能有效的描述——如以下示例所示:
Always #half_period areg = ~areg;