VHPI Applications

Overview

VHPI (VHDL Procedural Interface) provides standard means to access data in VHDL models elaborated and simulated in the simulator. The interface is implemented as a library of C functions, and is intended to meet the VHPI standard being developed by IEEE. VHPI applications must be compiled and linked to a shared library. They can be further bound with VHDL design units and subprograms. To learn how to build VHPI Applications, see Building VHPI Applications. To learn how to use VHPI Applications, see Using VHPI Applications. For a list of supported constructs, see Supported Functions and Objects.

VHPI provides the following functionality:

  • Access to Static VHDL Design Data

    This provides access to behavioral and structural parts of the elaborated model. A user application can, for example, traverse the hierarchy of a VHDL design, fetch properties of VHDL objects or navigate between objects of a specific type. This functionality is valuable for third party tools such as delay calculators or synthesis tools.

  • Access to Dynamic VHDL Objects

    This functionality enables reading and changing values of VHDL objects such as signals or variables. A value can be fetched in a few different formats as described by the VHPI specification. It is also possible to change the format of a fetched value.

  • Simulation Interaction and Control

    The simulation interaction is achieved by registering callbacks to happen for specific conditions. A callback is a communication mechanism between the simulator and the user's C code. A callback can be registered for a variety of reasons, as described by the VHPI standard.

  • Foreign Model Instantiation and Intercommunication Mechanism

    VHPI user applications have to be registered during simulation startup in order to work properly. The registration mechanism uses VHPI foreign architectures, procedures and functions.

Building VHPI Applications

Header Files

The \PLI\Include and \interfaces\include subdirectories of the Active-HDL and Riviera-PRO installation directories, respectively, contain header files that must be included in your PLI application.

#include <vhpi_user.h>
#include <aldecpli.h>

Registering VHPI Applications

Each VHPI library must include at least one function to register VHPI applications. A pointer to this function is located in the vhpi_startup_routines array. The array must be null-terminated. Names of registering functions are arbitrary.

PLI_VOID (*vhpi_startup_routines[])() = {
  startup_1,
  startup_2,
  null
};

Functions that register VHPI applications, such as startup_1 and startup_2, use the standard VHPI function vhpi_register_foreignf(). The vhpi_register_foreignf() function gets a pointer to the vhpiForeignDataT structure as a parameter. The structure specifies how a VHPI function is to be registered.

PLI_VOID startup_1() {
vhpiForeignDataT foreignData = {
              foreignData.kind        = vhpiArchF,
              foreignData.libraryName = "myvhpi",
              foreignData.modelName   = "myvhpitask",
              foreignData.elabf       = elab_arch,
              foreignData.execf       = sim_arch };
  vhpi_register_foreignf(&foreignData);
}

The vhpiForeignDataT structure is defined in the vhpi_user.h header file.

vhpiForeignT kind

The field specifies which VHDL statement will be represented by the VHPI application.

  • vhpiArchF signifies that the VHPI application is an architecture.

  • vhpiProcF signifies that the VHPI application is a procedure.

  • vhpiFuncF signifies that the VHPI application is a function.

char *libraryName

The name of the library containing VHPI routines. If you omit the extension, the default extension is added automatically. If the library cannot be found in the current directory, the locations pointed by the PATH system variable are checked.

char *modelName

The name of the VHPI model that is used to locate a model in the shared library. Note that the same name must be used during registration of the VHPI model on the VHDL side of the interface.

void (*elabf) (const vhpiCbDataT* cbdata)

Specifies an elaboration function name. The null value specifies that no elaboration function is required for the foreign model. When registering a foreign procedure or function, this field should be set to null. When registering a foreign architecture, the field should contain the name of a function associated with the architecture.

void (*execf) (const vhpiCbDataT* cbdata)

Specifies the name of a registered execution function when registering a foreign procedure or function.

NOTE: Foreign architectures can also be registered during elaboration using the -loadvhpi argument for the asim command. In this case, you do not have to register a VHPI application in the C code as it is described above. Note that -loadvhpi argument can be applied only to foreign architectures; it cannot be used for foreign functions nor procedures.

Using VHPI Applications

VHPI applications are registered using the foreign attribute which is declared in the std library in the standard package. A value of the foreign attribute is a string that contains a sequence of identifiers.

