不使用访问类型的 VHDL 可变长度数组
VHDL variable length arrays without using access types
在可综合的 VHDL 设计中,我经常需要做一些“软件”计算,将高级参数 (generic
s) 转换为低级配置。要进行这些计算,有可用的基本软件工具很有用,例如动态内存分配。
澄清一下,这种参数转换通常采用 function
调用的形式,为某些 constant
赋值,例如:
constant internal_config_c : config_t := calc_low_level_config(params_g);
因此,请注意这个问题纯粹是关于 VHDL“软件”编程(calc_low_level_config
里面的东西)。我的问题不是关于综合(后来使用 internal_config_c
的东西),我只提到综合,因为 Xilinx Vivado 综合不支持 access
类型,这对我来说是最自然的创建方式VHDL 中的动态数组。
因此,我的问题是:VHDL 中有哪些编程结构(除了 access
类型)可用于使用(或模仿)可变大小数组?
我能想到的唯一可能的解决方案是递归。我不喜欢这样,因为我发现递归函数往往非常难读,所以我很想了解任何替代方法。
为了说明,这是一个使用 access
类型的简化但完整的玩具示例:
entity top is
generic (
params_g : integer_vector := (7, 11, 6)
);
end;
architecture rtl of top is
function internal_calculations(x : natural) return bit_vector is
begin
-- Toy example...
if x mod 3 = 2 then
return "1101";
elsif 7*x mod 5 < 3 then
return (x-1 downto 0 => '1');
else
return (3*(x/2)-1 downto 0 => '0');
end if;
end function;
function calc_low_level_config(params : integer_vector) return bit_vector is
type ptr_t is access bit_vector;
variable data : ptr_t := new bit_vector'(0 to -1 => '0');
begin
-- Collect variable-length data
for i in params'range loop
data := new bit_vector'(data.all & internal_calculations(params(i)));
end loop;
-- Print
report to_string(data.all);
return data.all;
end function;
constant internal_config_c : bit_vector := calc_low_level_config(params_g);
begin
end;
在 Modelsim 中对此进行仿真打印出预期结果:
vlib work
vcom -2008 top.vhd
vsim work.top
# ** Note: 0000000001101111111
但是,上述实现无法通过Xilinx Vivado综合。因此,我能想到的唯一可用的选项就是递归,如下图:
function calc_low_level_config(params : integer_vector; idx : integer) return bit_vector is
begin
if idx = params'high then
-- Exit condition
return internal_calculations(params(idx));
else
-- Recurse
return internal_calculations(params(idx)) & calc_low_level_config(params, idx+1);
end if;
end function;
constant internal_config_c : bit_vector := calc_low_level_config(params_g, params_g'low);
有没有更好的方法?
编辑:回应以下最初的评论:
- 上面的示例代码不适用于在真实项目中进行综合。我专门写它来说明我想做的数组大小调整类型。这是我对最小但完整(可编译)示例的尝试。
- 我不是在询问在这个极其简化的示例中是否需要调整数组大小。我关于 VHDL 语言的问题是主要的,这个例子是次要的。如果分散注意力,请忽略该示例。
- 我的真实例子比较复杂(在同一个循环中涉及多个变长数组,其长度变化是相互依赖的,依赖于深度嵌套的函数调用)。我用C++和MATLAB写的验证模型使用的是可变大小数组,所以我很确定如果可能的话我也想在VHDL中使用可变大小数组。
我认为这个问题的最佳答案已经由 Tricky 在上面的评论中提供了:
The only other way would be to know the length of the whole vector in
advance, and populate the bits by working out the slice ranges. The
recursive form here is probably the least effort. VHDL has no "dynamic
sizing" objects. Even for access types you need to know the length
when you create the object.
在可综合的 VHDL 设计中,我经常需要做一些“软件”计算,将高级参数 (generic
s) 转换为低级配置。要进行这些计算,有可用的基本软件工具很有用,例如动态内存分配。
澄清一下,这种参数转换通常采用 function
调用的形式,为某些 constant
赋值,例如:
constant internal_config_c : config_t := calc_low_level_config(params_g);
因此,请注意这个问题纯粹是关于 VHDL“软件”编程(calc_low_level_config
里面的东西)。我的问题不是关于综合(后来使用 internal_config_c
的东西),我只提到综合,因为 Xilinx Vivado 综合不支持 access
类型,这对我来说是最自然的创建方式VHDL 中的动态数组。
因此,我的问题是:VHDL 中有哪些编程结构(除了 access
类型)可用于使用(或模仿)可变大小数组?
我能想到的唯一可能的解决方案是递归。我不喜欢这样,因为我发现递归函数往往非常难读,所以我很想了解任何替代方法。
为了说明,这是一个使用 access
类型的简化但完整的玩具示例:
entity top is
generic (
params_g : integer_vector := (7, 11, 6)
);
end;
architecture rtl of top is
function internal_calculations(x : natural) return bit_vector is
begin
-- Toy example...
if x mod 3 = 2 then
return "1101";
elsif 7*x mod 5 < 3 then
return (x-1 downto 0 => '1');
else
return (3*(x/2)-1 downto 0 => '0');
end if;
end function;
function calc_low_level_config(params : integer_vector) return bit_vector is
type ptr_t is access bit_vector;
variable data : ptr_t := new bit_vector'(0 to -1 => '0');
begin
-- Collect variable-length data
for i in params'range loop
data := new bit_vector'(data.all & internal_calculations(params(i)));
end loop;
-- Print
report to_string(data.all);
return data.all;
end function;
constant internal_config_c : bit_vector := calc_low_level_config(params_g);
begin
end;
在 Modelsim 中对此进行仿真打印出预期结果:
vlib work
vcom -2008 top.vhd
vsim work.top
# ** Note: 0000000001101111111
但是,上述实现无法通过Xilinx Vivado综合。因此,我能想到的唯一可用的选项就是递归,如下图:
function calc_low_level_config(params : integer_vector; idx : integer) return bit_vector is
begin
if idx = params'high then
-- Exit condition
return internal_calculations(params(idx));
else
-- Recurse
return internal_calculations(params(idx)) & calc_low_level_config(params, idx+1);
end if;
end function;
constant internal_config_c : bit_vector := calc_low_level_config(params_g, params_g'low);
有没有更好的方法?
编辑:回应以下最初的评论:
- 上面的示例代码不适用于在真实项目中进行综合。我专门写它来说明我想做的数组大小调整类型。这是我对最小但完整(可编译)示例的尝试。
- 我不是在询问在这个极其简化的示例中是否需要调整数组大小。我关于 VHDL 语言的问题是主要的,这个例子是次要的。如果分散注意力,请忽略该示例。
- 我的真实例子比较复杂(在同一个循环中涉及多个变长数组,其长度变化是相互依赖的,依赖于深度嵌套的函数调用)。我用C++和MATLAB写的验证模型使用的是可变大小数组,所以我很确定如果可能的话我也想在VHDL中使用可变大小数组。
我认为这个问题的最佳答案已经由 Tricky 在上面的评论中提供了:
The only other way would be to know the length of the whole vector in advance, and populate the bits by working out the slice ranges. The recursive form here is probably the least effort. VHDL has no "dynamic sizing" objects. Even for access types you need to know the length when you create the object.