Challenge #27 - ajainPSU/ECE410-510-Codefests GitHub Wiki

Overview

The final phase of this design flow centers on systematically verifying, validating, and benchmarking the hardware design to ensure its correctness and performance in preparation for hardware-software co-design integration. This stage builds upon earlier functional development by applying rigorous verification strategies to obtain a benchmark of the actual system that has been being built up throughout the term.

In this challenge, modern verification practices are applied through a structured 10-step methodology, incorporating constrained random testing, coverage metrics, Python reference model comparison, performance benchmarking, regression testing, and corner-case stress tests. Using cocotb as a co-simulation framework, the design is evaluated across both functional correctness and performance dimensions, comparing results against the software reference model. The process ultimately generates comprehensive validation reports and final benchmarking results, forming the last critical step before any potential hardware synthesis or deployment.

Verification Testbench & Coverage Tracker

The cocotb testbench from Challenge #25 was edited extensively, and is structured as such:

  • initialize_dut(): Applies initial clock generation, reset sequencing, and SPI line initialization for simulation setup and ensures all hardware registers and FSMs begin in a known state before stimulus is applied.

  • Reference Model Integration: Uses software reference model (QRCodeRecognizer) for hardware/software comparison. Both hardware (hardware_mode=True) and software (hardware_mode=False) models can be invoked for side-by-side verification, which allows for full-cycle HW-SW behavioral comparison during Reed-Solomon and perspective warp tests.

  • Functional Validation Tests:

  1. test_hw_vs_sw_rs_correction(): Verifies Reed-Solomon correction hardware against the software reference model, randomly generates test payloads with injected random bit errors, compares hardware-corrected outputs with software reference corrections, logs results into performance CSV logs.
  2. test_hw_vs_sw_warp_identity(): Verifies the warp_image() pipeline using an identity homography matrix, applies known checkerboard patterns. Allows future insertion of additional SPI hardware validation calls.
  • Constrained Random Verification (CRV):
  1. test_randomized_rs_correction(): Randomly generates Reed-Solomon payloads and error locations, tests pipeline robustness across random message lengths, symbol counts, and injected errors.
  2. test_randomized_image_warp(): Generates randomized synthetic binary images and small perturbation homographies, tests the robustness of warp transformations under varying geometry.
  • Boundary & Corner Case Tests: test_overflow_underflow() which tests system stability under extreme message lengths (msg_len=1 and msg_len=255) and validates that no overflow/underflow behavior occurs inside hardware datapaths.

  • SPI Master Driver: Under the class SPIMaster(), which fully models SPI master functionality (clock edge generation, full byte serialization (MOSI/MISO), and CS activation/deactivation). Also allows complete SPI-based transactions.

  • Logging & Performance Tracking: Detailed logs are automatically written with timestamped filenames, performance data is exported to CSV for post-simulation analysis, and logs both simulation time and test parameters for regression test reporting.

  • FSM coverage hooks: Includes commented scaffolding for full FSM coverage tracking (Berlekamp-Massey, Chien search, Forney algorithm) to allow eventual collection of complete state-transition coverage metrics.

The coverage_manager.py module provides a general-purpose functional coverage infrastructure to track finite state machine (FSM) behavior during hardware simulation. It is designed to complement the main cocotb_testbench_validation.py testbench by enabling formal measurement of how thoroughly the verification tests exercise internal hardware control logic — particularly FSM states inside Reed-Solomon decoders (Berlekamp-Massey, Chien Search, Forney Algorithm) and control datapaths. While the primary testbench validates functional correctness by comparing hardware output to software reference models, the Coverage Manager allows additional structural coverage monitoring by observing which states inside FSM-based modules are actually exercised during test execution.

With an integration flow, it follows as:

  • Testbench startup: The testbench registers each hardware FSM (e.g., forney, chien, bm) using CoverageManager.register_module(). Full state spaces (e.g., [0,1,2,3,4]) for each FSM are defined for complete coverage tracking.
  • Simulation runtime: For any signal handle passed in, monitor_fsm() asynchronously samples the FSM state at periodic intervals (e.g., every 10ns). Every observed FSM state is recorded in real-time using observe_state().
  • After test completion: The coverage report is printed to console and optionally exported via export_report().

NOTE: HW model call is temporarily skipped for debugging (scaffold prepared). TestFactory failed.

Results

Figure 1 below shows the partial results I was looking for from validating my design.

Final-ish 1

Final-ish2

Figure 1: Final-ish results of validation of the project.

The results show that the testbench instantiates the DUT (qr_wrapper.v) and drives it with a sequence of randomized and edge-case test vectors, including Reed‑Solomon (RS) correction checks and perspective-warp evaluations. Each test resets the DUT, applies specific inputs, and asserts correctness by comparing hardware outputs against the Python reference model.

