Search code examples
vhdlmodelsim

Set VHDL foreign attribute based on generic


I'm trying to write VHDL module that calls foreign subprograms and support both the VHDL-2008 VHPI interface and the Modelsim FLI interface. The VHDL-2008 mechanism to tag a foreign subprogram is:

atrribute foreign of some_subprogram : procedure is "VHPI libname;some_subprogram";

But Modelsim's FLI defines it as:

attribute foreign of some_subprogram : procedure is "some_subprogram libname";

I'd like to use the same entity/architecture pair for these since all of the VHDL is identical. All that is different is the foreign subprogram attribute. I've tried something like:

function get_foreign_attribute_string(func_name : in string; libname : in libname) return string;

attribute foreign of some_subprogram : procedure is get_foreign_attribute_string("some_subprogram", "libname");

However Modelsim rejects this saying that the foreign attribute is not a string literal.

I tried pushing the functions into a package, and have the attributes defined in the package body, but it requires that the attribute be attached to the function declaration.

Short of declaring two packages and selectively compiling based on the toolset, I'm not sure how this can be accomplished.

Andy ideas?

Edit: Here's a sample case.

library std; -- for foriegn attribute
use std.all;

entity foo is
  generic
  (
    SIMULATOR : integer range 0 to 1 -- 0 = Modelsim FLI, 1 = VHDL-2008 VHPI
  );
end entity foo;

architecture test of foo is
  function get_foreign_attribute_string(func_name : in string; libname : in string) return string is
  begin
    case SIMULATOR is
      when 0 =>
        return func_name & " " & libname;
      when 1 =>
        return "VHPI " & libname & ";" & func_name;
    end case;
  end function;

  procedure some_subprogram is
  begin
      report "some_subprogram";
  end procedure;
  attribute foreign of some_subprogram : procedure is get_foreign_attribute_string("some_subprogram", "libname");
begin
end architecture test;

Edit: Here's my first cut at a workaround:

library std; -- for foreign attribute
use std.all;

entity foo is
  generic
  (
    SIMULATOR : integer range 0 to 1 -- 0 = Modelsim FLI, 1 = VHDL-2008 VHPI
  );
end entity foo;

architecture test of foo is
  procedure some_subprogram_mti is
  begin
    assert false;
  end procedure some_subprogram_mti;
  attribute foreign of some_subprogram_mti : procedure is "some_subprogram libname";

  procedure some_subprogram_vhpi is
  begin
    assert false;
  end procedure some_subprogram_vhpi;
  attribute foreign of some_subprogram_vhpi : procedure is "VHPI libname;some_subprogram";

  procedure some_subprogram is
  begin
    case SIMULATOR is
      when 0 =>
        some_subprogram_mti;
      when 1 =>
        some_subprogram_vhpi;
    end case;
  end procedure;

begin
end architecture test;

Unfortunately, this too fails since the simulator tries to bind the foreign functions during elaboration. And the _vhpi versions will not bind.


Solution

  • Not really an answer, but too long for a comment:

    This seems to be a special behaviour of the foreign attribute. So, this code works fine on Modelsim:

    entity ATTRIBUTE_TEST is
    end entity ATTRIBUTE_TEST;
    
    architecture ATTRIBUTE_TEST of ATTRIBUTE_TEST is
      function get_foreign_attribute_string(func_name : in string; libname : in string) return string is
      begin
        return func_name & " " & libname;
      end function;
      procedure some_subprogram is
      begin
          report "some_subprogram";
        end procedure;
      attribute not_foreign : string;
      attribute not_foreign of some_subprogram : procedure is get_foreign_attribute_string("some_subprogram", "libname");
    begin
      process
      begin
        report "process";
        wait;
      end process;    
    end architecture ATTRIBUTE_TEST;
    

    Section 14.4.1 of the 1076-2008 states:

    The elaboration of a declarative part consists of the elaboration of the declarative items, if any, in the order in which they are given in the declarative part. This rule holds for all declarative parts, with the following three exceptions:

    ...

    c) A subprogram declarative part whose subprogram is decorated with the 'FOREIGN attribute defined in package STANDARD.

    For these cases, the declarative items are not elaborated; instead, the design entity or subprogram is subject to implementation-dependent elaboration.

    Which seems to be relevant here.