As I stated in my comment, mem
is an inferred level-sensitive latch (for rest of the answer I will use latch for anything level-sensitive, and flop for anything edge-sensitive). Latches are inferred in always blocks that are not edge-triggered (posedge
/negedge
) and is not assigned to a deterministic value if all logical branches.
Here is your original logic reformatted with my comments:
always @(data_trigger or reset) // <-- poorly inferred latch
begin
if (reset) // Asynchronous reset because 'reset' is in the sensitivity list
begin
for (n = 0; n < 10; n = n+1) mem[n] = 8'h00;
i = 0;
checksum_buff = 8'h00;
end
else if (data_trigger) // <-- Also asynchronous
begin
if ( i < 10)
begin
mem[i] = input_data;
i = i + 1; // <-- as a latch will cause feedback loop on FPGA, will not be detected on in Simulations
end
else
begin
checksum_buff = input_data;
i = 0; // <-- also will cause a feedback loop to 'if(i<10)' in FPGA
end
end
end
Except for synchronous logic, synthesizers do not look at the sensitivity list. Therefore input_data
and i
are actually part of the sensitivity list during synthesis. Simulation does use the sensitivity list, therefore it will ignore changes to input_data
and i
. This is a place where simulation and synthesis will mismatch.
i
is part of the real sensitivity and it is updated on every pass of the always block. This creates an asynchronous feedback will data_trigger
is high and reset
is low. If you were to have added i
to your sensitivity list, your simulation would likely hang from an infinite loop. On FPGA there is a slight propagation delay so you will results of seemingly random data. If you were measuring power you would also see high power consumption in this condition.
If you look through your log files there may be a warning about the asynchronous feedback.
i
needs to be a flop. mem
and checksum_buff
should be flops too. From an eyeball review of your code, it looks like everything is running on the posedge clk
domain. Therefore I suggest you change the code to:
always @(posedge clk)
begin
if (reset)
begin
for (n = 0; n < 10; n = n+1) mem[n] <= 8'h00;
i <= 0;
checksum_buff <= 8'h00;
end
else if (data_trigger)
begin
if ( i < 10)
begin
mem[i] <= input_data;
i <= i + 1;
end
else
begin
checksum_buff <= input_data;
i <= 0;
end
end
end
With this reset will also be synchronous. If you really want asynchronous reset, change it to always @(posedge clk or posedge reset)
. If you really want data_trigger
to be the clocking event (I don't recommend it) then change the posedge clk
to posedge data_trigger
AND replace else if (data_trigger)
with else
. Any posedge
/negedge
signal referenced in the block is treated as an asynchronous trigger. You have this issue in your checksum256
module.
Verilog combinational logic should be written in always @*
or the synonymous always @(*)
. You will run into code that give a list of signals instead of a literal *
; don't do that. That style is for legacy Verilog-1995. Since Verilog-2001 @*
/@(*)
is the preferred strategy to limit the risk an incomplete sensitivity list. The other thing for proper combinational logic is that each left-hand-side (LHS) signal must be assigned to a determinate value for all possible logic branches. Assigning it to itself doesn't count. Assigning it a determinate value at the top of an always block before an if
or case
gives it a default assignment. Combinational logic should be assigned with blocking statements (=
).
Synchronous logic must be have a clocking trigger posedge
or negedge
. Do not reference the clock signal in the body of the of the always block. Up to two additional posedge
or negedge
signals can be in the sensitivity list for asynchronous reset/preset, and asynchronous must assign registers to constants. Not all FPGAs support flops with asynchronous reset/preset; some have a limited number. Check the manual for your board. Synchronous logic should be assigned with non-blocking statements (<=
).
Latches usually should be avoided. Unfortunately they can be unintentionally inferred with what should be combinational logic. A latch happens when not all logical branches assign the signal to a deterministic value. If you need a latch, keep it logic simple and assign with non-blocking.
always @* begin
if (enable) Q <= D;
end
If you have SystemVerilog you can be more explicit by replacing always @*
with always_comb
and always_latch
. This way your synthesizer can do a better job warning you about unintentional latches.
FYI: Verilog non-blocking was inspired/copied form VHDL. The usage of blocking and non-blocking should be similar between the two.
The issue is that the keywords "posedge" and "negedge" in Verilog (or "rising_edge" and "falling_edge" in VHDL) have very special meaning to the synthesizer. The synthesizer gives every signal attached with these keywords a dedicated clock routing network on the FPGA. Do not use those keywords for any signal that you do not want connected to a clock routing network on the FPGA (which obviously, should be no signal other than a clock).
It is a great waste to use one of the precious few dedicated clock routing networks on an FPGA just to have an asynchronous reset. I know of no way around this and the solution is to actually just not use asynchronous resets at all. Just use synchronous resets.
The use of asynchronous resets appears to be a practice that was carried over from ASIC design early on that has been misapplied to FPGAs and repeatedly taught turning it into a bad habit. Asynchronous resets have advantages in ASIC design that do not carry over to FPGA design due to the hardware constraints of the FPGA. One such advantage is saving gates which you can do in an ASIC since you have control over everything, but in an FPGA the flip-flops are already there and all have a clock input anyways so you save nothing.
It is interesting that asynchronous resets in FPGAs also monitor the clock signal as well. You would think this would not be necessary since the reset is asynchronous, after all, so why would it ever need to trigger on a clock at all? The reason is because if the asynchronous reset deasserts too soon after a clock edge, there are metastability issues because timings are violated. A true asynchronous reset (as one that might appear in an ASIC which is where the practice came from) would not need to also trigger off the clock to stop this from happening.
The only weakness I have been able to find about synchronous resets is that if you have multiple clock domains and improperly use the synchronous reset with only the higher speed clocks in mind, it is possible for the slower clock domain to miss the reset pulse since the reset deasserts before the slow clock can tick to register the reset pulse. However, you can protect against this by design and I do not think it is a big deal compared to using a dedicated clock routing network for something so trivial as an asynchronous reset.
Best Answer
I posted the same on Xilinx Forum and I think it could be an issue with Vivado not properly cleaning the
.sysdef
file inproj.runs/impl_1/
.After manually deleting it and re-generating the bitstream (which was fast because most of it was already compiled), the export gave me the proper
.hdf
.