Bug Report: With WritebackStage=1, FENCE.I refetches while an older store is still outstanding, so the next instructions can be stale
I maintainer di solito rispondono entro 2 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 55/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Ambito
- operating-systems
Direzione di ricerca
Start with the ID/EX FSM in rtl/ibex_id_stage.sv, especially the jump_in_dec case, and the decoder entry in rtl/ibex_decoder.sv that treats FENCE.I as a jump. Reproduce with the attached bench at data latency 2, then check that FENCE.I delays its refetch until the older store responds while ordinary jumps retain early fetch. Done when the instruction after FENCE.I sees the updated encoding at all tested latencies.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Hello I believe I've found a bug in this core. Please take a look.
Observed Behavior
With WritebackStage = 1, a store to instruction memory directly followed by FENCE.I can leave the next instruction stale. While the store waits in WB for its response, FENCE.I sits stalled in ID/EX, but its jump to pc+4 (flush and refetch) has already been issued. The refetch can reach memory before the store is performed, and the instruction after FENCE.I runs its old encoding.
| data response latency | expected | CHERIoT On | RV32E | WritebackStage = 0 (RV32E) |
|---|---|---|---|---|
1 cycle (+dlat=1) |
7, 9 | 7, 9 | 7, 9 | 7, 9 |
2 cycles (+dlat=2) |
7, 9 | 1, 2 | 1, 2 | 7, 9 |
3 cycles (+dlat=3) |
7, 9 | 1, 2 | 1, 2 | 7, 9 |
BranchTargetALU = 1 (the opentitan / maxperf* setting) gives 1, 2 at latency 2, like the default build.
Cause: FENCE.I is implemented as a jump to pc+4, and with the writeback stage a jump raises its pc set while an older load/store is still outstanding in WB. The early fetch is by design for ordinary jumps (comment at ibex_id_stage.sv:803-809); for FENCE.I it lets the refetch overtake the store FENCE.I is meant to order.
| what | where |
|---|---|
| FENCE.I is decoded as a jump to the next pc | rtl/ibex_decoder.sv:652 |
| the jump is raised when the instruction executes speculatively | rtl/ibex_id_stage.sv:885 |
jump_set_raw = jump_set_dec for every jump, FENCE.I included |
rtl/ibex_id_stage.sv:937 |
instr_executing_spec does not wait for an outstanding load/store in WB |
rtl/ibex_id_stage.sv:1045 |
Attached: simulation logs (evidence/shipped_*.log) and a formal counterexample (waveform/formal_cex.vcd, depth 10, data port answering 1 or 2 cycles after the grant): a store sh to 0x800000bc is granted in cycle 4 and answered in cycle 6; FENCE.I is stalled in ID/EX from cycle 5, but pc_set is 1 in cycle 5 and the refetch of 0x800000bc is granted then; in cycle 8 the instruction at 0x800000bc retires with its old encoding.
Expected Behavior
The instruction after FENCE.I runs its new encoding at every data latency (7, 9), as with WritebackStage = 0. RISC-V Unprivileged Specification, "Zifencei":
A FENCE.I instruction ensures that a subsequent instruction fetch on a RISC-V hart will see any previous data stores already visible to the same RISC-V hart.
A possible fix: do not raise FENCE.I's jump while an older memory access is outstanding; keep it in its first cycle until the access completes (it is stalled then anyway). In the jump_in_dec case of the ID/EX FSM, for example:
jump_in_dec: begin
if (icache_inval_o && (outstanding_load_wb_i | outstanding_store_wb_i) && ~lsu_resp_valid_i) begin
id_fsm_d = FIRST_CYCLE; // FENCE.I: wait for the older load/store before refetching
stall_jump = 1'b1;
end else begin
id_fsm_d = BranchTargetALU ? FIRST_CYCLE : MULTI_CYCLE;
stall_jump = ~BranchTargetALU;
jump_set_raw = jump_set_dec;
end
end
Ordinary jumps keep their early fetch.
Steps to reproduce the issue
Parameters: ibex_top with BaseIsa = ibex_pkg::BaseIsaRV32IorCHERIoT, RV32E = 1, WritebackStage = 1, other parameters at their defaults (no icache); cheriot_enable_i held On and, in a second run, Off (RV32E mode). Needed: WritebackStage = 1 and a data memory that answers a store more than one cycle after its grant (allowed by doc/03_reference/load_store_unit.rst). ibex_configs.yaml sets WritebackStage: 1 in opentitan, maxperf* and experimental-branch-predictor.
The upstream Simple System ties cheriot_enable_i off and answers data in one cycle, so the attached bench tb_ibex_cheriot.sv instantiates ibex_top directly (see README.txt). It answers a data request +dlat=N cycles after the grant and performs a store when it answers; fetches are answered one cycle after their grant. +define+AB_WB0 builds WritebackStage = 0, +define+AB_BTALU builds BranchTargetALU = 1.
fencei_smc.S (with crt.S, common.h, link.ld):
sw x12, 0(x11) # x12 = 0x00700513 = addi x10, x0, 7; x11 -> target
fence.i
target:
addi x10, x0, 1 # old encoding; report x10, expected 7
The second case stores addi x10, x0, 9 over addi x10, x0, 2.
git clone https://github.com/lowRISC/ibex && cd ibex && git checkout 626034d7- Run the attached script, which assembles the program, builds the bench with Verilator (
+define+SYNTHESIS) and runs it at latency 1, 2 and 3 in both modes:sh run.sh <ibex checkout> # assembles with: riscv32-unknown-elf-gcc -march=rv32emc_zicsr_zifencei_zcb -mabi=ilp32e -nostdlib -nostartfiles -T link.ld crt.S fencei_smc.S - Each
SIGline is the value ofx10for one case. Output at latency 2 (latency 3 is the same; latency 1 prints 7, 9):CHERIoT mode, data latency 2: SIG 00000001 SIG 00000002 RV32E mode, data latency 2: SIG 00000001 SIG 00000002
No changes to the Ibex source code.
My Environment
EDA tool and version:
Verilator 5.044 (simulation); riscv32-unknown-elf-gcc 16.1.0.
Operating system:
Red Hat Enterprise Linux 8.10
Version of the Ibex source code:
626034d7557ab85a6d989b13011b44296bad26fa (master, 2026-11-06), unmodified.
All of the relevant materials pertaining to the bug:
- Lingua principale
- SystemVerilog
- Stelle
- 2.2k
- Fork
- 836
- Merge medio
- 5g 8h
- PR unite (30g)
- 22
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di lowRISC/ibex
-
[Bug Report] rvfi_intr is not set on the first instruction of an exception handlerForse già presa @h-filali l’ha presa 6 giorni fa. ApertaType:Bug
Difficoltà 2/5 Mezza giornata Idoneità per principianti 68/100
lowRISC/ibex#2556 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
Type:Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
lowRISC/ibex#2528 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
mip documentation errorApertaType:Bug
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
I maintainer di solito rispondono entro 2 giorni
-
[doc] Document basic commands for running/checking IbexForse già presa @shrutikbalwan l’ha presa 46 giorni fa. ApertaComponent:Doc Good First Issue Type:Task
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
lowRISC/ibex#741 · 3 commenti ·
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 42/100
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di lowRISC/ibex
Issue simili
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 89/100
-
Ship /Local/Applications, the Local domain's Applications folderForse già presa @pkgdemon l’ha presa oggi. Apertaarea:base enhancement
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 94/100
nextbsd/nextbsd-userland#612 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno