邏輯綜合
一、綜合綜述
綜合的過程是將行為描述的電路、 RTL 級的電路轉換到門級的過程。
三個階段:轉換(translation)、映射(mapping) 與優化(optimization)。
- 轉換:將 HDL 的描述轉換成一個與工藝獨立(technology-independent)的 RTL 級網表(網表中 RTL 模塊通過連線互聯);
- 映射:根據具體指定的工藝庫, 將 RTL 級網表映射到工藝庫上, 成為一個門級網表;
- 優化:根據設計者施加的諸如延時、 面積方面的約束條件,對門級網表進行優化。
1.1 DC
使用 DC 做綜合也包含轉換、 優化和映射三個階段。

轉換是使用 gtech.db庫中的 RTL 級單元來組成一個中間網表;
優化與映射是綜合工具對已有的中間網表進行分析,去掉其中的冗余單元,并對不滿足限制條件(如 constraints.tcl)的路徑進行優化,然后將優化之后的電路映射到由制造商提供的工藝庫上(如 core_slow.db)。
二、Verilog 語言結構到門級的映射
2.1 if語句的綜合
如果在使用 if 語句時, 沒有指出條件判斷的所有可能情況,就會在電路中引入鎖存器(Latch)。
由于鎖存器和觸發器兩種時序單元共存的電路會增大測試的難度,因此,在綜合的時候盡量只選用一種時序單元, 為了不在電路中引入鎖存器, 應該使用完備的 if…else if…else 的語句結構。
但是只有組合邏輯會出現這個問題。
2.2 case語句的綜合
同樣的,組合邏輯中,case語句未覆蓋所有情況也會引入Latch。有下面幾種方法:
- 在case語句的最后加入default;
- case語句之前給被賦值信號賦初值;
- 如果沒寫的情況不可能出現,可以加入指令//synopsys full_case。
always @(Toggle) begin
case(Toggle) //synopsys full_case
2'b00: ;
2'b01: ;
endcase
end
如果case項是互斥的,可以加入指令//synopsys parallel_case進行并行檢查,
always @(Toggle) begin
case(Toggle) //synopsys parallel_case
3'bxx1: ;
3'bx1x: ;
3'b1xx: ;
default: ;
endcase
end
2.3 循環語句的綜合
verilog有四種循環語句:for、while、repeat和forever。只有for可以綜合,綜合方法是把for循環展開。
always @(Address) begin
for(J = 3; J >= 0; J = J - 1)
if(Address == J) Line[J] = 1;
else Line[J] = 0;
end
//展開后等價于
if(Address == 3) Line[3] = 1; else Line[3] = 0;
if(Address == 2) Line[2] = 1; else Line[2] = 0;
if(Address == 1) Line[1] = 1; else Line[1] = 0;
if(Address == 0) Line[0] = 1; else Line[0] = 0;
2.4 算術電路的綜合
遇到“+”、“-”和“*”等算術運算符和“>”、“<”、“>=”和“<=”等邏輯運算符時,DC會在DesignWare 中選取合適的邏輯電路來實現該運算符 。
DesignWare 分為 DesignWare Basic 與 DesignWare Foundation。DesignWare Basic 提供基本的電路,DesignWare Foundation 提供性能較高的電路結構。
三、使用Design Compiler進行綜合
大致分為以下4個部分:
- 預綜合過程(Pre-synthesis Processes);
- 施加設計約束(Constrainting the Design);
- 設計綜合(Synthesizing the Design);
- 后綜合過程(Post-synthesis Process)。
3.1 預綜合過程
預綜合過程是指在綜合過程之前的一些為綜合做準備的步驟, 包括 Design Compiler 的啟動、 設置各種庫文件、 創建啟動腳本文件、 讀入設計文件、 DC 中的設計對象、 各種模塊的劃分以及 Verilog 的編碼等等。
3.1.1 DC啟動
- dc_shell-t命令行方式
該方式是以 TCL(Tool Command Language) 為基礎的,在該腳本語言上擴展了實現 Design Compiler 的命令。
- dc_shell -gui圖形界面方式
使用圖形界面, 如菜單、 對話框等來實現 Design Compiler 的功能,并提供圖形方式的顯示電路。工藝庫(target_library)
command.log用于記錄用戶在使用 Design Compiler 時所執行的命令以及設置的參數;
filenames.log 用于記錄 design compiler 訪問過的目錄,包括庫、源文件等,filenames.log 文件在退出 design compiler 時會被自動刪除。
3.1.2 庫文件設置
- 工藝庫(target_library):綜合后電路網表要最終映射到的庫,由 Foundary 提供的,一般是.db 的格式。包含了各個門級單元的行為、 引腳、 面積以及時序信息;
- 鏈接庫(link_library):設置模塊或者單元電路的引用,對于所有 DC 可能用到的庫,都需要在 link_library 中指定。在 link_library 的設置中必須包含’*’, 表示 DC 在引用實例化模塊或者單元電路時首先搜索已經調進 DC memory 的模塊和單元電路。同時需要設置 search_path,因為 link_library 默認是在運行 DC 的目錄下尋找相關引用;
- 符號庫 (symbol_library):定義了單元電路顯示的 Schematic 的庫,后綴是.sdb,用于圖形界面看電路;
- 綜合庫(synthetic_library):在2.4中提到,使用 DesignWare Foundation 才需要在 synthetic_library 中設置,同時在 link_library 中鏈接;
3.1.3 啟動文件設置

