繁体   English   中英

如何在VHDL-2008或更高版本中模拟C ++类

[英]How to emulating C++ classes in VHDL-2008 or above

有没有一种方法可以仅使用VHDL函数和VHDL记录来模拟VHDL-2008中C ++类的数据封装功能? 我已经看到这种类型的事情用“ c”之类的语言完成过很多次,但对于VHDL却很少。

具体来说,我想将所有类数据公开给类的每个方法,只是为了保持简单。

示例C ++:

class item_t {
   public:
       uint32_t addr;
       uint32_t data;
       bool     valid;
};

class keeper_t {
    public:
        item_t data[100];
        void     put(uint32_t addr, uint32_t data);
        uint32_t get(uint32_t addr);
};

我对如何在VHDL中模拟上面的代码的想法是创建一条记录来保存类数据,并在每次保存类状态时将其传递到每个函数中。 我在VHDL中使用此技术的问题是,如何修改传递给函数的“类”数据结构? 当涉及到将结构返回到调用过程时,VHDL实际上非常有限。 例:

library ieee;
use ieee.std_logic_1164.all;

--------------------------------------------------
package ADT is

  constant A_OK        :integer := 0;
  constant max_keepers :natural := 100;

  type keeper_item_t is record
    addr     :std_logic_vector(31 downto 0);
    data     :std_logic_vector(31 downto 0);
    valid    :std_logic;
  end record;  

  type keeper_t is array (0 to max_keepers) of keeper_item_t;

  function keeper_new return keeper_t;
  function keeper_add(signal k :inout keeper_t) return integer;
  function keeper_get(signal k :inout keeper_t; signal kitem: out keeper_item_t) return integer;

end package ADT;

--------------------------------------------------
package body ADT is

  function keeper_new return keeper_t is
      variable rkeeper :keeper_t;
  begin
      rkeeper(0).addr  <= X"AABBCCDD";
      rkeeper(0).data  <= X"10101010";
      rkeeper(0).valid <= '0';
      return rkeeper;
  end function;

  function keeper_add(signal k :inout keeper_t) return integer is
  begin
      k(0).addr  <= X"12345678";
      k(0).data  <= X"BEEF1234";
      k(0).valid <= '1';
      return A_OK;
  end function;

  function keeper_get(signal k :inout keeper_t; signal kitem: out keeper_item_t) return integer is
    variable kitem: keeper_item_t;
  begin
      kitem := k(0);
      return A_OK;
  end function;

end package body;

--------------------------------------------------
entity testbench is
end entity;

--------------------------------------------------
architecture sim of testbench is
begin

process
    variable kp :keeper_t;
    variable ki :keeper_item_t;
    variable ok :integer;
begin
        kp := keeper_new;   
    ok := keeper_put(kp);
    ki := keeper_get(kp);       
    wait;
end process;

end architecture;

上面的VHDL代码未编译并生成以下语法错误:

