]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/translate.c
tcg/tci: Add TCG_TARGET_DEFAULT_MO
[mirror_qemu.git] / target / hppa / translate.c
CommitLineData
61766fe9
RH
1/*
2 * HPPA emulation cpu translation for qemu.
3 *
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "disas/disas.h"
23#include "qemu/host-utils.h"
24#include "exec/exec-all.h"
25#include "tcg-op.h"
26#include "exec/cpu_ldst.h"
27
28#include "exec/helper-proto.h"
29#include "exec/helper-gen.h"
30
31#include "trace-tcg.h"
32#include "exec/log.h"
33
34typedef struct DisasCond {
35 TCGCond c;
36 TCGv a0, a1;
37 bool a0_is_n;
38 bool a1_is_0;
39} DisasCond;
40
41typedef struct DisasContext {
42 struct TranslationBlock *tb;
43 CPUState *cs;
44
45 target_ulong iaoq_f;
46 target_ulong iaoq_b;
47 target_ulong iaoq_n;
48 TCGv iaoq_n_var;
49
50 int ntemps;
51 TCGv temps[8];
52
53 DisasCond null_cond;
54 TCGLabel *null_lab;
55
56 bool singlestep_enabled;
57 bool psw_n_nonzero;
58} DisasContext;
59
60/* Return values from translate_one, indicating the state of the TB.
61 Note that zero indicates that we are not exiting the TB. */
62
63typedef enum {
64 NO_EXIT,
65
66 /* We have emitted one or more goto_tb. No fixup required. */
67 EXIT_GOTO_TB,
68
69 /* We are not using a goto_tb (for whatever reason), but have updated
70 the iaq (for whatever reason), so don't do it again on exit. */
71 EXIT_IAQ_N_UPDATED,
72
73 /* We are exiting the TB, but have neither emitted a goto_tb, nor
74 updated the iaq for the next instruction to be executed. */
75 EXIT_IAQ_N_STALE,
76
77 /* We are ending the TB with a noreturn function call, e.g. longjmp.
78 No following code will be executed. */
79 EXIT_NORETURN,
80} ExitStatus;
81
82typedef struct DisasInsn {
83 uint32_t insn, mask;
84 ExitStatus (*trans)(DisasContext *ctx, uint32_t insn,
85 const struct DisasInsn *f);
b2167459 86 union {
eff235eb
PB
87 void (*ttt)(TCGv, TCGv, TCGv);
88 void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
89 void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
90 void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
91 void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
92 void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
93 void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
94 } f;
61766fe9
RH
95} DisasInsn;
96
97/* global register indexes */
98static TCGv_env cpu_env;
99static TCGv cpu_gr[32];
100static TCGv cpu_iaoq_f;
101static TCGv cpu_iaoq_b;
102static TCGv cpu_sar;
103static TCGv cpu_psw_n;
104static TCGv cpu_psw_v;
105static TCGv cpu_psw_cb;
106static TCGv cpu_psw_cb_msb;
107static TCGv cpu_cr26;
108static TCGv cpu_cr27;
109
110#include "exec/gen-icount.h"
111
112void hppa_translate_init(void)
113{
114#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
115
116 typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
117 static const GlobalVar vars[] = {
118 DEF_VAR(sar),
119 DEF_VAR(cr26),
120 DEF_VAR(cr27),
121 DEF_VAR(psw_n),
122 DEF_VAR(psw_v),
123 DEF_VAR(psw_cb),
124 DEF_VAR(psw_cb_msb),
125 DEF_VAR(iaoq_f),
126 DEF_VAR(iaoq_b),
127 };
128
129#undef DEF_VAR
130
131 /* Use the symbolic register names that match the disassembler. */
132 static const char gr_names[32][4] = {
133 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
134 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
135 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
136 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
137 };
138
139 static bool done_init = 0;
140 int i;
141
142 if (done_init) {
143 return;
144 }
145 done_init = 1;
146
147 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
148 tcg_ctx.tcg_env = cpu_env;
149
150 TCGV_UNUSED(cpu_gr[0]);
151 for (i = 1; i < 32; i++) {
152 cpu_gr[i] = tcg_global_mem_new(cpu_env,
153 offsetof(CPUHPPAState, gr[i]),
154 gr_names[i]);
155 }
156
157 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
158 const GlobalVar *v = &vars[i];
159 *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
160 }
161}
162
129e9cc3
RH
163static DisasCond cond_make_f(void)
164{
165 DisasCond r = { .c = TCG_COND_NEVER };
166 TCGV_UNUSED(r.a0);
167 TCGV_UNUSED(r.a1);
168 return r;
169}
170
171static DisasCond cond_make_n(void)
172{
173 DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
174 r.a0 = cpu_psw_n;
175 TCGV_UNUSED(r.a1);
176 return r;
177}
178
179static DisasCond cond_make_0(TCGCond c, TCGv a0)
180{
181 DisasCond r = { .c = c, .a1_is_0 = true };
182
183 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
184 r.a0 = tcg_temp_new();
185 tcg_gen_mov_tl(r.a0, a0);
186 TCGV_UNUSED(r.a1);
187
188 return r;
189}
190
191static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
192{
193 DisasCond r = { .c = c };
194
195 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
196 r.a0 = tcg_temp_new();
197 tcg_gen_mov_tl(r.a0, a0);
198 r.a1 = tcg_temp_new();
199 tcg_gen_mov_tl(r.a1, a1);
200
201 return r;
202}
203
204static void cond_prep(DisasCond *cond)
205{
206 if (cond->a1_is_0) {
207 cond->a1_is_0 = false;
208 cond->a1 = tcg_const_tl(0);
209 }
210}
211
212static void cond_free(DisasCond *cond)
213{
214 switch (cond->c) {
215 default:
216 if (!cond->a0_is_n) {
217 tcg_temp_free(cond->a0);
218 }
219 if (!cond->a1_is_0) {
220 tcg_temp_free(cond->a1);
221 }
222 cond->a0_is_n = false;
223 cond->a1_is_0 = false;
224 TCGV_UNUSED(cond->a0);
225 TCGV_UNUSED(cond->a1);
226 /* fallthru */
227 case TCG_COND_ALWAYS:
228 cond->c = TCG_COND_NEVER;
229 break;
230 case TCG_COND_NEVER:
231 break;
232 }
233}
234
61766fe9
RH
235static TCGv get_temp(DisasContext *ctx)
236{
237 unsigned i = ctx->ntemps++;
238 g_assert(i < ARRAY_SIZE(ctx->temps));
239 return ctx->temps[i] = tcg_temp_new();
240}
241
242static TCGv load_const(DisasContext *ctx, target_long v)
243{
244 TCGv t = get_temp(ctx);
245 tcg_gen_movi_tl(t, v);
246 return t;
247}
248
249static TCGv load_gpr(DisasContext *ctx, unsigned reg)
250{
251 if (reg == 0) {
252 TCGv t = get_temp(ctx);
253 tcg_gen_movi_tl(t, 0);
254 return t;
255 } else {
256 return cpu_gr[reg];
257 }
258}
259
260static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
261{
129e9cc3 262 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
61766fe9
RH
263 return get_temp(ctx);
264 } else {
265 return cpu_gr[reg];
266 }
267}
268
129e9cc3
RH
269static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
270{
271 if (ctx->null_cond.c != TCG_COND_NEVER) {
272 cond_prep(&ctx->null_cond);
273 tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
274 ctx->null_cond.a1, dest, t);
275 } else {
276 tcg_gen_mov_tl(dest, t);
277 }
278}
279
280static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
281{
282 if (reg != 0) {
283 save_or_nullify(ctx, cpu_gr[reg], t);
284 }
285}
286
96d6407f
RH
287#ifdef HOST_WORDS_BIGENDIAN
288# define HI_OFS 0
289# define LO_OFS 4
290#else
291# define HI_OFS 4
292# define LO_OFS 0
293#endif
294
295static TCGv_i32 load_frw_i32(unsigned rt)
296{
297 TCGv_i32 ret = tcg_temp_new_i32();
298 tcg_gen_ld_i32(ret, cpu_env,
299 offsetof(CPUHPPAState, fr[rt & 31])
300 + (rt & 32 ? LO_OFS : HI_OFS));
301 return ret;
302}
303
ebe9383c
RH
304static TCGv_i32 load_frw0_i32(unsigned rt)
305{
306 if (rt == 0) {
307 return tcg_const_i32(0);
308 } else {
309 return load_frw_i32(rt);
310 }
311}
312
313static TCGv_i64 load_frw0_i64(unsigned rt)
314{
315 if (rt == 0) {
316 return tcg_const_i64(0);
317 } else {
318 TCGv_i64 ret = tcg_temp_new_i64();
319 tcg_gen_ld32u_i64(ret, cpu_env,
320 offsetof(CPUHPPAState, fr[rt & 31])
321 + (rt & 32 ? LO_OFS : HI_OFS));
322 return ret;
323 }
324}
325
96d6407f
RH
326static void save_frw_i32(unsigned rt, TCGv_i32 val)
327{
328 tcg_gen_st_i32(val, cpu_env,
329 offsetof(CPUHPPAState, fr[rt & 31])
330 + (rt & 32 ? LO_OFS : HI_OFS));
331}
332
333#undef HI_OFS
334#undef LO_OFS
335
336static TCGv_i64 load_frd(unsigned rt)
337{
338 TCGv_i64 ret = tcg_temp_new_i64();
339 tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
340 return ret;
341}
342
ebe9383c
RH
343static TCGv_i64 load_frd0(unsigned rt)
344{
345 if (rt == 0) {
346 return tcg_const_i64(0);
347 } else {
348 return load_frd(rt);
349 }
350}
351
96d6407f
RH
352static void save_frd(unsigned rt, TCGv_i64 val)
353{
354 tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
355}
356
129e9cc3
RH
357/* Skip over the implementation of an insn that has been nullified.
358 Use this when the insn is too complex for a conditional move. */
359static void nullify_over(DisasContext *ctx)
360{
361 if (ctx->null_cond.c != TCG_COND_NEVER) {
362 /* The always condition should have been handled in the main loop. */
363 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
364
365 ctx->null_lab = gen_new_label();
366 cond_prep(&ctx->null_cond);
367
368 /* If we're using PSW[N], copy it to a temp because... */
369 if (ctx->null_cond.a0_is_n) {
370 ctx->null_cond.a0_is_n = false;
371 ctx->null_cond.a0 = tcg_temp_new();
372 tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
373 }
374 /* ... we clear it before branching over the implementation,
375 so that (1) it's clear after nullifying this insn and
376 (2) if this insn nullifies the next, PSW[N] is valid. */
377 if (ctx->psw_n_nonzero) {
378 ctx->psw_n_nonzero = false;
379 tcg_gen_movi_tl(cpu_psw_n, 0);
380 }
381
382 tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
383 ctx->null_cond.a1, ctx->null_lab);
384 cond_free(&ctx->null_cond);
385 }
386}
387
388/* Save the current nullification state to PSW[N]. */
389static void nullify_save(DisasContext *ctx)
390{
391 if (ctx->null_cond.c == TCG_COND_NEVER) {
392 if (ctx->psw_n_nonzero) {
393 tcg_gen_movi_tl(cpu_psw_n, 0);
394 }
395 return;
396 }
397 if (!ctx->null_cond.a0_is_n) {
398 cond_prep(&ctx->null_cond);
399 tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
400 ctx->null_cond.a0, ctx->null_cond.a1);
401 ctx->psw_n_nonzero = true;
402 }
403 cond_free(&ctx->null_cond);
404}
405
406/* Set a PSW[N] to X. The intention is that this is used immediately
407 before a goto_tb/exit_tb, so that there is no fallthru path to other
408 code within the TB. Therefore we do not update psw_n_nonzero. */
409static void nullify_set(DisasContext *ctx, bool x)
410{
411 if (ctx->psw_n_nonzero || x) {
412 tcg_gen_movi_tl(cpu_psw_n, x);
413 }
414}
415
416/* Mark the end of an instruction that may have been nullified.
417 This is the pair to nullify_over. */
418static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
419{
420 TCGLabel *null_lab = ctx->null_lab;
421
422 if (likely(null_lab == NULL)) {
423 /* The current insn wasn't conditional or handled the condition
424 applied to it without a branch, so the (new) setting of
425 NULL_COND can be applied directly to the next insn. */
426 return status;
427 }
428 ctx->null_lab = NULL;
429
430 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
431 /* The next instruction will be unconditional,
432 and NULL_COND already reflects that. */
433 gen_set_label(null_lab);
434 } else {
435 /* The insn that we just executed is itself nullifying the next
436 instruction. Store the condition in the PSW[N] global.
437 We asserted PSW[N] = 0 in nullify_over, so that after the
438 label we have the proper value in place. */
439 nullify_save(ctx);
440 gen_set_label(null_lab);
441 ctx->null_cond = cond_make_n();
442 }
443
444 assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
445 if (status == EXIT_NORETURN) {
446 status = NO_EXIT;
447 }
448 return status;
449}
450
61766fe9
RH
451static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
452{
453 if (unlikely(ival == -1)) {
454 tcg_gen_mov_tl(dest, vval);
455 } else {
456 tcg_gen_movi_tl(dest, ival);
457 }
458}
459
460static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
461{
462 return ctx->iaoq_f + disp + 8;
463}
464
465static void gen_excp_1(int exception)
466{
467 TCGv_i32 t = tcg_const_i32(exception);
468 gen_helper_excp(cpu_env, t);
469 tcg_temp_free_i32(t);
470}
471
472static ExitStatus gen_excp(DisasContext *ctx, int exception)
473{
474 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
475 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
129e9cc3 476 nullify_save(ctx);
61766fe9
RH
477 gen_excp_1(exception);
478 return EXIT_NORETURN;
479}
480
481static ExitStatus gen_illegal(DisasContext *ctx)
482{
129e9cc3
RH
483 nullify_over(ctx);
484 return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
61766fe9
RH
485}
486
487static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
488{
489 /* Suppress goto_tb in the case of single-steping and IO. */
490 if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
491 return false;
492 }
493 return true;
494}
495
129e9cc3
RH
496/* If the next insn is to be nullified, and it's on the same page,
497 and we're not attempting to set a breakpoint on it, then we can
498 totally skip the nullified insn. This avoids creating and
499 executing a TB that merely branches to the next TB. */
500static bool use_nullify_skip(DisasContext *ctx)
501{
502 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
503 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
504}
505
61766fe9
RH
506static void gen_goto_tb(DisasContext *ctx, int which,
507 target_ulong f, target_ulong b)
508{
509 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
510 tcg_gen_goto_tb(which);
511 tcg_gen_movi_tl(cpu_iaoq_f, f);
512 tcg_gen_movi_tl(cpu_iaoq_b, b);
513 tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
514 } else {
515 copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
516 copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
517 if (ctx->singlestep_enabled) {
518 gen_excp_1(EXCP_DEBUG);
519 } else {
4137cb83 520 tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
61766fe9
RH
521 }
522 }
523}
524
b2167459
RH
525/* PA has a habit of taking the LSB of a field and using that as the sign,
526 with the rest of the field becoming the least significant bits. */
527static target_long low_sextract(uint32_t val, int pos, int len)
528{
529 target_ulong x = -(target_ulong)extract32(val, pos, 1);
530 x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
531 return x;
532}
533
ebe9383c
RH
534static unsigned assemble_rt64(uint32_t insn)
535{
536 unsigned r1 = extract32(insn, 6, 1);
537 unsigned r0 = extract32(insn, 0, 5);
538 return r1 * 32 + r0;
539}
540
541static unsigned assemble_ra64(uint32_t insn)
542{
543 unsigned r1 = extract32(insn, 7, 1);
544 unsigned r0 = extract32(insn, 21, 5);
545 return r1 * 32 + r0;
546}
547
548static unsigned assemble_rb64(uint32_t insn)
549{
550 unsigned r1 = extract32(insn, 12, 1);
551 unsigned r0 = extract32(insn, 16, 5);
552 return r1 * 32 + r0;
553}
554
555static unsigned assemble_rc64(uint32_t insn)
556{
557 unsigned r2 = extract32(insn, 8, 1);
558 unsigned r1 = extract32(insn, 13, 3);
559 unsigned r0 = extract32(insn, 9, 2);
560 return r2 * 32 + r1 * 4 + r0;
561}
562
98cd9ca7
RH
563static target_long assemble_12(uint32_t insn)
564{
565 target_ulong x = -(target_ulong)(insn & 1);
566 x = (x << 1) | extract32(insn, 2, 1);
567 x = (x << 10) | extract32(insn, 3, 10);
568 return x;
569}
570
b2167459
RH
571static target_long assemble_16(uint32_t insn)
572{
573 /* Take the name from PA2.0, which produces a 16-bit number
574 only with wide mode; otherwise a 14-bit number. Since we don't
575 implement wide mode, this is always the 14-bit number. */
576 return low_sextract(insn, 0, 14);
577}
578
96d6407f
RH
579static target_long assemble_16a(uint32_t insn)
580{
581 /* Take the name from PA2.0, which produces a 14-bit shifted number
582 only with wide mode; otherwise a 12-bit shifted number. Since we
583 don't implement wide mode, this is always the 12-bit number. */
584 target_ulong x = -(target_ulong)(insn & 1);
585 x = (x << 11) | extract32(insn, 2, 11);
586 return x << 2;
587}
588
98cd9ca7
RH
589static target_long assemble_17(uint32_t insn)
590{
591 target_ulong x = -(target_ulong)(insn & 1);
592 x = (x << 5) | extract32(insn, 16, 5);
593 x = (x << 1) | extract32(insn, 2, 1);
594 x = (x << 10) | extract32(insn, 3, 10);
595 return x << 2;
596}
597
b2167459
RH
598static target_long assemble_21(uint32_t insn)
599{
600 target_ulong x = -(target_ulong)(insn & 1);
601 x = (x << 11) | extract32(insn, 1, 11);
602 x = (x << 2) | extract32(insn, 14, 2);
603 x = (x << 5) | extract32(insn, 16, 5);
604 x = (x << 2) | extract32(insn, 12, 2);
605 return x << 11;
606}
607
98cd9ca7
RH
608static target_long assemble_22(uint32_t insn)
609{
610 target_ulong x = -(target_ulong)(insn & 1);
611 x = (x << 10) | extract32(insn, 16, 10);
612 x = (x << 1) | extract32(insn, 2, 1);
613 x = (x << 10) | extract32(insn, 3, 10);
614 return x << 2;
615}
616
b2167459
RH
617/* The parisc documentation describes only the general interpretation of
618 the conditions, without describing their exact implementation. The
619 interpretations do not stand up well when considering ADD,C and SUB,B.
620 However, considering the Addition, Subtraction and Logical conditions
621 as a whole it would appear that these relations are similar to what
622 a traditional NZCV set of flags would produce. */
623
624static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
625{
626 DisasCond cond;
627 TCGv tmp;
628
629 switch (cf >> 1) {
630 case 0: /* Never / TR */
631 cond = cond_make_f();
632 break;
633 case 1: /* = / <> (Z / !Z) */
634 cond = cond_make_0(TCG_COND_EQ, res);
635 break;
636 case 2: /* < / >= (N / !N) */
637 cond = cond_make_0(TCG_COND_LT, res);
638 break;
639 case 3: /* <= / > (N | Z / !N & !Z) */
640 cond = cond_make_0(TCG_COND_LE, res);
641 break;
642 case 4: /* NUV / UV (!C / C) */
643 cond = cond_make_0(TCG_COND_EQ, cb_msb);
644 break;
645 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
646 tmp = tcg_temp_new();
647 tcg_gen_neg_tl(tmp, cb_msb);
648 tcg_gen_and_tl(tmp, tmp, res);
649 cond = cond_make_0(TCG_COND_EQ, tmp);
650 tcg_temp_free(tmp);
651 break;
652 case 6: /* SV / NSV (V / !V) */
653 cond = cond_make_0(TCG_COND_LT, sv);
654 break;
655 case 7: /* OD / EV */
656 tmp = tcg_temp_new();
657 tcg_gen_andi_tl(tmp, res, 1);
658 cond = cond_make_0(TCG_COND_NE, tmp);
659 tcg_temp_free(tmp);
660 break;
661 default:
662 g_assert_not_reached();
663 }
664 if (cf & 1) {
665 cond.c = tcg_invert_cond(cond.c);
666 }
667
668 return cond;
669}
670
671/* Similar, but for the special case of subtraction without borrow, we
672 can use the inputs directly. This can allow other computation to be
673 deleted as unused. */
674
675static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
676{
677 DisasCond cond;
678
679 switch (cf >> 1) {
680 case 1: /* = / <> */
681 cond = cond_make(TCG_COND_EQ, in1, in2);
682 break;
683 case 2: /* < / >= */
684 cond = cond_make(TCG_COND_LT, in1, in2);
685 break;
686 case 3: /* <= / > */
687 cond = cond_make(TCG_COND_LE, in1, in2);
688 break;
689 case 4: /* << / >>= */
690 cond = cond_make(TCG_COND_LTU, in1, in2);
691 break;
692 case 5: /* <<= / >> */
693 cond = cond_make(TCG_COND_LEU, in1, in2);
694 break;
695 default:
696 return do_cond(cf, res, sv, sv);
697 }
698 if (cf & 1) {
699 cond.c = tcg_invert_cond(cond.c);
700 }
701
702 return cond;
703}
704
705/* Similar, but for logicals, where the carry and overflow bits are not
706 computed, and use of them is undefined. */
707
708static DisasCond do_log_cond(unsigned cf, TCGv res)
709{
710 switch (cf >> 1) {
711 case 4: case 5: case 6:
712 cf &= 1;
713 break;
714 }
715 return do_cond(cf, res, res, res);
716}
717
98cd9ca7
RH
718/* Similar, but for shift/extract/deposit conditions. */
719
720static DisasCond do_sed_cond(unsigned orig, TCGv res)
721{
722 unsigned c, f;
723
724 /* Convert the compressed condition codes to standard.
725 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
726 4-7 are the reverse of 0-3. */
727 c = orig & 3;
728 if (c == 3) {
729 c = 7;
730 }
731 f = (orig & 4) / 4;
732
733 return do_log_cond(c * 2 + f, res);
734}
735
b2167459
RH
736/* Similar, but for unit conditions. */
737
738static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
739{
740 DisasCond cond;
741 TCGv tmp, cb;
742
743 TCGV_UNUSED(cb);
744 if (cf & 8) {
745 /* Since we want to test lots of carry-out bits all at once, do not
746 * do our normal thing and compute carry-in of bit B+1 since that
747 * leaves us with carry bits spread across two words.
748 */
749 cb = tcg_temp_new();
750 tmp = tcg_temp_new();
751 tcg_gen_or_tl(cb, in1, in2);
752 tcg_gen_and_tl(tmp, in1, in2);
753 tcg_gen_andc_tl(cb, cb, res);
754 tcg_gen_or_tl(cb, cb, tmp);
755 tcg_temp_free(tmp);
756 }
757
758 switch (cf >> 1) {
759 case 0: /* never / TR */
760 case 1: /* undefined */
761 case 5: /* undefined */
762 cond = cond_make_f();
763 break;
764
765 case 2: /* SBZ / NBZ */
766 /* See hasless(v,1) from
767 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
768 */
769 tmp = tcg_temp_new();
770 tcg_gen_subi_tl(tmp, res, 0x01010101u);
771 tcg_gen_andc_tl(tmp, tmp, res);
772 tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
773 cond = cond_make_0(TCG_COND_NE, tmp);
774 tcg_temp_free(tmp);
775 break;
776
777 case 3: /* SHZ / NHZ */
778 tmp = tcg_temp_new();
779 tcg_gen_subi_tl(tmp, res, 0x00010001u);
780 tcg_gen_andc_tl(tmp, tmp, res);
781 tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
782 cond = cond_make_0(TCG_COND_NE, tmp);
783 tcg_temp_free(tmp);
784 break;
785
786 case 4: /* SDC / NDC */
787 tcg_gen_andi_tl(cb, cb, 0x88888888u);
788 cond = cond_make_0(TCG_COND_NE, cb);
789 break;
790
791 case 6: /* SBC / NBC */
792 tcg_gen_andi_tl(cb, cb, 0x80808080u);
793 cond = cond_make_0(TCG_COND_NE, cb);
794 break;
795
796 case 7: /* SHC / NHC */
797 tcg_gen_andi_tl(cb, cb, 0x80008000u);
798 cond = cond_make_0(TCG_COND_NE, cb);
799 break;
800
801 default:
802 g_assert_not_reached();
803 }
804 if (cf & 8) {
805 tcg_temp_free(cb);
806 }
807 if (cf & 1) {
808 cond.c = tcg_invert_cond(cond.c);
809 }
810
811 return cond;
812}
813
814/* Compute signed overflow for addition. */
815static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
816{
817 TCGv sv = get_temp(ctx);
818 TCGv tmp = tcg_temp_new();
819
820 tcg_gen_xor_tl(sv, res, in1);
821 tcg_gen_xor_tl(tmp, in1, in2);
822 tcg_gen_andc_tl(sv, sv, tmp);
823 tcg_temp_free(tmp);
824
825 return sv;
826}
827
828/* Compute signed overflow for subtraction. */
829static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
830{
831 TCGv sv = get_temp(ctx);
832 TCGv tmp = tcg_temp_new();
833
834 tcg_gen_xor_tl(sv, res, in1);
835 tcg_gen_xor_tl(tmp, in1, in2);
836 tcg_gen_and_tl(sv, sv, tmp);
837 tcg_temp_free(tmp);
838
839 return sv;
840}
841
842static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
843 unsigned shift, bool is_l, bool is_tsv, bool is_tc,
844 bool is_c, unsigned cf)
845{
846 TCGv dest, cb, cb_msb, sv, tmp;
847 unsigned c = cf >> 1;
848 DisasCond cond;
849
850 dest = tcg_temp_new();
851 TCGV_UNUSED(cb);
852 TCGV_UNUSED(cb_msb);
853
854 if (shift) {
855 tmp = get_temp(ctx);
856 tcg_gen_shli_tl(tmp, in1, shift);
857 in1 = tmp;
858 }
859
860 if (!is_l || c == 4 || c == 5) {
861 TCGv zero = tcg_const_tl(0);
862 cb_msb = get_temp(ctx);
863 tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
864 if (is_c) {
865 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
866 }
867 tcg_temp_free(zero);
868 if (!is_l) {
869 cb = get_temp(ctx);
870 tcg_gen_xor_tl(cb, in1, in2);
871 tcg_gen_xor_tl(cb, cb, dest);
872 }
873 } else {
874 tcg_gen_add_tl(dest, in1, in2);
875 if (is_c) {
876 tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
877 }
878 }
879
880 /* Compute signed overflow if required. */
881 TCGV_UNUSED(sv);
882 if (is_tsv || c == 6) {
883 sv = do_add_sv(ctx, dest, in1, in2);
884 if (is_tsv) {
885 /* ??? Need to include overflow from shift. */
886 gen_helper_tsv(cpu_env, sv);
887 }
888 }
889
890 /* Emit any conditional trap before any writeback. */
891 cond = do_cond(cf, dest, cb_msb, sv);
892 if (is_tc) {
893 cond_prep(&cond);
894 tmp = tcg_temp_new();
895 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
896 gen_helper_tcond(cpu_env, tmp);
897 tcg_temp_free(tmp);
898 }
899
900 /* Write back the result. */
901 if (!is_l) {
902 save_or_nullify(ctx, cpu_psw_cb, cb);
903 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
904 }
905 save_gpr(ctx, rt, dest);
906 tcg_temp_free(dest);
907
908 /* Install the new nullification. */
909 cond_free(&ctx->null_cond);
910 ctx->null_cond = cond;
911 return NO_EXIT;
912}
913
914static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
915 bool is_tsv, bool is_b, bool is_tc, unsigned cf)
916{
917 TCGv dest, sv, cb, cb_msb, zero, tmp;
918 unsigned c = cf >> 1;
919 DisasCond cond;
920
921 dest = tcg_temp_new();
922 cb = tcg_temp_new();
923 cb_msb = tcg_temp_new();
924
925 zero = tcg_const_tl(0);
926 if (is_b) {
927 /* DEST,C = IN1 + ~IN2 + C. */
928 tcg_gen_not_tl(cb, in2);
929 tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
930 tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
931 tcg_gen_xor_tl(cb, cb, in1);
932 tcg_gen_xor_tl(cb, cb, dest);
933 } else {
934 /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
935 operations by seeding the high word with 1 and subtracting. */
936 tcg_gen_movi_tl(cb_msb, 1);
937 tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
938 tcg_gen_eqv_tl(cb, in1, in2);
939 tcg_gen_xor_tl(cb, cb, dest);
940 }
941 tcg_temp_free(zero);
942
943 /* Compute signed overflow if required. */
944 TCGV_UNUSED(sv);
945 if (is_tsv || c == 6) {
946 sv = do_sub_sv(ctx, dest, in1, in2);
947 if (is_tsv) {
948 gen_helper_tsv(cpu_env, sv);
949 }
950 }
951
952 /* Compute the condition. We cannot use the special case for borrow. */
953 if (!is_b) {
954 cond = do_sub_cond(cf, dest, in1, in2, sv);
955 } else {
956 cond = do_cond(cf, dest, cb_msb, sv);
957 }
958
959 /* Emit any conditional trap before any writeback. */
960 if (is_tc) {
961 cond_prep(&cond);
962 tmp = tcg_temp_new();
963 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
964 gen_helper_tcond(cpu_env, tmp);
965 tcg_temp_free(tmp);
966 }
967
968 /* Write back the result. */
969 save_or_nullify(ctx, cpu_psw_cb, cb);
970 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
971 save_gpr(ctx, rt, dest);
972 tcg_temp_free(dest);
973
974 /* Install the new nullification. */
975 cond_free(&ctx->null_cond);
976 ctx->null_cond = cond;
977 return NO_EXIT;
978}
979
980static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
981 TCGv in2, unsigned cf)
982{
983 TCGv dest, sv;
984 DisasCond cond;
985
986 dest = tcg_temp_new();
987 tcg_gen_sub_tl(dest, in1, in2);
988
989 /* Compute signed overflow if required. */
990 TCGV_UNUSED(sv);
991 if ((cf >> 1) == 6) {
992 sv = do_sub_sv(ctx, dest, in1, in2);
993 }
994
995 /* Form the condition for the compare. */
996 cond = do_sub_cond(cf, dest, in1, in2, sv);
997
998 /* Clear. */
999 tcg_gen_movi_tl(dest, 0);
1000 save_gpr(ctx, rt, dest);
1001 tcg_temp_free(dest);
1002
1003 /* Install the new nullification. */
1004 cond_free(&ctx->null_cond);
1005 ctx->null_cond = cond;
1006 return NO_EXIT;
1007}
1008
1009static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
1010 unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
1011{
1012 TCGv dest = dest_gpr(ctx, rt);
1013
1014 /* Perform the operation, and writeback. */
1015 fn(dest, in1, in2);
1016 save_gpr(ctx, rt, dest);
1017
1018 /* Install the new nullification. */
1019 cond_free(&ctx->null_cond);
1020 if (cf) {
1021 ctx->null_cond = do_log_cond(cf, dest);
1022 }
1023 return NO_EXIT;
1024}
1025
1026static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1027 TCGv in2, unsigned cf, bool is_tc,
1028 void (*fn)(TCGv, TCGv, TCGv))
1029{
1030 TCGv dest;
1031 DisasCond cond;
1032
1033 if (cf == 0) {
1034 dest = dest_gpr(ctx, rt);
1035 fn(dest, in1, in2);
1036 save_gpr(ctx, rt, dest);
1037 cond_free(&ctx->null_cond);
1038 } else {
1039 dest = tcg_temp_new();
1040 fn(dest, in1, in2);
1041
1042 cond = do_unit_cond(cf, dest, in1, in2);
1043
1044 if (is_tc) {
1045 TCGv tmp = tcg_temp_new();
1046 cond_prep(&cond);
1047 tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1048 gen_helper_tcond(cpu_env, tmp);
1049 tcg_temp_free(tmp);
1050 }
1051 save_gpr(ctx, rt, dest);
1052
1053 cond_free(&ctx->null_cond);
1054 ctx->null_cond = cond;
1055 }
1056 return NO_EXIT;
1057}
1058
96d6407f
RH
1059/* Emit a memory load. The modify parameter should be
1060 * < 0 for pre-modify,
1061 * > 0 for post-modify,
1062 * = 0 for no base register update.
1063 */
1064static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1065 unsigned rx, int scale, target_long disp,
1066 int modify, TCGMemOp mop)
1067{
1068 TCGv addr, base;
1069
1070 /* Caller uses nullify_over/nullify_end. */
1071 assert(ctx->null_cond.c == TCG_COND_NEVER);
1072
1073 addr = tcg_temp_new();
1074 base = load_gpr(ctx, rb);
1075
1076 /* Note that RX is mutually exclusive with DISP. */
1077 if (rx) {
1078 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1079 tcg_gen_add_tl(addr, addr, base);
1080 } else {
1081 tcg_gen_addi_tl(addr, base, disp);
1082 }
1083
1084 if (modify == 0) {
1085 tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
1086 } else {
1087 tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
1088 MMU_USER_IDX, mop);
1089 save_gpr(ctx, rb, addr);
1090 }
1091 tcg_temp_free(addr);
1092}
1093
1094static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1095 unsigned rx, int scale, target_long disp,
1096 int modify, TCGMemOp mop)
1097{
1098 TCGv addr, base;
1099
1100 /* Caller uses nullify_over/nullify_end. */
1101 assert(ctx->null_cond.c == TCG_COND_NEVER);
1102
1103 addr = tcg_temp_new();
1104 base = load_gpr(ctx, rb);
1105
1106 /* Note that RX is mutually exclusive with DISP. */
1107 if (rx) {
1108 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1109 tcg_gen_add_tl(addr, addr, base);
1110 } else {
1111 tcg_gen_addi_tl(addr, base, disp);
1112 }
1113
1114 if (modify == 0) {
1115 tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
1116 } else {
1117 tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
1118 MMU_USER_IDX, mop);
1119 save_gpr(ctx, rb, addr);
1120 }
1121 tcg_temp_free(addr);
1122}
1123
1124static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1125 unsigned rx, int scale, target_long disp,
1126 int modify, TCGMemOp mop)
1127{
1128 TCGv addr, base;
1129
1130 /* Caller uses nullify_over/nullify_end. */
1131 assert(ctx->null_cond.c == TCG_COND_NEVER);
1132
1133 addr = tcg_temp_new();
1134 base = load_gpr(ctx, rb);
1135
1136 /* Note that RX is mutually exclusive with DISP. */
1137 if (rx) {
1138 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1139 tcg_gen_add_tl(addr, addr, base);
1140 } else {
1141 tcg_gen_addi_tl(addr, base, disp);
1142 }
1143
1144 tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1145
1146 if (modify != 0) {
1147 save_gpr(ctx, rb, addr);
1148 }
1149 tcg_temp_free(addr);
1150}
1151
1152static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1153 unsigned rx, int scale, target_long disp,
1154 int modify, TCGMemOp mop)
1155{
1156 TCGv addr, base;
1157
1158 /* Caller uses nullify_over/nullify_end. */
1159 assert(ctx->null_cond.c == TCG_COND_NEVER);
1160
1161 addr = tcg_temp_new();
1162 base = load_gpr(ctx, rb);
1163
1164 /* Note that RX is mutually exclusive with DISP. */
1165 if (rx) {
1166 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1167 tcg_gen_add_tl(addr, addr, base);
1168 } else {
1169 tcg_gen_addi_tl(addr, base, disp);
1170 }
1171
1172 tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1173
1174 if (modify != 0) {
1175 save_gpr(ctx, rb, addr);
1176 }
1177 tcg_temp_free(addr);
1178}
1179
1180#if TARGET_LONG_BITS == 64
1181#define do_load_tl do_load_64
1182#define do_store_tl do_store_64
1183#else
1184#define do_load_tl do_load_32
1185#define do_store_tl do_store_32
1186#endif
1187
1188static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1189 unsigned rx, int scale, target_long disp,
1190 int modify, TCGMemOp mop)
1191{
1192 TCGv dest;
1193
1194 nullify_over(ctx);
1195
1196 if (modify == 0) {
1197 /* No base register update. */
1198 dest = dest_gpr(ctx, rt);
1199 } else {
1200 /* Make sure if RT == RB, we see the result of the load. */
1201 dest = get_temp(ctx);
1202 }
1203 do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
1204 save_gpr(ctx, rt, dest);
1205
1206 return nullify_end(ctx, NO_EXIT);
1207}
1208
1209static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1210 unsigned rx, int scale, target_long disp,
1211 int modify)
1212{
1213 TCGv_i32 tmp;
1214
1215 nullify_over(ctx);
1216
1217 tmp = tcg_temp_new_i32();
1218 do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1219 save_frw_i32(rt, tmp);
1220 tcg_temp_free_i32(tmp);
1221
1222 if (rt == 0) {
1223 gen_helper_loaded_fr0(cpu_env);
1224 }
1225
1226 return nullify_end(ctx, NO_EXIT);
1227}
1228
1229static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1230 unsigned rx, int scale, target_long disp,
1231 int modify)
1232{
1233 TCGv_i64 tmp;
1234
1235 nullify_over(ctx);
1236
1237 tmp = tcg_temp_new_i64();
1238 do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1239 save_frd(rt, tmp);
1240 tcg_temp_free_i64(tmp);
1241
1242 if (rt == 0) {
1243 gen_helper_loaded_fr0(cpu_env);
1244 }
1245
1246 return nullify_end(ctx, NO_EXIT);
1247}
1248
1249static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1250 target_long disp, int modify, TCGMemOp mop)
1251{
1252 nullify_over(ctx);
1253 do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1254 return nullify_end(ctx, NO_EXIT);
1255}
1256
1257static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1258 unsigned rx, int scale, target_long disp,
1259 int modify)
1260{
1261 TCGv_i32 tmp;
1262
1263 nullify_over(ctx);
1264
1265 tmp = load_frw_i32(rt);
1266 do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1267 tcg_temp_free_i32(tmp);
1268
1269 return nullify_end(ctx, NO_EXIT);
1270}
1271
1272static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1273 unsigned rx, int scale, target_long disp,
1274 int modify)
1275{
1276 TCGv_i64 tmp;
1277
1278 nullify_over(ctx);
1279
1280 tmp = load_frd(rt);
1281 do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1282 tcg_temp_free_i64(tmp);
1283
1284 return nullify_end(ctx, NO_EXIT);
1285}
1286
ebe9383c
RH
1287static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1288 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1289{
1290 TCGv_i32 tmp;
1291
1292 nullify_over(ctx);
1293 tmp = load_frw0_i32(ra);
1294
1295 func(tmp, cpu_env, tmp);
1296
1297 save_frw_i32(rt, tmp);
1298 tcg_temp_free_i32(tmp);
1299 return nullify_end(ctx, NO_EXIT);
1300}
1301
1302static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1303 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1304{
1305 TCGv_i32 dst;
1306 TCGv_i64 src;
1307
1308 nullify_over(ctx);
1309 src = load_frd(ra);
1310 dst = tcg_temp_new_i32();
1311
1312 func(dst, cpu_env, src);
1313
1314 tcg_temp_free_i64(src);
1315 save_frw_i32(rt, dst);
1316 tcg_temp_free_i32(dst);
1317 return nullify_end(ctx, NO_EXIT);
1318}
1319
1320static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1321 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1322{
1323 TCGv_i64 tmp;
1324
1325 nullify_over(ctx);
1326 tmp = load_frd0(ra);
1327
1328 func(tmp, cpu_env, tmp);
1329
1330 save_frd(rt, tmp);
1331 tcg_temp_free_i64(tmp);
1332 return nullify_end(ctx, NO_EXIT);
1333}
1334
1335static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1336 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1337{
1338 TCGv_i32 src;
1339 TCGv_i64 dst;
1340
1341 nullify_over(ctx);
1342 src = load_frw0_i32(ra);
1343 dst = tcg_temp_new_i64();
1344
1345 func(dst, cpu_env, src);
1346
1347 tcg_temp_free_i32(src);
1348 save_frd(rt, dst);
1349 tcg_temp_free_i64(dst);
1350 return nullify_end(ctx, NO_EXIT);
1351}
1352
1353static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt,
1354 unsigned ra, unsigned rb,
1355 void (*func)(TCGv_i32, TCGv_env,
1356 TCGv_i32, TCGv_i32))
1357{
1358 TCGv_i32 a, b;
1359
1360 nullify_over(ctx);
1361 a = load_frw0_i32(ra);
1362 b = load_frw0_i32(rb);
1363
1364 func(a, cpu_env, a, b);
1365
1366 tcg_temp_free_i32(b);
1367 save_frw_i32(rt, a);
1368 tcg_temp_free_i32(a);
1369 return nullify_end(ctx, NO_EXIT);
1370}
1371
1372static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt,
1373 unsigned ra, unsigned rb,
1374 void (*func)(TCGv_i64, TCGv_env,
1375 TCGv_i64, TCGv_i64))
1376{
1377 TCGv_i64 a, b;
1378
1379 nullify_over(ctx);
1380 a = load_frd0(ra);
1381 b = load_frd0(rb);
1382
1383 func(a, cpu_env, a, b);
1384
1385 tcg_temp_free_i64(b);
1386 save_frd(rt, a);
1387 tcg_temp_free_i64(a);
1388 return nullify_end(ctx, NO_EXIT);
1389}
1390
98cd9ca7
RH
1391/* Emit an unconditional branch to a direct target, which may or may not
1392 have already had nullification handled. */
1393static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
1394 unsigned link, bool is_n)
1395{
1396 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1397 if (link != 0) {
1398 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1399 }
1400 ctx->iaoq_n = dest;
1401 if (is_n) {
1402 ctx->null_cond.c = TCG_COND_ALWAYS;
1403 }
1404 return NO_EXIT;
1405 } else {
1406 nullify_over(ctx);
1407
1408 if (link != 0) {
1409 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1410 }
1411
1412 if (is_n && use_nullify_skip(ctx)) {
1413 nullify_set(ctx, 0);
1414 gen_goto_tb(ctx, 0, dest, dest + 4);
1415 } else {
1416 nullify_set(ctx, is_n);
1417 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1418 }
1419
1420 nullify_end(ctx, NO_EXIT);
1421
1422 nullify_set(ctx, 0);
1423 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1424 return EXIT_GOTO_TB;
1425 }
1426}
1427
1428/* Emit a conditional branch to a direct target. If the branch itself
1429 is nullified, we should have already used nullify_over. */
1430static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
1431 DisasCond *cond)
1432{
1433 target_ulong dest = iaoq_dest(ctx, disp);
1434 TCGLabel *taken = NULL;
1435 TCGCond c = cond->c;
98cd9ca7
RH
1436 bool n;
1437
1438 assert(ctx->null_cond.c == TCG_COND_NEVER);
1439
1440 /* Handle TRUE and NEVER as direct branches. */
1441 if (c == TCG_COND_ALWAYS) {
1442 return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
1443 }
1444 if (c == TCG_COND_NEVER) {
1445 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
1446 }
1447
1448 taken = gen_new_label();
1449 cond_prep(cond);
1450 tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
1451 cond_free(cond);
1452
1453 /* Not taken: Condition not satisfied; nullify on backward branches. */
1454 n = is_n && disp < 0;
1455 if (n && use_nullify_skip(ctx)) {
1456 nullify_set(ctx, 0);
a881c8e7 1457 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
98cd9ca7
RH
1458 } else {
1459 if (!n && ctx->null_lab) {
1460 gen_set_label(ctx->null_lab);
1461 ctx->null_lab = NULL;
1462 }
1463 nullify_set(ctx, n);
a881c8e7 1464 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
98cd9ca7
RH
1465 }
1466
1467 gen_set_label(taken);
1468
1469 /* Taken: Condition satisfied; nullify on forward branches. */
1470 n = is_n && disp >= 0;
1471 if (n && use_nullify_skip(ctx)) {
1472 nullify_set(ctx, 0);
a881c8e7 1473 gen_goto_tb(ctx, 1, dest, dest + 4);
98cd9ca7
RH
1474 } else {
1475 nullify_set(ctx, n);
a881c8e7 1476 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
98cd9ca7
RH
1477 }
1478
1479 /* Not taken: the branch itself was nullified. */
1480 if (ctx->null_lab) {
1481 gen_set_label(ctx->null_lab);
1482 ctx->null_lab = NULL;
a881c8e7 1483 return EXIT_IAQ_N_STALE;
98cd9ca7
RH
1484 } else {
1485 return EXIT_GOTO_TB;
1486 }
1487}
1488
1489/* Emit an unconditional branch to an indirect target. This handles
1490 nullification of the branch itself. */
1491static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
1492 unsigned link, bool is_n)
1493{
1494 TCGv a0, a1, next, tmp;
1495 TCGCond c;
1496
1497 assert(ctx->null_lab == NULL);
1498
1499 if (ctx->null_cond.c == TCG_COND_NEVER) {
1500 if (link != 0) {
1501 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1502 }
1503 next = get_temp(ctx);
1504 tcg_gen_mov_tl(next, dest);
1505 ctx->iaoq_n = -1;
1506 ctx->iaoq_n_var = next;
1507 if (is_n) {
1508 ctx->null_cond.c = TCG_COND_ALWAYS;
1509 }
1510 } else if (is_n && use_nullify_skip(ctx)) {
1511 /* The (conditional) branch, B, nullifies the next insn, N,
1512 and we're allowed to skip execution N (no single-step or
4137cb83 1513 tracepoint in effect). Since the goto_ptr that we must use
98cd9ca7
RH
1514 for the indirect branch consumes no special resources, we
1515 can (conditionally) skip B and continue execution. */
1516 /* The use_nullify_skip test implies we have a known control path. */
1517 tcg_debug_assert(ctx->iaoq_b != -1);
1518 tcg_debug_assert(ctx->iaoq_n != -1);
1519
1520 /* We do have to handle the non-local temporary, DEST, before
1521 branching. Since IOAQ_F is not really live at this point, we
1522 can simply store DEST optimistically. Similarly with IAOQ_B. */
1523 tcg_gen_mov_tl(cpu_iaoq_f, dest);
1524 tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
1525
1526 nullify_over(ctx);
1527 if (link != 0) {
1528 tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
1529 }
4137cb83 1530 tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
98cd9ca7
RH
1531 return nullify_end(ctx, NO_EXIT);
1532 } else {
1533 cond_prep(&ctx->null_cond);
1534 c = ctx->null_cond.c;
1535 a0 = ctx->null_cond.a0;
1536 a1 = ctx->null_cond.a1;
1537
1538 tmp = tcg_temp_new();
1539 next = get_temp(ctx);
1540
1541 copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1542 tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
1543 ctx->iaoq_n = -1;
1544 ctx->iaoq_n_var = next;
1545
1546 if (link != 0) {
1547 tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
1548 }
1549
1550 if (is_n) {
1551 /* The branch nullifies the next insn, which means the state of N
1552 after the branch is the inverse of the state of N that applied
1553 to the branch. */
1554 tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
1555 cond_free(&ctx->null_cond);
1556 ctx->null_cond = cond_make_n();
1557 ctx->psw_n_nonzero = true;
1558 } else {
1559 cond_free(&ctx->null_cond);
1560 }
1561 }
1562
1563 return NO_EXIT;
1564}
1565
7ad439df
RH
1566/* On Linux, page zero is normally marked execute only + gateway.
1567 Therefore normal read or write is supposed to fail, but specific
1568 offsets have kernel code mapped to raise permissions to implement
1569 system calls. Handling this via an explicit check here, rather
1570 in than the "be disp(sr2,r0)" instruction that probably sent us
1571 here, is the easiest way to handle the branch delay slot on the
1572 aforementioned BE. */
1573static ExitStatus do_page_zero(DisasContext *ctx)
1574{
1575 /* If by some means we get here with PSW[N]=1, that implies that
1576 the B,GATE instruction would be skipped, and we'd fault on the
1577 next insn within the privilaged page. */
1578 switch (ctx->null_cond.c) {
1579 case TCG_COND_NEVER:
1580 break;
1581 case TCG_COND_ALWAYS:
1582 tcg_gen_movi_tl(cpu_psw_n, 0);
1583 goto do_sigill;
1584 default:
1585 /* Since this is always the first (and only) insn within the
1586 TB, we should know the state of PSW[N] from TB->FLAGS. */
1587 g_assert_not_reached();
1588 }
1589
1590 /* Check that we didn't arrive here via some means that allowed
1591 non-sequential instruction execution. Normally the PSW[B] bit
1592 detects this by disallowing the B,GATE instruction to execute
1593 under such conditions. */
1594 if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1595 goto do_sigill;
1596 }
1597
1598 switch (ctx->iaoq_f) {
1599 case 0x00: /* Null pointer call */
1600 gen_excp_1(EXCP_SIGSEGV);
1601 return EXIT_NORETURN;
1602
1603 case 0xb0: /* LWS */
1604 gen_excp_1(EXCP_SYSCALL_LWS);
1605 return EXIT_NORETURN;
1606
1607 case 0xe0: /* SET_THREAD_POINTER */
1608 tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
1609 tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
1610 tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1611 return EXIT_IAQ_N_UPDATED;
1612
1613 case 0x100: /* SYSCALL */
1614 gen_excp_1(EXCP_SYSCALL);
1615 return EXIT_NORETURN;
1616
1617 default:
1618 do_sigill:
1619 gen_excp_1(EXCP_SIGILL);
1620 return EXIT_NORETURN;
1621 }
1622}
1623
b2167459
RH
1624static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
1625 const DisasInsn *di)
1626{
1627 cond_free(&ctx->null_cond);
1628 return NO_EXIT;
1629}
1630
98a9cb79
RH
1631static ExitStatus trans_break(DisasContext *ctx, uint32_t insn,
1632 const DisasInsn *di)
1633{
1634 nullify_over(ctx);
1635 return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
1636}
1637
1638static ExitStatus trans_sync(DisasContext *ctx, uint32_t insn,
1639 const DisasInsn *di)
1640{
1641 /* No point in nullifying the memory barrier. */
1642 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1643
1644 cond_free(&ctx->null_cond);
1645 return NO_EXIT;
1646}
1647
1648static ExitStatus trans_mfia(DisasContext *ctx, uint32_t insn,
1649 const DisasInsn *di)
1650{
1651 unsigned rt = extract32(insn, 0, 5);
1652 TCGv tmp = dest_gpr(ctx, rt);
1653 tcg_gen_movi_tl(tmp, ctx->iaoq_f);
1654 save_gpr(ctx, rt, tmp);
1655
1656 cond_free(&ctx->null_cond);
1657 return NO_EXIT;
1658}
1659
1660static ExitStatus trans_mfsp(DisasContext *ctx, uint32_t insn,
1661 const DisasInsn *di)
1662{
1663 unsigned rt = extract32(insn, 0, 5);
1664 TCGv tmp = dest_gpr(ctx, rt);
1665
1666 /* ??? We don't implement space registers. */
1667 tcg_gen_movi_tl(tmp, 0);
1668 save_gpr(ctx, rt, tmp);
1669
1670 cond_free(&ctx->null_cond);
1671 return NO_EXIT;
1672}
1673
1674static ExitStatus trans_mfctl(DisasContext *ctx, uint32_t insn,
1675 const DisasInsn *di)
1676{
1677 unsigned rt = extract32(insn, 0, 5);
1678 unsigned ctl = extract32(insn, 21, 5);
1679 TCGv tmp;
1680
1681 switch (ctl) {
1682 case 11: /* SAR */
1683#ifdef TARGET_HPPA64
1684 if (extract32(insn, 14, 1) == 0) {
1685 /* MFSAR without ,W masks low 5 bits. */
1686 tmp = dest_gpr(ctx, rt);
1687 tcg_gen_andi_tl(tmp, cpu_sar, 31);
1688 save_gpr(ctx, rt, tmp);
1689 break;
1690 }
1691#endif
1692 save_gpr(ctx, rt, cpu_sar);
1693 break;
1694 case 16: /* Interval Timer */
1695 tmp = dest_gpr(ctx, rt);
1696 tcg_gen_movi_tl(tmp, 0); /* FIXME */
1697 save_gpr(ctx, rt, tmp);
1698 break;
1699 case 26:
1700 save_gpr(ctx, rt, cpu_cr26);
1701 break;
1702 case 27:
1703 save_gpr(ctx, rt, cpu_cr27);
1704 break;
1705 default:
1706 /* All other control registers are privileged. */
1707 return gen_illegal(ctx);
1708 }
1709
1710 cond_free(&ctx->null_cond);
1711 return NO_EXIT;
1712}
1713
1714static ExitStatus trans_mtctl(DisasContext *ctx, uint32_t insn,
1715 const DisasInsn *di)
1716{
1717 unsigned rin = extract32(insn, 16, 5);
1718 unsigned ctl = extract32(insn, 21, 5);
1719 TCGv tmp;
1720
1721 if (ctl == 11) { /* SAR */
1722 tmp = tcg_temp_new();
1723 tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
1724 save_or_nullify(ctx, cpu_sar, tmp);
1725 tcg_temp_free(tmp);
1726 } else {
1727 /* All other control registers are privileged or read-only. */
1728 return gen_illegal(ctx);
1729 }
1730
1731 cond_free(&ctx->null_cond);
1732 return NO_EXIT;
1733}
1734
1735static ExitStatus trans_mtsarcm(DisasContext *ctx, uint32_t insn,
1736 const DisasInsn *di)
1737{
1738 unsigned rin = extract32(insn, 16, 5);
1739 TCGv tmp = tcg_temp_new();
1740
1741 tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
1742 tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
1743 save_or_nullify(ctx, cpu_sar, tmp);
1744 tcg_temp_free(tmp);
1745
1746 cond_free(&ctx->null_cond);
1747 return NO_EXIT;
1748}
1749
1750static ExitStatus trans_ldsid(DisasContext *ctx, uint32_t insn,
1751 const DisasInsn *di)
1752{
1753 unsigned rt = extract32(insn, 0, 5);
1754 TCGv dest = dest_gpr(ctx, rt);
1755
1756 /* Since we don't implement space registers, this returns zero. */
1757 tcg_gen_movi_tl(dest, 0);
1758 save_gpr(ctx, rt, dest);
1759
1760 cond_free(&ctx->null_cond);
1761 return NO_EXIT;
1762}
1763
1764static const DisasInsn table_system[] = {
1765 { 0x00000000u, 0xfc001fe0u, trans_break },
1766 /* We don't implement space register, so MTSP is a nop. */
1767 { 0x00001820u, 0xffe01fffu, trans_nop },
1768 { 0x00001840u, 0xfc00ffffu, trans_mtctl },
1769 { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
1770 { 0x000014a0u, 0xffffffe0u, trans_mfia },
1771 { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
1772 { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
1773 { 0x00000400u, 0xffffffffu, trans_sync },
1774 { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
1775};
1776
1777static ExitStatus trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
1778 const DisasInsn *di)
1779{
1780 unsigned rb = extract32(insn, 21, 5);
1781 unsigned rx = extract32(insn, 16, 5);
1782 TCGv dest = dest_gpr(ctx, rb);
1783 TCGv src1 = load_gpr(ctx, rb);
1784 TCGv src2 = load_gpr(ctx, rx);
1785
1786 /* The only thing we need to do is the base register modification. */
1787 tcg_gen_add_tl(dest, src1, src2);
1788 save_gpr(ctx, rb, dest);
1789
1790 cond_free(&ctx->null_cond);
1791 return NO_EXIT;
1792}
1793
1794static ExitStatus trans_probe(DisasContext *ctx, uint32_t insn,
1795 const DisasInsn *di)
1796{
1797 unsigned rt = extract32(insn, 0, 5);
1798 unsigned rb = extract32(insn, 21, 5);
1799 unsigned is_write = extract32(insn, 6, 1);
1800 TCGv dest;
1801
1802 nullify_over(ctx);
1803
1804 /* ??? Do something with priv level operand. */
1805 dest = dest_gpr(ctx, rt);
1806 if (is_write) {
1807 gen_helper_probe_w(dest, load_gpr(ctx, rb));
1808 } else {
1809 gen_helper_probe_r(dest, load_gpr(ctx, rb));
1810 }
1811 save_gpr(ctx, rt, dest);
1812 return nullify_end(ctx, NO_EXIT);
1813}
1814
1815static const DisasInsn table_mem_mgmt[] = {
1816 { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */
1817 { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */
1818 { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
1819 { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */
1820 { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
1821 { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */
1822 { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
1823 { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */
1824 { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
1825 { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */
1826 { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
1827 { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */
1828 { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
1829 { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */
1830 { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */
1831};
1832
b2167459
RH
1833static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
1834 const DisasInsn *di)
1835{
1836 unsigned r2 = extract32(insn, 21, 5);
1837 unsigned r1 = extract32(insn, 16, 5);
1838 unsigned cf = extract32(insn, 12, 4);
1839 unsigned ext = extract32(insn, 8, 4);
1840 unsigned shift = extract32(insn, 6, 2);
1841 unsigned rt = extract32(insn, 0, 5);
1842 TCGv tcg_r1, tcg_r2;
1843 bool is_c = false;
1844 bool is_l = false;
1845 bool is_tc = false;
1846 bool is_tsv = false;
1847 ExitStatus ret;
1848
1849 switch (ext) {
1850 case 0x6: /* ADD, SHLADD */
1851 break;
1852 case 0xa: /* ADD,L, SHLADD,L */
1853 is_l = true;
1854 break;
1855 case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1856 is_tsv = true;
1857 break;
1858 case 0x7: /* ADD,C */
1859 is_c = true;
1860 break;
1861 case 0xf: /* ADD,C,TSV */
1862 is_c = is_tsv = true;
1863 break;
1864 default:
1865 return gen_illegal(ctx);
1866 }
1867
1868 if (cf) {
1869 nullify_over(ctx);
1870 }
1871 tcg_r1 = load_gpr(ctx, r1);
1872 tcg_r2 = load_gpr(ctx, r2);
1873 ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1874 return nullify_end(ctx, ret);
1875}
1876
1877static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
1878 const DisasInsn *di)
1879{
1880 unsigned r2 = extract32(insn, 21, 5);
1881 unsigned r1 = extract32(insn, 16, 5);
1882 unsigned cf = extract32(insn, 12, 4);
1883 unsigned ext = extract32(insn, 6, 6);
1884 unsigned rt = extract32(insn, 0, 5);
1885 TCGv tcg_r1, tcg_r2;
1886 bool is_b = false;
1887 bool is_tc = false;
1888 bool is_tsv = false;
1889 ExitStatus ret;
1890
1891 switch (ext) {
1892 case 0x10: /* SUB */
1893 break;
1894 case 0x30: /* SUB,TSV */
1895 is_tsv = true;
1896 break;
1897 case 0x14: /* SUB,B */
1898 is_b = true;
1899 break;
1900 case 0x34: /* SUB,B,TSV */
1901 is_b = is_tsv = true;
1902 break;
1903 case 0x13: /* SUB,TC */
1904 is_tc = true;
1905 break;
1906 case 0x33: /* SUB,TSV,TC */
1907 is_tc = is_tsv = true;
1908 break;
1909 default:
1910 return gen_illegal(ctx);
1911 }
1912
1913 if (cf) {
1914 nullify_over(ctx);
1915 }
1916 tcg_r1 = load_gpr(ctx, r1);
1917 tcg_r2 = load_gpr(ctx, r2);
1918 ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1919 return nullify_end(ctx, ret);
1920}
1921
1922static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
1923 const DisasInsn *di)
1924{
1925 unsigned r2 = extract32(insn, 21, 5);
1926 unsigned r1 = extract32(insn, 16, 5);
1927 unsigned cf = extract32(insn, 12, 4);
1928 unsigned rt = extract32(insn, 0, 5);
1929 TCGv tcg_r1, tcg_r2;
1930 ExitStatus ret;
1931
1932 if (cf) {
1933 nullify_over(ctx);
1934 }
1935 tcg_r1 = load_gpr(ctx, r1);
1936 tcg_r2 = load_gpr(ctx, r2);
eff235eb 1937 ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
b2167459
RH
1938 return nullify_end(ctx, ret);
1939}
1940
1941/* OR r,0,t -> COPY (according to gas) */
1942static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1943 const DisasInsn *di)
1944{
1945 unsigned r1 = extract32(insn, 16, 5);
1946 unsigned rt = extract32(insn, 0, 5);
1947
1948 if (r1 == 0) {
1949 TCGv dest = dest_gpr(ctx, rt);
1950 tcg_gen_movi_tl(dest, 0);
1951 save_gpr(ctx, rt, dest);
1952 } else {
1953 save_gpr(ctx, rt, cpu_gr[r1]);
1954 }
1955 cond_free(&ctx->null_cond);
1956 return NO_EXIT;
1957}
1958
1959static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1960 const DisasInsn *di)
1961{
1962 unsigned r2 = extract32(insn, 21, 5);
1963 unsigned r1 = extract32(insn, 16, 5);
1964 unsigned cf = extract32(insn, 12, 4);
1965 unsigned rt = extract32(insn, 0, 5);
1966 TCGv tcg_r1, tcg_r2;
1967 ExitStatus ret;
1968
1969 if (cf) {
1970 nullify_over(ctx);
1971 }
1972 tcg_r1 = load_gpr(ctx, r1);
1973 tcg_r2 = load_gpr(ctx, r2);
1974 ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1975 return nullify_end(ctx, ret);
1976}
1977
1978static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1979 const DisasInsn *di)
1980{
1981 unsigned r2 = extract32(insn, 21, 5);
1982 unsigned r1 = extract32(insn, 16, 5);
1983 unsigned cf = extract32(insn, 12, 4);
1984 unsigned rt = extract32(insn, 0, 5);
1985 TCGv tcg_r1, tcg_r2;
1986 ExitStatus ret;
1987
1988 if (cf) {
1989 nullify_over(ctx);
1990 }
1991 tcg_r1 = load_gpr(ctx, r1);
1992 tcg_r2 = load_gpr(ctx, r2);
1993 ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1994 return nullify_end(ctx, ret);
1995}
1996
1997static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1998 const DisasInsn *di)
1999{
2000 unsigned r2 = extract32(insn, 21, 5);
2001 unsigned r1 = extract32(insn, 16, 5);
2002 unsigned cf = extract32(insn, 12, 4);
2003 unsigned is_tc = extract32(insn, 6, 1);
2004 unsigned rt = extract32(insn, 0, 5);
2005 TCGv tcg_r1, tcg_r2, tmp;
2006 ExitStatus ret;
2007
2008 if (cf) {
2009 nullify_over(ctx);
2010 }
2011 tcg_r1 = load_gpr(ctx, r1);
2012 tcg_r2 = load_gpr(ctx, r2);
2013 tmp = get_temp(ctx);
2014 tcg_gen_not_tl(tmp, tcg_r2);
2015 ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
2016 return nullify_end(ctx, ret);
2017}
2018
2019static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
2020 const DisasInsn *di)
2021{
2022 unsigned r2 = extract32(insn, 21, 5);
2023 unsigned cf = extract32(insn, 12, 4);
2024 unsigned is_i = extract32(insn, 6, 1);
2025 unsigned rt = extract32(insn, 0, 5);
2026 TCGv tmp;
2027 ExitStatus ret;
2028
2029 nullify_over(ctx);
2030
2031 tmp = get_temp(ctx);
2032 tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2033 if (!is_i) {
2034 tcg_gen_not_tl(tmp, tmp);
2035 }
2036 tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2037 tcg_gen_muli_tl(tmp, tmp, 6);
2038 ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2039 is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2040
2041 return nullify_end(ctx, ret);
2042}
2043
2044static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
2045 const DisasInsn *di)
2046{
2047 unsigned r2 = extract32(insn, 21, 5);
2048 unsigned r1 = extract32(insn, 16, 5);
2049 unsigned cf = extract32(insn, 12, 4);
2050 unsigned rt = extract32(insn, 0, 5);
2051 TCGv dest, add1, add2, addc, zero, in1, in2;
2052
2053 nullify_over(ctx);
2054
2055 in1 = load_gpr(ctx, r1);
2056 in2 = load_gpr(ctx, r2);
2057
2058 add1 = tcg_temp_new();
2059 add2 = tcg_temp_new();
2060 addc = tcg_temp_new();
2061 dest = tcg_temp_new();
2062 zero = tcg_const_tl(0);
2063
2064 /* Form R1 << 1 | PSW[CB]{8}. */
2065 tcg_gen_add_tl(add1, in1, in1);
2066 tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2067
2068 /* Add or subtract R2, depending on PSW[V]. Proper computation of
2069 carry{8} requires that we subtract via + ~R2 + 1, as described in
2070 the manual. By extracting and masking V, we can produce the
2071 proper inputs to the addition without movcond. */
2072 tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2073 tcg_gen_xor_tl(add2, in2, addc);
2074 tcg_gen_andi_tl(addc, addc, 1);
2075 /* ??? This is only correct for 32-bit. */
2076 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2077 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2078
2079 tcg_temp_free(addc);
2080 tcg_temp_free(zero);
2081
2082 /* Write back the result register. */
2083 save_gpr(ctx, rt, dest);
2084
2085 /* Write back PSW[CB]. */
2086 tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2087 tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2088
2089 /* Write back PSW[V] for the division step. */
2090 tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2091 tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2092
2093 /* Install the new nullification. */
2094 if (cf) {
2095 TCGv sv;
2096 TCGV_UNUSED(sv);
2097 if (cf >> 1 == 6) {
2098 /* ??? The lshift is supposed to contribute to overflow. */
2099 sv = do_add_sv(ctx, dest, add1, add2);
2100 }
2101 ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2102 }
2103
2104 tcg_temp_free(add1);
2105 tcg_temp_free(add2);
2106 tcg_temp_free(dest);
2107
2108 return nullify_end(ctx, NO_EXIT);
2109}
2110
2111static const DisasInsn table_arith_log[] = {
2112 { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */
2113 { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
eff235eb
PB
2114 { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2115 { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2116 { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2117 { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
b2167459
RH
2118 { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2119 { 0x08000380u, 0xfc000fe0u, trans_uxor },
2120 { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2121 { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2122 { 0x08000440u, 0xfc000fe0u, trans_ds },
2123 { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2124 { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2125 { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2126 { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2127};
2128
2129static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
2130{
2131 target_long im = low_sextract(insn, 0, 11);
2132 unsigned e1 = extract32(insn, 11, 1);
2133 unsigned cf = extract32(insn, 12, 4);
2134 unsigned rt = extract32(insn, 16, 5);
2135 unsigned r2 = extract32(insn, 21, 5);
2136 unsigned o1 = extract32(insn, 26, 1);
2137 TCGv tcg_im, tcg_r2;
2138 ExitStatus ret;
2139
2140 if (cf) {
2141 nullify_over(ctx);
2142 }
2143
2144 tcg_im = load_const(ctx, im);
2145 tcg_r2 = load_gpr(ctx, r2);
2146 ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2147
2148 return nullify_end(ctx, ret);
2149}
2150
2151static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
2152{
2153 target_long im = low_sextract(insn, 0, 11);
2154 unsigned e1 = extract32(insn, 11, 1);
2155 unsigned cf = extract32(insn, 12, 4);
2156 unsigned rt = extract32(insn, 16, 5);
2157 unsigned r2 = extract32(insn, 21, 5);
2158 TCGv tcg_im, tcg_r2;
2159 ExitStatus ret;
2160
2161 if (cf) {
2162 nullify_over(ctx);
2163 }
2164
2165 tcg_im = load_const(ctx, im);
2166 tcg_r2 = load_gpr(ctx, r2);
2167 ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2168
2169 return nullify_end(ctx, ret);
2170}
2171
2172static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2173{
2174 target_long im = low_sextract(insn, 0, 11);
2175 unsigned cf = extract32(insn, 12, 4);
2176 unsigned rt = extract32(insn, 16, 5);
2177 unsigned r2 = extract32(insn, 21, 5);
2178 TCGv tcg_im, tcg_r2;
2179 ExitStatus ret;
2180
2181 if (cf) {
2182 nullify_over(ctx);
2183 }
2184
2185 tcg_im = load_const(ctx, im);
2186 tcg_r2 = load_gpr(ctx, r2);
2187 ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2188
2189 return nullify_end(ctx, ret);
2190}
2191
96d6407f
RH
2192static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2193 const DisasInsn *di)
2194{
2195 unsigned rt = extract32(insn, 0, 5);
2196 unsigned m = extract32(insn, 5, 1);
2197 unsigned sz = extract32(insn, 6, 2);
2198 unsigned a = extract32(insn, 13, 1);
2199 int disp = low_sextract(insn, 16, 5);
2200 unsigned rb = extract32(insn, 21, 5);
2201 int modify = (m ? (a ? -1 : 1) : 0);
2202 TCGMemOp mop = MO_TE | sz;
2203
2204 return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
2205}
2206
2207static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2208 const DisasInsn *di)
2209{
2210 unsigned rt = extract32(insn, 0, 5);
2211 unsigned m = extract32(insn, 5, 1);
2212 unsigned sz = extract32(insn, 6, 2);
2213 unsigned u = extract32(insn, 13, 1);
2214 unsigned rx = extract32(insn, 16, 5);
2215 unsigned rb = extract32(insn, 21, 5);
2216 TCGMemOp mop = MO_TE | sz;
2217
2218 return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
2219}
2220
2221static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2222 const DisasInsn *di)
2223{
2224 int disp = low_sextract(insn, 0, 5);
2225 unsigned m = extract32(insn, 5, 1);
2226 unsigned sz = extract32(insn, 6, 2);
2227 unsigned a = extract32(insn, 13, 1);
2228 unsigned rr = extract32(insn, 16, 5);
2229 unsigned rb = extract32(insn, 21, 5);
2230 int modify = (m ? (a ? -1 : 1) : 0);
2231 TCGMemOp mop = MO_TE | sz;
2232
2233 return do_store(ctx, rr, rb, disp, modify, mop);
2234}
2235
2236static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn,
2237 const DisasInsn *di)
2238{
2239 unsigned rt = extract32(insn, 0, 5);
2240 unsigned m = extract32(insn, 5, 1);
2241 unsigned i = extract32(insn, 12, 1);
2242 unsigned au = extract32(insn, 13, 1);
2243 unsigned rx = extract32(insn, 16, 5);
2244 unsigned rb = extract32(insn, 21, 5);
2245 TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
2246 TCGv zero, addr, base, dest;
2247 int modify, disp = 0, scale = 0;
2248
2249 nullify_over(ctx);
2250
2251 /* ??? Share more code with do_load and do_load_{32,64}. */
2252
2253 if (i) {
2254 modify = (m ? (au ? -1 : 1) : 0);
2255 disp = low_sextract(rx, 0, 5);
2256 rx = 0;
2257 } else {
2258 modify = m;
2259 if (au) {
2260 scale = mop & MO_SIZE;
2261 }
2262 }
2263 if (modify) {
2264 /* Base register modification. Make sure if RT == RB, we see
2265 the result of the load. */
2266 dest = get_temp(ctx);
2267 } else {
2268 dest = dest_gpr(ctx, rt);
2269 }
2270
2271 addr = tcg_temp_new();
2272 base = load_gpr(ctx, rb);
2273 if (rx) {
2274 tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
2275 tcg_gen_add_tl(addr, addr, base);
2276 } else {
2277 tcg_gen_addi_tl(addr, base, disp);
2278 }
2279
2280 zero = tcg_const_tl(0);
2281 tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
2282 zero, MMU_USER_IDX, mop);
2283 if (modify) {
2284 save_gpr(ctx, rb, addr);
2285 }
2286 save_gpr(ctx, rt, dest);
2287
2288 return nullify_end(ctx, NO_EXIT);
2289}
2290
2291static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn,
2292 const DisasInsn *di)
2293{
2294 target_long disp = low_sextract(insn, 0, 5);
2295 unsigned m = extract32(insn, 5, 1);
2296 unsigned a = extract32(insn, 13, 1);
2297 unsigned rt = extract32(insn, 16, 5);
2298 unsigned rb = extract32(insn, 21, 5);
2299 TCGv addr, val;
2300
2301 nullify_over(ctx);
2302
2303 addr = tcg_temp_new();
2304 if (m || disp == 0) {
2305 tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
2306 } else {
2307 tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
2308 }
2309 val = load_gpr(ctx, rt);
2310
2311 if (a) {
2312 gen_helper_stby_e(cpu_env, addr, val);
2313 } else {
2314 gen_helper_stby_b(cpu_env, addr, val);
2315 }
2316
2317 if (m) {
2318 tcg_gen_addi_tl(addr, addr, disp);
2319 tcg_gen_andi_tl(addr, addr, ~3);
2320 save_gpr(ctx, rb, addr);
2321 }
2322 tcg_temp_free(addr);
2323
2324 return nullify_end(ctx, NO_EXIT);
2325}
2326
2327static const DisasInsn table_index_mem[] = {
2328 { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
2329 { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
2330 { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
2331 { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
2332 { 0x0c001300u, 0xfc0013c0, trans_stby },
2333};
2334
b2167459
RH
2335static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
2336{
2337 unsigned rt = extract32(insn, 21, 5);
2338 target_long i = assemble_21(insn);
2339 TCGv tcg_rt = dest_gpr(ctx, rt);
2340
2341 tcg_gen_movi_tl(tcg_rt, i);
2342 save_gpr(ctx, rt, tcg_rt);
2343 cond_free(&ctx->null_cond);
2344
2345 return NO_EXIT;
2346}
2347
2348static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
2349{
2350 unsigned rt = extract32(insn, 21, 5);
2351 target_long i = assemble_21(insn);
2352 TCGv tcg_rt = load_gpr(ctx, rt);
2353 TCGv tcg_r1 = dest_gpr(ctx, 1);
2354
2355 tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2356 save_gpr(ctx, 1, tcg_r1);
2357 cond_free(&ctx->null_cond);
2358
2359 return NO_EXIT;
2360}
2361
2362static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
2363{
2364 unsigned rb = extract32(insn, 21, 5);
2365 unsigned rt = extract32(insn, 16, 5);
2366 target_long i = assemble_16(insn);
2367 TCGv tcg_rt = dest_gpr(ctx, rt);
2368
2369 /* Special case rb == 0, for the LDI pseudo-op.
2370 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
2371 if (rb == 0) {
2372 tcg_gen_movi_tl(tcg_rt, i);
2373 } else {
2374 tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2375 }
2376 save_gpr(ctx, rt, tcg_rt);
2377 cond_free(&ctx->null_cond);
2378
2379 return NO_EXIT;
2380}
2381
96d6407f
RH
2382static ExitStatus trans_load(DisasContext *ctx, uint32_t insn,
2383 bool is_mod, TCGMemOp mop)
2384{
2385 unsigned rb = extract32(insn, 21, 5);
2386 unsigned rt = extract32(insn, 16, 5);
2387 target_long i = assemble_16(insn);
2388
2389 return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2390}
2391
2392static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn)
2393{
2394 unsigned rb = extract32(insn, 21, 5);
2395 unsigned rt = extract32(insn, 16, 5);
2396 target_long i = assemble_16a(insn);
2397 unsigned ext2 = extract32(insn, 1, 2);
2398
2399 switch (ext2) {
2400 case 0:
2401 case 1:
2402 /* FLDW without modification. */
2403 return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2404 case 2:
2405 /* LDW with modification. Note that the sign of I selects
2406 post-dec vs pre-inc. */
2407 return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
2408 default:
2409 return gen_illegal(ctx);
2410 }
2411}
2412
2413static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn)
2414{
2415 target_long i = assemble_16a(insn);
2416 unsigned t1 = extract32(insn, 1, 1);
2417 unsigned a = extract32(insn, 2, 1);
2418 unsigned t0 = extract32(insn, 16, 5);
2419 unsigned rb = extract32(insn, 21, 5);
2420
2421 /* FLDW with modification. */
2422 return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2423}
2424
2425static ExitStatus trans_store(DisasContext *ctx, uint32_t insn,
2426 bool is_mod, TCGMemOp mop)
2427{
2428 unsigned rb = extract32(insn, 21, 5);
2429 unsigned rt = extract32(insn, 16, 5);
2430 target_long i = assemble_16(insn);
2431
2432 return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2433}
2434
2435static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn)
2436{
2437 unsigned rb = extract32(insn, 21, 5);
2438 unsigned rt = extract32(insn, 16, 5);
2439 target_long i = assemble_16a(insn);
2440 unsigned ext2 = extract32(insn, 1, 2);
2441
2442 switch (ext2) {
2443 case 0:
2444 case 1:
2445 /* FSTW without modification. */
2446 return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2447 case 2:
2448 /* LDW with modification. */
2449 return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
2450 default:
2451 return gen_illegal(ctx);
2452 }
2453}
2454
2455static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn)
2456{
2457 target_long i = assemble_16a(insn);
2458 unsigned t1 = extract32(insn, 1, 1);
2459 unsigned a = extract32(insn, 2, 1);
2460 unsigned t0 = extract32(insn, 16, 5);
2461 unsigned rb = extract32(insn, 21, 5);
2462
2463 /* FSTW with modification. */
2464 return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2465}
2466
2467static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn)
2468{
2469 unsigned t0 = extract32(insn, 0, 5);
2470 unsigned m = extract32(insn, 5, 1);
2471 unsigned t1 = extract32(insn, 6, 1);
2472 unsigned ext3 = extract32(insn, 7, 3);
2473 /* unsigned cc = extract32(insn, 10, 2); */
2474 unsigned i = extract32(insn, 12, 1);
2475 unsigned ua = extract32(insn, 13, 1);
2476 unsigned rx = extract32(insn, 16, 5);
2477 unsigned rb = extract32(insn, 21, 5);
2478 unsigned rt = t1 * 32 + t0;
2479 int modify = (m ? (ua ? -1 : 1) : 0);
2480 int disp, scale;
2481
2482 if (i == 0) {
2483 scale = (ua ? 2 : 0);
2484 disp = 0;
2485 modify = m;
2486 } else {
2487 disp = low_sextract(rx, 0, 5);
2488 scale = 0;
2489 rx = 0;
2490 modify = (m ? (ua ? -1 : 1) : 0);
2491 }
2492
2493 switch (ext3) {
2494 case 0: /* FLDW */
2495 return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
2496 case 4: /* FSTW */
2497 return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
2498 }
2499 return gen_illegal(ctx);
2500}
2501
2502static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn)
2503{
2504 unsigned rt = extract32(insn, 0, 5);
2505 unsigned m = extract32(insn, 5, 1);
2506 unsigned ext4 = extract32(insn, 6, 4);
2507 /* unsigned cc = extract32(insn, 10, 2); */
2508 unsigned i = extract32(insn, 12, 1);
2509 unsigned ua = extract32(insn, 13, 1);
2510 unsigned rx = extract32(insn, 16, 5);
2511 unsigned rb = extract32(insn, 21, 5);
2512 int modify = (m ? (ua ? -1 : 1) : 0);
2513 int disp, scale;
2514
2515 if (i == 0) {
2516 scale = (ua ? 3 : 0);
2517 disp = 0;
2518 modify = m;
2519 } else {
2520 disp = low_sextract(rx, 0, 5);
2521 scale = 0;
2522 rx = 0;
2523 modify = (m ? (ua ? -1 : 1) : 0);
2524 }
2525
2526 switch (ext4) {
2527 case 0: /* FLDD */
2528 return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
2529 case 8: /* FSTD */
2530 return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
2531 default:
2532 return gen_illegal(ctx);
2533 }
2534}
2535
98cd9ca7
RH
2536static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
2537 bool is_true, bool is_imm, bool is_dw)
2538{
2539 target_long disp = assemble_12(insn) * 4;
2540 unsigned n = extract32(insn, 1, 1);
2541 unsigned c = extract32(insn, 13, 3);
2542 unsigned r = extract32(insn, 21, 5);
2543 unsigned cf = c * 2 + !is_true;
2544 TCGv dest, in1, in2, sv;
2545 DisasCond cond;
2546
2547 nullify_over(ctx);
2548
2549 if (is_imm) {
2550 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2551 } else {
2552 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2553 }
2554 in2 = load_gpr(ctx, r);
2555 dest = get_temp(ctx);
2556
2557 tcg_gen_sub_tl(dest, in1, in2);
2558
2559 TCGV_UNUSED(sv);
2560 if (c == 6) {
2561 sv = do_sub_sv(ctx, dest, in1, in2);
2562 }
2563
2564 cond = do_sub_cond(cf, dest, in1, in2, sv);
2565 return do_cbranch(ctx, disp, n, &cond);
2566}
2567
2568static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
2569 bool is_true, bool is_imm)
2570{
2571 target_long disp = assemble_12(insn) * 4;
2572 unsigned n = extract32(insn, 1, 1);
2573 unsigned c = extract32(insn, 13, 3);
2574 unsigned r = extract32(insn, 21, 5);
2575 unsigned cf = c * 2 + !is_true;
2576 TCGv dest, in1, in2, sv, cb_msb;
2577 DisasCond cond;
2578
2579 nullify_over(ctx);
2580
2581 if (is_imm) {
2582 in1 = load_const(ctx, low_sextract(insn, 16, 5));
2583 } else {
2584 in1 = load_gpr(ctx, extract32(insn, 16, 5));
2585 }
2586 in2 = load_gpr(ctx, r);
2587 dest = dest_gpr(ctx, r);
2588 TCGV_UNUSED(sv);
2589 TCGV_UNUSED(cb_msb);
2590
2591 switch (c) {
2592 default:
2593 tcg_gen_add_tl(dest, in1, in2);
2594 break;
2595 case 4: case 5:
2596 cb_msb = get_temp(ctx);
2597 tcg_gen_movi_tl(cb_msb, 0);
2598 tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
2599 break;
2600 case 6:
2601 tcg_gen_add_tl(dest, in1, in2);
2602 sv = do_add_sv(ctx, dest, in1, in2);
2603 break;
2604 }
2605
2606 cond = do_cond(cf, dest, cb_msb, sv);
2607 return do_cbranch(ctx, disp, n, &cond);
2608}
2609
2610static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
2611{
2612 target_long disp = assemble_12(insn) * 4;
2613 unsigned n = extract32(insn, 1, 1);
2614 unsigned c = extract32(insn, 15, 1);
2615 unsigned r = extract32(insn, 16, 5);
2616 unsigned p = extract32(insn, 21, 5);
2617 unsigned i = extract32(insn, 26, 1);
2618 TCGv tmp, tcg_r;
2619 DisasCond cond;
2620
2621 nullify_over(ctx);
2622
2623 tmp = tcg_temp_new();
2624 tcg_r = load_gpr(ctx, r);
2625 if (i) {
2626 tcg_gen_shli_tl(tmp, tcg_r, p);
2627 } else {
2628 tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
2629 }
2630
2631 cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
2632 tcg_temp_free(tmp);
2633 return do_cbranch(ctx, disp, n, &cond);
2634}
2635
2636static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
2637{
2638 target_long disp = assemble_12(insn) * 4;
2639 unsigned n = extract32(insn, 1, 1);
2640 unsigned c = extract32(insn, 13, 3);
2641 unsigned t = extract32(insn, 16, 5);
2642 unsigned r = extract32(insn, 21, 5);
2643 TCGv dest;
2644 DisasCond cond;
2645
2646 nullify_over(ctx);
2647
2648 dest = dest_gpr(ctx, r);
2649 if (is_imm) {
2650 tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
2651 } else if (t == 0) {
2652 tcg_gen_movi_tl(dest, 0);
2653 } else {
2654 tcg_gen_mov_tl(dest, cpu_gr[t]);
2655 }
2656
2657 cond = do_sed_cond(c, dest);
2658 return do_cbranch(ctx, disp, n, &cond);
2659}
2660
0b1347d2
RH
2661static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
2662 const DisasInsn *di)
2663{
2664 unsigned rt = extract32(insn, 0, 5);
2665 unsigned c = extract32(insn, 13, 3);
2666 unsigned r1 = extract32(insn, 16, 5);
2667 unsigned r2 = extract32(insn, 21, 5);
2668 TCGv dest;
2669
2670 if (c) {
2671 nullify_over(ctx);
2672 }
2673
2674 dest = dest_gpr(ctx, rt);
2675 if (r1 == 0) {
2676 tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
2677 tcg_gen_shr_tl(dest, dest, cpu_sar);
2678 } else if (r1 == r2) {
2679 TCGv_i32 t32 = tcg_temp_new_i32();
2680 tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
2681 tcg_gen_rotr_i32(t32, t32, cpu_sar);
2682 tcg_gen_extu_i32_tl(dest, t32);
2683 tcg_temp_free_i32(t32);
2684 } else {
2685 TCGv_i64 t = tcg_temp_new_i64();
2686 TCGv_i64 s = tcg_temp_new_i64();
2687
2688 tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
2689 tcg_gen_extu_tl_i64(s, cpu_sar);
2690 tcg_gen_shr_i64(t, t, s);
2691 tcg_gen_trunc_i64_tl(dest, t);
2692
2693 tcg_temp_free_i64(t);
2694 tcg_temp_free_i64(s);
2695 }
2696 save_gpr(ctx, rt, dest);
2697
2698 /* Install the new nullification. */
2699 cond_free(&ctx->null_cond);
2700 if (c) {
2701 ctx->null_cond = do_sed_cond(c, dest);
2702 }
2703 return nullify_end(ctx, NO_EXIT);
2704}
2705
2706static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
2707 const DisasInsn *di)
2708{
2709 unsigned rt = extract32(insn, 0, 5);
2710 unsigned cpos = extract32(insn, 5, 5);
2711 unsigned c = extract32(insn, 13, 3);
2712 unsigned r1 = extract32(insn, 16, 5);
2713 unsigned r2 = extract32(insn, 21, 5);
2714 unsigned sa = 31 - cpos;
2715 TCGv dest, t2;
2716
2717 if (c) {
2718 nullify_over(ctx);
2719 }
2720
2721 dest = dest_gpr(ctx, rt);
2722 t2 = load_gpr(ctx, r2);
2723 if (r1 == r2) {
2724 TCGv_i32 t32 = tcg_temp_new_i32();
2725 tcg_gen_trunc_tl_i32(t32, t2);
2726 tcg_gen_rotri_i32(t32, t32, sa);
2727 tcg_gen_extu_i32_tl(dest, t32);
2728 tcg_temp_free_i32(t32);
2729 } else if (r1 == 0) {
2730 tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
2731 } else {
2732 TCGv t0 = tcg_temp_new();
2733 tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
2734 tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
2735 tcg_temp_free(t0);
2736 }
2737 save_gpr(ctx, rt, dest);
2738
2739 /* Install the new nullification. */
2740 cond_free(&ctx->null_cond);
2741 if (c) {
2742 ctx->null_cond = do_sed_cond(c, dest);
2743 }
2744 return nullify_end(ctx, NO_EXIT);
2745}
2746
2747static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
2748 const DisasInsn *di)
2749{
2750 unsigned clen = extract32(insn, 0, 5);
2751 unsigned is_se = extract32(insn, 10, 1);
2752 unsigned c = extract32(insn, 13, 3);
2753 unsigned rt = extract32(insn, 16, 5);
2754 unsigned rr = extract32(insn, 21, 5);
2755 unsigned len = 32 - clen;
2756 TCGv dest, src, tmp;
2757
2758 if (c) {
2759 nullify_over(ctx);
2760 }
2761
2762 dest = dest_gpr(ctx, rt);
2763 src = load_gpr(ctx, rr);
2764 tmp = tcg_temp_new();
2765
2766 /* Recall that SAR is using big-endian bit numbering. */
2767 tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
2768 if (is_se) {
2769 tcg_gen_sar_tl(dest, src, tmp);
2770 tcg_gen_sextract_tl(dest, dest, 0, len);
2771 } else {
2772 tcg_gen_shr_tl(dest, src, tmp);
2773 tcg_gen_extract_tl(dest, dest, 0, len);
2774 }
2775 tcg_temp_free(tmp);
2776 save_gpr(ctx, rt, dest);
2777
2778 /* Install the new nullification. */
2779 cond_free(&ctx->null_cond);
2780 if (c) {
2781 ctx->null_cond = do_sed_cond(c, dest);
2782 }
2783 return nullify_end(ctx, NO_EXIT);
2784}
2785
2786static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
2787 const DisasInsn *di)
2788{
2789 unsigned clen = extract32(insn, 0, 5);
2790 unsigned pos = extract32(insn, 5, 5);
2791 unsigned is_se = extract32(insn, 10, 1);
2792 unsigned c = extract32(insn, 13, 3);
2793 unsigned rt = extract32(insn, 16, 5);
2794 unsigned rr = extract32(insn, 21, 5);
2795 unsigned len = 32 - clen;
2796 unsigned cpos = 31 - pos;
2797 TCGv dest, src;
2798
2799 if (c) {
2800 nullify_over(ctx);
2801 }
2802
2803 dest = dest_gpr(ctx, rt);
2804 src = load_gpr(ctx, rr);
2805 if (is_se) {
2806 tcg_gen_sextract_tl(dest, src, cpos, len);
2807 } else {
2808 tcg_gen_extract_tl(dest, src, cpos, len);
2809 }
2810 save_gpr(ctx, rt, dest);
2811
2812 /* Install the new nullification. */
2813 cond_free(&ctx->null_cond);
2814 if (c) {
2815 ctx->null_cond = do_sed_cond(c, dest);
2816 }
2817 return nullify_end(ctx, NO_EXIT);
2818}
2819
2820static const DisasInsn table_sh_ex[] = {
2821 { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
2822 { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
2823 { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
2824 { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
2825};
2826
2827static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
2828 const DisasInsn *di)
2829{
2830 unsigned clen = extract32(insn, 0, 5);
2831 unsigned cpos = extract32(insn, 5, 5);
2832 unsigned nz = extract32(insn, 10, 1);
2833 unsigned c = extract32(insn, 13, 3);
2834 target_long val = low_sextract(insn, 16, 5);
2835 unsigned rt = extract32(insn, 21, 5);
2836 unsigned len = 32 - clen;
2837 target_long mask0, mask1;
2838 TCGv dest;
2839
2840 if (c) {
2841 nullify_over(ctx);
2842 }
2843 if (cpos + len > 32) {
2844 len = 32 - cpos;
2845 }
2846
2847 dest = dest_gpr(ctx, rt);
2848 mask0 = deposit64(0, cpos, len, val);
2849 mask1 = deposit64(-1, cpos, len, val);
2850
2851 if (nz) {
2852 TCGv src = load_gpr(ctx, rt);
2853 if (mask1 != -1) {
2854 tcg_gen_andi_tl(dest, src, mask1);
2855 src = dest;
2856 }
2857 tcg_gen_ori_tl(dest, src, mask0);
2858 } else {
2859 tcg_gen_movi_tl(dest, mask0);
2860 }
2861 save_gpr(ctx, rt, dest);
2862
2863 /* Install the new nullification. */
2864 cond_free(&ctx->null_cond);
2865 if (c) {
2866 ctx->null_cond = do_sed_cond(c, dest);
2867 }
2868 return nullify_end(ctx, NO_EXIT);
2869}
2870
2871static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
2872 const DisasInsn *di)
2873{
2874 unsigned clen = extract32(insn, 0, 5);
2875 unsigned cpos = extract32(insn, 5, 5);
2876 unsigned nz = extract32(insn, 10, 1);
2877 unsigned c = extract32(insn, 13, 3);
2878 unsigned rr = extract32(insn, 16, 5);
2879 unsigned rt = extract32(insn, 21, 5);
2880 unsigned rs = nz ? rt : 0;
2881 unsigned len = 32 - clen;
2882 TCGv dest, val;
2883
2884 if (c) {
2885 nullify_over(ctx);
2886 }
2887 if (cpos + len > 32) {
2888 len = 32 - cpos;
2889 }
2890
2891 dest = dest_gpr(ctx, rt);
2892 val = load_gpr(ctx, rr);
2893 if (rs == 0) {
2894 tcg_gen_deposit_z_tl(dest, val, cpos, len);
2895 } else {
2896 tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
2897 }
2898 save_gpr(ctx, rt, dest);
2899
2900 /* Install the new nullification. */
2901 cond_free(&ctx->null_cond);
2902 if (c) {
2903 ctx->null_cond = do_sed_cond(c, dest);
2904 }
2905 return nullify_end(ctx, NO_EXIT);
2906}
2907
2908static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
2909 const DisasInsn *di)
2910{
2911 unsigned clen = extract32(insn, 0, 5);
2912 unsigned nz = extract32(insn, 10, 1);
2913 unsigned i = extract32(insn, 12, 1);
2914 unsigned c = extract32(insn, 13, 3);
2915 unsigned rt = extract32(insn, 21, 5);
2916 unsigned rs = nz ? rt : 0;
2917 unsigned len = 32 - clen;
2918 TCGv val, mask, tmp, shift, dest;
2919 unsigned msb = 1U << (len - 1);
2920
2921 if (c) {
2922 nullify_over(ctx);
2923 }
2924
2925 if (i) {
2926 val = load_const(ctx, low_sextract(insn, 16, 5));
2927 } else {
2928 val = load_gpr(ctx, extract32(insn, 16, 5));
2929 }
2930 dest = dest_gpr(ctx, rt);
2931 shift = tcg_temp_new();
2932 tmp = tcg_temp_new();
2933
2934 /* Convert big-endian bit numbering in SAR to left-shift. */
2935 tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
2936
2937 mask = tcg_const_tl(msb + (msb - 1));
2938 tcg_gen_and_tl(tmp, val, mask);
2939 if (rs) {
2940 tcg_gen_shl_tl(mask, mask, shift);
2941 tcg_gen_shl_tl(tmp, tmp, shift);
2942 tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
2943 tcg_gen_or_tl(dest, dest, tmp);
2944 } else {
2945 tcg_gen_shl_tl(dest, tmp, shift);
2946 }
2947 tcg_temp_free(shift);
2948 tcg_temp_free(mask);
2949 tcg_temp_free(tmp);
2950 save_gpr(ctx, rt, dest);
2951
2952 /* Install the new nullification. */
2953 cond_free(&ctx->null_cond);
2954 if (c) {
2955 ctx->null_cond = do_sed_cond(c, dest);
2956 }
2957 return nullify_end(ctx, NO_EXIT);
2958}
2959
2960static const DisasInsn table_depw[] = {
2961 { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
2962 { 0xd4000800u, 0xfc001800u, trans_depw_imm },
2963 { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
2964};
2965
98cd9ca7
RH
2966static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
2967{
2968 unsigned n = extract32(insn, 1, 1);
2969 unsigned b = extract32(insn, 21, 5);
2970 target_long disp = assemble_17(insn);
2971
2972 /* unsigned s = low_uextract(insn, 13, 3); */
2973 /* ??? It seems like there should be a good way of using
2974 "be disp(sr2, r0)", the canonical gateway entry mechanism
2975 to our advantage. But that appears to be inconvenient to
2976 manage along side branch delay slots. Therefore we handle
2977 entry into the gateway page via absolute address. */
2978
2979 /* Since we don't implement spaces, just branch. Do notice the special
2980 case of "be disp(*,r0)" using a direct branch to disp, so that we can
2981 goto_tb to the TB containing the syscall. */
2982 if (b == 0) {
2983 return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
2984 } else {
2985 TCGv tmp = get_temp(ctx);
2986 tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
2987 return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
2988 }
2989}
2990
2991static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
2992 const DisasInsn *di)
2993{
2994 unsigned n = extract32(insn, 1, 1);
2995 unsigned link = extract32(insn, 21, 5);
2996 target_long disp = assemble_17(insn);
2997
2998 return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
2999}
3000
3001static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
3002 const DisasInsn *di)
3003{
3004 unsigned n = extract32(insn, 1, 1);
3005 target_long disp = assemble_22(insn);
3006
3007 return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
3008}
3009
3010static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
3011 const DisasInsn *di)
3012{
3013 unsigned n = extract32(insn, 1, 1);
3014 unsigned rx = extract32(insn, 16, 5);
3015 unsigned link = extract32(insn, 21, 5);
3016 TCGv tmp = get_temp(ctx);
3017
3018 tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
3019 tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
3020 return do_ibranch(ctx, tmp, link, n);
3021}
3022
3023static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
3024 const DisasInsn *di)
3025{
3026 unsigned n = extract32(insn, 1, 1);
3027 unsigned rx = extract32(insn, 16, 5);
3028 unsigned rb = extract32(insn, 21, 5);
3029 TCGv dest;
3030
3031 if (rx == 0) {
3032 dest = load_gpr(ctx, rb);
3033 } else {
3034 dest = get_temp(ctx);
3035 tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
3036 tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
3037 }
3038 return do_ibranch(ctx, dest, 0, n);
3039}
3040
3041static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
3042 const DisasInsn *di)
3043{
3044 unsigned n = extract32(insn, 1, 1);
3045 unsigned rb = extract32(insn, 21, 5);
3046 unsigned link = extract32(insn, 13, 1) ? 2 : 0;
3047
3048 return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
3049}
3050
3051static const DisasInsn table_branch[] = {
3052 { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3053 { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3054 { 0xe8004000u, 0xfc00fffdu, trans_blr },
3055 { 0xe800c000u, 0xfc00fffdu, trans_bv },
3056 { 0xe800d000u, 0xfc00dffcu, trans_bve },
3057};
3058
ebe9383c
RH
3059static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3060 const DisasInsn *di)
3061{
3062 unsigned rt = extract32(insn, 0, 5);
3063 unsigned ra = extract32(insn, 21, 5);
eff235eb 3064 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
3065}
3066
3067static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3068 const DisasInsn *di)
3069{
3070 unsigned rt = assemble_rt64(insn);
3071 unsigned ra = assemble_ra64(insn);
eff235eb 3072 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
3073}
3074
3075static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn,
3076 const DisasInsn *di)
3077{
3078 unsigned rt = extract32(insn, 0, 5);
3079 unsigned ra = extract32(insn, 21, 5);
eff235eb 3080 return do_fop_ded(ctx, rt, ra, di->f.ded);
ebe9383c
RH
3081}
3082
3083static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3084 const DisasInsn *di)
3085{
3086 unsigned rt = extract32(insn, 0, 5);
3087 unsigned ra = extract32(insn, 21, 5);
eff235eb 3088 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
3089}
3090
3091static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3092 const DisasInsn *di)
3093{
3094 unsigned rt = assemble_rt64(insn);
3095 unsigned ra = extract32(insn, 21, 5);
eff235eb 3096 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
3097}
3098
3099static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3100 const DisasInsn *di)
3101{
3102 unsigned rt = extract32(insn, 0, 5);
3103 unsigned ra = extract32(insn, 21, 5);
eff235eb 3104 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
3105}
3106
3107static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3108 const DisasInsn *di)
3109{
3110 unsigned rt = extract32(insn, 0, 5);
3111 unsigned ra = assemble_ra64(insn);
eff235eb 3112 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
3113}
3114
3115static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3116 const DisasInsn *di)
3117{
3118 unsigned rt = extract32(insn, 0, 5);
3119 unsigned rb = extract32(insn, 16, 5);
3120 unsigned ra = extract32(insn, 21, 5);
eff235eb 3121 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
3122}
3123
3124static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3125 const DisasInsn *di)
3126{
3127 unsigned rt = assemble_rt64(insn);
3128 unsigned rb = assemble_rb64(insn);
3129 unsigned ra = assemble_ra64(insn);
eff235eb 3130 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
3131}
3132
3133static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3134 const DisasInsn *di)
3135{
3136 unsigned rt = extract32(insn, 0, 5);
3137 unsigned rb = extract32(insn, 16, 5);
3138 unsigned ra = extract32(insn, 21, 5);
eff235eb 3139 return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
ebe9383c
RH
3140}
3141
3142static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3143{
3144 tcg_gen_mov_i32(dst, src);
3145}
3146
3147static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3148{
3149 tcg_gen_mov_i64(dst, src);
3150}
3151
3152static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3153{
3154 tcg_gen_andi_i32(dst, src, INT32_MAX);
3155}
3156
3157static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3158{
3159 tcg_gen_andi_i64(dst, src, INT64_MAX);
3160}
3161
3162static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3163{
3164 tcg_gen_xori_i32(dst, src, INT32_MIN);
3165}
3166
3167static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3168{
3169 tcg_gen_xori_i64(dst, src, INT64_MIN);
3170}
3171
3172static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3173{
3174 tcg_gen_ori_i32(dst, src, INT32_MIN);
3175}
3176
3177static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3178{
3179 tcg_gen_ori_i64(dst, src, INT64_MIN);
3180}
3181
3182static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3183 unsigned y, unsigned c)
3184{
3185 TCGv_i32 ta, tb, tc, ty;
3186
3187 nullify_over(ctx);
3188
3189 ta = load_frw0_i32(ra);
3190 tb = load_frw0_i32(rb);
3191 ty = tcg_const_i32(y);
3192 tc = tcg_const_i32(c);
3193
3194 gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3195
3196 tcg_temp_free_i32(ta);
3197 tcg_temp_free_i32(tb);
3198 tcg_temp_free_i32(ty);
3199 tcg_temp_free_i32(tc);
3200
3201 return nullify_end(ctx, NO_EXIT);
3202}
3203
3204static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3205 const DisasInsn *di)
3206{
3207 unsigned c = extract32(insn, 0, 5);
3208 unsigned y = extract32(insn, 13, 3);
3209 unsigned rb = extract32(insn, 16, 5);
3210 unsigned ra = extract32(insn, 21, 5);
3211 return do_fcmp_s(ctx, ra, rb, y, c);
3212}
3213
3214static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3215 const DisasInsn *di)
3216{
3217 unsigned c = extract32(insn, 0, 5);
3218 unsigned y = extract32(insn, 13, 3);
3219 unsigned rb = assemble_rb64(insn);
3220 unsigned ra = assemble_ra64(insn);
3221 return do_fcmp_s(ctx, ra, rb, y, c);
3222}
3223
3224static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3225 const DisasInsn *di)
3226{
3227 unsigned c = extract32(insn, 0, 5);
3228 unsigned y = extract32(insn, 13, 3);
3229 unsigned rb = extract32(insn, 16, 5);
3230 unsigned ra = extract32(insn, 21, 5);
3231 TCGv_i64 ta, tb;
3232 TCGv_i32 tc, ty;
3233
3234 nullify_over(ctx);
3235
3236 ta = load_frd0(ra);
3237 tb = load_frd0(rb);
3238 ty = tcg_const_i32(y);
3239 tc = tcg_const_i32(c);
3240
3241 gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3242
3243 tcg_temp_free_i64(ta);
3244 tcg_temp_free_i64(tb);
3245 tcg_temp_free_i32(ty);
3246 tcg_temp_free_i32(tc);
3247
3248 return nullify_end(ctx, NO_EXIT);
3249}
3250
3251static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn,
3252 const DisasInsn *di)
3253{
3254 unsigned y = extract32(insn, 13, 3);
3255 unsigned cbit = (y ^ 1) - 1;
3256 TCGv t;
3257
3258 nullify_over(ctx);
3259
3260 t = tcg_temp_new();
3261 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3262 tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3263 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3264 tcg_temp_free(t);
3265
3266 return nullify_end(ctx, NO_EXIT);
3267}
3268
3269static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn,
3270 const DisasInsn *di)
3271{
3272 unsigned c = extract32(insn, 0, 5);
3273 int mask;
3274 bool inv = false;
3275 TCGv t;
3276
3277 nullify_over(ctx);
3278
3279 t = tcg_temp_new();
3280 tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3281
3282 switch (c) {
3283 case 0: /* simple */
3284 tcg_gen_andi_tl(t, t, 0x4000000);
3285 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3286 goto done;
3287 case 2: /* rej */
3288 inv = true;
3289 /* fallthru */
3290 case 1: /* acc */
3291 mask = 0x43ff800;
3292 break;
3293 case 6: /* rej8 */
3294 inv = true;
3295 /* fallthru */
3296 case 5: /* acc8 */
3297 mask = 0x43f8000;
3298 break;
3299 case 9: /* acc6 */
3300 mask = 0x43e0000;
3301 break;
3302 case 13: /* acc4 */
3303 mask = 0x4380000;
3304 break;
3305 case 17: /* acc2 */
3306 mask = 0x4200000;
3307 break;
3308 default:
3309 return gen_illegal(ctx);
3310 }
3311 if (inv) {
3312 TCGv c = load_const(ctx, mask);
3313 tcg_gen_or_tl(t, t, c);
3314 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3315 } else {
3316 tcg_gen_andi_tl(t, t, mask);
3317 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3318 }
3319 done:
3320 return nullify_end(ctx, NO_EXIT);
3321}
3322
3323static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn,
3324 const DisasInsn *di)
3325{
3326 unsigned rt = extract32(insn, 0, 5);
3327 unsigned rb = assemble_rb64(insn);
3328 unsigned ra = assemble_ra64(insn);
3329 TCGv_i64 a, b;
3330
3331 nullify_over(ctx);
3332
3333 a = load_frw0_i64(ra);
3334 b = load_frw0_i64(rb);
3335 tcg_gen_mul_i64(a, a, b);
3336 save_frd(rt, a);
3337 tcg_temp_free_i64(a);
3338 tcg_temp_free_i64(b);
3339
3340 return nullify_end(ctx, NO_EXIT);
3341}
3342
eff235eb
PB
3343#define FOP_DED trans_fop_ded, .f.ded
3344#define FOP_DEDD trans_fop_dedd, .f.dedd
ebe9383c 3345
eff235eb
PB
3346#define FOP_WEW trans_fop_wew_0c, .f.wew
3347#define FOP_DEW trans_fop_dew_0c, .f.dew
3348#define FOP_WED trans_fop_wed_0c, .f.wed
3349#define FOP_WEWW trans_fop_weww_0c, .f.weww
ebe9383c
RH
3350
3351static const DisasInsn table_float_0c[] = {
3352 /* floating point class zero */
3353 { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3354 { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3355 { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3356 { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3357 { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3358 { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3359
3360 { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3361 { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3362 { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3363 { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3364 { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3365 { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3366
3367 /* floating point class three */
3368 { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3369 { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3370 { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3371 { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3372
3373 { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3374 { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3375 { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3376 { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3377
3378 /* floating point class one */
3379 /* float/float */
3380 { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3381 { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3382 /* int/float */
3383 { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3384 { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3385 { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3386 { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3387 /* float/int */
3388 { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3389 { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3390 { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3391 { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3392 /* float/int truncate */
3393 { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3394 { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3395 { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3396 { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3397 /* uint/float */
3398 { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3399 { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3400 { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3401 { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3402 /* float/uint */
3403 { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3404 { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3405 { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3406 { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3407 /* float/uint truncate */
3408 { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3409 { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3410 { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3411 { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3412
3413 /* floating point class two */
3414 { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3415 { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3416 { 0x30002420, 0xffffffe0, trans_ftest_q },
3417 { 0x30000420, 0xffff1fff, trans_ftest_t },
3418
3419 /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3420 This is machine/revision == 0, which is reserved for simulator. */
3421 { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3422};
3423
3424#undef FOP_WEW
3425#undef FOP_DEW
3426#undef FOP_WED
3427#undef FOP_WEWW
eff235eb
PB
3428#define FOP_WEW trans_fop_wew_0e, .f.wew
3429#define FOP_DEW trans_fop_dew_0e, .f.dew
3430#define FOP_WED trans_fop_wed_0e, .f.wed
3431#define FOP_WEWW trans_fop_weww_0e, .f.weww
ebe9383c
RH
3432
3433static const DisasInsn table_float_0e[] = {
3434 /* floating point class zero */
3435 { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3436 { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3437 { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3438 { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3439 { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3440 { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3441
3442 { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3443 { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3444 { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3445 { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3446 { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3447 { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3448
3449 /* floating point class three */
3450 { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3451 { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3452 { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3453 { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3454
3455 { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3456 { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3457 { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3458 { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3459
3460 { 0x38004700, 0xfc00ef60, trans_xmpyu },
3461
3462 /* floating point class one */
3463 /* float/float */
3464 { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3465 { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3466 /* int/float */
3467 { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3468 { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3469 { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3470 { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3471 /* float/int */
3472 { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3473 { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3474 { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3475 { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3476 /* float/int truncate */
3477 { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3478 { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3479 { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3480 { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3481 /* uint/float */
3482 { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3483 { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3484 { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3485 { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3486 /* float/uint */
3487 { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3488 { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3489 { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3490 { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3491 /* float/uint truncate */
3492 { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3493 { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3494 { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3495 { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3496
3497 /* floating point class two */
3498 { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3499 { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3500};
3501
3502#undef FOP_WEW
3503#undef FOP_DEW
3504#undef FOP_WED
3505#undef FOP_WEWW
3506#undef FOP_DED
3507#undef FOP_DEDD
3508
3509/* Convert the fmpyadd single-precision register encodings to standard. */
3510static inline int fmpyadd_s_reg(unsigned r)
3511{
3512 return (r & 16) * 2 + 16 + (r & 15);
3513}
3514
3515static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub)
3516{
3517 unsigned tm = extract32(insn, 0, 5);
3518 unsigned f = extract32(insn, 5, 1);
3519 unsigned ra = extract32(insn, 6, 5);
3520 unsigned ta = extract32(insn, 11, 5);
3521 unsigned rm2 = extract32(insn, 16, 5);
3522 unsigned rm1 = extract32(insn, 21, 5);
3523
3524 nullify_over(ctx);
3525
3526 /* Independent multiply & add/sub, with undefined behaviour
3527 if outputs overlap inputs. */
3528 if (f == 0) {
3529 tm = fmpyadd_s_reg(tm);
3530 ra = fmpyadd_s_reg(ra);
3531 ta = fmpyadd_s_reg(ta);
3532 rm2 = fmpyadd_s_reg(rm2);
3533 rm1 = fmpyadd_s_reg(rm1);
3534 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3535 do_fop_weww(ctx, ta, ta, ra,
3536 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3537 } else {
3538 do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3539 do_fop_dedd(ctx, ta, ta, ra,
3540 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3541 }
3542
3543 return nullify_end(ctx, NO_EXIT);
3544}
3545
3546static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3547 const DisasInsn *di)
3548{
3549 unsigned rt = assemble_rt64(insn);
3550 unsigned neg = extract32(insn, 5, 1);
3551 unsigned rm1 = assemble_ra64(insn);
3552 unsigned rm2 = assemble_rb64(insn);
3553 unsigned ra3 = assemble_rc64(insn);
3554 TCGv_i32 a, b, c;
3555
3556 nullify_over(ctx);
3557 a = load_frw0_i32(rm1);
3558 b = load_frw0_i32(rm2);
3559 c = load_frw0_i32(ra3);
3560
3561 if (neg) {
3562 gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3563 } else {
3564 gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3565 }
3566
3567 tcg_temp_free_i32(b);
3568 tcg_temp_free_i32(c);
3569 save_frw_i32(rt, a);
3570 tcg_temp_free_i32(a);
3571 return nullify_end(ctx, NO_EXIT);
3572}
3573
3574static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3575 const DisasInsn *di)
3576{
3577 unsigned rt = extract32(insn, 0, 5);
3578 unsigned neg = extract32(insn, 5, 1);
3579 unsigned rm1 = extract32(insn, 21, 5);
3580 unsigned rm2 = extract32(insn, 16, 5);
3581 unsigned ra3 = assemble_rc64(insn);
3582 TCGv_i64 a, b, c;
3583
3584 nullify_over(ctx);
3585 a = load_frd0(rm1);
3586 b = load_frd0(rm2);
3587 c = load_frd0(ra3);
3588
3589 if (neg) {
3590 gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3591 } else {
3592 gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3593 }
3594
3595 tcg_temp_free_i64(b);
3596 tcg_temp_free_i64(c);
3597 save_frd(rt, a);
3598 tcg_temp_free_i64(a);
3599 return nullify_end(ctx, NO_EXIT);
3600}
3601
3602static const DisasInsn table_fp_fused[] = {
3603 { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3604 { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3605};
3606
61766fe9
RH
3607static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
3608 const DisasInsn table[], size_t n)
3609{
3610 size_t i;
3611 for (i = 0; i < n; ++i) {
3612 if ((insn & table[i].mask) == table[i].insn) {
3613 return table[i].trans(ctx, insn, &table[i]);
3614 }
3615 }
3616 return gen_illegal(ctx);
3617}
3618
3619#define translate_table(ctx, insn, table) \
3620 translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
3621
3622static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
3623{
3624 uint32_t opc = extract32(insn, 26, 6);
3625
3626 switch (opc) {
98a9cb79
RH
3627 case 0x00: /* system op */
3628 return translate_table(ctx, insn, table_system);
3629 case 0x01:
3630 return translate_table(ctx, insn, table_mem_mgmt);
b2167459
RH
3631 case 0x02:
3632 return translate_table(ctx, insn, table_arith_log);
96d6407f
RH
3633 case 0x03:
3634 return translate_table(ctx, insn, table_index_mem);
ebe9383c
RH
3635 case 0x06:
3636 return trans_fmpyadd(ctx, insn, false);
b2167459
RH
3637 case 0x08:
3638 return trans_ldil(ctx, insn);
96d6407f
RH
3639 case 0x09:
3640 return trans_copr_w(ctx, insn);
b2167459
RH
3641 case 0x0A:
3642 return trans_addil(ctx, insn);
96d6407f
RH
3643 case 0x0B:
3644 return trans_copr_dw(ctx, insn);
ebe9383c
RH
3645 case 0x0C:
3646 return translate_table(ctx, insn, table_float_0c);
b2167459
RH
3647 case 0x0D:
3648 return trans_ldo(ctx, insn);
ebe9383c
RH
3649 case 0x0E:
3650 return translate_table(ctx, insn, table_float_0e);
96d6407f
RH
3651
3652 case 0x10:
3653 return trans_load(ctx, insn, false, MO_UB);
3654 case 0x11:
3655 return trans_load(ctx, insn, false, MO_TEUW);
3656 case 0x12:
3657 return trans_load(ctx, insn, false, MO_TEUL);
3658 case 0x13:
3659 return trans_load(ctx, insn, true, MO_TEUL);
3660 case 0x16:
3661 return trans_fload_mod(ctx, insn);
3662 case 0x17:
3663 return trans_load_w(ctx, insn);
3664 case 0x18:
3665 return trans_store(ctx, insn, false, MO_UB);
3666 case 0x19:
3667 return trans_store(ctx, insn, false, MO_TEUW);
3668 case 0x1A:
3669 return trans_store(ctx, insn, false, MO_TEUL);
3670 case 0x1B:
3671 return trans_store(ctx, insn, true, MO_TEUL);
3672 case 0x1E:
3673 return trans_fstore_mod(ctx, insn);
3674 case 0x1F:
3675 return trans_store_w(ctx, insn);
3676
98cd9ca7
RH
3677 case 0x20:
3678 return trans_cmpb(ctx, insn, true, false, false);
3679 case 0x21:
3680 return trans_cmpb(ctx, insn, true, true, false);
3681 case 0x22:
3682 return trans_cmpb(ctx, insn, false, false, false);
3683 case 0x23:
3684 return trans_cmpb(ctx, insn, false, true, false);
b2167459
RH
3685 case 0x24:
3686 return trans_cmpiclr(ctx, insn);
3687 case 0x25:
3688 return trans_subi(ctx, insn);
ebe9383c
RH
3689 case 0x26:
3690 return trans_fmpyadd(ctx, insn, true);
98cd9ca7
RH
3691 case 0x27:
3692 return trans_cmpb(ctx, insn, true, false, true);
3693 case 0x28:
3694 return trans_addb(ctx, insn, true, false);
3695 case 0x29:
3696 return trans_addb(ctx, insn, true, true);
3697 case 0x2A:
3698 return trans_addb(ctx, insn, false, false);
3699 case 0x2B:
3700 return trans_addb(ctx, insn, false, true);
b2167459
RH
3701 case 0x2C:
3702 case 0x2D:
3703 return trans_addi(ctx, insn);
ebe9383c
RH
3704 case 0x2E:
3705 return translate_table(ctx, insn, table_fp_fused);
98cd9ca7
RH
3706 case 0x2F:
3707 return trans_cmpb(ctx, insn, false, false, true);
96d6407f 3708
98cd9ca7
RH
3709 case 0x30:
3710 case 0x31:
3711 return trans_bb(ctx, insn);
3712 case 0x32:
3713 return trans_movb(ctx, insn, false);
3714 case 0x33:
3715 return trans_movb(ctx, insn, true);
0b1347d2
RH
3716 case 0x34:
3717 return translate_table(ctx, insn, table_sh_ex);
3718 case 0x35:
3719 return translate_table(ctx, insn, table_depw);
98cd9ca7
RH
3720 case 0x38:
3721 return trans_be(ctx, insn, false);
3722 case 0x39:
3723 return trans_be(ctx, insn, true);
3724 case 0x3A:
3725 return translate_table(ctx, insn, table_branch);
96d6407f
RH
3726
3727 case 0x04: /* spopn */
3728 case 0x05: /* diag */
3729 case 0x0F: /* product specific */
3730 break;
3731
3732 case 0x07: /* unassigned */
3733 case 0x15: /* unassigned */
3734 case 0x1D: /* unassigned */
3735 case 0x37: /* unassigned */
3736 case 0x3F: /* unassigned */
61766fe9
RH
3737 default:
3738 break;
3739 }
3740 return gen_illegal(ctx);
3741}
3742
9c489ea6 3743void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
61766fe9 3744{
9c489ea6 3745 CPUHPPAState *env = cs->env_ptr;
61766fe9
RH
3746 DisasContext ctx;
3747 ExitStatus ret;
3748 int num_insns, max_insns, i;
3749
3750 ctx.tb = tb;
3751 ctx.cs = cs;
3752 ctx.iaoq_f = tb->pc;
3753 ctx.iaoq_b = tb->cs_base;
3754 ctx.singlestep_enabled = cs->singlestep_enabled;
3755
3756 ctx.ntemps = 0;
3757 for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
3758 TCGV_UNUSED(ctx.temps[i]);
3759 }
3760
3761 /* Compute the maximum number of insns to execute, as bounded by
3762 (1) icount, (2) single-stepping, (3) branch delay slots, or
3763 (4) the number of insns remaining on the current page. */
3764 max_insns = tb->cflags & CF_COUNT_MASK;
3765 if (max_insns == 0) {
3766 max_insns = CF_COUNT_MASK;
3767 }
3768 if (ctx.singlestep_enabled || singlestep) {
3769 max_insns = 1;
3770 } else if (max_insns > TCG_MAX_INSNS) {
3771 max_insns = TCG_MAX_INSNS;
3772 }
3773
3774 num_insns = 0;
3775 gen_tb_start(tb);
3776
129e9cc3
RH
3777 /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */
3778 ctx.null_cond = cond_make_f();
3779 ctx.psw_n_nonzero = false;
3780 if (tb->flags & 1) {
3781 ctx.null_cond.c = TCG_COND_ALWAYS;
3782 ctx.psw_n_nonzero = true;
3783 }
3784 ctx.null_lab = NULL;
3785
61766fe9
RH
3786 do {
3787 tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
3788 num_insns++;
3789
3790 if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
3791 ret = gen_excp(&ctx, EXCP_DEBUG);
3792 break;
3793 }
3794 if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
3795 gen_io_start();
3796 }
3797
7ad439df
RH
3798 if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
3799 ret = do_page_zero(&ctx);
3800 assert(ret != NO_EXIT);
3801 } else {
61766fe9
RH
3802 /* Always fetch the insn, even if nullified, so that we check
3803 the page permissions for execute. */
3804 uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
3805
3806 /* Set up the IA queue for the next insn.
3807 This will be overwritten by a branch. */
3808 if (ctx.iaoq_b == -1) {
3809 ctx.iaoq_n = -1;
3810 ctx.iaoq_n_var = get_temp(&ctx);
3811 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
3812 } else {
3813 ctx.iaoq_n = ctx.iaoq_b + 4;
3814 TCGV_UNUSED(ctx.iaoq_n_var);
3815 }
3816
129e9cc3
RH
3817 if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
3818 ctx.null_cond.c = TCG_COND_NEVER;
3819 ret = NO_EXIT;
3820 } else {
3821 ret = translate_one(&ctx, insn);
3822 assert(ctx.null_lab == NULL);
3823 }
61766fe9
RH
3824 }
3825
3826 for (i = 0; i < ctx.ntemps; ++i) {
3827 tcg_temp_free(ctx.temps[i]);
3828 TCGV_UNUSED(ctx.temps[i]);
3829 }
3830 ctx.ntemps = 0;
3831
3832 /* If we see non-linear instructions, exhaust instruction count,
3833 or run out of buffer space, stop generation. */
3834 /* ??? The non-linear instruction restriction is purely due to
3835 the debugging dump. Otherwise we *could* follow unconditional
3836 branches within the same page. */
3837 if (ret == NO_EXIT
3838 && (ctx.iaoq_b != ctx.iaoq_f + 4
3839 || num_insns >= max_insns
3840 || tcg_op_buf_full())) {
129e9cc3
RH
3841 if (ctx.null_cond.c == TCG_COND_NEVER
3842 || ctx.null_cond.c == TCG_COND_ALWAYS) {
3843 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
3844 gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
3845 ret = EXIT_GOTO_TB;
3846 } else {
3847 ret = EXIT_IAQ_N_STALE;
3848 }
61766fe9
RH
3849 }
3850
3851 ctx.iaoq_f = ctx.iaoq_b;
3852 ctx.iaoq_b = ctx.iaoq_n;
3853 if (ret == EXIT_NORETURN
3854 || ret == EXIT_GOTO_TB
3855 || ret == EXIT_IAQ_N_UPDATED) {
3856 break;
3857 }
3858 if (ctx.iaoq_f == -1) {
3859 tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
3860 copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
129e9cc3 3861 nullify_save(&ctx);
61766fe9
RH
3862 ret = EXIT_IAQ_N_UPDATED;
3863 break;
3864 }
3865 if (ctx.iaoq_b == -1) {
3866 tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
3867 }
3868 } while (ret == NO_EXIT);
3869
3870 if (tb->cflags & CF_LAST_IO) {
3871 gen_io_end();
3872 }
3873
3874 switch (ret) {
3875 case EXIT_GOTO_TB:
3876 case EXIT_NORETURN:
3877 break;
3878 case EXIT_IAQ_N_STALE:
3879 copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
3880 copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
129e9cc3 3881 nullify_save(&ctx);
61766fe9
RH
3882 /* FALLTHRU */
3883 case EXIT_IAQ_N_UPDATED:
3884 if (ctx.singlestep_enabled) {
3885 gen_excp_1(EXCP_DEBUG);
3886 } else {
4137cb83 3887 tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
61766fe9
RH
3888 }
3889 break;
3890 default:
3891 abort();
3892 }
3893
3894 gen_tb_end(tb, num_insns);
3895
3896 tb->size = num_insns * 4;
3897 tb->icount = num_insns;
3898
3899#ifdef DEBUG_DISAS
3900 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
3901 && qemu_log_in_addr_range(tb->pc)) {
3902 qemu_log_lock();
7ad439df
RH
3903 switch (tb->pc) {
3904 case 0x00:
3905 qemu_log("IN:\n0x00000000: (null)\n\n");
3906 break;
3907 case 0xb0:
3908 qemu_log("IN:\n0x000000b0: light-weight-syscall\n\n");
3909 break;
3910 case 0xe0:
3911 qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n\n");
3912 break;
3913 case 0x100:
3914 qemu_log("IN:\n0x00000100: syscall\n\n");
3915 break;
3916 default:
3917 qemu_log("IN: %s\n", lookup_symbol(tb->pc));
3918 log_target_disas(cs, tb->pc, tb->size, 1);
3919 qemu_log("\n");
3920 break;
3921 }
61766fe9
RH
3922 qemu_log_unlock();
3923 }
3924#endif
3925}
3926
3927void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
3928 target_ulong *data)
3929{
3930 env->iaoq_f = data[0];
3931 if (data[1] != -1) {
3932 env->iaoq_b = data[1];
3933 }
3934 /* Since we were executing the instruction at IAOQ_F, and took some
3935 sort of action that provoked the cpu_restore_state, we can infer
3936 that the instruction was not nullified. */
3937 env->psw_n = 0;
3938}