DC啟動時按從上到下的順序讀取三個路徑下的啟動文件(.synopsys_dc.setup),后面的啟動文件會覆蓋前面的啟動文件:
- $SYNOPSYS/admin/setup 目錄下, DC 安裝的標準初始化文件;
- 當前用戶的$HOME 目錄下,一般用于設置一些用戶本人使用的變量以及一些個性化設置;
- DC 啟動的目錄下,一般用于與所在設計相關的設置。
3.1.4 讀入設計文件
對于 TCL 工作模式,讀取不同的文件格式需要使用不同的命令。
read_db file.db //TCL 工作模式讀取 DB 格式
read_verilog file.v //TCL 工作模式讀取 verilog 格式
read_vhdl file.vhd //TCL 工作模式讀取 VHDL 格式
3.1.5 設計對象
注意:DC 識別 Clock 不是通過 HDL 的書面表達, 而是要通過設計者施加一定的約束來區分的,
create_clock ... [get_ports CLK]
如果Port、Net、Pin都叫CLK,比如上面這個圖,怎么知道把哪個CLK設置為時鐘呢?
其實上面的代碼已經給出答案了[get_ports CLK],即把port的CLK設置為時鐘。
這個代碼是搜索對象,下圖是tcl和dcsh各自的搜索對象的語法,

3.1.6 設計劃分
原則一:不要讓一個組合電路穿越過多的模塊:即一個完整的組合邏輯就寫在一個module里。
原則二:寄存模塊的輸出:每個模塊的輸出在輸出前先過一個寄存器,但是可能存在粘滯邏輯的問題:

