What's the difference for VHDL code between simulation and synthesis?

Hi, The following is from Xilinx "Synthesis and Simulation Design Guide". Could you give me an example to show their differences? And explain a little to me? Thank you very much.

You may need to modify your code to successfully synthesize your design because certain design constructs that are effective for simulation may not be as effective for synthesis. The synthesis syntax and code set may differ slightly from the simulator syntax and code set.

Reply to
fl
Loading thread data ...

'Differ slightly' is being way too generous. Usually it means more along the lines of 'not supported at all' for synthesis even though it is perfectly legitimate code. Some examples and how you would write the code for simulation are shown below.

  1. A delay line (commercially available part from many sources....but not inside an FPGA typically). x
Reply to
KJ

There are several possible cases (non exhaustive) :

- Code that's just _not_ syntesizable :

process begin wait until reset='0'; wait for 3 ns; sig

Reply to
Sylvain Munaut

Describing wires explicitly is a very popular style and works well for synthesis. But it is possible for me to describe procedurally, how a set of registers are to be updated, like this:

formatting link
And leave it to synthesis to work out the wires, like this:
formatting link

-- Mike Treseler

Reply to
Mike Treseler

The only reason the above code could be considered 'just _not_ syntesizable' is because the behaviour of 'sig' prior to getting to where it is assigned has not been defined and is a design error that one would fix while still in simulation.

But given that code, if the synthesizer wants to assume that 'sig' defaults to 1 then it would synthesize to 'sig' always being '1'. If instead it assumed that 'sig' defaults to '0' then it is again synthesizable with an inverter and a 3 ns delay line. If market pressure causes the FPGA suppliers to start adding delay lines to their parts then the above code can be targeted to one of those devices, if not it can still be implemented with commercially availabe parts so it is not 'just _not_ syntesizable' it's just not supported by FPGA software at this time....but there are a whole slew of things that are not supported, and those are typically bugs/limitations/whatever with the software that result in web cases to the support lines when I run across them. The end result of that is they improve their tool. Things like delay lines would be added as functional blocks when (if) there is sufficient market demand for that function.

Again, an example not of unsynthesizable code but of perfectly valid and synthesizable code that a particular supplier may not support for their own various reasons.

I want the tools to figure out the proper bitstream that needs to be loaded into a part so that a vast array of RAM look up tables, transistors and flip flops inside that device will implement what I want it to do. In order to do that I describe functionally what I want the hardware to do, I definitely do not describe the hardware that I want built (i.e. the look up table contents, transistor on/off states, etc....and I doubt I'm alone in that regard).

KJ

Reply to
KJ

I think one thing that others have not pointed out is the fact that an HDL is just that... a Hardware Description Language. You can use an HDL to write programs and they will run in a simulator. This is often done in developing a test bench to drive signals to your device and to monitor the outputs in simulation. But if you want to write code that can be synthesized by the compiler, you have to be describing hardware.

"Describing hardware" means you can only use constructs that the compiler understands. See the difference? Simulation operates on the full language. Synthesis only works with a subset that actually describes hardware.

The examples are far too numerous to list, but here is one. If you want to use a register, you show it as a process which is scheduled to run when the clock transitions or the async reset transitions.

Example1: process (SysClk, Reset) begin if (Reset = '1') then DataOutReg '0'); elsif (rising_edge(SysClk)) then if (SCFG_CMD = '1') THEN DataOutReg

Reply to
rickman

As I pointed out in my first post, what many people refer to as 'not synthesizable' really means that they can't find a tool that supports the code as it is written. Something that is 'not synthesizable' can never be built. Living with the limitations of a particular tool(s) is not the same thing at all.

Agreed.

But that does not imply that it couldn't be synthesized using two sets of flip flops whose results get combined. You might not find a synthesis tool in 2007 that accepts the above code, but that doesn't mean that there won't be one in 2008 that will. Whether there is such a tool or not depends on how many users scream to brand A and X that they really need this. It can be synthesized, just not how you are focusing on how you think it must be synthesized.

Agreed. Since one needs to get today's job done with tools you have today you need to understand the limitation of the tools as they are today. I've submitted dozens of web cases in areas that should be supported but errored out or produced incorrect results. The tools were updated and improved, thus changing what was not synthesizable into something that is. Each of those things were areas where the synthesis tool did not support a language construct and it should. Bottom line right now for the code I right, I'm finding Altera way ahead of Xilinx and Synplify so I'm working with X and S to get their tools improved so that they too can have less stuff that some would consider to be 'not synthesizable'.

KJ

Reply to
KJ

Could you give us an example of something Altera can do that Synplify can't? (I've always "felt" Synplify to be ahead of the vendor-specific tools, but it sounds like that may have changed :-)

Thanks! Martin

--
martin.j.thompson@trw.com 
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.net/electronics.html
Reply to
Martin Thompson

