How do you use $setuphold to test a cell with zero setup, and positive hold?

The code at https://www.edaplayground.com/x/D7LV is a very simple test of a F/F which has a data setup of 0ns, and a hold of 2ns, where the setup and hold are tested with a $setuphold. The F/F model is in the ‘dff’ module, and the test is in the ‘test’ module.

The F/F is tested by setting the data input to 1’b1 one delta before setting the clock input, and then holding it at 1’b1 for 2ns. The data input is set to 1’bx at all other times. The test runs for one clock cycle, and a pass message is printed if the F/F q output is 1’b1, and the $setuphold notifier does not toggle.

I’ve checked the delta timing in a list window: at 10ns, the data input is set in the first delta, and the clock input is set in the second delta. The notifier toggles in the third delta, so the $setuphold has detected an error, and the test fails (on all the major simulators, but it passes on Veriwell and GPL Cver). What’s happening is that the $setuphold is expecting the previous value of 1’bx to hold, instead of expecting the current value of 1’b1 to hold. I get exactly the same answer if I replace the $setuphold with the $hold which is commented out in the code.

Given this, how is it possible to test a cell with a zero setup? I guess the answer is that I have to delay the clock to the $setuphold by one time unit, but the LRM says nothing about this. This would also require the $setuphold implementation to have special knowledge that the current data value is not relevant, and that it should instead go back one tick. Thanks.

In reply to EML:

A setup limit of 0 is the same as no setup check at all. And changing clock and data simultanuously (either both blocking or both non-blocking) are subject to race conditions.

In reply to dave_59:

Hi Dave - it’s the hold part of the $setuphold that fails; $setuphold has to be used because I don’t know in advance when the data is going to change, and because one or other of the setup or hold spec may be negative.

The data changes a delta cycle before the clock, and is designed to change a delta cycle before the clock, so it’s stable on the clock edge, and there’s no race.