06-02-2017 01:00 AM
I have a design as shown below. The signal config_ct is synchronous from a process
and is split into other signals config. The config signal is then used as a selection with
a asynchronous mux which compares if all bits in the config ="00" and set output ch_out
equal ch_in or out_temp. Where ch_in and out_temp are from a clk synchronous process.
Could the ch_out be used from the mux into a synchronous process or is it considered
asynchronous due to the mux? Are additional constraints necessary to ensure that config, ch_out
don't have delay larger than 1 clk from ch_in and out_temp to process where ch_out is used and
cause metastability etc?
Should the use of ch_out(1) in the process be re-synchronize by e.g. 2 FF before its used in the
My only constrain so far is clk=100MHz.
gen: FOR i IN 1 TO 5 GENERATE
config(i*8 DOWNTO (1+8*(i-1))) <= config_ct(i-1);
END GENERATE gen;
IF rst_n = '0' THEN
config_ct <= (OTHERS => (OTHERS => '0'));
ELSIF RISING_EDGE(clk) THEN
config_ct(conv_integer(unsigned(adr(7 DOWNTO 0)))) <= data_wr;
mx:FOR i IN 1 TO 5 GENERATE
ch_out(i) <= ch_in(i) WHEN config((8*i) DOWNTO (1+(i-1)*8)) = X"00" ELSE
END GENERATE mx;
IF rst_n = '0' THEN
cnt <= '0'
ELSIF RISING_EDGE(clk) THEN
IF ch_out(1)='1' THEN
cnt <= '1'
06-02-2017 09:07 AM
Don't confuse asynchronous signals (a hardware concept) with a VHDL process that has no clock (which some call an asynchronous process). These are not the same thing.
In HDL (Verilog/VHDL/SystemVerilog), you have two types of processes:
- clocked processes
- these are evaluated only on the edge of the clock (possibly with an asynchronous reset)
- these are sometimes called synchronous processes
- combinational (or combinatorial) processes
- these are not dependent (directly) on the rising edge of the clock
- these change state immediately whenever any of their inputs change state (in VHDL after a delta delay)
- this are sometimes called asynchronous processes (which is a bit of a misnomer)
In a synchronous system, you can freely mix combinatorial and clocked processes. This is done all the time.
You only need to worry about synchronization (or clock crossing) if you use a signal in a clocked process that comes from a clocked process using an (unrelated) clock, or from a truly asynchronous signal (i.e. from an input pin of the FPGA that has no synchronization with any clock).
In your design, the combinatorial MUX depends only on signals that are synchronous to the clock (ch_in, config and out_tmp). By definition, the output of this MUX can, therefore, only change when one of these inputs change. These inputs change only synchronously to the clock, therefore the output of the MUX is also synchronous to the clock (in spite of the fact that it comes from a combinatorial - what some call asynchronous - process).
06-06-2017 10:15 PM
The signals from the clk process is leaving trough a FF, then used in the non clocked mux process where its outputs are used
in another clk process. Are the timing of signals analyzed so they don’t create setup, hold, metastability at the arriving clk process, since they passing a non clk process and could change "at any time"? Is it enough with only a create_clock -name clk 20 [get_ports clkin] as a constrain to ensure that all signals passing from clk process, to another clk process through a non clk process are timed and routed correctly? I thought this was only "guaranteed" then using clk processes.
06-14-2017 03:36 AM
I assume that the process below to infer an block-ram is also synchronous at the ff output
and could directly be used by another process (timing auto checked by tool without any other constraints).
But what is the meaning of sometimes create an register at the output (ff out) of the ram instead of reading it
outside the clocked process direct out, could both be used directly?
if (en='1') then
out <= ram(conv_integer(unsigned(address))); //ff out
if (we='1') then
ram(conv_integer(unsigned(address))) <= in;
out = ram(conv_integer(unsigned(address))); //direct out
06-14-2017 07:51 AM
When you write Register Transfer Language (RTL) code using a Hardware Description Language (HDL) like Verilog/SystemVerilog or VHDL, you describe the behavior of a system. In RTL we write primarily synchronous systems, and we describe their behavior by defining the "Registers" (usually FFs) and the Transfers that go between them using the Language. When done this way we are describing a "cycle accurate" description of the system - we define what happens on each clock cycle of the system. As we discussed previously, this can be done with clocked processes or combinatorial processes whose inputs combinatorially trace back to other clocked processes (or synchronous primary inputs).
The synthesis process then infers hardware that exactly matches the cycle accurate behavior described by the RTL (assuming they can meet static timing requirements).
The terms "synchronous and asynchronous" have lots of meanings in digital design (which can be confusing) - they have different meanings in different contexts. The first is (as I said above) both of these are describing synchronous systems.
In these code snippets, you are describing Random Access Memories. The two definitions of "out" behave differently. The combinatorial out will show the data in the "address" location immediately - on the same cycle as the address takes its value - this is referred to as an "asynchronous read RAM". The other definition of out, will give the data at "address", but only after the next clock cycle - this is referred to as a "synchronous read RAM".
Now lets look at synthesis. Synthesis attempts to match these behaviors to logic cells within the FPGA. In the FPGA there are two types of RAM cells
- distributed SelectRAM cells
- these are implemented in the lookup table (LUT) in some of the slices in the FPGA array
- fundamentally these are 64x1 single ported RAMs with asynchronous reads
- they can be combined to make dual and more ported RAMs
- they can be combined (as all RAMs can) to make deeper and/or wider RAMs
- Block RAMs
- these are separate resources in a separate area (column) of the FPGA
- these are fundamentally 36kbit dual-port RAMs with synchronous reads
You can always implement a RAM that is described in RTL with synchronous read behavior using an asynchronous RAM - this can be done simply by putting a flip-flop on the output (which is easily done in the slice of the distributed RAM). You cannot, however, implement a RAM that is described in RTL with asynchronous read behavior in a cell that has synchronous reads...
Therefore, if you want to use the larger blockRAMs, you must design your system to have synchronous reads.