]>
Commit | Line | Data |
---|---|---|
e67db06e JL |
1 | /* |
2 | * OpenRISC translation | |
3 | * | |
4 | * Copyright (c) 2011-2012 Jia Liu <[email protected]> | |
5 | * Feng Gao <[email protected]> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
779fc6ad | 10 | * version 2.1 of the License, or (at your option) any later version. |
e67db06e JL |
11 | * |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
ed2decc6 | 21 | #include "qemu/osdep.h" |
e67db06e | 22 | #include "cpu.h" |
022c62cb | 23 | #include "exec/exec-all.h" |
76cad711 | 24 | #include "disas/disas.h" |
dcb32f1d | 25 | #include "tcg/tcg-op.h" |
1de7afc9 | 26 | #include "qemu/log.h" |
1de7afc9 | 27 | #include "qemu/bitops.h" |
90c84c56 | 28 | #include "qemu/qemu-print.h" |
f08b6170 | 29 | #include "exec/cpu_ldst.h" |
77fc6f5e | 30 | #include "exec/translator.h" |
bbe418f2 | 31 | |
2ef6175a RH |
32 | #include "exec/helper-proto.h" |
33 | #include "exec/helper-gen.h" | |
7de9729f | 34 | #include "exec/gen-icount.h" |
e67db06e | 35 | |
508127e2 | 36 | #include "exec/log.h" |
a7e30d84 | 37 | |
77fc6f5e | 38 | /* is_jmp field values */ |
64e46c95 | 39 | #define DISAS_EXIT DISAS_TARGET_0 /* force exit to main loop */ |
8000ba56 | 40 | #define DISAS_JUMP DISAS_TARGET_1 /* exit via jmp_pc/jmp_pc_imm */ |
77fc6f5e | 41 | |
bbe418f2 | 42 | typedef struct DisasContext { |
1ffa4bce | 43 | DisasContextBase base; |
bbe418f2 | 44 | uint32_t mem_idx; |
a01deb36 | 45 | uint32_t tb_flags; |
bbe418f2 | 46 | uint32_t delayed_branch; |
fe636d37 | 47 | uint32_t cpucfgr; |
2b13b4b9 | 48 | uint32_t avr; |
8000ba56 RH |
49 | |
50 | /* If not -1, jmp_pc contains this value and so is a direct jump. */ | |
51 | target_ulong jmp_pc_imm; | |
d29f4368 RH |
52 | |
53 | /* The temporary corresponding to register 0 for this compilation. */ | |
54 | TCGv R0; | |
118671f0 RH |
55 | /* The constant zero. */ |
56 | TCGv zero; | |
bbe418f2 JL |
57 | } DisasContext; |
58 | ||
2ba65417 RH |
59 | static inline bool is_user(DisasContext *dc) |
60 | { | |
61 | #ifdef CONFIG_USER_ONLY | |
62 | return true; | |
63 | #else | |
b9bed1b9 | 64 | return !(dc->tb_flags & TB_FLAGS_SM); |
2ba65417 RH |
65 | #endif |
66 | } | |
67 | ||
7de9729f | 68 | /* Include the auto-generated decoder. */ |
abff1abf | 69 | #include "decode-insns.c.inc" |
7de9729f | 70 | |
bbe418f2 | 71 | static TCGv cpu_sr; |
8bba7619 | 72 | static TCGv cpu_regs[32]; |
bbe418f2 JL |
73 | static TCGv cpu_pc; |
74 | static TCGv jmp_pc; /* l.jr/l.jalr temp pc */ | |
bbe418f2 | 75 | static TCGv cpu_ppc; |
84775c43 | 76 | static TCGv cpu_sr_f; /* bf/bnf, F flag taken */ |
97458071 RH |
77 | static TCGv cpu_sr_cy; /* carry (unsigned overflow) */ |
78 | static TCGv cpu_sr_ov; /* signed overflow */ | |
930c3d00 RH |
79 | static TCGv cpu_lock_addr; |
80 | static TCGv cpu_lock_value; | |
bbe418f2 | 81 | static TCGv_i32 fpcsr; |
6f7332ba | 82 | static TCGv_i64 cpu_mac; /* MACHI:MACLO */ |
a01deb36 | 83 | static TCGv_i32 cpu_dflag; |
bbe418f2 | 84 | |
e67db06e JL |
85 | void openrisc_translate_init(void) |
86 | { | |
bbe418f2 JL |
87 | static const char * const regnames[] = { |
88 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
89 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
90 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
91 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
92 | }; | |
93 | int i; | |
94 | ||
e1ccc054 | 95 | cpu_sr = tcg_global_mem_new(cpu_env, |
bbe418f2 | 96 | offsetof(CPUOpenRISCState, sr), "sr"); |
a01deb36 RH |
97 | cpu_dflag = tcg_global_mem_new_i32(cpu_env, |
98 | offsetof(CPUOpenRISCState, dflag), | |
99 | "dflag"); | |
e1ccc054 | 100 | cpu_pc = tcg_global_mem_new(cpu_env, |
bbe418f2 | 101 | offsetof(CPUOpenRISCState, pc), "pc"); |
e1ccc054 | 102 | cpu_ppc = tcg_global_mem_new(cpu_env, |
bbe418f2 | 103 | offsetof(CPUOpenRISCState, ppc), "ppc"); |
e1ccc054 | 104 | jmp_pc = tcg_global_mem_new(cpu_env, |
bbe418f2 | 105 | offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc"); |
84775c43 RH |
106 | cpu_sr_f = tcg_global_mem_new(cpu_env, |
107 | offsetof(CPUOpenRISCState, sr_f), "sr_f"); | |
97458071 RH |
108 | cpu_sr_cy = tcg_global_mem_new(cpu_env, |
109 | offsetof(CPUOpenRISCState, sr_cy), "sr_cy"); | |
110 | cpu_sr_ov = tcg_global_mem_new(cpu_env, | |
111 | offsetof(CPUOpenRISCState, sr_ov), "sr_ov"); | |
930c3d00 RH |
112 | cpu_lock_addr = tcg_global_mem_new(cpu_env, |
113 | offsetof(CPUOpenRISCState, lock_addr), | |
114 | "lock_addr"); | |
115 | cpu_lock_value = tcg_global_mem_new(cpu_env, | |
116 | offsetof(CPUOpenRISCState, lock_value), | |
117 | "lock_value"); | |
e1ccc054 | 118 | fpcsr = tcg_global_mem_new_i32(cpu_env, |
bbe418f2 JL |
119 | offsetof(CPUOpenRISCState, fpcsr), |
120 | "fpcsr"); | |
6f7332ba RH |
121 | cpu_mac = tcg_global_mem_new_i64(cpu_env, |
122 | offsetof(CPUOpenRISCState, mac), | |
123 | "mac"); | |
bbe418f2 | 124 | for (i = 0; i < 32; i++) { |
8bba7619 RH |
125 | cpu_regs[i] = tcg_global_mem_new(cpu_env, |
126 | offsetof(CPUOpenRISCState, | |
127 | shadow_gpr[0][i]), | |
128 | regnames[i]); | |
bbe418f2 | 129 | } |
bbe418f2 JL |
130 | } |
131 | ||
bbe418f2 JL |
132 | static void gen_exception(DisasContext *dc, unsigned int excp) |
133 | { | |
af42d354 | 134 | gen_helper_exception(cpu_env, tcg_constant_i32(excp)); |
bbe418f2 JL |
135 | } |
136 | ||
137 | static void gen_illegal_exception(DisasContext *dc) | |
138 | { | |
1ffa4bce | 139 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); |
bbe418f2 | 140 | gen_exception(dc, EXCP_ILLEGAL); |
1ffa4bce | 141 | dc->base.is_jmp = DISAS_NORETURN; |
bbe418f2 JL |
142 | } |
143 | ||
2b13b4b9 RH |
144 | static bool check_v1_3(DisasContext *dc) |
145 | { | |
146 | return dc->avr >= 0x01030000; | |
147 | } | |
148 | ||
fe636d37 | 149 | static bool check_of32s(DisasContext *dc) |
bbe418f2 | 150 | { |
fe636d37 | 151 | return dc->cpucfgr & CPUCFGR_OF32S; |
bbe418f2 | 152 | } |
bbe418f2 | 153 | |
62f2b038 RH |
154 | static bool check_of64a32s(DisasContext *dc) |
155 | { | |
156 | return dc->cpucfgr & CPUCFGR_OF64A32S; | |
157 | } | |
158 | ||
8bba7619 RH |
159 | static TCGv cpu_R(DisasContext *dc, int reg) |
160 | { | |
d29f4368 RH |
161 | if (reg == 0) { |
162 | return dc->R0; | |
163 | } else { | |
164 | return cpu_regs[reg]; | |
165 | } | |
8bba7619 RH |
166 | } |
167 | ||
cdd0f459 RH |
168 | /* |
169 | * We're about to write to REG. On the off-chance that the user is | |
170 | * writing to R0, re-instate the architectural register. | |
171 | */ | |
172 | static void check_r0_write(DisasContext *dc, int reg) | |
173 | { | |
174 | if (unlikely(reg == 0)) { | |
d29f4368 | 175 | dc->R0 = cpu_regs[0]; |
cdd0f459 RH |
176 | } |
177 | } | |
6597c28d | 178 | |
97458071 | 179 | static void gen_ove_cy(DisasContext *dc) |
9ecaa27e | 180 | { |
0c53d734 | 181 | if (dc->tb_flags & SR_OVE) { |
97458071 | 182 | gen_helper_ove_cy(cpu_env); |
0c53d734 | 183 | } |
9ecaa27e RH |
184 | } |
185 | ||
97458071 | 186 | static void gen_ove_ov(DisasContext *dc) |
9ecaa27e | 187 | { |
0c53d734 | 188 | if (dc->tb_flags & SR_OVE) { |
97458071 | 189 | gen_helper_ove_ov(cpu_env); |
0c53d734 | 190 | } |
9ecaa27e RH |
191 | } |
192 | ||
97458071 | 193 | static void gen_ove_cyov(DisasContext *dc) |
9ecaa27e | 194 | { |
0c53d734 | 195 | if (dc->tb_flags & SR_OVE) { |
97458071 | 196 | gen_helper_ove_cyov(cpu_env); |
0c53d734 | 197 | } |
9ecaa27e RH |
198 | } |
199 | ||
200 | static void gen_add(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
201 | { | |
e0efc48f | 202 | TCGv t0 = tcg_temp_new(); |
9ecaa27e | 203 | TCGv res = tcg_temp_new(); |
9ecaa27e | 204 | |
e0efc48f | 205 | tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, srcb, dc->zero); |
97458071 | 206 | tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); |
9ecaa27e | 207 | tcg_gen_xor_tl(t0, res, srcb); |
97458071 | 208 | tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); |
9ecaa27e RH |
209 | tcg_temp_free(t0); |
210 | ||
211 | tcg_gen_mov_tl(dest, res); | |
212 | tcg_temp_free(res); | |
213 | ||
97458071 | 214 | gen_ove_cyov(dc); |
9ecaa27e RH |
215 | } |
216 | ||
217 | static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
218 | { | |
e0efc48f | 219 | TCGv t0 = tcg_temp_new(); |
9ecaa27e | 220 | TCGv res = tcg_temp_new(); |
9ecaa27e | 221 | |
e0efc48f RH |
222 | tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, cpu_sr_cy, dc->zero); |
223 | tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, dc->zero); | |
97458071 | 224 | tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); |
9ecaa27e | 225 | tcg_gen_xor_tl(t0, res, srcb); |
97458071 | 226 | tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); |
9ecaa27e RH |
227 | tcg_temp_free(t0); |
228 | ||
229 | tcg_gen_mov_tl(dest, res); | |
230 | tcg_temp_free(res); | |
231 | ||
97458071 | 232 | gen_ove_cyov(dc); |
9ecaa27e RH |
233 | } |
234 | ||
235 | static void gen_sub(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
236 | { | |
237 | TCGv res = tcg_temp_new(); | |
9ecaa27e RH |
238 | |
239 | tcg_gen_sub_tl(res, srca, srcb); | |
97458071 RH |
240 | tcg_gen_xor_tl(cpu_sr_cy, srca, srcb); |
241 | tcg_gen_xor_tl(cpu_sr_ov, res, srcb); | |
242 | tcg_gen_and_tl(cpu_sr_ov, cpu_sr_ov, cpu_sr_cy); | |
243 | tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_cy, srca, srcb); | |
9ecaa27e RH |
244 | |
245 | tcg_gen_mov_tl(dest, res); | |
246 | tcg_temp_free(res); | |
247 | ||
97458071 | 248 | gen_ove_cyov(dc); |
9ecaa27e RH |
249 | } |
250 | ||
251 | static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
252 | { | |
9ecaa27e RH |
253 | TCGv t0 = tcg_temp_new(); |
254 | ||
97458071 | 255 | tcg_gen_muls2_tl(dest, cpu_sr_ov, srca, srcb); |
9ecaa27e | 256 | tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1); |
97458071 | 257 | tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0); |
9ecaa27e RH |
258 | tcg_temp_free(t0); |
259 | ||
97458071 RH |
260 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); |
261 | gen_ove_ov(dc); | |
9ecaa27e RH |
262 | } |
263 | ||
264 | static void gen_mulu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
265 | { | |
97458071 RH |
266 | tcg_gen_muls2_tl(dest, cpu_sr_cy, srca, srcb); |
267 | tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_cy, cpu_sr_cy, 0); | |
9ecaa27e | 268 | |
97458071 | 269 | gen_ove_cy(dc); |
9ecaa27e RH |
270 | } |
271 | ||
272 | static void gen_div(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
273 | { | |
9ecaa27e RH |
274 | TCGv t0 = tcg_temp_new(); |
275 | ||
97458071 | 276 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_ov, srcb, 0); |
9ecaa27e RH |
277 | /* The result of divide-by-zero is undefined. |
278 | Supress the host-side exception by dividing by 1. */ | |
97458071 | 279 | tcg_gen_or_tl(t0, srcb, cpu_sr_ov); |
9ecaa27e RH |
280 | tcg_gen_div_tl(dest, srca, t0); |
281 | tcg_temp_free(t0); | |
282 | ||
97458071 RH |
283 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); |
284 | gen_ove_ov(dc); | |
9ecaa27e RH |
285 | } |
286 | ||
287 | static void gen_divu(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) | |
288 | { | |
9ecaa27e RH |
289 | TCGv t0 = tcg_temp_new(); |
290 | ||
97458071 | 291 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_cy, srcb, 0); |
9ecaa27e RH |
292 | /* The result of divide-by-zero is undefined. |
293 | Supress the host-side exception by dividing by 1. */ | |
97458071 | 294 | tcg_gen_or_tl(t0, srcb, cpu_sr_cy); |
9ecaa27e RH |
295 | tcg_gen_divu_tl(dest, srca, t0); |
296 | tcg_temp_free(t0); | |
297 | ||
97458071 | 298 | gen_ove_cy(dc); |
9ecaa27e | 299 | } |
da1d7759 | 300 | |
cc5de49e RH |
301 | static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb) |
302 | { | |
303 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
304 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
305 | ||
306 | tcg_gen_ext_tl_i64(t1, srca); | |
307 | tcg_gen_ext_tl_i64(t2, srcb); | |
308 | if (TARGET_LONG_BITS == 32) { | |
309 | tcg_gen_mul_i64(cpu_mac, t1, t2); | |
310 | tcg_gen_movi_tl(cpu_sr_ov, 0); | |
311 | } else { | |
312 | TCGv_i64 high = tcg_temp_new_i64(); | |
313 | ||
314 | tcg_gen_muls2_i64(cpu_mac, high, t1, t2); | |
315 | tcg_gen_sari_i64(t1, cpu_mac, 63); | |
316 | tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high); | |
317 | tcg_temp_free_i64(high); | |
318 | tcg_gen_trunc_i64_tl(cpu_sr_ov, t1); | |
319 | tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); | |
320 | ||
321 | gen_ove_ov(dc); | |
322 | } | |
323 | tcg_temp_free_i64(t1); | |
324 | tcg_temp_free_i64(t2); | |
325 | } | |
326 | ||
327 | static void gen_muldu(DisasContext *dc, TCGv srca, TCGv srcb) | |
328 | { | |
329 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
330 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
331 | ||
332 | tcg_gen_extu_tl_i64(t1, srca); | |
333 | tcg_gen_extu_tl_i64(t2, srcb); | |
334 | if (TARGET_LONG_BITS == 32) { | |
335 | tcg_gen_mul_i64(cpu_mac, t1, t2); | |
336 | tcg_gen_movi_tl(cpu_sr_cy, 0); | |
337 | } else { | |
338 | TCGv_i64 high = tcg_temp_new_i64(); | |
339 | ||
340 | tcg_gen_mulu2_i64(cpu_mac, high, t1, t2); | |
341 | tcg_gen_setcondi_i64(TCG_COND_NE, high, high, 0); | |
342 | tcg_gen_trunc_i64_tl(cpu_sr_cy, high); | |
343 | tcg_temp_free_i64(high); | |
344 | ||
345 | gen_ove_cy(dc); | |
346 | } | |
347 | tcg_temp_free_i64(t1); | |
348 | tcg_temp_free_i64(t2); | |
349 | } | |
350 | ||
6f7332ba RH |
351 | static void gen_mac(DisasContext *dc, TCGv srca, TCGv srcb) |
352 | { | |
353 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
354 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
355 | ||
356 | tcg_gen_ext_tl_i64(t1, srca); | |
357 | tcg_gen_ext_tl_i64(t2, srcb); | |
358 | tcg_gen_mul_i64(t1, t1, t2); | |
359 | ||
360 | /* Note that overflow is only computed during addition stage. */ | |
361 | tcg_gen_xor_i64(t2, cpu_mac, t1); | |
362 | tcg_gen_add_i64(cpu_mac, cpu_mac, t1); | |
363 | tcg_gen_xor_i64(t1, t1, cpu_mac); | |
364 | tcg_gen_andc_i64(t1, t1, t2); | |
365 | tcg_temp_free_i64(t2); | |
366 | ||
367 | #if TARGET_LONG_BITS == 32 | |
368 | tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); | |
369 | #else | |
370 | tcg_gen_mov_i64(cpu_sr_ov, t1); | |
371 | #endif | |
372 | tcg_temp_free_i64(t1); | |
373 | ||
374 | gen_ove_ov(dc); | |
375 | } | |
376 | ||
cc5de49e RH |
377 | static void gen_macu(DisasContext *dc, TCGv srca, TCGv srcb) |
378 | { | |
379 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
380 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
381 | ||
382 | tcg_gen_extu_tl_i64(t1, srca); | |
383 | tcg_gen_extu_tl_i64(t2, srcb); | |
384 | tcg_gen_mul_i64(t1, t1, t2); | |
385 | tcg_temp_free_i64(t2); | |
386 | ||
387 | /* Note that overflow is only computed during addition stage. */ | |
388 | tcg_gen_add_i64(cpu_mac, cpu_mac, t1); | |
389 | tcg_gen_setcond_i64(TCG_COND_LTU, t1, cpu_mac, t1); | |
390 | tcg_gen_trunc_i64_tl(cpu_sr_cy, t1); | |
391 | tcg_temp_free_i64(t1); | |
392 | ||
393 | gen_ove_cy(dc); | |
394 | } | |
395 | ||
6f7332ba RH |
396 | static void gen_msb(DisasContext *dc, TCGv srca, TCGv srcb) |
397 | { | |
398 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
399 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
400 | ||
401 | tcg_gen_ext_tl_i64(t1, srca); | |
402 | tcg_gen_ext_tl_i64(t2, srcb); | |
403 | tcg_gen_mul_i64(t1, t1, t2); | |
404 | ||
405 | /* Note that overflow is only computed during subtraction stage. */ | |
406 | tcg_gen_xor_i64(t2, cpu_mac, t1); | |
407 | tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); | |
408 | tcg_gen_xor_i64(t1, t1, cpu_mac); | |
409 | tcg_gen_and_i64(t1, t1, t2); | |
410 | tcg_temp_free_i64(t2); | |
411 | ||
412 | #if TARGET_LONG_BITS == 32 | |
413 | tcg_gen_extrh_i64_i32(cpu_sr_ov, t1); | |
414 | #else | |
415 | tcg_gen_mov_i64(cpu_sr_ov, t1); | |
416 | #endif | |
417 | tcg_temp_free_i64(t1); | |
418 | ||
419 | gen_ove_ov(dc); | |
420 | } | |
421 | ||
cc5de49e RH |
422 | static void gen_msbu(DisasContext *dc, TCGv srca, TCGv srcb) |
423 | { | |
424 | TCGv_i64 t1 = tcg_temp_new_i64(); | |
425 | TCGv_i64 t2 = tcg_temp_new_i64(); | |
426 | ||
427 | tcg_gen_extu_tl_i64(t1, srca); | |
428 | tcg_gen_extu_tl_i64(t2, srcb); | |
429 | tcg_gen_mul_i64(t1, t1, t2); | |
430 | ||
431 | /* Note that overflow is only computed during subtraction stage. */ | |
432 | tcg_gen_setcond_i64(TCG_COND_LTU, t2, cpu_mac, t1); | |
433 | tcg_gen_sub_i64(cpu_mac, cpu_mac, t1); | |
434 | tcg_gen_trunc_i64_tl(cpu_sr_cy, t2); | |
435 | tcg_temp_free_i64(t2); | |
436 | tcg_temp_free_i64(t1); | |
437 | ||
438 | gen_ove_cy(dc); | |
439 | } | |
440 | ||
3a7be554 | 441 | static bool trans_l_add(DisasContext *dc, arg_dab *a) |
bbe418f2 | 442 | { |
cdd0f459 | 443 | check_r0_write(dc, a->d); |
8bba7619 | 444 | gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
445 | return true; |
446 | } | |
bbe418f2 | 447 | |
3a7be554 | 448 | static bool trans_l_addc(DisasContext *dc, arg_dab *a) |
6ad216ab | 449 | { |
cdd0f459 | 450 | check_r0_write(dc, a->d); |
8bba7619 | 451 | gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
452 | return true; |
453 | } | |
cf2ae442 | 454 | |
3a7be554 | 455 | static bool trans_l_sub(DisasContext *dc, arg_dab *a) |
6ad216ab | 456 | { |
cdd0f459 | 457 | check_r0_write(dc, a->d); |
8bba7619 | 458 | gen_sub(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
459 | return true; |
460 | } | |
bbe418f2 | 461 | |
3a7be554 | 462 | static bool trans_l_and(DisasContext *dc, arg_dab *a) |
6ad216ab | 463 | { |
cdd0f459 | 464 | check_r0_write(dc, a->d); |
8bba7619 | 465 | tcg_gen_and_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
466 | return true; |
467 | } | |
468 | ||
3a7be554 | 469 | static bool trans_l_or(DisasContext *dc, arg_dab *a) |
6ad216ab | 470 | { |
cdd0f459 | 471 | check_r0_write(dc, a->d); |
8bba7619 | 472 | tcg_gen_or_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
473 | return true; |
474 | } | |
475 | ||
3a7be554 | 476 | static bool trans_l_xor(DisasContext *dc, arg_dab *a) |
6ad216ab | 477 | { |
cdd0f459 | 478 | check_r0_write(dc, a->d); |
8bba7619 | 479 | tcg_gen_xor_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
480 | return true; |
481 | } | |
bbe418f2 | 482 | |
3a7be554 | 483 | static bool trans_l_sll(DisasContext *dc, arg_dab *a) |
6ad216ab | 484 | { |
cdd0f459 | 485 | check_r0_write(dc, a->d); |
8bba7619 | 486 | tcg_gen_shl_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
487 | return true; |
488 | } | |
bbe418f2 | 489 | |
3a7be554 | 490 | static bool trans_l_srl(DisasContext *dc, arg_dab *a) |
6ad216ab | 491 | { |
cdd0f459 | 492 | check_r0_write(dc, a->d); |
8bba7619 | 493 | tcg_gen_shr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
494 | return true; |
495 | } | |
cc5de49e | 496 | |
3a7be554 | 497 | static bool trans_l_sra(DisasContext *dc, arg_dab *a) |
6ad216ab | 498 | { |
cdd0f459 | 499 | check_r0_write(dc, a->d); |
8bba7619 | 500 | tcg_gen_sar_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
501 | return true; |
502 | } | |
bbe418f2 | 503 | |
3a7be554 | 504 | static bool trans_l_ror(DisasContext *dc, arg_dab *a) |
6ad216ab | 505 | { |
cdd0f459 | 506 | check_r0_write(dc, a->d); |
8bba7619 | 507 | tcg_gen_rotr_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
508 | return true; |
509 | } | |
bbe418f2 | 510 | |
3a7be554 | 511 | static bool trans_l_exths(DisasContext *dc, arg_da *a) |
6ad216ab | 512 | { |
cdd0f459 | 513 | check_r0_write(dc, a->d); |
8bba7619 | 514 | tcg_gen_ext16s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); |
6ad216ab RH |
515 | return true; |
516 | } | |
cc5de49e | 517 | |
3a7be554 | 518 | static bool trans_l_extbs(DisasContext *dc, arg_da *a) |
6ad216ab | 519 | { |
cdd0f459 | 520 | check_r0_write(dc, a->d); |
8bba7619 | 521 | tcg_gen_ext8s_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); |
6ad216ab RH |
522 | return true; |
523 | } | |
524 | ||
3a7be554 | 525 | static bool trans_l_exthz(DisasContext *dc, arg_da *a) |
6ad216ab | 526 | { |
cdd0f459 | 527 | check_r0_write(dc, a->d); |
8bba7619 | 528 | tcg_gen_ext16u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); |
6ad216ab RH |
529 | return true; |
530 | } | |
531 | ||
3a7be554 | 532 | static bool trans_l_extbz(DisasContext *dc, arg_da *a) |
6ad216ab | 533 | { |
cdd0f459 | 534 | check_r0_write(dc, a->d); |
8bba7619 | 535 | tcg_gen_ext8u_tl(cpu_R(dc, a->d), cpu_R(dc, a->a)); |
6ad216ab RH |
536 | return true; |
537 | } | |
538 | ||
3a7be554 | 539 | static bool trans_l_cmov(DisasContext *dc, arg_dab *a) |
6ad216ab | 540 | { |
cdd0f459 | 541 | check_r0_write(dc, a->d); |
118671f0 | 542 | tcg_gen_movcond_tl(TCG_COND_NE, cpu_R(dc, a->d), cpu_sr_f, dc->zero, |
8bba7619 | 543 | cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
544 | return true; |
545 | } | |
546 | ||
3a7be554 | 547 | static bool trans_l_ff1(DisasContext *dc, arg_da *a) |
6ad216ab | 548 | { |
cdd0f459 | 549 | check_r0_write(dc, a->d); |
8bba7619 RH |
550 | tcg_gen_ctzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), -1); |
551 | tcg_gen_addi_tl(cpu_R(dc, a->d), cpu_R(dc, a->d), 1); | |
6ad216ab RH |
552 | return true; |
553 | } | |
554 | ||
3a7be554 | 555 | static bool trans_l_fl1(DisasContext *dc, arg_da *a) |
6ad216ab | 556 | { |
cdd0f459 | 557 | check_r0_write(dc, a->d); |
8bba7619 RH |
558 | tcg_gen_clzi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), TARGET_LONG_BITS); |
559 | tcg_gen_subfi_tl(cpu_R(dc, a->d), TARGET_LONG_BITS, cpu_R(dc, a->d)); | |
6ad216ab RH |
560 | return true; |
561 | } | |
562 | ||
3a7be554 | 563 | static bool trans_l_mul(DisasContext *dc, arg_dab *a) |
6ad216ab | 564 | { |
cdd0f459 | 565 | check_r0_write(dc, a->d); |
8bba7619 | 566 | gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
567 | return true; |
568 | } | |
569 | ||
3a7be554 | 570 | static bool trans_l_mulu(DisasContext *dc, arg_dab *a) |
6ad216ab | 571 | { |
cdd0f459 | 572 | check_r0_write(dc, a->d); |
8bba7619 | 573 | gen_mulu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
574 | return true; |
575 | } | |
576 | ||
3a7be554 | 577 | static bool trans_l_div(DisasContext *dc, arg_dab *a) |
6ad216ab | 578 | { |
cdd0f459 | 579 | check_r0_write(dc, a->d); |
8bba7619 | 580 | gen_div(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
581 | return true; |
582 | } | |
583 | ||
3a7be554 | 584 | static bool trans_l_divu(DisasContext *dc, arg_dab *a) |
6ad216ab | 585 | { |
cdd0f459 | 586 | check_r0_write(dc, a->d); |
8bba7619 | 587 | gen_divu(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
588 | return true; |
589 | } | |
590 | ||
3a7be554 | 591 | static bool trans_l_muld(DisasContext *dc, arg_ab *a) |
6ad216ab | 592 | { |
8bba7619 | 593 | gen_muld(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab RH |
594 | return true; |
595 | } | |
596 | ||
3a7be554 | 597 | static bool trans_l_muldu(DisasContext *dc, arg_ab *a) |
6ad216ab | 598 | { |
8bba7619 | 599 | gen_muldu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6ad216ab | 600 | return true; |
bbe418f2 JL |
601 | } |
602 | ||
3a7be554 | 603 | static bool trans_l_j(DisasContext *dc, arg_l_j *a) |
136e13ae RH |
604 | { |
605 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
606 | ||
136e13ae | 607 | tcg_gen_movi_tl(jmp_pc, tmp_pc); |
8000ba56 | 608 | dc->jmp_pc_imm = tmp_pc; |
136e13ae RH |
609 | dc->delayed_branch = 2; |
610 | return true; | |
611 | } | |
612 | ||
3a7be554 | 613 | static bool trans_l_jal(DisasContext *dc, arg_l_jal *a) |
136e13ae RH |
614 | { |
615 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
616 | target_ulong ret_pc = dc->base.pc_next + 8; | |
617 | ||
8bba7619 | 618 | tcg_gen_movi_tl(cpu_regs[9], ret_pc); |
136e13ae RH |
619 | /* Optimize jal being used to load the PC for PIC. */ |
620 | if (tmp_pc != ret_pc) { | |
621 | tcg_gen_movi_tl(jmp_pc, tmp_pc); | |
8000ba56 | 622 | dc->jmp_pc_imm = tmp_pc; |
136e13ae RH |
623 | dc->delayed_branch = 2; |
624 | } | |
625 | return true; | |
626 | } | |
627 | ||
628 | static void do_bf(DisasContext *dc, arg_l_bf *a, TCGCond cond) | |
629 | { | |
630 | target_ulong tmp_pc = dc->base.pc_next + a->n * 4; | |
af42d354 RH |
631 | TCGv t_next = tcg_constant_tl(dc->base.pc_next + 8); |
632 | TCGv t_true = tcg_constant_tl(tmp_pc); | |
136e13ae | 633 | |
118671f0 | 634 | tcg_gen_movcond_tl(cond, jmp_pc, cpu_sr_f, dc->zero, t_true, t_next); |
136e13ae RH |
635 | dc->delayed_branch = 2; |
636 | } | |
637 | ||
3a7be554 | 638 | static bool trans_l_bf(DisasContext *dc, arg_l_bf *a) |
136e13ae | 639 | { |
136e13ae RH |
640 | do_bf(dc, a, TCG_COND_NE); |
641 | return true; | |
642 | } | |
643 | ||
3a7be554 | 644 | static bool trans_l_bnf(DisasContext *dc, arg_l_bf *a) |
136e13ae | 645 | { |
136e13ae RH |
646 | do_bf(dc, a, TCG_COND_EQ); |
647 | return true; | |
648 | } | |
649 | ||
3a7be554 | 650 | static bool trans_l_jr(DisasContext *dc, arg_l_jr *a) |
136e13ae | 651 | { |
8bba7619 | 652 | tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); |
136e13ae RH |
653 | dc->delayed_branch = 2; |
654 | return true; | |
655 | } | |
656 | ||
3a7be554 | 657 | static bool trans_l_jalr(DisasContext *dc, arg_l_jalr *a) |
136e13ae | 658 | { |
8bba7619 RH |
659 | tcg_gen_mov_tl(jmp_pc, cpu_R(dc, a->b)); |
660 | tcg_gen_movi_tl(cpu_regs[9], dc->base.pc_next + 8); | |
136e13ae RH |
661 | dc->delayed_branch = 2; |
662 | return true; | |
663 | } | |
664 | ||
3a7be554 | 665 | static bool trans_l_lwa(DisasContext *dc, arg_load *a) |
d80bff19 RH |
666 | { |
667 | TCGv ea; | |
668 | ||
cdd0f459 | 669 | check_r0_write(dc, a->d); |
d80bff19 | 670 | ea = tcg_temp_new(); |
8bba7619 RH |
671 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); |
672 | tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, MO_TEUL); | |
d80bff19 | 673 | tcg_gen_mov_tl(cpu_lock_addr, ea); |
8bba7619 | 674 | tcg_gen_mov_tl(cpu_lock_value, cpu_R(dc, a->d)); |
d80bff19 RH |
675 | tcg_temp_free(ea); |
676 | return true; | |
677 | } | |
678 | ||
14776ab5 | 679 | static void do_load(DisasContext *dc, arg_load *a, MemOp mop) |
d80bff19 RH |
680 | { |
681 | TCGv ea; | |
682 | ||
cdd0f459 | 683 | check_r0_write(dc, a->d); |
d80bff19 | 684 | ea = tcg_temp_new(); |
8bba7619 RH |
685 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); |
686 | tcg_gen_qemu_ld_tl(cpu_R(dc, a->d), ea, dc->mem_idx, mop); | |
d80bff19 RH |
687 | tcg_temp_free(ea); |
688 | } | |
689 | ||
3a7be554 | 690 | static bool trans_l_lwz(DisasContext *dc, arg_load *a) |
d80bff19 | 691 | { |
d80bff19 RH |
692 | do_load(dc, a, MO_TEUL); |
693 | return true; | |
694 | } | |
695 | ||
3a7be554 | 696 | static bool trans_l_lws(DisasContext *dc, arg_load *a) |
d80bff19 | 697 | { |
d80bff19 RH |
698 | do_load(dc, a, MO_TESL); |
699 | return true; | |
700 | } | |
701 | ||
3a7be554 | 702 | static bool trans_l_lbz(DisasContext *dc, arg_load *a) |
d80bff19 | 703 | { |
d80bff19 RH |
704 | do_load(dc, a, MO_UB); |
705 | return true; | |
706 | } | |
707 | ||
3a7be554 | 708 | static bool trans_l_lbs(DisasContext *dc, arg_load *a) |
d80bff19 | 709 | { |
d80bff19 RH |
710 | do_load(dc, a, MO_SB); |
711 | return true; | |
712 | } | |
713 | ||
3a7be554 | 714 | static bool trans_l_lhz(DisasContext *dc, arg_load *a) |
d80bff19 | 715 | { |
d80bff19 RH |
716 | do_load(dc, a, MO_TEUW); |
717 | return true; | |
718 | } | |
719 | ||
3a7be554 | 720 | static bool trans_l_lhs(DisasContext *dc, arg_load *a) |
d80bff19 | 721 | { |
d80bff19 RH |
722 | do_load(dc, a, MO_TESW); |
723 | return true; | |
724 | } | |
725 | ||
3a7be554 | 726 | static bool trans_l_swa(DisasContext *dc, arg_store *a) |
d80bff19 RH |
727 | { |
728 | TCGv ea, val; | |
729 | TCGLabel *lab_fail, *lab_done; | |
730 | ||
d80bff19 | 731 | ea = tcg_temp_new(); |
8bba7619 | 732 | tcg_gen_addi_tl(ea, cpu_R(dc, a->a), a->i); |
d80bff19 | 733 | |
d80bff19 RH |
734 | lab_fail = gen_new_label(); |
735 | lab_done = gen_new_label(); | |
736 | tcg_gen_brcond_tl(TCG_COND_NE, ea, cpu_lock_addr, lab_fail); | |
737 | tcg_temp_free(ea); | |
738 | ||
739 | val = tcg_temp_new(); | |
740 | tcg_gen_atomic_cmpxchg_tl(val, cpu_lock_addr, cpu_lock_value, | |
4d10fa0f | 741 | cpu_R(dc, a->b), dc->mem_idx, MO_TEUL); |
d80bff19 RH |
742 | tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, val, cpu_lock_value); |
743 | tcg_temp_free(val); | |
744 | ||
745 | tcg_gen_br(lab_done); | |
746 | ||
747 | gen_set_label(lab_fail); | |
748 | tcg_gen_movi_tl(cpu_sr_f, 0); | |
749 | ||
750 | gen_set_label(lab_done); | |
751 | tcg_gen_movi_tl(cpu_lock_addr, -1); | |
752 | return true; | |
753 | } | |
754 | ||
14776ab5 | 755 | static void do_store(DisasContext *dc, arg_store *a, MemOp mop) |
d80bff19 RH |
756 | { |
757 | TCGv t0 = tcg_temp_new(); | |
8bba7619 RH |
758 | tcg_gen_addi_tl(t0, cpu_R(dc, a->a), a->i); |
759 | tcg_gen_qemu_st_tl(cpu_R(dc, a->b), t0, dc->mem_idx, mop); | |
d80bff19 RH |
760 | tcg_temp_free(t0); |
761 | } | |
762 | ||
3a7be554 | 763 | static bool trans_l_sw(DisasContext *dc, arg_store *a) |
d80bff19 | 764 | { |
d80bff19 RH |
765 | do_store(dc, a, MO_TEUL); |
766 | return true; | |
767 | } | |
768 | ||
3a7be554 | 769 | static bool trans_l_sb(DisasContext *dc, arg_store *a) |
d80bff19 | 770 | { |
d80bff19 RH |
771 | do_store(dc, a, MO_UB); |
772 | return true; | |
773 | } | |
774 | ||
3a7be554 | 775 | static bool trans_l_sh(DisasContext *dc, arg_store *a) |
d80bff19 | 776 | { |
d80bff19 RH |
777 | do_store(dc, a, MO_TEUW); |
778 | return true; | |
779 | } | |
780 | ||
3a7be554 | 781 | static bool trans_l_nop(DisasContext *dc, arg_l_nop *a) |
bbe418f2 | 782 | { |
8816f70b RH |
783 | return true; |
784 | } | |
bbe418f2 | 785 | |
3e0e41ef RH |
786 | static bool trans_l_adrp(DisasContext *dc, arg_l_adrp *a) |
787 | { | |
788 | if (!check_v1_3(dc)) { | |
789 | return false; | |
790 | } | |
791 | check_r0_write(dc, a->d); | |
792 | ||
793 | tcg_gen_movi_i32(cpu_R(dc, a->d), | |
794 | (dc->base.pc_next & TARGET_PAGE_MASK) + | |
795 | ((target_long)a->i << TARGET_PAGE_BITS)); | |
796 | return true; | |
797 | } | |
798 | ||
3a7be554 | 799 | static bool trans_l_addi(DisasContext *dc, arg_rri *a) |
8816f70b | 800 | { |
cdd0f459 | 801 | check_r0_write(dc, a->d); |
af42d354 | 802 | gen_add(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); |
8816f70b RH |
803 | return true; |
804 | } | |
bbe418f2 | 805 | |
3a7be554 | 806 | static bool trans_l_addic(DisasContext *dc, arg_rri *a) |
8816f70b | 807 | { |
cdd0f459 | 808 | check_r0_write(dc, a->d); |
af42d354 | 809 | gen_addc(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); |
8816f70b RH |
810 | return true; |
811 | } | |
bbe418f2 | 812 | |
3a7be554 | 813 | static bool trans_l_muli(DisasContext *dc, arg_rri *a) |
8816f70b | 814 | { |
cdd0f459 | 815 | check_r0_write(dc, a->d); |
af42d354 | 816 | gen_mul(dc, cpu_R(dc, a->d), cpu_R(dc, a->a), tcg_constant_tl(a->i)); |
8816f70b RH |
817 | return true; |
818 | } | |
bbe418f2 | 819 | |
3a7be554 | 820 | static bool trans_l_maci(DisasContext *dc, arg_l_maci *a) |
8816f70b | 821 | { |
af42d354 | 822 | gen_mac(dc, cpu_R(dc, a->a), tcg_constant_tl(a->i)); |
8816f70b RH |
823 | return true; |
824 | } | |
bbe418f2 | 825 | |
3a7be554 | 826 | static bool trans_l_andi(DisasContext *dc, arg_rrk *a) |
8816f70b | 827 | { |
cdd0f459 | 828 | check_r0_write(dc, a->d); |
8bba7619 | 829 | tcg_gen_andi_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); |
8816f70b RH |
830 | return true; |
831 | } | |
bbe418f2 | 832 | |
3a7be554 | 833 | static bool trans_l_ori(DisasContext *dc, arg_rrk *a) |
8816f70b | 834 | { |
cdd0f459 | 835 | check_r0_write(dc, a->d); |
8bba7619 | 836 | tcg_gen_ori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->k); |
8816f70b RH |
837 | return true; |
838 | } | |
bbe418f2 | 839 | |
3a7be554 | 840 | static bool trans_l_xori(DisasContext *dc, arg_rri *a) |
8816f70b | 841 | { |
cdd0f459 | 842 | check_r0_write(dc, a->d); |
8bba7619 | 843 | tcg_gen_xori_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), a->i); |
8816f70b RH |
844 | return true; |
845 | } | |
bbe418f2 | 846 | |
3a7be554 | 847 | static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) |
8816f70b | 848 | { |
cdd0f459 | 849 | check_r0_write(dc, a->d); |
bbe418f2 | 850 | |
2ba65417 | 851 | if (is_user(dc)) { |
8816f70b RH |
852 | gen_illegal_exception(dc); |
853 | } else { | |
c28fa81f | 854 | TCGv spr = tcg_temp_new(); |
b9e40bac PD |
855 | |
856 | if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { | |
857 | gen_io_start(); | |
858 | if (dc->delayed_branch) { | |
859 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
860 | tcg_gen_discard_tl(jmp_pc); | |
861 | } else { | |
862 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); | |
863 | } | |
864 | dc->base.is_jmp = DISAS_EXIT; | |
865 | } | |
866 | ||
8bba7619 RH |
867 | tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); |
868 | gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); | |
c28fa81f | 869 | tcg_temp_free(spr); |
8816f70b | 870 | } |
8816f70b RH |
871 | return true; |
872 | } | |
bbe418f2 | 873 | |
3a7be554 | 874 | static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) |
8816f70b | 875 | { |
2ba65417 | 876 | if (is_user(dc)) { |
bbe418f2 | 877 | gen_illegal_exception(dc); |
8816f70b | 878 | } else { |
c28fa81f | 879 | TCGv spr; |
01ec3ec9 | 880 | |
b9e40bac PD |
881 | if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { |
882 | gen_io_start(); | |
883 | } | |
01ec3ec9 RH |
884 | /* For SR, we will need to exit the TB to recognize the new |
885 | * exception state. For NPC, in theory this counts as a branch | |
886 | * (although the SPR only exists for use by an ICE). Save all | |
887 | * of the cpu state first, allowing it to be overwritten. | |
888 | */ | |
889 | if (dc->delayed_branch) { | |
890 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
891 | tcg_gen_discard_tl(jmp_pc); | |
892 | } else { | |
893 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); | |
894 | } | |
895 | dc->base.is_jmp = DISAS_EXIT; | |
896 | ||
c28fa81f | 897 | spr = tcg_temp_new(); |
8bba7619 RH |
898 | tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); |
899 | gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b)); | |
c28fa81f | 900 | tcg_temp_free(spr); |
bbe418f2 | 901 | } |
8816f70b | 902 | return true; |
bbe418f2 JL |
903 | } |
904 | ||
3a7be554 | 905 | static bool trans_l_mac(DisasContext *dc, arg_ab *a) |
bbe418f2 | 906 | { |
8bba7619 | 907 | gen_mac(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
99d863d6 RH |
908 | return true; |
909 | } | |
bbe418f2 | 910 | |
3a7be554 | 911 | static bool trans_l_msb(DisasContext *dc, arg_ab *a) |
99d863d6 | 912 | { |
8bba7619 | 913 | gen_msb(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
99d863d6 RH |
914 | return true; |
915 | } | |
cc5de49e | 916 | |
3a7be554 | 917 | static bool trans_l_macu(DisasContext *dc, arg_ab *a) |
99d863d6 | 918 | { |
8bba7619 | 919 | gen_macu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
99d863d6 RH |
920 | return true; |
921 | } | |
cc5de49e | 922 | |
3a7be554 | 923 | static bool trans_l_msbu(DisasContext *dc, arg_ab *a) |
99d863d6 | 924 | { |
8bba7619 | 925 | gen_msbu(dc, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
99d863d6 | 926 | return true; |
bbe418f2 JL |
927 | } |
928 | ||
3a7be554 | 929 | static bool trans_l_slli(DisasContext *dc, arg_dal *a) |
bbe418f2 | 930 | { |
cdd0f459 | 931 | check_r0_write(dc, a->d); |
8bba7619 RH |
932 | tcg_gen_shli_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), |
933 | a->l & (TARGET_LONG_BITS - 1)); | |
e20c2592 RH |
934 | return true; |
935 | } | |
bbe418f2 | 936 | |
3a7be554 | 937 | static bool trans_l_srli(DisasContext *dc, arg_dal *a) |
e20c2592 | 938 | { |
cdd0f459 | 939 | check_r0_write(dc, a->d); |
8bba7619 RH |
940 | tcg_gen_shri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), |
941 | a->l & (TARGET_LONG_BITS - 1)); | |
e20c2592 RH |
942 | return true; |
943 | } | |
bbe418f2 | 944 | |
3a7be554 | 945 | static bool trans_l_srai(DisasContext *dc, arg_dal *a) |
e20c2592 | 946 | { |
cdd0f459 | 947 | check_r0_write(dc, a->d); |
8bba7619 RH |
948 | tcg_gen_sari_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), |
949 | a->l & (TARGET_LONG_BITS - 1)); | |
e20c2592 RH |
950 | return true; |
951 | } | |
bbe418f2 | 952 | |
3a7be554 | 953 | static bool trans_l_rori(DisasContext *dc, arg_dal *a) |
e20c2592 | 954 | { |
cdd0f459 | 955 | check_r0_write(dc, a->d); |
8bba7619 RH |
956 | tcg_gen_rotri_tl(cpu_R(dc, a->d), cpu_R(dc, a->a), |
957 | a->l & (TARGET_LONG_BITS - 1)); | |
e20c2592 | 958 | return true; |
bbe418f2 JL |
959 | } |
960 | ||
3a7be554 | 961 | static bool trans_l_movhi(DisasContext *dc, arg_l_movhi *a) |
bbe418f2 | 962 | { |
cdd0f459 | 963 | check_r0_write(dc, a->d); |
8bba7619 | 964 | tcg_gen_movi_tl(cpu_R(dc, a->d), a->k << 16); |
e720a571 RH |
965 | return true; |
966 | } | |
bbe418f2 | 967 | |
3a7be554 | 968 | static bool trans_l_macrc(DisasContext *dc, arg_l_macrc *a) |
e720a571 | 969 | { |
cdd0f459 | 970 | check_r0_write(dc, a->d); |
8bba7619 | 971 | tcg_gen_trunc_i64_tl(cpu_R(dc, a->d), cpu_mac); |
e720a571 RH |
972 | tcg_gen_movi_i64(cpu_mac, 0); |
973 | return true; | |
bbe418f2 JL |
974 | } |
975 | ||
3a7be554 | 976 | static bool trans_l_sfeq(DisasContext *dc, arg_ab *a) |
bbe418f2 | 977 | { |
8bba7619 RH |
978 | tcg_gen_setcond_tl(TCG_COND_EQ, cpu_sr_f, |
979 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
980 | return true; |
981 | } | |
bbe418f2 | 982 | |
3a7be554 | 983 | static bool trans_l_sfne(DisasContext *dc, arg_ab *a) |
fbb3e29a | 984 | { |
8bba7619 RH |
985 | tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_f, |
986 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
987 | return true; |
988 | } | |
bbe418f2 | 989 | |
3a7be554 | 990 | static bool trans_l_sfgtu(DisasContext *dc, arg_ab *a) |
fbb3e29a | 991 | { |
8bba7619 RH |
992 | tcg_gen_setcond_tl(TCG_COND_GTU, cpu_sr_f, |
993 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
994 | return true; |
995 | } | |
bbe418f2 | 996 | |
3a7be554 | 997 | static bool trans_l_sfgeu(DisasContext *dc, arg_ab *a) |
fbb3e29a | 998 | { |
8bba7619 RH |
999 | tcg_gen_setcond_tl(TCG_COND_GEU, cpu_sr_f, |
1000 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1001 | return true; |
1002 | } | |
bbe418f2 | 1003 | |
3a7be554 | 1004 | static bool trans_l_sfltu(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1005 | { |
8bba7619 RH |
1006 | tcg_gen_setcond_tl(TCG_COND_LTU, cpu_sr_f, |
1007 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1008 | return true; |
1009 | } | |
bbe418f2 | 1010 | |
3a7be554 | 1011 | static bool trans_l_sfleu(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1012 | { |
8bba7619 RH |
1013 | tcg_gen_setcond_tl(TCG_COND_LEU, cpu_sr_f, |
1014 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1015 | return true; |
1016 | } | |
bbe418f2 | 1017 | |
3a7be554 | 1018 | static bool trans_l_sfgts(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1019 | { |
8bba7619 RH |
1020 | tcg_gen_setcond_tl(TCG_COND_GT, cpu_sr_f, |
1021 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1022 | return true; |
1023 | } | |
bbe418f2 | 1024 | |
3a7be554 | 1025 | static bool trans_l_sfges(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1026 | { |
8bba7619 RH |
1027 | tcg_gen_setcond_tl(TCG_COND_GE, cpu_sr_f, |
1028 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1029 | return true; |
1030 | } | |
bbe418f2 | 1031 | |
3a7be554 | 1032 | static bool trans_l_sflts(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1033 | { |
8bba7619 RH |
1034 | tcg_gen_setcond_tl(TCG_COND_LT, cpu_sr_f, |
1035 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a RH |
1036 | return true; |
1037 | } | |
bbe418f2 | 1038 | |
3a7be554 | 1039 | static bool trans_l_sfles(DisasContext *dc, arg_ab *a) |
fbb3e29a | 1040 | { |
8bba7619 RH |
1041 | tcg_gen_setcond_tl(TCG_COND_LE, |
1042 | cpu_sr_f, cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
fbb3e29a | 1043 | return true; |
bbe418f2 JL |
1044 | } |
1045 | ||
3a7be554 | 1046 | static bool trans_l_sfeqi(DisasContext *dc, arg_ai *a) |
bbe418f2 | 1047 | { |
8bba7619 | 1048 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1049 | return true; |
1050 | } | |
bbe418f2 | 1051 | |
3a7be554 | 1052 | static bool trans_l_sfnei(DisasContext *dc, arg_ai *a) |
032de4fc | 1053 | { |
8bba7619 | 1054 | tcg_gen_setcondi_tl(TCG_COND_NE, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1055 | return true; |
1056 | } | |
bbe418f2 | 1057 | |
3a7be554 | 1058 | static bool trans_l_sfgtui(DisasContext *dc, arg_ai *a) |
032de4fc | 1059 | { |
8bba7619 | 1060 | tcg_gen_setcondi_tl(TCG_COND_GTU, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1061 | return true; |
1062 | } | |
bbe418f2 | 1063 | |
3a7be554 | 1064 | static bool trans_l_sfgeui(DisasContext *dc, arg_ai *a) |
032de4fc | 1065 | { |
8bba7619 | 1066 | tcg_gen_setcondi_tl(TCG_COND_GEU, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1067 | return true; |
1068 | } | |
bbe418f2 | 1069 | |
3a7be554 | 1070 | static bool trans_l_sfltui(DisasContext *dc, arg_ai *a) |
032de4fc | 1071 | { |
8bba7619 | 1072 | tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1073 | return true; |
1074 | } | |
bbe418f2 | 1075 | |
3a7be554 | 1076 | static bool trans_l_sfleui(DisasContext *dc, arg_ai *a) |
032de4fc | 1077 | { |
8bba7619 | 1078 | tcg_gen_setcondi_tl(TCG_COND_LEU, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1079 | return true; |
1080 | } | |
bbe418f2 | 1081 | |
3a7be554 | 1082 | static bool trans_l_sfgtsi(DisasContext *dc, arg_ai *a) |
032de4fc | 1083 | { |
8bba7619 | 1084 | tcg_gen_setcondi_tl(TCG_COND_GT, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1085 | return true; |
1086 | } | |
bbe418f2 | 1087 | |
3a7be554 | 1088 | static bool trans_l_sfgesi(DisasContext *dc, arg_ai *a) |
032de4fc | 1089 | { |
8bba7619 | 1090 | tcg_gen_setcondi_tl(TCG_COND_GE, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1091 | return true; |
1092 | } | |
bbe418f2 | 1093 | |
3a7be554 | 1094 | static bool trans_l_sfltsi(DisasContext *dc, arg_ai *a) |
032de4fc | 1095 | { |
8bba7619 | 1096 | tcg_gen_setcondi_tl(TCG_COND_LT, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc RH |
1097 | return true; |
1098 | } | |
bbe418f2 | 1099 | |
3a7be554 | 1100 | static bool trans_l_sflesi(DisasContext *dc, arg_ai *a) |
032de4fc | 1101 | { |
8bba7619 | 1102 | tcg_gen_setcondi_tl(TCG_COND_LE, cpu_sr_f, cpu_R(dc, a->a), a->i); |
032de4fc | 1103 | return true; |
bbe418f2 JL |
1104 | } |
1105 | ||
3a7be554 | 1106 | static bool trans_l_sys(DisasContext *dc, arg_l_sys *a) |
bbe418f2 | 1107 | { |
7de9729f RH |
1108 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); |
1109 | gen_exception(dc, EXCP_SYSCALL); | |
1110 | dc->base.is_jmp = DISAS_NORETURN; | |
1111 | return true; | |
1112 | } | |
bbe418f2 | 1113 | |
3a7be554 | 1114 | static bool trans_l_trap(DisasContext *dc, arg_l_trap *a) |
7de9729f | 1115 | { |
7de9729f RH |
1116 | tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); |
1117 | gen_exception(dc, EXCP_TRAP); | |
1118 | dc->base.is_jmp = DISAS_NORETURN; | |
1119 | return true; | |
1120 | } | |
bbe418f2 | 1121 | |
3a7be554 | 1122 | static bool trans_l_msync(DisasContext *dc, arg_l_msync *a) |
7de9729f | 1123 | { |
7de9729f RH |
1124 | tcg_gen_mb(TCG_MO_ALL); |
1125 | return true; | |
1126 | } | |
bbe418f2 | 1127 | |
3a7be554 | 1128 | static bool trans_l_psync(DisasContext *dc, arg_l_psync *a) |
7de9729f | 1129 | { |
7de9729f RH |
1130 | return true; |
1131 | } | |
bbe418f2 | 1132 | |
3a7be554 | 1133 | static bool trans_l_csync(DisasContext *dc, arg_l_csync *a) |
7de9729f | 1134 | { |
7de9729f | 1135 | return true; |
bbe418f2 JL |
1136 | } |
1137 | ||
3a7be554 | 1138 | static bool trans_l_rfe(DisasContext *dc, arg_l_rfe *a) |
8816f70b | 1139 | { |
2ba65417 | 1140 | if (is_user(dc)) { |
8816f70b RH |
1141 | gen_illegal_exception(dc); |
1142 | } else { | |
1143 | gen_helper_rfe(cpu_env); | |
64e46c95 | 1144 | dc->base.is_jmp = DISAS_EXIT; |
8816f70b | 1145 | } |
8816f70b RH |
1146 | return true; |
1147 | } | |
1148 | ||
fe636d37 | 1149 | static bool do_fp2(DisasContext *dc, arg_da *a, |
6fd204a2 RH |
1150 | void (*fn)(TCGv, TCGv_env, TCGv)) |
1151 | { | |
fe636d37 RH |
1152 | if (!check_of32s(dc)) { |
1153 | return false; | |
1154 | } | |
cdd0f459 | 1155 | check_r0_write(dc, a->d); |
8bba7619 | 1156 | fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a)); |
6fd204a2 | 1157 | gen_helper_update_fpcsr(cpu_env); |
fe636d37 | 1158 | return true; |
6fd204a2 | 1159 | } |
bbe418f2 | 1160 | |
fe636d37 | 1161 | static bool do_fp3(DisasContext *dc, arg_dab *a, |
6fd204a2 RH |
1162 | void (*fn)(TCGv, TCGv_env, TCGv, TCGv)) |
1163 | { | |
fe636d37 RH |
1164 | if (!check_of32s(dc)) { |
1165 | return false; | |
1166 | } | |
cdd0f459 | 1167 | check_r0_write(dc, a->d); |
8bba7619 | 1168 | fn(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6fd204a2 | 1169 | gen_helper_update_fpcsr(cpu_env); |
fe636d37 | 1170 | return true; |
6fd204a2 RH |
1171 | } |
1172 | ||
fe636d37 | 1173 | static bool do_fpcmp(DisasContext *dc, arg_ab *a, |
6fd204a2 RH |
1174 | void (*fn)(TCGv, TCGv_env, TCGv, TCGv), |
1175 | bool inv, bool swap) | |
1176 | { | |
fe636d37 RH |
1177 | if (!check_of32s(dc)) { |
1178 | return false; | |
1179 | } | |
6fd204a2 | 1180 | if (swap) { |
8bba7619 | 1181 | fn(cpu_sr_f, cpu_env, cpu_R(dc, a->b), cpu_R(dc, a->a)); |
6fd204a2 | 1182 | } else { |
8bba7619 | 1183 | fn(cpu_sr_f, cpu_env, cpu_R(dc, a->a), cpu_R(dc, a->b)); |
6fd204a2 RH |
1184 | } |
1185 | if (inv) { | |
1186 | tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); | |
bbe418f2 | 1187 | } |
6fd204a2 | 1188 | gen_helper_update_fpcsr(cpu_env); |
fe636d37 | 1189 | return true; |
bbe418f2 JL |
1190 | } |
1191 | ||
3a7be554 | 1192 | static bool trans_lf_add_s(DisasContext *dc, arg_dab *a) |
bbe418f2 | 1193 | { |
fe636d37 | 1194 | return do_fp3(dc, a, gen_helper_float_add_s); |
6fd204a2 | 1195 | } |
bbe418f2 | 1196 | |
3a7be554 | 1197 | static bool trans_lf_sub_s(DisasContext *dc, arg_dab *a) |
6fd204a2 | 1198 | { |
fe636d37 | 1199 | return do_fp3(dc, a, gen_helper_float_sub_s); |
6fd204a2 RH |
1200 | } |
1201 | ||
3a7be554 | 1202 | static bool trans_lf_mul_s(DisasContext *dc, arg_dab *a) |
6fd204a2 | 1203 | { |
fe636d37 | 1204 | return do_fp3(dc, a, gen_helper_float_mul_s); |
6fd204a2 RH |
1205 | } |
1206 | ||
3a7be554 | 1207 | static bool trans_lf_div_s(DisasContext *dc, arg_dab *a) |
6fd204a2 | 1208 | { |
fe636d37 | 1209 | return do_fp3(dc, a, gen_helper_float_div_s); |
6fd204a2 RH |
1210 | } |
1211 | ||
3a7be554 | 1212 | static bool trans_lf_rem_s(DisasContext *dc, arg_dab *a) |
6fd204a2 | 1213 | { |
fe636d37 | 1214 | return do_fp3(dc, a, gen_helper_float_rem_s); |
6fd204a2 RH |
1215 | return true; |
1216 | } | |
1217 | ||
3a7be554 | 1218 | static bool trans_lf_itof_s(DisasContext *dc, arg_da *a) |
6fd204a2 | 1219 | { |
fe636d37 | 1220 | return do_fp2(dc, a, gen_helper_itofs); |
6fd204a2 RH |
1221 | } |
1222 | ||
3a7be554 | 1223 | static bool trans_lf_ftoi_s(DisasContext *dc, arg_da *a) |
6fd204a2 | 1224 | { |
fe636d37 | 1225 | return do_fp2(dc, a, gen_helper_ftois); |
6fd204a2 | 1226 | } |
7de9729f | 1227 | |
3a7be554 | 1228 | static bool trans_lf_madd_s(DisasContext *dc, arg_dab *a) |
6fd204a2 | 1229 | { |
fe636d37 RH |
1230 | if (!check_of32s(dc)) { |
1231 | return false; | |
1232 | } | |
cdd0f459 | 1233 | check_r0_write(dc, a->d); |
8bba7619 RH |
1234 | gen_helper_float_madd_s(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), |
1235 | cpu_R(dc, a->a), cpu_R(dc, a->b)); | |
6fd204a2 RH |
1236 | gen_helper_update_fpcsr(cpu_env); |
1237 | return true; | |
1238 | } | |
bbe418f2 | 1239 | |
3a7be554 | 1240 | static bool trans_lf_sfeq_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1241 | { |
fe636d37 | 1242 | return do_fpcmp(dc, a, gen_helper_float_eq_s, false, false); |
6fd204a2 RH |
1243 | } |
1244 | ||
3a7be554 | 1245 | static bool trans_lf_sfne_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1246 | { |
fe636d37 | 1247 | return do_fpcmp(dc, a, gen_helper_float_eq_s, true, false); |
6fd204a2 RH |
1248 | } |
1249 | ||
3a7be554 | 1250 | static bool trans_lf_sfgt_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1251 | { |
fe636d37 | 1252 | return do_fpcmp(dc, a, gen_helper_float_lt_s, false, true); |
6fd204a2 RH |
1253 | } |
1254 | ||
3a7be554 | 1255 | static bool trans_lf_sfge_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1256 | { |
fe636d37 | 1257 | return do_fpcmp(dc, a, gen_helper_float_le_s, false, true); |
6fd204a2 RH |
1258 | } |
1259 | ||
3a7be554 | 1260 | static bool trans_lf_sflt_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1261 | { |
fe636d37 | 1262 | return do_fpcmp(dc, a, gen_helper_float_lt_s, false, false); |
6fd204a2 RH |
1263 | } |
1264 | ||
3a7be554 | 1265 | static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a) |
6fd204a2 | 1266 | { |
fe636d37 | 1267 | return do_fpcmp(dc, a, gen_helper_float_le_s, false, false); |
6fd204a2 RH |
1268 | } |
1269 | ||
2b13b4b9 RH |
1270 | static bool trans_lf_sfueq_s(DisasContext *dc, arg_ab *a) |
1271 | { | |
1272 | if (!check_v1_3(dc)) { | |
1273 | return false; | |
1274 | } | |
1275 | return do_fpcmp(dc, a, gen_helper_float_ueq_s, false, false); | |
1276 | } | |
1277 | ||
1278 | static bool trans_lf_sfult_s(DisasContext *dc, arg_ab *a) | |
1279 | { | |
1280 | if (!check_v1_3(dc)) { | |
1281 | return false; | |
1282 | } | |
1283 | return do_fpcmp(dc, a, gen_helper_float_ult_s, false, false); | |
1284 | } | |
1285 | ||
1286 | static bool trans_lf_sfugt_s(DisasContext *dc, arg_ab *a) | |
1287 | { | |
1288 | if (!check_v1_3(dc)) { | |
1289 | return false; | |
1290 | } | |
1291 | return do_fpcmp(dc, a, gen_helper_float_ult_s, false, true); | |
1292 | } | |
1293 | ||
1294 | static bool trans_lf_sfule_s(DisasContext *dc, arg_ab *a) | |
1295 | { | |
1296 | if (!check_v1_3(dc)) { | |
1297 | return false; | |
1298 | } | |
1299 | return do_fpcmp(dc, a, gen_helper_float_ule_s, false, false); | |
1300 | } | |
1301 | ||
1302 | static bool trans_lf_sfuge_s(DisasContext *dc, arg_ab *a) | |
1303 | { | |
1304 | if (!check_v1_3(dc)) { | |
1305 | return false; | |
1306 | } | |
1307 | return do_fpcmp(dc, a, gen_helper_float_ule_s, false, true); | |
1308 | } | |
1309 | ||
1310 | static bool trans_lf_sfun_s(DisasContext *dc, arg_ab *a) | |
1311 | { | |
1312 | if (!check_v1_3(dc)) { | |
1313 | return false; | |
1314 | } | |
1315 | return do_fpcmp(dc, a, gen_helper_float_un_s, false, false); | |
1316 | } | |
1317 | ||
62f2b038 RH |
1318 | static bool check_pair(DisasContext *dc, int r, int p) |
1319 | { | |
1320 | return r + 1 + p < 32; | |
1321 | } | |
1322 | ||
1323 | static void load_pair(DisasContext *dc, TCGv_i64 t, int r, int p) | |
1324 | { | |
1325 | tcg_gen_concat_i32_i64(t, cpu_R(dc, r + 1 + p), cpu_R(dc, r)); | |
1326 | } | |
1327 | ||
1328 | static void save_pair(DisasContext *dc, TCGv_i64 t, int r, int p) | |
1329 | { | |
1330 | tcg_gen_extr_i64_i32(cpu_R(dc, r + 1 + p), cpu_R(dc, r), t); | |
1331 | } | |
1332 | ||
1333 | static bool do_dp3(DisasContext *dc, arg_dab_pair *a, | |
1334 | void (*fn)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) | |
1335 | { | |
1336 | TCGv_i64 t0, t1; | |
1337 | ||
1338 | if (!check_of64a32s(dc) || | |
1339 | !check_pair(dc, a->a, a->ap) || | |
1340 | !check_pair(dc, a->b, a->bp) || | |
1341 | !check_pair(dc, a->d, a->dp)) { | |
1342 | return false; | |
1343 | } | |
1344 | check_r0_write(dc, a->d); | |
1345 | ||
1346 | t0 = tcg_temp_new_i64(); | |
1347 | t1 = tcg_temp_new_i64(); | |
1348 | load_pair(dc, t0, a->a, a->ap); | |
1349 | load_pair(dc, t1, a->b, a->bp); | |
1350 | fn(t0, cpu_env, t0, t1); | |
1351 | save_pair(dc, t0, a->d, a->dp); | |
1352 | tcg_temp_free_i64(t0); | |
1353 | tcg_temp_free_i64(t1); | |
1354 | ||
1355 | gen_helper_update_fpcsr(cpu_env); | |
1356 | return true; | |
1357 | } | |
1358 | ||
1359 | static bool do_dp2(DisasContext *dc, arg_da_pair *a, | |
1360 | void (*fn)(TCGv_i64, TCGv_env, TCGv_i64)) | |
1361 | { | |
1362 | TCGv_i64 t0; | |
1363 | ||
1364 | if (!check_of64a32s(dc) || | |
1365 | !check_pair(dc, a->a, a->ap) || | |
1366 | !check_pair(dc, a->d, a->dp)) { | |
1367 | return false; | |
1368 | } | |
1369 | check_r0_write(dc, a->d); | |
1370 | ||
1371 | t0 = tcg_temp_new_i64(); | |
1372 | load_pair(dc, t0, a->a, a->ap); | |
1373 | fn(t0, cpu_env, t0); | |
1374 | save_pair(dc, t0, a->d, a->dp); | |
1375 | tcg_temp_free_i64(t0); | |
1376 | ||
1377 | gen_helper_update_fpcsr(cpu_env); | |
1378 | return true; | |
1379 | } | |
1380 | ||
1381 | static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a, | |
1382 | void (*fn)(TCGv, TCGv_env, TCGv_i64, TCGv_i64), | |
1383 | bool inv, bool swap) | |
1384 | { | |
1385 | TCGv_i64 t0, t1; | |
1386 | ||
1387 | if (!check_of64a32s(dc) || | |
1388 | !check_pair(dc, a->a, a->ap) || | |
1389 | !check_pair(dc, a->b, a->bp)) { | |
1390 | return false; | |
1391 | } | |
1392 | ||
1393 | t0 = tcg_temp_new_i64(); | |
1394 | t1 = tcg_temp_new_i64(); | |
1395 | load_pair(dc, t0, a->a, a->ap); | |
1396 | load_pair(dc, t1, a->b, a->bp); | |
1397 | if (swap) { | |
1398 | fn(cpu_sr_f, cpu_env, t1, t0); | |
1399 | } else { | |
1400 | fn(cpu_sr_f, cpu_env, t0, t1); | |
1401 | } | |
1402 | tcg_temp_free_i64(t0); | |
1403 | tcg_temp_free_i64(t1); | |
1404 | ||
1405 | if (inv) { | |
1406 | tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); | |
1407 | } | |
1408 | gen_helper_update_fpcsr(cpu_env); | |
1409 | return true; | |
1410 | } | |
1411 | ||
1412 | static bool trans_lf_add_d(DisasContext *dc, arg_dab_pair *a) | |
1413 | { | |
1414 | return do_dp3(dc, a, gen_helper_float_add_d); | |
1415 | } | |
1416 | ||
1417 | static bool trans_lf_sub_d(DisasContext *dc, arg_dab_pair *a) | |
1418 | { | |
1419 | return do_dp3(dc, a, gen_helper_float_sub_d); | |
1420 | } | |
1421 | ||
1422 | static bool trans_lf_mul_d(DisasContext *dc, arg_dab_pair *a) | |
1423 | { | |
1424 | return do_dp3(dc, a, gen_helper_float_mul_d); | |
1425 | } | |
1426 | ||
1427 | static bool trans_lf_div_d(DisasContext *dc, arg_dab_pair *a) | |
1428 | { | |
1429 | return do_dp3(dc, a, gen_helper_float_div_d); | |
1430 | } | |
1431 | ||
1432 | static bool trans_lf_rem_d(DisasContext *dc, arg_dab_pair *a) | |
1433 | { | |
1434 | return do_dp3(dc, a, gen_helper_float_rem_d); | |
1435 | } | |
1436 | ||
1437 | static bool trans_lf_itof_d(DisasContext *dc, arg_da_pair *a) | |
1438 | { | |
1439 | return do_dp2(dc, a, gen_helper_itofd); | |
1440 | } | |
1441 | ||
1442 | static bool trans_lf_ftoi_d(DisasContext *dc, arg_da_pair *a) | |
1443 | { | |
1444 | return do_dp2(dc, a, gen_helper_ftoid); | |
1445 | } | |
1446 | ||
1447 | static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a) | |
1448 | { | |
1449 | TCGv_i64 t0; | |
1450 | ||
1451 | if (!check_of64a32s(dc) || | |
1452 | !check_pair(dc, a->d, a->dp)) { | |
1453 | return false; | |
1454 | } | |
1455 | check_r0_write(dc, a->d); | |
1456 | ||
1457 | t0 = tcg_temp_new_i64(); | |
1458 | gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a)); | |
1459 | save_pair(dc, t0, a->d, a->dp); | |
1460 | tcg_temp_free_i64(t0); | |
1461 | ||
1462 | gen_helper_update_fpcsr(cpu_env); | |
1463 | return true; | |
1464 | } | |
1465 | ||
1466 | static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a) | |
1467 | { | |
1468 | TCGv_i64 t0; | |
1469 | ||
1470 | if (!check_of64a32s(dc) || | |
1471 | !check_pair(dc, a->a, a->ap)) { | |
1472 | return false; | |
1473 | } | |
1474 | check_r0_write(dc, a->d); | |
1475 | ||
1476 | t0 = tcg_temp_new_i64(); | |
1477 | load_pair(dc, t0, a->a, a->ap); | |
1478 | gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0); | |
1479 | tcg_temp_free_i64(t0); | |
1480 | ||
1481 | gen_helper_update_fpcsr(cpu_env); | |
1482 | return true; | |
1483 | } | |
1484 | ||
1485 | static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a) | |
1486 | { | |
1487 | TCGv_i64 t0, t1, t2; | |
1488 | ||
1489 | if (!check_of64a32s(dc) || | |
1490 | !check_pair(dc, a->a, a->ap) || | |
1491 | !check_pair(dc, a->b, a->bp) || | |
1492 | !check_pair(dc, a->d, a->dp)) { | |
1493 | return false; | |
1494 | } | |
1495 | check_r0_write(dc, a->d); | |
1496 | ||
1497 | t0 = tcg_temp_new_i64(); | |
1498 | t1 = tcg_temp_new_i64(); | |
1499 | t2 = tcg_temp_new_i64(); | |
1500 | load_pair(dc, t0, a->d, a->dp); | |
1501 | load_pair(dc, t1, a->a, a->ap); | |
1502 | load_pair(dc, t2, a->b, a->bp); | |
1503 | gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2); | |
1504 | save_pair(dc, t0, a->d, a->dp); | |
1505 | tcg_temp_free_i64(t0); | |
1506 | tcg_temp_free_i64(t1); | |
1507 | tcg_temp_free_i64(t2); | |
1508 | ||
1509 | gen_helper_update_fpcsr(cpu_env); | |
1510 | return true; | |
1511 | } | |
1512 | ||
1513 | static bool trans_lf_sfeq_d(DisasContext *dc, arg_ab_pair *a) | |
1514 | { | |
1515 | return do_dpcmp(dc, a, gen_helper_float_eq_d, false, false); | |
1516 | } | |
1517 | ||
1518 | static bool trans_lf_sfne_d(DisasContext *dc, arg_ab_pair *a) | |
1519 | { | |
1520 | return do_dpcmp(dc, a, gen_helper_float_eq_d, true, false); | |
1521 | } | |
1522 | ||
1523 | static bool trans_lf_sfgt_d(DisasContext *dc, arg_ab_pair *a) | |
1524 | { | |
1525 | return do_dpcmp(dc, a, gen_helper_float_lt_d, false, true); | |
1526 | } | |
1527 | ||
1528 | static bool trans_lf_sfge_d(DisasContext *dc, arg_ab_pair *a) | |
1529 | { | |
1530 | return do_dpcmp(dc, a, gen_helper_float_le_d, false, true); | |
1531 | } | |
1532 | ||
1533 | static bool trans_lf_sflt_d(DisasContext *dc, arg_ab_pair *a) | |
1534 | { | |
1535 | return do_dpcmp(dc, a, gen_helper_float_lt_d, false, false); | |
1536 | } | |
1537 | ||
1538 | static bool trans_lf_sfle_d(DisasContext *dc, arg_ab_pair *a) | |
1539 | { | |
1540 | return do_dpcmp(dc, a, gen_helper_float_le_d, false, false); | |
1541 | } | |
1542 | ||
2b13b4b9 RH |
1543 | static bool trans_lf_sfueq_d(DisasContext *dc, arg_ab_pair *a) |
1544 | { | |
1545 | return do_dpcmp(dc, a, gen_helper_float_ueq_d, false, false); | |
1546 | } | |
1547 | ||
1548 | static bool trans_lf_sfule_d(DisasContext *dc, arg_ab_pair *a) | |
1549 | { | |
1550 | return do_dpcmp(dc, a, gen_helper_float_ule_d, false, false); | |
1551 | } | |
1552 | ||
1553 | static bool trans_lf_sfuge_d(DisasContext *dc, arg_ab_pair *a) | |
1554 | { | |
1555 | return do_dpcmp(dc, a, gen_helper_float_ule_d, false, true); | |
1556 | } | |
1557 | ||
1558 | static bool trans_lf_sfult_d(DisasContext *dc, arg_ab_pair *a) | |
1559 | { | |
1560 | return do_dpcmp(dc, a, gen_helper_float_ult_d, false, false); | |
1561 | } | |
1562 | ||
1563 | static bool trans_lf_sfugt_d(DisasContext *dc, arg_ab_pair *a) | |
1564 | { | |
1565 | return do_dpcmp(dc, a, gen_helper_float_ult_d, false, true); | |
1566 | } | |
1567 | ||
1568 | static bool trans_lf_sfun_d(DisasContext *dc, arg_ab_pair *a) | |
1569 | { | |
1570 | return do_dpcmp(dc, a, gen_helper_float_un_d, false, false); | |
1571 | } | |
1572 | ||
a4fd3ec3 | 1573 | static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) |
e67db06e | 1574 | { |
a4fd3ec3 | 1575 | DisasContext *dc = container_of(dcb, DisasContext, base); |
9c489ea6 | 1576 | CPUOpenRISCState *env = cs->env_ptr; |
a4fd3ec3 | 1577 | int bound; |
1ffa4bce | 1578 | |
a4fd3ec3 | 1579 | dc->mem_idx = cpu_mmu_index(env, false); |
1ffa4bce | 1580 | dc->tb_flags = dc->base.tb->flags; |
a01deb36 | 1581 | dc->delayed_branch = (dc->tb_flags & TB_FLAGS_DFLAG) != 0; |
fe636d37 | 1582 | dc->cpucfgr = env->cpucfgr; |
2b13b4b9 | 1583 | dc->avr = env->avr; |
8000ba56 RH |
1584 | dc->jmp_pc_imm = -1; |
1585 | ||
a4fd3ec3 EC |
1586 | bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; |
1587 | dc->base.max_insns = MIN(dc->base.max_insns, bound); | |
1588 | } | |
bbe418f2 | 1589 | |
a4fd3ec3 EC |
1590 | static void openrisc_tr_tb_start(DisasContextBase *db, CPUState *cs) |
1591 | { | |
1592 | DisasContext *dc = container_of(db, DisasContext, base); | |
bbe418f2 | 1593 | |
6597c28d RH |
1594 | /* Allow the TCG optimizer to see that R0 == 0, |
1595 | when it's true, which is the common case. */ | |
118671f0 | 1596 | dc->zero = tcg_constant_tl(0); |
6597c28d | 1597 | if (dc->tb_flags & TB_FLAGS_R0_0) { |
118671f0 | 1598 | dc->R0 = dc->zero; |
6597c28d | 1599 | } else { |
d29f4368 | 1600 | dc->R0 = cpu_regs[0]; |
6597c28d | 1601 | } |
a4fd3ec3 | 1602 | } |
6597c28d | 1603 | |
a4fd3ec3 EC |
1604 | static void openrisc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) |
1605 | { | |
1606 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
bbe418f2 | 1607 | |
a4fd3ec3 EC |
1608 | tcg_gen_insn_start(dc->base.pc_next, (dc->delayed_branch ? 1 : 0) |
1609 | | (dc->base.num_insns > 1 ? 2 : 0)); | |
1610 | } | |
b933066a | 1611 | |
a4fd3ec3 EC |
1612 | static void openrisc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) |
1613 | { | |
1614 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
1615 | OpenRISCCPU *cpu = OPENRISC_CPU(cs); | |
4e116893 | 1616 | uint32_t insn = translator_ldl(&cpu->env, &dc->base, dc->base.pc_next); |
a4fd3ec3 | 1617 | |
c7b6f54b RH |
1618 | if (!decode(dc, insn)) { |
1619 | gen_illegal_exception(dc); | |
1620 | } | |
a4fd3ec3 EC |
1621 | dc->base.pc_next += 4; |
1622 | ||
8000ba56 RH |
1623 | /* When exiting the delay slot normally, exit via jmp_pc. |
1624 | * For DISAS_NORETURN, we have raised an exception and already exited. | |
1625 | * For DISAS_EXIT, we found l.rfe in a delay slot. There's nothing | |
1626 | * in the manual saying this is illegal, but it surely it should. | |
1627 | * At least or1ksim overrides pcnext and ignores the branch. | |
1628 | */ | |
1629 | if (dc->delayed_branch | |
1630 | && --dc->delayed_branch == 0 | |
1631 | && dc->base.is_jmp == DISAS_NEXT) { | |
1632 | dc->base.is_jmp = DISAS_JUMP; | |
bbe418f2 | 1633 | } |
a4fd3ec3 EC |
1634 | } |
1635 | ||
1636 | static void openrisc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) | |
1637 | { | |
1638 | DisasContext *dc = container_of(dcbase, DisasContext, base); | |
8000ba56 | 1639 | target_ulong jmp_dest; |
24c32852 | 1640 | |
e0a369cf RH |
1641 | /* If we have already exited the TB, nothing following has effect. */ |
1642 | if (dc->base.is_jmp == DISAS_NORETURN) { | |
1643 | return; | |
1644 | } | |
1645 | ||
8000ba56 | 1646 | /* Adjust the delayed branch state for the next TB. */ |
a01deb36 RH |
1647 | if ((dc->tb_flags & TB_FLAGS_DFLAG ? 1 : 0) != (dc->delayed_branch != 0)) { |
1648 | tcg_gen_movi_i32(cpu_dflag, dc->delayed_branch != 0); | |
1649 | } | |
1650 | ||
8000ba56 RH |
1651 | /* For DISAS_TOO_MANY, jump to the next insn. */ |
1652 | jmp_dest = dc->base.pc_next; | |
1653 | tcg_gen_movi_tl(cpu_ppc, jmp_dest - 4); | |
1654 | ||
e0a369cf | 1655 | switch (dc->base.is_jmp) { |
8000ba56 RH |
1656 | case DISAS_JUMP: |
1657 | jmp_dest = dc->jmp_pc_imm; | |
1658 | if (jmp_dest == -1) { | |
1659 | /* The jump destination is indirect/computed; use jmp_pc. */ | |
1660 | tcg_gen_mov_tl(cpu_pc, jmp_pc); | |
1661 | tcg_gen_discard_tl(jmp_pc); | |
b21fce53 | 1662 | tcg_gen_lookup_and_goto_ptr(); |
8000ba56 RH |
1663 | break; |
1664 | } | |
1665 | /* The jump destination is direct; use jmp_pc_imm. | |
1666 | However, we will have stored into jmp_pc as well; | |
1667 | we know now that it wasn't needed. */ | |
1668 | tcg_gen_discard_tl(jmp_pc); | |
1669 | /* fallthru */ | |
1670 | ||
e0a369cf | 1671 | case DISAS_TOO_MANY: |
adf1f3de | 1672 | if (translator_use_goto_tb(&dc->base, jmp_dest)) { |
8000ba56 RH |
1673 | tcg_gen_goto_tb(0); |
1674 | tcg_gen_movi_tl(cpu_pc, jmp_dest); | |
1675 | tcg_gen_exit_tb(dc->base.tb, 0); | |
adf1f3de RH |
1676 | break; |
1677 | } | |
1678 | tcg_gen_movi_tl(cpu_pc, jmp_dest); | |
b21fce53 | 1679 | tcg_gen_lookup_and_goto_ptr(); |
e0a369cf | 1680 | break; |
8000ba56 | 1681 | |
e0a369cf | 1682 | case DISAS_EXIT: |
b21fce53 | 1683 | tcg_gen_exit_tb(NULL, 0); |
e0a369cf RH |
1684 | break; |
1685 | default: | |
1686 | g_assert_not_reached(); | |
bbe418f2 | 1687 | } |
a4fd3ec3 | 1688 | } |
bbe418f2 | 1689 | |
8eb806a7 RH |
1690 | static void openrisc_tr_disas_log(const DisasContextBase *dcbase, |
1691 | CPUState *cs, FILE *logfile) | |
a4fd3ec3 EC |
1692 | { |
1693 | DisasContext *s = container_of(dcbase, DisasContext, base); | |
0a7df5da | 1694 | |
8eb806a7 RH |
1695 | fprintf(logfile, "IN: %s\n", lookup_symbol(s->base.pc_first)); |
1696 | target_disas(logfile, cs, s->base.pc_first, s->base.tb->size); | |
a4fd3ec3 | 1697 | } |
bbe418f2 | 1698 | |
a4fd3ec3 EC |
1699 | static const TranslatorOps openrisc_tr_ops = { |
1700 | .init_disas_context = openrisc_tr_init_disas_context, | |
1701 | .tb_start = openrisc_tr_tb_start, | |
1702 | .insn_start = openrisc_tr_insn_start, | |
a4fd3ec3 EC |
1703 | .translate_insn = openrisc_tr_translate_insn, |
1704 | .tb_stop = openrisc_tr_tb_stop, | |
1705 | .disas_log = openrisc_tr_disas_log, | |
1706 | }; | |
1707 | ||
306c8721 RH |
1708 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, |
1709 | target_ulong pc, void *host_pc) | |
a4fd3ec3 EC |
1710 | { |
1711 | DisasContext ctx; | |
1712 | ||
306c8721 RH |
1713 | translator_loop(cs, tb, max_insns, pc, host_pc, |
1714 | &openrisc_tr_ops, &ctx.base); | |
e67db06e JL |
1715 | } |
1716 | ||
90c84c56 | 1717 | void openrisc_cpu_dump_state(CPUState *cs, FILE *f, int flags) |
e67db06e | 1718 | { |
878096ee AF |
1719 | OpenRISCCPU *cpu = OPENRISC_CPU(cs); |
1720 | CPUOpenRISCState *env = &cpu->env; | |
e67db06e | 1721 | int i; |
878096ee | 1722 | |
90c84c56 | 1723 | qemu_fprintf(f, "PC=%08x\n", env->pc); |
e67db06e | 1724 | for (i = 0; i < 32; ++i) { |
90c84c56 MA |
1725 | qemu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i), |
1726 | (i % 4) == 3 ? '\n' : ' '); | |
e67db06e JL |
1727 | } |
1728 | } |