首页 > 解决方案 > 不使用访问类型的 VHDL 可变长度数组

问题描述

在可综合的 VHDL 设计中,我经常需要做一些“软件”计算来将高级参数 ( generics) 转换为低级配置。要进行这些计算,有可用的基本软件工具很有用,例如动态内存分配。

澄清一下,这种参数转换通常采用function为 some 赋值的调用形式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
# ** 注: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);

有没有更好的办法?

编辑:针对以下最初的评论:

标签: arraysdynamicvhdl

解决方案


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

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


推荐阅读