Root/plasma/logic/reg_bank.vhd

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

Archive Download this file

Branches:
master



interactive