Skip to content

Our recommended way to write testbenches is racy #377

Closed
@whitequark

Description

@whitequark

We currently nudge people towards writing testbenches where the testbench modifies signals (inputs, registers) on the same edge as the edge-triggered synchronous logic (i.e. posedge for default posedge domains), but this is wrong:

  1. testbenches written like this are susceptible to races, especially if yield Settle() is used;
  2. VCD files produced by testbenches written like this are hard to read because changes to inputs (and, rarely, registers) made by the bench, as well as any combinatorial logic triggered by those changes, appear at the same instant of time in the waveform viewer as the changes caused by the posedge.

Migen did not suffer from the problem (1) because it had a far simpler simulator that always ordered synchronous logic after the testbench logic and had no way to advance the simulation by zero time. (However, this caused severe issues for testbench logic by making it impossible to observe combinatorial feedback; e.g. it is not possible to implement a 1-cycle FIFOInterface.read() in Migen).

Migen did suffer from the problem (2).

Activity

whitequark

whitequark commented on May 3, 2020

@whitequark
MemberAuthor

See also #228.

whitequark

whitequark commented on May 3, 2020

@whitequark
MemberAuthor

What I think we should do is to recommend using the inactive edge of a clock domain for testbench logic. This is actually already the recommended way to use CXXRTL, for the same reason. This implies eliminating or reworking Tick as it currently exists.

whitequark

whitequark commented on Oct 20, 2020

@whitequark
MemberAuthor

There is a partial solution to issue (1) in a branch. We discussed issue (2) on IRC and it is possible that nothing needs to be done there because if the DUT was embedded in a normal module, the waveform dump would have the same problem as with the recommended way of writing testbenches.

github-4o

github-4o commented on Mar 10, 2021

@github-4o

my group has been using this approach for years cause we run our testbenches for both rtl and post-synthesis netlists. so the first things i did with nmigen is:

  1. add inactive edge action for sim
  2. add compatibility layer for nmigen sim and cocotb

the letter ensures we'll run the same testbenches for nmigen code, generated rtl and partial vendor-specific netlists. not quite there yet, but we are working towards it.

that was my 5 cents invested into motivation for inactive edge action. as for the actual fix, i'm using the attached patch
patch_nmigen_sim.txt

whitequark

whitequark commented on Apr 13, 2024

@whitequark
MemberAuthor

This issue is resolved by the combination of #1232 (which allows visualizing delta cycles in Python simulations) and #1213 (which is a meta-issue that thoroughly improves our simulation semantics).

added this to the 0.5 milestone on Apr 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @whitequark@github-4o

        Issue actions

          Our recommended way to write testbenches is racy · Issue #377 · amaranth-lang/amaranth