]> rtime.felk.cvut.cz Git - fpga/openmsp430.git/commitdiff
Add custom generics RAM.
authorVladimir Burian <buriavl2@fel.cvut.cz>
Thu, 10 Mar 2011 12:29:28 +0000 (13:29 +0100)
committerVladimir Burian <buriavl2@fel.cvut.cz>
Thu, 10 Mar 2011 12:29:28 +0000 (13:29 +0100)
This generics entity produces array of block RAM primitives with
appropriate address and data decoders. The naming convention of
block RAM primitives is defined and it's simply to write correct
*.bmm file.

memory/ram_generic.vhd [new file with mode: 0644]

diff --git a/memory/ram_generic.vhd b/memory/ram_generic.vhd
new file mode 100644 (file)
index 0000000..f1570d2
--- /dev/null
@@ -0,0 +1,278 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+library UNISIM;
+use UNISIM.vcomponents.all;
+
+--------------------------------------------------------------------------------
+-- Generator of synchronous memory with generic size and width of address and
+-- data buses made up of RAMB primitives.
+--
+-- There is no special relation between SIZE and ADDR_WIDTH parameters. Both
+-- values are independent of each other.
+--
+-- Currently basic building element are: RAMB16_S9, RAMB_S4 and RAMB_S2
+-- primitives (which are preset at least in Virtex-II/II-Pro and Spartan-3/3E
+-- devices). If your device doesn't contain one of these memory primitives, the
+-- only thing you have to do is to add simple generate statement of your
+-- primitive into the BLOCKS statement and add record about this new memory
+-- primitive to the BRAM_TYPE_ARRAY.
+--
+-- Resulting memory is composed of regular array of one memory primitive type
+-- which must be specified by BRAM_TYPE generic parameter. One iteration of
+-- BLOCKS generate statement produces one row in memory array which is called
+-- BLOCK. One iteration of generate statement in BLOCKS (named after memory
+-- primitive) produces one memory primitive in memory array.
+--
+-- Input ports "we" and "din" have default zero values. So it's not required
+-- to connect them.
+--
+--
+-- Memory primitives naming convention is following:
+--
+-- <path to component>/BLOCKS[<row num>].<mem primitive name>.B[<col num>].BRAM
+--
+-- Higher data bits -> higher <col num>
+-- Higher address   -> higher <row num>
+-- <mem primitive name> is name specified in BRAM_TYPE parameter.
+--
+--
+-- Example of Block RAM Memory Map (*.bmm) file:
+--
+--      // ram_generic: SIZE=16kB, WIDTH=8b, BRAM_TYPE=RAMB16_S2
+--      ADDRESS_SPACE blockrom RAMB16 [0x0000:0x3fff]
+--        BUS_BLOCK
+--            <path>/BLOCKS[0].RAMB16_S2.B[3].BRAM [7:6];
+--            <path>/BLOCKS[0].RAMB16_S2.B[2].BRAM [5:4];
+--            <path>/BLOCKS[0].RAMB16_S2.B[1].BRAM [3:2];
+--            <path>/BLOCKS[0].RAMB16_S2.B[0].BRAM [1:0];
+--        END_BUS_BLOCK;
+--        BUS_BLOCK
+--            <path>/BLOCKS[1].RAMB16_S2.B[3].BRAM [7:6];
+--            <path>/BLOCKS[1].RAMB16_S2.B[2].BRAM [5:4];
+--            <path>/BLOCKS[1].RAMB16_S2.B[1].BRAM [3:2];
+--            <path>/BLOCKS[1].RAMB16_S2.B[0].BRAM [1:0];
+--        END_BUS_BLOCK;
+--      END_ADDRESS_SPACE;
+--------------------------------------------------------------------------------
+
+entity ram_generic is
+  generic (
+    BRAM_TYPE  : string  := "RAMB16_S9";  -- Memory primitive used
+    SIZE       : integer := 8*1024;       -- Physical size in bytes
+    ADDR_WIDTH : integer := 16;           -- Width of address port
+    DATA_WIDTH : integer := 8;            -- Width of data port
+    NEG_EN     : boolean := false;        -- Low active "enable"
+    NEG_WE     : boolean := false);       -- Low active "write enable"
+  port (
+    clk  : in  std_logic;
+    addr : in  std_logic_vector (ADDR_WIDTH-1 downto 0);
+    en   : in  std_logic;
+    we   : in  std_logic                                := '0';
+    din  : in  std_logic_vector (DATA_WIDTH-1 downto 0) := conv_std_logic_vector(0, DATA_WIDTH);
+    dout : out std_logic_vector (DATA_WIDTH-1 downto 0));
+end entity ram_generic;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of ram_generic is
+
+  type bram_type_t is record
+    name       : string (1 to 15);
+    name_width : integer;
+    addr_width : integer;
+    data_width : integer;
+  end record bram_type_t;
+
+  type bram_type_array_t is array (natural range <>) of bram_type_t;
+  
+  constant BRAM_TYPE_ARRAY : bram_type_array_t := (
+    ("RAMB16_S9      ", 9,11, 8),
+    ("RAMB16_S4      ", 9,12, 4),
+    ("RAMB16_S2      ", 9,13, 2));
+
+  impure function select_bram_type (constant name : string) return bram_type_t is
+    variable result_exists : boolean;
+    variable result_index  : integer;
+  begin
+    for i in BRAM_TYPE_ARRAY'range loop
+      if BRAM_TYPE_ARRAY(i).name(1 to BRAM_TYPE_ARRAY(i).name_width) = name then
+        result_exists := true;
+        result_index := i;
+      end if;
+    end loop;
+
+    if not result_exists then
+      assert false
+        report "Block RAM type """ & BRAM_TYPE & """ is unsupported!"
+        severity ERROR;
+    end if;
+
+    return bram_type_array(result_index);
+  end function select_bram_type;
+
+  
+  constant BRAM_USED       : bram_type_t := select_bram_type(BRAM_TYPE);
+  constant BRAM_DATA_WIDTH : integer     := BRAM_USED.data_width;
+  constant BRAM_PER_BLOCK  : integer     := ((DATA_WIDTH - 1) / BRAM_DATA_WIDTH) + 1;
+  
+  constant BLOCK_ADDR_WIDTH : integer := BRAM_USED.addr_width;
+  constant BLOCK_SIZE       : integer := 2**BLOCK_ADDR_WIDTH;
+  constant BLOCK_COUNT      : integer := ((SIZE - 1) / BLOCK_SIZE) + 1;
+
+
+  subtype BLOCK_RANGE is natural range BLOCK_COUNT-1 downto 0;
+  subtype BRAM_RANGE  is natural range BRAM_PER_BLOCK-1 downto 0;
+
+  type block_data_t is array (BRAM_RANGE) of
+    std_logic_vector (BRAM_DATA_WIDTH-1 downto 0);
+
+  
+  type data_array_t is array (BLOCK_RANGE) of block_data_t;
+  type ctrl_array_t is array (BLOCK_RANGE) of std_logic;
+
+  
+  signal dout_array : data_array_t;
+  signal din_array  : block_data_t;
+  signal en_array   : ctrl_array_t;
+  signal we_array   : ctrl_array_t;
+
+  signal block_addr      : std_logic_vector (BLOCK_ADDR_WIDTH-1 downto 0);
+  signal block_index     : integer;
+  signal block_index_reg : integer;
+
+  signal inter_en : std_logic;
+  signal inter_we : std_logic;
+
+--------------------------------------------------------------------------------
+  
+begin
+
+  -- Adjust input control signals according to NEG_EN and NEG_WE generic
+  -- parameters.
+  SIGNALS_LEVEL : process (en, we) is
+  begin
+    if NEG_EN then
+      inter_en <= not en;
+    else
+      inter_en <= en;
+    end if;
+
+    if NEG_WE then
+      inter_we <= not we;
+    else
+      inter_we <= we;
+    end if;
+  end process;
+      
+
+  -- Decode and latch address of BLOCK (i.e. RAM row).
+  BLOCK_INDEX_DECODER : process (clk, addr) is
+  begin
+    block_index <= conv_integer(addr) / BLOCK_SIZE;    
+
+    if rising_edge(clk) and inter_en = '1' then
+      block_index_reg <= block_index;
+    end if;
+  end process;
+
+  
+  -- Address decoder which produces control signals and data inputs for all
+  -- blocks and RAM columns and multiplexes data outputs from all RAMs.
+  DECODER : process (addr, din, inter_en, inter_we) is
+    variable dout_var : std_logic_vector (BRAM_PER_BLOCK*BRAM_DATA_WIDTH-1 downto 0);
+    variable din_var  : std_logic_vector (BRAM_PER_BLOCK*BRAM_DATA_WIDTH-1 downto 0);
+  begin
+    -- decode address to single block RAM
+    if addr'HIGH <= block_addr'HIGH then
+      -- when logic address space is smaller then or equal to 1 BLOCK size
+      block_addr <= (others => '0');
+      block_addr (addr'RANGE) <= addr;
+    else
+      -- when logic address space is bigger then 1 BLOCK size
+      block_addr <= addr (block_addr'RANGE);
+    end if;
+
+    -- split "din" to data inputs of appropriate RAM columns
+    din_var := (others => '0');
+    din_var (din'RANGE) := din;
+    
+    for i in BRAM_RANGE loop
+      din_array (i) <= din_var ((i+1)*BRAM_DATA_WIDTH-1 downto i*BRAM_DATA_WIDTH);
+    end loop;
+
+    -- concatenate data outputs of appropriate RAMs into "dout".
+    dout       <= (others => '0');
+
+    if block_index_reg < BLOCK_COUNT then
+      for i in BRAM_RANGE loop
+        dout_var := dout_var & dout_array (block_index_reg)(i);
+      end loop;
+
+      dout <= dout_var (dout'RANGE);
+    end if;
+
+    -- produce "en" and "we" signals for all RAMs.
+    en_array   <= (others => inter_en);
+
+    we_array   <= (others => '0');
+    
+    if block_index < BLOCK_COUNT then
+      we_array (block_index) <= inter_we;
+    end if;
+  end process;
+
+  
+  -- Generation of RAMB array. Each iteration produces memory block with full
+  -- width and length dependent on used memory primitive. Length of one block
+  -- is computed from BLOCK_ADDR_WIDTH constant.
+  BLOCKS : for i in 0 to BLOCK_COUNT-1 generate
+    RAMB16_S9 : if BRAM_TYPE = "RAMB16_S9" generate
+      B : for j in BRAM_RANGE generate
+        BRAM : RAMB16_S9
+          port map (
+            clk  => clk,
+            addr => block_addr,
+            en   => en_array (i),
+            we   => we_array (i),
+            di   => din_array (j),
+            do   => dout_array (i)(j),
+            dip  => "0",
+            dop  => open,
+            ssr  => '0');
+      end generate;
+    end generate;
+
+    RAMB16_S4 : if BRAM_TYPE = "RAMB16_S4" generate
+      B : for j in BRAM_RANGE generate
+        BRAM : RAMB16_S4
+          port map (
+            clk  => clk,
+            addr => block_addr,
+            en   => en_array (i),
+            we   => we_array (i),
+            di   => din_array (j),
+            do   => dout_array (i)(j),
+            ssr  => '0');
+      end generate;
+    end generate;
+    
+    RAMB16_S2 : if BRAM_TYPE = "RAMB16_S2" generate
+      B : for j in BRAM_RANGE generate
+        BRAM : RAMB16_S2
+          port map (
+            clk  => clk,
+            addr => block_addr,
+            en   => en_array (i),
+            we   => we_array (i),
+            di   => din_array (j),
+            do   => dout_array (i)(j),
+            ssr  => '0');
+      end generate;
+    end generate;
+  end generate;
+
+end architecture behavioral;
+