Ghdl: Pass Toplevel generic to ghdl_main()

Created on 31 Mar 2020  路  4Comments  路  Source: ghdl/ghdl

Description
I am not getting any valid parsing of a argc, argv pair when calling ghdl_main() in a custom main(). I noted that the documented example of 'ghdl -r --std-08 bugtest -gDEPTH=12' was a little picky, and only worked when '-g...' was at the end.

Expected behaviour
The generics default to inexplicit values (Integer = -2147483648, a default I did not specify). I want the generic to take on the value after the '=' in the '-gDEPTH=12'. I then struggled to pass a value for a std_logic generic. What are the limits of '-g'?

I also looked at passing ghdl_main all four arguments (-r, --std-08, bugtest, -gDEPTH=12) instead of just '-gDEPTH=12', and including a leading space on the arguments. No avail.

How to reproduce?

```vhd :file: BugTest.vhd
library ieee;

entity BugTest is
generic (
depth : integer
);
end entity BugTest;

architecture RTL of BugTest is

begin
process
begin
report "Toplevel generic value is: " & integer'image(depth);
wait;
end process;
end architecture RTL;


```c :file: main.c
#include <stdio.h>

extern int ghdl_main(char argc, char* argv[]);

int main(int argc, char const *argv[])
{
    char argPtr0[] = " -r";
    char argPtr1[] = " --std=08";   
    char argPtr2[] = " bugtest";
    char argPtr3[] = " -gDEPTH=12";

    char* argPtr[] = {/*argPtr0, argPtr1, argPtr2, */argPtr3};

    printf("\nargs: [%s,%s,%s,%s]\n", argPtr[0], argPtr[1], argPtr[2], argPtr[3]);
    printf("ghdl_main return: %d\n", ghdl_main(1, argPtr+3)); //including other arguments causes flag conflicts

    return 0;
}

```sh :image: ghdl/ghdl:buster-llvm
gcc -c main.c &&
ghdl -a BugTest.vhd &&
ghdl -e -Wl,main.o bugtest &&
./bugtest &&
rm *.o work-obj93.cf bugtest

echo Below works
ghdl -a BugTest.vhd &&
ghdl -e BugTest &&
ghdl -r --std-08 bugtest -gDEPTH=12 &&
rm *.o work-obj93.cf bugtest
```
Context
$ ghdl --version
GHDL 0.36-dev (Ubuntu 0.35+git20181129+dfsg-4ubuntu1) [Dunoon edition]
Compiled with GNAT Version: 8.3.0
llvm code generator

Additional context
I'd happily dive into the repo if someone points me in the right direction.

C VHPIDIRECT Question

Most helpful comment

Thanks @umarcor for the answer.
@RocketRoss Feel free to ask any question about the code. Also feel free to improve the documentation about ghdl_main.

All 4 comments

@RocketRoss, I'm pretty sure this is a PEBCAK. I have intensively used this feature and it works as expected. Let's dive into it!

I am not getting any valid parsing of a argc, argv pair when calling ghdl_main() in a custom main().

You need to call ghdl_main with the same arguments that it would get from a regular call from the system. That is: an integer, and a pointer to pointers which hold strings. The integer must be the number of arguments plus one, because argument 0 is the path of the binary. In practice, I believe that GHDL ignores argument 0, so it can be a null pointer.

I noted that the documented example of 'ghdl -r --std-08 bugtest -gDEPTH=12' was a little picky, and only worked when '-g...' was at the end.

The arguments that ghdl_main accepts are the ones that a binary generated by LLVM/GCC backends accepts, i.e. the runtime/simulation arguments. In the example command you provide, -r --std=08 bugtest are compilation/execution arguments for ghdl, and -gDEPTH=12 is the runtime/simulation argument. So, if you wanted to do an equivalent call to ghdl_main, you need to pass 2, {NULL, "-gDEPTH=12"}. This is pseudocode, you need to use the corresponding valid variables/types in C.

Notes:

  • AFAIK -r and --elab-run are the only GHDL commands that accept two sets of arguments, both being separated by entity_name [architecture_name]. When using LLVM backend, I recommend not to use ghdl -r, because it can be misleading, as it happened to you.
  • In the (not near) future, it might change how GHDL handles generics. Currently, generics are runtime arguments. In the future, they would be compilation arguments. As a result, now you can generate a single binary and execute it multiple times with different arguments. That might not be possible in the future.

The generics default to inexplicit values (Integer = -2147483648, a default I did not specify).

You can set a default value for the generics in the top-level VHDL entity. This way, you don't need to provide any runtime argument. Of course, this requires you compile once for each set of params.

I want the generic to take on the value after the '=' in the '-gDEPTH=12'. I then struggled to pass a value for a std_logic generic. What are the limits of '-g'?

I think that GHDL has limited support for generic types in the CLI. I would stick to strings or integers. However:

  • JSON-for-VHDL allows to encode a set of parameters as a base16 encoded stringified JSON struct, and it provides VHDL functions to read specific values from it. It is valid for synthesis.
  • See #1117 and VUnit/vunit#588.

