關於四位計數器的設計,阻塞式與非阻塞式賦值引發的問題

1、今天,從教材中學了兩種可綜合的四位計術器的設計方法,先附上代碼吧。

(1)、建模:

方法一:

module counter1(out,cout,data,load,cin,clk);
  input [3:0]data;
  input load,cin,clk;
  output cout;
  output [3:0]out;
  reg [3:0]out;
  
  always @(posedge clk)
  if(load)
    out<=data;
  else
    out<=out+cin;
    
  assign cout=&out&cin;
  
endmodule


方法二:

module counter2(preout,out,cout,data,load,cin,clk);
  input [3:0]data;
  input load,cin,clk;
  output cout;
  output [3:0]out,preout;
  reg [3:0]out;
  reg cout;
  reg [3:0]preout;

//preout起到一種監控作用,是我自己添加的。
  
  always @(posedge clk)
  begin
    out<=preout;
  end
  
  always @(out,data,load,cin)
  begin
    {cout,preout}=out+cin;
    if(load)
      preout=data;
    
      
  end    
  
  
endmodule

(2)、testbench:

`include "counter2.v"


module counter_stimulus;
  reg load,cin,clk;
  reg [3:0]data;
  wire [3:0] out;
  wire cout;


  counter2 ct(out,cout,data,load,cin,clk);
  
  initial
  begin
    clk=1;
    forever #5 clk=~clk;
  end
  
  initial
  begin
    data=4'd5;
    cin=0;
    load=1;
    #5 load=0;
    #10 cin=1;
  end
  
endmodule
  

(3)、仿真效果圖:



2、下面我來說說,出現的問題,第一次仿真時,仿真結果如下圖(1):其中,out和cout的值都是紅線,不確定值,於是我在counter2的代碼中,添加了preout作爲輸出變量,仿真便出現了圖(2)的仿真效果:


圖(1)

圖(2)

由圖(2)可知,當上升沿到來前,load變成0,preout變成了未知值,除都非,我在仿真模塊中把load前10ns的值設置爲1,讓preout一直爲1,才能保證後面時刻仿真正確。

後來分析,發現問題就出現在阻塞和非阻塞的賦值方式上,因爲在錯誤代碼中,我對preout使用了非阻塞式賦值,如下圖,而在正確代碼中,我採取的是阻塞式。具體,阻塞式和非阻塞式的區別,還要在後面的學習中,繼續鞏固學習。在此,我只明白,問題出在這,但不能說出個所以然來。
   


3、此部分是後續添加的,在學習過阻塞式及非阻塞式賦值後來解決第二部分所出現的問題。看上面圖片的代碼,第一個always過程塊表示一個時序電路,採用非阻塞式賦值肯定沒有問題。但第二個always過程表示一個組合邏輯,不適合採用非阻塞式賦值,這是因爲當load值變化爲1時,preout置爲data,即爲0101,這個沒錯,但當load爲0時,就只執行{count,preout}<=out+cin;而這個非阻塞賦值等號右邊參與運算的是out的初始值,而out的初始值爲未知值x,因此,cout和preout保持爲未知值x。採用阻塞式的仿真圖如下:值得特別注意的是,當always過程塊表示一個時序電路時,過程塊中的賦值必須爲非阻塞式賦值,而當always過程塊表示一個組合邏輯時,過程塊中的賦值必須爲阻塞式賦值。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章