第二章:系统建模与抽象层次

各位同学,今天我们来聊聊系统建模。这个话题,说白了就是回答一个问题:我们到底该用什么视角去看一个芯片系统?

我刚开始做芯片架构时,总觉得建模就是写代码。后来被现实狠狠教育了一顿——不同阶段、不同目的,你得用不同的抽象层次去看问题。否则,要么细节太多跑不动,要么太粗糙啥也看不出来。

2.1 为什么需要不同抽象层次?

你想想看,设计一个复杂的SoC,如果一上来就盯着每个晶体管的开关,那估计十年也搞不完。反过来,如果全程只画框图,流片回来大概率是个砖头。

所以,我们需要分层建模。每一层解决不同的问题:

  • 系统级建模:看功能对不对,架构合不合理
  • 事务级建模:看通信和交互是否顺畅
  • 行为级建模:看算法和逻辑是否正确
  • RTL级建模:看能不能综合,时序能不能满足

这就像盖房子。你总得先画个效果图(系统级),再画施工图(RTL级),中间还得有结构图(事务级)和管线图(行为级)。跳过任何一步,都可能出大问题。

核心观点:抽象层次越高,仿真速度越快,但精度越低。抽象层次越低,精度越高,但仿真速度越慢。这是个经典的trade-off。

2.2 系统级建模(System-Level Modeling)

系统级建模,我习惯叫它「大图建模」。这个阶段,我们不关心具体怎么实现,只关心系统行为性能指标

举个例子,你要设计一个AI加速芯片。系统级模型会告诉你:

  • 需要多少算力(TOPS)
  • 内存带宽够不够
  • 功耗预算能不能覆盖
  • 任务调度是否合理

我在项目中遇到过一件事:有个团队直接跳过了系统级建模,上来就写RTL。结果做到一半发现,总线带宽根本不够,所有外设都在抢资源。最后只能推倒重来,白白浪费了三个月。

我的建议:系统级建模用SystemC或者Python做原型验证。速度快,改起来也方便。千万别在这个阶段纠结细节。

2.3 事务级建模(Transaction-Level Modeling, TLM)

事务级建模,说白了就是只看通信,不看实现。我们把一次总线读写、一次DMA传输、一次中断响应,都看作一个「事务」。

为什么需要TLM?因为系统级模型太粗糙,RTL又太慢。TLM正好卡在中间——它比系统级更精确,又比RTL快几个数量级。

我记得有一次做多核处理器验证。用RTL仿真跑一个操作系统启动,要整整两天。换成TLM模型,十分钟就跑完了。而且关键的性能瓶颈点,TLM都能准确反映出来。

TLM的建模方式通常有两种:

  • 近似时间TLM:带时间戳,可以估算性能
  • 无时间TLM:只关心功能正确性,不关心时序

注意:TLM模型虽然快,但不能用来做时序验证。我曾经见过有人用TLM跑出来的时序去签核,结果流片回来时序全崩了。TLM的时序是估算,不是精确值。

2.4 行为级建模(Behavioral-Level Modeling)

行为级建模,我理解就是用高级语言描述算法和逻辑。比如用C/C++写一个FFT算法,用Matlab验证一个滤波器系数,用Python搭一个神经网络。

这个阶段,我们关注的是:

  • 算法是否正确
  • 数值精度是否够
  • 有没有边界情况没处理

行为级模型通常不可综合,但它是通往RTL的桥梁。我个人的习惯是:先写行为级模型,跑通所有测试用例,再开始写RTL。这样能避免很多低级错误。

// 行为级建模示例:一个简单的FIR滤波器
// 用C语言描述,方便调试和验证
void fir_filter(int *input, int *output, int len) {
    int taps[4] = {1, 2, 2, 1};  // 滤波器系数
    for (int i = 3; i < len; i++) {
        output[i] = taps[0]*input[i] + 
                    taps[1]*input[i-1] + 
                    taps[2]*input[i-2] + 
                    taps[3]*input[i-3];
    }
}

避坑指南:我曾经在行为级模型里用了一个浮点除法,觉得没问题。结果到RTL实现时发现,硬件除法器面积太大,根本放不下。所以行为级建模时,就要考虑硬件的可实现性。

2.5 RTL级建模(Register-Transfer Level Modeling)

RTL级建模,这是芯片设计的硬核阶段。我们用Verilog或VHDL描述每个时钟周期、每个寄存器的行为。

RTL模型的特点:

  • 可综合:能直接映射到门级电路
  • 时序精确:每个信号的变化都在时钟边沿
  • 仿真慢:一个复杂的SoC,RTL仿真一天可能跑不了几毫秒

我刚开始做RTL设计时,总觉得写代码就是全部。后来才明白,RTL建模最重要的是可读性和可维护性。你写的代码,三个月后自己都看不懂,那还不如不写。

// RTL建模示例:同一个FIR滤波器的Verilog实现
module fir_filter (
    input  clk,
    input  rst_n,
    input  [7:0] data_in,
    output [9:0] data_out
);
    reg [7:0] shift_reg [0:3];
    wire [9:0] sum;
    
    // 移位寄存器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            shift_reg[0] <= 0;
            shift_reg[1] <= 0;
            shift_reg[2] <= 0;
            shift_reg[3] <= 0;
        end else begin
            shift_reg[0] <= data_in;
            shift_reg[1] <= shift_reg[0];
            shift_reg[2] <= shift_reg[1];
            shift_reg[3] <= shift_reg[2];
        end
    end
    
    // 乘加运算
    assign sum = shift_reg[0] + 
                 (shift_reg[1] << 1) + 
                 (shift_reg[2] << 1) + 
                 shift_reg[3];
    assign data_out = sum;
endmodule

警告:RTL模型一旦写好,改起来成本很高。我见过太多人因为RTL写得太随意,导致综合后时序不满足,最后只能大改。所以写RTL时,脑子里就要有电路图。

2.6 不同抽象层次的优缺点对比

为了让你看得更清楚,我整理了一个表格:

抽象层次 仿真速度 精度 可综合 主要用途
系统级 极快(秒级) 架构探索、性能评估
事务级(TLM) 快(分钟级) 通信验证、性能分析
行为级 中等(小时级) 较高 通常不可 算法验证、功能调试
RTL级 慢(天级) 综合、时序分析、签核

嗯,这里要注意:没有哪个层次是万能的。你得根据项目阶段和验证目标,选择合适的抽象层次。我见过最糟糕的做法是:全程只用RTL仿真,结果项目延期半年。

2.7 本章知识体系图

下面这张图,是我自己画的,展示了不同抽象层次之间的关系和转换路径:

系统建模抽象层次体系 系统级建模 架构探索、性能评估 事务级建模 通信验证、性能分析 行为级建模 算法验证、功能调试 RTL级建模 综合、时序分析、签核 抽象层次降低,精度提高 仿真速度降低 不同抽象层次服务于不同设计阶段,需根据目标合理选择

2.8 我的经验总结

做了这么多年芯片,我最大的体会是:建模不是目的,验证才是。你建再漂亮的模型,如果跑不出bug,那就是白搭。

我个人习惯的做法是:

  1. 先用系统级模型确定架构和性能目标
  2. 再用TLM模型验证通信和交互
  3. 然后用行为级模型跑通所有算法
  4. 最后才写RTL,并且用前几个模型做参考

这样一层层下来,bug基本都在早期被发现了。等到RTL阶段,主要工作就是优化时序和面积,而不是修功能bug。

最后说一句:不要觉得建模浪费时间。你花在建模上的每一分钟,都会在后面的RTL调试中加倍还给你。这是我在无数项目中验证过的真理。


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