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 /* Addressing mode helper */
25 static uint16_t reverse16(uint16_t val
)
27 uint8_t high
= (uint8_t)(val
>> 8);
28 uint8_t low
= (uint8_t)(val
& 0xff);
32 rl
= (uint16_t)((high
* 0x0202020202ULL
& 0x010884422010ULL
) % 1023);
33 rh
= (uint16_t)((low
* 0x0202020202ULL
& 0x010884422010ULL
) % 1023);
35 return (rh
<< 8) | rl
;
38 uint32_t helper_br_update(uint32_t reg
)
40 uint32_t index
= reg
& 0xffff;
41 uint32_t incr
= reg
>> 16;
42 uint32_t new_index
= reverse16(reverse16(index
) + reverse16(incr
));
43 return reg
- index
+ new_index
;
46 uint32_t helper_circ_update(uint32_t reg
, uint32_t off
)
48 uint32_t index
= reg
& 0xffff;
49 uint32_t length
= reg
>> 16;
50 int32_t new_index
= index
+ off
;
56 return reg
- index
+ new_index
;
59 #define SSOV(env, ret, arg, len) do { \
60 int64_t max_pos = INT##len ##_MAX; \
61 int64_t max_neg = INT##len ##_MIN; \
62 if (arg > max_pos) { \
63 env->PSW_USB_V = (1 << 31); \
64 env->PSW_USB_SV = (1 << 31); \
65 ret = (target_ulong)max_pos; \
67 if (arg < max_neg) { \
68 env->PSW_USB_V = (1 << 31); \
69 env->PSW_USB_SV = (1 << 31); \
70 ret = (target_ulong)max_neg; \
73 ret = (target_ulong)arg; \
76 env->PSW_USB_AV = arg ^ arg * 2u; \
77 env->PSW_USB_SAV |= env->PSW_USB_AV; \
80 target_ulong
helper_add_ssov(CPUTriCoreState
*env
, target_ulong r1
,
84 int64_t t1
= sextract64(r1
, 0, 32);
85 int64_t t2
= sextract64(r2
, 0, 32);
86 int64_t result
= t1
+ t2
;
87 SSOV(env
, ret
, result
, 32);
91 target_ulong
helper_sub_ssov(CPUTriCoreState
*env
, target_ulong r1
,
95 int64_t t1
= sextract64(r1
, 0, 32);
96 int64_t t2
= sextract64(r2
, 0, 32);
97 int64_t result
= t1
- t2
;
98 SSOV(env
, ret
, result
, 32);
102 /* context save area (CSA) related helpers */
104 static int cdc_increment(target_ulong
*psw
)
106 if ((*psw
& MASK_PSW_CDC
) == 0x7f) {
111 /* check for overflow */
112 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
113 int mask
= (1u << (7 - lo
)) - 1;
114 int count
= *psw
& mask
;
122 static int cdc_decrement(target_ulong
*psw
)
124 if ((*psw
& MASK_PSW_CDC
) == 0x7f) {
127 /* check for underflow */
128 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
129 int mask
= (1u << (7 - lo
)) - 1;
130 int count
= *psw
& mask
;
138 static bool cdc_zero(target_ulong
*psw
)
140 int cdc
= *psw
& MASK_PSW_CDC
;
141 /* Returns TRUE if PSW.CDC.COUNT == 0 or if PSW.CDC ==
142 7'b1111111, otherwise returns FALSE. */
147 int lo
= clo32((*psw
& MASK_PSW_CDC
) << (32 - 7));
148 int mask
= (1u << (7 - lo
)) - 1;
149 int count
= *psw
& mask
;
153 static void save_context_upper(CPUTriCoreState
*env
, int ea
)
155 cpu_stl_data(env
, ea
, env
->PCXI
);
156 cpu_stl_data(env
, ea
+4, env
->PSW
);
157 cpu_stl_data(env
, ea
+8, env
->gpr_a
[10]);
158 cpu_stl_data(env
, ea
+12, env
->gpr_a
[11]);
159 cpu_stl_data(env
, ea
+16, env
->gpr_d
[8]);
160 cpu_stl_data(env
, ea
+20, env
->gpr_d
[9]);
161 cpu_stl_data(env
, ea
+24, env
->gpr_d
[10]);
162 cpu_stl_data(env
, ea
+28, env
->gpr_d
[11]);
163 cpu_stl_data(env
, ea
+32, env
->gpr_a
[12]);
164 cpu_stl_data(env
, ea
+36, env
->gpr_a
[13]);
165 cpu_stl_data(env
, ea
+40, env
->gpr_a
[14]);
166 cpu_stl_data(env
, ea
+44, env
->gpr_a
[15]);
167 cpu_stl_data(env
, ea
+48, env
->gpr_d
[12]);
168 cpu_stl_data(env
, ea
+52, env
->gpr_d
[13]);
169 cpu_stl_data(env
, ea
+56, env
->gpr_d
[14]);
170 cpu_stl_data(env
, ea
+60, env
->gpr_d
[15]);
173 static void save_context_lower(CPUTriCoreState
*env
, int ea
)
175 cpu_stl_data(env
, ea
, env
->PCXI
);
176 cpu_stl_data(env
, ea
+4, env
->gpr_a
[11]);
177 cpu_stl_data(env
, ea
+8, env
->gpr_a
[2]);
178 cpu_stl_data(env
, ea
+12, env
->gpr_a
[3]);
179 cpu_stl_data(env
, ea
+16, env
->gpr_d
[0]);
180 cpu_stl_data(env
, ea
+20, env
->gpr_d
[1]);
181 cpu_stl_data(env
, ea
+24, env
->gpr_d
[2]);
182 cpu_stl_data(env
, ea
+28, env
->gpr_d
[3]);
183 cpu_stl_data(env
, ea
+32, env
->gpr_a
[4]);
184 cpu_stl_data(env
, ea
+36, env
->gpr_a
[5]);
185 cpu_stl_data(env
, ea
+40, env
->gpr_a
[6]);
186 cpu_stl_data(env
, ea
+44, env
->gpr_a
[7]);
187 cpu_stl_data(env
, ea
+48, env
->gpr_d
[4]);
188 cpu_stl_data(env
, ea
+52, env
->gpr_d
[5]);
189 cpu_stl_data(env
, ea
+56, env
->gpr_d
[6]);
190 cpu_stl_data(env
, ea
+60, env
->gpr_d
[7]);
193 static void restore_context_upper(CPUTriCoreState
*env
, int ea
,
194 target_ulong
*new_PCXI
, target_ulong
*new_PSW
)
196 *new_PCXI
= cpu_ldl_data(env
, ea
);
197 *new_PSW
= cpu_ldl_data(env
, ea
+4);
198 env
->gpr_a
[10] = cpu_ldl_data(env
, ea
+8);
199 env
->gpr_a
[11] = cpu_ldl_data(env
, ea
+12);
200 env
->gpr_d
[8] = cpu_ldl_data(env
, ea
+16);
201 env
->gpr_d
[9] = cpu_ldl_data(env
, ea
+20);
202 env
->gpr_d
[10] = cpu_ldl_data(env
, ea
+24);
203 env
->gpr_d
[11] = cpu_ldl_data(env
, ea
+28);
204 env
->gpr_a
[12] = cpu_ldl_data(env
, ea
+32);
205 env
->gpr_a
[13] = cpu_ldl_data(env
, ea
+36);
206 env
->gpr_a
[14] = cpu_ldl_data(env
, ea
+40);
207 env
->gpr_a
[15] = cpu_ldl_data(env
, ea
+44);
208 env
->gpr_d
[12] = cpu_ldl_data(env
, ea
+48);
209 env
->gpr_d
[13] = cpu_ldl_data(env
, ea
+52);
210 env
->gpr_d
[14] = cpu_ldl_data(env
, ea
+56);
211 env
->gpr_d
[15] = cpu_ldl_data(env
, ea
+60);
214 static void restore_context_lower(CPUTriCoreState
*env
, int ea
,
215 target_ulong
*ra
, target_ulong
*pcxi
)
217 *pcxi
= cpu_ldl_data(env
, ea
);
218 *ra
= cpu_ldl_data(env
, ea
+4);
219 env
->gpr_a
[2] = cpu_ldl_data(env
, ea
+8);
220 env
->gpr_a
[3] = cpu_ldl_data(env
, ea
+12);
221 env
->gpr_d
[0] = cpu_ldl_data(env
, ea
+16);
222 env
->gpr_d
[1] = cpu_ldl_data(env
, ea
+20);
223 env
->gpr_d
[2] = cpu_ldl_data(env
, ea
+24);
224 env
->gpr_d
[3] = cpu_ldl_data(env
, ea
+28);
225 env
->gpr_a
[4] = cpu_ldl_data(env
, ea
+32);
226 env
->gpr_a
[5] = cpu_ldl_data(env
, ea
+36);
227 env
->gpr_a
[6] = cpu_ldl_data(env
, ea
+40);
228 env
->gpr_a
[7] = cpu_ldl_data(env
, ea
+44);
229 env
->gpr_d
[4] = cpu_ldl_data(env
, ea
+48);
230 env
->gpr_d
[5] = cpu_ldl_data(env
, ea
+52);
231 env
->gpr_d
[6] = cpu_ldl_data(env
, ea
+56);
232 env
->gpr_d
[7] = cpu_ldl_data(env
, ea
+60);
235 void helper_call(CPUTriCoreState
*env
, uint32_t next_pc
)
237 target_ulong tmp_FCX
;
239 target_ulong new_FCX
;
243 /* if (FCX == 0) trap(FCU); */
247 /* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */
248 if (psw
& MASK_PSW_CDE
) {
249 if (cdc_increment(&psw
)) {
257 /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
258 ea
= ((env
->FCX
& MASK_FCX_FCXS
) << 12) +
259 ((env
->FCX
& MASK_FCX_FCXO
) << 6);
260 /* new_FCX = M(EA, word); */
261 new_FCX
= cpu_ldl_data(env
, ea
);
262 /* M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
263 A[12], A[13], A[14], A[15], D[12], D[13], D[14],
265 save_context_upper(env
, ea
);
267 /* PCXI.PCPN = ICR.CCPN; */
268 env
->PCXI
= (env
->PCXI
& 0xffffff) +
269 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
270 /* PCXI.PIE = ICR.IE; */
271 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
272 ((env
->ICR
& MASK_ICR_IE
) << 15));
274 env
->PCXI
|= MASK_PCXI_UL
;
276 /* PCXI[19: 0] = FCX[19: 0]; */
277 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
278 /* FCX[19: 0] = new_FCX[19: 0]; */
279 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
280 /* A[11] = next_pc[31: 0]; */
281 env
->gpr_a
[11] = next_pc
;
283 /* if (tmp_FCX == LCX) trap(FCD);*/
284 if (tmp_FCX
== env
->LCX
) {
290 void helper_ret(CPUTriCoreState
*env
)
293 target_ulong new_PCXI
;
294 target_ulong new_PSW
, psw
;
297 /* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/
298 if (env
->PSW
& MASK_PSW_CDE
) {
299 if (cdc_decrement(&(env
->PSW
))) {
303 /* if (PCXI[19: 0] == 0) then trap(CSU); */
304 if ((env
->PCXI
& 0xfffff) == 0) {
307 /* if (PCXI.UL == 0) then trap(CTYP); */
308 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
311 /* PC = {A11 [31: 1], 1’b0}; */
312 env
->PC
= env
->gpr_a
[11] & 0xfffffffe;
314 /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
315 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
316 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
317 /* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
318 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
319 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
320 /* M(EA, word) = FCX; */
321 cpu_stl_data(env
, ea
, env
->FCX
);
322 /* FCX[19: 0] = PCXI[19: 0]; */
323 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
324 /* PCXI = new_PCXI; */
325 env
->PCXI
= new_PCXI
;
327 if (tricore_feature(env
, TRICORE_FEATURE_13
)) {
329 psw_write(env
, new_PSW
);
331 /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
332 psw_write(env
, (new_PSW
& ~(0x3000000)) + (psw
& (0x3000000)));
336 void helper_bisr(CPUTriCoreState
*env
, uint32_t const9
)
338 target_ulong tmp_FCX
;
340 target_ulong new_FCX
;
347 ea
= ((env
->FCX
& 0xf0000) << 12) + ((env
->FCX
& 0xffff) << 6);
349 /* new_FCX = M(EA, word); */
350 new_FCX
= cpu_ldl_data(env
, ea
);
351 /* M(EA, 16 * word) = {PCXI, A[11], A[2], A[3], D[0], D[1], D[2], D[3], A[4]
352 , A[5], A[6], A[7], D[4], D[5], D[6], D[7]}; */
353 save_context_lower(env
, ea
);
356 /* PCXI.PCPN = ICR.CCPN */
357 env
->PCXI
= (env
->PCXI
& 0xffffff) +
358 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
359 /* PCXI.PIE = ICR.IE */
360 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
361 ((env
->ICR
& MASK_ICR_IE
) << 15));
363 env
->PCXI
&= ~(MASK_PCXI_UL
);
364 /* PCXI[19: 0] = FCX[19: 0] */
365 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
366 /* FXC[19: 0] = new_FCX[19: 0] */
367 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
369 env
->ICR
|= MASK_ICR_IE
;
371 env
->ICR
|= const9
; /* ICR.CCPN = const9[7: 0];*/
373 if (tmp_FCX
== env
->LCX
) {
378 void helper_rfe(CPUTriCoreState
*env
)
381 target_ulong new_PCXI
;
382 target_ulong new_PSW
;
383 /* if (PCXI[19: 0] == 0) then trap(CSU); */
384 if ((env
->PCXI
& 0xfffff) == 0) {
387 /* if (PCXI.UL == 0) then trap(CTYP); */
388 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
389 /* raise CTYP trap */
391 /* if (!cdc_zero() AND PSW.CDE) then trap(NEST); */
392 if (!cdc_zero(&(env
->PSW
)) && (env
->PSW
& MASK_PSW_CDE
)) {
395 /* ICR.IE = PCXI.PIE; */
396 env
->ICR
= (env
->ICR
& ~MASK_ICR_IE
) + ((env
->PCXI
& MASK_PCXI_PIE
) >> 15);
397 /* ICR.CCPN = PCXI.PCPN; */
398 env
->ICR
= (env
->ICR
& ~MASK_ICR_CCPN
) +
399 ((env
->PCXI
& MASK_PCXI_PCPN
) >> 24);
400 /*EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0};*/
401 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
402 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
403 /*{new_PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
404 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
405 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
406 /* M(EA, word) = FCX;*/
407 cpu_stl_data(env
, ea
, env
->FCX
);
408 /* FCX[19: 0] = PCXI[19: 0]; */
409 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
410 /* PCXI = new_PCXI; */
411 env
->PCXI
= new_PCXI
;
413 psw_write(env
, new_PSW
);
416 void helper_ldlcx(CPUTriCoreState
*env
, uint32_t ea
)
419 /* insn doesn't load PCXI and RA */
420 restore_context_lower(env
, ea
, &dummy
, &dummy
);
423 void helper_lducx(CPUTriCoreState
*env
, uint32_t ea
)
426 /* insn doesn't load PCXI and PSW */
427 restore_context_upper(env
, ea
, &dummy
, &dummy
);
430 void helper_stlcx(CPUTriCoreState
*env
, uint32_t ea
)
432 save_context_lower(env
, ea
);
435 void helper_stucx(CPUTriCoreState
*env
, uint32_t ea
)
437 save_context_upper(env
, ea
);
440 static inline void QEMU_NORETURN
do_raise_exception_err(CPUTriCoreState
*env
,
445 CPUState
*cs
= CPU(tricore_env_get_cpu(env
));
446 cs
->exception_index
= exception
;
447 env
->error_code
= error_code
;
450 /* now we have a real cpu fault */
451 cpu_restore_state(cs
, pc
);
457 void tlb_fill(CPUState
*cs
, target_ulong addr
, int is_write
, int mmu_idx
,
461 ret
= cpu_tricore_handle_mmu_fault(cs
, addr
, is_write
, mmu_idx
);
463 TriCoreCPU
*cpu
= TRICORE_CPU(cs
);
464 CPUTriCoreState
*env
= &cpu
->env
;
465 do_raise_exception_err(env
, cs
->exception_index
,
466 env
->error_code
, retaddr
);