ITADN
tommythorn/simmerv
tommythorn/simmerv · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Rust

Simmerv

Simmerv 是一个用 Rust 编写的 RISC-V SoC 模拟器, 可编译为 WebAssembly。 它最初是 Takahiro 的 riscv-rust 模拟器 的一个分支,但如今已 被大量重写,使其更加完整且 速度更快。 最终,我们预计它将变得显著更快, 但这项工作被推迟,直到我们能够运行标准基准测试 和现成的 Linux 发行版。

在线演示

您可以在浏览器中在模拟器上运行 Linux:在线演示 在此

在 Simmerv 上启动 Ubuntu(加速 50 倍)

Installing and running Ubuntu

特性

  • 模拟 RISC-V RV64GC_Zba_Zbb_Zbc_Zbs_Zicond_Zfhmin_Svinval_Svade_Svpbmt_Sstc_Zicbom_Zicbop_Zicboz_Zihpm (RVA22) 处理器和外围设备 (CLINT, PLIC, NS16550A UART, virtio 块设备, 以及 VirtIO 以太网)
  • 可选的 RVA23 模式,通过 --rva23 启用:V 向量扩展 (RVV 1.0, ELEN=64, VLEN=128 或 256,通过 --vlen 实现) 以及 Zcb, Zimop, Zcmop, Zfa, Zawrs, Zacas, Zabha, Zvbb, Zvkt 和 Zihintntl。 启动 Ubuntu 26.04 的 RVA23 移植版本。
  • 支持原生和 WASM 目标
  • 快照
  • 速度计

指令/特性支持状态

RVA22 配置文件(完整)

  • RV64IMAC
  • RV64FD
  • RV64Zifencei
  • RV64Zicsr
  • Zba, Zbb, Zbc, Zbs ("B" 扩展)
  • Zicond
  • Zfhmin (半精度浮点转换)
  • Zihpm (硬件性能计数器)
  • Zicbom, Zicbop, Zicboz (缓存块操作)
  • Svinval (细粒度 TLB 无效化)
  • Svade (硬件 A/D 访问故障)
  • Sstc (stimecmp/menvcfg 定时器比较)
  • Sv39, Sv48, Sv57 (较宽的两个为可选启用:参见 --satp-mode)
  • Svpbmt (基于页面的内存类型;接受 PTE,无需模拟缓存)
  • 特权规范 1.12 (mcounteren/scounteren, senvcfg, 0 个条目的 PMP 存根)
  • Svnapot
  • [-] PMP 强制 (实现了 0 个条目;允许所有访问)

该模拟器支持上述列出的所有指令。

  • 通过所有 RV64IMC 的 riscof (RISC-V 架构测试)
  • 启动 Buildroot, Debian Trixie, Ubuntu
  • 支持 Linux OpenSBI 和传统 BBL 启动

