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