Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have just started learning digital logic design with FPGA's, and have been building a lot of projects. Most of the times (since I am kind of a noob), I have a design that simulates perfectly (Behavioural simulation) but does not synthesize properly.

So, my question is "what are the design steps that I can incorporate in my workflow, that will ensure that I have a working design that will work right on my FPGA ?"

I have two main areas where I expect advise, but this is absolutely based on a very narrow viewpoint of mine as a beginner, and more are welcome :

  • What all steps (viewing RTL schematic, post synthesis simulation, ...) should I undertake learning for the best practice.
  • What all things should I keep in mind while designing my logic (say FSM's or sequential circuits) to avoid any unexpected results.

I am using a Xilinx Spartan 6 FPGA, and Xilinx ISE Design suite for my work.

share|improve this question
    
What sort of problems are you encountering with synthesis? Do you achieve a high level of coverage in the simulation? – pjc50 Mar 2 at 9:55
    
@pjc50 I don't understand the question. What do you mean "high level of coverage in simulation" ? – ironstein Mar 2 at 9:56
1  
You have a testbench or stimulus driving the simulation. Coverage tools tell you how much of the design is actually being exercised by the test, as a percentage. If this number is too low then your testbench is inadequate and you're not testing some cases which could come up in real usage. – pjc50 Mar 2 at 10:29
    
@pjc50 that is actually a very good advice. What is the equivalent of this in Xilinx ISE design suite ? – ironstein Mar 2 at 11:39
1  
Worth noting: synthesizes and "definitely works on actual hardware" are different levels of rigor. There are patterns one can follow to make sure it synthesizes. However, when it comes to making it work on actual hardware, with certainty, one must remember the maxim of simulation: "All models are wrong; some are useful." – Cort Ammon Mar 2 at 14:23

At a place I worked there were two camps of FPGA designers. One camp I called simulate, simulate, simulate or s cubed. The other camp was all about design.

The s cubed guys used a simulator like modelsim, they would come up with an initial design via coding methods and\or blocks in the design suite. Then they would simulate it and find the things that wouldn't work, then change the code. This process was iterated several times until they came up with a design that worked.

The design camp (which I preferred) would design the waveform on paper (or digital paper like visio), exactly what was required. Then come up with a logic diagram. This is a self-documenting process. Then the diagram was translated to code (the code and the diagram were 1:1 if there was something in the diagram, there was a process for it in the code). Then it was simulated, and the simulation waveform was compared with the designed waveform on paper, and was expected to be the same.

I ended up doing both, sometimes I would get into s cubed mode, and it wasn't very fun. I found that I lost sight of my goal sometimes. For example, I would change a state in a state machine, and the change would ripple down to the next state, then I would have to fix that. I ended up spending more time than thinking about it.

Which camp would you rather be in? I think there needs to be rigorous design, do what works for you, but I think the more detailed and rigorous you are at designing, the less problems you will have in the long run. I gave some examples of what is possible, they may not fit the organizational structure of your workplace. The reason why design detail and careful planning is so useful, is it forces you to think about what your doing. It makes it easy to debug. Develop a design workflow that allows this to happen. Also, get really familiar with the simulation tools and write good testbenches that will test all of the conditions that the simulated device might experience. This of course needs to be balanced with time. For example write ADC HDL code that will simulate the device in your simulations.

The most valuable tool to have in FPGA design (in my opinion) is a good testing procedure that will allow you to fully test your design and run it through its paces. An FPGA design cannot be expected "to just work" it takes effort to make sure all of the pieces work. If you spot errors, then go back to the simulation and design and learn what the differences between a simulated FPGA and RTL are. That mainly comes with experience, but if the design works in simulation but not in hardware then you need to find out why there is a difference.

A few key things that I learned:
1) Sanitize your inputs, the clock and reset circuits need to be clean or you can get metastablity propagating through your system. Know what a dual rank synchronizer is. There are many different topologies for reset circuits, know how to use them (there is a great article out there on the web, I don't have it on hand though).
2) Get the requirements of the design up front and then design around those. If the people around you won't give you definite requirements, then come up with some on your own.
3) Matlab fixed point toolbox is great for simulating control systems and DSP applications, but you might not have access to that. It's a great way to prove a design before you code.
4) Design comes first, then coding, then simulating.
5) Strongly typed, also keep signal names consistent on pcb schematic and hdl. (this is also why I much prefer VHDL over verilog.

share|improve this answer
2  
+1 for "s cubed" or \$simulation^3\$ – Paebbels Mar 2 at 9:27
    
Quite good : to "rigorous design" I would add "using the type system". Example : an array index of appropriate type such as the array's range, no need to test for out of bounds condition. I would only disagree with "waveform compared with the designed waveform on paper " ... the designed waveform should be in VHDL by that stage, (or perhaps read from text file) and the simulator should perform the comparison. – Brian Drummond Mar 2 at 14:32
    
It could be done that way also, I found it useful to design a waveform on paper because it gave something to compare against. Like an ADC waveform, the timing was designed and then compared to the modlesim output, then verified physically. If the modelsim output is correct, then compare it to that. The code was strongly typed (I forgot to mention that), but that is really important. That is why I much prefer VHDL over verilog, there are less shortcuts you can take. And it makes the code much more readable. – laptop2d Mar 2 at 17:12

Main things are:

  • Careful coding to avoid non-synthesizable structures
  • Minimize logic levels for better timing performance (make logic between registers as simple as possible)
  • test, test, test to ensure functional correctness and check for things like uninitialized regs and disconnected wires
  • synthesis and check synthesis logs for warnings, make sure the warnings do not indicate issues (I.e. Removed register warning could be intentional (didn't use a module output) or unintentional (forgot to connect module output/typo/etc.))
  • mapping and check map report for utilization figures, make sure the FPGA is not too full
  • place and route and timing analysis, make sure that your design will run at the required clock speed

I have had several rather complex designs work correctly (or at least mostly correctly) on the first test on an actual FPGA by following the above. No need to check the RTL schematic, that's just extremely cumbersome and a complete waste of time for large designs. A post-synthesis simulation would be much more useful.

share|improve this answer
1  
thank you for your quick reply. Could you please elaborate upon the second point (minimize logic levels). – ironstein Mar 2 at 6:20

All your synthesizable code needs to be expressable as:

  • LUTs
  • Flip-flops
  • Vendor-specific primitives

Vendor-specific primitives are either instantiated explicitly, or generated by the vendor's wizard, or inferred by very specific coding patterns, so there shouldn't be any ambiguity there.

In VHDL for example, you can't use wait for in synthesizable code. To understand why, try deterministically expressing wait for 100 ns using LUTs or flip-flops. You can't.

That doesn't mean that you can't implement it by setting up a counter with a known clock frequency (with period that can divide 100 ns) and use its count to know when the time is up. But the synthesis engine won't come up with this scheme automatically, you need to be explicit about the architecture in terms of combinational logic (gates/LUTs) and registers.

So the main thing to keep in mind in order to generate synthesizable code, is to have a relatively clear picture of how your code becomes logic gates and flip flops. That is really it.

share|improve this answer
    
wait until rising_edge(clk); is certainly synthesisable, though some tools impose restrictions on its use. – Brian Drummond Mar 2 at 14:34

The most obvious first step is to check the warnings.

Xilinx tools produce log files which warn about anything that could be not what the coder intended. Sometimes this is annoying, when you have reams of warnings about unused signals which you know perfectly well are unused. But sometimes it catches genuine bugs. If you're a newbie, the chances of you making a mistake are significantly higher.

Then you need to set up timing constraints. How quickly after a rising edge on clock A does data line B need to be set? Or how long does data line B need to be held before a falling edge on clock A? Timing constraints will let you specify all this. If you don't have timing constraints, the compiler may assume that you don't particularly care and could route your signals anywhere. If you have timing constraints, the compiler will work to make sure your signals meet those constraints by moving placement around. And if it can't meet the timing constraints, it will put up a warning.

If your problem is that outputs aren't doing what you expect, look in detail at the I/O blocks. Each I/O pin has a bit of associated logic and a flip-flop. The order in which you specify your logic and state variables in your code may not make it possible for your code to fit into this architecture, so you get an extra delay from wherever it happens to be placed. Warnings on timing constraints will tell you if this happens (assuming you've set up your timing constraints), but fixing it requires you to understand the hardware and how your design will map into hardware. Generally this is only an issue when you start hitting high clock rates, but it's worth mentioning.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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