08-22-2016 01:52 AM
What's the best practice to do a (rising or falling) edge detection on an external asynchronous clock (like SPI clock)?
note that I want to accomplish a fully synchronous design, so run everything on my internal (100MHz) clock wich is sufficiently larger than the external clock signal, and use 'ticks' to trigger events.
one idea :
other idea :
additional question :
08-22-2016 05:01 AM
use a 3-stage synchronizer, and look at the last 2 FF's to detect the edge
By definition, this doesn't exist. In order to be a "synchronizer", the chain of flip-flops must be back to back with no fanout - the output of one flip-flop must drive only the input of the next flip-flop. In the case you state above, the 3rd flip-flop is not a synchronizer flip-flop, since the output of the 2nd flip-flop also drives the gate that does the edge detect.
So your two circuits are the same.
Now, in RTL, you can write this system a variety of ways. You can have two processes - one which does the two synchronizer flip-flops and one that does the extra flip-flop and the gate, or you can have one process that implements a 3 stage shifter and use the 2nd to last and last outputs as your edge detect. These two descriptions end up being the same - a 2 stage synchronizer followed by an edge detector.
Note: To make this a true synchornizer, the first two flip-flops should have the ASYNC_REG property set on them (in Vivado). If you try and set the ASYNC_REG on the third flip-flop, then the report_cdc command should give you a warning (or error), due to the extra fanout between things that have been marked as synchronizer flip-flops.
Avrum
08-22-2016 02:01 AM
08-22-2016 04:04 AM
Idea No. 1 would be the best practice in my opinion. Following Fig shows a synchronizer circuit with a Neg edge detector circuit.
08-22-2016 05:01 AM
use a 3-stage synchronizer, and look at the last 2 FF's to detect the edge
By definition, this doesn't exist. In order to be a "synchronizer", the chain of flip-flops must be back to back with no fanout - the output of one flip-flop must drive only the input of the next flip-flop. In the case you state above, the 3rd flip-flop is not a synchronizer flip-flop, since the output of the 2nd flip-flop also drives the gate that does the edge detect.
So your two circuits are the same.
Now, in RTL, you can write this system a variety of ways. You can have two processes - one which does the two synchronizer flip-flops and one that does the extra flip-flop and the gate, or you can have one process that implements a 3 stage shifter and use the 2nd to last and last outputs as your edge detect. These two descriptions end up being the same - a 2 stage synchronizer followed by an edge detector.
Note: To make this a true synchornizer, the first two flip-flops should have the ASYNC_REG property set on them (in Vivado). If you try and set the ASYNC_REG on the third flip-flop, then the report_cdc command should give you a warning (or error), due to the extra fanout between things that have been marked as synchronizer flip-flops.
Avrum
08-22-2016 01:48 PM - edited 08-22-2016 02:22 PM
thanks @avrumw, I followed your suggestions, googled a bit around and came up with this :
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity sync_with_edge_detect is port ( clock : in std_logic; async_in : in std_logic; sync_out : out std_logic; rising_edge_tick : out std_logic; falling_edge_tick : out std_logic ); end sync_with_edge_detect; architecture Behavioral of sync_with_edge_detect is -- *** SYNCHRONIZER FLIPFLOPS *** signal sync_ffs : std_logic_vector(1 downto 0) := (others => '0'); attribute ASYNC_REG : string; attribute ASYNC_REG of sync_ffs : signal is "true"; -- *** EDGE DETECT FLIPFLOP *** signal edge_detect_ff : std_logic := '0'; begin process (clock) begin if rising_edge(clock) then sync_ffs(0) <= async_in; sync_ffs(1) <= sync_ffs(0); end if; end process; sync_out <= sync_ffs(1); process (clock) begin if rising_edge(clock) then edge_detect_ff <= sync_ffs(1); end if; end process; -- edge detect rising_edge_tick <= (not edge_detect_ff) and sync_ffs(1);
falling_edge_tick <= edge_detect_ff and (not sync_ffs(1)); end Behavioral;
after googling around, I'm a bit puzzled with something basic VHDL I guess : should I assign an initial value during signal declaration or not? (I mean the := '0' and := (others => '0').
Do these have an impact on synthesis? Or is it only necessary for simulation?
08-22-2016 02:00 PM
I'm a bit puzzled if I should assign an initial value during signal declaration (the := '0' and := (others => '0').
Yes, they affect synthesis.
When the FPGA is configured (the bitstream is downloaded), all flip-flops in the design are initialized to a known value. The synthesis tool decides what the value is. The mechanism is (pretty much) as follows
a) if there is an initialization value for the underlying signal/reg, then that is used
b) if there is no initialization for the signal/reg, but the RTL describes a reset value for the flip-flop then that is used
c) if neither of the above are true, then the flip-flop is initialized to 0
So, in this case, since you have no explicit reset, without the initial value, the FFs would end up with case c, and get initialized to 0. With the initialization, you end up in case a). So on the face of it, it looks like it would make no difference. However, as you mentioned, it does affect simulation. With case c) the signal/reg would start with an unknown value, whereas with case a), it is set to 0. Since synthesis will end up with this FF being initialized to 0 in either case, one would argue that a) is better, because simulation will now match what ends up happening in synthesis.
And, of course, I just want to point out that if you use a) with a value of 1 (rather than 0) then you will end with the INIT value of the flip-flop being 1. Again, simulation and synthesis will match...
Avrum
08-22-2016 02:25 PM
thanks @avrumw, that's the most concise and clear explanation I've read so far on signal initialisation ... :-)
so I should pay more attention to initialisation, especially when there is no reset ...
that probably explains why my post-synthesis simulation shows a lot of undefined signals (orange), while in behavioural simulation all signals are defined (green)
note : I just edited my code above, I had rising and falling edge ticks switched.
08-22-2016 06:56 PM
that probably explains why my post-synthesis simulation shows a lot of undefined signals (orange), while in behavioural simulation all signals are defined (green)
It really should be the other way around...
When simulating a synthesized netlist, the model for the FDCE/FDPE/FDSE/FDRE simulates the INIT functionality - so at time 0 all flip-flops will initialize to the INIT value assigned to them by the synthesis engine.
However, in RTL code, if you have a signal that doesn't have an initial value at declaration, it will implicitly have an undefined value until some process gives it a value.
Avrum
08-22-2016 11:50 PM
thanks @avrumw
mmm .. my simulation issue is solved ... think it was some caching problem, or the sim was using an outdated synthesised netlist - I've seen this more than once ... let's forget about that, sorry.
to complete this thread, I'm interested to understand better the init mechanism (It probably deserves it's own thread ...if you want me to start a new topic let me know, I'll be happy to do that)
Is this correct reasoning (?) :
a) -> the init values assigned at signal declaration are put into the bitstream in such a way that they asynchronously preset the FF with the '0' or '1', at the moment the bitstream finished downloading? I asume this mechanism also works for vectors like := X"1234"
b) -> what if both init value and RTL reset are there, or they are conflicting? i.e. signal is declared with := '1', but the RTL process describes a reset signal that sets the value to := '0'?
Would there be a difference if the RTL reset is synchronous vs asynchronous?
c) -> I've read that the 'leftmost' value in the enumeration list of possible values is used, so for std_logic this is '0' (?)
08-23-2016 08:24 AM
a) -> the init values assigned at signal declaration are put into the bitstream in such a way that they asynchronously preset the FF with the '0' or '1', at the moment the bitstream finished downloading? I asume this mechanism also works for vectors like := X"1234"
While correct, I would like to expand on some points for clarity.
First, in Xilinx parlance, certain words are used for certain types of resets
- preset - asynchronously load a 1 (FDPE)
- clear - asynchronously load with 0 (FDCE)
- set - synchronously load with a 1 (FDSE)
- reset - synchronously load with a 0 (FDRE)
(Although sometimes all of the above are referred to as "resetting" the flip-flop). The rest of the acronym is (probably) Flip-flop D-type preset/clear/set/reset with Enable.
So, I would not use the word "preset the FF" in the above statement, but "load"...
Next, the INIT value is a property of the flip-flop that is loaded via the bitstream. The loading of the INIT value into the flip-flop storage element is controlled by the GSR (Global Set Reset) net from the configuration logic. The GSR remains active during the first stages of the configuration, but is deasserted at a particular point in the sequence (you have some control over this by setting configuration bitstream options).
The GSR functionality can be used to minimize the need for user resets, but the GSR is (by definition) asynchronous to any user clock, and is relatively slow - it is not guaranteed to affect all flip-flops at the same time. (So there is some complexity to using this).
The GSR can also be reasserted by user logic, by instantiating the STARTUPE2 block and connecting a fabric signal to the GSR pin. However, this is not recommended and is very hard to use (since the act of asserting the GSR affects all flip-flops, probably including the ones that were responsible for asserting GSR...)
I assume this mechanism also works for vectors like := X"1234"
At synthesis time, a "bus" of flip-flops is implemented as independent flip-flops. So, in this case, you would end up with 16 flip-flops, with some of them implemented as FDRE and some as FDSE (assuming they were synchronously set/reset).
b) -> what if both init value and RTL reset are there, or they are conflicting? i.e. signal is declared with := '1', but the RTL process describes a reset signal that sets the value to := '0'?
In most FPGA families they are not conflicting. The nomenclature is a bit different in ISE and Vivado - I will talk about the Vivado way.
The INIT property is orthogonal to any reset value. The reset value determines whether the flip-flop is implemented using an FDCE, FDPE, FDRE, or FDSE. All these flip-flops have an INIT property which determines the value during GSR. So, it is perfectly acceptable to have an FDCE or FDRE with an INIT of 1 (or vice versa).
Be aware that the tools can do some changes to map the synchronous Reset or Set functionality (FDRE/FDSE) to use combinatorial logic in front of the D input, and then use any type of flip-flop with the user reset functionality disabled (so, for example, an FDPE with the P tied to ground). This can be done as part of "control set optimization".
The ISE terminology is a bit different; in ISE (at least after place and route, not after synthesis), there is only one type of flip-flop primitive and it has a number of properties
INIT - the GSR initialization value
SRVAL - the reset value
SRTYPE - asynchronous or synchronous
(you can see how these map to the same thing as the Vivado FDPE/FDCE/FDSE/FDRE representation).
The only exception are the Spartan families (Spartan-6 for sure, and I am pretty certain earlier Spartan families as well), which have one combined SRINITVAL (instead of a separate one for SRVAL and INIT). For these families, if both a reset value and an signal initialization value exist in your RTL, the SRINITVAL gets set to the reset value.
Would there be a difference if the RTL reset is synchronous vs asynchronous?
No.
c) -> I've read that the 'leftmost' value in the enumeration list of possible values is used, so for std_logic this is '0' (?)
I don't know - this is a VHDL detail (and I am mostly a Verilog guy...)
Avrum