RVA23 配置文件(进行中)

  • V — 向量扩展,RVV 1.0。 包含 Zve64d 以及完整的 V 指令集:配置、单位步长 / 跨步 / 索引 / 分段 / 整寄存器 / 仅首元素故障的加载和存储, 整数、定点、掩码、置换和浮点运算, 以及带有 mstatus.VSvstart / vl / vtype / vxrm / vxsat / vcsr / vlenb CSR。 VLEN 默认为 128(Zvl128b,即配置文件 的最小值);--vlen 256 则选择 Zvl256b
  • Zvfh, Zvfhmin — 向量半精度(完整的算术集,它是 配置文件所要求的 Zvfhmin 的超集)
  • Zvkt, Zkt — 恒定时间执行;通过没有数据依赖时序的功能 模型即可轻松满足
  • Zicond, Zfhmin, Zicbom/z/p, Svinval, Svnapot, Svpbmt, Sstc, Svade (继承自 RVA22)
  • Zcb — 较新的压缩编码。 每一条都缩写了一个 模拟器已经拥有的指令,因此所有十二条都直接解码为 该 uop,而不是并行执行路径。
  • Zimop, Zcmop — 可能是操作。 mop.r.n / mop.rr.nrd 写入零;c.mop.n 不改变任何架构状态。
  • Zfa — fli(两个常量表),fminm/fmaxm,静默比较 fleq/fltqfround/froundnx 以及 fcvtmod.w.d。 半精度成员被省略:它们需要完整的 Zfh,而 RVA23 并未强制要求,且此模拟器也未实现。
  • Zvbb — 向量基本位操作(vandnvbrevvbrev8vrev8, vclz, vctz, vcpop, vrol, vror, vwsll),以及与之相关的 Zvkb,它是一个严格子集
  • Zawrs — wait-on-reservation-set。 两种形式都可能立即终止等待 且原因任意,因此两者均作为空操作(no-op)退休。
  • Zacas — amocas.b/h/w/d/q,包括针对偶数/奇数 寄存器对的 quadword 形式
  • Zabha — 所有 AMO 的字节和半字形式
  • Zihintntl — 非临时局部性提示。 四个提示是 ADD x0, x0, x2..x5(以及 C.ADD x0, x2..x5 压缩形式),因此 任何符合规范的 hart 已经将它们作为空操作退休;功能模型 没有缓存层次结构可供提示,这也是 ZktZvkt 免费满足的原因。 已验证其不会修改 x0 和源 寄存器。
  • satp 中的 Sv48, Sv57。 通过 --satp-mode sv48 / sv57 选择加入,因为 Linux 保持 satp 接受的最宽模式:默认使用 Sv57 会将 所有现有客户机迁移到更深的页表。 由 Tenstorrent 套件的 paging_sv48paging_sv57 组进行验证。
  • Supm / Ssnpm / Smnpm — 指针掩码。 已推迟。 没有任何东西依赖 它:掩码是按进程选择加入的(prctl(PR_SET_TAGGED_ADDR_CTRL)), 因此未找到它的软件只是不标记指针,而 唯一的实际受益者 -- HWASAN,这也是 Android 依赖 Arm 的 等效 TBI 的原因 -- 在 RISC-V 上尚不存在。 模拟器也不会 获得该功能旨在提供的东西:重点在于硬件免费忽略 标签位,而在这里这仅仅是“不对这些 addresses". 若 LLVM 获得 RISC-V HWASAN 支持,或某个发行版提供 经过 HWASAN 插桩的 RISC-V 软件包,则重新评估。
  • Sscofpmf — 计数溢出中断。 计数器从全 1 回绕时 在 0->1 边沿置位 OF 并触发 LCOFIP;该中断 以 CounterOverflowInterrupt 形式投递,且 scountovf 反映此状态。 在两个设备树中均有声明。
  • Ssstateen / Smstateen — 状态使能 CSR。 mstateen0SE0ENVCFG 位门控 M 模式以下的 sstateen0senvcfg;其余所有 位,以及 mstateen1..3 / sstateen0..3 整体,读取值为零,因为 这些位所保护的状态(AIA、IMSIC、ZcmtjvtZfinxfcsr、 自定义)在此处不存在。 mstateen0 复位为允许状态而非 架构定义的零值:它所门控的唯一状态是 senvcfg,因此 默认拒绝既无保护意义,又会破坏任何早于 Smstateen 且 从未开启该门控的固件。
  • H — 虚拟化扩展,RVA23S64 所必需。 已推迟。 运行 Linux 无需此扩展,仅托管 Linux 时需要:若来宾系统未检测到 H,则 不提供 KVM。 它也是规模最大的一项——两级 地址转换、VS 模式 CSR 组、虚拟化加载/存储指令——且位于 MMU 快速路径上。 Tenstorrent 的测试套件包含一个 h_ext 测试 树,目前被跳过,因此测试将在该扩展被实现时 等待执行。