If you can build the second description, I would like to see that. Do you know this is possible or are you just speculating? I have never seen a good example of a register clocked on both edges done in an FPGA.

Reply to
rickman

Synplify used to have it over quartus on viewers, but quartus has caught up. As far as synthesis, it varies with the design, but I would call A and S comparable for an altera target. X needs some focus on advanced synthesis. For example, I wish they would take this one seriously:

formatting link
formatting link
formatting link

It has been hanging fire since ISE 6.1i, It wouldn't be so bad if I got an error message. I get synthesis that does not match simulation.

The suggested "solution"

formatting link
is to avoid the legal code that causes the problem. Note that brand A and S and Modelsim get it right.

-- Mike Treseler

Reply to
Mike Treseler

This is an interesting issue. I had to refresh my knowledge of procedures in VHDL. But I don't understand why you say the Xilinx solution to the problem is to "avoid the legal code". They are saying that it will work if you simply pass the variable into the procedure rather then use it as a global variable. To be honest, I find your use of procedures for very simple functions inside of a process to be hard to read. It seems like using parameters instead of a global might even make the code more readable. Is that something you don't want to do?

Reply to
rickman

The declaration is a regular variable. The name chosen by the original author is indeed unfortunate.

In vhdl, a "global" would be declared shared. I am not advocating shared variables or suggesting that anyone support synthesis for them.

The point is that the variable is in scope for both procedures, and should not require parameters. That would be a belt and suspenders.

The point of my code was to demonstrate a complex problem in as simple a way as I could, and I guess I fell short of that mark.

The procedure update_regs_fix is the way I would have coded this example: _______ procedure update_regs_fix is begin if incr = '1' and decr = '0' then increment; elsif incr = '0' and decr = '1' then decrement; end if; end procedure update_regs_fix; ________

This is very easy for me to read.

There is no global variable in either example. Adding parameters where they are not needed makes the code *harder* to read not easier.

-- Mike Treseler

Reply to
Mike Treseler

A few years back my general ranking of tools as to adherance to the standard was Modelsim, Synplify, Quartus. Now a days, I'd put Quartus way ahead of Synplify with Modelsim still #1 but Quartus a very close 2nd (again, only in regards to correctly interpreting the code, not anything else). I haven't played enough with ISE but the little bit that I have seems to put it close to but a bit behind Synplify. I say that mainly because the first two bugs I found in ISE were the exact same two bugs that I had with Synplify...but I think S has fixed them now.

I didn't take too much time to filter these (sorry, getting late) but hopefully you can get the gist of what isn't working

Example 0: Time is not synthesizable...even as a constant (I 'think' this is fixed with Synplify now after I reported it a year or so ago....ISE still doesn't like this but I'm told that they are considering it)

constant PULSE_HIGH_TIME: time := 1 us; constant CLOCK_PERIOD: time := 10 ns; signal My_Counter: natural range 0 to (PULSE_HIGH_TIME / CLOCK_PERIOD);

Example 1. This one is somewhat involved but it has to do with when you have an enumerated type and try to take the 'pos attribute.

Perusing the log file further, it appears that Synplify can produce either a note or a warning or the above mentioned error when it encounters usage of an enumerated type. The line that causes the error is

Line 1324: constant CPU_ROUTER_LOW_INDEX_RANGE: natural := t_CPU_ROUTER_COMPONENT_CONNECTIONS'pos(t_CPU_ROUTER_COMPONENT_CONNECTION S'low);

where 't_CPU_ROUTER_COMPONENT_CONNECTIONS' is defined to be a subtype of 't_CPU_INTERFACES'

Line 1302: subtype t_CPU_ROUTER_COMPONENT_CONNECTIONS is t_CPU_INTERFACES;

and 't_CPU_INTERFACES' is defined to be an enumerated type.

Line 155: type t_CPU_INTERFACES is (rt_Feeder, rt_Track, rt_SpiIntf,rt_Cam_Cntl, rt_Micr, rt_Trk_Cntl, rt_InkJet, rt_Franker, rt_Gate,rt_Ports);

The line that causes the error should have returned the position of the lowest ordered element in the enumerated type. In other words t_CPU_ROUTER_COMPONENT_CONNECTIONS'pos(t_CPU_ROUTER_COMPONENT_CONNECTION S'low) Since 'rt_Feeder' is the lowermost enumeration, this is equivalent to t_CPU_ROUTER_COMPONENT_CONNECTIONS'pos(rt_Feeder) And this should be equal to 0

Example 2: Range of a generic can not be used to define the range of a port

The line of code in question is in one of the outputs of an entity Line 624: Track_Speed_Select: out natural range ALLOWABLE_TRACK_SPEEDS'range;

where 'ALLOWABLE_TRACK_SPEEDS' is an input generic for that entity and is defined on line 519

ALLOWABLE_TRACK_SPEEDS: arr_real := (1.0,1.0);

What Synplify should be doing is taking the range of the input generic and using that to define the range of the output signal 'Track_Speed_Select'.

