【发布时间】:2021-02-13 23:58:32
【问题描述】:
在可综合的 VHDL 设计中,我经常需要做一些“软件”计算来将高级参数 (generics) 转换为低级配置。要进行这些计算,有可用的基本软件工具(例如动态内存分配)很有用。
为了澄清,这种参数转换通常采用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 工作
vcom -2008 top.vhd
vsim work.top
# ** 注: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);
有没有更好的办法?
编辑:针对以下最初的 cmets:
- 上面的示例代码不适用于实际项目中的综合。我专门写了它来说明我想要做的数组大小调整的类型。这是我对一个最小但完整(可编译)的示例的尝试。
- 在这个极其简化的示例中,我并不是在询问是否需要调整数组大小。我关于 VHDL 语言的问题是主要的,而示例则非常次要。如果会分散注意力,请忽略该示例。
- 我的真实例子很复杂(在同一个循环中涉及多个可变长度数组,其长度变化是相互依赖的,并且依赖于深度嵌套的函数调用)。我用 C++ 和 MATLAB 编写的验证模型使用可变大小数组,所以我很确定如果可能的话我也想在 VHDL 中使用可变大小数组。
【问题讨论】:
-
您的示例顶部没有任何动态。依赖于泛型常量(泛型的默认类)的表达式(这里是函数调用)是全局静态的(IEEE Std 1076-2008 9.4.3 全局静态初级),这意味着 internal_config_c 的值是在细化时确定的,而不是在模拟期间确定的.该函数在细化过程中被调用。您在合成过程中收到哪些错误消息?没有任何动态驱动综合的输出端口将不会产生任何逻辑。如果没有更好的例子,您是在描述 XY 问题吗?
-
data.all的大小在每次循环迭代中都在增加——我所说的就是这个大小变化。正如我所说,我的问题不是关于综合。我知道我的玩具示例不会产生任何逻辑。这是故意的——当我对 VHDL 语言有特定的编程问题时,尽量避免关于综合的无关讨论。 Vivado 2020.1 中的合成失败并出现错误“[Synth 8-27] allocator not supported [top.vhd:23]”。我非常有信心这不是 XY 问题。 -
您似乎发现 Vivado 综合不会容忍分配的对象,即使在细化期间调用的函数中也不会为常量声明生成值表达式。支持递归函数调用(UG901,2020.2),综合中新的函数声明风格会发生什么?这表明您不是在询问specific programming problem,而是说它是XY problem。在这里您可以找到长度,然后在不分配或递归的情况下填充向量。
-
递归是我上面已经提供的解决方案。但是,正如我上面所写的,“我很想了解任何替代方案”。如果您有答案,请随时回答问题。
-
唯一的另一种方法是提前知道整个向量的长度,并通过计算切片范围来填充位。这里的递归形式可能是最省力的。 VHDL 没有“动态调整大小”对象。即使对于访问类型,您也需要在创建对象时知道长度。仅供参考 - 空范围位字符串文字可以简单地写为“”。