因此 RVA23 是完整的,但 SupmH 除外,两者均因上述相同原因被推迟:没有任何内容依赖于它们,它们也不阻塞 simmerv 所针对的任何内容。

覆盖率并非自我报告:用户态指令集由 Tenstorrent 的架构测试进行验证(参见 tests/tenstorrent/run.sh),向量实现则在两种 VLEN 宽度下与 QEMU 逐条指令进行差异比对(tests/vector/run.sh)。

设备树会通告已实现的内容,以便来宾可以发现。 这包括默认(非---rva23)机器,该机器过去仅命名 imafdc 以及少数几个 CSR 扩展,尽管它一直拥有 bitmanip 指令集、ZicondZfhmin 以及缓存块操作。

V、Zcb、Zimop、Zcmop、Zfa、Zvbb、Zawrs、Zacas 和 Zabha 默认关闭, 并通过 --rva23 一起启用,以便在没有该标志的运行中仍然模拟一个 会陷入所有这些编码的 hart。(从 RVA22 继承的条目 始终开启。)RVA23 强制要求 V,因此一个开关即可涵盖全部:它控制 指令解码、misa V 位以及向量 CSR,并切换到一个 其 cpu 节点通告该配置文件的设备树。

$ cargo r -r -- --rva23 -n my-vector-program.elf

要启动 Ubuntu 的 RVA23 移植版,来宾内核也必须使用 CONFIG_RISCV_ISA_V=y 进行构建——如果没有它,内核会从设备树解析出的 ISA 中丢弃 v,并且 RVA23 用户空间会在 ld.so 中的第一条向量指令处崩溃,因为该配置文件允许 glibc 发出没有标量回退的向量代码。启动日志中的 riscv: base ISA extensions 是需要检查的内容:它应显示为 acdfimv

$ cargo r -r -- --rva23 -f ubuntu-26.04-preinstalled-server-riscv64.img \
      fw_payload.bin,0x80000000

tests/vector/run.sh 构建了一个裸机测试器 —— 涵盖所有 SEW、LMUL、舍入模式和寻址形式的 1994 个指令用例,既包括 RVA23 的扩展,也包括基础 RVV —— 并将 simmerv 的转录与 QEMU 的 virt 机器进行差异比对,该机器共享 simmerv 的内存映射。 目前所有 1994 行转录完全匹配,两侧均触发三个陷阱:vwsllSEW=64 时,其中扩展后的元素超出 ELEN 且编码必须为非法。

一个有意为之的差异:simmerv 强制执行 vill、寄存器组对齐、EMUL 范围以及“带掩码指令不得写入 v0”的规则,但不执行更细粒度的源/目的重叠约束(双宽度 vs2 组内的窄化 vs1,段加载目的与索引组重叠)。 QEMU 对这些情况会触发非法指令;simmerv 则执行它们。 没有符合规范的汇编器会生成这些指令。

如何使用 VirtIO 块设备 (/dev/vda) 运行 Linux

非常重要:镜像使用 git LFS 存储。 安装 LFS(别忘了 git lfs install 也要安装),如有需要请重新检出。 否则 镜像将是包含 LFS 指针的小文件。

$ cargo r -r -- linux/fw_payload.bin,0x80000000 -f linux/rootfs.img

$ cargo r -r -- -c linux/opensbi/fw_jump.elf,0x80000000 linux/vmlinux,0x80200000 -f linux/rootfs.img

如何使用 initramfs (/dev/ram) 运行 Linux

分配 2 GiB,使用设备树,将 initramfs 置于 0xa0000000, 并在该地址加载 initrd2+gdb.cpio 二进制文件。

$ (cd linux;cargo r -r -- -m 2048 -d with-initrd.dtb fw_payload.bin,0x80000000 initrd2+gdb.cpio,0xa0000000)

如何配置网络 (VirtIO-net)

