3
\$\begingroup\$

In this day and age we can just use the memory IP provided to us by the FPGA vendor be it a soft IP or hard IP. This makes it almost trivial to communicate with high speed memory devices like DDR2 and DDR3 RAMs from the FPGA side. The PCB layout is still a massive challenge though and there is no doubt about this at all.

Many years ago I read that once upon a time, the engineers had to design a memory controller for high speed RAMs themself for an FPGA being used in their design. I am not sure how often this happened. I remember reading that at that time, the most difficult part of the memory controller design was the PHY.

From memory I can remember that it gave a reason as well. The reason it gave is that the PHY required very precise control of propagation delays and this required some sort of novel idea to be achieved in FPGA that has this issue with a nondeterministic propagation delay between different cells every time we compile the design.

Is this true? If this is true, how was this problem solved? I have never found details of this anywhere but I am curious to know what special steps engineers took to solve such a problem. It seems that they had to specify very tight timing constraints for specific paths and let the fitter do the rest, but if all it took was some SDC constraints, that does not appear too difficult to me in theory.

\$\endgroup\$
3
  • \$\begingroup\$ FPGA tools (like Vivado for example) have the ability to calculate maximum and minimum timing for the signals given the actual implementation that it made. If the timing on each run was different enough to sometimes cause failures, then its likely they didn't have proper timing constraints. Meaning they didn't tell the tool what timing would be acceptable. If you tell the tool that the relative timing on certain signals has to be within some bounds (usually relative to a clock), the tool will tell you if you failed or not after implementation. \$\endgroup\$
    – user4574
    Commented Sep 10, 2020 at 22:56
  • \$\begingroup\$ thanks, my question is about how this problem was solved BEFORE we had all these wonderful GUIs to help us make all this piece of cake. Now we just open GUI and enter few numbers and the rest is handled automatically. I am not exactly sure what type of timing constraints would be required for the PHY or if this was even the most complex part of the memory controller at all. \$\endgroup\$
    – gyuunyuu
    Commented Sep 10, 2020 at 22:59
  • \$\begingroup\$ I believe that the timing aspects of the tools have been there since nearly the beginning (at least for Xilinx). But the tool doesn't require you to write constraints, and many people forget to, and then have mystery problems later. \$\endgroup\$
    – user4574
    Commented Sep 10, 2020 at 23:05

3 Answers 3

5
\$\begingroup\$

The problem was solved by the FPGA vendors realizing that this was an important thing to be able to do, and they began incorporating the necessary hardware into every I/O pad's logic. The key element is a programmable delay line, and the vendor's memory controller IP includes the logic to calibrate the delays automatically.

For example, look at Xilinx UG388, "Spartan-6 FPGA Memory Controller User Guide", Chapter 4, "MCB Operation", where it talks about the startup sequence and self-calibration. The key element is called IDELAY. You can learn more about this primitive in UG381, "Spartan-6 FPGA SelectIO Resources User Guide", p. 70, "I/O Delay Overview".

\$\endgroup\$
2
  • \$\begingroup\$ "programmable delay line" hmm. I do know about the DLL but this appears to be a different thing. If I was to design my own memory controller, I guess I would need to make use of this thing. I don't think I have come across it before this though. How is this programmable delay line implemented if we are to achieve very precise, sub-ns control over delay? \$\endgroup\$
    – gyuunyuu
    Commented Sep 14, 2020 at 0:03
  • 1
    \$\begingroup\$ See the links that I added above. \$\endgroup\$
    – Dave Tweed
    Commented Sep 14, 2020 at 1:08
2
\$\begingroup\$

I had the privilege of being a software & systems guy working on a project back when DDR in FPGA was new -- this would have been late 1990's, early 2000's. The way this was accomplished then was by locking down the position of the gates in the FPGA. Basically, this is a level of hand-holding that isn't usually necessary, but which the tools allowed (and may, still, I don't know). By locking the relationship of the gates to the I/O pins, the various delays were guaranteed to be preserved.

I'm not sure if this still needs to be done or not.

\$\endgroup\$
2
  • \$\begingroup\$ Actually today we have vendor provided memory controllers as soft IP or hard blocks on the silicon. Therefore, we don't need to worry muc about this. I would be grateful if you could provide some more details about this. The memory controller has many functions which include periodic refresh, activate and precharge of rows, manage burst transfers e.t.c. What part of the design required you to specify delay and what method did you use to achieve this? FPGAs in early 2000s had little logic resouce for a memory controller to be implemented in them I guess. \$\endgroup\$
    – gyuunyuu
    Commented Sep 10, 2020 at 23:34
  • \$\begingroup\$ I can't remember. Probably whatever needed to be closely synchronized, but I wasn't directly involved in that. \$\endgroup\$
    – TimWescott
    Commented Sep 11, 2020 at 0:19
2
\$\begingroup\$

I had the pleasure of making my own DDR controller on a Cyclone IV a few years ago. The main motivation was that the tools no longer contained DDR[1] controller IP at the time, and the application was a little bit unique in that the memory was being used as an enormous lookup table with truly random addressing, and needed consistent timing for every access. This actually simplified the state machine logic quite a bit since I didn't have to worry about keeping the rows precharged or anything like that: Just precharge the row, read the data, end the sequence. Rinse and repeat.

From a digital state machine standpoint, it really wasn't that challenging. The memory datasheets have pretty good state machine flow diagrams, and just generally understanding that you need to schedule in your refreshes to meet the specs. You can either have an evenly distributed refreshes or one big burst of refreshes.

You have to understand the low level interface hardware available at the FPGA IO blocks. You'll need to find a bi-directional DDR block, where the output write data is clocked out by your FPGA clock and the input data is clocked in from the DDR strobes. Every FPGA vendor and family does this a little bit differently. I highly recommend simulating to make sure you're doing it right.

The next hardest part is the timing constraints. The bidirectional data pins from can be tricky when it comes to writing IO timing constraints, especially when the outputs and inputs are clocked from different sources, and again, each vendor has slight nuances on how to write them properly.

Finally it's just a matter of meeting timing. You can use the IODELAYs if available, use PLLs with adjustable phases, just whatever you need to do to meet timing.

\$\endgroup\$
2
  • \$\begingroup\$ What macro did you use to produce the type of bidirectional IO blocks that you have described? Yes, most certainly it is timing that is the hardest part. Do you have know of any very similar example design that I can study along with the timing constraints? Did you do all the work all by yourself? \$\endgroup\$
    – gyuunyuu
    Commented Oct 5, 2020 at 14:57
  • \$\begingroup\$ I believe it was the ALTDDIO_BIDIR which has a separate inclock/outclock port. Unfortunately no on the example design. \$\endgroup\$ Commented Oct 5, 2020 at 17:48

Your Answer

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

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