From 5e9007c2f5ae58fc4797c5c5dfe52eeac0b1f3eb Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Sun, 5 Apr 2020 06:15:05 +0200 Subject: [PATCH 01/37] Update Foreign.rst to reflect my learnings I found the page to be a little unclear in when and why to link to externally generated object files. It is a simple point in hindsight, but moving Linking foreign object files to GHDL to right after Foreign Declarations of Function makes it easier to see the link. I also added a Hint on how to pass command line arguments to ghdl_main, and wrote that the one code block is Python code (which wasn't immediately obvious to me at least). --- doc/using/Foreign.rst | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 7eda97a806..f4233c3a29 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -62,6 +62,25 @@ The value of the attribute must start with ``VHPIDIRECT`` (an upper-case keyword followed by one or more blanks). The linkage name of the subprogram follows. +The object file with the source code for the foreign subprogram must then be +linked to GHDL, as below. + +.. _Linking_with_foreign_object_files: + +Linking foreign object files to GHDL +==================================== + +You may add additional files or options during the link of `GHDL` using +``-Wl,`` as described in :ref:`passing-options-to-other-programs`. +For example:: + + ghdl -e -Wl,-lm math_tb + +will create the :file:`math_tb` executable with the :file:`lm` (mathematical) +library. + +Note the :file:`c` library is always linked with an executable. + .. _Restrictions_on_foreign_declarations: Restrictions on foreign declarations @@ -110,22 +129,6 @@ Accesses to an unconstrained array are fat pointers. Other accesses correspond t Files are represented by a 32 bit word, which corresponds to an index in a table. -.. _Linking_with_foreign_object_files: - -Linking foreign object files to GHDL -==================================== - -You may add additional files or options during the link of `GHDL` using -``-Wl,`` as described in :ref:`passing-options-to-other-programs`. -For example:: - - ghdl -e -Wl,-lm math_tb - -will create the :file:`math_tb` executable with the :file:`lm` (mathematical) -library. - -Note the :file:`c` library is always linked with an executable. - .. _Starting_a_simulation_from_a_foreign_program: Wrapping and starting a GHDL simulation from a foreign program @@ -140,6 +143,9 @@ in C: extern int ghdl_main (int argc, char **argv); +.. HINT:: + Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have an unused entry at index 0, effectively shifting all other indicies along by 1. This first index replicates a command line call which has the executable's path as the first argument. See `here `_ for a related discussion. + in Ada: .. code-block:: Ada @@ -203,7 +209,7 @@ See :ref:`gccllvm-only-programs` for further details about ``--bind`` and ``--li Dynamically loading foreign objects from GHDL ============================================= -Instead of linking and building foreign objects along with GHDL, it is also possible to load foreign resources dinamically. +Instead of linking and building foreign objects along with GHDL, it is also possible to load foreign resources dynamically. In order to do so, provide the path and name of the shared library where the resource is to be loaded from. For example: .. code-block:: VHDL @@ -219,7 +225,7 @@ that all the libraries and sources analyzed by GHDL generate position independen Furthermore, when the binary is built, argument ``-Wl,-pie`` needs to be provided. PIE binaries can be loaded and executed from any language that supports C-alike signatures and types -(C, C++, golang, Python, Rust, etc.). For example: +(C, C++, golang, Python, Rust, etc.). For example, in Python: .. code-block:: Python From 23cae01bfce5c851a033873749600b61ece6d7b7 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Mon, 6 Apr 2020 19:14:25 +0200 Subject: [PATCH 02/37] Update Foreign.rst to reflect my learnings: Rev1 Move Linking... back to original spot. Better hint, and extra reference to simulation options. --- doc/using/Foreign.rst | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index f4233c3a29..0da6132148 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -63,23 +63,7 @@ upper-case keyword followed by one or more blanks). The linkage name of the subprogram follows. The object file with the source code for the foreign subprogram must then be -linked to GHDL, as below. - -.. _Linking_with_foreign_object_files: - -Linking foreign object files to GHDL -==================================== - -You may add additional files or options during the link of `GHDL` using -``-Wl,`` as described in :ref:`passing-options-to-other-programs`. -For example:: - - ghdl -e -Wl,-lm math_tb - -will create the :file:`math_tb` executable with the :file:`lm` (mathematical) -library. - -Note the :file:`c` library is always linked with an executable. +linked to GHDL, expanded upon in :ref:`Starting_a_simulation_from_a_foreign_program`. .. _Restrictions_on_foreign_declarations: @@ -129,6 +113,22 @@ Accesses to an unconstrained array are fat pointers. Other accesses correspond t Files are represented by a 32 bit word, which corresponds to an index in a table. +.. _Linking_with_foreign_object_files: + +Linking foreign object files to GHDL +==================================== + +You may add additional files or options during the link of `GHDL` using +``-Wl,`` as described in :ref:`passing-options-to-other-programs`. +For example:: + + ghdl -e -Wl,-lm math_tb + +will create the :file:`math_tb` executable with the :file:`lm` (mathematical) +library. + +Note the :file:`c` library is always linked with an executable. + .. _Starting_a_simulation_from_a_foreign_program: Wrapping and starting a GHDL simulation from a foreign program @@ -143,8 +143,11 @@ in C: extern int ghdl_main (int argc, char **argv); +-- HINT:: + Further reading is at :ref:`USING:Simulation`, :ref:`simulation_options` and :ref:`Elab_Run:command` :ref:`elaborate_and_run_elab_run`. + .. HINT:: - Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have an unused entry at index 0, effectively shifting all other indicies along by 1. This first index replicates a command line call which has the executable's path as the first argument. See `here `_ for a related discussion. + Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of main()'s argv, or (not suggested, despite a lack of consequences) left empty. in Ada: From f01cb36c6d9ba848b28aaa37f2273f9ccaae4db6 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Mon, 6 Apr 2020 19:20:27 +0200 Subject: [PATCH 03/37] Add reference-able label to --elab-run --- doc/using/InvokingGHDL.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/using/InvokingGHDL.rst b/doc/using/InvokingGHDL.rst index 4deb96b7f2..613fdaf056 100644 --- a/doc/using/InvokingGHDL.rst +++ b/doc/using/InvokingGHDL.rst @@ -108,6 +108,8 @@ See section :ref:`USING:Simulation`, for details on options. .. index:: cmd elaborate and run +.. _elab_and_run:command: + Elaborate and run [``--elab-run``] ---------------------------------- From 914585ba7247899e351292ac53fbe7fbcf59ec1d Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Mon, 6 Apr 2020 19:21:57 +0200 Subject: [PATCH 04/37] Update Foreign.rst to reflect my learnings: Rev2 Clean up reference hint. --- doc/using/Foreign.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 0da6132148..226ff04c32 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -143,8 +143,8 @@ in C: extern int ghdl_main (int argc, char **argv); --- HINT:: - Further reading is at :ref:`USING:Simulation`, :ref:`simulation_options` and :ref:`Elab_Run:command` :ref:`elaborate_and_run_elab_run`. +.. HINT:: + Further reading is at :ref:`simulation_options` and :ref:`elab_and_run:command`. .. HINT:: Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of main()'s argv, or (not suggested, despite a lack of consequences) left empty. From 9028b5f12534ec5fe5c171667ac86320171de282 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Mon, 6 Apr 2020 19:27:12 +0200 Subject: [PATCH 05/37] Update Foreign.rst to reflect my learnings: Rev3 Further clean reference hints. --- doc/using/Foreign.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 226ff04c32..011cece0e9 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -144,7 +144,7 @@ in C: extern int ghdl_main (int argc, char **argv); .. HINT:: - Further reading is at :ref:`simulation_options` and :ref:`elab_and_run:command`. + Further reading is at :ref:`simulation_options`, :ref:`Elaboration:command` and :ref:`Run:command`. .. HINT:: Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of main()'s argv, or (not suggested, despite a lack of consequences) left empty. From ac2eff969415ab32014c4abc97578b6cbfee0722 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Mon, 6 Apr 2020 19:37:16 +0200 Subject: [PATCH 06/37] Update Foreign.rst to reflect my learnings: Rev4 Improve hints. --- doc/using/Foreign.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 011cece0e9..6c89b2169c 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -144,10 +144,11 @@ in C: extern int ghdl_main (int argc, char **argv); .. HINT:: - Further reading is at :ref:`simulation_options`, :ref:`Elaboration:command` and :ref:`Run:command`. + To compile the executable with the custom `main()`, its object file will have to be listed in the elaboration step. Analysis must be made of the HDL files, then elaboration with `-Wl,main.o toplevelEntityName` as arguments. Additional object files are flagged separate `-Wl,*` arguments. The elaboration step will compile the executable with the custom `main()` entrypoint. + Further reading (particularly about the backend restrictions) is at , :ref:`Elaboration:command` and :ref:`Run:command`. .. HINT:: - Immitating the run time flags within your own main(), such as ``-gDEPTH=12``, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of main()'s argv, or (not suggested, despite a lack of consequences) left empty. + Immitating the run time flags within your own `main()`, such as ``-gDEPTH=12`` from :ref:`simulation_options`, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of the argv passed to `main()`, or (not suggested, despite a lack of consequences) left empty. in Ada: From 0a208c11d5df3f95958d3d8e3ff9f6a6fe79eec5 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:00:04 +0200 Subject: [PATCH 07/37] Examples link to systemc-fosdem16 and hwd-ide --- doc/examples/VHPIDIRECT.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/examples/VHPIDIRECT.rst b/doc/examples/VHPIDIRECT.rst index f8eddf9112..e25a8fc2f4 100644 --- a/doc/examples/VHPIDIRECT.rst +++ b/doc/examples/VHPIDIRECT.rst @@ -16,3 +16,14 @@ ghdlex and netpp `ghdlex `_ is a set of C extensions to facilitate data exchange between a GHDL simulation and external applications. VHPIDIRECT mechanisms are used to wrap GHDL data types into structures usable from a C library. `ghdlex` uses the `netpp `_ library to expose virtual entities (such as pins or RAM) to the network. It also demonstrates simple data I/O through unix pipes. A few VHDL example entities are provided, such as a virtual console, FIFOs, RAM. The author of `netpp` and `ghdlex` is also working on `MaSoCist `_, a linux'ish build system for System on Chip designs, based on GHDL. It allows to handle more complex setup, e.g. how a RISC-V architecture (for example) is regress-tested using a virtual debug interface. + +SystemC and VHDL mixed simulation +================================= + +There is an example under `Demo of mixed vhdl + systemc simulation `_. + + +Examples Collection +=================== + +Past the examples under :ref:`USING:QuickStart:` there is a collection of GHDL use cases under eine's `hwd-ide `_. \ No newline at end of file From 4cd7c00cf8922ef7c5d1dab3544b79c66aa6ece5 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:00:49 +0200 Subject: [PATCH 08/37] Reference-able label of Foreign declarations --- doc/using/Foreign.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 6c89b2169c..9f479d2c7d 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -24,6 +24,8 @@ You can define a subprogram in a foreign language (such as `C` or inspect the hierarchy, set callbacks and/or assign signals. GHDL does not support VHPI. For these kind of features, it is suggested to use VPI instead (see :ref:`VPI_build_commands`). +.. _foreign_declarations: + Foreign declarations ==================== @@ -144,7 +146,10 @@ in C: extern int ghdl_main (int argc, char **argv); .. HINT:: - To compile the executable with the custom `main()`, its object file will have to be listed in the elaboration step. Analysis must be made of the HDL files, then elaboration with `-Wl,main.o toplevelEntityName` as arguments. Additional object files are flagged separate `-Wl,*` arguments. The elaboration step will compile the executable with the custom `main()` entrypoint. + To compile the executable with the custom `main()`, its object file will have to be listed in the elaboration step. + Analysis must be made of the HDL files, then elaboration with `-Wl,main.o toplevelEntityName` as arguments. + Additional object files are flagged separate `-Wl,*` arguments as per :ref:`Linking_with_foreign_object_files`. + The elaboration step will compile the executable with the custom `main()` entrypoint. Further reading (particularly about the backend restrictions) is at , :ref:`Elaboration:command` and :ref:`Run:command`. .. HINT:: From 7e98cc298898d38e8a4fd5a2397a53730fdaa5d4 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:01:22 +0200 Subject: [PATCH 09/37] Caccess Example added. --- doc/examples/quick_start/Caccess/README.rst | 72 +++++++++++++++++++ doc/examples/quick_start/Caccess/build.sh | 6 ++ doc/examples/quick_start/Caccess/cAccess.vhd | 63 ++++++++++++++++ doc/examples/quick_start/Caccess/cSharedVar.c | 37 ++++++++++ doc/examples/quick_start/Caccess/cSharedVar.h | 26 +++++++ doc/examples/quick_start/Caccess/main.c | 36 ++++++++++ doc/examples/quick_start/Caccess/toplevel.vhd | 33 +++++++++ doc/examples/quick_start/README.rst | 1 + 8 files changed, 274 insertions(+) create mode 100644 doc/examples/quick_start/Caccess/README.rst create mode 100644 doc/examples/quick_start/Caccess/build.sh create mode 100644 doc/examples/quick_start/Caccess/cAccess.vhd create mode 100644 doc/examples/quick_start/Caccess/cSharedVar.c create mode 100644 doc/examples/quick_start/Caccess/cSharedVar.h create mode 100644 doc/examples/quick_start/Caccess/main.c create mode 100644 doc/examples/quick_start/Caccess/toplevel.vhd diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst new file mode 100644 index 0000000000..da41ea7005 --- /dev/null +++ b/doc/examples/quick_start/Caccess/README.rst @@ -0,0 +1,72 @@ +.. program:: ghdl +.. _QuickStart:C_Access: + +`C Access` example +===================== + +The files +--------- + +The VHPIDIRECT method of accessing C-side variables and functions from VHDL requires these variables and functions to be declared +in a package. Each function's `foreign` attribute is set to highlight that the function has a foreign C-side definition, as per +:ref:`foreign_declarations`. + +.. literalinclude:: c_access.vhdl + :language: vhdl + +Assuming, for now, that these foreign functions perform as their names indicate they should, the toplevel test bench is defined next. + +.. literalinclude:: toplevel.vhdl + :language: vhdl + +Perhaps this example's flow is clearer by now: the testbench will use an integer array from C, the size of which is defined in C. +It will use a C-side function to prompt the user to set the value for index zero and then print and adjust all of the other indices. +Then the user is prompted to conclude the simulation or repeat the process. + + +The C functions and variables that GHDL accesses are kept in a separate .c/.h file: + +.. literalinclude:: cSharedVar.h + :language: c + +.. literalinclude:: cSharedVar.c + :language: c + +These are also exposed to the custom entry point in main.c: + +.. literalinclude:: main.c + :language: c + +Compilation +----------- + +- Firstly, the HDL files must be analysed by GHDL, producing object files for each (:ref:`Analysis:command`). +- Before the elaboration step, the object files for each `.c` file used is needed, so compile each with `gcc -c main.c -o main.o`. +- Elaborate with each C-side object file and finally the name of the toplevel entity. See :ref:`Starting_a_simulation_from_a_foreign_program` and :ref:`Linking_with_foreign_object_files`. + - The elaboration step is only possible with a GCC or LLVM backend. See :ref:`Elaboration:command`. +- Execute the produced executable. + +The compilation steps should look something like: + +-- literalinclude:: build.sh + :language: sh + +.. code-block:: shell + + Hello world! + +.. HINT:: + If a GCC/LLVM variant of `GHDL` is used: + + * :ref:`Analysis ` generates a file, :file:`hello.o`, which is the object file corresponding to + your `VHDL` program. This is not created with :ref:`mcode `. These kind of object files can be + compiled into foreign programs (see :ref:`Linking_with_Ada`). + * The :ref:`elaboration ` step is mandatory after running the analysis and prior to launching the + simulation. This will generate an executable binary named :file:`hello_world`. + * As a result, :option:`-r` is just a passthrough to the binary generated in the `elaboration`. Therefore, the + executable can be run directly: ``./hello_world``. See :option:`-r` for more informartion. + +.. HINT:: + + :option:`-e` can be bypassed with :ref:`mcode `, since :option:`-r` actually elaborates the design and saves + it on memory before running the simulation. But you can still use it to check for some elaboration problems. diff --git a/doc/examples/quick_start/Caccess/build.sh b/doc/examples/quick_start/Caccess/build.sh new file mode 100644 index 0000000000..901a07ffe9 --- /dev/null +++ b/doc/examples/quick_start/Caccess/build.sh @@ -0,0 +1,6 @@ +gcc -c cSharedVar.c -o cSharedVar.o && +gcc -c main.c -o main.o && +ghdl-llvm -a cAccess.vhd toplevel.vhd && +ghdl-llvm -e -Wl,main.o -Wl,cSharedVar.o toplevel +./toplevel +rm *.o work-obj*.cf toplevel diff --git a/doc/examples/quick_start/Caccess/cAccess.vhd b/doc/examples/quick_start/Caccess/cAccess.vhd new file mode 100644 index 0000000000..a2f26f532d --- /dev/null +++ b/doc/examples/quick_start/Caccess/cAccess.vhd @@ -0,0 +1,63 @@ +library ieee; +use ieee.std_logic_1164.all; + +package cAccess is + + type int_ptr is access integer; -- represented C-side with int + function c_intArrSize_ptr return int_ptr; -- represented C-side with int* + attribute foreign of c_intArrSize_ptr : + function is "VHPIDIRECT getIntArrSize"; -- getIntArrSize is the C-side function name + + shared variable c_sizeInt : int_ptr := c_intArrSize_ptr; + + type int_arr is array(0 to c_sizeInt.all-1) of integer; + type int_arr_ptr is access int_arr; -- represented C-side with int* + + + function c_intArr_ptr return int_arr_ptr; + attribute foreign of c_intArr_ptr : + function is "VHPIDIRECT getIntArr_ptr"; + procedure c_promptIndexValue(index: integer); + attribute foreign of c_promptIndexValue : + procedure is "VHPIDIRECT promptIndexValue"; + + shared variable c_intArr : int_arr_ptr := c_intArr_ptr; + + type char_ptr is access std_ulogic; -- represented C-side with char + function c_finished_ptr return char_ptr; + attribute foreign of c_finished_ptr : + function is "VHPIDIRECT getFinished_ptr"; + + procedure c_promptFinished; + attribute foreign of c_promptFinished : + procedure is "VHPIDIRECT promptFinished"; + + shared variable c_finished : char_ptr := c_finished_ptr; +end package cAccess; + +package body cAccess is + + function c_intArrSize_ptr return int_ptr is + begin + assert false report "c_intArrSize_ptr VHPI" severity failure; + end c_intArrSize_ptr; + + + function c_intArr_ptr return int_arr_ptr is + begin + assert false report "c_intArr_ptr VHPI" severity failure; + end c_intArr_ptr; + procedure c_promptIndexValue(index: integer) is + begin + assert false report "c_promptIndexValue VHPI" severity failure; + end c_promptIndexValue; + + function c_finished_ptr return char_ptr is + begin + assert false report "c_finished_ptr VHPI" severity failure; + end c_finished_ptr; + procedure c_promptFinished is + begin + assert false report "c_promptFinished VHPI" severity failure; + end c_promptFinished; +end package body cAccess; diff --git a/doc/examples/quick_start/Caccess/cSharedVar.c b/doc/examples/quick_start/Caccess/cSharedVar.c new file mode 100644 index 0000000000..dd1a7f2f71 --- /dev/null +++ b/doc/examples/quick_start/Caccess/cSharedVar.c @@ -0,0 +1,37 @@ +#include "cSharedVar.h" + +int* getIntArrSize(){ + return &sizeInt; +} + +int* getIntArr_ptr(){ + return intArray; +} + +void promptIndexValue(int index){ + char strIn[8]; + + printf("Enter a number for index %d: ", index); + fgets(strIn, sizeof strIn, stdin); + printf("\n"); + sscanf(strIn, "%d", &intArray[index]); +} + + +char* getFinished_ptr(){ + return &finishedChar; +} + +void promptFinished(){ + char strIn[3]; + + printf("Conclude simulation? (Y/n): "); + fgets(strIn, sizeof strIn, stdin); + printf("\n"); + if(strIn[0] == 'N' || strIn[0] == 'n'){ + finishedChar = VHDL_0; + } + else{ + finishedChar = VHDL_1; + } +} \ No newline at end of file diff --git a/doc/examples/quick_start/Caccess/cSharedVar.h b/doc/examples/quick_start/Caccess/cSharedVar.h new file mode 100644 index 0000000000..a3a6923704 --- /dev/null +++ b/doc/examples/quick_start/Caccess/cSharedVar.h @@ -0,0 +1,26 @@ +#include + +int sizeInt; +int* getIntArrSize(); + +int* intArray; +int* getintArray_ptr(); +void promptIndexValue(); + +char finishedChar; +char* getFinished_ptr(); +void promptFinished(); + +static const char VHDL_BIT_STATE[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'}; + +enum VHDL_BIT_CHAR { +VHDL_U = 0, +VHDL_X = 1, +VHDL_0 = 2, +VHDL_1 = 3, +VHDL_Z = 4, +VHDL_W = 5, +VHDL_L = 6, +VHDL_H = 7, +VHDL_D = 8, +}; diff --git a/doc/examples/quick_start/Caccess/main.c b/doc/examples/quick_start/Caccess/main.c new file mode 100644 index 0000000000..bb5a8ef147 --- /dev/null +++ b/doc/examples/quick_start/Caccess/main.c @@ -0,0 +1,36 @@ +#include + +#include "cSharedVar.h" + +extern int ghdl_main(char argc, char* argv[]); + +int main(int argc, char const *argv[]) +{ + char strIn[3]; + printf("Enter the Integer Array length [1-9]: "); + fgets(strIn, sizeof strIn, stdin); + printf("\n"); + sscanf(strIn, "%d", &sizeInt); + + if(sizeInt < 1) + sizeInt = 1; + + intArray = malloc(sizeInt*sizeof(int)); + + for (int i = 0; i < sizeInt; i++) + { + intArray[i] = i*i; + } + + printf("ghdl_main return: %d\n", ghdl_main(0, NULL)); + printf("\n********************************\nghdl simulation completed.\n\n"); + + for (int i = 0; i < sizeInt; i++) + { + printf("intArray[%d] = %d\n", i, intArray[i]); + } + + return 0; +} + + diff --git a/doc/examples/quick_start/Caccess/toplevel.vhd b/doc/examples/quick_start/Caccess/toplevel.vhd new file mode 100644 index 0000000000..7675f43c3b --- /dev/null +++ b/doc/examples/quick_start/Caccess/toplevel.vhd @@ -0,0 +1,33 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.cAccess.all; + +entity toplevel is +end entity toplevel; + +architecture RTL of toplevel is + +begin + + process + begin + report "array length: " & integer'image(c_intArr.all'length); + + c_promptIndexValue(0); + + for i in 1 to c_intArr.all'right loop + report "c_intArr[" & integer'image(i) &"] = " & integer'image(c_intArr.all(i)) & ". Set to: " & integer'image(2*c_intArr.all(i)); + c_intArr.all(i) := 2*c_intArr.all(i); + end loop; + + c_promptFinished; + if(c_finished.all = '1') then + wait; + end if; + report "c_finished = " & std_ulogic'image(c_finished.all); + end process; + + +end architecture RTL; diff --git a/doc/examples/quick_start/README.rst b/doc/examples/quick_start/README.rst index 7fb8f046a7..73c26f8949 100644 --- a/doc/examples/quick_start/README.rst +++ b/doc/examples/quick_start/README.rst @@ -48,3 +48,4 @@ in the hope of helping understand the different use cases: heartbeat/README adder/README DLXModelSuite + Caccess/README From 86fb725b20dfdf83f0ff8a1eb9c2676423590b3b Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:20:45 +0200 Subject: [PATCH 10/37] Revise c_access README.rst --- doc/examples/quick_start/Caccess/README.rst | 39 +++++++-------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst index da41ea7005..31b39c9f48 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/quick_start/Caccess/README.rst @@ -9,12 +9,14 @@ The files The VHPIDIRECT method of accessing C-side variables and functions from VHDL requires these variables and functions to be declared in a package. Each function's `foreign` attribute is set to highlight that the function has a foreign C-side definition, as per -:ref:`foreign_declarations`. +:ref:`foreign_declarations`. + +This example starts with :file:`c_access.vhdl`: .. literalinclude:: c_access.vhdl :language: vhdl -Assuming, for now, that these foreign functions perform as their names indicate they should, the toplevel test bench is defined next. +Assuming, for now, that these foreign functions perform as their names indicate they should, the toplevel test bench is defined next (:file:`toplevel.vhdl`): .. literalinclude:: toplevel.vhdl :language: vhdl @@ -24,7 +26,7 @@ It will use a C-side function to prompt the user to set the value for index zero Then the user is prompted to conclude the simulation or repeat the process. -The C functions and variables that GHDL accesses are kept in a separate .c/.h file: +The C functions and variables that GHDL accesses are kept in a separate pair (:file:`cSharedVar.h`, :file:`cSharedVar.c`): .. literalinclude:: cSharedVar.h :language: c @@ -32,11 +34,14 @@ The C functions and variables that GHDL accesses are kept in a separate .c/.h fi .. literalinclude:: cSharedVar.c :language: c -These are also exposed to the custom entry point in main.c: +These are also exposed to the custom entry point in :file:`main.c`: .. literalinclude:: main.c :language: c +It is seen that the array's length is established, and its contents filled with square numbers, before the GHDL simulation happens. +After that, the array is read out. + Compilation ----------- @@ -46,27 +51,7 @@ Compilation - The elaboration step is only possible with a GCC or LLVM backend. See :ref:`Elaboration:command`. - Execute the produced executable. -The compilation steps should look something like: - --- literalinclude:: build.sh - :language: sh - -.. code-block:: shell - - Hello world! - -.. HINT:: - If a GCC/LLVM variant of `GHDL` is used: - - * :ref:`Analysis ` generates a file, :file:`hello.o`, which is the object file corresponding to - your `VHDL` program. This is not created with :ref:`mcode `. These kind of object files can be - compiled into foreign programs (see :ref:`Linking_with_Ada`). - * The :ref:`elaboration ` step is mandatory after running the analysis and prior to launching the - simulation. This will generate an executable binary named :file:`hello_world`. - * As a result, :option:`-r` is just a passthrough to the binary generated in the `elaboration`. Therefore, the - executable can be run directly: ``./hello_world``. See :option:`-r` for more informartion. - -.. HINT:: +The compilation steps should look something like :file:`build.sh`: - :option:`-e` can be bypassed with :ref:`mcode `, since :option:`-r` actually elaborates the design and saves - it on memory before running the simulation. But you can still use it to check for some elaboration problems. +.. literalinclude:: build.sh + :language: sh \ No newline at end of file From 63193c2f544e5bc6cc331519479ec453a14dabc7 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:40:35 +0200 Subject: [PATCH 11/37] Fix .vhd literal includes --- doc/examples/quick_start/Caccess/README.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst index 31b39c9f48..d79f268caf 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/quick_start/Caccess/README.rst @@ -13,12 +13,12 @@ in a package. Each function's `foreign` attribute is set to highlight that the f This example starts with :file:`c_access.vhdl`: -.. literalinclude:: c_access.vhdl +.. literalinclude:: c_access.vhd :language: vhdl Assuming, for now, that these foreign functions perform as their names indicate they should, the toplevel test bench is defined next (:file:`toplevel.vhdl`): -.. literalinclude:: toplevel.vhdl +.. literalinclude:: toplevel.vhd :language: vhdl Perhaps this example's flow is clearer by now: the testbench will use an integer array from C, the size of which is defined in C. @@ -26,14 +26,17 @@ It will use a C-side function to prompt the user to set the value for index zero Then the user is prompted to conclude the simulation or repeat the process. -The C functions and variables that GHDL accesses are kept in a separate pair (:file:`cSharedVar.h`, :file:`cSharedVar.c`): +The C functions and variables that GHDL accesses are kept in a separate header/code pair. :file:`cSharedVar.h`: .. literalinclude:: cSharedVar.h :language: c +And :file:`cSharedVar.c`: + .. literalinclude:: cSharedVar.c :language: c + These are also exposed to the custom entry point in :file:`main.c`: .. literalinclude:: main.c From bb33ea0446602d0e9209ad82b34e43fbaab8a0b8 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:45:03 +0200 Subject: [PATCH 12/37] Another fix for .vhd file include -_- --- doc/examples/quick_start/Caccess/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst index d79f268caf..50ac9c495a 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/quick_start/Caccess/README.rst @@ -13,7 +13,7 @@ in a package. Each function's `foreign` attribute is set to highlight that the f This example starts with :file:`c_access.vhdl`: -.. literalinclude:: c_access.vhd +.. literalinclude:: cAccess.vhd :language: vhdl Assuming, for now, that these foreign functions perform as their names indicate they should, the toplevel test bench is defined next (:file:`toplevel.vhdl`): From 986645879441f7d25948708831bcb759a417d4af Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 10:48:02 +0200 Subject: [PATCH 13/37] Grammar fix is->are --- doc/examples/quick_start/Caccess/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst index 50ac9c495a..aec7673c20 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/quick_start/Caccess/README.rst @@ -49,7 +49,7 @@ Compilation ----------- - Firstly, the HDL files must be analysed by GHDL, producing object files for each (:ref:`Analysis:command`). -- Before the elaboration step, the object files for each `.c` file used is needed, so compile each with `gcc -c main.c -o main.o`. +- Before the elaboration step, the object files of all `.c` files being used are needed, so compile each with `gcc -c main.c -o main.o`. - Elaborate with each C-side object file and finally the name of the toplevel entity. See :ref:`Starting_a_simulation_from_a_foreign_program` and :ref:`Linking_with_foreign_object_files`. - The elaboration step is only possible with a GCC or LLVM backend. See :ref:`Elaboration:command`. - Execute the produced executable. From cdb33daa8df5338054bbf28df9c2fb4ddcbeb9f9 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 12:05:28 +0200 Subject: [PATCH 14/37] Add tip for passing GHDL_main() runtime options --- doc/examples/quick_start/Caccess/README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/quick_start/Caccess/README.rst index aec7673c20..7332161ad3 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/quick_start/Caccess/README.rst @@ -45,6 +45,9 @@ These are also exposed to the custom entry point in :file:`main.c`: It is seen that the array's length is established, and its contents filled with square numbers, before the GHDL simulation happens. After that, the array is read out. +.. TIP:: + To pass GHDL runtime options, see the second hint under :ref:`Starting_a_simulation_from_a_foreign_program`. + Compilation ----------- From 15e6d9e3dfdf0cd1931b5fa02d0574ad706cfa07 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 14:35:51 +0200 Subject: [PATCH 15/37] Fix Quickstart reference --- doc/examples/VHPIDIRECT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/VHPIDIRECT.rst b/doc/examples/VHPIDIRECT.rst index e25a8fc2f4..845b381ec0 100644 --- a/doc/examples/VHPIDIRECT.rst +++ b/doc/examples/VHPIDIRECT.rst @@ -26,4 +26,4 @@ There is an example under `Demo of mixed vhdl + systemc simulation `_. \ No newline at end of file +Past the examples under :ref:`USING:QuickStart` there is a collection of GHDL use cases under eine's `hwd-ide `_. \ No newline at end of file From 82b586e9f2b566b640003498e1a69f15131a2d10 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Tue, 7 Apr 2020 14:43:18 +0200 Subject: [PATCH 16/37] Add use case of -frelaxed-rules --- doc/examples/quick_start/README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/examples/quick_start/README.rst b/doc/examples/quick_start/README.rst index 73c26f8949..78108868f0 100644 --- a/doc/examples/quick_start/README.rst +++ b/doc/examples/quick_start/README.rst @@ -26,7 +26,8 @@ The following tips might be useful: * Use :option:`--ieee=synopsys <--ieee>` if your design depends on a non-standard implementation of the IEEE library. - * Use :option:`-fexplicit` and :option:`-frelaxed-rules` if needed. + * Use :option:`-fexplicit` and :option:`-frelaxed-rules` if needed. For instance when relaxing VHDL 2008's need for shared + variables to be protected types, you can use `--std=08 -frelaxed`. * Use :option:`--work=LIB_NAME <--work>` to analyze files into the ``LIB_NAME`` library. To use files analyzed to a different directory, give the path From 8d0ac86c2efb5488298c040c020628969b6d7403 Mon Sep 17 00:00:00 2001 From: umarcor Date: Wed, 11 Dec 2019 12:11:13 +0100 Subject: [PATCH 17/37] doc: add VHPIDIRECT demo --- doc/examples/README.rst | 2 +- doc/examples/{ => vhpidirect}/VHPIDIRECT.rst | 7 + doc/examples/vhpidirect/demo/README.rst | 21 ++ doc/examples/vhpidirect/demo/ghdl.h | 224 +++++++++++++++++++ doc/examples/vhpidirect/demo/main.c | 160 +++++++++++++ doc/examples/vhpidirect/demo/run.sh | 9 + doc/examples/vhpidirect/demo/tb.vhd | 110 +++++++++ 7 files changed, 532 insertions(+), 1 deletion(-) rename doc/examples/{ => vhpidirect}/VHPIDIRECT.rst (92%) create mode 100644 doc/examples/vhpidirect/demo/README.rst create mode 100644 doc/examples/vhpidirect/demo/ghdl.h create mode 100644 doc/examples/vhpidirect/demo/main.c create mode 100644 doc/examples/vhpidirect/demo/run.sh create mode 100644 doc/examples/vhpidirect/demo/tb.vhd diff --git a/doc/examples/README.rst b/doc/examples/README.rst index 921bcf2a38..be4d731029 100644 --- a/doc/examples/README.rst +++ b/doc/examples/README.rst @@ -9,4 +9,4 @@ or interaction with third-party projects. It is suggested for users who are new .. toctree:: - ../examples/VHPIDIRECT + ./vhpidirect/VHPIDIRECT diff --git a/doc/examples/VHPIDIRECT.rst b/doc/examples/vhpidirect/VHPIDIRECT.rst similarity index 92% rename from doc/examples/VHPIDIRECT.rst rename to doc/examples/vhpidirect/VHPIDIRECT.rst index f8eddf9112..6524e0fa08 100644 --- a/doc/examples/VHPIDIRECT.rst +++ b/doc/examples/vhpidirect/VHPIDIRECT.rst @@ -3,6 +3,13 @@ Data exchange through VHPIDIRECT ################################ +.. toctree:: + :hidden: + + demo/README + +See :ref:`Examples:VHPIDIRECT:Demo` for a demo about how to pass different types of data to/from VHDL and C through VHPIDIRECT. + VUnit ===== diff --git a/doc/examples/vhpidirect/demo/README.rst b/doc/examples/vhpidirect/demo/README.rst new file mode 100644 index 0000000000..5e4a21cdf2 --- /dev/null +++ b/doc/examples/vhpidirect/demo/README.rst @@ -0,0 +1,21 @@ +.. program:: ghdl +.. _Examples:VHPIDIRECT:Demo: + +VHPIDIRECT Demo +=============== + +The following sources show how to pass different types of data to/from VHDL and C through VHPIDIRECT. + +.. NOTE:: :file:`ghdl.h` is a reference of GHDL's ABI, which can be imported to easily convert data types. However, the ABI is not settled, so it might change without prior notice. + +.. literalinclude:: run.sh + :language: bash + +.. literalinclude:: tb.vhd + :language: vhdl + +.. literalinclude:: main.c + :language: c + +.. literalinclude:: ghdl.h + :language: c diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h new file mode 100644 index 0000000000..23e06fb95f --- /dev/null +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -0,0 +1,224 @@ +#ifndef GHDL_TYPES_H +#define GHDL_TYPES_H + +#include +#include +#include +#include + +// Range/bounds of a dimension of an unconstrained array with dimensions of type 'natural' +typedef struct { + int32_t left; + int32_t right; + int32_t dir; + int32_t len; +} range_t; + +// Range/bounds of an unconstrained array with 1, 2 or 3 dimensions of type 'natural' +typedef struct { + range_t dim_1; +} bounds_t; +typedef struct { + range_t dim_1; + range_t dim_2; +} bounds2D_t; +typedef struct { + range_t dim_1; + range_t dim_2; + range_t dim_3; +} bounds3D_t; + +// Unconstrained array with dimensions of type 'natural' +typedef struct { + void* array; + bounds_t* bounds; +} ghdl_NaturalDimArr_t; + +// Access to an unconstrained array with 1 dimension of type 'natural' +typedef struct { + range_t range; + uint8_t array[]; +} ghdl_AccNaturalDimArr_t; + +/* +* Print custom types +*/ + +void print(ghdl_NaturalDimArr_t* ptr) { + printf("array: %p\n", ptr->array); + printf("bounds: %p\n", ptr->bounds); + printf("bounds.left: %d\n", ptr->bounds->dim_1.left); + printf("bounds.right: %d\n", ptr->bounds->dim_1.right); + printf("bounds.dir: %d\n", ptr->bounds->dim_1.dir); + printf("bounds.len: %d\n", ptr->bounds->dim_1.len); +} + +/* +* Convert a fat pointer of an unconstrained string, to a (null terminated) C string +*/ + +// @umarcor +char* ghdlToString(ghdl_NaturalDimArr_t* ptr) { + assert(ptr != NULL); + assert(ptr->bounds != NULL); + int len = ptr->bounds->dim_1.len; + char* str = malloc(sizeof(char) * len + 1); + strncpy(str, ptr->array, len); + str[len] = '\0'; + return str; +} + +// In the prototype, Bradley declares a value instead of a reference. Why? + +// @bradleyharden +/* +char* ghdl_array_to_string(array_t array) { + // Add a null character, because GHDL strings are not null-terminated + char *string = malloc(array.range->len + 1); + strncpy(string, array.array, array.range->len); + string[array.range->len] = '\0'; + return string; +} +*/ + +/* +* Convert a fat pointer of an uncontrained array with (up to 3) dimensions of type 'natural', to C types +*/ + +void ghdlToArray(ghdl_NaturalDimArr_t* ptr, void** vec, int* len, int num) { + assert(ptr != NULL); + assert(ptr->bounds != NULL); + *vec = ptr->array; + + void* b = ptr->bounds; + switch (num) { + case 1: + len[0] = ((bounds_t*)b)->dim_1.len; + break; + case 2: + len[0] = ((bounds2D_t*)b)->dim_2.len; + len[1] = ((bounds2D_t*)b)->dim_1.len; + break; + case 3: + len[0] = ((bounds3D_t*)b)->dim_3.len; + len[1] = ((bounds3D_t*)b)->dim_2.len; + len[2] = ((bounds3D_t*)b)->dim_1.len; + break; + } +} + +/* +* Convert a (null terminated) C string, to a fat pointer of an unconstrained string +*/ + +// @umarcor +/* +ghdl_NaturalDimArr_t* ghdlFromString(char* str) { + uint32_t len = strlen(str); + ghdl_NaturalDimArr_t* ptr = malloc(sizeof(ghdl_NaturalDimArr_t)); + ptr->array = malloc(sizeof(char) * len); + strncpy((char*)(ptr->array), str, len); + ptr->bounds = malloc(sizeof(bounds_t)); + bounds_t* b = ptr->bounds; + b->dim_1.left = 1; + b->dim_1.right = len; + b->dim_1.dir = 0; + b->dim_1.len = len; + return ptr; +} +*/ + +// Again, the prototype I had (above) returns a reference instead of a value (Bradley's below) + +// @bradleyharden +ghdl_NaturalDimArr_t ghdlFromString(char *string) { + range_t *range = malloc(sizeof(range_t)); + assert(range != NULL); + uint32_t len = strlen(string); + range->left = 1; + range->right = len; + range->dir = 0; + range->len = len; + // Don't bother copying the string, because GHDL will do that anyway + return (ghdl_NaturalDimArr_t){.array=string, .bounds=(bounds_t*)range}; +} + +/* +* Convert C types representing an unconstrained array with a dimension of type 'natural', to a fat pointer +*/ + +ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int num) { + bounds_t* b = malloc(sizeof(bounds_t)); + assert(b != NULL); + switch (num) { + case 3: + // TODO + case 2: + // TODO + case 1: + b->dim_1.left = 0; + b->dim_1.right = len[0]-1; + b->dim_1.dir = 0; + b->dim_1.len = len[0]; + } + return (ghdl_NaturalDimArr_t){.array=vec, .bounds=b}; +} + +/* +* Convert an access to an unconstrained string, to a (null terminated) C string +*/ + +char* ghdlAccToString(ghdl_AccNaturalDimArr_t *line) { + // Add a null character, because GHDL strings are not null-terminated + char *string = malloc(line->range.len + 1); + strncpy(string, line->array, line->range.len); + string[line->range.len] = '\0'; +} + +/* +* Convert C types representing an unconstrained array with a dimension of type 'natural', to an access +*/ + +// TODO: support 2 and 3 dimensions +ghdl_AccNaturalDimArr_t* ghdlAccFromArray(uint32_t length, size_t bytes) { + ghdl_AccNaturalDimArr_t *access = malloc(sizeof(ghdl_AccNaturalDimArr_t) + length * bytes); + assert(access != NULL); + access->range.left = 0; + access->range.right = length - 1; + access->range.dir = 0; + access->range.len = length; + return access; +} + +/* +* Convert a (null terminated) C string, to an access to an unconstrained string +*/ + +/* +// @umarcor +ghdl_AccNaturalDimArr_t* ghdlLineFromString(char *str) { + uint32_t len = strlen(str); + ghdl_AccNaturalDimArr_t *line = malloc(sizeof(ghdl_AccNaturalDimArr_t) + sizeof(char) * len); + line->bounds.left = 1; + line->bounds.right = len; + line->bounds.dir = 0; + line->bounds.len = len; + strncpy(line->array, str, len); + return line; +} +*/ + +// @bradleyharden +ghdl_AccNaturalDimArr_t* ghdlAccFromString(char *string) { + uint32_t length = strlen(string); + ghdl_AccNaturalDimArr_t *line = ghdlAccFromArray(length, 1); + // New access objects default to numbering from 0, + // but VHDL strings must be numbered from 1 + line->range.left++; + line->range.right++; + // Don't copy the null termination + strncpy(line->array, string, length); + return line; +} + +#endif diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c new file mode 100644 index 0000000000..b4e0c478d7 --- /dev/null +++ b/doc/examples/vhpidirect/demo/main.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include + +#include + +typedef struct rec_t { + char r_char; + int32_t r_int; +} rec_t; + +typedef enum {standby, start, busy, done} enum_t; + +void testCinterface( + char v_char, + int32_t v_int, + uint32_t v_nat, + uint32_t v_pos, + double v_real, + bool v_bool, + bool v_bit, + int64_t v_time, + rec_t* v_rec, + uint8_t v_enum, + ghdl_NaturalDimArr_t* v_str, + ghdl_NaturalDimArr_t* v_vec_int, + ghdl_NaturalDimArr_t* v_vec_real, + ghdl_NaturalDimArr_t* v_vec_bool, + ghdl_NaturalDimArr_t* v_vec_bit, + ghdl_NaturalDimArr_t* v_vec_phy, + ghdl_NaturalDimArr_t* v_vec_rec, + ghdl_NaturalDimArr_t* v_vec_enum, + ghdl_NaturalDimArr_t* v_2vec_real +) { + assert(v_char == 'k'); + printf("v_char : %c\n", v_char); + + assert(v_int == -6); + printf("v_int : %d\n", v_int); + + assert(v_nat == 9); + printf("v_nat : %d\n", v_nat); + + assert(v_pos == 3); + printf("v_pos : %d\n", v_pos); + + assert(v_real == 3.34); + printf("v_real : %f\n", v_real); + + assert(v_bool == true); + printf("v_bool : %d\n", v_bool); + + assert(v_bit == true); + printf("v_bit : %d\n", v_bit); + + assert(v_time == 20e6); + printf("v_time : %d\n", v_time); + + assert(v_rec != NULL); + assert(v_rec->r_char == 'y'); + assert(v_rec->r_int == 5); + printf("v_rec : %p %c %d\n", v_rec, v_rec->r_char, v_rec->r_int); + + assert(v_enum == busy); + printf("v_enum : %d %d\n", v_enum, busy); + + char* str = ghdlToString(v_str); + printf("v_str : %p '%s' [%d]\n", v_str->array, str, strlen(str)); + + int* len = malloc(2 * sizeof(int)); + + int32_t* vec_int; + ghdlToArray(v_vec_int, (void**)&vec_int, len, 1); + assert(vec_int[0] == 11); + assert(vec_int[1] == 22); + assert(vec_int[2] == 33); + assert(vec_int[3] == 44); + assert(vec_int[4] == 55); + printf("v_vec_int : %p [%d]\n", vec_int, len[0]); + + double* vec_real; + ghdlToArray(v_vec_real, (void**)&vec_real, len, 1); + assert(vec_real[0] == 0.5); + assert(vec_real[1] == 1.75); + assert(vec_real[2] == 3.33); + assert(vec_real[3] == -0.125); + assert(vec_real[4] == -0.67); + assert(vec_real[5] == -2.21); + printf("v_vec_real : %p [%d]\n", vec_real, len[0]); + + bool* vec_bool; + ghdlToArray(v_vec_bool, (void**)&vec_bool, len, 1); + assert(vec_bool[0] == 0); + assert(vec_bool[1] == 1); + assert(vec_bool[2] == 1); + assert(vec_bool[3] == 0); + printf("v_vec_bool : %p [%d]\n", vec_bool, len[0]); + + bool* vec_bit; + ghdlToArray(v_vec_bit, (void**)&vec_bit, len, 1); + assert(vec_bit[0] == 1); + assert(vec_bit[1] == 0); + assert(vec_bit[2] == 1); + assert(vec_bit[3] == 0); + printf("v_vec_bit : %p [%d]\n", vec_bit, len[0]); + + int64_t* vec_phy; + ghdlToArray(v_vec_phy, (void**)&vec_phy, len, 1); + assert(vec_phy[0] == 1e6); + assert(vec_phy[1] == 50e3); + assert(vec_phy[2] == 1.34e9); + printf("v_vec_phy : %p [%d]\n", vec_phy, len[0]); + + rec_t* vec_rec; + ghdlToArray(v_vec_rec, (void**)&vec_rec, len, 1); + assert(vec_rec[0].r_char == 'x'); + assert(vec_rec[0].r_int == 17); + assert(vec_rec[1].r_char == 'y'); + assert(vec_rec[1].r_int == 25); + printf("v_vec_rec : %p [%d]\n", vec_rec, len[0]); + + uint8_t* vec_enum; + ghdlToArray(v_vec_enum, (void**)&vec_enum, len, 1); + assert(vec_enum[0] == start); + assert(vec_enum[1] == busy); + assert(vec_enum[2] == standby); + printf("v_vec_enum : %p [%d]\n", vec_enum, len[0]); + + double* vec2_real_base; + ghdlToArray(v_2vec_real, (void**)&vec2_real_base, len, 2); + double (*vec2_real)[len[0]] = (double(*)[len[0]])vec2_real_base; + assert(vec2_real[0][0] == 0.1); + assert(vec2_real[0][1] == 0.25); + assert(vec2_real[0][2] == 0.5); + assert(vec2_real[1][0] == 3.33); + assert(vec2_real[1][1] == 4.25); + assert(vec2_real[1][2] == 5.0); + printf("v_2vec_real : %p [%d, %d]\n", vec_enum, len[1], len[0]); +} + +void getString(ghdl_NaturalDimArr_t* ptr) { + *ptr = ghdlFromString("HELLO WORLD"); +} + +void getIntVec(ghdl_NaturalDimArr_t* ptr) { + int32_t vec[6] = {11, 22, 33, 44, 55}; + int32_t len[1] = {5}; + int x; + for ( x=0 ; x) of integer; + type real_vec_t is array(natural range <>) of real; + type bool_vec_t is array(natural range <>) of boolean; + type time_vec_t is array(natural range <>) of time; + type rec_vec_t is array(natural range <>) of rec_t; + type enum_vec_t is array(natural range <>) of enum_t; + + type real_2vec_t is array (natural range <>, natural range <>) of real; + +begin + process + + procedure testCinterface( + v_char : character := 'k'; + v_int : integer := -6; + v_nat : natural := 9; + v_pos : positive := 3; + v_real : real := 3.34; + v_bool : boolean := true; + v_bit : bit := '1'; + v_time : time := 20 ns; + v_rec : rec_t := ('y', 5); + v_enum : enum_t := busy; + v_str : string := "hellostr"; + v_vec_int : int_vec_t := (11, 22, 33, 44, 55); + v_vec_real : real_vec_t := (0.5, 1.75, 3.33, -0.125, -0.67, -2.21); + v_vec_bool : bool_vec_t := (false, true, true, false); + v_vec_bit : bit_vector := ('1', '0', '1', '0'); + v_vec_time : time_vec_t := (1 ns, 50 ps, 1.34 us); + v_vec_rec : rec_vec_t := (('x', 17),('y', 25)); + v_vec_enum : enum_vec_t := (start, busy, standby); + v_2vec_real : real_2vec_t := ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)) + ) is + begin assert false report "VHPIDIRECT testCinterface" severity failure; end; + attribute foreign of testCinterface : procedure is "VHPIDIRECT testCinterface"; + + function getString return string is + begin assert false report "VHPIDIRECT getString" severity failure; end; + attribute foreign of getString : function is "VHPIDIRECT getString"; + + function getIntVec return int_vec_t is + begin assert false report "VHPIDIRECT getIntVec" severity failure; end; + attribute foreign of getIntVec : function is "VHPIDIRECT getIntVec"; + + function getLine return line is + begin assert false report "VHPIDIRECT getLine" severity failure; end; + attribute foreign of getLine : function is "VHPIDIRECT getLine"; + + constant g_str: string := getString; + constant g_int_vec: int_vec_t := getIntVec; + + variable g_line: line := getLine; + + begin + + testCinterface( + v_char => 'k', + v_int => -6, + v_nat => 9, + v_pos => 3, + v_real => 3.34, + v_bool => true, + v_bit => '1', + v_time => 20 ns, + v_rec => ('y', 5), + v_enum => busy, + v_str => "hellostr", + v_vec_int => (11, 22, 33, 44, 55), + v_vec_real => (0.5, 1.75, 3.33, -0.125, -0.67, -2.21), + v_vec_bool => (false, true, true, false), + v_vec_bit => ('1', '0', '1', '0'), + v_vec_time => (1 ns, 50 ps, 1.34 us), + v_vec_rec => (('x', 17),('y', 25)), + v_vec_enum => (start, busy, standby), + v_2vec_real => ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)) + ); + + report "g_str'length: " & integer'image(g_str'length) severity note; + if g_str'length /= 0 then + report "g_str: " & g_str severity note; + end if; + report "string: " & getString severity note; + + report "g_int_vec'length: " & integer'image(g_int_vec'length) severity note; + for x in g_int_vec'range loop + report integer'image(x) & ": " & integer'image(g_int_vec(x)) severity note; + assert g_int_vec(x) = 11*(x+1) severity warning; + end loop; + + report "g_line: " & g_line.all severity note; + report "getLine: " & getLine.all severity note; + assert getLine.all = "HELLO WORLD" severity failure; + + wait; + end process; +end; From c8954531f7cdf3169febb91e57abefa3938cd704 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 09:33:31 +0200 Subject: [PATCH 18/37] HDL_LOGIC_STATE/CHAR appended --- doc/examples/vhpidirect/demo/ghdl.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index 23e06fb95f..fea98b5240 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -221,4 +221,23 @@ ghdl_AccNaturalDimArr_t* ghdlAccFromString(char *string) { return line; } +/* +* Handle C char for the appropriate values in std_ulogic and std_logic. +*/ + +// @RocketRoss +static const char HDL_LOGIC_STATE[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'}; + +enum HDL_LOGIC_CHAR { +HDL_U = 0, +HDL_X = 1, +HDL_0 = 2, +HDL_1 = 3, +HDL_Z = 4, +HDL_W = 5, +HDL_L = 6, +HDL_H = 7, +HDL_D = 8, +}; + #endif From 76dcc940128d492253cf2e144aaab304c10db918 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 09:35:18 +0200 Subject: [PATCH 19/37] testCinterface with v_logic v_ulogic use ieee --- doc/examples/vhpidirect/demo/main.c | 8 ++++++++ doc/examples/vhpidirect/demo/tb.vhd | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index b4e0c478d7..152dbb078d 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -15,6 +15,8 @@ typedef struct rec_t { typedef enum {standby, start, busy, done} enum_t; void testCinterface( + char v_logic, + char v_ulogic, char v_char, int32_t v_int, uint32_t v_nat, @@ -35,6 +37,12 @@ void testCinterface( ghdl_NaturalDimArr_t* v_vec_enum, ghdl_NaturalDimArr_t* v_2vec_real ) { + assert(v_logic == HDL_H); + printf("v_logic : %c\n", HDL_LOGIC_STATE[v_logic]); + + assert(v_ulogic == HDL_Z); + printf("v_ulogic : %c\n", HDL_LOGIC_STATE[v_ulogic]); + assert(v_char == 'k'); printf("v_char : %c\n", v_char); diff --git a/doc/examples/vhpidirect/demo/tb.vhd b/doc/examples/vhpidirect/demo/tb.vhd index 10cc9322b3..80944fcdbd 100644 --- a/doc/examples/vhpidirect/demo/tb.vhd +++ b/doc/examples/vhpidirect/demo/tb.vhd @@ -1,5 +1,8 @@ use std.textio.line; +library ieee; +use ieee.std_logic_1164.all; + entity tb is end; @@ -25,6 +28,8 @@ begin process procedure testCinterface( + v_logic : std_logic := 'H'; + v_ulogic : std_ulogic := 'Z'; v_char : character := 'k'; v_int : integer := -6; v_nat : natural := 9; @@ -68,6 +73,8 @@ begin begin testCinterface( + v_logic => 'H', + v_ulogic => 'Z', v_char => 'k', v_int => -6, v_nat => 9, From 12ab3624263e403219fe7b9c3eaf3abd919989a5 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 09:36:16 +0200 Subject: [PATCH 20/37] c getLogicIntValue, and tb assert to confirm enum --- doc/examples/vhpidirect/demo/main.c | 4 ++++ doc/examples/vhpidirect/demo/tb.vhd | 35 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 152dbb078d..832baa746d 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -166,3 +166,7 @@ void getIntVec(ghdl_NaturalDimArr_t* ptr) { ghdl_AccNaturalDimArr_t* getLine() { return ghdlAccFromString("HELLO WORLD"); } + +int getLogicIntValue(char logic){ + return 0 + logic; +} \ No newline at end of file diff --git a/doc/examples/vhpidirect/demo/tb.vhd b/doc/examples/vhpidirect/demo/tb.vhd index 80944fcdbd..730c951618 100644 --- a/doc/examples/vhpidirect/demo/tb.vhd +++ b/doc/examples/vhpidirect/demo/tb.vhd @@ -70,6 +70,18 @@ begin variable g_line: line := getLine; + function getLogicValue(logic : std_logic) return integer is + begin assert false report "VHPIDIRECT getLogicValue" severity failure; end; + attribute foreign of getLogicValue : function is "VHPIDIRECT getLogicIntValue"; + + function getUlogicValue(logic : std_ulogic) return integer is + begin assert false report "VHPIDIRECT getUlogicValue" severity failure; end; + attribute foreign of getUlogicValue : function is "VHPIDIRECT getLogicIntValue"; + + function getBitValue(bitVal : bit) return integer is + begin assert false report "VHPIDIRECT getBitValue" severity failure; end; + attribute foreign of getBitValue : function is "VHPIDIRECT getLogicIntValue"; + begin testCinterface( @@ -112,6 +124,29 @@ begin report "getLine: " & getLine.all severity note; assert getLine.all = "HELLO WORLD" severity failure; + assert 0 = getLogicValue('U') severity error; + assert 1 = getLogicValue('X') severity error; + assert 2 = getLogicValue('0') severity error; + assert 3 = getLogicValue('1') severity error; + assert 4 = getLogicValue('Z') severity error; + assert 5 = getLogicValue('W') severity error; + assert 6 = getLogicValue('L') severity error; + assert 7 = getLogicValue('H') severity error; + assert 8 = getLogicValue('-') severity error; + + assert 0 = getUlogicValue('U') severity error; + assert 1 = getUlogicValue('X') severity error; + assert 2 = getUlogicValue('0') severity error; + assert 3 = getUlogicValue('1') severity error; + assert 4 = getUlogicValue('Z') severity error; + assert 5 = getUlogicValue('W') severity error; + assert 6 = getUlogicValue('L') severity error; + assert 7 = getUlogicValue('H') severity error; + assert 8 = getUlogicValue('-') severity error; + + assert 0 = getBitValue('0') severity error; + assert 1 = getBitValue('1') severity error; + wait; end process; end; From e8e57454c8f9ca5696cdd297340eedd786903cd6 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 09:36:38 +0200 Subject: [PATCH 21/37] clean compilation warnings --- doc/examples/vhpidirect/demo/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 832baa746d..358d8fe728 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -65,7 +65,7 @@ void testCinterface( printf("v_bit : %d\n", v_bit); assert(v_time == 20e6); - printf("v_time : %d\n", v_time); + printf("v_time : %ld\n", v_time); assert(v_rec != NULL); assert(v_rec->r_char == 'y'); @@ -76,7 +76,7 @@ void testCinterface( printf("v_enum : %d %d\n", v_enum, busy); char* str = ghdlToString(v_str); - printf("v_str : %p '%s' [%d]\n", v_str->array, str, strlen(str)); + printf("v_str : %p '%s' [%ld]\n", v_str->array, str, strlen(str)); int* len = malloc(2 * sizeof(int)); From 2c9aadb6546a0d0a1dc83c1129c2673b62bca469 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 09:54:15 +0200 Subject: [PATCH 22/37] Revert changes to using/* documentation --- doc/using/Foreign.rst | 19 ++----------------- doc/using/InvokingGHDL.rst | 2 -- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 9f479d2c7d..7eda97a806 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -24,8 +24,6 @@ You can define a subprogram in a foreign language (such as `C` or inspect the hierarchy, set callbacks and/or assign signals. GHDL does not support VHPI. For these kind of features, it is suggested to use VPI instead (see :ref:`VPI_build_commands`). -.. _foreign_declarations: - Foreign declarations ==================== @@ -64,9 +62,6 @@ The value of the attribute must start with ``VHPIDIRECT`` (an upper-case keyword followed by one or more blanks). The linkage name of the subprogram follows. -The object file with the source code for the foreign subprogram must then be -linked to GHDL, expanded upon in :ref:`Starting_a_simulation_from_a_foreign_program`. - .. _Restrictions_on_foreign_declarations: Restrictions on foreign declarations @@ -145,16 +140,6 @@ in C: extern int ghdl_main (int argc, char **argv); -.. HINT:: - To compile the executable with the custom `main()`, its object file will have to be listed in the elaboration step. - Analysis must be made of the HDL files, then elaboration with `-Wl,main.o toplevelEntityName` as arguments. - Additional object files are flagged separate `-Wl,*` arguments as per :ref:`Linking_with_foreign_object_files`. - The elaboration step will compile the executable with the custom `main()` entrypoint. - Further reading (particularly about the backend restrictions) is at , :ref:`Elaboration:command` and :ref:`Run:command`. - -.. HINT:: - Immitating the run time flags within your own `main()`, such as ``-gDEPTH=12`` from :ref:`simulation_options`, requires the argv to have the executable's path at index 0, effectively shifting all other indicies along by 1. This can be taken from the 0 index of the argv passed to `main()`, or (not suggested, despite a lack of consequences) left empty. - in Ada: .. code-block:: Ada @@ -218,7 +203,7 @@ See :ref:`gccllvm-only-programs` for further details about ``--bind`` and ``--li Dynamically loading foreign objects from GHDL ============================================= -Instead of linking and building foreign objects along with GHDL, it is also possible to load foreign resources dynamically. +Instead of linking and building foreign objects along with GHDL, it is also possible to load foreign resources dinamically. In order to do so, provide the path and name of the shared library where the resource is to be loaded from. For example: .. code-block:: VHDL @@ -234,7 +219,7 @@ that all the libraries and sources analyzed by GHDL generate position independen Furthermore, when the binary is built, argument ``-Wl,-pie`` needs to be provided. PIE binaries can be loaded and executed from any language that supports C-alike signatures and types -(C, C++, golang, Python, Rust, etc.). For example, in Python: +(C, C++, golang, Python, Rust, etc.). For example: .. code-block:: Python diff --git a/doc/using/InvokingGHDL.rst b/doc/using/InvokingGHDL.rst index 613fdaf056..4deb96b7f2 100644 --- a/doc/using/InvokingGHDL.rst +++ b/doc/using/InvokingGHDL.rst @@ -108,8 +108,6 @@ See section :ref:`USING:Simulation`, for details on options. .. index:: cmd elaborate and run -.. _elab_and_run:command: - Elaborate and run [``--elab-run``] ---------------------------------- From 48dba5b32cc115b59b53fa087c809f32c90e94c3 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 10:09:38 +0200 Subject: [PATCH 23/37] Examples page: Clean up single entry toctree --- doc/examples/README.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/doc/examples/README.rst b/doc/examples/README.rst index be4d731029..17e2ea9bc9 100644 --- a/doc/examples/README.rst +++ b/doc/examples/README.rst @@ -3,10 +3,7 @@ Examples ######## -This sections contains advanced examples using specific features of the language, the tool, -or interaction with third-party projects. It is suggested for users who are new to either -`GHDL` or `VHDL` to read :ref:`USING:QuickStart` first. +It is suggested for users who are new to either `GHDL` or `VHDL` to read :ref:`USING:QuickStart` first. -.. toctree:: - - ./vhpidirect/VHPIDIRECT +Then :ref:`Examples:VHPIDIRECT` contains advanced examples using specific features of the language, the tool, +or interaction with third-party projects. From fd6cfb9239268029d2d46a03a035e9271baf2440 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 10:10:34 +0200 Subject: [PATCH 24/37] Move cAccess VHPI example to VHPIDIRECT --- doc/examples/quick_start/README.rst | 1 - doc/examples/{quick_start => vhpidirect}/Caccess/README.rst | 2 +- doc/examples/{quick_start => vhpidirect}/Caccess/build.sh | 0 doc/examples/{quick_start => vhpidirect}/Caccess/cAccess.vhd | 0 doc/examples/{quick_start => vhpidirect}/Caccess/cSharedVar.c | 0 doc/examples/{quick_start => vhpidirect}/Caccess/cSharedVar.h | 0 doc/examples/{quick_start => vhpidirect}/Caccess/main.c | 0 doc/examples/{quick_start => vhpidirect}/Caccess/toplevel.vhd | 0 doc/examples/vhpidirect/VHPIDIRECT.rst | 3 +++ 9 files changed, 4 insertions(+), 2 deletions(-) rename doc/examples/{quick_start => vhpidirect}/Caccess/README.rst (98%) rename doc/examples/{quick_start => vhpidirect}/Caccess/build.sh (100%) rename doc/examples/{quick_start => vhpidirect}/Caccess/cAccess.vhd (100%) rename doc/examples/{quick_start => vhpidirect}/Caccess/cSharedVar.c (100%) rename doc/examples/{quick_start => vhpidirect}/Caccess/cSharedVar.h (100%) rename doc/examples/{quick_start => vhpidirect}/Caccess/main.c (100%) rename doc/examples/{quick_start => vhpidirect}/Caccess/toplevel.vhd (100%) diff --git a/doc/examples/quick_start/README.rst b/doc/examples/quick_start/README.rst index 78108868f0..8e26361ca3 100644 --- a/doc/examples/quick_start/README.rst +++ b/doc/examples/quick_start/README.rst @@ -49,4 +49,3 @@ in the hope of helping understand the different use cases: heartbeat/README adder/README DLXModelSuite - Caccess/README diff --git a/doc/examples/quick_start/Caccess/README.rst b/doc/examples/vhpidirect/Caccess/README.rst similarity index 98% rename from doc/examples/quick_start/Caccess/README.rst rename to doc/examples/vhpidirect/Caccess/README.rst index 7332161ad3..45d7b39bef 100644 --- a/doc/examples/quick_start/Caccess/README.rst +++ b/doc/examples/vhpidirect/Caccess/README.rst @@ -1,5 +1,5 @@ .. program:: ghdl -.. _QuickStart:C_Access: +.. _VHPIDIRECT_Example:C_Access: `C Access` example ===================== diff --git a/doc/examples/quick_start/Caccess/build.sh b/doc/examples/vhpidirect/Caccess/build.sh similarity index 100% rename from doc/examples/quick_start/Caccess/build.sh rename to doc/examples/vhpidirect/Caccess/build.sh diff --git a/doc/examples/quick_start/Caccess/cAccess.vhd b/doc/examples/vhpidirect/Caccess/cAccess.vhd similarity index 100% rename from doc/examples/quick_start/Caccess/cAccess.vhd rename to doc/examples/vhpidirect/Caccess/cAccess.vhd diff --git a/doc/examples/quick_start/Caccess/cSharedVar.c b/doc/examples/vhpidirect/Caccess/cSharedVar.c similarity index 100% rename from doc/examples/quick_start/Caccess/cSharedVar.c rename to doc/examples/vhpidirect/Caccess/cSharedVar.c diff --git a/doc/examples/quick_start/Caccess/cSharedVar.h b/doc/examples/vhpidirect/Caccess/cSharedVar.h similarity index 100% rename from doc/examples/quick_start/Caccess/cSharedVar.h rename to doc/examples/vhpidirect/Caccess/cSharedVar.h diff --git a/doc/examples/quick_start/Caccess/main.c b/doc/examples/vhpidirect/Caccess/main.c similarity index 100% rename from doc/examples/quick_start/Caccess/main.c rename to doc/examples/vhpidirect/Caccess/main.c diff --git a/doc/examples/quick_start/Caccess/toplevel.vhd b/doc/examples/vhpidirect/Caccess/toplevel.vhd similarity index 100% rename from doc/examples/quick_start/Caccess/toplevel.vhd rename to doc/examples/vhpidirect/Caccess/toplevel.vhd diff --git a/doc/examples/vhpidirect/VHPIDIRECT.rst b/doc/examples/vhpidirect/VHPIDIRECT.rst index 4dabd711c6..eb675f4d02 100644 --- a/doc/examples/vhpidirect/VHPIDIRECT.rst +++ b/doc/examples/vhpidirect/VHPIDIRECT.rst @@ -6,8 +6,11 @@ Data exchange through VHPIDIRECT .. toctree:: :hidden: + Caccess/README demo/README +:ref:`VHPIDIRECT_Example:C_Access` is a straight forward example of executing the GHDL simulation from a personal entry point, while accessing variables (an int, int array and char). + See :ref:`Examples:VHPIDIRECT:Demo` for a demo about how to pass different types of data to/from VHDL and C through VHPIDIRECT. VUnit From 8aba8d2ab0d91f15cbafc9eed0e4adb42919607d Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 10:28:15 +0200 Subject: [PATCH 25/37] VHPIDIRECT func/var not only in packages. --- doc/examples/vhpidirect/Caccess/README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/examples/vhpidirect/Caccess/README.rst b/doc/examples/vhpidirect/Caccess/README.rst index 45d7b39bef..77678793c2 100644 --- a/doc/examples/vhpidirect/Caccess/README.rst +++ b/doc/examples/vhpidirect/Caccess/README.rst @@ -8,9 +8,12 @@ The files --------- The VHPIDIRECT method of accessing C-side variables and functions from VHDL requires these variables and functions to be declared -in a package. Each function's `foreign` attribute is set to highlight that the function has a foreign C-side definition, as per +with the `foreign` attribute a certain way. It is set to highlight that the function has a foreign C-side definition, as per :ref:`foreign_declarations`. +The foreign functions can be declared HDL-side in a package as follows, or the declarative part of an architecture (as in :ref:`Examples:VHPIDIRECT:Demo`). +The difference being the scope of the declarations. + This example starts with :file:`c_access.vhdl`: .. literalinclude:: cAccess.vhd From 92dd40b1af78e29ccc62e888c145a18549aaf15e Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 10:35:01 +0200 Subject: [PATCH 26/37] label foreign_declarations --- doc/using/Foreign.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 7eda97a806..b4d358941d 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -24,6 +24,8 @@ You can define a subprogram in a foreign language (such as `C` or inspect the hierarchy, set callbacks and/or assign signals. GHDL does not support VHPI. For these kind of features, it is suggested to use VPI instead (see :ref:`VPI_build_commands`). +.. _foreign_declarations: + Foreign declarations ==================== From 335553583f1083cdd55c86818802982db29e68eb Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 18:23:02 +0200 Subject: [PATCH 27/37] Fixed ghdlFromArray, added helper ghdlSetRange --- doc/examples/vhpidirect/demo/ghdl.h | 39 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index fea98b5240..08dc50671e 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -143,25 +143,50 @@ ghdl_NaturalDimArr_t ghdlFromString(char *string) { return (ghdl_NaturalDimArr_t){.array=string, .bounds=(bounds_t*)range}; } +// @RocketRoss +/* +* Helper to setup the bouds_t for ghdlFromArray +*/ + +void ghdlSetRange(range_t* r, int len, bool reversed){ + if(!reversed){//to + r->left = 0; + r->right = len-1; + r->dir = 0; + r->len = len; + } + else{//downto + r->left = len-1; + r->right = 0; + r->dir = 1; + r->len = len; + } +} + +// @bradleyharden??? /* * Convert C types representing an unconstrained array with a dimension of type 'natural', to a fat pointer */ -ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int num) { +ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { bounds_t* b = malloc(sizeof(bounds_t)); + void* a; assert(b != NULL); - switch (num) { + switch (dims) { case 3: // TODO + break; case 2: // TODO + break; case 1: - b->dim_1.left = 0; - b->dim_1.right = len[0]-1; - b->dim_1.dir = 0; - b->dim_1.len = len[0]; + a = malloc(sizeof(int)*len[0]); + memmove(a, vec, sizeof(int)*len[0]); + vec = a; + + ghdlSetRange(&(b->dim_1), len[0], false); } - return (ghdl_NaturalDimArr_t){.array=vec, .bounds=b}; + return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; } /* From 7c6379cc4fd1e61b9ebf1d40e6788894665027d7 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 18:32:12 +0200 Subject: [PATCH 28/37] Handle and test 2D int array --- doc/examples/vhpidirect/demo/ghdl.h | 35 ++++++++++++++++++ doc/examples/vhpidirect/demo/main.c | 55 +++++++++++++++++++++++++++-- doc/examples/vhpidirect/demo/tb.vhd | 25 +++++++++++-- 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index 08dc50671e..164b8d767c 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -34,6 +34,12 @@ typedef struct { bounds_t* bounds; } ghdl_NaturalDimArr_t; +// Unconstrained array with 2 dimensions of type 'natural' +typedef struct { + void* array; + bounds2D_t* bounds; +} ghdl_Natural2DimArr_t; + // Access to an unconstrained array with 1 dimension of type 'natural' typedef struct { range_t range; @@ -53,6 +59,19 @@ void print(ghdl_NaturalDimArr_t* ptr) { printf("bounds.len: %d\n", ptr->bounds->dim_1.len); } +void print2d(ghdl_Natural2DimArr_t* ptr) { + printf("array: %p\n", ptr->array); + printf("bounds: %p\n", ptr->bounds); + printf("bounds1.left: %d\n", ptr->bounds->dim_1.left); + printf("bounds1.right: %d\n", ptr->bounds->dim_1.right); + printf("bounds1.dir: %d\n", ptr->bounds->dim_1.dir); + printf("bounds1.len: %d\n", ptr->bounds->dim_1.len); + printf("bounds2.left: %d\n", ptr->bounds->dim_2.left); + printf("bounds2.right: %d\n", ptr->bounds->dim_2.right); + printf("bounds2.dir: %d\n", ptr->bounds->dim_2.dir); + printf("bounds2.len: %d\n", ptr->bounds->dim_2.len); +} + /* * Convert a fat pointer of an unconstrained string, to a (null terminated) C string */ @@ -189,6 +208,22 @@ ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; } +// @RocketRoss +ghdl_Natural2DimArr_t ghdlFromArray2d(void* vec, int* len, int dims){ + bounds2D_t* b = malloc(sizeof(bounds2D_t)); + void* a; + assert(b != NULL); + + a = malloc(sizeof(int)*len[0]*len[1]); + memmove(a, vec, sizeof(int)*len[0]*len[1]); + vec = a; + + ghdlSetRange(&(b->dim_1), len[0], false); + ghdlSetRange(&(b->dim_2), len[1], false); + + return (ghdl_Natural2DimArr_t){.array= a, .bounds=b}; +} + /* * Convert an access to an unconstrained string, to a (null terminated) C string */ diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 358d8fe728..9106039683 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -35,7 +35,8 @@ void testCinterface( ghdl_NaturalDimArr_t* v_vec_phy, ghdl_NaturalDimArr_t* v_vec_rec, ghdl_NaturalDimArr_t* v_vec_enum, - ghdl_NaturalDimArr_t* v_2vec_real + ghdl_NaturalDimArr_t* v_2vec_real, + ghdl_Natural2DimArr_t* v_mat_int ) { assert(v_logic == HDL_H); printf("v_logic : %c\n", HDL_LOGIC_STATE[v_logic]); @@ -147,6 +148,22 @@ void testCinterface( assert(vec2_real[1][1] == 4.25); assert(vec2_real[1][2] == 5.0); printf("v_2vec_real : %p [%d, %d]\n", vec_enum, len[1], len[0]); + + printf("\nVerify GHDL Matrix in C\n"); + //print2d(v_mat_int); + int* len2 = malloc(2 * sizeof(int)); + + int32_t* mat_int; + ghdlToArray(v_mat_int, (void**)&mat_int, len2, 2); + for (int i = 0; i < len2[1]; i++) + { + for (int j = 0; j < len2[0]; j++) + { + printf("C assert: %d == (val: %d) @ [%d,%d](%d)\n", 11*(i*len2[0]+j+1), mat_int[i*len2[1]+j], i, j, i*len2[1]+j); + assert(mat_int[i*len2[0]+j] == 11*(i*len2[0]+j+1)); + } + } + printf("v_mat_int : %p [%d,%d]\n\n", mat_int, len2[0], len2[1]); } void getString(ghdl_NaturalDimArr_t* ptr) { @@ -157,10 +174,42 @@ void getIntVec(ghdl_NaturalDimArr_t* ptr) { int32_t vec[6] = {11, 22, 33, 44, 55}; int32_t len[1] = {5}; int x; + *ptr = ghdlFromArray(vec, len, 1); + printf("\n1D Array values [%d]:\n", len[0]); for ( x=0 ; x) of enum_t; type real_2vec_t is array (natural range <>, natural range <>) of real; - + + type int_2vec_t is array(natural range <>, natural range <>) of integer; begin process @@ -48,7 +49,8 @@ begin v_vec_time : time_vec_t := (1 ns, 50 ps, 1.34 us); v_vec_rec : rec_vec_t := (('x', 17),('y', 25)); v_vec_enum : enum_vec_t := (start, busy, standby); - v_2vec_real : real_2vec_t := ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)) + v_2vec_real : real_2vec_t := ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)); + v_mat_int : int_2vec_t := ((11, 22, 33), (44, 55, 66)) ) is begin assert false report "VHPIDIRECT testCinterface" severity failure; end; attribute foreign of testCinterface : procedure is "VHPIDIRECT testCinterface"; @@ -61,12 +63,17 @@ begin begin assert false report "VHPIDIRECT getIntVec" severity failure; end; attribute foreign of getIntVec : function is "VHPIDIRECT getIntVec"; + function getIntMat return int_2vec_t is + begin assert false report "VHPIDIRECT getIntMat" severity failure; end; + attribute foreign of getIntMat : function is "VHPIDIRECT getIntMat"; + function getLine return line is begin assert false report "VHPIDIRECT getLine" severity failure; end; attribute foreign of getLine : function is "VHPIDIRECT getLine"; constant g_str: string := getString; constant g_int_vec: int_vec_t := getIntVec; + constant g_int_mat: int_2vec_t := getIntMat; variable g_line: line := getLine; @@ -82,6 +89,7 @@ begin begin assert false report "VHPIDIRECT getBitValue" severity failure; end; attribute foreign of getBitValue : function is "VHPIDIRECT getLogicIntValue"; + variable spareInt: integer; begin testCinterface( @@ -105,7 +113,8 @@ begin v_vec_time => (1 ns, 50 ps, 1.34 us), v_vec_rec => (('x', 17),('y', 25)), v_vec_enum => (start, busy, standby), - v_2vec_real => ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)) + v_2vec_real => ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)), + v_mat_int => ((11, 22, 33), (44, 55, 66)) ); report "g_str'length: " & integer'image(g_str'length) severity note; @@ -147,6 +156,16 @@ begin assert 0 = getBitValue('0') severity error; assert 1 = getBitValue('1') severity error; + spareInt := 0; + report "g_int_mat'length: " & integer'image(g_int_mat'length) severity note; + for i in g_int_mat'range(1) loop + for j in g_int_mat'range(2) loop + spareInt := spareInt + 1; + assert g_int_mat(i, j) = 11*spareInt severity error; + report "Asserted Mat [" & integer'image(i) & "," & integer'image(j) & "]: " & integer'image(g_int_mat(i, j)) severity note; + end loop ; + end loop ; + wait; end process; end; From 579fd30e60bde66a9d53603e412727204788ae67 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 18:38:48 +0200 Subject: [PATCH 29/37] Handle and test 3D int arrays. --- doc/examples/vhpidirect/demo/ghdl.h | 38 +++++++++++++++++++++ doc/examples/vhpidirect/demo/main.c | 51 +++++++++++++++++++++++++++-- doc/examples/vhpidirect/demo/tb.vhd | 26 +++++++++++++-- 3 files changed, 110 insertions(+), 5 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index 164b8d767c..a24b08722b 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -40,6 +40,12 @@ typedef struct { bounds2D_t* bounds; } ghdl_Natural2DimArr_t; +// Unconstrained array with 3 dimensions of type 'natural' +typedef struct { + void* array; + bounds3D_t* bounds; +} ghdl_Natural3DimArr_t; + // Access to an unconstrained array with 1 dimension of type 'natural' typedef struct { range_t range; @@ -72,6 +78,22 @@ void print2d(ghdl_Natural2DimArr_t* ptr) { printf("bounds2.len: %d\n", ptr->bounds->dim_2.len); } +void print3d(ghdl_Natural3DimArr_t* ptr) { + printf("array: %p\n", ptr->array); + printf("bounds: %p\n", ptr->bounds); + printf("bounds1.left: %d\n", ptr->bounds->dim_1.left); + printf("bounds1.right: %d\n", ptr->bounds->dim_1.right); + printf("bounds1.dir: %d\n", ptr->bounds->dim_1.dir); + printf("bounds1.len: %d\n", ptr->bounds->dim_1.len); + printf("bounds2.left: %d\n", ptr->bounds->dim_2.left); + printf("bounds2.right: %d\n", ptr->bounds->dim_2.right); + printf("bounds2.dir: %d\n", ptr->bounds->dim_2.dir); + printf("bounds2.len: %d\n", ptr->bounds->dim_2.len); + printf("bounds3.left: %d\n", ptr->bounds->dim_3.left); + printf("bounds3.right: %d\n", ptr->bounds->dim_3.right); + printf("bounds3.dir: %d\n", ptr->bounds->dim_3.dir); + printf("bounds3.len: %d\n", ptr->bounds->dim_3.len); +} /* * Convert a fat pointer of an unconstrained string, to a (null terminated) C string */ @@ -224,6 +246,22 @@ ghdl_Natural2DimArr_t ghdlFromArray2d(void* vec, int* len, int dims){ return (ghdl_Natural2DimArr_t){.array= a, .bounds=b}; } +ghdl_Natural3DimArr_t ghdlFromArray3d(void* vec, int* len, int dims){ + bounds3D_t* b = malloc(sizeof(bounds3D_t)); + void* a; + assert(b != NULL); + + a = malloc(sizeof(int)*len[0]*len[1]*len[2]); + memmove(a, vec, sizeof(int)*len[0]*len[1]*len[2]); + vec = a; + + ghdlSetRange(&(b->dim_1), len[0], false); + ghdlSetRange(&(b->dim_2), len[1], false); + ghdlSetRange(&(b->dim_3), len[2], false); + + return (ghdl_Natural3DimArr_t){.array= a, .bounds=b}; +} + /* * Convert an access to an unconstrained string, to a (null terminated) C string */ diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 9106039683..75874f1f2f 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -36,7 +36,8 @@ void testCinterface( ghdl_NaturalDimArr_t* v_vec_rec, ghdl_NaturalDimArr_t* v_vec_enum, ghdl_NaturalDimArr_t* v_2vec_real, - ghdl_Natural2DimArr_t* v_mat_int + ghdl_Natural2DimArr_t* v_mat_int, + ghdl_Natural3DimArr_t* v_3d_int ) { assert(v_logic == HDL_H); printf("v_logic : %c\n", HDL_LOGIC_STATE[v_logic]); @@ -164,6 +165,27 @@ void testCinterface( } } printf("v_mat_int : %p [%d,%d]\n\n", mat_int, len2[0], len2[1]); + + printf("\nVerify the 3D GHDL array in C\n"); + //print3d(v_3d_int); + int* len3 = malloc(3 * sizeof(int)); + + int32_t* d3_int; + ghdlToArray(v_3d_int, (void**)&d3_int, len3, 3); + for(int i = 0; i < len3[0]; i++) + { + for (int j = 0; j < len3[1]; j++) + { + for (int k = 0; k < len3[2]; k++) + { + printf("C assert: %d == (val: %d) @ [%d,%d,%d](%d)\n", 11*(i*len3[1]*len3[2]+j*len3[2]+k+1), d3_int[i*len3[1]*len3[2]+j*len3[2]+k], i, j, k, i*len3[1]*len3[2]+j*len3[2]+k); + assert(d3_int[i*len3[1]*len3[2]+j*len3[2]+k] == 11*(i*len3[1]*len3[2]+j*len3[2]+k+1)); + } + } + } + printf("v_3d_int : %p [%d,%d,%d]\n\n", d3_int, len3[0], len3[1], len3[2]); + + printf("end testCinterface\n\n"); } void getString(ghdl_NaturalDimArr_t* ptr) { @@ -209,7 +231,32 @@ void getIntMat(ghdl_Natural2DimArr_t* ptr){ } printf("\n"); } - printf("\n"); +} + +void getInt3d(ghdl_Natural3DimArr_t* ptr){ + int32_t d3[2][4][3]; + int32_t len[3] = {2, 4, 3}; + int x, y, z; + for ( x=0 ; x) of enum_t; type real_2vec_t is array (natural range <>, natural range <>) of real; - + type int_2vec_t is array(natural range <>, natural range <>) of integer; + type int_3vec_t is array(natural range <>, natural range <>, natural range <>) of integer; begin process @@ -50,7 +51,8 @@ begin v_vec_rec : rec_vec_t := (('x', 17),('y', 25)); v_vec_enum : enum_vec_t := (start, busy, standby); v_2vec_real : real_2vec_t := ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)); - v_mat_int : int_2vec_t := ((11, 22, 33), (44, 55, 66)) + v_mat_int : int_2vec_t := ((11, 22, 33), (44, 55, 66)); + v_3d_int : int_3vec_t := ( ((11, 22, 33), (44, 55, 66)), ((77, 88, 99), (110, 121, 132)) ) ) is begin assert false report "VHPIDIRECT testCinterface" severity failure; end; attribute foreign of testCinterface : procedure is "VHPIDIRECT testCinterface"; @@ -67,6 +69,10 @@ begin begin assert false report "VHPIDIRECT getIntMat" severity failure; end; attribute foreign of getIntMat : function is "VHPIDIRECT getIntMat"; + function getInt3d return int_3vec_t is + begin assert false report "VHPIDIRECT getInt3d" severity failure; end; + attribute foreign of getInt3d : function is "VHPIDIRECT getInt3d"; + function getLine return line is begin assert false report "VHPIDIRECT getLine" severity failure; end; attribute foreign of getLine : function is "VHPIDIRECT getLine"; @@ -74,6 +80,7 @@ begin constant g_str: string := getString; constant g_int_vec: int_vec_t := getIntVec; constant g_int_mat: int_2vec_t := getIntMat; + constant g_int_3d: int_3vec_t := getInt3d; variable g_line: line := getLine; @@ -114,7 +121,8 @@ begin v_vec_rec => (('x', 17),('y', 25)), v_vec_enum => (start, busy, standby), v_2vec_real => ((0.1, 0.25, 0.5),(3.33, 4.25, 5.0)), - v_mat_int => ((11, 22, 33), (44, 55, 66)) + v_mat_int => ((11, 22, 33), (44, 55, 66)), + v_3d_int => ( ((11, 22, 33), (44, 55, 66)), ((77, 88, 99), (110, 121, 132)) ) ); report "g_str'length: " & integer'image(g_str'length) severity note; @@ -166,6 +174,18 @@ begin end loop ; end loop ; + spareInt := 0; + report "g_int_3d'length: " & integer'image(g_int_3d'length) severity note; + for i in g_int_3d'range(1) loop + for j in g_int_3d'range(2) loop + for k in g_int_3d'range(3) loop + spareInt := spareInt + 1; + assert g_int_3d(i, j, k) = 11*spareInt severity error; + report "Asserted 3D [" & integer'image(i) & "," & integer'image(j) & "," & integer'image(k) & "]: " & integer'image(g_int_3d(i, j, k)) severity note; + end loop; + end loop ; + end loop ; + wait; end process; end; From 17604fc1f2835246695858973954678efbd986fe Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 20:31:01 +0200 Subject: [PATCH 30/37] Fix tests for 2D and 3D --- doc/examples/vhpidirect/demo/main.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 75874f1f2f..ffd95a6d2f 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -156,12 +156,14 @@ void testCinterface( int32_t* mat_int; ghdlToArray(v_mat_int, (void**)&mat_int, len2, 2); - for (int i = 0; i < len2[1]; i++) + for (int i = 0; i < len2[0]; i++) { - for (int j = 0; j < len2[0]; j++) + for (int j = 0; j < len2[1]; j++) { - printf("C assert: %d == (val: %d) @ [%d,%d](%d)\n", 11*(i*len2[0]+j+1), mat_int[i*len2[1]+j], i, j, i*len2[1]+j); - assert(mat_int[i*len2[0]+j] == 11*(i*len2[0]+j+1)); + int ind[] = {i, j}; + int flatIndex = getFlatArrayIndex(ind, len2, 2); + printf("C assert: %d == (val: %d) @ [%d,%d](%d)\n", 11*(flatIndex+1), mat_int[flatIndex], i, j, flatIndex); + assert(mat_int[flatIndex] == 11*(flatIndex+1)); } } printf("v_mat_int : %p [%d,%d]\n\n", mat_int, len2[0], len2[1]); @@ -178,8 +180,10 @@ void testCinterface( { for (int k = 0; k < len3[2]; k++) { - printf("C assert: %d == (val: %d) @ [%d,%d,%d](%d)\n", 11*(i*len3[1]*len3[2]+j*len3[2]+k+1), d3_int[i*len3[1]*len3[2]+j*len3[2]+k], i, j, k, i*len3[1]*len3[2]+j*len3[2]+k); - assert(d3_int[i*len3[1]*len3[2]+j*len3[2]+k] == 11*(i*len3[1]*len3[2]+j*len3[2]+k+1)); + int ind[] = {i, j, k}; + int flatIndex = getFlatArrayIndex(ind, len3, 3); + printf("C assert: %d == (val: %d) @ [%d,%d,%d](%d)\n", 11*(flatIndex+1), d3_int[flatIndex], i, j, k, flatIndex); + assert(d3_int[flatIndex] == 11*(flatIndex+1)); } } } From 8b4cace23e1f7d92c5089c15fb32ff39affa4332 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 20:44:32 +0200 Subject: [PATCH 31/37] Re: Collapse 2D/3D to ghdl_NaturalDimArr_t. --- doc/examples/vhpidirect/demo/ghdl.h | 99 ++++++----------------------- doc/examples/vhpidirect/demo/main.c | 30 ++++----- 2 files changed, 36 insertions(+), 93 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index a24b08722b..8fd4d18f92 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -34,18 +34,6 @@ typedef struct { bounds_t* bounds; } ghdl_NaturalDimArr_t; -// Unconstrained array with 2 dimensions of type 'natural' -typedef struct { - void* array; - bounds2D_t* bounds; -} ghdl_Natural2DimArr_t; - -// Unconstrained array with 3 dimensions of type 'natural' -typedef struct { - void* array; - bounds3D_t* bounds; -} ghdl_Natural3DimArr_t; - // Access to an unconstrained array with 1 dimension of type 'natural' typedef struct { range_t range; @@ -65,35 +53,6 @@ void print(ghdl_NaturalDimArr_t* ptr) { printf("bounds.len: %d\n", ptr->bounds->dim_1.len); } -void print2d(ghdl_Natural2DimArr_t* ptr) { - printf("array: %p\n", ptr->array); - printf("bounds: %p\n", ptr->bounds); - printf("bounds1.left: %d\n", ptr->bounds->dim_1.left); - printf("bounds1.right: %d\n", ptr->bounds->dim_1.right); - printf("bounds1.dir: %d\n", ptr->bounds->dim_1.dir); - printf("bounds1.len: %d\n", ptr->bounds->dim_1.len); - printf("bounds2.left: %d\n", ptr->bounds->dim_2.left); - printf("bounds2.right: %d\n", ptr->bounds->dim_2.right); - printf("bounds2.dir: %d\n", ptr->bounds->dim_2.dir); - printf("bounds2.len: %d\n", ptr->bounds->dim_2.len); -} - -void print3d(ghdl_Natural3DimArr_t* ptr) { - printf("array: %p\n", ptr->array); - printf("bounds: %p\n", ptr->bounds); - printf("bounds1.left: %d\n", ptr->bounds->dim_1.left); - printf("bounds1.right: %d\n", ptr->bounds->dim_1.right); - printf("bounds1.dir: %d\n", ptr->bounds->dim_1.dir); - printf("bounds1.len: %d\n", ptr->bounds->dim_1.len); - printf("bounds2.left: %d\n", ptr->bounds->dim_2.left); - printf("bounds2.right: %d\n", ptr->bounds->dim_2.right); - printf("bounds2.dir: %d\n", ptr->bounds->dim_2.dir); - printf("bounds2.len: %d\n", ptr->bounds->dim_2.len); - printf("bounds3.left: %d\n", ptr->bounds->dim_3.left); - printf("bounds3.right: %d\n", ptr->bounds->dim_3.right); - printf("bounds3.dir: %d\n", ptr->bounds->dim_3.dir); - printf("bounds3.len: %d\n", ptr->bounds->dim_3.len); -} /* * Convert a fat pointer of an unconstrained string, to a (null terminated) C string */ @@ -210,56 +169,40 @@ void ghdlSetRange(range_t* r, int len, bool reversed){ */ ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { - bounds_t* b = malloc(sizeof(bounds_t)); + void* b; void* a; assert(b != NULL); switch (dims) { case 3: - // TODO + b = malloc(sizeof(bounds3D_t)); + + a = malloc(sizeof(int)*len[0]*len[1]*len[2]); + memmove(a, vec, sizeof(int)*len[0]*len[1]*len[2]); + vec = a; + + ghdlSetRange(&(((bounds3D_t*)b)->dim_1), len[0], false); + ghdlSetRange(&(((bounds3D_t*)b)->dim_2), len[1], false); + ghdlSetRange(&(((bounds3D_t*)b)->dim_3), len[2], false); break; case 2: - // TODO + b = malloc(sizeof(bounds2D_t)); + + a = malloc(sizeof(int)*len[0]*len[1]); + memmove(a, vec, sizeof(int)*len[0]*len[1]); + vec = a; + + ghdlSetRange(&(((bounds2D_t*)b)->dim_1), len[0], false); + ghdlSetRange(&(((bounds2D_t*)b)->dim_2), len[1], false); break; case 1: + b = malloc(sizeof(bounds_t)); a = malloc(sizeof(int)*len[0]); memmove(a, vec, sizeof(int)*len[0]); vec = a; - ghdlSetRange(&(b->dim_1), len[0], false); + ghdlSetRange(&(((bounds_t*)b)->dim_1), len[0], false); } - return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; -} - -// @RocketRoss -ghdl_Natural2DimArr_t ghdlFromArray2d(void* vec, int* len, int dims){ - bounds2D_t* b = malloc(sizeof(bounds2D_t)); - void* a; - assert(b != NULL); - - a = malloc(sizeof(int)*len[0]*len[1]); - memmove(a, vec, sizeof(int)*len[0]*len[1]); - vec = a; - - ghdlSetRange(&(b->dim_1), len[0], false); - ghdlSetRange(&(b->dim_2), len[1], false); - - return (ghdl_Natural2DimArr_t){.array= a, .bounds=b}; -} - -ghdl_Natural3DimArr_t ghdlFromArray3d(void* vec, int* len, int dims){ - bounds3D_t* b = malloc(sizeof(bounds3D_t)); - void* a; - assert(b != NULL); - - a = malloc(sizeof(int)*len[0]*len[1]*len[2]); - memmove(a, vec, sizeof(int)*len[0]*len[1]*len[2]); - vec = a; - - ghdlSetRange(&(b->dim_1), len[0], false); - ghdlSetRange(&(b->dim_2), len[1], false); - ghdlSetRange(&(b->dim_3), len[2], false); - - return (ghdl_Natural3DimArr_t){.array= a, .bounds=b}; + return (ghdl_NaturalDimArr_t){.array= a, .bounds=(bounds_t*)b}; } /* diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index ffd95a6d2f..dbed8585e1 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -14,6 +14,15 @@ typedef struct rec_t { typedef enum {standby, start, busy, done} enum_t; +int getFlatArrayIndex(int* dimIndex, int* lens, int dims){ + if(dims == 1){ + return dimIndex[0]; + } + else{ + return dimIndex[dims-1] + (lens[dims-1]*getFlatArrayIndex(dimIndex, lens, dims-1)); + } +} + void testCinterface( char v_logic, char v_ulogic, @@ -36,8 +45,8 @@ void testCinterface( ghdl_NaturalDimArr_t* v_vec_rec, ghdl_NaturalDimArr_t* v_vec_enum, ghdl_NaturalDimArr_t* v_2vec_real, - ghdl_Natural2DimArr_t* v_mat_int, - ghdl_Natural3DimArr_t* v_3d_int + ghdl_NaturalDimArr_t* v_mat_int, + ghdl_NaturalDimArr_t* v_3d_int ) { assert(v_logic == HDL_H); printf("v_logic : %c\n", HDL_LOGIC_STATE[v_logic]); @@ -207,16 +216,7 @@ void getIntVec(ghdl_NaturalDimArr_t* ptr) { } } -int getFlatArrayIndex(int* dimIndex, int* lens, int dims){ - if(dims == 1){ - return dimIndex[0]; - } - else{ - return dimIndex[dims-1] + (lens[dims-1]*getFlatArrayIndex(dimIndex, lens, dims-1)); - } -} - -void getIntMat(ghdl_Natural2DimArr_t* ptr){ +void getIntMat(ghdl_NaturalDimArr_t* ptr){ int32_t mat[2][3]; int32_t len[2] = {2, 3}; int x, y; @@ -227,7 +227,7 @@ void getIntMat(ghdl_Natural2DimArr_t* ptr){ mat[x][y] = 11*(flatIndex+1); } } - *ptr = ghdlFromArray2d(mat, len, 2); + *ptr = ghdlFromArray(mat, len, 2); printf("\n2D Array values [%d,%d]:\n", len[0], len[1]); for ( x=0 ; x Date: Wed, 8 Apr 2020 20:49:59 +0200 Subject: [PATCH 32/37] Make ghdl_NaturalDimArr_t dimensions boundless --- doc/examples/vhpidirect/demo/ghdl.h | 100 ++++++++-------------------- 1 file changed, 29 insertions(+), 71 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index 8fd4d18f92..8622961b5c 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -14,24 +14,10 @@ typedef struct { int32_t len; } range_t; -// Range/bounds of an unconstrained array with 1, 2 or 3 dimensions of type 'natural' -typedef struct { - range_t dim_1; -} bounds_t; -typedef struct { - range_t dim_1; - range_t dim_2; -} bounds2D_t; -typedef struct { - range_t dim_1; - range_t dim_2; - range_t dim_3; -} bounds3D_t; - // Unconstrained array with dimensions of type 'natural' typedef struct { void* array; - bounds_t* bounds; + range_t* bounds; } ghdl_NaturalDimArr_t; // Access to an unconstrained array with 1 dimension of type 'natural' @@ -44,13 +30,16 @@ typedef struct { * Print custom types */ -void print(ghdl_NaturalDimArr_t* ptr) { - printf("array: %p\n", ptr->array); - printf("bounds: %p\n", ptr->bounds); - printf("bounds.left: %d\n", ptr->bounds->dim_1.left); - printf("bounds.right: %d\n", ptr->bounds->dim_1.right); - printf("bounds.dir: %d\n", ptr->bounds->dim_1.dir); - printf("bounds.len: %d\n", ptr->bounds->dim_1.len); +void printUnconstrained(ghdl_NaturalDimArr_t* ptr, int dims) { + printf("array: %p\n", ptr->array); + printf("bounds: %p\n", ptr->bounds); + int i; + for(i = 0; i < dims; i++){ + printf("bounds%d.left: %d\n", i, ptr->bounds[i].left); + printf("bounds%d.right: %d\n", i, ptr->bounds[i].right); + printf("bounds%d.dir: %d\n", i, ptr->bounds[i].dir); + printf("bounds%d.len: %d\n", i, ptr->bounds[i].len); + } } /* @@ -61,7 +50,7 @@ void print(ghdl_NaturalDimArr_t* ptr) { char* ghdlToString(ghdl_NaturalDimArr_t* ptr) { assert(ptr != NULL); assert(ptr->bounds != NULL); - int len = ptr->bounds->dim_1.len; + int len = ptr->bounds[0].len; char* str = malloc(sizeof(char) * len + 1); strncpy(str, ptr->array, len); str[len] = '\0'; @@ -90,20 +79,9 @@ void ghdlToArray(ghdl_NaturalDimArr_t* ptr, void** vec, int* len, int num) { assert(ptr->bounds != NULL); *vec = ptr->array; - void* b = ptr->bounds; - switch (num) { - case 1: - len[0] = ((bounds_t*)b)->dim_1.len; - break; - case 2: - len[0] = ((bounds2D_t*)b)->dim_2.len; - len[1] = ((bounds2D_t*)b)->dim_1.len; - break; - case 3: - len[0] = ((bounds3D_t*)b)->dim_3.len; - len[1] = ((bounds3D_t*)b)->dim_2.len; - len[2] = ((bounds3D_t*)b)->dim_1.len; - break; + for (int i = 0; i < num; i++) + { + len[i] = ptr->bounds[num-i-1].len; } } @@ -140,7 +118,7 @@ ghdl_NaturalDimArr_t ghdlFromString(char *string) { range->dir = 0; range->len = len; // Don't bother copying the string, because GHDL will do that anyway - return (ghdl_NaturalDimArr_t){.array=string, .bounds=(bounds_t*)range}; + return (ghdl_NaturalDimArr_t){.array=string, .bounds=range}; } // @RocketRoss @@ -163,46 +141,26 @@ void ghdlSetRange(range_t* r, int len, bool reversed){ } } -// @bradleyharden??? +// @RocketRoss /* * Convert C types representing an unconstrained array with a dimension of type 'natural', to a fat pointer */ ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { - void* b; - void* a; + range_t* b = malloc(sizeof(range_t)*dims); assert(b != NULL); - switch (dims) { - case 3: - b = malloc(sizeof(bounds3D_t)); - - a = malloc(sizeof(int)*len[0]*len[1]*len[2]); - memmove(a, vec, sizeof(int)*len[0]*len[1]*len[2]); - vec = a; - - ghdlSetRange(&(((bounds3D_t*)b)->dim_1), len[0], false); - ghdlSetRange(&(((bounds3D_t*)b)->dim_2), len[1], false); - ghdlSetRange(&(((bounds3D_t*)b)->dim_3), len[2], false); - break; - case 2: - b = malloc(sizeof(bounds2D_t)); - - a = malloc(sizeof(int)*len[0]*len[1]); - memmove(a, vec, sizeof(int)*len[0]*len[1]); - vec = a; - - ghdlSetRange(&(((bounds2D_t*)b)->dim_1), len[0], false); - ghdlSetRange(&(((bounds2D_t*)b)->dim_2), len[1], false); - break; - case 1: - b = malloc(sizeof(bounds_t)); - a = malloc(sizeof(int)*len[0]); - memmove(a, vec, sizeof(int)*len[0]); - vec = a; - - ghdlSetRange(&(((bounds_t*)b)->dim_1), len[0], false); + + int totalSize = 1; + for (int i = 0; i < dims; i++) + { + totalSize *= len[i]; + ghdlSetRange(b+i, len[i], false); } - return (ghdl_NaturalDimArr_t){.array= a, .bounds=(bounds_t*)b}; + + void* a = malloc(sizeof(int)*totalSize); + memmove(a, vec, sizeof(int)*totalSize); + vec = a; + return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; } /* From f287b530b994015fd40d178522b91b900d3ceb22 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 21:07:45 +0200 Subject: [PATCH 33/37] Remove quick_start reference from VHPIDIRECT --- doc/examples/vhpidirect/VHPIDIRECT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/vhpidirect/VHPIDIRECT.rst b/doc/examples/vhpidirect/VHPIDIRECT.rst index eb675f4d02..248695f25a 100644 --- a/doc/examples/vhpidirect/VHPIDIRECT.rst +++ b/doc/examples/vhpidirect/VHPIDIRECT.rst @@ -36,4 +36,4 @@ There is an example under `Demo of mixed vhdl + systemc simulation `_. \ No newline at end of file +There is a collection of GHDL use cases under eine's `hwd-ide `_. \ No newline at end of file From b05b832639b4e111d8c6aeeb1dea65abca6f0137 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Wed, 8 Apr 2020 21:18:16 +0200 Subject: [PATCH 34/37] printUnconstrained -> printAttributes --- doc/examples/vhpidirect/demo/ghdl.h | 12 ++++++------ doc/examples/vhpidirect/demo/main.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index 8622961b5c..ad5a0a140a 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -30,15 +30,15 @@ typedef struct { * Print custom types */ -void printUnconstrained(ghdl_NaturalDimArr_t* ptr, int dims) { +void printAttributes(ghdl_NaturalDimArr_t* ptr, int dims) { printf("array: %p\n", ptr->array); printf("bounds: %p\n", ptr->bounds); int i; for(i = 0; i < dims; i++){ - printf("bounds%d.left: %d\n", i, ptr->bounds[i].left); - printf("bounds%d.right: %d\n", i, ptr->bounds[i].right); - printf("bounds%d.dir: %d\n", i, ptr->bounds[i].dir); - printf("bounds%d.len: %d\n", i, ptr->bounds[i].len); + printf("bounds[%d].left: %d\n", i+1, ptr->bounds[i].left); + printf("bounds[%d].right: %d\n", i+1, ptr->bounds[i].right); + printf("bounds[%d].dir: %d\n", i+1, ptr->bounds[i].dir); + printf("bounds[%d].len: %d\n", i+1, ptr->bounds[i].len); } } @@ -123,7 +123,7 @@ ghdl_NaturalDimArr_t ghdlFromString(char *string) { // @RocketRoss /* -* Helper to setup the bouds_t for ghdlFromArray +* Helper to setup the bounds_t for ghdlFromArray */ void ghdlSetRange(range_t* r, int len, bool reversed){ diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index dbed8585e1..4d0c59b6db 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -160,7 +160,7 @@ void testCinterface( printf("v_2vec_real : %p [%d, %d]\n", vec_enum, len[1], len[0]); printf("\nVerify GHDL Matrix in C\n"); - //print2d(v_mat_int); + printAttributes(v_mat_int, 2); int* len2 = malloc(2 * sizeof(int)); int32_t* mat_int; @@ -178,7 +178,7 @@ void testCinterface( printf("v_mat_int : %p [%d,%d]\n\n", mat_int, len2[0], len2[1]); printf("\nVerify the 3D GHDL array in C\n"); - //print3d(v_3d_int); + printAttributes(v_3d_int, 3); int* len3 = malloc(3 * sizeof(int)); int32_t* d3_int; From e63ac0f1203306710f3dfb4e7530a9a6c86a24a5 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Thu, 9 Apr 2020 16:18:29 +0200 Subject: [PATCH 35/37] Free malloc'd C Pointers: valgrind confirmation --- doc/examples/vhpidirect/demo/ghdl.h | 37 +++++++---- doc/examples/vhpidirect/demo/main.c | 97 +++++++++++++++++++++++------ doc/examples/vhpidirect/demo/run.sh | 6 +- doc/examples/vhpidirect/demo/tb.vhd | 14 +++-- 4 files changed, 116 insertions(+), 38 deletions(-) diff --git a/doc/examples/vhpidirect/demo/ghdl.h b/doc/examples/vhpidirect/demo/ghdl.h index ad5a0a140a..4db4ce1909 100644 --- a/doc/examples/vhpidirect/demo/ghdl.h +++ b/doc/examples/vhpidirect/demo/ghdl.h @@ -12,17 +12,17 @@ typedef struct { int32_t right; int32_t dir; int32_t len; -} range_t; +} bounds_t; // Unconstrained array with dimensions of type 'natural' typedef struct { void* array; - range_t* bounds; + bounds_t* bounds; } ghdl_NaturalDimArr_t; // Access to an unconstrained array with 1 dimension of type 'natural' typedef struct { - range_t range; + bounds_t range; uint8_t array[]; } ghdl_AccNaturalDimArr_t; @@ -110,7 +110,7 @@ ghdl_NaturalDimArr_t* ghdlFromString(char* str) { // @bradleyharden ghdl_NaturalDimArr_t ghdlFromString(char *string) { - range_t *range = malloc(sizeof(range_t)); + bounds_t *range = malloc(sizeof(bounds_t)); assert(range != NULL); uint32_t len = strlen(string); range->left = 1; @@ -126,7 +126,7 @@ ghdl_NaturalDimArr_t ghdlFromString(char *string) { * Helper to setup the bounds_t for ghdlFromArray */ -void ghdlSetRange(range_t* r, int len, bool reversed){ +void ghdlSetRange(bounds_t* r, int len, bool reversed){ if(!reversed){//to r->left = 0; r->right = len-1; @@ -146,20 +146,31 @@ void ghdlSetRange(range_t* r, int len, bool reversed){ * Convert C types representing an unconstrained array with a dimension of type 'natural', to a fat pointer */ -ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { - range_t* b = malloc(sizeof(range_t)*dims); +ghdl_NaturalDimArr_t ghdlFromPointer(void* vec, int* len, int dims) {//handled malloc'd pointer in freeCPointers() + bounds_t* b = malloc(sizeof(bounds_t)*dims); assert(b != NULL); + for (int i = 0; i < dims; i++) + { + ghdlSetRange(b+i, len[i], false); + } + + void *a = vec; + return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; +} + +ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims, int sizeOfDataType) {//handled malloc'd pointer in freeCPointers() + bounds_t* b = malloc(sizeof(bounds_t)*dims); int totalSize = 1; for (int i = 0; i < dims; i++) { totalSize *= len[i]; ghdlSetRange(b+i, len[i], false); } - - void* a = malloc(sizeof(int)*totalSize); - memmove(a, vec, sizeof(int)*totalSize); - vec = a; + + void *a = malloc(sizeOfDataType * totalSize); + memcpy(a, vec, sizeOfDataType * totalSize); + return (ghdl_NaturalDimArr_t){.array= a, .bounds=b}; } @@ -167,7 +178,7 @@ ghdl_NaturalDimArr_t ghdlFromArray(void* vec, int* len, int dims) { * Convert an access to an unconstrained string, to a (null terminated) C string */ -char* ghdlAccToString(ghdl_AccNaturalDimArr_t *line) { +char* ghdlAccToString(ghdl_AccNaturalDimArr_t *line) {//TODO Test //TODO handle malloc'd pointer // Add a null character, because GHDL strings are not null-terminated char *string = malloc(line->range.len + 1); strncpy(string, line->array, line->range.len); @@ -179,7 +190,7 @@ char* ghdlAccToString(ghdl_AccNaturalDimArr_t *line) { */ // TODO: support 2 and 3 dimensions -ghdl_AccNaturalDimArr_t* ghdlAccFromArray(uint32_t length, size_t bytes) { +ghdl_AccNaturalDimArr_t* ghdlAccFromArray(uint32_t length, size_t bytes) {//TODO handle malloc'd pointer ghdl_AccNaturalDimArr_t *access = malloc(sizeof(ghdl_AccNaturalDimArr_t) + length * bytes); assert(access != NULL); access->range.left = 0; diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 4d0c59b6db..9b0567b253 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -14,6 +14,18 @@ typedef struct rec_t { typedef enum {standby, start, busy, done} enum_t; +int32_t* vec; +bounds_t* vec_bounds; +int32_t* mat; +bounds_t* mat_bounds; +int32_t* d3_ptr; +bounds_t* d3_bounds; +int* len; +int* len2; +int* len3; +bounds_t* string_bounds; +ghdl_AccNaturalDimArr_t* line; + int getFlatArrayIndex(int* dimIndex, int* lens, int dims){ if(dims == 1){ return dimIndex[0]; @@ -88,8 +100,9 @@ void testCinterface( char* str = ghdlToString(v_str); printf("v_str : %p '%s' [%ld]\n", v_str->array, str, strlen(str)); + free(str); - int* len = malloc(2 * sizeof(int)); + len = malloc(2 * sizeof(int)); int32_t* vec_int; ghdlToArray(v_vec_int, (void**)&vec_int, len, 1); @@ -161,7 +174,7 @@ void testCinterface( printf("\nVerify GHDL Matrix in C\n"); printAttributes(v_mat_int, 2); - int* len2 = malloc(2 * sizeof(int)); + len2 = malloc(2 * sizeof(int)); int32_t* mat_int; ghdlToArray(v_mat_int, (void**)&mat_int, len2, 2); @@ -179,7 +192,7 @@ void testCinterface( printf("\nVerify the 3D GHDL array in C\n"); printAttributes(v_3d_int, 3); - int* len3 = malloc(3 * sizeof(int)); + len3 = malloc(3 * sizeof(int)); int32_t* d3_int; ghdlToArray(v_3d_int, (void**)&d3_int, len3, 3); @@ -201,61 +214,106 @@ void testCinterface( printf("end testCinterface\n\n"); } +void freePointers(){ + free(vec); + free(vec_bounds); + free(mat); + free(mat_bounds); + free(d3_ptr); + free(d3_bounds); + free(string_bounds); + free(line); + free(len); + free(len2); + free(len3); +} + void getString(ghdl_NaturalDimArr_t* ptr) { *ptr = ghdlFromString("HELLO WORLD"); + string_bounds = ptr->bounds; } -void getIntVec(ghdl_NaturalDimArr_t* ptr) { - int32_t vec[6] = {11, 22, 33, 44, 55}; - int32_t len[1] = {5}; - int x; - *ptr = ghdlFromArray(vec, len, 1); +void getIntVec(ghdl_NaturalDimArr_t *ptr) {//Notice how similar this is to getIntMat() which is supposedly a 2D array (it is also actually just a flat (1D) array) + vec = malloc(2*3*sizeof(int32_t)); + int32_t len[1] = {2*3}; + int x, y; + for ( x=0 ; x<2 ; x++ ) { + for ( y=0 ; y<3 ; y++ ) { + int flatIndex = x*3+y; + vec[flatIndex] = 11*(flatIndex+1); + } + } + + *ptr = ghdlFromPointer((void *)vec, len, 1); + vec_bounds = ptr->bounds; + assert(ptr->array == vec); + printf("\n1D Array values [%d]:\n", len[0]); for ( x=0 ; xarray)[x]); + assert(vec[x] == ((int32_t*)ptr->array)[x]); } + } void getIntMat(ghdl_NaturalDimArr_t* ptr){ - int32_t mat[2][3]; + mat = malloc(2*3*sizeof(int32_t)); int32_t len[2] = {2, 3}; - int x, y; + int x, y, ind[2]; for ( x=0 ; xbounds; printf("\n2D Array values [%d,%d]:\n", len[0], len[1]); for ( x=0 ; xarray)[flatIndex]); } printf("\n"); } + } void getInt3d(ghdl_NaturalDimArr_t* ptr){ int32_t d3[2][4][3]; int32_t len[3] = {2, 4, 3}; - int x, y, z; + int x, y, z, ind[3]; for ( x=0 ; xarray; + d3_bounds = ptr->bounds; printf("\n3D Array values [%d,%d,%d]:\n", len[0], len[1], len[2]); for ( x=0 ; xarray)[flatIndex]); } printf("\n"); } @@ -264,7 +322,8 @@ void getInt3d(ghdl_NaturalDimArr_t* ptr){ } ghdl_AccNaturalDimArr_t* getLine() { - return ghdlAccFromString("HELLO WORLD"); + line = ghdlAccFromString("HELLO WORLD"); + return line; } int getLogicIntValue(char logic){ diff --git a/doc/examples/vhpidirect/demo/run.sh b/doc/examples/vhpidirect/demo/run.sh index fe202d5f25..99e67b2291 100644 --- a/doc/examples/vhpidirect/demo/run.sh +++ b/doc/examples/vhpidirect/demo/run.sh @@ -5,5 +5,7 @@ cd "$(dirname $0)" set -e ghdl -a -O0 -g tb.vhd -ghdl -e -O0 -g -Wl,-I./ -Wl,main.c tb -./tb +ghdl -e -O0 -g -Wl,-I./ -Wl,main.c tb && +#./tb && +valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./tb && +cat valgrind-out.txt | grep -A 4 "LEAK SUMMARY" diff --git a/doc/examples/vhpidirect/demo/tb.vhd b/doc/examples/vhpidirect/demo/tb.vhd index 49148ca064..bece9a1542 100644 --- a/doc/examples/vhpidirect/demo/tb.vhd +++ b/doc/examples/vhpidirect/demo/tb.vhd @@ -95,6 +95,10 @@ begin function getBitValue(bitVal : bit) return integer is begin assert false report "VHPIDIRECT getBitValue" severity failure; end; attribute foreign of getBitValue : function is "VHPIDIRECT getLogicIntValue"; + + procedure freeCPointers is + begin assert false report "VHPIDIRECT freeCPointers" severity failure; end; + attribute foreign of freeCPointers : procedure is "VHPIDIRECT freePointers"; variable spareInt: integer; begin @@ -129,7 +133,7 @@ begin if g_str'length /= 0 then report "g_str: " & g_str severity note; end if; - report "string: " & getString severity note; + --report "string: " & getString severity note;--g_str results from calling getString(), calling it again means a malloc'd pointer is lost. report "g_int_vec'length: " & integer'image(g_int_vec'length) severity note; for x in g_int_vec'range loop @@ -138,7 +142,7 @@ begin end loop; report "g_line: " & g_line.all severity note; - report "getLine: " & getLine.all severity note; + --report "getLine: " & getLine.all severity note;--g_line results from calling getLine(), calling it again means a malloc'd pointer is lost. assert getLine.all = "HELLO WORLD" severity failure; assert 0 = getLogicValue('U') severity error; @@ -169,8 +173,8 @@ begin for i in g_int_mat'range(1) loop for j in g_int_mat'range(2) loop spareInt := spareInt + 1; + report "Asserting Mat [" & integer'image(i) & "," & integer'image(j) & "]: " & integer'image(g_int_mat(i, j)) severity note; assert g_int_mat(i, j) = 11*spareInt severity error; - report "Asserted Mat [" & integer'image(i) & "," & integer'image(j) & "]: " & integer'image(g_int_mat(i, j)) severity note; end loop ; end loop ; @@ -180,12 +184,14 @@ begin for j in g_int_3d'range(2) loop for k in g_int_3d'range(3) loop spareInt := spareInt + 1; + report "Asserting 3D [" & integer'image(i) & "," & integer'image(j) & "," & integer'image(k) & "]: " & integer'image(g_int_3d(i, j, k)) severity note; assert g_int_3d(i, j, k) = 11*spareInt severity error; - report "Asserted 3D [" & integer'image(i) & "," & integer'image(j) & "," & integer'image(k) & "]: " & integer'image(g_int_3d(i, j, k)) severity note; end loop; end loop ; end loop ; + freeCPointers; + report "No errors/failures. Concluding testbench." severity note; wait; end process; end; From b6ac9a7376b57583b80794c34acc232e9c4edcc5 Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Thu, 9 Apr 2020 20:17:13 +0200 Subject: [PATCH 36/37] Handle second call getLine/String, no valgrind --- doc/examples/vhpidirect/demo/main.c | 6 ++++++ doc/examples/vhpidirect/demo/run.sh | 6 +++--- doc/examples/vhpidirect/demo/tb.vhd | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/doc/examples/vhpidirect/demo/main.c b/doc/examples/vhpidirect/demo/main.c index 9b0567b253..f50858d46d 100644 --- a/doc/examples/vhpidirect/demo/main.c +++ b/doc/examples/vhpidirect/demo/main.c @@ -229,6 +229,9 @@ void freePointers(){ } void getString(ghdl_NaturalDimArr_t* ptr) { + if(string_bounds != NULL){//this handles a second call//this handles a second call + free(string_bounds); + } *ptr = ghdlFromString("HELLO WORLD"); string_bounds = ptr->bounds; } @@ -322,6 +325,9 @@ void getInt3d(ghdl_NaturalDimArr_t* ptr){ } ghdl_AccNaturalDimArr_t* getLine() { + if(line != NULL){//this handles a second call + free(line); + } line = ghdlAccFromString("HELLO WORLD"); return line; } diff --git a/doc/examples/vhpidirect/demo/run.sh b/doc/examples/vhpidirect/demo/run.sh index 99e67b2291..282b42fd5b 100644 --- a/doc/examples/vhpidirect/demo/run.sh +++ b/doc/examples/vhpidirect/demo/run.sh @@ -6,6 +6,6 @@ set -e ghdl -a -O0 -g tb.vhd ghdl -e -O0 -g -Wl,-I./ -Wl,main.c tb && -#./tb && -valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./tb && -cat valgrind-out.txt | grep -A 4 "LEAK SUMMARY" +./tb +#valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt ./tb && +#cat valgrind-out.txt | grep -A 4 "LEAK SUMMARY" diff --git a/doc/examples/vhpidirect/demo/tb.vhd b/doc/examples/vhpidirect/demo/tb.vhd index bece9a1542..61f44970f0 100644 --- a/doc/examples/vhpidirect/demo/tb.vhd +++ b/doc/examples/vhpidirect/demo/tb.vhd @@ -133,7 +133,7 @@ begin if g_str'length /= 0 then report "g_str: " & g_str severity note; end if; - --report "string: " & getString severity note;--g_str results from calling getString(), calling it again means a malloc'd pointer is lost. + report "string: " & getString severity note;--g_str results from calling getString(), calling it again means a malloc'd pointer can be lost. report "g_int_vec'length: " & integer'image(g_int_vec'length) severity note; for x in g_int_vec'range loop @@ -142,7 +142,7 @@ begin end loop; report "g_line: " & g_line.all severity note; - --report "getLine: " & getLine.all severity note;--g_line results from calling getLine(), calling it again means a malloc'd pointer is lost. + report "getLine: " & getLine.all severity note;--g_line results from calling getLine(), calling it again means a malloc'd pointer can be lost. assert getLine.all = "HELLO WORLD" severity failure; assert 0 = getLogicValue('U') severity error; From 3c99b5b96b9fc854f04e78e1b30516925f48911d Mon Sep 17 00:00:00 2001 From: RocketRoss Date: Sat, 11 Apr 2020 08:49:06 +0200 Subject: [PATCH 37/37] Label .. _foreign_declarations: --- doc/using/Foreign.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst index 60a8953b87..679e4d7c8b 100644 --- a/doc/using/Foreign.rst +++ b/doc/using/Foreign.rst @@ -24,13 +24,10 @@ You can define a subprogram in a foreign language (such as `C` or inspect the hierarchy, set callbacks and/or assign signals. GHDL does not support VHPI. For these kind of features, it is suggested to use VPI instead (see :ref:`VPI_build_commands`). -<<<<<<< HEAD .. _foreign_declarations: -======= .. ATTENTION:: As a consequence of the runtime copyright, you are not allowed to distribute an executable produced by GHDL without allowing access to the VHDL sources. See :ref:`INTRO:Copyrights`. ->>>>>>> origin/master Foreign declarations ====================