Observed Behavior
With SecureIbex=1, WritebackStage=1, BranchTargetALU=0, and runtime data-independent timing enabled, a branch held behind an outstanding writeback load produces an instruction fetch before the ID FSM reaches its target-calculation cycle.
For a not-taken beq x5,x6,+16 at PC 0x1000, with x5=0x100 and x6=0x20, the production decoder, ID controller/FSM, ALU, and prefetch buffer produce:
IBEX_SECURE_PENDING_REDIRECT first_cycle=1 branch_taken=0 target=000000e0 expected=00001004
IBEX_SECURE_INSTR_BUS redirect=000000e0 branch_taken=0 first_cycle=1
IBEX_SECURE_INSTR_BUS redirect=00001004 branch_taken=0 first_cycle=0
BUG_CONFIRMED: SecureIbex exposed a spurious instruction fetch to 0x000000e0 before correcting to PC+4 (0x00001004)
The test also runs the same pending not-taken branch with runtime data-independent timing disabled and observes no early redirect.
Expected Behavior
A branch blocked in its comparison cycle must not expose the comparison ALU result as an instruction address. In fixed-time mode, the not-taken redirect should be PC+4 after the registered branch decision is available.
Impact
The later redirect corrects architectural control flow, so this report does not claim that the branch finally retires to the wrong PC. The defect is the additional externally visible fetch to an address derived from rs1-rs2; it adds unintended instruction-bus traffic and exposes an operand-dependent address in a mode whose documented purpose is data-independent timing and power behavior.
Steps to reproduce the issue
I have provided some scripts to reproduce the bug. From this issue directory, run:
Scripts: test.zip
My Environment
EDA tool and version: Verilator 5.020
Operating system: Linux x86_64
Version of the Ibex source code: 8b8ee086aef72e0833b7f0493d9d33e1f4d3c8e2
Root cause analysis
branch_set_raw_q captures branch_set_raw_d every cycle, while id_fsm_q advances only when instr_executing is true. An outstanding writeback memory access suppresses instr_executing but not the branch-set register update. With data-independent timing enabled, branch_set_raw_d is asserted even for a not-taken branch, so the controller raises pc_set_o while the decoder still selects the first-cycle comparison operands. The source already contains a comment that this register should be qualified with instr_executing.
Possible fix
Qualify the branch_set_raw_q update with instr_executing, consistent with the ID FSM update, or otherwise suppress branch_set until the branch target operands are selected. Add a regression asserting that a blocked first-cycle branch cannot issue an instruction request using the comparison result.
Observed Behavior
With
SecureIbex=1,WritebackStage=1,BranchTargetALU=0, and runtime data-independent timing enabled, a branch held behind an outstanding writeback load produces an instruction fetch before the ID FSM reaches its target-calculation cycle.For a not-taken
beq x5,x6,+16at PC0x1000, withx5=0x100andx6=0x20, the production decoder, ID controller/FSM, ALU, and prefetch buffer produce:The test also runs the same pending not-taken branch with runtime data-independent timing disabled and observes no early redirect.
Expected Behavior
A branch blocked in its comparison cycle must not expose the comparison ALU result as an instruction address. In fixed-time mode, the not-taken redirect should be
PC+4after the registered branch decision is available.Impact
The later redirect corrects architectural control flow, so this report does not claim that the branch finally retires to the wrong PC. The defect is the additional externally visible fetch to an address derived from
rs1-rs2; it adds unintended instruction-bus traffic and exposes an operand-dependent address in a mode whose documented purpose is data-independent timing and power behavior.Steps to reproduce the issue
I have provided some scripts to reproduce the bug. From this issue directory, run:
Scripts: test.zip
My Environment
EDA tool and version: Verilator 5.020
Operating system: Linux x86_64
Version of the Ibex source code:
8b8ee086aef72e0833b7f0493d9d33e1f4d3c8e2Root cause analysis
branch_set_raw_qcapturesbranch_set_raw_devery cycle, whileid_fsm_qadvances only wheninstr_executingis true. An outstanding writeback memory access suppressesinstr_executingbut not the branch-set register update. With data-independent timing enabled,branch_set_raw_dis asserted even for a not-taken branch, so the controller raisespc_set_owhile the decoder still selects the first-cycle comparison operands. The source already contains a comment that this register should be qualified withinstr_executing.Possible fix
Qualify the
branch_set_raw_qupdate withinstr_executing, consistent with the ID FSM update, or otherwise suppressbranch_setuntil the branch target operands are selected. Add a regression asserting that a blocked first-cycle branch cannot issue an instruction request using the comparison result.