第二章:网表文件格式详解
做FPGA设计这么多年,我接触过的网表格式少说也有七八种。但真正在实际项目中天天打交道的,其实就那么几个。今天咱们就聊聊EDIF、Verilog网表、VHDL网表,还有Xilinx那套NGC/NGO格式。
你可能会问:为什么要搞这么多种格式?说白了,就像不同国家说不同语言一样。EDA工具厂商各有一套,历史原因加上技术演进,就形成了现在的局面。
2.1 EDIF格式详解
EDIF(Electronic Design Interchange Format)算是网表格式里的"老前辈"了。我记得刚入行那会儿,很多老工程师还在用这个格式做设计交换。
EDIF的核心特点:
- 基于Lisp语法结构,用括号嵌套表达层次关系
- 支持原理图级和网表级描述
- 标准版本有EDIF 2 0 0和EDIF 3 0 0
来看一个简单的EDIF网表示例:
(edif simple_example
(edifVersion 2 0 0)
(edifLevel 0)
(keywordMap (keywordLevel 0))
(cell AND2
(cellType GENERIC)
(view netlist
(viewType NETLIST)
(interface
(port A (direction INPUT))
(port B (direction INPUT))
(port Y (direction OUTPUT))
)
(contents
(instance I1 (cellRef AND2))
(net N1
(joined
(portRef A)
(portRef I1 A)
)
)
)
)
)
)
嗯,这里要注意:EDIF的括号嵌套非常深。我在项目中遇到过几次,用文本编辑器打开EDIF文件,括号匹配能把人看晕。建议用专门的EDIF查看工具,或者至少用带括号高亮的编辑器。
2.2 Verilog网表格式
Verilog网表,说白了就是把RTL代码综合后的门级描述。现在大部分FPGA项目都在用这个格式。我个人习惯用Verilog网表做后仿真,因为可读性比EDIF好太多了。
Verilog网表的核心要素:
- 模块实例化:每个逻辑单元对应一个module实例
- 线网连接:用wire/reg描述信号连接关系
- 端口映射:通过端口名或位置进行连接
一个典型的Verilog网表示例:
module top (
input clk,
input rst_n,
input [7:0] data_in,
output [7:0] data_out
);
wire [7:0] reg_data;
wire clk_int;
// 时钟缓冲实例
BUFG clk_buf (
.I(clk),
.O(clk_int)
);
// 寄存器实例
FDRE #(.INIT(1'b0)) reg_inst[7:0] (
.C(clk_int),
.CE(1'b1),
.R(~rst_n),
.D(data_in),
.Q(reg_data)
);
// 输出缓冲
assign data_out = reg_data;
endmodule
你想想看,这种格式是不是比EDIF直观多了?每个实例叫什么、连什么线,一目了然。
2.3 VHDL网表格式
VHDL网表在军工和航天项目里用得比较多。它的特点是语法严谨,类型检查严格。我刚开始接触VHDL网表时,觉得它比Verilog啰嗦,但用久了发现,这种严谨其实能避免很多低级错误。
VHDL网表的特点:
- 实体-架构分离:entity定义端口,architecture描述实现
- 强类型系统:信号类型必须严格匹配
- 支持配置:可以在顶层配置底层模块的实现方式
VHDL网表示例:
library ieee;
use ieee.std_logic_1164.all;
entity top is
port (
clk : in std_logic;
rst_n : in std_logic;
din : in std_logic_vector(7 downto 0);
dout : out std_logic_vector(7 downto 0)
);
end entity top;
architecture structural of top is
signal reg_data : std_logic_vector(7 downto 0);
signal clk_int : std_logic;
begin
-- 时钟缓冲
clk_buf : BUFG
port map (
I => clk,
O => clk_int
);
-- 寄存器阵列
reg_inst : for i in 0 to 7 generate
FDRE
generic map (INIT => '0')
port map (
C => clk_int,
CE => '1',
R => not rst_n,
D => din(i),
Q => reg_data(i)
);
end generate;
-- 输出赋值
dout <= reg_data;
end architecture structural;
2.4 Xilinx NGC/NGO格式
NGC(Netlist for Graphics and Constraints)和NGO(Netlist for Generic Optimization)是Xilinx的专有格式。说白了,就是Xilinx工具内部用的二进制网表格式。
这两种格式的区别:
| 特性 | NGC | NGO |
|---|---|---|
| 文件扩展名 | .ngc | .ngo |
| 包含内容 | 网表+约束 | 仅网表 |
| 可读性 | 二进制,不可读 | 二进制,不可读 |
| 主要用途 | IP核交付 | 综合中间结果 |
我在项目中用NGC格式最多的情况,就是封装IP核。把设计综合成NGC文件,交给其他团队使用,既保护了源代码,又方便集成。
2.5 格式对比与选择建议
说了这么多,到底该用哪种格式?我根据自己的经验,给个参考:
- 设计交换:首选EDIF,兼容性最好
- 后仿真调试:用Verilog/VHDL网表,可读性强
- IP核交付:用NGC(Xilinx环境)或EDIF(通用环境)
- 工具内部处理:让工具自己选,别瞎操心
最后说一句:不管用哪种格式,一定要保留好综合报告和约束文件。我见过太多人只保存网表,结果调试时找不到时序信息,那才叫一个抓瞎。
好了,网表格式这块就聊到这儿。记住一点:格式只是载体,真正重要的是网表里描述的逻辑功能。下功夫把格式搞懂,后面做信号追踪才能得心应手。
公众号:蓝海资料掘金营,微信deep3321