上一篇介绍了处理器开发中的功能参考模型 NEMU,它作为 C++ 编写的参考模型,可以在仿真器速度略微下降的情况下保证待测处理器的功能正确性。同时,作为功能验证模拟器, NEMU 忽略了硬件实现中的许多细节,在敏捷开发中,如果要对处理器的性能建模,常见的方式是通过软件模拟的方式先获得硬件架构的性能趋势,该需求引入下文工具 XS-GEM5
一、项目背景
在现代高性能 CPU 的开发中,传统的"先设计后实现"模式已经无法满足快速迭代和性能优化的需求。香山处理器项目采用了敏捷开发模式,通过三层建模体系——功能建模(NEMU)、性能建模(GEM5)、真实建模(RTL)——形成了一个完整的设计验证闭环,大幅提升了开发效率和设计质量。
二、框架功能介绍
(1)三层建模体系的定位
1.NEMU:功能黄金模型(Functional Golden Model)
NEMU 是一个轻量级的指令集模拟器,作为整个验证体系的"功能基准"。它以最快的速度执行指令流,确保架构行为的正确性。在实际业务场景中,NEMU 扮演着"参考模型"的角色:
? 快速验证指令语义的正确实现
? 为性能模型和 RTL 提供功能对比基准(Difftest)
? 生成全系统检查点(RVGCpt),支持长程序的快速快进
? 作为 SimPoint 工作流的基础,识别代表性执行区域
2.XS-GEM5:性能探索模型(Performance Exploration Model)
XS-GEM5 是专为香山处理器定制的 GEM5 模拟器,位于功能建模和 RTL 实现之间的关键层。它的核心价值在于:
? 微架构性能预测:在 RTL 实现前快速评估设计决策(如分支预测器、预取器、调度器)的性能影响
? 参数空间探索:通过配置脚本快速调整流水线深度、缓存层次、预取策略等参数
? 与 RTL 对齐:维护多个配置变体(kmhv2.py、kmhv3.py、idealkmhv3.py),在保守设置和激进优化之间平衡,随 RTL 进度同步演进
3.RTL:真实硬件实现(Real Hardware Implementation)
RTL 是最终可综合的硬件描述,代表实际流片的设计。通过前两层建模的验证和调优,RTL 实现时已经具备了:
? 经过功能验证的正确性保证(NEMU Difftest)
? 经过性能预估的微架构参数(GEM5 仿真结果)
? 明确的设计取舍和优化方向
(2)实际业务场景中指导迭代的例子
在香山处理器的迭代开发中,这三层模型形成了紧密的反馈循环:
1. 架构设计阶段:
团队提出新的微架构特性(如 TAGESC 分支预测器、分布式调度器),首先在 GEM5 中实现原型,通过 SPEC CPU 等负载快速评估性能收益。
2. RTL 开发阶段:
RTL 工程师根据 GEM5 验证过的设计参数进行实现,同时保持与 NEMU 的 Difftest 对比,确保功能正确。如维护kmhv3.py(RTL 对齐版本)和idealkmhv3.py(性能激进版本)两个配置,前者与 RTL 开发进度同步,后者探索理论性能上限。
3. 性能调优阶段:
当 RTL 实现与 GEM5 预测出现偏差时,通过 GEM5 快速测试各种优化方案(调整预取器参数、修改 TLB 配置等),验证后再回流到 RTL。
4. 验证回归阶段:
通过 CI 流程,每次代码提交都会触发 GEM5 性能测试,确保性能不会意外退化。
三、框架速览
(1)模拟器架构
XS-GEM5 遵循从 gem5 继承的模块化架构,并在模拟堆栈的多个层中扩展了香山特定组件。该架构支持多个 ISA 目标,主要关注 RISC-V,同时通过 gem5 框架保持与 ARM、X86 和其他架构的兼容性。
模拟引擎使用SCons 构建,构建配置在 build_opts/ 目录中指定。源代码位于src/ 中,包含不同组件的子目录:arch/(ISA 实现)、cpu/(处理器模型)、mem/(内存系统)和dev/(设备模型)。configs/ 目录中的配置脚本驱动模拟设置,其中configs/common/xiangshan.py 提供香山特定的系统初始化,configs/example/ 包含可直接运行的模拟场景。
(2)高层组织架构
香山处理器架构遵循经典的多级组织结构,将执行核心、缓存层次和内存子系统集成到一个内聚的系统中。下图展示了主要的架构组件及其互连关系:
1. 核心流水线架构
香山处理器实现了深度的乱序流水线,将前端操作与后端执行解耦,以最大化指令吞吐量。流水线分为不同的阶段:取指、译码、重命名、分派、发射、执行和提交,每个阶段都具有可配置参数以支持不同的微架构实现。
基础 O3CPU 配置定义了可为不同核心变体定制的基本流水线参数:
2. 解耦前端设计
香山前端采用解耦分支预测架构,将取指目标预测与分支方向预测分离,从而实现更高的取指带宽和改进的预测准确性。该设计解决了为乱序后端维持稳定指令流这一基本挑战。
分支预测子系统
解耦前端集成了多个预测组件:
取指目标队列架构
解耦设计通过取指目标队列 进行通信,该队列保存由 BPU 生成的预测取指目标。取指引擎使用这些目标向 I-cache 生成指令流请求,从而有效地将预测与取指时序解耦。这种分离使 BPU 能够领先于取指运行,即使在流水线停顿期间也能保持队列深度。
3. 存储层次结构
香山实现了复杂的多级缓存层次结构,旨在为内存密集型工作负载提供高带宽和低延迟。存储系统支持传统的时序模式仿真和基于 Ruby 的详细建模,用于一致性协议验证。
缓存组织
缓存层次结构遵循经典的多级设计:
一致性协议
香山的默认一致性协议是 MI_example,这是一种简单的非阻塞缓存一致性协议,在保持仿真效率的同时提供正确性保证。对于更详细的一致性建模,可以配置 Ruby 协议,例如 MESI_Two_Level 或 MOESI_AMD_Base。
4. 预取架构
香山实现了一个综合性的多预取器协调框架,该框架集成了跨不同缓存级别的多种预取算法。这种分层方法解决了不同的访问模式,同时管理预取带宽以避免缓存污染。
预取器分配
预取器系统在缓存级别之间分配算法:
协调框架
多预取器框架实现了主动和被动卸载 机制,以优化预取生成。主动预取器根据观察到的模式主动发出预取请求,而被动预取器分析访问历史以生成提示,这些提示可由下游的其他预取器使用。
这种协调实现了复杂的预取器组合,其中简单的检测器(如跨步检测)馈入复杂的生成器(如 SMS 模式匹配),从而在最大限度地减少冗余请求的同时最大化覆盖率。
预取器框架包括下游提示机制,L1 预取器可以通过 add_pf_downstream 接口将预测传达给L2/L3 预取器,从而实现跨级预取器协作。
(3)冒烟教程
1.配置与仿真
前置条件与环境配置
使用包管理器安装所需的软件包:
sudo apt install build-essential git m4 scons zlib1g zlib1g-dev \libprotobuf-dev protobuf-compiler libprotoc-dev libgoogle-perftools-dev \python3-dev libboost-all-dev pkg-config libsqlite3-dev zstd libzstd-dev
2.配置 Python 环境
XS-GEM5 明确要求 Python 3.8。如果你的系统安装了更新版本的 Python,请使用 conda 或 pyenv 管理 Python 环境。推荐的方法是使用 miniconda,因为它易于设置且具有环境隔离功能:
# 安装 Minicondamkdir -p ~/miniconda3wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.shbash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3rm -f ~/miniconda3/miniconda.sh
重启终端后,创建并激活 Python 3.8 环境:
初始化shell(二选一):~/miniconda3/bin/conda init bash # 使用 bash# 或~/miniconda3/bin/conda init zsh # 使用 zsh创建并激活 Python 3.8 环境:conda create --name py38 --file $gem5_home/ext/xs_env/gem5-py38.txtconda activate py38
3.克隆与初始设置
首先克隆 XS-GEM5 仓库并设置外部依赖项:
git clone https://github.com/OpenXiangShan/GEM5.gitcd GEM5
仓库结构包含了你所需的所有组件:
GEM5/├── configs/ # 配置脚本│ ├── example/ # 示例配置│ └── common/ # 共享配置模块├── src/ # 源代码├── ext/ # 外部依赖项 (DRAMSim3)├── util/xs_scripts/ # XS-GEM5 辅助脚本└── build/ # 构建输出目录(构建过程中创建)
4.设置 DRAMSim3
DRAMSim3 是实现逼真内存系统模拟所必需的。使用提供的初始化脚本自动下载并构建 DRAMSim3:
bash ./init.sh该脚本会将DRAMSim3 克隆到 ext/dramsim3/DRAMsim3,创建构建目录,运行CMake 配置,并使用并行构建编译库。你只需运行一次——未来的 XS-GEM5 构建将使用已编译好的 DRAMSim3。
来源:init.sh, docs/quick_start.md, README.md
5.构建 XS-GEM5
安装好依赖项并构建完 DRAMSim3 后,使用 SCons 编译 XS-GEM5:
scons build/RISCV/gem5.opt --gold-linker -j$(nproc)export gem5_home=`pwd`
构建过程可能需要 15-30 分钟,具体取决于你的硬件。以下是各选项的作用:
? build/RISCV/gem5.opt:指定目标二进制文件(优化的 RISC-V 构建)
? --gold-linker:使用 gold 链接器以加快链接速度
? -j$(nproc):启用并行编译,使用所有可用的 CPU 核心
第一次构建 XS-GEM5 时,你可能会看到关于安装 git hooks 进行代码风格检查的提示。按 Enter 键接受此操作——这有助于维持代码质量标准。
如果构建成功完成,你可以在build/RISCV/gem5.opt 找到可执行文件。通过检查二进制文件是否存在来验证构建:
ls -lh build/RISCV/gem5.opt来源:docs/quick_start.md, README.md
6.准备工作负载
下载即用型二进制文件和 difftest 所需的参考设计:
# 下载预编译工作负载git clone https://github.com/OpenXiangShan/ready-to-run.git # 下载用于 difftest 验证的 NEMU 参考设计wget https://github.com/OpenXiangShan/GEM5/releases/download/2024-10-16/riscv64-nemu-interpreter-c1469286ca32-so # 设置环境变量export GCBV_REF_SO=`realpath riscv64-nemu-interpreter-c1469286ca32-so`export GCBV_RESTORER= # 新的二进制文件不需要
GCBV_REF_SO 变量指向用于在线验证的黄金模型(NEMU)。XS-GEM5 会将其执行结果与 NEMU 进行比较,以确保正确性。
7.准备参考模型
编译一个 NEMU 用来给 GEM5 作为功能实现对比:
git clone git@github.com:OpenXiangShan/NEMU.gitcd NEMU# 2) 配置并编译 NEMU(生成 ref_so)export NEMU_HOME=$(pwd)make riscv64-gem5-ref_defconfigmake -jcd ../
GCBV_REF_SO 变量指向用于在线验证的黄金模型(NEMU)。XS-GEM5 会将其执行结果与 NEMU 进行比较,以确保正确性。
8.执行模拟
使用默认配置运行 CoreMark 工作负载:
./build/RISCV/gem5.opt ./configs/example/kmhv2.py --raw-cpt --generic-rv-cpt=./ready-to-run/coremark-2-iteration.bin模拟完成后(通常需要几秒钟),检查结果:
grep 'cpu.ipc' m5out/stats.txt你应该能看到一个 IPC(每周期指令数)值,表明模拟已成功完成。模拟输出存储在 m5out 目录中,其中包含详细的统计信息和日志。
9.相关启动参数解析
xiangshan.py 配置脚本是设置香山处理器模型的入口点,包括前端(分支预测)、后端(乱序执行)和内存层次结构(缓存、预取器、DRAMSim3)。
四、总结
根据上文总结,XS-GEM5 是基于 python 模拟硬件架构的全系统仿真器,对于处理器的不同部件,通过软件灵活度高的特性,结合先进论文和业界产品,进行设计空间探索工作,作为敏捷验证方法,提高工作效率。
点击下方图标,关注开芯院平台
▼
