本文討論Verilog HDL與綜合相關的問題。

一、賦值

本節討論如何在Verilog中的實現不同的賦值,以及它們在邏輯綜合中會推斷出什麼樣的電路。

1.1、當對同一個net,使用多個assign語句,會綜合出什麼樣的邏輯?

在可綜合的verilog代碼中,為同一個net使用多個assign語句是錯誤的。綜合工具會報出語法錯誤,即「net is being driven by more than one source」。 例如,以下是錯誤的:

//only one type of output assignment is legal for synthesis
wire tmp ;
assign tmp = in1 & in2 ;
assign tmp = in1 | in2 ;

但是,使用多個assign來驅動三態net 是合法的語句,如下示例所示:

input enable1 , enable2 ;
wire tmp ;
assigm tmp = (enable1 == 1』b1) ? (in1 & in2) : 1』bz ;
assigm tmp = (enable2 == 1』b1) ? (in3 & in3) : 1』bz ;

1.2、條件賦值在邏輯綜合時會推斷出什麼電路?

條件賦值通過「?:」實現。條件賦值在邏輯綜合時被推斷為MUX。 例如,以下示例是一個簡單的MUX:

wire wire1 ;
assign wire1 = (sel == 1』b1) ? a : b ;

1.3、條件賦值嵌套會綜合出什麼樣的電路?

如下例所示,條件賦值嵌套會被綜合成MUX 「tree 」:

assign out1 = (sel1 == 1』b1) ? in1 :
(sel2 == 1』b1) ? in2 :
(sel3 == 1』b1) ? in3 :in4 ;

1.4 在同一個always語句塊中,對同一個reg變數多次賦值會綜合出什麼電路 ?

在同一個always語句塊中,對同一個reg變數進行多次非阻塞賦值時,邏輯綜合時會選擇最後一個賦值。 例如:

module lower(clk ,in1 ,in2 ,out2) ;
input clk ,in1 , in2 ;
outout out2 ;
reg tmp ;
always@(posedge clk) begin
tmp <= (in1 ^ in2) ;
tmp <= (in1 & in2) ;
tmp <= (in1 | in2) ;
end
assign out2 = tmp ;
endmodule

在剛剛的示例中,OR邏輯是最後一個賦值。因此,綜合出來的邏輯是OR門。 如果最後一個賦值是「&」運算符,它會綜合成一個AND邏輯。

對於組合邏輯中always語句塊中的阻塞賦值來說,情況也是如此。

always@(in1 , in2) begin
tmp = (in1 & in2) ;
tmp = (in1 ^ in2) ;
tmp = (in1 | in2) ; // The final logic picked up is the OR gate
end

如果多次賦值存在於if-else或case語句中。 例如,

在這種情況下,在每個時鐘周期僅執行一個唯一的賦值。

在上面的例子中,沒有關於哪個語句會被執行賦值的歧義,因為分支控制是明確定義的。

1.5 為什麼時序邏輯應該用非阻塞賦值,如果用阻塞賦值會發生什麼?並且與組合邏輯進行比較。

阻塞賦值和非阻塞賦值之間的主要區別是阻塞賦值中的RHS會被立即賦值到LHS,而非阻塞賦值,LHS的賦值是發生在RHS值被計算之後。

以下說明了在時序邏輯中使用阻塞賦值和非阻塞賦值的不同場景:

1.5.1 在時序邏輯中使用阻塞賦值

以下是時序邏輯中使用阻塞賦值的Verilog模塊示例:

在上面的例子中,reg1,reg2,reg3,out1都是阻塞賦值。 綜合結果是單個FF觸發器,輸入為in1,q輸出為out1,如圖下圖所示:

這是因為in1和out1之間的中間結果是以阻塞賦值形式存儲在reg1,reg2和reg3中。 結果,對out1的RHS最終計算會被立即賦值到out1, reg1,reg2和reg3已經通過綜合進行了優化。

1.5.2 在時序邏輯中使用非阻塞賦值

以下代碼示例了時序邏輯中使用非阻塞賦值:

在上面的例子中,reg1,reg2,reg3,out1為非阻塞賦值。 綜合結果為4個觸發器。

這是因為in1和out1之間的中間結果是以非阻塞賦值存儲在reg1,reg2和reg3中。在這種情況下,輸出是由clk事件控制的移位寄存器。

1.5.3 在組合邏輯中使用阻塞賦值

以下示例說明了組合邏輯中的阻塞賦值的用法:

在上面的使用阻塞賦值的組合邏輯語句中,沒有posedge,並且「<=」被「=」替換。 由此綜合的邏輯很簡單,是in1到out1之間的連線。

這是因為所有的賦值都是立即執行的,沒有需要等待的事件。

2、Tasks 和Functions

Tasks 和 functions主要是有助於代碼的可重用性。

2.1 function中的邏輯被綜合成了什麼?

由於function中沒有任何時序結構,function只能綜合出組合邏輯。

例如,以下function有2個輸入信號和一個控制信號,輸出算術運算結果。

2.2Verilog function有哪些重要的注意事項?

2.2.1 每次調用function時,局部變數和返回值應該是都會被賦值,否則將導致形成鎖存器。 例如,以下示例中,if條件語句沒有else語句。也就是說,如果sel是false,該function將返回其先前調用的值,就好像結果被鎖存住了。

2.2.2 fucntion只用於綜合成組合邏輯。但是,fucntion的最終結果可以用作D觸發器的輸入。

