55 KiB
| html | ||||||
|---|---|---|---|---|---|---|
|
版本信息
| 版本号 | 作者 | 修订原因 | 修订内容 | 日期 |
|---|---|---|---|---|
| v1.0 | 周爽 | 初始版本 | - | 2026.04.13 |
| v1.1 | 周爽 | 内容完善 | 1. 新增开发环境要求; 2. 修改 makefile; 3. 提供 Vivado 2024.2 + VCS 2018.09 虚拟机; |
2026.04.27 |
1. 引言
本文档具体描述了 ez-Q 2.5 测控电子学固件的设计、仿真、测试等方面的具体要求与实现方案,是固件设计人员进行固件功能开发、固件系统集成与测试等工作的依据。
2. 依据文件
| 序号 | 文件编号及文件名称 | 版本号 |
|---|---|---|
| 1 | ez-Q 2.5-RS-01_ez-Q 2.5 测控系统研制项目需求文档 | v1.2 |
| 2 | ez-Q 2.5-SDD-01_ez-Q 2.5 测控系统研制项目总体设计报告 | v1.0 |
| 3 | ez-Q 2.5-SDD-03_ez-Q 2.5 测控系统标准交互协议及控制服务接口设计 | v1.3 |
| 4 | ez-Q 2.5-TK-SDD-001 调控子系统设计报告 | v1.0 |
| 5 | ez-Q 2.5-RD-SDD-01_ez-Q 2.5 读出子系统总体设计 | v1.0 |
| 6 | ez-Q 2.5-CC-SDD-01_ez-Q 2.5 通信子系统设计报告 | v1.0 |
| 7 | ez-Q 2.5-FB-SDD-01_ez-Q 2.5 反馈子系统设计报告 | v0.2 |
| 8 | ez-Q 2.5-SDD-05_ez-Q 2.5 测控系统调控通道编程控制模型 | v0.3 |
| 9 | ez-Q 2.5-SDD-09_ez-Q 2.5 测控系统调控通道历史无关的配置功能项 | v0.3 |
| 10 | ez-Q 2.5-SDD-07_ez-Q 2.5 读出子系统编程控制模型 | v0.1 |
| 11 | ez-Q 2.5-SDD-08_ez-Q 2.5 读出子系统历史无关配置集 | v0.1 |
| 12 | ez-Q 2.5 子系统间通信协议 | v0.1 |
3. 定义、简写和缩略语
| 序号 | 名词/缩写 | 解释 |
|---|---|---|
| 1 | ez-Q 2.5 | CMOS测控系统的室温芯片板卡版本(ez-Q 2.0机箱框架) |
| 2 | FPGA | Field Programmable Gate Array,现场可编程逻辑门阵列 |
| 3 | DDR | Double Data Rate SDRAM,双倍速率同步动态随机存储器 |
| 4 | Flash | Flash Memory,非失性存储 |
| 5 | SFP | Small Form Pluggable,小型可插拔模块 |
| 6 | UDP | User Datagram Protocol,用户数据报协议 |
| 7 | TCP | Transmission Control Protocol,传输控制协议 |
| 8 | GT | Gigabit Transceiver,吉比特收发器 |
| 9 | TOE | Tcp Offload Engine,TCP卸载引擎 |
| 10 | IIC | Inter-Integrated Circuit,集成电路总线 |
| 11 | UART | Universal Asynchronous Receiver/Transmitter,通用异步收发器 |
| 12 | PL | Progarmmable Logic,可编程逻辑 |
| 13 | PS | Processing System,处理系统 |
| 14 | Aurora | 基于Serdes技术的Xilinx高速串行通信协议 |
| 15 | eMMC | embedded MultiMediaCard, 嵌入式多媒体卡 |
| 16 | EEPROM | Electrically Erasable Programmableread only memory,带电可擦可编程只读存储器 |
| 17 | LVDS | Low-Voltage Differential Signaling,低压差分信号 |
| 18 | PUMP | 泵浦信号,控制量子放大器的高频微波信号(>6GHz) |
| 19 | SMA | SubMiniature version A,一种常用的射频同轴连接器类型 |
4. 固件设计需求
本章节基于 ez-Q 2.5 测控电子学固件的任务背景和需求来源,提炼出各个子系统的固件设计需求。
4.1. 调控子系统固件需求
| 序号 | 功能 | 固件需求 |
|---|---|---|
| 1 | 与通信子系统通信 | 具备与通信子系统的Aurora高速通信功能,接口数据率 ≥ 6Gbps; |
| 2 | XY信号输出 | 具备对XY芯片的控制功能,通过SPI接口对XY芯片进行配置,实现XY信号的输出; |
| 3 | RESET信号输出 | 具备对RESET芯片的控制功能,通过SPI接口对RESET芯片进行配置,实现RESET信号的输出; |
| 4 | Qubit Z信号输出 | 具备对Z芯片的控制功能,通过SPI接口对Z芯片进行配置,实现Qubit Z信号的输出; |
| 5 | Coupler Z信号输出 | 具备对Z芯片的控制功能,通过SPI接口对Z芯片进行配置,实现Coupler Z信号的输出; |
| 6 | 温度监视 | 具备对调控板的温度信息收集功能; |
| 7 | 状态上报 | 具备关键业务信息监测、单板状态监测以及状态信息上报功能; |
| 8 | 掉电不易失存储功能 | 具备对非易失性存储的读写功能,实现参数管理与控制; |
| 9 | 大容量数据存储 | 具备通过DDR进行大容量数据存储的功能; |
| 10 | 固件注入重载功能 | 具备固件远程升级功能; |
4.2. 读出子系统固件需求
| 序号 | 功能 | 固件需求 |
|---|---|---|
| 1 | 与通信子系统通信 | 具备与通信子系统的Aurora高速通信功能,接口数据率 ≥ 6Gbps; |
| 2 | 读出激励信号输出 | 具备对RBPU芯片的控制功能,通过SPI接口对RBPU芯片进行配置,实现读出激励信号的输出; |
| 3 | 读出基带信号处理 | 具备对RBPU芯片采集数据的处理功能,通过LVDS接口接收RBPU芯片采集的数据,实现读出基带信号处理; |
| 4 | 全局反馈态传输和分发功能 | 具备对全局反馈态数据的的传输和分发功能,通过高速接口传输给反馈子系统,接口数据率 ≥ 10Gbps; |
| 5 | 温度监视 | 具备对读出板的温度信息收集功能; |
| 6 | 状态上报 | 具备关键业务信息监测、单板状态监测以及状态信息上报功能; |
| 7 | 掉电不易失存储功能 | 具备对非易失性存储的读写功能,实现参数管理与控制; |
| 8 | 大容量数据存储 | 具备通过DDR进行大容量数据存储的功能; |
| 9 | 固件注入重载功能 | 具备固件远程升级功能; |
4.3. 通信子系统固件需求
| 序号 | 功能 | 固件需求 |
|---|---|---|
| 1 | 与上位机通信 | 具备与上位机的万兆以太网通信功能,支持UDP协议与TCP协议; |
| 2 | 与调控板通信 | 具备与调控板Aurora高速通信功能,接口数据率 ≥ 6Gbps; |
| 3 | 与读出板通信 | 具备与读出板Aurora高速通信功能,接口数据率 ≥ 6Gbps; |
| 4 | PUMP通信控制功能 | 具备对PUMP板卡的控制功能,包括频率设置,功率设置,状态查询; |
| 5 | 混频通信控制功能 | 具备对混频板卡的控制功能,包括频率设置,衰减设置,状态查询; |
| 6 | 同步控制功能 | 具备同步信号的产生与分发功能; |
| 7 | 机箱控制功能 | 具备机箱风扇控制,机箱内板卡独立上下电功能; |
| 8 | 温度监视 | 具备对通信板的温度信息收集功能; |
| 9 | 状态上报 | 具备关键业务信息监测、单板状态监测以及状态信息上报功能; |
| 10 | 掉电不易失存储功能 | 具备对非易失性存储的读写功能,实现参数管理与控制; |
| 11 | 大容量数据存储 | 具备通过DDR进行大容量数据存储的功能; |
| 12 | 运维管理功能 | 具备运维管理功能,支持独立的运维管理通道; |
| 13 | 固件注入重载功能 | 具备固件远程升级功能; |
4.4. 反馈子系统固件需求
| 序号 | 功能 | 固件需求 |
|---|---|---|
| 1 | 与上位机通信 | 具备与上位机的万兆以太网通信功能,支持UDP协议与TCP协议; |
| 2 | 态汇聚功能 | 具备态信息汇聚功能,支持与读出板间的高速通信,接口数据率 ≥ 10Gbps; |
| 3 | 反馈命令分发功能 | 具备反馈命令分发功能,支持与读出板间的高速通信,接口数据率 ≥ 10Gbps; |
| 4 | 比特动态映射 | 具备在一个线路中动态切换任意比特映射表的功能; |
| 5 | 全局反馈总延迟 | 要求包括汇聚、处理和分发,含通信在内的传输时间不超过1us; |
| 6 | 温度监视 | 具备对反馈板的温度信息收集功能; |
| 7 | 状态上报 | 具备关键业务信息监测、单板状态监测以及状态信息上报功能; |
| 8 | 掉电不易失存储功能 | 具备对非易失性存储的读写功能,实现参数管理与控制; |
| 9 | 大容量数据存储 | 具备通过DDR进行大容量数据存储的功能; |
| 10 | 固件注入重载功能 | 具备固件远程升级功能; |
4.5. 易用性和可测试性需求
对于用户而言,机箱固件基本等同于黑盒,出现问题时很难通过远程访问对固件进行问题排查于定位。为提升固件系统的易用性和可测试性,从以下几方面入手:
- 固件内增加异常监控,对传输错误、解码错误等异常进行监测记录;
- 对关键状态机增加状态机活跃监测机制,状态机卡死时报告异常;
- 对关键状态机记录状态机跳转日志,便于排查状态机跳转是否正常;
- 反馈固件支持历史信息读取;
- 支持运行状态监控,定时上报状态信息;
- 支持远程复位,实现固件远程一键重启;
- 支持固件远程升级;
- 支持参数存储与加载。将部分配置参数提前写入板卡上的非易失性存储,上电时固件自动加载,减少配置操作。
提高易用性和可测试性的具体方案如下表所示。
| 序号 | 需求 | 设计方案 |
|---|---|---|
| 1 | 状态机活跃监测机制 | 检测状态机的状态停留时间,通过状态停留是否超时判断状态机是否卡死。状态机卡死时,将异常信息记录至固件寄存器,支持上位机远程读取异常信息; |
| 2 | 状态机跳转日志 | 记录状态机最近若干次的状态与对应的状态停留时间,作为状态机跳转日志,支持上位机远程读取该日志; |
| 3 | 反馈历史信息读取 | 在DDR中记录最近若干条的反馈信息,支持上位机远程读取该信息; |
| 4 | 状态监测与异常告警 | 固件内记录系统的各种状态信息与异常告警,并定期上报。需要记录的内容包括但不限于:链路状态、流量统计、数据错误统计、温度信息等; |
| 5 | 远程复位 | 固件内定义复位寄存器,上位机软件通过写入该寄存器来触发远程复位; |
| 6 | 固件远程升级 | 固件支持flash的读写控制;机箱系统支持并行升级; |
| 7 | 参数存储与加载 | 固件支持eMMC/EEPROM的读写控制,上电初始化阶段自动从eMMC/EEPROM读出配置参数。 |
4.6. 开发环境要求
逻辑开发环境:Vivado 2024.2; 逻辑仿真环境:QuestaSim, VCS; 嵌入式开发环境:Vitis 2024.2。
5. 仿真与测试要求
各子系统的固件要经过固件仿真、固件自测、系统测试等阶段,来排查固件设计中可能存在的问题,充分验证固件设计的正确性、可靠性。本章节从固件仿真和固件自测2个方面来具体描述。
5.1. 固件模块仿真要求
为验证固件功能、查找功能缺陷,需要对固件进行模块级仿真,并输出仿真报告。固件模块仿真需要包括功能验证与代码覆盖率分析两部分。
功能验证阶段,需要结合仿真波形分析模块的输入输出时序、内部关键信号、状态机跳转等是否与设计相符,以验证模块是否满足了设计要求。对于有性能需求的模块(如数据率、输入输出延迟等),需要结合仿真波形给出性能评估。
代码覆盖率分析包括行覆盖率、分支覆盖率、条件覆盖率、翻转覆盖率和FSM覆盖率等,它可以衡量验证工作是否充分全面,具体要求如下表所示。
| 序号 | 验证项 | 指标 | 仿真工具 |
|---|---|---|---|
| 1 | 行覆盖率 | ≥ 95% | VCS、QuestaSim 等 |
| 2 | 分支覆盖率 | ≥ 90% | VCS、QuestaSim 等 |
| 3 | 条件覆盖率 | ≥ 90% | VCS、QuestaSim 等 |
| 4 | 翻转覆盖率 | ≥ 90% | VCS、QuestaSim 等 |
| 5 | FSM覆盖率 | ≥ 90% | VCS、QuestaSim 等 |
5.2. 固件自测试要求
完成固件模块仿真后,对固件进行板卡级自测试,并输出固件自测试报告,固件需保证如下功能正常:
- 通信接口基础测试:
- 完成与系统联调相关的所有通信接口(如:SPI、网络接口、自定义数据链路等)的初始化、配置与基础连通性测试;
- 接口应能稳定地发送和接收测试数据帧,并验证数据的基本完整性与正确性;
- 硬件基础自检:
- 完成对关键硬件资源的初始化与功能性检查;
- 验证电源、时钟源、关键存储器(如RAM, Flash, eMMC, EEPROM)的基本读写功能与完整性;
- 核心功能模块自验证:
- 完成对固件内部核心功能模块(如:数据处理流水线、控制算法、关键状态机、中断服务程序等)的基础功能测试;
- 测试应覆盖模块的主要输入输出路径和处理逻辑,使用模拟输入、预设模式或内部激励源进行验证;
- 模块输出结果需符合预期设计规格,或在预设容差范围内。关键模块需报告其自检状态(通过/失败);
- 异常处理与容错能力:
- 错误检测与恢复机制:验证固件中实现的错误检测机制能够准确识别异常情况,并采取适当的措施进行恢复或报告;
- 边界条件测试:对所有输入参数和操作条件执行边界值分析,确保固件能够在极端条件下稳定运行。
6. 文档输出要求
固件设计人员需输出 《固件设计文档》、《固件IDS表》、《固件仿真报告》和《固件调试报告》 作为后续验收的内容。
7. 固件功能实现方案
本章节对部分固件功能给出实现方案,供固件设计人员参考。
7.1. 状态机监测机制
对于关键路径的状态机(如 Transaction 的收发与解析)加入活跃监测与日志记录机制,便于故障定位。状态机监测机制具体包括:
- 通过计时器记录状态机在各个状态停留的时间;
- 根据状态机设计给出各个状态的超时标准;如果超时,输出异常指示,记录至寄存器,也可将必要的异常信息记录至寄存器,这些寄存器支持从上位机读取;例如,Transaction 解析的状态机出现异常,将 Transaction 的 64-bit 头部作为异常信息记录至寄存器;
- 通信链路上的状态机(如 Aurora 通信)出现超时异常时,固件需要对状态机进行复位,保证异常出现时上位机仍然可以访问固件寄存器;
- 将状态机在各个状态停留的时间和状态跳转记录作为日志记录到寄存器,支持从上位机读取;每条日志 32-bit,其中 [31:24] 为状态,[23:0] 为状态停留时间;日志条数可根据状态数量调整,不少于状态数量的两倍;状态机日志格式如下表所示。
| 序号 | [31:24] | [23:0] |
|---|---|---|
| 1 | 当前状态 | 停留时间 |
| 2 | 上次状态 | 停留时间 |
| 3 | 上上次状态 | 停留时间 |
| 4 | ... | ... |
7.2. 固件远程更新
支持固件远程更新的板卡包括通信板、反馈板、调控板和读出板,通过远程控制 FPGA 给 flash 写入 Bin 数据的方式实现固件更新。
7.2.1. 工作流程
固件更新流程由上位机发起,如图7.1所示,主要包括3个步骤:
- (1)上位机通过 TCP 发送 Bin 数据至通信板(通信板、调控板和读出板的 Bin)和反馈板(反馈板的 Bin);通信板将调控板和读出板的 Bin 数据转发至对应的板卡;
- (1.1)对于通信板和反馈板,PL 将接收到的 Bin 数据缓存到 PL 侧的 DDR 中;对于调控板和读出板,FPGA 将接收到的 Bin 数据缓存到 DDR 中;
- (2)完成 Bin 数据发送后,上位机在指定的固件寄存器(具体查看固件 IDS 表)处写入固件更新指令;
- (2.1)固件接收到固件更新指令后;对于通信板和反馈板,PL 将 Bin 数据从 DDR 中读出;对于调控板和读出板,FPGA 将 Bin 数据从 DDR 中读出;
- (2.2)对于通信板和反馈板,PL 将 Bin 数据发送给 PS;
- (2.3)对于通信板和反馈板,PS 将 Bin 数据写入 flash;对于调控板和读出板,FPGA 将 Bin 数据写入 flash;
- (3)上位机通过读取固件寄存器来获取固件更新状态;
图7.1. 固件更新流程
7.2.2. 数据格式
固件更新流程中的各个步骤都采用 Transaction 协议,根据 Transaction 协议中的扩展地址(EXADDR 字段)和固件更新指令来区分当前 Transaction 是否为固件更新数据。Transaction 为固件更新的 Bin 数据时,EXADDR的低3比特为 0b111。固件更新时,默认 flash 数据是从地址0开始的,固件不关心 Transaction 中的 ADDR 字段。
Bin 文件大小一般超过10MB,超过了1个 Transaction 的最大长度,上位机需要根据实际情况将1个 Bin 文件拆分为多个 Transaction;拆分出来的多个 Transaction 要按照先低地址后高地址的顺序依次发送。如图7.2.所示,一个 Bin 文件被拆分为两个 Transaction,先发低地址数据,再发高地址数据,相邻两个 Transaction 的 Bin 数据是连续的;Transaction 是以 32-bit 为单位的,在1个 32-bit 中,高地址在高位,低地址在低位;对于 Bin 数据不是 32-bit 整数倍的情况,在最后一个 32-bit 中,有效数据从低位开始排放,剩余位置填充任意数据。
图7.2. Bin 数据传输格式
7.2.3. 固件更新指令
固件更新指令对应为固件的3个寄存器 Bin_Update1、Bin_Update2和Bin_Update3。
寄存器 Bin_Update1 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31] | EXEC | 1 | 执行固件更新标志位。上位机将此bit置1,开始固件更新;固件完成更新后将此bit置0 | 0x0 |
| [30] | SUCC | 1 | 更新成功标志位。固件更新成功后,固件将此bit置1 | 0x0 |
| [29] | FAIL | 1 | 更新失败标志位。固件更新失败后,固件将此bit置1 | 0x0 |
| [28:0] | RSV | 29 | RSV | 0x00000000 |
寄存器 Bin_Update2 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31:0] | LENGTH | 32 | Bin 数据长度,单位 Byte | 0x00000000 |
寄存器 Bin_Update3 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31:0] | FINISHED_BYTES | 32 | 固件已写入 flash 的数据量,单位 Byte | 0x00000000 |
上位机发送固件更新指令时,先将 Bin 数据长度写入 Bin_Update2,再给 Bin_Update1 写入0x80000000。
固件接收到固件更新指令后,检测到 EXEC 为1,进入固件更新流程,根据 LENGTH 将 Bin 数据写入 flash,并将 Bin_Update3 清零。flash 写入过程中,固件将已写入的数据量更新到 Bin_Update3 中,上位机通过该寄存器来获取更新进度。完成 flash 更新后,固件根据更新结果将 SUCC 或 FAIL 置1,将 EXEC 置0。
7.3. eMMC/EEPROM 读写
eMMC/EEPROM 用于存储板卡配置参数,通信板和反馈板使用 eMMC,调控板和读出板使用 EEPROM。eMMC 支持最大 4GB 存储空间,EEPROM 支持最大 8kB 存储空间。eMMC/EEPROM 的读写最小单位为页,eMMC 一页为512 Bytes,EEPROM 一页为32 Bytes。
7.3.1. 工作流程
eMMC/EEPROM 的写入流程如图7.3.所示,主要包括3个步骤:
- (1)上位机通过 TCP 将待写入 eMMC/EEPROM 的数据发送至通信板(通信板、调控板和读出板的数据)和反馈板(反馈板的数据);通信板将调控板和读出板的数据转发至对应的板卡;
- (1.1)对于通信板和反馈板,PL 将接收到的数据缓存到 PL 侧的 DDR 中;对于调控板和读出板,FPGA 将接收到的数据缓存到 DDR 中;
- (2)完成数据发送后,上位机在指定的固件寄存器(具体查看固件 IDS 表)处写入 eMMC/EEPROM 写入指令;
- (2.1)固件接收到 eMMC/EEPROM 写入指令后;对于通信板和反馈板,PL 将数据从 DDR 中读出;对于调控板和读出板,FPGA 将数据从 DDR 中读出;
- (2.2)对于通信板和反馈板,PL 将数据发送给 PS;
- (2.3)对于通信板和反馈板,PS 将数据写入 eMMC;对于调控板和读出板,FPGA 将数据写入 EEPROM;
- (3)上位机通过读取固件寄存器来获取 eMMC/EEPROM 的写入结果;
图7.3. eMMC/EEPROM 写入流程
eMMC/EEPROM 的读取流程,如图7.4.所示,主要包括3个步骤:
- (1)上位机在指定的固件寄存器(具体查看固件 IDS 表)处写入 eMMC/EEPROM 读取指令;
- (1.1)对于通信板和反馈板,PL 将读取指令信息传递给 PS;
- (2)固件根据 eMMC/EEPROM 读取指令读取对应 eMMC/EEPROM 空间的数据,根据 Transaction 协议完成数据封装;
- (2.1)对于通信板和反馈板,由 PS 发起 eMMC 读取流程;对于调控板和读出板,由 FPGA 发起 EEPROM 读取流程;
- (3)固件将读取的 eMMC/EEPROM 数据发送至上位机,上位机通过通信板接收通信板、调控板和读出板的 eMMC/EEPROM 数据,通过反馈板接收反馈板的 eMMC 数据;
图7.4. eMMC/EEPROM 读取流程
7.3.2. 数据格式
Transaction 为 eMMC/EEPROM 数据时,EXADDR的低3比特为0b111。
7.3.2.1. eMMC 数据格式
eMMC 可以存储寄存器和 Transaction 两种格式的数据,寄存器数据用于配置通信板/反馈板的本地寄存器(例如 IP 地址),Transaction 数据用于通信板配置机箱内的其他板卡(例如通道延迟)。
寄存器数据以“寄存器数据+寄存器地址”的格式存储,从页起始开始顺序存储;有效数据结束后,紧接着是 CRC32 校验值,如图7.5.所示。
图7.5. eMMC 寄存器数据格式
Transaction 数据按照 Transaction 格式完整存入 eMMC,从页起始开始顺序存储;有效数据结束后,紧接着是 CRC32 校验值,如图7.6.所示。
图7.6. eMMC Transaction 数据格式
eMMC 的第0页用于 eMMC 识别和指示有效配置的起始地址和数据长度,如图7.7.所示。第0页的前 32-bit 为版本号(VID);接下来的 32-bit 为第0页有效数据长度(单位为字节,不包括 VID、PAGE_0_LENGTH 和 CRC32);后续内容为配置起始地址和配置数据长度(不包括 CRC32),单位为字节,配置起始地址在低地址,配置数据长度在高地址,配置起始地址要求按页(512 Bytes)对齐;有效数据结束后,紧接着是 CRC32 校验值(从页起始开始计算,直至有效数据结束)。
对于通信板,eMMC 的第0页保存了通信板、调控板、读出板、混频板、泵浦板的配置数据起始地址和配置数据长度;对于没有配置数据的板卡,对应的配置数据长度写为 0x0000_0000。
图7.7. eMMC 第0页数据格式
7.3.2.2. EEPROM 数据格式
EEPROM 中以 Transaction 格式存储数据,其内容为板卡配置参数(如通道衰减、DAC 配置等)。EEPROM 的第0页前 32-bit 为版本号(VID);接下来的 32-bit 为配置数据长度(单位为字节,不包括 VID、DATA_LENGTH 和 CRC32);后续内容为 Transaction;有效数据结束后,紧接着是 CRC32 校验值(计算 VID、DATA_LENGTH 和 Transaction 得到)。如图7.8.所示。
图7.8. EEPROM 数据格式
7.3.3. eMMC/EEPROM 读写指令
eMMC/EEPROM 读写指令对应为固件的3个寄存器 Param_Update1、Param_Update2和Param_Update3。
寄存器 Param_Update1 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31] | EXEC | 1 | eMMC/EEPROM 执行标志位,上位机发起读写操作时将此bit置1,固件完成读写操作后将此bit置0 | 0x0 |
| [30] | SUCC | 1 | eMMC/EEPROM 操作成功标志位,读写成功后,固件将此bit置1 | 0x0 |
| [29] | FAIL | 1 | eMMC/EEPROM 操作失败标志位,读写失败后,固件将此bit置1 | 0x0 |
| [28] | W/R | 1 | eMMC/EEPROM 读写标志位;0:W;1:R | 0x0 |
| [27:0] | RSV | 28 | RSV | 0x0000000 |
寄存器 Param_Update2 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31:0] | LENGTH | 32 | eMMC/EEPROM 数据长度,单位为字节 | 0x00000000 |
寄存器 Param_Update3 的具体定义如下:
| 比特序 | 数据结构 | 长度 / bit | 描述 | 默认值 |
|---|---|---|---|---|
| [31:0] | ADDR | 32 | eMMC/EEPROM 数据起始地址,单位为字节 | 0x00000000 |
上位机发送 eMMC/EEPROM 读写指令时,先将数据长度和起始地址写入 Param_Update2 和 Param_Update3,再给 Param_Update1 写入 0x80000000(写)或 0x90000000(读)。
对于 eMMC,要求 LENGTH 和 ADDR 都按照512 Bytes对齐;对于 EEPROM,要求 LENGTH 和 ADDR 都按照32 Bytes对齐。
7.4. 系统初始化
ez-Q 2.5机箱的初始化流程分为板卡自身初始化和机箱初始化两部分;板卡自身初始化时,各个板卡通过读取各自的板上非易失性存储设备(eMMC/EEPROM)获取初始化配置;机箱初始化时,通信板从 eMMC 中读取初始化配置,发送给各个板卡(调控板、读出板、混频板和泵浦板)。具体的初始化流程如图7.9.所示。
图7.9. 初始化流程
- 机箱上电,通信板上电;
- 通信板自动进入初始化流程,读取eMMC中的通信板配置,并完成各项配置;
- 通信板初始化成功后,上位机与通信板建立网络连接,并读取通信板的初始化状态寄存器,确认通信板初始化完成;
- 根据实验需求和板卡安装情况,通过通信板对机箱内其他板块卡上电;
- 上电后,各个板卡自动进入初始化流程。反馈板从 eMMC 中读取数据,并完成初始化配置;调控板和读出板从 EEPROM 中读取数据,并完成初始化配置;
- 上位机查询各个板卡(不包括通信板)的初始化状态寄存器,确认所有板卡初始化完成;
- 上位机向通信板发送机箱初始化指令(写寄存器),通信板开始机箱初始化流程;
- 通信板从从 eMMC 中依次读取各个板卡的配置参数,并发送到对应的板卡,完成板卡配置;
- 上位机查询通信板的初始化状态寄存器,确认机箱初始化完成;
- 初始化成功。
基于以上初始化流程,调控板、读出板、通信板和反馈板要求具备初始化状态寄存器,供上位机查询板卡初始化状态;通信板还要求具备初始化指令寄存器,供上位机发起机箱初始化。
7.5. 状态监控
通信板、反馈板、调控板和读出板的固件寄存器定义中包含有状态寄存器,状态寄存器可以提供版本号(逻辑版本、嵌入式版本等)、运行时间、温度等信息,每个寄存器大小为32比特。上位机通过获取这些状态寄存器的数据实现状态监控。
7.5.1. 工作流程
状态监控的工作流程如图7.100所示,分为3个步骤。
- (1)通信板固件周期性(例如每秒1次)生成状态监控命令,并发送给通信板内部的状态监控模块、调控板和读出板;对于调控板和读出板,状态监控命令即为读取状态寄存器的 Transaction;
- (2)各板卡或模块接收到状态监控命令后,根据命令读取对应的寄存器,并将状态数据发送到通信板的状态上传模块;
- (3)通信板的状态上传模块接收到状态数据后,通过 UDP 将状态数据广播给上位机,上位机通过固件寄存器表来解析状态信息;
反馈板的状态监控流程和通信板基本一致,反馈板仅与上位机通信,没有与其他板卡通信的步骤。
图7.10. 状态监控流程
7.5.2. 数据协议
通信板和反馈板通过 UDP 与上位机通信,对 UDP 的内容进行了进一步的帧封装。通信板和反馈板通过网段内广播的方式将状态数据上报给上位机,例如定期向192.168.0.255发送状态数据。整个机箱系统的状态数据量较大,可能会分成多个帧广播发送。
UDP 帧数据格式定义如下:
| 序号 | 数据结构 | 长度 | 比特序 | 功能描述 |
|---|---|---|---|---|
| 1 | HEADER | 16 bits | [31:16] | 0x4547,TOE 寄存器; 0x494e,状态监控; 0x4d44,控制命令; |
| ^ | LENGTH | 16 bits | [15:0] | PAYLOAD 字段的长度,单位为 byte |
| 2 | PAYLOAD | N*4 bytes | [31:0] | 负载数据,长度为 32-bit 的整数倍 |
| 3 | CHECK | 32 bits | [31:0] | CRC32 校验,计算 PAYLOAD 字段的 CRC32 |
TOE 寄存器数据(0x4547)用于配置固件的 TOE 寄存器,PAYLOAD 里包含一条或多条完整的 Transaction,一个 Transaction 不会被拆分到多个 PAYLOAD 中。
状态监控数据(0x494e)由通信板和反馈板主动广播,PAYLOAD 里包含一条或多条完整的 Transaction,一个 Transaction 不会被拆分到多个 PAYLOAD 中。
控制命令(0x4d44)是预留的 UDP 控制接口,目前定义:PAYLOAD 为 0x10000001 时,固件开启状态监控;PAYLOAD 为 0x10000000 时,固件关闭状态监控。
7.5.3. 地址定义
固件根据 Transaction 协议中的扩展地址(EXADDR 字段)来区分当前 Transaction 是否为固件寄存器。EXADDR 的低3比特为0b000 时,Transaction 访问固件寄存器,Transaction 的 ADDR 字段为固件寄存器地址。同时,为便于通信板区分上位机通过 TCP 主动读写固件寄存器和 UDP 广播状态数据,使用 EXADDR[8] 作为标志位。
| 序号 | EXADDR[8] | EXADDR[2:0] | 描述 |
|---|---|---|---|
| 1 | 1'b0 | 3'b000 | 状态监控数据,通过 UDP 广播 |
| 2 | 1'b1 | 3'b000 | 上位机读写固件寄存器数据,通过 TCP 传输 |
8. 辅助工具
8.1. Vivado + QuestaSim 联合仿真
操作系统:Windows, Linux;
以 Windows 系统下的仿真为例,以下操作使用的是 Vivado 2025.2 和 QuestaSim 2024.1。
8.1.1. 编译仿真库
在 Vivado 界面点击 Tools -> Compile Simulation Libraries...,弹出对话框,如图8.1.所示。
图8.1. 编译仿真库
Simulator:选择 Questasim Advanced Simulator; Compiled library location:设置编译后仿真库的保存路径; Simulator executable path:设置仿真器路径,即 vlog.exe 所在文件夹的路径。
使用以下 tcl 命令也可以完成仿真库的编译:
compile_simlib -simulator questa -simulator_exec_path {仿真器路径} -family all -language all -library all -dir {仿真库保存路径}
8.1.2. 仿真
有多种方式可以完成 Vivado + QuestaSim 的联合仿真,这里介绍 Vivado 界面调用 QuestaSim 和 tcl 脚本两种方式。对于不需要频繁修改仿真参数的使用情况,通过 Vivado 界面调用 QuestaSim 使用起来更简单;使用 tcl 脚本的方式则是功能更全面,且没有兼容性问题。
8.1.2.1. Vivado 界面调用 QuestaSim 仿真
8.1.2.1.1. 第三方仿真器设置
在 Vivado 界面点击 Settings -> 3rd Party Simulators,完成 QuestaSim 相关设置,如图8.2.所示。
图8.2. Vivado 设置第三方仿真器
Install Paths -> QuestaSim:QuestaSim 的安装路径,即 vlog.exe 所在文件夹的路径; Default Compiled Library Paths -> Questa:编译后仿真库的保存路径。
8.1.2.1.2. Vivado仿真设置
在 Vivado 界面点击 Settings -> Simulation,将目标仿真器设置为 Questa Advanced Simulator,如图8.3.所示。
图8.3. Vivado 仿真设置
Target simulator:设置为 Questa Advanced Simulator; Compiled library location:设置编译后仿真库的保存路径。
8.1.2.1.3. 代码覆盖率设置
在 Settings -> Simulation -> Compilation -> questa.compile.vlog.more_options 处填入参数 “-cover bcfst”,在 Settings -> Simulation -> Simulation -> questa.simulate.vsim.more_options 处填入参数 “-coverage”,如图8.4.所示。
图8.4. QuestaSim 覆盖率设置
QuestaSim 支持6种代码覆盖率,可根据需求设置配置参数:
- b:分支覆盖率 (Branch)
- c:条件覆盖率 (Condition)
- e:表达式覆盖率 (Expression)
- f:有限状态机覆盖率 (FSM)
- t:信号翻转覆盖率 (Toggle)
- s:语句/行覆盖率 (Statement)
8.1.2.1.4. 运行仿真
完成前面的设置后,在 Vivado 中 Run Simulation 就会调用 QuestaSim 进行仿真。设置仿真时间,运行仿真,即可查看仿真结果,如图8.5.所示。
图8.5. QuestaSim 界面运行仿真
8.1.2.1.5. 生成覆盖率报告
在 QuestaSim 界面点击 Tools -> Coverage Report -> HTML ... 生成 html 格式的覆盖率报告,如图8.6.所示。生成的 html 报告保存在 Vivado 工程的仿真目录下,名为 covhtmlreport 的文件夹。
图8.6. QuestaSim 生成覆盖率报告
8.1.2.2 tcl 脚本仿真
使用 tcl 脚本进行仿真需要 filelist 和 run.tcl 文件,新建一个 QuestaSim 仿真的工程目录,并创建这些文件(文件名可修改)。
8.1.2.2.1. 更新配置文件
完成仿真库的编译后,在仿真库的文件下会有一个 modelsim.ini 文件,以文本形式打开此文件。在文件中的 [Library] 部分,定义了库映射,如图8.7.所示,复制库映射的内容。
图8.7. 配置文件
在 QuestaSim 的安装目录下(例如 C:\questasim64_2024.1),也有一个 modelsim.ini 文件,将复制的内容粘贴到此文件的 [Library] 部分。
QuestaSim 正确识别配置文件后,可以在软件的 Library 窗口看到添加的仿真库,如图8.8.所示。
图8.8. QestaSim 的 Library 窗口
8.1.2.2.2. filelist
filelist 文件中记录了仿真所需的所有源文件的路径,文件中必须要包括以下文件路径:
- glbl.v,这是 Xilinx 官方的初始化模块,位于 Vivado 的安装目录下;
- 工程源码,需要被仿真的所有工程源码。如果使用了 Xilinx 的 IP,需要将 IP 相关的仿真文件也加入 filelist。
可以在 Vivado 中使用以下 tcl 命令获取仿真文件的路径:
get_files -compile_order sources -used_in simulation
下面是一个 filelist.f 的示例:
C:/AMDDesignTools/2025.2/Vivado/data/verilog/src/glbl.v
D:/Xilinx_Projects/Vivado_Projects/questasim_exp/project_1/project_1.srcs/sources_1/new/top.v
D:/Xilinx_Projects/Vivado_Projects/questasim_exp/project_1/project_1.srcs/sim_1/new/tb_top.v
如果需要进行 Verilog 和 VHDL 的混合仿真,建议将两种文件的路径分别保存到两个 filelist 中(如 filelist_vlog.f 和 filelist_vhdl.f)。
8.1.2.2.3. tcl 脚本
tcl 脚本通过读取 filelist 来获取仿真文件的路径,执行 vlib、vlog、vsim、run 等指令完成仿真。下面是一个 run.tcl 的示例:
# ================== set top module
if {$argc >= 1} {
set TB_TOP $1
} else {
set TB_TOP "tb_top"
}
# ================== create lib
if {[file exists work]} {
file delete -force work
}
vlib work
# ================== compile
if {[file exists "filelist_vhdl.f"]} {
vcom -2008 -f filelist_vhdl.f
}
vlog -sv +acc -cover bcfst -f filelist_vlog.f
# ================== simulation
vsim -coverage -voptargs=+acc -L xpm -L unisim -L unimacro -L simprims_ver -L secureip -onfinish stop work.$TB_TOP work.glbl
add wave -r /*
run -all
# ================== generate coverage report
coverage save cov.ucdb
coverage report -html -output covhtmlreport -annotate -assert -code bcfst -verbose
这个 tcl 脚本从 filelist_vlog.f 中获取 verilog 文件路径,从 filelist_vhdl.f 中获取 VHDL 文件路径(非必须);默认的仿真顶层模块名为 tb_top,支持通过输入参数来更换顶层模块;该 tcl 脚本会保存覆盖率数据,并生成 html 报告,报告保存在 QuestaSim 工程目录下的 covhtmlreport 文件夹。
8.1.2.2.4. 运行仿真
在 QuestaSim 的 Transcript 窗口执行指令来运行仿真:
- 切换到 QuestaSim 工程目录,例如:
cd d:/QuestaSim_Porjects/exp2 - 运行 tcl 脚本,例如:
do run.tcl。如果需要更换仿真顶层模块,例如修改为 tb_top_sim,输入:do run.tcl tb_top_sim
tcl 脚本运行完成后,即可在 QuestaSim 界面查看仿真结果。
8.1.3. 查看仿真结果
QestaSim 的仿真波形窗口如图8.9.所示。
图8.9. QestaSim 的波形窗口
QuetsaSim 的覆盖率窗口如图8.10.所示,在窗口右上角切换覆盖率类型。
图8.10. QestaSim 的覆盖率窗口
在 html 报告的文件夹中,打开 index.html 也可以查看覆盖率详情,如图8.11.所示。
图8.11. QestaSim 的覆盖率报告
Visualizer 是 QuestaSim 的一个高级调试工具包,具有波形查看、代码覆盖分析、有限状态机调试等功能。在 Visualizer 的 Transcript 窗口使用 visualizer -viewcov指令查看覆盖率,例如:
visualizer -viewcov D:/QuestaSim_Porjects/exp2/cov.ucdb
*.ucdb 文件是仿真时保存的覆盖率数据,Visualizer 的覆盖率界面如图8.12.所示。
图8.12. visualizer 的覆盖率界面
8.2. Vivado + VCS 联合仿真
操作系统:Linux;
以下操作使用的是 Vivado 2019.2,VCS 2018.09 SP2 和 Verdi 2018.09 SP2。
8.2.1. 编译仿真库
在 Vivado 界面点击 Tools -> Compile Simulation Libraries...,弹出对话框,如图8.13.所示。
图8.13. 编译仿真库
Simulator:选择 Verilog Complier Simulator; Compiled library location:设置编译后仿真库的保存路径; Simulator executable path:设置仿真器路径。
使用以下 tcl 命令也可以完成仿真库的编译:
compile_simlib -simulator vcs -simulator_exec_path {仿真器路径} -family all -language all -library all -dir {仿真库保存路径}
完成编译后,在仿真库保存路径下可以看到各个 IP 的仿真库,以及一个 synopsys_sim.setup 文件。
8.2.2. 仿真
仿真需要 filelist、makefile 和 synopsys_sim.setup 文件,新建一个 VCS 仿真的工程目录,并创建这些文件。
8.2.2.1 链接仿真库
在 VCS 仿真工程目录下新建 synopsys_sim.setup 文件,文件内容如下:
WORK > DEFAULT
DEFAULT : ./work
OTHERS = /data/work/yxu/Vivado_2025d2_SimLib_VCS/synopsys_sim.setup
OTHERS 后面的文件路径就是仿真库保存路径下的 synopsys_sim.setup 文件路径。VCS 仿真时会调用这个文件来链接所有的器件库。
8.2.2.2 Testbench
在 Testbench 中需要添加以下内容,用于 dump fsdb 波形和 mem 等(将 xxx.fsdb 替换为想要的文件名)以及初始化:
glbl u_glbl();
initial begin
$fsdbDumpfile("xxx.fsdb");
$fsdbDumpvars();
end
8.2.2.3 filelist
filelist 文件中记录了仿真所需的所有源文件的路径,文件中必须要包括以下文件路径:
- glbl.v,这是 Xilinx 官方的初始化模块,位于 Vivado 的安装目录下;
- 工程源码,需要被仿真的所有工程源码。如果使用了 Xilinx 的 IP,需要将 IP 相关的仿真文件也加入 filelist。
可以在 Vivado 中使用以下 tcl 命令获取仿真文件的路径:
get_files -compile_order sources -used_in simulation
下面是一个 filelist.f 的示例:
/opt/xilinx/Vivado/2019.2/data/verilog/src/glbl.v
/data/work/yxu/Vivado_space/vcs_sim_prj/project_1/project_1.srcs/sources_1/new/top.v
/data/work/yxu/Vivado_space/vcs_sim_prj/project_1/project_1.srcs/sim_1/new/tb_top.v
如果需要进行 Verilog 和 VHDL 的混合仿真,建议将两种文件的路径分别保存到两个 filelist 中(如 filelist_vlog.f 和 filelist_vhdl.f)。
8.2.2.4. makefile
makefile 通过读取 filelist 来获取仿真文件的路径,执行 vlogan、vhdlan、vcs 等指令完成仿真。下面是一个 makefile 的示例:
# ========= Tool =========
VCS = vcs
VLOGAN = vlogan
VHDLAN = vhdlan
# ========= Top =========
TOP ?= tb_top
TB_TOP = $(TOP)
# ========= Filelists =========
VLOG_FILELIST = filelist_vlog.f
VHDL_FILELIST = filelist_vhdl.f
# ========= Compile Options =========
VLOGAN_OPTS = -full64 -sverilog +v2k +lint=TFIPC-L
VHDLAN_OPTS = -full64
# ========= Link Options =========
VCS_OPTS = -full64 -Mupdate -j8 -lca -q \
-timescale=1ns/1ps \
-debug_access+pp \
+nospecify \
-cm line+cond+fsm+tgl+branch \
-cm_dir ./coverage/simv.vdb
# ========= Simulation =========
SIMV = ./simv
SIMV_OPTS = sync:busywait -Xdprof=timeline \
-cm line+cond+fsm+tgl+branch \
-cm_dir ./coverage/simv.vdb
# ========= Targets =========
all: comp run
comp:
@mkdir -p work
@if [ -f $(VHDL_FILELIST) ]; then \
$(VHDLAN) $(VHDLAN_OPTS) -f $(VHDL_FILELIST); \
fi
$(VLOGAN) $(VLOGAN_OPTS) -f $(VLOG_FILELIST)
$(VCS) $(VCS_OPTS) -top $(TB_TOP) -l compile.log
run:
$(SIMV) $(SIMV_OPTS)
dbg:
verdi -sverilog -f $(VLOG_FILELIST) $(FILES) -top $(TB_TOP) -ssf *.fsdb -nologo &
clean:
rm -rf DVE* simv* *log ucli.key verdiLog urgReport csrc novas.* \
*fsdb* *.dat *.daidir *.vdb *~ partitionlib/ dprof.dir/ \
dprof.txt \
cov:
verdi -cov -covdir coverage/merged.vdb &
cov_d:
dve -full64 -covdir coverage/*.vdb &
merge:
urg -full64 -dbname coverage/merged.vdb -flex_merge union -dir coverage/simv.vdb -parallel -maxjobs 64&
merge_i:
urg -full64 -flex_merge union -dir coverage/merged.vdb -dir coverage/mem_test.vdb -dbname coverage/merged.vdb -parallel -maxjobs 64&
这个 makefile 从 filelist_vlog.f 中获取 verilog 文件路径,从 filelist_vhdl.f 中获取 VHDL 文件路径(非必须);默认的仿真顶层模块名为 tb_top,支持通过输入参数来更换顶层模块。
将 makefile 从 Windows 系统复制到 Linux 系统时,可能会出现语法错误。原因是 makefile 语法要求命令行必须以 Tab 开头,不同系统下 Tab 占用的空格数量可能不同,通过 vim 或 gvim 编辑 makefile,把命令行开头的空格改为 Tab 即可。
8.2.2.5. 运行仿真
输入:make all 运行仿真;如果需要更换仿真顶层模块,例如修改为 tb_top_sim,输入:make all TOP=tb_top_sim
8.2.3. 查看仿真结果
输入:make dbg,打开 Verdi 查看仿真波形,如图8.14.所示。
图8.14. Verdi 查看波形
输入以下指令,打开 Verdi 查看覆盖率,如图8.15.所示。
make merge
make cov
图8.15. Verdi 查看覆盖率
8.3. Vivado 版本管理
版本要求:此方法适用于 Vivado 2022.2 及之后的版本。
必需的管理内容:工程文件(*.xpr)、源文件夹(*.srcs)和 .gitignore;建议的管理内容:工程 tcl 脚本(*.tcl,与*.xpr一样可以重建工程)。
将需要版本管理的内容直接 "git add" + "git commit" 即可。通过该方法管理的内容可以完整重建 Vivado 工程,通过 *.xpr 或 *.tcl 即可重建工程。
注意事项:
- Vivado 2022.2 之前的版本需要管理 tcl 脚本和源文件(不是源文件夹,源文件夹里包含了 IP 的派生文件等不需要版本管理的内容);
- 对于有 Black Design 的工程,重建后的工程可能会缺少 Black Design 的 HDL wrapper,需要在新工程里手动生成;
- tcl 脚本的生成如图8.16.所示:
图1. Vivado生成TCL
- .gitignore 参考:
# 1. ignore all
*
# 2. vivado project file
!/*.xpr
# 3. user readme.txt
!/readme.txt
# 4. design source files
!/*.srcs/
!/*.srcs/**
# 5. tcl to recreate project
!/create_project.tcl
# 6. .gitignore
!/.gitignore
# 7.
!*/
8.4. Vitis 版本管理
源文件 将硬件描述文件(*.xsa)、用户源文件(*.c,*.h等)和 .gitignore 加入管理,其他文件都不管理。重建工程时,需要通过这些文件重新走一遍新建工程的流程,用 xsa 文件新建平台工程,将源文件加入新的应用工程。
Workspace 使用 Vitis 的 File -> Export 功能,可以将整个 workspace(包括平台工程和应用工程等)导出为一个 zip 压缩包;重建工程时,只需要 File -> Import 就可以完全恢复workspace。对 zip 里的内容无法进行版本管理,仅作为工程备份。
A. 附录
A.1. CRC32
生成多项式:G(x) = x^32^ + x^26^ + x^23^ + x^22^ + x^16^ + x^12^ + x^11^ + x^10^ + x^8^ + x^7^ + x^5^ + x^4^ + x^2^ + x + 1,初始值为0xffffffff。输入输出均不反转、不异或。
参考代码:
// Verilog:
function [31:0] calc_crc32;
input [31:0] data;
input [31:0] crc;
reg [31:0] new_crc;
integer i;
localparam [31:0] POLY = 32'h04C11DB7;
begin
new_crc = crc ^ data;
for (i = 0; i < 32; i = i + 1) begin
if (new_crc[31]) begin
new_crc = (new_crc << 1) ^ POLY;
end else begin
new_crc = new_crc << 1;
end
end
calc_crc32 = new_crc;
end
endfunction
// C:
u32 CalculateCRC32(u32 init_value, u8 *data, u32 length, u32 polynomial)
{
u32 crc = init_value;
u32 words = length >> 2;
for (u32 i = 0; i < words; i++)
{
u32 w = ((u32)data[4*i+3] << 24) |
((u32)data[4*i+2] << 16) |
((u32)data[4*i+1] << 8) |
((u32)data[4*i]);
for (int b = 0; b < 32; b++)
{
crc ^= (w & 0x80000000);
w <<= 1;
crc = (crc & 0x80000000) ?
((crc << 1) ^ polynomial) :
(crc << 1);
}
}
return crc;
}
A.2. 下载链接
Vivado 2024.2 + Vitis 2024.2:https://pan.quark.cn/s/b7886c4f623a 提取码:77t1
QuestaSim 2014.1:https://pan.baidu.com/s/1vaCy-6WtdBn5Uew3WMBEcQ?pwd=71c4
CentOS 虚拟机(Vivado 2024.2 + VCS 2018.09 SP2):https://pan.quark.cn/s/1d13755fada3 提取码:wA6m