Verilog 時(shí)序控制

2022-05-17 10:24 更新

關(guān)鍵詞:時(shí)延控制,事件觸發(fā),邊沿觸發(fā),電平觸發(fā)

Verilog 提供了 2 大類時(shí)序控制方法:時(shí)延控制和事件控制。事件控制主要分為邊沿觸發(fā)事件控制與電平敏感事件控制。

時(shí)延控制

基于時(shí)延的時(shí)序控制出現(xiàn)在表達(dá)式中,它指定了語句從開始執(zhí)行到執(zhí)行完畢之間的時(shí)間間隔。

時(shí)延可以是數(shù)字、標(biāo)識(shí)符或者表達(dá)式。

根據(jù)在表達(dá)式中的位置差異,時(shí)延控制又可以分為常規(guī)時(shí)延與內(nèi)嵌時(shí)延。

常規(guī)時(shí)延

遇到常規(guī)延時(shí)時(shí),該語句需要等待一定時(shí)間,然后將計(jì)算結(jié)果賦值給目標(biāo)信號(hào)。

格式為:?#delay procedural_statement?,例如:

reg  value_test ;
reg  value_general ;
#10  value_general    = value_test ;

該時(shí)延方式的另一種寫法是直接將井號(hào) ?#? 獨(dú)立成一個(gè)時(shí)延執(zhí)行語句,例如:

#10 ;
value_ single         = value_test ;

內(nèi)嵌時(shí)延

遇到內(nèi)嵌延時(shí)時(shí),該語句先將計(jì)算結(jié)果保存,然后等待一定的時(shí)間后賦值給目標(biāo)信號(hào)。

內(nèi)嵌時(shí)延控制加在賦值號(hào)之后。例如:

reg  value_test ;
reg  value_embed ;
value_embed        = #10 value_test ;

需要說明的是,這 2 種時(shí)延控制方式的效果是有所不同的。

當(dāng)延時(shí)語句的賦值符號(hào)右端是常量時(shí),2 種時(shí)延控制都能達(dá)到相同的延時(shí)賦值效果。

當(dāng)延時(shí)語句的賦值符號(hào)右端是變量時(shí),2 種時(shí)延控制可能會(huì)產(chǎn)生不同的延時(shí)賦值效果。

例如下面仿真代碼:

