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