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