In PLAY_STORED_DATA, the only exit conditions on playback_scl_fedge are:
-- line 346-357
elsif playback_scl_fedge = '1' and mux_r.playback_bits < sample_r.bit_count then
... -- output next bit
elsif playback_scl_fedge = '1' and mux_r.playback_bits = sample_r.bit_count and cpu_scl_in = '0' then
... -- hand off
end if;
The case playback_scl_fedge = '1' and mux_r.playback_bits = sample_r.bit_count and cpu_scl_in = '1' is entirely unhandled. Since playback runs considerably faster than the CPU SCL, this is the common case: playback finishes all buffered bits while the CPU SCL is still in its high phase.
What happens: the state machine sits in PLAY_STORED_DATA as the playback counter keeps running. On the next playback_scl_redge, v.playback_bits becomes bit_count + 1. Now neither fedge condition ever fires again (playback_bits < bit_count is false; playback_bits = bit_count is false). The machine is stuck, and each subsequent playback_scl_redge increments playback_bits further. Eventually it indexes sample_r.data_bits(7) or higher — out of bounds on a unsigned(6 downto 0).
Possible Fix: when playback has caught up (mux_r.playback_bits >= sample_r.bit_count), the right trigger for handoff is the CPU's own falling edge (cpu_scl_fedge), not a playback falling edge. Add a branch:
elsif cpu_scl_fedge = '1' and mux_r.playback_bits >= sample_r.bit_count then
v.state := ENSURE_PLAYBACK_HOLD;
...
end if;
This also eliminates the need to check cpu_scl_in on the playback edges for handoff: just wait for the actual CPU SCL falling edge.
Also by analysis and simulation, I haven't caught this in real hardware, but it is a class of bug totally dependent on data patterns and timing
In
PLAY_STORED_DATA, the only exit conditions onplayback_scl_fedgeare:The case
playback_scl_fedge = '1'andmux_r.playback_bits = sample_r.bit_countandcpu_scl_in = '1'is entirely unhandled. Since playback runs considerably faster than the CPU SCL, this is the common case: playback finishes all buffered bits while the CPU SCL is still in its high phase.What happens: the state machine sits in
PLAY_STORED_DATAas the playback counter keeps running. On the nextplayback_scl_redge,v.playback_bitsbecomesbit_count + 1. Now neither fedge condition ever fires again (playback_bits < bit_countis false;playback_bits = bit_countis false). The machine is stuck, and each subsequentplayback_scl_redgeincrementsplayback_bitsfurther. Eventually it indexessample_r.data_bits(7)or higher — out of bounds on aunsigned(6 downto 0).Possible Fix: when playback has caught up (
mux_r.playback_bits >= sample_r.bit_count), the right trigger for handoff is the CPU's own falling edge (cpu_scl_fedge), not a playback falling edge. Add a branch:This also eliminates the need to check
cpu_scl_inon the playback edges for handoff: just wait for the actual CPU SCL falling edge.Also by analysis and simulation, I haven't caught this in real hardware, but it is a class of bug totally dependent on data patterns and timing