2011-02-14 100 views
1

我有这块IP应该是一个32位字节的可寻址内存。但我不能推断块RAM,它推断大量的触发器...为了ISE自动推断内存块,满足哪些要求?

它应该适合于只有双端口块RAM,Spartan3e(xc3s1200e-4fg320),确实是内存分成两个阵列在一个奇数排列...

这是代码,我希望这可能有助于理解我做错了什么?

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 

package mem_types is 
    type memory_t is array (natural range <>) of std_logic_vector(7 downto 0); 
end mem_types; 

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use IEEE.STD_LOGIC_ARITH.ALL; 
use IEEE.STD_LOGIC_UNSIGNED.ALL; 
use work.mem_types.all; 

---- Uncomment the following library declaration if instantiating 
---- any Xilinx primitives in this code. 
--library UNISIM; 
--use UNISIM.VComponents.all; 

entity ram is 
    generic (
     INIT : memory_t(0 to 4095) := (others => (others => '0')) 
    ); 

    port (clk, rst : in std_logic; 
      addr : in std_logic_vector(11 downto 0); 
      din : in std_logic_vector(31 downto 0); 
      dout : out std_logic_vector(31 downto 0); 
      we : std_logic_vector(3 downto 0) 
     ); 
end ram; 

architecture Behavioral of ram is 
    type ramport_t is record 
     addr : std_logic_vector(10 downto 0); 
     dout : std_logic_vector(7 downto 0); 
     din : std_logic_vector(7 downto 0); 
     wea : std_logic; 
    end record; 
    signal port0a, port0b, port1a, port1b : ramport_t; 
    signal addr_a, addr_b, addr_c, addr_d : std_logic_vector(11 downto 0); 
    signal memory0, memory1 : memory_t(0 to 2047); 
begin 

    addr_a <= addr; 
    addr_b <= addr+1; 
    addr_c <= addr+2; 
    addr_d <= addr+3; 

    port0a.addr <= addr_a(11 downto 1) when addr_a(0) = '0' else addr_b(11 downto 1); 
    port1a.addr <= addr_b(11 downto 1) when addr_b(0) = '1' else addr_a(11 downto 1); 
    port0b.addr <= addr_c(11 downto 1) when addr_c(0) = '0' else addr_d(11 downto 1); 
    port1b.addr <= addr_d(11 downto 1) when addr_d(0) = '1' else addr_c(11 downto 1); 

    dout(07 downto 00) <= port0a.dout when addr_a(0) = '0' else port1a.dout; 
    dout(15 downto 08) <= port1a.dout when addr_b(0) = '1' else port0a.dout; 
    dout(23 downto 16) <= port0b.dout when addr_c(0) = '0' else port1b.dout; 
    dout(31 downto 24) <= port1b.dout when addr_d(0) = '1' else port0b.dout; 

    port0a.din <= din(07 downto 00) when addr_a(0) = '0' else din(15 downto 08); 
    port1a.din <= din(15 downto 08) when addr_b(0) = '1' else din(07 downto 00); 
    port0b.din <= din(23 downto 16) when addr_c(0) = '0' else din(31 downto 24); 
    port1b.din <= din(31 downto 24) when addr_d(0) = '1' else din(23 downto 16); 

    port0a.wea <= we(0) when addr_a(0) = '0' else we(1); 
    port1a.wea <= we(1) when addr_b(0) = '1' else we(0); 
    port0b.wea <= we(2) when addr_c(0) = '0' else we(3); 
    port1b.wea <= we(3) when addr_d(0) = '1' else we(2); 

    port0a.dout <= memory0(conv_integer(port0a.addr)); 
    port0b.dout <= memory0(conv_integer(port0b.addr)); 
    port1a.dout <= memory1(conv_integer(port1a.addr)); 
    port1b.dout <= memory1(conv_integer(port1b.addr)); 

    process (clk, rst) 
    begin 
     if rst = '1' then 
      for a in 0 to 2047 loop 
       memory0(a) <= INIT(a*2); 
      end loop; 
     elsif falling_edge(clk) then 
      if (port0a.wea = '1') then 
       memory0(conv_integer(port0a.addr)) <= port0a.din; 
      end if; 

      if (port0b.wea = '1') then 
       memory0(conv_integer(port0b.addr)) <= port0b.din; 
      end if; 
     end if; 
    end process; 

    process (clk, rst) 
    begin 
     if rst = '1' then 
      for a in 0 to 2047 loop 
       memory1(a) <= INIT((a*2)+1); 
      end loop; 
     elsif falling_edge(clk) then 
      if (port1a.wea = '1') then 
       memory1(conv_integer(port1a.addr)) <= port1a.din; 
      end if; 

      if (port1b.wea = '1') then 
       memory1(conv_integer(port1b.addr)) <= port1b.din; 
      end if; 
     end if; 
    end process; 

end Behavioral; 
+1

首先,您可能想要使用ieee.NUMERIC_STD.all而不是非标准库STD_LOGIC_ARITH和STD_LOGIC_UNSIGNED。这解释了为什么:http://parallelpoints.com/node/3 – Philippe 2011-02-14 09:46:40

回答

2

这在Xilinx Synthesis Guide编码为FPGA流说明。我几乎可以肯定,重置循环会导致触发器被推断出来。该代码要求同时访问存储器的所有元素,这对Block RAM是不可能的。

1

你不能做到这一点:

process (clk, rst) 
begin 
    if rst = '1' then 
     for a in 0 to 2047 loop 
      memory0(a) <= INIT(a*2); 
     end loop; 

......作为被要求一个复位内存,而不是初始化之一。

初始化,您需要更改信号的声明是形式

signal memory0 : memory_t(0 to 2047) := (some list of integers or something that returns an array of integers); 

的方式目前你正在做它(与你的init的交错),意味着你将不得不使用功能:

function init_mem(init_values: memory_t) returns memory_t is 
variable retval : memory_t(init_values'high/2)+1 downto 0); 
begin 
    for i in retval'range loop 
     retval(i) := init_values(2*i); 
    end for; 
end function; 

(注意,这是输入了我的头顶,我甚至不试图编译它,所以道歉,对任何拼写错误和语法错误......但我希望你的想法:)

然后您可以使用它来初始化信号:

signal memory0 : memory_t(0 to 2047) := init_mem(INIT); 

这将全部用于仿真。您可能会或可能不会成功推出INIT值的XST合成器 - 我还没有尝试过。检查综合日志文件以查看它所报告的内容 - 请向我们报告它是否正常工作以及您尝试使用哪种版本的XST。

相关问题