《Verilog數字系統設計教程》[第3版] 夏宇聞_學習總結_1-8


緒論

思考題

  1. 什么是信號處理電路?它通常由哪兩大部分組成?

    信號處理電路是進行一些復雜的數字運算和數據處理,並且又有實時響應要求的電路。兩大部分:高速數據通道接口、高速算法電路。

  2. 為什么要設計專用的信號處理電路?

    部分數字信號處理對時間要求苛刻,通用微處理器芯片為一般目的設計,通用性不可能為某一特殊的算法設計一系列專用運算電路,內部總線寬度不能隨意改變,算法速度受限。

  3. 什么是實時處理系統?

    具有實時響應的處理系統。

  4. 為什么要用硬件描述語言來設計復雜的算法邏輯電路?

    設計和制造能進行快速計算的硬線邏輯專用電路必須學習數字電路基本知識和硬件描述語言,現代復雜數字邏輯系統的設計都借助於EDA工具完成,無論電路系統的仿真和綜合都需掌握HDL。

  5. 能不能完全用C語言替代硬件描述語言進行算法邏輯電路的設計?

    不能,C語言做基礎算法的描述和驗證;設計專用電路進行有速度要求的實時數據處理,需編寫HDL進行仿真,從電路結構上保證算法能滿足要求,並能通過與前后端的設備接口正確無誤交換數據。

  6. 為什么在算法邏輯電路的設計中需要用C語言和HDL配合使用來提高設計效率?

    C語言靈活、差錯功能強,還可以通過PLI(編程語言接口)編寫自己的系統任務,並直接與硬件仿真器(如Verilog-XL)結合使用。此外,C語言有可靠的編譯環境,語法完備,缺陷少,應用多領域;Verilog語言僅針對硬件描述,在別處(如算法表達)並不方便。Verilog的仿真、綜合、差錯工具等大部分軟件是商業軟件,缺乏長期大量使用,可靠性差,亦有很多缺陷。

    既利用C語言的完整性,又結合Verilog對硬件描述的精確性。

第1章 Verilog的基本知識

硬件描述語言(HDL, Hardware Description Language):是電子系統硬件行為描述、結構描述、數據流描述的語言

思考題

  1. 什么是硬件描述語言?主要作用是什么?

    是電子系統硬件行為描述、結構描述、數據流描述的語言。

    作用:數字電路系統的設計可以從頂層到底層(從抽象到具體)逐層描述設計思想,用一系列風層次的模塊來表示極其復雜的數字系統。

  2. 目前世界上符合IEEE標准的硬件描述語言有哪兩種?它們各有什么特點?

    Verilog HDL和VHDL兩種。

    共同特點:能夠形式化地抽象表示電路的行為和結構;支持邏輯設計中層次與范圍的描述;可借用高級語言的精巧結構簡化電路行為的描述;具有電路仿真與驗證機制以保證設計的正確性;支持電路描述由高層到底層的綜合轉換;硬件描述與實現工藝無關;便於文檔管理;易於理解和設計重用。

    不同:Verilog HDL易掌握,VHDL掌握較困難

  3. 什么情況下需要采用硬件描述語言的設計方法?

    對邏輯電路及系統設計的時間要求很短時,需采用HDL的設計方法。

  4. 采用硬件描述語言設計方法的優點是什么?缺點?

    優點:與工藝無關。工程師在功能設計、邏輯驗證階段可以不必過多考慮門級工藝實現的具體細節,只需利用系統設計時對芯片的要求,施加不同的約束條件,即可設計出實際電路。

    缺點:需要相應的EDA工具,而EDA工具的穩定性需要進一步的在工程中提升。

  5. 簡單敘述一下利用EDA工具並采用硬件描述語言的設計方法和流程?

    自頂向下(Top_Down)設計方法:從系統級開始,划分為基本單元,再划分為下一層次基本單元,直到可以直接用EDA元件庫中的基本元件實現為止。

    基本流程由兩大功能部分組成:

    1)設計開發。即從編寫設計文檔->綜合到布局布線->電路生成這樣一系列步驟。

    2)設計驗證。進行各種仿真的一系列步驟,如果在仿真過程中發現問題就返回設計輸入進行修改。

  6. 硬件描述語言可以用哪兩種方式參與復雜數字電路的設計?

    復雜數字電路的設計、復雜數字電路的仿真驗證。

  7. 用硬件描述語言設計的數字系統需要經過哪些步驟才能與具體的電路相對應?

    編寫設計文件,功能仿真,優化、布局布線,布線后門及仿真。

  8. 為什么說用硬件描述語言設計的數字邏輯系統具有最大的靈活性並可以映射到任何工藝的電路上?

    硬件描述語言的設計具有與工藝無關性。(見思考題4)

  9. 軟核是什么?虛擬器件是什么?它們的作用是什么?

    軟核(Soft Core):功能經過驗證的、可綜合的、實現后電路結構總門數在5000門以上的Verilog HDL模型。

    虛擬器件:由軟核構成的器件。

    新電路研制過程中,軟核和虛擬器件可以很容易地借助EDA綜合工具與其他外部邏輯結合為一體,重用性大大縮短設計周期,加快復雜電路的設計。

  10. 集成電路行業中IP的含義是什么?固核是什么?硬核是什么?與軟核相比它們各有什么特點?各適合於什么場合?

    知識產權(IP, Intellectual Property)。

    固核(Firm Core):在某一種現場可編程門陣列(FPGA)器件上實現的、經驗證是正確的、總門數在5000門以上的電路結構編碼文件。

    硬核(Hard Core):在某一種專用集成電路工藝的(ASIC)器件上實現的、經驗證是正確的、總門數在5000門以上的電路結構版圖掩膜。

    在具體實現手段和工藝技術尚未確定的邏輯設計階段,軟核具有最大的靈活性,很容易借助EDA綜合工具與其他外部邏輯結合為一體;相比之下固核和硬核與其他外部邏輯電路結合為一體的靈活性要差很多,特別是電路實現工藝技術改變時更是如此。

  11. 簡述Top_Down設計方法和硬件描述語言的關系?

    Top_Down設計方法首先從系統設計入手,從頂層進行功能划分和結構設計。系統總仿真時頂層進行功能划分的主要環節,而該過程需要采用硬件描述語言的方法。

  12. System Verilog與Verilog有什么關系?適合於何種設計?

    System Verilog是Verilog語言的擴展和延伸。

    Verilog適合系統級、算法級、寄存器級、邏輯級、門級、電路開關級設計;System Verilog更適合於可重用的可綜合IP和可重用的驗證用IP設計,以及特大型(千萬門級以上)基於IP的系統級設計和驗證。