I also looked at passing ghdl_main all four arguments (-r, --std-08, bugtest, -gDEPTH=12) instead of just '-gDEPTH=12', and including a leading space on the arguments. No avail.

As said, you need to pass two arguments, the first one being the path to the binary or NULL, and the second one -gDEPTH=12. Hope it works at first try now!

Yes! A PEBCAK indeed. Forgot about the binary-path being the first argument.

The integer must be the number of arguments plus one, because argument 0 is the path of the binary. In practice, I believe that GHDL ignores argument 0, so it can be a null pointer.

Say no more!

you need to pass 2, {NULL, "-gDEPTH=12"}. This is pseudocode, you need to use the corresponding valid variables/types in C.

Exactly the issue.

Hope it works at first try now!

Indeed it did. Many thanks @umarcor :champagne:

I think that GHDL has limited support for generic types in the CLI. I would stick to strings or integers.

Roger dodger. VUnit was next on my list of conquests.

The following is curiosity talk.


In the future, they would be compilation arguments. As a result, now you can generate a single binary and execute it multiple times with different arguments. That might not be possible in the future.

Yes, I noted that. Seems to make sense that the generics should rather fall down to be a part of the elaboration phase, because one can use generics to alter generate statements: so the final executable is still rather dynamic as it can adapt to any value for a generic???

I am curious about the backend. Does GHDL try to come up with a straight shot/flat if-else maze to mimic circuitry, or does it just wrap up the vhdl code smartly and then run through it and increment clocks at certain points.

Still it is quite nice to be able to rerun a single executable with for simulation environments...

Hope it works at first try now!

Indeed it did. Many thanks @umarcor 馃嵕

Awesome 馃帀

Roger dodger. VUnit was next on my list of conquests.

Do not hesitate to ask, either in the issues or in the chat!

Yes, I noted that. Seems to make sense that the generics should rather fall down to be a part of the elaboration phase, because one can use generics to alter generate statements

Exactly. Tristan's point is that there are some elaboration-time optimisations that cannot be applied if elaboration is delayed to runtime. Currently what the LRM defines as "elaboration" is split between GHDL's elaboration and runtime commands. I.e. -e and -r or executing the binary. Executing --elab-run --no-run is the closest to execute an elaboration "exactly" in terms of the LRM, no less, no more.

so the final executable is still rather dynamic as it can adapt to any value for a generic???

Once again, exactly. I believe this is an unvaluable feature. Technically, together with VUnit's verification componets VHDL libs, it allows you to take a VHDL design with AXI, Wishbone or Avalon top-level interfaces and provide an "executable model" of it, so that users can evaluate/test your design in a software environment. They get either a binary or a shared library with a nice software API to write/read to/from the model.

It is also possible to use GHDL to embed a hardware design as a replacement of an existing function. This is what dbhi.github.io is about. Furthermore, the "executable model" can be called as a function in Octave, so that data in the workspace is modified by the simulation at runtime. Since it is dynamic as you said, a single binary suffices to support any generics. For example, I'm using it to test a matrix multiplication core.

However, because of the licensing of GRT (GPL), you NEED to allow users to access the VHDL sources that you used to generate the "executable model". Unlike verilator, which allows a similar procedure to be used for distributing obfuscated executable models, licensing in GHDL is otherwise. Actually, Tristan has considered writing a ghdlator which would provide an alternative.

I am curious about the backend. Does GHDL try to come up with a straight shot/flat if-else maze to mimic circuitry, or does it just wrap up the vhdl code smartly and then run through it and increment clocks at certain points.

The "backend" is GRT, GHDL's Runtime Library that is embedded into the generated binaries. I believe that's the part of GHDL (as a project) which ensures that execution is cycle-accurate. I'm pretty sure that it does not mimic circuitry at all. The purpose of GHDL is to be bit-accurate and cycle-accurate, but it is a compiler not a synthesiser. You can see it as "a compiler for a flavour of ADA with a companion runtime library". Except that "the flavour" is VHDL, which is arguably much more complex. Hence, it is closer to wrapping the code smartly and incrementing delta cycles at certain points. Actually, the sources of GRT are quite intuitive to read. For example, here you have ghdl_main: https://github.com/ghdl/ghdl/blob/master/src/grt/ghdl_main.adb And here you find Run, Run_Elab, Run_Simul and Run_Finish: https://github.com/ghdl/ghdl/blob/master/src/grt/grt-main.adb

Well, it WAS compiler/simulator only. In the last 12 months Tristan did a titanic effort to enable ghdl --synth. However, as you might imagine, that's a completely different elaboration backend which has nothing to do with GRT, mcode, LLVM, GCC.

Thanks @umarcor for the answer.
@RocketRoss Feel free to ask any question about the code. Also feel free to improve the documentation about ghdl_main.

Was this page helpful?
0 / 5 - 0 ratings