上面的ABC三模塊的輸出都經過了寄存器,是正確的。但是在頂層中,A和B的輸出經過了一個組合邏輯后,輸入給C module,這就叫粘滯邏輯,可以通過把這個組合邏輯放到C的組合邏輯中解決。
原則三:根據綜合時間長短控制模塊大小:就是把很大的組合邏輯用寄存器隔開,形成多個小的組合邏輯,提升綜合效率;
原則四:將同步邏輯部分與其他部分分離。
3.2 施加設計約束
- 時序和面積約束;
- 電路的環境屬性;
- 時序和負載在不同模塊之間的分配以及時序分析。
3.2.1 時序與面積
3.2.1.1 定義面積約束
定義面積約束通過 set_max_area 命令完成,
current_design PRGRM_CNT_TOP
set_max_area 100
給 PRGRM_CNT_TOP 的設計施加了一個最大面積 100 單位的約束,100的單位有Foundary決定,一般是:
- 二輸入與非門的大小;
- 晶體管的數目;
- 實際的面積(平方微米等等)。
3.2.1.2 同步設計的時序特點和目標
同步時序電路的特點:電路中的信號從一個受時鐘控制的寄存器觸發, 到達另一個受時鐘控制的寄存器。
目標:約束電路中所有的時序路徑。
時序路徑可以分為三類:輸入到寄存器的路徑、寄存器到寄存器之間的路徑以及寄存器到輸出的路徑。
3.2.1.3 定義時鐘
時序電路以及組合電路的優化都是以時鐘為基準來計算路徑延遲。
定義時鐘必須定義時鐘源(Clock source), 時鐘源可以是端口也可以是管腳;另外還必須定義時鐘的周期,
create_clock -period 10 [get_ports Clk]
set_dont_touch_network [get_clocks Clk]
- 把端口Clk設置為周期為10ns的時鐘;
- 把時鐘網絡設置為dont touch,即不優化時鐘。
占空比(Duty Cycle)、 時鐘偏差(Clock Skew)和時鐘名字(Clock Name)是可選配置項。
3.2.1.4 約束輸入路徑
輸入延時是指被綜合模塊外的寄存器觸發的信號在到達被綜合模塊之前經過的延時。
set_input_delay -max 4 -clock Clk [get_ports A]
被綜合模塊的端口 A 的最大輸入延時為 4ns,為了滿足時序單元建立時間(setup time)的要求。如果用-min,則是針對保持時間的約束使用的。
3.2.1.5 約束輸出路徑
set_output_delay -max 5.4 -clock Clk [get_ports B]
被綜合模塊的輸出端口 B 的最大輸出延時為 5.4ns
3.2.2 環境屬性
外界的溫度變化、電路的供電電壓變化、輸入輸出的外圍電路的驅動能力和負載大小以及電路內部的互連線延時。
3.2.2.1 設置輸出負載
輸出負載過大會加大電路的 transition time,影響時序特性;而如果不設置輸出負載,那么 DC 默認輸出負載為 0,這樣綜合出來的電路時序顯然過于樂觀。
設置輸出負載是通過 DC 的 set_load 命令完成。
該命令有兩種用法, 一種是直接給端口賦一個具體的值, 另外則結合另一個命令 load_of 指出它的負載相當于工藝庫中的哪個單元的負載值,
set_load 5 [get_ports OUT1]
set_load [load_of my_lib/and2a0/A] [get_ports OUT1]
set_load [expr [load_of my_lib/inv1a0/A] * 3] [get_ports OUT1]
- 直接給端口OUT1賦5;
- 給端口OUT1賦 my_lib 中 and2a0 單元的 A 管腳的負載值;
- OUT1 相當于接了三個 inv1a0 單元的 A 管腳的負載值。
3.2.2.2 設置輸入驅動
為了更加準確的估計模塊輸入的時序,同樣需要知道輸入端口所接單元的驅動能力。 在默認的情況下, DC 認為驅動輸入的單元的驅動能力為無窮大,即 transition time 為 0。
設置輸入驅動是通過 DC 的 set_driving_cell 命令完成。set_driving_cell 是指定使用庫中的某一個單元來驅動輸入端口。 該命令是在輸入端口之前假想一個驅動單元, 然后按照該單元的輸出電阻來計算 transition time,從而計算輸入端口到門單元電路的延遲。
set_driving_cell -lib_cell and2a0 [get_ports IN1]
設置模塊輸入端口 IN1 的驅動單元是工藝庫中的 and2a0。
3.2.2.3 設置工作條件
工作條件包括三方面:溫度、 電壓以及工藝。
單元的延時會隨著溫度的上升而增加; 隨著電壓的上升而減小; 隨著工藝尺寸的增大而增大。
工藝庫中提供的工作條件一般分為三種: 最好情況(best case)、 典型情況(typical case)以及最差情況(worst case)。
最好情況用于保持時間(hold time)的時序分析,最差情況用于建立時間(setup time)的時序分析。
- 通過 report_lib 命令來列出在當前的工藝庫里提供了哪幾種工作條件;
- 通過 set_operating_conditions 指定需要用到的工作條件,
set_operating_conditions -max "slow_125_1.62"
“ ”中是工作條件的名字,-max表示分析建立時間。
3.2.2.4 設置連線負載模型
連線負載模型基于連線的扇出,估計它的電阻電容等寄生參數,由 Foundry 提供。
以下討論模塊內部的連線。
- 通過命令 report_lib 查詢連線負載模型;
- 通過 DC 的 set_wire_load_model 命令設置連線負載模型;
set_wire_load_model -name 160KGATES
不過默認情況下DC會自動選擇連線負載模型。
以下討論模塊外部的互連線。
如果是模塊外部連線,就必須使用 set_wire_load_model 命令,此時有三個模式:圍繞(enclosed)、頂層(top)以及分段(segmented)
圍繞:用這兩個module的最接近的頂層module的負載模型代替;
頂層:用最頂層module的負載模型代替;
分段:根據穿過的三段的模型相加得到。
3.2.3 時序分析
Design Time 是 DC 的一個內嵌的靜態時序分析引擎,PrimeTime 是在 DesignTime 的基礎上發展起來的獨立的專業的時序工具,效率和應用范圍更高。
靜態時序分析的三個步驟:
- 將電路分解成不同的時序路徑(timing paths);
- 計算每段路徑的延時;
- 檢查所有路徑的延時,看是否能滿足時序要求。
3.2.3.1 分解時序路徑
DesignTime 對時序路徑的分解是根據時序路徑的起點和終點的位置來決定的。
數據路徑:
- 輸入到寄存器;
- 寄存器到寄存器;
- 寄存器到輸出;
- 輸入到輸出。
時鐘路徑:
- 時鐘輸入到寄存器;
3.2.4 DC Tcl 初步
3.2.4.1 執行 DC-Tcl 腳本
第一種:
dc_shell-t
source my.tcl
也可以結合起來
dc_shell-t -f my.tcl
dc_shell-t -f my.tcl > my.log
dc_shell-t -f my.tcl | tee my.log
- 打開dc_shell并執行my.tcl
- 打開dc_shell后,將執行結果記錄在my.log里;
- 打開dc_shell后,將執行結果記錄在my.log里并且打印出來。
聲明
本文內容均參考自《DesignCompiler中文guide手冊》。
浙公網安備 33010602011771號