第2章 Verilog語法的基本概念

Verilog模型可以是實際電路的不同級別抽象,5種:

  1. 系統級(system-level):用語言提供的高級結構能夠實現待設計模塊的外部性能的模型。

  2. 算法級(algorithm-level):用語言提供的高級結構能夠實現算法運行的模型。

  3. RTL級(register transfer level):描述數據在寄存器之間的流動和如何處理、控制這些數據流動的模型。

    以上三種屬於行為描述,只有RTL級才與邏輯電路有明確的對應關系。

  4. 門級(gate-level):描述邏輯門以及邏輯門之間連接的模型。

    與邏輯電路有確定的連接關系

  5. 開關級(switch-level):描述期間中三極管和存儲節點以及它們之間連接的模型。

    與具體的物理電路有對應關系

測試在功能級(即行為級)進行,稱為前(RTL)仿真;

邏輯網表(邏輯布爾表達式),稱為邏輯網表仿真;

門級結構級,稱為門級仿真。

如果門級結構模塊與具體的工藝技術對應起來,並加上布局布線引入的延遲模型,此時的仿真稱為布線后仿真,與實際電路情況非常接近。

思考題

  1. Verilog語言有什么作用?

    • 可描述順序執行或並行執行的程序結構;

    • 用延遲表達式或事件表達式來明確的控制過程的啟動時間;

    • 通過命名的事件來觸發其他過程里的激活行為或停止行為;

    • 提供了條件如if-else、case等循環程序結構;

    • 提供了可帶參數且非零延續時間的任務(task)程序結構;

    • 提供了可定義新的操作符的函數結構(function);

    • 提供了用於建立表達式的算術運算符、邏輯運算符、位運算符;

    • Verilog HDL語言作為一種結構化的語言非常適用於門級和開關級的模型設計

    • 提供了一套完整的表示組合邏輯的基本元件的原語(primitive);

    • 提供了雙向通路(總線)和電阻器件的原語;

    • 可建立MOS器件的電荷分享和電荷衰減動態模型;

    • Verilog HDL的構造性語句可以精確地建立信號的模型。

  2. 構成模塊的關鍵詞是什么?

    module、endmodule

  3. 為什么說可以用Verilog構成非常復雜的電路結構?

    Verilog HDL程序由模塊構成;模塊可以進行層次嵌套,大型的數字電路設計可以分割成不同的小模塊實現特定功能。

  4. 為什么可以用比較抽象的描述來設計具體的電路結構?

    有抽象描述設計電路結構的語言,是適合數字系統設計的語言。

  5. 是否任意抽象的符合語法的Verilog模塊都可以通過綜合工具轉變為電路結構?

    不能。符合語法,還要符合一些基本規則。

  6. 什么叫綜合?

    通過綜合工具把行為級描述的模塊通過邏輯網表自動轉化為門級形式的模塊叫綜合。

  7. 綜合是由什么工具來完成的?

    EDA工具完成綜合。

  8. 通過綜合產生的是什么?產生的結果有什么用處?

    產生的是由與、或、非門組成的組合邏輯電路。產生的模塊很容易與某種工藝的基本元件逐一對應,再通過布局布線工具自動轉變為某種工具工藝的電路布線結構。

  9. 仿真是什么?為什么要仿真?

    仿真是對電路模塊進行動態的全面測試。通過觀察測試模塊的輸出信號是否符合要求,可以調試和驗證邏輯系統的設計和結構准確與否,並發現問題及時修改。

  10. 仿真可以在幾層面上進行?每個層面的仿真有什么意義?

    分別為前仿真、邏輯網表仿真、門級仿真和布線后仿真。

    前三者可以調試和驗證邏輯系統的設計和結構准確與否,並發現問題及時修改;布線后仿真分析設計的電路模塊運行是否正常。

  11. 模塊的端口是如何描述的?

  12. 在引用實例模塊時,如何在主模塊中連接信號線?

    .()

    “.”表示被引用模塊的端口,“()”表示本模塊中與之連接的模塊。

  13. 如何產生連續的周期性測試時鍾?

    always #(period/2) clock = ~clock;

  14. 如果不用initial塊,能否產生測試時鍾?

    不能,不用initial塊,無時鍾初始值。

  15. 從本講的簡單例子,是否能明白always塊與initial塊有什么不同?

    initial執行一次,always執行無數次。

  16. 為什么說Verilog可以用來設計數字邏輯電路和系統?

    同1. Verilog作用。

