Bug Report: With WritebackStage=1, FENCE.I refetches while an older store is still outstanding, so the next instructions can be stale
Maintainer thường phản hồi trong vòng 2 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 55/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Lĩnh vực
- operating-systems
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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:
- Ngôn ngữ chính
- SystemVerilog
- Star
- 2.2k
- Fork
- 836
- Merge trung bình
- 5 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 22
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của lowRISC/ibex
-
[Bug Report] rvfi_intr is not set on the first instruction of an exception handlerCó thể đã có người làm @h-filali đã nhận 6 ngày trước. Đang mởType:Bug
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 68/100
lowRISC/ibex#2556 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Type:Bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
lowRISC/ibex#2528 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
mip documentation errorĐang mởType:Bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 2 ngày
-
[doc] Document basic commands for running/checking IbexCó thể đã có người làm @shrutikbalwan đã nhận 46 ngày trước. Đang mởComponent:Doc Good First Issue Type:Task
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
lowRISC/ibex#741 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 42/100
Maintainer thường phản hồi trong vòng 2 ngày
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 89/100
-
Ship /Local/Applications, the Local domain's Applications folderCó thể đã có người làm @pkgdemon đã nhận hôm nay. Đang mởarea:base enhancement
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 94/100
nextbsd/nextbsd-userland#612 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày