Add Tercel PHY reset synchronization
[microwatt.git] / writeback.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 use work.crhelpers.all;
8
9 entity writeback is
10 port (
11 clk : in std_ulogic;
12 rst : in std_ulogic;
13
14 e_in : in Execute1ToWritebackType;
15 l_in : in Loadstore1ToWritebackType;
16 fp_in : in FPUToWritebackType;
17
18 w_out : out WritebackToRegisterFileType;
19 c_out : out WritebackToCrFileType;
20 f_out : out WritebackToFetch1Type;
21
22 flush_out : out std_ulogic;
23 interrupt_out: out std_ulogic;
24 complete_out : out instr_tag_t
25 );
26 end entity writeback;
27
28 architecture behaviour of writeback is
29 type irq_state_t is (WRITE_SRR0, WRITE_SRR1);
30
31 type reg_type is record
32 state : irq_state_t;
33 srr1 : std_ulogic_vector(63 downto 0);
34 end record;
35
36 signal r, rin : reg_type;
37
38 begin
39 writeback_0: process(clk)
40 variable x : std_ulogic_vector(0 downto 0);
41 variable y : std_ulogic_vector(0 downto 0);
42 variable w : std_ulogic_vector(0 downto 0);
43 begin
44 if rising_edge(clk) then
45 if rst = '1' then
46 r.state <= WRITE_SRR0;
47 r.srr1 <= (others => '0');
48 else
49 r <= rin;
50 end if;
51
52 -- Do consistency checks only on the clock edge
53 x(0) := e_in.valid;
54 y(0) := l_in.valid;
55 w(0) := fp_in.valid;
56 assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
57 to_integer(unsigned(w))) <= 1 severity failure;
58
59 x(0) := e_in.write_enable;
60 y(0) := l_in.write_enable;
61 w(0) := fp_in.write_enable;
62 assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
63 to_integer(unsigned(w))) <= 1 severity failure;
64
65 w(0) := e_in.write_cr_enable;
66 x(0) := (e_in.write_enable and e_in.rc);
67 y(0) := fp_in.write_cr_enable;
68 assert (to_integer(unsigned(w)) + to_integer(unsigned(x)) +
69 to_integer(unsigned(y))) <= 1 severity failure;
70
71 assert not (e_in.valid = '1' and e_in.instr_tag.valid = '0') severity failure;
72 assert not (l_in.valid = '1' and l_in.instr_tag.valid = '0') severity failure;
73 assert not (fp_in.valid = '1' and fp_in.instr_tag.valid = '0') severity failure;
74 end if;
75 end process;
76
77 writeback_1: process(all)
78 variable v : reg_type;
79 variable f : WritebackToFetch1Type;
80 variable cf: std_ulogic_vector(3 downto 0);
81 variable zero : std_ulogic;
82 variable sign : std_ulogic;
83 variable scf : std_ulogic_vector(3 downto 0);
84 variable vec : integer range 0 to 16#fff#;
85 variable srr1 : std_ulogic_vector(15 downto 0);
86 variable intr : std_ulogic;
87 begin
88 w_out <= WritebackToRegisterFileInit;
89 c_out <= WritebackToCrFileInit;
90 f := WritebackToFetch1Init;
91 interrupt_out <= '0';
92 vec := 0;
93 v := r;
94
95 complete_out <= instr_tag_init;
96 if e_in.valid = '1' then
97 complete_out <= e_in.instr_tag;
98 elsif l_in.valid = '1' then
99 complete_out <= l_in.instr_tag;
100 elsif fp_in.valid = '1' then
101 complete_out <= fp_in.instr_tag;
102 end if;
103
104 intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;
105
106 if r.state = WRITE_SRR1 then
107 w_out.write_reg <= fast_spr_num(SPR_SRR1);
108 w_out.write_data <= r.srr1;
109 w_out.write_enable <= '1';
110 interrupt_out <= '1';
111 v.state := WRITE_SRR0;
112
113 elsif intr = '1' then
114 w_out.write_reg <= fast_spr_num(SPR_SRR0);
115 w_out.write_enable <= '1';
116 v.state := WRITE_SRR1;
117 srr1 := (others => '0');
118 if e_in.interrupt = '1' then
119 vec := e_in.intr_vec;
120 w_out.write_data <= e_in.last_nia;
121 srr1 := e_in.srr1;
122 elsif l_in.interrupt = '1' then
123 vec := l_in.intr_vec;
124 w_out.write_data <= l_in.srr0;
125 srr1 := l_in.srr1;
126 elsif fp_in.interrupt = '1' then
127 vec := fp_in.intr_vec;
128 w_out.write_data <= fp_in.srr0;
129 srr1 := fp_in.srr1;
130 end if;
131 v.srr1(63 downto 31) := e_in.msr(63 downto 31);
132 v.srr1(30 downto 27) := srr1(14 downto 11);
133 v.srr1(26 downto 22) := e_in.msr(26 downto 22);
134 v.srr1(21 downto 16) := srr1(5 downto 0);
135 v.srr1(15 downto 0) := e_in.msr(15 downto 0);
136
137 else
138 if e_in.write_enable = '1' then
139 w_out.write_reg <= e_in.write_reg;
140 w_out.write_data <= e_in.write_data;
141 w_out.write_enable <= '1';
142 end if;
143
144 if e_in.write_cr_enable = '1' then
145 c_out.write_cr_enable <= '1';
146 c_out.write_cr_mask <= e_in.write_cr_mask;
147 c_out.write_cr_data <= e_in.write_cr_data;
148 end if;
149
150 if e_in.write_xerc_enable = '1' then
151 c_out.write_xerc_enable <= '1';
152 c_out.write_xerc_data <= e_in.xerc;
153 end if;
154
155 if fp_in.write_enable = '1' then
156 w_out.write_reg <= fp_in.write_reg;
157 w_out.write_data <= fp_in.write_data;
158 w_out.write_enable <= '1';
159 end if;
160
161 if fp_in.write_cr_enable = '1' then
162 c_out.write_cr_enable <= '1';
163 c_out.write_cr_mask <= fp_in.write_cr_mask;
164 c_out.write_cr_data <= fp_in.write_cr_data;
165 end if;
166
167 if l_in.write_enable = '1' then
168 w_out.write_reg <= l_in.write_reg;
169 w_out.write_data <= l_in.write_data;
170 w_out.write_enable <= '1';
171 end if;
172
173 if l_in.rc = '1' then
174 -- st*cx. instructions
175 scf(3) := '0';
176 scf(2) := '0';
177 scf(1) := l_in.store_done;
178 scf(0) := l_in.xerc.so;
179 c_out.write_cr_enable <= '1';
180 c_out.write_cr_mask <= num_to_fxm(0);
181 c_out.write_cr_data(31 downto 28) <= scf;
182 end if;
183
184 -- Perform CR0 update for RC forms
185 -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
186 if e_in.rc = '1' and e_in.write_enable = '1' then
187 zero := not (or e_in.write_data(31 downto 0));
188 if e_in.mode_32bit = '0' then
189 sign := e_in.write_data(63);
190 zero := zero and not (or e_in.write_data(63 downto 32));
191 else
192 sign := e_in.write_data(31);
193 end if;
194 c_out.write_cr_enable <= '1';
195 c_out.write_cr_mask <= num_to_fxm(0);
196 cf(3) := sign;
197 cf(2) := not sign and not zero;
198 cf(1) := zero;
199 cf(0) := e_in.xerc.so;
200 c_out.write_cr_data(31 downto 28) <= cf;
201 end if;
202 end if;
203
204 -- Outputs to fetch1
205 f.redirect := e_in.redirect;
206 f.br_nia := e_in.last_nia;
207 f.br_last := e_in.br_last;
208 f.br_taken := e_in.br_taken;
209 if intr = '1' then
210 f.redirect := '1';
211 f.br_last := '0';
212 f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));
213 f.virt_mode := '0';
214 f.priv_mode := '1';
215 -- XXX need an interrupt LE bit here, e.g. from LPCR
216 f.big_endian := '0';
217 f.mode_32bit := '0';
218 else
219 if e_in.abs_br = '1' then
220 f.redirect_nia := e_in.br_offset;
221 else
222 f.redirect_nia := std_ulogic_vector(unsigned(e_in.last_nia) + unsigned(e_in.br_offset));
223 end if;
224 -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
225 f.virt_mode := e_in.redir_mode(3);
226 f.priv_mode := e_in.redir_mode(2);
227 f.big_endian := e_in.redir_mode(1);
228 f.mode_32bit := e_in.redir_mode(0);
229 end if;
230
231 f_out <= f;
232 flush_out <= f_out.redirect;
233
234 rin <= v;
235 end process;
236 end;