Closed avelure closed 2 months ago
Hello @avelure , unrelated to this topic, I see that you are using NVC a lot and publishing a lot of bug reports. Could you try to test with the new code coverage implementation please ? It might reveal some bugs.
Hi, @Blebowski. It is on my agenda, I just haven't gotten around to it yet. I might have some work for you within a month or so :)
@avelure UVVM uses shared variables of an ordinary type for communication which was deprecated and removed from VHDL in the 2002 revision.
Using variables of this sort introduces to VHDL the same race conditions that exist in Verilog and the result is that two compliant simulators can produce different simulation results due to it. Especially if you are expecting something to happen at an exact clock cycle. Let me explain. During a given simulation cycle, perhaps due to clock rising, if both the process that sets a communication variable runs and the process that reads the communication variable runs, then whether the process that reads the variable sees what was set during that clock cycle or the next clock cycle will depend on which process runs first.
The LRM does not dictate the order in which simulators run a particular process and you will find that different simulators will indeed run the processes in different orders. It is even possible that due to optimization that a given simulator will run processes in different orders after recompiling a design.
Your warnings from ModelSim,
# ** Warning: (vsim-8684) No drivers exist on inout port /test/i1_axilite_vvc/axilite_vvc_master_if.write_address_channel.awready, and its initial value is not used.
# Therefore, simulation behavior may occur that is not in compliance with
are due to ModelSim doing port collapsing optimizations. What they are not clearly saying is that the result of this optimization modelsim may do something that is not in compliance with the standard. What it seams is happening in this sort of optimization is that the ports are removed from the design and the code is migrated up one level (sort of like unrolling a subprogram). As a result, the ports and any initializations (typically to Z) are gone. It should be noted that this sort of issue only potentially causes issues in simulators that do port collapsing optimizations (ie: modelsim). A long time ago, OSVVM interfaces initialized ports to all Z. I never saw an issue with it.
There are other ways to communicate with Verification Components that are language legal - such as what OSVVM does. See https://osvvm.org/archives/1668.
I looked at this a bit but I can't see anything obviously wrong. @avelure is there any way to spot the difference in behaviour in a waveform output? Does GHDL or another simulator give the same result as ModelSim?
Hello @avelure , unrelated to this topic, ...
@Blebowski BTW I just enabled GitHub Discussions for this project. That can be used in future for feedback, Q&A, etc.
Hi @nickg , thanks, I will use those for further questions.
@bpadalino tested with RiveraPRO and got the same result as Modelsim so there is probably a bug here somewhere.
Note that some of the transactions did happen in a different order.
Attaching all logs here for posterity.
I figured out how to fix the simulation. By adding another wait for 0 ns
here, the simulation completes just fine.
Unsure if this is a bug in nvc
and the calculation of the delta cycles, or if it's a race condition that UVVM is not considering and they need to change to wait an extra delta cycle in some other places?
h/t to @JimLewis for suggesting adding an extra delta cycle.
Yes, I found the same earlier, there is a delta-cycle transition that can be filtered out by adding delta-cycle waits at various places, but I don't think that fixes the root cause.
I think it might be due to handling of the protected variable queues, but I'm still investigating.
queues_are_empty(VOID)
returns true at one point where it shouldn't.
I think it might be due to handling of the protected variable queues, but I'm still investigating.
queues_are_empty(VOID)
returns true at one point where it shouldn't.
Just curious, what makes you say that it returns true
when it shouldn't? Is it possible the explanation @JimLewis gave above about the ordering of processes?
Do you know if there is something we can instrument to see if nvc
and modelsim
are running the processes in different orders?
Just trying to understand the thought process and to verify that indeed the function should return true when it isn't.
@avelure This was a curious problem to look at. I added to my notebook that when setting and reading flags in a shared variable - whether it is a protected type or ordinary type - you can run into process order issues.
So you need to work though the details of when await_completion reads any activity indication and when axilite_write indicates it is doing activity.
It's definitely to do with the order the processes are run in. Here's a very simple diff you can apply to NVC which causes the processes to be run in the reverse order to normal:
diff --git a/src/thread.c b/src/thread.c
index 1ccf27e801a0..1428d1fcdc42 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -1020,7 +1020,7 @@ void workq_start(workq_t *wq)
nparallel += wptr.count;
}
else {
- for (int j = 0; j < wptr.count; j++)
+ for (int j = wptr.count - 1; j >= 0; j--)
execute_task(&(eq->tasks[j]));
nserial += wptr.count;
}
If I apply that then the test has the same behaviour as Modelsim/RiveraPRO.
The LRM doesn't specify which order the processes are to be run in (they might even be run concurrently) so UVVM shouldn't be relying on that. We do seem to be running them in a different order to every other simulator though, but I think that's just an implementation detail.
I wonder if there is any value in being able to randomize this to help expose issues with verification frameworks? Maybe run forward, backward and random?
Anyway, I'm glad the little insight @JimLewis had was able to resolve where the bug resides.
I wonder if there is any value in being able to randomize this to help expose issues with verification frameworks? Maybe run forward, backward and random?
This is a good idea. I've added a --shuffle
option to the -r
command. With that the test case above can pass around half the time.
I did not find the root cause for this in UVVM, meanwhile there has been a new release of UVVM v2 (2024.09.19) where the affected code has been rewritten to avoid the issue in all VVCs.
I'm running a testcase with the Axilite VVC from UVVM and I get a different result on NVC vs Modelsim.
Output from nvc:
Output from Modelsim:
As you can see the await_completion finishes at 1050 on NVC and 1102.5 on Modelsim, additionally the write_response_channel_check is run before on modelsim.
There are earlier test in the testcase that checks the passthrough of data, however I do see some warnings in modelsim, is it related to this?