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