--line:20:  function keeper_get(signal k :inout keeper_t; signal kitem: out 
keeper.vhd:20:30: mode of a function parameter cannot be inout or out
keeper.vhd:21:30: mode of a function parameter cannot be inout or out
keeper.vhd:21:56: mode of a function parameter cannot be inout or out

为了解决这个问题,我想我需要传递一个VHDL“访问指针”而不是keeper_t结构本身。 如果我这样做,那么我将一个只读指针传递给该函数,该指针又指向可以修改的实际数据结构?

    type Keeper_Ptr_t is access keeper_t;

    --Dereferencing a VHDL Access Type: The suffix .all is 
    --  used to de-reference a pointer, i.e. it gives 
    --  you the thing pointed to by the pointer.

所以我也尝试使用访问类型的这种方法:

library ieee;
use ieee.std_logic_1164.all;

--------------------------------------------------
package ADT is

  constant A_OK        :integer := 0;
  constant max_keepers :natural := 100;

  type keeper_item_t is record
    addr     :std_logic_vector(31 downto 0);
    data     :std_logic_vector(31 downto 0);
    valid    :std_logic;
  end record;  

  type keeper_t is array (0 to max_keepers) of keeper_item_t;

  type keeper_ptr_t is access keeper_t;

  function keeper_new return keeper_t;
  function keeper_add(kp: keeper_ptr_t) return integer;
  function keeper_get(kp: keeper_ptr_t) return keeper_item_t;

end package ADT;

--------------------------------------------------
package body ADT is

  function keeper_new return keeper_t is
      variable rkeeper :keeper_t;
  begin
      rkeeper(0).addr  <= X"AABBCCDD";
      rkeeper(0).data  <= X"10101010";
      rkeeper(0).valid <= '0';
      return rkeeper;
  end function;

  function keeper_add(kp: keeper_ptr_t) return integer is
  begin
      kp.all(0).addr  <= X"12345678";
      kp.all(0).data  <= X"BEEF1234";
      kp.all(0).valid <= '1';
      return A_OK;
  end function;

  function keeper_get(kp: keeper_ptr_t) return keeper_item_t is
  begin
      return kp.all(0);
  end function;

end package body;

--------------------------------------------------
entity testbench is
end entity;

--------------------------------------------------
architecture sim of testbench is
begin

process
    variable kp :keeper_t;
    variable ki :keeper_item_t;
    variable ok :integer;
begin
    kp := keeper_new;   
    ok := keeper_put(kp);
    ki := keeper_get(kp);       
    wait;
end process;

end architecture;

该版本失败,并显示以下错误:

keeper.vhd:22:23: type of constant interface "kp" cannot be access type "keeper_ptr_t"
keeper.vhd:23:23: type of constant interface "kp" cannot be access type "keeper_ptr_t"

您还希望研究vhdl 2002中的受保护类型。它们与类相似,因为它们可以具有带有内部变量的成员函数和过程。 vhdl 2008中存在一些限制,例如无法传入/传出访问类型,orc拥有它们的数组(均已在vhdl 2019中修复)。 但是仍然有可能构建队列或随机分组生成器之类的东西。

Type pt is protected
  Procedure add_one;
  Function get_val return integer;
End protected pt;

Type pt is protected body
  Variable x : integer;

  Procedure add_one is
  Begin
   X := x + 1;
  End  procedure;

  Function get_val return integer is
  Begin
    Return x;
  End function get_val;
End protected body pt;

.....

Process
  Variable ptv : pt;
Begin
  Ptv.add_one;
  Ptv.add_one;

  Report to_string(ptv.get_val);
  Wait;
End process;

OSVVM是一个很好的示例,它广泛使用了受保护的类型(通常是2008年的功能)。

我从中学到的是:

(1)将记录的访问指针作为“变量”类型传递给过程。 并且不要将函数用于类方法。

(2)使用“不纯函数”为“类”创建新方法,使用“ new”关键字返回新分配的记录。

您实际上可以做得更好。 VUnit已实现了引用,其作用类似于指针,但是常量。 使用常量,您可以做的事情没有任何限制。 您可以将它们与函数一起使用,可以从中构建数组,可以不受限制地共享它们,也可以将它们包含在泛型等中。一个示例是使用基本integer_vector_ptr_t类型构建的整数数组 它可以作为有关如何构建自己的类型的示例。 还有其他基于相同原理构建的数据类型,例如队列字典

VHDL-2019将解决一些受保护类型的问题,但它们不如常量灵活。 VUnit中的引用甚至可以与VHDL-93一起使用。

您可以在此处了解更多信息。

免责声明:我是作者之一。

这是可能的!

我从中学到的是:

(1)将记录的访问指针作为“变量”类型传递给过程。 并且不要将函数用于类方法。

(2)使用“不纯函数”为“类”创建新方法,使用“ new”关键字返回新分配的记录。


library ieee;
use ieee.std_logic_1164.all;

--------------------------------------------------
package ADT is

  constant A_OK        :integer := 0;
  constant max_keepers :natural := 100;

  type keeper_item_t is record
    addr     :std_logic_vector(31 downto 0);
    data     :std_logic_vector(31 downto 0);
    valid    :std_logic;
  end record;  

  type keeper_t is array (0 to max_keepers) of keeper_item_t;

  type keeper_ptr_t is access keeper_t;

  impure function keeper_new return keeper_ptr_t;
  procedure keeper_add(variable kp: inout keeper_ptr_t);
  procedure keeper_get(variable kp: inout keeper_ptr_t; variable item: out keeper_item_t);

end package ADT;

--------------------------------------------------
package body ADT is

    impure function keeper_new return keeper_ptr_t is
        variable kp : keeper_ptr_t;
    begin
        kp := new keeper_t;
        kp.all(0).addr  := X"AABBCCDD";
        kp.all(0).data  := X"10101010";
        kp.all(0).valid := '0';
        return kp;
    end function;

    procedure keeper_add(variable kp: inout keeper_ptr_t) is
    begin
        kp.all(0).addr  := X"12345678";
        kp.all(0).data  := X"BEEF1234";
        kp.all(0).valid := '1';
    end procedure;

    procedure keeper_get(variable kp: inout keeper_ptr_t; variable item: out keeper_item_t) is
    begin
        item := kp.all(0);
    end procedure;

end package body;

use work.ADT.all;

--------------------------------------------------
entity testbench is
end entity;

--------------------------------------------------
architecture sim of testbench is
begin

process
    variable km :keeper_t;
    variable kp :keeper_ptr_t;
    variable ki :keeper_item_t;
    variable ok :integer;
begin
    kp := keeper_new;
    keeper_add(kp);
    keeper_get(kp, ki);     
    wait;
end process;

end architecture;

使用VHDL和访问指针模拟的类的另一个示例:

-- Behavorial Fifo for use in testbench
--------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

--------------------------------------------------
package pkg_simfifo is
    subtype uint32_t is unsigned(31 downto 0);

    constant max_simfifos :natural := 100;

    type simfifo_item_t is record
       addr     :std_logic_vector(31 downto 0);
       data     :std_logic_vector(31 downto 0);
       valid    :std_logic;
    end record;  

    type simfifo_array_t is array (0 to max_simfifos) of simfifo_item_t;

    type simfifo_class_t is record
        karray :simfifo_array_t;
        count  :integer;
    end record;

    type simfifo_ptr_t is access simfifo_class_t;

    impure function simfifo_new return simfifo_ptr_t;

    procedure simfifo_purge(
        variable that :inout  simfifo_ptr_t
    );

    -- Push Onto Fifo
    procedure simfifo_push(
        variable that :inout  simfifo_ptr_t;
                 addr :in     std_logic_vector(31 downto 0);
                 data :in     std_logic_vector(31 downto 0);        
        variable ok   :out    std_logic
    );
    procedure simfifo_push(
        variable that :inout  simfifo_ptr_t;
                 addr :in     unsigned(31 downto 0);
                 data :in     unsigned(31 downto 0);
        variable ok   :out    std_logic
    );

    -- Pop from Fifo
    procedure simfifo_pop(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    std_logic_vector(31 downto 0);
        variable data  :out    std_logic_vector(31 downto 0);
        variable valid :out    std_logic
    );
    procedure simfifo_pop(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    unsigned(31 downto 0);
        variable data  :out    unsigned(31 downto 0);
        variable valid :out    std_logic
    );

    -- Peak without Popping
    procedure simfifo_peek(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    std_logic_vector(31 downto 0);
        variable data  :out    std_logic_vector(31 downto 0);
        variable valid :out    std_logic
    );

    -- Peak without Popping
    procedure simfifo_peek(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    unsigned(31 downto 0);
        variable data  :out    unsigned(31 downto 0);
        variable valid :out    std_logic
    );

    procedure simfifo_get_count(
        variable that  :inout  simfifo_ptr_t; 
                 count :out    integer
    );

end package;

--------------------------------------------------
package body pkg_simfifo is

    impure function simfifo_new return simfifo_ptr_t is
        variable that : simfifo_ptr_t;
    begin
        that := new simfifo_class_t;
        simfifo_purge(that);        
        return that;
    end function;

    procedure simfifo_purge(
        variable that   :inout  simfifo_ptr_t
    ) is
    begin        
        that.all.count := 0;                

        for i in 0 to max_simfifos loop
            that.all.karray(0).addr  := (others => '0');
            that.all.karray(0).data  := (others => 'X');
            that.all.karray(0).valid := '0';
        end loop;

    end procedure;

    -- Push Onto Fifo
    procedure simfifo_push(
        variable that :inout  simfifo_ptr_t;
                 addr :in     std_logic_vector(31 downto 0);
                 data :in     std_logic_vector(31 downto 0);        
        variable ok   :out    std_logic
    ) is  
        variable i    :integer;
    begin

        --insert address at end of array
        if (that.all.count < max_simfifos) then
             i := that.all.count;
            that.all.karray(i).addr  := addr;
            that.all.karray(i).data  := data;
            that.all.karray(i).valid := '1';
            that.all.count := that.all.count + 1;
            ok := '1';
            return;
        end if;

        -- no more space in array
        ok := '0';
        return;        
    end procedure;

    -- Push Onto Fifo
    procedure simfifo_push(
        variable that :inout  simfifo_ptr_t;
                 addr :in     unsigned(31 downto 0);
                 data :in     unsigned(31 downto 0);
        variable ok   :out    std_logic
    ) is
        variable slv_addr :std_logic_vector(31 downto 0);
        variable slv_data :std_logic_vector(31 downto 0);        
    begin
        simfifo_push(
            that, 
            std_logic_vector(addr),
            std_logic_vector(data),
            ok
        );
        return;        
    end procedure;


    -- Pop from Fifo
    procedure simfifo_pop(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    std_logic_vector(31 downto 0);
        variable data  :out    std_logic_vector(31 downto 0);
        variable valid :out    std_logic
    ) is
    begin
        addr   := that.all.karray(0).addr;
        data   := that.all.karray(0).data;
        valid  := that.all.karray(0).valid;

        -- Shift Down
        for i in 0 to max_simfifos-1 loop
            --report "max_simfifos" & integer'image(max_simfifos) & " i:" & integer'image(i) & " i+1:" & integer'image(i+1);
            that.all.karray(i) := that.all.karray(i+1);
            if (that.all.karray(i+1).valid = '0') then
                exit;
            end if;            
        end loop;
        that.all.karray(max_simfifos-1).valid := '0';
        that.all.karray(max_simfifos-1).data  := (others => 'X');
        that.all.karray(max_simfifos-1).addr  := (others => 'X');


        if (that.all.count /= 0) then
            that.all.count := that.all.count - 1;
        end if;

    end procedure;

    -- Pop from Fifo
    procedure simfifo_pop(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    unsigned(31 downto 0);
        variable data  :out    unsigned(31 downto 0);
        variable valid :out    std_logic
    ) is
        variable slv_addr :std_logic_vector(31 downto 0);
        variable slv_data :std_logic_vector(31 downto 0);
    begin
        simfifo_pop(
            that,
            slv_addr,
            slv_data,
            valid
        );

        addr := unsigned(slv_addr);    
        data := unsigned(slv_data);
    end procedure;

    -- Peek from Fifo
    procedure simfifo_peek(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    std_logic_vector(31 downto 0);
        variable data  :out    std_logic_vector(31 downto 0);
        variable valid :out    std_logic
    ) is
    begin
        addr   := that.all.karray(0).addr;
        data   := that.all.karray(0).data;
        valid  := that.all.karray(0).valid;
    end procedure;

    -- Pop from Fifo
    procedure simfifo_peek(
        variable that  :inout  simfifo_ptr_t; 
        variable addr  :out    unsigned(31 downto 0);
        variable data  :out    unsigned(31 downto 0);
        variable valid :out    std_logic
    ) is
        variable slv_addr :std_logic_vector(31 downto 0);
        variable slv_data :std_logic_vector(31 downto 0);
    begin
        simfifo_peek(
            that,
            slv_addr,
            slv_data,
            valid
        );

        addr := unsigned(slv_addr);
        data := unsigned(slv_addr);
    end procedure;

    -- Peek from Fif    
    procedure simfifo_get_count(
        variable that  :inout  simfifo_ptr_t; 
                 count :out    integer
    ) is
    begin
        count := that.all.count;
    end procedure;

end package body;

--library ieee;
--use ieee.std_logic_1164.all;
--use work.pkg_simfifo.all;
--
----------------------------------------------------
--entity testbench is
--end entity;
--
----------------------------------------------------
--architecture sim of testbench is
--begin
--
--process
--  variable that   :simfifo_ptr_t;
--    variable wvalid :std_logic;
--    variable raddr  :std_logic_vector(31 downto 0);
--    variable rdata  :std_logic_vector(31 downto 0);
--    variable rvalid :std_logic;
--begin
--    that := simfifo_new;
--    
--    simfifo_push  (that, X"10102323", X"AAAABBBB", wvalid);
--    simfifo_push  (that, X"10102334", X"EEEECCCC", wvalid);
--    
--    simfifo_pop   (that, raddr, rdata, rvalid);        
--    report "pop: " & to_hstring(rdata);
--    
--    simfifo_pop   (that, raddr, rdata, rvalid);        
--    report "pop: " & to_hstring(rdata);
--    
--    simfifo_pop   (that, raddr, rdata, rvalid);        
--    report "pop: " & to_hstring(rdata);
--    
--    wait;
--end process;
--
--end architecture;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM