![]() |
![]() |
![]() |
![]() |
Using the VHDL FLI with foreign subprograms
Declaring a foreign subprogram in VHDL
To call a foreign C subprogram, you must write a VHDL subprogram declaration that has the equivalent VHDL parameters and return type. Then use the FOREIGN attribute to specify which C function and module to load. The syntax of the FOREIGN attribute is almost identical to the syntax used for foreign architectures. For instance:
procedure in_params( vhdl_integer : IN integer; vhdl_enum : IN severity_level; vhdl_real : IN real; vhdl_array : IN string); attribute FOREIGN of in_params : procedure is "in_params app.so";
You must also write a subprogram body for the subprogram, but it will never be called. For instance:
procedure in_params( vhdl_integer : IN integer; vhdl_enum : IN severity_level; vhdl_real : IN real; vhdl_array : IN string) is begin report "ERROR: foreign subprogram in_params not called"; end;
Matching VHDL parameters with C parameters
Use the table below to match the C parameters in your foreign C subprogram to the VHDL parameters in your VHDL package declaration. The parameters must match in order as well as type.
Note: Handles to foreign subprogram parameters (non-signals) are not persistent. The handles are no longer valid after the subprogram has exited, so they cannot be saved and used later by other foreign code. Arrays are not NULL-terminated. The length of an array can be determined by calling mti_TickLength() on the array's type.
Array and record SIGNAL parameters are passed as an mtiVariableIdT type. Any array or record subelements of these composite variables are also of type mtiVariableIdT. The values of all scalar subelements are of type mtiSignalIdT. To access the signal IDs, use mti_GetVarSubelements() at each composite level. For each subelement that is of a scalar type, use mti_GetVarValueIndirect() to get the signal ID of the scalar. Once you have the signal IDs of the scalar subelements, you can use the FLI signal functions to manipulate the signals.
Matching VHDL return types with C return types
Use the table below to match the C return types in your foreign C subprogram to the VHDL return types in your VHDL code.
VHDL Return Type C Return Type Integer int Enumeration int Real1 mtiRealT Timea mtiTime64T Array -- Not supported -- File -- Not supported -- Record -- Not supported -- Access -- Not supported --
1On Linux, the compiler switch -freg-struct-return must be used when compiling any FLI application code that contains foreign functions that return real or time values.
MtiRealT is a special type that must be used as the return type of a foreign function that returns a real value. Macros are provided in mti.h for setting values in and getting values out of variables of type mtiRealT.
C code and VHDL examples
The following examples illustrate the association between C functions and VHDL procedures. The C function is connected to the VHDL procedure through the FOREIGN attribute specification.
C subprogram example
Functions declared in this code, in_params( ) and out_params( ), have parameters and return types that match the procedures in the subsequent package declaration (pkg).
#include <stdio.h> #include "mti.h" char *severity[] = {"NOTE", "WARNING", "ERROR", "FAILURE"}; static char *get_string(mtiVariableIdT id); void in_params ( int vhdl_integer, /* IN integer */ int vhdl_enum, /* IN severity_level */ double *vhdl_real, /* IN real */ mtiVariableIdT vhdl_array /* IN string */ ) { printf("Integer = %d\n", vhdl_integer); printf("Enum = %s\n", severity[vhdl_enum]); printf("Real = %g\n", *vhdl_real); printf("String = %s\n", get_string(vhdl_array)); } void out_params ( int *vhdl_integer, /* OUT integer */ char *vhdl_enum, /* OUT severity_level */ double *vhdl_real, /* OUT real */ mtiVariableIdT vhdl_array /* OUT string */ ) { char *val; int i, len, first; *vhdl_integer += 1; *vhdl_enum += 1; if (*vhdl_enum > 3){ *vhdl_enum = 0; } *vhdl_real += 1.01; /* rotate the array */ val = mti_GetArrayVarValue(vhdl_array, NULL); len = mti_TickLength(mti_GetVarType(vhdl_array)); first = val[0]; for (i = 0; i < len - 1; i++){ val[i] = val[i+1]; } val[len - 1] = first; } /* Convert a VHDL String array into a NULL terminated string */ static char *get_string(mtiVariableIdT id) { static char buf[1000]; mtiTypeIdT type; int len; mti_GetArrayVarValue(id, buf); type = mti_GetVarType(id); len = mti_TickLength(type); buf[len] = 0; return buf; }Package (pkg) example
The FOREIGN attribute specification links the C functions (declared above) to VHDL procedures (in_params( ) and out_params( )) in pkg.
package pkg is procedure in_params( vhdl_integer : IN integer; vhdl_enum : IN severity_level; vhdl_real : IN real; vhdl_array : IN string); attribute foreign of in_params : procedure is "in_params test.sl"; procedure out_params( vhdl_integer : OUT integer; vhdl_enum : OUT severity_level; vhdl_real : OUT real; vhdl_array : OUT string); attribute foreign of out_params : procedure is "out_params test.sl"; end; package body pkg is procedure in_params( vhdl_integer : IN integer; vhdl_enum : IN severity_level; vhdl_real : IN real; vhdl_array : IN string) is begin report "ERROR: foreign subprogram in_params not called"; end; procedure out_params( vhdl_integer : OUT integer; vhdl_enum : OUT severity_level; vhdl_real : OUT real; vhdl_array : OUT string) is begin report "ERROR: foreign subprogram out_params not called"; end; end;Entity (test) example
The VHDL model test contains calls to procedures (in_params( ) and out_params( )) that are declared in pkg and linked to functions in the C code.
entity test is end test; use work.pkg.all; architecture only of test is begin process variable int : integer := 0; variable enum : severity_level := note; variable r : real := 0.0; variable s : string(1 to 5) := "abcde"; begin for i in 1 to 10 loop in_params(int, enum, r, s); out_params(int, enum, r, s); end loop; wait; end process; end;
![]() Model Technology Inc. Voice: (503) 641-1340 Fax: (503)526-5410 http://www.model.com sales@model.com |
![]() |
![]() |
![]() |
![]() |