1. 课程导论与开发环境搭建

各位同学好,我是你们这门课的老周。在FPGA这行摸爬滚打了十几年,踩过的坑比走过的路还多。今天咱们开始第一讲,先把地基打牢。

这门课叫《FPGA时序约束与RISC-V软核优化性能调优实战》,名字挺长,但核心就两件事:让FPGA跑得快,让RISC-V软核跑得稳。说白了,就是教你如何把一块芯片的性能压榨到极致。

1.1 为什么时序约束是FPGA设计的“命门”?

很多新手觉得,代码写完了,仿真通过了,就万事大吉。结果一上板,要么不工作,要么偶尔抽风。为什么?

我刚开始做FPGA时也犯过这毛病。有一次做一个视频处理项目,仿真跑得完美,结果板子一跑,画面时不时花屏。查了三天,最后发现是时钟路径上有个组合逻辑延迟超标了。从那以后,我再也不敢轻视时序约束。

时序约束,说白了就是告诉工具:你的电路必须在多快的时间内完成计算。工具会根据这个要求,去优化布局布线,确保每条路径都不超时。

核心概念:静态时序分析(STA)是检查电路能否在目标频率下稳定工作的唯一手段。它不依赖仿真向量,而是穷举所有路径,计算最坏情况下的延迟。

没有约束,工具就不知道你的目标频率是多少。它会随便布,结果可能就是——你的设计只能跑50MHz,但你期望的是100MHz。

1.2 RISC-V软核:为什么选它?

RISC-V这几年火得不行。为什么?因为它开源、精简、可定制。你想想看,以前想用个CPU核,要么买ARM授权,要么用开源但复杂的OpenRISC。RISC-V的出现,让FPGA工程师也能轻松拥有一个属于自己的处理器。

咱们这门课选用的RISC-V软核,是经过我实际项目验证过的。它有几个特点:

  • 五级流水线:取指、译码、执行、访存、写回,标准的RISC-V架构
  • 支持RV32I指令集:基础整数指令,够用且高效
  • 可配置:可以按需裁剪,比如去掉乘法器、调整缓存大小
  • 面积小:在Xilinx Artix-7上只占约3000个LUT

但软核也有软核的烦恼。我在一个项目中,把RISC-V软核跑到了200MHz,结果发现访存路径成了瓶颈。这就是为什么咱们要把时序约束和软核优化结合起来学——两者是相辅相成的。

1.3 开发环境搭建:Vivado + Vitis

工欲善其事,必先利其器。咱们用Xilinx家的工具链:Vivado做FPGA综合布线,Vitis做RISC-V的软件开发。

安装过程我就不赘述了,网上教程很多。我提几个关键点:

工具 版本建议 用途 注意事项
Vivado 2022.2 或更新 FPGA设计、综合、实现、时序分析 安装时勾选“Vivado HL WebPACK”即可,够用
Vitis 2022.2 或更新 RISC-V交叉编译、调试、下载 需要单独安装,或者用Vivado自带的Vitis
RISC-V工具链 GCC 10+ 编译C代码为RISC-V机器码 推荐用SiFive提供的预编译包

我的习惯:Vivado和Vitis装在同一台机器上,但项目目录分开。Vivado工程放在 D:/FPGA_Projects/,Vitis工作空间放在 D:/Vitis_Workspace/。这样方便管理,也避免路径冲突。

1.4 第一个RISC-V软核工程

好,咱们动手。创建一个最简单的RISC-V软核工程,让它跑起来。

步骤一:创建Vivado工程

  1. 打开Vivado,点击“Create Project”
  2. 选择RTL Project,勾选“Do not specify sources at this time”
  3. 选择器件:我用的Xilinx Artix-7 xc7a35tcsg324-1
  4. 点击Finish

步骤二:添加RISC-V软核源码

咱们用的是一个精简版的RISC-V核,叫“PicoRV32”。它只有一个Verilog文件,非常干净。

