40cd5b401e2cdf149ba3f4f35cd61db09ea3f83e
[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 begin
86 w_out <= WritebackToRegisterFileInit;
87 c_out <= WritebackToCrFileInit;
88 f := WritebackToFetch1Init;
89 interrupt_out <= '0';
90 vec := 0;
91 v := r;
92
93 complete_out <= instr_tag_init;
94 if e_in.valid = '1' then
95 complete_out <= e_in.instr_tag;
96 elsif l_in.valid = '1' then
97 complete_out <= l_in.instr_tag;
98 elsif fp_in.valid = '1' then
99 complete_out <= fp_in.instr_tag;
100 end if;
101
102 if r.state = WRITE_SRR1 then
103 w_out.write_reg <= fast_spr_num(SPR_SRR1);
104 w_out.write_data <= r.srr1;
105 w_out.write_enable <= '1';
106 interrupt_out <= '1';
107 v.state := WRITE_SRR0;
108
109 elsif e_in.interrupt = '1' then
110 w_out.write_reg <= fast_spr_num(SPR_SRR0);
111 w_out.write_data <= e_in.last_nia;
112 w_out.write_enable <= '1';
113 v.state := WRITE_SRR1;
114 v.srr1(63 downto 32) := e_in.msr(63 downto 32);
115 v.srr1(31 downto 0) := e_in.msr(31 downto 0) or e_in.srr1;
116 vec := e_in.intr_vec;
117
118 elsif l_in.interrupt = '1' then
119 w_out.write_reg <= fast_spr_num(SPR_SRR0);
120 w_out.write_data <= l_in.srr0;
121 w_out.write_enable <= '1';
122 v.state := WRITE_SRR1;
123 v.srr1(63 downto 32) := e_in.msr(63 downto 32);
124 v.srr1(31 downto 0) := e_in.msr(31 downto 0) or l_in.srr1;
125 vec := l_in.intr_vec;
126
127 else
128 if e_in.write_enable = '1' then
129 w_out.write_reg <= e_in.write_reg;
130 w_out.write_data <= e_in.write_data;
131 w_out.write_enable <= '1';
132 end if;
133
134 if e_in.write_cr_enable = '1' then
135 c_out.write_cr_enable <= '1';
136 c_out.write_cr_mask <= e_in.write_cr_mask;
137 c_out.write_cr_data <= e_in.write_cr_data;
138 end if;
139
140 if e_in.write_xerc_enable = '1' then
141 c_out.write_xerc_enable <= '1';
142 c_out.write_xerc_data <= e_in.xerc;
143 end if;
144
145 if fp_in.write_enable = '1' then
146 w_out.write_reg <= fp_in.write_reg;
147 w_out.write_data <= fp_in.write_data;
148 w_out.write_enable <= '1';
149 end if;
150
151 if fp_in.write_cr_enable = '1' then
152 c_out.write_cr_enable <= '1';
153 c_out.write_cr_mask <= fp_in.write_cr_mask;
154 c_out.write_cr_data <= fp_in.write_cr_data;
155 end if;
156
157 if l_in.write_enable = '1' then
158 w_out.write_reg <= l_in.write_reg;
159 w_out.write_data <= l_in.write_data;
160 w_out.write_enable <= '1';
161 end if;
162
163 if l_in.rc = '1' then
164 -- st*cx. instructions
165 scf(3) := '0';
166 scf(2) := '0';
167 scf(1) := l_in.store_done;
168 scf(0) := l_in.xerc.so;
169 c_out.write_cr_enable <= '1';
170 c_out.write_cr_mask <= num_to_fxm(0);
171 c_out.write_cr_data(31 downto 28) <= scf;
172 end if;
173
174 -- Perform CR0 update for RC forms
175 -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
176 if e_in.rc = '1' and e_in.write_enable = '1' then
177 zero := not (or e_in.write_data(31 downto 0));
178 if e_in.mode_32bit = '0' then
179 sign := e_in.write_data(63);
180 zero := zero and not (or e_in.write_data(63 downto 32));
181 else
182 sign := e_in.write_data(31);
183 end if;
184 c_out.write_cr_enable <= '1';
185 c_out.write_cr_mask <= num_to_fxm(0);
186 cf(3) := sign;
187 cf(2) := not sign and not zero;
188 cf(1) := zero;
189 cf(0) := e_in.xerc.so;
190 c_out.write_cr_data(31 downto 28) <= cf;
191 end if;
192 end if;
193
194 -- Outputs to fetch1
195 f.redirect := e_in.redirect;
196 f.br_nia := e_in.last_nia;
197 f.br_last := e_in.br_last;
198 f.br_taken := e_in.br_taken;
199 if e_in.interrupt = '1' or l_in.interrupt = '1' then
200 f.redirect := '1';
201 f.br_last := '0';
202 f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));
203 f.virt_mode := '0';
204 f.priv_mode := '1';
205 -- XXX need an interrupt LE bit here, e.g. from LPCR
206 f.big_endian := '0';
207 f.mode_32bit := '0';
208 else
209 if e_in.abs_br = '1' then
210 f.redirect_nia := e_in.br_offset;
211 else
212 f.redirect_nia := std_ulogic_vector(unsigned(e_in.last_nia) + unsigned(e_in.br_offset));
213 end if;
214 -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
215 f.virt_mode := e_in.redir_mode(3);
216 f.priv_mode := e_in.redir_mode(2);
217 f.big_endian := e_in.redir_mode(1);
218 f.mode_32bit := e_in.redir_mode(0);
219 end if;
220
221 f_out <= f;
222 flush_out <= f_out.redirect;
223
224 rin <= v;
225 end process;
226 end;