1、如何快速做一个逻辑综合
在这里需要记住:在设置库的搜索路径、设置工艺库的时候,要使用set_app_var.其他的设置可以使用set了。
读取rtl代码使用read_file,写出网表使用write_file,最后会得到很多报告(.rpt)
在这里我们使用下面的代码作为顶层模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 module my_module( input logic clk, input logic rst_n, input logic [1 :0 ] sel, input logic [31 :0 ] wdata, input logic wr_en, output logic [31 :0 ] rdata ); logic [31 :0 ] register_file[3 :0 ];always @(posedge clk or negedge rst_n) begin if (!rst_n) begin for (int i = 0 ; i < 4 ; i++) begin register_file[i] <= 'h0 ; end end else begin if (wr_en) begin register_file[sel] <= wdata; end end end assign rdata = register_file[sel];endmodule
一个读写共用地址线、支持同步写入与异步读取的 4行 × 32位宽 的微型寄存器堆(Register File)。
.db文件是给DC读取,对应的.lib文件是供人参考。lib compiler工具可将.lib文件转换为.db文件
.lib (Liberty格式) 是明文的文本文件,可以用记事本打开它
Synopsys 的 DC 综合工具它嫌读文本太慢了!所以,Synopsys 把 .lib 编译、加密成了它独家专属的二进制格式——也就是这个 .db (Database) 文件。
所以总结一句话:.lib 是给人看的工艺库,.db 是给 DC 工具高效率使用的工艺库。
只要你在 .v 文件里看到 GTECH 前缀和 SEQGEN 单元,就可以 100% 判定这是一个未经映射(Unmapped)的中间态网表。
看到 SEQGEN :时序逻辑的毛坯
特征:寄存器不是具体的工艺单元(如 SMIC 的 DFFRQX1M),而是统一标着 SEQGEN 。 含义:这代表 Design Compiler 已经识别出这里需要“存数据”,但还没决定用哪个电压、哪个尺寸的触发器去存。
看到 GTECH_ 前缀:组合逻辑的占位符
特征:所有的门电路都叫 GTECH_AND2、GTECH_NOT、GTECH_BUF 等。 含义:这些是 Synopsys 内部的通用逻辑符号。它们没有物理尺寸,没有延迟数据,只是在逻辑上告诉工具“这里有个与门”。
逻辑块操作符 (MUX_OP, SELECT_OP)
特征:出现这种大写字母结尾且带 _OP 的单元。 含义:这是 DC 把你的 if-else 或 case 语句初步转换成的“功能块”。在最终映射时,它们会被拆解成一大堆细碎的组合门电路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 module my_module ( clk, rst_n, sel, wdata, wr_en, rdata ); input [1 :0 ] sel; input [31 :0 ] wdata; output [31 :0 ] rdata; input clk, rst_n, wr_en; \**SEQGEN** \register_file_reg[1 ][0 ] ( .clear (N8), .preset (1'b0 ), .next_state (wdata[0 ]), .clocked_on (clk), .data_in (1'b0 ), .enable (1'b0 ), .Q (\register_file[1 ][0 ] ), .synch_clear (1'b0 ), .synch_preset (1'b0 ), .synch_toggle (1'b0 ), .synch_enable (N15) ); \**SEQGEN** \register_file_reg[0 ][31 ] ( .clear (N8), .preset (1'b0 ), .next_state (wdata[31 ]), .clocked_on (clk), .data_in (1'b0 ), .enable (1'b0 ), .Q (\register_file[0 ][31 ] ), .synch_clear (1'b0 ), .synch_preset (1'b0 ), .synch_toggle (1'b0 ), .synch_enable (N14) ); \**SEQGEN** \register_file_reg[0 ][30 ] ( .clear (N8), .preset (1'b0 ), .next_state (wdata[30 ]), .clocked_on (clk), .data_in (1'b0 ), .enable (1'b0 ), .Q (\register_file[0 ][30 ] ), .synch_clear (1'b0 ), .synch_preset (1'b0 ), .synch_toggle (1'b0 ), .synch_enable (N14) ); GTECH_AND2 C529 ( .A (sel[0 ]), .B (sel[1 ]), .Z (N13) ); GTECH_AND2 C530 ( .A (N0), .B (sel[1 ]), .Z (N12) ); GTECH_NOT I_0 ( .A (sel[0 ]), .Z (N0) ); GTECH_AND2 C531 ( .A (sel[0 ]), .B (N1), .Z (N11) ); GTECH_BUF B_2 ( .A (sel[0 ]), .Z (N6) ); GTECH_BUF B_3 ( .A (sel[1 ]), .Z (N7) ); GTECH_NOT I_4 ( .A (rst_n), .Z (N8) ); GTECH_NOT I_5 ( .A (wr_en), .Z (N9) ); endmodule
起点 (RTL):你写的 .sv 源代码。
第一站 (Elaborate):执行 read_file 后,DC 把代码翻译成 GTECH 网表。你现在看的就是这一站的产物。
第二站 (Compile):执行 compile_ultra 后,DC 会把 GTECH 替换为具体的工艺单元。
终点 (Mapped):产生包含 DFFRQX1M 或 OA22XLM 等真实单元的 Mapped 网表。
postcompile.v 是给 Design Compiler 自己看的,而 change_names 后的网表是给全世界看的。
🔍 区别一:逃逸字符 vs. 规范命名 (Escaped Names)
这是最容易看出来的区别。
postcompile.v (带有“反斜杠”): 你看它的连线名和实例名:\register_file[3][31]。 原理:在 Verilog 语法中,如果名字里带中括号 [],编译器会觉得那是数组。DC 为了保留你 RTL 里的层级美感,强行加了反斜杠 \ 作为转义。 毒点:这种格式虽然合法,但到了后端工具(比如 Innovus)或者仿真器里,经常会报错或识别混乱。 change_names 后 (干净清爽): 名字变成了:register_file_reg_3__31_。 原理:DC 把所有的 [ 和 ] 全都换成了下划线 _。 优点:这叫“合法化(Legalization)”,所有 EDA 工具都能无压力识别,这是大厂流片网表的标配格式。
📊 区别二:零散连线 vs. 总线合并 (Bus Reconstruction)
这一部分体现了 change_names 的强大整理能力。
postcompile.v: 声明了一大堆密密麻麻的单根 wire,比如 wire \register_file[3][31] , \register_file[3][30] …。 这就像是一捆乱麻,每一根线都有一个极其古怪的长名字。 change_names 后: 直接合并成了:wire [127:0] register_file;。 原理:工具识别出这些分散的线其实是同一个寄存器组,于是重新打包成了一个 128 位的向量(Vector)。 赢在哪里:代码行数瞬间缩减,可读性提升了 100 倍!
🏗️ 区别三:实例引脚的引用方式
postcompile.v: 引脚连接:.Q(\register_file[3][31] )。 change_names 后: 引脚连接:.Q(register_file[127])。 含义:所有的引用都从“奇奇怪怪的字符串”回归到了正常的“数组索引”。
举一个下面的例子:
综合工具把这些寄存器,直接chang_name优化成下面的了:
下面的这些寄存器:
更换名字:
使用下划线等进行命名:
2、逻辑综合脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 # 1. 基础环境定义 set TOP_MODULE my_module set VERSION v1_ss_run set_host_options -max_cores 8 define_design_lib WORK -path ./WORK set OUTPUT_DIR ./results/${VERSION}/outputs set REPORT_DIR ./results/${VERSION}/reports if {![file exists $OUTPUT_DIR]} {file mkdir -p $OUTPUT_DIR} if {![file exists $REPORT_DIR]} {file mkdir -p $REPORT_DIR} # 2. 工艺库配置 set_app_var search_path ". ./library" set_app_var target_library "ss_1v62_125c.db" set_app_var link_path "* ss_1v62_125c.db" # 3. 读入设计与转换 read_file -format sverilog "./sources/${TOP_MODULE}.sv" current_design ${TOP_MODULE} link # 输出 GTECH 中间态网表 write_file -hierarchy -format ddc -output ${OUTPUT_DIR}/${TOP_MODULE}.precompile.ddc write_file -hierarchy -format verilog -output ${OUTPUT_DIR}/${TOP_MODULE}.precompile.v # 4. 施加约束 create_clock -period 10.0 [get_ports clk] # 5. 核心综合阶段 compile_ultra # 输出映射后网表 write_file -format verilog -hierarchy -output ${OUTPUT_DIR}/${TOP_MODULE}.postcompile.v write_file -format ddc -hierarchy -output ${OUTPUT_DIR}/${TOP_MODULE}.postcompile.ddc # 6. 网表合法化 (去除反斜杠, 合并总线) change_names -rules verilog -hierarchy # 输出最终交付级网表 write_file -format verilog -hierarchy -output ${OUTPUT_DIR}/${TOP_MODULE}.mapped.v write_file -format ddc -hierarchy -output ${OUTPUT_DIR}/${TOP_MODULE}.mapped.ddc # 7. 生成体检报告 report_timing > ${REPORT_DIR}/${TOP_MODULE}.timing.rpt report_area > ${REPORT_DIR}/${TOP_MODULE}.area.rpt report_power > ${REPORT_DIR}/${TOP_MODULE}.power.rpt echo "Synthesis Finished! Results are in ${VERSION} folder." exit
3、查看area.rpt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 **************************************** Report : area Design : my_module Version: O-2018.06-SP1 Date : Thu Feb 26 19:54:00 2026 **************************************** Library(s) Used: slow (File: /tools/Lib/digit_lib/smic180/std/synopsys/slow.db) Number of ports: 69 Number of nets: 403 Number of cells: 366 Number of combinational cells: 238 Number of sequential cells: 128 Number of macros/black boxes: 0 Number of buf/inv: 6 Number of references: 5 Combinational area: 3632.428809 Buf/Inv area: 39.916800 Noncombinational area: 8089.804688 Macro/Black Box area: 0.000000 Net Interconnect area: undefined (No wire load specified) Total cell area: 11722.233497 Total area: undefined 1
我们来看一下其中的这个报告做了什么:
Number of ports (69):芯片对外的引脚总数。你的输入信号 + 输出信号加起来一共有 69 根线。
Number of nets (403):芯片内部的“血管”数量。门电路和门电路之间有 403 根导线连着
Number of cells (366):你的总砖头数! 整个设计一共用了 366 个标准单元。
Number of macros/black boxes (0):你没有用到 SRAM 内存块或者第三方大 IP。
Number of buf/inv: 6 (缓冲器与反相器的数量)
专业全称:Buffer (缓冲器) / Inverter (反相器 或 非门)。
军师通俗解释:这俩兄弟是芯片里的**“后勤运输队长”和“信号翻转员”**。
Inverter (非门):负责把 0 变成 1,把 1 变成 0。
Buffer (缓冲器):逻辑上它什么都不干(输入 1,输出还是 1)。它的真实物理作用是**“信号放大中继站”**!当你的一个引脚要同时驱动几十个门电路(Fanout 扇出太大),或者要跑一段很长的金属线时,信号会衰减。工具就会强行在中间插一个 Buffer,给信号“打鸡血”续航。
Number of references: 5 (引用的“乐高积木”种类) Total cells 是 366 个(你一共用了 366 块乐高积木盖房子)。 但这行 references: 5 告诉你:这 366 块积木,其实翻来覆去只用了 5 种不同的型号! DC 工具精确且唯一地使用了以下 5 种标准单元:
DFFSXL (带有置位功能的 D触发器):这是你的记忆体。
INVXL (反相器 / 非门):信号翻转员。
NOR2XL (两输入或非门):基础逻辑单元。
NAND2XL (两输入与非门):基础逻辑单元。
🔥 AOI22XL (AND-OR-Invert 2-2 复合门):全场真正的 MVP!
下面这堆内容是啥呢:
1 2 3 4 5 Combinational area: 3632.428809 Buf/Inv area: 39.916800 Noncombinational area: 8089.804688 Macro/Black Box area: 0.000000 Net Interconnect area: undefined (No wire load specified)
Combinational area: 3632.42 (组合逻辑占地)
它是啥:这就是你用来做“4选1多路选择器 (MUX)”和“写地址译码器 (Decoder)”的那些砖头——满屏的 AOI22XL、NAND、NOR。
军师点评:它们负责纯粹的逻辑计算,一共花了 3600 多平方微米。
Buf/Inv area: 39.91 (后勤跑腿占地)
它是啥:包含在上面那个组合逻辑面积里的一小部分。这就是咱们之前抓出来的仅仅 6 个的反相器(INV)和缓冲器(BUF)。
军师点评:你看,面积才区区 39.9!跟总面积比起来简直就是九牛一毛。这再次证明了你代码的数据通路极其通畅,没怎么动用“信号中继站”。
Noncombinational area: 8089.80 (非组合逻辑 / 时序逻辑占地)它是啥:这就是你那 $4 \times 32 = 128$ 个极其金贵的 DFFSXL(D触发器)!🔥 架构师的极度坦诚:兄弟,看到这个极其悬殊的对比了吗?你 238 个组合门才占 3600,而 128 个触发器居然占了 8000 多!工业界铁律:触发器(寄存器)是芯片里最占面积、最吃功耗的“吞金兽”! 所以为什么现在复杂的 CPU 缓存都要用定制的 SRAM,而不敢直接用触发器去拼(Register File 一般只做小容量的寄存器堆),这就是血淋淋的物理成本!
Macro/Black Box area: 0.00 (宏单元/黑盒占地)
它是啥:如果你在代码里调用了现成的、别人画好的大黑盒(比如从内存编译器里生成的 SRAM 模块,或者买来的 PLL 锁相环 IP)。
军师点评:你是纯手写的 RTL 代码,全是用标准单元(细碎的乐高积木)拼的,所以大模块面积是 0。
Net Interconnect area: undefined (导线互连占地)
它是啥:门电路之间那些金属连线所占的面积。
军师点评:为什么是 undefined(未知)?因为它后面跟着一句大实话——(No wire load specified)(未指定线负载模型)。DC 综合工具现在只是在脑子里把你建好了,根本没把这些模块真正放在一块二维板子上,所以连线有多长它完全不知道!除非你强制给它一个预估模型(Wire Load Model),否则它拒绝对导线面积负责。
Total cell area: 11722.23 (总净使用面积)
它是啥:把组合逻辑 (3632) + 触发器 (8089) 加起来的纯室内使用面积。
Total area: undefined (带公摊的总建筑面积)
它是啥:单元使用面积 + 走线面积。
军师点评:既然连线面积是未知的,总面积当然也是未知的。你想知道真正的带走线总面积,只有等到了 Innovus 布局布线之后,看真实的版图数据!
4、timing.rpt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 Information: Updating design information... (UID-85) **************************************** Report : timing -path full -delay max -max_paths 1 Design : my_module Version: O-2018.06-SP1 Date : Thu Feb 26 19:54:00 2026 **************************************** Operating Conditions: slow Library: slow Wire Load Model Mode: top Startpoint: register_file_reg_2__1_ (rising edge-triggered flip-flop clocked by clk) Endpoint: register_file_reg_2__1_ (rising edge-triggered flip-flop clocked by clk) Path Group: clk Path Type: max Point Incr Path ----------------------------------------------------------- clock clk (rise edge) 0.00 0.00 clock network delay (ideal) 0.00 0.00 register_file_reg_2__1_/CK (DFFSXL) 0.00 0.00 r register_file_reg_2__1_/QN (DFFSXL) 0.57 0.57 f U460/Y (AOI22XL) 0.21 0.78 r register_file_reg_2__1_/D (DFFSXL) 0.00 0.78 r data arrival time 0.78 clock clk (rise edge) 10.00 10.00 clock network delay (ideal) 0.00 10.00 register_file_reg_2__1_/CK (DFFSXL) 0.00 10.00 r library setup time -0.09 9.91 data required time 9.91 ----------------------------------------------------------- data required time 9.91 data arrival time -0.78 ----------------------------------------------------------- slack (MET) 9.12 1
我们先注释一下这个时序报告:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 Operating Conditions: slow Library: slow ## 军师批注:【环境侦测】当前处于 180nm 的炼狱模式(高温低压),此时晶体管跑得最慢,用来查 Setup 违例最准。 Wire Load Model Mode: top ## 军师批注:【连线预估】因为还没进行物理连线,工具在此使用顶层线负载模型(瞎猜导线延迟)。 Startpoint: register_file_reg_2__1_ (rising edge-triggered flip-flop clocked by clk) ## 军师批注:【起跑线】数据的发射源。这是一个由 clk 上升沿触发的 D 触发器。 Endpoint: register_file_reg_2__1_ (rising edge-triggered flip-flop clocked by clk) ## 军师批注:【终点线】数据的接收端。你看,起点和终点是同一个触发器!说明这是一个“自己反馈给自己”的路径(寄存器保持原值)。 Path Group: clk Path Type: max ## 军师批注:再次确认,这是 clk 时钟域下的 Setup (max) 检查。 Point Incr Path ----------------------------------------------------------- ## ========== 第一幕:计算数据实际到达时间 (Data Arrival Time) ========== ## clock clk (rise edge) 0.00 0.00 ## 军师批注:【发令枪响】在 0.00ns 时刻,时钟上升沿到来。 clock network delay (ideal) 0.00 0.00 ## 军师批注:因为这是前端综合,还没做时钟树综合(CTS),所以工具假设时钟网是“完美的(ideal)”,延迟为0。 register_file_reg_2__1_/CK (DFFSXL) 0.00 0.00 r ## 军师批注:时钟信号瞬间到达了发射端触发器的 CK (Clock) 引脚。末尾的 'r' 代表上升沿 (rise)。 register_file_reg_2__1_/QN (DFFSXL) 0.57 0.57 f ## 军师批注:【触发器出翻转延迟】时钟敲击后,触发器把数据从 QN 引脚吐出来,花了 0.57ns。末尾的 'f' 代表数据是个下降沿 (fall,从1变0)。 U460/Y (AOI22XL) 0.21 0.78 r ## 军师批注:【组合逻辑延迟】数据跑在走廊上,穿过了 U460 这个复合逻辑门,花了 0.21ns。此时总耗时累加为 0.78ns。数据变成上升沿 'r'。 register_file_reg_2__1_/D (DFFSXL) 0.00 0.78 r ## 军师批注:数据终于抵达了接收端触发器的 D 引脚。路上导线延迟为 0.00 (综合阶段忽略不计)。 data arrival time 0.78 ## 军师批注:【总结算 1】数据实际跑到终点,总共花了 0.78ns。 ## ========== 第二幕:计算系统死线 (Data Required Time) ========== ## clock clk (rise edge) 10.00 10.00 ## 军师批注:【下一次发令枪响】因为你在脚本里约束了周期是 10.00ns,所以下一个时钟沿在 10.00ns 时刻到来。 clock network delay (ideal) 0.00 10.00 ## 军师批注:接收端的时钟树延迟,依然假设是完美的 0.00ns。 register_file_reg_2__1_/CK (DFFSXL) 0.00 10.00 r ## 军师批注:10.00ns 时刻,时钟准确敲击接收端触发器。 library setup time -0.09 9.91 ## 军师批注:【傲娇的建立时间】查阅 slow.db 发现,这个 DFFSXL 触发器要求数据必须“提前 0.09ns”到达并保持稳定。所以 10.00 减去 0.09。 data required time 9.91 ## 军师批注:【总结算 2】工具下达最后通牒:数据必须在 9.91ns 之前到达!(这就是死线) ----------------------------------------------------------- ## ========== 第三幕:最终审判 (Slack Calculation) ========== ## data required time 9.91 ## 军师批注:这是要求的死线。 data arrival time -0.78 ## 军师批注:这是实际到达时间。公式是 Required 减去 Arrival。 ----------------------------------------------------------- slack (MET) 9.12 ## 军师批注:【宣判结果】9.91 - 0.78 = 9.12ns。 ## 因为是正数,所以是 MET(满足要求)!你不仅没迟到,还提前了 9.12ns 抵达终点,时序极其宽裕! ## 如果这里是负数,就会显示 VIOLATED(违例),那就得回去改代码或者降频了。 1
5、power.rpt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 Information: Propagating switching activity (low effort zero delay simulation). (PWR-6) Warning: Design has unannotated primary inputs. (PWR-414) Warning: Design has unannotated sequential cell outputs. (PWR-415) **************************************** Report : power -analysis_effort low Design : my_module Version: O-2018.06-SP1 Date : Thu Feb 26 19:54:00 2026 **************************************** Library(s) Used: slow (File: /tools/Lib/digit_lib/smic180/std/synopsys/slow.db) Operating Conditions: slow Library: slow Wire Load Model Mode: top Global Operating Voltage = 1.62 #架构师洞察:咱们之前说 180nm 的标准电压是 1.8V。但在 slow.db(炼狱模式)下, #代工厂假设电源供电极度不稳,直接把电压拉低到了 1.62V(也就是 1.8V 跌了 10%)! #在吃不饱饭的情况下,工具开始计算它的能耗。 Power-specific unit information : Voltage Units = 1V Capacitance Units = 1.000000pf Time Units = 1ns Dynamic Power Units = 1mW (derived from V,C,T units) Leakage Power Units = 1pW Cell Internal Power = 689.8427 uW (97%) Net Switching Power = 20.8919 uW (3%) --------- Total Dynamic Power = 710.7345 uW (100%) Cell Leakage Power = 304.1248 nW Internal Switching Leakage Total Power Group Power Power Power Power ( % ) Attrs -------------------------------------------------------------------------------------------------- io_pad 0.0000 0.0000 0.0000 0.0000 ( 0.00%) memory 0.0000 0.0000 0.0000 0.0000 ( 0.00%) black_box 0.0000 0.0000 0.0000 0.0000 ( 0.00%) clock_network 0.0000 0.0000 0.0000 0.0000 ( 0.00%) register 0.6746 2.5900e-03 2.0173e+05 0.6774 ( 95.27%) sequential 0.0000 0.0000 0.0000 0.0000 ( 0.00%) combinational 1.5198e-02 1.8302e-02 1.0239e+05 3.3602e-02 ( 4.73%) -------------------------------------------------------------------------------------------------- Total 0.6898 mW 2.0892e-02 mW 3.0412e+05 pW 0.7110 mW 1
Cell Internal Power (内部功耗) = 689.84 uW (97%)
这是逻辑门内部晶体管在 0 和 1 切换时,瞬间短路产生的功耗,以及充放电内部电容的功耗。它占了绝对的大头。
Net Switching Power (翻转功耗) = 20.89 uW (3%)
这是给外部“导线”充放电产生的功耗。
为什么只有 3% 这么惨? 因为你现在在综合阶段!咱们在看面积报告时就说过,连线还没画出来,导线长度是 undefined,所以给导线充电的功耗自然被工具严重低估了。
Cell Leakage Power (漏电流功耗) = 304.12 nW (极其微小)
这是芯片只要通上电,哪怕什么都不干,像水龙头漏水一样偷偷溜走的功耗。
在 180nm 这种远古工艺里,漏电小到只有几百纳瓦(nW),可以忽略不计。但如果你以后做 28nm 甚至 7nm,漏电功耗会大到让你怀疑人生,甚至能占到总功耗的 30% 以上!
这里重点强调一下register、sequential、combinational的区别:
Latch是什么:在广义学术上,寄存器也算 Sequential;但在咱们这份综合功耗报告里,sequential 这一行被工具专门用来统计“锁存器 (Latch)”!
为什么它很危险? 假设时钟的高电平占了半个周期(比如 5ns)。在这漫长的 5ns 里,Latch 的大门是完全敞开的!如果这期间外面的输入信号因为干扰抖动了一下,这个错误数据会立刻冲进 Latch 里被记住,进而引发整个芯片的崩溃。这叫“时序不可控”。
在硬件层面,Latch 是一种**电平敏感(Level-sensitive)**的存储单元。
它的特性:想象一扇门。
当“使能信号”(通常是时钟 clk)是高电平时,这扇门是完全敞开的。外面发生什么,里面就跟着变什么(这叫透明模式,Transparent)。
只有当“使能信号”变为低电平时,门才砰地关上,锁住最后那一刻的数据。
对比 DFF(寄存器):DFF 只在时钟上升沿那一瞬间(比如从 0 变 1 的那 0.1 纳秒)开门看一眼数据,然后迅速关门。其余时间雷打不动。
6、-hierarchy含义 在 Synopsys Design Compiler (DC) 或相关工具中,write_file命令的 -hierarchy 选项用于在输出的网表文件中保留原始设计的层次结构。
作用详解 保留模块边界:
有 -hierarchy:输出的网表文件会保持你在RTL代码中定义的模块层次。顶层模块会包含对子模块的实例化,子模块本身也会被定义。
无 -hierarchy:工具会进行扁平化处理。所有底层子模块(通常是标准单元)都会被展开并直接连接到顶层模块中,原始的模块名和边界会消失,网表变成一个巨大的、只有最底层单元的平面网络。
输出结果对比: 保留层次 (-hierarchy):
1 2 3 4 5 6 7 8 9 10 module TOP (input clk, input d, output q); SUB u_sub (.clk (clk), .d (d), .q (q)); endmodule module SUB (input clk, input d, output q); DFFX1 u_dff (.CLK (clk), .D (d), .Q (q)); endmodule
扁平化 (无 -hierarchy):
1 2 3 4 5 6 module TOP (input clk, input d, output q); DFFX1 u_dff (.CLK (clk), .D (d), .Q (q)); endmodule
为什么需要使用 -hierarchy?
便于调试与分析:保留层次结构与你的RTL设计一一对应,在排查时序违例、功耗问题或进行后仿真时,你可以清晰地定位到是哪个功能模块出了问题。
满足后端流程需求:很多布局布线工具可以进行层次化设计或模块化布局。保留层次信息有助于后端工具更好地理解设计结构,可能对优化布局、缩短运行时间有好处。
数据重用与接口清晰:.ddc格式是Synopsys的数据库格式,能保存约束、属性等更多信息。保留层次的DDC文件可以更方便地在不同工具(如Formality形式验证工具)或不同阶段(综合与布局布线后)之间传递和复用设计数据。