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
,
118 target_ulong
*new_FCX
)
120 *new_FCX
= cpu_ldl_data(env
, ea
);
121 cpu_stl_data(env
, ea
, env
->PCXI
);
122 cpu_stl_data(env
, ea
+4, env
->PSW
);
123 cpu_stl_data(env
, ea
+8, env
->gpr_a
[10]);
124 cpu_stl_data(env
, ea
+12, env
->gpr_a
[11]);
125 cpu_stl_data(env
, ea
+16, env
->gpr_d
[8]);
126 cpu_stl_data(env
, ea
+20, env
->gpr_d
[9]);
127 cpu_stl_data(env
, ea
+24, env
->gpr_d
[10]);
128 cpu_stl_data(env
, ea
+28, env
->gpr_d
[11]);
129 cpu_stl_data(env
, ea
+32, env
->gpr_a
[12]);
130 cpu_stl_data(env
, ea
+36, env
->gpr_a
[13]);
131 cpu_stl_data(env
, ea
+40, env
->gpr_a
[14]);
132 cpu_stl_data(env
, ea
+44, env
->gpr_a
[15]);
133 cpu_stl_data(env
, ea
+48, env
->gpr_d
[12]);
134 cpu_stl_data(env
, ea
+52, env
->gpr_d
[13]);
135 cpu_stl_data(env
, ea
+56, env
->gpr_d
[14]);
136 cpu_stl_data(env
, ea
+60, env
->gpr_d
[15]);
140 static void save_context_lower(CPUTriCoreState
*env
, int ea
,
141 target_ulong
*new_FCX
)
143 *new_FCX
= cpu_ldl_data(env
, ea
);
144 cpu_stl_data(env
, ea
, env
->PCXI
);
145 cpu_stl_data(env
, ea
+4, env
->PSW
);
146 cpu_stl_data(env
, ea
+8, env
->gpr_a
[2]);
147 cpu_stl_data(env
, ea
+12, env
->gpr_a
[3]);
148 cpu_stl_data(env
, ea
+16, env
->gpr_d
[0]);
149 cpu_stl_data(env
, ea
+20, env
->gpr_d
[1]);
150 cpu_stl_data(env
, ea
+24, env
->gpr_d
[2]);
151 cpu_stl_data(env
, ea
+28, env
->gpr_d
[3]);
152 cpu_stl_data(env
, ea
+32, env
->gpr_a
[4]);
153 cpu_stl_data(env
, ea
+36, env
->gpr_a
[5]);
154 cpu_stl_data(env
, ea
+40, env
->gpr_a
[6]);
155 cpu_stl_data(env
, ea
+44, env
->gpr_a
[7]);
156 cpu_stl_data(env
, ea
+48, env
->gpr_d
[4]);
157 cpu_stl_data(env
, ea
+52, env
->gpr_d
[5]);
158 cpu_stl_data(env
, ea
+56, env
->gpr_d
[6]);
159 cpu_stl_data(env
, ea
+60, env
->gpr_d
[7]);
162 static void restore_context_upper(CPUTriCoreState
*env
, int ea
,
163 target_ulong
*new_PCXI
, target_ulong
*new_PSW
)
165 *new_PCXI
= cpu_ldl_data(env
, ea
);
166 *new_PSW
= cpu_ldl_data(env
, ea
+4);
167 env
->gpr_a
[10] = cpu_ldl_data(env
, ea
+8);
168 env
->gpr_a
[11] = cpu_ldl_data(env
, ea
+12);
169 env
->gpr_d
[8] = cpu_ldl_data(env
, ea
+16);
170 env
->gpr_d
[9] = cpu_ldl_data(env
, ea
+20);
171 env
->gpr_d
[10] = cpu_ldl_data(env
, ea
+24);
172 env
->gpr_d
[11] = cpu_ldl_data(env
, ea
+28);
173 env
->gpr_a
[12] = cpu_ldl_data(env
, ea
+32);
174 env
->gpr_a
[13] = cpu_ldl_data(env
, ea
+36);
175 env
->gpr_a
[14] = cpu_ldl_data(env
, ea
+40);
176 env
->gpr_a
[15] = cpu_ldl_data(env
, ea
+44);
177 env
->gpr_d
[12] = cpu_ldl_data(env
, ea
+48);
178 env
->gpr_d
[13] = cpu_ldl_data(env
, ea
+52);
179 env
->gpr_d
[14] = cpu_ldl_data(env
, ea
+56);
180 env
->gpr_d
[15] = cpu_ldl_data(env
, ea
+60);
181 cpu_stl_data(env
, ea
, env
->FCX
);
184 void helper_call(CPUTriCoreState
*env
, uint32_t next_pc
)
186 target_ulong tmp_FCX
;
188 target_ulong new_FCX
;
192 /* if (FCX == 0) trap(FCU); */
196 /* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */
197 if (psw
& MASK_PSW_CDE
) {
198 if (cdc_increment(&psw
)) {
206 /* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
207 ea
= ((env
->FCX
& MASK_FCX_FCXS
) << 12) +
208 ((env
->FCX
& MASK_FCX_FCXO
) << 6);
209 /* new_FCX = M(EA, word);
210 M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
211 A[12], A[13], A[14], A[15], D[12], D[13], D[14],
213 save_context_upper(env
, ea
, &new_FCX
);
215 /* PCXI.PCPN = ICR.CCPN; */
216 env
->PCXI
= (env
->PCXI
& 0xffffff) +
217 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
218 /* PCXI.PIE = ICR.IE; */
219 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
220 ((env
->ICR
& MASK_ICR_IE
) << 15));
222 env
->PCXI
|= MASK_PCXI_UL
;
224 /* PCXI[19: 0] = FCX[19: 0]; */
225 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
226 /* FCX[19: 0] = new_FCX[19: 0]; */
227 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
228 /* A[11] = next_pc[31: 0]; */
229 env
->gpr_a
[11] = next_pc
;
231 /* if (tmp_FCX == LCX) trap(FCD);*/
232 if (tmp_FCX
== env
->LCX
) {
238 void helper_ret(CPUTriCoreState
*env
)
241 target_ulong new_PCXI
;
242 target_ulong new_PSW
, psw
;
245 /* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/
246 if (env
->PSW
& MASK_PSW_CDE
) {
247 if (cdc_decrement(&(env
->PSW
))) {
251 /* if (PCXI[19: 0] == 0) then trap(CSU); */
252 if ((env
->PCXI
& 0xfffff) == 0) {
255 /* if (PCXI.UL == 0) then trap(CTYP); */
256 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
259 /* PC = {A11 [31: 1], 1’b0}; */
260 env
->PC
= env
->gpr_a
[11] & 0xfffffffe;
262 /* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
263 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
264 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
265 /* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
266 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word);
267 M(EA, word) = FCX; */
268 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
269 /* FCX[19: 0] = PCXI[19: 0]; */
270 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
271 /* PCXI = new_PCXI; */
272 env
->PCXI
= new_PCXI
;
274 if (tricore_feature(env
, TRICORE_FEATURE_13
)) {
276 psw_write(env
, new_PSW
);
278 /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
279 psw_write(env
, (new_PSW
& ~(0x3000000)) + (psw
& (0x3000000)));
283 void helper_bisr(CPUTriCoreState
*env
, uint32_t const9
)
285 target_ulong tmp_FCX
;
287 target_ulong new_FCX
;
294 ea
= ((env
->FCX
& 0xf0000) << 12) + ((env
->FCX
& 0xffff) << 6);
296 save_context_lower(env
, ea
, &new_FCX
);
298 /* PCXI.PCPN = ICR.CCPN */
299 env
->PCXI
= (env
->PCXI
& 0xffffff) +
300 ((env
->ICR
& MASK_ICR_CCPN
) << 24);
301 /* PCXI.PIE = ICR.IE */
302 env
->PCXI
= ((env
->PCXI
& ~MASK_PCXI_PIE
) +
303 ((env
->ICR
& MASK_ICR_IE
) << 15));
305 env
->PCXI
&= ~(MASK_PCXI_UL
);
306 /* PCXI[19: 0] = FCX[19: 0] */
307 env
->PCXI
= (env
->PCXI
& 0xfff00000) + (env
->FCX
& 0xfffff);
308 /* FXC[19: 0] = new_FCX[19: 0] */
309 env
->FCX
= (env
->FCX
& 0xfff00000) + (new_FCX
& 0xfffff);
311 env
->ICR
|= MASK_ICR_IE
;
313 env
->ICR
|= const9
; /* ICR.CCPN = const9[7: 0];*/
315 if (tmp_FCX
== env
->LCX
) {
320 void helper_rfe(CPUTriCoreState
*env
)
323 target_ulong new_PCXI
;
324 target_ulong new_PSW
;
325 /* if (PCXI[19: 0] == 0) then trap(CSU); */
326 if ((env
->PCXI
& 0xfffff) == 0) {
329 /* if (PCXI.UL == 0) then trap(CTYP); */
330 if ((env
->PCXI
& MASK_PCXI_UL
) == 0) {
331 /* raise CTYP trap */
333 /* if (!cdc_zero() AND PSW.CDE) then trap(NEST); */
334 if (!cdc_zero(&(env
->PSW
)) && (env
->PSW
& MASK_PSW_CDE
)) {
337 /* ICR.IE = PCXI.PIE; */
338 env
->ICR
= (env
->ICR
& ~MASK_ICR_IE
) + ((env
->PCXI
& MASK_PCXI_PIE
) >> 15);
339 /* ICR.CCPN = PCXI.PCPN; */
340 env
->ICR
= (env
->ICR
& ~MASK_ICR_CCPN
) +
341 ((env
->PCXI
& MASK_PCXI_PCPN
) >> 24);
342 /*EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0};*/
343 ea
= ((env
->PCXI
& MASK_PCXI_PCXS
) << 12) +
344 ((env
->PCXI
& MASK_PCXI_PCXO
) << 6);
345 /*{new_PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
346 A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word);
348 restore_context_upper(env
, ea
, &new_PCXI
, &new_PSW
);
349 /* FCX[19: 0] = PCXI[19: 0]; */
350 env
->FCX
= (env
->FCX
& 0xfff00000) + (env
->PCXI
& 0x000fffff);
351 /* PCXI = new_PCXI; */
352 env
->PCXI
= new_PCXI
;
354 psw_write(env
, new_PSW
);
357 static inline void QEMU_NORETURN
do_raise_exception_err(CPUTriCoreState
*env
,
362 CPUState
*cs
= CPU(tricore_env_get_cpu(env
));
363 cs
->exception_index
= exception
;
364 env
->error_code
= error_code
;
367 /* now we have a real cpu fault */
368 cpu_restore_state(cs
, pc
);
374 static inline void QEMU_NORETURN
do_raise_exception(CPUTriCoreState
*env
,
378 do_raise_exception_err(env
, exception
, 0, pc
);
381 void tlb_fill(CPUState
*cs
, target_ulong addr
, int is_write
, int mmu_idx
,
385 ret
= cpu_tricore_handle_mmu_fault(cs
, addr
, is_write
, mmu_idx
);
387 TriCoreCPU
*cpu
= TRICORE_CPU(cs
);
388 CPUTriCoreState
*env
= &cpu
->env
;
389 do_raise_exception_err(env
, cs
->exception_index
,
390 env
->error_code
, retaddr
);