This testbench also integrates two processing paths: the RS decoder and the warp transformer. During RS correction tests, it injects error-bearing codewords and verifies the corrected outputs match the Python baseline. For the warp identity test, it loads a clean QR grid, lets the hardware warp it, and checks if the result matches the original grid—validating proper homography computation. The randomized warp test runs multiple iterations with varied homographies, ensuring broad functional coverage. Overflow/underflow tests push boundary conditions (e.g., minimal or maximal field sizes), verifying the hardware correctly handles RS message sizes from 1 to 255 bytes and 1 to 128 error bytes without failing.

The test run produced the following summary:

  • Test count: 5
  • All tests passed successfully—no mismatches between hardware and software during RS correction, identity warp, randomized warp, or overflow/underflow scenarios.
  • Simulation metrics:
  1. Total simulation cycles: ~1,010 ns for all tests.
  2. Real runtime: ~0.54 s with symmetric data throughput.
  • IO Performance: Averaging between 30–150 ns per transaction across different tests, with an overall TPS (transactions per second) metric of ~1,858 ns/s—indicative of high hardware efficiency under validation (commented-out tests were disabled).

Optional behavioral checks—such as detailed waveform dumps, value logging on every warp frame, or byte‑per‑byte comparison of RS vectors—are currently disabled. If reactivated, these would emit per-iteration debug output and waveform coverage, increased simulation cycles (runtime increasing to ~1500-2000 ns).

Issues/Problems

Figure 2 shows issues with the FSM based logic for verification.

MissingForney

Partial Results 2

Figure 2: FSM failures when running verification/validation.

When executing test_fsm_coverage_forney, the system attempted to activate state coverage monitoring for the finite state machine inside the forney_algorithm module. However, cocotb reported: **Forney FSM signals not found. Skipping FSM monitoring.

FSM coverage test completed in 1 cycles. FSM missed states: [0, 1, 2, 3, 4, 5, 6, 7, 8]**

The entire state machine for the Forney algorithm was not detected for coverage due to cocotb’s inability to locate the internal FSM signals. This suggests that either:

  • The FSM state signal (likely something like forney_state or state) was not properly exposed or retained in synthesis.
  • The Verilog module hierarchy was flattened or optimized such that cocotb’s hierarchical lookup (e_forney.*) could not resolve the signal.
  • The internal state register may not have been given a full (* keep *) attribute to prevent synthesis elimination.

As a result, the FSM test failed, with no state activity recorded. This is a coverage failure rather than a logic error.

During the broader test_coverage_all_fsms test, cocotb attempted to register cross-module FSM signals but encountered:

**Could not register FSM signals: qr_wrapper contains no object named syndrome_inst **

This suggests that within the current qr_spi_top module hierarchy (or the version of qr_wrapper used in this run), cocotb could not locate the expected syndrome submodule instance. This could occur if:

  • The syndrome calculator module was renamed, refactored, or flattened in synthesis.
  • The testbench’s expected hierarchical path was out-of-sync with the current RTL design.
  • Submodule instantiations were parameterized or conditionally instantiated in this synthesis pass.

Despite this, the overall system-wide FSM coverage test was able to pass for the FSMs that were registered successfully. The test sequence reached test_simultaneous_spi_conflicts, where arbitration and SPI contention were exercised. The test stalled after beginning the first SPI transfer:

Sending first SPI transfer...

No further events were logged. The simulation was manually interrupted via KeyboardInterrupt as the simulation was deadlocked or stalled that needs further debugging, as illustrated in Figure 3 below.

Partial Results V2b

Figure 3: Validation script running before keyboard interrupt (it stalled at this point).

Furthermore additional errors were detected which resulted in various tests being commented out:

  1. TestFactory Parameterization Misconfiguration, which had: TypeError: test_hw_vs_sw_rs_correction() got an unexpected keyword argument 'msg_len' where the test_hw_vs_sw_rs_correction function was written as a non-parameterized cocotb test. However, it was mistakenly registered with TestFactory using the parameterized call format, which caused TestFactory to attempt invoking it with additional arguments (msg_len, ec_bytes, etc.).

  2. Test Registration Looping & Apparent Infinite Simulation, where testing the regression validation appears stuck and processes all tests repeatedly. After commenting out the TestFactory instantiation, cocotb proceeded to execute all discovered tests sequentially (total of 9). Many tests failed early due to the unresolved parameterization and import errors, but cocotb continued progressing through the test suite, creating the illusion of a simulation hang.

  3. FSM Coverage Monitor Binding Issues where it reported as Forney FSM signals not found. Skipping FSM monitoring Where the forney_algorithm submodule's FSM signals were not correctly registered for coverage collection because hierarchical bindings were missing or incorrectly referenced.

Additionally there was an AttributeError on FSM coverage where it reported: qr_wrapper contains no object named syndrome_inst and qr_wrapper contains no object named active where FSM coverage attempted to bind to internal instances (like syndrome_inst or forney_inst.active) without correctly traversing hierarchical module paths from qr_wrapper.

  1. Blocking behavior during the "await" calls, where the simulation freezes after reset during test_hw_vs_sw_rs_correction(), which got blocked during the await call in the testbench: corrected_hw = await recognizer_hw.rs.correct_errors(test_msg[:], ec_bytes) This suggests the call into the hardware interface or its binding layer failed silently, likely due to the upstream missing imports, FSM binding problems, or incorrect DUT signal access.

Suggested improvements/resolutions

If I had more time, I would fix issues 1-4 above with the following plan:

  1. TestFactory
  • Step 1: Write a properly parameterized RS correction test function, such as: async def rs_correction_parameterized(dut, msg_len, ec_bytes, err_count):
  • Step 2: Update the TestFactory to reference this function.
  • Step 3: Remove any prior TestFactory bindings that still reference the old non-parameterized function (test_hw_vs_sw_rs_correction).
  • Step 4: Move any logic from the old function into the parameterized function as appropriate.
  1. Test Registration Looping & Supposed Infinite Simulation
  • Step 1: After fixing the parameterization (from above), verify that cocotb’s automatic discovery works properly by pruning duplicate or broken tests via utilizing "main" to call factory.generate_tests()
  • Step 2: Confirm that no non-parameterized versions remain accidentally registered.
  • Step 3: Run pytest --collect-only or cocotb-regression to validate the discovered test suite.
  1. FSM Coverage Monitor Binding Issues
  • Step 1: Review the hierarchal module instantiations from the very large verilog file that holds my hardware accelerated modules.
  • Step 2: In coverage_manager.py, rewrite signal bindings to access FSM signals via submodule instances.
  • Step 3: Validate FSM signal names match exactly the instantiated submodule names in qr_wrapper.
  • Step 4: Add additional error handling if hierarchical bindings fail, so debugging is easier for future FSM integration.
  1. Blocking Behavior During Awaiting Calls:
  • Step 1: Fully fix parameterization and FSM coverage issues first since it seems to derive from those.
  • Step 2: Confirm that recognizer_hw and its binding into cocotb is correct in which recognizer_hw must correctly wrap the DUT and manage input/output signal mapping and verify correct_errors() triggers the hardware pipeline and that signals flow properly between cocotb and Verilog.
  • Step 3: Add timeout wrappers around await calls to identify where the blockage occurs.
  • Step 4: Verify that reset behavior fully completes before entering the await call in which any race condition here can cause the await to hang -- which also seems to be the case.

LLM Inquiries

All following LLM inquiries with GPT-4o utilized the w9-codefest.pdf to analyze the suggestions/requirements for the testbench.

27-I1

27-I1b

27-I1c

Figure 4: LLM Inquiry to verify if step 1 of validation was meeting expectations.

27-I2

27-I2b

27-I2c

Figure 5: LLM Inquiry to get an example of a reset and interconnectivity logic.

27-I3

27-I3b

Figure 6: Another LLM inquiry about reset and interconnectivity logic.

27-I4

27-I4b

27-I4c

27-I4d

27-I4e

Figure 7: LLM Inquiry to verify if Step 2 of validation was fulfilled.

27-I5

27-I5b

27-I5c

27-I5d

27-I5e

Figure 8: LLM Inquiry to verify if Step 3 of validation was fulfilled.

27-I6

27-I6b

27-I6c

27-I6d

27-I6e

Figure 9: LLM Inquiry to verify if Step 4 of validation was fulfilled.

27-I7

27-I7b

27-I7c

27-I7d

Figure 10: LLM Inquiry to verify if Step 5 of validation was fulfilled.

27-I8

27-I8b

27-I8c

27-I8d

Figure 11: LLM Inquiry to verify if Step 6 of validation was fulfilled.

27-I9

27-I9b

27-I9c

27-I9d

Figure 12: LLM Inquiry to verify if Step 7 of validation was fulfilled.

27-I10

27-I10b

27-I10c

27-I10d

Figure 13: LLM Inquiry to verify if Step 8 of validation was fulfilled.

27-I11

27-I11b

27-I11c

27-I11d

27-I11e

27-I11f

Figure 14: LLM Inquiry to verify if Step 9 of validation was fulfilled.