1. 项目概述与工具定位
如果你刚接触FPGA开发,面对Vivado这样功能庞大、界面复杂的工具,第一步的迷茫感我深有体会。Vivado HLs(High-Level Synthesis)2015.4虽然是数年前的版本,但其核心设计流程与后续版本一脉相承,对于学习FPGA开发的基础概念和操作逻辑而言,依然是一个稳定且经典的选择。FPGA的魅力在于其硬件可重构性,你可以像软件工程师写代码一样,用硬件描述语言(HDL)定义出专用的数字电路,但最终它将以并行的、硬件级的速度运行。这个过程的核心,就是将你写的VHDL或Verilog代码,通过一系列工具链操作,“翻译”并“烧录”成FPGA芯片内部可执行的硬件配置文件,也就是我们常说的比特流(Bitstream)文件。
本文将以Xilinx Artix-7系列的Basys 3开发板(主芯片为xc7a35tcpg236-1)为目标平台,手把手带你走通从零开始在Vivado HLs 2015.4中创建项目、编写VHDL代码、进行综合实现,并最终通过三种主流方式将设计下载到板卡上的全过程。无论你是电子工程专业的学生,还是希望涉足硬件加速领域的软件开发者,这篇指南都将帮你绕过我当初踩过的那些坑,快速建立起对FPGA开发流程的直观理解。我们会聚焦于最核心、最必要的步骤,避开那些初期容易让人分心的高级功能,确保你能在最短时间内看到自己的代码在硬件上跑起来。
2. 开发环境准备与项目创建详解
工欲善其事,必先利其器。在开始写代码之前,确保你的开发环境就绪是第一步。你需要从Xilinx官网(现为AMD官网)下载并安装Vivado Design Suite 2015.4的HLs版本。安装过程需要注意选择安装器件支持,务必勾选“Artix-7”系列,否则后续将无法找到我们的目标芯片。安装完成后,首次启动Vivado可能会稍慢,这是正常现象。
2.1 创建新项目的关键步骤与选项解析
启动Vivado后,你会看到“Quick Start”界面。这里我们选择“Create Project”,而不是打开已有项目。点击后,会弹出一个创建新项目的向导。
第一步:项目命名与路径向导的第一步会要求你填写项目名称和存储位置。这里有个实操心得:项目名称最好使用英文、无空格且具有描述性,例如led_blinker或pwm_controller。存储路径同样建议使用全英文路径,避免任何中文字符,这是为了避免后续工具链在解析路径时可能出现的潜在错误。一个良好的习惯是为所有FPGA项目建立一个专属目录,比如D:\FPGA_Projects,然后在里面为每个项目创建子文件夹。
第二步:选择项目类型接下来会进入“Project Type”选择界面。这里通常选择“RTL Project”。RTL(Register Transfer Level)意味着你将从寄存器传输级开始设计,即直接使用VHDL或Verilog进行编码。下面的“Do not specify sources at this time”选项建议先不勾选。虽然我们可以稍后添加源文件,但在向导中添加有助于Vivado提前识别设计语言,并应用相应的语法检查和模板。
第三步:添加或创建设计源文件这是核心步骤之一。在“Add Sources”界面,我们点击“Create File”。在弹出的对话框中,“File name”填写为top(或其他你喜欢的顶层模块名),“File type”务必根据你的设计语言选择“VHDL”或“Verilog”。这里我们以VHDL为例。点击OK后,文件会出现在列表中。此时,Vivado会弹出一个“Define Module”窗口,这是为你自动创建模块声明的便捷功能。对于初学者,我建议在这里先简单定义几个输入输出端口,例如一个时钟输入clk,一个复位输入rst_n,和几个LED输出leds(3 downto 0)。方向(Direction)分别选择input、input和output,对于leds,需要勾选“Bus”,并设置MSB为3,LSB为0。这能帮你快速搭建一个框架。当然,你也可以选择跳过,后续在代码文件中手动编写实体(entity)声明。
第四步:添加约束文件(XDC)在“Add Constraints”界面,我们同样选择“Create File”。约束文件(.xdc)的作用是告诉Vivado你的设计中的端口(如clk,leds)具体对应到开发板上的哪个物理引脚(Pin),以及这些端口所遵循的电气特性和时序要求。对于Basys 3,Digilent提供了现成的约束文件,你可以从官网下载。但在初次学习时,我们也可以先创建一个空的约束文件(如basys3.xdc)稍后手动添加,或者直接点击“Next”跳过,在生成比特流前再添加。不过,一个重要的注意事项是:没有正确的约束文件,你的设计将无法正确映射到芯片引脚,下载后自然不会有任何现象。
第五步:选择目标器件这是至关重要的一步,直接决定了综合实现过程针对的是哪颗芯片。在“Default Part”界面,我们需要手动筛选出Basys 3使用的芯片。
- 在“Parts”选项卡下,在筛选栏中依次选择或输入:
- Family:
Artix-7 - Package:
cpg236 - Speed Grade:
-1
- Family:
- 在列表中找到并选中器件:
xc7a35tcpg236-1。请仔细核对型号,xc7a35t是芯片系列,cpg236是封装,-1是速度等级。选中后点击“Next”。
第六步:项目信息总览最后一步是“New Project Summary”,这里会列出你之前所有的选择,包括项目类型、源文件、约束文件和目标器件。请务必仔细核对,特别是器件型号。确认无误后,点击“Finish”,Vivado便会为你创建项目并打开主设计界面。
2.2 项目目录结构初探
项目创建完成后,在你的项目存储路径下,Vivado会生成一系列目录。了解它们有助于后续的问题排查:
project_name.srcs/: 存放源代码和约束文件。project_name.runs/: 这是核心目录,后续综合(synth_1)和实现(impl_1)的日志、报告以及最终生成的比特流文件(.bit)都在这里。project_name.cache/: Vivado的缓存文件,用于加速后续打开和操作。project_name.xpr: 项目文件,双击它即可在Vivado中打开整个项目。
3. VHDL源代码编写与设计管理
项目创建好后,在Vivado左侧的“Sources”窗口的“Design Sources”下,你应该能看到刚才创建的top.vhd文件。双击它,就可以在中间的编辑区域开始编写代码了。
3.1 编写一个简单的LED闪烁程序
让我们从一个最经典的“Hello World”级程序——LED闪烁开始。这将涉及时钟分频,是理解FPGA时序逻辑的基础。将以下VHDL代码替换或写入你的top.vhd文件:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; -- 用于使用无符号数类型 entity top is Port ( clk : in STD_LOGIC; -- 系统时钟,Basys3上为100MHz rst_n : in STD_LOGIC; -- 低电平有效的复位按钮(假设连接) leds : out STD_LOGIC_VECTOR (3 downto 0) -- 4位LED输出 ); end top; architecture Behavioral of top is -- 定义一个26位的计数器,用于分频 (100MHz / 2^26 ≈ 1.5Hz) signal counter : unsigned(25 downto 0) := (others => '0'); -- 定义一个寄存器,用于存储LED的当前状态 signal led_reg : STD_LOGIC_VECTOR(3 downto 0) := "0001"; -- 初始状态,仅最低位亮 begin -- 进程:计数器递增与LED状态切换 process(clk) begin if rising_edge(clk) then -- 在时钟上升沿触发 if rst_n = '0' then -- 异步复位(低电平有效) counter <= (others => '0'); led_reg <= "0001"; else -- 计数器递增 counter <= counter + 1; -- 当计数器计满时(最高位为1),切换LED状态 if counter(25) = '1' then -- 检查计数器的最高位 led_reg <= led_reg(2 downto 0) & led_reg(3); -- 循环左移 counter <= (others => '0'); -- 重置计数器 end if; end if; end if; end process; -- 将内部寄存器输出到端口 leds <= led_reg; end Behavioral;代码解析与注意事项:
- 库声明:
IEEE.STD_LOGIC_1164是标准逻辑库,定义了STD_LOGIC等类型。IEEE.NUMERIC_STD库则提供了用于算术运算的unsigned/signed类型,比直接用STD_LOGIC_VECTOR进行算术操作更安全、更直观。 - 实体(Entity):定义了模块的输入输出端口,即与外部世界的接口。这里我们定义了时钟
clk、复位rst_n和LED输出leds。 - 结构体(Architecture):描述了模块内部的行为或结构。
Behavioral表示行为级描述。 - 信号(Signal):用于模块内部连接,相当于硬件内部的连线或寄存器。
counter是一个26位无符号数,用于计数。led_reg是一个4位标准逻辑向量,用于存储LED的当前显示模式。 - 进程(Process):描述时序逻辑(带时钟)或组合逻辑。
(clk)是敏感列表,表示进程由clk信号的变化触发。rising_edge(clk)是检测时钟上升沿的标准写法。 - 复位逻辑:
if rst_n = '0' then定义了复位条件。Basys 3板载一个CPU复位按钮(通常高电平有效),但我们的代码假设了一个低电平有效的复位信号。在实际约束中,我们需要将rst_n映射到那个按钮上,并根据其实际有效电平调整代码。这是一个常见的易错点。 - 分频逻辑:100MHz的时钟太快,人眼无法分辨LED的亮灭变化。我们通过一个26位计数器,每计数到2^25(约3350万)个时钟周期,才让
counter(25)变为1,从而触发LED状态切换,实现大约1.5Hz的闪烁频率。led_reg(2 downto 0) & led_reg(3)是VHDL中的连接操作符,实现了循环左移功能。 - 输出赋值:
leds <= led_reg;将内部寄存器的值持续输出到端口。
注意:写完代码后,可以先点击工具栏上的“Run Synthesis”(运行综合)进行初步的语法和基本逻辑检查。如果代码有语法错误,会在下方的“Messages”窗口中以红色错误(Error)形式显示。综合成功不代表设计功能正确,但能保证语法和基本结构无误。
3.2 创建并理解约束文件(XDC)
代码写好了,但Vivado还不知道clk、rst_n和leds这些信号应该连接到Basys 3板子的哪个物理引脚上。这就需要约束文件来定义。
- 添加或创建约束文件:如果创建项目时跳过了,可以在“Sources”窗口的“Constraints”目录上右键,选择“Add Sources” -> “Add or create constraints”。创建一个新文件,如
basys3.xdc。 - 编写引脚约束:打开
basys3.xdc,添加以下内容。这些引脚编号需要查阅Basys 3的官方原理图或用户手册。
# 时钟信号定义:连接到板载的100MHz时钟晶体(W5引脚) set_property PACKAGE_PIN W5 [get_ports clk] set_property IOSTANDARD LVCMOS33 [get_ports clk] create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk] # 复位信号定义:连接到板载的CPU复位按钮(T18引脚,高电平有效) # 注意:我们的代码中是低电平复位,因此这里需要取反,或者调整代码。这里先按代码映射。 set_property PACKAGE_PIN T18 [get_ports rst_n] set_property IOSTANDARD LVCMOS33 [get_ports rst_n] # LED输出定义:连接到板载的4个LED(U16, E19, U19, V19引脚) set_property PACKAGE_PIN U16 [get_ports {leds[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds[0]}] set_property PACKAGE_PIN E19 [get_ports {leds[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds[1]}] set_property PACKAGE_PIN U19 [get_ports {leds[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds[2]}] set_property PACKAGE_PIN V19 [get_ports {leds[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds[3]}]约束文件解析:
set_property PACKAGE_PIN <引脚号> [get_ports <端口名>]: 这是最关键的引脚位置约束,将设计中的端口绑定到FPGA芯片的具体物理引脚上。set_property IOSTANDARD LVCMOS33 [get_ports ...]: 设置端口的I/O电气标准。Basys 3的Bank电压是3.3V,所以选择LVCMOS33。create_clock ...: 创建时钟约束。-period 10.00表示时钟周期为10ns,即100MHz。这个约束对于时序分析至关重要,它告诉Vivado你的设计需要在这个频率下稳定工作。没有此时钟约束,Vivado将无法进行有效的时序优化和验证。
实操心得:引脚约束错误是导致下载后板子毫无反应的最常见原因。务必确保你使用的引脚编号与开发板手册完全一致。一个快速验证的方法是,下载Digilent官方提供的Basys 3主约束文件(Master XDC),里面包含了所有外设的引脚定义,你可以从中复制你需要的部分。
4. 综合、实现与比特流生成全流程
源代码和约束文件都准备好后,就进入了将逻辑描述转化为硬件配置文件的阶段。这个过程主要由三个步骤组成:综合(Synthesis)、实现(Implementation)和生成比特流(Generate Bitstream)。
4.1 运行综合(Synthesis)
综合是将你的VHDL/Verilog代码,翻译成由FPGA内部基本元件(如查找表LUT、触发器FF、块RAM等)组成的网表(Netlist)的过程。你可以点击左侧“Flow Navigator”中的“Run Synthesis”,或者直接点击工具栏上的橙色齿轮图标。
- 过程:Vivado会启动综合引擎,解析你的代码,进行逻辑优化,并映射到目标器件(xc7a35t)的可用资源上。你可以在下方的“Tcl Console”或“Log”窗口看到进度。
- 结果:综合完成后,会弹出一个对话框。建议选择“Run Implementation”(直接进入实现步骤)并点击OK。同时,综合报告会详细列出资源使用情况(LUT、FF、IO等)、时序预估等信息。对于我们的简单设计,资源使用率会非常低。
4.2 运行实现(Implementation)
实现是更底层的步骤,它包含三个子过程:
- 布局(Place):决定综合后的网表中的各个逻辑单元,具体放置在FPGA芯片的哪个物理位置上。
- 布线(Route):用芯片内部的可编程互连资源,将所有放置好的逻辑单元按照网表要求连接起来。
- 时序分析(Timing Analysis):验证布局布线后的设计,是否能在你约束的时钟频率(这里是100MHz)下稳定工作。
点击“Run Implementation”后,Vivado会自动执行上述过程。实现比综合更耗时。
- 关键结果查看:实现完成后,务必打开“Implementation”下的“Timing Report”。你会看到“Timing Summary”。这里需要关注一个核心指标:“WNS (Worst Negative Slack)”。
- 如果WNS >= 0(例如 0.123ns),恭喜你,你的设计满足了时序要求,可以在100MHz下稳定运行。
- 如果WNS < 0(例如 -0.456ns),这意味着设计存在时序违例,在最坏的路径上,信号比要求的时钟周期慢了0.456ns。这样的设计下载到板子上可能会工作不稳定。对于初学者的小设计,出现负松弛通常是因为时钟约束不对(比如实际时钟不是100MHz)或逻辑路径过于复杂(在我们的简单例子中几乎不可能)。
4.3 生成比特流文件(Generate Bitstream)
比特流文件(.bit)是前面所有步骤的最终产出,它是一个二进制文件,包含了配置FPGA内部所有可编程点(开关、查找表内容等)的信息。点击“Generate Bitstream”,Vivado会基于实现后的设计,生成这个文件。
在生成比特流之前,有一个非常重要的配置:
- 点击菜单栏的Tools -> Project Settings...。
- 在弹出窗口的左侧选择Bitstream。
- 在右侧,确保勾选了“-bin_file”选项。这样Vivado会同时生成
.bit文件(用于JTAG调试)和.bin文件(用于SPI Flash烧录)。 - 你还可以在这里进行其他设置,例如启用比特流压缩(
bitstream compression),这能减小文件大小,加快配置速度。对于Artix-7,可以将其设置为TRUE。
点击“Generate Bitstream”后,等待完成。生成的.bit和.bin文件位于项目目录下的project_name.runs/impl_1文件夹中,文件名通常与你的顶层设计名相同(如top.bit)。
5. 比特流文件下载至开发板的三种方式
生成比特流文件后,就可以将其配置到Basys 3开发板上了。Basys 3提供了三种主流的配置方式,各有适用场景。
5.1 JTAG方式:最常用的调试方式
JTAG是联合测试行动组的缩写,它是调试和编程FPGA最直接、最常用的接口。通过板载的USB-UART/JTAG桥接芯片(通常是FTDI或Cypress的芯片),你的电脑可以通过一根Micro-USB线同时为板子供电、进行JTAG编程和UART通信。
操作步骤:
- 硬件连接:用Micro-USB线连接Basys 3的“PROG/UART”口到电脑。确保板子上的电源跳线(如果存在)选择为“USB”供电。最关键的一步:找到板卡上的配置模式跳线
JP1,将其短接帽连接到JTAG位置(通常标记为“JTAG”的两根针)。 - 打开Vivado的“Hardware Manager”。如果之前没有打开,可以在左侧“Flow Navigator”最下方找到并点击“Open Hardware Manager”。
- 点击“Open target” -> “Auto Connect”。如果驱动安装正确,Vivado应该能自动识别到板卡,并显示器件型号(如
xc7a35t_0)。 - 右键识别到的器件,选择“Program Device...”。
- 在弹出的窗口中,点击“...”按钮,导航到
project_name.runs/impl_1目录,选择生成的.bit文件。 - 点击“Program”。编程过程很快,完成后你的设计会立即在FPGA上运行。此时你应该能看到Basys 3上的4个LED开始循环闪烁。
注意事项:JTAG配置是易失性的。一旦FPGA断电,配置信息就会丢失,下次上电需要重新编程。因此它非常适合在开发调试阶段反复修改和下载代码。
5.2 Quad SPI Flash方式:固化最终设计
如果你有一个已经调试完成、不需要经常改动的设计,希望板子上电后就能自动运行,那么就需要将比特流烧录到板载的SPI Flash非易失性存储器中。FPGA在上电时,会主动从SPI Flash中读取配置信息完成自我配置。
操作步骤:
- 切换跳线:将
JP1跳线切换到QSPI位置。 - 在“Hardware Manager”中连接板卡(同上)。
- 右键已连接的器件,这次选择“Add Configuration Memory Device...”。
- 在弹出的搜索框中,输入
spansion进行搜索。Basys 3通常使用“s25fl032p-spi-x1_x2_x4”这个型号。选中它并点击OK。 - 接下来会提示你是否立即编程该配置存储器,点击OK。
- 在下一个窗口中,需要选择配置文件。这里务必选择
.bin文件,而不是.bit文件。导航到你的.bin文件所在位置并选中它。 - 点击OK开始烧录。烧录SPI Flash比JTAG编程慢得多,可能需要几十秒。烧录完成后,Vivado会提示成功。
- 验证:给板子重新上电(或按一下板子的PROG按钮),你会发现即使没有连接USB线,没有打开Vivado,LED闪烁程序也会自动运行。这就是非易失性配置的魅力。
5.3 USB存储设备方式:便捷的演示模式
这是一种非常有趣的配置方式。Basys 3的FPGA芯片支持从USB端口读取比特流文件。你可以将一个FAT32格式的U盘,插入板子的USB HOST端口,FPGA上电时会自动读取U盘根目录下的.bit文件进行配置。
操作步骤:
- 切换跳线:将
JP1跳线切换到USB位置。 - 准备U盘:准备一个格式化为FAT32文件系统的U盘。注意:U盘根目录下最好只有一个
.bit文件,且文件名不宜过长过复杂,避免FPGA识别问题。可以将之前生成的top.bit文件复制到U盘根目录。 - 硬件连接:将准备好的U盘插入Basys 3的USB HOST接口(Type-A口)。同时,仍需通过Micro-USB线或外部电源为板子供电。
- 上电启动:给板子上电。板子上的“DONE”LED灯会闪烁,表示正在从U盘加载配置。加载完成后,程序开始运行。
实操心得:这种方式非常适合项目演示或展示。你可以准备多个存有不同功能
.bit文件的U盘,通过更换U盘来快速切换FPGA实现的不同功能,无需连接电脑。但需要注意的是,这种方式同样也是易失性的,断电后配置丢失,下次上电需要重新从U盘加载。
6. 常见问题排查与调试技巧实录
即使按照步骤操作,第一次尝试也难免会遇到问题。下面是我在多年教学中总结的初学者最常见的问题及其解决方法。
6.1 问题速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| Vivado无法识别板卡(Hardware Manager中无设备) | 1. USB线仅用于供电,无数据传输功能。 2. 电脑未安装USB驱动。 3. JP1跳线位置错误。 4. 板卡损坏(较罕见)。 | 1. 换一根数据线,确保能传输数据。 2. 连接板卡后,检查设备管理器。如有未知设备,需安装Digilent或Xilinx的USB驱动(Vivado安装包内通常包含)。 3. 确认JP1跳线在JTAG位置(用于编程识别)。 4. 尝试换一台电脑或USB端口。 |
| 编程失败,提示“Cannot program device”等错误 | 1. 比特流文件与目标器件不匹配。 2. 板卡正在被其他软件占用。 3. 电源不稳定。 | 1. 确认生成比特流时选择的目标器件是xc7a35tcpg236-1。2. 关闭可能占用JTAG口的其他软件(如旧版本的ISE、Diligent Adept等)。 3. 尝试使用外部电源适配器为板卡供电,而非仅靠USB供电。 |
| 下载成功后,板卡无任何现象(LED不亮) | 这是最高频的问题! 1.约束文件错误:引脚映射不对。 2.复位逻辑问题:复位信号有效电平与代码或物理连接不符。 3.时钟约束缺失或错误:未创建时钟约束或频率不对。 4.代码逻辑错误:例如分频计数器位宽不够,闪烁频率过快/过慢。 | 1.首要检查约束文件:逐字核对clk,rst_n,leds的引脚编号是否与Basys 3手册一致。2.检查复位:Basys 3的CPU复位按钮(RESET)是高电平有效。如果代码像本例一样是低电平复位,则需要一个反相器。更简单的做法是:在约束文件中将 rst_n映射到某个拨码开关上,下载后拨动开关来手动复位。3.检查时钟约束:确认 .xdc文件中create_clock的-period值是否正确(100MHz对应10ns)。4.仿真验证:在Vivado中为设计添加一个测试平台(Testbench),进行行为级仿真,看计数器 led_reg是否能按预期变化。 |
| 时序报告显示WNS为负值(时序违例) | 1. 时钟约束过于苛刻(周期设得太小)。 2. 设计中存在复杂的组合逻辑路径。 | 1. 对于Basys 3,确认时钟约束是否为10ns(100MHz)。如果写成了其他值,改正即可。 2. 对于这个简单的闪烁程序,几乎不可能违例。如果出现,很可能是约束错误。如果是在更复杂的设计中,需要优化代码结构或插入流水线寄存器。 |
| SPI Flash烧录成功,但重新上电后不运行 | 1. JP1跳线未切回QSPI模式(烧录后忘记改回)。 2. 烧录时选错了 .bin文件或存储器型号。3. SPI Flash芯片损坏。 | 1.烧录完成后,必须将JP1跳线改回QSPI模式,FPGA才能从上电开始从Flash读取配置。 2. 重新执行烧录步骤,仔细核对存储器件型号和选择的 .bin文件。3. 尝试用JTAG模式是否能正常编程和运行,以排除FPGA本身问题。 |
| USB方式配置失败 | 1. U盘不是FAT32格式。 2. .bit文件不在U盘根目录,或根目录下有多个.bit文件。3. JP1跳线不在USB模式。 4. USB口供电不足。 | 1. 将U盘格式化为FAT32。 2. 确保U盘根目录下只有一个目标 .bit文件。3. 确认JP1跳线在USB位置。 4. 尝试使用外部电源为板卡供电。 |
6.2 调试核心技巧:使用内部逻辑分析仪(ILA)
当你的设计没有按预期工作时,仅靠观察外部引脚(如LED)是远远不够的。你需要“看到”FPGA内部信号(如counter寄存器、led_reg寄存器)的真实波形。Vivado集成了强大的ILA(Integrated Logic Analyzer)核,可以像示波器一样捕获内部信号。
添加ILA核的简化流程:
- 在“Flow Navigator”中点击“IP Catalog”。
- 搜索“ILA”,双击“ILA (Integrated Logic Analyzer)”打开配置界面。
- 在“General Options”中,设置采样深度(如1024),这决定了能捕获多长时间的波形。
- 在“Probe Ports”中,添加你需要观察的信号。例如,将
counter的位宽设为26,将led_reg的位宽设为4。你可以添加多个探测端口。 - 点击OK,生成ILA核。Vivado会自动修改你的设计,将ILA核插入并连接到待测信号。
- 重新运行综合、实现和生成比特流。
- 用JTAG方式下载新的比特流文件。
- 在“Hardware Manager”中,你会发现除了FPGA设备,下面还多了一个ILA核。点击“Run Trigger”或“Single Shot”来捕获信号。
- 在波形窗口中,你就可以看到
counter是如何递增的,led_reg是如何在counter(25)变高时移位的。这能直观地帮你判断是分频逻辑错了,还是输出逻辑错了。
掌握ILA的使用,是FPGA调试从入门到精通的关键一步。它把黑盒变成了白盒,让你能真正理解硬件在每一个时钟周期内的行为。