2016-08-18 96 views
0

我试图推断VHDL二维块RAM。但详细的电路原来是寄存器和MUX的电路。对于有关RAM中的代码的主要文件是:推断2D块RAM赛灵思vivado

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; 

我怎样才能确保代码被推断为一个块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; 
+0

你或许应该尝试使用一维数组。内存推断是棘手的。如果您没有完全遵守供应商模板,则合成器无法达到您想要的效果。 –

回答

0

当访问一个块RAM,则每个时钟允许数据字的读出在单个地址,并且每个时钟允许在一个单一地址的数据字的写入。

在提供的设计中,每个时钟都读取所有位置,然后在每个时钟写入所有位置。

这样的设计没有实现的块RAM和工具,因此不能使用块RAM。

+0

即使我尝试读取RAM中的单个元素,该电路仍然不会被推断为块RAM。我在上面的问题中添加了更新后的电路 – user3575732

+0

该工具可以使用Block RAM或分布式FF和多路复用器实现设计,因为这允许根据约束进行优化。如果由于某种原因你真的想要一个块RAM,那么直接实例化它。 –

0

如果您试图推断FPGA中的特定硬件,最好的方法是查看您正在使用的任何设备和/或工具链的综合用户指南。对于Vivado,这是“Vivado Design Suite用户指南:综合(UG901)”。我不会链接到这个网址,因为随着Vivado的每个新版本URL的变化,但如果你去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行。

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

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。我假设你看到如下消息:“它不会映射到BRAM,它太稀疏”或类似。然而,你可以做一个小窍门。如果要使用单独的ROW_ADDRCOL_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; 

注:VHDL为过去5年,所以我没有写任何东西你应该模拟它并检查它的行为是否正确。特别是这部分:

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

Ekhm ...强类型语言...

+0

'row_and_col <=((2 ** 5)* row_addr)+ col_addr;'?我看到的大多数长链类型转换都很容易避免。 –

+0

@scary_jeff是的,这应该做的工作。 –