摘要:本文从源代码层面深入剖析 Verilator 的内部架构,涵盖其目录结构、核心类体系(V3Global、V3Options、AstNode、V3Number、V3Graph 等)、编译管线的四大阶段(前端 → 语义分析 → 变换优化 → 后端代码生成),以及 ~50+ 个 AST 变换 Pass 的执行流程。全文以大量流程图、列表和表格为主,每个流程图后均配有列表说明,适合希望理解 Verilator 内部工作机制或准备参与贡献的开发者阅读。
目录:
-
• 📁 目录结构一览 -
• 🏛️ 核心组件体系 -
• V3Global:全局状态中心 -
• V3Options:配置状态中心 -
• AstNode:AST 节点基类 -
• V3Number:四值逻辑数值系统 -
• V3Graph:图算法基础设施 -
• 核心组件全景关系图 -
• ⚙️ 编译管线:四大阶段 -
• 入口点与初始化 -
• 阶段一:前端(文本 → AST) -
• 阶段二:语义分析与展开 -
• 阶段三:变换与优化 Pass -
• 阶段四:后端代码生成 -
• 🔄 变换 Pass 的详细执行序列 -
• 🧩 Pass 执行架构:Visitor 模式 -
• 🎯 总结
📁 目录结构一览
Verilator 的源代码组织清晰,各目录职责分明:
📋 说明:
-
• 根节点 ROOT:代表 Verilator 源码仓库的根目录,所有其他目录都从它展开。 -
• bin/目录: -
• verilator:用户直接调用的 Perl 包装脚本,负责设置环境变量。 -
• verilator_bin:真正执行编译的核心二进制。 -
• verilator_bin_dbg:调试版本,保留更多断言与调试符号。 -
• src/目录: -
• V3*.cpp/.h:翻译器的全部核心源代码。 -
• verilog.y:Bison 语法描述文件,定义 Verilog 语法规则。 -
• verilog.l:Flex 词法描述文件,定义 Token 识别规则。 -
• include/目录: -
• verilated.h:仿真运行时核心头文件,用户 App 必须包含。 -
• verilated.mk:生成的 Makefile 会包含此文件,统一构建规则。 -
• verilated_vcd_c.h:VCD 波形输出支持。 -
• 其他目录: -
• test_regress/:内部回归测试,保证每次提交不破坏现有功能。 -
• examples/:入门示例,包含 C 与 SystemC 两种风格。 -
• docs/:文档源文件,生成官网上的手册。 -
• bin/verilator:Perl 包装脚本,负责命令参数处理、设置VERILATOR_ROOT环境变量、可选地在调试器中包装执行,然后调用真正的二进制verilator_bin(或调试模式下的verilator_bin_dbg)。 -
• include/:包含全局例程和头文件,用户编译生成的 C++ 模型时需要将这些文件加入编译器的-I路径。 -
• src/:Verilator 翻译器的全部核心源代码,所有V3*开头的文件都在此。 -
• 输出目录:所有生成的文件放在 --Mdir指定的目录中,默认为obj_dir。
🏛️ 核心组件体系
Verilator 的内部实现围绕几个核心类展开,它们构成了整个编译器的骨架。
📋 说明:
-
• 🌐 全局状态层: -
• V3Global:全局单例,持有 AST 根节点与所有全局配置。 -
• V3Options:存储命令行解析结果,约 150+ 个选项变量。 -
• 两者关系: V3Global包含V3Options。 -
• 🌳 AST 层: -
• AstNode:所有 AST 节点的抽象基类。 -
• AstNetList:整棵 AST 的根节点。 -
• AstModule:表示一个 Verilog 模块。 -
• AstVar:表示信号 / 变量。 -
• AstAlways:表示always过程块。 -
• 🔧 工具层: -
• V3Number:四值逻辑数值系统,用于编译期常量计算。 -
• V3Graph:通用有向图框架,用于数据流分析。 -
• FileLine:源码位置追踪,用于错误报告。 -
• ⚙️ 变换 Pass 层: -
• VNVisitor:所有 Pass 的基类。 -
• V3Width:宽度推断。 -
• V3Const:常量传播。 -
• V3Order:执行顺序排序。 -
• 📤 后端层: -
• V3EmitC:C++ 代码发射器,遍历 AST 输出最终代码。 -
• 关键依赖关系: -
• V3Global持有 AST 根节点。 -
• AstNode使用V3Number表示常量。 -
• VNVisitor遍历AstNode,并构建V3Graph。 -
• V3EmitC遍历 AST 树根进行代码发射。
V3Global:全局状态中心
V3Global 是整个 Verilator 程序的顶层类,作为全局单例(实例名为 v3Global)存在。
-
• 核心成员: -
• m_rootp:指向 AST 的根节点AstNetList。 -
• opt:包含V3Options对象,存储所有命令行选项和配置状态。 -
• 关键方法: -
• boot():初始化子系统。 -
• readFiles():读取并解析输入文件。 -
• 使用模式:在 Verilator 代码中,任何地方都可以通过 v3Global访问全局状态。
📋 说明:
-
• 单例 VG(V3Global):整个程序生命周期只有一个实例,任何地方都能访问。 -
• 成员 m_rootp:指向 AST 根节点,编译全过程围绕它进行。 -
• 成员 opt:指向V3Options,所有配置从这里读取。 -
• 方法 boot():由main()调用,初始化全局子系统。 -
• 方法 readFiles():由main()调用,读取并解析源文件。 -
• 访问者 ANY:任意 V3 代码都可以通过v3Global.rootp或v3Global.opt访问全局状态。 -
• 外部产物: -
• AST 树:由 m_rootp指向。 -
• 编译选项:由 opt指向。
V3Options:配置状态中心
V3Options 是 Verilator 的配置中心,使用 Pimpl(Pointer to Implementation)模式隐藏实现细节,包含约 150+ 个成员变量表示不同的配置设置。
-
• 核心职责: -
• 解析命令行参数(通过 V3OptionParser)。 -
• 存储所有选项值(如 --cc、--exe、--trace等)。 -
• 提供配置查询接口。 -
• 访问方式:通过 v3Global.opt访问单例。
📋 说明:
-
• 输入 CMD:用户在命令行输入的所有参数。 -
• 解析器 VP(V3OptionParser):负责把命令行拆解成结构化选项。 -
• 核心 VO(V3Options):解析后的配置单例,所有模块都从这里读取配置。 -
• 配置项示例: -
• --cc:选择 C++ 代码生成模式。 -
• --exe:生成可执行文件。 -
• --trace:启用波形追踪。 -
• --top-module:指定顶层模块。 -
• --Mdir:指定输出目录。 -
• ... 150+ 选项:还有大量其他选项。 -
• 消费者: -
• V3Width:宽度推断时读取配置(如是否有符号扩展)。 -
• V3Order:排序时读取配置(如是否需要多线程)。 -
• V3EmitC:发射代码时读取配置(如输出目录、文件命名)。
AstNode:AST 节点基类
AstNode 是 Verilator 抽象语法树中所有节点的抽象基类,是整个编译过程中核心的中间表示。
-
• 节点链接结构: -
• op1p()~op4p():四个子节点指针,用于表示操作数或子语句。 -
• nextp():指向下一个兄弟节点。 -
• backp():指向父节点或前一个兄弟节点。 -
• 类型系统: -
• type():返回VNType枚举值,标识具体节点子类。 -
• dtypep():指向AstNodeDType,描述节点值的数据类型。 -
• 源码追踪: -
• fileline():返回FileLine*对象,追踪源文件和行号。 -
• 类型检查宏(避免 RTTI 开销): -
• VN_IS(nodep, NodeType):类型判断。 -
• VN_CAST(nodep, NodeType):类型转换。 -
• VN_AS(nodep, NodeType):断言类型并转换。
📋 说明:
-
• 根基类 AstNode:所有 AST 节点的共同祖先,提供统一的类型系统与链接机制。 -
• 子类分类: -
• AstNetList:整个 AST 的根节点。 -
• AstModule:表示一个 Verilog 模块。 -
• AstNodeExpr:所有表达式的基类,如常量、加法、位选择。 -
• AstNodeStmt:所有语句的基类,如always、if、赋值。 -
• AstNodeDType:数据类型描述节点。 -
• 表达式子类: -
• AstConst:编译期常量(值存在V3Number中)。 -
• AstAdd:加法运算。 -
• AstSel:位选择(如a[3:0])。 -
• 语句子类: -
• AstAlways:always块。 -
• AstIf:条件语句。 -
• AstAssign:赋值语句。 -
• 继承层次: AstNode是所有节点的祖先,AstNodeExpr和AstNodeStmt是两大分支。
AST 节点链接结构示意图:
📋 说明:
-
• 根节点 N1(AstNetList):整棵树的入口。 -
• 模块节点 N2(AstModule):根节点的唯一子模块。 -
• 变量链: N3(clk)→N4(rst)→N5(count),通过nextp连接成兄弟链表。 -
• 过程块 N6(AstAlways):位于变量链之后。 -
• if语句N7:always块的子节点。 -
• 赋值语句 N8(AstAssign):if语句的子节点。 -
• backp反向链接:N2指向N1,N3指向N2,N4指向N3,形成双向链表。 -
• nextp虚线箭头:表示兄弟节点的横向链接。 -
• 实线箭头:表示父子节点的纵向链接。
V3Number:四值逻辑数值系统
V3Number 是 Verilator 内部的数值表示系统,在编译期常量折叠和 AST 中表示常量值。
-
• 核心能力: -
• 任意精度整数运算(宽度可配置)。 -
• 四值逻辑(0、1、X、Z)表示。 -
• 64 位 IEEE 754 浮点数支持。 -
• 字符串支持。 -
• 存储策略(按位宽优化): -
• 内联存储:宽度 ≤ MAX_INLINE_WIDTH(通常 128 或 256 位)。 -
• 动态存储:宽度更大的数字使用动态分配的向量。 -
• 字符串存储:字符串类型存储在 m_string成员中。 -
• 四值逻辑编码:使用双比特编码。 -
• 00→ 逻辑 0 -
• 10→ 逻辑 1 -
• 01→ Z(高阻) -
• 11→ X(未知)
📋 说明:
-
• 核心 NUM(V3Number):任意精度数值表示。 -
• 判断 MODE:根据位宽选择存储策略。 -
• 三种存储策略: -
• INLINE:位宽较小,直接栈上存储,避免堆分配。 -
• DYN:位宽较大,堆分配向量。 -
• STR:字符串类型,存储在m_string成员。 -
• 四值编码 ENC: -
• 00:逻辑 0。 -
• 10:逻辑 1。 -
• 01:Z(高阻)。 -
• 11:X(未知)。 -
• 运算符重载 OPS: -
• OP1算术运算(加减乘除)。 -
• OP2位运算(与或非异或)。 -
• OP3比较运算(大小相等)。 -
• OP4浮点运算。
V3Graph:图算法基础设施
V3Graph 是 Verilator 提供的通用有向图框架,许多优化 Pass 使用图算法来分析数据流并确定安全的变换。
-
• 核心类: -
• V3Graph:图容器,管理顶点和边。 -
• V3GraphVertex:顶点基类。 -
• V3GraphEdge:边基类。 -
• 典型用途: -
• 数据流分析(依赖图构建)。 -
• 拓扑排序(确定 eval()中语句的执行顺序)。 -
• 弱连通分量分析。 -
• 输出:支持 GraphViz dot 格式输出,便于可视化。
📋 说明:
-
• 核心 VG(V3Graph):图容器,管理所有顶点和边。 -
• 顶点与边: -
• VV(V3GraphVertex):顶点基类,所有顶点继承自此。 -
• VE(V3GraphEdge):边基类,所有边继承自此。 -
• 三种典型用途: -
• U1数据流分析:构建依赖图,分析信号之间的依赖关系。 -
• U2拓扑排序:确定eval()中语句的执行顺序。 -
• U3弱连通分量:拆分逻辑块以便并行执行。 -
• 输出: -
• ORDER:拓扑排序结果,决定 C++ 代码中语句顺序。 -
• DOT:GraphViz dot 格式文件,可用图形工具可视化依赖图。
核心组件全景关系图
📋 说明:
-
• 🌐 顶层控制层: -
• main():程序入口。 -
• process():编译主流程,负责编排各阶段。 -
• ⚙️ 全局状态层: -
• V3Global:全局单例,持有 AST 与配置。 -
• V3Options:命令行解析结果。 -
• main()调用process(),process()通过V3Global访问所有状态。 -
• 🌳 AST 中间表示层: -
• AstNetList:树根,V3Global持有。 -
• AstModule:模块节点。 -
• AstVar、AstAlways:模块内的变量与过程块。 -
• AstNodeStmt、AstNodeExpr:语句和表达式基类。 -
• 🔧 工具支撑层: -
• V3Number:数值系统,被多个 Pass 使用。 -
• V3Graph:图框架,用于数据流分析。 -
• FileLine:源码位置追踪,用于错误报告。 -
• ⚙️ Pass 变换层: -
• VNVisitor:所有 Pass 的基类,遍历 AST。 -
• V3Param、V3Width、V3Const、V3Order:典型 Pass。 -
• VNVisitor遍历 AST 根节点,并使用V3Number与V3Graph。 -
• 📤 后端发射层: -
• V3EmitC:遍历 AST 树根,使用V3Number发射最终 C++ 代码。
⚙️ 编译管线:四大阶段
Verilator 的编译管线分为四个顺序执行的阶段,从 Verilog/SystemVerilog 源代码到最终的可执行仿真模型。
📋 说明:
-
• 🚪 入口点: -
• bin/verilator:用户命令行调用的 Perl 脚本。 -
• verilator_bin:真正执行的二进制。 -
• main():C++ 程序入口。 -
• V3Global::boot():初始化全局状态。 -
• process():进入编译主流程。 -
• 📝 阶段一:前端: -
• V3PreProc:预处理,处理宏与包含。 -
• V3PreLex:基于 Flex 的词法分析。 -
• V3ParseBison:基于 Bison 的语法分析。 -
• 输出: AST抽象语法树。 -
• 🔍 阶段二:语义分析: -
• Link:链接引用。 -
• V3Param:参数展开。 -
• V3Width:宽度推断。 -
• Elaboration:设计展开。 -
• ⚡ 阶段三:变换优化: -
• ~50+ 变换 Pass:一系列 AST 变换。 -
• V3Order:调度排序。 -
• 📤 阶段四:后端: -
• V3EmitC:C++ 代码发射。 -
• 输出: .cpp/.h/.mk文件。 -
• 阶段间数据流: process()⇒ 前端 ⇒ AST ⇒ 语义分析 ⇒ 展开后 AST ⇒ 变换 ⇒ 优化后 AST ⇒ 后端 ⇒ 文件。
四大阶段数据流全景:
📋 说明:
-
• 输入 SRC:.v或.sv源代码文件。 -
• 中间 AST 表示: -
• A1:原始 AST(前端输出)。 -
• A2:展开后 AST(语义分析输出)。 -
• A3:优化后 AST(变换优化输出)。 -
• 输出 OUT:.cpp/.h/.mk文件。 -
• 前端数据: -
• T1:Token 流。 -
• T2:原始 AST。 -
• 语义分析数据: -
• T3:位宽信息。 -
• T4:参数绑定。 -
• 优化数据: -
• T5:常量折叠结果。 -
• T6:执行顺序图。 -
• 虚线箭头:表示数据的辅助流动方向。
入口点与初始化
-
• bin/verilator(Perl 包装脚本): -
• 处理命令行参数。 -
• 设置 VERILATOR_ROOT环境变量。 -
• 可选地在调试器(gdb、valgrind、rr)中包装执行。 -
• 调用核心二进制 verilator_bin(或verilator_bin_dbg)。 -
• src/Verilator.cpp::main(): -
• 初始化 V3Options解析命令行参数。 -
• 创建 V3Global单例存储全局状态。 -
• 调用 V3Global::boot()初始化子系统。 -
• 调用主函数 process()。
📋 说明:
-
• 输入 START:用户输入的命令行,例如verilator --cc top.v。 -
• Perl 脚本 PERL:bin/verilator,进行环境配置。 -
• 环境变量 ENV:设置VERILATOR_ROOT,让核心二进制找到运行时文件。 -
• 调试分支 DBG: -
• 是:走 DBGBIN(verilator_bin_dbg),可被 gdb/valgrind 调试。 -
• 否:走 BIN(verilator_bin),普通执行。 -
• 核心入口 MAIN:Verilator.cpp::main()函数。 -
• 参数解析 PARSE:V3Options解析命令行,生成配置。 -
• 单例初始化 INIT:创建V3Global,全局状态就绪。 -
• 子系统启动 BOOT:V3Global::boot()初始化各子系统。 -
• 主流程 PROC:调用process(),进入四大编译阶段。
阶段一:前端(文本 → AST)
前端将文本形式的 HDL 转换为抽象语法树(AST),分为三个子步骤:
前端处理流程图:
📋 说明:
-
• 输入 SRC:top.v源代码文件。 -
• 预处理器 PP(V3PreProc): -
• PP1:处理include指令,插入被包含文件。 -
• PP2:展开define宏。 -
• PP3:处理条件编译ifdef/ifndef/else/endif。 -
• 输出: TOKToken 流。 -
• 词法分析 LEX(V3PreLex): -
• 基于 Flex 实现。 -
• 输出多种 Token 类型: -
• T1:yaINTNUM整数常量。 -
• T2:yaID__ETC标识符。 -
• T3:yaSTRING字符串。 -
• T4:运算符 Token。 -
• 语法分析 PARSE(V3ParseBison): -
• 基于 Bison 实现。 -
• 从 Token 流构造 AST 节点。 -
• AST 节点输出: -
• N1:AstModule,模块节点。 -
• N2:AstVar,变量节点。 -
• N3:AstAlways,过程块。 -
• N4:AstAssign,赋值语句。 -
• 最终输出 AST:完整的抽象语法树。 -
• 预处理:维护 FileLine对象进行文件和行号追踪。 -
• 词法分析:返回 yaINTNUM、yaID__ETC、yaSTRING等 token,支持基于状态的扫描以适应不同语言上下文。 -
• 语法分析:创建专门的节点类型( AstModule、AstVar、AstAlways等),管理解析状态。
阶段二:语义分析与展开
-
• 链接(Link):AST 中的 cell 被链接,读取并解析额外文件,函数、变量引用被链接到定义。 -
• 参数解析:参数被解析,设计被展开。 -
• 宽度推断(V3Width):为所有表达式计算位宽,是最复杂的 Pass 之一,处理 SystemVerilog 复杂的类型传播规则。
📋 说明:
-
• 输入 AST:前端生成的原始 AST。 -
• 链接 LINK:解析所有引用,读取被包含文件,将变量/函数引用链接到定义。 -
• 参数展开 PARAM(V3Param):为每个参数组合克隆模块,消除参数化。 -
• 宽度推断 WIDTH(V3Width): -
• W1:插入AstCCast,处理类型转换。 -
• W2:插入AstExtend,处理符号/零扩展。 -
• W3:插入AstSel,处理位提取。 -
• WIDTHC(V3WidthCommit):提交宽度推断结果。 -
• 展开 ELAB:生成完整的层次结构,将高层描述展开为低层逻辑。 -
• 输出 AST2:展开后 AST,准备进入变换优化阶段。
阶段三:变换与优化 Pass
Verilator 在 AST 上执行~50+ 个顺序变换 Pass,每个 Pass 实现为一个独立的 Visitor 类,遍历并修改 AST。
阶段四:后端代码生成
-
• V3EmitC:C++ 代码发射子系统的主协调器。 -
• 多个专门的发射类生成 C++ 模型的不同方面: emitc()、emitcInlines()、emitcSyms()、emitcTrace()等。 -
• 最终输出 .cpp、.h文件和构建系统文件(Makefile)。
📋 说明:
-
• 输入 AST:变换优化后的 AST。 -
• 协调器 EMITC(V3EmitC):代码发射主协调器,按类别调用不同发射器。 -
• 六大发射器: -
• E1(emitc()):主 C++ 代码,输出Vtop.cpp与Vtop.h。 -
• E2(emitcInlines()):内联函数,输出Vtop__Inlines.h。 -
• E3(emitcSyms()):符号表,输出Vtop__Syms.cpp/.h。 -
• E4(emitcTrace()):波形追踪代码,输出Vtop__Trace.cpp/.h。 -
• E5(emitcMakefile()):构建规则,输出Vtop.mk。 -
• E6(emitcCells()):单元层次,输出Vtop__Cell.h。 -
• 输出文件: -
• OUT1~OUT7:最终用户可编译的文件集合。
🔄 变换 Pass 的详细执行序列
以下是 Verilator 编译管线中主要变换 Pass 的执行序列,按阶段分组:
完整 Pass 序列流程图:
📋 说明:
-
• 输入 START:展开后 AST,从语义分析阶段进入。 -
• 前置 LINK(V3LinkResolve):符号解析,链接所有引用。 -
• 📦 插桩阶段 G1: -
• V3Coverage:插入覆盖率统计代码。 -
• V3Assert:插入断言检查。 -
• V3Randomize:插入随机化逻辑。 -
• 🏗️ 结构变换阶段 G2: -
• V3Inst:实例展开(消除模块实例化)。 -
• V3Scope:作用域展平(消除层次结构)。 -
• V3Inline:模块内联。 -
• V3Task:任务展开。 -
• ⚡ 逻辑优化阶段 G3: -
• V3Const:常量折叠。 -
• V3Gate:门级优化。 -
• V3Unknown:X 消除(四值转二值)。 -
• V3Tristate:三态消除。 -
• V3Const(再次):第二次常量折叠,处理新暴露的常量。 -
• 📐 调度排序阶段 G4: -
• V3Active:拆分always块为 active 区域。 -
• V3Delayed:处理非阻塞赋值的延迟语义。 -
• V3Order:确定eval()内的执行顺序。 -
• 📝 代码准备阶段 G5: -
• V3Expand:展开复杂表达式。 -
• V3Premit:预提交优化。 -
• V3Depth:计算表达式深度。 -
• V3Descope:去除作用域信息。 -
• 输出 DONE:优化完成的 AST,准备进入后端发射。 -
• V3Param:通过为每个唯一的参数组合创建专门的克隆来消除参数化模块。必须在大多数其他变换之前执行,因为参数影响信号位宽、数组大小和条件生成块。 -
• V3Width:执行类型推断和位宽计算,插入 AstCCast进行类型转换,添加AstExtend进行符号/零扩展,当位宽不匹配时添加AstSel进行位提取。 -
• V3Const:在编译的不同阶段多次调用,执行常量折叠和传播。 -
• V3Inst:分两阶段进行实例展开—— dearrayAll()移除 cell 数组,instAll()将模块实例转换为线网赋值。
🧩 Pass 执行架构:Visitor 模式
所有变换 Pass 都使用 Visitor 设计模式遍历 AST。
-
• 基类:每个 Pass 继承 VNVisitor基类,并为特定的 AST 节点类型实现visit方法。 -
• 主执行循环:变换序列由 Verilator.cpp::process()编排。 -
• 优势: -
• 每个 Pass 只需关注自己关心的节点类型。 -
• 通过 Visitor 模式实现 AST 的解耦遍历。 -
• 新 Pass 的添加不影响现有 Pass。
Visitor 模式类关系图:
📋 说明:
-
• 节点基类 AstNode(抽象): -
• 提供 op1p()~op4p()四个子节点指针。 -
• nextp()/backp()用于兄弟与父节点链接。 -
• type()返回节点类型(VNType枚举)。 -
• dtypep()返回数据类型描述。 -
• fileline()返回源码位置。 -
• 表达式基类 AstNodeExpr(抽象):所有表达式的祖先,提供width()方法。 -
• 语句基类 AstNodeStmt(抽象):所有语句的祖先。 -
• 访问者基类 VNVisitor(抽象): -
• visit(AstNode*):处理节点。 -
• iterate(AstNode*):遍历节点。 -
• iterateChildren(AstNode*):遍历子节点。 -
• 典型 Pass: -
• V3Width:实现visit(AstAdd*)、visit(AstVar*)、visit(AstConst*)。 -
• V3Const:实现visit(AstAdd*)、visit(AstMul*)、visit(AstSel*)。 -
• V3Order:实现visit(AstAlways*)、visit(AstAssign*)。 -
• V3EmitC:实现visit(AstNetList*)、visit(AstModule*)。 -
• 继承关系( <|--):所有 Pass 继承自VNVisitor,所有节点继承自AstNode。 -
• 依赖关系( ..>):VNVisitor依赖AstNode进行遍历。
Pass 编排与 Visitor 遍历流程:
📋 说明:
-
• 参与者 PROC(process()):主控流程,顺序调用各 Pass。 -
• 参与者 AST:被所有 Pass 遍历和修改。 -
• 步骤 1-2: PROC调用V3Param,后者克隆参数化模块并返回。 -
• 步骤 3-4: PROC调用V3Width,后者计算位宽并插入 Cast。 -
• 步骤 5-6: PROC调用V3Const,后者折叠常量表达式。 -
• 步骤 7-8: PROC调用V3Order,后者确定执行顺序。 -
• 步骤 9-10: PROC调用V3EmitC,后者遍历 AST 生成 C++ 代码。 -
• -->>虚线:表示返回控制权给PROC。
Visitor 遍历 AST 的详细展开图:
📋 说明:
-
• 访问者 VIS(VNVisitor):从 AST 根节点开始遍历。 -
• 遍历顺序: -
• ROOT(AstNetList):遍历根。 -
• M1(AstModule):进入模块。 -
• V1(AstVar clk)→V2(AstVar rst)→V3(AstVar count):按nextp横向遍历变量。 -
• A1(AstAlways):进入过程块。 -
• IF(AstIf):进入条件语句。 -
• AS1(AstAssign count=0):then 分支。 -
• AS2(AstAssign count=count+1):else 分支。 -
• visit方法处理(虚线箭头):VIS对每个节点调用对应的visit方法,进行具体处理。 -
• 实线箭头:表示遍历路径( iterate与iterateChildren)。 -
• 虚线箭头:表示访问者对节点的具体处理。
🎯 总结
完整编译流程一图总览:
📋 说明:
-
• 输入 SRC:Verilog/SystemVerilog 源代码。 -
• 📝 前端 FE:预处理 + 词法 + 语法分析。 -
• 内部组件: V3PreProc、V3PreLex、V3ParseBison。 -
• 输出: AST1原始 AST。 -
• 🔍 语义分析 ME:链接 + 参数展开 + 宽度推断 + 展开。 -
• 内部组件: V3Param、V3Width、V3WidthCommit。 -
• 输出: AST2展开后 AST。 -
• ⚡ 变换优化 OPT:~50+ 个 Pass。 -
• 内部组件: V3Const、V3Gate、V3Order。 -
• 输出: AST3优化后 AST。 -
• 📤 后端发射 BE:C++ 代码生成。 -
• 内部组件: V3EmitC、V3EmitCFunc、V3EmitCMake。 -
• 输出: FILES(.cpp/.h/.mk)。 -
• 🔨 编译 COMPILE:GCC/Clang 编译生成的 C++ 代码。 -
• 🚀 最终产物 EXE:可执行仿真器。 -
• 目录结构: bin/(包装脚本)、src/(核心源代码)、include/(运行时头文件)、test_regress/(回归测试)。 -
• 核心类体系: -
• V3Global:全局单例,持有 AST 根节点和配置。 -
• V3Options:配置中心,150+ 个选项变量。 -
• AstNode:AST 基类,四子指针 + next/back 链接,VNType 类型系统。 -
• V3Number:四值逻辑数值系统,内联/动态/字符串三种存储策略。 -
• V3Graph:通用有向图框架,用于数据流分析和拓扑排序。 -
• 编译管线: -
1. 前端:预处理 → 词法分析(Flex)→ 语法分析(Bison)→ AST。 -
2. 语义分析:链接 → 参数展开 → 宽度推断 → 展开。 -
3. 变换优化:~50+ 个 Pass,按依赖关系顺序执行。 -
4. 后端:V3EmitC 协调多个发射类生成 C++ 代码。 -
• Pass 架构:Visitor 模式,每个 Pass 继承 VNVisitor,由process()统一编排。
📚 参考资源
• Verilator Internals Manual:https://verilator.org/guide/latest/internals.html • Verilator 官方文档:https://verilator.org/guide/latest/ • GitHub 仓库:https://github.com/verilator/verilator • DeepWiki Verilator 文档:https://deepwiki.com/verilator/verilator