第3章 模塊的結構、數據類型、變量和基本運算符號

x代表不定值;z代表高阻值,可寫作?。

取模運算結果的符號位采用模運算式里第一個操作數的符號位。

邏輯運算符:&&,||,!。邏輯運算,輸出為1位。

位運算符:~,|,^,&,^~。逐位邏輯運算,輸出與輸入位數一致。

縮位運算符:&,|,^。單目運算符,按位邏輯運算,輸出為1位。

思考題

  1. 模塊由幾個部分組成?

    描述接口、描述邏輯功能兩部分組成。

  2. 端口分為幾種?

    3種,輸入口、輸出口、輸入/輸出口。

  1. 為什么端口要說明信號的位寬?

    不說明信號位寬可能會在信號發生改變時發生錯誤,不容易看出接收信號的數據寬度,很難進行數據處理。

  2. 能否說模塊相當於電路圖中的功能模塊,端口相當於功能模塊的引腳?

    可以,每個模塊都有特定功能,功能的實現必須依靠具體電路,端口是信號傳遞通道,相當於功能模塊引腳。

  3. 模塊中的功能描述可以由哪幾類語句或語句塊組成?它們出現的順序會不會影響功能的描述?

    assign語句聲明、實例元件、always塊。出現順序不影響功能描述。

  4. 這幾類描述中的哪一種直接與電路結構有關?

    實例元件直接與電路結構相關。

  5. 最基本的Verilog變量有哪幾種類型?

    wire、reg、memory。

  6. reg型和wire型變量的差別是什么?

    reg型是寄存器變量,相當於存儲單元;wire型是線型變量,相當於物理連線。根本性差別在於reg型保持最后一次的賦值,wire型需要持續的驅動。

  7. 由連續賦值語句(assign)賦值的變量是否能是reg類型的?

    不能,左側必須是線網型數據(wire)。

  8. 在always模塊中被賦值的變量能否是wire類型的?如果不能是wire類型的,那么必須是什么類型的?它們表示的一定是實際的寄存器嗎?

    always塊中被賦值變量不能是wire型,必須是reg型,表示的不一定是實際的寄存器。

  9. 參數類型的變量有什么用處?

    可以提高程序的可讀性和可維護性。

  10. Verilog語法規定的參數傳遞和重新定義功能有什么直接的應用價值?

    可以用於定義延遲時間和變量寬度。

  11. 邏輯比較運算符小於等於“<=”和非阻塞賦值“<=”的表示是完全一樣的,為什么Verilog在語句解釋和編譯時不會搞錯?

    邏輯比較時<=兩邊是兩個操作數,是雙目運算符;在非阻塞賦值時<=右邊是操作數,是單目運算符。

  12. 是否可以說實例引用的描述實際就是嚴格意義上的電路結構描述?

    不能,實例引用的描述是在門級電路上描述,和嚴格意義的電路結構仍有差距。

第4章 運算符、賦值語句和結構說明語句

==相等;!=不等;===相同;!==不同

=== 0 1 x z == 0 1 x z
0 1 0 0 0 0 1 0 x x
1 0 1 0 0 1 0 1 x x
x 0 0 1 0 x x x x x
z 0 0 0 1 z x x x x
各運算符優先級(由高到低)
! ~
* / %
+ -
<< >>
< <= > >=
== != === !==
&
^ ^~
|
&&
||
?:

思考題

  1. 邏輯運算符與按位邏輯運算符有什么不同,它們各在什么場合使用?

    邏輯運算符輸出1位,按位運算符輸出與輸入位數一致;邏輯運算符多用於條件判斷,按位運算符用於信號的運算和檢測。

  2. 指出兩種邏輯等式運算符的不同點,解釋書上的真值表。

    區別:相等和相同。

  3. 拼接符的作用是什么?為什么說合理使用拼接符可以提高程序的可讀性和可維護性?拼接符表示的操作其物理意義是什么?

    拼接符可以把兩個或多個信號的某些位拼接起來進行運算操作。借助拼接符可以用一個信號名表示由多位信號組成的復雜信號。物理意義:將多個信號結合成一個信號。

  4. 如果都不帶時間延遲,阻塞和非阻塞賦值有什么不同?舉例說明它們的不同點?

    阻塞是順序執行,非阻塞賦值是並行執行。

    //非阻塞賦值
    always @(posedge clk) begin
        b <= a;
        c <= b;
    end
    //阻塞賦值
    always @(posedge clk) begin
        b = a;
        c = b;
    end

    非阻塞賦值在always塊結束后執行,描述功能為兩個D觸發器;

    阻塞賦值先后執行,描述功能只用一個D觸發器存儲a值。

  5. 舉例說明順序塊和並行塊的不同。

    //順序塊
    begin
        #50 r = 'h35;
        #50 r = 'hE2;
        #50 r = 'h00;
        #50 ->end_wave;
    end
    //並行塊
    fork
        #50  r = 'h35;
        #100 r = 'hE2;
        #150 r = 'h00;
        #200 ->end_wave;
    join

    效果相同,前者順序執行,后者並行執行。

  6. 如果在順序塊中,前面有一條語句是無限循環,下面的語句能否進行?

    不能。

  7. 如果在並行塊中,發生上述情況,會如何呢?

    下面語句可以執行。

