【问题标题】:Use of Array Slices in VHDL在 VHDL 中使用数组切片
【发布时间】:2018-05-22 18:18:03
【问题描述】:

我正在尝试设计一个可综合的 VHDL 代码,它使用一些多维数组功能。 RTL 有一个 64 字深的数组(称为 big_array_s,64 x 16 位),用于存储一些初始 LUT 值。还有一个在设计中使用的 4 字深数组(small_array_s,4 x 16 位)。需要将大数组的一部分分配到小数组中。在下面的sn-ps代码中进行了说明。

type small_array is array (0 to 3) of bit_vector(15 downto 0);
type big_array is array (0 to 64) of bit_vector(15 downto 0);

signal small_array_s : small_array;
signal big_array_s : big_array := init_array_func("test.dat");

init_array_func() 是一个 VHDL 函数,它使用“test.dat”ascii 文件中的数据初始化 big_array_s。我被卡住的部分是将 big_array_s 的一部分分配给 small_array_s。例如,

small_array_s  <= big_array_s(0 to 3);

是我需要通过 RTL 实现的目标。但是这种直接赋值是不可能的,因为 LHS 和 RHS 是不同的数组类型。 我的问题是如何在 VHDL 中实现这种数组切片?


我可以使用的另一种方法是将 big_array 类型声明为 small_array 的数组。例如,

type small_array is array (0 to 3) of bit_vector(15 downto 0);
type big_array is array (0 to 15) of small_array;

signal small_array_s : small_array;
signal big_array_s : big_array;

在这种情况下,声明

small_array_s  <= big_array_s(0);

会很顺利。但是考虑到综合支持,我对如何初始化数组big_array_s持怀疑态度。

【问题讨论】:

  • 它不是 3D 数组。那将是type three_dee is array(0 to 15, 0 to 3, 15 downto 0) of bit。相反,您正在描述一个锯齿状的数组:数组的数组。
  • 我同意你的观点。这是我的失误。

标签: arrays vhdl fpga


【解决方案1】:

您的问题中没有声明多维 (3D) 数组类型。您的 big_array 的第二个声明有一个索引。

IEEE 标准 1976-2008

5.3.2 数组类型
5.3.2.1 概述

一个数组对象的特征是索引的数量(数组的维数);每个索引的类型、位置和范围;以及元素的类型和可能的约束。指数的顺序很重要。

一维数组对于每个可能的索引值都有一个不同的元素。多维数组对于每个可能的索引值序列都有一个不同的元素,可以通过为每个索引(按给定顺序)选择一个值来形成。给定索引的可能值是属于相应范围的所有值;此值范围称为索引范围

对于您的第一个方法,您可以声明子类型而不是独立类型。结果是它们是同一类型。

这样做没有风险,在 VHDL 中分配需要在右侧表达式中为左侧目标中的每个元素匹配一个匹配元素。元素数量不匹配的代码可以分析和详细说明,但会导致运行时错误报告边界不匹配(并且需要综合以遵守 VHDL 语义)。

为您的第一个 sn-p 创建一个有效的 Minimal, Complete and Verifiable example 看起来像这样:

entity some_array is
end entity;

