When debugging VHDL code it is very useful to get the call stack trace on for instance a failing assert.
This is found in commercial simulators. Without a call stack trace it can be very hard to determine where the error occurred if re-usable sub-programs like check or check_equal are used. Much verification code will contain such re-usable wrapper functions around asserts; for instance VUnit check package or OSVVM Alert package. Surely many VHDL coders will have wrapped asserts in re-usable functions to raise the abstraction level of their test benches and avoid copy paste coding.
Consider the following code:
test.vhd:
:::vhdl
entity test is
end entity;
architecture a of test is
procedure check(value : boolean) is
begin
assert value;
end procedure;
begin
main : process
procedure do_some_other_stuff is
begin
check(false);
end procedure;
procedure do_stuff is
begin
check(true);
do_some_other_stuff;
check(true);
end procedure;
begin
check(true);
do_stuff;
wait;
end process;
end architecture;
unhelpful command line output:
> ghdl -a test.vhd && ghdl --elab-run test
test.vhd:7:5:@0ms:(assertion error): Assertion violation
The error message just tells me an assert has failed in my re-usable check function which is not very helpful and making it very hard to locate the error if it is used everywhere. It would be great to get a full stack trace such as:
helpful command line output:
> ghdl -a test.vhd && ghdl --elab-run test
test.vhd:7:5:@0ms:(assertion error): Assertion violation
... called from test.vhd:14 do_some_other_stuff
... called from test.vhd:20 do_stuff
... called from test.vhd:25 main
Other simulators expose this as a TCL command that you can execute after simulation has stopped on an error or any other reason. Having it enabled by a command line flag would also work.
A simple implementation of this would be to store a static table of line numbers and strings to all possible call locations and pushing/popping indexes to this table when calling and returning from subprograms. For people who do not want to pay for the runtime overhead maybe a flag has to be added such that it can be disabled thus also disabling the possibility to have a stack trace.
If you are using llvm or gcc backend, compile and elaborate with -g.
Then run within gdb. Set a breakpoint on do_report. And then:
It would be easy to have a better name for the breakpoint.
But I suppose you'd prefer something easier to use...
Tristan.
Last edit: Tristan Gingold 2015-05-12
Thank you for the suggestion. As you say I would prefer something more integrated and less dependent on the internal program structure of GHDL. The names in the gdb stack trace does not directly point to vhdl files and corresponding line numbers either. Also users of GHDL might not have gdb. Anyway it is better than nothing for now but I still think my original feature request is valid.
I agree this is not integrated and that names aren't demangled.
But the trace points to vhdl files and line numbers.
I am investigating which symbolisation libraries can be used.
When I suggested the same feature to the author of NVC he said he was thinking about using LLVM debug info. Since you are supporting three backends; mcode, gcc and llvm. This would probably not be attractive to you. Maybe you have to solve it by generating such a location table and manually inserting push/pop of indexes to it in the GHDL base code before emitting it to the backend.
One general question I have for you is what is your thoughts about the future of the backends of GHDL? It seems mcode cannot work on x86_64 which is what most compures are since many years and that GCC backend is known for being hard to build. Isnt LLVM the best option? Many new programming languages that come out these days are based on LLVM like Swift from Apple and Rust from Mozilla. I could imagine that the cost of an open source project to maintain three backends would be high?
All the backends (mcode, gcc and llvm) can generate dwarf debug info; so using debug info is not a real issue.
I am not thrilled by having a location table - shouldn't be that efficient. I am still investigating.
The future of the backends is a good question. mcode has some good advantages: easy to build, very scalable, very fast for running the test suite. llvm was recently added and may be less mature than gcc. For sure, mcode and gcc somewhat overlaps...
Great that they all support dwarf debug info. Then that might still be a good option.
LLVM should be quite fast as well when not asking it to do many optimizations. It also supports JIT which I suspect is good for quickly running short tests but will scale up to long tess when more optimization has been performed. It was also easy to build, this is why I choose to use the LLVM backend myself, mcode will not work on my 64-bit machine and I gave up trying to build the gcc backend. Are you planning on adding x86_64 support for mcode by the way?
The code to support LLVM JIT is already here, but I haven't tested it strongly.
Mcode should work on your 64 bit linux machine, provided you use a 32 bit compiler (compatibility mode).
I don't plan to add x86_64 mcode, unless LLVM JIT reveals to be a disaster - but that's not expected! I am not sure how to use debug info in LLVM JIT.
Sorry for claiming that there were not references to vhdl file and line numbers. Somehow I did not see it before you reformatted the post. This makes it more useful actually.
No problems. My fault: the formatting of gdb output was indeed unreadable!
Just to clarify my request a bit regarding the user interface. One would not want the backtrace for every report. Peferably the severity level of when a backtrace is printed would be separately configured. Personally I would want to exit on severity>=error and have the backtrace for severity>=warning. Also one would want a backtrace for every fatal error that stops simulation such as divide by zero or index out of range errors etc.
I have a prototype for this feature:
GHDL -r test --assert-level=error
test.vhdl:7:5:@0ms:(assertion error): Assertion violation
ghdl_mcode:error: assertion failed
from: work.test(a).check at test.vhdl:7
from: work.test(a).main.do_some_other_stuff at test.vhdl:14
from: work.test(a).main.do_stuff at test.vhdl:20
from: process work.test(a).main at test.vhdl:25
ghdl_mcode:error: simulation failed
It currently works with mcode, but I plan to support llvm too.
Tristan.
Great! This would be a big usability lift for GHDL. Looking forward to having this with the LLVM backend which is the one I mainly use.
This is now implemented. You get:
test.vhdl:7:5:@0ms:(assertion error): Assertion violation
ghdl:error: assertion failed
from: work.test(a).check at test.vhdl:7
from: work.test(a).main.do_some_other_stuff at test.vhdl:14
from: work.test(a).main.do_stuff at test.vhdl:20
from: process work.test(a).main at test.vhdl:25
You need libbacktrace (from gcc) for this feature when using llvm.
Thanks,
Tristan.