第5章 條件語句、循環語句、塊語句與生成語句

使用if和case語句時條件完全,避免產生不必要的鎖存器。

循環語句:

  1. forever:必須寫在initial塊中。

  2. repeat:

  3. while

  4. for

//乘法器
parameter size = 8, longsize = 16;
reg [size:1] opa, opb;
reg [longsize:1] result;
​
//repeat實現
begin: mult_repeat
    reg [longsize:1] shift_opa, shift_opb;
    shift_opa = opa;
    shift_opb = opb;
    result = 0;
    repeat(size) begin
        if (shift_opb[1])
            result = result + shift_opa;
        shift_opa = shift_opa << 1;
        shift_opb = shift_opb >> 1;
    end
end//for實現
begin: mult_for
    integer bindex;
    result = 0;
    for(bindex=1; bindex<=size; bindex=bindex+1)
        if(opb[bindex])
            result = result + (opa << (bindex-1));
end

命名塊:

  1. 可以聲明局部變量;

  2. 是設計層次的一部分,可以通過層次名引用進行訪問;

  3. 可以被禁用,例如停止執行(關鍵字disable)。

循環生成語句:

  1. 仿真器對生成塊中的代碼確立(展平),再仿真;

  2. genvar用於聲明生成變量,只能用在生成快中;確立后的代碼中不存在生成變量;

  3. 生成變量的值只能由循環生成語句改變;

  4. 循環生成語句名字:or_loop,層次化引用:or_loop[0].g1、or_loop[1].g1。

本地參數localparam:不能用參數重定義(defparam)修改,也不能在實例引用時通過傳遞參數語句修改,即#(參數1,參數2,...)。

