目录

work — Linux 环境复现指南

本仓库是一个 RISC-V RV64 裸机量化大模型推理工程:在带 AME 矩阵加速器RVV 向量扩展 的自研 SoC(AMD Versal Premium VP1902 FPGA / RTL 仿真)上运行 Qwen3-0.6B 的 W8A8 / W4A8 推理。

本文件是在一台干净 Linux 上从零复现编译环境的操作手册。照着 §1→§5 走即可。


0. 需要装的东西(总表)

# 组件 作用 来源
1 基础构建工具 make / cmake / ninja / python3 等 apt
2 RISC-V GNU 交叉工具链 提供 sysroot、-lgcc、objcopy/readelf/objdump apt
3 自研 AME-aware clang-21(核心) 唯一能编译 AME 指令的编译器 + lld 链接器 拷贝预编译 / 源码自建
4 Python 转换环境 量化权重、生成模型 / tokenizer blob pip

真正特殊、且无法用发行版软件替代的只有第 3 项。其余都是标准 apt/pip 包。

环境基线(本机已验证):Ubuntu 22.04(源 WSL2,正迁往原生 Linux),x86_64,Python 3.10.12。 整机迁移到 Linux 的完整搬运 / 避坑清单见 §7


1. 主机基础工具

sudo apt update
sudo apt install -y build-essential make cmake ninja-build \
                    python3 python3-pip git file coreutils gawk bc

file/awk/od/dd/stattest/sim/*/elf_to_verilog.sh 用到,coreutils/gawk 已包含。)


2. RISC-V GNU 交叉工具链

sudo apt install -y \
  gcc-riscv64-linux-gnu \
  binutils-riscv64-linux-gnu \
  binutils-riscv64-unknown-elf
提供什么 本机验证版本
gcc-riscv64-linux-gnu sysroot /usr/riscv64-linux-gnu + libgcc(链接用 -lgcc 4:11.2.0
binutils-riscv64-linux-gnu riscv64-linux-gnu-objcopy / -readelf 2.38
binutils-riscv64-unknown-elf riscv64-unknown-elf-objcopy / -objdump(仅 sim 生成 Verilog 镜像/反汇编时用) 2.35.1

所有 Makefile 给 clang 传的固定三元组参数就是基于这个 sysroot:

--target=riscv64-linux-gnu --sysroot=/usr/riscv64-linux-gnu --gcc-toolchain=/usr

可选:tools/bench/firmware 里的 RVV/SPM/AME operator L1 固件默认仍会找 /opt/riscv/riscv64-unknown-elf 这个 newlib 裸机 sysroot;DMA/SPM 和 AME pure 固件走 /usr/riscv64-linux-gnu + -lgcc


3. 自研 AME-aware clang-21(核心步骤)

工程所有裸机目标都用一个支持 AME 自定义指令的 LLVM/Clang fork。 发行版 apt install clang 装出来的 clang 不认识 AME 助记符msettile*/mlae8/ mqma.b.mm 等),无法编译 models/qwen3/ame_mix_offline_i8.c 这类用真助记符的固件。 ⚠️ 注意发行版 clang-21 与本 fork 同名易混,迁移时尤其要确认走的是 fork——详见 §7.2

  • fork 来源:https://gitlink.org.cn/michaelcjl/llvm-project_riscv.git
  • 本机已用 commit:ad6e3420706aaf5ab557d3023b5a3fac6e2954d7clang version 21.0.0git
  • Makefile 默认查找路径:~/opt/llvm-project_riscv/build/bin/
  • 需要这些可执行文件:clang-21clangclang++lld/ld.lld-fuse-ld=lld)、 llvm-arllvm-objcopyllvm-objdumpllvm-nm

有两条路,优先选 A(自建一次要几个小时)。

路 A:拷贝预编译产物(推荐)

如果还能访问已装好的旧机器,直接把整棵 build 目录搬过去最省事。

# 在旧机:打包(整棵约 7 GB,未裁剪)
tar -C ~/opt -czf llvm-riscv-build.tgz llvm-project_riscv

# 在新机:解到同样路径
mkdir -p ~/opt && tar -C ~/opt -xzf llvm-riscv-build.tgz

最小拷贝集(若想省空间,~4.3 GB → 可再 strip 减小):只需

  • build/bin/(上面列出的那几个二进制;clang 按相对路径找资源目录)
  • build/lib/clang/21/(clang 自带头文件,必须一起拷,仅 ~8 MB;缺了会报找不到 stddef.h 等)

二进制为未 strip 版本,体积大但可直接用。clang 会相对自身定位 ../lib/clang/21,所以保持 binlib 的相对结构即可。

