不使用访问类型的 VHDL 可变长度数组

VHDL variable length arrays without using access types

在可综合的 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 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);

有没有更好的方法?

编辑:回应以下最初的评论:

我认为这个问题的最佳答案已经由 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.