Skip to content

[rtl] Two LTP shortenings: decoder illegal_insn don't-care + controller csr_pipe_flush qualifier#2441

Open
adsurg wants to merge 2 commits into
lowRISC:masterfrom
adsurg:decoder-dontcare-and-controller-csr-pipe-flush-trim
Open

[rtl] Two LTP shortenings: decoder illegal_insn don't-care + controller csr_pipe_flush qualifier#2441
adsurg wants to merge 2 commits into
lowRISC:masterfrom
adsurg:decoder-dontcare-and-controller-csr-pipe-flush-trim

Conversation

@adsurg
Copy link
Copy Markdown

@adsurg adsurg commented May 24, 2026

Summary

Two independent combinational-restructuring cleanups in the same region of the longest topological path (LTP) on the small-config Ibex. Each is a separate commit; both are pure functional no-ops (no register added, no pipeline-stage change, no architectural side-effect difference) and each shortens one arc of the LTP. The two commits are independent and can be merged separately if reviewers want to accept one but not the other.

The changes:

  1. ibex_decoder.sv — drop the csr_access_o = 1'b0 mask inside the illegal_insn catch-all. The mask is a functional no-op (downstream gating already prevents CSR side-effects for illegal instructions) but creates a long arc from decoder/illegal_insn through cs_registers/illegal_csr_insn_o back into id_stage/illegal_insn_o.
  2. ibex_controller.sv — drop the redundant & instr_valid_i from the csr_pipe_flush assignment. csr_pipe_flush_i is already qualified by instr_valid_i at the source (id_stage builds it from csr_op_en_o = csr_access_o & instr_executing & instr_id_done_o, and instr_executing AND-includes instr_valid_i), so the local AND is a logical identity.

Each change has its full safety argument in the commit message and inline code comment.

Critical path

Both changes target arcs in the dominant post-stall_id portion of the LTP:

  • csr_op_en_o → csr_pipe_flush_i → csr_pipe_flush → special_req_flush_only → special_req → halt_if → id_in_ready_o → ctrl_fsm_ns
  • The decoder commit additionally removes the back-arc from illegal_insn through csr_access_o → cs_registers.illegal_csr_insn_o → id_stage.illegal_insn_o → controller.exc_req_d → instr_kill that converges into the same chain.

Measurements

Pending per-PR isolated synthesis (Yosys + ltp on small-config Ibex; same flow as #2440). To be added before requesting final review.

Functional verification (small-config Ibex, both commits applied; rv32im, RV32MFast, RV32Zca, WB=1, BP=1, no PMP/icache/security):

test result
CoreMark 100i cycles unchanged (37,362,985)
CoreMark CRCs 0xe714 / 0x1fd7 / 0x8e3a (golden)
return42 / hello / fwd_test all pass with identical cycle counts

Security disclosure — decoder commit

The decoder commit leaves csr_access_o asserted for illegal instructions, which means cs_registers performs its internal CSR-address decode for the illegal opcode's CSR field. No architectural side-effect occurs — csr_op_en_o is gated low by instr_executing, which is forced low on illegal_insn. However, in threat models that include timing or power side-channels on illegal-instruction handling, the cs_registers internal decode is a side-channel surface that the original csr_access_o = 1'b0 mask did not expose.

For security-sensitive deployments (e.g. OpenTitan-style cores where illegal-instruction-decode side-channels may be in scope), reviewers may prefer to reject the decoder commit and accept the gate cost. The csr_pipe_flush commit has no equivalent concern.

adsurg added 2 commits May 24, 2026 17:51
The current decoder masks csr_access_o = 1'b0 inside the illegal_insn
catch-all. That mask is a functional no-op (downstream gating already
prevents CSR side-effects on illegal instructions) but creates a long
combinational arc on the longest topological path:

  decoder.illegal_insn -> decoder.csr_access_o ->
    cs_registers.illegal_csr_insn_o ->
      id_stage.illegal_insn_o (OR-merge) -> controller.exc_req_d ->
        id_stage.instr_kill -> instr_executing ->
          LSU FSM -> id_stage.stall_mem -> en_wb_o ->
            instr_id_done_o -> cs_registers.csr_op_en_i ->
              id_stage.csr_pipe_flush -> controller.special_req ->
                controller.halt_if -> id_in_ready_o -> ctrl_fsm_ns

Functional argument (see code comment): csr_op_en_o already AND-gates
csr_access_o with instr_executing & instr_id_done_o, and instr_executing
is forced low whenever an illegal_insn raises id_exception, so no CSR
side-effect can occur. The illegal_insn_dec=1 case is already OR-merged
into illegal_insn_o regardless of what illegal_csr_insn_o reports.

Combinational restructuring (don't-care simplification); no register
added, no pipeline-stage change, no architectural side-effect change.

SECURITY DISCLOSURE: leaving csr_access_o asserted for an illegal
instruction means cs_registers performs its internal address decode
for the illegal opcode's CSR field even though no architectural CSR
side-effect occurs. In threat models that include timing or power
side-channels on illegal-instruction handling, this is a side-channel
surface that the original mask did not expose. See code comment.
Reviewers in security-sensitive deployments (e.g. OpenTitan) may
prefer to retain the mask and accept the gate cost.

Single-block edit; +24 / -1 lines in ibex_decoder.sv.
…flush

csr_pipe_flush is currently computed as

  assign csr_pipe_flush = csr_pipe_flush_i & instr_valid_i;

The & instr_valid_i is redundant: csr_pipe_flush_i is already qualified
by instr_valid_i at its source. id_stage builds csr_op_en_o (which feeds
csr_pipe_flush_i upstream) as

  csr_op_en_o = csr_access_o & instr_executing & instr_id_done_o

and instr_executing already AND-includes instr_valid_i. So the AND here
is a logical identity (x & 1 = x in the cases where x can be 1).

Removing the redundant gate shortens the chain

  csr_op_en_o -> csr_pipe_flush_i -> csr_pipe_flush ->
    special_req_flush_only -> special_req -> halt_if ->
      id_in_ready_o -> ctrl_fsm_ns

which is the dominant post-stall_id portion of the longest topological
path on the small-config Ibex.

Combinational restructuring only; no new register, no pipeline-stage
change, no functional difference.

Single-line edit (plus comment); +10 / -1 lines in ibex_controller.sv.
@adsurg adsurg changed the title Decoder dontcare and controller csr pipe flush trim [rtl] Two LTP shortenings: decoder illegal_insn don't-care + controller csr_pipe_flush qualifier May 24, 2026
@adsurg adsurg marked this pull request as ready for review May 24, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant