]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/translate.c
target/hppa: Avoid async_safe_run_on_cpu on uniprocessor system
[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);
4845f015
SS
2063 reg = load_gpr(ctx, a->r);
2064
35136a77
RH
2065 switch (ctl) {
2066 case CR_IT:
ad75a51e 2067 gen_helper_write_interval_timer(tcg_env, reg);
35136a77 2068 break;
4f5f2548 2069 case CR_EIRR:
ad75a51e 2070 gen_helper_write_eirr(tcg_env, reg);
4f5f2548
RH
2071 break;
2072 case CR_EIEM:
ad75a51e 2073 gen_helper_write_eiem(tcg_env, reg);
31234768 2074 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
4f5f2548
RH
2075 break;
2076
35136a77
RH
2077 case CR_IIASQ:
2078 case CR_IIAOQ:
2079 /* FIXME: Respect PSW_Q bit */
2080 /* The write advances the queue and stores to the back element. */
aac0f603 2081 tmp = tcg_temp_new_i64();
6fd0c7bc 2082 tcg_gen_ld_i64(tmp, tcg_env,
35136a77 2083 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
6fd0c7bc
RH
2084 tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2085 tcg_gen_st_i64(reg, tcg_env,
35136a77
RH
2086 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
2087 break;
2088
d5de20bd
SS
2089 case CR_PID1:
2090 case CR_PID2:
2091 case CR_PID3:
2092 case CR_PID4:
6fd0c7bc 2093 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
d5de20bd 2094#ifndef CONFIG_USER_ONLY
ad75a51e 2095 gen_helper_change_prot_id(tcg_env);
d5de20bd
SS
2096#endif
2097 break;
2098
35136a77 2099 default:
6fd0c7bc 2100 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
35136a77
RH
2101 break;
2102 }
31234768 2103 return nullify_end(ctx);
4f5f2548 2104#endif
98a9cb79
RH
2105}
2106
c603e14a 2107static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
98a9cb79 2108{
aac0f603 2109 TCGv_i64 tmp = tcg_temp_new_i64();
98a9cb79 2110
6fd0c7bc
RH
2111 tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
2112 tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
98a9cb79 2113 save_or_nullify(ctx, cpu_sar, tmp);
98a9cb79
RH
2114
2115 cond_free(&ctx->null_cond);
31234768 2116 return true;
98a9cb79
RH
2117}
2118
e36f27ef 2119static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
98a9cb79 2120{
6fd0c7bc 2121 TCGv_i64 dest = dest_gpr(ctx, a->t);
98a9cb79 2122
2330504c
HD
2123#ifdef CONFIG_USER_ONLY
2124 /* We don't implement space registers in user mode. */
6fd0c7bc 2125 tcg_gen_movi_i64(dest, 0);
2330504c 2126#else
967662cd
RH
2127 tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2128 tcg_gen_shri_i64(dest, dest, 32);
2330504c 2129#endif
e36f27ef 2130 save_gpr(ctx, a->t, dest);
98a9cb79
RH
2131
2132 cond_free(&ctx->null_cond);
31234768 2133 return true;
98a9cb79
RH
2134}
2135
e36f27ef 2136static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
e1b5a5ed 2137{
e36f27ef
RH
2138 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2139#ifndef CONFIG_USER_ONLY
6fd0c7bc 2140 TCGv_i64 tmp;
e1b5a5ed 2141
e1b5a5ed
RH
2142 nullify_over(ctx);
2143
aac0f603 2144 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2145 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2146 tcg_gen_andi_i64(tmp, tmp, ~a->i);
ad75a51e 2147 gen_helper_swap_system_mask(tmp, tcg_env, tmp);
e36f27ef 2148 save_gpr(ctx, a->t, tmp);
e1b5a5ed
RH
2149
2150 /* Exit the TB to recognize new interrupts, e.g. PSW_M. */
31234768
RH
2151 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2152 return nullify_end(ctx);
e36f27ef 2153#endif
e1b5a5ed
RH
2154}
2155
e36f27ef 2156static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
e1b5a5ed 2157{
e36f27ef
RH
2158 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2159#ifndef CONFIG_USER_ONLY
6fd0c7bc 2160 TCGv_i64 tmp;
e1b5a5ed 2161
e1b5a5ed
RH
2162 nullify_over(ctx);
2163
aac0f603 2164 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2165 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
2166 tcg_gen_ori_i64(tmp, tmp, a->i);
ad75a51e 2167 gen_helper_swap_system_mask(tmp, tcg_env, tmp);
e36f27ef 2168 save_gpr(ctx, a->t, tmp);
e1b5a5ed
RH
2169
2170 /* Exit the TB to recognize new interrupts, e.g. PSW_I. */
31234768
RH
2171 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2172 return nullify_end(ctx);
e36f27ef 2173#endif
e1b5a5ed
RH
2174}
2175
c603e14a 2176static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
e1b5a5ed 2177{
e1b5a5ed 2178 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
c603e14a 2179#ifndef CONFIG_USER_ONLY
6fd0c7bc 2180 TCGv_i64 tmp, reg;
e1b5a5ed
RH
2181 nullify_over(ctx);
2182
c603e14a 2183 reg = load_gpr(ctx, a->r);
aac0f603 2184 tmp = tcg_temp_new_i64();
ad75a51e 2185 gen_helper_swap_system_mask(tmp, tcg_env, reg);
e1b5a5ed
RH
2186
2187 /* Exit the TB to recognize new interrupts. */
31234768
RH
2188 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
2189 return nullify_end(ctx);
c603e14a 2190#endif
e1b5a5ed 2191}
f49b3537 2192
e36f27ef 2193static bool do_rfi(DisasContext *ctx, bool rfi_r)
f49b3537 2194{
f49b3537 2195 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
e36f27ef 2196#ifndef CONFIG_USER_ONLY
f49b3537
RH
2197 nullify_over(ctx);
2198
e36f27ef 2199 if (rfi_r) {
ad75a51e 2200 gen_helper_rfi_r(tcg_env);
f49b3537 2201 } else {
ad75a51e 2202 gen_helper_rfi(tcg_env);
f49b3537 2203 }
31234768 2204 /* Exit the TB to recognize new interrupts. */
8532a14e 2205 tcg_gen_exit_tb(NULL, 0);
31234768 2206 ctx->base.is_jmp = DISAS_NORETURN;
f49b3537 2207
31234768 2208 return nullify_end(ctx);
e36f27ef
RH
2209#endif
2210}
2211
2212static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2213{
2214 return do_rfi(ctx, false);
2215}
2216
2217static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2218{
2219 return do_rfi(ctx, true);
f49b3537 2220}
6210db05 2221
96927adb
RH
2222static bool trans_halt(DisasContext *ctx, arg_halt *a)
2223{
2224 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
e36f27ef 2225#ifndef CONFIG_USER_ONLY
96927adb 2226 nullify_over(ctx);
ad75a51e 2227 gen_helper_halt(tcg_env);
96927adb
RH
2228 ctx->base.is_jmp = DISAS_NORETURN;
2229 return nullify_end(ctx);
2230#endif
2231}
2232
2233static bool trans_reset(DisasContext *ctx, arg_reset *a)
6210db05
HD
2234{
2235 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
96927adb 2236#ifndef CONFIG_USER_ONLY
6210db05 2237 nullify_over(ctx);
ad75a51e 2238 gen_helper_reset(tcg_env);
31234768
RH
2239 ctx->base.is_jmp = DISAS_NORETURN;
2240 return nullify_end(ctx);
96927adb 2241#endif
6210db05 2242}
e1b5a5ed 2243
4a4554c6
HD
2244static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2245{
2246 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2247#ifndef CONFIG_USER_ONLY
2248 nullify_over(ctx);
ad75a51e 2249 gen_helper_getshadowregs(tcg_env);
4a4554c6
HD
2250 return nullify_end(ctx);
2251#endif
2252}
2253
deee69a1 2254static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
98a9cb79 2255{
deee69a1 2256 if (a->m) {
6fd0c7bc
RH
2257 TCGv_i64 dest = dest_gpr(ctx, a->b);
2258 TCGv_i64 src1 = load_gpr(ctx, a->b);
2259 TCGv_i64 src2 = load_gpr(ctx, a->x);
98a9cb79 2260
deee69a1 2261 /* The only thing we need to do is the base register modification. */
6fd0c7bc 2262 tcg_gen_add_i64(dest, src1, src2);
deee69a1
RH
2263 save_gpr(ctx, a->b, dest);
2264 }
98a9cb79 2265 cond_free(&ctx->null_cond);
31234768 2266 return true;
98a9cb79
RH
2267}
2268
deee69a1 2269static bool trans_probe(DisasContext *ctx, arg_probe *a)
98a9cb79 2270{
6fd0c7bc 2271 TCGv_i64 dest, ofs;
eed14219 2272 TCGv_i32 level, want;
6fd0c7bc 2273 TCGv_i64 addr;
98a9cb79
RH
2274
2275 nullify_over(ctx);
2276
deee69a1
RH
2277 dest = dest_gpr(ctx, a->t);
2278 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
eed14219 2279
deee69a1 2280 if (a->imm) {
29dd6f64 2281 level = tcg_constant_i32(a->ri);
98a9cb79 2282 } else {
eed14219 2283 level = tcg_temp_new_i32();
6fd0c7bc 2284 tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
eed14219 2285 tcg_gen_andi_i32(level, level, 3);
98a9cb79 2286 }
29dd6f64 2287 want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
eed14219 2288
ad75a51e 2289 gen_helper_probe(dest, tcg_env, addr, level, want);
eed14219 2290
deee69a1 2291 save_gpr(ctx, a->t, dest);
31234768 2292 return nullify_end(ctx);
98a9cb79
RH
2293}
2294
deee69a1 2295static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
8d6ae7fb 2296{
8577f354
RH
2297 if (ctx->is_pa20) {
2298 return false;
2299 }
deee69a1
RH
2300 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2301#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2302 TCGv_i64 addr;
2303 TCGv_i64 ofs, reg;
8d6ae7fb 2304
8d6ae7fb
RH
2305 nullify_over(ctx);
2306
deee69a1
RH
2307 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2308 reg = load_gpr(ctx, a->r);
2309 if (a->addr) {
8577f354 2310 gen_helper_itlba_pa11(tcg_env, addr, reg);
8d6ae7fb 2311 } else {
8577f354 2312 gen_helper_itlbp_pa11(tcg_env, addr, reg);
8d6ae7fb
RH
2313 }
2314
32dc7569
SS
2315 /* Exit TB for TLB change if mmu is enabled. */
2316 if (ctx->tb_flags & PSW_C) {
31234768
RH
2317 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2318 }
2319 return nullify_end(ctx);
deee69a1 2320#endif
8d6ae7fb 2321}
63300a00 2322
eb25d10f 2323static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
63300a00 2324{
deee69a1
RH
2325 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2326#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2327 TCGv_i64 addr;
2328 TCGv_i64 ofs;
63300a00 2329
63300a00
RH
2330 nullify_over(ctx);
2331
deee69a1 2332 form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
eb25d10f
HD
2333
2334 /*
2335 * Page align now, rather than later, so that we can add in the
2336 * page_size field from pa2.0 from the low 4 bits of GR[b].
2337 */
2338 tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2339 if (ctx->is_pa20) {
2340 tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
63300a00 2341 }
eb25d10f
HD
2342
2343 if (local) {
2344 gen_helper_ptlb_l(tcg_env, addr);
63300a00 2345 } else {
ad75a51e 2346 gen_helper_ptlb(tcg_env, addr);
63300a00
RH
2347 }
2348
eb25d10f
HD
2349 if (a->m) {
2350 save_gpr(ctx, a->b, ofs);
2351 }
2352
2353 /* Exit TB for TLB change if mmu is enabled. */
2354 if (ctx->tb_flags & PSW_C) {
2355 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2356 }
2357 return nullify_end(ctx);
2358#endif
2359}
2360
2361static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2362{
2363 return do_pxtlb(ctx, a, false);
2364}
2365
2366static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2367{
2368 return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2369}
2370
2371static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2372{
2373 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2374#ifndef CONFIG_USER_ONLY
2375 nullify_over(ctx);
2376
2377 trans_nop_addrx(ctx, a);
2378 gen_helper_ptlbe(tcg_env);
2379
63300a00 2380 /* Exit TB for TLB change if mmu is enabled. */
6797c315
NH
2381 if (ctx->tb_flags & PSW_C) {
2382 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2383 }
2384 return nullify_end(ctx);
2385#endif
2386}
2387
2388/*
2389 * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
2390 * See
2391 * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
2392 * page 13-9 (195/206)
2393 */
2394static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
2395{
8577f354
RH
2396 if (ctx->is_pa20) {
2397 return false;
2398 }
6797c315
NH
2399 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2400#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2401 TCGv_i64 addr, atl, stl;
2402 TCGv_i64 reg;
6797c315
NH
2403
2404 nullify_over(ctx);
2405
2406 /*
2407 * FIXME:
2408 * if (not (pcxl or pcxl2))
2409 * return gen_illegal(ctx);
6797c315
NH
2410 */
2411
6fd0c7bc
RH
2412 atl = tcg_temp_new_i64();
2413 stl = tcg_temp_new_i64();
2414 addr = tcg_temp_new_i64();
6797c315 2415
ad75a51e 2416 tcg_gen_ld32u_i64(stl, tcg_env,
6797c315
NH
2417 a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
2418 : offsetof(CPUHPPAState, cr[CR_IIASQ]));
ad75a51e 2419 tcg_gen_ld32u_i64(atl, tcg_env,
6797c315
NH
2420 a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
2421 : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
2422 tcg_gen_shli_i64(stl, stl, 32);
d265360f 2423 tcg_gen_or_i64(addr, atl, stl);
6797c315
NH
2424
2425 reg = load_gpr(ctx, a->r);
2426 if (a->addr) {
8577f354 2427 gen_helper_itlba_pa11(tcg_env, addr, reg);
6797c315 2428 } else {
8577f354
RH
2429 gen_helper_itlbp_pa11(tcg_env, addr, reg);
2430 }
2431
2432 /* Exit TB for TLB change if mmu is enabled. */
2433 if (ctx->tb_flags & PSW_C) {
2434 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
6797c315 2435 }
8577f354
RH
2436 return nullify_end(ctx);
2437#endif
2438}
6797c315 2439
8577f354
RH
2440static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
2441{
2442 if (!ctx->is_pa20) {
2443 return false;
2444 }
2445 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2446#ifndef CONFIG_USER_ONLY
2447 nullify_over(ctx);
2448 {
2449 TCGv_i64 src1 = load_gpr(ctx, a->r1);
2450 TCGv_i64 src2 = load_gpr(ctx, a->r2);
2451
2452 if (a->data) {
2453 gen_helper_idtlbt_pa20(tcg_env, src1, src2);
2454 } else {
2455 gen_helper_iitlbt_pa20(tcg_env, src1, src2);
2456 }
2457 }
6797c315 2458 /* Exit TB for TLB change if mmu is enabled. */
32dc7569 2459 if (ctx->tb_flags & PSW_C) {
31234768
RH
2460 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2461 }
2462 return nullify_end(ctx);
deee69a1 2463#endif
63300a00 2464}
2dfcca9f 2465
deee69a1 2466static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
2dfcca9f 2467{
deee69a1
RH
2468 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2469#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2470 TCGv_i64 vaddr;
2471 TCGv_i64 ofs, paddr;
2dfcca9f 2472
2dfcca9f
RH
2473 nullify_over(ctx);
2474
deee69a1 2475 form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2dfcca9f 2476
aac0f603 2477 paddr = tcg_temp_new_i64();
ad75a51e 2478 gen_helper_lpa(paddr, tcg_env, vaddr);
2dfcca9f
RH
2479
2480 /* Note that physical address result overrides base modification. */
deee69a1
RH
2481 if (a->m) {
2482 save_gpr(ctx, a->b, ofs);
2dfcca9f 2483 }
deee69a1 2484 save_gpr(ctx, a->t, paddr);
2dfcca9f 2485
31234768 2486 return nullify_end(ctx);
deee69a1 2487#endif
2dfcca9f 2488}
43a97b81 2489
deee69a1 2490static bool trans_lci(DisasContext *ctx, arg_lci *a)
43a97b81 2491{
43a97b81
RH
2492 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2493
2494 /* The Coherence Index is an implementation-defined function of the
2495 physical address. Two addresses with the same CI have a coherent
2496 view of the cache. Our implementation is to return 0 for all,
2497 since the entire address space is coherent. */
a4db4a78 2498 save_gpr(ctx, a->t, ctx->zero);
43a97b81 2499
31234768
RH
2500 cond_free(&ctx->null_cond);
2501 return true;
43a97b81 2502}
98a9cb79 2503
faf97ba1 2504static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2505{
0c982a28
RH
2506 return do_add_reg(ctx, a, false, false, false, false);
2507}
b2167459 2508
faf97ba1 2509static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2510{
2511 return do_add_reg(ctx, a, true, false, false, false);
2512}
b2167459 2513
faf97ba1 2514static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2515{
2516 return do_add_reg(ctx, a, false, true, false, false);
b2167459
RH
2517}
2518
faf97ba1 2519static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2520{
0c982a28
RH
2521 return do_add_reg(ctx, a, false, false, false, true);
2522}
b2167459 2523
faf97ba1 2524static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2525{
2526 return do_add_reg(ctx, a, false, true, false, true);
2527}
b2167459 2528
63c427c6 2529static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2530{
2531 return do_sub_reg(ctx, a, false, false, false);
b2167459
RH
2532}
2533
63c427c6 2534static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2535{
0c982a28
RH
2536 return do_sub_reg(ctx, a, true, false, false);
2537}
b2167459 2538
63c427c6 2539static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2540{
2541 return do_sub_reg(ctx, a, false, false, true);
b2167459
RH
2542}
2543
63c427c6 2544static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2545{
0c982a28
RH
2546 return do_sub_reg(ctx, a, true, false, true);
2547}
2548
63c427c6 2549static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2550{
2551 return do_sub_reg(ctx, a, false, true, false);
2552}
2553
63c427c6 2554static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2555{
2556 return do_sub_reg(ctx, a, true, true, false);
2557}
2558
fa8e3bed 2559static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2560{
6fd0c7bc 2561 return do_log_reg(ctx, a, tcg_gen_andc_i64);
0c982a28
RH
2562}
2563
fa8e3bed 2564static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2565{
6fd0c7bc 2566 return do_log_reg(ctx, a, tcg_gen_and_i64);
0c982a28
RH
2567}
2568
fa8e3bed 2569static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2570{
2571 if (a->cf == 0) {
2572 unsigned r2 = a->r2;
2573 unsigned r1 = a->r1;
2574 unsigned rt = a->t;
b2167459 2575
7aee8189
RH
2576 if (rt == 0) { /* NOP */
2577 cond_free(&ctx->null_cond);
2578 return true;
2579 }
2580 if (r2 == 0) { /* COPY */
2581 if (r1 == 0) {
6fd0c7bc
RH
2582 TCGv_i64 dest = dest_gpr(ctx, rt);
2583 tcg_gen_movi_i64(dest, 0);
7aee8189
RH
2584 save_gpr(ctx, rt, dest);
2585 } else {
2586 save_gpr(ctx, rt, cpu_gr[r1]);
2587 }
2588 cond_free(&ctx->null_cond);
2589 return true;
2590 }
2591#ifndef CONFIG_USER_ONLY
2592 /* These are QEMU extensions and are nops in the real architecture:
2593 *
2594 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2595 * or %r31,%r31,%r31 -- death loop; offline cpu
2596 * currently implemented as idle.
2597 */
2598 if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
7aee8189
RH
2599 /* No need to check for supervisor, as userland can only pause
2600 until the next timer interrupt. */
2601 nullify_over(ctx);
2602
2603 /* Advance the instruction queue. */
741322f4
RH
2604 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2605 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
7aee8189
RH
2606 nullify_set(ctx, 0);
2607
2608 /* Tell the qemu main loop to halt until this cpu has work. */
ad75a51e 2609 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
29dd6f64 2610 offsetof(CPUState, halted) - offsetof(HPPACPU, env));
7aee8189
RH
2611 gen_excp_1(EXCP_HALTED);
2612 ctx->base.is_jmp = DISAS_NORETURN;
2613
2614 return nullify_end(ctx);
2615 }
2616#endif
b2167459 2617 }
6fd0c7bc 2618 return do_log_reg(ctx, a, tcg_gen_or_i64);
0c982a28 2619}
7aee8189 2620
fa8e3bed 2621static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2622{
6fd0c7bc 2623 return do_log_reg(ctx, a, tcg_gen_xor_i64);
b2167459
RH
2624}
2625
345aa35f 2626static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2627{
6fd0c7bc 2628 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2629
0c982a28 2630 if (a->cf) {
b2167459
RH
2631 nullify_over(ctx);
2632 }
0c982a28
RH
2633 tcg_r1 = load_gpr(ctx, a->r1);
2634 tcg_r2 = load_gpr(ctx, a->r2);
345aa35f 2635 do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
31234768 2636 return nullify_end(ctx);
b2167459
RH
2637}
2638
af240753 2639static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2640{
6fd0c7bc 2641 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2642
0c982a28 2643 if (a->cf) {
b2167459
RH
2644 nullify_over(ctx);
2645 }
0c982a28
RH
2646 tcg_r1 = load_gpr(ctx, a->r1);
2647 tcg_r2 = load_gpr(ctx, a->r2);
6fd0c7bc 2648 do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
31234768 2649 return nullify_end(ctx);
b2167459
RH
2650}
2651
af240753 2652static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
b2167459 2653{
6fd0c7bc 2654 TCGv_i64 tcg_r1, tcg_r2, tmp;
b2167459 2655
0c982a28 2656 if (a->cf) {
b2167459
RH
2657 nullify_over(ctx);
2658 }
0c982a28
RH
2659 tcg_r1 = load_gpr(ctx, a->r1);
2660 tcg_r2 = load_gpr(ctx, a->r2);
aac0f603 2661 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2662 tcg_gen_not_i64(tmp, tcg_r2);
2663 do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
31234768 2664 return nullify_end(ctx);
b2167459
RH
2665}
2666
af240753 2667static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2668{
2669 return do_uaddcm(ctx, a, false);
2670}
2671
af240753 2672static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2673{
2674 return do_uaddcm(ctx, a, true);
2675}
2676
af240753 2677static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
b2167459 2678{
6fd0c7bc 2679 TCGv_i64 tmp;
b2167459
RH
2680
2681 nullify_over(ctx);
2682
aac0f603 2683 tmp = tcg_temp_new_i64();
6fd0c7bc 2684 tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
b2167459 2685 if (!is_i) {
6fd0c7bc 2686 tcg_gen_not_i64(tmp, tmp);
b2167459 2687 }
6fd0c7bc
RH
2688 tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
2689 tcg_gen_muli_i64(tmp, tmp, 6);
af240753 2690 do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
6fd0c7bc 2691 is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
31234768 2692 return nullify_end(ctx);
b2167459
RH
2693}
2694
af240753 2695static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2696{
2697 return do_dcor(ctx, a, false);
2698}
2699
af240753 2700static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2701{
2702 return do_dcor(ctx, a, true);
2703}
2704
2705static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
b2167459 2706{
a4db4a78 2707 TCGv_i64 dest, add1, add2, addc, in1, in2;
6fd0c7bc 2708 TCGv_i64 cout;
b2167459
RH
2709
2710 nullify_over(ctx);
2711
0c982a28
RH
2712 in1 = load_gpr(ctx, a->r1);
2713 in2 = load_gpr(ctx, a->r2);
b2167459 2714
aac0f603
RH
2715 add1 = tcg_temp_new_i64();
2716 add2 = tcg_temp_new_i64();
2717 addc = tcg_temp_new_i64();
2718 dest = tcg_temp_new_i64();
b2167459
RH
2719
2720 /* Form R1 << 1 | PSW[CB]{8}. */
6fd0c7bc
RH
2721 tcg_gen_add_i64(add1, in1, in1);
2722 tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
b2167459 2723
72ca8753
RH
2724 /*
2725 * Add or subtract R2, depending on PSW[V]. Proper computation of
2726 * carry requires that we subtract via + ~R2 + 1, as described in
2727 * the manual. By extracting and masking V, we can produce the
2728 * proper inputs to the addition without movcond.
2729 */
6fd0c7bc
RH
2730 tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
2731 tcg_gen_xor_i64(add2, in2, addc);
2732 tcg_gen_andi_i64(addc, addc, 1);
72ca8753 2733
a4db4a78
RH
2734 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2735 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2736 addc, ctx->zero);
b2167459 2737
b2167459 2738 /* Write back the result register. */
0c982a28 2739 save_gpr(ctx, a->t, dest);
b2167459
RH
2740
2741 /* Write back PSW[CB]. */
6fd0c7bc
RH
2742 tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
2743 tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
b2167459
RH
2744
2745 /* Write back PSW[V] for the division step. */
72ca8753 2746 cout = get_psw_carry(ctx, false);
6fd0c7bc
RH
2747 tcg_gen_neg_i64(cpu_psw_v, cout);
2748 tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
b2167459
RH
2749
2750 /* Install the new nullification. */
0c982a28 2751 if (a->cf) {
6fd0c7bc 2752 TCGv_i64 sv = NULL;
b47a4a02 2753 if (cond_need_sv(a->cf >> 1)) {
b2167459
RH
2754 /* ??? The lshift is supposed to contribute to overflow. */
2755 sv = do_add_sv(ctx, dest, add1, add2);
2756 }
a751eb31 2757 ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
b2167459
RH
2758 }
2759
31234768 2760 return nullify_end(ctx);
b2167459
RH
2761}
2762
0588e061 2763static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
b2167459 2764{
0588e061
RH
2765 return do_add_imm(ctx, a, false, false);
2766}
b2167459 2767
0588e061
RH
2768static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
2769{
2770 return do_add_imm(ctx, a, true, false);
b2167459
RH
2771}
2772
0588e061 2773static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
b2167459 2774{
0588e061
RH
2775 return do_add_imm(ctx, a, false, true);
2776}
b2167459 2777
0588e061
RH
2778static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
2779{
2780 return do_add_imm(ctx, a, true, true);
2781}
b2167459 2782
0588e061
RH
2783static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
2784{
2785 return do_sub_imm(ctx, a, false);
2786}
b2167459 2787
0588e061
RH
2788static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
2789{
2790 return do_sub_imm(ctx, a, true);
b2167459
RH
2791}
2792
345aa35f 2793static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
b2167459 2794{
6fd0c7bc 2795 TCGv_i64 tcg_im, tcg_r2;
b2167459 2796
0588e061 2797 if (a->cf) {
b2167459
RH
2798 nullify_over(ctx);
2799 }
2800
6fd0c7bc 2801 tcg_im = tcg_constant_i64(a->i);
0588e061 2802 tcg_r2 = load_gpr(ctx, a->r);
345aa35f 2803 do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
b2167459 2804
31234768 2805 return nullify_end(ctx);
b2167459
RH
2806}
2807
0843563f
RH
2808static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
2809 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
2810{
2811 TCGv_i64 r1, r2, dest;
2812
2813 if (!ctx->is_pa20) {
2814 return false;
2815 }
2816
2817 nullify_over(ctx);
2818
2819 r1 = load_gpr(ctx, a->r1);
2820 r2 = load_gpr(ctx, a->r2);
2821 dest = dest_gpr(ctx, a->t);
2822
2823 fn(dest, r1, r2);
2824 save_gpr(ctx, a->t, dest);
2825
2826 return nullify_end(ctx);
2827}
2828
151f309b
RH
2829static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
2830 void (*fn)(TCGv_i64, TCGv_i64, int64_t))
2831{
2832 TCGv_i64 r, dest;
2833
2834 if (!ctx->is_pa20) {
2835 return false;
2836 }
2837
2838 nullify_over(ctx);
2839
2840 r = load_gpr(ctx, a->r);
2841 dest = dest_gpr(ctx, a->t);
2842
2843 fn(dest, r, a->i);
2844 save_gpr(ctx, a->t, dest);
2845
2846 return nullify_end(ctx);
2847}
2848
3bbb8e48
RH
2849static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
2850 void (*fn)(TCGv_i64, TCGv_i64,
2851 TCGv_i64, TCGv_i32))
2852{
2853 TCGv_i64 r1, r2, dest;
2854
2855 if (!ctx->is_pa20) {
2856 return false;
2857 }
2858
2859 nullify_over(ctx);
2860
2861 r1 = load_gpr(ctx, a->r1);
2862 r2 = load_gpr(ctx, a->r2);
2863 dest = dest_gpr(ctx, a->t);
2864
2865 fn(dest, r1, r2, tcg_constant_i32(a->sh));
2866 save_gpr(ctx, a->t, dest);
2867
2868 return nullify_end(ctx);
2869}
2870
0843563f
RH
2871static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
2872{
2873 return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
2874}
2875
2876static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
2877{
2878 return do_multimedia(ctx, a, gen_helper_hadd_ss);
2879}
2880
2881static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
2882{
2883 return do_multimedia(ctx, a, gen_helper_hadd_us);
2884}
2885
1b3cb7c8
RH
2886static bool trans_havg(DisasContext *ctx, arg_rrr *a)
2887{
2888 return do_multimedia(ctx, a, gen_helper_havg);
2889}
2890
151f309b
RH
2891static bool trans_hshl(DisasContext *ctx, arg_rri *a)
2892{
2893 return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
2894}
2895
2896static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
2897{
2898 return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
2899}
2900
2901static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
2902{
2903 return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
2904}
2905
3bbb8e48
RH
2906static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
2907{
2908 return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
2909}
2910
2911static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
2912{
2913 return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
2914}
2915
10c9e58d
RH
2916static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
2917{
2918 return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
2919}
2920
2921static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
2922{
2923 return do_multimedia(ctx, a, gen_helper_hsub_ss);
2924}
2925
2926static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
2927{
2928 return do_multimedia(ctx, a, gen_helper_hsub_us);
2929}
2930
c2a7ee3f
RH
2931static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2932{
2933 uint64_t mask = 0xffff0000ffff0000ull;
2934 TCGv_i64 tmp = tcg_temp_new_i64();
2935
2936 tcg_gen_andi_i64(tmp, r2, mask);
2937 tcg_gen_andi_i64(dst, r1, mask);
2938 tcg_gen_shri_i64(tmp, tmp, 16);
2939 tcg_gen_or_i64(dst, dst, tmp);
2940}
2941
2942static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
2943{
2944 return do_multimedia(ctx, a, gen_mixh_l);
2945}
2946
2947static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2948{
2949 uint64_t mask = 0x0000ffff0000ffffull;
2950 TCGv_i64 tmp = tcg_temp_new_i64();
2951
2952 tcg_gen_andi_i64(tmp, r1, mask);
2953 tcg_gen_andi_i64(dst, r2, mask);
2954 tcg_gen_shli_i64(tmp, tmp, 16);
2955 tcg_gen_or_i64(dst, dst, tmp);
2956}
2957
2958static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
2959{
2960 return do_multimedia(ctx, a, gen_mixh_r);
2961}
2962
2963static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2964{
2965 TCGv_i64 tmp = tcg_temp_new_i64();
2966
2967 tcg_gen_shri_i64(tmp, r2, 32);
2968 tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
2969}
2970
2971static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
2972{
2973 return do_multimedia(ctx, a, gen_mixw_l);
2974}
2975
2976static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
2977{
2978 tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
2979}
2980
2981static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
2982{
2983 return do_multimedia(ctx, a, gen_mixw_r);
2984}
2985
4e7abdb1
RH
2986static bool trans_permh(DisasContext *ctx, arg_permh *a)
2987{
2988 TCGv_i64 r, t0, t1, t2, t3;
2989
2990 if (!ctx->is_pa20) {
2991 return false;
2992 }
2993
2994 nullify_over(ctx);
2995
2996 r = load_gpr(ctx, a->r1);
2997 t0 = tcg_temp_new_i64();
2998 t1 = tcg_temp_new_i64();
2999 t2 = tcg_temp_new_i64();
3000 t3 = tcg_temp_new_i64();
3001
3002 tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
3003 tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
3004 tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
3005 tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
3006
3007 tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
3008 tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
3009 tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
3010
3011 save_gpr(ctx, a->t, t0);
3012 return nullify_end(ctx);
3013}
3014
1cd012a5 3015static bool trans_ld(DisasContext *ctx, arg_ldst *a)
96d6407f 3016{
b5caa17c
RH
3017 if (ctx->is_pa20) {
3018 /*
3019 * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3020 * Any base modification still occurs.
3021 */
3022 if (a->t == 0) {
3023 return trans_nop_addrx(ctx, a);
3024 }
3025 } else if (a->size > MO_32) {
0786a3b6 3026 return gen_illegal(ctx);
0786a3b6 3027 }
c53e401e
RH
3028 return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
3029 a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
3030}
3031
1cd012a5 3032static bool trans_st(DisasContext *ctx, arg_ldst *a)
96d6407f 3033{
1cd012a5 3034 assert(a->x == 0 && a->scale == 0);
c53e401e 3035 if (!ctx->is_pa20 && a->size > MO_32) {
0786a3b6 3036 return gen_illegal(ctx);
0786a3b6 3037 }
c53e401e 3038 return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
3039}
3040
1cd012a5 3041static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
96d6407f 3042{
b1af755c 3043 MemOp mop = MO_TE | MO_ALIGN | a->size;
a4db4a78 3044 TCGv_i64 dest, ofs;
6fd0c7bc 3045 TCGv_i64 addr;
96d6407f 3046
c53e401e 3047 if (!ctx->is_pa20 && a->size > MO_32) {
51416c4e
RH
3048 return gen_illegal(ctx);
3049 }
3050
96d6407f
RH
3051 nullify_over(ctx);
3052
1cd012a5 3053 if (a->m) {
86f8d05f
RH
3054 /* Base register modification. Make sure if RT == RB,
3055 we see the result of the load. */
aac0f603 3056 dest = tcg_temp_new_i64();
96d6407f 3057 } else {
1cd012a5 3058 dest = dest_gpr(ctx, a->t);
96d6407f
RH
3059 }
3060
1cd012a5
RH
3061 form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
3062 a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
b1af755c
RH
3063
3064 /*
3065 * For hppa1.1, LDCW is undefined unless aligned mod 16.
3066 * However actual hardware succeeds with aligned mod 4.
3067 * Detect this case and log a GUEST_ERROR.
3068 *
3069 * TODO: HPPA64 relaxes the over-alignment requirement
3070 * with the ,co completer.
3071 */
3072 gen_helper_ldc_check(addr);
3073
a4db4a78 3074 tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
b1af755c 3075
1cd012a5
RH
3076 if (a->m) {
3077 save_gpr(ctx, a->b, ofs);
96d6407f 3078 }
1cd012a5 3079 save_gpr(ctx, a->t, dest);
96d6407f 3080
31234768 3081 return nullify_end(ctx);
96d6407f
RH
3082}
3083
1cd012a5 3084static bool trans_stby(DisasContext *ctx, arg_stby *a)
96d6407f 3085{
6fd0c7bc
RH
3086 TCGv_i64 ofs, val;
3087 TCGv_i64 addr;
96d6407f
RH
3088
3089 nullify_over(ctx);
3090
1cd012a5 3091 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
86f8d05f 3092 ctx->mmu_idx == MMU_PHYS_IDX);
1cd012a5
RH
3093 val = load_gpr(ctx, a->r);
3094 if (a->a) {
f9f46db4 3095 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 3096 gen_helper_stby_e_parallel(tcg_env, addr, val);
f9f46db4 3097 } else {
ad75a51e 3098 gen_helper_stby_e(tcg_env, addr, val);
f9f46db4 3099 }
96d6407f 3100 } else {
f9f46db4 3101 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 3102 gen_helper_stby_b_parallel(tcg_env, addr, val);
f9f46db4 3103 } else {
ad75a51e 3104 gen_helper_stby_b(tcg_env, addr, val);
f9f46db4 3105 }
96d6407f 3106 }
1cd012a5 3107 if (a->m) {
6fd0c7bc 3108 tcg_gen_andi_i64(ofs, ofs, ~3);
1cd012a5 3109 save_gpr(ctx, a->b, ofs);
96d6407f 3110 }
96d6407f 3111
31234768 3112 return nullify_end(ctx);
96d6407f
RH
3113}
3114
25460fc5
RH
3115static bool trans_stdby(DisasContext *ctx, arg_stby *a)
3116{
6fd0c7bc
RH
3117 TCGv_i64 ofs, val;
3118 TCGv_i64 addr;
25460fc5
RH
3119
3120 if (!ctx->is_pa20) {
3121 return false;
3122 }
3123 nullify_over(ctx);
3124
3125 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
3126 ctx->mmu_idx == MMU_PHYS_IDX);
3127 val = load_gpr(ctx, a->r);
3128 if (a->a) {
3129 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3130 gen_helper_stdby_e_parallel(tcg_env, addr, val);
3131 } else {
3132 gen_helper_stdby_e(tcg_env, addr, val);
3133 }
3134 } else {
3135 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3136 gen_helper_stdby_b_parallel(tcg_env, addr, val);
3137 } else {
3138 gen_helper_stdby_b(tcg_env, addr, val);
3139 }
3140 }
3141 if (a->m) {
6fd0c7bc 3142 tcg_gen_andi_i64(ofs, ofs, ~7);
25460fc5
RH
3143 save_gpr(ctx, a->b, ofs);
3144 }
3145
3146 return nullify_end(ctx);
3147}
3148
1cd012a5 3149static bool trans_lda(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
3150{
3151 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
3152
3153 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 3154 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 3155 trans_ld(ctx, a);
d0a851cc 3156 ctx->mmu_idx = hold_mmu_idx;
31234768 3157 return true;
d0a851cc
RH
3158}
3159
1cd012a5 3160static bool trans_sta(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
3161{
3162 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
3163
3164 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 3165 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 3166 trans_st(ctx, a);
d0a851cc 3167 ctx->mmu_idx = hold_mmu_idx;
31234768 3168 return true;
d0a851cc 3169}
95412a61 3170
0588e061 3171static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
b2167459 3172{
6fd0c7bc 3173 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459 3174
6fd0c7bc 3175 tcg_gen_movi_i64(tcg_rt, a->i);
0588e061 3176 save_gpr(ctx, a->t, tcg_rt);
b2167459 3177 cond_free(&ctx->null_cond);
31234768 3178 return true;
b2167459
RH
3179}
3180
0588e061 3181static bool trans_addil(DisasContext *ctx, arg_addil *a)
b2167459 3182{
6fd0c7bc
RH
3183 TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
3184 TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
b2167459 3185
6fd0c7bc 3186 tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
b2167459
RH
3187 save_gpr(ctx, 1, tcg_r1);
3188 cond_free(&ctx->null_cond);
31234768 3189 return true;
b2167459
RH
3190}
3191
0588e061 3192static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
b2167459 3193{
6fd0c7bc 3194 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459
RH
3195
3196 /* Special case rb == 0, for the LDI pseudo-op.
d265360f 3197 The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */
0588e061 3198 if (a->b == 0) {
6fd0c7bc 3199 tcg_gen_movi_i64(tcg_rt, a->i);
b2167459 3200 } else {
6fd0c7bc 3201 tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
b2167459 3202 }
0588e061 3203 save_gpr(ctx, a->t, tcg_rt);
b2167459 3204 cond_free(&ctx->null_cond);
31234768 3205 return true;
b2167459
RH
3206}
3207
6fd0c7bc 3208static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
e9efd4bc 3209 unsigned c, unsigned f, bool d, unsigned n, int disp)
98cd9ca7 3210{
6fd0c7bc 3211 TCGv_i64 dest, in2, sv;
98cd9ca7
RH
3212 DisasCond cond;
3213
98cd9ca7 3214 in2 = load_gpr(ctx, r);
aac0f603 3215 dest = tcg_temp_new_i64();
98cd9ca7 3216
6fd0c7bc 3217 tcg_gen_sub_i64(dest, in1, in2);
98cd9ca7 3218
f764718d 3219 sv = NULL;
b47a4a02 3220 if (cond_need_sv(c)) {
98cd9ca7
RH
3221 sv = do_sub_sv(ctx, dest, in1, in2);
3222 }
3223
4fe9533a 3224 cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
01afb7be 3225 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
3226}
3227
01afb7be 3228static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
98cd9ca7 3229{
e9efd4bc
RH
3230 if (!ctx->is_pa20 && a->d) {
3231 return false;
3232 }
01afb7be 3233 nullify_over(ctx);
e9efd4bc
RH
3234 return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3235 a->c, a->f, a->d, a->n, a->disp);
01afb7be 3236}
98cd9ca7 3237
01afb7be
RH
3238static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
3239{
c65c3ee1
RH
3240 if (!ctx->is_pa20 && a->d) {
3241 return false;
3242 }
98cd9ca7 3243 nullify_over(ctx);
6fd0c7bc 3244 return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
c65c3ee1 3245 a->c, a->f, a->d, a->n, a->disp);
01afb7be
RH
3246}
3247
6fd0c7bc 3248static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
01afb7be
RH
3249 unsigned c, unsigned f, unsigned n, int disp)
3250{
6fd0c7bc 3251 TCGv_i64 dest, in2, sv, cb_cond;
01afb7be 3252 DisasCond cond;
bdcccc17 3253 bool d = false;
98cd9ca7 3254
f25d3160
RH
3255 /*
3256 * For hppa64, the ADDB conditions change with PSW.W,
3257 * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3258 */
3259 if (ctx->tb_flags & PSW_W) {
3260 d = c >= 5;
3261 if (d) {
3262 c &= 3;
3263 }
3264 }
3265
98cd9ca7 3266 in2 = load_gpr(ctx, r);
aac0f603 3267 dest = tcg_temp_new_i64();
f764718d 3268 sv = NULL;
bdcccc17 3269 cb_cond = NULL;
98cd9ca7 3270
b47a4a02 3271 if (cond_need_cb(c)) {
aac0f603
RH
3272 TCGv_i64 cb = tcg_temp_new_i64();
3273 TCGv_i64 cb_msb = tcg_temp_new_i64();
bdcccc17 3274
6fd0c7bc
RH
3275 tcg_gen_movi_i64(cb_msb, 0);
3276 tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
3277 tcg_gen_xor_i64(cb, in1, in2);
3278 tcg_gen_xor_i64(cb, cb, dest);
bdcccc17 3279 cb_cond = get_carry(ctx, d, cb, cb_msb);
b47a4a02 3280 } else {
6fd0c7bc 3281 tcg_gen_add_i64(dest, in1, in2);
b47a4a02
SS
3282 }
3283 if (cond_need_sv(c)) {
98cd9ca7 3284 sv = do_add_sv(ctx, dest, in1, in2);
98cd9ca7
RH
3285 }
3286
a751eb31 3287 cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
43675d20 3288 save_gpr(ctx, r, dest);
01afb7be 3289 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
3290}
3291
01afb7be
RH
3292static bool trans_addb(DisasContext *ctx, arg_addb *a)
3293{
3294 nullify_over(ctx);
3295 return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
3296}
3297
3298static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
3299{
3300 nullify_over(ctx);
6fd0c7bc 3301 return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
01afb7be
RH
3302}
3303
3304static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
98cd9ca7 3305{
6fd0c7bc 3306 TCGv_i64 tmp, tcg_r;
98cd9ca7
RH
3307 DisasCond cond;
3308
3309 nullify_over(ctx);
3310
aac0f603 3311 tmp = tcg_temp_new_i64();
01afb7be 3312 tcg_r = load_gpr(ctx, a->r);
84e224d4 3313 if (cond_need_ext(ctx, a->d)) {
1e9ab9fb 3314 /* Force shift into [32,63] */
6fd0c7bc
RH
3315 tcg_gen_ori_i64(tmp, cpu_sar, 32);
3316 tcg_gen_shl_i64(tmp, tcg_r, tmp);
1e9ab9fb 3317 } else {
6fd0c7bc 3318 tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
1e9ab9fb 3319 }
98cd9ca7 3320
1e9ab9fb 3321 cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be 3322 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3323}
3324
01afb7be
RH
3325static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
3326{
6fd0c7bc 3327 TCGv_i64 tmp, tcg_r;
01afb7be 3328 DisasCond cond;
1e9ab9fb 3329 int p;
01afb7be
RH
3330
3331 nullify_over(ctx);
3332
aac0f603 3333 tmp = tcg_temp_new_i64();
01afb7be 3334 tcg_r = load_gpr(ctx, a->r);
84e224d4 3335 p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
6fd0c7bc 3336 tcg_gen_shli_i64(tmp, tcg_r, p);
01afb7be
RH
3337
3338 cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be
RH
3339 return do_cbranch(ctx, a->disp, a->n, &cond);
3340}
3341
3342static bool trans_movb(DisasContext *ctx, arg_movb *a)
98cd9ca7 3343{
6fd0c7bc 3344 TCGv_i64 dest;
98cd9ca7
RH
3345 DisasCond cond;
3346
3347 nullify_over(ctx);
3348
01afb7be
RH
3349 dest = dest_gpr(ctx, a->r2);
3350 if (a->r1 == 0) {
6fd0c7bc 3351 tcg_gen_movi_i64(dest, 0);
98cd9ca7 3352 } else {
6fd0c7bc 3353 tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
98cd9ca7
RH
3354 }
3355
4fa52edf
RH
3356 /* All MOVB conditions are 32-bit. */
3357 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be
RH
3358 return do_cbranch(ctx, a->disp, a->n, &cond);
3359}
3360
3361static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
3362{
6fd0c7bc 3363 TCGv_i64 dest;
01afb7be
RH
3364 DisasCond cond;
3365
3366 nullify_over(ctx);
3367
3368 dest = dest_gpr(ctx, a->r);
6fd0c7bc 3369 tcg_gen_movi_i64(dest, a->i);
01afb7be 3370
4fa52edf
RH
3371 /* All MOVBI conditions are 32-bit. */
3372 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be 3373 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3374}
3375
f7b775a9 3376static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
0b1347d2 3377{
6fd0c7bc 3378 TCGv_i64 dest, src2;
0b1347d2 3379
f7b775a9
RH
3380 if (!ctx->is_pa20 && a->d) {
3381 return false;
3382 }
30878590 3383 if (a->c) {
0b1347d2
RH
3384 nullify_over(ctx);
3385 }
3386
30878590 3387 dest = dest_gpr(ctx, a->t);
f7b775a9 3388 src2 = load_gpr(ctx, a->r2);
30878590 3389 if (a->r1 == 0) {
f7b775a9 3390 if (a->d) {
6fd0c7bc 3391 tcg_gen_shr_i64(dest, src2, cpu_sar);
f7b775a9 3392 } else {
aac0f603 3393 TCGv_i64 tmp = tcg_temp_new_i64();
e1d635e8 3394
6fd0c7bc
RH
3395 tcg_gen_ext32u_i64(dest, src2);
3396 tcg_gen_andi_i64(tmp, cpu_sar, 31);
3397 tcg_gen_shr_i64(dest, dest, tmp);
f7b775a9
RH
3398 }
3399 } else if (a->r1 == a->r2) {
3400 if (a->d) {
6fd0c7bc 3401 tcg_gen_rotr_i64(dest, src2, cpu_sar);
f7b775a9
RH
3402 } else {
3403 TCGv_i32 t32 = tcg_temp_new_i32();
3404 TCGv_i32 s32 = tcg_temp_new_i32();
3405
6fd0c7bc
RH
3406 tcg_gen_extrl_i64_i32(t32, src2);
3407 tcg_gen_extrl_i64_i32(s32, cpu_sar);
f7b775a9
RH
3408 tcg_gen_andi_i32(s32, s32, 31);
3409 tcg_gen_rotr_i32(t32, t32, s32);
6fd0c7bc 3410 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3411 }
0b1347d2 3412 } else {
6fd0c7bc 3413 TCGv_i64 src1 = load_gpr(ctx, a->r1);
f7b775a9
RH
3414
3415 if (a->d) {
aac0f603
RH
3416 TCGv_i64 t = tcg_temp_new_i64();
3417 TCGv_i64 n = tcg_temp_new_i64();
6fd0c7bc
RH
3418
3419 tcg_gen_xori_i64(n, cpu_sar, 63);
3420 tcg_gen_shl_i64(t, src2, n);
3421 tcg_gen_shli_i64(t, t, 1);
3422 tcg_gen_shr_i64(dest, src1, cpu_sar);
3423 tcg_gen_or_i64(dest, dest, t);
f7b775a9
RH
3424 } else {
3425 TCGv_i64 t = tcg_temp_new_i64();
3426 TCGv_i64 s = tcg_temp_new_i64();
3427
6fd0c7bc 3428 tcg_gen_concat32_i64(t, src2, src1);
967662cd
RH
3429 tcg_gen_andi_i64(s, cpu_sar, 31);
3430 tcg_gen_shr_i64(dest, t, s);
f7b775a9 3431 }
0b1347d2 3432 }
30878590 3433 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3434
3435 /* Install the new nullification. */
3436 cond_free(&ctx->null_cond);
30878590 3437 if (a->c) {
4fa52edf 3438 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3439 }
31234768 3440 return nullify_end(ctx);
0b1347d2
RH
3441}
3442
f7b775a9 3443static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
0b1347d2 3444{
f7b775a9 3445 unsigned width, sa;
6fd0c7bc 3446 TCGv_i64 dest, t2;
0b1347d2 3447
f7b775a9
RH
3448 if (!ctx->is_pa20 && a->d) {
3449 return false;
3450 }
30878590 3451 if (a->c) {
0b1347d2
RH
3452 nullify_over(ctx);
3453 }
3454
f7b775a9
RH
3455 width = a->d ? 64 : 32;
3456 sa = width - 1 - a->cpos;
3457
30878590
RH
3458 dest = dest_gpr(ctx, a->t);
3459 t2 = load_gpr(ctx, a->r2);
05bfd4db 3460 if (a->r1 == 0) {
6fd0c7bc 3461 tcg_gen_extract_i64(dest, t2, sa, width - sa);
c53e401e 3462 } else if (width == TARGET_LONG_BITS) {
6fd0c7bc 3463 tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
0b1347d2 3464 } else {
f7b775a9
RH
3465 assert(!a->d);
3466 if (a->r1 == a->r2) {
3467 TCGv_i32 t32 = tcg_temp_new_i32();
6fd0c7bc 3468 tcg_gen_extrl_i64_i32(t32, t2);
f7b775a9 3469 tcg_gen_rotri_i32(t32, t32, sa);
6fd0c7bc 3470 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3471 } else {
967662cd
RH
3472 tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3473 tcg_gen_extract_i64(dest, dest, sa, 32);
f7b775a9 3474 }
0b1347d2 3475 }
30878590 3476 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3477
3478 /* Install the new nullification. */
3479 cond_free(&ctx->null_cond);
30878590 3480 if (a->c) {
4fa52edf 3481 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3482 }
31234768 3483 return nullify_end(ctx);
0b1347d2
RH
3484}
3485
bd792da3 3486static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
0b1347d2 3487{
bd792da3 3488 unsigned widthm1 = a->d ? 63 : 31;
6fd0c7bc 3489 TCGv_i64 dest, src, tmp;
0b1347d2 3490
bd792da3
RH
3491 if (!ctx->is_pa20 && a->d) {
3492 return false;
3493 }
30878590 3494 if (a->c) {
0b1347d2
RH
3495 nullify_over(ctx);
3496 }
3497
30878590
RH
3498 dest = dest_gpr(ctx, a->t);
3499 src = load_gpr(ctx, a->r);
aac0f603 3500 tmp = tcg_temp_new_i64();
0b1347d2
RH
3501
3502 /* Recall that SAR is using big-endian bit numbering. */
6fd0c7bc
RH
3503 tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
3504 tcg_gen_xori_i64(tmp, tmp, widthm1);
d781cb77 3505
30878590 3506 if (a->se) {
bd792da3 3507 if (!a->d) {
6fd0c7bc 3508 tcg_gen_ext32s_i64(dest, src);
bd792da3
RH
3509 src = dest;
3510 }
6fd0c7bc
RH
3511 tcg_gen_sar_i64(dest, src, tmp);
3512 tcg_gen_sextract_i64(dest, dest, 0, a->len);
0b1347d2 3513 } else {
bd792da3 3514 if (!a->d) {
6fd0c7bc 3515 tcg_gen_ext32u_i64(dest, src);
bd792da3
RH
3516 src = dest;
3517 }
6fd0c7bc
RH
3518 tcg_gen_shr_i64(dest, src, tmp);
3519 tcg_gen_extract_i64(dest, dest, 0, a->len);
0b1347d2 3520 }
30878590 3521 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3522
3523 /* Install the new nullification. */
3524 cond_free(&ctx->null_cond);
30878590 3525 if (a->c) {
bd792da3 3526 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3527 }
31234768 3528 return nullify_end(ctx);
0b1347d2
RH
3529}
3530
bd792da3 3531static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
0b1347d2 3532{
bd792da3 3533 unsigned len, cpos, width;
6fd0c7bc 3534 TCGv_i64 dest, src;
0b1347d2 3535
bd792da3
RH
3536 if (!ctx->is_pa20 && a->d) {
3537 return false;
3538 }
30878590 3539 if (a->c) {
0b1347d2
RH
3540 nullify_over(ctx);
3541 }
3542
bd792da3
RH
3543 len = a->len;
3544 width = a->d ? 64 : 32;
3545 cpos = width - 1 - a->pos;
3546 if (cpos + len > width) {
3547 len = width - cpos;
3548 }
3549
30878590
RH
3550 dest = dest_gpr(ctx, a->t);
3551 src = load_gpr(ctx, a->r);
3552 if (a->se) {
6fd0c7bc 3553 tcg_gen_sextract_i64(dest, src, cpos, len);
0b1347d2 3554 } else {
6fd0c7bc 3555 tcg_gen_extract_i64(dest, src, cpos, len);
0b1347d2 3556 }
30878590 3557 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3558
3559 /* Install the new nullification. */
3560 cond_free(&ctx->null_cond);
30878590 3561 if (a->c) {
bd792da3 3562 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3563 }
31234768 3564 return nullify_end(ctx);
0b1347d2
RH
3565}
3566
72ae4f2b 3567static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
0b1347d2 3568{
72ae4f2b 3569 unsigned len, width;
c53e401e 3570 uint64_t mask0, mask1;
6fd0c7bc 3571 TCGv_i64 dest;
0b1347d2 3572
72ae4f2b
RH
3573 if (!ctx->is_pa20 && a->d) {
3574 return false;
3575 }
30878590 3576 if (a->c) {
0b1347d2
RH
3577 nullify_over(ctx);
3578 }
72ae4f2b
RH
3579
3580 len = a->len;
3581 width = a->d ? 64 : 32;
3582 if (a->cpos + len > width) {
3583 len = width - a->cpos;
0b1347d2
RH
3584 }
3585
30878590
RH
3586 dest = dest_gpr(ctx, a->t);
3587 mask0 = deposit64(0, a->cpos, len, a->i);
3588 mask1 = deposit64(-1, a->cpos, len, a->i);
0b1347d2 3589
30878590 3590 if (a->nz) {
6fd0c7bc
RH
3591 TCGv_i64 src = load_gpr(ctx, a->t);
3592 tcg_gen_andi_i64(dest, src, mask1);
3593 tcg_gen_ori_i64(dest, dest, mask0);
0b1347d2 3594 } else {
6fd0c7bc 3595 tcg_gen_movi_i64(dest, mask0);
0b1347d2 3596 }
30878590 3597 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3598
3599 /* Install the new nullification. */
3600 cond_free(&ctx->null_cond);
30878590 3601 if (a->c) {
72ae4f2b 3602 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3603 }
31234768 3604 return nullify_end(ctx);
0b1347d2
RH
3605}
3606
72ae4f2b 3607static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
0b1347d2 3608{
30878590 3609 unsigned rs = a->nz ? a->t : 0;
72ae4f2b 3610 unsigned len, width;
6fd0c7bc 3611 TCGv_i64 dest, val;
0b1347d2 3612
72ae4f2b
RH
3613 if (!ctx->is_pa20 && a->d) {
3614 return false;
3615 }
30878590 3616 if (a->c) {
0b1347d2
RH
3617 nullify_over(ctx);
3618 }
72ae4f2b
RH
3619
3620 len = a->len;
3621 width = a->d ? 64 : 32;
3622 if (a->cpos + len > width) {
3623 len = width - a->cpos;
0b1347d2
RH
3624 }
3625
30878590
RH
3626 dest = dest_gpr(ctx, a->t);
3627 val = load_gpr(ctx, a->r);
0b1347d2 3628 if (rs == 0) {
6fd0c7bc 3629 tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
0b1347d2 3630 } else {
6fd0c7bc 3631 tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
0b1347d2 3632 }
30878590 3633 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3634
3635 /* Install the new nullification. */
3636 cond_free(&ctx->null_cond);
30878590 3637 if (a->c) {
72ae4f2b 3638 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3639 }
31234768 3640 return nullify_end(ctx);
0b1347d2
RH
3641}
3642
72ae4f2b 3643static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
6fd0c7bc 3644 bool d, bool nz, unsigned len, TCGv_i64 val)
0b1347d2 3645{
0b1347d2 3646 unsigned rs = nz ? rt : 0;
72ae4f2b 3647 unsigned widthm1 = d ? 63 : 31;
6fd0c7bc 3648 TCGv_i64 mask, tmp, shift, dest;
c53e401e 3649 uint64_t msb = 1ULL << (len - 1);
0b1347d2 3650
0b1347d2 3651 dest = dest_gpr(ctx, rt);
aac0f603
RH
3652 shift = tcg_temp_new_i64();
3653 tmp = tcg_temp_new_i64();
0b1347d2
RH
3654
3655 /* Convert big-endian bit numbering in SAR to left-shift. */
6fd0c7bc
RH
3656 tcg_gen_andi_i64(shift, cpu_sar, widthm1);
3657 tcg_gen_xori_i64(shift, shift, widthm1);
0b1347d2 3658
aac0f603 3659 mask = tcg_temp_new_i64();
6fd0c7bc
RH
3660 tcg_gen_movi_i64(mask, msb + (msb - 1));
3661 tcg_gen_and_i64(tmp, val, mask);
0b1347d2 3662 if (rs) {
6fd0c7bc
RH
3663 tcg_gen_shl_i64(mask, mask, shift);
3664 tcg_gen_shl_i64(tmp, tmp, shift);
3665 tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
3666 tcg_gen_or_i64(dest, dest, tmp);
0b1347d2 3667 } else {
6fd0c7bc 3668 tcg_gen_shl_i64(dest, tmp, shift);
0b1347d2 3669 }
0b1347d2
RH
3670 save_gpr(ctx, rt, dest);
3671
3672 /* Install the new nullification. */
3673 cond_free(&ctx->null_cond);
3674 if (c) {
72ae4f2b 3675 ctx->null_cond = do_sed_cond(ctx, c, d, dest);
0b1347d2 3676 }
31234768 3677 return nullify_end(ctx);
0b1347d2
RH
3678}
3679
72ae4f2b 3680static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
30878590 3681{
72ae4f2b
RH
3682 if (!ctx->is_pa20 && a->d) {
3683 return false;
3684 }
a6deecce
SS
3685 if (a->c) {
3686 nullify_over(ctx);
3687 }
72ae4f2b
RH
3688 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
3689 load_gpr(ctx, a->r));
30878590
RH
3690}
3691
72ae4f2b 3692static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
30878590 3693{
72ae4f2b
RH
3694 if (!ctx->is_pa20 && a->d) {
3695 return false;
3696 }
a6deecce
SS
3697 if (a->c) {
3698 nullify_over(ctx);
3699 }
72ae4f2b 3700 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
6fd0c7bc 3701 tcg_constant_i64(a->i));
30878590 3702}
0b1347d2 3703
8340f534 3704static bool trans_be(DisasContext *ctx, arg_be *a)
98cd9ca7 3705{
6fd0c7bc 3706 TCGv_i64 tmp;
98cd9ca7 3707
c301f34e 3708#ifdef CONFIG_USER_ONLY
98cd9ca7
RH
3709 /* ??? It seems like there should be a good way of using
3710 "be disp(sr2, r0)", the canonical gateway entry mechanism
3711 to our advantage. But that appears to be inconvenient to
3712 manage along side branch delay slots. Therefore we handle
3713 entry into the gateway page via absolute address. */
98cd9ca7
RH
3714 /* Since we don't implement spaces, just branch. Do notice the special
3715 case of "be disp(*,r0)" using a direct branch to disp, so that we can
3716 goto_tb to the TB containing the syscall. */
8340f534
RH
3717 if (a->b == 0) {
3718 return do_dbranch(ctx, a->disp, a->l, a->n);
98cd9ca7 3719 }
c301f34e 3720#else
c301f34e 3721 nullify_over(ctx);
660eefe1
RH
3722#endif
3723
aac0f603 3724 tmp = tcg_temp_new_i64();
6fd0c7bc 3725 tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
660eefe1 3726 tmp = do_ibranch_priv(ctx, tmp);
c301f34e
RH
3727
3728#ifdef CONFIG_USER_ONLY
8340f534 3729 return do_ibranch(ctx, tmp, a->l, a->n);
c301f34e
RH
3730#else
3731 TCGv_i64 new_spc = tcg_temp_new_i64();
3732
8340f534
RH
3733 load_spr(ctx, new_spc, a->sp);
3734 if (a->l) {
741322f4 3735 copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e
RH
3736 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3737 }
8340f534 3738 if (a->n && use_nullify_skip(ctx)) {
a0180973 3739 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
6fd0c7bc 3740 tcg_gen_addi_i64(tmp, tmp, 4);
a0180973 3741 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e
RH
3742 tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3743 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3744 } else {
741322f4 3745 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3746 if (ctx->iaoq_b == -1) {
3747 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3748 }
a0180973 3749 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e 3750 tcg_gen_mov_i64(cpu_iasq_b, new_spc);
8340f534 3751 nullify_set(ctx, a->n);
c301f34e 3752 }
c301f34e 3753 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3754 ctx->base.is_jmp = DISAS_NORETURN;
3755 return nullify_end(ctx);
c301f34e 3756#endif
98cd9ca7
RH
3757}
3758
8340f534 3759static bool trans_bl(DisasContext *ctx, arg_bl *a)
98cd9ca7 3760{
8340f534 3761 return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
98cd9ca7
RH
3762}
3763
8340f534 3764static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
43e05652 3765{
c53e401e 3766 uint64_t dest = iaoq_dest(ctx, a->disp);
43e05652 3767
6e5f5300
SS
3768 nullify_over(ctx);
3769
43e05652
RH
3770 /* Make sure the caller hasn't done something weird with the queue.
3771 * ??? This is not quite the same as the PSW[B] bit, which would be
3772 * expensive to track. Real hardware will trap for
3773 * b gateway
3774 * b gateway+4 (in delay slot of first branch)
3775 * However, checking for a non-sequential instruction queue *will*
3776 * diagnose the security hole
3777 * b gateway
3778 * b evil
3779 * in which instructions at evil would run with increased privs.
3780 */
3781 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
3782 return gen_illegal(ctx);
3783 }
3784
3785#ifndef CONFIG_USER_ONLY
3786 if (ctx->tb_flags & PSW_C) {
b77af26e 3787 CPUHPPAState *env = cpu_env(ctx->cs);
43e05652
RH
3788 int type = hppa_artype_for_page(env, ctx->base.pc_next);
3789 /* If we could not find a TLB entry, then we need to generate an
3790 ITLB miss exception so the kernel will provide it.
3791 The resulting TLB fill operation will invalidate this TB and
3792 we will re-translate, at which point we *will* be able to find
3793 the TLB entry and determine if this is in fact a gateway page. */
3794 if (type < 0) {
31234768
RH
3795 gen_excp(ctx, EXCP_ITLB_MISS);
3796 return true;
43e05652
RH
3797 }
3798 /* No change for non-gateway pages or for priv decrease. */
3799 if (type >= 4 && type - 4 < ctx->privilege) {
3800 dest = deposit32(dest, 0, 2, type - 4);
3801 }
3802 } else {
3803 dest &= -4; /* priv = 0 */
3804 }
3805#endif
3806
6e5f5300 3807 if (a->l) {
6fd0c7bc 3808 TCGv_i64 tmp = dest_gpr(ctx, a->l);
6e5f5300 3809 if (ctx->privilege < 3) {
6fd0c7bc 3810 tcg_gen_andi_i64(tmp, tmp, -4);
6e5f5300 3811 }
6fd0c7bc 3812 tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
6e5f5300
SS
3813 save_gpr(ctx, a->l, tmp);
3814 }
3815
3816 return do_dbranch(ctx, dest, 0, a->n);
43e05652
RH
3817}
3818
8340f534 3819static bool trans_blr(DisasContext *ctx, arg_blr *a)
98cd9ca7 3820{
b35aec85 3821 if (a->x) {
aac0f603 3822 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
3823 tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
3824 tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
b35aec85
RH
3825 /* The computation here never changes privilege level. */
3826 return do_ibranch(ctx, tmp, a->l, a->n);
3827 } else {
3828 /* BLR R0,RX is a good way to load PC+8 into RX. */
3829 return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3830 }
98cd9ca7
RH
3831}
3832
8340f534 3833static bool trans_bv(DisasContext *ctx, arg_bv *a)
98cd9ca7 3834{
6fd0c7bc 3835 TCGv_i64 dest;
98cd9ca7 3836
8340f534
RH
3837 if (a->x == 0) {
3838 dest = load_gpr(ctx, a->b);
98cd9ca7 3839 } else {
aac0f603 3840 dest = tcg_temp_new_i64();
6fd0c7bc
RH
3841 tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
3842 tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
98cd9ca7 3843 }
660eefe1 3844 dest = do_ibranch_priv(ctx, dest);
8340f534 3845 return do_ibranch(ctx, dest, 0, a->n);
98cd9ca7
RH
3846}
3847
8340f534 3848static bool trans_bve(DisasContext *ctx, arg_bve *a)
98cd9ca7 3849{
6fd0c7bc 3850 TCGv_i64 dest;
98cd9ca7 3851
c301f34e 3852#ifdef CONFIG_USER_ONLY
8340f534
RH
3853 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3854 return do_ibranch(ctx, dest, a->l, a->n);
c301f34e
RH
3855#else
3856 nullify_over(ctx);
8340f534 3857 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
c301f34e 3858
741322f4 3859 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3860 if (ctx->iaoq_b == -1) {
3861 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3862 }
741322f4 3863 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
c301f34e 3864 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
8340f534 3865 if (a->l) {
741322f4 3866 copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 3867 }
8340f534 3868 nullify_set(ctx, a->n);
c301f34e 3869 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3870 ctx->base.is_jmp = DISAS_NORETURN;
3871 return nullify_end(ctx);
c301f34e 3872#endif
98cd9ca7
RH
3873}
3874
a8966ba7
RH
3875static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3876{
3877 /* All branch target stack instructions implement as nop. */
3878 return ctx->is_pa20;
3879}
3880
1ca74648
RH
3881/*
3882 * Float class 0
3883 */
ebe9383c 3884
1ca74648 3885static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3886{
1ca74648 3887 tcg_gen_mov_i32(dst, src);
ebe9383c
RH
3888}
3889
59f8c04b
HD
3890static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
3891{
a300dad3
RH
3892 uint64_t ret;
3893
c53e401e 3894 if (ctx->is_pa20) {
a300dad3
RH
3895 ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3896 } else {
3897 ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3898 }
3899
59f8c04b 3900 nullify_over(ctx);
a300dad3 3901 save_frd(0, tcg_constant_i64(ret));
59f8c04b
HD
3902 return nullify_end(ctx);
3903}
3904
1ca74648 3905static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3906{
1ca74648 3907 return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
ebe9383c
RH
3908}
3909
1ca74648 3910static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3911{
1ca74648 3912 tcg_gen_mov_i64(dst, src);
ebe9383c
RH
3913}
3914
1ca74648 3915static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3916{
1ca74648 3917 return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
ebe9383c
RH
3918}
3919
1ca74648 3920static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3921{
1ca74648 3922 tcg_gen_andi_i32(dst, src, INT32_MAX);
ebe9383c
RH
3923}
3924
1ca74648 3925static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3926{
1ca74648 3927 return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
ebe9383c
RH
3928}
3929
1ca74648 3930static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3931{
1ca74648 3932 tcg_gen_andi_i64(dst, src, INT64_MAX);
ebe9383c
RH
3933}
3934
1ca74648 3935static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3936{
1ca74648 3937 return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
ebe9383c
RH
3938}
3939
1ca74648 3940static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3941{
1ca74648 3942 return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
ebe9383c
RH
3943}
3944
1ca74648 3945static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3946{
1ca74648 3947 return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
ebe9383c
RH
3948}
3949
1ca74648 3950static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3951{
1ca74648 3952 return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
ebe9383c
RH
3953}
3954
1ca74648 3955static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3956{
1ca74648 3957 return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
ebe9383c
RH
3958}
3959
1ca74648 3960static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3961{
1ca74648 3962 tcg_gen_xori_i32(dst, src, INT32_MIN);
ebe9383c
RH
3963}
3964
1ca74648 3965static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3966{
1ca74648 3967 return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
ebe9383c
RH
3968}
3969
3970static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3971{
3972 tcg_gen_xori_i64(dst, src, INT64_MIN);
3973}
3974
1ca74648
RH
3975static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
3976{
3977 return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
3978}
3979
3980static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c
RH
3981{
3982 tcg_gen_ori_i32(dst, src, INT32_MIN);
3983}
3984
1ca74648
RH
3985static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
3986{
3987 return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
3988}
3989
ebe9383c
RH
3990static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3991{
3992 tcg_gen_ori_i64(dst, src, INT64_MIN);
3993}
3994
1ca74648
RH
3995static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
3996{
3997 return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
3998}
3999
4000/*
4001 * Float class 1
4002 */
4003
4004static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
4005{
4006 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
4007}
4008
4009static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
4010{
4011 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
4012}
4013
4014static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
4015{
4016 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
4017}
4018
4019static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
4020{
4021 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
4022}
4023
4024static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
4025{
4026 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
4027}
4028
4029static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
4030{
4031 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
4032}
4033
4034static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
4035{
4036 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
4037}
4038
4039static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
4040{
4041 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
4042}
4043
4044static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
4045{
4046 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
4047}
4048
4049static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
4050{
4051 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
4052}
4053
4054static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
4055{
4056 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
4057}
4058
4059static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
4060{
4061 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
4062}
4063
4064static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
4065{
4066 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
4067}
4068
4069static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
4070{
4071 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
4072}
4073
4074static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
4075{
4076 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
4077}
4078
4079static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
4080{
4081 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
4082}
4083
4084static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
4085{
4086 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
4087}
4088
4089static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
4090{
4091 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
4092}
4093
4094static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
4095{
4096 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
4097}
4098
4099static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
4100{
4101 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
4102}
4103
4104static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
4105{
4106 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
4107}
4108
4109static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
4110{
4111 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
4112}
4113
4114static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
4115{
4116 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
4117}
4118
4119static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
4120{
4121 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
4122}
4123
4124static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
4125{
4126 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
4127}
4128
4129static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
4130{
4131 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
4132}
4133
4134/*
4135 * Float class 2
4136 */
4137
4138static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
ebe9383c
RH
4139{
4140 TCGv_i32 ta, tb, tc, ty;
4141
4142 nullify_over(ctx);
4143
1ca74648
RH
4144 ta = load_frw0_i32(a->r1);
4145 tb = load_frw0_i32(a->r2);
29dd6f64
RH
4146 ty = tcg_constant_i32(a->y);
4147 tc = tcg_constant_i32(a->c);
ebe9383c 4148
ad75a51e 4149 gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
ebe9383c 4150
1ca74648 4151 return nullify_end(ctx);
ebe9383c
RH
4152}
4153
1ca74648 4154static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
ebe9383c 4155{
ebe9383c
RH
4156 TCGv_i64 ta, tb;
4157 TCGv_i32 tc, ty;
4158
4159 nullify_over(ctx);
4160
1ca74648
RH
4161 ta = load_frd0(a->r1);
4162 tb = load_frd0(a->r2);
29dd6f64
RH
4163 ty = tcg_constant_i32(a->y);
4164 tc = tcg_constant_i32(a->c);
ebe9383c 4165
ad75a51e 4166 gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
ebe9383c 4167
31234768 4168 return nullify_end(ctx);
ebe9383c
RH
4169}
4170
1ca74648 4171static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
ebe9383c 4172{
6fd0c7bc 4173 TCGv_i64 t;
ebe9383c
RH
4174
4175 nullify_over(ctx);
4176
aac0f603 4177 t = tcg_temp_new_i64();
6fd0c7bc 4178 tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
ebe9383c 4179
1ca74648
RH
4180 if (a->y == 1) {
4181 int mask;
4182 bool inv = false;
4183
4184 switch (a->c) {
4185 case 0: /* simple */
6fd0c7bc 4186 tcg_gen_andi_i64(t, t, 0x4000000);
1ca74648
RH
4187 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4188 goto done;
4189 case 2: /* rej */
4190 inv = true;
4191 /* fallthru */
4192 case 1: /* acc */
4193 mask = 0x43ff800;
4194 break;
4195 case 6: /* rej8 */
4196 inv = true;
4197 /* fallthru */
4198 case 5: /* acc8 */
4199 mask = 0x43f8000;
4200 break;
4201 case 9: /* acc6 */
4202 mask = 0x43e0000;
4203 break;
4204 case 13: /* acc4 */
4205 mask = 0x4380000;
4206 break;
4207 case 17: /* acc2 */
4208 mask = 0x4200000;
4209 break;
4210 default:
4211 gen_illegal(ctx);
4212 return true;
4213 }
4214 if (inv) {
6fd0c7bc
RH
4215 TCGv_i64 c = tcg_constant_i64(mask);
4216 tcg_gen_or_i64(t, t, c);
1ca74648
RH
4217 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4218 } else {
6fd0c7bc 4219 tcg_gen_andi_i64(t, t, mask);
1ca74648
RH
4220 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4221 }
4222 } else {
4223 unsigned cbit = (a->y ^ 1) - 1;
4224
6fd0c7bc 4225 tcg_gen_extract_i64(t, t, 21 - cbit, 1);
1ca74648 4226 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
1ca74648
RH
4227 }
4228
4229 done:
31234768 4230 return nullify_end(ctx);
ebe9383c
RH
4231}
4232
1ca74648
RH
4233/*
4234 * Float class 2
4235 */
4236
4237static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 4238{
1ca74648
RH
4239 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
4240}
ebe9383c 4241
1ca74648
RH
4242static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
4243{
4244 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
4245}
ebe9383c 4246
1ca74648
RH
4247static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
4248{
4249 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
4250}
ebe9383c 4251
1ca74648
RH
4252static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
4253{
4254 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
ebe9383c
RH
4255}
4256
1ca74648 4257static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 4258{
1ca74648
RH
4259 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
4260}
4261
4262static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
4263{
4264 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
4265}
4266
4267static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
4268{
4269 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
4270}
4271
4272static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
4273{
4274 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
4275}
4276
4277static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
4278{
4279 TCGv_i64 x, y;
ebe9383c
RH
4280
4281 nullify_over(ctx);
4282
1ca74648
RH
4283 x = load_frw0_i64(a->r1);
4284 y = load_frw0_i64(a->r2);
4285 tcg_gen_mul_i64(x, x, y);
4286 save_frd(a->t, x);
ebe9383c 4287
31234768 4288 return nullify_end(ctx);
ebe9383c
RH
4289}
4290
ebe9383c
RH
4291/* Convert the fmpyadd single-precision register encodings to standard. */
4292static inline int fmpyadd_s_reg(unsigned r)
4293{
4294 return (r & 16) * 2 + 16 + (r & 15);
4295}
4296
b1e2af57 4297static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
ebe9383c 4298{
b1e2af57
RH
4299 int tm = fmpyadd_s_reg(a->tm);
4300 int ra = fmpyadd_s_reg(a->ra);
4301 int ta = fmpyadd_s_reg(a->ta);
4302 int rm2 = fmpyadd_s_reg(a->rm2);
4303 int rm1 = fmpyadd_s_reg(a->rm1);
ebe9383c
RH
4304
4305 nullify_over(ctx);
4306
b1e2af57
RH
4307 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4308 do_fop_weww(ctx, ta, ta, ra,
4309 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
ebe9383c 4310
31234768 4311 return nullify_end(ctx);
ebe9383c
RH
4312}
4313
b1e2af57
RH
4314static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4315{
4316 return do_fmpyadd_s(ctx, a, false);
4317}
4318
4319static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4320{
4321 return do_fmpyadd_s(ctx, a, true);
4322}
4323
4324static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4325{
4326 nullify_over(ctx);
4327
4328 do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4329 do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4330 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4331
4332 return nullify_end(ctx);
4333}
4334
4335static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4336{
4337 return do_fmpyadd_d(ctx, a, false);
4338}
4339
4340static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4341{
4342 return do_fmpyadd_d(ctx, a, true);
4343}
4344
c3bad4f8 4345static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
ebe9383c 4346{
c3bad4f8 4347 TCGv_i32 x, y, z;
ebe9383c
RH
4348
4349 nullify_over(ctx);
c3bad4f8
RH
4350 x = load_frw0_i32(a->rm1);
4351 y = load_frw0_i32(a->rm2);
4352 z = load_frw0_i32(a->ra3);
ebe9383c 4353
c3bad4f8 4354 if (a->neg) {
ad75a51e 4355 gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
ebe9383c 4356 } else {
ad75a51e 4357 gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
ebe9383c
RH
4358 }
4359
c3bad4f8 4360 save_frw_i32(a->t, x);
31234768 4361 return nullify_end(ctx);
ebe9383c
RH
4362}
4363
c3bad4f8 4364static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
ebe9383c 4365{
c3bad4f8 4366 TCGv_i64 x, y, z;
ebe9383c
RH
4367
4368 nullify_over(ctx);
c3bad4f8
RH
4369 x = load_frd0(a->rm1);
4370 y = load_frd0(a->rm2);
4371 z = load_frd0(a->ra3);
ebe9383c 4372
c3bad4f8 4373 if (a->neg) {
ad75a51e 4374 gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
ebe9383c 4375 } else {
ad75a51e 4376 gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
ebe9383c
RH
4377 }
4378
c3bad4f8 4379 save_frd(a->t, x);
31234768 4380 return nullify_end(ctx);
ebe9383c
RH
4381}
4382
15da177b
SS
4383static bool trans_diag(DisasContext *ctx, arg_diag *a)
4384{
cf6b28d4
HD
4385 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4386#ifndef CONFIG_USER_ONLY
4387 if (a->i == 0x100) {
4388 /* emulate PDC BTLB, called by SeaBIOS-hppa */
ad75a51e
RH
4389 nullify_over(ctx);
4390 gen_helper_diag_btlb(tcg_env);
4391 return nullify_end(ctx);
cf6b28d4 4392 }
ad75a51e
RH
4393#endif
4394 qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4395 return true;
15da177b
SS
4396}
4397
b542683d 4398static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
61766fe9 4399{
51b061fb 4400 DisasContext *ctx = container_of(dcbase, DisasContext, base);
f764718d 4401 int bound;
61766fe9 4402
51b061fb 4403 ctx->cs = cs;
494737b7 4404 ctx->tb_flags = ctx->base.tb->flags;
bd6243a3 4405 ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
3d68ee7b
RH
4406
4407#ifdef CONFIG_USER_ONLY
c01e5dfb 4408 ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
3d68ee7b 4409 ctx->mmu_idx = MMU_USER_IDX;
c01e5dfb
HD
4410 ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4411 ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
217d1a5e 4412 ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
3d68ee7b 4413#else
494737b7 4414 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
bb67ec32
RH
4415 ctx->mmu_idx = (ctx->tb_flags & PSW_D
4416 ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4417 : MMU_PHYS_IDX);
3d68ee7b 4418
c301f34e
RH
4419 /* Recover the IAOQ values from the GVA + PRIV. */
4420 uint64_t cs_base = ctx->base.tb->cs_base;
4421 uint64_t iasq_f = cs_base & ~0xffffffffull;
4422 int32_t diff = cs_base;
4423
4424 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4425 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4426#endif
51b061fb 4427 ctx->iaoq_n = -1;
f764718d 4428 ctx->iaoq_n_var = NULL;
61766fe9 4429
a4db4a78
RH
4430 ctx->zero = tcg_constant_i64(0);
4431
3d68ee7b
RH
4432 /* Bound the number of instructions by those left on the page. */
4433 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
b542683d 4434 ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
51b061fb 4435}
61766fe9 4436
51b061fb
RH
4437static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
4438{
4439 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4440
3d68ee7b 4441 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
51b061fb
RH
4442 ctx->null_cond = cond_make_f();
4443 ctx->psw_n_nonzero = false;
494737b7 4444 if (ctx->tb_flags & PSW_N) {
51b061fb
RH
4445 ctx->null_cond.c = TCG_COND_ALWAYS;
4446 ctx->psw_n_nonzero = true;
129e9cc3 4447 }
51b061fb
RH
4448 ctx->null_lab = NULL;
4449}
129e9cc3 4450
51b061fb
RH
4451static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
4452{
4453 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4454
51b061fb
RH
4455 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
4456}
4457
51b061fb
RH
4458static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
4459{
4460 DisasContext *ctx = container_of(dcbase, DisasContext, base);
b77af26e 4461 CPUHPPAState *env = cpu_env(cs);
51b061fb 4462 DisasJumpType ret;
51b061fb
RH
4463
4464 /* Execute one insn. */
ba1d0b44 4465#ifdef CONFIG_USER_ONLY
c301f34e 4466 if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
31234768
RH
4467 do_page_zero(ctx);
4468 ret = ctx->base.is_jmp;
51b061fb 4469 assert(ret != DISAS_NEXT);
ba1d0b44
RH
4470 } else
4471#endif
4472 {
51b061fb
RH
4473 /* Always fetch the insn, even if nullified, so that we check
4474 the page permissions for execute. */
4e116893 4475 uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
51b061fb
RH
4476
4477 /* Set up the IA queue for the next insn.
4478 This will be overwritten by a branch. */
4479 if (ctx->iaoq_b == -1) {
4480 ctx->iaoq_n = -1;
aac0f603 4481 ctx->iaoq_n_var = tcg_temp_new_i64();
6fd0c7bc 4482 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
7ad439df 4483 } else {
51b061fb 4484 ctx->iaoq_n = ctx->iaoq_b + 4;
f764718d 4485 ctx->iaoq_n_var = NULL;
61766fe9
RH
4486 }
4487
51b061fb
RH
4488 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
4489 ctx->null_cond.c = TCG_COND_NEVER;
4490 ret = DISAS_NEXT;
4491 } else {
1a19da0d 4492 ctx->insn = insn;
31274b46
RH
4493 if (!decode(ctx, insn)) {
4494 gen_illegal(ctx);
4495 }
31234768 4496 ret = ctx->base.is_jmp;
51b061fb 4497 assert(ctx->null_lab == NULL);
61766fe9 4498 }
51b061fb 4499 }
61766fe9 4500
3d68ee7b
RH
4501 /* Advance the insn queue. Note that this check also detects
4502 a priority change within the instruction queue. */
51b061fb 4503 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
c301f34e
RH
4504 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4505 && use_goto_tb(ctx, ctx->iaoq_b)
4506 && (ctx->null_cond.c == TCG_COND_NEVER
4507 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
51b061fb
RH
4508 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4509 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
31234768 4510 ctx->base.is_jmp = ret = DISAS_NORETURN;
51b061fb 4511 } else {
31234768 4512 ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
c301f34e 4513 }
61766fe9 4514 }
51b061fb
RH
4515 ctx->iaoq_f = ctx->iaoq_b;
4516 ctx->iaoq_b = ctx->iaoq_n;
c301f34e 4517 ctx->base.pc_next += 4;
51b061fb 4518
c5d0aec2
RH
4519 switch (ret) {
4520 case DISAS_NORETURN:
4521 case DISAS_IAQ_N_UPDATED:
4522 break;
4523
4524 case DISAS_NEXT:
4525 case DISAS_IAQ_N_STALE:
4526 case DISAS_IAQ_N_STALE_EXIT:
4527 if (ctx->iaoq_f == -1) {
a0180973 4528 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
741322f4 4529 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 4530#ifndef CONFIG_USER_ONLY
c5d0aec2 4531 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
c301f34e 4532#endif
c5d0aec2
RH
4533 nullify_save(ctx);
4534 ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4535 ? DISAS_EXIT
4536 : DISAS_IAQ_N_UPDATED);
4537 } else if (ctx->iaoq_b == -1) {
a0180973 4538 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
c5d0aec2
RH
4539 }
4540 break;
4541
4542 default:
4543 g_assert_not_reached();
51b061fb
RH
4544 }
4545}
4546
4547static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
4548{
4549 DisasContext *ctx = container_of(dcbase, DisasContext, base);
e1b5a5ed 4550 DisasJumpType is_jmp = ctx->base.is_jmp;
61766fe9 4551
e1b5a5ed 4552 switch (is_jmp) {
869051ea 4553 case DISAS_NORETURN:
61766fe9 4554 break;
51b061fb 4555 case DISAS_TOO_MANY:
869051ea 4556 case DISAS_IAQ_N_STALE:
e1b5a5ed 4557 case DISAS_IAQ_N_STALE_EXIT:
741322f4
RH
4558 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4559 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
51b061fb 4560 nullify_save(ctx);
61766fe9 4561 /* FALLTHRU */
869051ea 4562 case DISAS_IAQ_N_UPDATED:
8532a14e 4563 if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
7f11636d 4564 tcg_gen_lookup_and_goto_ptr();
8532a14e 4565 break;
61766fe9 4566 }
c5d0aec2
RH
4567 /* FALLTHRU */
4568 case DISAS_EXIT:
4569 tcg_gen_exit_tb(NULL, 0);
61766fe9
RH
4570 break;
4571 default:
51b061fb 4572 g_assert_not_reached();
61766fe9 4573 }
51b061fb 4574}
61766fe9 4575
8eb806a7
RH
4576static void hppa_tr_disas_log(const DisasContextBase *dcbase,
4577 CPUState *cs, FILE *logfile)
51b061fb 4578{
c301f34e 4579 target_ulong pc = dcbase->pc_first;
61766fe9 4580
ba1d0b44
RH
4581#ifdef CONFIG_USER_ONLY
4582 switch (pc) {
51b061fb 4583 case 0x00:
8eb806a7 4584 fprintf(logfile, "IN:\n0x00000000: (null)\n");
ba1d0b44 4585 return;
51b061fb 4586 case 0xb0:
8eb806a7 4587 fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
ba1d0b44 4588 return;
51b061fb 4589 case 0xe0:
8eb806a7 4590 fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
ba1d0b44 4591 return;
51b061fb 4592 case 0x100:
8eb806a7 4593 fprintf(logfile, "IN:\n0x00000100: syscall\n");
ba1d0b44 4594 return;
61766fe9 4595 }
ba1d0b44
RH
4596#endif
4597
8eb806a7
RH
4598 fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
4599 target_disas(logfile, cs, pc, dcbase->tb->size);
51b061fb
RH
4600}
4601
4602static const TranslatorOps hppa_tr_ops = {
4603 .init_disas_context = hppa_tr_init_disas_context,
4604 .tb_start = hppa_tr_tb_start,
4605 .insn_start = hppa_tr_insn_start,
51b061fb
RH
4606 .translate_insn = hppa_tr_translate_insn,
4607 .tb_stop = hppa_tr_tb_stop,
4608 .disas_log = hppa_tr_disas_log,
4609};
4610
597f9b2d 4611void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
306c8721 4612 target_ulong pc, void *host_pc)
51b061fb
RH
4613{
4614 DisasContext ctx;
306c8721 4615 translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
61766fe9 4616}