Simmerv 在第二个 virtio-mmio 窗口上模拟了一个 VirtIO-net 设备(MAC 52:54:00:12:34:56)。内置的设备树已经声明了它,因此带有 CONFIG_VIRTIO_NET 的来宾内核会自动探测它——但在你附加主机后端之前,该设备处于非活动状态(数据包会被丢弃)。除了后端提供的功能外,没有内置的模拟器 NAT/DHCP。

Linux: TAP 接口 (-T)

在 Linux 上,Simmerv 将来宾的网卡连接到一个 TAP 设备——这是一个没有自身 DHCP 或 NAT 的原始二层链路,因此你需要配置主机端并为来宾分配静态地址(或者如果你愿意,可以将 tap0 桥接到真实网络)。

  1. 创建一个由你的用户拥有的持久化 TAP(这样 Simmerv 就不需要 root 权限):
$ sudo ip tuntap add dev tap0 mode tap user $USER
$ sudo ip link set tap0 up
$ sudo ip addr add 172.16.0.1/24 dev tap0
  1. 对于访客互联网访问,在主机上启用转发 + NAT。 MASQUERADE 规则必须指定您的面向互联网的接口——从默认路由自动检测, 而不是假设 eth0
$ UPLINK=$(ip route show default | awk '{print $5; exit}')   # e.g. enp9s0, wlan0
$ echo "NAT via uplink: $UPLINK"                              # sanity-check it
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o "$UPLINK" -j MASQUERADE
$ sudo iptables -A FORWARD -i tap0 -j ACCEPT
$ sudo iptables -A FORWARD -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT

如果来宾能够到达主机(172.16.0.1)但无法到达更远的地方, 此规则几乎总是罪魁祸首——使用 sudo iptables -t nat -L POSTROUTING -n -v 检查它(错误的 out 接口,或 当来宾生成流量时 pkts 计数卡在 0)。

  1. 运行附加到 TAP 的 Simmerv(-T <ifname>):
$ cargo r -r -- -T tap0 linux/fw_payload.bin,0x80000000 -f linux/rootfs.img
  1. 在客户机内部配置接口(名称可能为 eth0enp0s… 等 — 请检查 ip link):
# in the guest
$ ip addr add 172.16.0.2/24 dev eth0
$ ip link set eth0 up
$ ip route add default via 172.16.0.1        # only needed for step 2
$ echo 'nameserver 1.1.1.1' > /etc/resolv.conf

主机(172.16.0.1)和来宾(172.16.0.2)现在可以互相 ping 通;通过 步骤 2,来宾还可以访问互联网。之后使用 sudo ip tuntap del dev tap0 mode tap 移除 TAP。

macOS: vmnet 共享/NAT(--vmnet

在 macOS 上,Simmerv 使用 Apple 的 vmnet.framework共享模式运行,该模式 会自动提供 DHCP NAT —— 来宾只需请求一个 地址。vmnet 共享模式需要提升权限,因此请在 sudo 下运行。首先进行构建,以免 sudo 以 root 身份重新构建整个目录树:

$ cargo build -r
$ sudo ./target/release/simmerv_cli --vmnet linux/fw_payload.bin,0x80000000 -f linux/rootfs.img

客户机将获取 vmnet 子网(通常为 192.168.x.x)上的地址, 并通过 NAT 连接到宿主机的网络。如果客户机镜像未自动启用链路, 请在其中运行一个 DHCP 客户端:

# in the guest
$ udhcpc -i eth0        # busybox; or: dhclient eth0

(-T/--tap 仅限 Linux,--vmnet 仅限 macOS;在另一平台上均会报错。)

如何运行 riscv-tests

$ ./run-riscv-tests.sh

如何在 Web 浏览器中导入和使用 WebAssembly RISC-V 模拟器

参见 wasm/web

如何安装和使用 WebAssembly RISC-V 模拟器 npm 包

参见 wasm/npm

链接

Linux RISC-V 移植

在 QEMU 上运行 64 位 RISC-V Linux

规范