Table of Contents Previous page Next page Index

ModelSim

Model Technology Inc.


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.


Parameters of class
CONSTANT OR VARIABLE
Parameters of class SIGNAL
VHDL Type
IN
INOUT/OUT
IN
Integer
int
int *
mtiSignalIdT
Enumeration
int
char * if <= 256 values
int * if > 256 values
mtiSignalIdT
Real
double *
double *
mtiSignalIdT
Time
mtiTime64T *
mtiTime64T *
mtiSignalIdT
Array
mtiVariableIdT
mtiVariableIdT
mtiVariableIdT
Record
mtiVariableIdT
mtiVariableIdT
mtiVariableIdT
File
-- Not supported --
Access Integer
int
int *
-- Not supported --
Access Enumeration
int
int *
-- Not supported --
Access Real
double *
double *
-- Not supported --
Access Array
mtiVariableIdT
mtiVariableIdT
-- Not supported --
Access File
-- Not supported --
Access Record
-- Not supported --

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 --

1
On 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
TOC PREV NEXT INDEX

ModelSim