芯片设计的“翻译官”与“优化师”:揭秘逻辑综合

作者:Tim Chen,文章来源:亚科鸿禹

逻辑综合

在我们谈论智能手机、人工智能芯片等现代科技奇迹时,其核心都是一块指甲盖大小的芯片。这块芯片上布满了数十亿甚至上百亿个晶体管。如此庞大复杂的设计,是如何从工程师的一个想法变成现实的呢?其中一个非常关键、非常神奇的步骤就是——逻辑综合。

1. 什么是逻辑综合 – Logic Synthesis

我们可以用一个比喻来理解:

建筑师(设计师):芯片架构师使用硬件描述语言(Hardware Description Language),如Verilog-HDL或VHDL,编写代码。这就像用中文写下了一份详细的建筑需求说明书,里面可能描述“这里要一个客厅,那里要三间卧室,要采光好…”。这份代码被称为寄存器传输级代码(RTL -- Register-Transfer Level),它描述了电路的功能和行为,但并没有规定具体用什么材料、怎么建造。

施工队与结构工程师(逻辑综合工具):逻辑综合工具就是这个核心角色。它接收了这份中文建筑需求说明书,也就是寄存器传输级代码,并查阅一本“本地建材与施工手册”(标准单元库,包含了与门、或门、触发器等基本逻辑单元的具体物理信息)。

施工图(网表):最终,综合工具输出一份极其详细的“施工图”——门级网表。这份图纸不再有抽象描述,而是精确列出了需要哪些“砖块”(标准单元),它们之间如何连接,以及这些连接需要满足多快的速度,占用多大的面积。

所以,逻辑综合的本质就是:将描述电路功能的高抽象层次寄存器传输级代码,自动转换为基于标准单元的低抽象层次门级网表的过程。

2. 为什么需要逻辑综合

随着芯片规模不断扩大,现代芯片一般包含数十亿个晶体管,没有逻辑综合,手动处理数亿个晶体管的设计和连接,是人类不可能完成的任务,需要逻辑综合来接管这项繁重的工作。而且,一个好的芯片不仅要功能正确,还要跑得快(高性能)、体积小(小面积)、耗电少(低功耗)。这些目标常常相互冲突。逻辑综合工具能在设计师指定的约束条件下,自动寻找最佳平衡点,比如插入缓冲器来提高速度,或共享逻辑来减小面积。因此逻辑综合工具是现代芯片设计的必需工具。

3. 逻辑综合的发展简史

史前时代:设计师手工画晶体管电路图,效率极低,易出错。

学术萌芽:1980年代,加州大学伯克利分校的研究人员开发了Espresso逻辑最小化算法和MIS综合系统,奠定了理论基础。

商业诞生:Synopsys公司成立于1986年,并推出了第一款商用综合工具Design Compiler,革命性地将综合技术带入工业界,开启了RTL设计的新纪元。

物理综合:2000年后,芯片工艺进入纳米级别,连线的延迟变得至关重要。传统的综合工具无法准确预估,于是物理综合技术出现,将综合与布局规划结合,极大地提高了预测准确性。

高层次综合:这是当前较前沿方向之一。将设计抽象层次再次提升,允许设计师用C/C++/SystemC等算法级语言描述功能,由工具自动生成RTL代码。

4. 常见逻辑综合工具

Synopsys Design Compiler®: ASIC综合工具行业黄金标准,功能全面,性能强大。

Cadence Genus Synthesis Solution: Design Compiler的主要竞争对手,强调更好的网表质量和更快的运行时间。

Synopsys Synplify Pro/Premier®: FPGA第三方综合工具的市场领导。
Siemens EDA Precision RTL/Plus: Synplify的主要竞争对手,同样非常强大。
AMD-Xilinx Vivado® Synthesis: AMD-Xilinx器件官方工具,集成于全流程设计套件中。
Altera Quartus Prime Synthesis: Intel FPGA器件官方工具,集成于全流程设计套件中。
Yosys: 领先的开源综合工具,支持从RTL到门级的综合。

近年来,国产EDA厂商如亚科鸿禹在综合工具的研发也有很大突破。自主研发的逻辑综合工具已经成功应用于亚科鸿禹原型验证和硬件仿真的产品中,成为亚科鸿禹产品链中关键的一环,并且在运行时间,网表质量,易用性等方面已经可以媲美业内主流竞品。

5. 常见综合逻辑用例和综合器处理过程

触发器

RTL代码:

module d_ff (

input wire clk, // 时钟

input wire rst_n, // 异步复位,低电平有效

input wire d, // 数据输入

output reg q // 数据输出

);

always @(posedge clk or negedge rst_n) begin

if (!rst_n) begin

// 异步复位:只要rst_n为低,立即将q置为0

q <= 1'b0;

end else begin

// 同步操作:在clk的上升沿,将d的值锁存到q

q <= d;

end

end

endmodule

综合器处理过程:

解析RTL

综合器首先读取HDL代码,进行语法和语义检查,并将其转换为内部的中间表示(Intermediate Representation)。它会识别出always/process块、敏感列表、控制结构(if-else)等,然后分析敏感列表。这个列表包含了边沿敏感的信号(posedge和negedge)。这是一个非常强烈的提示,告诉综合器这个进程描述的是一个时序逻辑电路,而不是组合逻辑。接着综合器会分析控制流。综合器看到条件语句首先检查复位信号,并且复位信号是在时钟边沿条件下执行赋值。这精确匹配了一个带异步复位的D触发器的行为。异步复位路径if (!rst_n) 对应触发器复位端(rst_n)的控制逻辑,同步数据路径else分支的 q <= d 对应了触发器的数据输入(D)到输出(Q)的路径。基于以上,综合器推断出这个进程需要被实现为一个标准的D触发器(DFF)。

