]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/translate.c
target/hppa: Use tcg_temp_new_i64 not tcg_temp_new
[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"
61766fe9
RH
26#include "exec/helper-proto.h"
27#include "exec/helper-gen.h"
869051ea 28#include "exec/translator.h"
61766fe9
RH
29#include "exec/log.h"
30
d53106c9
RH
31#define HELPER_H "helper.h"
32#include "exec/helper-info.c.inc"
33#undef HELPER_H
34
aac0f603
RH
35/* Choose to use explicit sizes within this file. */
36#undef tcg_temp_new
d53106c9 37
61766fe9
RH
38typedef struct DisasCond {
39 TCGCond c;
6fd0c7bc 40 TCGv_i64 a0, a1;
61766fe9
RH
41} DisasCond;
42
43typedef struct DisasContext {
d01a3625 44 DisasContextBase base;
61766fe9
RH
45 CPUState *cs;
46
c53e401e
RH
47 uint64_t iaoq_f;
48 uint64_t iaoq_b;
49 uint64_t iaoq_n;
6fd0c7bc 50 TCGv_i64 iaoq_n_var;
61766fe9 51
61766fe9
RH
52 DisasCond null_cond;
53 TCGLabel *null_lab;
54
1a19da0d 55 uint32_t insn;
494737b7 56 uint32_t tb_flags;
3d68ee7b
RH
57 int mmu_idx;
58 int privilege;
61766fe9 59 bool psw_n_nonzero;
bd6243a3 60 bool is_pa20;
217d1a5e
RH
61
62#ifdef CONFIG_USER_ONLY
63 MemOp unalign;
64#endif
61766fe9
RH
65} DisasContext;
66
217d1a5e
RH
67#ifdef CONFIG_USER_ONLY
68#define UNALIGN(C) (C)->unalign
69#else
2d4afb03 70#define UNALIGN(C) MO_ALIGN
217d1a5e
RH
71#endif
72
e36f27ef 73/* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */
451e4ffd 74static int expand_sm_imm(DisasContext *ctx, int val)
e36f27ef
RH
75{
76 if (val & PSW_SM_E) {
77 val = (val & ~PSW_SM_E) | PSW_E;
78 }
79 if (val & PSW_SM_W) {
80 val = (val & ~PSW_SM_W) | PSW_W;
81 }
82 return val;
83}
84
deee69a1 85/* Inverted space register indicates 0 means sr0 not inferred from base. */
451e4ffd 86static int expand_sr3x(DisasContext *ctx, int val)
deee69a1
RH
87{
88 return ~val;
89}
90
1cd012a5
RH
91/* Convert the M:A bits within a memory insn to the tri-state value
92 we use for the final M. */
451e4ffd 93static int ma_to_m(DisasContext *ctx, int val)
1cd012a5
RH
94{
95 return val & 2 ? (val & 1 ? -1 : 1) : 0;
96}
97
740038d7 98/* Convert the sign of the displacement to a pre or post-modify. */
451e4ffd 99static int pos_to_m(DisasContext *ctx, int val)
740038d7
RH
100{
101 return val ? 1 : -1;
102}
103
451e4ffd 104static int neg_to_m(DisasContext *ctx, int val)
740038d7
RH
105{
106 return val ? -1 : 1;
107}
108
109/* Used for branch targets and fp memory ops. */
451e4ffd 110static int expand_shl2(DisasContext *ctx, int val)
01afb7be
RH
111{
112 return val << 2;
113}
114
740038d7 115/* Used for fp memory ops. */
451e4ffd 116static int expand_shl3(DisasContext *ctx, int val)
740038d7
RH
117{
118 return val << 3;
119}
120
0588e061 121/* Used for assemble_21. */
451e4ffd 122static int expand_shl11(DisasContext *ctx, int val)
0588e061
RH
123{
124 return val << 11;
125}
126
72ae4f2b
RH
127static int assemble_6(DisasContext *ctx, int val)
128{
129 /*
130 * Officially, 32 * x + 32 - y.
131 * Here, x is already in bit 5, and y is [4:0].
132 * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
133 * with the overflow from bit 4 summing with x.
134 */
135 return (val ^ 31) + 1;
136}
137
c65c3ee1
RH
138/* Translate CMPI doubleword conditions to standard. */
139static int cmpbid_c(DisasContext *ctx, int val)
140{
141 return val ? val : 4; /* 0 == "*<<" */
142}
143
01afb7be 144
40f9f908 145/* Include the auto-generated decoder. */
abff1abf 146#include "decode-insns.c.inc"
40f9f908 147
869051ea
RH
148/* We are not using a goto_tb (for whatever reason), but have updated
149 the iaq (for whatever reason), so don't do it again on exit. */
150#define DISAS_IAQ_N_UPDATED DISAS_TARGET_0
61766fe9 151
869051ea
RH
152/* We are exiting the TB, but have neither emitted a goto_tb, nor
153 updated the iaq for the next instruction to be executed. */
154#define DISAS_IAQ_N_STALE DISAS_TARGET_1
61766fe9 155
e1b5a5ed
RH
156/* Similarly, but we want to return to the main loop immediately
157 to recognize unmasked interrupts. */
158#define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2
c5d0aec2 159#define DISAS_EXIT DISAS_TARGET_3
e1b5a5ed 160
61766fe9 161/* global register indexes */
6fd0c7bc 162static TCGv_i64 cpu_gr[32];
33423472 163static TCGv_i64 cpu_sr[4];
494737b7 164static TCGv_i64 cpu_srH;
6fd0c7bc
RH
165static TCGv_i64 cpu_iaoq_f;
166static TCGv_i64 cpu_iaoq_b;
c301f34e
RH
167static TCGv_i64 cpu_iasq_f;
168static TCGv_i64 cpu_iasq_b;
6fd0c7bc
RH
169static TCGv_i64 cpu_sar;
170static TCGv_i64 cpu_psw_n;
171static TCGv_i64 cpu_psw_v;
172static TCGv_i64 cpu_psw_cb;
173static TCGv_i64 cpu_psw_cb_msb;
61766fe9 174
61766fe9
RH
175void hppa_translate_init(void)
176{
177#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
178
6fd0c7bc 179 typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
61766fe9 180 static const GlobalVar vars[] = {
35136a77 181 { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
61766fe9
RH
182 DEF_VAR(psw_n),
183 DEF_VAR(psw_v),
184 DEF_VAR(psw_cb),
185 DEF_VAR(psw_cb_msb),
186 DEF_VAR(iaoq_f),
187 DEF_VAR(iaoq_b),
188 };
189
190#undef DEF_VAR
191
192 /* Use the symbolic register names that match the disassembler. */
193 static const char gr_names[32][4] = {
194 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
195 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
196 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
197 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
198 };
33423472 199 /* SR[4-7] are not global registers so that we can index them. */
494737b7
RH
200 static const char sr_names[5][4] = {
201 "sr0", "sr1", "sr2", "sr3", "srH"
33423472 202 };
61766fe9 203
61766fe9
RH
204 int i;
205
f764718d 206 cpu_gr[0] = NULL;
61766fe9 207 for (i = 1; i < 32; i++) {
ad75a51e 208 cpu_gr[i] = tcg_global_mem_new(tcg_env,
61766fe9
RH
209 offsetof(CPUHPPAState, gr[i]),
210 gr_names[i]);
211 }
33423472 212 for (i = 0; i < 4; i++) {
ad75a51e 213 cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
33423472
RH
214 offsetof(CPUHPPAState, sr[i]),
215 sr_names[i]);
216 }
ad75a51e 217 cpu_srH = tcg_global_mem_new_i64(tcg_env,
494737b7
RH
218 offsetof(CPUHPPAState, sr[4]),
219 sr_names[4]);
61766fe9
RH
220
221 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
222 const GlobalVar *v = &vars[i];
ad75a51e 223 *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
61766fe9 224 }
c301f34e 225
ad75a51e 226 cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
c301f34e
RH
227 offsetof(CPUHPPAState, iasq_f),
228 "iasq_f");
ad75a51e 229 cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
c301f34e
RH
230 offsetof(CPUHPPAState, iasq_b),
231 "iasq_b");
61766fe9
RH
232}
233
129e9cc3
RH
234static DisasCond cond_make_f(void)
235{
f764718d
RH
236 return (DisasCond){
237 .c = TCG_COND_NEVER,
238 .a0 = NULL,
239 .a1 = NULL,
240 };
129e9cc3
RH
241}
242
df0232fe
RH
243static DisasCond cond_make_t(void)
244{
245 return (DisasCond){
246 .c = TCG_COND_ALWAYS,
247 .a0 = NULL,
248 .a1 = NULL,
249 };
250}
251
129e9cc3
RH
252static DisasCond cond_make_n(void)
253{
f764718d
RH
254 return (DisasCond){
255 .c = TCG_COND_NE,
256 .a0 = cpu_psw_n,
6fd0c7bc 257 .a1 = tcg_constant_i64(0)
f764718d 258 };
129e9cc3
RH
259}
260
6fd0c7bc 261static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
129e9cc3 262{
129e9cc3 263 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
4fe9533a
RH
264 return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
265}
266
6fd0c7bc 267static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0)
4fe9533a 268{
6fd0c7bc 269 return cond_make_tmp(c, a0, tcg_constant_i64(0));
b47a4a02 270}
129e9cc3 271
6fd0c7bc 272static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0)
b47a4a02 273{
aac0f603 274 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc 275 tcg_gen_mov_i64(tmp, a0);
b47a4a02 276 return cond_make_0_tmp(c, tmp);
129e9cc3
RH
277}
278
6fd0c7bc 279static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
129e9cc3 280{
aac0f603
RH
281 TCGv_i64 t0 = tcg_temp_new_i64();
282 TCGv_i64 t1 = tcg_temp_new_i64();
129e9cc3 283
6fd0c7bc
RH
284 tcg_gen_mov_i64(t0, a0);
285 tcg_gen_mov_i64(t1, a1);
4fe9533a 286 return cond_make_tmp(c, t0, t1);
129e9cc3
RH
287}
288
129e9cc3
RH
289static void cond_free(DisasCond *cond)
290{
291 switch (cond->c) {
292 default:
f764718d
RH
293 cond->a0 = NULL;
294 cond->a1 = NULL;
129e9cc3
RH
295 /* fallthru */
296 case TCG_COND_ALWAYS:
297 cond->c = TCG_COND_NEVER;
298 break;
299 case TCG_COND_NEVER:
300 break;
301 }
302}
303
6fd0c7bc 304static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
61766fe9
RH
305{
306 if (reg == 0) {
aac0f603 307 TCGv_i64 t = tcg_temp_new_i64();
6fd0c7bc 308 tcg_gen_movi_i64(t, 0);
61766fe9
RH
309 return t;
310 } else {
311 return cpu_gr[reg];
312 }
313}
314
6fd0c7bc 315static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
61766fe9 316{
129e9cc3 317 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
aac0f603 318 return tcg_temp_new_i64();
61766fe9
RH
319 } else {
320 return cpu_gr[reg];
321 }
322}
323
6fd0c7bc 324static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
129e9cc3
RH
325{
326 if (ctx->null_cond.c != TCG_COND_NEVER) {
6fd0c7bc 327 tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
6e94937a 328 ctx->null_cond.a1, dest, t);
129e9cc3 329 } else {
6fd0c7bc 330 tcg_gen_mov_i64(dest, t);
129e9cc3
RH
331 }
332}
333
6fd0c7bc 334static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
129e9cc3
RH
335{
336 if (reg != 0) {
337 save_or_nullify(ctx, cpu_gr[reg], t);
338 }
339}
340
e03b5686 341#if HOST_BIG_ENDIAN
96d6407f
RH
342# define HI_OFS 0
343# define LO_OFS 4
344#else
345# define HI_OFS 4
346# define LO_OFS 0
347#endif
348
349static TCGv_i32 load_frw_i32(unsigned rt)
350{
351 TCGv_i32 ret = tcg_temp_new_i32();
ad75a51e 352 tcg_gen_ld_i32(ret, tcg_env,
96d6407f
RH
353 offsetof(CPUHPPAState, fr[rt & 31])
354 + (rt & 32 ? LO_OFS : HI_OFS));
355 return ret;
356}
357
ebe9383c
RH
358static TCGv_i32 load_frw0_i32(unsigned rt)
359{
360 if (rt == 0) {
0992a930
RH
361 TCGv_i32 ret = tcg_temp_new_i32();
362 tcg_gen_movi_i32(ret, 0);
363 return ret;
ebe9383c
RH
364 } else {
365 return load_frw_i32(rt);
366 }
367}
368
369static TCGv_i64 load_frw0_i64(unsigned rt)
370{
0992a930 371 TCGv_i64 ret = tcg_temp_new_i64();
ebe9383c 372 if (rt == 0) {
0992a930 373 tcg_gen_movi_i64(ret, 0);
ebe9383c 374 } else {
ad75a51e 375 tcg_gen_ld32u_i64(ret, tcg_env,
ebe9383c
RH
376 offsetof(CPUHPPAState, fr[rt & 31])
377 + (rt & 32 ? LO_OFS : HI_OFS));
ebe9383c 378 }
0992a930 379 return ret;
ebe9383c
RH
380}
381
96d6407f
RH
382static void save_frw_i32(unsigned rt, TCGv_i32 val)
383{
ad75a51e 384 tcg_gen_st_i32(val, tcg_env,
96d6407f
RH
385 offsetof(CPUHPPAState, fr[rt & 31])
386 + (rt & 32 ? LO_OFS : HI_OFS));
387}
388
389#undef HI_OFS
390#undef LO_OFS
391
392static TCGv_i64 load_frd(unsigned rt)
393{
394 TCGv_i64 ret = tcg_temp_new_i64();
ad75a51e 395 tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
96d6407f
RH
396 return ret;
397}
398
ebe9383c
RH
399static TCGv_i64 load_frd0(unsigned rt)
400{
401 if (rt == 0) {
0992a930
RH
402 TCGv_i64 ret = tcg_temp_new_i64();
403 tcg_gen_movi_i64(ret, 0);
404 return ret;
ebe9383c
RH
405 } else {
406 return load_frd(rt);
407 }
408}
409
96d6407f
RH
410static void save_frd(unsigned rt, TCGv_i64 val)
411{
ad75a51e 412 tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
96d6407f
RH
413}
414
33423472
RH
415static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
416{
417#ifdef CONFIG_USER_ONLY
418 tcg_gen_movi_i64(dest, 0);
419#else
420 if (reg < 4) {
421 tcg_gen_mov_i64(dest, cpu_sr[reg]);
494737b7
RH
422 } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
423 tcg_gen_mov_i64(dest, cpu_srH);
33423472 424 } else {
ad75a51e 425 tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
33423472
RH
426 }
427#endif
428}
429
129e9cc3
RH
430/* Skip over the implementation of an insn that has been nullified.
431 Use this when the insn is too complex for a conditional move. */
432static void nullify_over(DisasContext *ctx)
433{
434 if (ctx->null_cond.c != TCG_COND_NEVER) {
435 /* The always condition should have been handled in the main loop. */
436 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
437
438 ctx->null_lab = gen_new_label();
129e9cc3
RH
439
440 /* If we're using PSW[N], copy it to a temp because... */
6e94937a 441 if (ctx->null_cond.a0 == cpu_psw_n) {
aac0f603 442 ctx->null_cond.a0 = tcg_temp_new_i64();
6fd0c7bc 443 tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
129e9cc3
RH
444 }
445 /* ... we clear it before branching over the implementation,
446 so that (1) it's clear after nullifying this insn and
447 (2) if this insn nullifies the next, PSW[N] is valid. */
448 if (ctx->psw_n_nonzero) {
449 ctx->psw_n_nonzero = false;
6fd0c7bc 450 tcg_gen_movi_i64(cpu_psw_n, 0);
129e9cc3
RH
451 }
452
6fd0c7bc 453 tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
6e94937a 454 ctx->null_cond.a1, ctx->null_lab);
129e9cc3
RH
455 cond_free(&ctx->null_cond);
456 }
457}
458
459/* Save the current nullification state to PSW[N]. */
460static void nullify_save(DisasContext *ctx)
461{
462 if (ctx->null_cond.c == TCG_COND_NEVER) {
463 if (ctx->psw_n_nonzero) {
6fd0c7bc 464 tcg_gen_movi_i64(cpu_psw_n, 0);
129e9cc3
RH
465 }
466 return;
467 }
6e94937a 468 if (ctx->null_cond.a0 != cpu_psw_n) {
6fd0c7bc 469 tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
6e94937a 470 ctx->null_cond.a0, ctx->null_cond.a1);
129e9cc3
RH
471 ctx->psw_n_nonzero = true;
472 }
473 cond_free(&ctx->null_cond);
474}
475
476/* Set a PSW[N] to X. The intention is that this is used immediately
477 before a goto_tb/exit_tb, so that there is no fallthru path to other
478 code within the TB. Therefore we do not update psw_n_nonzero. */
479static void nullify_set(DisasContext *ctx, bool x)
480{
481 if (ctx->psw_n_nonzero || x) {
6fd0c7bc 482 tcg_gen_movi_i64(cpu_psw_n, x);
129e9cc3
RH
483 }
484}
485
486/* Mark the end of an instruction that may have been nullified.
40f9f908
RH
487 This is the pair to nullify_over. Always returns true so that
488 it may be tail-called from a translate function. */
31234768 489static bool nullify_end(DisasContext *ctx)
129e9cc3
RH
490{
491 TCGLabel *null_lab = ctx->null_lab;
31234768 492 DisasJumpType status = ctx->base.is_jmp;
129e9cc3 493
f49b3537
RH
494 /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
495 For UPDATED, we cannot update on the nullified path. */
496 assert(status != DISAS_IAQ_N_UPDATED);
497
129e9cc3
RH
498 if (likely(null_lab == NULL)) {
499 /* The current insn wasn't conditional or handled the condition
500 applied to it without a branch, so the (new) setting of
501 NULL_COND can be applied directly to the next insn. */
31234768 502 return true;
129e9cc3
RH
503 }
504 ctx->null_lab = NULL;
505
506 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
507 /* The next instruction will be unconditional,
508 and NULL_COND already reflects that. */
509 gen_set_label(null_lab);
510 } else {
511 /* The insn that we just executed is itself nullifying the next
512 instruction. Store the condition in the PSW[N] global.
513 We asserted PSW[N] = 0 in nullify_over, so that after the
514 label we have the proper value in place. */
515 nullify_save(ctx);
516 gen_set_label(null_lab);
517 ctx->null_cond = cond_make_n();
518 }
869051ea 519 if (status == DISAS_NORETURN) {
31234768 520 ctx->base.is_jmp = DISAS_NEXT;
129e9cc3 521 }
31234768 522 return true;
129e9cc3
RH
523}
524
c53e401e 525static uint64_t gva_offset_mask(DisasContext *ctx)
698240d1
RH
526{
527 return (ctx->tb_flags & PSW_W
528 ? MAKE_64BIT_MASK(0, 62)
529 : MAKE_64BIT_MASK(0, 32));
530}
531
6fd0c7bc
RH
532static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
533 uint64_t ival, TCGv_i64 vval)
61766fe9 534{
c53e401e 535 uint64_t mask = gva_offset_mask(ctx);
f13bf343
RH
536
537 if (ival != -1) {
6fd0c7bc 538 tcg_gen_movi_i64(dest, ival & mask);
f13bf343
RH
539 return;
540 }
541 tcg_debug_assert(vval != NULL);
542
543 /*
544 * We know that the IAOQ is already properly masked.
545 * This optimization is primarily for "iaoq_f = iaoq_b".
546 */
547 if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) {
6fd0c7bc 548 tcg_gen_mov_i64(dest, vval);
61766fe9 549 } else {
6fd0c7bc 550 tcg_gen_andi_i64(dest, vval, mask);
61766fe9
RH
551 }
552}
553
c53e401e 554static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp)
61766fe9
RH
555{
556 return ctx->iaoq_f + disp + 8;
557}
558
559static void gen_excp_1(int exception)
560{
ad75a51e 561 gen_helper_excp(tcg_env, tcg_constant_i32(exception));
61766fe9
RH
562}
563
31234768 564static void gen_excp(DisasContext *ctx, int exception)
61766fe9 565{
741322f4
RH
566 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
567 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
129e9cc3 568 nullify_save(ctx);
61766fe9 569 gen_excp_1(exception);
31234768 570 ctx->base.is_jmp = DISAS_NORETURN;
61766fe9
RH
571}
572
31234768 573static bool gen_excp_iir(DisasContext *ctx, int exc)
1a19da0d 574{
31234768 575 nullify_over(ctx);
6fd0c7bc 576 tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
ad75a51e 577 tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
31234768
RH
578 gen_excp(ctx, exc);
579 return nullify_end(ctx);
1a19da0d
RH
580}
581
31234768 582static bool gen_illegal(DisasContext *ctx)
61766fe9 583{
31234768 584 return gen_excp_iir(ctx, EXCP_ILL);
61766fe9
RH
585}
586
40f9f908
RH
587#ifdef CONFIG_USER_ONLY
588#define CHECK_MOST_PRIVILEGED(EXCP) \
589 return gen_excp_iir(ctx, EXCP)
590#else
591#define CHECK_MOST_PRIVILEGED(EXCP) \
31234768
RH
592 do { \
593 if (ctx->privilege != 0) { \
594 return gen_excp_iir(ctx, EXCP); \
595 } \
e1b5a5ed 596 } while (0)
40f9f908 597#endif
e1b5a5ed 598
c53e401e 599static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
61766fe9 600{
57f91498 601 return translator_use_goto_tb(&ctx->base, dest);
61766fe9
RH
602}
603
129e9cc3
RH
604/* If the next insn is to be nullified, and it's on the same page,
605 and we're not attempting to set a breakpoint on it, then we can
606 totally skip the nullified insn. This avoids creating and
607 executing a TB that merely branches to the next TB. */
608static bool use_nullify_skip(DisasContext *ctx)
609{
610 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
611 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
612}
613
61766fe9 614static void gen_goto_tb(DisasContext *ctx, int which,
c53e401e 615 uint64_t f, uint64_t b)
61766fe9
RH
616{
617 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
618 tcg_gen_goto_tb(which);
a0180973
RH
619 copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL);
620 copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL);
07ea28b4 621 tcg_gen_exit_tb(ctx->base.tb, which);
61766fe9 622 } else {
741322f4
RH
623 copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b);
624 copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var);
8532a14e 625 tcg_gen_lookup_and_goto_ptr();
61766fe9
RH
626 }
627}
628
b47a4a02
SS
629static bool cond_need_sv(int c)
630{
631 return c == 2 || c == 3 || c == 6;
632}
633
634static bool cond_need_cb(int c)
635{
636 return c == 4 || c == 5;
637}
638
6fd0c7bc 639/* Need extensions from TCGv_i32 to TCGv_i64. */
72ca8753
RH
640static bool cond_need_ext(DisasContext *ctx, bool d)
641{
c53e401e 642 return !(ctx->is_pa20 && d);
72ca8753
RH
643}
644
b47a4a02
SS
645/*
646 * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of
647 * the Parisc 1.1 Architecture Reference Manual for details.
648 */
b2167459 649
a751eb31 650static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc 651 TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv)
b2167459
RH
652{
653 DisasCond cond;
6fd0c7bc 654 TCGv_i64 tmp;
b2167459
RH
655
656 switch (cf >> 1) {
b47a4a02 657 case 0: /* Never / TR (0 / 1) */
b2167459
RH
658 cond = cond_make_f();
659 break;
660 case 1: /* = / <> (Z / !Z) */
a751eb31 661 if (cond_need_ext(ctx, d)) {
aac0f603 662 tmp = tcg_temp_new_i64();
6fd0c7bc 663 tcg_gen_ext32u_i64(tmp, res);
a751eb31
RH
664 res = tmp;
665 }
b2167459
RH
666 cond = cond_make_0(TCG_COND_EQ, res);
667 break;
b47a4a02 668 case 2: /* < / >= (N ^ V / !(N ^ V) */
aac0f603 669 tmp = tcg_temp_new_i64();
6fd0c7bc 670 tcg_gen_xor_i64(tmp, res, sv);
a751eb31 671 if (cond_need_ext(ctx, d)) {
6fd0c7bc 672 tcg_gen_ext32s_i64(tmp, tmp);
a751eb31 673 }
b47a4a02 674 cond = cond_make_0_tmp(TCG_COND_LT, tmp);
b2167459 675 break;
b47a4a02
SS
676 case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */
677 /*
678 * Simplify:
679 * (N ^ V) | Z
680 * ((res < 0) ^ (sv < 0)) | !res
681 * ((res ^ sv) < 0) | !res
682 * (~(res ^ sv) >= 0) | !res
683 * !(~(res ^ sv) >> 31) | !res
684 * !(~(res ^ sv) >> 31 & res)
685 */
aac0f603 686 tmp = tcg_temp_new_i64();
6fd0c7bc 687 tcg_gen_eqv_i64(tmp, res, sv);
a751eb31 688 if (cond_need_ext(ctx, d)) {
6fd0c7bc
RH
689 tcg_gen_sextract_i64(tmp, tmp, 31, 1);
690 tcg_gen_and_i64(tmp, tmp, res);
691 tcg_gen_ext32u_i64(tmp, tmp);
a751eb31 692 } else {
6fd0c7bc
RH
693 tcg_gen_sari_i64(tmp, tmp, 63);
694 tcg_gen_and_i64(tmp, tmp, res);
a751eb31 695 }
b47a4a02 696 cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
b2167459
RH
697 break;
698 case 4: /* NUV / UV (!C / C) */
a751eb31 699 /* Only bit 0 of cb_msb is ever set. */
b2167459
RH
700 cond = cond_make_0(TCG_COND_EQ, cb_msb);
701 break;
702 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
aac0f603 703 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
704 tcg_gen_neg_i64(tmp, cb_msb);
705 tcg_gen_and_i64(tmp, tmp, res);
a751eb31 706 if (cond_need_ext(ctx, d)) {
6fd0c7bc 707 tcg_gen_ext32u_i64(tmp, tmp);
a751eb31 708 }
b47a4a02 709 cond = cond_make_0_tmp(TCG_COND_EQ, tmp);
b2167459
RH
710 break;
711 case 6: /* SV / NSV (V / !V) */
a751eb31 712 if (cond_need_ext(ctx, d)) {
aac0f603 713 tmp = tcg_temp_new_i64();
6fd0c7bc 714 tcg_gen_ext32s_i64(tmp, sv);
a751eb31
RH
715 sv = tmp;
716 }
b2167459
RH
717 cond = cond_make_0(TCG_COND_LT, sv);
718 break;
719 case 7: /* OD / EV */
aac0f603 720 tmp = tcg_temp_new_i64();
6fd0c7bc 721 tcg_gen_andi_i64(tmp, res, 1);
b47a4a02 722 cond = cond_make_0_tmp(TCG_COND_NE, tmp);
b2167459
RH
723 break;
724 default:
725 g_assert_not_reached();
726 }
727 if (cf & 1) {
728 cond.c = tcg_invert_cond(cond.c);
729 }
730
731 return cond;
732}
733
734/* Similar, but for the special case of subtraction without borrow, we
735 can use the inputs directly. This can allow other computation to be
736 deleted as unused. */
737
4fe9533a 738static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc
RH
739 TCGv_i64 res, TCGv_i64 in1,
740 TCGv_i64 in2, TCGv_i64 sv)
b2167459 741{
4fe9533a
RH
742 TCGCond tc;
743 bool ext_uns;
b2167459
RH
744
745 switch (cf >> 1) {
746 case 1: /* = / <> */
4fe9533a
RH
747 tc = TCG_COND_EQ;
748 ext_uns = true;
b2167459
RH
749 break;
750 case 2: /* < / >= */
4fe9533a
RH
751 tc = TCG_COND_LT;
752 ext_uns = false;
b2167459
RH
753 break;
754 case 3: /* <= / > */
4fe9533a
RH
755 tc = TCG_COND_LE;
756 ext_uns = false;
b2167459
RH
757 break;
758 case 4: /* << / >>= */
4fe9533a
RH
759 tc = TCG_COND_LTU;
760 ext_uns = true;
b2167459
RH
761 break;
762 case 5: /* <<= / >> */
4fe9533a
RH
763 tc = TCG_COND_LEU;
764 ext_uns = true;
b2167459
RH
765 break;
766 default:
a751eb31 767 return do_cond(ctx, cf, d, res, NULL, sv);
b2167459 768 }
4fe9533a 769
b2167459 770 if (cf & 1) {
4fe9533a 771 tc = tcg_invert_cond(tc);
b2167459 772 }
4fe9533a 773 if (cond_need_ext(ctx, d)) {
aac0f603
RH
774 TCGv_i64 t1 = tcg_temp_new_i64();
775 TCGv_i64 t2 = tcg_temp_new_i64();
b2167459 776
4fe9533a 777 if (ext_uns) {
6fd0c7bc
RH
778 tcg_gen_ext32u_i64(t1, in1);
779 tcg_gen_ext32u_i64(t2, in2);
4fe9533a 780 } else {
6fd0c7bc
RH
781 tcg_gen_ext32s_i64(t1, in1);
782 tcg_gen_ext32s_i64(t2, in2);
4fe9533a
RH
783 }
784 return cond_make_tmp(tc, t1, t2);
785 }
786 return cond_make(tc, in1, in2);
b2167459
RH
787}
788
df0232fe
RH
789/*
790 * Similar, but for logicals, where the carry and overflow bits are not
791 * computed, and use of them is undefined.
792 *
793 * Undefined or not, hardware does not trap. It seems reasonable to
794 * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
795 * how cases c={2,3} are treated.
796 */
b2167459 797
b5af8423 798static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
6fd0c7bc 799 TCGv_i64 res)
b2167459 800{
b5af8423
RH
801 TCGCond tc;
802 bool ext_uns;
a751eb31 803
df0232fe
RH
804 switch (cf) {
805 case 0: /* never */
806 case 9: /* undef, C */
807 case 11: /* undef, C & !Z */
808 case 12: /* undef, V */
809 return cond_make_f();
810
811 case 1: /* true */
812 case 8: /* undef, !C */
813 case 10: /* undef, !C | Z */
814 case 13: /* undef, !V */
815 return cond_make_t();
816
817 case 2: /* == */
b5af8423
RH
818 tc = TCG_COND_EQ;
819 ext_uns = true;
820 break;
df0232fe 821 case 3: /* <> */
b5af8423
RH
822 tc = TCG_COND_NE;
823 ext_uns = true;
824 break;
df0232fe 825 case 4: /* < */
b5af8423
RH
826 tc = TCG_COND_LT;
827 ext_uns = false;
828 break;
df0232fe 829 case 5: /* >= */
b5af8423
RH
830 tc = TCG_COND_GE;
831 ext_uns = false;
832 break;
df0232fe 833 case 6: /* <= */
b5af8423
RH
834 tc = TCG_COND_LE;
835 ext_uns = false;
836 break;
df0232fe 837 case 7: /* > */
b5af8423
RH
838 tc = TCG_COND_GT;
839 ext_uns = false;
840 break;
df0232fe
RH
841
842 case 14: /* OD */
843 case 15: /* EV */
a751eb31 844 return do_cond(ctx, cf, d, res, NULL, NULL);
df0232fe
RH
845
846 default:
847 g_assert_not_reached();
b2167459 848 }
b5af8423
RH
849
850 if (cond_need_ext(ctx, d)) {
aac0f603 851 TCGv_i64 tmp = tcg_temp_new_i64();
b5af8423
RH
852
853 if (ext_uns) {
6fd0c7bc 854 tcg_gen_ext32u_i64(tmp, res);
b5af8423 855 } else {
6fd0c7bc 856 tcg_gen_ext32s_i64(tmp, res);
b5af8423
RH
857 }
858 return cond_make_0_tmp(tc, tmp);
859 }
860 return cond_make_0(tc, res);
b2167459
RH
861}
862
98cd9ca7
RH
863/* Similar, but for shift/extract/deposit conditions. */
864
4fa52edf 865static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
6fd0c7bc 866 TCGv_i64 res)
98cd9ca7
RH
867{
868 unsigned c, f;
869
870 /* Convert the compressed condition codes to standard.
871 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
872 4-7 are the reverse of 0-3. */
873 c = orig & 3;
874 if (c == 3) {
875 c = 7;
876 }
877 f = (orig & 4) / 4;
878
b5af8423 879 return do_log_cond(ctx, c * 2 + f, d, res);
98cd9ca7
RH
880}
881
b2167459
RH
882/* Similar, but for unit conditions. */
883
6fd0c7bc
RH
884static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res,
885 TCGv_i64 in1, TCGv_i64 in2)
b2167459
RH
886{
887 DisasCond cond;
6fd0c7bc 888 TCGv_i64 tmp, cb = NULL;
c53e401e 889 uint64_t d_repl = d ? 0x0000000100000001ull : 1;
b2167459 890
b2167459
RH
891 if (cf & 8) {
892 /* Since we want to test lots of carry-out bits all at once, do not
893 * do our normal thing and compute carry-in of bit B+1 since that
894 * leaves us with carry bits spread across two words.
895 */
aac0f603
RH
896 cb = tcg_temp_new_i64();
897 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
898 tcg_gen_or_i64(cb, in1, in2);
899 tcg_gen_and_i64(tmp, in1, in2);
900 tcg_gen_andc_i64(cb, cb, res);
901 tcg_gen_or_i64(cb, cb, tmp);
b2167459
RH
902 }
903
904 switch (cf >> 1) {
905 case 0: /* never / TR */
906 case 1: /* undefined */
907 case 5: /* undefined */
908 cond = cond_make_f();
909 break;
910
911 case 2: /* SBZ / NBZ */
912 /* See hasless(v,1) from
913 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
914 */
aac0f603 915 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
916 tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u);
917 tcg_gen_andc_i64(tmp, tmp, res);
918 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u);
b2167459 919 cond = cond_make_0(TCG_COND_NE, tmp);
b2167459
RH
920 break;
921
922 case 3: /* SHZ / NHZ */
aac0f603 923 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
924 tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u);
925 tcg_gen_andc_i64(tmp, tmp, res);
926 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u);
b2167459 927 cond = cond_make_0(TCG_COND_NE, tmp);
b2167459
RH
928 break;
929
930 case 4: /* SDC / NDC */
6fd0c7bc 931 tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u);
b2167459
RH
932 cond = cond_make_0(TCG_COND_NE, cb);
933 break;
934
935 case 6: /* SBC / NBC */
6fd0c7bc 936 tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u);
b2167459
RH
937 cond = cond_make_0(TCG_COND_NE, cb);
938 break;
939
940 case 7: /* SHC / NHC */
6fd0c7bc 941 tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u);
b2167459
RH
942 cond = cond_make_0(TCG_COND_NE, cb);
943 break;
944
945 default:
946 g_assert_not_reached();
947 }
b2167459
RH
948 if (cf & 1) {
949 cond.c = tcg_invert_cond(cond.c);
950 }
951
952 return cond;
953}
954
6fd0c7bc
RH
955static TCGv_i64 get_carry(DisasContext *ctx, bool d,
956 TCGv_i64 cb, TCGv_i64 cb_msb)
72ca8753
RH
957{
958 if (cond_need_ext(ctx, d)) {
aac0f603 959 TCGv_i64 t = tcg_temp_new_i64();
6fd0c7bc 960 tcg_gen_extract_i64(t, cb, 32, 1);
72ca8753
RH
961 return t;
962 }
963 return cb_msb;
964}
965
6fd0c7bc 966static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
72ca8753
RH
967{
968 return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
969}
970
b2167459 971/* Compute signed overflow for addition. */
6fd0c7bc
RH
972static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
973 TCGv_i64 in1, TCGv_i64 in2)
b2167459 974{
aac0f603
RH
975 TCGv_i64 sv = tcg_temp_new_i64();
976 TCGv_i64 tmp = tcg_temp_new_i64();
b2167459 977
6fd0c7bc
RH
978 tcg_gen_xor_i64(sv, res, in1);
979 tcg_gen_xor_i64(tmp, in1, in2);
980 tcg_gen_andc_i64(sv, sv, tmp);
b2167459
RH
981
982 return sv;
983}
984
985/* Compute signed overflow for subtraction. */
6fd0c7bc
RH
986static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
987 TCGv_i64 in1, TCGv_i64 in2)
b2167459 988{
aac0f603
RH
989 TCGv_i64 sv = tcg_temp_new_i64();
990 TCGv_i64 tmp = tcg_temp_new_i64();
b2167459 991
6fd0c7bc
RH
992 tcg_gen_xor_i64(sv, res, in1);
993 tcg_gen_xor_i64(tmp, in1, in2);
994 tcg_gen_and_i64(sv, sv, tmp);
b2167459
RH
995
996 return sv;
997}
998
6fd0c7bc
RH
999static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
1000 TCGv_i64 in2, unsigned shift, bool is_l,
faf97ba1 1001 bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
b2167459 1002{
6fd0c7bc 1003 TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp;
b2167459
RH
1004 unsigned c = cf >> 1;
1005 DisasCond cond;
1006
aac0f603 1007 dest = tcg_temp_new_i64();
f764718d
RH
1008 cb = NULL;
1009 cb_msb = NULL;
bdcccc17 1010 cb_cond = NULL;
b2167459
RH
1011
1012 if (shift) {
aac0f603 1013 tmp = tcg_temp_new_i64();
6fd0c7bc 1014 tcg_gen_shli_i64(tmp, in1, shift);
b2167459
RH
1015 in1 = tmp;
1016 }
1017
b47a4a02 1018 if (!is_l || cond_need_cb(c)) {
6fd0c7bc 1019 TCGv_i64 zero = tcg_constant_i64(0);
aac0f603
RH
1020 cb_msb = tcg_temp_new_i64();
1021 cb = tcg_temp_new_i64();
bdcccc17 1022
6fd0c7bc 1023 tcg_gen_add2_i64(dest, cb_msb, in1, zero, in2, zero);
b2167459 1024 if (is_c) {
6fd0c7bc 1025 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
bdcccc17 1026 get_psw_carry(ctx, d), 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{
6fd0c7bc 1104 TCGv_i64 dest, sv, cb, cb_msb, zero, 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
6fd0c7bc 1112 zero = tcg_constant_i64(0);
b2167459
RH
1113 if (is_b) {
1114 /* DEST,C = IN1 + ~IN2 + C. */
6fd0c7bc
RH
1115 tcg_gen_not_i64(cb, in2);
1116 tcg_gen_add2_i64(dest, cb_msb, in1, zero, get_psw_carry(ctx, d), zero);
1117 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, zero);
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
RH
1125 TCGv_i64 one = tcg_constant_i64(1);
1126 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, zero);
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();
967662cd 1341 tcg_gen_andi_tl(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx));
698240d1 1342#ifndef CONFIG_USER_ONLY
86f8d05f
RH
1343 if (!is_phys) {
1344 tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
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
deee69a1 2323static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
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
RH
2332 form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2333 if (a->m) {
2334 save_gpr(ctx, a->b, ofs);
63300a00 2335 }
deee69a1 2336 if (a->local) {
ad75a51e 2337 gen_helper_ptlbe(tcg_env);
63300a00 2338 } else {
ad75a51e 2339 gen_helper_ptlb(tcg_env, addr);
63300a00
RH
2340 }
2341
2342 /* Exit TB for TLB change if mmu is enabled. */
6797c315
NH
2343 if (ctx->tb_flags & PSW_C) {
2344 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2345 }
2346 return nullify_end(ctx);
2347#endif
2348}
2349
2350/*
2351 * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
2352 * See
2353 * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
2354 * page 13-9 (195/206)
2355 */
2356static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
2357{
8577f354
RH
2358 if (ctx->is_pa20) {
2359 return false;
2360 }
6797c315
NH
2361 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2362#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2363 TCGv_i64 addr, atl, stl;
2364 TCGv_i64 reg;
6797c315
NH
2365
2366 nullify_over(ctx);
2367
2368 /*
2369 * FIXME:
2370 * if (not (pcxl or pcxl2))
2371 * return gen_illegal(ctx);
6797c315
NH
2372 */
2373
6fd0c7bc
RH
2374 atl = tcg_temp_new_i64();
2375 stl = tcg_temp_new_i64();
2376 addr = tcg_temp_new_i64();
6797c315 2377
ad75a51e 2378 tcg_gen_ld32u_i64(stl, tcg_env,
6797c315
NH
2379 a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
2380 : offsetof(CPUHPPAState, cr[CR_IIASQ]));
ad75a51e 2381 tcg_gen_ld32u_i64(atl, tcg_env,
6797c315
NH
2382 a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
2383 : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
2384 tcg_gen_shli_i64(stl, stl, 32);
2385 tcg_gen_or_tl(addr, atl, stl);
6797c315
NH
2386
2387 reg = load_gpr(ctx, a->r);
2388 if (a->addr) {
8577f354 2389 gen_helper_itlba_pa11(tcg_env, addr, reg);
6797c315 2390 } else {
8577f354
RH
2391 gen_helper_itlbp_pa11(tcg_env, addr, reg);
2392 }
2393
2394 /* Exit TB for TLB change if mmu is enabled. */
2395 if (ctx->tb_flags & PSW_C) {
2396 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
6797c315 2397 }
8577f354
RH
2398 return nullify_end(ctx);
2399#endif
2400}
6797c315 2401
8577f354
RH
2402static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
2403{
2404 if (!ctx->is_pa20) {
2405 return false;
2406 }
2407 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2408#ifndef CONFIG_USER_ONLY
2409 nullify_over(ctx);
2410 {
2411 TCGv_i64 src1 = load_gpr(ctx, a->r1);
2412 TCGv_i64 src2 = load_gpr(ctx, a->r2);
2413
2414 if (a->data) {
2415 gen_helper_idtlbt_pa20(tcg_env, src1, src2);
2416 } else {
2417 gen_helper_iitlbt_pa20(tcg_env, src1, src2);
2418 }
2419 }
6797c315 2420 /* Exit TB for TLB change if mmu is enabled. */
32dc7569 2421 if (ctx->tb_flags & PSW_C) {
31234768
RH
2422 ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2423 }
2424 return nullify_end(ctx);
deee69a1 2425#endif
63300a00 2426}
2dfcca9f 2427
deee69a1 2428static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
2dfcca9f 2429{
deee69a1
RH
2430 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2431#ifndef CONFIG_USER_ONLY
6fd0c7bc
RH
2432 TCGv_i64 vaddr;
2433 TCGv_i64 ofs, paddr;
2dfcca9f 2434
2dfcca9f
RH
2435 nullify_over(ctx);
2436
deee69a1 2437 form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2dfcca9f 2438
aac0f603 2439 paddr = tcg_temp_new_i64();
ad75a51e 2440 gen_helper_lpa(paddr, tcg_env, vaddr);
2dfcca9f
RH
2441
2442 /* Note that physical address result overrides base modification. */
deee69a1
RH
2443 if (a->m) {
2444 save_gpr(ctx, a->b, ofs);
2dfcca9f 2445 }
deee69a1 2446 save_gpr(ctx, a->t, paddr);
2dfcca9f 2447
31234768 2448 return nullify_end(ctx);
deee69a1 2449#endif
2dfcca9f 2450}
43a97b81 2451
deee69a1 2452static bool trans_lci(DisasContext *ctx, arg_lci *a)
43a97b81 2453{
43a97b81
RH
2454 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2455
2456 /* The Coherence Index is an implementation-defined function of the
2457 physical address. Two addresses with the same CI have a coherent
2458 view of the cache. Our implementation is to return 0 for all,
2459 since the entire address space is coherent. */
6fd0c7bc 2460 save_gpr(ctx, a->t, tcg_constant_i64(0));
43a97b81 2461
31234768
RH
2462 cond_free(&ctx->null_cond);
2463 return true;
43a97b81 2464}
98a9cb79 2465
faf97ba1 2466static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2467{
0c982a28
RH
2468 return do_add_reg(ctx, a, false, false, false, false);
2469}
b2167459 2470
faf97ba1 2471static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2472{
2473 return do_add_reg(ctx, a, true, false, false, false);
2474}
b2167459 2475
faf97ba1 2476static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2477{
2478 return do_add_reg(ctx, a, false, true, false, false);
b2167459
RH
2479}
2480
faf97ba1 2481static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
b2167459 2482{
0c982a28
RH
2483 return do_add_reg(ctx, a, false, false, false, true);
2484}
b2167459 2485
faf97ba1 2486static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
0c982a28
RH
2487{
2488 return do_add_reg(ctx, a, false, true, false, true);
2489}
b2167459 2490
63c427c6 2491static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2492{
2493 return do_sub_reg(ctx, a, false, false, false);
b2167459
RH
2494}
2495
63c427c6 2496static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2497{
0c982a28
RH
2498 return do_sub_reg(ctx, a, true, false, false);
2499}
b2167459 2500
63c427c6 2501static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2502{
2503 return do_sub_reg(ctx, a, false, false, true);
b2167459
RH
2504}
2505
63c427c6 2506static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2507{
0c982a28
RH
2508 return do_sub_reg(ctx, a, true, false, true);
2509}
2510
63c427c6 2511static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2512{
2513 return do_sub_reg(ctx, a, false, true, false);
2514}
2515
63c427c6 2516static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2517{
2518 return do_sub_reg(ctx, a, true, true, false);
2519}
2520
fa8e3bed 2521static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2522{
6fd0c7bc 2523 return do_log_reg(ctx, a, tcg_gen_andc_i64);
0c982a28
RH
2524}
2525
fa8e3bed 2526static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2527{
6fd0c7bc 2528 return do_log_reg(ctx, a, tcg_gen_and_i64);
0c982a28
RH
2529}
2530
fa8e3bed 2531static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2532{
2533 if (a->cf == 0) {
2534 unsigned r2 = a->r2;
2535 unsigned r1 = a->r1;
2536 unsigned rt = a->t;
b2167459 2537
7aee8189
RH
2538 if (rt == 0) { /* NOP */
2539 cond_free(&ctx->null_cond);
2540 return true;
2541 }
2542 if (r2 == 0) { /* COPY */
2543 if (r1 == 0) {
6fd0c7bc
RH
2544 TCGv_i64 dest = dest_gpr(ctx, rt);
2545 tcg_gen_movi_i64(dest, 0);
7aee8189
RH
2546 save_gpr(ctx, rt, dest);
2547 } else {
2548 save_gpr(ctx, rt, cpu_gr[r1]);
2549 }
2550 cond_free(&ctx->null_cond);
2551 return true;
2552 }
2553#ifndef CONFIG_USER_ONLY
2554 /* These are QEMU extensions and are nops in the real architecture:
2555 *
2556 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2557 * or %r31,%r31,%r31 -- death loop; offline cpu
2558 * currently implemented as idle.
2559 */
2560 if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
7aee8189
RH
2561 /* No need to check for supervisor, as userland can only pause
2562 until the next timer interrupt. */
2563 nullify_over(ctx);
2564
2565 /* Advance the instruction queue. */
741322f4
RH
2566 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2567 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
7aee8189
RH
2568 nullify_set(ctx, 0);
2569
2570 /* Tell the qemu main loop to halt until this cpu has work. */
ad75a51e 2571 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
29dd6f64 2572 offsetof(CPUState, halted) - offsetof(HPPACPU, env));
7aee8189
RH
2573 gen_excp_1(EXCP_HALTED);
2574 ctx->base.is_jmp = DISAS_NORETURN;
2575
2576 return nullify_end(ctx);
2577 }
2578#endif
b2167459 2579 }
6fd0c7bc 2580 return do_log_reg(ctx, a, tcg_gen_or_i64);
0c982a28 2581}
7aee8189 2582
fa8e3bed 2583static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28 2584{
6fd0c7bc 2585 return do_log_reg(ctx, a, tcg_gen_xor_i64);
b2167459
RH
2586}
2587
345aa35f 2588static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2589{
6fd0c7bc 2590 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2591
0c982a28 2592 if (a->cf) {
b2167459
RH
2593 nullify_over(ctx);
2594 }
0c982a28
RH
2595 tcg_r1 = load_gpr(ctx, a->r1);
2596 tcg_r2 = load_gpr(ctx, a->r2);
345aa35f 2597 do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
31234768 2598 return nullify_end(ctx);
b2167459
RH
2599}
2600
af240753 2601static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
b2167459 2602{
6fd0c7bc 2603 TCGv_i64 tcg_r1, tcg_r2;
b2167459 2604
0c982a28 2605 if (a->cf) {
b2167459
RH
2606 nullify_over(ctx);
2607 }
0c982a28
RH
2608 tcg_r1 = load_gpr(ctx, a->r1);
2609 tcg_r2 = load_gpr(ctx, a->r2);
6fd0c7bc 2610 do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64);
31234768 2611 return nullify_end(ctx);
b2167459
RH
2612}
2613
af240753 2614static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
b2167459 2615{
6fd0c7bc 2616 TCGv_i64 tcg_r1, tcg_r2, tmp;
b2167459 2617
0c982a28 2618 if (a->cf) {
b2167459
RH
2619 nullify_over(ctx);
2620 }
0c982a28
RH
2621 tcg_r1 = load_gpr(ctx, a->r1);
2622 tcg_r2 = load_gpr(ctx, a->r2);
aac0f603 2623 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
2624 tcg_gen_not_i64(tmp, tcg_r2);
2625 do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64);
31234768 2626 return nullify_end(ctx);
b2167459
RH
2627}
2628
af240753 2629static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2630{
2631 return do_uaddcm(ctx, a, false);
2632}
2633
af240753 2634static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
0c982a28
RH
2635{
2636 return do_uaddcm(ctx, a, true);
2637}
2638
af240753 2639static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
b2167459 2640{
6fd0c7bc 2641 TCGv_i64 tmp;
b2167459
RH
2642
2643 nullify_over(ctx);
2644
aac0f603 2645 tmp = tcg_temp_new_i64();
6fd0c7bc 2646 tcg_gen_shri_i64(tmp, cpu_psw_cb, 3);
b2167459 2647 if (!is_i) {
6fd0c7bc 2648 tcg_gen_not_i64(tmp, tmp);
b2167459 2649 }
6fd0c7bc
RH
2650 tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
2651 tcg_gen_muli_i64(tmp, tmp, 6);
af240753 2652 do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false,
6fd0c7bc 2653 is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64);
31234768 2654 return nullify_end(ctx);
b2167459
RH
2655}
2656
af240753 2657static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2658{
2659 return do_dcor(ctx, a, false);
2660}
2661
af240753 2662static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
0c982a28
RH
2663{
2664 return do_dcor(ctx, a, true);
2665}
2666
2667static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
b2167459 2668{
6fd0c7bc
RH
2669 TCGv_i64 dest, add1, add2, addc, zero, in1, in2;
2670 TCGv_i64 cout;
b2167459
RH
2671
2672 nullify_over(ctx);
2673
0c982a28
RH
2674 in1 = load_gpr(ctx, a->r1);
2675 in2 = load_gpr(ctx, a->r2);
b2167459 2676
aac0f603
RH
2677 add1 = tcg_temp_new_i64();
2678 add2 = tcg_temp_new_i64();
2679 addc = tcg_temp_new_i64();
2680 dest = tcg_temp_new_i64();
6fd0c7bc 2681 zero = tcg_constant_i64(0);
b2167459
RH
2682
2683 /* Form R1 << 1 | PSW[CB]{8}. */
6fd0c7bc
RH
2684 tcg_gen_add_i64(add1, in1, in1);
2685 tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
b2167459 2686
72ca8753
RH
2687 /*
2688 * Add or subtract R2, depending on PSW[V]. Proper computation of
2689 * carry requires that we subtract via + ~R2 + 1, as described in
2690 * the manual. By extracting and masking V, we can produce the
2691 * proper inputs to the addition without movcond.
2692 */
6fd0c7bc
RH
2693 tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
2694 tcg_gen_xor_i64(add2, in2, addc);
2695 tcg_gen_andi_i64(addc, addc, 1);
72ca8753 2696
6fd0c7bc
RH
2697 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2698 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
b2167459 2699
b2167459 2700 /* Write back the result register. */
0c982a28 2701 save_gpr(ctx, a->t, dest);
b2167459
RH
2702
2703 /* Write back PSW[CB]. */
6fd0c7bc
RH
2704 tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
2705 tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
b2167459
RH
2706
2707 /* Write back PSW[V] for the division step. */
72ca8753 2708 cout = get_psw_carry(ctx, false);
6fd0c7bc
RH
2709 tcg_gen_neg_i64(cpu_psw_v, cout);
2710 tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
b2167459
RH
2711
2712 /* Install the new nullification. */
0c982a28 2713 if (a->cf) {
6fd0c7bc 2714 TCGv_i64 sv = NULL;
b47a4a02 2715 if (cond_need_sv(a->cf >> 1)) {
b2167459
RH
2716 /* ??? The lshift is supposed to contribute to overflow. */
2717 sv = do_add_sv(ctx, dest, add1, add2);
2718 }
a751eb31 2719 ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv);
b2167459
RH
2720 }
2721
31234768 2722 return nullify_end(ctx);
b2167459
RH
2723}
2724
0588e061 2725static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
b2167459 2726{
0588e061
RH
2727 return do_add_imm(ctx, a, false, false);
2728}
b2167459 2729
0588e061
RH
2730static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
2731{
2732 return do_add_imm(ctx, a, true, false);
b2167459
RH
2733}
2734
0588e061 2735static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
b2167459 2736{
0588e061
RH
2737 return do_add_imm(ctx, a, false, true);
2738}
b2167459 2739
0588e061
RH
2740static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
2741{
2742 return do_add_imm(ctx, a, true, true);
2743}
b2167459 2744
0588e061
RH
2745static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
2746{
2747 return do_sub_imm(ctx, a, false);
2748}
b2167459 2749
0588e061
RH
2750static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
2751{
2752 return do_sub_imm(ctx, a, true);
b2167459
RH
2753}
2754
345aa35f 2755static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
b2167459 2756{
6fd0c7bc 2757 TCGv_i64 tcg_im, tcg_r2;
b2167459 2758
0588e061 2759 if (a->cf) {
b2167459
RH
2760 nullify_over(ctx);
2761 }
2762
6fd0c7bc 2763 tcg_im = tcg_constant_i64(a->i);
0588e061 2764 tcg_r2 = load_gpr(ctx, a->r);
345aa35f 2765 do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
b2167459 2766
31234768 2767 return nullify_end(ctx);
b2167459
RH
2768}
2769
1cd012a5 2770static bool trans_ld(DisasContext *ctx, arg_ldst *a)
96d6407f 2771{
c53e401e 2772 if (!ctx->is_pa20 && a->size > MO_32) {
0786a3b6 2773 return gen_illegal(ctx);
0786a3b6 2774 }
c53e401e
RH
2775 return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
2776 a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
2777}
2778
1cd012a5 2779static bool trans_st(DisasContext *ctx, arg_ldst *a)
96d6407f 2780{
1cd012a5 2781 assert(a->x == 0 && a->scale == 0);
c53e401e 2782 if (!ctx->is_pa20 && a->size > MO_32) {
0786a3b6 2783 return gen_illegal(ctx);
0786a3b6 2784 }
c53e401e 2785 return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
96d6407f
RH
2786}
2787
1cd012a5 2788static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
96d6407f 2789{
b1af755c 2790 MemOp mop = MO_TE | MO_ALIGN | a->size;
6fd0c7bc
RH
2791 TCGv_i64 zero, dest, ofs;
2792 TCGv_i64 addr;
96d6407f 2793
c53e401e 2794 if (!ctx->is_pa20 && a->size > MO_32) {
51416c4e
RH
2795 return gen_illegal(ctx);
2796 }
2797
96d6407f
RH
2798 nullify_over(ctx);
2799
1cd012a5 2800 if (a->m) {
86f8d05f
RH
2801 /* Base register modification. Make sure if RT == RB,
2802 we see the result of the load. */
aac0f603 2803 dest = tcg_temp_new_i64();
96d6407f 2804 } else {
1cd012a5 2805 dest = dest_gpr(ctx, a->t);
96d6407f
RH
2806 }
2807
1cd012a5
RH
2808 form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
2809 a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
b1af755c
RH
2810
2811 /*
2812 * For hppa1.1, LDCW is undefined unless aligned mod 16.
2813 * However actual hardware succeeds with aligned mod 4.
2814 * Detect this case and log a GUEST_ERROR.
2815 *
2816 * TODO: HPPA64 relaxes the over-alignment requirement
2817 * with the ,co completer.
2818 */
2819 gen_helper_ldc_check(addr);
2820
6fd0c7bc
RH
2821 zero = tcg_constant_i64(0);
2822 tcg_gen_atomic_xchg_i64(dest, addr, zero, ctx->mmu_idx, mop);
b1af755c 2823
1cd012a5
RH
2824 if (a->m) {
2825 save_gpr(ctx, a->b, ofs);
96d6407f 2826 }
1cd012a5 2827 save_gpr(ctx, a->t, dest);
96d6407f 2828
31234768 2829 return nullify_end(ctx);
96d6407f
RH
2830}
2831
1cd012a5 2832static bool trans_stby(DisasContext *ctx, arg_stby *a)
96d6407f 2833{
6fd0c7bc
RH
2834 TCGv_i64 ofs, val;
2835 TCGv_i64 addr;
96d6407f
RH
2836
2837 nullify_over(ctx);
2838
1cd012a5 2839 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
86f8d05f 2840 ctx->mmu_idx == MMU_PHYS_IDX);
1cd012a5
RH
2841 val = load_gpr(ctx, a->r);
2842 if (a->a) {
f9f46db4 2843 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 2844 gen_helper_stby_e_parallel(tcg_env, addr, val);
f9f46db4 2845 } else {
ad75a51e 2846 gen_helper_stby_e(tcg_env, addr, val);
f9f46db4 2847 }
96d6407f 2848 } else {
f9f46db4 2849 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
ad75a51e 2850 gen_helper_stby_b_parallel(tcg_env, addr, val);
f9f46db4 2851 } else {
ad75a51e 2852 gen_helper_stby_b(tcg_env, addr, val);
f9f46db4 2853 }
96d6407f 2854 }
1cd012a5 2855 if (a->m) {
6fd0c7bc 2856 tcg_gen_andi_i64(ofs, ofs, ~3);
1cd012a5 2857 save_gpr(ctx, a->b, ofs);
96d6407f 2858 }
96d6407f 2859
31234768 2860 return nullify_end(ctx);
96d6407f
RH
2861}
2862
25460fc5
RH
2863static bool trans_stdby(DisasContext *ctx, arg_stby *a)
2864{
6fd0c7bc
RH
2865 TCGv_i64 ofs, val;
2866 TCGv_i64 addr;
25460fc5
RH
2867
2868 if (!ctx->is_pa20) {
2869 return false;
2870 }
2871 nullify_over(ctx);
2872
2873 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
2874 ctx->mmu_idx == MMU_PHYS_IDX);
2875 val = load_gpr(ctx, a->r);
2876 if (a->a) {
2877 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2878 gen_helper_stdby_e_parallel(tcg_env, addr, val);
2879 } else {
2880 gen_helper_stdby_e(tcg_env, addr, val);
2881 }
2882 } else {
2883 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2884 gen_helper_stdby_b_parallel(tcg_env, addr, val);
2885 } else {
2886 gen_helper_stdby_b(tcg_env, addr, val);
2887 }
2888 }
2889 if (a->m) {
6fd0c7bc 2890 tcg_gen_andi_i64(ofs, ofs, ~7);
25460fc5
RH
2891 save_gpr(ctx, a->b, ofs);
2892 }
2893
2894 return nullify_end(ctx);
2895}
2896
1cd012a5 2897static bool trans_lda(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
2898{
2899 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
2900
2901 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 2902 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 2903 trans_ld(ctx, a);
d0a851cc 2904 ctx->mmu_idx = hold_mmu_idx;
31234768 2905 return true;
d0a851cc
RH
2906}
2907
1cd012a5 2908static bool trans_sta(DisasContext *ctx, arg_ldst *a)
d0a851cc
RH
2909{
2910 int hold_mmu_idx = ctx->mmu_idx;
d0a851cc
RH
2911
2912 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
d0a851cc 2913 ctx->mmu_idx = MMU_PHYS_IDX;
1cd012a5 2914 trans_st(ctx, a);
d0a851cc 2915 ctx->mmu_idx = hold_mmu_idx;
31234768 2916 return true;
d0a851cc 2917}
95412a61 2918
0588e061 2919static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
b2167459 2920{
6fd0c7bc 2921 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459 2922
6fd0c7bc 2923 tcg_gen_movi_i64(tcg_rt, a->i);
0588e061 2924 save_gpr(ctx, a->t, tcg_rt);
b2167459 2925 cond_free(&ctx->null_cond);
31234768 2926 return true;
b2167459
RH
2927}
2928
0588e061 2929static bool trans_addil(DisasContext *ctx, arg_addil *a)
b2167459 2930{
6fd0c7bc
RH
2931 TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
2932 TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
b2167459 2933
6fd0c7bc 2934 tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
b2167459
RH
2935 save_gpr(ctx, 1, tcg_r1);
2936 cond_free(&ctx->null_cond);
31234768 2937 return true;
b2167459
RH
2938}
2939
0588e061 2940static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
b2167459 2941{
6fd0c7bc 2942 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
b2167459
RH
2943
2944 /* Special case rb == 0, for the LDI pseudo-op.
2945 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
0588e061 2946 if (a->b == 0) {
6fd0c7bc 2947 tcg_gen_movi_i64(tcg_rt, a->i);
b2167459 2948 } else {
6fd0c7bc 2949 tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
b2167459 2950 }
0588e061 2951 save_gpr(ctx, a->t, tcg_rt);
b2167459 2952 cond_free(&ctx->null_cond);
31234768 2953 return true;
b2167459
RH
2954}
2955
6fd0c7bc 2956static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
e9efd4bc 2957 unsigned c, unsigned f, bool d, unsigned n, int disp)
98cd9ca7 2958{
6fd0c7bc 2959 TCGv_i64 dest, in2, sv;
98cd9ca7
RH
2960 DisasCond cond;
2961
98cd9ca7 2962 in2 = load_gpr(ctx, r);
aac0f603 2963 dest = tcg_temp_new_i64();
98cd9ca7 2964
6fd0c7bc 2965 tcg_gen_sub_i64(dest, in1, in2);
98cd9ca7 2966
f764718d 2967 sv = NULL;
b47a4a02 2968 if (cond_need_sv(c)) {
98cd9ca7
RH
2969 sv = do_sub_sv(ctx, dest, in1, in2);
2970 }
2971
4fe9533a 2972 cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
01afb7be 2973 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
2974}
2975
01afb7be 2976static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
98cd9ca7 2977{
e9efd4bc
RH
2978 if (!ctx->is_pa20 && a->d) {
2979 return false;
2980 }
01afb7be 2981 nullify_over(ctx);
e9efd4bc
RH
2982 return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
2983 a->c, a->f, a->d, a->n, a->disp);
01afb7be 2984}
98cd9ca7 2985
01afb7be
RH
2986static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
2987{
c65c3ee1
RH
2988 if (!ctx->is_pa20 && a->d) {
2989 return false;
2990 }
98cd9ca7 2991 nullify_over(ctx);
6fd0c7bc 2992 return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
c65c3ee1 2993 a->c, a->f, a->d, a->n, a->disp);
01afb7be
RH
2994}
2995
6fd0c7bc 2996static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
01afb7be
RH
2997 unsigned c, unsigned f, unsigned n, int disp)
2998{
6fd0c7bc 2999 TCGv_i64 dest, in2, sv, cb_cond;
01afb7be 3000 DisasCond cond;
bdcccc17 3001 bool d = false;
98cd9ca7 3002
f25d3160
RH
3003 /*
3004 * For hppa64, the ADDB conditions change with PSW.W,
3005 * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3006 */
3007 if (ctx->tb_flags & PSW_W) {
3008 d = c >= 5;
3009 if (d) {
3010 c &= 3;
3011 }
3012 }
3013
98cd9ca7 3014 in2 = load_gpr(ctx, r);
aac0f603 3015 dest = tcg_temp_new_i64();
f764718d 3016 sv = NULL;
bdcccc17 3017 cb_cond = NULL;
98cd9ca7 3018
b47a4a02 3019 if (cond_need_cb(c)) {
aac0f603
RH
3020 TCGv_i64 cb = tcg_temp_new_i64();
3021 TCGv_i64 cb_msb = tcg_temp_new_i64();
bdcccc17 3022
6fd0c7bc
RH
3023 tcg_gen_movi_i64(cb_msb, 0);
3024 tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
3025 tcg_gen_xor_i64(cb, in1, in2);
3026 tcg_gen_xor_i64(cb, cb, dest);
bdcccc17 3027 cb_cond = get_carry(ctx, d, cb, cb_msb);
b47a4a02 3028 } else {
6fd0c7bc 3029 tcg_gen_add_i64(dest, in1, in2);
b47a4a02
SS
3030 }
3031 if (cond_need_sv(c)) {
98cd9ca7 3032 sv = do_add_sv(ctx, dest, in1, in2);
98cd9ca7
RH
3033 }
3034
a751eb31 3035 cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
43675d20 3036 save_gpr(ctx, r, dest);
01afb7be 3037 return do_cbranch(ctx, disp, n, &cond);
98cd9ca7
RH
3038}
3039
01afb7be
RH
3040static bool trans_addb(DisasContext *ctx, arg_addb *a)
3041{
3042 nullify_over(ctx);
3043 return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
3044}
3045
3046static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
3047{
3048 nullify_over(ctx);
6fd0c7bc 3049 return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
01afb7be
RH
3050}
3051
3052static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
98cd9ca7 3053{
6fd0c7bc 3054 TCGv_i64 tmp, tcg_r;
98cd9ca7
RH
3055 DisasCond cond;
3056
3057 nullify_over(ctx);
3058
aac0f603 3059 tmp = tcg_temp_new_i64();
01afb7be 3060 tcg_r = load_gpr(ctx, a->r);
84e224d4 3061 if (cond_need_ext(ctx, a->d)) {
1e9ab9fb 3062 /* Force shift into [32,63] */
6fd0c7bc
RH
3063 tcg_gen_ori_i64(tmp, cpu_sar, 32);
3064 tcg_gen_shl_i64(tmp, tcg_r, tmp);
1e9ab9fb 3065 } else {
6fd0c7bc 3066 tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
1e9ab9fb 3067 }
98cd9ca7 3068
1e9ab9fb 3069 cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be 3070 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3071}
3072
01afb7be
RH
3073static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
3074{
6fd0c7bc 3075 TCGv_i64 tmp, tcg_r;
01afb7be 3076 DisasCond cond;
1e9ab9fb 3077 int p;
01afb7be
RH
3078
3079 nullify_over(ctx);
3080
aac0f603 3081 tmp = tcg_temp_new_i64();
01afb7be 3082 tcg_r = load_gpr(ctx, a->r);
84e224d4 3083 p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0);
6fd0c7bc 3084 tcg_gen_shli_i64(tmp, tcg_r, p);
01afb7be
RH
3085
3086 cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
01afb7be
RH
3087 return do_cbranch(ctx, a->disp, a->n, &cond);
3088}
3089
3090static bool trans_movb(DisasContext *ctx, arg_movb *a)
98cd9ca7 3091{
6fd0c7bc 3092 TCGv_i64 dest;
98cd9ca7
RH
3093 DisasCond cond;
3094
3095 nullify_over(ctx);
3096
01afb7be
RH
3097 dest = dest_gpr(ctx, a->r2);
3098 if (a->r1 == 0) {
6fd0c7bc 3099 tcg_gen_movi_i64(dest, 0);
98cd9ca7 3100 } else {
6fd0c7bc 3101 tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
98cd9ca7
RH
3102 }
3103
4fa52edf
RH
3104 /* All MOVB conditions are 32-bit. */
3105 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be
RH
3106 return do_cbranch(ctx, a->disp, a->n, &cond);
3107}
3108
3109static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
3110{
6fd0c7bc 3111 TCGv_i64 dest;
01afb7be
RH
3112 DisasCond cond;
3113
3114 nullify_over(ctx);
3115
3116 dest = dest_gpr(ctx, a->r);
6fd0c7bc 3117 tcg_gen_movi_i64(dest, a->i);
01afb7be 3118
4fa52edf
RH
3119 /* All MOVBI conditions are 32-bit. */
3120 cond = do_sed_cond(ctx, a->c, false, dest);
01afb7be 3121 return do_cbranch(ctx, a->disp, a->n, &cond);
98cd9ca7
RH
3122}
3123
f7b775a9 3124static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
0b1347d2 3125{
6fd0c7bc 3126 TCGv_i64 dest, src2;
0b1347d2 3127
f7b775a9
RH
3128 if (!ctx->is_pa20 && a->d) {
3129 return false;
3130 }
30878590 3131 if (a->c) {
0b1347d2
RH
3132 nullify_over(ctx);
3133 }
3134
30878590 3135 dest = dest_gpr(ctx, a->t);
f7b775a9 3136 src2 = load_gpr(ctx, a->r2);
30878590 3137 if (a->r1 == 0) {
f7b775a9 3138 if (a->d) {
6fd0c7bc 3139 tcg_gen_shr_i64(dest, src2, cpu_sar);
f7b775a9 3140 } else {
aac0f603 3141 TCGv_i64 tmp = tcg_temp_new_i64();
e1d635e8 3142
6fd0c7bc
RH
3143 tcg_gen_ext32u_i64(dest, src2);
3144 tcg_gen_andi_i64(tmp, cpu_sar, 31);
3145 tcg_gen_shr_i64(dest, dest, tmp);
f7b775a9
RH
3146 }
3147 } else if (a->r1 == a->r2) {
3148 if (a->d) {
6fd0c7bc 3149 tcg_gen_rotr_i64(dest, src2, cpu_sar);
f7b775a9
RH
3150 } else {
3151 TCGv_i32 t32 = tcg_temp_new_i32();
3152 TCGv_i32 s32 = tcg_temp_new_i32();
3153
6fd0c7bc
RH
3154 tcg_gen_extrl_i64_i32(t32, src2);
3155 tcg_gen_extrl_i64_i32(s32, cpu_sar);
f7b775a9
RH
3156 tcg_gen_andi_i32(s32, s32, 31);
3157 tcg_gen_rotr_i32(t32, t32, s32);
6fd0c7bc 3158 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3159 }
0b1347d2 3160 } else {
6fd0c7bc 3161 TCGv_i64 src1 = load_gpr(ctx, a->r1);
f7b775a9
RH
3162
3163 if (a->d) {
aac0f603
RH
3164 TCGv_i64 t = tcg_temp_new_i64();
3165 TCGv_i64 n = tcg_temp_new_i64();
6fd0c7bc
RH
3166
3167 tcg_gen_xori_i64(n, cpu_sar, 63);
3168 tcg_gen_shl_i64(t, src2, n);
3169 tcg_gen_shli_i64(t, t, 1);
3170 tcg_gen_shr_i64(dest, src1, cpu_sar);
3171 tcg_gen_or_i64(dest, dest, t);
f7b775a9
RH
3172 } else {
3173 TCGv_i64 t = tcg_temp_new_i64();
3174 TCGv_i64 s = tcg_temp_new_i64();
3175
6fd0c7bc 3176 tcg_gen_concat32_i64(t, src2, src1);
967662cd
RH
3177 tcg_gen_andi_i64(s, cpu_sar, 31);
3178 tcg_gen_shr_i64(dest, t, s);
f7b775a9 3179 }
0b1347d2 3180 }
30878590 3181 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3182
3183 /* Install the new nullification. */
3184 cond_free(&ctx->null_cond);
30878590 3185 if (a->c) {
4fa52edf 3186 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3187 }
31234768 3188 return nullify_end(ctx);
0b1347d2
RH
3189}
3190
f7b775a9 3191static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
0b1347d2 3192{
f7b775a9 3193 unsigned width, sa;
6fd0c7bc 3194 TCGv_i64 dest, t2;
0b1347d2 3195
f7b775a9
RH
3196 if (!ctx->is_pa20 && a->d) {
3197 return false;
3198 }
30878590 3199 if (a->c) {
0b1347d2
RH
3200 nullify_over(ctx);
3201 }
3202
f7b775a9
RH
3203 width = a->d ? 64 : 32;
3204 sa = width - 1 - a->cpos;
3205
30878590
RH
3206 dest = dest_gpr(ctx, a->t);
3207 t2 = load_gpr(ctx, a->r2);
05bfd4db 3208 if (a->r1 == 0) {
6fd0c7bc 3209 tcg_gen_extract_i64(dest, t2, sa, width - sa);
c53e401e 3210 } else if (width == TARGET_LONG_BITS) {
6fd0c7bc 3211 tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
0b1347d2 3212 } else {
f7b775a9
RH
3213 assert(!a->d);
3214 if (a->r1 == a->r2) {
3215 TCGv_i32 t32 = tcg_temp_new_i32();
6fd0c7bc 3216 tcg_gen_extrl_i64_i32(t32, t2);
f7b775a9 3217 tcg_gen_rotri_i32(t32, t32, sa);
6fd0c7bc 3218 tcg_gen_extu_i32_i64(dest, t32);
f7b775a9 3219 } else {
967662cd
RH
3220 tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3221 tcg_gen_extract_i64(dest, dest, sa, 32);
f7b775a9 3222 }
0b1347d2 3223 }
30878590 3224 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3225
3226 /* Install the new nullification. */
3227 cond_free(&ctx->null_cond);
30878590 3228 if (a->c) {
4fa52edf 3229 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest);
0b1347d2 3230 }
31234768 3231 return nullify_end(ctx);
0b1347d2
RH
3232}
3233
bd792da3 3234static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
0b1347d2 3235{
bd792da3 3236 unsigned widthm1 = a->d ? 63 : 31;
6fd0c7bc 3237 TCGv_i64 dest, src, tmp;
0b1347d2 3238
bd792da3
RH
3239 if (!ctx->is_pa20 && a->d) {
3240 return false;
3241 }
30878590 3242 if (a->c) {
0b1347d2
RH
3243 nullify_over(ctx);
3244 }
3245
30878590
RH
3246 dest = dest_gpr(ctx, a->t);
3247 src = load_gpr(ctx, a->r);
aac0f603 3248 tmp = tcg_temp_new_i64();
0b1347d2
RH
3249
3250 /* Recall that SAR is using big-endian bit numbering. */
6fd0c7bc
RH
3251 tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
3252 tcg_gen_xori_i64(tmp, tmp, widthm1);
d781cb77 3253
30878590 3254 if (a->se) {
bd792da3 3255 if (!a->d) {
6fd0c7bc 3256 tcg_gen_ext32s_i64(dest, src);
bd792da3
RH
3257 src = dest;
3258 }
6fd0c7bc
RH
3259 tcg_gen_sar_i64(dest, src, tmp);
3260 tcg_gen_sextract_i64(dest, dest, 0, a->len);
0b1347d2 3261 } else {
bd792da3 3262 if (!a->d) {
6fd0c7bc 3263 tcg_gen_ext32u_i64(dest, src);
bd792da3
RH
3264 src = dest;
3265 }
6fd0c7bc
RH
3266 tcg_gen_shr_i64(dest, src, tmp);
3267 tcg_gen_extract_i64(dest, dest, 0, a->len);
0b1347d2 3268 }
30878590 3269 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3270
3271 /* Install the new nullification. */
3272 cond_free(&ctx->null_cond);
30878590 3273 if (a->c) {
bd792da3 3274 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3275 }
31234768 3276 return nullify_end(ctx);
0b1347d2
RH
3277}
3278
bd792da3 3279static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
0b1347d2 3280{
bd792da3 3281 unsigned len, cpos, width;
6fd0c7bc 3282 TCGv_i64 dest, src;
0b1347d2 3283
bd792da3
RH
3284 if (!ctx->is_pa20 && a->d) {
3285 return false;
3286 }
30878590 3287 if (a->c) {
0b1347d2
RH
3288 nullify_over(ctx);
3289 }
3290
bd792da3
RH
3291 len = a->len;
3292 width = a->d ? 64 : 32;
3293 cpos = width - 1 - a->pos;
3294 if (cpos + len > width) {
3295 len = width - cpos;
3296 }
3297
30878590
RH
3298 dest = dest_gpr(ctx, a->t);
3299 src = load_gpr(ctx, a->r);
3300 if (a->se) {
6fd0c7bc 3301 tcg_gen_sextract_i64(dest, src, cpos, len);
0b1347d2 3302 } else {
6fd0c7bc 3303 tcg_gen_extract_i64(dest, src, cpos, len);
0b1347d2 3304 }
30878590 3305 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3306
3307 /* Install the new nullification. */
3308 cond_free(&ctx->null_cond);
30878590 3309 if (a->c) {
bd792da3 3310 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3311 }
31234768 3312 return nullify_end(ctx);
0b1347d2
RH
3313}
3314
72ae4f2b 3315static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
0b1347d2 3316{
72ae4f2b 3317 unsigned len, width;
c53e401e 3318 uint64_t mask0, mask1;
6fd0c7bc 3319 TCGv_i64 dest;
0b1347d2 3320
72ae4f2b
RH
3321 if (!ctx->is_pa20 && a->d) {
3322 return false;
3323 }
30878590 3324 if (a->c) {
0b1347d2
RH
3325 nullify_over(ctx);
3326 }
72ae4f2b
RH
3327
3328 len = a->len;
3329 width = a->d ? 64 : 32;
3330 if (a->cpos + len > width) {
3331 len = width - a->cpos;
0b1347d2
RH
3332 }
3333
30878590
RH
3334 dest = dest_gpr(ctx, a->t);
3335 mask0 = deposit64(0, a->cpos, len, a->i);
3336 mask1 = deposit64(-1, a->cpos, len, a->i);
0b1347d2 3337
30878590 3338 if (a->nz) {
6fd0c7bc
RH
3339 TCGv_i64 src = load_gpr(ctx, a->t);
3340 tcg_gen_andi_i64(dest, src, mask1);
3341 tcg_gen_ori_i64(dest, dest, mask0);
0b1347d2 3342 } else {
6fd0c7bc 3343 tcg_gen_movi_i64(dest, mask0);
0b1347d2 3344 }
30878590 3345 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3346
3347 /* Install the new nullification. */
3348 cond_free(&ctx->null_cond);
30878590 3349 if (a->c) {
72ae4f2b 3350 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3351 }
31234768 3352 return nullify_end(ctx);
0b1347d2
RH
3353}
3354
72ae4f2b 3355static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
0b1347d2 3356{
30878590 3357 unsigned rs = a->nz ? a->t : 0;
72ae4f2b 3358 unsigned len, width;
6fd0c7bc 3359 TCGv_i64 dest, val;
0b1347d2 3360
72ae4f2b
RH
3361 if (!ctx->is_pa20 && a->d) {
3362 return false;
3363 }
30878590 3364 if (a->c) {
0b1347d2
RH
3365 nullify_over(ctx);
3366 }
72ae4f2b
RH
3367
3368 len = a->len;
3369 width = a->d ? 64 : 32;
3370 if (a->cpos + len > width) {
3371 len = width - a->cpos;
0b1347d2
RH
3372 }
3373
30878590
RH
3374 dest = dest_gpr(ctx, a->t);
3375 val = load_gpr(ctx, a->r);
0b1347d2 3376 if (rs == 0) {
6fd0c7bc 3377 tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
0b1347d2 3378 } else {
6fd0c7bc 3379 tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
0b1347d2 3380 }
30878590 3381 save_gpr(ctx, a->t, dest);
0b1347d2
RH
3382
3383 /* Install the new nullification. */
3384 cond_free(&ctx->null_cond);
30878590 3385 if (a->c) {
72ae4f2b 3386 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
0b1347d2 3387 }
31234768 3388 return nullify_end(ctx);
0b1347d2
RH
3389}
3390
72ae4f2b 3391static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
6fd0c7bc 3392 bool d, bool nz, unsigned len, TCGv_i64 val)
0b1347d2 3393{
0b1347d2 3394 unsigned rs = nz ? rt : 0;
72ae4f2b 3395 unsigned widthm1 = d ? 63 : 31;
6fd0c7bc 3396 TCGv_i64 mask, tmp, shift, dest;
c53e401e 3397 uint64_t msb = 1ULL << (len - 1);
0b1347d2 3398
0b1347d2 3399 dest = dest_gpr(ctx, rt);
aac0f603
RH
3400 shift = tcg_temp_new_i64();
3401 tmp = tcg_temp_new_i64();
0b1347d2
RH
3402
3403 /* Convert big-endian bit numbering in SAR to left-shift. */
6fd0c7bc
RH
3404 tcg_gen_andi_i64(shift, cpu_sar, widthm1);
3405 tcg_gen_xori_i64(shift, shift, widthm1);
0b1347d2 3406
aac0f603 3407 mask = tcg_temp_new_i64();
6fd0c7bc
RH
3408 tcg_gen_movi_i64(mask, msb + (msb - 1));
3409 tcg_gen_and_i64(tmp, val, mask);
0b1347d2 3410 if (rs) {
6fd0c7bc
RH
3411 tcg_gen_shl_i64(mask, mask, shift);
3412 tcg_gen_shl_i64(tmp, tmp, shift);
3413 tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
3414 tcg_gen_or_i64(dest, dest, tmp);
0b1347d2 3415 } else {
6fd0c7bc 3416 tcg_gen_shl_i64(dest, tmp, shift);
0b1347d2 3417 }
0b1347d2
RH
3418 save_gpr(ctx, rt, dest);
3419
3420 /* Install the new nullification. */
3421 cond_free(&ctx->null_cond);
3422 if (c) {
72ae4f2b 3423 ctx->null_cond = do_sed_cond(ctx, c, d, dest);
0b1347d2 3424 }
31234768 3425 return nullify_end(ctx);
0b1347d2
RH
3426}
3427
72ae4f2b 3428static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
30878590 3429{
72ae4f2b
RH
3430 if (!ctx->is_pa20 && a->d) {
3431 return false;
3432 }
a6deecce
SS
3433 if (a->c) {
3434 nullify_over(ctx);
3435 }
72ae4f2b
RH
3436 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
3437 load_gpr(ctx, a->r));
30878590
RH
3438}
3439
72ae4f2b 3440static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
30878590 3441{
72ae4f2b
RH
3442 if (!ctx->is_pa20 && a->d) {
3443 return false;
3444 }
a6deecce
SS
3445 if (a->c) {
3446 nullify_over(ctx);
3447 }
72ae4f2b 3448 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
6fd0c7bc 3449 tcg_constant_i64(a->i));
30878590 3450}
0b1347d2 3451
8340f534 3452static bool trans_be(DisasContext *ctx, arg_be *a)
98cd9ca7 3453{
6fd0c7bc 3454 TCGv_i64 tmp;
98cd9ca7 3455
c301f34e 3456#ifdef CONFIG_USER_ONLY
98cd9ca7
RH
3457 /* ??? It seems like there should be a good way of using
3458 "be disp(sr2, r0)", the canonical gateway entry mechanism
3459 to our advantage. But that appears to be inconvenient to
3460 manage along side branch delay slots. Therefore we handle
3461 entry into the gateway page via absolute address. */
98cd9ca7
RH
3462 /* Since we don't implement spaces, just branch. Do notice the special
3463 case of "be disp(*,r0)" using a direct branch to disp, so that we can
3464 goto_tb to the TB containing the syscall. */
8340f534
RH
3465 if (a->b == 0) {
3466 return do_dbranch(ctx, a->disp, a->l, a->n);
98cd9ca7 3467 }
c301f34e 3468#else
c301f34e 3469 nullify_over(ctx);
660eefe1
RH
3470#endif
3471
aac0f603 3472 tmp = tcg_temp_new_i64();
6fd0c7bc 3473 tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp);
660eefe1 3474 tmp = do_ibranch_priv(ctx, tmp);
c301f34e
RH
3475
3476#ifdef CONFIG_USER_ONLY
8340f534 3477 return do_ibranch(ctx, tmp, a->l, a->n);
c301f34e
RH
3478#else
3479 TCGv_i64 new_spc = tcg_temp_new_i64();
3480
8340f534
RH
3481 load_spr(ctx, new_spc, a->sp);
3482 if (a->l) {
741322f4 3483 copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e
RH
3484 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3485 }
8340f534 3486 if (a->n && use_nullify_skip(ctx)) {
a0180973 3487 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp);
6fd0c7bc 3488 tcg_gen_addi_i64(tmp, tmp, 4);
a0180973 3489 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e
RH
3490 tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3491 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3492 } else {
741322f4 3493 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3494 if (ctx->iaoq_b == -1) {
3495 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3496 }
a0180973 3497 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp);
c301f34e 3498 tcg_gen_mov_i64(cpu_iasq_b, new_spc);
8340f534 3499 nullify_set(ctx, a->n);
c301f34e 3500 }
c301f34e 3501 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3502 ctx->base.is_jmp = DISAS_NORETURN;
3503 return nullify_end(ctx);
c301f34e 3504#endif
98cd9ca7
RH
3505}
3506
8340f534 3507static bool trans_bl(DisasContext *ctx, arg_bl *a)
98cd9ca7 3508{
8340f534 3509 return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
98cd9ca7
RH
3510}
3511
8340f534 3512static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
43e05652 3513{
c53e401e 3514 uint64_t dest = iaoq_dest(ctx, a->disp);
43e05652 3515
6e5f5300
SS
3516 nullify_over(ctx);
3517
43e05652
RH
3518 /* Make sure the caller hasn't done something weird with the queue.
3519 * ??? This is not quite the same as the PSW[B] bit, which would be
3520 * expensive to track. Real hardware will trap for
3521 * b gateway
3522 * b gateway+4 (in delay slot of first branch)
3523 * However, checking for a non-sequential instruction queue *will*
3524 * diagnose the security hole
3525 * b gateway
3526 * b evil
3527 * in which instructions at evil would run with increased privs.
3528 */
3529 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
3530 return gen_illegal(ctx);
3531 }
3532
3533#ifndef CONFIG_USER_ONLY
3534 if (ctx->tb_flags & PSW_C) {
b77af26e 3535 CPUHPPAState *env = cpu_env(ctx->cs);
43e05652
RH
3536 int type = hppa_artype_for_page(env, ctx->base.pc_next);
3537 /* If we could not find a TLB entry, then we need to generate an
3538 ITLB miss exception so the kernel will provide it.
3539 The resulting TLB fill operation will invalidate this TB and
3540 we will re-translate, at which point we *will* be able to find
3541 the TLB entry and determine if this is in fact a gateway page. */
3542 if (type < 0) {
31234768
RH
3543 gen_excp(ctx, EXCP_ITLB_MISS);
3544 return true;
43e05652
RH
3545 }
3546 /* No change for non-gateway pages or for priv decrease. */
3547 if (type >= 4 && type - 4 < ctx->privilege) {
3548 dest = deposit32(dest, 0, 2, type - 4);
3549 }
3550 } else {
3551 dest &= -4; /* priv = 0 */
3552 }
3553#endif
3554
6e5f5300 3555 if (a->l) {
6fd0c7bc 3556 TCGv_i64 tmp = dest_gpr(ctx, a->l);
6e5f5300 3557 if (ctx->privilege < 3) {
6fd0c7bc 3558 tcg_gen_andi_i64(tmp, tmp, -4);
6e5f5300 3559 }
6fd0c7bc 3560 tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
6e5f5300
SS
3561 save_gpr(ctx, a->l, tmp);
3562 }
3563
3564 return do_dbranch(ctx, dest, 0, a->n);
43e05652
RH
3565}
3566
8340f534 3567static bool trans_blr(DisasContext *ctx, arg_blr *a)
98cd9ca7 3568{
b35aec85 3569 if (a->x) {
aac0f603 3570 TCGv_i64 tmp = tcg_temp_new_i64();
6fd0c7bc
RH
3571 tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3);
3572 tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8);
b35aec85
RH
3573 /* The computation here never changes privilege level. */
3574 return do_ibranch(ctx, tmp, a->l, a->n);
3575 } else {
3576 /* BLR R0,RX is a good way to load PC+8 into RX. */
3577 return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n);
3578 }
98cd9ca7
RH
3579}
3580
8340f534 3581static bool trans_bv(DisasContext *ctx, arg_bv *a)
98cd9ca7 3582{
6fd0c7bc 3583 TCGv_i64 dest;
98cd9ca7 3584
8340f534
RH
3585 if (a->x == 0) {
3586 dest = load_gpr(ctx, a->b);
98cd9ca7 3587 } else {
aac0f603 3588 dest = tcg_temp_new_i64();
6fd0c7bc
RH
3589 tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
3590 tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
98cd9ca7 3591 }
660eefe1 3592 dest = do_ibranch_priv(ctx, dest);
8340f534 3593 return do_ibranch(ctx, dest, 0, a->n);
98cd9ca7
RH
3594}
3595
8340f534 3596static bool trans_bve(DisasContext *ctx, arg_bve *a)
98cd9ca7 3597{
6fd0c7bc 3598 TCGv_i64 dest;
98cd9ca7 3599
c301f34e 3600#ifdef CONFIG_USER_ONLY
8340f534
RH
3601 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3602 return do_ibranch(ctx, dest, a->l, a->n);
c301f34e
RH
3603#else
3604 nullify_over(ctx);
8340f534 3605 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
c301f34e 3606
741322f4 3607 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
c301f34e
RH
3608 if (ctx->iaoq_b == -1) {
3609 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3610 }
741322f4 3611 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest);
c301f34e 3612 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
8340f534 3613 if (a->l) {
741322f4 3614 copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 3615 }
8340f534 3616 nullify_set(ctx, a->n);
c301f34e 3617 tcg_gen_lookup_and_goto_ptr();
31234768
RH
3618 ctx->base.is_jmp = DISAS_NORETURN;
3619 return nullify_end(ctx);
c301f34e 3620#endif
98cd9ca7
RH
3621}
3622
a8966ba7
RH
3623static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
3624{
3625 /* All branch target stack instructions implement as nop. */
3626 return ctx->is_pa20;
3627}
3628
1ca74648
RH
3629/*
3630 * Float class 0
3631 */
ebe9383c 3632
1ca74648 3633static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3634{
1ca74648 3635 tcg_gen_mov_i32(dst, src);
ebe9383c
RH
3636}
3637
59f8c04b
HD
3638static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
3639{
a300dad3
RH
3640 uint64_t ret;
3641
c53e401e 3642 if (ctx->is_pa20) {
a300dad3
RH
3643 ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
3644 } else {
3645 ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
3646 }
3647
59f8c04b 3648 nullify_over(ctx);
a300dad3 3649 save_frd(0, tcg_constant_i64(ret));
59f8c04b
HD
3650 return nullify_end(ctx);
3651}
3652
1ca74648 3653static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3654{
1ca74648 3655 return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
ebe9383c
RH
3656}
3657
1ca74648 3658static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3659{
1ca74648 3660 tcg_gen_mov_i64(dst, src);
ebe9383c
RH
3661}
3662
1ca74648 3663static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3664{
1ca74648 3665 return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
ebe9383c
RH
3666}
3667
1ca74648 3668static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3669{
1ca74648 3670 tcg_gen_andi_i32(dst, src, INT32_MAX);
ebe9383c
RH
3671}
3672
1ca74648 3673static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3674{
1ca74648 3675 return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
ebe9383c
RH
3676}
3677
1ca74648 3678static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
ebe9383c 3679{
1ca74648 3680 tcg_gen_andi_i64(dst, src, INT64_MAX);
ebe9383c
RH
3681}
3682
1ca74648 3683static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3684{
1ca74648 3685 return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
ebe9383c
RH
3686}
3687
1ca74648 3688static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3689{
1ca74648 3690 return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
ebe9383c
RH
3691}
3692
1ca74648 3693static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3694{
1ca74648 3695 return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
ebe9383c
RH
3696}
3697
1ca74648 3698static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3699{
1ca74648 3700 return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
ebe9383c
RH
3701}
3702
1ca74648 3703static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3704{
1ca74648 3705 return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
ebe9383c
RH
3706}
3707
1ca74648 3708static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c 3709{
1ca74648 3710 tcg_gen_xori_i32(dst, src, INT32_MIN);
ebe9383c
RH
3711}
3712
1ca74648 3713static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
ebe9383c 3714{
1ca74648 3715 return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
ebe9383c
RH
3716}
3717
3718static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3719{
3720 tcg_gen_xori_i64(dst, src, INT64_MIN);
3721}
3722
1ca74648
RH
3723static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
3724{
3725 return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
3726}
3727
3728static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
ebe9383c
RH
3729{
3730 tcg_gen_ori_i32(dst, src, INT32_MIN);
3731}
3732
1ca74648
RH
3733static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
3734{
3735 return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
3736}
3737
ebe9383c
RH
3738static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3739{
3740 tcg_gen_ori_i64(dst, src, INT64_MIN);
3741}
3742
1ca74648
RH
3743static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
3744{
3745 return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
3746}
3747
3748/*
3749 * Float class 1
3750 */
3751
3752static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
3753{
3754 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
3755}
3756
3757static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
3758{
3759 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
3760}
3761
3762static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
3763{
3764 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
3765}
3766
3767static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
3768{
3769 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
3770}
3771
3772static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
3773{
3774 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
3775}
3776
3777static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
3778{
3779 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
3780}
3781
3782static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
3783{
3784 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
3785}
3786
3787static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
3788{
3789 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
3790}
3791
3792static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
3793{
3794 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
3795}
3796
3797static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
3798{
3799 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
3800}
3801
3802static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
3803{
3804 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
3805}
3806
3807static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
3808{
3809 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
3810}
3811
3812static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
3813{
3814 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
3815}
3816
3817static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
3818{
3819 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
3820}
3821
3822static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
3823{
3824 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
3825}
3826
3827static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
3828{
3829 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
3830}
3831
3832static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
3833{
3834 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
3835}
3836
3837static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
3838{
3839 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
3840}
3841
3842static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
3843{
3844 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
3845}
3846
3847static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
3848{
3849 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
3850}
3851
3852static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
3853{
3854 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
3855}
3856
3857static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
3858{
3859 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
3860}
3861
3862static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
3863{
3864 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
3865}
3866
3867static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
3868{
3869 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
3870}
3871
3872static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
3873{
3874 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
3875}
3876
3877static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
3878{
3879 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
3880}
3881
3882/*
3883 * Float class 2
3884 */
3885
3886static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
ebe9383c
RH
3887{
3888 TCGv_i32 ta, tb, tc, ty;
3889
3890 nullify_over(ctx);
3891
1ca74648
RH
3892 ta = load_frw0_i32(a->r1);
3893 tb = load_frw0_i32(a->r2);
29dd6f64
RH
3894 ty = tcg_constant_i32(a->y);
3895 tc = tcg_constant_i32(a->c);
ebe9383c 3896
ad75a51e 3897 gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
ebe9383c 3898
1ca74648 3899 return nullify_end(ctx);
ebe9383c
RH
3900}
3901
1ca74648 3902static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
ebe9383c 3903{
ebe9383c
RH
3904 TCGv_i64 ta, tb;
3905 TCGv_i32 tc, ty;
3906
3907 nullify_over(ctx);
3908
1ca74648
RH
3909 ta = load_frd0(a->r1);
3910 tb = load_frd0(a->r2);
29dd6f64
RH
3911 ty = tcg_constant_i32(a->y);
3912 tc = tcg_constant_i32(a->c);
ebe9383c 3913
ad75a51e 3914 gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
ebe9383c 3915
31234768 3916 return nullify_end(ctx);
ebe9383c
RH
3917}
3918
1ca74648 3919static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
ebe9383c 3920{
6fd0c7bc 3921 TCGv_i64 t;
ebe9383c
RH
3922
3923 nullify_over(ctx);
3924
aac0f603 3925 t = tcg_temp_new_i64();
6fd0c7bc 3926 tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
ebe9383c 3927
1ca74648
RH
3928 if (a->y == 1) {
3929 int mask;
3930 bool inv = false;
3931
3932 switch (a->c) {
3933 case 0: /* simple */
6fd0c7bc 3934 tcg_gen_andi_i64(t, t, 0x4000000);
1ca74648
RH
3935 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3936 goto done;
3937 case 2: /* rej */
3938 inv = true;
3939 /* fallthru */
3940 case 1: /* acc */
3941 mask = 0x43ff800;
3942 break;
3943 case 6: /* rej8 */
3944 inv = true;
3945 /* fallthru */
3946 case 5: /* acc8 */
3947 mask = 0x43f8000;
3948 break;
3949 case 9: /* acc6 */
3950 mask = 0x43e0000;
3951 break;
3952 case 13: /* acc4 */
3953 mask = 0x4380000;
3954 break;
3955 case 17: /* acc2 */
3956 mask = 0x4200000;
3957 break;
3958 default:
3959 gen_illegal(ctx);
3960 return true;
3961 }
3962 if (inv) {
6fd0c7bc
RH
3963 TCGv_i64 c = tcg_constant_i64(mask);
3964 tcg_gen_or_i64(t, t, c);
1ca74648
RH
3965 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3966 } else {
6fd0c7bc 3967 tcg_gen_andi_i64(t, t, mask);
1ca74648
RH
3968 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3969 }
3970 } else {
3971 unsigned cbit = (a->y ^ 1) - 1;
3972
6fd0c7bc 3973 tcg_gen_extract_i64(t, t, 21 - cbit, 1);
1ca74648 3974 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
1ca74648
RH
3975 }
3976
3977 done:
31234768 3978 return nullify_end(ctx);
ebe9383c
RH
3979}
3980
1ca74648
RH
3981/*
3982 * Float class 2
3983 */
3984
3985static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 3986{
1ca74648
RH
3987 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
3988}
ebe9383c 3989
1ca74648
RH
3990static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
3991{
3992 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
3993}
ebe9383c 3994
1ca74648
RH
3995static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
3996{
3997 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
3998}
ebe9383c 3999
1ca74648
RH
4000static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
4001{
4002 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
ebe9383c
RH
4003}
4004
1ca74648 4005static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
ebe9383c 4006{
1ca74648
RH
4007 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
4008}
4009
4010static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
4011{
4012 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
4013}
4014
4015static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
4016{
4017 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
4018}
4019
4020static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
4021{
4022 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
4023}
4024
4025static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
4026{
4027 TCGv_i64 x, y;
ebe9383c
RH
4028
4029 nullify_over(ctx);
4030
1ca74648
RH
4031 x = load_frw0_i64(a->r1);
4032 y = load_frw0_i64(a->r2);
4033 tcg_gen_mul_i64(x, x, y);
4034 save_frd(a->t, x);
ebe9383c 4035
31234768 4036 return nullify_end(ctx);
ebe9383c
RH
4037}
4038
ebe9383c
RH
4039/* Convert the fmpyadd single-precision register encodings to standard. */
4040static inline int fmpyadd_s_reg(unsigned r)
4041{
4042 return (r & 16) * 2 + 16 + (r & 15);
4043}
4044
b1e2af57 4045static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
ebe9383c 4046{
b1e2af57
RH
4047 int tm = fmpyadd_s_reg(a->tm);
4048 int ra = fmpyadd_s_reg(a->ra);
4049 int ta = fmpyadd_s_reg(a->ta);
4050 int rm2 = fmpyadd_s_reg(a->rm2);
4051 int rm1 = fmpyadd_s_reg(a->rm1);
ebe9383c
RH
4052
4053 nullify_over(ctx);
4054
b1e2af57
RH
4055 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4056 do_fop_weww(ctx, ta, ta, ra,
4057 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
ebe9383c 4058
31234768 4059 return nullify_end(ctx);
ebe9383c
RH
4060}
4061
b1e2af57
RH
4062static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4063{
4064 return do_fmpyadd_s(ctx, a, false);
4065}
4066
4067static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4068{
4069 return do_fmpyadd_s(ctx, a, true);
4070}
4071
4072static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4073{
4074 nullify_over(ctx);
4075
4076 do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4077 do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4078 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4079
4080 return nullify_end(ctx);
4081}
4082
4083static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4084{
4085 return do_fmpyadd_d(ctx, a, false);
4086}
4087
4088static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4089{
4090 return do_fmpyadd_d(ctx, a, true);
4091}
4092
c3bad4f8 4093static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
ebe9383c 4094{
c3bad4f8 4095 TCGv_i32 x, y, z;
ebe9383c
RH
4096
4097 nullify_over(ctx);
c3bad4f8
RH
4098 x = load_frw0_i32(a->rm1);
4099 y = load_frw0_i32(a->rm2);
4100 z = load_frw0_i32(a->ra3);
ebe9383c 4101
c3bad4f8 4102 if (a->neg) {
ad75a51e 4103 gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
ebe9383c 4104 } else {
ad75a51e 4105 gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
ebe9383c
RH
4106 }
4107
c3bad4f8 4108 save_frw_i32(a->t, x);
31234768 4109 return nullify_end(ctx);
ebe9383c
RH
4110}
4111
c3bad4f8 4112static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
ebe9383c 4113{
c3bad4f8 4114 TCGv_i64 x, y, z;
ebe9383c
RH
4115
4116 nullify_over(ctx);
c3bad4f8
RH
4117 x = load_frd0(a->rm1);
4118 y = load_frd0(a->rm2);
4119 z = load_frd0(a->ra3);
ebe9383c 4120
c3bad4f8 4121 if (a->neg) {
ad75a51e 4122 gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
ebe9383c 4123 } else {
ad75a51e 4124 gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
ebe9383c
RH
4125 }
4126
c3bad4f8 4127 save_frd(a->t, x);
31234768 4128 return nullify_end(ctx);
ebe9383c
RH
4129}
4130
15da177b
SS
4131static bool trans_diag(DisasContext *ctx, arg_diag *a)
4132{
cf6b28d4
HD
4133 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4134#ifndef CONFIG_USER_ONLY
4135 if (a->i == 0x100) {
4136 /* emulate PDC BTLB, called by SeaBIOS-hppa */
ad75a51e
RH
4137 nullify_over(ctx);
4138 gen_helper_diag_btlb(tcg_env);
4139 return nullify_end(ctx);
cf6b28d4 4140 }
ad75a51e
RH
4141#endif
4142 qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4143 return true;
15da177b
SS
4144}
4145
b542683d 4146static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
61766fe9 4147{
51b061fb 4148 DisasContext *ctx = container_of(dcbase, DisasContext, base);
f764718d 4149 int bound;
61766fe9 4150
51b061fb 4151 ctx->cs = cs;
494737b7 4152 ctx->tb_flags = ctx->base.tb->flags;
bd6243a3 4153 ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
3d68ee7b
RH
4154
4155#ifdef CONFIG_USER_ONLY
c01e5dfb 4156 ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX);
3d68ee7b 4157 ctx->mmu_idx = MMU_USER_IDX;
c01e5dfb
HD
4158 ctx->iaoq_f = ctx->base.pc_first | ctx->privilege;
4159 ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege;
217d1a5e 4160 ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
3d68ee7b 4161#else
494737b7 4162 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
bb67ec32
RH
4163 ctx->mmu_idx = (ctx->tb_flags & PSW_D
4164 ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4165 : MMU_PHYS_IDX);
3d68ee7b 4166
c301f34e
RH
4167 /* Recover the IAOQ values from the GVA + PRIV. */
4168 uint64_t cs_base = ctx->base.tb->cs_base;
4169 uint64_t iasq_f = cs_base & ~0xffffffffull;
4170 int32_t diff = cs_base;
4171
4172 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4173 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4174#endif
51b061fb 4175 ctx->iaoq_n = -1;
f764718d 4176 ctx->iaoq_n_var = NULL;
61766fe9 4177
3d68ee7b
RH
4178 /* Bound the number of instructions by those left on the page. */
4179 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
b542683d 4180 ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
51b061fb 4181}
61766fe9 4182
51b061fb
RH
4183static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
4184{
4185 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4186
3d68ee7b 4187 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
51b061fb
RH
4188 ctx->null_cond = cond_make_f();
4189 ctx->psw_n_nonzero = false;
494737b7 4190 if (ctx->tb_flags & PSW_N) {
51b061fb
RH
4191 ctx->null_cond.c = TCG_COND_ALWAYS;
4192 ctx->psw_n_nonzero = true;
129e9cc3 4193 }
51b061fb
RH
4194 ctx->null_lab = NULL;
4195}
129e9cc3 4196
51b061fb
RH
4197static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
4198{
4199 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4200
51b061fb
RH
4201 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
4202}
4203
51b061fb
RH
4204static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
4205{
4206 DisasContext *ctx = container_of(dcbase, DisasContext, base);
b77af26e 4207 CPUHPPAState *env = cpu_env(cs);
51b061fb 4208 DisasJumpType ret;
51b061fb
RH
4209
4210 /* Execute one insn. */
ba1d0b44 4211#ifdef CONFIG_USER_ONLY
c301f34e 4212 if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
31234768
RH
4213 do_page_zero(ctx);
4214 ret = ctx->base.is_jmp;
51b061fb 4215 assert(ret != DISAS_NEXT);
ba1d0b44
RH
4216 } else
4217#endif
4218 {
51b061fb
RH
4219 /* Always fetch the insn, even if nullified, so that we check
4220 the page permissions for execute. */
4e116893 4221 uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
51b061fb
RH
4222
4223 /* Set up the IA queue for the next insn.
4224 This will be overwritten by a branch. */
4225 if (ctx->iaoq_b == -1) {
4226 ctx->iaoq_n = -1;
aac0f603 4227 ctx->iaoq_n_var = tcg_temp_new_i64();
6fd0c7bc 4228 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4);
7ad439df 4229 } else {
51b061fb 4230 ctx->iaoq_n = ctx->iaoq_b + 4;
f764718d 4231 ctx->iaoq_n_var = NULL;
61766fe9
RH
4232 }
4233
51b061fb
RH
4234 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
4235 ctx->null_cond.c = TCG_COND_NEVER;
4236 ret = DISAS_NEXT;
4237 } else {
1a19da0d 4238 ctx->insn = insn;
31274b46
RH
4239 if (!decode(ctx, insn)) {
4240 gen_illegal(ctx);
4241 }
31234768 4242 ret = ctx->base.is_jmp;
51b061fb 4243 assert(ctx->null_lab == NULL);
61766fe9 4244 }
51b061fb 4245 }
61766fe9 4246
3d68ee7b
RH
4247 /* Advance the insn queue. Note that this check also detects
4248 a priority change within the instruction queue. */
51b061fb 4249 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
c301f34e
RH
4250 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4251 && use_goto_tb(ctx, ctx->iaoq_b)
4252 && (ctx->null_cond.c == TCG_COND_NEVER
4253 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
51b061fb
RH
4254 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4255 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
31234768 4256 ctx->base.is_jmp = ret = DISAS_NORETURN;
51b061fb 4257 } else {
31234768 4258 ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
c301f34e 4259 }
61766fe9 4260 }
51b061fb
RH
4261 ctx->iaoq_f = ctx->iaoq_b;
4262 ctx->iaoq_b = ctx->iaoq_n;
c301f34e 4263 ctx->base.pc_next += 4;
51b061fb 4264
c5d0aec2
RH
4265 switch (ret) {
4266 case DISAS_NORETURN:
4267 case DISAS_IAQ_N_UPDATED:
4268 break;
4269
4270 case DISAS_NEXT:
4271 case DISAS_IAQ_N_STALE:
4272 case DISAS_IAQ_N_STALE_EXIT:
4273 if (ctx->iaoq_f == -1) {
a0180973 4274 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b);
741322f4 4275 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e 4276#ifndef CONFIG_USER_ONLY
c5d0aec2 4277 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
c301f34e 4278#endif
c5d0aec2
RH
4279 nullify_save(ctx);
4280 ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT
4281 ? DISAS_EXIT
4282 : DISAS_IAQ_N_UPDATED);
4283 } else if (ctx->iaoq_b == -1) {
a0180973 4284 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var);
c5d0aec2
RH
4285 }
4286 break;
4287
4288 default:
4289 g_assert_not_reached();
51b061fb
RH
4290 }
4291}
4292
4293static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
4294{
4295 DisasContext *ctx = container_of(dcbase, DisasContext, base);
e1b5a5ed 4296 DisasJumpType is_jmp = ctx->base.is_jmp;
61766fe9 4297
e1b5a5ed 4298 switch (is_jmp) {
869051ea 4299 case DISAS_NORETURN:
61766fe9 4300 break;
51b061fb 4301 case DISAS_TOO_MANY:
869051ea 4302 case DISAS_IAQ_N_STALE:
e1b5a5ed 4303 case DISAS_IAQ_N_STALE_EXIT:
741322f4
RH
4304 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4305 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
51b061fb 4306 nullify_save(ctx);
61766fe9 4307 /* FALLTHRU */
869051ea 4308 case DISAS_IAQ_N_UPDATED:
8532a14e 4309 if (is_jmp != DISAS_IAQ_N_STALE_EXIT) {
7f11636d 4310 tcg_gen_lookup_and_goto_ptr();
8532a14e 4311 break;
61766fe9 4312 }
c5d0aec2
RH
4313 /* FALLTHRU */
4314 case DISAS_EXIT:
4315 tcg_gen_exit_tb(NULL, 0);
61766fe9
RH
4316 break;
4317 default:
51b061fb 4318 g_assert_not_reached();
61766fe9 4319 }
51b061fb 4320}
61766fe9 4321
8eb806a7
RH
4322static void hppa_tr_disas_log(const DisasContextBase *dcbase,
4323 CPUState *cs, FILE *logfile)
51b061fb 4324{
c301f34e 4325 target_ulong pc = dcbase->pc_first;
61766fe9 4326
ba1d0b44
RH
4327#ifdef CONFIG_USER_ONLY
4328 switch (pc) {
51b061fb 4329 case 0x00:
8eb806a7 4330 fprintf(logfile, "IN:\n0x00000000: (null)\n");
ba1d0b44 4331 return;
51b061fb 4332 case 0xb0:
8eb806a7 4333 fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n");
ba1d0b44 4334 return;
51b061fb 4335 case 0xe0:
8eb806a7 4336 fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
ba1d0b44 4337 return;
51b061fb 4338 case 0x100:
8eb806a7 4339 fprintf(logfile, "IN:\n0x00000100: syscall\n");
ba1d0b44 4340 return;
61766fe9 4341 }
ba1d0b44
RH
4342#endif
4343
8eb806a7
RH
4344 fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
4345 target_disas(logfile, cs, pc, dcbase->tb->size);
51b061fb
RH
4346}
4347
4348static const TranslatorOps hppa_tr_ops = {
4349 .init_disas_context = hppa_tr_init_disas_context,
4350 .tb_start = hppa_tr_tb_start,
4351 .insn_start = hppa_tr_insn_start,
51b061fb
RH
4352 .translate_insn = hppa_tr_translate_insn,
4353 .tb_stop = hppa_tr_tb_stop,
4354 .disas_log = hppa_tr_disas_log,
4355};
4356
597f9b2d 4357void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
306c8721 4358 target_ulong pc, void *host_pc)
51b061fb
RH
4359{
4360 DisasContext ctx;
306c8721 4361 translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
61766fe9 4362}