第二章:网表文件格式详解

做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查看工具,或者至少用带括号高亮的编辑器。

避坑指南:我曾经在项目交付时,客户要求提供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直观多了?每个实例叫什么、连什么线,一目了然。

实用技巧:做信号追踪时,我建议保留综合后的Verilog网表。这样在调试时,可以直接用文本搜索找到目标信号,比在GUI里翻来翻去快得多。

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;
重要提示:VHDL网表在做混合语言仿真时特别容易出问题。我建议在综合前就确定好用哪种语言,避免后期混用带来的麻烦。

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文件,交给其他团队使用,既保护了源代码,又方便集成。

注意:NGC格式是Xilinx特有的,换到其他厂商的FPGA就没法用了。我曾经有个项目,前期用NGC封装IP,后期要换Altera的芯片,结果所有IP都得重新综合,工作量翻倍。

2.5 格式对比与选择建议

说了这么多,到底该用哪种格式?我根据自己的经验,给个参考:

  • 设计交换:首选EDIF,兼容性最好
  • 后仿真调试:用Verilog/VHDL网表,可读性强
  • IP核交付:用NGC(Xilinx环境)或EDIF(通用环境)
  • 工具内部处理:让工具自己选,别瞎操心

最后说一句:不管用哪种格式,一定要保留好综合报告和约束文件。我见过太多人只保存网表,结果调试时找不到时序信息,那才叫一个抓瞎。

网表格式知识体系 FPGA网表格式 EDIF格式 Verilog网表 VHDL网表 NGC/NGO格式 Lisp语法 · 括号嵌套 支持原理图/网表级 模块实例化 · 线网连接 可读性强 · 后仿真常用 实体-架构分离 强类型 · 军工常用 二进制 · 不可读 IP核交付 · 工具专用 选择建议:设计交换用EDIF,调试用Verilog/VHDL,IP交付用NGC

好了,网表格式这块就聊到这儿。记住一点:格式只是载体,真正重要的是网表里描述的逻辑功能。下功夫把格式搞懂,后面做信号追踪才能得心应手。


公众号:蓝海资料掘金营,微信deep3321