路 B:从源码编译

git clone https://gitlink.org.cn/michaelcjl/llvm-project_riscv.git ~/opt/llvm-project_riscv
cd ~/opt/llvm-project_riscv
git checkout ad6e3420706aaf5ab557d3023b5a3fac6e2954d7

cmake -S llvm -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_PROJECTS="clang;lld" \
  -DLLVM_TARGETS_TO_BUILD="RISCV" \
  -DLLVM_ENABLE_EXPERIMENTAL_EXTENSIONS=ON

ninja -C build clang clang-resource-headers lld llvm-ar llvm-objcopy llvm-objdump llvm-nm

clang-resource-headers 确保生成 build/lib/clang/21/include。编译需 ~30+ GB 磁盘、较长时间。)

让构建找到它

Makefile 顶部用 CUSTOM_LLVM ?= $(HOME)/opt/llvm-project_riscv/build/binCLANG ?= .../clang-21 引用。装到默认路径就无需改任何东西。装别处则:

make CLANG=/abs/path/clang-21 CUSTOM_LLVM=/abs/path/bin ...

✅ 重组时已清除历史硬编码用户路径(旧的 /home/luoyue/home/zhang1)。 kernel/Makefilemodels/qwen3/Makefile 现统一走 ~/opt/llvm-project_riscv/build/bin 默认通配;装别处用 make CLANG=... 覆盖即可。


4. Python 模型转换环境

权重量化 / 生成 blob 的脚本(tools/quantization/*.pytools/tokenizer/*.pytools/*.shtests/*/extract_real_case.py)需要:

python3 -m pip install torch transformers safetensors numpy
组件 本机验证版本 说明
Python 3.10.12
torch 2.11.0 仅做量化打包,CPU 版即可,不需要 GPU/CUDA
transformers 5.3.0 读 safetensors / config
safetensors 随 transformers
numpy 2.2.6

模型源:转换脚本默认从 /tmp/Qwen3-0.6B(HF safetensors)读取,可用 MODEL_SOURCE=/path/to/Qwen3-0.6B 覆盖。