// 在Vivado中,点击 Add Sources -> Add or create design sources
// 选择 picorv32.v 文件
// 然后创建一个顶层模块 top.v

步骤三:编写顶层模块

module top (
    input  wire        clk,
    input  wire        rst_n,
    output wire [31:0] led
);

    // 实例化PicoRV32
    wire        mem_valid;
    wire        mem_instr;
    wire [31:0] mem_addr;
    wire [31:0] mem_wdata;
    wire [3:0]  mem_wstrb;
    reg  [31:0] mem_rdata;
    wire        mem_ready;

    picorv32 #(
        .ENABLE_MUL(1),
        .ENABLE_DIV(1)
    ) cpu (
        .clk         (clk),
        .resetn      (rst_n),
        .mem_valid   (mem_valid),
        .mem_instr   (mem_instr),
        .mem_addr    (mem_addr),
        .mem_wdata   (mem_wdata),
        .mem_wstrb   (mem_wstrb),
        .mem_rdata   (mem_rdata),
        .mem_ready   (mem_ready)
    );

    // 简单的内存模型:只读,地址0x0000_0000开始
    reg [31:0] rom [0:255];
    initial $readmemh("firmware.hex", rom);

    always @(posedge clk) begin
        if (mem_valid & mem_ready) begin
            mem_rdata <= rom[mem_addr[9:2]];
        end
    end

    assign mem_ready = mem_valid;
    assign led = mem_rdata;

endmodule

注意:这里的 firmware.hex 是RISC-V的机器码文件,需要用Vitis编译生成。别急,下一步就讲。

步骤四:用Vitis编译固件

  1. 打开Vitis,创建一个新的Application Project
  2. 选择“RISC-V”平台(如果没有,需要先导入)
  3. 写一个简单的C程序:
// main.c
volatile unsigned int *led = (unsigned int *)0x00000000;

void main() {
    while(1) {
        *led = 0xAAAAAAAA;  // 让LED交替闪烁
        for(int i=0; i<100000; i++);
        *led = 0x55555555;
        for(int i=0; i<100000; i++);
    }
}
  1. 编译生成 firmware.hex,复制到Vivado工程目录下

步骤五:综合、实现、生成比特流

在Vivado中点击“Generate Bitstream”。如果一切顺利,你会看到时序报告。嗯,第一次跑可能时序不满足,别慌,这正是咱们后面要解决的问题。

1.5 本章知识体系

为了让你更直观地理解本章内容,我画了一张图:

第一章知识体系图 第一章:课程导论与开发环境搭建 时序约束概述 RISC-V软核简介 开发环境搭建 STA静态时序分析 建立/保持时间 五级流水线 RV32I指令集 Vivado/Vitis RISC-V工具链 核心目标:掌握时序约束基础 + 搭建RISC-V软核开发环境 为后续章节的实战优化打下坚实基础 第一个RISC-V软核工程实践

这张图把本章的知识点串起来了。你看,时序约束、RISC-V软核、开发环境,三者是并列关系。而最下面的“第一个RISC-V软核工程实践”,则是把前面所有知识落地的关键一步。

1.6 避坑指南

最后,分享几个我踩过的坑:

  • 路径问题:Vivado工程路径不要有中文,不要有空格。我曾经因为路径里有个“&”符号,折腾了一下午。
  • 版本匹配:Vivado和Vitis的版本必须一致。2022.1的Vivado配2022.2的Vitis,大概率会报错。
  • 固件格式:$readmemh 读取的hex文件,必须是每行一个32位数据,且是十六进制格式。少个换行符都可能读错。
  • 复位极性:PicoRV32的复位是低电平有效,别搞反了。我见过有人把 resetn 接高电平,结果CPU一直复位,啥也跑不起来。

我的建议:第一次跑通后,别急着往下学。花点时间看看Vivado的时序报告,哪怕现在看不懂,也要知道它长什么样。后面咱们会反复跟它打交道。