[英]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.