]> rtime.felk.cvut.cz Git - fpga/plasma.git/blob - vhdl/reg_bank.vhd
Local copy of Plasma MIPS project.
[fpga/plasma.git] / vhdl / reg_bank.vhd
1 ---------------------------------------------------------------------\r
2 -- TITLE: Register Bank\r
3 -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com)\r
4 -- DATE CREATED: 2/2/01\r
5 -- FILENAME: reg_bank.vhd\r
6 -- PROJECT: Plasma CPU core\r
7 -- COPYRIGHT: Software placed into the public domain by the author.\r
8 --    Software 'as is' without warranty.  Author liable for nothing.\r
9 -- DESCRIPTION:\r
10 --    Implements a register bank with 32 registers that are 32-bits wide.\r
11 --    There are two read-ports and one write port.\r
12 ---------------------------------------------------------------------\r
13 library ieee;\r
14 use ieee.std_logic_1164.all;\r
15 use ieee.std_logic_unsigned.all;\r
16 use work.mlite_pack.all;\r
17 --library UNISIM;               --May need to uncomment for ModelSim\r
18 --use UNISIM.vcomponents.all;   --May need to uncomment for ModelSim\r
19 \r
20 entity reg_bank is\r
21    generic(memory_type : string := "XILINX_16X");\r
22    port(clk            : in  std_logic;\r
23         reset_in       : in  std_logic;\r
24         pause          : in  std_logic;\r
25         rs_index       : in  std_logic_vector(5 downto 0);\r
26         rt_index       : in  std_logic_vector(5 downto 0);\r
27         rd_index       : in  std_logic_vector(5 downto 0);\r
28         reg_source_out : out std_logic_vector(31 downto 0);\r
29         reg_target_out : out std_logic_vector(31 downto 0);\r
30         reg_dest_new   : in  std_logic_vector(31 downto 0);\r
31         intr_enable    : out std_logic);\r
32 end; --entity reg_bank\r
33 \r
34 \r
35 --------------------------------------------------------------------\r
36 -- The ram_block architecture attempts to use TWO dual-port memories.\r
37 -- Different FPGAs and ASICs need different implementations.\r
38 -- Choose one of the RAM implementations below.\r
39 -- I need feedback on this section!\r
40 --------------------------------------------------------------------\r
41 architecture ram_block of reg_bank is\r
42    signal intr_enable_reg : std_logic;\r
43    type ram_type is array(31 downto 0) of std_logic_vector(31 downto 0);\r
44    \r
45    --controls access to dual-port memories\r
46    signal addr_read1, addr_read2 : std_logic_vector(4 downto 0);\r
47    signal addr_write             : std_logic_vector(4 downto 0);\r
48    signal data_out1, data_out2   : std_logic_vector(31 downto 0);\r
49    signal write_enable           : std_logic;\r
50 \r
51 begin\r
52   \r
53 reg_proc: process(clk, rs_index, rt_index, rd_index, reg_dest_new, \r
54       intr_enable_reg, data_out1, data_out2, reset_in, pause)\r
55 begin\r
56    --setup for first dual-port memory\r
57    if rs_index = "101110" then  --reg_epc CP0 14\r
58       addr_read1 <= "00000";\r
59    else\r
60       addr_read1 <= rs_index(4 downto 0);\r
61    end if;\r
62    case rs_index is\r
63    when "000000" => reg_source_out <= ZERO;\r
64    when "101100" => reg_source_out <= ZERO(31 downto 1) & intr_enable_reg;\r
65                     --interrupt vector address = 0x3c\r
66    when "111111" => reg_source_out <= ZERO(31 downto 8) & "00111100";\r
67    when others   => reg_source_out <= data_out1;\r
68    end case;\r
69 \r
70    --setup for second dual-port memory\r
71    addr_read2 <= rt_index(4 downto 0);\r
72    case rt_index is\r
73    when "000000" => reg_target_out <= ZERO;\r
74    when others   => reg_target_out <= data_out2;\r
75    end case;\r
76 \r
77    --setup write port for both dual-port memories\r
78    if rd_index /= "000000" and rd_index /= "101100" and pause = '0' then\r
79       write_enable <= '1';\r
80    else\r
81       write_enable <= '0';\r
82    end if;\r
83    if rd_index = "101110" then  --reg_epc CP0 14\r
84       addr_write <= "00000";\r
85    else\r
86       addr_write <= rd_index(4 downto 0);\r
87    end if;\r
88 \r
89    if reset_in = '1' then\r
90       intr_enable_reg <= '0';\r
91    elsif rising_edge(clk) then\r
92       if rd_index = "101110" then     --reg_epc CP0 14\r
93          intr_enable_reg <= '0';      --disable interrupts\r
94       elsif rd_index = "101100" then\r
95          intr_enable_reg <= reg_dest_new(0);\r
96       end if;\r
97    end if;\r
98 \r
99    intr_enable <= intr_enable_reg;\r
100 end process;\r
101 \r
102 \r
103 --------------------------------------------------------------\r
104 ---- Pick only ONE of the dual-port RAM implementations below!\r
105 --------------------------------------------------------------\r
106 \r
107    -- Option #1\r
108    -- One tri-port RAM, two read-ports, one write-port\r
109    -- 32 registers 32-bits wide\r
110    tri_port_mem:\r
111    if memory_type = "TRI_PORT_X" generate\r
112       ram_proc: process(clk, addr_read1, addr_read2, \r
113             addr_write, reg_dest_new, write_enable)\r
114       variable tri_port_ram : ram_type := (others => ZERO);\r
115       begin\r
116          data_out1 <= tri_port_ram(conv_integer(addr_read1));\r
117          data_out2 <= tri_port_ram(conv_integer(addr_read2));\r
118          if rising_edge(clk) then\r
119             if write_enable = '1' then\r
120                tri_port_ram(conv_integer(addr_write)) := reg_dest_new;\r
121             end if;\r
122          end if;\r
123       end process;\r
124    end generate; --tri_port_mem\r
125 \r
126 \r
127    -- Option #2\r
128    -- Two dual-port RAMs, each with one read-port and one write-port\r
129    dual_port_mem:\r
130    if memory_type = "DUAL_PORT_" generate\r
131       ram_proc2: process(clk, addr_read1, addr_read2, \r
132             addr_write, reg_dest_new, write_enable)\r
133       variable dual_port_ram1 : ram_type := (others => ZERO);\r
134       variable dual_port_ram2 : ram_type := (others => ZERO);\r
135       begin\r
136          data_out1 <= dual_port_ram1(conv_integer(addr_read1));\r
137          data_out2 <= dual_port_ram2(conv_integer(addr_read2));\r
138          if rising_edge(clk) then\r
139             if write_enable = '1' then\r
140                dual_port_ram1(conv_integer(addr_write)) := reg_dest_new;\r
141                dual_port_ram2(conv_integer(addr_write)) := reg_dest_new;\r
142             end if;\r
143          end if;\r
144       end process;\r
145    end generate; --dual_port_mem\r
146 \r
147 \r
148    -- Option #3\r
149    -- RAM16X1D: 16 x 1 positive edge write, asynchronous read dual-port \r
150    -- distributed RAM for all Xilinx FPGAs\r
151    -- From library UNISIM; use UNISIM.vcomponents.all;\r
152    xilinx_16x1d:\r
153    if memory_type = "XILINX_16X" generate\r
154       signal data_out1A, data_out1B : std_logic_vector(31 downto 0);\r
155       signal data_out2A, data_out2B : std_logic_vector(31 downto 0);\r
156       signal weA, weB               : std_logic;\r
157       signal no_connect             : std_logic_vector(127 downto 0);\r
158    begin\r
159       weA <= write_enable and not addr_write(4);  --lower 16 registers\r
160       weB <= write_enable and addr_write(4);      --upper 16 registers\r
161       \r
162       reg_loop: for i in 0 to 31 generate\r
163       begin\r
164          --Read port 1 lower 16 registers\r
165          reg_bit1a : RAM16X1D\r
166          port map (\r
167             WCLK  => clk,              -- Port A write clock input\r
168             WE    => weA,              -- Port A write enable input\r
169             A0    => addr_write(0),    -- Port A address[0] input bit\r
170             A1    => addr_write(1),    -- Port A address[1] input bit\r
171             A2    => addr_write(2),    -- Port A address[2] input bit\r
172             A3    => addr_write(3),    -- Port A address[3] input bit\r
173             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
174             DPRA0 => addr_read1(0),    -- Port B address[0] input bit\r
175             DPRA1 => addr_read1(1),    -- Port B address[1] input bit\r
176             DPRA2 => addr_read1(2),    -- Port B address[2] input bit\r
177             DPRA3 => addr_read1(3),    -- Port B address[3] input bit\r
178             DPO   => data_out1A(i),    -- Port B 1-bit data output\r
179             SPO   => no_connect(i)     -- Port A 1-bit data output\r
180          );\r
181          --Read port 1 upper 16 registers\r
182          reg_bit1b : RAM16X1D\r
183          port map (\r
184             WCLK  => clk,              -- Port A write clock input\r
185             WE    => weB,              -- Port A write enable input\r
186             A0    => addr_write(0),    -- Port A address[0] input bit\r
187             A1    => addr_write(1),    -- Port A address[1] input bit\r
188             A2    => addr_write(2),    -- Port A address[2] input bit\r
189             A3    => addr_write(3),    -- Port A address[3] input bit\r
190             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
191             DPRA0 => addr_read1(0),    -- Port B address[0] input bit\r
192             DPRA1 => addr_read1(1),    -- Port B address[1] input bit\r
193             DPRA2 => addr_read1(2),    -- Port B address[2] input bit\r
194             DPRA3 => addr_read1(3),    -- Port B address[3] input bit\r
195             DPO   => data_out1B(i),    -- Port B 1-bit data output\r
196             SPO   => no_connect(32+i)  -- Port A 1-bit data output\r
197          );\r
198          --Read port 2 lower 16 registers\r
199          reg_bit2a : RAM16X1D\r
200          port map (\r
201             WCLK  => clk,              -- Port A write clock input\r
202             WE    => weA,              -- Port A write enable input\r
203             A0    => addr_write(0),    -- Port A address[0] input bit\r
204             A1    => addr_write(1),    -- Port A address[1] input bit\r
205             A2    => addr_write(2),    -- Port A address[2] input bit\r
206             A3    => addr_write(3),    -- Port A address[3] input bit\r
207             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
208             DPRA0 => addr_read2(0),    -- Port B address[0] input bit\r
209             DPRA1 => addr_read2(1),    -- Port B address[1] input bit\r
210             DPRA2 => addr_read2(2),    -- Port B address[2] input bit\r
211             DPRA3 => addr_read2(3),    -- Port B address[3] input bit\r
212             DPO   => data_out2A(i),    -- Port B 1-bit data output\r
213             SPO   => no_connect(64+i)  -- Port A 1-bit data output\r
214          );\r
215          --Read port 2 upper 16 registers\r
216          reg_bit2b : RAM16X1D\r
217          port map (\r
218             WCLK  => clk,              -- Port A write clock input\r
219             WE    => weB,              -- Port A write enable input\r
220             A0    => addr_write(0),    -- Port A address[0] input bit\r
221             A1    => addr_write(1),    -- Port A address[1] input bit\r
222             A2    => addr_write(2),    -- Port A address[2] input bit\r
223             A3    => addr_write(3),    -- Port A address[3] input bit\r
224             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
225             DPRA0 => addr_read2(0),    -- Port B address[0] input bit\r
226             DPRA1 => addr_read2(1),    -- Port B address[1] input bit\r
227             DPRA2 => addr_read2(2),    -- Port B address[2] input bit\r
228             DPRA3 => addr_read2(3),    -- Port B address[3] input bit\r
229             DPO   => data_out2B(i),    -- Port B 1-bit data output\r
230             SPO   => no_connect(96+i)  -- Port A 1-bit data output\r
231          );\r
232       end generate; --reg_loop\r
233 \r
234       data_out1 <= data_out1A when addr_read1(4)='0' else data_out1B;\r
235       data_out2 <= data_out2A when addr_read2(4)='0' else data_out2B;\r
236    end generate; --xilinx_16x1d\r
237 \r
238 \r
239    -- Option #4\r
240    -- RAM32X1D: 32 x 1 positive edge write, asynchronous read dual-port \r
241    -- distributed RAM for 5-LUT Xilinx FPGAs such as Virtex-5\r
242    -- From library UNISIM; use UNISIM.vcomponents.all;\r
243    xilinx_32x1d:\r
244    if memory_type = "XILINX_32X" generate\r
245       signal no_connect             : std_logic_vector(63 downto 0);\r
246    begin\r
247       reg_loop: for i in 0 to 31 generate\r
248       begin\r
249          --Read port 1\r
250          reg_bit1 : RAM32X1D\r
251          port map (\r
252             WCLK  => clk,              -- Port A write clock input\r
253             WE    => write_enable,     -- Port A write enable input\r
254             A0    => addr_write(0),    -- Port A address[0] input bit\r
255             A1    => addr_write(1),    -- Port A address[1] input bit\r
256             A2    => addr_write(2),    -- Port A address[2] input bit\r
257             A3    => addr_write(3),    -- Port A address[3] input bit\r
258             A4    => addr_write(4),    -- Port A address[4] input bit\r
259             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
260             DPRA0 => addr_read1(0),    -- Port B address[0] input bit\r
261             DPRA1 => addr_read1(1),    -- Port B address[1] input bit\r
262             DPRA2 => addr_read1(2),    -- Port B address[2] input bit\r
263             DPRA3 => addr_read1(3),    -- Port B address[3] input bit\r
264             DPRA4 => addr_read1(4),    -- Port B address[4] input bit\r
265             DPO   => data_out1(i),     -- Port B 1-bit data output\r
266             SPO   => no_connect(i)     -- Port A 1-bit data output\r
267          );\r
268          --Read port 2\r
269          reg_bit2 : RAM32X1D\r
270          port map (\r
271             WCLK  => clk,              -- Port A write clock input\r
272             WE    => write_enable,     -- Port A write enable input\r
273             A0    => addr_write(0),    -- Port A address[0] input bit\r
274             A1    => addr_write(1),    -- Port A address[1] input bit\r
275             A2    => addr_write(2),    -- Port A address[2] input bit\r
276             A3    => addr_write(3),    -- Port A address[3] input bit\r
277             A4    => addr_write(4),    -- Port A address[4] input bit\r
278             D     => reg_dest_new(i),  -- Port A 1-bit data input\r
279             DPRA0 => addr_read2(0),    -- Port B address[0] input bit\r
280             DPRA1 => addr_read2(1),    -- Port B address[1] input bit\r
281             DPRA2 => addr_read2(2),    -- Port B address[2] input bit\r
282             DPRA3 => addr_read2(3),    -- Port B address[3] input bit\r
283             DPRA4 => addr_read2(4),    -- Port B address[4] input bit\r
284             DPO   => data_out2(i),     -- Port B 1-bit data output\r
285             SPO   => no_connect(32+i)  -- Port A 1-bit data output\r
286          );\r
287       end generate; --reg_loop\r
288    end generate; --xilinx_32x1d\r
289 \r
290 \r
291    -- Option #5\r
292    -- Altera LPM_RAM_DP\r
293    altera_mem:\r
294    if memory_type = "ALTERA_LPM" generate\r
295       signal clk_delayed : std_logic;\r
296       signal addr_reg    : std_logic_vector(4 downto 0);\r
297       signal data_reg    : std_logic_vector(31 downto 0);\r
298       signal q1          : std_logic_vector(31 downto 0);\r
299       signal q2          : std_logic_vector(31 downto 0);\r
300    begin\r
301       -- Altera dual port RAMs must have the addresses registered (sampled\r
302       -- at the rising edge).  This is very unfortunate.\r
303       -- Therefore, the dual port RAM read clock must delayed so that\r
304       -- the read address signal can be sent from the mem_ctrl block.\r
305       -- This solution also delays the how fast the registers are read so the \r
306       -- maximum clock speed is cut in half (12.5 MHz instead of 25 MHz).\r
307 \r
308       clk_delayed <= not clk;  --Could be delayed by 1/4 clock cycle instead\r
309       dpram_bypass: process(clk, addr_write, reg_dest_new, write_enable)\r
310       begin\r
311          if rising_edge(clk) and write_enable = '1' then\r
312             addr_reg <= addr_write;\r
313             data_reg <= reg_dest_new;\r
314          end if;\r
315       end process; --dpram_bypass\r
316 \r
317       -- Bypass dpram if reading what was just written (Altera limitation)\r
318       data_out1 <= q1 when addr_read1 /= addr_reg else data_reg;\r
319       data_out2 <= q2 when addr_read2 /= addr_reg else data_reg;\r
320       \r
321       lpm_ram_dp_component1 : lpm_ram_dp\r
322       generic map (\r
323          LPM_WIDTH => 32,\r
324          LPM_WIDTHAD => 5,\r
325          --LPM_NUMWORDS => 0,\r
326          LPM_INDATA => "REGISTERED",\r
327          LPM_OUTDATA => "UNREGISTERED",\r
328          LPM_RDADDRESS_CONTROL => "REGISTERED",\r
329          LPM_WRADDRESS_CONTROL => "REGISTERED",\r
330          LPM_FILE => "UNUSED",\r
331          LPM_TYPE => "LPM_RAM_DP",\r
332          USE_EAB  => "ON",\r
333          INTENDED_DEVICE_FAMILY => "UNUSED",\r
334          RDEN_USED => "FALSE",\r
335          LPM_HINT => "UNUSED")\r
336       port map (\r
337          RDCLOCK   => clk_delayed,\r
338          RDCLKEN   => '1',\r
339          RDADDRESS => addr_read1,\r
340          RDEN      => '1',\r
341          DATA      => reg_dest_new,\r
342          WRADDRESS => addr_write,\r
343          WREN      => write_enable,\r
344          WRCLOCK   => clk,\r
345          WRCLKEN   => '1',\r
346          Q         => q1);\r
347       lpm_ram_dp_component2 : lpm_ram_dp\r
348       generic map (\r
349          LPM_WIDTH => 32,\r
350          LPM_WIDTHAD => 5,\r
351          --LPM_NUMWORDS => 0,\r
352          LPM_INDATA => "REGISTERED",\r
353          LPM_OUTDATA => "UNREGISTERED",\r
354          LPM_RDADDRESS_CONTROL => "REGISTERED",\r
355          LPM_WRADDRESS_CONTROL => "REGISTERED",\r
356          LPM_FILE => "UNUSED",\r
357          LPM_TYPE => "LPM_RAM_DP",\r
358          USE_EAB  => "ON",\r
359          INTENDED_DEVICE_FAMILY => "UNUSED",\r
360          RDEN_USED => "FALSE",\r
361          LPM_HINT => "UNUSED")\r
362       port map (\r
363          RDCLOCK   => clk_delayed,\r
364          RDCLKEN   => '1',\r
365          RDADDRESS => addr_read2,\r
366          RDEN      => '1',\r
367          DATA      => reg_dest_new,\r
368          WRADDRESS => addr_write,\r
369          WREN      => write_enable,\r
370          WRCLOCK   => clk,\r
371          WRCLKEN   => '1',\r
372          Q         => q2);\r
373    end generate; --altera_mem\r
374 \r
375 end; --architecture ram_block\r