Example 3:

@E: CD297 :"C:\Designs\ZFpga_EM1_Syn\HDL\ZFpga_Common\Avl_Lexmark_A640_Ink_Jet_Controller\Avl_Lexmark_A640_Ink_Jet_Controller.vhd":724:3:724:11|Width mismatch, location has width 32, value 1

The offending line of code is

Line 724: RetVal(i) := Convert_Track_Speed_To_Sample_Time(Track_Speed(i), Samples_Per_Second);

But 'RetVal' is defined to be an array of time types (work.pkg_VHD_Common.arr_time) therefore RetVal(i) (the left side of the line being reported as an error) is of type 'time'.

The function 'Convert_Track_Speed_To_Sample_Time' is a function that returns type 'time' as well. The error message indicates that the location has a width of 32 which is not correct, it has a width of 1.

It should be noted that the use of type 'time' in this design is only for the purposes of computing other constants that then get used to define ranges of other signals; I'm not trying to synthesize any signals of type 'time'

Example 4: If you define a record type and have some element that is a vector you can't use the length of that vector to define the range of an integer. I think it went something like this.... type t_My_Type is record .... Some_Field: std_ulogic_vector(7 downto 0); end record; ... signal My_Counter: natural range 0 to 2**t_My_Type'Some_Field'length - 1

I reported this one a while back, I'm not sure if it's been fixed in Synplify or not....ISE has this problem (reported to brand X, they are taking it under advisement).

KJ

Reply to
KJ

Yes, you are right that this is not a "global" variable. But the point is that the one way you have it coded does not work with XST. So why is that a real problem? There are at least two way to code it correctly. This sort of thing (not supporting all valid code styles) has plagued HDLs since they were invented.

Yes, the procedure is easy to read. The procedures increment and decrement are even easier to read. But in context this just seems to me to spread the code over many more lines than is needed and does nothing to *improve* the readability of the code. If you had procedures that were being shared I could see the point of it. But this is just breaking the code into modules for the sake of having modules, in my opinion.

I have coded in Forth and this language encourages the use of many small routines to facilitate correct coding and debugging. Part of the goal is to write reusable modules. Here I don't see how the procedures are easier to code or debug and there is no reuse.

I don't agree. If a procedure is modifying a parameter, I easily know exactly what is happening. If it is modifying a variable that is in a wider scope, I have to look for the variable and figure out which scope it currently being used. Even better than parameters would be to not use procedures for such small snippets of code.

architecture RTL of proc_demo is begin p_main : process (clk, rst) variable count_v : unsigned(data'range); begin if rst = '1' then count_v := (others => '0'); elsif rising_edge(clk) then if incr = '1' then count_v := count_v + 1; end if; if decr = '1' then count_v := count_v - 1; end if; end if; data

Reply to
rickman

The fact that XST does not throw an error.

Instead, it silently creates hardware that doesn't sim anything like the code.

Not supporting every odd version is fine. Producing a bad netlist is not.

This is a simplified example with one purpose: to demonstrate the bug to xilinx.

When I write production code, I use use procedures for duplicated blocks of code. I do sometimes like to share a variable between two procedures. For example, I might want to share an input register variable between a collect_data procedure and a readback procedure that packs in a status bit. It works fine. If I make a mistake, it shows up in the sim, just like any other mistake.

-- Mike Treseler

Reply to
Mike Treseler

Many thanks for that - interesting stuff!

Cheers, Martin

-- snipped-for-privacy@trw.com TRW Conekt - Consultancy in Engineering, Knowledge and Technology

formatting link

Reply to
Martin Thompson

Like I said, your description does not imply that it couldn't be synthesized using two sets of flops suitably combined. See code below for functionally equivalent code that implements your example 2 but does so in a way that I'm sure you can see that it can be synthesized. Note, I'm not suggesting that writing dual edge flop code is good practice or anything, I'm simply saying that the code that you presented is synthesizable, since it is functionally equivalent to the code that I list below which clearly is synthesizable. That implies that your Example 2 code is just not supported by today's tools, quite possibly due to the lack of any real demand for support for such coding....but, like I said in the earlier post, 'not supported' is not the same as 'not synthesizable'.

KJ

Example2a: process (SysClk, Reset) begin if (Reset = '1') then DataOutReg_re '0'); elsif rising_edge(SysClk) then if (SCFG_CMD = '1') THEN DataOutReg_re

Reply to
KJ

KJ also copy/pastes to avoid writing . There are of course other examples but I didn't want to be hammering the suppliers too much in a public forum.

KJ

Reply to
KJ

Sometimes they need a nudge. Thanks for the posting. I found it informative, and commend you for taking the time to submit all those bug reports. Synthesis crosses the newsgroup boundaries, and I am sometimes conflicted about which groups are interested in discussing it.

-- Mike Treseler

Reply to
Mike Treseler

Reply to
rickman

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.