目录
RTL Parser 的主要工作
RTL Parser 的底层实现机制
1. Lexical Analyzer(词法分析器)
2. Syntax Analyzer(语法分析器)
3. Pre-Semantic Analyzer(预语义检查器)
4. Behavioral Description Collection(行为表达式采集)
✨ 总结一下(一张表清晰看)
小细节分享(很多人不知道)
小结一句话
RTL Parser 在整个 Design Compiler(DC_SHELL)流程中是第一个把源代码转换成内部可操作数据的模块,它直接决定了后续 Elaboration、HLO、Datapath 优化的基础结构。
你问得非常到位,不仅要知道它做了什么,还要知道它是怎么实现的——下面我就从功能到底层实现机制给你全面讲一遍。
在 Design Compiler 里,RTL Parser负责把输入的 HDL(比如 Verilog、VHDL)源代码转成内部的语法树(AST, Abstract Syntax Tree)和初步的数据对象(Symbol Table)。
主要包括:
阶段 | 具体内容 |
---|---|
1. 词法分析(Lexical Analysis) | 把源代码分割成一个个有意义的 Token(关键词、变量名、符号、数字等) |
2. 语法分析(Syntax Analysis) | 把 Token 按语言语法规则组合成 AST(树形结构,描述代码结构) |
3. 初步语义检查(Pre-Semantic Check) | 检查类型定义、端口声明、参数合法性,收集 symbol 表(名字和对象的映射) |
4. 构建设计单元(Design Units) | 把 module、entity、architecture 等转化为 design_unit 结构 |
5. 保留行为描述 | 对 always、assign、process 等保留为行为表达式,供 HLO 后续展开 |
注意:在这一步 不会做任何 elaboration,比如 module instantiation、位宽调整、时序分析,这些都是后面阶段做的。
DC_SHELL 的 RTL Parser,底层大致可以分为四大模块:
用手写的 DFA(Deterministic Finite Automaton)或者Lex 工具生成的扫描器。
把源码一行行读入,切分成:
关键字(如 module
, input
, wire
, always
)
标识符(变量名)
运算符(+
, -
, *
, ?
, :
)
常量(比如 8'd255)
实现细节:
内部是状态机(Finite State Machine)
读取字符并跳转状态,最终输出 Token
有 Error Recovery 机制(比如漏掉分号时,尽量找出后续 Token)
典型使用LALR(1) 或 LR(1) Parser(Shift-Reduce Parser)
基于 Verilog/VHDL 的 BNF(巴科斯范式)描述的语法规则构建解析树。
遇到规则匹配时进行 Reduce,构建 AST(Abstract Syntax Tree)节点。
例如,看到:
assign y = a + b;
构建 AST 大概是:
assign_stmt
├── lhs: identifier (y)
├── rhs: add_expr
├── operand1: identifier (a)
├── operand2: identifier (b)
内部数据结构一般是:
ast_node
:带有 node_type(如 assign、always、module_decl)和 child pointers
每个节点还记录位置信息(行号、列号)方便报错和后续映射回源代码。
在 Parser 阶段直接做简单检查,提高错误检测的早期性:
检查端口定义是否重复
参数定义是否符合语法
端口 direction 是否合规(input/output/inout)
wire/reg 类型约束基本检查
这一步不会检查类型匹配,比如说一个加法的左右是否都是 logic
型,这要等 elaboration 以后。
同时,这一步会收集:
Symbol Table(符号表):模块名、变量名、端口名、参数名 → 地址
Module List(模块列表)
Early Netlist Skeleton(粗略连线信息)
把所有 combinational 和 sequential 逻辑块保存在 AST 中。
always
块、assign
语句、initial
块都被记录为抽象节点,供后续 HLO 调度。
比如:
always @(posedge clk) begin
if (reset)
q <= 0;
else
q <= d;
end
会被记录成:
always
node
sensitivity list(posedge clk)
if-else structure
non-blocking assignment (<=
) expression
而不是一开始就直接建成 Flip-Flop!
这一阶段不做硬件推导,只是保留逻辑描述。
步骤 | 作用 | 是否生成硬件? |
---|---|---|
词法分析 | 把代码分成 Token | ❌ |
语法分析 | 解析成 AST 树 | ❌ |
预语义分析 | 检查基本语义错误,生成 Symbol Table | ❌ |
行为收集 | 保存 always/assign 等逻辑块描述 | ❌ |
注意:
到这里为止,DC 还没有生成任何硬件电路!
只有到了 Elaboration/HLO 后才会把这些 AST 转成硬件表示(dataflow, FSM, datapath node)
DC 的 Verilog Parser 是支持不规范代码的,比如多余逗号、端口顺序不严格。
有隐藏参数 verilog_standard
可以设定为 1995
, 2001
, 2005
, SystemVerilog
,影响 Parser 行为。
其实 DC 里 Verilog 和 VHDL 是分别独立实现的两个 Parser 引擎,但中间 IR 是统一的。
Parser 在内部会加一个 invisible "root" node,把所有 module/architecture 挂在下面,方便 traversal。
RTL Parser 把 HDL 源代码解析成 AST 和 Symbol Table,并保留行为描述,为后续 elaboration、调度、绑定打下基础,它本身不做电路生成,只是构建中间表示。