-
Notifications
You must be signed in to change notification settings - Fork 350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strange issue with synchronous signal update #1335
Comments
Note: I have tried fairly hard to create a small repro-case without luck. I've created a little test bench, importing a components calling into C with roughly the same state machine etc... but in all cases, we see as expected the transition back to "cmd" on the cycle after the wdata_ready pulse. Note also that if I change the state machine to use two processes as follow, then the problem goes away:
Though I still can't quite figure out what's wrong with the single-process variant |
If you want to reproduce, you can git clone my repository and use the "sim-litedram" branch git clone git://git.ozlabs.org/home/benh/microwatt.git You can then do
To build it. You'll need verilator installed. I then run it with the following command and wait until it hangs at "memtest_bus..."
With this in foo.wopt:
You can then look for the first 0->1 transition of user_port0_cmd_valid to see the problem |
The most obvious possibility is a delta between system_clk and clk.
Are they really the same clock ?
I will have a look at it later. Ideally after finishing the attribute work!
|
I have just checked out your repo and indeed system_clk and clk are not in phase.
In sim_litedram.vhdl the process should use user_clk instead of clk.
|
I'm curious here, mind educating me ? When using the sim model, sim_litedram.vhdl does:
(system_clk is user_clk) So how come they aren't in phase ? Isn't the above basically just a wire ? IE. they are the same clocks no ? (and yes I verified your fix does work, but I'd love to understand why :) |
For synthesis, they are just the same wire.
For simulation, no.
user_clk <= clk;
is the same as:
process (clk)
begin
user_clk <= clk;
end process;
So when there is an event on clk, all processes that are sensitive to clk are scheduled to run.
In your case, that includes the process for user_clk assignment and the process that accesses to the lite dram.
Then this is the next delta.
Then the signals are updated (and that includes the user_clk). And the processes that are sensitive are scheduled.
This includes the state machine, which reads the new values from litedram that have been updated in the previous delta.
Conclusion: never assign clocks.
In verilog, you have non blocking assignments and blocking assignments. You could play with clocks using blocking assignments. But you have to be very careful about that. In an ideal HDL, you would be able to do immediate assignment only for clocks.
|
Ok. I see. Something to keep in mind then, thanks. |
Description
I apologize for not having a small repro-case nor even a good grasp on the issue here,
it's quite possibly me not understanding something properly but ...
In order to be able to test microwatt (VHDL) with Litedram (Verilog) in sim together, I
made a verilator model of litedram, which I wrapped with vhpidirect, and plugged it
in-place of the verilog when running GHDL.
Note: This is testing a case that is working fine on FPGA after vivado synthesis.
In this setup, llitedram is wrapped twice:
litedram-wrapper.vhdl is the normal wrapper that imports the litedram verilog as a "component", instanciates it, and implement the conversion between microwatt wishbone bus and litedram "port".
in sim, the verilog component is replaced by a vhdl entity in a separate file that uses VHPIDIRECT to call into the verilator model.
The problem happens In the first wrapper (that converts the wishbone bus from microwatt to the litedram port). In there is this rather simple process:
The various user_port0_ signals are either locally generated (user_port0_cmd_valid) or coming
from the litedram component.
The following wave file show what happens:
The key thing here is the behaviour of "state":
The first transition from "cmd" to "mwrite" is as expected: user_port0_cmd_valid becomes 1,
and on the next clock, the above state machine observes it and sets state to mwrite.
HOWEVER, the transition then from mwrite back to cmd is abnormal, at least unless I misunderstand something here: We see user_port0_wdata_ready being set to 1 and on the same cycle state goes to cmd. It should have only be observed on the next cycle.
Now this probably requires diving a bit more on how user_port0_wdata_ready is generated. It's done in this piece of VHDL:
Here, the litedram_* calls are VHPIDIRECT calls. However the whole thing happens in a if rising_edge(clk) block, thus user_port_native_0_wdata_ready should have been assigned "normally" as part of a synchronous process, and thus not observed by the first state machine until the next cycle.
Note: I've moved thing around in the above snipped, clock before, clock after, clock in the middle, etc.. with no changes.
Am I missing something here ?
As a result of this, the wishbone acks aren't generated and the core hangs. They are generated as by this:
This all seem to work fine when syntesized on FPGA.
Context
Please, provide the following information:
$ ghdl --version
GHDL 1.0-dev (v0.37.0-579-g7285f745) [Dunoon edition]
Compiled with GNAT Version: 7.5.0
llvm code generator
Written by Tristan Gingold.
The text was updated successfully, but these errors were encountered: