Quick Start¶
‘rand’ from stdlib¶
By default, GHDL includes the standard C library in the generated simulation models. Hence, resources from stdlib
can be used without any modification to the build procedure.
This example shows how to import and use rand
to generate and print 10 integer numbers. The VHDL code is equivalent
to the following C snippet. However, note that this C source is NOT required, because stdlib
is already built in.
#include <stdlib.h>
#include <stdio.h>
int main (void) {
int i;
for (i = 0; i < 10; i++)
printf ("%d\n", rand ());
return 0;
}
‘sin’ from libmath¶
By the same token, it is possible to include functions from system library by just providing the corresponding linker flag.
In this example, function sin
from the math
library is used to compute 10 values. As in the previous example,
no additional C sources are required, because the math
library is already compiled and installed in the system.
custom C¶
When the required functionality is not available in pre-built libraries, custom C sources and/or objects can be added to the elaboration and/or linking.
This example shows how to bind custom C functions in VHDL as either procedures or functions. Four cases are included:
custom_procedure
, custom_procedure_withargs
, custom_function
and custom_function_withargs
. In all
cases, the parameters are defined as integers, in order to keep it simple. See Type declarations
for further details.
Since either C sources or pre-compiled .o
objects can be added, in C/C++ projects of moderate complexity, it might
be desirable to merge all the C sources in a single object before elaborating the design.
Wrapping ghdl_main¶
basic¶
Instead of using GHDL’s own entrypoint to the execution, it is possible to wrap it by providing a custom program
entrypoint (main
function), wherein the execution of the simulation is triggered by calling ghdl_main
.
This example shows the most basic of such usage. ghdl_main
is declared as extern
in C, and arguments argc
and argv
are passed without modification. However, this sets the ground for custom prepocessing and postprocessing
in a foreign language.
Other options are to just pass empty arguments (ghdl_main(0, NULL)
) or to customize them:
char* args[] = {NULL, "--wave=wave.ghw"};
ghdl_main(2, args);
See Wrapping a simulation for further details about the constraints of argv
. Furthermore, section
Command-Line Arguments below shows argument parsing/manipulation strategies.
time¶
Although most of the provided examples are written in C, VHPIDIRECT can be used with any language that supports a C-like compile and link model.
This example shows how to time the execution of a simulation from either C or Ada. In both cases, function clock
is
used to get the time before and after calling ghdl_main
. Regarding the build procedure, it is to be noted that C
sources are elaborated with -e
, because GHDL allows passing parameters (in this case, additional C sources)
to the compiler and/or linker. However, since it is not possible to do so with Ada, gnatmake
, --bind
and
--list-link
are used instead. See Linking object files for further info about custom linking setups.
Hint
Compared to the previous example, the declaration of ghdl_main
includes three arguments in this example:
int argc, void** argv, void** envp
. This is done for illustration purposes only, as it has no real effect on the
exercise.
exitcb¶
When wrapped in a foreign language, calls to ghdl_main
should return an exit code and allow the regular execution of the
wrapper, so that users can handle simulation results in there. However, bugs might result in failures that exit immediately
through an abortion signal. This example shows how to register an exit handler and a signal handler, to allow executing
custom code regardless of crashes in the simulation.
In VHDL 1993, simulation termination statements and exit codes that simulators should produce were undefined. Therefore, it was
common practice to termine the simulations through reports of severity failure
. When wrapping GHDL, such strategies
might result in undesired exit procedures. Using VHDL 2008 is suggested.
Linking¶
bind¶
Although GHDL’s elaborate command can compile and link C sources, it is sometimes preferred or required to call a compiler explicitly with custom arguments. This is useful, e.g., when a simulation is to be embedded in the build of an existing C/C++ application.
This example is equivalent to basic, but it shows how to use
--bind
and --list-link
instead of -e
. See Linking object files for further
details.
Hint
Objects generated by --bind
are created in the working directory. See GCC/LLVM only commands and
ghdl#781.
package¶
If the auxillary VHPIDIRECT subprograms need to be accessed in more than one entity, it is possible to package the subprograms. This also makes it very easy to reuse the VHPIDIRECT declarations in different projects.
In this example two different entities use a C defined c_printInt(val: integer)
subprogram to print two different
numbers. Subprogram declaration requirements are detailed under the Type declarations section.
Command-Line Arguments¶
Top-level generics¶
As explained in Simulation options, there is no standard method in VHDL to obtain command-line arguments. However,
GHDL allows to override top-level generics, with certain restrictions. See -gGENERIC
and ghdl#1388 for
further details.
In this example, two top-level generics of types string
and integer
are used. First, default values are
used. Then, both are overriden through CLI arguments. Note that top-level generics cannot be undefined; hence, the user must
provide either default values or CLI arguments.
Parsing/customizing argv
¶
By the same token, when wrapping a simulation, ghdl_main
receives argc
, argv
and env
as any regular
main
function in C. Hence, when GHDL is wrapped as explained in Wrapping a simulation,
it is possible to either pass raw arguments or to process them before calling ghdl_main
. As a result, overrides for
top-level generics can be defined in C sources. Otherwise, GHDL will complain by producing an error.
These examples showcase multiple approaches to manipulate top-level generics when GHDL is wrapped:
rawargs: pass arguments without modification. This, which is equivalent to basic above, is the minimal requirement for default CLI features to be available when wrapping GHDL.
procargs: pass arguments and set/add some. First, no argument is provided and
genStr
is assigned a value in C. Then,genInt
is provided andgenStr
is added in C.Note
This is a naive approach without any specific library. getopt and/or Argp are popular ways to parse arguments in C. A complete example that uses getopt or Argp would be very welcome, since it would allow non trivial arguments (
[c options] -- [ghdl options]
or[ghdl options] -- [c options]
). Feel free to open a PR!fcnargs: pass arguments without modification, but use a function call to set the default of top-level generics. That is, when no arguments are provided, the value defined in C is used. However, when
-ggenInt=
is provided, it overrides the value of the top-level generic.
Setting parameters in C through VHDL generics¶
This example is the opposite of fcnargs
. A VHDL generic is passed to C when calling an external subprogram. Although
this might feel as a rare use case, it is common when adapting designs that are not aware of VHPIDIRECT features, to
enhance them with external snippets/libraries in a testbench.
JSON-for-VHDL¶
JSON-for-VHDL is a synthesizable VHDL library that allows to provide configuration parameters through either a JSON file or an stringified (and optionally base16 encoded) top-level generic. Together with jq or the libraries available for almost any language, it is a very powerful resource to pass large amounts of params with minimal maintenance effort.
Examples are available at Paebbels/JSON-for-VHDL:tests.