`timescale 1ns/1ns
 
module test ;
    reg  value_test ;
    reg  value_general, value_embed, value_single ;
 
    //signal source
    initial begin
        value_test        = 0 ;
        #25 ;      value_test        = 1 ;
        #35 ;      value_test        = 0 ;        //absolute 60ns
        #40 ;      value_test        = 1 ;        //absolute 100ns
        #10 ;      value_test        = 0 ;        //absolute 110ns
    end
 
    //(1)general delay control
    initial begin
        value_general     = 1;
        #10 value_general  = value_test ; //10ns, value_test=0
        #45 value_general  = value_test ; //55ns, value_test=1
        #30 value_general  = value_test ; //85ns, value_test=0
        #20 value_general  = value_test ; //105ns, value_test=1
    end
 
    //(2)embedded delay control
    initial begin
        value_embed       = 1;
        value_embed  = #10 value_test ; //0ns, value_test=0
        value_embed  = #45 value_test ; //10ns, value_test=0
        value_embed  = #30 value_test ; //55ns, value_test=1
        value_embed  = #20 value_test ; //85ns, value_test=0
    end
 
    //(3)single delay control
    initial begin
        value_single      = 1;
        #10 ;
        value_single = value_test ; //10ns, value_test=0
        #45 ;
        value_single = value_test ; //55ns, value_test=1
        #30 ;
        value_single = value_test ; //85ns, value_test=0
        #20 ;
        value_single = value_test ; //105ns, value_test=1
    end
 
    always begin
        #10;
        if ($time >= 150) begin
            $finish ;
        end
    end
 
endmodule

仿真結(jié)果如下,由圖可知:

  • 一般延時(shí)的兩種表達(dá)方式執(zhí)行的結(jié)果都是一致的。
  • 一般時(shí)延賦值方式:遇到延遲語句后先延遲一定的時(shí)間,然后將當(dāng)前操作數(shù)賦值給目標(biāo)信號(hào),并沒有"慣性延遲"的特點(diǎn),不會(huì)漏掉相對(duì)較窄的脈沖。
  • 內(nèi)嵌時(shí)延賦值方式:遇到延遲語句后,先計(jì)算出表達(dá)式右端的結(jié)果,然后再延遲一定的時(shí)間,賦值給目標(biāo)信號(hào)。


下面分析下內(nèi)嵌延時(shí)的賦值過程:

value_embed  = #10 value_test ; //0ns, value_test=0

0ns 時(shí),執(zhí)行此延時(shí)語句。

先將 0 賦值給信號(hào) ?value_embed?, 延遲 10ns 輸出為 0;

value_embed  = #45 value_test ; //10ns, value_test=0

10ns 時(shí),執(zhí)行此延時(shí)語句。

由于此時(shí) ?value_test ?仍然為 0,所以 ?value_embed ?值不變。

即到 55ns 時(shí),?value_embed ?值仍然保持為 0。

value_embed  = #30 value_test ; //55ns, value_test=1

同理,55ns 時(shí),?value_test ?值為 1,將其賦值給 ?value_embed ?并延遲 30ns 輸出。

所以 85ns 時(shí),?value_embed ?輸出為 1。

value_embed  = #20 value_test ; //85ns, value_test=0

同理,105ns 時(shí),?value_embed ?輸出為 0。

邊沿觸發(fā)事件控制

在 Verilog 中,事件是指某一個(gè) ?reg ?或 ?wire ?型變量發(fā)生了值的變化。

基于事件觸發(fā)的時(shí)序控制又主要分為以下幾種。

一般事件控制

事件控制用符號(hào) ?@? 表示。

語句執(zhí)行的條件是信號(hào)的值發(fā)生特定的變化。

關(guān)鍵字 ?posedge ?指信號(hào)發(fā)生邊沿正向跳變,?negedge ?指信號(hào)發(fā)生負(fù)向邊沿跳變,未指明跳變方向時(shí),則 2 種情況的邊沿變化都會(huì)觸發(fā)相關(guān)事件。例如:

//信號(hào)clk只要發(fā)生變化,就執(zhí)行q<=d,雙邊沿D觸發(fā)器模型
always @(clk) q <= d ;                
//在信號(hào)clk上升沿時(shí)刻,執(zhí)行q<=d,正邊沿D觸發(fā)器模型
always @(posedge clk) q <= d ;  
//在信號(hào)clk下降沿時(shí)刻,執(zhí)行q<=d,負(fù)邊沿D觸發(fā)器模型
always @(negedge clk) q <= d ;
//立刻計(jì)算d的值,并在clk上升沿時(shí)刻賦值給q,不推薦這種寫法
q = @(posedge clk) d ;

命名事件控制

用戶可以聲明 event(事件)類型的變量,并觸發(fā)該變量來識(shí)別該事件是否發(fā)生。命名事件用關(guān)鍵字 event 來聲明,觸發(fā)信號(hào)用 ?->? 表示。例如:

event     start_receiving ;
always @( posedge clk_samp) begin
        -> start_receiving ;       //采樣時(shí)鐘上升沿作為時(shí)間觸發(fā)時(shí)刻
end
 
always @(start_receiving) begin
    data_buf = {data_if[0], data_if[1]} ; //觸發(fā)時(shí)刻,對(duì)多維數(shù)據(jù)整合
end

敏感列表

當(dāng)多個(gè)信號(hào)或事件中任意一個(gè)發(fā)生變化都能夠觸發(fā)語句的執(zhí)行時(shí),Verilog 中使用"或"表達(dá)式來描述這種情況,用關(guān)鍵字 ?or ?連接多個(gè)事件或信號(hào)。這些事件或信號(hào)組成的列表稱為"敏感列表"。當(dāng)然,or 也可以用逗號(hào) ?,? 來代替。例如:

//帶有低有效復(fù)位端的D觸發(fā)器模型
always @(posedge clk or negedge rstn)    begin      
//always @(posedge clk , negedge rstn)    begin      
//也可以使用逗號(hào)陳列多個(gè)事件觸發(fā)
    if(! rstn)begin
        q <= 1'b ;      
    end
    else begin
        q <= d ;
    end
end

當(dāng)組合邏輯輸入變量很多時(shí),那么編寫敏感列表會(huì)很繁瑣。此時(shí),更為簡(jiǎn)潔的寫法是 ?@*? 或 ?@(*)?,表示對(duì)語句塊中的所有輸入變量的變化都是敏感的。例如:

always @(*) begin
//always @(a, b, c, d, e, f, g, h, i, j, k, l, m) begin
//兩種寫法等價(jià)
    assign s = a? b+c : d ? e+f : g ? h+i : j ? k+l : m ;
end

電平敏感事件控制

前面所討論的事件控制都是需要等待信號(hào)值的變化或事件的觸發(fā),使用 ?@+敏感列表? 的方式來表示的。

Verilog 中還支持使用電平作為敏感信號(hào)來控制時(shí)序,即后面語句的執(zhí)行需要等待某個(gè)條件為真。Verilog 中使用關(guān)鍵字 ?wait ?來表示這種電平敏感情況。例如:

initial begin
    wait (start_enable) ;      //等待 start 信號(hào)
    forever begin
        //start信號(hào)使能后,在clk_samp上升沿,對(duì)數(shù)據(jù)進(jìn)行整合
        @(posedge clk_samp)  ;
        data_buf = {data_if[0], data_if[1]} ;      
    end
end

點(diǎn)擊這里下載源碼


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)