思考題

  1. 為什么建議在編寫Verilog模塊程序時,如果用到if語句,建議把配套的else情況也考慮在內?

    如果沒有配套的else語句,在不滿足if條件語句時,將會保持原來的狀態不變,從而在綜合時產生一個鎖存器,這並不是設計想要的結果。

  2. 用if(條件1)語句;else if(條件2)語句;else if(條件3)語句;…else 語句和用case endcase表示不同條件下的多個分支是完全相同的,還是有什么不同?

    不完全相同。if_else_if條件表達式更為直觀;case語句提供了對於不定值x和高阻值z的情況處理。

  3. 如果case語句的分支條件沒有覆蓋所有可能的組合條件,定義了default項和沒有定義default項有什么不同?

    定義default項的電路描述更清楚,綜合時不會產生不想要的結果,未定義default項會在綜合時產生一個鎖存器。

  4. 仔細闡述case、casex和casez之間的不同。

    case所有位均考慮,casez不考慮z位,casex不考慮z位和x位。

  5. forever語句如果運行了,在它下面的語句能否運行?它位於begin end塊和位於fork join塊有什么不同?

    不能運行。begin end順序塊,執行到forever后下面的語句不能執行;fork join並行塊,執行forever還是能執行下面的語句。

  6. forever語句、repeat語句能否獨立於過程塊而存在,即能否不在initial或always塊中使用?

    forever不能獨立於過程塊,repeat能夠獨立於過程塊。

  7. 用for循環為存儲器許多單元賦值時是否需要時間?如果不定義時間延遲,為什么它可以不需要時間就把不管多大的儲存器賦值完畢?

    定義時間延遲則需要時間,否則不需要。循環的邊界是確定的,那么在綜合時該循環語句被認為是重復的硬件結構。

  8. for循環是否可以表示可以綜合的組合邏輯?請舉例說明。

    可以。例如for循環實現的乘法器。

  9. 在編寫測試模塊時用什么方法可以使for循環按照時鍾的節拍運行?請比較下圖程序段。

    //
    always @(posedge clk) begin
        for(i=0; i<=1024; i=i+1)
            mem[i] = i;
    end
    //
    initial begin
        for(i=0; i<=1024; i=i+1) begin
            mem[i] = i;
            @(posedge clk)
        end
    end

    第一種不能,第二種可以。

  10. 聲明一個名為oscillate的寄存器變量並將它初始化為0,使其每30個時間單位進行一次取反操作,使用forever循環。

    reg oscillate;
    initial begin
        oscillate = 0;
        forever
            #30 oscillate = ~oscillate;
    end
  11. 設計一個周期為40個時間單位的時鍾信號,其占空比為25%。使用always和initial塊進行設計,將其在仿真0時刻的值初始化為0。

    initial begin
        clk = 0;
        always begin
            #30 clk = ~clk;
            #10 clk = ~clk;
        end
    end
  12. 給定下面含有阻塞過程賦值語句的initial塊,每條語句在什么仿真時刻開始執行?a、b、c和d在仿真過程中的中間值和仿真結束時的值是什么?

    initial begin
        a = 1'b0;
        b = #10 1'b0;
        c = #5  1'b0;
        d = #20 {a, b, c};
    end

    仿真開始第一條語句執行,10個時鍾單元后第二條執行,15個后第三條執行,35個后第四條執行。仿真中間a=0,b、c、d為x;仿真結束后a=1'b0,b=1'b0,c=1'b0,d=3'b000。

  13. 在12問中,如果initial塊中包括的是非阻塞過程賦值語句,那么各個問題的答案是什么?

    仿真開始第一條語句執行,10個時鍾單元后第二條執行,5個后第三條執行,20個后第四條執行。仿真中間a=0,b、c、d為x;仿真結束后a=1'b0,b=1'b0,c=1'b0,d=3'b000。

  14. d的最終值為?

    initial begin
        b = 1'b1;
        c = 1'b0;
        #10 b = 1'b0;
    endinitial begin
        d = #25 (b | c);
    end

    d = 1‘b0。

  15. 使用帶有同步清零端的D觸發器(清零端高電平有效,在時鍾下降沿執行清零操作)設計一個下降沿觸發的D觸發器,只能使用行為語句(D觸發器的輸出q應當聲明為寄存器變量)。使用設計出的D觸發器輸出一個周期為10個時間單位的時鍾信號。

    module dff_syn(d, clk, clr, q);
        input       d, clk, clr;
        output reg  q;
    ​
        always @(negedge clk)
            if (clr)    q <= 0;
            else        q <= d;
    endmodule//testbench
    `timescale 1ns/1ns
    module dff_syn_tb();
    reg     d, clk, clr;
    wire    q;
    initial begin
        d   = 0;
        clr = 0;
        clk = 0;
    ​
        #10 clr = 1;
        #20 clr = 0;
        forever
            #5 d = ~d;
    end
    dff_syn u1(d, clk, clr, q);
    always #5 clk = ~clk;
    endmodule
  16. 使用帶有異步清零端的D觸發器設計第15題中要求的D觸發器(在清零端變為高電平后立即執行清零操作,無須等待下一個時鍾下降沿),並對這個D觸發器進行測試。

    module dff_asyn(d, clk, clr, q);
        input       d, clk, clr;
        output  reg q;
    ​
        always @(negedge clk, posedge clr) begin
            if (clr)    q <= 0;
            else        q <= d;
        end
    endmodule//testbench
    `timescale 1ns/1ns
    module dff_asyn_tb();
    reg     d, clk, clr;
    wire    q;
    initial fork
        d   = 0;
        clr = 0;
        clk = 0;
    ​
        #10 clr = 1;
        #20 clr = 0;
        forever
            #5 d = ~d;
    join
    dff_asyn u1(d, clk, clr, q);
    always #5 clk = ~clk;
    endmodule
  17. 使用wait語句設計一個電平敏感的鎖存器,該鎖存器的輸入信號為d和clock,輸出為q,其功能是當clock=1時q=d。

    module L_FF(d, clock, q);
        input       d, clock;
        output  reg q;
        always @(*) begin
            wait(clock)
                q = d;
        end
    endmodule
  18. 使用條件語句設計四選一多路選擇器。

    module mux4_to_1(out, i0, i1, i2, i3, s1, s0);
    output  reg out;
    input       i0, i1, i2, i3;
    input       s1, s0;
    always @(*) begin
        if (s1==0 && s0==0)         out = i0;
        else if (s1==0 && s0==1)    out = i1;
        else if (s1==1 && s0==0)    out = i2;
        else if (s1==1 && s0==1)    out = i3;
        else                        out = 1'bx;
    end
    endmodule
  19. 使用case語句設計八功能的算術運算單元(ALU),其輸入信號a和b均為4位,功能選擇信號select為3位,輸出信號out為5位。ALU執行操作與select信號有關,具體關系如表所列(忽略輸出結果中的上溢和下溢的位)。

    select信號 功能
    3'b000 out = a
    3'b001 out = a+b
    3'b010 out = a-b
    3'b011 out = a/b
    3'b100 out = a%b
    3'b101 out = a<<1
    3'b110 out = a>>1
    3'b111 out = (a>b)
    module ALU(a, b, select, out);
    input       [3:0]   a, b;
    input       [2:0]   select;
    output  reg [4:0]   out;
    ​
    always @(select) begin
        case(select)
            3'b000: out = a;
            3'b001: out = a+b;
            3'b010: out = a-b;
            3'b011: out = a/b;
            3'b100: out = a%b;
            3'b101: out = a<<1;
            3'b110: out = a>>1;
            3'b111: out = a>b;
            default: out = 5'bx;
        endcase
    end
    endmodule
  20. 使用while循環設計一個時鍾信號發生器。其時鍾信號的初值為0,周期為10個時間單位。

    initial begin
        clk = 0;
        while(1)    #5 clk = ~clk;
    end
  21. 使用for循環對一個長度為1024(地址從0~1023)、位寬為4的寄存器類型數組cache_var進行初始化,把所有單元都設置為0。

    begin
        reg [3:0] cache_var[1023:0];
        integer i;
        for(i=0; i<1024; i=i+1)
            cache_var[i] = 0;
    end
  22. 使用forever循環設計一個時鍾信號,周期為10,占空比為40%,初值為0。

    initial begin
        clk = 0;
        forever begin
            #6 clk = ~clk;
            #4 clk = ~clk;
        end
    end
  23. 使用repeat將語句a=a+1延遲20個時鍾上升沿之后再執行。

    parameter delay = 20;
    reg a;
    begin
        repeat(delay)
            @(posedge clk);
        a = a + 1;
    end
  24. 下面是一個內嵌順序塊和並行塊的塊語句。該塊的執行結束時間是多少?事件的順序是怎樣的?每條語句的仿真結束時間是多少?

    initial begin           //順序
        x = 1'b0;           //0
        #5 y = 1'b1;        //5
        fork                //並行
            #20 a = x;      //25
            #15 b = y;      //20
        join                //順序
        #40 x = 1'b1;       //65
        fork                //並行
            #10 p = x;      //75
            begin               //順序
                #10 a = y;      //75
                #30 b = x;      //105
            end
            #5 m = y;       //70
        join
    end

    執行結束時間為105個時間單位。

  25. 用forever循環語句、命名塊(named block)和禁用(disabling of)命名塊來設計一個八位計數器。這個計數器從count=5開始計數,到count=67結束計數。每個時鍾正跳變沿計數器加一,時鍾的周期為10。計數器的計數只用了一次循環,然后禁用(使用disable語句)。

    reg [7:0] count;
    initial begin
        count = 5;
    end
    begin: named block
        forever begin: disabling of
            @(posedge clk)
                count = count + 1;
            if (count == 67)
                disable: disabling of;
        end
    end

