Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass Toplevel generic to ghdl_main() #1185

Closed
radonnachie opened this issue Mar 31, 2020 · 4 comments
Closed

Pass Toplevel generic to ghdl_main() #1185

radonnachie opened this issue Mar 31, 2020 · 4 comments

Comments

@radonnachie
Copy link
Contributor

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?

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;
#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;
}
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.

@umarcor
Copy link
Member

umarcor commented Mar 31, 2020

@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:

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!

@radonnachie
Copy link
Contributor Author

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 🍾

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...

@umarcor
Copy link
Member

umarcor commented Mar 31, 2020

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.

@tgingold
Copy link
Member

tgingold commented Apr 1, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants