aboutsummaryrefslogtreecommitdiffstats
path: root/doc/using/Foreign.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/using/Foreign.rst')
-rw-r--r--doc/using/Foreign.rst339
1 files changed, 339 insertions, 0 deletions
diff --git a/doc/using/Foreign.rst b/doc/using/Foreign.rst
new file mode 100644
index 000000000..7a50e4358
--- /dev/null
+++ b/doc/using/Foreign.rst
@@ -0,0 +1,339 @@
+.. FOREIGN:
+
+Interfacing to other languages
+##############################
+
+.. index:: interfacing
+
+.. index:: other languages
+
+.. index:: foreign
+
+.. index:: VHPI
+
+.. index:: VHPIDIRECT
+
+Interfacing with foreign languages through VHPIDIRECT is possible any platform.
+You can define a subprogram in a foreign language (such as `C` or
+`Ada`) and import it into a VHDL design.
+
+.. HINT::
+ VHPIDIRECT is the simplest way to call C code from VHDL. VHPI is a complex API to interface C and VHDL, which allows to
+ 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
+====================
+
+Only subprograms (functions or procedures) can be imported, using the foreign
+attribute. In this example, the `sin` function is imported:
+
+.. code-block:: VHDL
+
+ package math is
+ function sin (v : real) return real;
+ attribute foreign of sin : function is "VHPIDIRECT sin";
+ end math;
+
+ package body math is
+ function sin (v : real) return real is
+ begin
+ assert false severity failure;
+ end sin;
+ end math;
+
+
+A subprogram is made foreign if the `foreign` attribute decorates
+it. This attribute is declared in the 1993 revision of the
+``std.standard`` package. Therefore, you cannot use this feature in
+VHDL 1987.
+
+The decoration is achieved through an attribute specification. The
+attribute specification must be in the same declarative part as the
+subprogram and must be after it. This is a general rule for specifications.
+The value of the specification must be a locally static string.
+
+Even when a subprogram is foreign, its body must be present. However, since
+it won't be called, you can make it empty or simply put an assertion.
+
+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.
+
+.. _Restrictions_on_foreign_declarations:
+
+Restrictions on foreign declarations
+------------------------------------
+
+Any subprogram can be imported. GHDL puts no restrictions on foreign
+subprograms. However, the representation of a type or of an interface in a
+foreign language may be obscure. Most non-composite types are easily imported:
+
+
+*integer types*
+ They are represented by a 32 bit word. This generally corresponds to
+ `int` for `C` or `Integer` for `Ada`.
+
+*physical types*
+ They are represented by a 64 bit word. This generally corresponds to the
+ `long long` for `C` or `Long_Long_Integer` for `Ada`.
+
+*floating point types*
+ They are represented by a 64 bit floating point word. This generally
+ corresponds to `double` for `C` or `Long_Float` for `Ada`.
+
+*enumeration types*
+ They are represented by an 8 bit word, or, if the number of literals is
+ greater than 256, by a 32 bit word. There is no corresponding C type, since arguments are
+ not promoted.
+
+Non-composite types are passed by value. For the `in` mode, this
+corresponds to the `C` or `Ada` mechanism. The `out` and
+`inout` interfaces of non-composite types are gathered in a record
+and this record is passed by reference as the first argument to the
+subprogram. As a consequence, you shouldn't use `in` and
+`inout` modes in foreign subprograms, since they are not portable.
+
+Records are represented like a `C` structure and are passed by reference
+to subprograms.
+
+Arrays with static bounds are represented like a `C` array, whose
+length is the number of elements, and are passed by reference to subprograms.
+
+Unconstrained arrays are represented by a fat pointer. Do not use unconstrained
+arrays in foreign subprograms.
+
+Accesses to an unconstrained array are fat pointers. Other accesses correspond to an address and are passed to a subprogram like other non-composite types.
+
+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
+=================================================
+
+You may run your design from an external program. You just have to call
+the ``ghdl_main`` function which can be defined:
+
+in C:
+
+.. code-block:: C
+
+ extern int ghdl_main (int argc, char **argv);
+
+in Ada:
+
+.. code-block:: Ada
+
+ with System;
+ ...
+ function Ghdl_Main (Argc : Integer; Argv : System.Address)
+ return Integer;
+ pragma import (C, Ghdl_Main, "ghdl_main");
+
+
+This function must be called once, and returns 0 at the end of the simulation.
+
+.. _Linking_with_Ada:
+
+Linking GHDL to Ada/C
+=====================
+
+As explained previously in :ref:`Starting_a_simulation_from_a_foreign_program`,
+you can start a simulation from an `Ada` or `C` program. However the build
+process is not trivial: you have to elaborate your program and your
+`VHDL` design.
+
+.. HINT::
+ If the foreign language is C, this procedure is equivalent to the one described in
+ :ref:`Linking_with_foreign_object_files`, which is easier. Thus, this procedure is
+ explained for didactic purposes. When suitable, we suggest to use ``-e`` instead
+ of ``--bind`` and ``--list-link``.
+
+First, you have to analyze all your design files. In this example, we
+suppose there is only one design file, :file:`design.vhdl`.
+
+::
+
+ $ ghdl -a design.vhdl
+
+Then, bind your design. In this example, we suppose the entity at the
+design apex is ``design``.
+
+::
+
+ $ ghdl --bind design
+
+Finally, compile/bind your program and link it with your `VHDL`
+design::
+
+in C:
+
+::
+
+ gcc my_prog.c -Wl,`ghdl --list-link design`
+
+in Ada:
+
+::
+
+ $ gnatmake my_prog -largs `ghdl --list-link design`
+
+See :ref:`gccllvm-only-programs` for further details about ``--bind`` and ``--list-link``.
+
+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.
+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
+
+ attribute foreign of get_rand: function is "VHPIDIRECT ./getrand.so get_rand";
+
+Dynamically loading GHDL
+========================
+
+In order to generate a position independent executable (PIE), be it an executable binary
+or a shared library, GHDL must be built with config option ``--default-pic``. This will ensure
+that all the libraries and sources analyzed by GHDL generate position independent code (PIC).
+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:
+
+.. code-block:: Python
+
+ import ctypes
+ gbin = ctypes.CDLL(bin_path)
+
+ args = ['-gGENA="value"', 'gGENB="value"']
+
+ xargs = (ctypes.POINTER(ctypes.c_char) * (len(args) + 1))()
+ for i, arg in enumerate(args):
+ xargs[i] = ctypes.create_string_buffer(arg.encode('utf-8'))
+ return args[0], xargs
+
+ gbin.main(len(xargv)-1, xargv)
+
+ import _ctypes
+ # On GNU/Linux
+ _ctypes.dlclose(gbin._handle)
+ # On Windows
+ #_ctypes.FreeLibrary(gbin._handle)
+
+This allows seamless co-simulation using concurrent/parallel execution features available in each language:
+pthreads, goroutines/gochannels, multiprocessing/queues, etc. Moreover, it provides a mechanism to execute multiple
+GHDL simulations in parallel.
+
+Using GRT from Ada
+==================
+
+.. warning::
+ This topic is only for advanced users who know how to use `Ada`
+ and `GNAT`. This is provided only for reference; we have tested
+ this once before releasing `GHDL` 0.19, but this is not checked at
+ each release.
+
+The simulator kernel of `GHDL` named :dfn:`GRT` is written in
+`Ada95` and contains a very light and slightly adapted version
+of `VHPI`. Since it is an `Ada` implementation it is
+called :dfn:`AVHPI`. Although being tough, you may interface to `AVHPI`.
+
+For using `AVHPI`, you need the sources of `GHDL` and to recompile
+them (at least the `GRT` library). This library is usually compiled with
+a `No_Run_Time` pragma, so that the user does not need to install the
+`GNAT` runtime library. However, you certainly want to use the usual
+runtime library and want to avoid this pragma. For this, reset the
+`GRT_PRAGMA_FLAG` variable.
+
+::
+
+ $ make GRT_PRAGMA_FLAG= grt-all
+
+
+Since `GRT` is a self-contained library, you don't want
+`gnatlink` to fetch individual object files (furthermore this
+doesn't always work due to tricks used in `GRT`). For this,
+remove all the object files and make the :file:`.ali` files read-only.
+
+::
+
+ $ rm *.o
+ $ chmod -w *.ali
+
+
+You may then install the sources files and the :file:`.ali` files. I have never
+tested this step.
+
+You are now ready to use it.
+
+Here is an example, :file:`test_grt.adb` which displays the top
+level design name.
+
+.. code-block:: Ada
+
+ with System; use System;
+ with Grt.Avhpi; use Grt.Avhpi;
+ with Ada.Text_IO; use Ada.Text_IO;
+ with Ghdl_Main;
+
+ procedure Test_Grt is
+ -- VHPI handle.
+ H : VhpiHandleT;
+ Status : Integer;
+
+ -- Name.
+ Name : String (1 .. 64);
+ Name_Len : Integer;
+ begin
+ -- Elaborate and run the design.
+ Status := Ghdl_Main (0, Null_Address);
+
+ -- Display the status of the simulation.
+ Put_Line ("Status is " & Integer'Image (Status));
+
+ -- Get the root instance.
+ Get_Root_Inst(H);
+
+ -- Disp its name using vhpi API.
+ Vhpi_Get_Str (VhpiNameP, H, Name, Name_Len);
+ Put_Line ("Root instance name: " & Name (1 .. Name_Len));
+ end Test_Grt;
+
+
+First, analyze and bind your design::
+
+ $ ghdl -a counter.vhdl
+ $ ghdl --bind counter
+
+
+Then build the whole::
+
+ $ gnatmake test_grt -aL`grt_ali_path` -aI`grt_src_path` -largs
+ `ghdl --list-link counter`
+
+
+Finally, run your design::
+
+ $ ./test_grt
+ Status is 0
+ Root instance name: counter
+