attribute foreign of <unit_or_subprogram_name> : architecture is "VHPI <library_name>; <model_name>";
  • VHPI

    The first identifier is always VHPI. It indicates that the foreign model has a VHPI-based implementation.

  • library name

    The name of the library containing VHPI routines. If you omit the extension, the default shared library extension is added. If the library cannot be found in the current directory, the locations pointed by the PATH system variable are checked. The name specified here must match the char *libraryName field in the vhpiForeignDataT structure.

  • model_name

    Identifies a VHPI-based model implementation for a foreign architecture. The name of the string must match the char *modelName field in the vhpiForeignDataT structure.

The foreign models could be defined as follows:

entity test is end;

-- foreign architecture registration
architecture foreign_arch of test is
  attribute foreign of foreign_arch : architecture is "VHPI lib_name; arch";
begin
end;

library ieee;
use ieee.std_logic_1164.all;

entity tb is
end;

architecture tb_arch of tb is
  component test
  end component;

-- foreign procedure registration
procedure proc;
attribute foreign of proc : procedure is "VHPI lib_name; proc";

-- foreign function registration
function func return integer;
attribute foreign of func : function is "VHPI lib_name; func";

signal a : integer := 1;

begin
  uut: test;
  process begin
    a <= func;
    wait for 1 ns;
    proc;
    wait;
  end process;
end;

Example

The following example shows how to set a callback that reacts to writing data to memory. When a memory write is executed, the callback returns a current time, value and memory cell where the data was recorded.

library ieee;

entity top is
end;

architecture top of top is
    procedure callback_event;
        attribute foreign of callback_event: procedure is "VHPI test; test_init";

    type MEM is array ( NATURAL range <> ) of BIT_VECTOR( 7 downto  0 );
    signal memory_var : MEM( 3 downto 0 );

begin
    proc1: process
    begin
        callback_event;

        wait for 1 ps;    memory_var(0) <= "00111000";
        wait for 1 ps;    memory_var(2) <= "10010010";
        wait for 1 ps;    memory_var(3) <= "01101000";
        wait for 1 ps;    memory_var(0) <= "11100110";
        wait for 1 ps;    memory_var(2) <= "00000011";
        wait for 1 ps;    memory_var(3) <= "00110000";

        wait;
    end process;
end;

The memory is represented by the one-dimensional array memory_var of the BIT_VECTOR type. Registering is executed by the callback_event procedure called in the proc1 process. The procedure is a VHPI application that is expected to be localized under the test_init name in the test shared library as it is denoted in the procedure registration. The C++ part of the example is shown below.

#include <fstream>
#include <string>

#include <vhpi_user.h>
#include <aldecpli.h>

std::ofstream file;

PLI_VOID ValueChangeEvent (const struct vhpiCbDataS * cbDatap) {

    vhpiValueT* Value =  cbDatap->value;

    file << vhpi_get_str( vhpiFullNameP, cbDatap->obj ) << "\n";
    file << "    at time   : " << cbDatap->time->low << "\n";
    file << "    has value : " << Value->value.str   << "\n\n";
    file << std::flush;
}

PLI_VOID register_cb ( const struct vhpiCbDataS* cb_p ) {

    vhpiCbDataT      cbDataAction;
    vhpiValueT       *Value;
    vhpiTimeT        *Time;
    file.open("results.txt");

    vhpiHandleT hnd       = vhpi_handle_by_name("top.memory_var", NULL);
    vhpiHandleT hnditr    = vhpi_iterator(vhpiIndexedNames, hnd);

    Value = (vhpiValueT*) malloc ( sizeof(vhpiValueT) );
    Time  = (vhpiTimeT*)  malloc ( sizeof(vhpiTimeT) );

        Value->format            = vhpiStrVal;
        Value->bufSize           = 0;
        Value->value.intgs       = 0;
        cbDataAction.cb_rtn      = ValueChangeEvent;
        cbDataAction.reason      = vhpiCbValueChange;
        cbDataAction.time        = Time;
        cbDataAction.value       = Value;
        cbDataAction.user_data   = NULL;

  while ( vhpiHandleT hndByIdx = vhpi_scan (hnditr) ) {
            cbDataAction.obj         = hndByIdx;
            vhpi_register_cb (&cbDataAction, vhpiReturnCb);
       }
}

