Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Add `vmv_x_s_hazard` app: regression reproducer for the VWXUNARY0 vs1 hazard (#436)
- Add `vlseg_eew` app: Spike-vs-Ara differential probe for the segment-load EEW tracker bug (#453)
- Add `vzext_vf8` app: Spike-vs-Ara differential probe for the vzext/vsext.vf8 source-width bug (#452)
- Add `vmerge_v0_illegal` app: Spike-vs-Ara trap probe for the masked vmerge vd=v0 legality check (#460)

### Fixed

- Clear `use_vs1` for VWXUNARY0 (`vmv.x.s`, `vcpop.m`, `vfirst.m`) to avoid a spurious vs1 hazard (#436)
- Tag all destination registers of segment loads/stores in the EEW tracker, fixing corrupted vd+1..vd+nf read-back (#453)
- Force the `vsext.vf8`/`vzext.vf8` source element width to EW8 instead of the tracked eew, fixing a wrong result when the source register's last-written eew was not the 1/8-width view (#452)
- Raise illegal-instruction for a masked `vmerge`/`vfmerge` whose destination is `v0` (overlaps the mask source), matching the RVV vd/v0 overlap rule; `vmv.v.*`/`vfmv.v.f` (vm=1) stay legal (#460)
- Fix dump vtrace script for vsetvli instructions without x0 (ideal dispatcher)
- Fix Pathfinder and FFT performance
- Stall Ara and wait for ara_idle upon CSR write/read
Expand Down
60 changes: 60 additions & 0 deletions apps/vlseg_eew/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2026 ETH Zurich and University of Bologna.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Spike-vs-Ara differential probe for issue #453 (segment load corrupts
// vd+1..vd+nf on read-back when EEW != EW8).
//
// vlseg4e16.v writes v8..v11. The per-vreg EEW tracker only tagged the base vd,
// so reading v9/v10/v11 back triggered a spurious on-read reshuffle that
// byte-packs the data. We load 4 segments of 4 fields, store each field, and
// print them; diff Spike vs Ara.

#include <stdint.h>

#ifdef SPIKE
#include "util.h"
#include <stdio.h>
#elif defined ARA_LINUX
#include <stdio.h>
#else
#include "printf.h"
#endif

static volatile uint16_t in_buf[16]; // 4 elements x 4 fields, element-major
static volatile uint16_t f0[4], f1[4], f2[4], f3[4];

int main() {
uint64_t vl;

// in_buf[i*4 + j] = base[j] + i, with base = {1, 11, 21, 31}
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
in_buf[i * 4 + j] = (uint16_t)((j * 10 + 1) + i);

asm volatile("vsetivli %0, 4, e16, m1, ta, ma" : "=r"(vl));
asm volatile("vlseg4e16.v v8, (%0)" ::"r"(in_buf));
asm volatile("vse16.v v8, (%0)" ::"r"(f0) : "memory");
asm volatile("vse16.v v9, (%0)" ::"r"(f1) : "memory");
asm volatile("vse16.v v10, (%0)" ::"r"(f2) : "memory");
asm volatile("vse16.v v11, (%0)" ::"r"(f3) : "memory");

// Expected: f0={1,2,3,4} f1={11,12,13,14} f2={21,22,23,24} f3={31,32,33,34}
for (int i = 0; i < 4; i++) printf("a%d=%d\n", i, (int)f0[i]);
for (int i = 0; i < 4; i++) printf("b%d=%d\n", i, (int)f1[i]);
for (int i = 0; i < 4; i++) printf("c%d=%d\n", i, (int)f2[i]);
for (int i = 0; i < 4; i++) printf("d%d=%d\n", i, (int)f3[i]);
return 0;
}
60 changes: 60 additions & 0 deletions apps/vmerge_v0_illegal/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2026 ETH Zurich and University of Bologna.
// SPDX-License-Identifier: Apache-2.0
//
// Spike-vs-Ara differential trap probe for issue #460: a masked vmerge whose
// destination is v0 (also the mask source) must raise an illegal-instruction
// exception (mcause=2). vmv.v.* (vm=1) with vd=v0 stays legal.
//
// vsetivli x8, 10, e8, m4
// vmv.v.x v0, -1 ; legal (vm=1), must NOT trap
// vmv.v.x v20, 0x33 ; legal
// marker = 1 ; proves setup did not trap
// vmerge.vim v0, v20, -2, v0 ; illegal -> trap, mcause=2
// Expected (both): cause=2, marker=1.

#include <stdint.h>
#ifdef SPIKE
#include "util.h"
#include <stdio.h>
#elif defined ARA_LINUX
#include <stdio.h>
#else
#include "printf.h"
#endif

volatile uint64_t g_cause = 0xbad;
volatile uint64_t g_marker = 0;

asm(".global mtvec_handler\n"
".align 2\n"
"mtvec_handler:\n"
" addi sp, sp, -16\n"
" sd t0, 0(sp)\n"
" sd t1, 8(sp)\n"
" csrr t0, mcause\n la t1, g_cause\n sd t0, 0(t1)\n"
" la t0, trap_resume\n csrw mepc, t0\n"
" ld t0, 0(sp)\n ld t1, 8(sp)\n addi sp, sp, 16\n"
" mret\n");

extern char trap_resume[];
uintptr_t handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs) {
(void)epc;
(void)regs;
g_cause = cause;
return (uintptr_t)trap_resume;
}

int main() {
asm volatile("fence" ::: "memory");
asm volatile("vsetivli x8, 10, e8, m4");
asm volatile("li t0, -1\n vmv.v.x v0, t0" ::: "t0"); // legal (vm=1)
asm volatile("li t0, 0x33\n vmv.v.x v20, t0" ::: "t0"); // legal
g_marker = 1; // setup did not trap
asm volatile("vmerge.vim v0, v20, -2, v0\n" // illegal
".global trap_resume\n"
"trap_resume:\n");
asm volatile("fence" ::: "memory");

printf("cause=%d marker=%d\n", (int)g_cause, (int)g_marker);
return 0;
}
82 changes: 82 additions & 0 deletions apps/vmv_x_s_hazard/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2026 ETH Zurich and University of Bologna.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Regression reproducer for issue #436.
//
// The VWXUNARY0 instructions (vmv.x.s, vcpop.m, vfirst.m) are decoded in the
// OPMVV path of ara_dispatcher.sv, where ara_req.use_vs1 defaults to 1'b1.
// Their rs1 field encodes the *sub-opcode*, not a vector register:
//
// vmv.x.s -> rs1 = 0b00000 (0) -> a buggy dispatcher reads a false vs1 = v0
// vcpop.m -> rs1 = 0b10000 (16) -> false vs1 = v16
// vfirst.m -> rs1 = 0b10001 (17) -> false vs1 = v17
//
// Leaving use_vs1 asserted makes the main sequencer raise a spurious RAW hazard
// against whatever register number occupies the rs1 field. The dominant failure
// mode is serialization or a deadlock (not data corruption), so:
// * a hang is caught by the testbench cycle-timeout, and
// * we additionally self-check the returned scalars to guard against any
// regression that would corrupt the result while "fixing" the hazard.
//
// This test deliberately writes v0 immediately before each vmv.x.s that reads
// an unrelated source register, building a tight producer/consumer chain on the
// register the bug falsely depends on.

#include <stdint.h>

#ifdef SPIKE
#include "util.h"
#include <stdio.h>
#elif defined ARA_LINUX
#include <stdio.h>
#else
#include "printf.h"
#endif

#define N_ITERS 8

int main() {
uint64_t vl;
int errors = 0;

// SEW = 64, LMUL = 1
asm volatile("vsetvli %0, zero, e64, m1, ta, ma" : "=r"(vl));

// Tight chain: write v0 (the register vmv.x.s falsely depends on), write the
// real source v8, then read back element 0 from v8 via vmv.x.s. A correct
// dispatcher does not stall on v0 here.
for (int i = 0; i < N_ITERS; i++) {
uint64_t poison = 0xAAAA000000000000ULL | (uint64_t)i; // goes into v0
uint64_t src = 0x1122334455660000ULL | (uint64_t)i; // goes into v8
uint64_t out;

asm volatile("vmv.s.x v0, %0" ::"r"(poison)); // false-dependency target
asm volatile("vmv.s.x v8, %0" ::"r"(src)); // actual source element 0
asm volatile("vmv.x.s %0, v8" : "=r"(out)); // must read v8, not wait on v0

if (out != src) {
printf("vmv.x.s iter %d: got 0x%lx, expected 0x%lx\n", i, out, src);
errors++;
}
}

if (errors == 0)
printf("vmv_x_s_hazard: PASS\n");
else
printf("vmv_x_s_hazard: FAIL (%d errors)\n", errors);

return errors;
}
32 changes: 32 additions & 0 deletions apps/vzext_vf8/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2026 ETH Zurich and University of Bologna.
// SPDX-License-Identifier: Apache-2.0
//
// Spike-vs-Ara differential probe for issue #452 (vzext.vf8 reads the wrong
// source width). v28[0] (e16) = 0xa04f; vzext.vf8 to e64 should zero-extend the
// 8-bit sub-elements: v14[0]=0x4f, v14[1]=0xa0. Register-only (no race).

#include <stdint.h>
#ifdef SPIKE
#include "util.h"
#include <stdio.h>
#elif defined ARA_LINUX
#include <stdio.h>
#else
#include "printf.h"
#endif

int main() {
uint64_t x20, x21;
uint64_t v = 0xa04f;

asm volatile("vsetivli x8, 1, e16, mf4, ta, ma");
asm volatile("vmv.s.x v28, %0" ::"r"(v));
asm volatile("vsetivli x8, 27, e64, m1, ta, ma");
asm volatile("vzext.vf8 v14, v28");
asm volatile("vmv.x.s %0, v14" : "=r"(x20)); // expect 0x4f = 79
asm volatile("vslidedown.vi v15, v14, 1");
asm volatile("vmv.x.s %0, v15" : "=r"(x21)); // expect 0xa0 = 160

printf("x20=%d x21=%d\n", (int)x20, (int)x21);
return 0;
}
Loading