Skip to content

Commit

Permalink
vhpidirect: add header file and 'demo' (ghdl/ghdl#1059)
Browse files Browse the repository at this point in the history
  • Loading branch information
umarcor committed May 3, 2020
1 parent 8d8e8bf commit 6e3e701
Show file tree
Hide file tree
Showing 7 changed files with 521 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
vhpidirect/arrays/logicvector,
vhpidirect/arrays/matrices,
vhpidirect/arrays/matrices/framebuffer,
vhpidirect/cinterface/demo,
vpi/quickstart,
]
runs-on: ubuntu-latest
Expand Down Expand Up @@ -81,6 +82,7 @@ jobs:
vhpidirect/arrays/logicvector,
vhpidirect/arrays/matrices,
#vhpidirect/arrays/matrices/framebuffer, ! needs ImageMagick's 'convert'
vhpidirect/cinterface/demo,
vpi/quickstart,
]
runs-on: windows-latest
Expand Down
10 changes: 10 additions & 0 deletions doc/vhpidirect/examples/cinterface.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.. program:: ghdl
.. _COSIM:VHPIDIRECT:Examples:cinterface:

C interface
###########

:cosimtree:`demo <vhpidirect/cinterface/demo>`
**********************************************

This example is a reference and a test suite for the helper C headers provided in :cosimtree:`vhpidirect`. These headers are a reference of GHDL's ABI, and can be imported to easily convert non-trivial data types between C and VHDL. However, the ABI is not settled, so it might change without prior notice.
1 change: 1 addition & 0 deletions doc/vhpidirect/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Examples
quickstart
shared
arrays
cinterface
other
160 changes: 160 additions & 0 deletions vhpidirect/cinterface/demo/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>

#include <ghdl.h>

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<len[0] ; x++ ) {
printf("%d: %d\n", x, vec[x]);
}
*ptr = ghdlFromArray(vec, len, 1);
}

ghdl_AccNaturalDimArr_t* getLine() {
return ghdlAccFromString("HELLO WORLD");
}
14 changes: 14 additions & 0 deletions vhpidirect/cinterface/demo/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env sh

set -e

cd $(dirname "$0")

echo "Analyze tb.vhd"
ghdl -a -O0 -g tb.vhd

echo "Build tb (with main.c and headers)"
ghdl -e -O0 -g -Wl,-I../../ -Wl,main.c tb

echo "Execute tb"
./tb
110 changes: 110 additions & 0 deletions vhpidirect/cinterface/demo/tb.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std.textio.line;

entity tb is
end;

architecture arch of tb is

type rec_t is record
r_char: character;
r_int : integer;
end record;

type enum_t is (standby, start, busy, done);

type int_vec_t is array(natural range <>) 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;
Loading

0 comments on commit 6e3e701

Please sign in to comment.