2 * Copyright (c) 2012-2014 Bastian Koppelmann C-Lab/University Paderborn
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/host-utils.h"
20 #include "exec/helper-proto.h"
21 #include "exec/cpu_ldst.h"
23 #define SSOV(env, ret, arg, len) do { \
24 int64_t max_pos = INT##len ##_MAX; \
25 int64_t max_neg = INT##len ##_MIN; \
26 if (arg > max_pos) { \
27 env->PSW_USB_V = (1 << 31); \
28 env->PSW_USB_SV = (1 << 31); \
29 ret = (target_ulong)max_pos; \
31 if (arg < max_neg) { \
32 env->PSW_USB_V = (1 << 31); \
33 env->PSW_USB_SV = (1 << 31); \
34 ret = (target_ulong)max_neg; \
37 ret = (target_ulong)arg; \
40 env->PSW_USB_AV = arg ^ arg * 2u; \
41 env->PSW_USB_SAV |= env->PSW_USB_AV; \
44 target_ulong
helper_add_ssov(CPUTriCoreState
*env
, target_ulong r1
,
48 int64_t t1
= sextract64(r1
, 0, 32);
49 int64_t t2
= sextract64(r2
, 0, 32);
50 int64_t result
= t1
+ t2
;
51 SSOV(env
, ret
, result
, 32);
55 target_ulong
helper_sub_ssov(CPUTriCoreState
*env
, target_ulong r1
,
59 int64_t t1
= sextract64(r1
, 0, 32);
60 int64_t t2
= sextract64(r2
, 0, 32);
61 int64_t result
= t1
- t2
;
62 SSOV(env
, ret
, result
, 32);
66 /* context save area (CSA) related helpers */
68 static int cdc_increment(target_ulong
*psw
)
70 if ((*psw
& MASK_PSW_CDC
) == 0x7f) {
75 /* check for overflow */
76 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
77 int mask
= (1u << (7 - lo
)) - 1;
78 int count
= *psw
& mask
;
86 static int cdc_decrement(target_ulong
*psw
)
88 if ((*psw
& MASK_PSW_CDC
) == 0x7f) {
91 /* check for underflow */
92 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
93 int mask
= (1u << (7 - lo
)) - 1;
94 int count
= *psw
& mask
;
102 static bool cdc_zero(target_ulong
*psw
)
104 int cdc
= *psw
& MASK_PSW_CDC
;
105 /* Returns TRUE if PSW.CDC.COUNT == 0 or if PSW.CDC ==
106 7'b1111111, otherwise returns FALSE. */
111 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
112 int mask
= (1u << (7 - lo
)) - 1;
113 int count
= *psw
& mask
;
117 static void save_context_upper(CPUTriCoreState
*env
, int ea
)
119 cpu_stl_data(env
, ea
, env
->PCXI
);
120 cpu_stl_data(env
, ea
+4, env
->PSW
);
121 cpu_stl_data(env
, ea
+8, env
->gpr_a
[10]);
122 cpu_stl_data(env
, ea
+12, env
->gpr_a
[11]);
123 cpu_stl_data(env
, ea
+16, env
->gpr_d
[8]);
124 cpu_stl_data(env
, ea
+20, env
->gpr_d
[9]);
125 cpu_stl_data(env
, ea
+24, env
->gpr_d
[10]);
126 cpu_stl_data(env
, ea
+28, env
->gpr_d
[11]);
127 cpu_stl_data(env
, ea
+32, env
->gpr_a
[12]);
128 cpu_stl_data(env
, ea
+36, env
->gpr_a
[13]);
129 cpu_stl_data(env
, ea
+40, env
->gpr_a
[14]);
130 cpu_stl_data(env
, ea
+44, env
->gpr_a
[15]);
131 cpu_stl_data(env
, ea
+48, env
->gpr_d
[12]);
132 cpu_stl_data(env
, ea
+52, env
->gpr_d
[13]);
133 cpu_stl_data(env
, ea
+56, env
->gpr_d
[14]);
134 cpu_stl_data(env
, ea
+60, env
->gpr_d
[15]);
137 static void save_context_lower(CPUTriCoreState
*env
, int ea
)
139 cpu_stl_data(env
, ea
, env
->PCXI
);
140 cpu_stl_data(env
, ea
+4, env
->gpr_a
[11]);
141 cpu_stl_data(env
, ea
+8, env
->gpr_a
[2]);
142 cpu_stl_data(env
, ea
+12, env
->gpr_a
[3]);
143 cpu_stl_data(env
, ea
+16, env
->gpr_d
[0]);
144 cpu_stl_data(env
, ea
+20, env
->gpr_d
[1]);
145 cpu_stl_data(env
, ea
+24, env
->gpr_d
[2]);
146 cpu_stl_data(env
, ea
+28, env
->gpr_d
[3]);
147 cpu_stl_data(env
, ea
+32, env
->gpr_a
[4]);
148 cpu_stl_data(env
, ea
+36, env
->gpr_a
[5]);
149 cpu_stl_data(env
, ea
+40, env
->gpr_a
[6]);
150 cpu_stl_data(env
, ea
+44, env
->gpr_a
[7]);
151 cpu_stl_data(env
, ea
+48, env
->gpr_d
[4]);
152 cpu_stl_data(env
, ea
+52, env
->gpr_d
[5]);
153 cpu_stl_data(env
, ea
+56, env
->gpr_d
[6]);
154 cpu_stl_data(env
, ea
+60, env
->gpr_d
[7]);
157 static void restore_context_upper(CPUTriCoreState
*env
, int ea
,
158 target_ulong
*new_PCXI
, target_ulong
*new_PSW
)
160 *new_PCXI
= cpu_ldl_data(env
, ea
);
161 *new_PSW
= cpu_ldl_data(env
, ea
+4);
162 env
->gpr_a
[10] = cpu_ldl_data(env
, ea
+8);
163 env
->gpr_a
[11] = cpu_ldl_data(env
, ea
+12);
164 env
->gpr_d
[8] = cpu_ldl_data(env
, ea
+16);
165 env
->gpr_d
[9] = cpu_ldl_data(env
, ea
+20);
166 env
->gpr_d
[10] = cpu_ldl_data(env
, ea
+24);
167 env
->gpr_d
[11] = cpu_ldl_data(env
, ea
+28);
168 env
->gpr_a
[12] = cpu_ldl_data(env
, ea
+32);
169 env
->gpr_a
[13] = cpu_ldl_data(env
, ea
+36);
170 env
->gpr_a
[14] = cpu_ldl_data(env
, ea
+40);
171 env
->gpr_a
[15] = cpu_ldl_data(env
, ea
+44);
172 env
->gpr_d
[12] = cpu_ldl_data(env
, ea
+48);
173 env
->gpr_d
[13] = cpu_ldl_data(env
, ea
+52);
174 env
->gpr_d
[14] = cpu_ldl_data(env
, ea
+56);
175 env
->gpr_d
[15] = cpu_ldl_data(env
, ea
+60);
178 static void restore_context_lower(CPUTriCoreState
*env
, int ea
,
179 target_ulong
*ra
, target_ulong
*pcxi
)
181 *pcxi
= cpu_ldl_data(env
, ea
);
182 *ra
= cpu_ldl_data(env
, ea
+4);
183 env
->gpr_a
[2] = cpu_ldl_data(env
, ea
+8);
184 env
->gpr_a
[3] = cpu_ldl_data(env
, ea
+12);
185 env
->gpr_d
[0] = cpu_ldl_data(env
, ea
+16);
186 env
->gpr_d
[1] = cpu_ldl_data(env
, ea
+20);
187 env
->gpr_d
[2] = cpu_ldl_data(env
, ea
+24);
188 env
->gpr_d
[3] = cpu_ldl_data(env
, ea
+28);
189 env
->gpr_a
[4] = cpu_ldl_data(env
, ea
+32);
190 env
->gpr_a
[5] = cpu_ldl_data(env
, ea
+36);
191 env
->gpr_a
[6] = cpu_ldl_data(env
, ea
+40);
192 env
->gpr_a
[7] = cpu_ldl_data(env
, ea
+44);
193 env
->gpr_d
[4] = cpu_ldl_data(env
, ea
+48);
194 env
->gpr_d
[5] = cpu_ldl_data(env
, ea
+52);
195 env
->gpr_d
[6] = cpu_ldl_data(env
, ea
+56);
196 env
->gpr_d
[7] = cpu_ldl_data(env
, ea
+60);
199 void helper_call(CPUTriCoreState
*env
, uint32_t next_pc
)
201 target_ulong tmp_FCX
;
203 target_ulong new_FCX
;
207 /* if (FCX == 0) trap(FCU); */
211 /* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */
212 if (psw
& MASK_PSW_CDE
) {
213 if (cdc_increment(&psw
)) {
221 /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
222 ea
= ((env
->FCX
& MASK_FCX_FCXS
) << 12) +
223 ((env
->FCX
& MASK_FCX_FCXO
) << 6);
224 /* new_FCX = M(EA, word); */
225 new_FCX
= cpu_ldl_data(env
, ea
);
226 /* M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
227 A[12], A[13], A[14], A[15], D[12], D[13], D[14],
229 save_context_upper(env
, ea
);
231 /* PCXI.PCPN = ICR.CCPN; */
232 env
->PCXI
= (env
->PCXI
& 0xffffff) +
233 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
234 /* PCXI.PIE = ICR.IE; */
235 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
236 ((env
->ICR
& MASK_ICR_IE
) << 15));
238 env
->PCXI
|= MASK_PCXI_UL
;
240 /* PCXI[19: 0] = FCX[19: 0]; */
241 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
242 /* FCX[19: 0] = new_FCX[19: 0]; */
243 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
244 /* A[11] = next_pc[31: 0]; */
245 env
->gpr_a
[11] = next_pc
;
247 /* if (tmp_FCX == LCX) trap(FCD);*/
248 if (tmp_FCX
== env
->LCX
) {
254 void helper_ret(CPUTriCoreState
*env
)
257 target_ulong new_PCXI
;
258 target_ulong new_PSW
, psw
;
261 /* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/
262 if (env
->PSW
& MASK_PSW_CDE
) {
263 if (cdc_decrement(&(env
->PSW
))) {
267 /* if (PCXI[19: 0] == 0) then trap(CSU); */
268 if ((env
->PCXI
& 0xfffff) == 0) {
271 /* if (PCXI.UL == 0) then trap(CTYP); */
272 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
275 /* PC = {A11 [31: 1], 1’b0}; */
276 env
->PC
= env
->gpr_a
[11] & 0xfffffffe;
278 /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
279 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
280 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
281 /* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
282 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
283 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
284 /* M(EA, word) = FCX; */
285 cpu_stl_data(env
, ea
, env
->FCX
);
286 /* FCX[19: 0] = PCXI[19: 0]; */
287 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
288 /* PCXI = new_PCXI; */
289 env
->PCXI
= new_PCXI
;
291 if (tricore_feature(env
, TRICORE_FEATURE_13
)) {
293 psw_write(env
, new_PSW
);
295 /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
296 psw_write(env
, (new_PSW
& ~(0x3000000)) + (psw
& (0x3000000)));
300 void helper_bisr(CPUTriCoreState
*env
, uint32_t const9
)
302 target_ulong tmp_FCX
;
304 target_ulong new_FCX
;
311 ea
= ((env
->FCX
& 0xf0000) << 12) + ((env
->FCX
& 0xffff) << 6);
313 /* new_FCX = M(EA, word); */
314 new_FCX
= cpu_ldl_data(env
, ea
);
315 /* M(EA, 16 * word) = {PCXI, A[11], A[2], A[3], D[0], D[1], D[2], D[3], A[4]
316 , A[5], A[6], A[7], D[4], D[5], D[6], D[7]}; */
317 save_context_lower(env
, ea
);
320 /* PCXI.PCPN = ICR.CCPN */
321 env
->PCXI
= (env
->PCXI
& 0xffffff) +
322 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
323 /* PCXI.PIE = ICR.IE */
324 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
325 ((env
->ICR
& MASK_ICR_IE
) << 15));
327 env
->PCXI
&= ~(MASK_PCXI_UL
);
328 /* PCXI[19: 0] = FCX[19: 0] */
329 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
330 /* FXC[19: 0] = new_FCX[19: 0] */
331 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
333 env
->ICR
|= MASK_ICR_IE
;
335 env
->ICR
|= const9
; /* ICR.CCPN = const9[7: 0];*/
337 if (tmp_FCX
== env
->LCX
) {
342 void helper_rfe(CPUTriCoreState
*env
)
345 target_ulong new_PCXI
;
346 target_ulong new_PSW
;
347 /* if (PCXI[19: 0] == 0) then trap(CSU); */
348 if ((env
->PCXI
& 0xfffff) == 0) {
351 /* if (PCXI.UL == 0) then trap(CTYP); */
352 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
353 /* raise CTYP trap */
355 /* if (!cdc_zero() AND PSW.CDE) then trap(NEST); */
356 if (!cdc_zero(&(env
->PSW
)) && (env
->PSW
& MASK_PSW_CDE
)) {
359 /* ICR.IE = PCXI.PIE; */
360 env
->ICR
= (env
->ICR
& ~MASK_ICR_IE
) + ((env
->PCXI
& MASK_PCXI_PIE
) >> 15);
361 /* ICR.CCPN = PCXI.PCPN; */
362 env
->ICR
= (env
->ICR
& ~MASK_ICR_CCPN
) +
363 ((env
->PCXI
& MASK_PCXI_PCPN
) >> 24);
364 /*EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0};*/
365 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
366 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
367 /*{new_PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
368 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
369 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
370 /* M(EA, word) = FCX;*/
371 cpu_stl_data(env
, ea
, env
->FCX
);
372 /* FCX[19: 0] = PCXI[19: 0]; */
373 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
374 /* PCXI = new_PCXI; */
375 env
->PCXI
= new_PCXI
;
377 psw_write(env
, new_PSW
);
380 void helper_ldlcx(CPUTriCoreState
*env
, uint32_t ea
)
383 /* insn doesn't load PCXI and RA */
384 restore_context_lower(env
, ea
, &dummy
, &dummy
);
387 void helper_lducx(CPUTriCoreState
*env
, uint32_t ea
)
390 /* insn doesn't load PCXI and PSW */
391 restore_context_upper(env
, ea
, &dummy
, &dummy
);
394 void helper_stlcx(CPUTriCoreState
*env
, uint32_t ea
)
396 save_context_lower(env
, ea
);
399 void helper_stucx(CPUTriCoreState
*env
, uint32_t ea
)
401 save_context_upper(env
, ea
);
404 static inline void QEMU_NORETURN
do_raise_exception_err(CPUTriCoreState
*env
,
409 CPUState
*cs
= CPU(tricore_env_get_cpu(env
));
410 cs
->exception_index
= exception
;
411 env
->error_code
= error_code
;
414 /* now we have a real cpu fault */
415 cpu_restore_state(cs
, pc
);
421 void tlb_fill(CPUState
*cs
, target_ulong addr
, int is_write
, int mmu_idx
,
425 ret
= cpu_tricore_handle_mmu_fault(cs
, addr
, is_write
, mmu_idx
);
427 TriCoreCPU
*cpu
= TRICORE_CPU(cs
);
428 CPUTriCoreState
*env
= &cpu
->env
;
429 do_raise_exception_err(env
, cs
->exception_index
,
430 env
->error_code
, retaddr
);