仓库不使用 git-lfs,也没有 requirements.txtmodels/qwen3/model_data/*.bin(量化模型 blob) 是构建产物,由转换脚本生成,已被 .gitignore 排除,不随 git 迁移——迁移时只需带上 HF safetensors 源 + 转换脚本。


5. 验证环境

5.1 工具链可见性

~/opt/llvm-project_riscv/build/bin/clang-21 --version    # 应显示 21.0.0git
~/opt/llvm-project_riscv/build/bin/ld.lld --version
riscv64-linux-gnu-objcopy --version
riscv64-unknown-elf-objdump --version
python3 -c "import torch,transformers,safetensors,numpy; print('ok')"

5.2 编译器冒烟测试(确认 AME clang 能产出 RV64 目标)

printf 'int f(int x){return x+1;}\n' > /tmp/_smoke.c
~/opt/llvm-project_riscv/build/bin/clang-21 \
  --target=riscv64-linux-gnu --sysroot=/usr/riscv64-linux-gnu --gcc-toolchain=/usr \
  -march=rv64imafdc -mabi=lp64d -mcmodel=medany -c /tmp/_smoke.c -o /tmp/_smoke.o
file /tmp/_smoke.o          # 期望: ELF 64-bit LSB relocatable, UCB RISC-V ...

5.3 实际构建各模块

# 算子库 libops_kernels(唯一可信源)
make -C kernel static                        # -> kernel/build/libops_kernels.a

# FPGA benchmark 固件(L1 峰值与 operator profile)
make -C tools/bench/firmware l1_peaks          # -> tools/bench/firmware/build/*.bin

# W8A8 端到端裸机固件
#   若缺模型 blob,先转换(需 §4 的 Python 环境 + safetensors 源):
MODEL_SOURCE=/path/to/Qwen3-0.6B bash tools/generate_w8a8_model.sh
make -C models/qwen3                          # -> models/qwen3/build/qwen3_chat_w8a8_ame_fpga.bin

# RTL 波形仿真镜像(用到 riscv64-unknown-elf-objcopy/objdump)
make -C tests/sim/dma_spm_w8a8                # -> build/verilog/

# FPGA flash bin(W4A8 路径示例)
bash tests/flash/perf_dma_dequant_w4a8/build.sh

# L1 峰值微基准(DDR/SPM、纯 SPM 口、AME MAC/cyc、RVV MEM+ARITH;须在仓库根目录)
make -C tools/bench/firmware dma_spm_usage
make -C tools/bench/firmware spm_port_peak_fpga
make -C tools/bench/firmware ame_operator_profile_fpga
make -C tools/bench/firmware rvv_flops_peak_fpga
# 详情:models/qwen3/README.md「L1 峰值微基准编译」、docs/bench/measure_peaks_flash.md

所有裸机 ELF 在链接后会用 readelf 校验入口为 0x80000000,bin 按 64 字节对齐填充。 各模块的测试分类与运行要求见 tests/README.md;文档索引见 docs/README.md


6. 目标 ISA / 关键编译开关(排错参考)

ABI / 代码模型 -mabi=lp64d -mcmodel=medany
标量裸机 ISA -march=rv64imafdc
RVV 路径 ISA -march=rv64gcvtools/bench/firmware 的部分 L1 固件用 rv64gcv_zfh_zvfh_zicsr_zifencei
固定 VLEN(绕过 FPGA 对动态 csrr vlenb 的 trap) -mllvm -riscv-v-vector-bits-min=N -mllvm -riscv-v-vector-bits-max=N(tests=256,model/sim/flash=512)
链接器 lld-fuse-ld=lld)+ -lgcc
入口地址 锁定 0x80000000(链接脚本 *.ld

7. 环境迁移到 Linux:完整工具链 + 避坑

本节面向把整个工程从 WSL2 搬到一台原生 Linux。照 §7.1 把工具链配齐,§7.2 把 该带的东西带全,§7.3 落地后清理,最后用 §5 验证。

7.1 完整工具链清单(“确保工具链完全”)

组件 二进制 / 路径 本机已验证版本 来源
AME clang-21 fork(核心,不可替代) ~/opt/llvm-project_riscv/build/bin/clang-21 clang clang++ ld.lld lld llvm-ar llvm-objcopy llvm-objdump llvm-nm 21.0.0git(commit ad6e342…),target riscv64-unknown-unknown-elf 拷贝预编译 / §3 源码自建
fork 自带头文件(必须同拷 ~/opt/llvm-project_riscv/build/lib/clang/21/include 随 fork 同上
RISC-V GNU 交叉(sysroot + -lgcc riscv64-linux-gnu-{gcc,objcopy,readelf} + sysroot /usr/riscv64-linux-gnu gcc 11.4.0 / binutils 2.38 apt(§2)
RISC-V newlib 裸机工具 riscv64-unknown-elf-{objcopy,objdump} binutils 2.35.1 apt(§2)
Python 转换环境 python3 + torch numpy transformers safetensors Py 3.10.12 / torch 2.11.0 / transformers 5.3.0 / numpy 2.2.6 pip(§4,CPU 版即可)
基础构建 make file awk od dd stat(被 elf_to_verilog.sh 用) apt(§1)

落地后用 §5.1 的命令逐项核对版本。

7.2 两个会“静默踩坑”的 clang 陷阱

  1. /usr/bin/clang-21 是发行版 clang,不是 fork。 本机 apt 装的 clang-21(Ubuntu 21.1.8,target x86_64不认 AME 助记符。后果很隐蔽:
    • kernel/ 全部用 .word 0x… 固定编码写 AME,发行版 clang 也能编过
    • models/qwen3/ame_mix_offline_i8.c 用真助记符(msettile* / mlae8 / mqma.b.mm),只有 fork 能编。 各 Makefile 默认 CLANG := $(if $(wildcard $(CUSTOM_LLVM)/clang-21),…,clang-21): fork 装在默认路径就优先用 fork;fork 没装时会悄悄回退到发行版 clang-21,于是 kernel 编过、model 报错。→ 迁移后第一件事就是确认 fork 在 ~/opt/llvm-project_riscv/build/bin,或显式 make CLANG=/abs/clang-21
  2. fork 是 x86_64 预编译二进制(约 192 MB)。 只能在 x86_64 Linux 主机上跑。 若新机是 arm64 等其它架构,预编译产物无法运行,必须按 §3 路 B 从源码重建

7.3 该带什么 / 落地后必做

搬运清单:

  • 源码git(已重组,干净)。
  • fork:整棵 ~/opt/llvm-project_riscv/build/,或最小集 build/bin + build/lib/clang/21(~4.3 GB;§3 路 A)。
  • 模型权重 blobmodels/qwen3/model_data/*.bin(数百 MB ~ GB)已被 .gitignore 排除,不随 git 走。二选一:① rsync/tar 单独拷过去;② 带上 HF safetensors 源后用 tools/generate_w8a8_model.sh + tools/tokenizer/generate_tokenizer_blob.sh 重生成。
  • HF safetensors 源:转换脚本默认读 /tmp/Qwen3-0.6B,可 MODEL_SOURCE=… 覆盖。

落地后必做(顺序很重要):

  1. **清掉所有 build/**:旧 .d 依赖文件里写死了 /mnt/d/... 绝对路径,换机/换路径后 不清会直接报 “No rule to make target”。
    find . -type d -name build -not -path './.git/*' -exec rm -rf {} +
  2. 恢复脚本可执行位:WSL /mnt/d 是 777,搬到 ext4 或经 zip/Windows 盘中转可能丢 exec 位。chmod +x tools/*.sh tools/tokenizer/*.sh tests/flash/*/build.sh,或直接 bash <script>
  3. 行尾:若曾在 Windows 编辑过,CRLF 会让脚本 bad interpreter: /usr/bin/env bash^Msed -i 's/\r$//' <script>(或 dos2unix)。
  4. 放原生 ext4 路径(别留在 /mnt/d):避免 777 权限、*:Zone.Identifier 残留、 以及跨文件系统的慢 IO。

