Observed Behavior
cellift/src/ift_rom_mem.sv line 171 has a SystemVerilog dimension-mismatch bug that
silently truncates every preloaded taint word to its LSB.
When the read_taints() initial block reports a successful load via $display (e.g. Bank 0: tainting addr/wbytes 0x20000120 to boot rom addr 0x120: 01f00000), the value stored in
the mem_taints associative array is actually 32'h00000000 for that key — only bit 0 of
the intended 32-bit word is written, and bits [31:1] are silently dropped.
The downstream effects observed in the VCD/FST trace:
i_instr_rom.rdata_o_taint_before_conservative stays at 0 for the entire simulation.
i_instr_rom.rdata_t0 likewise stays at 0.
instr_rdata_t0 at the core input is 0, so no instruction-fetch taint propagates into
the ibex core.
SIMROMTAINT is therefore effectively a no-op for any taint mask whose bit 0 is 0.
Expected Behavior
For a taint preload line such as
(taints the rs2 field of the instruction at PC 0x80000480, word-level mask
0x01F00000), mem_taints[<key>] should hold 32'h01F00000 after the initial block runs.
The downstream i_instr_rom.rdata_t0 should be 0x01F00000 when PC = 0x80000480 is
fetched, and instr_rdata_t0 at the core boundary should reflect this taint.
The companion file cellift/src/ift_sram_mem.sv already demonstrates the correct behavior
with a 32-bit OR (mem_taints[<key>] |= word).
Steps to reproduce the issue
Setup
-
Build a cellift-ibex simulation that fetches PC = 0x80000480. (Any firmware containing
an instruction at that PC works.)
-
Create a taint preload file (e.g. /tmp/rom_taint.txt) with a single line:
(Word mask 0x01F00000 = rs2 field bits [24:20]. Bit 0 of this word is 0, which
is what triggers the bug.)
-
Export the env var and run the test:
export SIMROMTAINT=/tmp/rom_taint.txt
cd cellift-ibex/cellift
bash tests.sh
What you will see
The taint loader reports success on stdout:
Preloading boot rom taints with: /tmp/rom_taint.txt (bank 0) (offset 80000000)
Bank 0: tainting addr/wbytes 0000000020000120 to boot rom addr 0000000000000120: 01f00000
Done preloading boot rom taints (bank 0).
The ROM read fires correctly for that address:
ROM_READ: word_addr=00000120 rdata=022243b3
But in the VCD/FST trace (out.trace):
i_instr_rom.rdata_o_taint_before_conservative stays 0 for the entire run.
i_instr_rom.rdata_t0 stays 0.
instr_rdata_t0 at the core input stays 0.
Discriminating test pair
Re-run with the following two masks to confirm the LSB-truncation mechanism:
| meminit hex string |
intended 32-bit mask |
bit 0 |
observed instr_rdata_t0 |
01000000 |
0x00000001 |
1 |
0x00000001 (bit 0 propagates) |
feffffff |
0xFFFFFFFE |
0 |
0x00000000 (full mask silently dropped) |
Without the bug, the feffffff row should produce instr_rdata_t0 = 0xFFFFFFFE.
Root cause
// cellift/src/ift_rom_mem.sv, line 144
logic [Width-1:0] mem_taints [bit [31:0]]; // one-dimensional, 32-bit per entry
// cellift/src/ift_rom_mem.sv, line 171
mem_taints[((section_addr-AddrOffset)/WidthBytes+i)/NumBanks][taint_id] = word;
// ^^^^^^^^^^
// With NumTaints == 1, taint_id = 0, so [0] is a 1-bit slice of the 32-bit
// entry. SystemVerilog assigns only word[0] into that bit; word[31:1] is
// silently discarded.
Suggested fix
Replace line 171 with the SRAM-style 32-bit OR (drops the spurious [taint_id]):
mem_taints[((section_addr-AddrOffset)/WidthBytes+i)/NumBanks] |= word;
This matches the behavior implied by the surrounding $display and brings the ROM preload
in line with ift_sram_mem.sv.
My Environment
EDA tool and version:
Verilator (any recent version) + cellift-yosys (this repository's bundled version).
Operating system:
Ubuntu 22.04
Version of the Ibex source code:
comsec-group/cellift-ibex master branch.
Scope / Affected designs
- Affected:
cellift-ibex only, and only the SIMROMTAINT preload path through
ift_rom_mem.sv.
- Not affected (SRAM-side):
SIMSRAMTAINT via ift_sram_mem.sv is correct (uses
32-bit |=).
Observed Behavior
cellift/src/ift_rom_mem.svline 171 has a SystemVerilog dimension-mismatch bug thatsilently truncates every preloaded taint word to its LSB.
When the
read_taints()initial block reports a successful load via$display(e.g.Bank 0: tainting addr/wbytes 0x20000120 to boot rom addr 0x120: 01f00000), the value stored inthe
mem_taintsassociative array is actually32'h00000000for that key — only bit 0 ofthe intended 32-bit
wordis written, and bits[31:1]are silently dropped.The downstream effects observed in the VCD/FST trace:
i_instr_rom.rdata_o_taint_before_conservativestays at0for the entire simulation.i_instr_rom.rdata_t0likewise stays at0.instr_rdata_t0at the core input is0, so no instruction-fetch taint propagates intothe ibex core.
SIMROMTAINTis therefore effectively a no-op for any taint mask whose bit 0 is0.Expected Behavior
For a taint preload line such as
(taints the
rs2field of the instruction at PC0x80000480, word-level mask0x01F00000),mem_taints[<key>]should hold32'h01F00000after the initial block runs.The downstream
i_instr_rom.rdata_t0should be0x01F00000whenPC = 0x80000480isfetched, and
instr_rdata_t0at the core boundary should reflect this taint.The companion file
cellift/src/ift_sram_mem.svalready demonstrates the correct behaviorwith a 32-bit OR (
mem_taints[<key>] |= word).Steps to reproduce the issue
Setup
Build a cellift-ibex simulation that fetches
PC = 0x80000480. (Any firmware containingan instruction at that PC works.)
Create a taint preload file (e.g.
/tmp/rom_taint.txt) with a single line:(Word mask
0x01F00000=rs2field bits[24:20]. Bit 0 of this word is0, whichis what triggers the bug.)
Export the env var and run the test:
What you will see
The taint loader reports success on stdout:
The ROM read fires correctly for that address:
But in the VCD/FST trace (
out.trace):i_instr_rom.rdata_o_taint_before_conservativestays0for the entire run.i_instr_rom.rdata_t0stays0.instr_rdata_t0at the core input stays0.Discriminating test pair
Re-run with the following two masks to confirm the LSB-truncation mechanism:
instr_rdata_t0010000000x000000010x00000001(bit 0 propagates)feffffff0xFFFFFFFE0x00000000(full mask silently dropped)Without the bug, the
feffffffrow should produceinstr_rdata_t0 = 0xFFFFFFFE.Root cause
Suggested fix
Replace line 171 with the SRAM-style 32-bit OR (drops the spurious
[taint_id]):This matches the behavior implied by the surrounding
$displayand brings the ROM preloadin line with
ift_sram_mem.sv.My Environment
EDA tool and version:
Verilator (any recent version) + cellift-yosys (this repository's bundled version).
Operating system:
Ubuntu 22.04
Version of the Ibex source code:
comsec-group/cellift-ibexmasterbranch.Scope / Affected designs
cellift-ibexonly, and only theSIMROMTAINTpreload path throughift_rom_mem.sv.SIMSRAMTAINTviaift_sram_mem.svis correct (uses32-bit
|=).