第6章 結構語句、系統任務、函數語局和顯示系統任務

6.2 task和function

task和function的不同:

  1. function只能與主模塊共用同一個仿真時間單位;task可以定義自己的仿真時間單位,可以使用延遲、事件、時序控制結構;

  2. function可以調用其他函數,不能調用task;task能調用其他task和function;

  3. function至少有一個輸入變量,task可以沒有或有多個任何類型的變量;

  4. function返回一個值,task不返回值。

自動(遞歸)函數:automatic,仿真器為每一次函數調用動態分配新地址空間;自動函數中的局部變量不能通過層次名訪問,函數本身可以通過層次名調用。

function automatic func;

常量函數:integer;帶符號函數:signed。

6.4 常用系統任務

6.4.1 $display和$write

$display(p1, p2, ..., pn)將參數p2到pn按參數p1給定的格式輸出。
$write(p1, p2, ..., pn)p1稱為“格式控制”,p2到pn稱為“輸出表列”。

$display輸出后自動換行,$write不換行。

輸出格式 說明
%h或%H 十六進制數形式輸出
%d或%D 十進制數形式輸出
%o或%O 八進制數形式輸出
%b或%B 二進制數形式輸出
%c或%C ASCII碼字符形式輸出
%v或%V 輸出網絡型數據信號強度
%m或%M 輸出等級層次的名字
%s或%S 字符串形式輸出
%t或%T 當前的時間格式輸出
%e或%E 指數形式輸出實型數
%f或%F 十進制數形式輸出實型數
%g或%G 指數/十進制數形式輸出實型數,以較短的結果輸出
  • 十進制數格式輸出時,結果的高位0值用空格代替;其他進制,保留0;可以使用 %0h 自動調整顯示輸出數據寬度。

  • 十進制:所有位均為不定值/高阻值,結果為x/z;部分為不定值/高阻值,結果為X/Z。

  • 十六進制和八進制:對應進制數的所有位為不定值/高阻值,該位進制數結果為x/z;部分為不定值/高阻值,結果為X/Z。

6.4.2 文件輸出

$fopen("<文件名>")打開文件

返回一個稱為多通道描述符(multichannel descriptor)的32位值,只有一位被設置為1。標准輸出有一個多通道描述符,最低位(第0位)設置為1,一直開放。此后每次調用打開新通道,返回一個設置了第1位、第2位等,直到第30位。第31位是保留位。通道號與多通道描述符中被設置為1的位相對應。

$fdisplay(<文件描述符>, p1, p2, ..., pn)、$fmoitor/$fwrite/$fstrobe:都用於寫文件

文件描述符是一個多通道描述符,可以是一個文件句柄或多個文件句柄按位組合,會輸出到與文件描述符中值為1的位相關聯的所有文件中。

$fclose(<文件描述符>):關閉文件

文件關閉不能再寫,多通道描述符中相應位設置為0。

6.4.3 顯示層次

$display、$write、$monitor、$strobe任務中的%m選項可以顯示任何級別的層次,無需參數。

6.4.4 選通顯示(Strobing)

與$display相似;其他語句和$display在同一個時間單位執行順序不確定;$strobe在同時刻的其他賦值語句執行完成后才執行。

6.4.5 值變轉儲文件(VCD)

VCD是一個ACSII文件(.dmp),包含仿真時間、范圍與信號的定義以及仿真運行中信號值變化等信息。

$dumpvars選擇轉儲模塊實例或模塊實例信號
$dumpfile選擇VCD文件名稱
$dumpon, $dumpoff選擇轉儲過程的起點,終點
$dumpall選擇生成檢測點

思考題

  1. 怎樣理解initial語句只執行一次的概念?

    仿真開始時,initial語句只執行一次,塊內的語句可能不止執行一次。

  2. 在initial語句引導的過程塊中是否可以有循環語句?如果可以,是否與思考題1互相矛盾?

    可以有,不矛盾。initial語句執行一次,並不意味塊內語句不能是循環語句。

  3. 怎樣理解由always語句引導的過程塊是不斷活動的?

    仿真過程中always塊始終在循環的活動,檢查always語句后面的信號是否發生相應改變,如果沒有檢查信號將會進入一個循環,使仿真器鎖死。

  4. 不斷活動與不斷執行有什么不同?

    不斷活動是always語句不斷檢查是否滿足條件;不斷執行是always語句引導的過程中的語句不斷執行。

  5. 怎樣理解沿觸發和電平觸發的不同?

    沿觸發是信號上升沿或下降沿觸發,電平觸發是信號改變即觸發。

  6. 是不是可以說沿觸發是有間隔的,在一定的時間區間里只需要注意有限的點,而電平觸發卻需要注意無窮多個點?

    不是,沿觸發是邊沿觸發,電平觸發是信號改變時觸發。

  7. 沿觸發的always塊和電平觸發的always塊各表示什么類型的邏輯電路的行為?為什么?

    沿觸發表示時序邏輯電路,和時序有關;電平觸發表示組合邏輯電路,只和電平有關。

  8. 簡單敘述任務與函數的不同點。

    見6.2。

  9. 簡單敘述$display、$write和$strobe的不同點。

    $display輸出后自動換行,$write不能;$display和其他語句執行順序不確定,$strobe在同時刻的其他賦值語句執行完成后執行。

  10. 簡單敘述Verilog1364-2001版語法規定的電平敏感列表的簡化寫法。

    “or”可以用“,”代替。

  11. 如何在Verilog測試模塊中,利用文件的讀寫產生預定格式的信號,並記錄有測試價值的信號?

    提供系統任務,值變轉儲文件。

    initial
        $dumpfile("myfile.dmp");  //仿真信息轉儲到myfile.dmp文件
    initial
        $dumpvars;                //未指定變量范圍,設計中全部信號轉儲
    initial
        $dumpvars(1, top);        //轉儲模塊實例top中的信號,1表示層次等級,只轉儲top下第一層的信號
                                  //即轉儲top模塊中的變量,而不轉儲在top中調用模塊中的變量
    initial
        $dumpvars(2, top.m1);     //轉儲top.m1模塊下兩層的信號
    initial
        $dumpvars(0, top.m1);    //0表示轉儲top.m1模塊下各層的所有信號
    //啟動和停止轉儲過程
    initial begin
        $dumpon;               //啟動轉儲過程
        #1000 $dumpoff;        //過1000仿真時間單位后,停止轉儲過程
    end
    //生成一個檢查點,轉儲所有VCD變量的現行值
    initial
        $dumpall;

第7章 調試用系統任務和常用編譯預處理語句

7.1 $monitor

$monitor($time, , p1, p2, ..., pn);

", ,"代表一個空格,空參數輸出時顯示為空格。$monitoron和$monitoroff任務的作用是通過打開和關閉監控標志來控制監控任務$monitor的啟動和停止。調用$monitoron啟動$monitor時,立刻輸出顯示當前時刻參數列表的值。連續監視數據變化。

7.2 $time

$time返回一個64位整數表示當前仿真時刻值,受時間尺度比例影響,輸出是時間尺度的倍數,再取整。

$realtime返回實型數時間數字,以時間尺度為基准。

常用在$monitor中,用來做時間標記。

7.3 $finish

$finish;
$finish(n);

退出仿真器,返回主操作系統,即結束仿真過程。

可帶參數(不帶默認為1):0:不輸出任何信息;1:輸出當前仿真時刻和位置;2:輸出當前仿真時刻、位置和在仿真過程中所用memory及CPU時間的統計。

7.4 $stop

$stop;
$stop(n);

把EDA工具置成暫停模式,在仿真環境下給出一個交互式的命令提示符,將控制權交給用戶。參數值越大,輸出信息越多。

$stop和$finish常用在測試模塊的initial模塊中,配合時間延遲控制仿真的持續時間。

7.5 $readmemb和$readmemh

$readmemb("<數據文件名>", <存儲器名>);
$readmemb("<數據文件名>", <存儲器名>, <起始地址>);
$readmemb("<數據文件名>", <存儲器名>, <起始地址>, <結束地址>);
$readmemh("<數據文件名>", <存儲器名>);
$readmemh("<數據文件名>", <存儲器名>, <起始地址>);
$readmemh("<數據文件名>", <存儲器名>, <起始地址>, <結束地址>);