architecture fuu of some_array is
    -- type small_array is array (0 to 3) of bit_vector(15 downto 0);
    -- type big_array is array (0 to 64) of bit_vector(15 downto 0);
    type some_array is array (natural range <>) of bit_vector(15 downto 0);
    subtype small_array is some_array(0 to 3);
    subtype big_array is some_array (0 to 64);

    impure function init_array_func (init_file:  in string) return 
             big_array is
        use std.textio.all;
        file big_array_file: text is in init_file;
        variable file_line:         line;
        variable big_array_val:     big_array;
    begin
        for i in big_array'range  loop
            readline (big_array_file, file_line);
            read (file_line, big_array_val(i));
        end loop;
        return big_array_val;
    end function;

    function to_string (inp: bit_vector) return string is
        variable image_str: string (1 to inp'length);
        alias input_str:  bit_vector (1 to inp'length) is inp;
        begin
        for i in input_str'range loop
            image_str(i) := character'VALUE(bit'IMAGE(input_str(i)));
        end loop;
        return image_str;
    end function;

    signal small_array_s : small_array;
    signal big_array_s : big_array := init_array_func("test.dat");

begin
    small_array_s  <= big_array_s(0 to 3);

MONITOR:
    process
    begin
        wait on small_array_s;
        wait for 0 ns; -- not the default value;
        for i in small_array_s'range loop
            report "small_array_s(" & integer'image(i) & ") = " &
                    to_string(small_array_s(i));
        end loop;
    end process;

end architecture;

这给出了:

ghdl -r some_array
some_array.vhdl:47:13:@0ms:(报告说明): small_array_s(0) = 0000000000000000
some_array.vhdl:47:13:@0ms:(报告 注意):small_array_s(1) = 0000000000000001
some_array.vhdl:47:13:@0ms:(报告说明): small_array_s(2) = 0000000000000010
some_array.vhdl:47:13:@0ms:(报告说明): small_array_s(3) = 0000000000000011

这正确显示了前四个值初始化为已知 test.dat 内容的信号 big_array_s。

这些函数与 -2008 年之前的 VHDL 标准版本兼容,并且可以从其他示例中剪切、粘贴和编辑。

请注意,init_array_func 函数需要一个 test.dat 文件,其中包含至少 65 行 big_array 元素的有效值,并且可以通过传递 big_array 元素的数量(长度)来泛化这样的函数,返回值some_array 的任意子类型。

您还可以在具有相同维度(索引数)的数组类型与密切相关的元素类型之间进行显式类型转换:

9.3.6 类型转换

允许在密切相关的类型之间进行显式类型转换。特别是,类型与自身密切相关。其他类型仅在以下条件下密切相关:

...
— 数组类型——两个数组类型密切相关当且仅当类型具有相同的维度并且元素类型密切相关

注意,数组类型的元素类型必须遵守相同的要求,因为它是元素(一个子元素,这里是类型位)。

使用没有子类型声明的原始类型声明,唯一的其他变化就是赋值:

small_array_s  <= small_array(big_array_s(0 to 3));

其中类型转换操作数表达式 big_array_s(0 to 3) 与 small_array_s 维数相同,且元素类型密切相关(均为 bit_vector(15 downto 0))。

通过这些更改,上面的代码分析、阐述和模拟了相同的结果。

请注意,类型转换还依赖于赋值语义,以确保赋值目标和右侧表达式的匹配元素:

14.7.3.4 信号更新

为了在给定的仿真周期内更新信号,内核进程首先确定该信号的驱动值和有效值。然后内核进程用新确定的驱动值更新包含驱动值的变量。内核也会用新确定的有效值更新包含信号当前值的变量,如下:

...
b) 如果 S 是复合信号(包括数组的切片),则 S 的有效值隐式转换为 S 的子类型。子类型转换检查 S 的每个元素在有效值中是否存在匹配元素反之亦然。如果此检查失败,则会发生错误。然后将这个子类型转换的结果赋给代表 S 的当前值的变量。

关于子类型转换的一点意味着索引范围不必匹配,表达式和目标必须有匹配的元素。

【讨论】:

  • 答案很明确。小型和大型数组类型的子类型的使用并没有引起我的注意。我确实想过从 big_array 类型创建一个子类型,但 vhdl 不允许这样做。类型转换方法也是一种很好的方法。我希望它是可合成的。
【解决方案2】:

要进行数组切片,您可以使用 generate 语句一次复制一个 bit_vector(15 downto 0)。

关于 3D 阵列,我在使用 Xilinx Vivado 进行合成时体验不佳。 Vivado 将其识别为 3D 数组,告诉您它不受支持并实现了一堆寄存器。

【讨论】:

  • 如果我初始化一个数组并将其用作查找表,即我只是从中读取值,而不向其中写入任何内容,它会消耗任何寄存器或触发器资源吗?
猜你喜欢
  • 1970-01-01
  • 2012-05-09
  • 2014-06-10
  • 2014-12-07
  • 2012-11-10
  • 2019-02-21
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多