映射与优化
综合器从它的标准单元库(Standard Cell Library) 中找到一个最适合的D触发器单元。

输出网表
综合器生成一个门级网表文件(例如EDIF或Verilog Netlist)。这个网表不再包含行为级描述,而是由标准单元实例和它们之间的连接关系组成。综合器可能生成的网表如下:

module d_ff

(clk,

rst_n,

d,

q);

input clk;

input rst_n;

input d;

output q;

wire clk;

wire d;

wire q;

RTL_REG_ASYNC q_reg

(.C(clk),

.CLR(rst_n),

.D(d),

.Q(q));

endmodule

对应原理图如下:

加法器

RTL代码:

module simple_adder (

input wire [7:0] a, // 8位加数A

input wire [7:0] b, // 8位加数B

input wire cin, // 进位输入

output wire [7:0] sum, // 8位和

output wire cout // 进位输出

);

// 行为级描述:核心就是一行加法

assign {cout, sum} = a + b + cin;

endmodule

综合器处理过程:

解析RTL
综合器读取RTL,识别出 a, b, cin, sum, cout 这些信号,并理解核心操作是一个 8位加法。它将 a + b + cin 这个行为描述转换成一个内部的、与工艺无关的通用加法器单元。此时,它只知道需要实现一个加法功能,但并不知道具体用什么电路实现。

映射与优化
综合器根据设计者施加的约束(如“面积优先”还是“速度优先”),选择最优的实现结构。如果目标是面积最小化(Area-Optimized),综合器通常会选择一个行波进位加法器(Ripple-Carry Adder, RCA)。它的结构简单,由全加器(full_adder)串联而成,面积小,但速度慢(关键路径延迟长)。

输出网表
下面以行波进位加法器(Ripple-Carry Adder, RCA)为例给出原理图:

上图中的全加器子模块原理图如下:

RAM
这里我们介绍FPGA综合器综合一个同步读写、1024x8bit的单端口RAM(SPRAM) 的过程。

RTL代码:

module spram (

input wire clk, // 时钟

input wire we, // 写使能 (Write Enable)

input wire [9:0] addr, // 地址线 (1024=2^10, 所以需要10位)

input wire [7:0] data_in, // 写入的数据

output reg [7:0] data_out // 读出的数据

);

// 定义存储器数组

// 关键:使用 `reg` 类型定义一個深度为1024,宽度为8的数组

reg [7:0] ram [0:1023];

// 核心操作:所有操作都在时钟上升沿进行

always @(posedge clk) begin

if (we) begin // 写使能有效时,执行写操作

ram[addr] <= data_in;

end

// 无论读写,data_out 总是输出 ram[addr] 地址上的数据

data_out <= ram[addr];

end

endmodule

综合器处理过程:

解析RTL

综合器解析HDL代码时识别出 reg [width-1:0] mem [0:depth-1]; 这种数组声明格式。它发现对这个数组的访问是在同步时钟块(always @(posedge clk))中进行的。它还分析出写操作是由一个使能信号(we)控制的条件写入。一旦这些条件满足,综合器就“推断”出设计者想要的是一个同步RAM,而不是一堆分散的寄存器。

映射与优化

综合器会根据代码的细节和用户的约束,选择最合适的硬件资源来实现。如果是小容量RAM,深度很小(例如小于64),综合工具可能会选择用FPGA逻辑单元(查找表LUT和触发器FF)来实现,这称为 “分布式RAM(Distributed RAM)” 。它的特点是多端口访问灵活,但容量小。如果是大容量RAM:对于像上文1024x8这样的较大容量,综合器几乎总是会将其映射到FPGA的专用 “块RAM(Block RAM)” 上。BRAM是大型、高效的专用存储器硬核,节省逻辑资源,并且功耗更低。

输出网表

最终综合器会生成一个网表,其中不再包含原始的reg数组,而是实例化了目标FPGA器件中的一个BRAM原语(Primitive)。
下面是一个简化的Vivado生成的网表示例:

module spram (

input wire clk,

input wire we,

input wire [9:0] addr,

input wire [7:0] data_in,

output wire [7:0] data_out

);

// 工具自动实例化了FPGA的BRAM原语

RAMB18E2 #(

// ...一大堆配置参数,如读写宽度、操作模式等...

.WRITE_MODE_A("READ_FIRST"), // 例如,根据我们的代码行为配置模式

.WRITE_MODE_B("WRITE_FIRST"),

.WRITE_WIDTH_A(18),

.WRITE_WIDTH_B(0))

// ...

) ram_reg_bram_0 (

.ADDRARDADDR({addr,\ ,\ ,\ ,\ }),

.CLK(clk),

.WEA(we,we),

.ADDR(addr),

.DINADIN({\ ,\ ,\ ,\ ,\ ,\ ,\ ,\ ,data_in}),

.DOUTADOUT(data_out),

// ...连接其他必要的控制信号...

);

endmodule

对应的原理图如下:

6. 总结
逻辑综合是芯片设计流程中承上启下的关键枢纽。它就像一位技艺高超的翻译官和优化大师,将人类工程师的功能构想,精准、高效地翻译成芯片制造厂能理解的“语言”,并竭尽所能地将其优化到最佳状态。没有它,我们就不可能享受到如今由强大算力驱动的数字生活。它虽隐藏在幕后,却是当之无愧的芯片产业基石技术。