Open augustofg opened 2 years ago
Well, as a workaround you can use a procedure instead of a function if you don't need the return value:
entity tb is
generic (
g_TCP_PORT : natural := 14000
);
end tb;
architecture arch of tb is
type t_tcp_listener is access integer;
impure function new_tcp_listener (tcp_port : natural) return t_tcp_listener is
begin report "VHPIDIRECT new_tcp_listener" severity failure; end;
attribute foreign of new_tcp_listener : function is "VHPIDIRECT new_tcp_listener";
procedure delete_tcp_listener (variable listener : t_tcp_listener) is
begin report "VHPIDIRECT delete_tcp_listener" severity failure; end;
attribute foreign of delete_tcp_listener : procedure is "VHPIDIRECT delete_tcp_listener";
begin
process
variable net: t_tcp_listener;
begin
net := new_tcp_listener(g_TCP_PORT);
delete_tcp_listener(net);
wait;
end process;
end;
This works, if you don't touch the variable net
, so you don't corrupt the underlying object, but it seems not ideal.
Yes, you are hitting the limitations of vhdl: a function parameter cannot be an access type (or have an access type). You can indeed use a procedure instead. Or simply use handles instead of pointers.
After some experimentation I've found few caveats:
free
on the pointers used in access
types, deallocating explicitly causes double free errors;out
, and by reading the documentation this is discouraged:
Non-composite types are passed by value. For the in mode (default), this corresponds to the C or Ada mechanism. out and inout interfaces are gathered in a record and this record is passed by reference as the first argument to the subprogram. As a consequence, it is not suggested to use out and/or inout modes in foreign subprograms, since they are not portable. Restrictions on type declarationsNevertheless, I succeed in writing to a constrained std_logic_vector variable via a procedure:
library ieee;
use ieee.std_logic_1164.all;
entity obj_tb is
end obj_tb;
architecture arch of obj_tb is
type t_my_obj is access integer;
impure function new_obj (arg : natural) return t_my_obj is
begin report "VHPIDIRECT new_obj" severity failure; end;
attribute foreign of new_obj : function is "VHPIDIRECT new_obj";
procedure read_data_obj(variable obj : in t_my_obj;
variable data : out std_logic_vector(0 to 31)) is
begin report "VHPIDIRECT read_data_obj" severity failure; end;
attribute foreign of read_data_obj: procedure is "VHPIDIRECT read_data_obj";
begin
process
variable obj: t_my_obj;
variable data: std_logic_vector(31 downto 0);
begin
obj := new_obj(512);
read_data_obj(obj, data);
report "Data read: " & to_string(data) severity note;
wait;
end process;
end;
#include <stddef.h>
#include <stdlib.h>
typedef struct {
int data;
} obj;
obj* new_obj(int arg) {
obj* myobj = malloc(sizeof(obj));
myobj->data = arg;
return myobj;
}
typedef struct {
char data[32];
} read_data_obj_record;
void read_data_obj(obj* myobj, read_data_obj_record* rec) {
int mydata = myobj->data;
for (size_t i = 0; i < 32; i++) {
rec->data[i] = mydata & 0x80000000 ? 0x03 : 0x02;
mydata = mydata << 1;
}
}
$ ghdl -a --std=08 test_arguments.vhd
$ ghdl -e -Wl,testobj.c --std=08 obj_tb
./obj_tb
test_arguments.vhd:26:5:@0ms:(report note): Data read: 00000000000000000000001000000000
Though this seems to contradict the documentation: this record is passed by reference as the first argument to the subprogram. Maybe this is not true when passing access types?
I couldn't get working anything more complex than a single out
argument, the record layout seems to be wildly different from what I expected, but I think it is good enough for now.
Hi,
I'm developing a library to allow my VHDL testbenches to be able to listen to TCP connections and send / receive data. The library is written in a object oriented sytle, in which each function receives a pointer to a struct that stores the object internal state, for example:
Now, I couldn't find in the documentation and examples what VHDL type to use for storing an opaque pointer that comes from the C code. The best I could think was using an 'access type', but you can't call functions with an 'access type' argument:
Is there some way of invoking C functions with opaque pointers?
Thanks, Augusto.