Yosys内部数据结构深度解析:从RTLIL到网表生成的底层实现
如果你是一位数字IC开发者,并且已经不止于使用Yosys进行简单的综合流程,而是希望深入其内部,理解它如何将Verilog代码一步步转化为门级网表,甚至想定制自己的优化Pass,那么这篇文章正是为你准备的。我们将抛开表面的命令和流程,直接深入到Yosys的心脏——它的C++源码,特别是其核心的内部表示RTLIL。理解这些数据结构,就如同拿到了芯片设计工具的“源代码”,你将能洞察综合过程中的每一个细节,从内存管理到信号映射,从模块构建到优化Pass的运作机制。这不仅仅是学习一个工具,更是掌握一种将抽象硬件描述转化为具体电路实现的计算思维。
1. RTLIL:Yosys的硬件描述“通用语”
在深入代码之前,我们必须理解Yosys为何需要自己的中间表示。Verilog、VHDL等硬件描述语言语法复杂,直接在其抽象语法树上进行优化和变换极其困难。因此,Yosys在解析HDL代码后,会首先将其转换为一个统一的、更易于程序操作的内部格式,这就是RTLIL。
RTLIL,全称Register Transfer Level Intermediate Language,可以看作是Yosys内部的一种“硬件描述通用语”。它剥离了原始HDL中的语法糖和复杂结构,将设计抽象为几个核心概念:模块、线网、单元和连接。这种设计哲学非常清晰:一个硬件设计,无论多复杂,本质上就是由这些基本构件组合而成的。
1.1 核心类族:Design, Module, Wire, Cell
RTLIL的核心数据结构是一个层次化的类族,它们共同构成了整个设计的骨架。理解它们之间的关系是读懂Yosys源码的第一步。
-
RTLIL::Design: 这是整个设计的根容器。你可以把它想象成一个项目文件夹,里面存放了设计的所有模块(Module)。它通过一个字典(dict<RTLIL::IdString, RTLIL::Module*>)来管理这些模块,键是模块名,值是指向模块对象的指针。此外,它还管理着全局的选择栈、暂存板等状态信息。 -
RTLIL::Module: 这是设计的基本功能单元,对应Verilog中的一个module。它内部维护着几个关键容器:wires_: 一个字典,存储本模块内所有的线网(Wire)对象。cells_: 一个字典,存储本模块内所有的单元(Cell)对象。connections_: 一个向量,存储模块内的所有连接关系(SigSig,即信号到信号的连接)。
-
RTLIL::Wire: 代表硬件中的一根信号线。它不仅仅是一个名字,还包含了丰富的属性:int width; // 信号位宽 int start_offset; // 起始偏移(用于向量部分选择) int port_id; // 端口ID(如果是模块端口) bool port_input; // 是否为输入端口 bool port_output; // 是否为输出端口 bool upto; // 位序方向(用于向量声明) bool is_signed; // 是否为有符号数一个
Wire对象精确地描述了一组电信号的物理特性。 -
RTLIL::Cell: 代表一个逻辑单元或功能块。它可以是与门、或门、触发器、加法器,甚至是一个黑盒子模块。Cell的核心属性包括:type: 单元类型,如"$and"、"$dff"。connections_: 一个字典,将端口名(如"A","B","Y")映射到具体的信号(SigSpec)。parameters: 一个字典,存储单元的参数,例如LUT的查找表内容、触发器的初始值等。
提示:
Module中的connections_描述的是线网之间的直接连接(assign wire_a = wire_b;),而Cell中的connections_描述的是单元端口与外部线网的连接关系。这是两种不同层次的连接信息。
1.2 信号表示:SigSpec与SigBit
硬件设计中,信号(Signal)是最活跃的元素。Yosys使用RTLIL::SigSpec和RTLIL::SigBit来灵活地表示信号。
RTLIL::SigBit: 表示一个单一的信号位。它可以是一个Wire的某一位,也可以是一个常量值(State::S0,State::S1,State::Sx未知,State::Sz高阻)。RTLIL::SigSpec: 表示一个信号集合,可以包含多个SigBit。它用于表示多比特宽的信号,例如一个8位的总线。SigSpec内部实际上是一个std::vector<RTLIL::SigBit>。
这种设计的精妙之处在于其统一性。无论是单比特线网、多比特总线、常量,还是它们的拼接和切片,都可以用Sig


163

被折叠的 条评论
为什么被折叠?



