Test File: test_pe_diag.py

Back to Test: Systolic Gauss-Jordan.

Source file: test/systolic_gauss_jordan/test_pe_diag.py

RTL counterpart

What this test checks

This page corresponds to the direct cocotb truth-table test for the diagonal processing element. It is the shortest path from the RTL page to an executable behavior check.

The test:

  • resets the DUT

  • optionally preloads the internal diagonal state bit

  • enumerates reduce_sig_i, previous state, and data_i

  • compares observed outputs and next state against the Python golden model

How to run it

make -C test/systolic_gauss_jordan TEST=pe_diag

What to inspect while reading it

  • reset_dut() for the reset convention used by the suite

  • step() for the cycle-by-cycle driver pattern

  • pe_diag_truth_table_exhaustive() for the actual behavioral contract

Python source

 1import cocotb
 2from cocotb.clock import Clock
 3from cocotb.triggers import FallingEdge, ReadOnly, RisingEdge
 4
 5from trapeziod_test_utils import (
 6    OP_ADD,
 7    OP_LOCK,
 8    OP_PASS,
 9    OPCODE_NAMES,
10    pe_diag_golden,
11)
12
13
14async def reset_dut(dut):
15    await FallingEdge(dut.clk)
16    dut.rst.value = 1
17    dut.en_i.value = 1
18    dut.data_i.value = 0
19    dut.reduce_sig_i.value = 0
20
21    for _ in range(2):
22        await RisingEdge(dut.clk)
23
24    dut.rst.value = 0
25
26
27async def step(dut, data_i, reduce_sig_i):
28    await FallingEdge(dut.clk)
29    dut.data_i.value = data_i
30    dut.reduce_sig_i.value = reduce_sig_i
31    await RisingEdge(dut.clk)
32    await ReadOnly()
33
34    return {
35        "r": int(dut.r.value),
36        "data_o": int(dut.data_o.value),
37        "op_o": int(dut.op_o.value),
38        "reduce_o": int(dut.reduce_sig_o.value),
39    }
40
41
42@cocotb.test()
43async def pe_diag_truth_table_exhaustive(dut):
44    cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
45    dut.en_i.value = 1
46
47    for reduce_sig_i in (0, 1):
48        for r_prev in (0, 1):
49            for data_i in (0, 1):
50                await reset_dut(dut)
51
52                if r_prev == 1:
53                    preload = await step(dut, 1, 0)
54                    assert preload["r"] == 1, "Failed to preload pe_diag.r to 1"
55                    assert preload["op_o"] == OP_LOCK, (
56                        "Expected preload cycle to lock the diagonal state"
57                    )
58
59                observed = await step(dut, data_i, reduce_sig_i)
60                expected = pe_diag_golden(
61                    r_prev=r_prev,
62                    data_i=data_i,
63                    reduce_i=reduce_sig_i,
64                )
65
66                mismatch_row = (
67                    f"(reduce_sig_i={reduce_sig_i}, r_prev={r_prev}, data_i={data_i})"
68                )
69
70                assert observed["r"] == expected["r_next"], (
71                    f"{mismatch_row}: expected r_next={expected['r_next']}, "
72                    f"got {observed['r']}"
73                )
74                assert observed["data_o"] == expected["data_o"], (
75                    f"{mismatch_row}: expected data_o={expected['data_o']}, "
76                    f"got {observed['data_o']}"
77                )
78                assert observed["op_o"] == expected["op_o"], (
79                    f"{mismatch_row}: expected op_o={OPCODE_NAMES[expected['op_o']]}, "
80                    f"got {OPCODE_NAMES.get(observed['op_o'], observed['op_o'])}"
81                )
82                assert observed["reduce_o"] == expected["reduce_o"], (
83                    f"{mismatch_row}: expected reduce_o={expected['reduce_o']}, "
84                    f"got {observed['reduce_o']}"
85                )