在VHDL中为Xilinx vivado推断2d块RAM

时间:2016-08-18 03:59:44

标签: vhdl ram xilinx

我试图在VHDL中推断出一个2d块ram。但精心设计的电路原来是寄存器和MUX电路。与RAM相关的代码的主文件是:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.shared_resources.all;

entity weight_ram is
    port (clk : in std_logic;
            write_enable : in std_logic;
            row_addr : in natural range 0 to max_NR-1;
            data_in : in neuron_weight_array;
            data_out : out neuron_weight_array);
end weight_ram;

architecture rtl of weight_ram is
    signal ram : weight_ram_array;
begin
    ram_process : process (clk)
        variable f : integer;
    begin
        if (rising_edge (clk)) then
            if (write_enable = '1') then
                for f in 0 to n_feature-1 loop
                    ram (row_addr, f) <= data_in (f);
                end loop;
            end if;
            for f in 0 to n_feature-1 loop
                data_out (f) <= ram (row_addr, f);
            end loop;
        end if;
    end process;
end rtl;

包含常量的文件是:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package shared_resources is
    constant n_feature : integer := 24;
    constant max_NR : integer := 10; -- maximum number of neurons allowed
    constant weightw : integer := 10; -- width of the weight (1:0:9)

    subtype weight_type is signed (weightw-1 downto 0);
    type neuron_weight_array is array (0 to n_feature-1) of weight_type;
    type weight_ram_array is array (0 to max_NR-1, 0 to n_feature-1) of weight_type;
end shared_resources;

如何确保将代码推断为Block RAM?

更新:更新了代码以从2d数组中读取单个元素(基于morten zilmer的答案)。但它仍然没有被推断为Block RAM。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.shared_resources.all;

entity weight_ram is
    port (clk : in std_logic;
            write_enable : in std_logic;
            row_addr : in natural range 0 to max_NR-1;
            col_addr : in natural range 0 to n_feature-1;
            data_in : in weight_type;
            data_out : out weight_type);
end weight_ram;

architecture rtl of weight_ram is
    signal ram : weight_ram_array;
begin
    ram_process : process (clk)
        variable f : integer;
    begin
        if (rising_edge (clk)) then
            if (write_enable = '1') then
                ram (row_addr, col_addr) <= data_in;
            end if;
            data_out <= ram (row_addr, col_addr);
        end if;
    end process;
end rtl;

3 个答案:

答案 0 :(得分:0)

当访问Block RAM时,每个时钟允许在单个地址读取数据字,每个时钟允许在单个地址写入数据字。

在提供的设计中,所有位置都在每个时钟读取,当write_enable = '1'时,所有位置都在每个时钟写入。

因此设计没有实现Block RAM,因此该工具不能使用Block RAM。

答案 1 :(得分:0)

如果您试图推断FPGA中的特定硬件,最好的办法是查看您正在使用的任何设备和/或工具链的综合用户指南。对于Vivado,这是“Vivado Design Suite用户指南:综合(UG901)”。我不会链接到此,因为每个新版本的Vivado都会更改网址,但如果您转到the Xilinx web site并搜索UG901,则最新版本应为最佳结果。

本文档(或Xilinx ISE,Altera Quartus等的等效文档)将包含有关如何推断各种FPGA元素的示例部分,这些部分称为“推理模板”。在这种情况下,第3章有一节“RAM HDL编码指南”,这里有各种推断各种RAM样式的方法的例子,包括你的“单端口Block RAM”的要求。

我会对一些推理模板说一句话,就是他们不使用ieee.numeric_std.all。如果他们使用conv_integer这样的“旧”风格函数,您可以毫无问题地替换numeric_std等效函数(即to_integer)。

回到你的二维数组,你应该通过连接行号和列号来管理它,以便在写入宽度为10的内存时形成一个地址,类似于address <= column & row。< / p>

另一个警告是,如果内存深度很小,这些工具可能会自动将推断的Block RAM转换为分布式RAM。根据我的经验,如果这些工具做到了这一点,那么无论如何它都是最好的,但你可以很容易地看到至少通过打开Vivado中的“Elaborated Design”来推断出“内存块”,并看一下原理图。在此范围内,您应该能够将您的内存绘制为无法展开的单个块。这可以在合成期间使用分布式或块RAM,具体取决于存储器深度。

答案 2 :(得分:0)

此:

subtype weight_type is signed (weightw-1 downto 0);
type weight_ram_array is array (0 to max_NR-1, 0 to n_feature-1) of weight_type;

无法在Xilinx器件上合成BRAM。我假设您正在看到以下消息:&#34;它不会被映射到BRAM,它太稀疏&#34; 或类似。但是,你可以做一个小技巧。如果您想使用单独的 row_addr col_addr 进行地址计算,您可以更改内存并连接以下地址:

architecture rtl of weight_ram is

type my_weight_type_array is array(0 to max_NR*n_feature-1) of weight_type;
signal ram : my_weight_type_array;

signal row_and_col : natural range 0 to max_NR*n_feature-1 ;

begin
    row_and_col <= to_integer(to_unsigned(row_addr,4) & to_unsigned(col_addr,5));                                                                                                                    

    ram_process : process (clk)
        variable f : integer;
    begin
        if (rising_edge (clk)) then
            if (write_enable = '1') then
                ram (row_and_col) <= data_in;
            end if; 
            data_out <= ram (row_and_col);
        end if; 
    end process;
end rtl;

注意:我在过去5年中没有用VHDL编写任何内容,因此您应该模拟它并检查其行为是否正确。特别是这部分:

row_and_col <= to_integer(to_unsigned(row_addr,4) & to_unsigned(col_addr,5));

Ekhm ......强有力的语言......