From dcd30d5683ad09494fe2cf066acc0d85b3c50da0 Mon Sep 17 00:00:00 2001 From: umarcor Date: Sat, 11 Apr 2020 08:19:42 +0200 Subject: [PATCH] vhpidirect: add header file and 'demo' (ghdl/ghdl#1059) --- .github/workflows/test.yml | 1 + doc/vhpidirect/examples/demo.rst | 21 ++++ vhpidirect/demo/main.c | 160 +++++++++++++++++++++++++++++++ vhpidirect/demo/run.sh | 9 ++ vhpidirect/demo/tb.vhd | 110 +++++++++++++++++++++ 5 files changed, 301 insertions(+) create mode 100644 doc/vhpidirect/examples/demo.rst create mode 100644 vhpidirect/demo/main.c create mode 100755 vhpidirect/demo/run.sh create mode 100644 vhpidirect/demo/tb.vhd diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 485cbbae..3607f7d5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: wrapping/basic, wrapping/time, linking/bind, + demo, shared/shlib, shared/dlopen, shared/shghdl, diff --git a/doc/vhpidirect/examples/demo.rst b/doc/vhpidirect/examples/demo.rst new file mode 100644 index 00000000..0ed6d047 --- /dev/null +++ b/doc/vhpidirect/examples/demo.rst @@ -0,0 +1,21 @@ +.. program:: ghdl +.. _COSIM:VHPIDIRECT:Examples:demo: + +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/vhpidirect/demo/main.c b/vhpidirect/demo/main.c new file mode 100644 index 00000000..b4e0c478 --- /dev/null +++ b/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;