diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12e4f74d..2d14b38a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,6 +29,7 @@ jobs: vhpidirect/shared/dlopen, vhpidirect/shared/shghdl, vhpidirect/arrays/intvector, + vhpidirect/arrays/logicvector, ] runs-on: ubuntu-latest env: @@ -57,6 +58,7 @@ jobs: #vhpidirect/shared/dlopen, ! dlfcn.h is not available on win #vhpidirect/shared/shghdl, ! dlfcn.h is not available on win vhpidirect/arrays/intvector, + vhpidirect/arrays/logicvector, ] runs-on: windows-latest env: diff --git a/doc/vhpidirect/examples/arrays.rst b/doc/vhpidirect/examples/arrays.rst index a313e8aa..52d5276c 100644 --- a/doc/vhpidirect/examples/arrays.rst +++ b/doc/vhpidirect/examples/arrays.rst @@ -62,3 +62,56 @@ functionally equivalent: Note that VHPIDIRECT resources are defined in a package (as shown in :ref:`COSIM:VHPIDIRECT:Examples:quickstart:package`). The same package and the corresponding C source file (``caux.c``) are used in both examples, even though ``vhdlalloc`` does not need neither ``[c_]allocIntArr`` nor ``[c_]freePointer``. + +.. _COSIM:VHPIDIRECT:Examples:arrays:logicvectors: + +:cosimtree:`logicvector ` +************************************************************** + +Commonly signals in VHDL are of a logic type or a vector thereof (``std_logic`` and ``std_logic_vector``), coming from IEEE's ``std_logic_1164`` package. +These types can hold values other than high and low (``1`` and ``0``) and are enumerated as: + +0. 'U' +1. 'X' +2. '0' +3. '1' +4. 'Z' +5. 'W' +6. 'L' +7. 'H' +8. '-' + +As mentioned in :ref:`Restrictions_on_foreign_declarations`: + - Because the number of enumeration values is less than 256, logic values are transported in 8 bit words (a ``char`` type in C). + + - In this example two declarations make handling logic values in C a bit easier: + + - Providing logic values in C as their enumeration numbers is simplified with the use of a matching enumeration, ``HDL_LOGIC_STATES``. + - Printing out a logic value's associated character is also simplified with the ``const char HDL_LOGIC_CHAR[]`` declaration. + + - Logic vectors, of a bounded size, can be easily created in C as a ``char[]`` and passed to VHDL to be read as an ``access`` type in VHDL, in this case an access of a subtype of std_logic_vector. + + +This example builds on the integer vector example (:ref:`COSIM:VHPIDIRECT:Examples:arrays:intvector`), by instead passing an array of logic values. Foreign subprograms are declared that enable receiving the size of two different logic vectors as well as the vectors themselves from C. There is only one subprogram to get the size of both C arrays, and it takes in an integer to determine which array's size gets returned. + +.. HINT:: + The ``getLogicVecSize`` in VHDL is declared as receiving a ``boolean`` argument. In C the function is declared to receive an ``char`` argument. The VHDL booleans ``false`` and ``true`` are enumerations, and have integer values, ``0`` and ``1`` respectively. As with the logic values, the boolean enumerations use fewer than 8 bits, so the single byte in C's ``char`` variable receives the VHDL enumeration correctly. + +For illustrative purposes, the two vectors are populated with logic values in different ways: + +- LogicVectorA's indices are manually filled with enumeration values from HDL_LOGIC_STATES. + + - .. code-block:: C + + logic_vec_A[0] = HDL_U; + +- LogicVectorB's indices are filled with an integer value. + + - .. code-block:: C + + for(int i = 0; i < SIZE_LOGIC_VEC_B; i++){ + logic_vec_B[i] = 8-i; + } + +.. ATTENTION:: + The integer values that are given to ``char`` variables in C which are intended to be read as VHDL logic values, must be limited to [0, 8]. This ensures that they represent one of the 9 enumerated logic values. diff --git a/vhpidirect/arrays/logicvector/caux.c b/vhpidirect/arrays/logicvector/caux.c new file mode 100755 index 00000000..4c145264 --- /dev/null +++ b/vhpidirect/arrays/logicvector/caux.c @@ -0,0 +1,52 @@ +#include +#define SIZE_LOGIC_VEC_A (sizeof(logic_vec_A)/sizeof(char)) +#define SIZE_LOGIC_VEC_B (sizeof(logic_vec_B)/sizeof(char)) + +static const char HDL_LOGIC_CHAR[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'}; + +enum HDL_LOGIC_STATES { +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, +}; + +char logic_vec_A[3]; +char logic_vec_B[6]; + +int getLogicVecSize(char returnA){ + if(returnA) + return SIZE_LOGIC_VEC_A; + else + return SIZE_LOGIC_VEC_B; +} + +char* getLogicVecA(){ + //The HDL_LOGIC_STATES enum is used + logic_vec_A[0] = HDL_U; + logic_vec_A[1] = HDL_X; + logic_vec_A[2] = HDL_0; + + printf("A: 1D Array Logic Values [%ld]:\n", SIZE_LOGIC_VEC_A); + for(int i = 0; i < SIZE_LOGIC_VEC_A; i++){ + printf("[%d] = %c\t", i, HDL_LOGIC_CHAR[logic_vec_A[i]]); + } + printf("\n"); + return logic_vec_A; +} + +char* getLogicVecB(){ + //The equivalent value of HDL_LOGIC_STATES is used + printf("B: 1D Array Logic Values [%ld]:\n", SIZE_LOGIC_VEC_B); + for(int i = 0; i < SIZE_LOGIC_VEC_B; i++){ + logic_vec_B[i] = 8-i;//The last 'SIZE_LOGIC_VEC_B' HDL_LOGIC values, in reverse order. + printf("[%d] = %c\t", i, HDL_LOGIC_CHAR[logic_vec_B[i]]); + } + printf("\n"); + return logic_vec_B; +} diff --git a/vhpidirect/arrays/logicvector/run.sh b/vhpidirect/arrays/logicvector/run.sh new file mode 100755 index 00000000..b1a66566 --- /dev/null +++ b/vhpidirect/arrays/logicvector/run.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +cd "$(dirname $0)" + +set -e + +echo "Analyze tb.vhd" +ghdl -a tb.vhd + +echo "Build tb (with caux.c)" +ghdl -e -Wl,caux.c tb + +echo "Execute tb" +./tb diff --git a/vhpidirect/arrays/logicvector/tb.vhd b/vhpidirect/arrays/logicvector/tb.vhd new file mode 100755 index 00000000..7071bb54 --- /dev/null +++ b/vhpidirect/arrays/logicvector/tb.vhd @@ -0,0 +1,53 @@ +library ieee; +use ieee.std_logic_1164.all; + +entity tb is +end; + +architecture arch of tb is +begin + + process + + function getLogicVecSize(returnSizeOfA: boolean) return integer is + begin assert false report "VHPIDIRECT getLogicVecSize" severity failure; end; + attribute foreign of getLogicVecSize : function is "VHPIDIRECT getLogicVecSize"; + + subtype logic_vec_a_t is std_logic_vector(0 to getLogicVecSize(true)-1); + type logic_vec_a_ptr_t is access logic_vec_a_t; + + subtype logic_vec_b_t is std_ulogic_vector(0 to getLogicVecSize(false)-1); + type logic_vec_b_ptr_t is access logic_vec_b_t; + + function getLogicVecA return logic_vec_a_ptr_t is + begin assert false report "VHPIDIRECT getLogicVecA" severity failure; end; + attribute foreign of getLogicVecA : function is "VHPIDIRECT getLogicVecA"; + + function getLogicVecB return logic_vec_b_ptr_t is + begin assert false report "VHPIDIRECT getLogicVecB" severity failure; end; + attribute foreign of getLogicVecB : function is "VHPIDIRECT getLogicVecB"; + + variable g_logic_vec_a: logic_vec_a_ptr_t := getLogicVecA; + variable g_logic_vec_b: logic_vec_b_ptr_t := getLogicVecB; + + constant logicArray: std_logic_vector(0 to 8) := ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'); + + begin + + report "g_logic_vec_a'length: " & integer'image(g_logic_vec_a'length) severity note; + + for x in g_logic_vec_a'range loop + report "Asserting VecA [" & integer'image(x) & "]: " & std_logic'image(g_logic_vec_a(x)) severity note; + assert g_logic_vec_a(x) = logicArray(x) severity failure; + end loop; + + report "g_logic_vec_b'length: " & integer'image(g_logic_vec_b'length) severity note; + + for x in g_logic_vec_b'range loop + report "Asserting VecB [" & integer'image(x) & "]: " & std_logic'image(g_logic_vec_b(x)) severity note; + assert g_logic_vec_b(x) = logicArray(8-x) severity failure; + end loop; + + wait; + end process; +end;