Skip to content

Zhu-Liyan/GenSimpoint

Repository files navigation

RISC-V Full-System Simulator

这是一个轻量级、高性能的 RISC-V 32位全系统模拟器,支持 RV32IMAB 指令集,并集成了基于 Spike 的差异化测试 (Difftest) 以及 SimPoint 分析功能。


🚀 快速开始

1. 编译

确保您的系统中已安装 g++zlib 开发库,然后直接运行:

make -j$(nproc)

2. 基础运行

最简单的运行方式,加载二进制镜像并开始执行:

./a.out --image path/to/your/image.bin

🛠️ 参数说明

参数 说明 示例
--image <file> 必选。指定要加载的二进制镜像文件。 --image linux.bin
--mode <mode> 运行模式选择。可选:normal, bbv, ckpt, restore --mode normal
--diff 开启 Difftest 模式。与 Spike 逐条指令对比架构状态(仅在 normal 模式下可用)。 --diff
--out-bbv <file> bbv 模式下,指定产生的 BBV 文件路径。 --out-bbv test.bbv
--points <file> ckpt 模式下,指定输入的 SimPoint 结果文件。 --points test.points
--ckpt-dir <dir> 指定保存 Checkpoint 文件的目录。 --ckpt-dir ./checkpoint
--restore-file <file> 指定要恢复的 Checkpoint 文件路径。 --restore-file ckpt.gz
--max-insts <num> 运行的最大指令条数(主要用于 restore 模式采样)。 --max-insts 100000000

💡 使用示例

示例 1:开启严格模式 Difftest 运行 Linux

此模式下,模拟器会与 Spike 进行严格的 GPR 和 CSR 校验,任何逻辑偏差都会立即停止。

./a.out --image ../image/linux.bin --diff

示例 2:从 Checkpoint 恢复并运行采样

恢复之前保存的状态,并限制运行 1 亿条指令后自动退出并统计。

./a.out --image linux.bin --mode restore --restore-file checkpoint/ckpt_sp0.gz --max-insts 100000000

🧭 地址空间布局(当前实现)

当前实现采用“1GB 连续 RAM + 离散 IO word 存储”的方式:

1. RAM(连续分配)

  • 物理地址窗口:0x80000000 - 0xBFFFFFFF(1GB)
  • 仅该范围使用连续数组分配,用于镜像加载和正常内存访问
  • 超出 0xBFFFFFFF 会触发越界错误并退出

