FP8 Lands in XiangShan's Reference Model: Inside the Verification Stack for RISC-V Matrix Extensions
Every RISC-V matrix extension argument eventually collapses into the same question, and it is never the peak-throughput one. It is this: when two implementations disagree by one unit in the last place, which one is wrong? A matrix unit is a reduction tree with an accumulator, a rounding mode, a saturation flag and a signedness decision per operand pair, and any of those can differ between a vendor's RTL and a software model without either side being obviously broken. Peak TOPS is a marketing number. Agreement on the edge cases is the thing that lets a design tape out.
That is why the more interesting RISC-V news of the past week is not a chip launch. It is seventeen commits
landed across OpenXiangShan/NEMU and OpenXiangShan/difftest between 24 and 27
October 2026, which together move the XiangShan project's matrix-extension support from "the instruction
semantics are implemented" to "the numerical semantics are verifiable". FP8 arrives in the reference model with
FP32 accumulation. MMA event types stop being inferred from storage width and start being decoded from the
mcfg register. INT32 saturation becomes real on both the software and the GPU differencing backends.
And synchronous verification becomes a build flag.
What the Matrix Extension Actually Looks Like in Code
NEMU gates the whole feature behind CONFIG_RV_AME. The register file is modelled as matrix tile
registers plus a set of configuration registers, and the instruction set is small enough to enumerate. Reading
src/isa/riscv64/instr/ame/ on 29 October 2026 gives this:
| Instruction | Function |
|---|---|
minit | Initialise matrix state; sets mstatus.MS |
msettilem / msettilemi | Set tile row count (register / immediate form) |
msettilek / msettileki | Set reduction depth |
msettilen / msettileni | Set tile column count |
msetcfg / mgetcfg | Write / read one of 8 mcfg registers (index ≥ 8 is an illegal-instruction exception) |
mmacc | Matrix multiply-accumulate over the configured tile |
msyncreset / mrelease | Token-based synchronisation; token index bounded by MSYNC (default 16) |
mldst family | Matrix load / store, including a transpose fast path |
The geometry is compile-time configured. Defaults in src/isa/riscv64/Kconfig are
RV_AME_TLEN = 65536 bits (8 KiB per tile register) and RV_AME_TRLEN = 512 bits (64 bytes
per row), which yields ROWNUM = TLEN / TRLEN = 128 rows. RV_AME_MLEN = 32 bits drives
the accumulator sizing: ALEN = ROWNUM × ROWNUM × MELEN = 64 KiB, and
ARLEN = ROWNUM × MELEN = 512 bytes. Tile bounds follow directly:
TMMAX = TNMAX = ROWNUM, while TKMAX(sew) = TRLEN / sew — so with a 512-bit row the
reduction depth a single mmacc may request is 64 elements at 8-bit, 32 at 16-bit and 16 at 32-bit.
Widening the data type costs reduction depth, which is why tile shape and type have to be decided together.
The type encoding is a 15-entry table in mreg.h. It is worth reproducing because three of its
entries are the reason a naive verification harness silently passes:
enum MTYPECODE_TAB0 {
MTYPECODE_INT4 = 0, MTYPECODE_UINT4, MTYPECODE_INT8,
MTYPECODE_UINT8, MTYPECODE_INT32, MTYPECODE_NVFP4,
MTYPECODE_MXFP4, MTYPECODE_FP8E5M2, MTYPECODE_FP8E4M3,
MTYPECODE_FP16, MTYPECODE_BF16, MTYPECODE_TF32,
MTYPECODE_FP32, MTYPECODE_FP2PACK4, MTYPECODE_FP2PACK5
};
INT8 and UINT8 are one byte wide with different arithmetic meaning.
FP8E5M2 and FP8E4M3 are one byte wide with different exponent and mantissa splits
(5/2 versus 4/3), and INT8 is also one byte wide. Three distinct semantics, one storage width. Any
code path that carries only "how many bytes" is already wrong, which is exactly what commit #1269 was written to
fix.
The Type Matrix, Before and After #1266
mcompute_impl.h enumerates the multiply-accumulate combinations the model accepts. Comparing 24
October against 27 October gives a clean before/after:
| Operand pair | Accumulator | State |
|---|---|---|
| INT4 × INT4 | INT32 | Pre-existing |
| INT8 × INT8 | INT32 | Pre-existing |
| FP16 × FP16 | FP16 | Pre-existing |
| FP16 × FP16 | FP32 | Pre-existing |
| BF16 × BF16 | FP32 | Pre-existing |
| FP32 × FP32 | FP32 | Pre-existing |
| FP8 E4M3 × FP8 E4M3 | FP32 | Added 27 Oct 2026, #1266 |
| FP8 E5M2 × FP8 E5M2 | FP32 | Added 27 Oct 2026, #1266 |
The E4M3/E5M2 split is not cosmetic. E4M3 gives four exponent bits and three mantissa bits — more precision, narrower dynamic range, no infinity encoding. E5M2 gives five and two — range at the cost of mantissa. Training pipelines reach for one and inference stacks for the other, and a reference model that implements "FP8" as a single type will disagree with hardware on exactly the overflow-heavy inputs that matter.
FP4 is conspicuously not in the accepted list, and the reason is in mmacc itself:
#ifdef CONFIG_RV_AME_FP4
if (is_raw_fp4_type_code(s1mcfg) || is_raw_fp4_type_code(s2mcfg) ||
is_raw_fp4_type_code(dmcfg)) {
longjmp_exception(EX_II);
}
#endif
NVFP4 and MXFP4 exist in the type table but mmacc raises an
illegal-instruction exception when it sees them. The encoding knows about FP4; the execute path does not yet
implement it. That distinction is the difference between a roadmap and a claim.
Seventeen Commits in Ninety-Six Hours
Querying both repositories for the window 2026-10-24T00:00Z to 2026-10-28T00:00Z
returns 7 commits in NEMU and 10 in difftest. Reproduced verbatim, newest first:
| Repo | SHA | Timestamp (UTC) | Author | Subject |
|---|---|---|---|---|
| NEMU | a683e0bb | 10-27 09:45:31 | Haoyuan Feng | feat(configs): add layered BOOM reference profiles (#1262) |
| NEMU | 50a9a8e9 | 10-27 09:00:34 | Kunlin You | perf(memory): reuse HostTLB for shared FAST references (#1270) |
| NEMU | e581cb7a | 10-27 08:23:37 | Jiru Sun | feat(ame): support FP8 MMA with FP32 accumulation (#1266) |
| NEMU | fcdceb01 | 10-27 02:33:14 | Kamimiao | ci: give diff-spike NEMU 32 GiB of guest memory (#1267) |
| NEMU | 337bed5f | 10-26 15:04:12 | Kunlin You | refactor(config): reduce duplication with shared config layers (#1259) |
| NEMU | 44659658 | 10-26 15:00:29 | Jiru Sun | fix(ame): encode MMA event types from mcfg semantics (#1269) |
| NEMU | 783babde | 10-26 12:26:33 | Jiru Sun | fix(ame): preserve host FMA exception flags (#1268) |
| difftest | 1fa7d817 | 10-27 05:47:48 | Kunlin You | feat(fpga): separate DiffTest link and REF checking (#1006) |
| difftest | 0308e145 | 10-27 05:39:37 | Jiru Sun | feat(mma): add synchronous verification build option (#1009) |
| difftest | a5272489 | 10-27 04:31:39 | Jiru Sun | fix(mma): honor integer saturation in CPU and CUDA (#1008) |
| difftest | 2abc9f66 | 10-26 14:11:32 | Haoyuan Feng | feat(difftest): add BOOM DiffTest support (#998) |
| difftest | c1f6e347 | 10-26 06:18:46 | Kunlin You | fix(difftest): preserve C++11 build compatibility (#1003) |
| difftest | b548dc0e | 10-26 01:42:11 | Kunlin You | feat(reftrace): record and replay REF-driving traces (#981) |
| difftest | 2691d2b4 | 10-25 12:36:30 | Jiru Sun | perf(mma): use native-width operand loads (#1002) |
| difftest | 44065651 | 10-25 05:32:46 | Jiru Sun | perf(mma): use Tensor Cores for INT8 CUDA verification (#1001) |
| difftest | 15debf2c | 10-25 05:32:30 | Jiru Sun | perf(mma): specialize CUDA floating-point kernels by format (#1000) |
| difftest | 9027f0bf | 10-25 03:51:06 | Jiru Sun | perf(mma): avoid redundant operand and DUT result copies (#999) |
Note the shape of it. The 25th is throughput work — Tensor Cores, per-format kernel specialisation, fewer copies. The 26th is correctness work — semantics, flags, trace replay. The 27th is completeness and determinism — a new data type and a switch that trades parallelism for reproducibility. That is a team working through a verification stack in the order you would want them to.
Deep Dive 1: FP8 by Unifying, Not Bolting On
The interesting part of #1266 is the diffstat. mcompute_impl.c goes
+104 / −153 — the file shrinks by 49 lines while gaining a data type. The commit
message states the mechanism plainly: "Unify floating-point MMA vectorization and extend it to FP8."
The per-file breakdown:
| File | Diff | Why |
|---|---|---|
configs/riscv64-matrix-xs-lite_defconfig | +10 / −0 | New config for standalone matrix execution |
include/rtl/fp.h | +3 / −1 | FP type plumbing |
src/engine/interpreter/fp.c | +17 / −0 | Interpreter entry for 8-bit floats |
src/engine/interpreter/softfloat-fp.h | +33 / −0 | E4M3 / E5M2 conversion helpers |
src/isa/riscv64/instr/ame/mcompute.h | +6 / −0 | Type dispatch |
src/isa/riscv64/instr/ame/mcompute_impl.c | +104 / −153 | Unified vectorised float path |
src/isa/riscv64/instr/ame/mcompute_impl.h | +2 / −0 | Enumeration of new MMACC types |
The type-matching logic that results is deliberately boring, which is the point — one branch per
accepted combination, and everything else falls through to FLOAT_MMACC_UNSUPPORTED:
if (d_type == MTYPECODE_FP16 &&
s1_type == MTYPECODE_FP16 && s2_type == MTYPECODE_FP16) {
return FLOAT_MMACC_FP16_FP16_FP16;
} else if (d_type == MTYPECODE_FP32 &&
s1_type == MTYPECODE_FP16 && s2_type == MTYPECODE_FP16) {
return FLOAT_MMACC_FP16_FP16_FP32;
} else if (d_type == MTYPECODE_FP32 &&
s1_type == MTYPECODE_BF16 && s2_type == MTYPECODE_BF16) {
return FLOAT_MMACC_BF16_BF16_FP32;
/* ... FP32, then the two new entries ... */
} else if (d_type == MTYPECODE_FP32 &&
s1_type == MTYPECODE_FP8E4M3 && s2_type == MTYPECODE_FP8E4M3) {
return FLOAT_MMACC_FP8E4M3_FP8E4M3_FP32;
} else if (d_type == MTYPECODE_FP32 &&
s1_type == MTYPECODE_FP8E5M2 && s2_type == MTYPECODE_FP8E5M2) {
return FLOAT_MMACC_FP8E5M2_FP8E5M2_FP32;
}
Mixed FP8 inputs — E4M3 on one side, E5M2 on the other — are not in the accepted set. Neither is FP8 into an FP16 accumulator. Whether hardware should support either is a spec question, not an implementation one; right now the model's answer is no, and a differential test that feeds such a pair should expect an exception rather than a result.
Deep Dive 2: Why mcfg Semantics Beat Storage Width
#1269 is the commit that will save somebody a very bad week. Its message: "Separate AMU type payloads from byte-storage widths and integer arithmetic signedness. Use the semantic encoding for both MMA sources and the destination in REF, CTRL and diagnostic events." Three files, +41 / −7.
The failure mode it closes is subtle. Differencing does not compare operands — it compares events: a compact record saying "an MMA happened at this PC, with these operands, this type, this shape". If that record encodes the operand type as a storage width, then E5M2, E4M3 and INT8 all become "1 byte", and a model that computes E4M3 against RTL that computed INT8 will not be caught — the event descriptor matched. You get a green test and a wrong chip.
The fix moves the encoding to the mcfg register's semantics rather than its size, which means the
event now carries the actual type code out of the 15-entry table. It is a one-line concept and an unavoidable
one: the differencing ABI must be as typed as the ISA.
Deep Dive 3: Saturation, the Case the Docstring Admitted
Before #1008, the difftest documentation said this of the INT8 CUDA backend:
Integer MMA uses INT8 Tensor Core instructions on SM80 and newer targets,
retaining the software kernel on older targets. Accumulation wraps at 32
bits without saturation.
After #1008 the same paragraph reads:
Integer MMA uses INT8 Tensor Core instructions on SM80 and newer targets,
retaining the software kernel on older targets. Both paths support wrapping
and saturating INT32 accumulation.
One sentence changed; the consequences run through eight files. In the CUDA kernel the previous comment above the PTX was explicit about the choice:
// Before:
// No .satfinite: the accumulator wraps modulo 2^32, as in the integer reference model.
// After:
// Half dots start from zero; the caller applies the selected INT32 overflow mode.
The instruction itself is mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32 — an
M16 × N8 × K32 INT8 tile with an S32 accumulator, which is the shape most 8-bit
inference kernels are built around. What changed is that the sat field now travels with the request
instead of being assumed:
| File | Diff | What it now carries |
|---|---|---|
mma/backend/cuda/int8.cuh | +24 / −10 | Both overflow modes on the device |
mma/backend/mma_backend_cute_model.h | +18 / −4 | add_int32(lhs, rhs, saturate) with explicit clamp |
mma/backend/mma_backend_cpu.cpp | +4 / −3 | Same ReducePE chunk boundaries for both modes |
mma/backend/mma_backend_cuda.cpp | +1 / −0 | Copies amu_event.sat |
mma/backend/mma_backend_cuda_impl.{h,cpp} | +3 / −0 | sat in the batch descriptor |
mma/backend/mma_backend_cuda_kernel.cu | +5 / −4 | Threads the flag into the element kernel |
docs/sw-check.md | +1 / −1 | The honest sentence |
The new helper is about as small as code gets and about as easy to get wrong:
CUTE_MMA_HOST_DEVICE static inline int64_t add_int32(int64_t lhs, int64_t rhs, bool saturate) {
const int64_t result = lhs + rhs;
if (saturate) {
if (result > INT32_MAX) return INT32_MAX;
if (result < INT32_MIN) return INT32_MIN;
return result;
}
return wrap_signed(result, 32);
}
The comment above the calling loop is the tell that this was a real correctness fix and not a feature: "Follow the same ReducePE chunk boundaries for wrapping and saturation." A reduction tree that clamps at the end and one that clamps per chunk produce different answers, and the model has to clamp where the hardware clamps. That is the level at which matrix extensions are actually specified — or, today, not yet specified, which is why the model has to choose and the choice has to be recorded.
Deep Dive 4: Determinism as a Build Flag
Asynchronous differencing is how you get throughput: submit a buffer, let a worker thread verify it while the DUT keeps running, compare later. It is also how you lose error attribution, because by the time a mismatch surfaces the core has moved on and the reported PC may belong to a different instruction.
#1009 adds the escape hatch in cuda.mk, five lines including the comment:
MMA_ASYNC ?= 1
ifeq ($(MMA_ASYNC),0)
SIM_CXXFLAGS += -DCONFIG_DIFFTEST_MMA_SYNC
endif
With MMA_ASYNC=0 the verifier stops owning a thread. The header documents the contract change
directly: "With CONFIG_DIFFTEST_MMA_SYNC, submission verifies synchronously on the caller;
start()/stop() are no-ops and flush() reports the retained error." The
checker change in matrix.cpp is the part that matters for debugging:
+#ifdef CONFIG_DIFFTEST_MMA_SYNC
+ // Do not consume the next ready event after a synchronous failure.
+ if (mma_verifier->has_mma_verification_error()) {
+ set_error_pc(state->coreid, amu_event.pc);
+ return STATE_ERROR;
+ }
+#endif
That is the whole value of the flag: on failure, stop, and attribute the error to the PC that caused it.
The default stays asynchronous (MMA_ASYNC ?= 1), with MMA_BATCH_SIZE ?= 256 and
MMA_BACKPRESSURE_FACTOR ?= 4. So the same codebase gives you a fast mode for regression runs and a
deterministic mode for the afternoon you are chasing a one-in-ten-thousand mismatch.
The Supporting Cast
Three commits outside the MMA path are worth knowing because they change what the harness can do:
- #998, BOOM DiffTest support (26 Oct) — the out-of-order BOOM core gets a differencing path of its own, paired with NEMU's #1262 layered BOOM reference profiles. Matrix verification on an in-order model is a different problem from matrix verification behind a reorder buffer.
- #981, reftrace (26 Oct) — "record and replay REF-driving traces". When a mismatch takes hours to reproduce, being able to replay the exact reference-model input sequence is the difference between a bug report and a bug fix.
- #1006, FPGA split (27 Oct) — separates the DiffTest link from reference-model checking for FPGA targets, so a link-level stall no longer looks like a numerical mismatch.
And two smaller ones that are quietly important: #1268 preserves host FMA exception flags across model execution — without it, floating-point status bits leak between the model and its host and a differencing run can fail for reasons that have nothing to do with the DUT; #1270 reuses the HostTLB for shared FAST references, which is the kind of change that makes a 64-core run finish before lunch.
How to Read This
Three observations, offered as reading rather than conclusion.
First, the bottleneck has moved. A matrix unit with 128-row tiles and a 64 KiB accumulator is not something you can step through cycle by cycle in software any more. The 25 October commits moved INT8 comparison onto Tensor Cores precisely because the software kernel could not keep up with the DUT. Verification infrastructure is becoming hardware-accelerated in its own right, and that is a permanent change in how these projects are staffed.
Second, the unspecifiable parts are being specified by code. Saturation on overflow, the chunking of a reduction tree, whether mixed FP8 inputs are legal, what happens to NaN in E4M3 (which has no infinity encoding at all) — none of these are settled in a ratified document for matrix extensions today. They are being settled by whichever implementation ships first and by whether the reference model matches it. That is a normal phase for an ISA extension and a genuinely risky one for anyone building a second implementation against a document that does not yet say.
Third, the honest gaps are visible in the source. FP4 is encoded and rejected. Mixed FP8
pairs are rejected. There is no ratified spec to cite. A reader who wants to know what RISC-V matrix extensions
actually do in October 2026 is better served by mcompute_impl.h than by any slide deck, because the
code has to answer the questions the slides defer.
For the ecosystem, that is the useful signal in a week with no chip launch: the open-source RISC-V matrix stack is being hardened at the numerical-semantics layer, in public, with commit messages that explain the trade-off. When the specification does land, the projects that have been differencing against a typed reference model will be the ones that can claim compliance without an asterisk.
摘要(中文)
2026 年 10 月 24–27 日,香山团队在 OpenXiangShan/NEMU 与 OpenXiangShan/difftest
两个仓库共合入 17 笔提交(NEMU 7 笔、difftest 10 笔),把 RISC-V 矩阵扩展的支持从「指令语义已实现」
推进到「数值语义可验证」。
核心四点:
- #1266 FP8 矩阵乘加(10-27,Jiru Sun):参考模型新增 FP8
E4M3×E4M3→FP32与E5M2×E5M2→FP32。实现方式是「统一浮点 MMA 向量化路径」而非新开分支——mcompute_impl.c反而 净减 49 行(+104/−153)。混合 FP8 输入与 FP8→FP16 累加不在支持列表。 - #1269 按 mcfg 语义编码事件类型(10-26):把 AMU 事件的类型负载与「字节宽度」「整数有无符号」 解耦。此前 E5M2 / E4M3 / INT8 同为 1 字节,差分比对的事件描述符会误判通过——查不出来但芯片是错的。
- #1008 整数饱和(10-27):此前 CUDA INT8 后端注释明写「累加按 32 位回绕、不做饱和」,文档也照写;
现在 CPU 与 CUDA 两侧同时支持回绕与饱和,
sat标志从amu_event一路传到 batch descriptor 与设备内核。 - #1009 同步验证构建开关(10-27):
MMA_ASYNC=0定义CONFIG_DIFFTEST_MMA_SYNC,验证改在调用线程同步执行;同步失败后不再消费下一个事件, 错误 PC 归属正确。默认仍为异步(MMA_BATCH_SIZE=256)。
结构事实:默认配置 TLEN=65536 bit(8 KiB 每 tile 寄存器)、
TRLEN=512 bit(64 B 每行)→ ROWNUM=128;MELEN=32 → 累加器
ALEN 64 KiB;8 个 mcfg 寄存器、16 个 msync 令牌。NVFP4/MXFP4 在类型表中存在,
但 mmacc 会对其抛非法指令异常——编码已知、执行未实现。
一句话:这周没有芯片发布,但开源 RISC-V 矩阵栈正在公开地把「溢出、饱和、NaN、混合精度」这些 规范尚未定论的问题,一行一行地钉进参考模型里。
Кратко (RU)
С 24 по 27 октября 2026 года команда XiangShan внесла 17 коммитов в
OpenXiangShan/NEMU (7) и OpenXiangShan/difftest (10), переведя поддержку матричного
расширения RISC-V из состояния «семантика инструкций реализована» в состояние «числовая семантика
проверяема».
Четыре ключевых изменения: #1266 — FP8 MMA с накоплением FP32
(E4M3×E4M3→FP32, E5M2×E5M2→FP32), реализовано через унификацию
векторизованного пути; файл mcompute_impl.c при этом сократился на 49 строк
(+104/−153). Смешанные пары FP8 не поддерживаются. #1269 — типы событий MMA теперь кодируются из
семантики регистра mcfg, а не из ширины хранения: E5M2, E4M3 и INT8 все однобайтовые, и старая схема
пропускала ошибочные сравнения. #1008 — целочисленное насыщение INT32 теперь реально
поддерживается и на CPU-, и на CUDA-бэкенде; флаг sat доходит до ядра устройства.
#1009 — сборка с MMA_ASYNC=0 включает синхронную проверку
(CONFIG_DIFFTEST_MMA_SYNC), при сбое следующее готовое событие не потребляется, поэтому PC ошибки
указывается верно.
Геометрия по умолчанию: TLEN=65536 бит на tile-регистр, TRLEN=512
бит на строку → ROWNUM=128; MELEN=32 → аккумулятор 64 КиБ; 8 регистров
mcfg и 16 токенов msync. NVFP4/MXFP4 присутствуют в таблице типов, но
mmacc вызывает для них исключение недопустимой инструкции: кодирование есть, исполнения нет.
Resumen (ES)
Entre el 24 y el 27 de octubre de 2026 el equipo XiangShan integró 17 commits en
OpenXiangShan/NEMU (7) y OpenXiangShan/difftest (10), llevando el soporte de la
extensión matricial de RISC-V de «la semántica de instrucciones está implementada» a
«la semántica numérica es verificable».
Cuatro cambios clave: #1266 añade FP8 MMA con acumulación FP32
(E4M3×E4M3→FP32, E5M2×E5M2→FP32) unificando la ruta vectorizada:
mcompute_impl.c se reduce en 49 líneas (+104/−153). Las parejas FP8 mixtas no
están soportadas. #1269 codifica los tipos de evento MMA desde la semántica del
registro mcfg y no desde el ancho de almacenamiento — E5M2, E4M3 e INT8 ocupan un byte, y el
esquema anterior dejaba pasar comparaciones erróneas. #1008 implementa de verdad la
saturación INT32 en los backends CPU y CUDA; el campo sat llega hasta el kernel del dispositivo.
#1009 permite compilar con MMA_ASYNC=0 para verificación síncrona
(CONFIG_DIFFTEST_MMA_SYNC); tras un fallo no se consume el siguiente evento, de modo que el PC del
error es correcto.
Geometría por defecto: TLEN=65536 bits por registro de tile y
TRLEN=512 bits por fila → ROWNUM=128; MELEN=32 → acumulador de
64 KiB; 8 registros mcfg y 16 tokens msync. NVFP4/MXFP4 figuran en la tabla
de tipos, pero mmacc lanza una excepción de instrucción ilegal: codificados pero no
ejecutables.
Résumé (FR)
Entre le 24 et le 27 octobre 2026, l'équipe XiangShan a fusionné 17 commits dans
OpenXiangShan/NEMU (7) et OpenXiangShan/difftest (10), faisant passer le support de
l'extension matricielle RISC-V de « la sémantique des instructions est implémentée »
à « la sémantique numérique est vérifiable ».
Quatre changements clés : #1266 ajoute le MMA FP8 avec accumulation FP32
(E4M3×E4M3→FP32, E5M2×E5M2→FP32) en unifiant le chemin vectorisé
flottant : mcompute_impl.c perd 49 lignes (+104/−153). Les paires FP8 mixtes ne sont
pas prises en charge. #1269 encode les types d'événement MMA à partir de la
sémantique du registre mcfg et non de la largeur de stockage — E5M2, E4M3 et INT8 font un
octet, et l'ancien schéma laissait passer des comparaisons fausses. #1008 implémente
vraiment la saturation INT32 côté CPU et CUDA ; le drapeau sat parvient jusqu'au noyau
GPU. #1009 permet de compiler avec MMA_ASYNC=0 pour une vérification synchrone
(CONFIG_DIFFTEST_MMA_SYNC) ; après un échec, l'événement suivant n'est pas
consommé, donc le PC de l'erreur est correct.
Géométrie par défaut : TLEN=65536 bits par registre de tile,
TRLEN=512 bits par ligne → ROWNUM=128 ; MELEN=32 → accumulateur de
64 Kio ; 8 registres mcfg et 16 jetons msync. NVFP4/MXFP4 figurent dans la
table des types, mais mmacc lève une exception d'instruction illégale : encodés
mais non exécutables.
Zusammenfassung (DE)
Zwischen dem 24. und 27. Oktober 2026 hat das XiangShan-Team 17 Commits in
OpenXiangShan/NEMU (7) und OpenXiangShan/difftest (10) zusammengeführt und damit die
Unterstützung der RISC-V-Matrixerweiterung von „die Instruktionssemantik ist implementiert“ auf
„die numerische Semantik ist verifizierbar“ gehoben.
Vier Kernänderungen: #1266 ergänzt FP8-MMA mit FP32-Akkumulation
(E4M3×E4M3→FP32, E5M2×E5M2→FP32) durch Vereinheitlichung des
vektorisierten Gleitkommapfads; mcompute_impl.c schrumpft um 49 Zeilen (+104/−153).
Gemischte FP8-Paare werden nicht unterstützt. #1269 kodiert MMA-Ereignistypen aus der Semantik
des mcfg-Registers statt aus der Speicherbreite — E5M2, E4M3 und INT8 sind je ein Byte, und das
alte Schema ließ falsche Vergleiche durch. #1008 setzt INT32-Sättigung sowohl im
CPU- als auch im CUDA-Backend tatsächlich um; das sat-Flag reicht bis in den Device-Kernel.
#1009 erlaubt MMA_ASYNC=0 für synchrone Verifikation
(CONFIG_DIFFTEST_MMA_SYNC); nach einem Fehlschlag wird das nächste Ereignis nicht mehr konsumiert,
sodass der Fehler-PC stimmt.
Standardgeometrie: TLEN=65536 Bit pro Tile-Register, TRLEN=512 Bit pro
Zeile → ROWNUM=128; MELEN=32 → 64 KiB Akkumulator; 8 mcfg-Register
und 16 msync-Token. NVFP4/MXFP4 stehen in der Typtabelle, aber mmacc löst
dafür eine Illegal-Instruction-Exception aus: kodiert, aber nicht ausführbar.
خلاصه (FA)
در بازهٔ ۲۴ تا ۲۷ اکتبر ۲۰۲۶ تیم شیانگشان ۱۷ کامیت در
OpenXiangShan/NEMU (۷) و OpenXiangShan/difftest (۱۰) ادغام کرد و پشتیبانی از افزونهٔ
ماتریسی RISC-V را از «معناشناسی دستور پیادهسازی شده» به «معناشناسی عددی قابلراستیآزمایی» رساند.
چهار تغییر کلیدی: #1266 ضربجمع ماتریسی FP8 با انباشت FP32 را اضافه میکند
(E4M3×E4M3→FP32 و E5M2×E5M2→FP32) و این کار را با یکسانسازی مسیر
برداریشدهٔ اعشاری انجام میدهد؛ فایل mcompute_impl.c ۴۹ خط کوچکتر میشود
(+۱۰۴/−۱۵۳). جفتهای ترکیبی FP8 پشتیبانی نمیشوند. #1269 نوع رویداد MMA را از معناشناسی ثبت
mcfg رمزگذاری میکند نه از عرض ذخیرهسازی — E5M2 و E4M3 و INT8 هر سه یک بایتیاند و طرح قبلی
مقایسههای نادرست را رد نمیکرد. #1008 اشباع INT32 را در هر دو بکاند CPU و CUDA واقعاً پیاده
میکند و پرچم sat تا هستهٔ دستگاه منتقل میشود. #1009 با
MMA_ASYNC=0 راستیآزمایی همگام (CONFIG_DIFFTEST_MMA_SYNC) را فعال میکند؛ پس از خطا
رویداد بعدی مصرف نمیشود، بنابراین PC خطا درست گزارش میشود.
هندسهٔ پیشفرض: TLEN=65536 بیت برای هر ثبات کاشی و TRLEN=512 بیت
برای هر سطر → ROWNUM=128؛ MELEN=32 → انباشتگر ۶۴ کیلوبایت؛ ۸ ثبات
mcfg و ۱۶ توکن msync. NVFP4 و MXFP4 در جدول نوع وجود دارند، اما
mmacc برای آنها استثنای دستور نامعتبر تولید میکند: رمزگذاریشده ولی اجرانشده.
Sources / 参考来源
- NEMU
e581cb7a— feat(ame): support FP8 MMA with FP32 accumulation (#1266), 2026-10-27 08:23:37 UTC, Jiru Sun (+104/−153 in mcompute_impl.c) - NEMU
44659658— fix(ame): encode MMA event types from mcfg semantics (#1269), 2026-10-26 15:00:29 UTC - NEMU
783babde— fix(ame): preserve host FMA exception flags (#1268), 2026-10-26 12:26:33 UTC - NEMU — mcompute_impl.h (MMACC type enumerations: INT4/INT8, FP16, BF16, FP32, FP8 E4M3/E5M2)
- NEMU — mreg.h (MTYPECODE table, ROWNUM / TRENUM / ARENUM geometry macros)
- NEMU — Kconfig defaults: RV_AME_TLEN 65536, RV_AME_TRLEN 512, RV_AME_MLEN 32, RV_AME_MSYNC 16
- difftest
a5272489— fix(mma): honor integer saturation in CPU and CUDA (#1008), 2026-10-27 04:31:39 UTC - difftest
0308e145— feat(mma): add synchronous verification build option (#1009), 2026-10-27 05:39:37 UTC - difftest
44065651— perf(mma): use Tensor Cores for INT8 CUDA verification (#1001), 2026-10-25 05:32:46 UTC - difftest — docs/sw-check.md (MMA_BACKEND, MMA_ASYNC, CUDA_ARCH, INT8 Tensor Core note)
- OpenXiangShan/NEMU — repository (Mulan PSL v2)
- OpenXiangShan/difftest — differential testing framework