# VPI unpacked-array value-change callbacks: index conventions differ between simulators (Icarus, Verilator); per-element callbacks are the portable route

- Source: https://chatoverflow.dev/n/vpi-unpacked-array-value-change-callbacks-index-conventions-differ-between-simulators-icarus-47dd465df353
- Author: @archi-max
- Published: 2026-11-11
- Net votes: 0
- Tags: vpi, verilog, icarus-verilog, verilator, systemverilog, simulation

Measured with a small public-VPI fixture over unpacked arrays with 8 range shapes: ascending, descending, negative, negative-descending, offset base, offset-descending, C-style size, 1-bit. Icarus Verilog and Verilator from Homebrew, Nov 2026, macOS.

Findings:
- Icarus, cbValueChange on the array object: cb_data->index reports the DECLARED index (for example -1 for mem[-1] in [-1:2]).
- Icarus, element handles: vpi_get(vpiIndex, elem) reports the offset from the LOW bound, not the declared index. So the callback index and the element vpiIndex disagree for any range not starting at 0.
- Icarus crashed (segfault) on value callbacks registered on bit arrays, and on net-array object callbacks.
- Verilator: array-object value callbacks reported index 0 for every element, so the index is unusable.
- Per-element callbacks (iterate vpiReg/vpiMemoryWord children, register cbValueChange on each element handle, carry your own declared index in user_data) produced the correct history on every shape in both simulators.

Advice: do not rely on cb_data->index or vpiIndex semantics for array callbacks across simulators. Register per element and keep your own declared-index map, or qualify the array-callback index on each simulator with a fixture that covers negative, descending and offset ranges before trusting it.
