]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/translate.c
target/hppa: Clear upper bits in mtctl for pa1.x
[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
d6ea4236 9 * version 2.1 of the License, or (at your option) any later version.
61766fe9
RH
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"
dcb32f1d 25#include "tcg/tcg-op.h"
0843563f 26#include "tcg/tcg-op-gvec.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 "exec/log.h"
31
d53106c9
RH
32#define HELPER_H "helper.h"
33#include "exec/helper-info.c.inc"
34#undef HELPER_H
35
aac0f603
RH
36/* Choose to use explicit sizes within this file. */
37#undef tcg_temp_new
d53106c9 38
61766fe9
RH
39typedef struct DisasCond {
40 TCGCond c;
6fd0c7bc 41 TCGv_i64 a0, a1;
61766fe9
RH
42} DisasCond;
43
44typedef struct DisasContext {
d01a3625 45 DisasContextBase base;
61766fe9
RH
46 CPUState *cs;
47
c53e401e
RH
48 uint64_t iaoq_f;
49 uint64_t iaoq_b;
50 uint64_t iaoq_n;
6fd0c7bc 51 TCGv_i64 iaoq_n_var;
61766fe9 52
61766fe9
RH
53 DisasCond null_cond;
54 TCGLabel *null_lab;
55
a4db4a78
RH
56 TCGv_i64 zero;
57
1a19da0d 58 uint32_t insn;
494737b7 59 uint32_t tb_flags;
3d68ee7b
RH
60 int mmu_idx;
61 int privilege;
61766fe9 62 bool psw_n_nonzero;
bd6243a3 63 bool is_pa20;
217d1a5e
RH
64
65#ifdef CONFIG_USER_ONLY
66 MemOp unalign;
67#endif
61766fe9
RH
68} DisasContext;
69
217d1a5e
RH
70#ifdef CONFIG_USER_ONLY
71#define UNALIGN(C) (C)->unalign
72#else
2d4afb03 73#define UNALIGN(C) MO_ALIGN
217d1a5e
RH
74#endif
75
e36f27ef 76/* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */
451e4ffd 77static int expand_sm_imm(DisasContext *ctx, int val)
e36f27ef
RH
78{
79 if (val & PSW_SM_E) {
80 val = (val & ~PSW_SM_E) | PSW_E;
81 }
82 if (val & PSW_SM_W) {
83 val = (val & ~PSW_SM_W) | PSW_W;
84 }
85 return val;
86}
87
deee69a1 88/* Inverted space register indicates 0 means sr0 not inferred from base. */
451e4ffd 89static int expand_sr3x(DisasContext *ctx, int val)
deee69a1
RH
90{
91 return ~val;
92}
93
1cd012a5
RH
94/* Convert the M:A bits within a memory insn to the tri-state value
95 we use for the final M. */
451e4ffd 96static int ma_to_m(DisasContext *ctx, int val)
1cd012a5
RH
97{
98 return val & 2 ? (val & 1 ? -1 : 1) : 0;
99}
100
740038d7 101/* Convert the sign of the displacement to a pre or post-modify. */
451e4ffd 102static int pos_to_m(DisasContext *ctx, int val)
740038d7
RH
103{
104 return val ? 1 : -1;
105}
106
451e4ffd 107static int neg_to_m(DisasContext *ctx, int val)
740038d7
RH
108{
109 return val ? -1 : 1;
110}
111
112/* Used for branch targets and fp memory ops. */
451e4ffd 113static int expand_shl2(DisasContext *ctx, int val)
01afb7be
RH
114{
115 return val << 2;
116}
117
740038d7 118/* Used for fp memory ops. */
451e4ffd 119static int expand_shl3(DisasContext *ctx, int val)
740038d7
RH
120{
121 return val << 3;
122}
123
0588e061 124/* Used for assemble_21. */
451e4ffd 125static int expand_shl11(DisasContext *ctx, int val)
0588e061
RH
126{
127 return val << 11;
128}
129
72ae4f2b
RH
130static int assemble_6(DisasContext *ctx, int val)
131{
132 /*
133 * Officially, 32 * x + 32 - y.
134 * Here, x is already in bit 5, and y is [4:0].
135 * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
136 * with the overflow from bit 4 summing with x.
137 */
138 return (val ^ 31) + 1;
139}
140
c65c3ee1
RH
141/* Translate CMPI doubleword conditions to standard. */
142static int cmpbid_c(DisasContext *ctx, int val)
143{
144 return val ? val : 4; /* 0 == "*<<" */
145}
146
01afb7be 147
40f9f908 148/* Include the auto-generated decoder. */
abff1abf 149#include "decode-insns.c.inc"
40f9f908 150
869051ea
RH
151/* We are not using a goto_tb (for whatever reason), but have updated
152 the iaq (for whatever reason), so don't do it again on exit. */
153#define DISAS_IAQ_N_UPDATED DISAS_TARGET_0
61766fe9 154
869051ea
RH
155/* We are exiting the TB, but have neither emitted a goto_tb, nor
156 updated the iaq for the next instruction to be executed. */
157#define DISAS_IAQ_N_STALE DISAS_TARGET_1
61766fe9 158
e1b5a5ed
RH
159/* Similarly, but we want to return to the main loop immediately
160 to recognize unmasked interrupts. */
161#define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2
c5d0aec2 162#define DISAS_EXIT DISAS_TARGET_3
e1b5a5ed 163
61766fe9 164/* global register indexes */
6fd0c7bc 165static TCGv_i64 cpu_gr[32];
33423472 166static TCGv_i64 cpu_sr[4];
494737b7 167static TCGv_i64 cpu_srH;
6fd0c7bc
RH
168static TCGv_i64 cpu_iaoq_f;
169static TCGv_i64 cpu_iaoq_b;
c301f34e
RH
170static TCGv_i64 cpu_iasq_f;
171static TCGv_i64 cpu_iasq_b;
6fd0c7bc
RH
172static TCGv_i64 cpu_sar;
173static TCGv_i64 cpu_psw_n;
174static TCGv_i64 cpu_psw_v;
175static TCGv_i64 cpu_psw_cb;
176static TCGv_i64 cpu_psw_cb_msb;
61766fe9 177
61766fe9
RH
178void hppa_translate_init(void)
179{
180#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
181
6fd0c7bc 182 typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
61766fe9 183 static const GlobalVar vars[] = {
35136a77 184 { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
61766fe9
RH
185 DEF_VAR(psw_n),
186 DEF_VAR(psw_v),
187 DEF_VAR(psw_cb),
188 DEF_VAR(psw_cb_msb),
189 DEF_VAR(iaoq_f),
190 DEF_VAR(iaoq_b),
191 };
192
193#undef DEF_VAR
194
195 /* Use the symbolic register names that match the disassembler. */
196 static const char gr_names[32][4] = {
197 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
198 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
199 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
200 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
201 };
33423472 202 /* SR[4-7] are not global registers so that we can index them. */
494737b7
RH
203 static const char sr_names[5][4] = {
204 "sr0", "sr1", "sr2", "sr3", "srH"
33423472 205 };
61766fe9 206
61766fe9
RH
207 int i;
208
f764718d 209 cpu_gr[0] = NULL;
61766fe9 210 for (i = 1; i < 32; i++) {
ad75a51e 211 cpu_gr[i] = tcg_global_mem_new(tcg_env,
61766fe9
RH
212 offsetof(CPUHPPAState, gr[i]),
213 gr_names[i]);
214 }
33423472 215 for (i = 0; i < 4; i++) {
ad75a51e 216 cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
33423472
RH
217 offsetof(CPUHPPAState, sr[i]),
218 sr_names[i]);
219 }
ad75a51e 220 cpu_srH = tcg_global_mem_new_i64(tcg_env,
494737b7
RH
221 offsetof(CPUHPPAState, sr[4]),
222 sr_names[4]);
61766fe9
RH
223
224 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
225 const GlobalVar *v = &vars[i];
ad75a51e 226 *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
61766fe9 227 }
c301f34e 228
ad75a51e 229 cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
c301f34e
RH
230 offsetof(CPUHPPAState, iasq_f),
231 "iasq_f");
ad75a51e 232 cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
c301f34e
RH
233 offsetof(CPUHPPAState, iasq_b),
234 "iasq_b");
61766fe9
RH
235}
236
129e9cc3
RH
237static DisasCond cond_make_f(void)
238{
f764718d
RH
239 return (DisasCond){
240 .c = TCG_COND_NEVER,
241 .a0 = NULL,
242 .a1 = NULL,
243 };
129e9cc3
RH
244}
245
df0232fe
RH
246static DisasCond cond_make_t(void)
247{
248 return (DisasCond){
249 .c = TCG_COND_ALWAYS,
250 .a0 = NULL,
251 .a1 = NULL,
252 };
253}
254
129e9cc3
RH
255static DisasCond cond_make_n(void)
256{
f764718d
RH
257 return (DisasCond){
258 .c = TCG_COND_NE,
259 .a0 = cpu_psw_n,
6fd0c7bc 260 .a1 = tcg_constant_i64(0)
f764718d 261 };
129e9cc3
RH
262}
263
6fd0c7bc 264static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
129e9cc3 265{
129e9cc3 266 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
4fe9533a
RH
267 return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
268}
269
6fd0c7bc 270static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
4fe9533a 271{
6fd0c7bc 272 return cond_make_tmp(c, a0, tcg_constant_i64(0));
b47a4a02 273}
129e9cc3 274
6fd0c7bc 275static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
b47a4a02 276{
aac0f603 277 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc 278 tcg_gen_mov_i64(tmp, a0);
b47a4a02 279 return cond_make_0_tmp(c, tmp);
129e9cc3
RH
280}
281
6fd0c7bc 282static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
129e9cc3 283{
aac0f603
RH
284 TCGv_i64 t0 = tcg_temp_new_i64();
285 TCGv_i64 t1 = tcg_temp_new_i64();
129e9cc3 286
6fd0c7bc
RH
287 tcg_gen_mov_i64(t0, a0);
288 tcg_gen_mov_i64(t1, a1);
4fe9533a 289 return cond_make_tmp(c, t0, t1);
129e9cc3
RH
290}
291
129e9cc3
RH
292static void cond_free(DisasCond *cond)
293{
294 switch (cond->c) {
295 default:
f764718d
RH
296 cond->a0 = NULL;
297 cond->a1 = NULL;
129e9cc3
RH
298 /* fallthru */
299 case TCG_COND_ALWAYS:
300 cond->c = TCG_COND_NEVER;
301 break;
302 case TCG_COND_NEVER:
303 break;
304 }
305}
306
6fd0c7bc 307static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
61766fe9
RH
308{
309 if (reg == 0) {
bc3da3cf 310 return ctx->zero;
61766fe9
RH
311 } else {
312 return cpu_gr[reg];
313 }
314}
315
6fd0c7bc 316static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
61766fe9 317{
129e9cc3 318 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
aac0f603 319 return tcg_temp_new_i64();
61766fe9
RH
320 } else {
321 return cpu_gr[reg];
322 }
323}
324
6fd0c7bc 325static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
129e9cc3
RH
326{
327 if (ctx->null_cond.c != TCG_COND_NEVER) {
6fd0c7bc 328 tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
6e94937a 329 ctx->null_cond.a1, dest, t);
129e9cc3 330 } else {
6fd0c7bc 331 tcg_gen_mov_i64(dest, t);
129e9cc3
RH
332 }
333}
334
6fd0c7bc 335static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
129e9cc3
RH
336{
337 if (reg != 0) {
338 save_or_nullify(ctx, cpu_gr[reg], t);
339 }
340}
341
e03b5686 342#if HOST_BIG_ENDIAN
96d6407f
RH
343# define HI_OFS 0
344# define LO_OFS 4
345#else
346# define HI_OFS 4
347# define LO_OFS 0
348#endif
349
350static TCGv_i32 load_frw_i32(unsigned rt)
351{
352 TCGv_i32 ret = tcg_temp_new_i32();
ad75a51e 353 tcg_gen_ld_i32(ret, tcg_env,
96d6407f
RH
354 offsetof(CPUHPPAState, fr[rt & 31])
355 + (rt & 32 ? LO_OFS : HI_OFS));
356 return ret;
357}
358
ebe9383c
RH
359static TCGv_i32 load_frw0_i32(unsigned rt)
360{
361 if (rt == 0) {
0992a930
RH
362 TCGv_i32 ret = tcg_temp_new_i32();
363 tcg_gen_movi_i32(ret, 0);
364 return ret;
ebe9383c
RH
365 } else {
366 return load_frw_i32(rt);
367 }
368}
369
370static TCGv_i64 load_frw0_i64(unsigned rt)
371{
0992a930 372 TCGv_i64 ret = tcg_temp_new_i64();
ebe9383c 373 if (rt == 0) {
0992a930 374 tcg_gen_movi_i64(ret, 0);
ebe9383c 375 } else {
ad75a51e 376 tcg_gen_ld32u_i64(ret, tcg_env,
ebe9383c
RH
377 offsetof(CPUHPPAState, fr[rt & 31])
378 + (rt & 32 ? LO_OFS : HI_OFS));
ebe9383c 379 }
0992a930 380 return ret;
ebe9383c
RH
381}
382
96d6407f
RH
383static void save_frw_i32(unsigned rt, TCGv_i32 val)
384{
ad75a51e 385 tcg_gen_st_i32(val, tcg_env,
96d6407f
RH
386 offsetof(CPUHPPAState, fr[rt & 31])
387 + (rt & 32 ? LO_OFS : HI_OFS));
388}
389
390#undef HI_OFS
391#undef LO_OFS
392
393static TCGv_i64 load_frd(unsigned rt)
394{
395 TCGv_i64 ret = tcg_temp_new_i64();
ad75a51e 396 tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
96d6407f
RH
397 return ret;
398}
399
ebe9383c
RH
400static TCGv_i64 load_frd0(unsigned rt)
401{
402 if (rt == 0) {
0992a930
RH
403 TCGv_i64 ret = tcg_temp_new_i64();
404 tcg_gen_movi_i64(ret, 0);
405 return ret;
ebe9383c
RH
406 } else {
407 return load_frd(rt);
408 }
409}
410
96d6407f
RH
411static void save_frd(unsigned rt, TCGv_i64 val)
412{
ad75a51e 413 tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
96d6407f
RH
414}
415
33423472
RH
416static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
417{
418#ifdef CONFIG_USER_ONLY
419 tcg_gen_movi_i64(dest, 0);
420#else
421 if (reg < 4) {
422 tcg_gen_mov_i64(dest, cpu_sr[reg]);
494737b7
RH
423 } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
424 tcg_gen_mov_i64(dest, cpu_srH);
33423472 425 } else {
ad75a51e 426 tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
33423472
RH
427 }
428#endif
429}
430
129e9cc3
RH
431/* Skip over the implementation of an insn that has been nullified.
432 Use this when the insn is too complex for a conditional move. */
433static void nullify_over(DisasContext *ctx)
434{
435 if (ctx->null_cond.c != TCG_COND_NEVER) {
436 /* The always condition should have been handled in the main loop. */
437 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
438
439 ctx->null_lab = gen_new_label();
129e9cc3
RH
440
441 /* If we're using PSW[N], copy it to a temp because... */
6e94937a 442 if (ctx->null_cond.a0 == cpu_psw_n) {
aac0f603 443 ctx->null_cond.a0 = tcg_temp_new_i64();
6fd0c7bc 444 tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
129e9cc3
RH
445 }
446 /* ... we clear it before branching over the implementation,
447 so that (1) it's clear after nullifying this insn and
448 (2) if this insn nullifies the next, PSW[N] is valid. */
449 if (ctx->psw_n_nonzero) {
450 ctx->psw_n_nonzero = false;
6fd0c7bc 451 tcg_gen_movi_i64(cpu_psw_n, 0);
129e9cc3
RH
452 }
453
6fd0c7bc 454 tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
6e94937a 455 ctx->null_cond.a1, ctx->null_lab);
129e9cc3
RH
456 cond_free(&ctx->null_cond);
457 }
458}
459
460/* Save the current nullification state to PSW[N]. */
461static void nullify_save(DisasContext *ctx)
462{
463 if (ctx->null_cond.c == TCG_COND_NEVER) {
464 if (ctx->psw_n_nonzero) {
6fd0c7bc 465 tcg_gen_movi_i64(cpu_psw_n, 0);
129e9cc3
RH
466 }
467 return;
468 }
6e94937a 469 if (ctx->null_cond.a0 != cpu_psw_n) {
6fd0c7bc 470 tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
6e94937a 471 ctx->null_cond.a0, ctx->null_cond.a1);
129e9cc3
RH
472 ctx->psw_n_nonzero = true;
473 }
474 cond_free(&ctx->null_cond);
475}
476
477/* Set a PSW[N] to X. The intention is that this is used immediately
478 before a goto_tb/exit_tb, so that there is no fallthru path to other
479 code within the TB. Therefore we do not update psw_n_nonzero. */
480static void nullify_set(DisasContext *ctx, bool x)
481{
482 if (ctx->psw_n_nonzero || x) {
6fd0c7bc 483 tcg_gen_movi_i64(cpu_psw_n, x);
129e9cc3
RH
484 }
485}
486
487/* Mark the end of an instruction that may have been nullified.
40f9f908
RH
488 This is the pair to nullify_over. Always returns true so that
489 it may be tail-called from a translate function. */
31234768 490static bool nullify_end(DisasContext *ctx)
129e9cc3
RH
491{
492 TCGLabel *null_lab = ctx->null_lab;
31234768 493 DisasJumpType status = ctx->base.is_jmp;
129e9cc3 494
f49b3537
RH
495 /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
496 For UPDATED, we cannot update on the nullified path. */
497 assert(status != DISAS_IAQ_N_UPDATED);
498
129e9cc3
RH
499 if (likely(null_lab == NULL)) {
500 /* The current insn wasn't conditional or handled the condition
501 applied to it without a branch, so the (new) setting of
502 NULL_COND can be applied directly to the next insn. */
31234768 503 return true;
129e9cc3
RH
504 }
505 ctx->null_lab = NULL;
506
507 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
508 /* The next instruction will be unconditional,
509 and NULL_COND already reflects that. */
510 gen_set_label(null_lab);
511 } else {
512 /* The insn that we just executed is itself nullifying the next
513 instruction. Store the condition in the PSW[N] global.
514 We asserted PSW[N] = 0 in nullify_over, so that after the
515 label we have the proper value in place. */
516 nullify_save(ctx);
517 gen_set_label(null_lab);
518 ctx->null_cond = cond_make_n();
519 }
869051ea 520 if (status == DISAS_NORETURN) {
31234768 521 ctx->base.is_jmp = DISAS_NEXT;
129e9cc3 522 }
31234768 523 return true;
129e9cc3
RH
524}
525
c53e401e 526static uint64_t gva_offset_mask(DisasContext *ctx)
698240d1
RH
527{
528 return (ctx->tb_flags & PSW_W
529 ? MAKE_64BIT_MASK(0, 62)
530 : MAKE_64BIT_MASK(0, 32));
531}
532
6fd0c7bc
RH
533static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
534 uint64_t ival, TCGv_i64 vval)
61766fe9 535{
c53e401e 536 uint64_t mask = gva_offset_mask(ctx);
f13bf343
RH
537
538 if (ival != -1) {
6fd0c7bc 539 tcg_gen_movi_i64(dest, ival & mask);
f13bf343
RH
540 return;
541 }
542 tcg_debug_assert(vval != NULL);
543
544 /*
545 * We know that the IAOQ is already properly masked.
546 * This optimization is primarily for "iaoq_f = iaoq_b".
547 */
548 if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
6fd0c7bc 549 tcg_gen_mov_i64(dest, vval);
61766fe9 550 } else {
6fd0c7bc 551 tcg_gen_andi_i64(dest, vval, mask);
61766fe9
RH
552 }
553}
554
c53e401e 555static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
61766fe9
RH
556{
557 return ctx->iaoq_f + disp + 8;
558}
559
560static void gen_excp_1(int exception)
561{
ad75a51e 562 gen_helper_excp(tcg_env, tcg_constant_i32(exception));
61766fe9
RH
563}
564
31234768 565static void gen_excp(DisasContext *ctx, int exception)
61766fe9 566{
741322f4
RH
567 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
568 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
129e9cc3 569 nullify_save(ctx);
61766fe9 570 gen_excp_1(exception);
31234768 571 ctx->base.is_jmp = DISAS_NORETURN;
61766fe9
RH
572}
573
31234768 574static bool gen_excp_iir(DisasContext *ctx, int exc)
1a19da0d 575{
31234768 576 nullify_over(ctx);
6fd0c7bc 577 tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
ad75a51e 578 tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
31234768
RH
579 gen_excp(ctx, exc);
580 return nullify_end(ctx);
1a19da0d
RH
581}
582
31234768 583static bool gen_illegal(DisasContext *ctx)
61766fe9 584{
31234768 585 return gen_excp_iir(ctx, EXCP_ILL);
61766fe9
RH
586}
587
40f9f908
RH
588#ifdef CONFIG_USER_ONLY
589#define CHECK_MOST_PRIVILEGED(EXCP) \
590 return gen_excp_iir(ctx, EXCP)
591#else
592#define CHECK_MOST_PRIVILEGED(EXCP) \
31234768
RH
593 do { \
594 if (ctx->privilege != 0) { \
595 return gen_excp_iir(ctx, EXCP); \
596 } \
e1b5a5ed 597 } while (0)
40f9f908 598#endif
e1b5a5ed 599
c53e401e 600static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
61766fe9 601{
57f91498 602 return translator_use_goto_tb(&ctx->base, dest);
61766fe9
RH
603}
604
129e9cc3
RH
605/* If the next insn is to be nullified, and it's on the same page,
606 and we're not attempting to set a breakpoint on it, then we can
607 totally skip the nullified insn. This avoids creating and
608 executing a TB that merely branches to the next TB. */
609static bool use_nullify_skip(DisasContext *ctx)
610{
611 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
612 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
613}
614
61766fe9 615static void gen_goto_tb(DisasContext *ctx, int which,
c53e401e 616 uint64_t f, uint64_t b)
61766fe9
RH
617{
618 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
619 tcg_gen_goto_tb(which);
a0180973
RH
620 copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
621 copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
07ea28b4 622 tcg_gen_exit_tb(ctx->base.tb, which);
61766fe9 623 } else {
741322f4
RH
624 copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
625 copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
8532a14e 626 tcg_gen_lookup_and_goto_ptr();
61766fe9
RH
627 }
628}
629
b47a4a02
SS
630static bool cond_need_sv(int c)
631{
632 return c == 2 || c == 3 || c == 6;
633}
634
635static bool cond_need_cb(int c)
636{
637 return c == 4 || c == 5;
638}
639
6fd0c7bc 640/* Need extensions from TCGv_i32 to TCGv_i64. */
72ca8753
RH
641static bool cond_need_ext(DisasContext *ctx, bool d)
642{
c53e401e 643 return !(ctx->is_pa20 && d);
72ca8753
RH
644}
645
b47a4a02
SS
646/*
647 * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of
648 * the Parisc 1.1 Architecture Reference Manual for details.
649 */
b2167459 650
a751eb31 651static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc 652 TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
b2167459
RH
653{
654 DisasCond cond;
6fd0c7bc 655 TCGv_i64 tmp;
b2167459
RH
656
657 switch (cf >> 1) {
b47a4a02 658 case 0: /* Never / TR (0 / 1) */
b2167459
RH
659 cond = cond_make_f();
660 break;
661 case 1: /* = / <> (Z / !Z) */
a751eb31 662 if (cond_need_ext(ctx, d)) {
aac0f603 663 tmp = tcg_temp_new_i64();
6fd0c7bc 664 tcg_gen_ext32u_i64(tmp, res);
a751eb31
RH
665 res = tmp;
666 }
b2167459
RH
667 cond = cond_make_0(TCG_COND_EQ, res);
668 break;
b47a4a02 669 case 2: /* < / >= (N ^ V / !(N ^ V) */
aac0f603 670 tmp = tcg_temp_new_i64();
6fd0c7bc 671 tcg_gen_xor_i64(tmp, res, sv);
a751eb31 672 if (cond_need_ext(ctx, d)) {
6fd0c7bc 673 tcg_gen_ext32s_i64(tmp, tmp);
a751eb31 674 }
b47a4a02 675 cond = cond_make_0_tmp(TCG_COND_LT, tmp);
b2167459 676 break;
b47a4a02
SS
677 case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */
678 /*
679 * Simplify:
680 * (N ^ V) | Z
681 * ((res < 0) ^ (sv < 0)) | !res
682 * ((res ^ sv) < 0) | !res
683 * (~(res ^ sv) >= 0) | !res
684 * !(~(res ^ sv) >> 31) | !res
685 * !(~(res ^ sv) >> 31 & res)
686 */
aac0f603 687 tmp = tcg_temp_new_i64();
6fd0c7bc 688 tcg_gen_eqv_i64(tmp, res, sv);
a751eb31 689 if (cond_need_ext(ctx, d)) {
6fd0c7bc
RH
690 tcg_gen_sextract_i64(tmp, tmp, 31, 1);
691 tcg_gen_and_i64(tmp, tmp, res);
692 tcg_gen_ext32u_i64(tmp, tmp);
a751eb31 693 } else {
6fd0c7bc
RH
694 tcg_gen_sari_i64(tmp, tmp, 63);
695 tcg_gen_and_i64(tmp, tmp, res);
a751eb31 696 }
b47a4a02 697 cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
b2167459
RH
698 break;
699 case 4: /* NUV / UV (!C / C) */
a751eb31 700 /* Only bit 0 of cb_msb is ever set. */
b2167459
RH
701 cond = cond_make_0(TCG_COND_EQ, cb_msb);
702 break;
703 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
aac0f603 704 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
705 tcg_gen_neg_i64(tmp, cb_msb);
706 tcg_gen_and_i64(tmp, tmp, res);
a751eb31 707 if (cond_need_ext(ctx, d)) {
6fd0c7bc 708 tcg_gen_ext32u_i64(tmp, tmp);
a751eb31 709 }
b47a4a02 710 cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
b2167459
RH
711 break;
712 case 6: /* SV / NSV (V / !V) */
a751eb31 713 if (cond_need_ext(ctx, d)) {
aac0f603 714 tmp = tcg_temp_new_i64();
6fd0c7bc 715 tcg_gen_ext32s_i64(tmp, sv);
a751eb31
RH
716 sv = tmp;
717 }
b2167459
RH
718 cond = cond_make_0(TCG_COND_LT, sv);
719 break;
720 case 7: /* OD / EV */
aac0f603 721 tmp = tcg_temp_new_i64();
6fd0c7bc 722 tcg_gen_andi_i64(tmp, res, 1);
b47a4a02 723 cond = cond_make_0_tmp(TCG_COND_NE, tmp);
b2167459
RH
724 break;
725 default:
726 g_assert_not_reached();
727 }
728 if (cf & 1) {
729 cond.c = tcg_invert_cond(cond.c);
730 }
731
732 return cond;
733}
734
735/* Similar, but for the special case of subtraction without borrow, we
736 can use the inputs directly. This can allow other computation to be
737 deleted as unused. */
738
4fe9533a 739static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc
RH
740 TCGv_i64 res, TCGv_i64 in1,
741 TCGv_i64 in2, TCGv_i64 sv)
b2167459 742{
4fe9533a
RH
743 TCGCond tc;
744 bool ext_uns;
b2167459
RH
745
746 switch (cf >> 1) {
747 case 1: /* = / <> */
4fe9533a
RH
748 tc = TCG_COND_EQ;
749 ext_uns = true;
b2167459
RH
750 break;
751 case 2: /* < / >= */
4fe9533a
RH
752 tc = TCG_COND_LT;
753 ext_uns = false;
b2167459
RH
754 break;
755 case 3: /* <= / > */
4fe9533a
RH
756 tc = TCG_COND_LE;
757 ext_uns = false;
b2167459
RH
758 break;
759 case 4: /* << / >>= */
4fe9533a
RH
760 tc = TCG_COND_LTU;
761 ext_uns = true;
b2167459
RH
762 break;
763 case 5: /* <<= / >> */
4fe9533a
RH
764 tc = TCG_COND_LEU;
765 ext_uns = true;
b2167459
RH
766 break;
767 default:
a751eb31 768 return do_cond(ctx, cf, d, res, NULL, sv);
b2167459 769 }
4fe9533a 770
b2167459 771 if (cf & 1) {
4fe9533a 772 tc = tcg_invert_cond(tc);
b2167459 773 }
4fe9533a 774 if (cond_need_ext(ctx, d)) {
aac0f603
RH
775 TCGv_i64 t1 = tcg_temp_new_i64();
776 TCGv_i64 t2 = tcg_temp_new_i64();
b2167459 777
4fe9533a 778 if (ext_uns) {
6fd0c7bc
RH
779 tcg_gen_ext32u_i64(t1, in1);
780 tcg_gen_ext32u_i64(t2, in2);
4fe9533a 781 } else {
6fd0c7bc
RH
782 tcg_gen_ext32s_i64(t1, in1);
783 tcg_gen_ext32s_i64(t2, in2);
4fe9533a
RH
784 }
785 return cond_make_tmp(tc, t1, t2);
786 }
787 return cond_make(tc, in1, in2);
b2167459
RH
788}
789
df0232fe
RH
790/*
791 * Similar, but for logicals, where the carry and overflow bits are not
792 * computed, and use of them is undefined.
793 *
794 * Undefined or not, hardware does not trap. It seems reasonable to
795 * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
796 * how cases c={2,3} are treated.
797 */
b2167459 798
b5af8423 799static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc 800 TCGv_i64 res)
b2167459 801{
b5af8423
RH
802 TCGCond tc;
803 bool ext_uns;
a751eb31 804
df0232fe
RH
805 switch (cf) {
806 case 0: /* never */
807 case 9: /* undef, C */
808 case 11: /* undef, C & !Z */
809 case 12: /* undef, V */
810 return cond_make_f();
811
812 case 1: /* true */
813 case 8: /* undef, !C */
814 case 10: /* undef, !C | Z */
815 case 13: /* undef, !V */
816 return cond_make_t();
817
818 case 2: /* == */
b5af8423
RH
819 tc = TCG_COND_EQ;
820 ext_uns = true;
821 break;
df0232fe 822 case 3: /* <> */
b5af8423
RH
823 tc = TCG_COND_NE;
824 ext_uns = true;
825 break;
df0232fe 826 case 4: /* < */
b5af8423
RH
827 tc = TCG_COND_LT;
828 ext_uns = false;
829 break;
df0232fe 830 case 5: /* >= */
b5af8423
RH
831 tc = TCG_COND_GE;
832 ext_uns = false;
833 break;
df0232fe 834 case 6: /* <= */
b5af8423
RH
835 tc = TCG_COND_LE;
836 ext_uns = false;
837 break;
df0232fe 838 case 7: /* > */
b5af8423
RH
839 tc = TCG_COND_GT;
840 ext_uns = false;
841 break;
df0232fe
RH
842
843 case 14: /* OD */
844 case 15: /* EV */
a751eb31 845 return do_cond(ctx, cf, d, res, NULL, NULL);
df0232fe
RH
846
847 default:
848 g_assert_not_reached();
b2167459 849 }
b5af8423
RH
850
851 if (cond_need_ext(ctx, d)) {
aac0f603 852 TCGv_i64 tmp = tcg_temp_new_i64();
b5af8423
RH
853
854 if (ext_uns) {
6fd0c7bc 855 tcg_gen_ext32u_i64(tmp, res);
b5af8423 856 } else {
6fd0c7bc 857 tcg_gen_ext32s_i64(tmp, res);
b5af8423
RH
858 }
859 return cond_make_0_tmp(tc, tmp);
860 }
861 return cond_make_0(tc, res);
b2167459
RH
862}
863
98cd9ca7
RH
864/* Similar, but for shift/extract/deposit conditions. */
865
4fa52edf 866static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
6fd0c7bc 867 TCGv_i64 res)
98cd9ca7
RH
868{
869 unsigned c, f;
870
871 /* Convert the compressed condition codes to standard.
872 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
873 4-7 are the reverse of 0-3. */
874 c = orig & 3;
875 if (c == 3) {
876 c = 7;
877 }
878 f = (orig & 4) / 4;
879
b5af8423 880 return do_log_cond(ctx, c * 2 + f, d, res);
98cd9ca7
RH
881}
882
b2167459
RH
883/* Similar, but for unit conditions. */
884
6fd0c7bc
RH
885static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
886 TCGv_i64 in1, TCGv_i64 in2)
b2167459
RH
887{
888 DisasCond cond;
6fd0c7bc 889 TCGv_i64 tmp, cb = NULL;
c53e401e 890 uint64_t d_repl = d ? 0x0000000100000001ull : 1;
b2167459 891
b2167459
RH
892 if (cf & 8) {
893 /* Since we want to test lots of carry-out bits all at once, do not
894 * do our normal thing and compute carry-in of bit B+1 since that
895 * leaves us with carry bits spread across two words.
896 */
aac0f603
RH
897 cb = tcg_temp_new_i64();
898 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
899 tcg_gen_or_i64(cb, in1, in2);
900 tcg_gen_and_i64(tmp, in1, in2);
901 tcg_gen_andc_i64(cb, cb, res);
902 tcg_gen_or_i64(cb, cb, tmp);
b2167459
RH
903 }
904
905 switch (cf >> 1) {
906 case 0: /* never / TR */
907 case 1: /* undefined */
908 case 5: /* undefined */
909 cond = cond_make_f();
910 break;
911
912 case 2: /* SBZ / NBZ */
913 /* See hasless(v,1) from
914 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
915 */
aac0f603 916 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
917 tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
918 tcg_gen_andc_i64(tmp, tmp, res);
919 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
b2167459 920 cond = cond_make_0(TCG_COND_NE, tmp);
b2167459
RH
921 break;
922
923 case 3: /* SHZ / NHZ */
aac0f603 924 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
925 tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
926 tcg_gen_andc_i64(tmp, tmp, res);
927 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
b2167459 928 cond = cond_make_0(TCG_COND_NE, tmp);
b2167459
RH
929 break;
930
931 case 4: /* SDC / NDC */
6fd0c7bc 932 tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
b2167459
RH
933 cond = cond_make_0(TCG_COND_NE, cb);
934 break;
935
936 case 6: /* SBC / NBC */
6fd0c7bc 937 tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
b2167459
RH
938 cond = cond_make_0(TCG_COND_NE, cb);
939 break;
940
941 case 7: /* SHC / NHC */
6fd0c7bc 942 tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
b2167459
RH
943 cond = cond_make_0(TCG_COND_NE, cb);
944 break;
945
946 default:
947 g_assert_not_reached();
948 }
b2167459
RH
949 if (cf & 1) {
950 cond.c = tcg_invert_cond(cond.c);
951 }
952
953 return cond;
954}
955
6fd0c7bc
RH
956static TCGv_i64 get_carry(DisasContext *ctx, bool d,
957 TCGv_i64 cb, TCGv_i64 cb_msb)
72ca8753
RH
958{
959 if (cond_need_ext(ctx, d)) {
aac0f603 960 TCGv_i64 t = tcg_temp_new_i64();
6fd0c7bc 961 tcg_gen_extract_i64(t, cb, 32, 1);
72ca8753
RH
962 return t;
963 }
964 return cb_msb;
965}
966
6fd0c7bc 967static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
72ca8753
RH
968{
969 return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
970}
971
b2167459 972/* Compute signed overflow for addition. */
6fd0c7bc
RH
973static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
974 TCGv_i64 in1, TCGv_i64 in2)
b2167459 975{
aac0f603
RH
976 TCGv_i64 sv = tcg_temp_new_i64();
977 TCGv_i64 tmp = tcg_temp_new_i64();
b2167459 978
6fd0c7bc
RH
979 tcg_gen_xor_i64(sv, res, in1);
980 tcg_gen_xor_i64(tmp, in1, in2);
981 tcg_gen_andc_i64(sv, sv, tmp);
b2167459
RH
982
983 return sv;
984}
985
986/* Compute signed overflow for subtraction. */
6fd0c7bc
RH
987static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
988 TCGv_i64 in1, TCGv_i64 in2)
b2167459 989{
aac0f603
RH
990 TCGv_i64 sv = tcg_temp_new_i64();
991 TCGv_i64 tmp = tcg_temp_new_i64();
b2167459 992
6fd0c7bc
RH
993 tcg_gen_xor_i64(sv, res, in1);
994 tcg_gen_xor_i64(tmp, in1, in2);
995 tcg_gen_and_i64(sv, sv, tmp);
b2167459
RH
996
997 return sv;
998}
999
6fd0c7bc
RH
1000static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1001 TCGv_i64 in2, unsigned shift, bool is_l,
faf97ba1 1002 bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
b2167459 1003{
6fd0c7bc 1004 TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
b2167459
RH
1005 unsigned c = cf >> 1;
1006 DisasCond cond;
1007
aac0f603 1008 dest = tcg_temp_new_i64();
f764718d
RH
1009 cb = NULL;
1010 cb_msb = NULL;
bdcccc17 1011 cb_cond = NULL;
b2167459
RH
1012
1013 if (shift) {
aac0f603 1014 tmp = tcg_temp_new_i64();
6fd0c7bc 1015 tcg_gen_shli_i64(tmp, in1, shift);
b2167459
RH
1016 in1 = tmp;
1017 }
1018
b47a4a02 1019 if (!is_l || cond_need_cb(c)) {
aac0f603
RH
1020 cb_msb = tcg_temp_new_i64();
1021 cb = tcg_temp_new_i64();
bdcccc17 1022
a4db4a78 1023 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
b2167459 1024 if (is_c) {
6fd0c7bc 1025 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
a4db4a78 1026 get_psw_carry(ctx, d), ctx->zero);
b2167459 1027 }
6fd0c7bc
RH
1028 tcg_gen_xor_i64(cb, in1, in2);
1029 tcg_gen_xor_i64(cb, cb, dest);
bdcccc17
RH
1030 if (cond_need_cb(c)) {
1031 cb_cond = get_carry(ctx, d, cb, cb_msb);
b2167459
RH
1032 }
1033 } else {
6fd0c7bc 1034 tcg_gen_add_i64(dest, in1, in2);
b2167459 1035 if (is_c) {
6fd0c7bc 1036 tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
b2167459
RH
1037 }
1038 }
1039
1040 /* Compute signed overflow if required. */
f764718d 1041 sv = NULL;
b47a4a02 1042 if (is_tsv || cond_need_sv(c)) {
b2167459
RH
1043 sv = do_add_sv(ctx, dest, in1, in2);
1044 if (is_tsv) {
1045 /* ??? Need to include overflow from shift. */
ad75a51e 1046 gen_helper_tsv(tcg_env, sv);
b2167459
RH
1047 }
1048 }
1049
1050 /* Emit any conditional trap before any writeback. */
a751eb31 1051 cond = do_cond(ctx, cf, d, dest, cb_cond, sv);
b2167459 1052 if (is_tc) {
aac0f603 1053 tmp = tcg_temp_new_i64();
6fd0c7bc 1054 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
ad75a51e 1055 gen_helper_tcond(tcg_env, tmp);
b2167459
RH
1056 }
1057
1058 /* Write back the result. */
1059 if (!is_l) {
1060 save_or_nullify(ctx, cpu_psw_cb, cb);
1061 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1062 }
1063 save_gpr(ctx, rt, dest);
b2167459
RH
1064
1065 /* Install the new nullification. */
1066 cond_free(&ctx->null_cond);
1067 ctx->null_cond = cond;
b2167459
RH
1068}
1069
faf97ba1 1070static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
0c982a28
RH
1071 bool is_l, bool is_tsv, bool is_tc, bool is_c)
1072{
6fd0c7bc 1073 TCGv_i64 tcg_r1, tcg_r2;
0c982a28
RH
1074
1075 if (a->cf) {
1076 nullify_over(ctx);
1077 }
1078 tcg_r1 = load_gpr(ctx, a->r1);
1079 tcg_r2 = load_gpr(ctx, a->r2);
faf97ba1
RH
1080 do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1081 is_tsv, is_tc, is_c, a->cf, a->d);
0c982a28
RH
1082 return nullify_end(ctx);
1083}
1084
0588e061
RH
1085static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
1086 bool is_tsv, bool is_tc)
1087{
6fd0c7bc 1088 TCGv_i64 tcg_im, tcg_r2;
0588e061
RH
1089
1090 if (a->cf) {
1091 nullify_over(ctx);
1092 }
6fd0c7bc 1093 tcg_im = tcg_constant_i64(a->i);
0588e061 1094 tcg_r2 = load_gpr(ctx, a->r);
faf97ba1
RH
1095 /* All ADDI conditions are 32-bit. */
1096 do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
0588e061
RH
1097 return nullify_end(ctx);
1098}
1099
6fd0c7bc
RH
1100static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1101 TCGv_i64 in2, bool is_tsv, bool is_b,
63c427c6 1102 bool is_tc, unsigned cf, bool d)
b2167459 1103{
a4db4a78 1104 TCGv_i64 dest, sv, cb, cb_msb, tmp;
b2167459
RH
1105 unsigned c = cf >> 1;
1106 DisasCond cond;
1107
aac0f603
RH
1108 dest = tcg_temp_new_i64();
1109 cb = tcg_temp_new_i64();
1110 cb_msb = tcg_temp_new_i64();
b2167459 1111
b2167459
RH
1112 if (is_b) {
1113 /* DEST,C = IN1 + ~IN2 + C. */
6fd0c7bc 1114 tcg_gen_not_i64(cb, in2);
a4db4a78
RH
1115 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1116 get_psw_carry(ctx, d), ctx->zero);
1117 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
6fd0c7bc
RH
1118 tcg_gen_xor_i64(cb, cb, in1);
1119 tcg_gen_xor_i64(cb, cb, dest);
b2167459 1120 } else {
bdcccc17
RH
1121 /*
1122 * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
1123 * operations by seeding the high word with 1 and subtracting.
1124 */
6fd0c7bc 1125 TCGv_i64 one = tcg_constant_i64(1);
a4db4a78 1126 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
6fd0c7bc
RH
1127 tcg_gen_eqv_i64(cb, in1, in2);
1128 tcg_gen_xor_i64(cb, cb, dest);
b2167459 1129 }
b2167459
RH
1130
1131 /* Compute signed overflow if required. */
f764718d 1132 sv = NULL;
b47a4a02 1133 if (is_tsv || cond_need_sv(c)) {
b2167459
RH
1134 sv = do_sub_sv(ctx, dest, in1, in2);
1135 if (is_tsv) {
ad75a51e 1136 gen_helper_tsv(tcg_env, sv);
b2167459
RH
1137 }
1138 }
1139
1140 /* Compute the condition. We cannot use the special case for borrow. */
1141 if (!is_b) {
4fe9533a 1142 cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
b2167459 1143 } else {
a751eb31 1144 cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
b2167459
RH
1145 }
1146
1147 /* Emit any conditional trap before any writeback. */
1148 if (is_tc) {
aac0f603 1149 tmp = tcg_temp_new_i64();
6fd0c7bc 1150 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
ad75a51e 1151 gen_helper_tcond(tcg_env, tmp);
b2167459
RH
1152 }
1153
1154 /* Write back the result. */
1155 save_or_nullify(ctx, cpu_psw_cb, cb);
1156 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1157 save_gpr(ctx, rt, dest);
b2167459
RH
1158
1159 /* Install the new nullification. */
1160 cond_free(&ctx->null_cond);
1161 ctx->null_cond = cond;
b2167459
RH
1162}
1163
63c427c6 1164static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
0c982a28
RH
1165 bool is_tsv, bool is_b, bool is_tc)
1166{
6fd0c7bc 1167 TCGv_i64 tcg_r1, tcg_r2;
0c982a28
RH
1168
1169 if (a->cf) {
1170 nullify_over(ctx);
1171 }
1172 tcg_r1 = load_gpr(ctx, a->r1);
1173 tcg_r2 = load_gpr(ctx, a->r2);
63c427c6 1174 do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
0c982a28
RH
1175 return nullify_end(ctx);
1176}
1177
0588e061
RH
1178static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
1179{
6fd0c7bc 1180 TCGv_i64 tcg_im, tcg_r2;
0588e061
RH
1181
1182 if (a->cf) {
1183 nullify_over(ctx);
1184 }
6fd0c7bc 1185 tcg_im = tcg_constant_i64(a->i);
0588e061 1186 tcg_r2 = load_gpr(ctx, a->r);
63c427c6
RH
1187 /* All SUBI conditions are 32-bit. */
1188 do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
0588e061
RH
1189 return nullify_end(ctx);
1190}
1191
6fd0c7bc
RH
1192static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1193 TCGv_i64 in2, unsigned cf, bool d)
b2167459 1194{
6fd0c7bc 1195 TCGv_i64 dest, sv;
b2167459
RH
1196 DisasCond cond;
1197
aac0f603 1198 dest = tcg_temp_new_i64();
6fd0c7bc 1199 tcg_gen_sub_i64(dest, in1, in2);
b2167459
RH
1200
1201 /* Compute signed overflow if required. */
f764718d 1202 sv = NULL;
b47a4a02 1203 if (cond_need_sv(cf >> 1)) {
b2167459
RH
1204 sv = do_sub_sv(ctx, dest, in1, in2);
1205 }
1206
1207 /* Form the condition for the compare. */
4fe9533a 1208 cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
b2167459
RH
1209
1210 /* Clear. */
6fd0c7bc 1211 tcg_gen_movi_i64(dest, 0);
b2167459 1212 save_gpr(ctx, rt, dest);
b2167459
RH
1213
1214 /* Install the new nullification. */
1215 cond_free(&ctx->null_cond);
1216 ctx->null_cond = cond;
b2167459
RH
1217}
1218
6fd0c7bc
RH
1219static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1220 TCGv_i64 in2, unsigned cf, bool d,
1221 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
b2167459 1222{
6fd0c7bc 1223 TCGv_i64 dest = dest_gpr(ctx, rt);
b2167459
RH
1224
1225 /* Perform the operation, and writeback. */
1226 fn(dest, in1, in2);
1227 save_gpr(ctx, rt, dest);
1228
1229 /* Install the new nullification. */
1230 cond_free(&ctx->null_cond);
1231 if (cf) {
b5af8423 1232 ctx->null_cond = do_log_cond(ctx, cf, d, dest);
b2167459 1233 }
b2167459
RH
1234}
1235
fa8e3bed 1236static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
6fd0c7bc 1237 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
0c982a28 1238{
6fd0c7bc 1239 TCGv_i64 tcg_r1, tcg_r2;
0c982a28
RH
1240
1241 if (a->cf) {
1242 nullify_over(ctx);
1243 }
1244 tcg_r1 = load_gpr(ctx, a->r1);
1245 tcg_r2 = load_gpr(ctx, a->r2);
fa8e3bed 1246 do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
0c982a28
RH
1247 return nullify_end(ctx);
1248}
1249
6fd0c7bc
RH
1250static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1251 TCGv_i64 in2, unsigned cf, bool d, bool is_tc,
1252 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
b2167459 1253{
6fd0c7bc 1254 TCGv_i64 dest;
b2167459
RH
1255 DisasCond cond;
1256
1257 if (cf == 0) {
1258 dest = dest_gpr(ctx, rt);
1259 fn(dest, in1, in2);
1260 save_gpr(ctx, rt, dest);
1261 cond_free(&ctx->null_cond);
1262 } else {
aac0f603 1263 dest = tcg_temp_new_i64();
b2167459
RH
1264 fn(dest, in1, in2);
1265
59963d8f 1266 cond = do_unit_cond(cf, d, dest, in1, in2);
b2167459
RH
1267
1268 if (is_tc) {
aac0f603 1269 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc 1270 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1);
ad75a51e 1271 gen_helper_tcond(tcg_env, tmp);
b2167459
RH
1272 }
1273 save_gpr(ctx, rt, dest);
1274
1275 cond_free(&ctx->null_cond);
1276 ctx->null_cond = cond;
1277 }
b2167459
RH
1278}
1279
86f8d05f 1280#ifndef CONFIG_USER_ONLY
8d6ae7fb
RH
1281/* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
1282 from the top 2 bits of the base register. There are a few system
1283 instructions that have a 3-bit space specifier, for which SR0 is
1284 not special. To handle this, pass ~SP. */
6fd0c7bc 1285static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
86f8d05f
RH
1286{
1287 TCGv_ptr ptr;
6fd0c7bc 1288 TCGv_i64 tmp;
86f8d05f
RH
1289 TCGv_i64 spc;
1290
1291 if (sp != 0) {
8d6ae7fb
RH
1292 if (sp < 0) {
1293 sp = ~sp;
1294 }
6fd0c7bc 1295 spc = tcg_temp_new_i64();
8d6ae7fb
RH
1296 load_spr(ctx, spc, sp);
1297 return spc;
86f8d05f 1298 }
494737b7
RH
1299 if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1300 return cpu_srH;
1301 }
86f8d05f
RH
1302
1303 ptr = tcg_temp_new_ptr();
aac0f603 1304 tmp = tcg_temp_new_i64();
6fd0c7bc 1305 spc = tcg_temp_new_i64();
86f8d05f 1306
698240d1 1307 /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
6fd0c7bc
RH
1308 tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
1309 tcg_gen_andi_i64(tmp, tmp, 030);
1310 tcg_gen_trunc_i64_ptr(ptr, tmp);
86f8d05f 1311
ad75a51e 1312 tcg_gen_add_ptr(ptr, ptr, tcg_env);
86f8d05f 1313 tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
86f8d05f
RH
1314
1315 return spc;
1316}
1317#endif
1318
6fd0c7bc 1319static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
c53e401e 1320 unsigned rb, unsigned rx, int scale, int64_t disp,
86f8d05f
RH
1321 unsigned sp, int modify, bool is_phys)
1322{
6fd0c7bc
RH
1323 TCGv_i64 base = load_gpr(ctx, rb);
1324 TCGv_i64 ofs;
1325 TCGv_i64 addr;
86f8d05f
RH
1326
1327 /* Note that RX is mutually exclusive with DISP. */
1328 if (rx) {
aac0f603 1329 ofs = tcg_temp_new_i64();
6fd0c7bc
RH
1330 tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
1331 tcg_gen_add_i64(ofs, ofs, base);
86f8d05f 1332 } else if (disp || modify) {
aac0f603 1333 ofs = tcg_temp_new_i64();
6fd0c7bc 1334 tcg_gen_addi_i64(ofs, base, disp);
86f8d05f
RH
1335 } else {
1336 ofs = base;
1337 }
1338
1339 *pofs = ofs;
6fd0c7bc 1340 *pgva = addr = tcg_temp_new_i64();
d265360f 1341 tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
698240d1 1342#ifndef CONFIG_USER_ONLY
86f8d05f 1343 if (!is_phys) {
d265360f 1344 tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
86f8d05f 1345 }
86f8d05f
RH
1346#endif
1347}
1348
96d6407f
RH
1349/* Emit a memory load. The modify parameter should be
1350 * < 0 for pre-modify,
1351 * > 0 for post-modify,
1352 * = 0 for no base register update.
1353 */
1354static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
c53e401e 1355 unsigned rx, int scale, int64_t disp,
14776ab5 1356 unsigned sp, int modify, MemOp mop)
96d6407f 1357{
6fd0c7bc
RH
1358 TCGv_i64 ofs;
1359 TCGv_i64 addr;
96d6407f
RH
1360
1361 /* Caller uses nullify_over/nullify_end. */
1362 assert(ctx->null_cond.c == TCG_COND_NEVER);
1363
86f8d05f
RH
1364 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1365 ctx->mmu_idx == MMU_PHYS_IDX);
c1f55d97 1366 tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
86f8d05f
RH
1367 if (modify) {
1368 save_gpr(ctx, rb, ofs);
96d6407f 1369 }
96d6407f
RH
1370}
1371
1372static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
c53e401e 1373 unsigned rx, int scale, int64_t disp,
14776ab5 1374 unsigned sp, int modify, MemOp mop)
96d6407f 1375{
6fd0c7bc
RH
1376 TCGv_i64 ofs;
1377 TCGv_i64 addr;
96d6407f
RH
1378
1379 /* Caller uses nullify_over/nullify_end. */
1380 assert(ctx->null_cond.c == TCG_COND_NEVER);
1381
86f8d05f
RH
1382 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1383 ctx->mmu_idx == MMU_PHYS_IDX);
217d1a5e 1384 tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
86f8d05f
RH
1385 if (modify) {
1386 save_gpr(ctx, rb, ofs);
96d6407f 1387 }
96d6407f
RH
1388}
1389
1390static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
c53e401e 1391 unsigned rx, int scale, int64_t disp,
14776ab5 1392 unsigned sp, int modify, MemOp mop)
96d6407f 1393{
6fd0c7bc
RH
1394 TCGv_i64 ofs;
1395 TCGv_i64 addr;
96d6407f
RH
1396
1397 /* Caller uses nullify_over/nullify_end. */
1398 assert(ctx->null_cond.c == TCG_COND_NEVER);
1399
86f8d05f
RH
1400 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1401 ctx->mmu_idx == MMU_PHYS_IDX);
217d1a5e 1402 tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
86f8d05f
RH
1403 if (modify) {
1404 save_gpr(ctx, rb, ofs);
96d6407f 1405 }
96d6407f
RH
1406}
1407
1408static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
c53e401e 1409 unsigned rx, int scale, int64_t disp,
14776ab5 1410 unsigned sp, int modify, MemOp mop)
96d6407f 1411{
6fd0c7bc
RH
1412 TCGv_i64 ofs;
1413 TCGv_i64 addr;
96d6407f
RH
1414
1415 /* Caller uses nullify_over/nullify_end. */
1416 assert(ctx->null_cond.c == TCG_COND_NEVER);
1417
86f8d05f
RH
1418 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1419 ctx->mmu_idx == MMU_PHYS_IDX);
217d1a5e 1420 tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
86f8d05f
RH
1421 if (modify) {
1422 save_gpr(ctx, rb, ofs);
96d6407f 1423 }
96d6407f
RH
1424}
1425
1cd012a5 1426static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1427 unsigned rx, int scale, int64_t disp,
14776ab5 1428 unsigned sp, int modify, MemOp mop)
96d6407f 1429{
6fd0c7bc 1430 TCGv_i64 dest;
96d6407f
RH
1431
1432 nullify_over(ctx);
1433
1434 if (modify == 0) {
1435 /* No base register update. */
1436 dest = dest_gpr(ctx, rt);
1437 } else {
1438 /* Make sure if RT == RB, we see the result of the load. */
aac0f603 1439 dest = tcg_temp_new_i64();
96d6407f 1440 }
6fd0c7bc 1441 do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
96d6407f
RH
1442 save_gpr(ctx, rt, dest);
1443
1cd012a5 1444 return nullify_end(ctx);
96d6407f
RH
1445}
1446
740038d7 1447static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1448 unsigned rx, int scale, int64_t disp,
31234768 1449 unsigned sp, int modify)
96d6407f
RH
1450{
1451 TCGv_i32 tmp;
1452
1453 nullify_over(ctx);
1454
1455 tmp = tcg_temp_new_i32();
86f8d05f 1456 do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
96d6407f 1457 save_frw_i32(rt, tmp);
96d6407f
RH
1458
1459 if (rt == 0) {
ad75a51e 1460 gen_helper_loaded_fr0(tcg_env);
96d6407f
RH
1461 }
1462
740038d7
RH
1463 return nullify_end(ctx);
1464}
1465
1466static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1467{
1468 return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1469 a->disp, a->sp, a->m);
96d6407f
RH
1470}
1471
740038d7 1472static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1473 unsigned rx, int scale, int64_t disp,
31234768 1474 unsigned sp, int modify)
96d6407f
RH
1475{
1476 TCGv_i64 tmp;
1477
1478 nullify_over(ctx);
1479
1480 tmp = tcg_temp_new_i64();
fc313c64 1481 do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
96d6407f 1482 save_frd(rt, tmp);
96d6407f
RH
1483
1484 if (rt == 0) {
ad75a51e 1485 gen_helper_loaded_fr0(tcg_env);
96d6407f
RH
1486 }
1487
740038d7
RH
1488 return nullify_end(ctx);
1489}
1490
1491static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1492{
1493 return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1494 a->disp, a->sp, a->m);
96d6407f
RH
1495}
1496
1cd012a5 1497static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1498 int64_t disp, unsigned sp,
14776ab5 1499 int modify, MemOp mop)
96d6407f
RH
1500{
1501 nullify_over(ctx);
6fd0c7bc 1502 do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
1cd012a5 1503 return nullify_end(ctx);
96d6407f
RH
1504}
1505
740038d7 1506static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1507 unsigned rx, int scale, int64_t disp,
31234768 1508 unsigned sp, int modify)
96d6407f
RH
1509{
1510 TCGv_i32 tmp;
1511
1512 nullify_over(ctx);
1513
1514 tmp = load_frw_i32(rt);
86f8d05f 1515 do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
96d6407f 1516
740038d7
RH
1517 return nullify_end(ctx);
1518}
1519
1520static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1521{
1522 return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1523 a->disp, a->sp, a->m);
96d6407f
RH
1524}
1525
740038d7 1526static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
c53e401e 1527 unsigned rx, int scale, int64_t disp,
31234768 1528 unsigned sp, int modify)
96d6407f
RH
1529{
1530 TCGv_i64 tmp;
1531
1532 nullify_over(ctx);
1533
1534 tmp = load_frd(rt);
fc313c64 1535 do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
96d6407f 1536
740038d7
RH
1537 return nullify_end(ctx);
1538}
1539
1540static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1541{
1542 return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1543 a->disp, a->sp, a->m);
96d6407f
RH
1544}
1545
1ca74648 1546static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
31234768 1547 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
ebe9383c
RH
1548{
1549 TCGv_i32 tmp;
1550
1551 nullify_over(ctx);
1552 tmp = load_frw0_i32(ra);
1553
ad75a51e 1554 func(tmp, tcg_env, tmp);
ebe9383c
RH
1555
1556 save_frw_i32(rt, tmp);
1ca74648 1557 return nullify_end(ctx);
ebe9383c
RH
1558}
1559
1ca74648 1560static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
31234768 1561 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
ebe9383c
RH
1562{
1563 TCGv_i32 dst;
1564 TCGv_i64 src;
1565
1566 nullify_over(ctx);
1567 src = load_frd(ra);
1568 dst = tcg_temp_new_i32();
1569
ad75a51e 1570 func(dst, tcg_env, src);
ebe9383c 1571
ebe9383c 1572 save_frw_i32(rt, dst);
1ca74648 1573 return nullify_end(ctx);
ebe9383c
RH
1574}
1575
1ca74648 1576static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
31234768 1577 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
ebe9383c
RH
1578{
1579 TCGv_i64 tmp;
1580
1581 nullify_over(ctx);
1582 tmp = load_frd0(ra);
1583
ad75a51e 1584 func(tmp, tcg_env, tmp);
ebe9383c
RH
1585
1586 save_frd(rt, tmp);
1ca74648 1587 return nullify_end(ctx);
ebe9383c
RH
1588}
1589
1ca74648 1590static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
31234768 1591 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
ebe9383c
RH
1592{
1593 TCGv_i32 src;
1594 TCGv_i64 dst;
1595
1596 nullify_over(ctx);
1597 src = load_frw0_i32(ra);
1598 dst = tcg_temp_new_i64();
1599
ad75a51e 1600 func(dst, tcg_env, src);
ebe9383c 1601
ebe9383c 1602 save_frd(rt, dst);
1ca74648 1603 return nullify_end(ctx);
ebe9383c
RH
1604}
1605
1ca74648 1606static bool do_fop_weww(DisasContext *ctx, unsigned rt,
31234768
RH
1607 unsigned ra, unsigned rb,
1608 void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
ebe9383c
RH
1609{
1610 TCGv_i32 a, b;
1611
1612 nullify_over(ctx);
1613 a = load_frw0_i32(ra);
1614 b = load_frw0_i32(rb);
1615
ad75a51e 1616 func(a, tcg_env, a, b);
ebe9383c 1617
ebe9383c 1618 save_frw_i32(rt, a);
1ca74648 1619 return nullify_end(ctx);
ebe9383c
RH
1620}
1621
1ca74648 1622static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
31234768
RH
1623 unsigned ra, unsigned rb,
1624 void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
ebe9383c
RH
1625{
1626 TCGv_i64 a, b;
1627
1628 nullify_over(ctx);
1629 a = load_frd0(ra);
1630 b = load_frd0(rb);
1631
ad75a51e 1632 func(a, tcg_env, a, b);
ebe9383c 1633
ebe9383c 1634 save_frd(rt, a);
1ca74648 1635 return nullify_end(ctx);
ebe9383c
RH
1636}
1637
98cd9ca7
RH
1638/* Emit an unconditional branch to a direct target, which may or may not
1639 have already had nullification handled. */
c53e401e 1640static bool do_dbranch(DisasContext *ctx, uint64_t dest,
31234768 1641 unsigned link, bool is_n)
98cd9ca7
RH
1642{
1643 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1644 if (link != 0) {
741322f4 1645 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
98cd9ca7
RH
1646 }
1647 ctx->iaoq_n = dest;
1648 if (is_n) {
1649 ctx->null_cond.c = TCG_COND_ALWAYS;
1650 }
98cd9ca7
RH
1651 } else {
1652 nullify_over(ctx);
1653
1654 if (link != 0) {
741322f4 1655 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
98cd9ca7
RH
1656 }
1657
1658 if (is_n && use_nullify_skip(ctx)) {
1659 nullify_set(ctx, 0);
1660 gen_goto_tb(ctx, 0, dest, dest + 4);
1661 } else {
1662 nullify_set(ctx, is_n);
1663 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1664 }
1665
31234768 1666 nullify_end(ctx);
98cd9ca7
RH
1667
1668 nullify_set(ctx, 0);
1669 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
31234768 1670 ctx->base.is_jmp = DISAS_NORETURN;
98cd9ca7 1671 }
01afb7be 1672 return true;
98cd9ca7
RH
1673}
1674
1675/* Emit a conditional branch to a direct target. If the branch itself
1676 is nullified, we should have already used nullify_over. */
c53e401e 1677static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
31234768 1678 DisasCond *cond)
98cd9ca7 1679{
c53e401e 1680 uint64_t dest = iaoq_dest(ctx, disp);
98cd9ca7
RH
1681 TCGLabel *taken = NULL;
1682 TCGCond c = cond->c;
98cd9ca7
RH
1683 bool n;
1684
1685 assert(ctx->null_cond.c == TCG_COND_NEVER);
1686
1687 /* Handle TRUE and NEVER as direct branches. */
1688 if (c == TCG_COND_ALWAYS) {
01afb7be 1689 return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
98cd9ca7
RH
1690 }
1691 if (c == TCG_COND_NEVER) {
01afb7be 1692 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
98cd9ca7
RH
1693 }
1694
1695 taken = gen_new_label();
6fd0c7bc 1696 tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
98cd9ca7
RH
1697 cond_free(cond);
1698
1699 /* Not taken: Condition not satisfied; nullify on backward branches. */
1700 n = is_n && disp < 0;
1701 if (n && use_nullify_skip(ctx)) {
1702 nullify_set(ctx, 0);
a881c8e7 1703 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
98cd9ca7
RH
1704 } else {
1705 if (!n && ctx->null_lab) {
1706 gen_set_label(ctx->null_lab);
1707 ctx->null_lab = NULL;
1708 }
1709 nullify_set(ctx, n);
c301f34e
RH
1710 if (ctx->iaoq_n == -1) {
1711 /* The temporary iaoq_n_var died at the branch above.
1712 Regenerate it here instead of saving it. */
6fd0c7bc 1713 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
c301f34e 1714 }
a881c8e7 1715 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
98cd9ca7
RH
1716 }
1717
1718 gen_set_label(taken);
1719
1720 /* Taken: Condition satisfied; nullify on forward branches. */
1721 n = is_n && disp >= 0;
1722 if (n && use_nullify_skip(ctx)) {
1723 nullify_set(ctx, 0);
a881c8e7 1724 gen_goto_tb(ctx, 1, dest, dest + 4);
98cd9ca7
RH
1725 } else {
1726 nullify_set(ctx, n);
a881c8e7 1727 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
98cd9ca7
RH
1728 }
1729
1730 /* Not taken: the branch itself was nullified. */
1731 if (ctx->null_lab) {
1732 gen_set_label(ctx->null_lab);
1733 ctx->null_lab = NULL;
31234768 1734 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
98cd9ca7 1735 } else {
31234768 1736 ctx->base.is_jmp = DISAS_NORETURN;
98cd9ca7 1737 }
01afb7be 1738 return true;
98cd9ca7
RH
1739}
1740
1741/* Emit an unconditional branch to an indirect target. This handles
1742 nullification of the branch itself. */
6fd0c7bc 1743static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest,
31234768 1744 unsigned link, bool is_n)
98cd9ca7 1745{
6fd0c7bc 1746 TCGv_i64 a0, a1, next, tmp;
98cd9ca7
RH
1747 TCGCond c;
1748
1749 assert(ctx->null_lab == NULL);
1750
1751 if (ctx->null_cond.c == TCG_COND_NEVER) {
1752 if (link != 0) {
741322f4 1753 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
98cd9ca7 1754 }
aac0f603 1755 next = tcg_temp_new_i64();
6fd0c7bc 1756 tcg_gen_mov_i64(next, dest);
98cd9ca7 1757 if (is_n) {
c301f34e 1758 if (use_nullify_skip(ctx)) {
a0180973 1759 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next);
6fd0c7bc 1760 tcg_gen_addi_i64(next, next, 4);
a0180973 1761 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
c301f34e 1762 nullify_set(ctx, 0);
31234768 1763 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
01afb7be 1764 return true;
c301f34e 1765 }
98cd9ca7
RH
1766 ctx->null_cond.c = TCG_COND_ALWAYS;
1767 }
c301f34e
RH
1768 ctx->iaoq_n = -1;
1769 ctx->iaoq_n_var = next;
98cd9ca7
RH
1770 } else if (is_n && use_nullify_skip(ctx)) {
1771 /* The (conditional) branch, B, nullifies the next insn, N,
1772 and we're allowed to skip execution N (no single-step or
4137cb83 1773 tracepoint in effect). Since the goto_ptr that we must use
98cd9ca7
RH
1774 for the indirect branch consumes no special resources, we
1775 can (conditionally) skip B and continue execution. */
1776 /* The use_nullify_skip test implies we have a known control path. */
1777 tcg_debug_assert(ctx->iaoq_b != -1);
1778 tcg_debug_assert(ctx->iaoq_n != -1);
1779
1780 /* We do have to handle the non-local temporary, DEST, before
1781 branching. Since IOAQ_F is not really live at this point, we
1782 can simply store DEST optimistically. Similarly with IAOQ_B. */
a0180973 1783 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest);
aac0f603 1784 next = tcg_temp_new_i64();
6fd0c7bc 1785 tcg_gen_addi_i64(next, dest, 4);
a0180973 1786 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next);
98cd9ca7
RH
1787
1788 nullify_over(ctx);
1789 if (link != 0) {
9a91dd84 1790 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
98cd9ca7 1791 }
7f11636d 1792 tcg_gen_lookup_and_goto_ptr();
01afb7be 1793 return nullify_end(ctx);
98cd9ca7 1794 } else {
98cd9ca7
RH
1795 c = ctx->null_cond.c;
1796 a0 = ctx->null_cond.a0;
1797 a1 = ctx->null_cond.a1;
1798
aac0f603
RH
1799 tmp = tcg_temp_new_i64();
1800 next = tcg_temp_new_i64();
98cd9ca7 1801
741322f4 1802 copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var);
6fd0c7bc 1803 tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest);
98cd9ca7
RH
1804 ctx->iaoq_n = -1;
1805 ctx->iaoq_n_var = next;
1806
1807 if (link != 0) {
6fd0c7bc 1808 tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
98cd9ca7
RH
1809 }
1810
1811 if (is_n) {
1812 /* The branch nullifies the next insn, which means the state of N
1813 after the branch is the inverse of the state of N that applied
1814 to the branch. */
6fd0c7bc 1815 tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1);
98cd9ca7
RH
1816 cond_free(&ctx->null_cond);
1817 ctx->null_cond = cond_make_n();
1818 ctx->psw_n_nonzero = true;
1819 } else {
1820 cond_free(&ctx->null_cond);
1821 }
1822 }
01afb7be 1823 return true;
98cd9ca7
RH
1824}
1825
660eefe1
RH
1826/* Implement
1827 * if (IAOQ_Front{30..31} < GR[b]{30..31})
1828 * IAOQ_Next{30..31} ← GR[b]{30..31};
1829 * else
1830 * IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1831 * which keeps the privilege level from being increased.
1832 */
6fd0c7bc 1833static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
660eefe1 1834{
6fd0c7bc 1835 TCGv_i64 dest;
660eefe1
RH
1836 switch (ctx->privilege) {
1837 case 0:
1838 /* Privilege 0 is maximum and is allowed to decrease. */
1839 return offset;
1840 case 3:
993119fe 1841 /* Privilege 3 is minimum and is never allowed to increase. */
aac0f603 1842 dest = tcg_temp_new_i64();
6fd0c7bc 1843 tcg_gen_ori_i64(dest, offset, 3);
660eefe1
RH
1844 break;
1845 default:
aac0f603 1846 dest = tcg_temp_new_i64();
6fd0c7bc
RH
1847 tcg_gen_andi_i64(dest, offset, -4);
1848 tcg_gen_ori_i64(dest, dest, ctx->privilege);
1849 tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset);
660eefe1
RH
1850 break;
1851 }
1852 return dest;
660eefe1
RH
1853}
1854
ba1d0b44 1855#ifdef CONFIG_USER_ONLY
7ad439df
RH
1856/* On Linux, page zero is normally marked execute only + gateway.
1857 Therefore normal read or write is supposed to fail, but specific
1858 offsets have kernel code mapped to raise permissions to implement
1859 system calls. Handling this via an explicit check here, rather
1860 in than the "be disp(sr2,r0)" instruction that probably sent us
1861 here, is the easiest way to handle the branch delay slot on the
1862 aforementioned BE. */
31234768 1863static void do_page_zero(DisasContext *ctx)
7ad439df 1864{
6fd0c7bc 1865 TCGv_i64 tmp;
a0180973 1866
7ad439df
RH
1867 /* If by some means we get here with PSW[N]=1, that implies that
1868 the B,GATE instruction would be skipped, and we'd fault on the
8b81968c 1869 next insn within the privileged page. */
7ad439df
RH
1870 switch (ctx->null_cond.c) {
1871 case TCG_COND_NEVER:
1872 break;
1873 case TCG_COND_ALWAYS:
6fd0c7bc 1874 tcg_gen_movi_i64(cpu_psw_n, 0);
7ad439df
RH
1875 goto do_sigill;
1876 default:
1877 /* Since this is always the first (and only) insn within the
1878 TB, we should know the state of PSW[N] from TB->FLAGS. */
1879 g_assert_not_reached();
1880 }
1881
1882 /* Check that we didn't arrive here via some means that allowed
1883 non-sequential instruction execution. Normally the PSW[B] bit
1884 detects this by disallowing the B,GATE instruction to execute
1885 under such conditions. */
1886 if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1887 goto do_sigill;
1888 }
1889
ebd0e151 1890 switch (ctx->iaoq_f & -4) {
7ad439df 1891 case 0x00: /* Null pointer call */
2986721d 1892 gen_excp_1(EXCP_IMP);
31234768
RH
1893 ctx->base.is_jmp = DISAS_NORETURN;
1894 break;
7ad439df
RH
1895
1896 case 0xb0: /* LWS */
1897 gen_excp_1(EXCP_SYSCALL_LWS);
31234768
RH
1898 ctx->base.is_jmp = DISAS_NORETURN;
1899 break;
7ad439df
RH
1900
1901 case 0xe0: /* SET_THREAD_POINTER */
6fd0c7bc 1902 tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27]));
aac0f603 1903 tmp = tcg_temp_new_i64();
6fd0c7bc 1904 tcg_gen_ori_i64(tmp, cpu_gr[31], 3);
a0180973 1905 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
6fd0c7bc 1906 tcg_gen_addi_i64(tmp, tmp, 4);
a0180973 1907 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
31234768
RH
1908 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
1909 break;
7ad439df
RH
1910
1911 case 0x100: /* SYSCALL */
1912 gen_excp_1(EXCP_SYSCALL);
31234768
RH
1913 ctx->base.is_jmp = DISAS_NORETURN;
1914 break;
7ad439df
RH
1915
1916 default:
1917 do_sigill:
2986721d 1918 gen_excp_1(EXCP_ILL);
31234768
RH
1919 ctx->base.is_jmp = DISAS_NORETURN;
1920 break;
7ad439df
RH
1921 }
1922}
ba1d0b44 1923#endif
7ad439df 1924
deee69a1 1925static bool trans_nop(DisasContext *ctx, arg_nop *a)
b2167459
RH
1926{
1927 cond_free(&ctx->null_cond);
31234768 1928 return true;
b2167459
RH
1929}
1930
40f9f908 1931static bool trans_break(DisasContext *ctx, arg_break *a)
98a9cb79 1932{
31234768 1933 return gen_excp_iir(ctx, EXCP_BREAK);
98a9cb79
RH
1934}
1935
e36f27ef 1936static bool trans_sync(DisasContext *ctx, arg_sync *a)
98a9cb79
RH
1937{
1938 /* No point in nullifying the memory barrier. */
1939 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1940
1941 cond_free(&ctx->null_cond);
31234768 1942 return true;
98a9cb79
RH
1943}
1944
c603e14a 1945static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
98a9cb79 1946{
c603e14a 1947 unsigned rt = a->t;
6fd0c7bc
RH
1948 TCGv_i64 tmp = dest_gpr(ctx, rt);
1949 tcg_gen_movi_i64(tmp, ctx->iaoq_f);
98a9cb79
RH
1950 save_gpr(ctx, rt, tmp);
1951
1952 cond_free(&ctx->null_cond);
31234768 1953 return true;
98a9cb79
RH
1954}
1955
c603e14a 1956static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
98a9cb79 1957{
c603e14a
RH
1958 unsigned rt = a->t;
1959 unsigned rs = a->sp;
33423472 1960 TCGv_i64 t0 = tcg_temp_new_i64();
98a9cb79 1961
33423472
RH
1962 load_spr(ctx, t0, rs);
1963 tcg_gen_shri_i64(t0, t0, 32);
33423472 1964
967662cd 1965 save_gpr(ctx, rt, t0);
98a9cb79
RH
1966
1967 cond_free(&ctx->null_cond);
31234768 1968 return true;
98a9cb79
RH
1969}
1970
c603e14a 1971static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
98a9cb79 1972{
c603e14a
RH
1973 unsigned rt = a->t;
1974 unsigned ctl = a->r;
6fd0c7bc 1975 TCGv_i64 tmp;
98a9cb79
RH
1976
1977 switch (ctl) {
35136a77 1978 case CR_SAR:
c603e14a 1979 if (a->e == 0) {
98a9cb79
RH
1980 /* MFSAR without ,W masks low 5 bits. */
1981 tmp = dest_gpr(ctx, rt);
6fd0c7bc 1982 tcg_gen_andi_i64(tmp, cpu_sar, 31);
98a9cb79 1983 save_gpr(ctx, rt, tmp);
35136a77 1984 goto done;
98a9cb79 1985 }
98a9cb79 1986 save_gpr(ctx, rt, cpu_sar);
35136a77
RH
1987 goto done;
1988 case CR_IT: /* Interval Timer */
1989 /* FIXME: Respect PSW_S bit. */
1990 nullify_over(ctx);
98a9cb79 1991 tmp = dest_gpr(ctx, rt);
dfd1b812 1992 if (translator_io_start(&ctx->base)) {
49c29d6c 1993 gen_helper_read_interval_timer(tmp);
31234768 1994 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
49c29d6c
RH
1995 } else {
1996 gen_helper_read_interval_timer(tmp);
49c29d6c 1997 }
98a9cb79 1998 save_gpr(ctx, rt, tmp);
31234768 1999 return nullify_end(ctx);
98a9cb79 2000 case 26:
98a9cb79 2001 case 27:
98a9cb79
RH
2002 break;
2003 default:
2004 /* All other control registers are privileged. */
35136a77
RH
2005 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2006 break;
98a9cb79
RH
2007 }
2008
aac0f603 2009 tmp = tcg_temp_new_i64();
6fd0c7bc 2010 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
35136a77
RH
2011 save_gpr(ctx, rt, tmp);
2012
2013 done:
98a9cb79 2014 cond_free(&ctx->null_cond);
31234768 2015 return true;
98a9cb79
RH
2016}
2017
c603e14a 2018static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
33423472 2019{
c603e14a
RH
2020 unsigned rr = a->r;
2021 unsigned rs = a->sp;
967662cd 2022 TCGv_i64 tmp;
33423472
RH
2023
2024 if (rs >= 5) {
2025 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2026 }
2027 nullify_over(ctx);
2028
967662cd
RH
2029 tmp = tcg_temp_new_i64();
2030 tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
33423472
RH
2031
2032 if (rs >= 4) {
967662cd 2033 tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
494737b7 2034 ctx->tb_flags &= ~TB_FLAG_SR_SAME;
33423472 2035 } else {
967662cd 2036 tcg_gen_mov_i64(cpu_sr[rs], tmp);
33423472 2037 }
33423472 2038
31234768 2039 return nullify_end(ctx);
33423472
RH
2040}
2041
c603e14a 2042static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
98a9cb79 2043{
c603e14a 2044 unsigned ctl = a->t;
6fd0c7bc
RH
2045 TCGv_i64 reg;
2046 TCGv_i64 tmp;
98a9cb79 2047
35136a77 2048 if (ctl == CR_SAR) {
4845f015 2049 reg = load_gpr(ctx, a->r);
aac0f603 2050 tmp = tcg_temp_new_i64();
6fd0c7bc 2051 tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
98a9cb79 2052 save_or_nullify(ctx, cpu_sar, tmp);
35136a77
RH
2053
2054 cond_free(&ctx->null_cond);
31234768 2055 return true;
98a9cb79
RH
2056 }
2057
35136a77
RH
2058 /* All other control registers are privileged or read-only. */
2059 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2060
c603e14a 2061#ifndef CONFIG_USER_ONLY
35136a77 2062 nullify_over(ctx);
4c34bab0
HD
2063
2064 if (ctx->is_pa20) {
2065 reg = load_gpr(ctx, a->r);
2066 } else {
2067 reg = tcg_temp_new_i64();
2068 tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
2069 }
4845f015 2070
35136a77
RH
2071 switch (ctl) {
2072 case CR_IT:
ad75a51e 2073 gen_helper_write_interval_timer(tcg_env, reg);
35136a77 2074 break;
4f5f2548 2075 case CR_EIRR:
ad75a51e 2076 gen_helper_write_eirr(tcg_env, reg);
4f5f2548
RH
2077 break;
2078 case CR_EIEM:
ad75a51e 2079 gen_helper_write_eiem(tcg_env, reg);
31234768 2080 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
4f5f2548
RH
2081 break;
2082
35136a77
RH
2083 case CR_IIASQ:
2084 case CR_IIAOQ:
2085 /* FIXME: Respect PSW_Q bit */
2086 /* The write advances the queue and stores to the back element. */
aac0f603 2087 tmp = tcg_temp_new_i64();
6fd0c7bc 2088 tcg_gen_ld_i64(tmp, tcg_env,
35136a77 2089 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
6fd0c7bc
RH
2090 tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2091 tcg_gen_st_i64(reg, tcg_env,
35136a77
RH
2092 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
2093 break;
2094
d5de20bd
SS
2095 case CR_PID1:
2096 case CR_PID2:
2097 case CR_PID3:
2098 case CR_PID4:
6fd0c7bc 2099 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
d5de20bd 2100#ifndef CONFIG_USER_ONLY
ad75a51e 2101 gen_helper_change_prot_id(tcg_env);
d5de20bd
SS
2102#endif
2103 break;
2104
35136a77 2105 default:
6fd0c7bc 2106 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
35136a77
RH
2107 break;
2108 }
31234768 2109 return nullify_end(ctx);
4f5f2548 2110#endif
98a9cb79
RH
2111}
2112
c603e14a 2113static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
98a9cb79 2114{
aac0f603 2115 TCGv_i64 tmp = tcg_temp_new_i64();
98a9cb79 2116
6fd0c7bc
RH
2117 tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
2118 tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
98a9cb79 2119 save_or_nullify(ctx, cpu_sar, tmp);
98a9cb79
RH
2120
2121 cond_free(&ctx->null_cond);
31234768 2122 return true;
98a9cb79
RH
2123}
2124
e36f27ef 2125static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
98a9cb79 2126{
6fd0c7bc 2127 TCGv_i64 dest = dest_gpr(ctx, a->t);
98a9cb79 2128
2330504c
HD
2129#ifdef CONFIG_USER_ONLY
2130 /* We don't implement space registers in user mode. */
6fd0c7bc 2131 tcg_gen_movi_i64(dest, 0);
2330504c 2132#else
967662cd
RH
2133 tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2134 tcg_gen_shri_i64(dest, dest, 32);
2330504c 2135#endif
e36f27ef 2136 save_gpr(ctx, a->t, dest);
98a9cb79
RH
2137
2138 cond_free(&ctx->null_cond);
31234768 2139 return true;
98a9cb79
RH
2140}
2141
e36f27ef 2142static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
e1b5a5ed 2143{
e36f27ef
RH
2144 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2145#ifndef CONFIG_USER_ONLY
6fd0c7bc 2146 TCGv_i64 tmp;
e1b5a5ed 2147
e1b5a5ed
RH
2148 nullify_over(ctx);
2149
aac0f603 2150 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2151 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2152 tcg_gen_andi_i64(tmp, tmp, ~a->i);
ad75a51e 2153 gen_helper_swap_system_mask(tmp, tcg_env, tmp);
e36f27ef 2154 save_gpr(ctx, a->t, tmp);
e1b5a5ed
RH
2155
2156 /* Exit the TB to recognize new interrupts, e.g. PSW_M. */
31234768
RH
2157 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2158 return nullify_end(ctx);
e36f27ef 2159#endif
e1b5a5ed
RH
2160}
2161
e36f27ef 2162static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
e1b5a5ed 2163{
e36f27ef
RH
2164 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2165#ifndef CONFIG_USER_ONLY
6fd0c7bc 2166 TCGv_i64 tmp;
e1b5a5ed 2167
e1b5a5ed
RH
2168 nullify_over(ctx);
2169
aac0f603 2170 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2171 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2172 tcg_gen_ori_i64(tmp, tmp, a->i);
ad75a51e 2173 gen_helper_swap_system_mask(tmp, tcg_env, tmp);
e36f27ef 2174 save_gpr(ctx, a->t, tmp);
e1b5a5ed
RH
2175
2176 /* Exit the TB to recognize new interrupts, e.g. PSW_I. */
31234768
RH
2177 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2178 return nullify_end(ctx);
e36f27ef 2179#endif
e1b5a5ed
RH
2180}
2181
c603e14a 2182static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
e1b5a5ed 2183{
e1b5a5ed 2184 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
c603e14a 2185#ifndef CONFIG_USER_ONLY
6fd0c7bc 2186 TCGv_i64 tmp, reg;
e1b5a5ed
RH
2187 nullify_over(ctx);
2188
c603e14a 2189 reg = load_gpr(ctx, a->r);
aac0f603 2190 tmp = tcg_temp_new_i64();
ad75a51e 2191 gen_helper_swap_system_mask(tmp, tcg_env, reg);
e1b5a5ed
RH
2192
2193 /* Exit the TB to recognize new interrupts. */
31234768
RH
2194 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2195 return nullify_end(ctx);
c603e14a 2196#endif
e1b5a5ed 2197}
f49b3537 2198
e36f27ef 2199static bool do_rfi(DisasContext *ctx, bool rfi_r)
f49b3537 2200{
f49b3537 2201 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
e36f27ef 2202#ifndef CONFIG_USER_ONLY
f49b3537
RH
2203 nullify_over(ctx);
2204
e36f27ef 2205 if (rfi_r) {
ad75a51e 2206 gen_helper_rfi_r(tcg_env);
f49b3537 2207 } else {
ad75a51e 2208 gen_helper_rfi(tcg_env);
f49b3537 2209 }
31234768 2210 /* Exit the TB to recognize new interrupts. */
8532a14e 2211 tcg_gen_exit_tb(NULL, 0);
31234768 2212 ctx->base.is_jmp = DISAS_NORETURN;
f49b3537 2213
31234768 2214 return nullify_end(ctx);
e36f27ef
RH
2215#endif
2216}
2217
2218static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2219{
2220 return do_rfi(ctx, false);
2221}
2222
2223static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2224{
2225 return do_rfi(ctx, true);
f49b3537 2226}
6210db05 2227
96927adb
RH
2228static bool trans_halt(DisasContext *ctx, arg_halt *a)
2229{
2230 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
e36f27ef 2231#ifndef CONFIG_USER_ONLY
96927adb 2232 nullify_over(ctx);
ad75a51e 2233 gen_helper_halt(tcg_env);
96927adb
RH
2234 ctx->base.is_jmp = DISAS_NORETURN;
2235 return nullify_end(ctx);
2236#endif
2237}
2238
2239static bool trans_reset(DisasContext *ctx, arg_reset *a)
6210db05
HD
2240{
2241 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
96927adb 2242#ifndef CONFIG_USER_ONLY
6210db05 2243 nullify_over(ctx);
ad75a51e 2244 gen_helper_reset(tcg_env);
31234768
RH
2245 ctx->base.is_jmp = DISAS_NORETURN;
2246 return nullify_end(ctx);
96927adb 2247#endif
6210db05 2248}
e1b5a5ed 2249
4a4554c6
HD
2250static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2251{
2252 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2253#ifndef CONFIG_USER_ONLY
2254 nullify_over(ctx);
ad75a51e 2255 gen_helper_getshadowregs(tcg_env);
4a4554c6
HD
2256 return nullify_end(ctx);
2257#endif
2258}
2259
deee69a1 2260static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
98a9cb79 2261{
deee69a1 2262 if (a->m) {
6fd0c7bc
RH
2263 TCGv_i64 dest = dest_gpr(ctx, a->b);
2264 TCGv_i64 src1 = load_gpr(ctx, a->b);
2265 TCGv_i64 src2 = load_gpr(ctx, a->x);
98a9cb79 2266
deee69a1 2267 /* The only thing we need to do is the base register modification. */
6fd0c7bc 2268 tcg_gen_add_i64(dest, src1, src2);
deee69a1
RH
2269 save_gpr(ctx, a->b, dest);
2270 }
98a9cb79 2271 cond_free(&ctx->null_cond);
31234768 2272 return true;
98a9cb79
RH
2273}
2274
deee69a1 2275static bool trans_probe(DisasContext *ctx, arg_probe *a)
98a9cb79 2276{
6fd0c7bc 2277 TCGv_i64 dest, ofs;
eed14219 2278 TCGv_i32 level, want;
6fd0c7bc 2279 TCGv_i64 addr;
98a9cb79
RH
2280
2281 nullify_over(ctx);
2282
deee69a1
RH
2283 dest = dest_gpr(ctx, a->t);
2284 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
eed14219 2285
deee69a1 2286 if (a->imm) {
29dd6f64 2287 level = tcg_constant_i32(a->ri);
98a9cb79 2288 } else {
eed14219 2289 level = tcg_temp_new_i32();
6fd0c7bc 2290 tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
eed14219 2291 tcg_gen_andi_i32(level, level, 3);
98a9cb79 2292 }
29dd6f64 2293 want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
eed14219 2294
ad75a51e 2295 gen_helper_probe(dest, tcg_env, addr, level, want);
eed14219 2296
deee69a1 2297 save_gpr(ctx, a->t, dest);
31234768 2298 return nullify_end(ctx);
98a9cb79
RH
2299}
2300
deee69a1 2301static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
8d6ae7fb 2302{
8577f354
RH
2303 if (ctx->is_pa20) {
2304 return false;
2305 }
deee69a1
RH
2306 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2307#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2308 TCGv_i64 addr;
2309 TCGv_i64 ofs, reg;
8d6ae7fb 2310
8d6ae7fb
RH
2311 nullify_over(ctx);
2312
deee69a1
RH
2313 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2314 reg = load_gpr(ctx, a->r);
2315 if (a->addr) {
8577f354 2316 gen_helper_itlba_pa11(tcg_env, addr, reg);
8d6ae7fb 2317 } else {
8577f354 2318 gen_helper_itlbp_pa11(tcg_env, addr, reg);
8d6ae7fb
RH
2319 }
2320
32dc7569
SS
2321 /* Exit TB for TLB change if mmu is enabled. */
2322 if (ctx->tb_flags & PSW_C) {
31234768
RH
2323 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2324 }
2325 return nullify_end(ctx);
deee69a1 2326#endif
8d6ae7fb 2327}
63300a00 2328
eb25d10f 2329static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
63300a00 2330{
deee69a1
RH
2331 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2332#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2333 TCGv_i64 addr;
2334 TCGv_i64 ofs;
63300a00 2335
63300a00
RH
2336 nullify_over(ctx);
2337
deee69a1 2338 form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
eb25d10f
HD
2339
2340 /*
2341 * Page align now, rather than later, so that we can add in the
2342 * page_size field from pa2.0 from the low 4 bits of GR[b].
2343 */
2344 tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2345 if (ctx->is_pa20) {
2346 tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
63300a00 2347 }
eb25d10f
HD
2348
2349 if (local) {
2350 gen_helper_ptlb_l(tcg_env, addr);
63300a00 2351 } else {
ad75a51e 2352 gen_helper_ptlb(tcg_env, addr);
63300a00
RH
2353 }
2354
eb25d10f
HD
2355 if (a->m) {
2356 save_gpr(ctx, a->b, ofs);
2357 }
2358
2359 /* Exit TB for TLB change if mmu is enabled. */
2360 if (ctx->tb_flags & PSW_C) {
2361 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2362 }
2363 return nullify_end(ctx);
2364#endif
2365}
2366
2367static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2368{
2369 return do_pxtlb(ctx, a, false);
2370}
2371
2372static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2373{
2374 return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2375}
2376
2377static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2378{
2379 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2380#ifndef CONFIG_USER_ONLY
2381 nullify_over(ctx);
2382
2383 trans_nop_addrx(ctx, a);
2384 gen_helper_ptlbe(tcg_env);
2385
63300a00 2386 /* Exit TB for TLB change if mmu is enabled. */
6797c315
NH
2387 if (ctx->tb_flags & PSW_C) {
2388 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2389 }
2390 return nullify_end(ctx);
2391#endif
2392}
2393
2394/*
2395 * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
2396 * See
2397 * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
2398 * page 13-9 (195/206)
2399 */
2400static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
2401{
8577f354
RH
2402 if (ctx->is_pa20) {
2403 return false;
2404 }
6797c315
NH
2405 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2406#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2407 TCGv_i64 addr, atl, stl;
2408 TCGv_i64 reg;
6797c315
NH
2409
2410 nullify_over(ctx);
2411
2412 /*
2413 * FIXME:
2414 * if (not (pcxl or pcxl2))
2415 * return gen_illegal(ctx);
6797c315
NH
2416 */
2417
6fd0c7bc
RH
2418 atl = tcg_temp_new_i64();
2419 stl = tcg_temp_new_i64();
2420 addr = tcg_temp_new_i64();
6797c315 2421
ad75a51e 2422 tcg_gen_ld32u_i64(stl, tcg_env,
6797c315
NH
2423 a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
2424 : offsetof(CPUHPPAState, cr[CR_IIASQ]));
ad75a51e 2425 tcg_gen_ld32u_i64(atl, tcg_env,
6797c315
NH
2426 a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
2427 : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
2428 tcg_gen_shli_i64(stl, stl, 32);
d265360f 2429 tcg_gen_or_i64(addr, atl, stl);
6797c315
NH
2430
2431 reg = load_gpr(ctx, a->r);
2432 if (a->addr) {
8577f354 2433 gen_helper_itlba_pa11(tcg_env, addr, reg);
6797c315 2434 } else {
8577f354
RH
2435 gen_helper_itlbp_pa11(tcg_env, addr, reg);
2436 }
2437
2438 /* Exit TB for TLB change if mmu is enabled. */
2439 if (ctx->tb_flags & PSW_C) {
2440 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
6797c315 2441 }
8577f354
RH
2442 return nullify_end(ctx);
2443#endif
2444}
6797c315 2445
8577f354
RH
2446static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
2447{
2448 if (!ctx->is_pa20) {
2449 return false;
2450 }
2451 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2452#ifndef CONFIG_USER_ONLY
2453 nullify_over(ctx);
2454 {
2455 TCGv_i64 src1 = load_gpr(ctx, a->r1);
2456 TCGv_i64 src2 = load_gpr(ctx, a->r2);
2457
2458 if (a->data) {
2459 gen_helper_idtlbt_pa20(tcg_env, src1, src2);
2460 } else {
2461 gen_helper_iitlbt_pa20(tcg_env, src1, src2);
2462 }
2463 }
6797c315 2464 /* Exit TB for TLB change if mmu is enabled. */
32dc7569 2465 if (ctx->tb_flags & PSW_C) {
31234768
RH
2466 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2467 }
2468 return nullify_end(ctx);
deee69a1 2469#endif
63300a00 2470}
2dfcca9f 2471
deee69a1 2472static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
2dfcca9f 2473{
deee69a1
RH
2474 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2475#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2476 TCGv_i64 vaddr;
2477 TCGv_i64 ofs, paddr;
2dfcca9f 2478
2dfcca9f
RH
2479 nullify_over(ctx);
2480
deee69a1 2481 form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2dfcca9f 2482
aac0f603 2483 paddr = tcg_temp_new_i64();
ad75a51e 2484 gen_helper_lpa(paddr, tcg_env, vaddr);
2dfcca9f
RH
2485
2486 /* Note that physical address result overrides base modification. */
deee69a1
RH
2487 if (a->m) {
2488 save_gpr(ctx, a->b, ofs);
2dfcca9f 2489 }
deee69a1 2490 save_gpr(ctx, a->t, paddr);
2dfcca9f 2491
31234768 2492 return nullify_end(ctx);
deee69a1 2493#endif
2dfcca9f 2494}
43a97b81 2495
deee69a1 2496static bool trans_lci(DisasContext *ctx, arg_lci *a)
43a97b81 2497{
43a97b81
RH
2498 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2499
2500 /* The Coherence Index is an implementation-defined function of the
2501 physical address. Two addresses with the same CI have a coherent
2502 view of the cache. Our implementation is to return 0 for all,
2503 since the entire address space is coherent. */
a4db4a78 2504 save_gpr(ctx, a->t, ctx->zero);
43a97b81 2505
31234768
RH
2506 cond_free(&ctx->null_cond);
2507 return true;
43a97b81 2508}
98a9cb79 2509
faf97ba1 2510static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2511{
0c982a28
RH
2512 return do_add_reg(ctx, a, false, false, false, false);
2513}
b2167459 2514
faf97ba1 2515static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2516{
2517 return do_add_reg(ctx, a, true, false, false, false);
2518}
b2167459 2519
faf97ba1 2520static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2521{
2522 return do_add_reg(ctx, a, false, true, false, false);
b2167459
RH
2523}
2524
faf97ba1 2525static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2526{
0c982a28
RH
2527 return do_add_reg(ctx, a, false, false, false, true);
2528}
b2167459 2529
faf97ba1 2530static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2531{
2532 return do_add_reg(ctx, a, false, true, false, true);
2533}
b2167459 2534
63c427c6 2535static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2536{
2537 return do_sub_reg(ctx, a, false, false, false);
b2167459
RH
2538}
2539
63c427c6 2540static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2541{
0c982a28
RH
2542 return do_sub_reg(ctx, a, true, false, false);
2543}
b2167459 2544
63c427c6 2545static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2546{
2547 return do_sub_reg(ctx, a, false, false, true);
b2167459
RH
2548}
2549
63c427c6 2550static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2551{
0c982a28
RH
2552 return do_sub_reg(ctx, a, true, false, true);
2553}
2554
63c427c6 2555static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2556{
2557 return do_sub_reg(ctx, a, false, true, false);
2558}
2559
63c427c6 2560static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2561{
2562 return do_sub_reg(ctx, a, true, true, false);
2563}
2564
fa8e3bed 2565static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2566{
6fd0c7bc 2567 return do_log_reg(ctx, a, tcg_gen_andc_i64);
0c982a28
RH
2568}
2569
fa8e3bed 2570static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2571{
6fd0c7bc 2572 return do_log_reg(ctx, a, tcg_gen_and_i64);
0c982a28
RH
2573}
2574
fa8e3bed 2575static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2576{
2577 if (a->cf == 0) {
2578 unsigned r2 = a->r2;
2579 unsigned r1 = a->r1;
2580 unsigned rt = a->t;
b2167459 2581
7aee8189
RH
2582 if (rt == 0) { /* NOP */
2583 cond_free(&ctx->null_cond);
2584 return true;
2585 }
2586 if (r2 == 0) { /* COPY */
2587 if (r1 == 0) {
6fd0c7bc
RH
2588 TCGv_i64 dest = dest_gpr(ctx, rt);
2589 tcg_gen_movi_i64(dest, 0);
7aee8189
RH
2590 save_gpr(ctx, rt, dest);
2591 } else {
2592 save_gpr(ctx, rt, cpu_gr[r1]);
2593 }
2594 cond_free(&ctx->null_cond);
2595 return true;
2596 }
2597#ifndef CONFIG_USER_ONLY
2598 /* These are QEMU extensions and are nops in the real architecture:
2599 *
2600 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2601 * or %r31,%r31,%r31 -- death loop; offline cpu
2602 * currently implemented as idle.
2603 */
2604 if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
7aee8189
RH
2605 /* No need to check for supervisor, as userland can only pause
2606 until the next timer interrupt. */
2607 nullify_over(ctx);
2608
2609 /* Advance the instruction queue. */
741322f4
RH
2610 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2611 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
7aee8189
RH
2612 nullify_set(ctx, 0);
2613
2614 /* Tell the qemu main loop to halt until this cpu has work. */
ad75a51e 2615 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
29dd6f64 2616 offsetof(CPUState, halted) - offsetof(HPPACPU, env));
7aee8189
RH
2617 gen_excp_1(EXCP_HALTED);
2618 ctx->base.is_jmp = DISAS_NORETURN;
2619
2620 return nullify_end(ctx);
2621 }
2622#endif
b2167459 2623 }
6fd0c7bc 2624 return do_log_reg(ctx, a, tcg_gen_or_i64);
0c982a28 2625}
7aee8189 2626
fa8e3bed 2627static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2628{
6fd0c7bc 2629 return do_log_reg(ctx, a, tcg_gen_xor_i64);
b2167459
RH
2630}
2631
345aa35f 2632static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2633{
6fd0c7bc 2634 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2635
0c982a28 2636 if (a->cf) {
b2167459
RH
2637 nullify_over(ctx);
2638 }
0c982a28
RH
2639 tcg_r1 = load_gpr(ctx, a->r1);
2640 tcg_r2 = load_gpr(ctx, a->r2);
345aa35f 2641 do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
31234768 2642 return nullify_end(ctx);
b2167459
RH
2643}
2644
af240753 2645static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2646{
6fd0c7bc 2647 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2648
0c982a28 2649 if (a->cf) {
b2167459
RH
2650 nullify_over(ctx);
2651 }
0c982a28
RH
2652 tcg_r1 = load_gpr(ctx, a->r1);
2653 tcg_r2 = load_gpr(ctx, a->r2);
6fd0c7bc 2654 do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
31234768 2655 return nullify_end(ctx);
b2167459
RH
2656}
2657
af240753 2658static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
b2167459 2659{
6fd0c7bc 2660 TCGv_i64 tcg_r1, tcg_r2, tmp;
b2167459 2661
0c982a28 2662 if (a->cf) {
b2167459
RH
2663 nullify_over(ctx);
2664 }
0c982a28
RH
2665 tcg_r1 = load_gpr(ctx, a->r1);
2666 tcg_r2 = load_gpr(ctx, a->r2);
aac0f603 2667 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2668 tcg_gen_not_i64(tmp, tcg_r2);
2669 do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
31234768 2670 return nullify_end(ctx);
b2167459
RH
2671}
2672
af240753 2673static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2674{
2675 return do_uaddcm(ctx, a, false);
2676}
2677
af240753 2678static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2679{
2680 return do_uaddcm(ctx, a, true);
2681}
2682
af240753 2683static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
b2167459 2684{
6fd0c7bc 2685 TCGv_i64 tmp;
b2167459
RH
2686
2687 nullify_over(ctx);
2688
aac0f603 2689 tmp = tcg_temp_new_i64();
6fd0c7bc 2690 tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
b2167459 2691 if (!is_i) {
6fd0c7bc 2692 tcg_gen_not_i64(tmp, tmp);
b2167459 2693 }
6fd0c7bc
RH
2694 tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
2695 tcg_gen_muli_i64(tmp, tmp, 6);
af240753 2696 do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
6fd0c7bc 2697 is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
31234768 2698 return nullify_end(ctx);
b2167459
RH
2699}
2700
af240753 2701static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2702{
2703 return do_dcor(ctx, a, false);
2704}
2705
af240753 2706static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2707{
2708 return do_dcor(ctx, a, true);
2709}
2710
2711static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
b2167459 2712{
a4db4a78 2713 TCGv_i64 dest, add1, add2, addc, in1, in2;
6fd0c7bc 2714 TCGv_i64 cout;
b2167459
RH
2715
2716 nullify_over(ctx);
2717
0c982a28
RH
2718 in1 = load_gpr(ctx, a->r1);
2719 in2 = load_gpr(ctx, a->r2);
b2167459 2720
aac0f603
RH
2721 add1 = tcg_temp_new_i64();
2722 add2 = tcg_temp_new_i64();
2723 addc = tcg_temp_new_i64();
2724 dest = tcg_temp_new_i64();
b2167459
RH
2725
2726 /* Form R1 << 1 | PSW[CB]{8}. */
6fd0c7bc
RH
2727 tcg_gen_add_i64(add1, in1, in1);
2728 tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
b2167459 2729
72ca8753
RH
2730 /*
2731 * Add or subtract R2, depending on PSW[V]. Proper computation of
2732 * carry requires that we subtract via + ~R2 + 1, as described in
2733 * the manual. By extracting and masking V, we can produce the
2734 * proper inputs to the addition without movcond.
2735 */
6fd0c7bc
RH
2736 tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
2737 tcg_gen_xor_i64(add2, in2, addc);
2738 tcg_gen_andi_i64(addc, addc, 1);
72ca8753 2739
a4db4a78
RH
2740 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2741 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2742 addc, ctx->zero);
b2167459 2743
b2167459 2744 /* Write back the result register. */
0c982a28 2745 save_gpr(ctx, a->t, dest);
b2167459
RH
2746
2747 /* Write back PSW[CB]. */
6fd0c7bc
RH
2748 tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
2749 tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
b2167459
RH
2750
2751 /* Write back PSW[V] for the division step. */
72ca8753 2752 cout = get_psw_carry(ctx, false);
6fd0c7bc
RH
2753 tcg_gen_neg_i64(cpu_psw_v, cout);
2754 tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
b2167459
RH
2755
2756 /* Install the new nullification. */
0c982a28 2757 if (a->cf) {
6fd0c7bc 2758 TCGv_i64 sv = NULL;
b47a4a02 2759 if (cond_need_sv(a->cf >> 1)) {
b2167459
RH
2760 /* ??? The lshift is supposed to contribute to overflow. */
2761 sv = do_add_sv(ctx, dest, add1, add2);
2762 }
a751eb31 2763 ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
b2167459
RH
2764 }
2765
31234768 2766 return nullify_end(ctx);
b2167459
RH
2767}
2768
0588e061 2769static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
b2167459 2770{
0588e061
RH
2771 return do_add_imm(ctx, a, false, false);
2772}
b2167459 2773
0588e061
RH
2774static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
2775{
2776 return do_add_imm(ctx, a, true, false);
b2167459
RH
2777}
2778
0588e061 2779static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
b2167459 2780{
0588e061
RH
2781 return do_add_imm(ctx, a, false, true);
2782}
b2167459 2783
0588e061
RH
2784static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
2785{
2786 return do_add_imm(ctx, a, true, true);
2787}
b2167459 2788
0588e061
RH
2789static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
2790{
2791 return do_sub_imm(ctx, a, false);
2792}
b2167459 2793
0588e061
RH
2794static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
2795{
2796 return do_sub_imm(ctx, a, true);
b2167459
RH
2797}
2798
345aa35f 2799static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
b2167459 2800{
6fd0c7bc 2801 TCGv_i64 tcg_im, tcg_r2;
b2167459 2802
0588e061 2803 if (a->cf) {
b2167459
RH
2804 nullify_over(ctx);
2805 }
2806
6fd0c7bc 2807 tcg_im = tcg_constant_i64(a->i);
0588e061 2808 tcg_r2 = load_gpr(ctx, a->r);
345aa35f 2809 do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
b2167459 2810
31234768 2811 return nullify_end(ctx);
b2167459
RH
2812}
2813
0843563f
RH
2814static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
2815 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
2816{
2817 TCGv_i64 r1, r2, dest;
2818
2819 if (!ctx->is_pa20) {
2820 return false;
2821 }
2822
2823 nullify_over(ctx);
2824
2825 r1 = load_gpr(ctx, a->r1);
2826 r2 = load_gpr(ctx, a->r2);
2827 dest = dest_gpr(ctx, a->t);
2828
2829 fn(dest, r1, r2);
2830 save_gpr(ctx, a->t, dest);
2831
2832 return nullify_end(ctx);
2833}
2834
151f309b
RH
2835static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2836 void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2837{
2838 TCGv_i64 r, dest;
2839
2840 if (!ctx->is_pa20) {
2841 return false;
2842 }
2843
2844 nullify_over(ctx);
2845
2846 r = load_gpr(ctx, a->r);
2847 dest = dest_gpr(ctx, a->t);
2848
2849 fn(dest, r, a->i);
2850 save_gpr(ctx, a->t, dest);
2851
2852 return nullify_end(ctx);
2853}
2854
3bbb8e48
RH
2855static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
2856 void (*fn)(TCGv_i64, TCGv_i64,
2857 TCGv_i64, TCGv_i32))
2858{
2859 TCGv_i64 r1, r2, dest;
2860
2861 if (!ctx->is_pa20) {
2862 return false;
2863 }
2864
2865 nullify_over(ctx);
2866
2867 r1 = load_gpr(ctx, a->r1);
2868 r2 = load_gpr(ctx, a->r2);
2869 dest = dest_gpr(ctx, a->t);
2870
2871 fn(dest, r1, r2, tcg_constant_i32(a->sh));
2872 save_gpr(ctx, a->t, dest);
2873
2874 return nullify_end(ctx);
2875}
2876
0843563f
RH
2877static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
2878{
2879 return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
2880}
2881
2882static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
2883{
2884 return do_multimedia(ctx, a, gen_helper_hadd_ss);
2885}
2886
2887static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
2888{
2889 return do_multimedia(ctx, a, gen_helper_hadd_us);
2890}
2891
1b3cb7c8
RH
2892static bool trans_havg(DisasContext *ctx, arg_rrr *a)
2893{
2894 return do_multimedia(ctx, a, gen_helper_havg);
2895}
2896
151f309b
RH
2897static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2898{
2899 return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2900}
2901
2902static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2903{
2904 return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2905}
2906
2907static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2908{
2909 return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2910}
2911
3bbb8e48
RH
2912static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
2913{
2914 return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
2915}
2916
2917static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
2918{
2919 return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
2920}
2921
10c9e58d
RH
2922static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
2923{
2924 return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
2925}
2926
2927static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
2928{
2929 return do_multimedia(ctx, a, gen_helper_hsub_ss);
2930}
2931
2932static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
2933{
2934 return do_multimedia(ctx, a, gen_helper_hsub_us);
2935}
2936
c2a7ee3f
RH
2937static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2938{
2939 uint64_t mask = 0xffff0000ffff0000ull;
2940 TCGv_i64 tmp = tcg_temp_new_i64();
2941
2942 tcg_gen_andi_i64(tmp, r2, mask);
2943 tcg_gen_andi_i64(dst, r1, mask);
2944 tcg_gen_shri_i64(tmp, tmp, 16);
2945 tcg_gen_or_i64(dst, dst, tmp);
2946}
2947
2948static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2949{
2950 return do_multimedia(ctx, a, gen_mixh_l);
2951}
2952
2953static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2954{
2955 uint64_t mask = 0x0000ffff0000ffffull;
2956 TCGv_i64 tmp = tcg_temp_new_i64();
2957
2958 tcg_gen_andi_i64(tmp, r1, mask);
2959 tcg_gen_andi_i64(dst, r2, mask);
2960 tcg_gen_shli_i64(tmp, tmp, 16);
2961 tcg_gen_or_i64(dst, dst, tmp);
2962}
2963
2964static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2965{
2966 return do_multimedia(ctx, a, gen_mixh_r);
2967}
2968
2969static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2970{
2971 TCGv_i64 tmp = tcg_temp_new_i64();
2972
2973 tcg_gen_shri_i64(tmp, r2, 32);
2974 tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2975}
2976
2977static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2978{
2979 return do_multimedia(ctx, a, gen_mixw_l);
2980}
2981
2982static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2983{
2984 tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
2985}
2986
2987static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
2988{
2989 return do_multimedia(ctx, a, gen_mixw_r);
2990}
2991
4e7abdb1
RH
2992static bool trans_permh(DisasContext *ctx, arg_permh *a)
2993{
2994 TCGv_i64 r, t0, t1, t2, t3;
2995
2996 if (!ctx->is_pa20) {
2997 return false;
2998 }
2999
3000 nullify_over(ctx);
3001
3002 r = load_gpr(ctx, a->r1);
3003 t0 = tcg_temp_new_i64();
3004 t1 = tcg_temp_new_i64();
3005 t2 = tcg_temp_new_i64();
3006 t3 = tcg_temp_new_i64();
3007
3008 tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
3009 tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
3010 tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
3011 tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
3012
3013 tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
3014 tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
3015 tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
3016
3017 save_gpr(ctx, a->t, t0);
3018 return nullify_end(ctx);
3019}
3020
1cd012a5 3021static bool trans_ld(DisasContext *ctx, arg_ldst *a)
96d6407f 3022{
b5caa17c
RH
3023 if (ctx->is_pa20) {
3024 /*
3025 * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3026 * Any base modification still occurs.
3027 */
3028 if (a->t == 0) {
3029 return trans_nop_addrx(ctx, a);
3030 }
3031 } else if (a->size > MO_32) {
0786a3b6 3032 return gen_illegal(ctx);
0786a3b6 3033 }
c53e401e
RH
3034 return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
3035 a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
3036}
3037
1cd012a5 3038static bool trans_st(DisasContext *ctx, arg_ldst *a)
96d6407f 3039{
1cd012a5 3040 assert(a->x == 0 && a->scale == 0);
c53e401e 3041 if (!ctx->is_pa20 && a->size > MO_32) {
0786a3b6 3042 return gen_illegal(ctx);
0786a3b6 3043 }
c53e401e 3044 return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
3045}
3046
1cd012a5 3047static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
96d6407f 3048{
b1af755c 3049 MemOp mop = MO_TE | MO_ALIGN | a->size;
a4db4a78 3050 TCGv_i64 dest, ofs;
6fd0c7bc 3051 TCGv_i64 addr;
96d6407f 3052
c53e401e 3053 if (!ctx->is_pa20 && a->size > MO_32) {
51416c4e
RH
3054 return gen_illegal(ctx);
3055 }
3056
96d6407f
RH
3057 nullify_over(ctx);
3058
1cd012a5 3059 if (a->m) {
86f8d05f
RH
3060 /* Base register modification. Make sure if RT == RB,
3061 we see the result of the load. */
aac0f603 3062 dest = tcg_temp_new_i64();
96d6407f 3063 } else {
1cd012a5 3064 dest = dest_gpr(ctx, a->t);
96d6407f
RH
3065 }
3066
1cd012a5
RH
3067 form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
3068 a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
b1af755c
RH
3069
3070 /*
3071 * For hppa1.1, LDCW is undefined unless aligned mod 16.
3072 * However actual hardware succeeds with aligned mod 4.
3073 * Detect this case and log a GUEST_ERROR.
3074 *
3075 * TODO: HPPA64 relaxes the over-alignment requirement
3076 * with the ,co completer.
3077 */
3078 gen_helper_ldc_check(addr);
3079
a4db4a78 3080 tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
b1af755c 3081
1cd012a5
RH
3082 if (a->m) {
3083 save_gpr(ctx, a->b, ofs);
96d6407f 3084 }
1cd012a5 3085 save_gpr(ctx, a->t, dest);
96d6407f 3086
31234768 3087 return nullify_end(ctx);
96d6407f
RH
3088}
3089
1cd012a5 3090static bool trans_stby(DisasContext *ctx, arg_stby *a)
96d6407f 3091{
6fd0c7bc
RH
3092 TCGv_i64 ofs, val;
3093 TCGv_i64 addr;
96d6407f
RH
3094
3095 nullify_over(ctx);
3096
1cd012a5 3097 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
86f8d05f 3098 ctx->mmu_idx == MMU_PHYS_IDX);
1cd012a5
RH
3099 val = load_gpr(ctx, a->r);
3100 if (a->a) {
f9f46db4 3101 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 3102 gen_helper_stby_e_parallel(tcg_env, addr, val);
f9f46db4 3103 } else {
ad75a51e 3104 gen_helper_stby_e(tcg_env, addr, val);
f9f46db4 3105 }
96d6407f 3106 } else {
f9f46db4 3107 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 3108 gen_helper_stby_b_parallel(tcg_env, addr, val);
f9f46db4 3109 } else {
ad75a51e 3110 gen_helper_stby_b(tcg_env, addr, val);
f9f46db4 3111 }
96d6407f 3112 }
1cd012a5 3113 if (a->m) {
6fd0c7bc 3114 tcg_gen_andi_i64(ofs, ofs, ~3);
1cd012a5 3115 save_gpr(ctx, a->b, ofs);
96d6407f 3116 }
96d6407f 3117
31234768 3118 return nullify_end(ctx);
96d6407f
RH
3119}
3120
25460fc5
RH
3121static bool trans_stdby(DisasContext *ctx, arg_stby *a)
3122{
6fd0c7bc
RH
3123 TCGv_i64 ofs, val;
3124 TCGv_i64 addr;
25460fc5
RH
3125
3126 if (!ctx->is_pa20) {
3127 return false;
3128 }
3129 nullify_over(ctx);
3130
3131 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
3132 ctx->mmu_idx == MMU_PHYS_IDX);
3133 val = load_gpr(ctx, a->r);
3134 if (a->a) {
3135 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3136 gen_helper_stdby_e_parallel(tcg_env, addr, val);
3137 } else {
3138 gen_helper_stdby_e(tcg_env, addr, val);
3139 }
3140 } else {
3141 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3142 gen_helper_stdby_b_parallel(tcg_env, addr, val);
3143 } else {
3144 gen_helper_stdby_b(tcg_env, addr, val);
3145 }
3146 }
3147 if (a->m) {
6fd0c7bc 3148 tcg_gen_andi_i64(ofs, ofs, ~7);
25460fc5
RH
3149 save_gpr(ctx, a->b, ofs);
3150 }
3151
3152 return nullify_end(ctx);
3153}
3154
1cd012a5 3155static bool trans_lda(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
3156{
3157 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
3158
3159 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 3160 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 3161 trans_ld(ctx, a);
d0a851cc 3162 ctx->mmu_idx = hold_mmu_idx;
31234768 3163 return true;
d0a851cc
RH
3164}
3165
1cd012a5 3166static bool trans_sta(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
3167{
3168 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
3169
3170 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 3171 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 3172 trans_st(ctx, a);
d0a851cc 3173 ctx->mmu_idx = hold_mmu_idx;
31234768 3174 return true;
d0a851cc 3175}
95412a61 3176
0588e061 3177static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
b2167459 3178{
6fd0c7bc 3179 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459 3180
6fd0c7bc 3181 tcg_gen_movi_i64(tcg_rt, a->i);
0588e061 3182 save_gpr(ctx, a->t, tcg_rt);
b2167459 3183 cond_free(&ctx->null_cond);
31234768 3184 return true;
b2167459
RH
3185}
3186
0588e061 3187static bool trans_addil(DisasContext *ctx, arg_addil *a)
b2167459 3188{
6fd0c7bc
RH
3189 TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
3190 TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
b2167459 3191
6fd0c7bc 3192 tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
b2167459
RH
3193 save_gpr(ctx, 1, tcg_r1);
3194 cond_free(&ctx->null_cond);
31234768 3195 return true;
b2167459
RH
3196}
3197
0588e061 3198static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
b2167459 3199{
6fd0c7bc 3200 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459
RH
3201
3202 /* Special case rb == 0, for the LDI pseudo-op.
d265360f 3203 The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */
0588e061 3204 if (a->b == 0) {
6fd0c7bc 3205 tcg_gen_movi_i64(tcg_rt, a->i);
b2167459 3206 } else {
6fd0c7bc 3207 tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
b2167459 3208 }
0588e061 3209 save_gpr(ctx, a->t, tcg_rt);
b2167459 3210 cond_free(&ctx->null_cond);
31234768 3211 return true;
b2167459
RH
3212}
3213
6fd0c7bc 3214static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
e9efd4bc 3215 unsigned c, unsigned f, bool d, unsigned n, int disp)
98cd9ca7 3216{
6fd0c7bc 3217 TCGv_i64 dest, in2, sv;
98cd9ca7
RH
3218 DisasCond cond;
3219
98cd9ca7 3220 in2 = load_gpr(ctx, r);
aac0f603 3221 dest = tcg_temp_new_i64();
98cd9ca7 3222
6fd0c7bc 3223 tcg_gen_sub_i64(dest, in1, in2);
98cd9ca7 3224
f764718d 3225 sv = NULL;
b47a4a02 3226 if (cond_need_sv(c)) {
98cd9ca7
RH
3227 sv = do_sub_sv(ctx, dest, in1, in2);
3228 }
3229
4fe9533a 3230 cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
01afb7be 3231 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
3232}
3233
01afb7be 3234static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
98cd9ca7 3235{
e9efd4bc
RH
3236 if (!ctx->is_pa20 && a->d) {
3237 return false;
3238 }
01afb7be 3239 nullify_over(ctx);
e9efd4bc
RH
3240 return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3241 a->c, a->f, a->d, a->n, a->disp);
01afb7be 3242}
98cd9ca7 3243
01afb7be
RH
3244static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
3245{
c65c3ee1
RH
3246 if (!ctx->is_pa20 && a->d) {
3247 return false;
3248 }
98cd9ca7 3249 nullify_over(ctx);
6fd0c7bc 3250 return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
c65c3ee1 3251 a->c, a->f, a->d, a->n, a->disp);
01afb7be
RH
3252}
3253
6fd0c7bc 3254static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
01afb7be
RH
3255 unsigned c, unsigned f, unsigned n, int disp)
3256{
6fd0c7bc 3257 TCGv_i64 dest, in2, sv, cb_cond;
01afb7be 3258 DisasCond cond;
bdcccc17 3259 bool d = false;
98cd9ca7 3260
f25d3160
RH
3261 /*
3262 * For hppa64, the ADDB conditions change with PSW.W,
3263 * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3264 */
3265 if (ctx->tb_flags & PSW_W) {
3266 d = c >= 5;
3267 if (d) {
3268 c &= 3;
3269 }
3270 }
3271
98cd9ca7 3272 in2 = load_gpr(ctx, r);
aac0f603 3273 dest = tcg_temp_new_i64();
f764718d 3274 sv = NULL;
bdcccc17 3275 cb_cond = NULL;
98cd9ca7 3276
b47a4a02 3277 if (cond_need_cb(c)) {
aac0f603
RH
3278 TCGv_i64 cb = tcg_temp_new_i64();
3279 TCGv_i64 cb_msb = tcg_temp_new_i64();
bdcccc17 3280
6fd0c7bc
RH
3281 tcg_gen_movi_i64(cb_msb, 0);
3282 tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
3283 tcg_gen_xor_i64(cb, in1, in2);
3284 tcg_gen_xor_i64(cb, cb, dest);
bdcccc17 3285 cb_cond = get_carry(ctx, d, cb, cb_msb);
b47a4a02 3286 } else {
6fd0c7bc 3287 tcg_gen_add_i64(dest, in1, in2);
b47a4a02
SS
3288 }
3289 if (cond_need_sv(c)) {
98cd9ca7 3290 sv = do_add_sv(ctx, dest, in1, in2);
98cd9ca7
RH
3291 }
3292
a751eb31 3293 cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
43675d20 3294 save_gpr(ctx, r, dest);
01afb7be 3295 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
3296}
3297
01afb7be
RH
3298static bool trans_addb(DisasContext *ctx, arg_addb *a)
3299{
3300 nullify_over(ctx);
3301 return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
3302}
3303
3304static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
3305{
3306 nullify_over(ctx);
6fd0c7bc 3307 return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
01afb7be
RH
3308}
3309
3310static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
98cd9ca7 3311{
6fd0c7bc 3312 TCGv_i64 tmp, tcg_r;
98cd9ca7
RH
3313 DisasCond cond;
3314
3315 nullify_over(ctx);
3316
aac0f603 3317 tmp = tcg_temp_new_i64();
01afb7be 3318 tcg_r = load_gpr(ctx, a->r);
84e224d4 3319 if (cond_need_ext(ctx, a->d)) {
1e9ab9fb 3320 /* Force shift into [32,63] */
6fd0c7bc
RH
3321 tcg_gen_ori_i64(tmp, cpu_sar, 32);
3322 tcg_gen_shl_i64(tmp, tcg_r, tmp);
1e9ab9fb 3323 } else {
6fd0c7bc 3324 tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
1e9ab9fb 3325 }
98cd9ca7 3326
1e9ab9fb 3327 cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be 3328 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3329}
3330
01afb7be
RH
3331static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
3332{
6fd0c7bc 3333 TCGv_i64 tmp, tcg_r;
01afb7be 3334 DisasCond cond;
1e9ab9fb 3335 int p;
01afb7be
RH
3336
3337 nullify_over(ctx);
3338
aac0f603 3339 tmp = tcg_temp_new_i64();
01afb7be 3340 tcg_r = load_gpr(ctx, a->r);
84e224d4 3341 p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
6fd0c7bc 3342 tcg_gen_shli_i64(tmp, tcg_r, p);
01afb7be
RH
3343
3344 cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be
RH
3345 return do_cbranch(ctx, a->disp, a->n, &cond);
3346}
3347
3348static bool trans_movb(DisasContext *ctx, arg_movb *a)
98cd9ca7 3349{
6fd0c7bc 3350 TCGv_i64 dest;
98cd9ca7
RH
3351 DisasCond cond;
3352
3353 nullify_over(ctx);
3354
01afb7be
RH
3355 dest = dest_gpr(ctx, a->r2);
3356 if (a->r1 == 0) {
6fd0c7bc 3357 tcg_gen_movi_i64(dest, 0);
98cd9ca7 3358 } else {
6fd0c7bc 3359 tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
98cd9ca7
RH
3360 }
3361
4fa52edf
RH
3362 /* All MOVB conditions are 32-bit. */
3363 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be
RH
3364 return do_cbranch(ctx, a->disp, a->n, &cond);
3365}
3366
3367static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
3368{
6fd0c7bc 3369 TCGv_i64 dest;
01afb7be
RH
3370 DisasCond cond;
3371
3372 nullify_over(ctx);
3373
3374 dest = dest_gpr(ctx, a->r);
6fd0c7bc 3375 tcg_gen_movi_i64(dest, a->i);
01afb7be 3376
4fa52edf
RH
3377 /* All MOVBI conditions are 32-bit. */
3378 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be 3379 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3380}
3381
f7b775a9 3382static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
0b1347d2 3383{
6fd0c7bc 3384 TCGv_i64 dest, src2;
0b1347d2 3385
f7b775a9
RH
3386 if (!ctx->is_pa20 && a->d) {
3387 return false;
3388 }
30878590 3389 if (a->c) {
0b1347d2
RH
3390 nullify_over(ctx);
3391 }
3392
30878590 3393 dest = dest_gpr(ctx, a->t);
f7b775a9 3394 src2 = load_gpr(ctx, a->r2);
30878590 3395 if (a->r1 == 0) {
f7b775a9 3396 if (a->d) {
6fd0c7bc 3397 tcg_gen_shr_i64(dest, src2, cpu_sar);
f7b775a9 3398 } else {
aac0f603 3399 TCGv_i64 tmp = tcg_temp_new_i64();
e1d635e8 3400
6fd0c7bc
RH
3401 tcg_gen_ext32u_i64(dest, src2);
3402 tcg_gen_andi_i64(tmp, cpu_sar, 31);
3403 tcg_gen_shr_i64(dest, dest, tmp);
f7b775a9
RH
3404 }
3405 } else if (a->r1 == a->r2) {
3406 if (a->d) {
6fd0c7bc 3407 tcg_gen_rotr_i64(dest, src2, cpu_sar);
f7b775a9
RH
3408 } else {
3409 TCGv_i32 t32 = tcg_temp_new_i32();
3410 TCGv_i32 s32 = tcg_temp_new_i32();
3411
6fd0c7bc
RH
3412 tcg_gen_extrl_i64_i32(t32, src2);
3413 tcg_gen_extrl_i64_i32(s32, cpu_sar);
f7b775a9
RH
3414 tcg_gen_andi_i32(s32, s32, 31);
3415 tcg_gen_rotr_i32(t32, t32, s32);
6fd0c7bc 3416 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3417 }
0b1347d2 3418 } else {
6fd0c7bc 3419 TCGv_i64 src1 = load_gpr(ctx, a->r1);
f7b775a9
RH
3420
3421 if (a->d) {
aac0f603
RH
3422 TCGv_i64 t = tcg_temp_new_i64();
3423 TCGv_i64 n = tcg_temp_new_i64();
6fd0c7bc
RH
3424
3425 tcg_gen_xori_i64(n, cpu_sar, 63);
3426 tcg_gen_shl_i64(t, src2, n);
3427 tcg_gen_shli_i64(t, t, 1);
3428 tcg_gen_shr_i64(dest, src1, cpu_sar);
3429 tcg_gen_or_i64(dest, dest, t);
f7b775a9
RH
3430 } else {
3431 TCGv_i64 t = tcg_temp_new_i64();
3432 TCGv_i64 s = tcg_temp_new_i64();
3433
6fd0c7bc 3434 tcg_gen_concat32_i64(t, src2, src1);
967662cd
RH
3435 tcg_gen_andi_i64(s, cpu_sar, 31);
3436 tcg_gen_shr_i64(dest, t, s);
f7b775a9 3437 }
0b1347d2 3438 }
30878590 3439 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3440
3441 /* Install the new nullification. */
3442 cond_free(&ctx->null_cond);
30878590 3443 if (a->c) {
4fa52edf 3444 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3445 }
31234768 3446 return nullify_end(ctx);
0b1347d2
RH
3447}
3448
f7b775a9 3449static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
0b1347d2 3450{
f7b775a9 3451 unsigned width, sa;
6fd0c7bc 3452 TCGv_i64 dest, t2;
0b1347d2 3453
f7b775a9
RH
3454 if (!ctx->is_pa20 && a->d) {
3455 return false;
3456 }
30878590 3457 if (a->c) {
0b1347d2
RH
3458 nullify_over(ctx);
3459 }
3460
f7b775a9
RH
3461 width = a->d ? 64 : 32;
3462 sa = width - 1 - a->cpos;
3463
30878590
RH
3464 dest = dest_gpr(ctx, a->t);
3465 t2 = load_gpr(ctx, a->r2);
05bfd4db 3466 if (a->r1 == 0) {
6fd0c7bc 3467 tcg_gen_extract_i64(dest, t2, sa, width - sa);
c53e401e 3468 } else if (width == TARGET_LONG_BITS) {
6fd0c7bc 3469 tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
0b1347d2 3470 } else {
f7b775a9
RH
3471 assert(!a->d);
3472 if (a->r1 == a->r2) {
3473 TCGv_i32 t32 = tcg_temp_new_i32();
6fd0c7bc 3474 tcg_gen_extrl_i64_i32(t32, t2);
f7b775a9 3475 tcg_gen_rotri_i32(t32, t32, sa);
6fd0c7bc 3476 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3477 } else {
967662cd
RH
3478 tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3479 tcg_gen_extract_i64(dest, dest, sa, 32);
f7b775a9 3480 }
0b1347d2 3481 }
30878590 3482 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3483
3484 /* Install the new nullification. */
3485 cond_free(&ctx->null_cond);
30878590 3486 if (a->c) {
4fa52edf 3487 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3488 }
31234768 3489 return nullify_end(ctx);
0b1347d2
RH
3490}
3491
bd792da3 3492static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
0b1347d2 3493{
bd792da3 3494 unsigned widthm1 = a->d ? 63 : 31;
6fd0c7bc 3495 TCGv_i64 dest, src, tmp;
0b1347d2 3496
bd792da3
RH
3497 if (!ctx->is_pa20 && a->d) {
3498 return false;
3499 }
30878590 3500 if (a->c) {
0b1347d2
RH
3501 nullify_over(ctx);
3502 }
3503
30878590
RH
3504 dest = dest_gpr(ctx, a->t);
3505 src = load_gpr(ctx, a->r);
aac0f603 3506 tmp = tcg_temp_new_i64();
0b1347d2
RH
3507
3508 /* Recall that SAR is using big-endian bit numbering. */
6fd0c7bc
RH
3509 tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
3510 tcg_gen_xori_i64(tmp, tmp, widthm1);
d781cb77 3511
30878590 3512 if (a->se) {
bd792da3 3513 if (!a->d) {
6fd0c7bc 3514 tcg_gen_ext32s_i64(dest, src);
bd792da3
RH
3515 src = dest;
3516 }
6fd0c7bc
RH
3517 tcg_gen_sar_i64(dest, src, tmp);
3518 tcg_gen_sextract_i64(dest, dest, 0, a->len);
0b1347d2 3519 } else {
bd792da3 3520 if (!a->d) {
6fd0c7bc 3521 tcg_gen_ext32u_i64(dest, src);
bd792da3
RH
3522 src = dest;
3523 }
6fd0c7bc
RH
3524 tcg_gen_shr_i64(dest, src, tmp);
3525 tcg_gen_extract_i64(dest, dest, 0, a->len);
0b1347d2 3526 }
30878590 3527 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3528
3529 /* Install the new nullification. */
3530 cond_free(&ctx->null_cond);
30878590 3531 if (a->c) {
bd792da3 3532 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3533 }
31234768 3534 return nullify_end(ctx);
0b1347d2
RH
3535}
3536
bd792da3 3537static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
0b1347d2 3538{
bd792da3 3539 unsigned len, cpos, width;
6fd0c7bc 3540 TCGv_i64 dest, src;
0b1347d2 3541
bd792da3
RH
3542 if (!ctx->is_pa20 && a->d) {
3543 return false;
3544 }
30878590 3545 if (a->c) {
0b1347d2
RH
3546 nullify_over(ctx);
3547 }
3548
bd792da3
RH
3549 len = a->len;
3550 width = a->d ? 64 : 32;
3551 cpos = width - 1 - a->pos;
3552 if (cpos + len > width) {
3553 len = width - cpos;
3554 }
3555
30878590
RH
3556 dest = dest_gpr(ctx, a->t);
3557 src = load_gpr(ctx, a->r);
3558 if (a->se) {
6fd0c7bc 3559 tcg_gen_sextract_i64(dest, src, cpos, len);
0b1347d2 3560 } else {
6fd0c7bc 3561 tcg_gen_extract_i64(dest, src, cpos, len);
0b1347d2 3562 }
30878590 3563 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3564
3565 /* Install the new nullification. */
3566 cond_free(&ctx->null_cond);
30878590 3567 if (a->c) {
bd792da3 3568 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3569 }
31234768 3570 return nullify_end(ctx);
0b1347d2
RH
3571}
3572
72ae4f2b 3573static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
0b1347d2 3574{
72ae4f2b 3575 unsigned len, width;
c53e401e 3576 uint64_t mask0, mask1;
6fd0c7bc 3577 TCGv_i64 dest;
0b1347d2 3578
72ae4f2b
RH
3579 if (!ctx->is_pa20 && a->d) {
3580 return false;
3581 }
30878590 3582 if (a->c) {
0b1347d2
RH
3583 nullify_over(ctx);
3584 }
72ae4f2b
RH
3585
3586 len = a->len;
3587 width = a->d ? 64 : 32;
3588 if (a->cpos + len > width) {
3589 len = width - a->cpos;
0b1347d2
RH
3590 }
3591
30878590
RH
3592 dest = dest_gpr(ctx, a->t);
3593 mask0 = deposit64(0, a->cpos, len, a->i);
3594 mask1 = deposit64(-1, a->cpos, len, a->i);
0b1347d2 3595
30878590 3596 if (a->nz) {
6fd0c7bc
RH
3597 TCGv_i64 src = load_gpr(ctx, a->t);
3598 tcg_gen_andi_i64(dest, src, mask1);
3599 tcg_gen_ori_i64(dest, dest, mask0);
0b1347d2 3600 } else {
6fd0c7bc 3601 tcg_gen_movi_i64(dest, mask0);
0b1347d2 3602 }
30878590 3603 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3604
3605 /* Install the new nullification. */
3606 cond_free(&ctx->null_cond);
30878590 3607 if (a->c) {
72ae4f2b 3608 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3609 }
31234768 3610 return nullify_end(ctx);
0b1347d2
RH
3611}
3612
72ae4f2b 3613static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
0b1347d2 3614{
30878590 3615 unsigned rs = a->nz ? a->t : 0;
72ae4f2b 3616 unsigned len, width;
6fd0c7bc 3617 TCGv_i64 dest, val;
0b1347d2 3618
72ae4f2b
RH
3619 if (!ctx->is_pa20 && a->d) {
3620 return false;
3621 }
30878590 3622 if (a->c) {
0b1347d2
RH
3623 nullify_over(ctx);
3624 }
72ae4f2b
RH
3625
3626 len = a->len;
3627 width = a->d ? 64 : 32;
3628 if (a->cpos + len > width) {
3629 len = width - a->cpos;
0b1347d2
RH
3630 }
3631
30878590
RH
3632 dest = dest_gpr(ctx, a->t);
3633 val = load_gpr(ctx, a->r);
0b1347d2 3634 if (rs == 0) {
6fd0c7bc 3635 tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
0b1347d2 3636 } else {
6fd0c7bc 3637 tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
0b1347d2 3638 }
30878590 3639 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3640
3641 /* Install the new nullification. */
3642 cond_free(&ctx->null_cond);
30878590 3643 if (a->c) {
72ae4f2b 3644 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3645 }
31234768 3646 return nullify_end(ctx);
0b1347d2
RH
3647}
3648
72ae4f2b 3649static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
6fd0c7bc 3650 bool d, bool nz, unsigned len, TCGv_i64 val)
0b1347d2 3651{
0b1347d2 3652 unsigned rs = nz ? rt : 0;
72ae4f2b 3653 unsigned widthm1 = d ? 63 : 31;
6fd0c7bc 3654 TCGv_i64 mask, tmp, shift, dest;
c53e401e 3655 uint64_t msb = 1ULL << (len - 1);
0b1347d2 3656
0b1347d2 3657 dest = dest_gpr(ctx, rt);
aac0f603
RH
3658 shift = tcg_temp_new_i64();
3659 tmp = tcg_temp_new_i64();
0b1347d2
RH
3660
3661 /* Convert big-endian bit numbering in SAR to left-shift. */
6fd0c7bc
RH
3662 tcg_gen_andi_i64(shift, cpu_sar, widthm1);
3663 tcg_gen_xori_i64(shift, shift, widthm1);
0b1347d2 3664
aac0f603 3665 mask = tcg_temp_new_i64();
6fd0c7bc
RH
3666 tcg_gen_movi_i64(mask, msb + (msb - 1));
3667 tcg_gen_and_i64(tmp, val, mask);
0b1347d2 3668 if (rs) {
6fd0c7bc
RH
3669 tcg_gen_shl_i64(mask, mask, shift);
3670 tcg_gen_shl_i64(tmp, tmp, shift);
3671 tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
3672 tcg_gen_or_i64(dest, dest, tmp);
0b1347d2 3673 } else {
6fd0c7bc 3674 tcg_gen_shl_i64(dest, tmp, shift);
0b1347d2 3675 }
0b1347d2
RH
3676 save_gpr(ctx, rt, dest);
3677
3678 /* Install the new nullification. */
3679 cond_free(&ctx->null_cond);
3680 if (c) {
72ae4f2b 3681 ctx->null_cond = do_sed_cond(ctx, c, d, dest);
0b1347d2 3682 }
31234768 3683 return nullify_end(ctx);
0b1347d2
RH
3684}
3685
72ae4f2b 3686static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
30878590 3687{
72ae4f2b
RH
3688 if (!ctx->is_pa20 && a->d) {
3689 return false;
3690 }
a6deecce
SS
3691 if (a->c) {
3692 nullify_over(ctx);
3693 }
72ae4f2b
RH
3694 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
3695 load_gpr(ctx, a->r));
30878590
RH
3696}
3697
72ae4f2b 3698static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
30878590 3699{
72ae4f2b
RH
3700 if (!ctx->is_pa20 && a->d) {
3701 return false;
3702 }
a6deecce
SS
3703 if (a->c) {
3704 nullify_over(ctx);
3705 }
72ae4f2b 3706 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
6fd0c7bc 3707 tcg_constant_i64(a->i));
30878590 3708}
0b1347d2 3709
8340f534 3710static bool trans_be(DisasContext *ctx, arg_be *a)
98cd9ca7 3711{
6fd0c7bc 3712 TCGv_i64 tmp;
98cd9ca7 3713
c301f34e 3714#ifdef CONFIG_USER_ONLY
98cd9ca7
RH
3715 /* ??? It seems like there should be a good way of using
3716 "be disp(sr2, r0)", the canonical gateway entry mechanism
3717 to our advantage. But that appears to be inconvenient to
3718 manage along side branch delay slots. Therefore we handle
3719 entry into the gateway page via absolute address. */
98cd9ca7
RH
3720 /* Since we don't implement spaces, just branch. Do notice the special
3721 case of "be disp(*,r0)" using a direct branch to disp, so that we can
3722 goto_tb to the TB containing the syscall. */
8340f534
RH
3723 if (a->b == 0) {
3724 return do_dbranch(ctx, a->disp, a->l, a->n);
98cd9ca7 3725 }
c301f34e 3726#else
c301f34e 3727 nullify_over(ctx);
660eefe1
RH
3728#endif
3729
aac0f603 3730 tmp = tcg_temp_new_i64();
6fd0c7bc 3731 tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
660eefe1 3732 tmp = do_ibranch_priv(ctx, tmp);
c301f34e
RH
3733
3734#ifdef CONFIG_USER_ONLY
8340f534 3735 return do_ibranch(ctx, tmp, a->l, a->n);
c301f34e
RH
3736#else
3737 TCGv_i64 new_spc = tcg_temp_new_i64();
3738
8340f534
RH
3739 load_spr(ctx, new_spc, a->sp);
3740 if (a->l) {
741322f4 3741 copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e
RH
3742 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3743 }
8340f534 3744 if (a->n && use_nullify_skip(ctx)) {
a0180973 3745 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
6fd0c7bc 3746 tcg_gen_addi_i64(tmp, tmp, 4);
a0180973 3747 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e
RH
3748 tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3749 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3750 } else {
741322f4 3751 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3752 if (ctx->iaoq_b == -1) {
3753 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3754 }
a0180973 3755 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e 3756 tcg_gen_mov_i64(cpu_iasq_b, new_spc);
8340f534 3757 nullify_set(ctx, a->n);
c301f34e 3758 }
c301f34e 3759 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3760 ctx->base.is_jmp = DISAS_NORETURN;
3761 return nullify_end(ctx);
c301f34e 3762#endif
98cd9ca7
RH
3763}
3764
8340f534 3765static bool trans_bl(DisasContext *ctx, arg_bl *a)
98cd9ca7 3766{
8340f534 3767 return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
98cd9ca7
RH
3768}
3769
8340f534 3770static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
43e05652 3771{
c53e401e 3772 uint64_t dest = iaoq_dest(ctx, a->disp);
43e05652 3773
6e5f5300
SS
3774 nullify_over(ctx);
3775
43e05652
RH
3776 /* Make sure the caller hasn't done something weird with the queue.
3777 * ??? This is not quite the same as the PSW[B] bit, which would be
3778 * expensive to track. Real hardware will trap for
3779 * b gateway
3780 * b gateway+4 (in delay slot of first branch)
3781 * However, checking for a non-sequential instruction queue *will*
3782 * diagnose the security hole
3783 * b gateway
3784 * b evil
3785 * in which instructions at evil would run with increased privs.
3786 */
3787 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
3788 return gen_illegal(ctx);
3789 }
3790
3791#ifndef CONFIG_USER_ONLY
3792 if (ctx->tb_flags & PSW_C) {
b77af26e 3793 CPUHPPAState *env = cpu_env(ctx->cs);
43e05652
RH
3794 int type = hppa_artype_for_page(env, ctx->base.pc_next);
3795 /* If we could not find a TLB entry, then we need to generate an
3796 ITLB miss exception so the kernel will provide it.
3797 The resulting TLB fill operation will invalidate this TB and
3798 we will re-translate, at which point we *will* be able to find
3799 the TLB entry and determine if this is in fact a gateway page. */
3800 if (type < 0) {
31234768
RH
3801 gen_excp(ctx, EXCP_ITLB_MISS);
3802 return true;
43e05652
RH
3803 }
3804 /* No change for non-gateway pages or for priv decrease. */
3805 if (type >= 4 && type - 4 < ctx->privilege) {
3806 dest = deposit32(dest, 0, 2, type - 4);
3807 }
3808 } else {
3809 dest &= -4; /* priv = 0 */
3810 }
3811#endif
3812
6e5f5300 3813 if (a->l) {
6fd0c7bc 3814 TCGv_i64 tmp = dest_gpr(ctx, a->l);
6e5f5300 3815 if (ctx->privilege < 3) {
6fd0c7bc 3816 tcg_gen_andi_i64(tmp, tmp, -4);
6e5f5300 3817 }
6fd0c7bc 3818 tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
6e5f5300
SS
3819 save_gpr(ctx, a->l, tmp);
3820 }
3821
3822 return do_dbranch(ctx, dest, 0, a->n);
43e05652
RH
3823}
3824
8340f534 3825static bool trans_blr(DisasContext *ctx, arg_blr *a)
98cd9ca7 3826{
b35aec85 3827 if (a->x) {
aac0f603 3828 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
3829 tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
3830 tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
b35aec85
RH
3831 /* The computation here never changes privilege level. */
3832 return do_ibranch(ctx, tmp, a->l, a->n);
3833 } else {
3834 /* BLR R0,RX is a good way to load PC+8 into RX. */
3835 return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3836 }
98cd9ca7
RH
3837}
3838
8340f534 3839static bool trans_bv(DisasContext *ctx, arg_bv *a)
98cd9ca7 3840{
6fd0c7bc 3841 TCGv_i64 dest;
98cd9ca7 3842
8340f534
RH
3843 if (a->x == 0) {
3844 dest = load_gpr(ctx, a->b);
98cd9ca7 3845 } else {
aac0f603 3846 dest = tcg_temp_new_i64();
6fd0c7bc
RH
3847 tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
3848 tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
98cd9ca7 3849 }
660eefe1 3850 dest = do_ibranch_priv(ctx, dest);
8340f534 3851 return do_ibranch(ctx, dest, 0, a->n);
98cd9ca7
RH
3852}
3853
8340f534 3854static bool trans_bve(DisasContext *ctx, arg_bve *a)
98cd9ca7 3855{
6fd0c7bc 3856 TCGv_i64 dest;
98cd9ca7 3857
c301f34e 3858#ifdef CONFIG_USER_ONLY
8340f534
RH
3859 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3860 return do_ibranch(ctx, dest, a->l, a->n);
c301f34e
RH
3861#else
3862 nullify_over(ctx);
8340f534 3863 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
c301f34e 3864
741322f4 3865 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3866 if (ctx->iaoq_b == -1) {
3867 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3868 }
741322f4 3869 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
c301f34e 3870 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
8340f534 3871 if (a->l) {
741322f4 3872 copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 3873 }
8340f534 3874 nullify_set(ctx, a->n);
c301f34e 3875 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3876 ctx->base.is_jmp = DISAS_NORETURN;
3877 return nullify_end(ctx);
c301f34e 3878#endif
98cd9ca7
RH
3879}
3880
a8966ba7
RH
3881static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3882{
3883 /* All branch target stack instructions implement as nop. */
3884 return ctx->is_pa20;
3885}
3886
1ca74648
RH
3887/*
3888 * Float class 0
3889 */
ebe9383c 3890
1ca74648 3891static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3892{
1ca74648 3893 tcg_gen_mov_i32(dst, src);
ebe9383c
RH
3894}
3895
59f8c04b
HD
3896static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
3897{
a300dad3
RH
3898 uint64_t ret;
3899
c53e401e 3900 if (ctx->is_pa20) {
a300dad3
RH
3901 ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3902 } else {
3903 ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3904 }
3905
59f8c04b 3906 nullify_over(ctx);
a300dad3 3907 save_frd(0, tcg_constant_i64(ret));
59f8c04b
HD
3908 return nullify_end(ctx);
3909}
3910
1ca74648 3911static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3912{
1ca74648 3913 return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
ebe9383c
RH
3914}
3915
1ca74648 3916static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3917{
1ca74648 3918 tcg_gen_mov_i64(dst, src);
ebe9383c
RH
3919}
3920
1ca74648 3921static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3922{
1ca74648 3923 return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
ebe9383c
RH
3924}
3925
1ca74648 3926static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3927{
1ca74648 3928 tcg_gen_andi_i32(dst, src, INT32_MAX);
ebe9383c
RH
3929}
3930
1ca74648 3931static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3932{
1ca74648 3933 return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
ebe9383c
RH
3934}
3935
1ca74648 3936static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3937{
1ca74648 3938 tcg_gen_andi_i64(dst, src, INT64_MAX);
ebe9383c
RH
3939}
3940
1ca74648 3941static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3942{
1ca74648 3943 return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
ebe9383c
RH
3944}
3945
1ca74648 3946static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3947{
1ca74648 3948 return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
ebe9383c
RH
3949}
3950
1ca74648 3951static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3952{
1ca74648 3953 return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
ebe9383c
RH
3954}
3955
1ca74648 3956static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3957{
1ca74648 3958 return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
ebe9383c
RH
3959}
3960
1ca74648 3961static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3962{
1ca74648 3963 return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
ebe9383c
RH
3964}
3965
1ca74648 3966static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3967{
1ca74648 3968 tcg_gen_xori_i32(dst, src, INT32_MIN);
ebe9383c
RH
3969}
3970
1ca74648 3971static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3972{
1ca74648 3973 return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
ebe9383c
RH
3974}
3975
3976static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3977{
3978 tcg_gen_xori_i64(dst, src, INT64_MIN);
3979}
3980
1ca74648
RH
3981static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
3982{
3983 return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
3984}
3985
3986static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c
RH
3987{
3988 tcg_gen_ori_i32(dst, src, INT32_MIN);
3989}
3990
1ca74648
RH
3991static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
3992{
3993 return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
3994}
3995
ebe9383c
RH
3996static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3997{
3998 tcg_gen_ori_i64(dst, src, INT64_MIN);
3999}
4000
1ca74648
RH
4001static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
4002{
4003 return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
4004}
4005
4006/*
4007 * Float class 1
4008 */
4009
4010static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
4011{
4012 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
4013}
4014
4015static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
4016{
4017 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
4018}
4019
4020static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
4021{
4022 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
4023}
4024
4025static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
4026{
4027 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
4028}
4029
4030static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
4031{
4032 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
4033}
4034
4035static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
4036{
4037 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
4038}
4039
4040static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
4041{
4042 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
4043}
4044
4045static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
4046{
4047 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
4048}
4049
4050static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
4051{
4052 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
4053}
4054
4055static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
4056{
4057 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
4058}
4059
4060static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
4061{
4062 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
4063}
4064
4065static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
4066{
4067 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
4068}
4069
4070static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
4071{
4072 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
4073}
4074
4075static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
4076{
4077 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
4078}
4079
4080static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
4081{
4082 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
4083}
4084
4085static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
4086{
4087 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
4088}
4089
4090static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
4091{
4092 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
4093}
4094
4095static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
4096{
4097 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
4098}
4099
4100static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
4101{
4102 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
4103}
4104
4105static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
4106{
4107 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
4108}
4109
4110static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
4111{
4112 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
4113}
4114
4115static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
4116{
4117 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
4118}
4119
4120static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
4121{
4122 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
4123}
4124
4125static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
4126{
4127 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
4128}
4129
4130static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
4131{
4132 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
4133}
4134
4135static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
4136{
4137 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
4138}
4139
4140/*
4141 * Float class 2
4142 */
4143
4144static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
ebe9383c
RH
4145{
4146 TCGv_i32 ta, tb, tc, ty;
4147
4148 nullify_over(ctx);
4149
1ca74648
RH
4150 ta = load_frw0_i32(a->r1);
4151 tb = load_frw0_i32(a->r2);
29dd6f64
RH
4152 ty = tcg_constant_i32(a->y);
4153 tc = tcg_constant_i32(a->c);
ebe9383c 4154
ad75a51e 4155 gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
ebe9383c 4156
1ca74648 4157 return nullify_end(ctx);
ebe9383c
RH
4158}
4159
1ca74648 4160static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
ebe9383c 4161{
ebe9383c
RH
4162 TCGv_i64 ta, tb;
4163 TCGv_i32 tc, ty;
4164
4165 nullify_over(ctx);
4166
1ca74648
RH
4167 ta = load_frd0(a->r1);
4168 tb = load_frd0(a->r2);
29dd6f64
RH
4169 ty = tcg_constant_i32(a->y);
4170 tc = tcg_constant_i32(a->c);
ebe9383c 4171
ad75a51e 4172 gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
ebe9383c 4173
31234768 4174 return nullify_end(ctx);
ebe9383c
RH
4175}
4176
1ca74648 4177static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
ebe9383c 4178{
6fd0c7bc 4179 TCGv_i64 t;
ebe9383c
RH
4180
4181 nullify_over(ctx);
4182
aac0f603 4183 t = tcg_temp_new_i64();
6fd0c7bc 4184 tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
ebe9383c 4185
1ca74648
RH
4186 if (a->y == 1) {
4187 int mask;
4188 bool inv = false;
4189
4190 switch (a->c) {
4191 case 0: /* simple */
6fd0c7bc 4192 tcg_gen_andi_i64(t, t, 0x4000000);
1ca74648
RH
4193 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4194 goto done;
4195 case 2: /* rej */
4196 inv = true;
4197 /* fallthru */
4198 case 1: /* acc */
4199 mask = 0x43ff800;
4200 break;
4201 case 6: /* rej8 */
4202 inv = true;
4203 /* fallthru */
4204 case 5: /* acc8 */
4205 mask = 0x43f8000;
4206 break;
4207 case 9: /* acc6 */
4208 mask = 0x43e0000;
4209 break;
4210 case 13: /* acc4 */
4211 mask = 0x4380000;
4212 break;
4213 case 17: /* acc2 */
4214 mask = 0x4200000;
4215 break;
4216 default:
4217 gen_illegal(ctx);
4218 return true;
4219 }
4220 if (inv) {
6fd0c7bc
RH
4221 TCGv_i64 c = tcg_constant_i64(mask);
4222 tcg_gen_or_i64(t, t, c);
1ca74648
RH
4223 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4224 } else {
6fd0c7bc 4225 tcg_gen_andi_i64(t, t, mask);
1ca74648
RH
4226 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4227 }
4228 } else {
4229 unsigned cbit = (a->y ^ 1) - 1;
4230
6fd0c7bc 4231 tcg_gen_extract_i64(t, t, 21 - cbit, 1);
1ca74648 4232 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
1ca74648
RH
4233 }
4234
4235 done:
31234768 4236 return nullify_end(ctx);
ebe9383c
RH
4237}
4238
1ca74648
RH
4239/*
4240 * Float class 2
4241 */
4242
4243static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 4244{
1ca74648
RH
4245 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
4246}
ebe9383c 4247
1ca74648
RH
4248static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
4249{
4250 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
4251}
ebe9383c 4252
1ca74648
RH
4253static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
4254{
4255 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
4256}
ebe9383c 4257
1ca74648
RH
4258static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
4259{
4260 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
ebe9383c
RH
4261}
4262
1ca74648 4263static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 4264{
1ca74648
RH
4265 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
4266}
4267
4268static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
4269{
4270 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
4271}
4272
4273static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
4274{
4275 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
4276}
4277
4278static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
4279{
4280 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
4281}
4282
4283static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
4284{
4285 TCGv_i64 x, y;
ebe9383c
RH
4286
4287 nullify_over(ctx);
4288
1ca74648
RH
4289 x = load_frw0_i64(a->r1);
4290 y = load_frw0_i64(a->r2);
4291 tcg_gen_mul_i64(x, x, y);
4292 save_frd(a->t, x);
ebe9383c 4293
31234768 4294 return nullify_end(ctx);
ebe9383c
RH
4295}
4296
ebe9383c
RH
4297/* Convert the fmpyadd single-precision register encodings to standard. */
4298static inline int fmpyadd_s_reg(unsigned r)
4299{
4300 return (r & 16) * 2 + 16 + (r & 15);
4301}
4302
b1e2af57 4303static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
ebe9383c 4304{
b1e2af57
RH
4305 int tm = fmpyadd_s_reg(a->tm);
4306 int ra = fmpyadd_s_reg(a->ra);
4307 int ta = fmpyadd_s_reg(a->ta);
4308 int rm2 = fmpyadd_s_reg(a->rm2);
4309 int rm1 = fmpyadd_s_reg(a->rm1);
ebe9383c
RH
4310
4311 nullify_over(ctx);
4312
b1e2af57
RH
4313 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4314 do_fop_weww(ctx, ta, ta, ra,
4315 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
ebe9383c 4316
31234768 4317 return nullify_end(ctx);
ebe9383c
RH
4318}
4319
b1e2af57
RH
4320static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4321{
4322 return do_fmpyadd_s(ctx, a, false);
4323}
4324
4325static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4326{
4327 return do_fmpyadd_s(ctx, a, true);
4328}
4329
4330static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4331{
4332 nullify_over(ctx);
4333
4334 do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4335 do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4336 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4337
4338 return nullify_end(ctx);
4339}
4340
4341static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4342{
4343 return do_fmpyadd_d(ctx, a, false);
4344}
4345
4346static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4347{
4348 return do_fmpyadd_d(ctx, a, true);
4349}
4350
c3bad4f8 4351static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
ebe9383c 4352{
c3bad4f8 4353 TCGv_i32 x, y, z;
ebe9383c
RH
4354
4355 nullify_over(ctx);
c3bad4f8
RH
4356 x = load_frw0_i32(a->rm1);
4357 y = load_frw0_i32(a->rm2);
4358 z = load_frw0_i32(a->ra3);
ebe9383c 4359
c3bad4f8 4360 if (a->neg) {
ad75a51e 4361 gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
ebe9383c 4362 } else {
ad75a51e 4363 gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
ebe9383c
RH
4364 }
4365
c3bad4f8 4366 save_frw_i32(a->t, x);
31234768 4367 return nullify_end(ctx);
ebe9383c
RH
4368}
4369
c3bad4f8 4370static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
ebe9383c 4371{
c3bad4f8 4372 TCGv_i64 x, y, z;
ebe9383c
RH
4373
4374 nullify_over(ctx);
c3bad4f8
RH
4375 x = load_frd0(a->rm1);
4376 y = load_frd0(a->rm2);
4377 z = load_frd0(a->ra3);
ebe9383c 4378
c3bad4f8 4379 if (a->neg) {
ad75a51e 4380 gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
ebe9383c 4381 } else {
ad75a51e 4382 gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
ebe9383c
RH
4383 }
4384
c3bad4f8 4385 save_frd(a->t, x);
31234768 4386 return nullify_end(ctx);
ebe9383c
RH
4387}
4388
15da177b
SS
4389static bool trans_diag(DisasContext *ctx, arg_diag *a)
4390{
cf6b28d4
HD
4391 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4392#ifndef CONFIG_USER_ONLY
4393 if (a->i == 0x100) {
4394 /* emulate PDC BTLB, called by SeaBIOS-hppa */
ad75a51e
RH
4395 nullify_over(ctx);
4396 gen_helper_diag_btlb(tcg_env);
4397 return nullify_end(ctx);
cf6b28d4 4398 }
ad75a51e
RH
4399#endif
4400 qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4401 return true;
15da177b
SS
4402}
4403
b542683d 4404static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
61766fe9 4405{
51b061fb 4406 DisasContext *ctx = container_of(dcbase, DisasContext, base);
f764718d 4407 int bound;
61766fe9 4408
51b061fb 4409 ctx->cs = cs;
494737b7 4410 ctx->tb_flags = ctx->base.tb->flags;
bd6243a3 4411 ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
3d68ee7b
RH
4412
4413#ifdef CONFIG_USER_ONLY
c01e5dfb 4414 ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
3d68ee7b 4415 ctx->mmu_idx = MMU_USER_IDX;
c01e5dfb
HD
4416 ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4417 ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
217d1a5e 4418 ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
3d68ee7b 4419#else
494737b7 4420 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
bb67ec32
RH
4421 ctx->mmu_idx = (ctx->tb_flags & PSW_D
4422 ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4423 : MMU_PHYS_IDX);
3d68ee7b 4424
c301f34e
RH
4425 /* Recover the IAOQ values from the GVA + PRIV. */
4426 uint64_t cs_base = ctx->base.tb->cs_base;
4427 uint64_t iasq_f = cs_base & ~0xffffffffull;
4428 int32_t diff = cs_base;
4429
4430 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4431 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4432#endif
51b061fb 4433 ctx->iaoq_n = -1;
f764718d 4434 ctx->iaoq_n_var = NULL;
61766fe9 4435
a4db4a78
RH
4436 ctx->zero = tcg_constant_i64(0);
4437
3d68ee7b
RH
4438 /* Bound the number of instructions by those left on the page. */
4439 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
b542683d 4440 ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
51b061fb 4441}
61766fe9 4442
51b061fb
RH
4443static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
4444{
4445 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4446
3d68ee7b 4447 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
51b061fb
RH
4448 ctx->null_cond = cond_make_f();
4449 ctx->psw_n_nonzero = false;
494737b7 4450 if (ctx->tb_flags & PSW_N) {
51b061fb
RH
4451 ctx->null_cond.c = TCG_COND_ALWAYS;
4452 ctx->psw_n_nonzero = true;
129e9cc3 4453 }
51b061fb
RH
4454 ctx->null_lab = NULL;
4455}
129e9cc3 4456
51b061fb
RH
4457static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
4458{
4459 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4460
51b061fb
RH
4461 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
4462}
4463
51b061fb
RH
4464static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
4465{
4466 DisasContext *ctx = container_of(dcbase, DisasContext, base);
b77af26e 4467 CPUHPPAState *env = cpu_env(cs);
51b061fb 4468 DisasJumpType ret;
51b061fb
RH
4469
4470 /* Execute one insn. */
ba1d0b44 4471#ifdef CONFIG_USER_ONLY
c301f34e 4472 if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
31234768
RH
4473 do_page_zero(ctx);
4474 ret = ctx->base.is_jmp;
51b061fb 4475 assert(ret != DISAS_NEXT);
ba1d0b44
RH
4476 } else
4477#endif
4478 {
51b061fb
RH
4479 /* Always fetch the insn, even if nullified, so that we check
4480 the page permissions for execute. */
4e116893 4481 uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
51b061fb
RH
4482
4483 /* Set up the IA queue for the next insn.
4484 This will be overwritten by a branch. */
4485 if (ctx->iaoq_b == -1) {
4486 ctx->iaoq_n = -1;
aac0f603 4487 ctx->iaoq_n_var = tcg_temp_new_i64();
6fd0c7bc 4488 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
7ad439df 4489 } else {
51b061fb 4490 ctx->iaoq_n = ctx->iaoq_b + 4;
f764718d 4491 ctx->iaoq_n_var = NULL;
61766fe9
RH
4492 }
4493
51b061fb
RH
4494 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
4495 ctx->null_cond.c = TCG_COND_NEVER;
4496 ret = DISAS_NEXT;
4497 } else {
1a19da0d 4498 ctx->insn = insn;
31274b46
RH
4499 if (!decode(ctx, insn)) {
4500 gen_illegal(ctx);
4501 }
31234768 4502 ret = ctx->base.is_jmp;
51b061fb 4503 assert(ctx->null_lab == NULL);
61766fe9 4504 }
51b061fb 4505 }
61766fe9 4506
3d68ee7b
RH
4507 /* Advance the insn queue. Note that this check also detects
4508 a priority change within the instruction queue. */
51b061fb 4509 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
c301f34e
RH
4510 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4511 && use_goto_tb(ctx, ctx->iaoq_b)
4512 && (ctx->null_cond.c == TCG_COND_NEVER
4513 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
51b061fb
RH
4514 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4515 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
31234768 4516 ctx->base.is_jmp = ret = DISAS_NORETURN;
51b061fb 4517 } else {
31234768 4518 ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
c301f34e 4519 }
61766fe9 4520 }
51b061fb
RH
4521 ctx->iaoq_f = ctx->iaoq_b;
4522 ctx->iaoq_b = ctx->iaoq_n;
c301f34e 4523 ctx->base.pc_next += 4;
51b061fb 4524
c5d0aec2
RH
4525 switch (ret) {
4526 case DISAS_NORETURN:
4527 case DISAS_IAQ_N_UPDATED:
4528 break;
4529
4530 case DISAS_NEXT:
4531 case DISAS_IAQ_N_STALE:
4532 case DISAS_IAQ_N_STALE_EXIT:
4533 if (ctx->iaoq_f == -1) {
a0180973 4534 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
741322f4 4535 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 4536#ifndef CONFIG_USER_ONLY
c5d0aec2 4537 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
c301f34e 4538#endif
c5d0aec2
RH
4539 nullify_save(ctx);
4540 ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4541 ? DISAS_EXIT
4542 : DISAS_IAQ_N_UPDATED);
4543 } else if (ctx->iaoq_b == -1) {
a0180973 4544 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
c5d0aec2
RH
4545 }
4546 break;
4547
4548 default:
4549 g_assert_not_reached();
51b061fb
RH
4550 }
4551}
4552
4553static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
4554{
4555 DisasContext *ctx = container_of(dcbase, DisasContext, base);
e1b5a5ed 4556 DisasJumpType is_jmp = ctx->base.is_jmp;
61766fe9 4557
e1b5a5ed 4558 switch (is_jmp) {
869051ea 4559 case DISAS_NORETURN:
61766fe9 4560 break;
51b061fb 4561 case DISAS_TOO_MANY:
869051ea 4562 case DISAS_IAQ_N_STALE:
e1b5a5ed 4563 case DISAS_IAQ_N_STALE_EXIT:
741322f4
RH
4564 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4565 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
51b061fb 4566 nullify_save(ctx);
61766fe9 4567 /* FALLTHRU */
869051ea 4568 case DISAS_IAQ_N_UPDATED:
8532a14e 4569 if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
7f11636d 4570 tcg_gen_lookup_and_goto_ptr();
8532a14e 4571 break;
61766fe9 4572 }
c5d0aec2
RH
4573 /* FALLTHRU */
4574 case DISAS_EXIT:
4575 tcg_gen_exit_tb(NULL, 0);
61766fe9
RH
4576 break;
4577 default:
51b061fb 4578 g_assert_not_reached();
61766fe9 4579 }
51b061fb 4580}
61766fe9 4581
8eb806a7
RH
4582static void hppa_tr_disas_log(const DisasContextBase *dcbase,
4583 CPUState *cs, FILE *logfile)
51b061fb 4584{
c301f34e 4585 target_ulong pc = dcbase->pc_first;
61766fe9 4586
ba1d0b44
RH
4587#ifdef CONFIG_USER_ONLY
4588 switch (pc) {
51b061fb 4589 case 0x00:
8eb806a7 4590 fprintf(logfile, "IN:\n0x00000000: (null)\n");
ba1d0b44 4591 return;
51b061fb 4592 case 0xb0:
8eb806a7 4593 fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
ba1d0b44 4594 return;
51b061fb 4595 case 0xe0:
8eb806a7 4596 fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
ba1d0b44 4597 return;
51b061fb 4598 case 0x100:
8eb806a7 4599 fprintf(logfile, "IN:\n0x00000100: syscall\n");
ba1d0b44 4600 return;
61766fe9 4601 }
ba1d0b44
RH
4602#endif
4603
8eb806a7
RH
4604 fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
4605 target_disas(logfile, cs, pc, dcbase->tb->size);
51b061fb
RH
4606}
4607
4608static const TranslatorOps hppa_tr_ops = {
4609 .init_disas_context = hppa_tr_init_disas_context,
4610 .tb_start = hppa_tr_tb_start,
4611 .insn_start = hppa_tr_insn_start,
51b061fb
RH
4612 .translate_insn = hppa_tr_translate_insn,
4613 .tb_stop = hppa_tr_tb_stop,
4614 .disas_log = hppa_tr_disas_log,
4615};
4616
597f9b2d 4617void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
306c8721 4618 target_ulong pc, void *host_pc)
51b061fb
RH
4619{
4620 DisasContext ctx;
306c8721 4621 translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
61766fe9 4622}