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