【问题标题】:VHDL variable length arrays without using access types不使用访问类型的 VHDL 可变长度数组
【发布时间】: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 没有“动态调整大小”对象。即使对于访问类型,您也需要在创建对象时知道长度。仅供参考 - 空范围位字符串文字可以简单地写为“”。

标签: arrays dynamic vhdl


【解决方案1】:

我认为 Tricky 在上面的 cmets 中提供了这个问题的最佳答案:

唯一的另一种方法是知道整个向量的长度 前进,并通过计算切片范围来填充位。这 这里的递归形式可能是最省力的。 VHDL没有“动态 调整大小”对象。即使对于访问类型,您也需要知道长度 创建对象时。

【讨论】:

    猜你喜欢
    • 2014-06-17
    • 1970-01-01
    • 2021-07-04
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多