被讀取的數據文件內容只能包含:空白位置、注釋行、二進制/十六進制數字。

數據文件中地址格式為:@十六進制數;例:@hhhh。

7.6 $random

$random % b;    //b>0, (-b+1):(b-1)
{$random} % b;  //          0:(b-1)

產生一個32位的隨機數,帶符號的整形數。

//寬度隨機脈沖序列
`timescale 1ns/1ns
module random_pulse(dout);
    output reg [9:0] dout;
    integer delay1, delay2, k;
    initial begin
        #10 dout = 0;
        for(k=0; k<100; k=k+1) begin
            delay1 = 20*({$random}%6);      //0-100ns
            delay2 = 20*(1 + {$random}%3);  //20-60ns
            #delay1 dout = 1 << ({$random}%10);
            //dout隨機位為1,出現時間在0-100ns
            #delay2 dout = 0;
            //脈沖寬度在20-60ns
        end
    end
endmodule

7.7 編譯預處理

宏定義:`define 標識符(宏名) 字符串(宏內容)。宏定義時可引用已定義的宏名。

文件包含處理:`include “文件名”。

時間尺度:`timescale <時間單位>/<時間精度>。

條件編譯命令

`ifdef 宏名(標識符)
程序段1
`elsif
程序段2
`else
程序段3
`endif

`ifndef

條件執行:$test$plusargs("DISPLAY_VAR"),可以指定+DISPLAY_VAR選擇在運行時設置標志。

$value$plusargs,測試調用選項的參數值,未找到返回0。使用帶 + 的命令行啟動仿真器。

思考題

  1. 為什么在多模塊調試的情況下$monitor 需要配合$monitoron和$monitoroff來工作?

    多模塊調試時,調用$monitor模塊數不僅一個,而任何時刻只能有一個$monitor起作用,因此需要配合$monitoron和$monitoroff使用。

  2. 請用$random配合求模運算編寫:

    (1)用於測試的跳變沿抖動為周期1/10的時鍾波形。 (2)隨機出現的脈寬隨機的窄脈沖。

    module random_pulse(dout);
        output reg [9:0] dout;
        integer delay, k;
        initial begin
            #10 dout = 0;
            for(k=0; k<100; k=k+1) begin
                delay = {$random}%10;
                #delay dout = 1;
                #delay dout = 0;
            end
        end
    endmodule
  3. Verilog的編譯預處理與C語言的編譯預處理有什么不同?

    Verilog編譯預處理要以“`”開頭。

  4. 請仔細闡述`timescale編譯預處理的作用?

    說明該命令后模塊的時間單位和時間精度,可以在同一個設計里包含不同時間單位的模塊。

  5. 不同`timescale定義的多模塊仿真測試時需要注意什么?

    1. `timescale命令聲明本模塊時間單位和時間精度;

    2. $printtimescale輸出一個模塊的時間單位和時間精度;

    3. $time和$realtime以及%t格式輸出EDA工具記錄的時間信息。

  6. 為什么說系統任務$readmem可以用來產生用於算法驗證的極其復雜的測試用數據流?

    復雜數據可以用C語言產生,存在文件中,用$readmem取出存入存儲器,按節拍輸出,可用於驗證算法邏輯電路。

  7. 為什么說熟練地使用條件編譯命令可以使源代碼有更大的靈活性,可以適用於不同的實現對象,如不同工藝的ASIC或速度規模不同的FPGA或CPLD,從而為軟核的商品化創造條件?

    合理的使用條件編譯和條件執行預處理可以使測試程序適應不同的編譯環境,也可以把不同的測試過程編寫到一個統一的測試程序中去,可以簡化測試過程,對於復雜設計的驗證模塊的編寫很有實用價值。

第8章 練習

(7)

//1)
    reg [7:0] A;
    A = 2'hFF;
    //answer
    A = 8'b0000_0011
    A = 8'h03
//2)
    reg [7:0] B;
    B = 8'bZ0;
    //answer
    B = 8'bZZZZ_ZZZ0;

(15)以下模塊綜合后可能是哪一種硬件實現?

always @(posedge clock)
    if(a)
        C = B;
//1. 不能綜合
//2. 一個上升沿觸發器和一個多路器
//3. 一個輸入是A,B,clock的三輸入與門
//4. 一個透明鎖存器
//5. 一個帶有clock有使能引腳的上升沿觸發器
//answer:2和5。

(17)以下模塊被綜合后可能是哪一種硬件實現?

//1. 帶異步復位端的觸發器
//2. 不能綜合或與預先設想不一致
//3. 組合邏輯
//4. 帶邏輯的透明鎖存器
//5. 帶同步復位端的觸發器
//1)    5
always @(posedge clk) begin
    A <= B;
    if(C)
        A <= 1'b0;
end//2)    2
always @(A or B)
    case(A)
        1'b0: F = B;
        1'b1: G = B;
    endcase//3)    1
always @(posedge A or posedge B)
    if(A)
        C <= 1'b0;
    else
        C <= D;
​
//4)    2
always @(posedge clk or negedge rst)
    if(rst)
        A <= 1'b0;
    else
        A <= B;

(23){1, 0}值為?

64'H0000_0001_0000_0000

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM