Add Tercel PHY reset synchronization
[microwatt.git] / register_file.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4
5 library work;
6 use work.common.all;
7
8 entity register_file is
9 generic (
10 SIM : boolean := false;
11 HAS_FPU : boolean := true;
12 -- Non-zero to enable log data collection
13 LOG_LENGTH : natural := 0
14 );
15 port(
16 clk : in std_logic;
17
18 d_in : in Decode2ToRegisterFileType;
19 d_out : out RegisterFileToDecode2Type;
20
21 w_in : in WritebackToRegisterFileType;
22
23 dbg_gpr_req : in std_ulogic;
24 dbg_gpr_ack : out std_ulogic;
25 dbg_gpr_addr : in gspr_index_t;
26 dbg_gpr_data : out std_ulogic_vector(63 downto 0);
27
28 -- debug
29 sim_dump : in std_ulogic;
30 sim_dump_done : out std_ulogic;
31
32 log_out : out std_ulogic_vector(71 downto 0)
33 );
34 end entity register_file;
35
36 architecture behaviour of register_file is
37 type regfile is array(0 to 127) of std_ulogic_vector(63 downto 0);
38 signal registers : regfile := (others => (others => '0'));
39 signal rd_port_b : std_ulogic_vector(63 downto 0);
40 signal dbg_data : std_ulogic_vector(63 downto 0);
41 signal dbg_ack : std_ulogic;
42 begin
43 -- synchronous writes
44 register_write_0: process(clk)
45 variable w_addr : gspr_index_t;
46 begin
47 if rising_edge(clk) then
48 if w_in.write_enable = '1' then
49 w_addr := w_in.write_reg;
50 if HAS_FPU and w_addr(6) = '1' then
51 report "Writing FPR " & to_hstring(w_addr(4 downto 0)) & " " & to_hstring(w_in.write_data);
52 else
53 w_addr(6) := '0';
54 if w_addr(5) = '0' then
55 report "Writing GPR " & to_hstring(w_addr) & " " & to_hstring(w_in.write_data);
56 else
57 report "Writing GSPR " & to_hstring(w_addr) & " " & to_hstring(w_in.write_data);
58 end if;
59 end if;
60 assert not(is_x(w_in.write_data)) and not(is_x(w_in.write_reg)) severity failure;
61 registers(to_integer(unsigned(w_addr))) <= w_in.write_data;
62 end if;
63 end if;
64 end process register_write_0;
65
66 -- asynchronous reads
67 register_read_0: process(all)
68 variable a_addr, b_addr, c_addr : gspr_index_t;
69 variable w_addr : gspr_index_t;
70 begin
71 a_addr := d_in.read1_reg;
72 b_addr := d_in.read2_reg;
73 c_addr := d_in.read3_reg;
74 w_addr := w_in.write_reg;
75 if not HAS_FPU then
76 -- Make it obvious that we only want 64 GSPRs for a no-FPU implementation
77 a_addr(6) := '0';
78 b_addr(6) := '0';
79 c_addr(6) := '0';
80 w_addr(6) := '0';
81 end if;
82 if d_in.read1_enable = '1' then
83 report "Reading GPR " & to_hstring(a_addr) & " " & to_hstring(registers(to_integer(unsigned(a_addr))));
84 end if;
85 if d_in.read2_enable = '1' then
86 report "Reading GPR " & to_hstring(b_addr) & " " & to_hstring(registers(to_integer(unsigned(b_addr))));
87 end if;
88 if d_in.read3_enable = '1' then
89 report "Reading GPR " & to_hstring(c_addr) & " " & to_hstring(registers(to_integer(unsigned(c_addr))));
90 end if;
91 d_out.read1_data <= registers(to_integer(unsigned(a_addr)));
92 -- B read port is multiplexed with reads from the debug circuitry
93 if d_in.read2_enable = '0' and dbg_gpr_req = '1' and dbg_ack = '0' then
94 b_addr := dbg_gpr_addr;
95 if not HAS_FPU then
96 b_addr(6) := '0';
97 end if;
98 end if;
99 rd_port_b <= registers(to_integer(unsigned(b_addr)));
100 d_out.read2_data <= rd_port_b;
101 d_out.read3_data <= registers(to_integer(unsigned(c_addr)));
102
103 -- Forward any written data
104 if w_in.write_enable = '1' then
105 if a_addr = w_addr then
106 d_out.read1_data <= w_in.write_data;
107 end if;
108 if b_addr = w_addr then
109 d_out.read2_data <= w_in.write_data;
110 end if;
111 if c_addr = w_addr then
112 d_out.read3_data <= w_in.write_data;
113 end if;
114 end if;
115 end process register_read_0;
116
117 -- Latch read data and ack if dbg read requested and B port not busy
118 dbg_register_read: process(clk)
119 begin
120 if rising_edge(clk) then
121 if dbg_gpr_req = '1' then
122 if d_in.read2_enable = '0' and dbg_ack = '0' then
123 dbg_data <= rd_port_b;
124 dbg_ack <= '1';
125 end if;
126 else
127 dbg_ack <= '0';
128 end if;
129 end if;
130 end process;
131
132 dbg_gpr_ack <= dbg_ack;
133 dbg_gpr_data <= dbg_data;
134
135 -- Dump registers if core terminates
136 sim_dump_test: if SIM generate
137 dump_registers: process(all)
138 begin
139 if sim_dump = '1' then
140 loop_0: for i in 0 to 31 loop
141 report "GPR" & integer'image(i) & " " & to_hstring(registers(i));
142 end loop loop_0;
143
144 report "LR " & to_hstring(registers(to_integer(unsigned(fast_spr_num(SPR_LR)))));
145 report "CTR " & to_hstring(registers(to_integer(unsigned(fast_spr_num(SPR_CTR)))));
146 report "XER " & to_hstring(registers(to_integer(unsigned(fast_spr_num(SPR_XER)))));
147 sim_dump_done <= '1';
148 else
149 sim_dump_done <= '0';
150 end if;
151 end process;
152 end generate;
153
154 -- Keep GHDL synthesis happy
155 sim_dump_test_synth: if not SIM generate
156 sim_dump_done <= '0';
157 end generate;
158
159 rf_log: if LOG_LENGTH > 0 generate
160 signal log_data : std_ulogic_vector(71 downto 0);
161 begin
162 reg_log: process(clk)
163 begin
164 if rising_edge(clk) then
165 log_data <= w_in.write_data &
166 w_in.write_enable &
167 w_in.write_reg;
168 end if;
169 end process;
170 log_out <= log_data;
171 end generate;
172
173 end architecture behaviour;