2.2.3 fucntion不應包括延遲(#)或事件控制(@,wait)語句。

2.2.4 fucntion可以調用其他fucntion,但不能調用task。

2.2.5 fucntion在調用時會返回一個值。

2.2.6 fucntion內聲明的parameters,作用範圍僅在本地,並且不能在fucntion之外使用。 在以下示例中,width參數在函數之外聲明,double_width參數在函數內聲明。

2.3 task中的邏輯被綜合成了什麼?

雖然在task中可以有@等時序控制結構中,它僅適用於模擬。綜合工具會忽略所有task中的時序結構。因此,如果task中存在時序控制結構,可能會存在模擬和綜合不匹配的現象。

因此,在可綜合verilog中一般只會使用task綜合基本的組合邏輯,在testbench中調用帶有時序控制結構的task具有較好的通用性。

以下是組合邏輯task的示例,即comb_task,執行輸入in1的位或(OR)。 注意int_out1和int_out2的聲明是reg型,因為task的輸出只能通過reg而不是wire接收。

2.4 使用task和module實現可重用邏輯有什麼區別?

下表總結了兩種方法之間的差異:

task module

不能在task中例化module 可以在module中調用task

Task中的邏輯不能夠在floorplan中定義為block進行pre_place布局,只是sea-of-gates

Module可以在floorplan中定義為block,進行pre_place

2.5 task和fucntion是否可以在module-endmodule之外聲明么?

可以。 在SystemVerilog中,可以在module-endmodule外聲明task和function。在Verilog-1995或Verilog-2001中是不可以的,會產生編譯錯誤。例如,以下代碼中,在module-endmodule範圍之外聲明了task modify_value。

同樣,在使用SystemVerilog中,function-endfunction也可以在同一文件中的module-endmodule範圍之外聲明。

3存儲單元

在邏輯綜合中可以推斷出兩種存儲元素,即觸發器和鎖存器。 本節介紹這兩個要素之間的實現和比較

3.1不同類型觸發器的RTL模板

從RTL中綜合出的觸發器或鎖存器的類型取決於它們的代碼風格。 以下是幾個不同觸發器和鎖存器RTL示例。 在觸發器RTL中,posedge clk推斷出正邊沿觸發器,negedge clk推斷出負邊沿觸發器。

3.1.1 簡單的D觸發器

正邊沿觸發,無置位或複位

Module dff(clk , d,q) ;
Input clk ,d ;
Output q ;
Reg q ;
always@(posedge clk ) begin
q <= d ;
end
endmodule

在SystemVerilog中,可以使用always_ff代替always實現相同的代碼,如下所示:

Always_ff @(posedge clk) begin
Q<= d ;

End

3.1.2 非同步置位觸發器

正邊沿觸發,高電平有效非同步置位

Module asff(clk,d,set,q) ;
Input clk ,d,set ;
Ouput q ;
Reg q ;
always@(posedge clk or posedge set) begin
if(set) begin
q <= 1』b1
end
else begin
q <= d ;
end
end
endmodule

3.1.3 非同步複位觸發器

正邊沿觸發,高電平有效非同步複位

Module arff(clk ,d,reset,q) begin
Input clk ,d,reset ;
Output q ;
Reg q ;

always@(posedge clk or posedge reset) begin
if(reset) begin
q <= 1』b0 ;
end
else begin
q <= d ;
end
end
end

3.1.4 非同步置位和複位觸發器

正邊沿觸發,高電平有效的非同步置位,複位

Module arsff(clk,d,set,reset) ;
Input clk ,d,set,reset ;
Output q ;
Reg q ;
always@(posedge clk or posedge set or posedge reset) begin
if(set) begin
q <= 1』b1 ;
end

else if(reset) begin
q <= 1』b0 ;
end
else begin
q<= d ;
end

end
Endmodule

3.1.5 同步置位觸發器

正邊沿觸發,高電平有效的同步置位

Module ssff(clk , d,set,q) ;
Input clk ,d,set ;
Output q ;
Reg q ;
always@(posedge clk ) begin
if(set) begin
q <= 1』b1 ;
end
else begin
q <= d ;
end
end
endmodule

3.1.6 同步複位觸發器

正邊沿觸發,高電平有效的同步複位

Module srff(
Input clk ,d,reset ;
Output q );
Reg q ;
always@(posedge clk ) begin
if(reset) begin
q <= 1』b0 ;
end

else begin
q <= d ;
end
end
endmodule

3.1.7 同步置位和賦值觸發器

正邊沿觸發,高電平有效的同步置位和複位

Module ssrff(
Input clk ,
Input d ,
Input set ,
Input reset ,
Output q ) ;
Reg q ;
always@(posedge clk) begin
if(set) begin
q <= 1』b1 ;
end
else if(reset) begin
q <= 1』b0
end
else begin
q <= d ;
end
end

3.2不同類型鎖存器的RTL模板

3.2.1 簡單的D鎖存器

Module d1(sel ,d ,q) ;
Input sel ,d ;
Output q ;
Reg q ;
always@(*) begin
if(sel) begin
q <=d ;
end // note the else is missing
end
endmodule

在systemverilog中可以用always_latch代替always,無需指定敏感列表。

Always_latch // no explicit sensitivity list
If(sel) begin
Q <= d ;
End

3.2. 2 非同步置位鎖存器

Module asl (sel,d,set,q) ;
Input sel ,d ,set;
Output q ;
Reg q ;
always@(*) begin
if(set) begin
q = 1』b1 ;
end
else if(sel) begin
q = d ;
end
end
endmodule

    1. 非同步複位鎖存器

    Module arl(sel,d,reset,q) ;
    Input sel , d ,set ;
    Output q ;
    Reg q ;
    always@(*) begin
    if(reset) begin
    q = 1』b0 ;
    end
    else if(sel) begin
    q = d ;
    end
    end
    endmodule

      1. 非同步複位置位鎖存器

      Module asrl(sel ,d, set,reset,q) ;
      Input sel ,d,set,reset ;
      Output q ;
      Reg q ;
      always@(*) begin
      if(reset) begin
      q = 1』b0 ;
      end

      else if(set) begin
      q = 1』b1 ;
      end
      else if(sel) begin
      q =d ;
      end
      end
      endmodule

      以上所有示例都是一位存儲元件。可以增加reg聲明的位寬來增加觸發器或鎖存器的寬度。例如,

      reg [3:0] out1;

      這將創建4位觸發器或鎖存器。

      觸發器中非同步或同步複位,哪一個更好?

      非同步複位:

      1. 複位信號不是數據路徑中的一部分,不是觸發器D輸入的一部分
      2. 複位能在任何時候發生
      3. 不建議由內部邏輯生成非同步複位

      示例:

      always@(posedge clk or negedge reset) begin
      if(!reset) begin
      out1 <= 0 ;
      end
      else begin
      out1 <= in1 ;
      end
      end

      同步複位:

      1. 複位信號是數據路徑的一部分
      2. 複位只能在時鐘的有效邊沿發生
      3. 可以由內部邏輯生成同步複位

      示例:

      always@(posedge clk ) begin
      if(!reset) begin
      out2 <= 0 ;
      end
      else begin
      out2 <= in2 ;
      end
      end

      流程式控制制語句

      Verilog主要有三種流程式控制制結構,即case,

      if-else和「?:」。

      本節主要說明了case和if-else結構的實現細節和問題

      1. 如何在case語句和嵌套if-else之間進行選擇?

      case和if-else都是流程式控制制結構。 兩者在功能模擬上是類似的,但是使用場景是不同的。

      通常為以下場景選擇case語句:

      條件是互斥的,只有一個變數控制case語句中的流程。 case變數本身可以是

      不同信號的拼接。

      通常在以下場景中選擇多路if語句:

      綜合優先順序編碼邏輯,有多個變數控制語句流程。

      使用case語句比if-else語句更具可讀性,特別是用於狀態機時。

      在case結構中,如果未指定所有可能的case,並且缺少default語句,則會推斷出鎖存器。 同樣,對於if-else結構,如果缺少最後的else語句,也會推斷出鎖存器。

      如何避免if-else樹中的優先順序編碼器?

      if-else樹可能會綜合出優先順序編碼邏輯。 例如:

      module priorityencoder (ino,in1,in2,in3,sel) ;
      input in0 , in1,in2,in3 ;
      output [1:0] sel ;
      always@(in0,in1,in2,in3) begin
      sel = 2』b00 ;
      if(in0) sel = 2』b00 ;
      else (in1) sel = 2』b01 ;
      else (in2) sel = 2』b10 ;

      else (in3) sel = 2』b11 ;

      end
      endmodule //priorityencoder

      如果在in0和in1都是邏輯真的,in0分支將被採用,因為in0首先計算。EDA工具將綜合出優先順序編碼邏輯。

      ?:能用在連續賦值裡面,而if-else只能用在initial或者always語句塊中。

      Case語句default子語句的重要性是什麼?

      case語句中的default子語句表示除case之外的其他情況。如果缺少default子語句,則輸出默認會使用保存之前的值,因此會綜合出鎖存器(latch)。

      例如,以下case語句將生成一個latch:

      Module default_latch(in1,in2,opcode,out1) ;
      Input [1:0] in1,in2,opcode ;
      Output [1:0] out1 ;
      always@(in1 or in2 or opcode) begin
      case(opcode)
      2』b00 : out1 = in1 & in2 ;
      2』b01: out1 = in1 | in2 ;
      2』b10 : out1 = in1 ^ in2 ;
      //2』b11 : out1 = in1 % in2 ;
      //default : out1 = in1 & in2 ;

      endcase
      end
      endmodule

      在上面,通過兩行注釋,會綜合出鎖存器。

      組合邏輯和時序邏輯中的嵌套if-else實現有什麼區別?

      組合邏輯和時序邏輯中的always語句塊中的if-else實現是不同的。

      在組合邏輯中,當缺少嵌套if-else語句中的最後一個else子句時,它將推斷一個鎖存器,因為寄存器必須記住原來的值。例如:

      Reg latch1 ;
      always@(sel ,in1) begin
      if(sel) latch1 <= in1 ;
      end

      在一個時序邏輯的always語句塊中,如果最後的else語句丟失,仍然會繼續推斷出觸發器。例如:

      Reg ff1 ;
      always@(posedge clk) begin
      if(sel1) ff1 <= in1 ;
      end

      上面的代碼將推斷出如下邏輯。觸發器的D輸入端是門控後的輸出。

      狀態機

      有限狀態機(Finite State Machines)是設計中控制邏輯的重要部分。 本節討論各種類型的FSM編碼風格的差異。

      同步狀態機和非同步狀態機之間有什麼區別?

      同步狀態機和非同步狀態機是狀態機的兩種基本類型。

      非同步狀態機狀態在輸出信號經過一段時間延時後變化時,時間無法預測。同步狀態機狀態變化由時鐘信號控制。

      說明Mealy和Moore狀態機之間的差異。

      Mealy狀態機和Moore狀態機是兩種常用的狀態機編碼風格。 這兩種狀態機的基本框圖如下所示:

      Mealy狀態機輸出是當前狀態和輸入信號的函數。

      Moore狀態機輸出僅是當前狀態的函數。

      如果輸入信號沒有被寄存,Mealy狀態機可能會有毛刺,並且組合邏輯路徑比Moore狀態機長。所以,Mealy狀態機相對於Moore狀態機可能有更低的工作頻率。

      說明二進位編碼和onehot編碼狀態機之間的差異。

      二進位編碼需要更少的觸發器,onehot編碼需要的觸發器和狀態機狀態一樣多。因為輸出存在組合邏輯,二進位編碼時序沒有onehot編碼狀態機好。在ASIC中,如果輸出路徑時序不是很關鍵的話,推薦使用二進位編碼。在FPGA中,觸發器資源較多,可以使用onehot編碼。

      Memory

      Memory是晶元設計的重要組成部分。 Memory可以小到形成一個簡單的寄存器組。隨著晶元面積的增長,晶元中的Memory越來越多。本節討論綜合出設計中Memory的多維數組的含義和選擇來自工藝廠商Memory的一些需要考慮的因素。

      如何實現多維數組。

      Memory可以由綜合工具直接根據數組結構綜合出來。以下是用於綜合出小型存儲器的實例 RTL代碼。

      Module my_memory (datai,datao,clk,wr_n,addr) ;
      Parameter width = 4 ;
      Parameter log2_depth = 16 ;
      Input [width-1 : 0] datai ,addr ;
      Input clk ,wr_n,rd_n ;
      Output [width-1 :0] datao ;

      Reg [width-1 :0] memory [log2_depth -1 :0] ;
      Reg [width -1 : 0 ] datao ;
      always@(posedge clk) begin
      if(wr_n == 1』b0) memory[addr] <= datai ;
      else if(rd_n == 1』b0) datao <= memory[addr] ; //Synchronous read
      end

      endmodule //my_module

      上述代碼會綜合出64個根據地址索引的觸發器。

      Verilog-2001引入了多維存儲器。上面的例子可以擴展到三個維度,即x,y和z,如下:

      Module my_memory(datai , datao , clk ,wr_n ,addr_x , addr_y ,addr_z) begin
      Parameter width = 4 ;
      Parameter log2_d = 4 ;
      Input [width -1 : 0] datai , addr_x ,addr_y , addr_z ;
      Input clk ,wr_n ,rd_n ;
      Output [width -1 : 0] datao ;
      Reg [width-1 :0] memory [log2_d -1 : 0 ] //addr_x
      [log2_d -1 : 0 ] //addr_y
      [log2_d -1 : 0 ] ; //addr_z
      Reg [width-1 : 0] datao ;
      always@(posedge clk) begin
      if(wr_n == 1』b0 ) memory[addr_x][addr_y][addr_z] <= datai ;
      else if(rd_n == 1』b0) datao <= memory[addr_x][addr_y][addr_z] ;
      end
      end

      上面的多維數組最終會被合成x * y * z * width_=4 * 4 * 4 * 4= 256個單獨的觸發器。

      使用來自半導體供應商的硬核memory會有更好的時序,面積和功耗,因為??它的邏輯是經過優化的,而不是使用離散邏輯。

      但是,例化一個工藝相關的memory將使得該設計在不同工藝下不可重用。所以,我們應該在頂層用一個wrapper實例化設計和memory,而不是在設計中實例化memory。

      實例化工藝相關的memory有哪些需要考慮的因素?

      根據應用,memory的選擇基於在以下性能參數上:

      面積:如果該晶元,面積是主要關注點,那麼就需要高密度的memory。通常而言,面積還取決於memory的工藝。

      頻率:如果速度是主要關注點,那麼就需要高速的memory。

      功耗:這是低電壓和低功耗應用的關鍵問題之一。此外,如果功耗變高,則整個系統的性能變得更低。它還增加了最終的封裝成本。

      還需要考慮memory的其他設計變數:

      memory容量:例如,將memory指定為512Kbits。

      電壓:某些memory是針對特定電壓範圍而設計的。

      同步或非同步:指定memory是否具有同步讀/寫或非同步讀/寫。使用哪一個主要取決於是否存在時鐘和匹配設計的時序要求。

      單埠或多埠:確定memory是否由單個或多個讀/寫埠訪問。使用多埠memory的一個關鍵問題是多個埠正在嘗試寫入相同地址的memory會發生什麼問題。

      觸發器或基於鎖存器:確定memory內的基本單元是否是基於觸發器或者鎖存器。

      這種memory的重要考慮因素是可測試性和功耗。基於觸發器的設計比基於鎖存器更容易測試。隨著memory大小的增加,memory的可掃描性是重要的標準。許多供應商都提供了BIST邏輯,使memory可掃描。

      代碼風格

      以下要點總結了設計階段的主要考慮因素:

      寄存關鍵模塊的所有輸出。這將使得在系統級集成期間,介面時序很容易滿足

      根據時鐘域和功能目標,對設計進行劃分(Partition)

      遵循命名約定,便於以後的維護。

      避免實例化特定工藝的門

      在設計中使用參數化代碼

      避免在設計內部生成時鐘和複位

      在頂層的模塊實例化時避免使用膠合邏輯(glue logic)

      2.7.2什麼是「snake」路徑,為什麼要避免它們?

      一條snake路徑,就是一條穿越多個層次的路徑。

      設計中必須避免使用snake路徑,原因如下:

      在對頂層進行靜態時序分析時,它將構成一個很長的時序路徑。但是,在模塊級的靜態時序分析時可能不會被發現。

      綜合工具需要付出更多努力來優化跨層次的時序路徑,同時增加綜合時間。

      為了避免snake路徑

      寄存不同功能模塊的輸出。

      在功能上劃分設計,以避免跨越層次結構的過長的時序路徑。

      定期在集成後的,即使沒有完全通過驗證的設計中執行綜合,檢查是否存在snake路徑。這將通過時序報告提供早期的反饋。

      劃分設計時有哪些注意事項?

      大型設計需要以分層的方式處理。在劃分這些設計時需要考慮以下因素:

      功能:層次結構中邏輯的功能是劃分設計的主要標準。典型層次結構的劃分是:

      地址和數據路徑:此模塊通常包含地址和數據寄存器,用於驅動匯流排的地址和數據。

      控制邏輯:該模塊通常包含有限狀態機器(FSM)

      時鐘域:在多時鐘設計中,建議將同一個時鐘域中的模塊劃分在單個模塊。當信號需要與不同時鐘域中的模塊進行交互時,需要通過一個同步模塊,它將源時鐘域中的信號同步到目的時鐘域。

      面積:模塊中的邏輯太少會產生太多的層次結構,單個模塊中的邏輯過多會在以後的Floorplan期間產生問題。

      跨時鐘域設計考慮因素

      雖然每個模塊都功能正常,但更重要的是模塊間信號通信是否可靠。

      在這方面,同步設計相當有優勢。但是大多數設計都存在多個時鐘。信號跨時鐘域通信的可靠性變得越來越具有挑戰性。本文討論了信號跨越時鐘域時要考慮的幾個問題,以及如何提高可靠性。

      如何跨時鐘域可靠地傳達控制信息?

      當控制信號穿過時鐘域時,信號相對於目標時鐘域為非同步輸入。因此,該信號需要同步以滿足目的時鐘域的建立和保持要求,否則觸發器會進入亞穩態。

      常用方法之一是在源時鐘域和目標時鐘域之間採用兩級觸發器同步器。 如果第一個觸發器進入亞穩態,那麼第一個觸發器中的Q值是未知的,即1或0(模擬中的「x」)。

      通過串聯兩個觸發器,第二個觸發器總能確保捕獲第一個觸發器的輸出作為穩定數據。

      以下是2級同步器。 請注意,數據來自源時鐘clk1,而兩個觸發器由clk2驅動。

      一些工藝廠商和IP供應商甚至還有用於同步目的的特殊優化單元。 雖然這些單元有更少的建立和保持時間要求,但是面積可能比正常的觸發器大,也消耗更多的功耗。 同時,實例化特定工藝的門會使設計的重用性較差。在這種情況下,建議使用兩個觸發器定義一個同步模塊,並在設計中實例化它們。

      上述同步器只能處理目標時鐘可以採樣到的足夠長的電平信號。 如果脈衝信號寬度小於目標時鐘周期,上面的同步器就沒有用。

      傳輸跨時鐘域的,不同匯流排寬度數據的安全策略是什麼?

      當需要跨時鐘域傳輸不同匯流排寬度的數據時,FIFO(First In First Out,先進先出)是理想的組件。 如果匯流排寫入(將數據推入FIFO)和讀取(從FIFO中彈出數據)之間的寬度是不同的,則需要一個不對稱的FIFO。 許多工藝廠商的庫中都有非對稱FIFO。如下圖所示:

      上面FIFO中的標誌通常是full, empty, almost-full 和almost-empty.。FIFO的閾值可以設置為輸入信號或作為實例化參數。 wr_data和rd_data的寬度

      可以是不同的,但通常是整數倍的關係。

      可綜合RTL中常見的「陷阱」

      本文介紹了一些代碼中可能存在的可綜合 「陷阱」。

      2.9.1隻有輸入,沒有輸出的模塊將會綜合成什麼?

      僅有輸入且無輸出的模塊將會被綜合成沒有邏輯的模塊。

      2.9.2為什麼在綜合出的邏輯中看到鎖存器?

      有很多原因會導致在綜合出的邏輯中存在鎖存器。通常在綜合工具的日誌中都有詳細的說明。

      1、always語句塊中的if-else子句沒有最終的else子句,並且沒有初始值。

      2、case語句塊中沒有default子句,並且在進入case語句塊中沒有被賦初始默認值。

      2.9.3什麼是「組合時序環(combinatorial timing loops)」?為什麼要避免?

      combinatorial timing loops是指一個門或者很長的組合邏輯輸出被反饋作為其中一個門的輸入。這些路徑通常是由於大的組合邏輯塊中一個信號驅動同一個組合邏輯塊中的另一個信號。

      這些組合反饋迴路是不被需要的:

      1、由於組合反饋迴路中沒有時鐘來打斷路徑,所以組合邏輯環將無限振蕩

      ,其占空比取決於組合路徑上的延遲。例如,以下代碼是組合邏輯環:

      assign out1 = out1 & in1 ;

      這將導致out1作為其中一個組合邏輯輸入。

      這些循環會導致可測試性的問題。

      可以通過以下手段在早期發現組合邏輯環:

      1、在使用HDL語言設計過程中定期使用linting工具。

      這是迄今為止,捕獲和修復組合邏輯循環的最佳和最簡單的方法。

      1. 在功能模擬期間,期望的輸出行為沒有出現在輸出中,或者模擬根本沒有進行,因為模擬器停止在組合邏輯環了。
      2. 如果在模擬期間未檢測到組合邏輯環路,許多綜合工具都具有合適的報告命令,用於檢測組合邏輯環的存在。

      綜合工具會打破關鍵路徑分析的循環時序弧,然後繼續進行靜態時序分析。

      2.9.4組合always語句塊中的敏感列表如何影響綜合前後的模擬?

      在Verilog-1995中,在綜合和模擬之間, RHS中的所有元素都應該作為組合邏輯always語句塊的敏感列表的一部分。

      雖然綜合工具會根據不在敏感列表中的變數繼續綜合,但是模擬工具將忽略不在敏感列表中的變數的變化。結果是,功能模擬和綜合後模擬的行為是不同的。

      通常,文本編輯器(如具有Verilog語言模式的emacs)能夠自動推斷出正確的敏感列表變數,並自動將其添加到敏感列表中。 Linting工具也會在解析期間提供錯誤消息

      從Verilog-2001開始,這不再是一個問題。@(*)添加了所有的變數到敏感列表。例如,將RHS的所有元素都添加到敏感列表中:

      在Verilog-1995中:

      always@(in1 or in2 or in3 or in4) begin
      out1 = (in1 ^ in2) & (in3 | in4) ;
      end

      在Verilog-2001中:

      //note the use of 「,」in the place of 」or」
      always@(in1,in2,in3,in4) begin
      out1 = (in1 ^ in2) & (in3 | in4) ;
      end

      or

      //note the use of 「*」
      always@(*) begin
      out1 = (in1 ^ in2) & (in3 | in4) ;
      end

      在SystemVerilog中可以使用always_comb,如下:
      Always_comb
      Begin
      out1 = (in1 ^ in2) & (in3 | in4) ;
      end

      此時,代碼更加簡單,也更易於維護。

      RTL代碼,讓你的晶元更小

      本文描述了一個優化軟核面積的 RTL編碼技術。優化掉不需要的邏輯不僅減少了晶元面積,還減少了電路的開關活動,因此也減少了功耗。

      `ifdef,`ifndef,`elsif,`endif結構如何幫助最小化面積?

      以下是如何使用編譯器指令最小化邏輯設計面積的示例:

      `define MIN

      Module area_min_byifdef(in1,in2,in3,in4,out1) ;
      Input in1 ,in2 ,in3 ,in4;
      Output out1 ;
      `ifdef MIN
      Assign out1 = in1 & in2 ; // minimal area
      `else //large area
      Assign out1 = (in1 & in2) | (in3 ^ in4) ;
      `endif
      Endmodule

      使用編譯器指令可以選擇適當的模塊。在以下代碼中,使用編譯器指令選擇正確類型的計數器,即ripple 計數器和carry lookahead 計數器

      //`define CLA
      Module area_min_by_ifdef (a.b,c,sum,cout) ;
      Input a,b,c ;
      Output sum,cout ;
      `ifndef CLA
      Ripple_adder U_ripple (
      .in1(a) ,
      .in2(b) ,
      .in3(c) ,
      .sum(sum) ,
      .cout(cout)
      ) ; // smaller area , longer timing
      `else
      cla_adder U_cla (
      .in1(a) ,
      .in2(b) ,
      .in3(c) ,
      .sum(sum) ,
      .cout(cout)
      ) ; // larger area , faster timing

      `endif
      Endmodule

      在上面的例子中,`ifndef是指缺少CLA的`define

      因此,使用這種方法中,來選擇適當的代碼去實現你的電路功能。

      聲明一些reg位,但不賦值和使用會發生什麼?

      當聲明一些reg位,但不賦值和使用時,對應於那些位的邏輯會被優化掉。 例如,在下面的代碼中,雖然聲明了int_tmp,但是2:1位是未使用的。 該代碼將綜合出int_tmp [3]和int_tmp [0]相關的邏輯, tmp [2:1] 相關的邏輯會被優化掉。

      Module lower(in1,in1,clk,reset,out1 );
      Input in1 ,in2 ;
      Input clk ,reset ;
      Output [1:0] out1 ;
      Reg [3:0] int_tmp ;
      always@(posedge clk or negedge reset) begin
      if(!reset) int_tmp <= 0 ;
      else begin
      //Only bits 0 and 3 are used .
      //Bits [2:1] are not assigned
      Int_tmp[0] <= in1 ;
      Int_tmp[3] <= in2;
      end
      end
      endmodule

      RTL時序優化

      當一個設計被綜合成網表後,路徑中的門延遲和走線延遲等會對晶元的整體性能有影響。在設計的早期即模塊劃分和功能設計階段,就應該考慮到時序的影響。在功能驗證時考慮時序的影響就太晚了。

      設計中的關鍵路徑(critical path)是什麼?理解關鍵路徑的重點是什麼?

      關鍵路徑是通過具有最小slack的電路時序路徑。它不一定是設計中最長的路徑。在一個設計中可以有不止一個關鍵路徑。所有路徑中到達時間(arrival)和要求時間(required)之差為負值時,該路徑是一條違例路徑(violating path)。

      理解和識別設計中的關鍵路徑:

      1、它有助於修復靜態時序問題,特別是建立時間違例的關鍵路徑

      2、縮短關鍵路徑延遲可以提高頻率,和晶元的性能。

      如果在設計流程的早期就確定了關鍵路徑,可以適當地進行功能更改來縮短關鍵路徑延遲。考慮到路徑中觸發器的插入,會增加設計中的latency。

      如果關鍵路徑來自模塊中的輸入埠,建議寄存輸入。雖然這會增加latency,但有助於提高設計工作的頻率。

      如何適當地劃分設計以實現更好的靜態時序?

      正確地劃分設計,在設計的多個階段,直到後端流程都有幫助。在編寫HDL代碼之前就需要對設計進行劃分。

      以下是一些設計劃分的建議:

      1.邏輯劃分:通常我們會根據邏輯相關性來劃分設計。例如,數據路徑、控制模塊(FSMs)、存儲器和I / O。模塊劃分有助於多個團隊成員進行模塊級驗證,和項目管理、版本控制。通常,模塊大小應該在大約5 k門左右。

      在邏輯劃分時,寄存輸出關鍵模塊的輸出將大大減少長組合邏輯路徑和跨越多個層次的組合邏輯路徑,因此會有更好的靜態時序分析結果。

      對於特別的邏輯,如I/O、複位、時鐘應該位於單獨的模塊中。

      2、根據時鐘域劃分:按照相同的時鐘域進行邏輯劃分在綜合、靜態時序分析中起著重要的作用,並且需要在跨時鐘域間的同步模塊中定義false path。

      寄存器之間的「retime」是什麼意思?

      retime是指保持設計功能行為的情況下,改變寄存器位置的過程。

      retime有助於平衡流水線之間關鍵路徑的路徑延時,但是retime之後的形式驗證可能與原來的設計不同。

      為什麼在高速設計中,FSM首選one-hot編碼?

      由於one-hot編碼的每個狀態存在一個顯式的觸發器狀態,不需要輸出狀態解碼。 因此,觸發器的clock to q延遲是唯一的延遲。 這使得one-hot編碼適合用於高速設計

      可測性設計(DFT)

      可測試性(DFT)用來確保設計最終是可以測試的。DFT在增加故障覆蓋率(fault coverage)的同時也增加了面積。

      影響設計可測試性的主要因素是什麼?

      1、設計中存在三態匯流排

      2、由一個觸發器的輸出驅動另一個觸發器的複位

      3、設計中存在生成時鐘

      4、設計中存在門控時鐘

      5、設計中存在鎖存器

      晶元上片上三態匯流排對可測試性有什麼影響,該如何處理它?

      通常,晶元內不應存在三態匯流排,因為它們消耗更多的功耗。如果晶元上存在三態匯流排,應注意避免匯流排競爭,即同一時間在匯流排上驅動不同的值。匯流排衝突會消耗更多的功耗,進而導致晶元損壞。 在掃描測試階段避免匯流排競爭的途徑是控制三態緩衝器的使能,即與掃描使能信號進行「與」運算。

      在正常工作模式,scan_en_n信號為邏輯「1」,允許控制信號通過。

      在測試模式下,scan_en_n信號為邏輯「0」假定這些使能的控制輸入來自觸發器的輸出。 如下圖所示:

      這些緩衝器的Verilog示例代碼如下所示:

      Assign wire1 = (control_in1 & ~scan_en_n) ? in1 : 1』bz ;
      Assign wire1 = (control_in2 & ~scan_en_n) ? in2 : 1』bz ;

      晶元中的一些觸發器的複位由其他觸發器驅動對可測試性有什麼影響,該如何處理它?

      通常,觸發器的非同步置位或複位來自模塊和設計的輸入引腳。有時候,不可避免地由一個觸發器的輸出驅動另一個觸發器的非同步置位/複位。在這種情況下,在掃描測試期間,如果驅動觸發器獲得一個測試向量,使其複位另一個觸發器,則會發生功能錯誤。 為防止這種情況,複位信號應該和test_mode測試模式信號異或。如下圖所示:

      在正常工作模式, test_mode為1b0。但是,在測試期間,test_mode信號為1b1,從而使非同步複位失效。

      晶元中存在生成時鐘對可測試性有什麼影響,該如何處理它?

      生成時鐘由時鐘分頻器通過觸發器或晶元中的PLL產生。

      在這種情況下,需要在時鐘路徑中添加多路復用器,使用test_mode作為控制信號,多路復用器的輸入是常規時鐘和生成時鐘。

      晶元中有門控時鐘對可測試性有什麼影響,該如何處理它?

      在某些設計中,門控時鐘是不可避免的,它可以用來降低功耗。 因為時鐘現在通過組合邏輯,從而無法掃描測試。

      解決方法如下:

      組合反饋邏輯對可測試性有什麼影響,該如何處理它?

      在任何設計的任何階段都應該避免存在組合邏輯反饋。我們應該使用lint和綜合工具定期地檢查。組合邏輯反饋電路的存在會導致設計中不可預測的邏輯行為。 由於組合邏輯環的行為依賴於延遲,我們無法使用任何ATPG演算法進行測試。 因此,在邏輯上應該避免組合邏輯環。

      鎖存器對可測試性有什麼影響,該如何處理它?

      為了使鎖存器具有可控性,需要使能和測試模式信號進行異或。如下圖

      所示:

      低功耗

      低功耗是當今大多數晶元的關鍵要求。 晶元的功耗越大,設備就會越熱

      ,運行速度越慢。並且在高溫下,晶元的可靠性會降低。 本文討論如何在RTL級對功耗進行優化。

      在RTL編碼期間可以有哪些方法降低功耗?

      在晶元邏輯轉換期間,CMOS電路中的任何開關活動都會產生瞬時電流,因此增加了功耗。

      設計中最常見的存儲元件是同步觸發器,它的輸出會在輸入數據和時鐘改變時改變。 因此,如果輸入數據和時鐘只有在需要時才存在或者觸發就可以減少

      電路信號開關活動,降低功耗。 以下總結了一些降低功耗的機制:

      1、減少輸入數據的切換。

      2、減少觸發器的時鐘切換。

      3、減小晶元面積,因為可以減少門/觸發器的開關切換。

      以下深入討論了在RTL中實現的問題:

      如何減少觸發器的輸入數據切換來降低功耗?

      對於相對於時鐘很少更新的觸發器來說,應該僅在合適的時候更新觸發器,避免觸發器輸出沒有必要的更新。

      這可以通過使能觸發器實現,如下圖所示:

      實現使能觸發器的Verilog RTL的示例如下:

      Module enable_ff(
      Clk ,
      Sel ,
      Reset_n ,
      In1 ,
      out1 );
      input clk ,reset_n,sel ,in1 ;
      outpu out1 ;
      reg out1 ;
      always@(posedge clk or negedge reset_n) begin
      if(!reset_n) begin
      out1 <= 1』b0 ;
      end
      else if(sel) begin
      out1 <= in1 ;
      end
      else out1 <= out1 ;
      end
      endmodule

      通過遵循上述的編碼風格來降低功耗是不夠的,因為它有一個缺點:

      儘管使用使能觸發器可以減少數據切換,但是它引入了額外的邏輯到觸發器的

      D輸入,可能會增加關鍵路徑的延遲。

      另一個副作用是,會增加晶元的面積。

      時鐘門控如何減少功耗

      時鐘門控是節省功耗最常用的機制。 這種技術通過以下方式減少觸發器輸出的切換:

      1、無需在寄存器中重新載入相同的值

      2、降低時鐘網路功耗。

      時鐘門控最常用的方法是使用鎖存器

      和一個門,如下圖:

      當clk處於低電平時,鎖存器被使能。如果輸入控制信號為高,則Q在時鐘低電平時為高電平,並保持不變直到下一個clk的低電平。

      電路中的鎖存器輸出很容易滿足觸發器的建立時間要求。當輸入控制信號為低電平時,會阻止了clk的傳播。這使得門控時鐘網路沒有任何轉換活動。

      一個簡單的Verilog代碼可以描述上述邏輯,如下:

      Module gated_ff(in1 , cntrl_in , clk ,reset_n , out1 ) ;
      Input cntrl_in , in1 ,reset_n ;
      Output out1 ;

      Wire gated_clk ;
      Reg d_latch , out1 ;
      always@(cntrl_in , clk ) begin
      if(!clk) d_latch <= cntrl_in ;
      end

      assign gated_clk = d_latch & clk ;

      always@(posedge clk or negedge reset_n) begin
      if(reset_n) begin
      out1 <= 1』b0 ;
      end
      else begin
      out1 <= in1 ;
      end
      end
      endmodule

      在大型設計中門控時鐘都是通過綜合工具完成的,無需手動實現。

      此外,門控元件AND門可以根據使能的邏輯電平和觸發器邊沿觸發類型改變。

      鎖存器時鐘門控有哪些副作用,如何去修復?

      雖然使用鎖存器時鐘門控是一種很好的降低功耗方法,但是它引入了可測試性問題。 因為使用鎖存器門控時鐘時,時鐘信號現在僅受輸入控制信號的控制。在

      測試時,如果此信號為低,則時鐘信號無法傳播。

      要解決上述問題,需要添加其他邏輯增強可測試性。一種方法時鐘是在鎖存器的輸入端引入一個控制邏輯,使鎖存器在掃描測試期間處於「使能」狀態。 如下圖所示:

      一個簡單的Verilog代碼可以描述上述邏輯,如下:

      Module gated_ff (in1 , scan_en ,clk , reset_n , cntrl_in , out1) ;
      Input scan_en , in1 ,clk , reset_n , cntrl_in ;
      Output out1 ;
      wire gated_clk ,latch_en ;
      reg d_latch , out1 ;
      assign latch_en = scan_en | clk ;
      always@(cntrl_in , latch_en ) begin
      if(latch_en) d_latch <= cntrl_in ;
      end
      assign gated_clk = d_latch & clk ;
      always@(posedge gated_clk or negedge reset_n) begin
      if(!reset_n) out1 <= 1』b0 ;
      else out1 <= in1 ;
      end
      endmodule

      在大型設計中,上述邏輯可以通過綜合工具完成的,無需手動實現。

      在RTL設計階段還有其他的低功耗設計技術么?

      1. 高頻信號通過儘可能少的邏輯。一些必要的邏輯在高頻下運行,其餘邏輯可以相對較低的頻率下運行。
      2. 僅使用必要數量的觸發器來存儲數據值,即如果僅使用32位寄存器的4位,則不需要剩下的28位寄存器。通常,未使用的觸發器會綜合工具優化掉
      3. 使用晶元片選信號。來自CPU的地址不斷變化,不會一直指向所有的模塊。在這種情況下,最好在各個模塊根據地址解碼生成一個片選信號,以減少

      不必要的信號切換。

      4、狀態機選擇格雷碼而不是二進位編碼:

      由於格雷碼轉換隻有一位發生變化,因此觸發器切換以及它所驅動的邏輯的切換都會減少。但是,格雷碼比二進位編碼需要更多的觸發器。

      5、使用多路復用器而不是片上三態匯流排,因為三態匯流排可能會發生匯流排競爭,此時會導致內部匯流排短路。多路復用器的選擇避免了匯流排競爭,但會增加邏輯門的數量。三態匯流排還需要內部上拉電阻和更高的電流驅動。

      除RTL級外,有哪些系統級技術,影響晶元的功耗?

      1、降低工作電壓:功耗和電壓的平方成正比,在較低的電壓下工作

      一種降低功耗的方法。許多工藝廠商都有專為低功耗而設計的庫。

      1. 降低工作頻率:功耗和頻率成正比。設計可以考慮在較低的頻率下工作,然後增加匯流排寬度,以維持數據速率要求。例如, 100MHz的32位匯流排的數據傳輸與50MHz的64位匯流排相同。

      1. 降低走線的電容。

      在後端分析階段,可以採用哪些降低功耗的技術?

      以下是後端階段需要關心的,顯著影響整體功耗的幾個參數:

      1、功耗和時序敏感的邏輯走線更短:因為走線電容是長度,寬度和阻抗的函數,長的走線路徑通常具有更高的電容。 由於動態功耗與電容成比例,即電容越低

      功耗越低。所以,邏輯塊需要彼此相互接近


      推薦閱讀:
      相关文章