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