// callback registration
PLI_VOID startup_1() {
    vhpiForeignDataT foreignData =  {vhpiProcF, "test.dll", "test_init", NULL, register_cb};
    vhpi_register_foreignf(&foreignData);
}

PLI_VOID (*vhpi_startup_routines[])() = { startup_1, 0L };

The functionality of the VHPI procedure callback_event is defined by the register_cb function. The register_cb function is created on the basis of the VHPI function vhpi_register_cb that describes how the callback is to be registered. The function behavior is specified by the cbDataAction argument of the vhpiCbDataT structure type.

The cb_rtn structure field specifies the callback routine name, that is, the routine to be executed when an event for which the callback was registered occurs. The specified callback routine is ValueChangeEvent. The ValueChangeEvent routine dumps a callback time, name and value of a signal that triggered the callback to the results.txt output file.

The reason field specifies the reason for the callback is executed. It is set to vhpiCbValueChange so that the callback is executed when a value of an object changes. The obj field specifies the handle to the object on which the callback is set. The time and value fields specifies where the event time and the value of the object that triggered a callback are to be written.

The vhpi_register_cb function is called in the while instruction for each element of the top.memory_var array, so after executing of the while instruction the callbacks are set for each array element.

The callback_event procedure registers callbacks at the very beginning of the proc1 process. Therefore, each event occurrence on a memory_var element during the process execution causes a call of the ValueChangeEvent routine. The output file is as follows:

:top:memory_var(0)
    at time   : 1
    has value : 00111000

:top:memory_var(2)
    at time   : 2
    has value : 10010010

:top:memory_var(3)
    at time   : 3
    has value : 01101000

:top:memory_var(0)
    at time   : 4
    has value : 11100110

:top:memory_var(2)
    at time   : 5
    has value : 00000011

:top:memory_var(3)
    at time   : 6
    has value : 00110000

Supported Functions and Objects

The following VHPI functions are supported:

The following VHPI objects are supported:

  • unit

  • variable

  • callback

  • port

  • block

  • signal

  • generate

Non-standard Extensions to VHPI

vhpiLanguageP

The vhpiLanguageP property allows identifying the source language of an object whose handle was passed as an argument to the vhpi_get function.

The value returned by the vhpi_get function for the vhpiLanguageP property can be one of the following constants:

  • vhpiVerilog

  • vhpiVHDL

  • vhpiUndefined

Example (vhpiLanguageP)

#include "vhpi_user.h"
int what_language ( char* path ) {
  vhpiHandleT handle = vhpi_handle_by_name ( path, 0 );
  if ( !handle ) return -1;
  vhpiIntT language = vhpi_get ( vhpiLanguageP, handle );

  switch ( language )
  {
    case vhpiVerilog :   // Verilog
      return 1;
    case vhpiVHDL :      // VHDL
      return 2;
    case vhpiUndefined : // Not known
      return 4;
    default :            // an error
      return -1;
  }
}

The above example shows a VHPI function that checks the source language of an entity whose hierarchical name is given with the path parameter. A handle to the specified object is obtained with the vhpi_handle_by_name function. Then, a value of the vhpiLanguageP property is retrieved with the vhpi_get function. The case statement checks the value of the retrieved property for the source language.

Unsupported VHPI Functionality

The following functionality outlined in the VHPI standard is not supported:

  • Saving and restoring simulation state

  • Retrieving information about the basic type of a subtype

  • Retrieving detailed information regarding declarations in source files (i.e. starting and ending line numbers of entity declarations)

  • Sequential statement objects

The following VHPI functions are not implemented:

  • vhpi_get_data()

  • vhpi_protected_call()

  • vhpi_put_data()

The following VHPI relationships are not supported:

  • vhpiStmts

  • vhpiImmRegion

  • vhpiParamDecls

  • vhpiDepUnits

  • vhpiDrivenSigs

  • vhpiUses

Ask Us a Question
x
Ask Us a Question
x
Captcha ImageReload Captcha
Incorrect data entered.
Thank you! Your question has been submitted. Please allow 1-3 business days for someone to respond to your question.
Internal error occurred. Your question was not submitted. Please contact us using Feedback form.
We use cookies to ensure we give you the best user experience and to provide you with content we believe will be of relevance to you. If you continue to use our site, you consent to our use of cookies. A detailed overview on the use of cookies and other website information is located in our Privacy Policy.