2. IO / Boot(离散存储)

  • 0x00000000 附近:启动 stub(启动阶段写入)
  • 0x00001000 附近:Boot ROM stub(启动阶段写入)
  • 0x10000000 - 0x100000ff:UART(tree.dts 对应 reg size = 0x100
  • 0x10000004:OpenSBI 兼容寄存器(初始化写 0x00006000
  • 0x0c000000 - 0x0c20ffff:PLIC(tree.dts 对应 reg size = 0x210000
  • 0x0c201004:PLIC 中断相关寄存器(UART/PLIC 联动逻辑会访问)
  • 0x1fd0e000:Timer 寄存器(读取返回 sim_time
  • 0x1fd0e004:Timer 高位寄存器(当前返回 0)

说明:

  • 低地址和外设地址不再占用连续大内存,而是按 word_addr -> word_data 离散存储。
  • 读未初始化的离散 IO word 默认返回 0

💾 Checkpoint 格式(当前实现)

Checkpoint 使用 zlib gzip(写模式 wb1,文件后缀通常为 .gz),按如下顺序写入:

  1. header(固定 16 字节)
  2. CPU_state(POD 原样二进制)
  3. interval_inst_countuint64_t
  4. RAM 原始字节流(固定 ram_size 字节,当前为 1GB)
  5. io_ranges + io_data(重复 io_range_count 次):
    • io_range:两个 uint32_tbase, size
    • io_data:紧随其后的 size 字节原始数据

当前配置下的精确布局(未压缩逻辑布局)

  • header 字段顺序为:
    • magic"Rem\0"(4 字节)
    • version:当前为 2
    • ram_size:字节数(当前为 1GB)
    • io_range_count
  • CPU_state 当前大小:236 字节(0xEC
  • interval_inst_count 大小:8 字节
  • RAM 大小:0x40000000 字节(1GB)
  • io_range_count 当前为 4,顺序固定为:BOOT -> UART -> PLIC -> TIMER
区段 起始偏移 结束偏移 大小
Header 0x00000000 0x0000000F 0x10
CPU_state 0x00000010 0x000000FB 0xEC
interval_inst_count 0x000000FC 0x00000103 0x08
RAM 0x00000104 0x40000103 0x40000000
BOOT range descriptor (base,size) 0x40000104 0x4000010B 0x08
BOOT data (base=0x00000000,size=0x2000) 0x4000010C 0x4000210B 0x2000
UART range descriptor (base,size) 0x4000210C 0x40002113 0x08
UART data (base=0x10000000,size=0x100) 0x40002114 0x40002213 0x100
PLIC range descriptor (base,size) 0x40002214 0x4000221B 0x08
PLIC data (base=0x0c000000,size=0x210000) 0x4000221C 0x4021221B 0x210000
TIMER range descriptor (base,size) 0x4021221C 0x40212223 0x08
TIMER data (base=0x1fd0e000,size=0x8) 0x40212224 0x4021222B 0x08

总逻辑大小(未压缩)为 0x4021222C 字节(1,075,913,260 字节)。实际文件大小会因 gzip 压缩而变小。

兼容性

  • 当前恢复逻辑只支持新格式(含 headerio_rangesio_data),不兼容旧格式。

🔄 如何读取与恢复

1. 使用模拟器直接恢复(推荐)

./a.out --image linux.bin --mode restore --restore-file path/to/ckpt.gz --max-insts 100000000

恢复流程:

  1. 先通过 init() 分配 1GB RAM,并完成默认 Boot/IO 初始化
  2. 读取并校验 header(magic/version/ram_size)
  3. restore_checkpoint() 覆盖 CPU_stateinterval_inst_count
  4. 覆盖整个 1GB RAM 内容
  5. 读取并校验 IO 布局(base+size)是否与当前模拟器配置一致
  6. 读取每个 range 的 io_data 并恢复 IO 内容

2. 离线解析 checkpoint(二次开发)

若需要自己读取文件,按“Checkpoint 格式”中的顺序使用 gzread 逐段解析即可。关键点:

  • 必须先校验 magic="Rem\0"version=2
  • 必须使用与当前程序一致的 CPU_state 结构体布局(同编译器/ABI 假设)
  • RAM 字节数必须与运行配置一致(当前固定 1GB)
  • 最后按 io_ranges 顺序读取并校验,再读取对应 io_data

🏗️ 核心函数接口说明

1. Ref_cpu (主模拟器类)

  • init(reset_pc, image, size): 初始化处理器状态,分配内存并加载 binary 镜像到指定的 DRAM 基地址。
  • exec(config): 仿真主循环。根据 SimConfig 决定运行模式、处理周期计数、触发 Difftest 同步及处理检测点。
  • RISCV(): 取指、译码和分发的核心。处理取指异常,并根据 Opcode 调用不同的子执行函数。
  • RV32IM() / RV32A() / RV32CSR(): 分类处理整数、原子操作及 CSR 相关指令的执行逻辑。
  • save_checkpoint() / restore_checkpoint(): 使用 zlibCPU_state 以及整个物理内存进行压缩序列化/反序列化。

2. SpikeRef (金标准比对类)

  • step(n): 驱动 Spike 内部核心向前执行 n 条指令。
  • reg_check(state, priv): 比对 DUT 传入的状态(PC, GPR, CSR)与 Spike 内部状态。
  • sync_state(state, priv): 强制将 DUT 的所有架构上下文同步给 Spike(用于启动和中断对齐)。
  • sync_reg_from_dut(idx, val): 手术级同步。仅同步特定的通用寄存器(通常用于 I/O 读取后)。

📂 项目结构

  • include/: 所有的头文件,定义了指令集掩码、CSR 地址及类接口。
  • exec.cpp: 包含主要的指令执行逻辑以及硬件外设(如 UART/PLIC)的简易模拟。
  • simpoint.cpp: 负责 BBV 生成及 Checkpoint 的保存与恢复。
  • spike_ref.h: 处理与 Spike (libriscv) 的集成及状态对比。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors