You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
VHDL support in SpinalSim using GHDL as a backend #146
I think that implementing something as eval() with GHDL might be possible with either the VPI or the VHPI interfaces. I have gathered some examples in 1138-4EB/hwd-ide/tree/vpi-ex-ghdl/examples, but I have not thoroughly learnt it yet.
I was looking for something 'easier' to start with. I tried the following for now:
Replace generateVerilog and SpinalVerilog with generateVhdl and SpinalVhdl in VexRiscv/src/main/scala/vexriscv/demo/*.scala (see eine/VexRiscv@f9c7643).
However, sbt "run-main vexriscv.demo.MuraxWithRamInit" generates a Murax.vhd file now.
I created a VHDL testbench, using entity Murax in Murax.vhd as the UUT (see below).
I can successfully analyze, elaborate and run both Murax.vhd and tb_murax.vhd:
ghdl_args="--std=08 -fPIC"
ghdl -a $ghdl_args Murax.vhd
ghdl -a $ghdl_args tb_murax.vhd
ghdl -e $ghdl_args tb_murax
./tb_murax --vcd=murax.vcd
gtkwave murax.vcd murax.gtkw
However, I don't know how to check it. The next step is to add a UART RX in the testbench, in order to read the output from Murax. But I am not sure about the clk period and the baud rate. I saw https://github.com/SpinalHDL/VexRiscv/blob/master/src/test/cpp/murax/main.cpp#L13-L16, so I think that the expected period might be 83.333 ns (12 MHz) and the baud rate 115200. Is this correct? Also, should I provide any default value to the unused input ports (io_jtag_tms, io_jtag_tdi, io_jtag_tck, io_gpioA_read and io_uart_rxd)?
Files
tb_murax.vhd:
library ieee;
context ieee.ieee_std_context;
entity tb_murax isendentity;
architecture tb of tb_murax isconstant clk_period: time:=83333ps;
signal io_asyncReset : std_logic;
signal io_mainClk : std_logic:='0';
signal io_jtag_tms : std_logic;
signal io_jtag_tdi : std_logic;
signal io_jtag_tdo : std_logic;
signal io_jtag_tck : std_logic;
signal io_gpioA_read : std_logic_vector(31downto0);
signal io_gpioA_write : std_logic_vector(31downto0);
signal io_gpioA_writeEnable : std_logic_vector(31downto0);
signal io_uart_txd : std_logic;
signal io_uart_rxd : std_logic;
begin
io_mainClk <=not io_mainClk after clk_period/2;
main: processbegin
io_asyncReset <='1';
waitfor15*clk_period;
io_asyncReset <='0';
waitfor100ms;
report"End of simulation"severityfailure;
wait;
endprocess;
murax: entity work.Murax
portmap (
io_asyncReset => io_asyncReset,
io_mainClk => io_mainClk,
io_jtag_tms => io_jtag_tms,
io_jtag_tdi => io_jtag_tdi,
io_jtag_tdo => io_jtag_tdo,
io_jtag_tck => io_jtag_tck,
io_gpioA_read => io_gpioA_read,
io_gpioA_write => io_gpioA_write,
io_gpioA_writeEnable => io_gpioA_writeEnable,
io_uart_txd => io_uart_txd,
io_uart_rxd => io_uart_rxd
);
endarchitecture;
I tried adding UART RX and TX verification components to a VUnit testbench. So far it works ok. I could successfully write and get the same content out (as explained in SpinalHDL/VexRiscv#murax-soc). See testbench below:
I could also modify the demo program, rebuild it, and have it included when the SoC VHDL is generated.
@1138-4eb Sorry, i completly losed the track of this issue :/
Probably to interface other simulator, the good solution would be to do like cocotb, with VPI.
Hi @Dolu1990, thanks for pinging back! In the end, I did nothing with neither SpinalSim nor VPI. But I have successfully used GHDL, VUnit, VexRiscv and VHPI to run some simulations. The scheme is as follows:
A module name Apb3Axis was added to Murax. These are two AXI Streams (a master and a slave) mapped to some registers in the VexRiscv memory space. See https://github.com/1138-4EB/VexRiscv/tree/add-axis.
A software routine was written in order to read data from the slave stream, do some arithmetic operations, and put the results back through the master stream.
A VHDL testbench was written including: VexRiscv, VUnit UART verification components (RX and TX) and VUnit AXI Stream verification components (slave and master). Also, a companion C wrapper was written and some VHDL procedures were bind to C functions.
First, the RISCV software was built and the hex was generated. Then, the VHDL was generated with SpinalHDL. The VexRiscv VHDL and the testbench were compiled with GHDL. Last, a C app was built, adding the C wrapper and the compiled objects produced by GHDL.
When the app is started:
Some memory is allocated and test data is randomly generated.
GHDL is called internally as if it was any other function, and the simulation is started.
During simulation, callbacks in C are executed to get data from the app memory space and put it in the slave AXI Stream (input to the RISCV). Consequently, callbacks are executed to get data back from the master AXI Stream (output from the RISCV) to the app memory space.
When the simulation is finished, control is returned to the main app.
Moreover, all VHDL/VUnit logging features are available during simulation. Hence, execution statistics can be saved to log/csv files. Also, waveforms can be exported in any of the formats supported by GHDL, for further inspection with GUI tools, such as GtkWave.
Overall, it was some interesting investigation, as it is a useful setup to wrap GHDL in any other language that supports C-alike interfaces (say ada, golang, python, ruby, scala...).
However, I did not guess how to run the simulator only for the delta cycles corresponding to a timestamp, as you asked:
the def eval() function is called by spinalHDL to ask the simulatior to do delta cycles until everything is stabilized.
maybe that's a tricky thing ?
ATM, you call GHDL and the simulation runs until it is finished due to some assertion, error or because all the processes are stalled. I.e., the flow of the simulation is handled by GHDL.
Therefore, as you suggest,
Probably to interface other simulator, the good solution would be to do like cocotb, with VPI.
yes, VPI would probably be the best fit here. Unfortunately, I have no experience with it.
Nevertheless, I might have misunderstood the requirements for eval(). So, please, let me know if any of the info in this comment lights any bulb.
@Dolu1990
I realized that my library completely misses dealing with signed values. Should all three kinds (Int, Long, BigInt) be sign-extended when they are written on signals wider than their intrinsic bit site and vice-versa?
@bellaz89 Hmmm, so far i remember the SpinalSim API threat numbers as raw data, so there is no difference between signed and unsigned numbers. So that's already fine as far i can see ^^
@bellaz89, that's some interesting work. Thanks for the reference!
If going through the VPI path, you might find cocotb interesting. It uses either VPI or VHPI to interact with a bunch of simulators, GHDL being one of them.
For a more direct solution (with VHPIDIRECT/DPI), there is work in progress in VUnit/cosim. See also VUnit/vunit#603, ghdl/ghdl#1053 and ghdl/ghdl#1059. There are several comments about how to pass not only single values but also arrays or records/structs.
I discovered that my previous approach didn't work because of the inability to link the entire GHDL runtime into a dynamic library.
Therefore I rewrote it (https://github.com/bellaz89/VPIInteropREPL). This project uses boost-interprocess to communicate between the simulator and the client program.
Such an interface is a much cleaner approach than the older one and it allows to simulate with ghdl-mcode and icarus verilog. With minimal effort It could be possible to add the support of other (commercial) simulators that use VPI. Since the interfacing code doesn't change from simulation to simulation we can think about caching the modules and libraries for later use to speed up the simulations.
Either sim/yolo/adder.vhd or sim/yolo/adder.v are used for the test.
The backend code creates the JNI shared library and the VPI plugins in sim/simulation_plugins/.
Since both JNI and VPI objects don't change from simulation to simulation, they are re-used by the following simulations significantly speeding up the loading time.
Remaining tasks/ideas
Adding an user interface to manage the new simulators and their parameters.
Test/adapt the code on windows/macos machines
Stress test the backends (Vexriscv simulations? SpinalHDL test suite?)
Adding a SpinalSim flag to automatically pick the 'best' simulator using the installed simulators/rtl files extensions as information
I discovered that my previous approach didn't work because of the inability to link the entire GHDL runtime into a dynamic library.
Please, see https://ghdl.github.io/ghdl-cosim/vhpidirect/dynamic.html#generating-shared-libraries. That subsection was added/published less than 24h ago. It should allow you to pass pointers/accesses between VHDL and C, without having to resort to interprocesses. Nonetheless, it might still be useful to rely on them for different reasons.
Test/adapt the code on windows/macos machines
The reference about shared libs above is still not tested on Windows or macOS. However, since GitHub Actions supports both of them, I'd like to add it to CI.
Stress test the backends (Vexriscv simulations? SpinalHDL test suite?)
I have simulated VexRISCV with GHDL, including co-simulation with C. It works.
Might it be useful to run GHDL in parallel along with Verilator/ IVerilog to cross-check SpinalHDL's vhdl and verilog generators?
If possible, I think it would be so interesting to be able to co-simulate VHDL and Verilog sources (optionally with additional SpinalHDL). This is a very demanded feature, as mixed-language co-simulation with FOSS is not available yet: https://ghdl.readthedocs.io/en/latest/development/GSOC.html#mixed-language-vhdl-verilog. Precisely, there is a comment about GHDL and Verilator in https://ghdl.github.io/ghdl-cosim/#co-simulation-with-ghdl, because Tristan is thingking about adding a new backend to GHDL which would interact with Verilator (just as it interacts with yosys for synthesis). However, I don't know which would be the approach: to target an API or to generate C++/SystemC sources directly (which the user can then mix with Verilog->Verilator sources). An example (and presentation) about co-simulating VHDL and SystemC through GHDL is available https://github.com/ghdl/ghdl-cosim/tree/master/systemc. It has been recently discussed in the chat: March 26, 2020 10:54 AM.
I discovered that my previous approach didn't work because of the inability to link the entire GHDL runtime into a dynamic library.
Please, see https://ghdl.github.io/ghdl-cosim/vhpidirect/dynamic.html#generating-shared-libraries. That subsection was added/published less than 24h ago. It should allow you to pass pointers/accesses between VHDL and C, without having to resort to interprocesses. Nonetheless, it might still be useful to rely on them for different reasons.
This is a great news! However as you pointed out it is not the only reason why I switched to a multiple-processes approach:
(Disclaimer! I am not expert in VPI/GHDL/HDL simulations in general so my assumptions could be plain wrong :) )
The VPI API/workflow is not designed to work as a library that can be used from other programs/libraries and it doesn't return the control until the simulation is finished. Therefore to be able to perform a simulation in a single process, I had to use nasty tricks like making the VPI code to jump at an address defined at compile time and use a coroutine-like approach (boost-fiber) to do the context-switch between GHDL and the JVM. Even if this works in principle, the result is not so elegant IMHO. Using an interprocess approach results in a more natural way of exchanging data between the JVM and GHDL.
VPI is a (enough) documented API that works on different simulators. Therefore there might be the chance to support other free/commercial simulators that use such API with minimal effort. Plus it has some features like iterating/accessing the simulation object hierarchy that is quite useful when eg. initial value randomization is needed or to access an arbitrary signal just by its name at runtime. I see you are doing some work in that way #1053 , but, correct me if I am wrong, it is still in an early stage of development.
Also, I decided not to use 'cutting edge' features of GHDL right now to allow a SpinalHDL user to easily setup its development environment using system packages without the need to recompile/install GHDL by hand. Once the API of #1053 is fixed, documented, with all the features the VPI has, then it is possible to evaluate a switch to that.
Finally, the interprocess synchronization is done trough atomics. Therefore, even if the synchronization cost is higher than linking the runtime directly in the JVM, I think IMHO that the overhead is still quite low compared to the machine time required for nontrivial HDL simulations.
Test/adapt the code on windows/macos machines
The reference about shared libs above is still not tested on Windows or macOS. However, since GitHub Actions supports both of them, I'd like to add it to CI.
I think that the C++ side of the VPI interface code can be already run on different OSes since the only library dependency is boost-interprocess, (which is an header only lib). The part that worries me most is the Scala part where paths/commands/options are glued together to bootstrap the simulation.
Stress test the backends (Vexriscv simulations? SpinalHDL test suite?)
I have simulated VexRISCV with GHDL, including co-simulation with C. It works.
That is very nice to hear since I will need to simulate VexRiscv for work in VHDL :) . @Dolu1990 has already written some code to make SpinalSim tests to work with the GHDL backend. The (his) idea is to try to run every SpinalHDL test, which actually runs on Verilator, on the GHDL backend too for testing purposes.
Might it be useful to run GHDL in parallel along with Verilator/ IVerilog to cross-check SpinalHDL's vhdl and verilog generators?
If possible, I think it would be so interesting to be able to co-simulate VHDL and Verilog sources (optionally with additional SpinalHDL). This is a very demanded feature, as mixed-language co-simulation with FOSS is not available yet: https://ghdl.readthedocs.io/en/latest/development/GSOC.html#mixed-language-vhdl-verilog. Precisely, there is a comment about GHDL and Verilator in https://ghdl.github.io/ghdl-cosim/#co-simulation-with-ghdl, because Tristan is thinking about adding a new backend to GHDL which would interact with Verilator (just as it interacts with yosys for synthesis). However, I don't know which would be the approach: to target an API or to generate C++/SystemC sources directly (which the user can then mix with Verilog->Verilator sources). An example (and presentation) about co-simulating VHDL and SystemC through GHDL is available https://github.com/ghdl/ghdl-cosim/tree/master/systemc. It has been recently discussed in the chat: March 26, 2020 10:54 AM.
Mixed language cosim would be a very nice feature to have. Sadly I saw that the IVerilog simulator deprecated the VHDL simulation feature (steveicarus/iverilog#222) so right now I don't see a way to obtain this feature in the short term. From SpinalHDL perspective a way to perform mixed-lang would be to use the Verilator backend plus vhd2vl, but I never tested it so I am not able to say if it fits the common user needs.
(Disclaimer! I am not expert in VPI/GHDL/HDL simulations in general so my assumptions could be plain wrong :) )
None of us is! We are here to talk about it and hopefully learn something!
The VPI API/workflow is not designed to work as a library that can be used from other programs/libraries and it doesn't return the control until the simulation is finished.
I have not used VPI explicitly yet, so I'm not familiar with the details. However, I think that this limitation is not related to VPI, but to GHDL itself. No matter which cosimulation strategy you use, ghdl_main will run from start to finish and all you can define are callbacks. When step execution is documented for GRT, it will be possible to use it from VPI/VHPI/VHPIDIRECT... See ghdl/ghdl#1053 (comment).
Therefore to be able to perform a simulation in a single process, I had to use nasty tricks like making the VPI code to jump at an address defined at compile time and use a coroutine-like approach
I'm working around this in VUnit/vunit#568 with a 64bit counter that is shared between VHDL and C, and doing clock gating in the testbench to achieve a "stop the world" type of synch. Not elegant, but it works...
VPI is a (enough) documented API that works on different simulators. Therefore there might be the chance to support other free/commercial simulators that use such API with minimal effort.
Actually, I'd suggest to have a look at cocotb for reference. They use VPI/VHPI to target multiple free/commercial simulators. E.g. ghdl/ghdl#1228. That's why I think that the work you are doing might be equivalent, as long as cocotb's and SpinalHDL's execution models are similar.
Plus it has some features like iterating/accessing the simulation object hierarchy that is quite useful when eg. initial value randomization is needed or to access an arbitrary signal just by its name at runtime.
Precisely, this is the use case where I think that using VPI/VHPI pays off. For only sharing data in co-simulation contexts, it is not worth the hazzle. However, it can be really useful to peek deep in the hierarchy, such as swapping bits in space applications.
I see you are doing some work in that way ghdl/ghdl#1053
Not exactly. I'm mostly focused on VHPIDIRECT and on the C interface for the runtime library (GRT) that is embedded in the executables generated by GHDL.
VHPIDIRECT is similar to a Direct Programming Interface (DPI), since it allows to map procedures/functions only, from C to VHDL. For many use cases, this is equivalent to how VPI callbacks are defined and used. However, the main difference is that with VHPIDIRECT you need to call those functions from VHDL explicitly. So, from the designer's point of view, VPI/VHPI are a C-only approach that does not require to modify the VHDL, while VHPIDIRECT is for building the UUT and the testbench mostly in VHDL only. The main advantage of VHPIDIRECT is that, for non-complex data types, you don't need any 1K header. You just write what you need. See https://github.com/ghdl/ghdl-cosim/tree/master/vhpidirect/quickstart/customc.
Unfortunately, while sharing some data types between VHDL and C is straightforward, others (mainly unconstrained arrays) are fat pointers that are not documented. See https://ghdl.github.io/ghdl-cosim/vhpidirect/declarations.html#restrictions-on-type-declarations. Hence, the focus in ghdl/ghdl#1053 (now in ghdl/ghdl-cosim#3), is to document the fat pointers and to provide a helper header file that makes it easier to use them from C. Incidentaly, because of April 16, 2020 7:14 AM, I think that currently this restriction applies to VPI/VHPI too. Hence, documenting it for VHPIDIRECT might be useful to extend support in VPI. Let me elaborate:
Currently, I think that you can set callback with VPI, and you will get access to variables/signals deep in the hierarchy. However, you are limited with regard to which variables/signals you can access/set/get. Precisely, I believe that the types that you can easily modify from VPI are the same that can be directly used in VHPIDIRECT. The point is that VPI provides you a poor-man's solution: iterating through arrays in the foreign language and setting/getting/modifying each item one by one. There is no API in VHPIDIRECT to do so. From my point of view, it doesn't make sense to write a vhpidirect_user.h header that allows to do so from C, because that would be duplicating what VPI/VHPI offer. Instead, I want to provide a C header that allows to access type my_t is array (natural range <>, natural range <>) of real; as double my_matrix [][] in C. ATM, it is easy to do it with constrained arrays type my_t is array (0 to n, 0 to m) of real; as double my_matrix [n][m] (see https://github.com/umarcor/ghdl-cosim/pull/10/files), but not with unconstrained.
Managing the C interface is a separate, but related issue. As a matter of fact, VHPIDIRECT does work with any of the backends (mcode, LLVM or GCC), but mcode does not support calling the simulation engine from C. See ghdl/ghdl#1215 (comment). As said in ghdl/ghdl-cosim#1, I believe that regardless of the approach for VHDL to execute C (VHPIDIRECT/VPI/VHPI), the API to handle GRT from C is common. This is what ghdl/ghdl#1053 (comment) is about.
but, correct me if I am wrong, it is still in an early stage of development
Most of it is in early stage of documentation, but it was developed many years ago. Very few modifications have been done in the last years. For example, the ghdl -e -shared flag was added a few days ago. But doing gcc -shared -Wl,$(ghdl --list-link tb) -Wl,--version-script=./file.ver -Wl,-u,ghdl_main has been supported for years, albeit not documented. By the same token, VHPIDIRECT examples are being rewritten and published now, but the same interface has been available for many years (10, at leat, http://ygdes.com/GHDL/).
If you mean the step-by-step execution of GRT, yes that's in early stage of development.
Also, I decided not to use 'cutting edge' features of GHDL right now to allow a SpinalHDL user to easily setup its development environment using system packages without the need to recompile/install GHDL by hand.
I believe there is no requirement to use cutting edge features. You can pick a mostly GCC based build approach. The requirement to recompile/install GHDL does not apply to many platforms, because fPIC is used by default. All available docker images do have it enabled by default. In fact, I don't know whether there is any real disadvantage in making this the default (as it was done with synthesis).
Once the API of #1053 is fixed, documented, with all the features the VPI has, then it is possible to evaluate a switch to that.
I would not suggest to change the VPI API, not now, not in the future. The work is already done and, as you said, it can be useful for other simulators too. As a matter of fact, a DPI interface similar to VHPIDIRECT might be added to future versions of the VHDL standard. However, that's out of scope for now.
What I meant was to focus on:
Being able to generate shared libs with either GCC or ghdl -e.
The management of the runtime.
The possibility to use VHPIDIRECT to share resources between the wrapper C/Java/Scala and the main testbench in the HDL sources. I.e., not to copy KBs of test data, but to pass a pointer/access instead.
The part that worries me most is the Scala part where paths/commands/options are glued together to bootstrap the simulation.
Note that GHDL is tested on MSYS2/MINGW on Windows. Hence, this should be handled automatically.
That is very nice to hear since I will need to simulate VexRiscv for work in VHDL :) .
Mixed language cosim would be a very nice feature to have.
I didn't mean mixed-language per se, but to simulate VHDL with GHDL, Verilog with Verilator and use SpinalHDL as a scheduler/manager in Scala to handle communication between both through VPI. I believe that "proper" mixed-language is out-of-scope of SpinalHDL.
PS: the above message is just my personal opinion that might not reflect the view of SpinalHDL's mantainers :) .
Activity
Dolu1990 commentedon Sep 12, 2018
Actualy, there is this interface in the spinal.sim sources :
https://github.com/SpinalHDL/SpinalHDL/blob/master/sim/src/main/scala/spinal/sim/SimRaw.scala#L15
which as to be implemented for a given target simulator
For Verilator it's implemented as following :
https://github.com/SpinalHDL/SpinalHDL/blob/master/sim/src/main/scala/spinal/sim/SimVerilator.scala
+
https://github.com/SpinalHDL/SpinalHDL/blob/master/sim/src/main/scala/spinal/sim/VerilatorBackend.scala
So in the case of verilator it wasn't a crazy amount of work. Then i have no idea how the ghdl shared object interface appear :)
Dolu1990 commentedon Sep 12, 2018
the def eval() function is called by spinalHDL to ask the simulatior to do delta cycles until everything is stabilized.
maybe that's a tricky thing ?
eine commentedon Sep 12, 2018
Hi @Dolu1990! Thanks for the references.
I think that implementing something as
eval()with GHDL might be possible with either the VPI or the VHPI interfaces. I have gathered some examples in 1138-4EB/hwd-ide/tree/vpi-ex-ghdl/examples, but I have not thoroughly learnt it yet.I was looking for something 'easier' to start with. I tried the following for now:
generateVerilogandSpinalVerilogwithgenerateVhdlandSpinalVhdlinVexRiscv/src/main/scala/vexriscv/demo/*.scala(see eine/VexRiscv@f9c7643).sbt "run-main vexriscv.demo.MuraxWithRamInit"generates aMurax.vhdfile now.MuraxinMurax.vhdas the UUT (see below).Murax.vhdandtb_murax.vhd:However, I don't know how to check it. The next step is to add a UART RX in the testbench, in order to read the output from Murax. But I am not sure about the clk period and the baud rate. I saw https://github.com/SpinalHDL/VexRiscv/blob/master/src/test/cpp/murax/main.cpp#L13-L16, so I think that the expected period might be
83.333 ns(12 MHz) and the baud rate115200. Is this correct? Also, should I provide any default value to the unused input ports (io_jtag_tms,io_jtag_tdi,io_jtag_tck,io_gpioA_readandio_uart_rxd)?Files
tb_murax.vhd:murax.gtkw:eine commentedon Sep 13, 2018
I tried adding UART RX and TX verification components to a VUnit testbench. So far it works ok. I could successfully write and get the same content out (as explained in SpinalHDL/VexRiscv#murax-soc). See testbench below:
I could also modify the demo program, rebuild it, and have it included when the SoC VHDL is generated.
@Dolu1990 , I am now looking at how to replace the UART with either AXI4 Stream interfaces or FIFOs. However, I did only find AXI4 Full and AXI4 Lite in https://github.com/SpinalHDL/SpinalHDL/tree/master/lib/src/main/scala/spinal/lib/bus. Am I missing any other source?
Dolu1990 commentedon Jan 12, 2019
@1138-4eb Sorry, i completly losed the track of this issue :/
Probably to interface other simulator, the good solution would be to do like cocotb, with VPI.
How things are going ?
eine commentedon Jan 15, 2019
Hi @Dolu1990, thanks for pinging back! In the end, I did nothing with neither SpinalSim nor VPI. But I have successfully used GHDL, VUnit, VexRiscv and VHPI to run some simulations. The scheme is as follows:
Apb3Axiswas added to Murax. These are two AXI Streams (a master and a slave) mapped to some registers in the VexRiscv memory space. See https://github.com/1138-4EB/VexRiscv/tree/add-axis.generateVerilogandSpinalVerilogstatements were replaced withgenerateVhdlandSpinalVhdl. See https://github.com/1138-4EB/VexRiscv/tree/murax-vhdl-axis.First, the RISCV software was built and the hex was generated. Then, the VHDL was generated with SpinalHDL. The VexRiscv VHDL and the testbench were compiled with GHDL. Last, a C app was built, adding the C wrapper and the compiled objects produced by GHDL.
When the app is started:
Moreover, all VHDL/VUnit logging features are available during simulation. Hence, execution statistics can be saved to log/csv files. Also, waveforms can be exported in any of the formats supported by GHDL, for further inspection with GUI tools, such as GtkWave.
Overall, it was some interesting investigation, as it is a useful setup to wrap GHDL in any other language that supports C-alike interfaces (say ada, golang, python, ruby, scala...).
However, I did not guess how to run the simulator only for the delta cycles corresponding to a timestamp, as you asked:
ATM, you call GHDL and the simulation runs until it is finished due to some assertion, error or because all the processes are stalled. I.e., the flow of the simulation is handled by GHDL.
Therefore, as you suggest,
yes, VPI would probably be the best fit here. Unfortunately, I have no experience with it.
Nevertheless, I might have misunderstood the requirements for
eval(). So, please, let me know if any of the info in this comment lights any bulb.EDIT
ghdl/ghdl#154
bellaz89 commentedon Mar 1, 2020
Surfing around I found a useful resource:
https://essay.utwente.nl/70777/1/Verheij_MA_EEMCS.pdf
This is a master thesis on how the co-simulation between Clash and GHDL/ModelSim/Icarus was done.
C snippets are present in this thesis.
bellaz89 commentedon Mar 10, 2020
@eine
I created a frontend C++ library for GHDL. See https://github.com/bellaz89/GHDLInteropREPL. It should be enough for SpinalSim.
@Dolu1990
I realized that my library completely misses dealing with signed values. Should all three kinds (Int, Long, BigInt) be sign-extended when they are written on signals wider than their intrinsic bit site and vice-versa?
Dolu1990 commentedon Mar 10, 2020
@bellaz89 Hmmm, so far i remember the SpinalSim API threat numbers as raw data, so there is no difference between signed and unsigned numbers. So that's already fine as far i can see ^^
eine commentedon Mar 25, 2020
@bellaz89, that's some interesting work. Thanks for the reference!
If going through the VPI path, you might find cocotb interesting. It uses either VPI or VHPI to interact with a bunch of simulators, GHDL being one of them.
For a more direct solution (with VHPIDIRECT/DPI), there is work in progress in VUnit/cosim. See also VUnit/vunit#603, ghdl/ghdl#1053 and ghdl/ghdl#1059. There are several comments about how to pass not only single values but also arrays or records/structs.
bellaz89 commentedon Apr 7, 2020
I have some updates.
I discovered that my previous approach didn't work because of the inability to link the entire GHDL runtime into a dynamic library.
Therefore I rewrote it (https://github.com/bellaz89/VPIInteropREPL). This project uses boost-interprocess to communicate between the simulator and the client program.
Such an interface is a much cleaner approach than the older one and it allows to simulate with ghdl-mcode and icarus verilog. With minimal effort It could be possible to add the support of other (commercial) simulators that use VPI. Since the interfacing code doesn't change from simulation to simulation we can think about caching the modules and libraries for later use to speed up the simulations.
bellaz89 commentedon Apr 10, 2020
@Dolu1990
In #293 I did the following things:
I am able to run simulations nicely in scala with
sbt "sim/test:runMain spinal.sim.PlayGhdl"You need to have Icarus Verilog or GHDL in your path and boost/interprocess headers in your include path.
See https://github.com/bellaz89/SpinalHDL/blob/ee3bb11415b337bfb4614cffe0957d7ea070e9a8/sim/src/test/scala/spinal/sim/Test2.scala#L62 and https://github.com/bellaz89/SpinalHDL/blob/ee3bb11415b337bfb4614cffe0957d7ea070e9a8/sim/src/test/scala/spinal/sim/Test2.scala#L95
Either sim/yolo/adder.vhd or sim/yolo/adder.v are used for the test.
The backend code creates the JNI shared library and the VPI plugins in sim/simulation_plugins/.
Since both JNI and VPI objects don't change from simulation to simulation, they are re-used by the following simulations significantly speeding up the loading time.
Remaining tasks/ideas
IVerilogto cross-check SpinalHDL's vhdl and verilog generators?Update
Due to incompatibilities between SpinalSim and IVerilog execution model, the IVerilog backend is not working properly anymore. See #295 .
Update
Now Icarus Verilog backend works as it should
bellaz89 commentedon Apr 13, 2020
Updates #296
umarcor commentedon Apr 16, 2020
Please, see https://ghdl.github.io/ghdl-cosim/vhpidirect/dynamic.html#generating-shared-libraries. That subsection was added/published less than 24h ago. It should allow you to pass pointers/accesses between VHDL and C, without having to resort to interprocesses. Nonetheless, it might still be useful to rely on them for different reasons.
The reference about shared libs above is still not tested on Windows or macOS. However, since GitHub Actions supports both of them, I'd like to add it to CI.
I have simulated VexRISCV with GHDL, including co-simulation with C. It works.
If possible, I think it would be so interesting to be able to co-simulate VHDL and Verilog sources (optionally with additional SpinalHDL). This is a very demanded feature, as mixed-language co-simulation with FOSS is not available yet: https://ghdl.readthedocs.io/en/latest/development/GSOC.html#mixed-language-vhdl-verilog. Precisely, there is a comment about GHDL and Verilator in https://ghdl.github.io/ghdl-cosim/#co-simulation-with-ghdl, because Tristan is thingking about adding a new backend to GHDL which would interact with Verilator (just as it interacts with yosys for synthesis). However, I don't know which would be the approach: to target an API or to generate C++/SystemC sources directly (which the user can then mix with Verilog->Verilator sources). An example (and presentation) about co-simulating VHDL and SystemC through GHDL is available https://github.com/ghdl/ghdl-cosim/tree/master/systemc. It has been recently discussed in the chat: March 26, 2020 10:54 AM.
bellaz89 commentedon Apr 16, 2020
This is a great news! However as you pointed out it is not the only reason why I switched to a multiple-processes approach:
(Disclaimer! I am not expert in VPI/GHDL/HDL simulations in general so my assumptions could be plain wrong :) )
, but, correct me if I am wrong, it is still in an early stage of development.
Also, I decided not to use 'cutting edge' features of GHDL right now to allow a SpinalHDL user to easily setup its development environment using system packages without the need to recompile/install GHDL by hand. Once the API of #1053 is fixed, documented, with all the features the VPI has, then it is possible to evaluate a switch to that.
Finally, the interprocess synchronization is done trough atomics. Therefore, even if the synchronization cost is higher than linking the runtime directly in the JVM, I think IMHO that the overhead is still quite low compared to the machine time required for nontrivial HDL simulations.
I think that the C++ side of the VPI interface code can be already run on different OSes since the only library dependency is boost-interprocess, (which is an header only lib). The part that worries me most is the Scala part where paths/commands/options are glued together to bootstrap the simulation.
That is very nice to hear since I will need to simulate VexRiscv for work in VHDL :) . @Dolu1990 has already written some code to make SpinalSim tests to work with the GHDL backend. The (his) idea is to try to run every SpinalHDL test, which actually runs on Verilator, on the GHDL backend too for testing purposes.
Mixed language cosim would be a very nice feature to have. Sadly I saw that the IVerilog simulator deprecated the VHDL simulation feature (steveicarus/iverilog#222) so right now I don't see a way to obtain this feature in the short term. From SpinalHDL perspective a way to perform mixed-lang would be to use the Verilator backend plus vhd2vl, but I never tested it so I am not able to say if it fits the common user needs.
bellaz89 commentedon Apr 16, 2020
PS: the above message is just my personal opinion that might not reflect the view of SpinalHDL's mantainers :) .
umarcor commentedon Apr 16, 2020
None of us is! We are here to talk about it and hopefully learn something!
I have not used VPI explicitly yet, so I'm not familiar with the details. However, I think that this limitation is not related to VPI, but to GHDL itself. No matter which cosimulation strategy you use,
ghdl_mainwill run from start to finish and all you can define are callbacks. When step execution is documented for GRT, it will be possible to use it from VPI/VHPI/VHPIDIRECT... See ghdl/ghdl#1053 (comment).I'm working around this in VUnit/vunit#568 with a 64bit counter that is shared between VHDL and C, and doing clock gating in the testbench to achieve a "stop the world" type of synch. Not elegant, but it works...
Actually, I'd suggest to have a look at cocotb for reference. They use VPI/VHPI to target multiple free/commercial simulators. E.g. ghdl/ghdl#1228. That's why I think that the work you are doing might be equivalent, as long as cocotb's and SpinalHDL's execution models are similar.
Precisely, this is the use case where I think that using VPI/VHPI pays off. For only sharing data in co-simulation contexts, it is not worth the hazzle. However, it can be really useful to peek deep in the hierarchy, such as swapping bits in space applications.
Not exactly. I'm mostly focused on VHPIDIRECT and on the C interface for the runtime library (GRT) that is embedded in the executables generated by GHDL.
VHPIDIRECT is similar to a Direct Programming Interface (DPI), since it allows to map procedures/functions only, from C to VHDL. For many use cases, this is equivalent to how VPI callbacks are defined and used. However, the main difference is that with VHPIDIRECT you need to call those functions from VHDL explicitly. So, from the designer's point of view, VPI/VHPI are a C-only approach that does not require to modify the VHDL, while VHPIDIRECT is for building the UUT and the testbench mostly in VHDL only. The main advantage of VHPIDIRECT is that, for non-complex data types, you don't need any 1K header. You just write what you need. See https://github.com/ghdl/ghdl-cosim/tree/master/vhpidirect/quickstart/customc.
Unfortunately, while sharing some data types between VHDL and C is straightforward, others (mainly unconstrained arrays) are fat pointers that are not documented. See https://ghdl.github.io/ghdl-cosim/vhpidirect/declarations.html#restrictions-on-type-declarations. Hence, the focus in ghdl/ghdl#1053 (now in ghdl/ghdl-cosim#3), is to document the fat pointers and to provide a helper header file that makes it easier to use them from C. Incidentaly, because of April 16, 2020 7:14 AM, I think that currently this restriction applies to VPI/VHPI too. Hence, documenting it for VHPIDIRECT might be useful to extend support in VPI. Let me elaborate:
Currently, I think that you can set callback with VPI, and you will get access to variables/signals deep in the hierarchy. However, you are limited with regard to which variables/signals you can access/set/get. Precisely, I believe that the types that you can easily modify from VPI are the same that can be directly used in VHPIDIRECT. The point is that VPI provides you a poor-man's solution: iterating through arrays in the foreign language and setting/getting/modifying each item one by one. There is no API in VHPIDIRECT to do so. From my point of view, it doesn't make sense to write a
vhpidirect_user.hheader that allows to do so from C, because that would be duplicating what VPI/VHPI offer. Instead, I want to provide a C header that allows to accesstype my_t is array (natural range <>, natural range <>) of real;asdouble my_matrix [][]in C. ATM, it is easy to do it with constrained arraystype my_t is array (0 to n, 0 to m) of real;asdouble my_matrix [n][m](see https://github.com/umarcor/ghdl-cosim/pull/10/files), but not with unconstrained.Managing the C interface is a separate, but related issue. As a matter of fact, VHPIDIRECT does work with any of the backends (mcode, LLVM or GCC), but mcode does not support calling the simulation engine from C. See ghdl/ghdl#1215 (comment). As said in ghdl/ghdl-cosim#1, I believe that regardless of the approach for VHDL to execute C (VHPIDIRECT/VPI/VHPI), the API to handle GRT from C is common. This is what ghdl/ghdl#1053 (comment) is about.
Most of it is in early stage of documentation, but it was developed many years ago. Very few modifications have been done in the last years. For example, the
ghdl -e -sharedflag was added a few days ago. But doinggcc -shared -Wl,$(ghdl --list-link tb) -Wl,--version-script=./file.ver -Wl,-u,ghdl_mainhas been supported for years, albeit not documented. By the same token, VHPIDIRECT examples are being rewritten and published now, but the same interface has been available for many years (10, at leat, http://ygdes.com/GHDL/).If you mean the step-by-step execution of GRT, yes that's in early stage of development.
I believe there is no requirement to use cutting edge features. You can pick a mostly GCC based build approach. The requirement to recompile/install GHDL does not apply to many platforms, because fPIC is used by default. All available docker images do have it enabled by default. In fact, I don't know whether there is any real disadvantage in making this the default (as it was done with synthesis).
I would not suggest to change the VPI API, not now, not in the future. The work is already done and, as you said, it can be useful for other simulators too. As a matter of fact, a DPI interface similar to VHPIDIRECT might be added to future versions of the VHDL standard. However, that's out of scope for now.
What I meant was to focus on:
Note that GHDL is tested on MSYS2/MINGW on Windows. Hence, this should be handled automatically.
I have not touched it in a while, but you can have a look at https://github.com/dbhi/spinalhdl-riscv. See also eine/VexRiscv@cb1b3fd.
I didn't mean mixed-language per se, but to simulate VHDL with GHDL, Verilog with Verilator and use SpinalHDL as a scheduler/manager in Scala to handle communication between both through VPI. I believe that "proper" mixed-language is out-of-scope of SpinalHDL.
Sure. The same applies to mine and GHDL.
umarcor commentedon Apr 19, 2020
@bellaz89, see ghdl/ghdl#237 and ghdl/ghdl#1249.
numero-744 commentedon Jun 4, 2022
The requested feature has been added: https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Simulation/bootstraps.html#configuration
So this issue can be closed