cocotb_benches.dau_row_unpack_slots_tb

Attributes

SLOTS

OUT_WIDTH

IN_WIDTH

PAD_PACKED

PAD_ROW

Functions

multi_slot_unpack_matches_golden(dut)

every_slot_reads_its_own_packed_row(dut)

The stride test, stated directly.

random_field_maps_match_golden(dut)

Sweep field maps, not just the q6 one: an offset/width/sign combination

ragged_tail_pads_pass_through_unsliced(dut)

A row count that is not a multiple of SLOTS is padded by the host with

backpressure_preserves_rows_and_order(dut)

output_last_lands_on_the_final_beat(dut)

sustained_ingest_meets_the_slots_floor(dut)

SLOTS rows per beat is the whole point of the parameter, so the rate is

_packable_specs(rng)

A random field map this tile will accept at the configured SLOTS.

_beats(words) → list[int]

Pack SLOTS packed rows into one input beat, row s at [64*s +: 64].

_decode_row(row) → tuple[int, int, int, int]

One 128-bit quad row: [63:0] = w0 = {value, key}, [127:64] = w1 = {aux1, aux0}.

_split_beat(beat) → list[int]

_start(dut) → None

_run_raw(dut, beats, specs, *[, ready_pattern]) → list[int]

The emitted quad rows, still undecoded, so a pad stays visible.

_run(dut, words, specs, *[, ready_pattern])

_send_beats(dut, beats) → None

_collect_output(dut, ready_pattern, *, expect_beats) → list[int]

_collect_with_last(dut) → tuple[list[int], int | None]

bypass_short_final_beat_is_not_torn(dut)

REGRESSION. At SLOTS == 1 an input beat is half a quad row, so

a_layout_that_could_forge_the_pad_is_rejected(dut)

REGRESSION. The all-ones packed word is the ragged-tail PAD at

Module Contents

cocotb_benches.dau_row_unpack_slots_tb.SLOTS
cocotb_benches.dau_row_unpack_slots_tb.OUT_WIDTH
cocotb_benches.dau_row_unpack_slots_tb.IN_WIDTH
cocotb_benches.dau_row_unpack_slots_tb.PAD_PACKED = 18446744073709551615
cocotb_benches.dau_row_unpack_slots_tb.PAD_ROW = 340282366920938463463374607431768211455
async cocotb_benches.dau_row_unpack_slots_tb.multi_slot_unpack_matches_golden(dut)
async cocotb_benches.dau_row_unpack_slots_tb.every_slot_reads_its_own_packed_row(dut)

The stride test, stated directly.

One beat, every slot carrying a different key. A tile whose slice stride is hardcoded emits SLOTS copies of slot 0 and passes any test built on a uniform batch; here the keys are all distinct, so it cannot.

async cocotb_benches.dau_row_unpack_slots_tb.random_field_maps_match_golden(dut)

Sweep field maps, not just the q6 one: an offset/width/sign combination is what a hardcoded slice gets wrong at a width other than the one it was written against.

async cocotb_benches.dau_row_unpack_slots_tb.ragged_tail_pads_pass_through_unsliced(dut)

A row count that is not a multiple of SLOTS is padded by the host with the reserved all-ones packed word. It must emerge as the reserved all-ones PAD quad row – NOT as whatever the field descriptors would slice out of it – so the wide-row tiles downstream drop it by the convention they already implement.

async cocotb_benches.dau_row_unpack_slots_tb.backpressure_preserves_rows_and_order(dut)
async cocotb_benches.dau_row_unpack_slots_tb.output_last_lands_on_the_final_beat(dut)
async cocotb_benches.dau_row_unpack_slots_tb.sustained_ingest_meets_the_slots_floor(dut)

SLOTS rows per beat is the whole point of the parameter, so the rate is asserted against the registry declaration rather than assumed.

cocotb_benches.dau_row_unpack_slots_tb._packable_specs(rng)

A random field map this tile will accept at the configured SLOTS.

_random_specs happily fills all 64 bits, and at SLOTS > 1 a layout with no spare bit is refused as a bad config precisely because it could forge the all-ones PAD. Draw again until there is headroom rather than weakening the constraint – the rejection is the point.

cocotb_benches.dau_row_unpack_slots_tb._beats(words: list[int]) → list[int]

Pack SLOTS packed rows into one input beat, row s at [64*s +: 64].

cocotb_benches.dau_row_unpack_slots_tb._decode_row(row: int) → tuple[int, int, int, int]

One 128-bit quad row: [63:0] = w0 = {value, key}, [127:64] = w1 = {aux1, aux0}.

cocotb_benches.dau_row_unpack_slots_tb._split_beat(beat: int) → list[int]
async cocotb_benches.dau_row_unpack_slots_tb._start(dut) → None
async cocotb_benches.dau_row_unpack_slots_tb._run_raw(dut, beats, specs, *, ready_pattern=(1,)) → list[int]

The emitted quad rows, still undecoded, so a pad stays visible.

async cocotb_benches.dau_row_unpack_slots_tb._run(dut, words, specs, *, ready_pattern=(1,))
async cocotb_benches.dau_row_unpack_slots_tb._send_beats(dut, beats) → None
async cocotb_benches.dau_row_unpack_slots_tb._collect_output(dut, ready_pattern, *, expect_beats: int) → list[int]
async cocotb_benches.dau_row_unpack_slots_tb._collect_with_last(dut) → tuple[list[int], int | None]
async cocotb_benches.dau_row_unpack_slots_tb.bypass_short_final_beat_is_not_torn(dut)

REGRESSION. At SLOTS == 1 an input beat is half a quad row, so input_last on phase 0 really is a torn row. At SLOTS > 1 the beat holds SLOTS/2 WHOLE quad rows, and a batch with an odd number of rows ends exactly there – rejecting it as torn refuses a well-formed stream.

The generalization inherited the SLOTS == 1 rule unchanged, so this passed review and simulation until an independent reader asked what phase 0 MEANS when a beat carries whole rows.

async cocotb_benches.dau_row_unpack_slots_tb.a_layout_that_could_forge_the_pad_is_rejected(dut)

REGRESSION. The all-ones packed word is the ragged-tail PAD at SLOTS > 1. A field layout covering all 64 bits can PRODUCE all-ones from real data – four unsigned 16-bit fields at max – and that row would be dropped by the wide tiles. The same input unpacks normally at SLOTS == 1, so the ANSWER WOULD DEPEND ON OUT_WIDTH.

Rejecting the layout makes the sentinel unreachable by construction rather than by convention. Every real packing has room: SF1 q6 is 56 bits, q1 is 41.