2 use ieee.std_logic_1164.all;
3 use ieee.std_logic_arith.all;
4 use ieee.std_logic_unsigned.all;
7 use UNISIM.vcomponents.all;
9 --------------------------------------------------------------------------------
10 -- Generator of synchronous memory with generic size and width of address and
11 -- data buses made up of RAMB primitives.
13 -- There is no special relation between SIZE and ADDR_WIDTH parameters. Both
14 -- values are independent of each other.
16 -- Currently basic building element are: RAMB16_S9, RAMB_S4 and RAMB_S2
17 -- primitives (which are preset at least in Virtex-II/II-Pro and Spartan-3/3E
18 -- devices). If your device doesn't contain one of these memory primitives, the
19 -- only thing you have to do is to add simple generate statement of your
20 -- primitive into the BLOCKS statement and add record about this new memory
21 -- primitive to the BRAM_TYPE_ARRAY.
23 -- Resulting memory is composed of regular array of one memory primitive type
24 -- which must be specified by BRAM_TYPE generic parameter. One iteration of
25 -- BLOCKS generate statement produces one row in memory array which is called
26 -- BLOCK. One iteration of generate statement in BLOCKS (named after memory
27 -- primitive) produces one memory primitive in memory array.
29 -- Input ports "we" and "din" have default zero values. So it's not required
33 -- Memory primitives naming convention is following:
35 -- <path to component>/BLOCKS[<row num>].<mem primitive name>.B[<col num>].BRAM
37 -- Higher data bits -> higher <col num>
38 -- Higher address -> higher <row num>
39 -- <mem primitive name> is name specified in BRAM_TYPE parameter.
42 -- Example of Block RAM Memory Map (*.bmm) file:
44 -- // ram_generic: SIZE=16kB, WIDTH=8b, BRAM_TYPE=RAMB16_S2
45 -- ADDRESS_SPACE blockrom RAMB16 [0x0000:0x3fff]
47 -- <path>/BLOCKS[0].RAMB16_S2.B[3].BRAM [7:6];
48 -- <path>/BLOCKS[0].RAMB16_S2.B[2].BRAM [5:4];
49 -- <path>/BLOCKS[0].RAMB16_S2.B[1].BRAM [3:2];
50 -- <path>/BLOCKS[0].RAMB16_S2.B[0].BRAM [1:0];
53 -- <path>/BLOCKS[1].RAMB16_S2.B[3].BRAM [7:6];
54 -- <path>/BLOCKS[1].RAMB16_S2.B[2].BRAM [5:4];
55 -- <path>/BLOCKS[1].RAMB16_S2.B[1].BRAM [3:2];
56 -- <path>/BLOCKS[1].RAMB16_S2.B[0].BRAM [1:0];
59 --------------------------------------------------------------------------------
63 BRAM_TYPE : string := "RAMB16_S9"; -- Memory primitive used
64 SIZE : integer := 8*1024; -- Physical size in bytes
65 ADDR_WIDTH : integer := 16; -- Width of address port
66 DATA_WIDTH : integer := 8; -- Width of data port
67 NEG_EN : boolean := false; -- Low active "enable"
68 NEG_WE : boolean := false); -- Low active "write enable"
71 addr : in std_logic_vector (ADDR_WIDTH-1 downto 0);
73 we : in std_logic := '0';
74 din : in std_logic_vector (DATA_WIDTH-1 downto 0) := conv_std_logic_vector(0, DATA_WIDTH);
75 dout : out std_logic_vector (DATA_WIDTH-1 downto 0));
76 end entity ram_generic;
78 --------------------------------------------------------------------------------
80 architecture behavioral of ram_generic is
82 type bram_type_t is record
83 name : string (1 to 15);
87 end record bram_type_t;
89 type bram_type_array_t is array (natural range <>) of bram_type_t;
91 constant BRAM_TYPE_ARRAY : bram_type_array_t := (
92 ("RAMB16_S9 ", 9,11, 8),
93 ("RAMB16_S4 ", 9,12, 4),
94 ("RAMB16_S2 ", 9,13, 2));
96 impure function select_bram_type (constant name : string) return bram_type_t is
97 variable result_exists : boolean;
98 variable result_index : integer;
100 for i in BRAM_TYPE_ARRAY'range loop
101 if BRAM_TYPE_ARRAY(i).name(1 to BRAM_TYPE_ARRAY(i).name_width) = name then
102 result_exists := true;
107 if not result_exists then
109 report "Block RAM type """ & BRAM_TYPE & """ is unsupported!"
113 return bram_type_array(result_index);
114 end function select_bram_type;
117 constant BRAM_USED : bram_type_t := select_bram_type(BRAM_TYPE);
118 constant BRAM_DATA_WIDTH : integer := BRAM_USED.data_width;
119 constant BRAM_PER_BLOCK : integer := ((DATA_WIDTH - 1) / BRAM_DATA_WIDTH) + 1;
121 constant BLOCK_ADDR_WIDTH : integer := BRAM_USED.addr_width;
122 constant BLOCK_SIZE : integer := 2**BLOCK_ADDR_WIDTH;
123 constant BLOCK_COUNT : integer := ((SIZE - 1) / BLOCK_SIZE) + 1;
126 subtype BLOCK_RANGE is natural range BLOCK_COUNT-1 downto 0;
127 subtype BRAM_RANGE is natural range BRAM_PER_BLOCK-1 downto 0;
129 type block_data_t is array (BRAM_RANGE) of
130 std_logic_vector (BRAM_DATA_WIDTH-1 downto 0);
133 type data_array_t is array (BLOCK_RANGE) of block_data_t;
134 type ctrl_array_t is array (BLOCK_RANGE) of std_logic;
137 signal dout_array : data_array_t;
138 signal din_array : block_data_t;
139 signal en_array : ctrl_array_t;
140 signal we_array : ctrl_array_t;
142 signal block_addr : std_logic_vector (BLOCK_ADDR_WIDTH-1 downto 0);
143 signal block_index : integer;
144 signal block_index_reg : integer;
146 signal inter_en : std_logic;
147 signal inter_we : std_logic;
149 --------------------------------------------------------------------------------
153 -- Adjust input control signals according to NEG_EN and NEG_WE generic
155 SIGNALS_LEVEL : process (en, we) is
171 -- Decode and latch address of BLOCK (i.e. RAM row).
172 BLOCK_INDEX_DECODER : process (clk, addr) is
174 block_index <= conv_integer(addr) / BLOCK_SIZE;
176 if rising_edge(clk) and inter_en = '1' then
177 block_index_reg <= block_index;
182 -- Address decoder which produces control signals and data inputs for all
183 -- blocks and RAM columns and multiplexes data outputs from all RAMs.
184 DECODER : process (addr, din, inter_en, inter_we) is
185 variable dout_var : std_logic_vector (BRAM_PER_BLOCK*BRAM_DATA_WIDTH-1 downto 0);
186 variable din_var : std_logic_vector (BRAM_PER_BLOCK*BRAM_DATA_WIDTH-1 downto 0);
188 -- decode address to single block RAM
189 if addr'HIGH <= block_addr'HIGH then
190 -- when logic address space is smaller then or equal to 1 BLOCK size
191 block_addr <= (others => '0');
192 block_addr (addr'RANGE) <= addr;
194 -- when logic address space is bigger then 1 BLOCK size
195 block_addr <= addr (block_addr'RANGE);
198 -- split "din" to data inputs of appropriate RAM columns
199 din_var := (others => '0');
200 din_var (din'RANGE) := din;
202 for i in BRAM_RANGE loop
203 din_array (i) <= din_var ((i+1)*BRAM_DATA_WIDTH-1 downto i*BRAM_DATA_WIDTH);
206 -- concatenate data outputs of appropriate RAMs into "dout".
207 dout <= (others => '0');
209 if block_index_reg < BLOCK_COUNT then
210 for i in BRAM_RANGE loop
211 dout_var := dout_var & dout_array (block_index_reg)(i);
214 dout <= dout_var (dout'RANGE);
217 -- produce "en" and "we" signals for all RAMs.
218 en_array <= (others => inter_en);
220 we_array <= (others => '0');
222 if block_index < BLOCK_COUNT then
223 we_array (block_index) <= inter_we;
228 -- Generation of RAMB array. Each iteration produces memory block with full
229 -- width and length dependent on used memory primitive. Length of one block
230 -- is computed from BLOCK_ADDR_WIDTH constant.
231 BLOCKS : for i in 0 to BLOCK_COUNT-1 generate
232 RAMB16_S9 : if BRAM_TYPE = "RAMB16_S9" generate
233 B : for j in BRAM_RANGE generate
241 do => dout_array (i)(j),
248 RAMB16_S4 : if BRAM_TYPE = "RAMB16_S4" generate
249 B : for j in BRAM_RANGE generate
257 do => dout_array (i)(j),
262 RAMB16_S2 : if BRAM_TYPE = "RAMB16_S2" generate
263 B : for j in BRAM_RANGE generate
271 do => dout_array (i)(j),
277 end architecture behavioral;