2011-02-14 2 views
1

32 비트 바이트 주소 지정 가능 메모리로 간주되는이 IP 조각이 있습니다. 하지만 블록 램을 추론 할 수는 없지만 엄청난 양의 플립 플롭을 추론합니다 ...ISE 자동 추론 램 블록을 충족하기위한 요구 사항은 무엇입니까?

듀얼 포트 블록 램 만있는 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

우선, 표준이 아닌 라이브러리 STD_LOGIC_ARITH 및 STD_LOGIC_UNSIGNED 대신 ieee.NUMERIC_STD.all을 사용하려고합니다. 이유는 다음과 같습니다. http://parallelpoints.com/node/3 – Philippe

+0

IP 차단 마법사를 사용하여 생성 된 IP 블록을 명시 적으로 사용합니다. 이러한 블록을 유추하는 데는 걱정하지 않아도됩니다. 하드 IP 블록의 스위칭 한계에 도달하기 위해 등록 된 입출력을 최적화해야하는 경우 훨씬 더 많은 도움이됩니다. (블록 RAM은 다른 모든 하드 IP 블록과 마찬가지로 가장 빠른 속도로 실행하려면 추가 대기 시간이 필요합니다) – Marcus10110

답변

2

이것은 FPGA 흐름위한 코딩하에 Xilinx Synthesis Guide 설명한다. 나는 리셋 루프로 인해 플립이 유추 될 가능성이 거의 확실하다. 이 코드는 메모리의 모든 요소에 동시에 액세스해야하며 블록 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); 

방법 (인터리브 당신의 초기화의와 함께) 당신이 기능을 사용해야합니다 의미 당신은 그 일을하는이 될하기 위해 신호 선언을 변경해야 초기화하려면 :

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 버전에 대한 정보를 보내주십시오.

관련 문제