]> rtime.felk.cvut.cz Git - fpga/openmsp430.git/blob - memory/ram_generic.vhd
Submodule uart
[fpga/openmsp430.git] / memory / ram_generic.vhd
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.std_logic_arith.all;
4 use ieee.std_logic_unsigned.all;
5
6 library UNISIM;
7 use UNISIM.vcomponents.all;
8
9 --------------------------------------------------------------------------------
10 -- Generator of synchronous memory with generic size and width of address and
11 -- data buses made up of RAMB primitives.
12 --
13 -- There is no special relation between SIZE and ADDR_WIDTH parameters. Both
14 -- values are independent of each other.
15 --
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.
22 --
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.
28 --
29 -- Input ports "we" and "din" have default zero values. So it's not required
30 -- to connect them.
31 --
32 --
33 -- Memory primitives naming convention is following:
34 --
35 -- <path to component>/BLOCKS[<row num>].<mem primitive name>.B[<col num>].BRAM
36 --
37 -- Higher data bits -> higher <col num>
38 -- Higher address   -> higher <row num>
39 -- <mem primitive name> is name specified in BRAM_TYPE parameter.
40 --
41 --
42 -- Example of Block RAM Memory Map (*.bmm) file:
43 --
44 --      // ram_generic: SIZE=16kB, WIDTH=8b, BRAM_TYPE=RAMB16_S2
45 --      ADDRESS_SPACE blockrom RAMB16 [0x0000:0x3fff]
46 --        BUS_BLOCK
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];
51 --        END_BUS_BLOCK;
52 --        BUS_BLOCK
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];
57 --        END_BUS_BLOCK;
58 --      END_ADDRESS_SPACE;
59 --------------------------------------------------------------------------------
60
61 entity ram_generic is
62   generic (
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"
69   port (
70     clk  : in  std_logic;
71     addr : in  std_logic_vector (ADDR_WIDTH-1 downto 0);
72     en   : in  std_logic;
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;
77
78 --------------------------------------------------------------------------------
79
80 architecture behavioral of ram_generic is
81
82   type bram_type_t is record
83     name       : string (1 to 15);
84     name_width : integer;
85     addr_width : integer;
86     data_width : integer;
87   end record bram_type_t;
88
89   type bram_type_array_t is array (natural range <>) of bram_type_t;
90   
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));
95
96   impure function select_bram_type (constant name : string) return bram_type_t is
97     variable result_exists : boolean;
98     variable result_index  : integer;
99   begin
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;
103         result_index := i;
104       end if;
105     end loop;
106
107     if not result_exists then
108       assert false
109         report "Block RAM type """ & BRAM_TYPE & """ is unsupported!"
110         severity ERROR;
111     end if;
112
113     return bram_type_array(result_index);
114   end function select_bram_type;
115
116   
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;
120   
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;
124
125
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;
128
129   type block_data_t is array (BRAM_RANGE) of
130     std_logic_vector (BRAM_DATA_WIDTH-1 downto 0);
131
132   
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;
135
136   
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;
141
142   signal block_addr      : std_logic_vector (BLOCK_ADDR_WIDTH-1 downto 0);
143   signal block_index     : integer;
144   signal block_index_reg : integer;
145
146   signal inter_en : std_logic;
147   signal inter_we : std_logic;
148
149 --------------------------------------------------------------------------------
150   
151 begin
152
153   -- Adjust input control signals according to NEG_EN and NEG_WE generic
154   -- parameters.
155   SIGNALS_LEVEL : process (en, we) is
156   begin
157     if NEG_EN then
158       inter_en <= not en;
159     else
160       inter_en <= en;
161     end if;
162
163     if NEG_WE then
164       inter_we <= not we;
165     else
166       inter_we <= we;
167     end if;
168   end process;
169       
170
171   -- Decode and latch address of BLOCK (i.e. RAM row).
172   BLOCK_INDEX_DECODER : process (clk, addr) is
173   begin
174     block_index <= conv_integer(addr) / BLOCK_SIZE;    
175
176     if rising_edge(clk) and inter_en = '1' then
177       block_index_reg <= block_index;
178     end if;
179   end process;
180
181   
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);
187   begin
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;
193     else
194       -- when logic address space is bigger then 1 BLOCK size
195       block_addr <= addr (block_addr'RANGE);
196     end if;
197
198     -- split "din" to data inputs of appropriate RAM columns
199     din_var := (others => '0');
200     din_var (din'RANGE) := din;
201     
202     for i in BRAM_RANGE loop
203       din_array (i) <= din_var ((i+1)*BRAM_DATA_WIDTH-1 downto i*BRAM_DATA_WIDTH);
204     end loop;
205
206     -- concatenate data outputs of appropriate RAMs into "dout".
207     dout       <= (others => '0');
208
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);
212       end loop;
213
214       dout <= dout_var (dout'RANGE);
215     end if;
216
217     -- produce "en" and "we" signals for all RAMs.
218     en_array   <= (others => inter_en);
219
220     we_array   <= (others => '0');
221     
222     if block_index < BLOCK_COUNT then
223       we_array (block_index) <= inter_we;
224     end if;
225   end process;
226
227   
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
234         BRAM : RAMB16_S9
235           port map (
236             clk  => clk,
237             addr => block_addr,
238             en   => en_array (i),
239             we   => we_array (i),
240             di   => din_array (j),
241             do   => dout_array (i)(j),
242             dip  => "0",
243             dop  => open,
244             ssr  => '0');
245       end generate;
246     end generate;
247
248     RAMB16_S4 : if BRAM_TYPE = "RAMB16_S4" generate
249       B : for j in BRAM_RANGE generate
250         BRAM : RAMB16_S4
251           port map (
252             clk  => clk,
253             addr => block_addr,
254             en   => en_array (i),
255             we   => we_array (i),
256             di   => din_array (j),
257             do   => dout_array (i)(j),
258             ssr  => '0');
259       end generate;
260     end generate;
261     
262     RAMB16_S2 : if BRAM_TYPE = "RAMB16_S2" generate
263       B : for j in BRAM_RANGE generate
264         BRAM : RAMB16_S2
265           port map (
266             clk  => clk,
267             addr => block_addr,
268             en   => en_array (i),
269             we   => we_array (i),
270             di   => din_array (j),
271             do   => dout_array (i)(j),
272             ssr  => '0');
273       end generate;
274     end generate;
275   end generate;
276
277 end architecture behavioral;
278