2
\$\begingroup\$

I'm a software developer learning more about FPGA/VHDL and I wonder if using sequential languages for too long makes it harder to think about hardware.

My question is about connecting components together and I'm sure this is a very basic thing but I can't find a proper answer.

Assume I have an ALU component that has as input two 8 bit data items A(0-7) B(0-7) and an output O(0-7) as well as as operation to perform "OP". It will have a clock input too "CLK". It has the code in a "if rising_edge(clk)" statment

Now my understanding is that the output of the component will be set only on the rising edge of the clock, or importantly a very short time after this due to propagartion delays.

All good.

However I have a memory component too.

This has address A0-10, Data inputs D0-7 and a CLK. On the rising edge of the clock it stores the data in the address.

However there is a problem here. At the rising edge of the clock the output from the ALU isn't quite ready yet so what will the memory store? It seems like it would be a bit random as to whether it gets the new or the old output from the ALU depending on how quickly it manages to change. In code terms we have a race condition depending on if the ALU generates the data first or the memory component manages to sample that data first.

My questions are 1) Is this a real problem or am I missing something. 2) If it isn't a problem, how does it work? 3) If it is a problem how do I solve it (general principles are fine).

\$\endgroup\$
3
  • \$\begingroup\$ This similar question is possibly not a duplicate, but it may have some useful information if you haven't already seen it. \$\endgroup\$ Sep 4, 2015 at 10:28
  • \$\begingroup\$ Amusingly I asked that question too, about 2 years ago when I was looking at FPGAs before. I gave up at the time because I never really understood what I was doing well enough to progress but I've started again with a lot more background now . Clearly I still have the same gaps though as I'd forgotten I asked that. \$\endgroup\$ Sep 4, 2015 at 14:38
  • \$\begingroup\$ ROFL - I completely missed the fact that it was your question! Apologies, no sarcasm intended :-) \$\endgroup\$ Sep 4, 2015 at 14:50

2 Answers 2

5
\$\begingroup\$

It sounds like you understand this correctly. To answer your questions individually:

  1. This could be a real problem, but the FPGA registers and clock infrastructure work in a way that means you do not have to worry about this problem in a fully synchronous system such as the one you have described.

  2. There a few factors that allow you to reliably register data on the same clock edge that is altering said data:

    • The hold times for internal registers are very small, well under 1 nanosecond in for example a Xilinx Spartan 6 FPGA, and less than 0.2 nanoseconds for the block memory in said FPGA.
    • The clock network typically uses a very low skew design, so that the clock edge in one part of the FPGA happens very close in time to the edge in other parts. Contrast this with the data path, where your changing data signal has to propagate along the wire from one register to the next.
    • Each clocked element has a propagation delay from it's D input to its Q output.

    Combining these factors, when a clock edge occurs, the data seen by the second register (in your case a memory element) will not change until the register propagation delay plus the wire delay. As long as this total is more than the hold time for the receiving register, the design will work reliably. The clock skew does play a role here, but as before, this should (but see point 3.) be small compared to the other two factors.

  3. Your FPGA design tool chain will perform very detailed timing analysis of the entire design, provided that you have given it the right information in the form of constraints. This analysis will include any internal clock skews, delays, temperature and process verations, etc. It is always important to create constraints for clock periods, and any I/O timing. With these in place, the tool chain will tell you if there were any timing problems in your design. Even though the particular scenario you describe would never actually have a timing problem, I think this is an important point.

\$\endgroup\$
2
  • \$\begingroup\$ "Even though the particular scenario you describe would never actually have a timing problem" It could well do if the ALU is complex enough or the clock is fast enough. One of the most annoying parts of logic design work is tweaking your design trying to get the timing to pass. \$\endgroup\$ Dec 13, 2015 at 3:42
  • \$\begingroup\$ @PeterGreen If the design timing constraints cannot be met because of especially long paths or an overly optimistic goal, then of course you could end up with a design that doesn't work. However, the question asks whether having sequential clocked elements use the same clock edge in itself causes a problem. In fact, in the scenario described, using the same clock edge gives the best chance of passing the timing constraints. \$\endgroup\$
    – scary_jeff
    Dec 14, 2015 at 10:37
0
\$\begingroup\$

You are correct to identify it as a potential issue, and also correct in assuming it's so prominent the tools deal with it well.

In fact the ALU output is guaranteed to assume the computed value sometime after the clock edge, so there is no uncertainty; it will be stored into memory on the next clock edge. So you need to set the memory's WRITE ENABLE signal in the same cycle that the ALU outputs data.

The potential issue manifests itself in two ways : either

  • the clock signal can arrive at ALU and memory at different times (or different bits of the ALU at different times) - called "clock skew"
  • the ALU outputs take so long to reach the memory that they aren't ready in time for the next clock edge either.

Normally, you tell the tools your desired clock rate (and similar information, collectively called "timing constraints") and they translate the design appropriately - for example, locating ALU and memory close to each other to reduce routing delays - and a step called "static timing analysis" reports whether all the timing constraints have been met.

So usually, in practice, the tools take care of this problem for you.

You can experiment with timing constraints - say, ask the tools to meet speeds of 200,300,400 MHz and at some point they will fail : then they will list the slowest paths, and you can decide how best to make the design faster (if you need to).

For example, if you had a shift/rotate unit directly connected between ALU and memory, and this was too slow, you could make that unit a clocked process too, therefore speeding the design up by adding another pipeline stage.

In CPU design this causes problems because branches become slower thanks to the need to flush long pipelines (the Pentium-4 was heavily criticised for this) but in FPGA design it tends towards a design style that avoids branches altogether, or at least, as far as possible.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.