2
\$\begingroup\$

I've read different article (and book chapter too) about "component" and "subprogram". What i don't understand is what is the difference between the two...

I mean, i know that the component make easier the "hierarchical design" grouping "hardware pieces" somehow, while subprogram groups piece of code, but what i do not understand is how all this stuff behaves in synthesis. It is easy for me to understand how component behaves in synthesis (probably a compiler expand the component and just infers the logic embodied) but i don't figure out how a subprogram or function are synthetized.

Could you help me to understand?

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

First, look at subprograms. Subprograms are exactly as they are in a conventional programming language, C or Ada for example. Functions abstract over expressions, procedures (=void functions) abstract over statements. And they are normally called within sequential code, i.e. within a process ... and the process is key here..

(for completeness, functions can also be called outside a process, e.g. in a declaration to initialise an array or memory block)

Now a process resembles a complete C program (ignoring C's fork, join, pthread library etc which create multiple processes; ditto Ada's multitasking)

When you start it, it runs through to completion and stops - unless it contains a wait statement (VHDL) or sleep() call (C). And in VHDL for hardware, the normal form of process is started automatically when any signal in its sensitivity list (e.g. clock) is active.

(Think of clock or any other signal in VHDL as a communication channel from some other process - if you've used named pipes in C, you'll get the basic idea, but using signals is much easier)

Understand processes properly - including the fact that they can use variables exactly like your Ada or C program uses variables - and they can use signals differently, as communication to other processes, and we can move on to components.

Now you can view a VHDL design as composed of many processes, all communicating with each other using signals. Each process, internally, behaving like a simple C or Ada program. (Note that concurrent VHDL statements such as signal assignments are really a shorthand way of writing processes, so at the concurrent level, everything is a process. And at the sequential level, i.e. inside a process, everything is a statement or expression)

But what abstracts over processes, in the same way functions do over expressions?

First : entities/architectures.

  • An entity defines the interface to a process (or a group of processes) - i.e. its ports are the incoming and outgoing signals. Note the similarity to the argument list of a subprogram.
  • An architecture provides an implementation of the entity.

And finally

  • A component describes an entity you want to use in your design. It need not actually exist yet - but when you build the design (called "elaboration", a bit like linking) the libraries will be searched for an entity matching that component declaration. And then, failure to find an exact match (are you using the right libraries?) will be an error.

You can actually instantiate entities directly in a VHDL architecture and avoid dealing with components altogether : this involves specifying the precise library you want to find it in, and if you're doing this, the entity must already exist.

EDIT : what does synthesis do with a function? It implements it - or if you get too clever with older buggy synth tools, reports an error. Taking an integer addition as an example :

  • if both actual arguments are constants, it performs "constant folding" optimisation and generates no hardware for the addition
  • if both arguments are signals or variables, it will probably generate an adder of the correct size (inferred from the type of the arguments and result) i.e. if the arguments and result are all `natural range 0 to 7" it will generate a 3-bit unsigned adder.
  • NOTE that given this range restriction, adding 7+7 is erroneous behaviour. In simulation, assigning the result would report an error (unless you are using a broken simulator where range checks are off by default - like Xilinx ISIM). Synthesis, however, is allowed to assume you have verified correctness in simulation, so it has permission to do anything with broken code. In practice it'll probably wrap round so 7 + 7 = 6 or whatever is cheapest in hardware.
  • At a later stage it'll aggressively optimise : so if you add 1 to a variable, and an incrementer is cheaper than an adder, that's what you get.
  • Or if you neglect to use the result, it'll aggressively trim out the adder, and anything that led up to generating both arguments (if they aren't used anywhere else).

So get the design right in simulation first...

\$\endgroup\$
2
  • \$\begingroup\$ So basically the synthesis of everything depends on the context.. (i.e.) process. But again i don't get a point... if i talk about C i know that if i write a function int f(int) i know that the compiler will reserve a piece of memory for function body and will use properly the register or whatever for the intermediate computation. But i don't get in the case of a function VHDL what the compiler does, if i write a function for a 32 bit sum, or more complicated stuff what the compiler does? \$\endgroup\$ Commented Apr 14, 2015 at 11:52
  • 1
    \$\begingroup\$ @Lukkio I don't know if its technically accurate, but I like to think of VHDL's functions/procedure as inline. In that sense, they behave closer to C macros than functions. You will likely get the same simulation/synthesis result if you use function or inline it in your code. Obviously, one option is better for maintenance and readability. \$\endgroup\$ Commented Apr 14, 2015 at 23:29
1
\$\begingroup\$

A very simplistic answer: A component references an entity which is a container of concurrent code (multi-threaded). For synthesis, think general purpose hardware creation.

A subprogram (procedure/function) is a container of sequential code (a single thread). For synthesis, think small pieces of hardware (like Mux2, Mux4). Note some go through their design practice only using subprograms made available in standard libraries and not writing any of their own (for RTL design).

Where I think writing your own subprograms will benefit you the most is in writing testbenches. Think of capturing interface behavior, such as UartSend or CpuWrite/CpuRead in a procedure. Then to create a test, all you have to do is call the procedures multiple times from a process as shown below. Sure beats writing out the code out directly.

UartTestProc : process
begin
  Wait until DUT_READY ; 
  UartSend(X"4A", SDO, Clk) ; 
  UartSend(X"4B", SDO, Clk) ; 
  . . . 
\$\endgroup\$

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.