7.4 其它既有约束

  • 主 sysroot 是 apt 的 /usr/riscv64-linux-gnu/opt/riscv(newlib)仅 tools/bench/firmware 的部分 L1 固件目标需要。
  • tests/sim/*/elf_to_verilog.sh 额外依赖 riscv64-unknown-elf-objcopy/objdump
  • 算子库只有一份 kernel/models/qwen3/KERNEL_DIR=../../kernel 引用,别再往 模型目录里拷内核。
  1. 算子库只有 kernel/ 一份;models/qwen3/MakefileKERNEL_DIR=../../kernel 引用, 不要再在模型目录内拷贝内核。

附:项目结构(PyTorch / vLLM 式分层)

仓库按「编译内核 ↔ 模型运行时 ↔ 平台抽象 ↔ 工具 ↔ 测试 ↔ 文档」分层,每一类只有单一可信源(不再有三份内核 / 两份模型工作区的复制)。

work/
├── kernel/             # 唯一算子库 libops_kernels(= vLLM csrc / pytorch aten)
│   ├── include/backends/{scalar,rvv,ame,mix,w4a8}/
│   ├── src/backends/{scalar,rvv,ame,mix,w4a8}/
│   └── tests/          # 旧算子单元测试 / 探针,benchmark 已迁到 tools/bench/firmware
├── platform/           # 设备/启动抽象:uart、crt、encoding(= vLLM platforms)
│   └── linker/         # *.ld 链接脚本
├── tokenizer/          # 分词器组件:tokenizer_bpe.c + data/(词表/merges)
├── models/qwen3/       # Qwen3-0.6B W8A8 端到端运行时(= model_executor/models)
│   └── model_data/     # config.json 入树;*.bin 权重 blob 为生成物(gitignore)
├── tools/              # 离线脚本(= pytorch/tools + vLLM 量化转换)
│   ├── quantization/   # 权重量化 / 打包:W8A8 tile、W4A8、prune_lm_head…
│   ├── tokenizer/      # tokenizer blob 生成
│   ├── calib/          # 激活校准统计
│   └── bench/firmware/ # FPGA benchmark 固件(L1 峰值 / DMA-SPM / operator profile)
├── tests/              # 集成测试:sim(RTL 波形镜像)/ flash(FPGA 烧录 bin)
└── docs/               # ame/ dma/ quantization/ operator_report/ disasm/
目录 内容
kernel/ 算子库 libops_kernels(scalar / RVV / AME / mix / w4a8 后端)
tools/bench/firmware/ FPGA benchmark 固件:L1 峰值、DMA/SPM、AME operator profile
platform/ UART 驱动、启动 crt、encoding.hlinker/*.ld
tokenizer/ BPE 分词器与词表数据
models/qwen3/ Qwen3-0.6B W8A8 端到端裸机固件(运行时 + Makefile + model_data)
tools/ 量化 / tokenizer / 校准的离线 Python 脚本与编排 shell
tests/sim/* RTL 波形仿真 bin + Verilog memory image
tests/flash/* FPGA flash 烧录 bin
docs/ AME / RVV 指令手册、DMA 用法、量化、算子报告、反汇编

W8A8 vs beta:原 qwen3-w8a8qwen3-w8a8-beta 已合并为单一主干 models/qwen3/(非 beta 为正统:更新、且含 SPM 流式 decode)。beta 的实验性运行时(窗口注意力、no-sat 激活量化)保留在重组前检查点的 git 历史中,可按需作为构建开关复活;其可复用工具(prune_lm_head.py)与数据变体已并入 tools/

关于
2.4 GB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号