2 * HPPA emulation cpu translation for qemu.
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
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.
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.
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/>.
20 #include "qemu/osdep.h"
22 #include "qemu/host-utils.h"
23 #include "exec/exec-all.h"
24 #include "exec/page-protection.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"
32 #define HELPER_H "helper.h"
33 #include "exec/helper-info.c.inc"
36 /* Choose to use explicit sizes within this file. */
39 typedef struct DisasCond
{
44 typedef struct DisasIAQE
{
45 /* IASQ; may be null for no change from TB. */
47 /* IAOQ base; may be null for relative address. */
49 /* IAOQ addend; if base is null, relative to cpu_iaoq_f. */
53 typedef struct DisasDelayException
{
54 struct DisasDelayException
*next
;
60 /* Saved state at parent insn. */
61 DisasIAQE iaq_f
, iaq_b
;
62 } DisasDelayException
;
64 typedef struct DisasContext
{
65 DisasContextBase base
;
68 /* IAQ_Front, IAQ_Back. */
69 DisasIAQE iaq_f
, iaq_b
;
70 /* IAQ_Next, for jumps, otherwise null for simple advance. */
71 DisasIAQE iaq_j
, *iaq_n
;
73 /* IAOQ_Front at entry to TB. */
79 DisasDelayException
*delay_excp_list
;
90 bool insn_start_updated
;
92 #ifdef CONFIG_USER_ONLY
97 #ifdef CONFIG_USER_ONLY
98 #define UNALIGN(C) (C)->unalign
99 #define MMU_DISABLED(C) false
101 #define UNALIGN(C) MO_ALIGN
102 #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx)
105 /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */
106 static int expand_sm_imm(DisasContext
*ctx
, int val
)
108 /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
110 if (val
& PSW_SM_W
) {
113 val
&= ~(PSW_SM_W
| PSW_SM_E
| PSW_G
);
115 val
&= ~(PSW_SM_W
| PSW_SM_E
| PSW_O
);
120 /* Inverted space register indicates 0 means sr0 not inferred from base. */
121 static int expand_sr3x(DisasContext
*ctx
, int val
)
126 /* Convert the M:A bits within a memory insn to the tri-state value
127 we use for the final M. */
128 static int ma_to_m(DisasContext
*ctx
, int val
)
130 return val
& 2 ? (val
& 1 ? -1 : 1) : 0;
133 /* Convert the sign of the displacement to a pre or post-modify. */
134 static int pos_to_m(DisasContext
*ctx
, int val
)
139 static int neg_to_m(DisasContext
*ctx
, int val
)
144 /* Used for branch targets and fp memory ops. */
145 static int expand_shl2(DisasContext
*ctx
, int val
)
150 /* Used for assemble_21. */
151 static int expand_shl11(DisasContext
*ctx
, int val
)
156 static int assemble_6(DisasContext
*ctx
, int val
)
159 * Officially, 32 * x + 32 - y.
160 * Here, x is already in bit 5, and y is [4:0].
161 * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
162 * with the overflow from bit 4 summing with x.
164 return (val
^ 31) + 1;
167 /* Expander for assemble_16a(s,cat(im10a,0),i). */
168 static int expand_11a(DisasContext
*ctx
, int val
)
171 * @val is bit 0 and bits [4:15].
172 * Swizzle thing around depending on PSW.W.
174 int im10a
= extract32(val
, 1, 10);
175 int s
= extract32(val
, 11, 2);
176 int i
= (-(val
& 1) << 13) | (im10a
<< 3);
178 if (ctx
->tb_flags
& PSW_W
) {
184 /* Expander for assemble_16a(s,im11a,i). */
185 static int expand_12a(DisasContext
*ctx
, int val
)
188 * @val is bit 0 and bits [3:15].
189 * Swizzle thing around depending on PSW.W.
191 int im11a
= extract32(val
, 1, 11);
192 int s
= extract32(val
, 12, 2);
193 int i
= (-(val
& 1) << 13) | (im11a
<< 2);
195 if (ctx
->tb_flags
& PSW_W
) {
201 /* Expander for assemble_16(s,im14). */
202 static int expand_16(DisasContext
*ctx
, int val
)
205 * @val is bits [0:15], containing both im14 and s.
206 * Swizzle thing around depending on PSW.W.
208 int s
= extract32(val
, 14, 2);
209 int i
= (-(val
& 1) << 13) | extract32(val
, 1, 13);
211 if (ctx
->tb_flags
& PSW_W
) {
217 /* The sp field is only present with !PSW_W. */
218 static int sp0_if_wide(DisasContext
*ctx
, int sp
)
220 return ctx
->tb_flags
& PSW_W
? 0 : sp
;
223 /* Translate CMPI doubleword conditions to standard. */
224 static int cmpbid_c(DisasContext
*ctx
, int val
)
226 return val
? val
: 4; /* 0 == "*<<" */
230 * In many places pa1.x did not decode the bit that later became
231 * the pa2.0 D bit. Suppress D unless the cpu is pa2.0.
233 static int pa20_d(DisasContext
*ctx
, int val
)
235 return ctx
->is_pa20
& val
;
238 /* Include the auto-generated decoder. */
239 #include "decode-insns.c.inc"
241 /* We are not using a goto_tb (for whatever reason), but have updated
242 the iaq (for whatever reason), so don't do it again on exit. */
243 #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0
245 /* We are exiting the TB, but have neither emitted a goto_tb, nor
246 updated the iaq for the next instruction to be executed. */
247 #define DISAS_IAQ_N_STALE DISAS_TARGET_1
249 /* Similarly, but we want to return to the main loop immediately
250 to recognize unmasked interrupts. */
251 #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2
252 #define DISAS_EXIT DISAS_TARGET_3
254 /* global register indexes */
255 static TCGv_i64 cpu_gr
[32];
256 static TCGv_i64 cpu_sr
[4];
257 static TCGv_i64 cpu_srH
;
258 static TCGv_i64 cpu_iaoq_f
;
259 static TCGv_i64 cpu_iaoq_b
;
260 static TCGv_i64 cpu_iasq_f
;
261 static TCGv_i64 cpu_iasq_b
;
262 static TCGv_i64 cpu_sar
;
263 static TCGv_i64 cpu_psw_n
;
264 static TCGv_i64 cpu_psw_v
;
265 static TCGv_i64 cpu_psw_cb
;
266 static TCGv_i64 cpu_psw_cb_msb
;
267 static TCGv_i32 cpu_psw_xb
;
269 void hppa_translate_init(void)
271 #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
273 typedef struct { TCGv_i64
*var
; const char *name
; int ofs
; } GlobalVar
;
274 static const GlobalVar vars
[] = {
275 { &cpu_sar
, "sar", offsetof(CPUHPPAState
, cr
[CR_SAR
]) },
286 /* Use the symbolic register names that match the disassembler. */
287 static const char gr_names
[32][4] = {
288 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
289 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
290 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
291 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
293 /* SR[4-7] are not global registers so that we can index them. */
294 static const char sr_names
[5][4] = {
295 "sr0", "sr1", "sr2", "sr3", "srH"
301 for (i
= 1; i
< 32; i
++) {
302 cpu_gr
[i
] = tcg_global_mem_new(tcg_env
,
303 offsetof(CPUHPPAState
, gr
[i
]),
306 for (i
= 0; i
< 4; i
++) {
307 cpu_sr
[i
] = tcg_global_mem_new_i64(tcg_env
,
308 offsetof(CPUHPPAState
, sr
[i
]),
311 cpu_srH
= tcg_global_mem_new_i64(tcg_env
,
312 offsetof(CPUHPPAState
, sr
[4]),
315 for (i
= 0; i
< ARRAY_SIZE(vars
); ++i
) {
316 const GlobalVar
*v
= &vars
[i
];
317 *v
->var
= tcg_global_mem_new(tcg_env
, v
->ofs
, v
->name
);
320 cpu_psw_xb
= tcg_global_mem_new_i32(tcg_env
,
321 offsetof(CPUHPPAState
, psw_xb
),
323 cpu_iasq_f
= tcg_global_mem_new_i64(tcg_env
,
324 offsetof(CPUHPPAState
, iasq_f
),
326 cpu_iasq_b
= tcg_global_mem_new_i64(tcg_env
,
327 offsetof(CPUHPPAState
, iasq_b
),
331 static void set_insn_breg(DisasContext
*ctx
, int breg
)
333 assert(!ctx
->insn_start_updated
);
334 ctx
->insn_start_updated
= true;
335 tcg_set_insn_start_param(ctx
->base
.insn_start
, 2, breg
);
338 static DisasCond
cond_make_f(void)
347 static DisasCond
cond_make_t(void)
350 .c
= TCG_COND_ALWAYS
,
356 static DisasCond
cond_make_n(void)
361 .a1
= tcg_constant_i64(0)
365 static DisasCond
cond_make_tt(TCGCond c
, TCGv_i64 a0
, TCGv_i64 a1
)
367 assert (c
!= TCG_COND_NEVER
&& c
!= TCG_COND_ALWAYS
);
368 return (DisasCond
){ .c
= c
, .a0
= a0
, .a1
= a1
};
371 static DisasCond
cond_make_ti(TCGCond c
, TCGv_i64 a0
, uint64_t imm
)
373 return cond_make_tt(c
, a0
, tcg_constant_i64(imm
));
376 static DisasCond
cond_make_vi(TCGCond c
, TCGv_i64 a0
, uint64_t imm
)
378 TCGv_i64 tmp
= tcg_temp_new_i64();
379 tcg_gen_mov_i64(tmp
, a0
);
380 return cond_make_ti(c
, tmp
, imm
);
383 static DisasCond
cond_make_vv(TCGCond c
, TCGv_i64 a0
, TCGv_i64 a1
)
385 TCGv_i64 t0
= tcg_temp_new_i64();
386 TCGv_i64 t1
= tcg_temp_new_i64();
388 tcg_gen_mov_i64(t0
, a0
);
389 tcg_gen_mov_i64(t1
, a1
);
390 return cond_make_tt(c
, t0
, t1
);
393 static TCGv_i64
load_gpr(DisasContext
*ctx
, unsigned reg
)
402 static TCGv_i64
dest_gpr(DisasContext
*ctx
, unsigned reg
)
404 if (reg
== 0 || ctx
->null_cond
.c
!= TCG_COND_NEVER
) {
405 return tcg_temp_new_i64();
411 static void save_or_nullify(DisasContext
*ctx
, TCGv_i64 dest
, TCGv_i64 t
)
413 if (ctx
->null_cond
.c
!= TCG_COND_NEVER
) {
414 tcg_gen_movcond_i64(ctx
->null_cond
.c
, dest
, ctx
->null_cond
.a0
,
415 ctx
->null_cond
.a1
, dest
, t
);
417 tcg_gen_mov_i64(dest
, t
);
421 static void save_gpr(DisasContext
*ctx
, unsigned reg
, TCGv_i64 t
)
424 save_or_nullify(ctx
, cpu_gr
[reg
], t
);
436 static TCGv_i32
load_frw_i32(unsigned rt
)
438 TCGv_i32 ret
= tcg_temp_new_i32();
439 tcg_gen_ld_i32(ret
, tcg_env
,
440 offsetof(CPUHPPAState
, fr
[rt
& 31])
441 + (rt
& 32 ? LO_OFS
: HI_OFS
));
445 static TCGv_i32
load_frw0_i32(unsigned rt
)
448 TCGv_i32 ret
= tcg_temp_new_i32();
449 tcg_gen_movi_i32(ret
, 0);
452 return load_frw_i32(rt
);
456 static TCGv_i64
load_frw0_i64(unsigned rt
)
458 TCGv_i64 ret
= tcg_temp_new_i64();
460 tcg_gen_movi_i64(ret
, 0);
462 tcg_gen_ld32u_i64(ret
, tcg_env
,
463 offsetof(CPUHPPAState
, fr
[rt
& 31])
464 + (rt
& 32 ? LO_OFS
: HI_OFS
));
469 static void save_frw_i32(unsigned rt
, TCGv_i32 val
)
471 tcg_gen_st_i32(val
, tcg_env
,
472 offsetof(CPUHPPAState
, fr
[rt
& 31])
473 + (rt
& 32 ? LO_OFS
: HI_OFS
));
479 static TCGv_i64
load_frd(unsigned rt
)
481 TCGv_i64 ret
= tcg_temp_new_i64();
482 tcg_gen_ld_i64(ret
, tcg_env
, offsetof(CPUHPPAState
, fr
[rt
]));
486 static TCGv_i64
load_frd0(unsigned rt
)
489 TCGv_i64 ret
= tcg_temp_new_i64();
490 tcg_gen_movi_i64(ret
, 0);
497 static void save_frd(unsigned rt
, TCGv_i64 val
)
499 tcg_gen_st_i64(val
, tcg_env
, offsetof(CPUHPPAState
, fr
[rt
]));
502 static void load_spr(DisasContext
*ctx
, TCGv_i64 dest
, unsigned reg
)
504 #ifdef CONFIG_USER_ONLY
505 tcg_gen_movi_i64(dest
, 0);
508 tcg_gen_mov_i64(dest
, cpu_sr
[reg
]);
509 } else if (ctx
->tb_flags
& TB_FLAG_SR_SAME
) {
510 tcg_gen_mov_i64(dest
, cpu_srH
);
512 tcg_gen_ld_i64(dest
, tcg_env
, offsetof(CPUHPPAState
, sr
[reg
]));
518 * Write a value to psw_xb, bearing in mind the known value.
519 * To be used just before exiting the TB, so do not update the known value.
521 static void store_psw_xb(DisasContext
*ctx
, uint32_t xb
)
523 tcg_debug_assert(xb
== 0 || xb
== PSW_B
);
524 if (ctx
->psw_xb
!= xb
) {
525 tcg_gen_movi_i32(cpu_psw_xb
, xb
);
529 /* Write a value to psw_xb, and update the known value. */
530 static void set_psw_xb(DisasContext
*ctx
, uint32_t xb
)
532 store_psw_xb(ctx
, xb
);
536 /* Skip over the implementation of an insn that has been nullified.
537 Use this when the insn is too complex for a conditional move. */
538 static void nullify_over(DisasContext
*ctx
)
540 if (ctx
->null_cond
.c
!= TCG_COND_NEVER
) {
541 /* The always condition should have been handled in the main loop. */
542 assert(ctx
->null_cond
.c
!= TCG_COND_ALWAYS
);
544 ctx
->null_lab
= gen_new_label();
546 /* If we're using PSW[N], copy it to a temp because... */
547 if (ctx
->null_cond
.a0
== cpu_psw_n
) {
548 ctx
->null_cond
.a0
= tcg_temp_new_i64();
549 tcg_gen_mov_i64(ctx
->null_cond
.a0
, cpu_psw_n
);
551 /* ... we clear it before branching over the implementation,
552 so that (1) it's clear after nullifying this insn and
553 (2) if this insn nullifies the next, PSW[N] is valid. */
554 if (ctx
->psw_n_nonzero
) {
555 ctx
->psw_n_nonzero
= false;
556 tcg_gen_movi_i64(cpu_psw_n
, 0);
559 tcg_gen_brcond_i64(ctx
->null_cond
.c
, ctx
->null_cond
.a0
,
560 ctx
->null_cond
.a1
, ctx
->null_lab
);
561 ctx
->null_cond
= cond_make_f();
565 /* Save the current nullification state to PSW[N]. */
566 static void nullify_save(DisasContext
*ctx
)
568 if (ctx
->null_cond
.c
== TCG_COND_NEVER
) {
569 if (ctx
->psw_n_nonzero
) {
570 tcg_gen_movi_i64(cpu_psw_n
, 0);
574 if (ctx
->null_cond
.a0
!= cpu_psw_n
) {
575 tcg_gen_setcond_i64(ctx
->null_cond
.c
, cpu_psw_n
,
576 ctx
->null_cond
.a0
, ctx
->null_cond
.a1
);
577 ctx
->psw_n_nonzero
= true;
579 ctx
->null_cond
= cond_make_f();
582 /* Set a PSW[N] to X. The intention is that this is used immediately
583 before a goto_tb/exit_tb, so that there is no fallthru path to other
584 code within the TB. Therefore we do not update psw_n_nonzero. */
585 static void nullify_set(DisasContext
*ctx
, bool x
)
587 if (ctx
->psw_n_nonzero
|| x
) {
588 tcg_gen_movi_i64(cpu_psw_n
, x
);
592 /* Mark the end of an instruction that may have been nullified.
593 This is the pair to nullify_over. Always returns true so that
594 it may be tail-called from a translate function. */
595 static bool nullify_end(DisasContext
*ctx
)
597 TCGLabel
*null_lab
= ctx
->null_lab
;
598 DisasJumpType status
= ctx
->base
.is_jmp
;
600 /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
601 For UPDATED, we cannot update on the nullified path. */
602 assert(status
!= DISAS_IAQ_N_UPDATED
);
603 /* Taken branches are handled manually. */
604 assert(!ctx
->psw_b_next
);
606 if (likely(null_lab
== NULL
)) {
607 /* The current insn wasn't conditional or handled the condition
608 applied to it without a branch, so the (new) setting of
609 NULL_COND can be applied directly to the next insn. */
612 ctx
->null_lab
= NULL
;
614 if (likely(ctx
->null_cond
.c
== TCG_COND_NEVER
)) {
615 /* The next instruction will be unconditional,
616 and NULL_COND already reflects that. */
617 gen_set_label(null_lab
);
619 /* The insn that we just executed is itself nullifying the next
620 instruction. Store the condition in the PSW[N] global.
621 We asserted PSW[N] = 0 in nullify_over, so that after the
622 label we have the proper value in place. */
624 gen_set_label(null_lab
);
625 ctx
->null_cond
= cond_make_n();
627 if (status
== DISAS_NORETURN
) {
628 ctx
->base
.is_jmp
= DISAS_NEXT
;
633 static bool iaqe_variable(const DisasIAQE
*e
)
635 return e
->base
|| e
->space
;
638 static DisasIAQE
iaqe_incr(const DisasIAQE
*e
, int64_t disp
)
643 .disp
= e
->disp
+ disp
,
647 static DisasIAQE
iaqe_branchi(DisasContext
*ctx
, int64_t disp
)
650 .space
= ctx
->iaq_b
.space
,
651 .disp
= ctx
->iaq_f
.disp
+ 8 + disp
,
655 static DisasIAQE
iaqe_next_absv(DisasContext
*ctx
, TCGv_i64 var
)
658 .space
= ctx
->iaq_b
.space
,
663 static void copy_iaoq_entry(DisasContext
*ctx
, TCGv_i64 dest
,
664 const DisasIAQE
*src
)
666 tcg_gen_addi_i64(dest
, src
->base
? : cpu_iaoq_f
, src
->disp
);
669 static void install_iaq_entries(DisasContext
*ctx
, const DisasIAQE
*f
,
675 b_next
= iaqe_incr(f
, 4);
680 * There is an edge case
683 * for which F will use cpu_iaoq_b (from the indirect branch),
684 * and B will use cpu_iaoq_f (from the direct branch).
685 * In this case we need an extra temporary.
687 if (f
->base
!= cpu_iaoq_b
) {
688 copy_iaoq_entry(ctx
, cpu_iaoq_b
, b
);
689 copy_iaoq_entry(ctx
, cpu_iaoq_f
, f
);
690 } else if (f
->base
== b
->base
) {
691 copy_iaoq_entry(ctx
, cpu_iaoq_f
, f
);
692 tcg_gen_addi_i64(cpu_iaoq_b
, cpu_iaoq_f
, b
->disp
- f
->disp
);
694 TCGv_i64 tmp
= tcg_temp_new_i64();
695 copy_iaoq_entry(ctx
, tmp
, b
);
696 copy_iaoq_entry(ctx
, cpu_iaoq_f
, f
);
697 tcg_gen_mov_i64(cpu_iaoq_b
, tmp
);
701 tcg_gen_mov_i64(cpu_iasq_f
, f
->space
);
703 if (b
->space
|| f
->space
) {
704 tcg_gen_mov_i64(cpu_iasq_b
, b
->space
? : f
->space
);
708 static void install_link(DisasContext
*ctx
, unsigned link
, bool with_sr0
)
710 tcg_debug_assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
714 DisasIAQE next
= iaqe_incr(&ctx
->iaq_b
, 4);
715 copy_iaoq_entry(ctx
, cpu_gr
[link
], &next
);
716 #ifndef CONFIG_USER_ONLY
718 tcg_gen_mov_i64(cpu_sr
[0], cpu_iasq_b
);
723 static void gen_excp_1(int exception
)
725 gen_helper_excp(tcg_env
, tcg_constant_i32(exception
));
728 static void gen_excp(DisasContext
*ctx
, int exception
)
730 install_iaq_entries(ctx
, &ctx
->iaq_f
, &ctx
->iaq_b
);
732 gen_excp_1(exception
);
733 ctx
->base
.is_jmp
= DISAS_NORETURN
;
736 static DisasDelayException
*delay_excp(DisasContext
*ctx
, uint8_t excp
)
738 DisasDelayException
*e
= tcg_malloc(sizeof(DisasDelayException
));
740 memset(e
, 0, sizeof(*e
));
741 e
->next
= ctx
->delay_excp_list
;
742 ctx
->delay_excp_list
= e
;
744 e
->lab
= gen_new_label();
747 e
->set_n
= ctx
->psw_n_nonzero
? 0 : -1;
749 e
->iaq_f
= ctx
->iaq_f
;
750 e
->iaq_b
= ctx
->iaq_b
;
755 static bool gen_excp_iir(DisasContext
*ctx
, int exc
)
757 if (ctx
->null_cond
.c
== TCG_COND_NEVER
) {
758 tcg_gen_st_i64(tcg_constant_i64(ctx
->insn
),
759 tcg_env
, offsetof(CPUHPPAState
, cr
[CR_IIR
]));
762 DisasDelayException
*e
= delay_excp(ctx
, exc
);
763 tcg_gen_brcond_i64(tcg_invert_cond(ctx
->null_cond
.c
),
764 ctx
->null_cond
.a0
, ctx
->null_cond
.a1
, e
->lab
);
765 ctx
->null_cond
= cond_make_f();
770 static bool gen_illegal(DisasContext
*ctx
)
772 return gen_excp_iir(ctx
, EXCP_ILL
);
775 #ifdef CONFIG_USER_ONLY
776 #define CHECK_MOST_PRIVILEGED(EXCP) \
777 return gen_excp_iir(ctx, EXCP)
779 #define CHECK_MOST_PRIVILEGED(EXCP) \
781 if (ctx->privilege != 0) { \
782 return gen_excp_iir(ctx, EXCP); \
787 static bool use_goto_tb(DisasContext
*ctx
, const DisasIAQE
*f
,
790 return (!iaqe_variable(f
) &&
791 (b
== NULL
|| !iaqe_variable(b
)) &&
792 translator_use_goto_tb(&ctx
->base
, ctx
->iaoq_first
+ f
->disp
));
795 /* If the next insn is to be nullified, and it's on the same page,
796 and we're not attempting to set a breakpoint on it, then we can
797 totally skip the nullified insn. This avoids creating and
798 executing a TB that merely branches to the next TB. */
799 static bool use_nullify_skip(DisasContext
*ctx
)
801 return (!(tb_cflags(ctx
->base
.tb
) & CF_BP_PAGE
)
802 && !iaqe_variable(&ctx
->iaq_b
)
803 && (((ctx
->iaoq_first
+ ctx
->iaq_b
.disp
) ^ ctx
->iaoq_first
)
804 & TARGET_PAGE_MASK
) == 0);
807 static void gen_goto_tb(DisasContext
*ctx
, int which
,
808 const DisasIAQE
*f
, const DisasIAQE
*b
)
810 install_iaq_entries(ctx
, f
, b
);
811 if (use_goto_tb(ctx
, f
, b
)) {
812 tcg_gen_goto_tb(which
);
813 tcg_gen_exit_tb(ctx
->base
.tb
, which
);
815 tcg_gen_lookup_and_goto_ptr();
819 static bool cond_need_sv(int c
)
821 return c
== 2 || c
== 3 || c
== 6;
824 static bool cond_need_cb(int c
)
826 return c
== 4 || c
== 5;
830 * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of
831 * the Parisc 1.1 Architecture Reference Manual for details.
834 static DisasCond
do_cond(DisasContext
*ctx
, unsigned cf
, bool d
,
835 TCGv_i64 res
, TCGv_i64 uv
, TCGv_i64 sv
)
837 TCGCond sign_cond
, zero_cond
;
838 uint64_t sign_imm
, zero_imm
;
843 /* 64-bit condition. */
845 sign_cond
= TCG_COND_LT
;
847 zero_cond
= TCG_COND_EQ
;
849 /* 32-bit condition. */
850 sign_imm
= 1ull << 31;
851 sign_cond
= TCG_COND_TSTNE
;
852 zero_imm
= UINT32_MAX
;
853 zero_cond
= TCG_COND_TSTEQ
;
857 case 0: /* Never / TR (0 / 1) */
858 cond
= cond_make_f();
860 case 1: /* = / <> (Z / !Z) */
861 cond
= cond_make_vi(zero_cond
, res
, zero_imm
);
863 case 2: /* < / >= (N ^ V / !(N ^ V) */
864 tmp
= tcg_temp_new_i64();
865 tcg_gen_xor_i64(tmp
, res
, sv
);
866 cond
= cond_make_ti(sign_cond
, tmp
, sign_imm
);
868 case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */
872 * ((res < 0) ^ (sv < 0)) | !res
873 * ((res ^ sv) < 0) | !res
874 * ((res ^ sv) < 0 ? 1 : !res)
875 * !((res ^ sv) < 0 ? 0 : res)
877 tmp
= tcg_temp_new_i64();
878 tcg_gen_xor_i64(tmp
, res
, sv
);
879 tcg_gen_movcond_i64(sign_cond
, tmp
,
880 tmp
, tcg_constant_i64(sign_imm
),
882 cond
= cond_make_ti(zero_cond
, tmp
, zero_imm
);
884 case 4: /* NUV / UV (!UV / UV) */
885 cond
= cond_make_vi(TCG_COND_EQ
, uv
, 0);
887 case 5: /* ZNV / VNZ (!UV | Z / UV & !Z) */
888 tmp
= tcg_temp_new_i64();
889 tcg_gen_movcond_i64(TCG_COND_EQ
, tmp
, uv
, ctx
->zero
, ctx
->zero
, res
);
890 cond
= cond_make_ti(zero_cond
, tmp
, zero_imm
);
892 case 6: /* SV / NSV (V / !V) */
893 cond
= cond_make_vi(sign_cond
, sv
, sign_imm
);
895 case 7: /* OD / EV */
896 cond
= cond_make_vi(TCG_COND_TSTNE
, res
, 1);
899 g_assert_not_reached();
902 cond
.c
= tcg_invert_cond(cond
.c
);
908 /* Similar, but for the special case of subtraction without borrow, we
909 can use the inputs directly. This can allow other computation to be
910 deleted as unused. */
912 static DisasCond
do_sub_cond(DisasContext
*ctx
, unsigned cf
, bool d
,
913 TCGv_i64 res
, TCGv_i64 in1
,
914 TCGv_i64 in2
, TCGv_i64 sv
)
932 case 4: /* << / >>= */
936 case 5: /* <<= / >> */
941 return do_cond(ctx
, cf
, d
, res
, NULL
, sv
);
945 tc
= tcg_invert_cond(tc
);
948 TCGv_i64 t1
= tcg_temp_new_i64();
949 TCGv_i64 t2
= tcg_temp_new_i64();
952 tcg_gen_ext32u_i64(t1
, in1
);
953 tcg_gen_ext32u_i64(t2
, in2
);
955 tcg_gen_ext32s_i64(t1
, in1
);
956 tcg_gen_ext32s_i64(t2
, in2
);
958 return cond_make_tt(tc
, t1
, t2
);
960 return cond_make_vv(tc
, in1
, in2
);
964 * Similar, but for logicals, where the carry and overflow bits are not
965 * computed, and use of them is undefined.
967 * Undefined or not, hardware does not trap. It seems reasonable to
968 * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
969 * how cases c={2,3} are treated.
972 static DisasCond
do_log_cond(DisasContext
*ctx
, unsigned cf
, bool d
,
979 case 0: /* never / always */
980 case 4: /* undef, C */
981 case 5: /* undef, C & !Z */
982 case 6: /* undef, V */
983 return cf
& 1 ? cond_make_t() : cond_make_f();
984 case 1: /* == / <> */
985 tc
= d
? TCG_COND_EQ
: TCG_COND_TSTEQ
;
986 imm
= d
? 0 : UINT32_MAX
;
989 tc
= d
? TCG_COND_LT
: TCG_COND_TSTNE
;
990 imm
= d
? 0 : 1ull << 31;
993 tc
= cf
& 1 ? TCG_COND_GT
: TCG_COND_LE
;
995 TCGv_i64 tmp
= tcg_temp_new_i64();
996 tcg_gen_ext32s_i64(tmp
, res
);
997 return cond_make_ti(tc
, tmp
, 0);
999 return cond_make_vi(tc
, res
, 0);
1000 case 7: /* OD / EV */
1001 tc
= TCG_COND_TSTNE
;
1005 g_assert_not_reached();
1008 tc
= tcg_invert_cond(tc
);
1010 return cond_make_vi(tc
, res
, imm
);
1013 /* Similar, but for shift/extract/deposit conditions. */
1015 static DisasCond
do_sed_cond(DisasContext
*ctx
, unsigned orig
, bool d
,
1020 /* Convert the compressed condition codes to standard.
1021 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
1022 4-7 are the reverse of 0-3. */
1029 return do_log_cond(ctx
, c
* 2 + f
, d
, res
);
1032 /* Similar, but for unit zero conditions. */
1033 static DisasCond
do_unit_zero_cond(unsigned cf
, bool d
, TCGv_i64 res
)
1036 uint64_t d_repl
= d
? 0x0000000100000001ull
: 1;
1037 uint64_t ones
= 0, sgns
= 0;
1040 case 1: /* SBW / NBW */
1043 sgns
= d_repl
<< 31;
1046 case 2: /* SBZ / NBZ */
1047 ones
= d_repl
* 0x01010101u
;
1050 case 3: /* SHZ / NHZ */
1051 ones
= d_repl
* 0x00010001u
;
1056 /* Undefined, or 0/1 (never/always). */
1057 return cf
& 1 ? cond_make_t() : cond_make_f();
1061 * See hasless(v,1) from
1062 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1064 tmp
= tcg_temp_new_i64();
1065 tcg_gen_subi_i64(tmp
, res
, ones
);
1066 tcg_gen_andc_i64(tmp
, tmp
, res
);
1068 return cond_make_ti(cf
& 1 ? TCG_COND_TSTEQ
: TCG_COND_TSTNE
, tmp
, sgns
);
1071 static TCGv_i64
get_carry(DisasContext
*ctx
, bool d
,
1072 TCGv_i64 cb
, TCGv_i64 cb_msb
)
1075 TCGv_i64 t
= tcg_temp_new_i64();
1076 tcg_gen_extract_i64(t
, cb
, 32, 1);
1082 static TCGv_i64
get_psw_carry(DisasContext
*ctx
, bool d
)
1084 return get_carry(ctx
, d
, cpu_psw_cb
, cpu_psw_cb_msb
);
1087 /* Compute signed overflow for addition. */
1088 static TCGv_i64
do_add_sv(DisasContext
*ctx
, TCGv_i64 res
,
1089 TCGv_i64 in1
, TCGv_i64 in2
,
1090 TCGv_i64 orig_in1
, int shift
, bool d
)
1092 TCGv_i64 sv
= tcg_temp_new_i64();
1093 TCGv_i64 tmp
= tcg_temp_new_i64();
1095 tcg_gen_xor_i64(sv
, res
, in1
);
1096 tcg_gen_xor_i64(tmp
, in1
, in2
);
1097 tcg_gen_andc_i64(sv
, sv
, tmp
);
1103 /* Shift left by one and compare the sign. */
1104 tcg_gen_add_i64(tmp
, orig_in1
, orig_in1
);
1105 tcg_gen_xor_i64(tmp
, tmp
, orig_in1
);
1106 /* Incorporate into the overflow. */
1107 tcg_gen_or_i64(sv
, sv
, tmp
);
1111 int sign_bit
= d
? 63 : 31;
1113 /* Compare the sign against all lower bits. */
1114 tcg_gen_sextract_i64(tmp
, orig_in1
, sign_bit
, 1);
1115 tcg_gen_xor_i64(tmp
, tmp
, orig_in1
);
1117 * If one of the bits shifting into or through the sign
1118 * differs, then we have overflow.
1120 tcg_gen_extract_i64(tmp
, tmp
, sign_bit
- shift
, shift
);
1121 tcg_gen_movcond_i64(TCG_COND_NE
, sv
, tmp
, ctx
->zero
,
1122 tcg_constant_i64(-1), sv
);
1128 /* Compute unsigned overflow for addition. */
1129 static TCGv_i64
do_add_uv(DisasContext
*ctx
, TCGv_i64 cb
, TCGv_i64 cb_msb
,
1130 TCGv_i64 in1
, int shift
, bool d
)
1133 return get_carry(ctx
, d
, cb
, cb_msb
);
1135 TCGv_i64 tmp
= tcg_temp_new_i64();
1136 tcg_gen_extract_i64(tmp
, in1
, (d
? 63 : 31) - shift
, shift
);
1137 tcg_gen_or_i64(tmp
, tmp
, get_carry(ctx
, d
, cb
, cb_msb
));
1142 /* Compute signed overflow for subtraction. */
1143 static TCGv_i64
do_sub_sv(DisasContext
*ctx
, TCGv_i64 res
,
1144 TCGv_i64 in1
, TCGv_i64 in2
)
1146 TCGv_i64 sv
= tcg_temp_new_i64();
1147 TCGv_i64 tmp
= tcg_temp_new_i64();
1149 tcg_gen_xor_i64(sv
, res
, in1
);
1150 tcg_gen_xor_i64(tmp
, in1
, in2
);
1151 tcg_gen_and_i64(sv
, sv
, tmp
);
1156 static void gen_tc(DisasContext
*ctx
, DisasCond
*cond
)
1158 DisasDelayException
*e
;
1161 case TCG_COND_NEVER
:
1163 case TCG_COND_ALWAYS
:
1164 gen_excp_iir(ctx
, EXCP_COND
);
1167 e
= delay_excp(ctx
, EXCP_COND
);
1168 tcg_gen_brcond_i64(cond
->c
, cond
->a0
, cond
->a1
, e
->lab
);
1169 /* In the non-trap path, the condition is known false. */
1170 *cond
= cond_make_f();
1175 static void gen_tsv(DisasContext
*ctx
, TCGv_i64
*sv
, bool d
)
1177 DisasCond cond
= do_cond(ctx
, /* SV */ 12, d
, NULL
, NULL
, *sv
);
1178 DisasDelayException
*e
= delay_excp(ctx
, EXCP_OVERFLOW
);
1180 tcg_gen_brcond_i64(cond
.c
, cond
.a0
, cond
.a1
, e
->lab
);
1182 /* In the non-trap path, V is known zero. */
1183 *sv
= tcg_constant_i64(0);
1186 static void do_add(DisasContext
*ctx
, unsigned rt
, TCGv_i64 orig_in1
,
1187 TCGv_i64 in2
, unsigned shift
, bool is_l
,
1188 bool is_tsv
, bool is_tc
, bool is_c
, unsigned cf
, bool d
)
1190 TCGv_i64 dest
, cb
, cb_msb
, in1
, uv
, sv
, tmp
;
1191 unsigned c
= cf
>> 1;
1194 dest
= tcg_temp_new_i64();
1200 tmp
= tcg_temp_new_i64();
1201 tcg_gen_shli_i64(tmp
, in1
, shift
);
1205 if (!is_l
|| cond_need_cb(c
)) {
1206 cb_msb
= tcg_temp_new_i64();
1207 cb
= tcg_temp_new_i64();
1209 tcg_gen_add2_i64(dest
, cb_msb
, in1
, ctx
->zero
, in2
, ctx
->zero
);
1211 tcg_gen_add2_i64(dest
, cb_msb
, dest
, cb_msb
,
1212 get_psw_carry(ctx
, d
), ctx
->zero
);
1214 tcg_gen_xor_i64(cb
, in1
, in2
);
1215 tcg_gen_xor_i64(cb
, cb
, dest
);
1217 tcg_gen_add_i64(dest
, in1
, in2
);
1219 tcg_gen_add_i64(dest
, dest
, get_psw_carry(ctx
, d
));
1223 /* Compute signed overflow if required. */
1225 if (is_tsv
|| cond_need_sv(c
)) {
1226 sv
= do_add_sv(ctx
, dest
, in1
, in2
, orig_in1
, shift
, d
);
1228 gen_tsv(ctx
, &sv
, d
);
1232 /* Compute unsigned overflow if required. */
1234 if (cond_need_cb(c
)) {
1235 uv
= do_add_uv(ctx
, cb
, cb_msb
, orig_in1
, shift
, d
);
1238 /* Emit any conditional trap before any writeback. */
1239 cond
= do_cond(ctx
, cf
, d
, dest
, uv
, sv
);
1244 /* Write back the result. */
1246 save_or_nullify(ctx
, cpu_psw_cb
, cb
);
1247 save_or_nullify(ctx
, cpu_psw_cb_msb
, cb_msb
);
1249 save_gpr(ctx
, rt
, dest
);
1251 /* Install the new nullification. */
1252 ctx
->null_cond
= cond
;
1255 static bool do_add_reg(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
,
1256 bool is_l
, bool is_tsv
, bool is_tc
, bool is_c
)
1258 TCGv_i64 tcg_r1
, tcg_r2
;
1260 if (unlikely(is_tc
&& a
->cf
== 1)) {
1261 /* Unconditional trap on condition. */
1262 return gen_excp_iir(ctx
, EXCP_COND
);
1267 tcg_r1
= load_gpr(ctx
, a
->r1
);
1268 tcg_r2
= load_gpr(ctx
, a
->r2
);
1269 do_add(ctx
, a
->t
, tcg_r1
, tcg_r2
, a
->sh
, is_l
,
1270 is_tsv
, is_tc
, is_c
, a
->cf
, a
->d
);
1271 return nullify_end(ctx
);
1274 static bool do_add_imm(DisasContext
*ctx
, arg_rri_cf
*a
,
1275 bool is_tsv
, bool is_tc
)
1277 TCGv_i64 tcg_im
, tcg_r2
;
1279 if (unlikely(is_tc
&& a
->cf
== 1)) {
1280 /* Unconditional trap on condition. */
1281 return gen_excp_iir(ctx
, EXCP_COND
);
1286 tcg_im
= tcg_constant_i64(a
->i
);
1287 tcg_r2
= load_gpr(ctx
, a
->r
);
1288 /* All ADDI conditions are 32-bit. */
1289 do_add(ctx
, a
->t
, tcg_im
, tcg_r2
, 0, 0, is_tsv
, is_tc
, 0, a
->cf
, false);
1290 return nullify_end(ctx
);
1293 static void do_sub(DisasContext
*ctx
, unsigned rt
, TCGv_i64 in1
,
1294 TCGv_i64 in2
, bool is_tsv
, bool is_b
,
1295 bool is_tc
, unsigned cf
, bool d
)
1297 TCGv_i64 dest
, sv
, cb
, cb_msb
;
1298 unsigned c
= cf
>> 1;
1301 dest
= tcg_temp_new_i64();
1302 cb
= tcg_temp_new_i64();
1303 cb_msb
= tcg_temp_new_i64();
1306 /* DEST,C = IN1 + ~IN2 + C. */
1307 tcg_gen_not_i64(cb
, in2
);
1308 tcg_gen_add2_i64(dest
, cb_msb
, in1
, ctx
->zero
,
1309 get_psw_carry(ctx
, d
), ctx
->zero
);
1310 tcg_gen_add2_i64(dest
, cb_msb
, dest
, cb_msb
, cb
, ctx
->zero
);
1311 tcg_gen_xor_i64(cb
, cb
, in1
);
1312 tcg_gen_xor_i64(cb
, cb
, dest
);
1315 * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
1316 * operations by seeding the high word with 1 and subtracting.
1318 TCGv_i64 one
= tcg_constant_i64(1);
1319 tcg_gen_sub2_i64(dest
, cb_msb
, in1
, one
, in2
, ctx
->zero
);
1320 tcg_gen_eqv_i64(cb
, in1
, in2
);
1321 tcg_gen_xor_i64(cb
, cb
, dest
);
1324 /* Compute signed overflow if required. */
1326 if (is_tsv
|| cond_need_sv(c
)) {
1327 sv
= do_sub_sv(ctx
, dest
, in1
, in2
);
1329 gen_tsv(ctx
, &sv
, d
);
1333 /* Compute the condition. We cannot use the special case for borrow. */
1335 cond
= do_sub_cond(ctx
, cf
, d
, dest
, in1
, in2
, sv
);
1337 cond
= do_cond(ctx
, cf
, d
, dest
, get_carry(ctx
, d
, cb
, cb_msb
), sv
);
1340 /* Emit any conditional trap before any writeback. */
1345 /* Write back the result. */
1346 save_or_nullify(ctx
, cpu_psw_cb
, cb
);
1347 save_or_nullify(ctx
, cpu_psw_cb_msb
, cb_msb
);
1348 save_gpr(ctx
, rt
, dest
);
1350 /* Install the new nullification. */
1351 ctx
->null_cond
= cond
;
1354 static bool do_sub_reg(DisasContext
*ctx
, arg_rrr_cf_d
*a
,
1355 bool is_tsv
, bool is_b
, bool is_tc
)
1357 TCGv_i64 tcg_r1
, tcg_r2
;
1362 tcg_r1
= load_gpr(ctx
, a
->r1
);
1363 tcg_r2
= load_gpr(ctx
, a
->r2
);
1364 do_sub(ctx
, a
->t
, tcg_r1
, tcg_r2
, is_tsv
, is_b
, is_tc
, a
->cf
, a
->d
);
1365 return nullify_end(ctx
);
1368 static bool do_sub_imm(DisasContext
*ctx
, arg_rri_cf
*a
, bool is_tsv
)
1370 TCGv_i64 tcg_im
, tcg_r2
;
1375 tcg_im
= tcg_constant_i64(a
->i
);
1376 tcg_r2
= load_gpr(ctx
, a
->r
);
1377 /* All SUBI conditions are 32-bit. */
1378 do_sub(ctx
, a
->t
, tcg_im
, tcg_r2
, is_tsv
, 0, 0, a
->cf
, false);
1379 return nullify_end(ctx
);
1382 static void do_cmpclr(DisasContext
*ctx
, unsigned rt
, TCGv_i64 in1
,
1383 TCGv_i64 in2
, unsigned cf
, bool d
)
1388 dest
= tcg_temp_new_i64();
1389 tcg_gen_sub_i64(dest
, in1
, in2
);
1391 /* Compute signed overflow if required. */
1393 if (cond_need_sv(cf
>> 1)) {
1394 sv
= do_sub_sv(ctx
, dest
, in1
, in2
);
1397 /* Form the condition for the compare. */
1398 cond
= do_sub_cond(ctx
, cf
, d
, dest
, in1
, in2
, sv
);
1401 tcg_gen_movi_i64(dest
, 0);
1402 save_gpr(ctx
, rt
, dest
);
1404 /* Install the new nullification. */
1405 ctx
->null_cond
= cond
;
1408 static void do_log(DisasContext
*ctx
, unsigned rt
, TCGv_i64 in1
,
1409 TCGv_i64 in2
, unsigned cf
, bool d
,
1410 void (*fn
)(TCGv_i64
, TCGv_i64
, TCGv_i64
))
1412 TCGv_i64 dest
= dest_gpr(ctx
, rt
);
1414 /* Perform the operation, and writeback. */
1416 save_gpr(ctx
, rt
, dest
);
1418 /* Install the new nullification. */
1419 ctx
->null_cond
= do_log_cond(ctx
, cf
, d
, dest
);
1422 static bool do_log_reg(DisasContext
*ctx
, arg_rrr_cf_d
*a
,
1423 void (*fn
)(TCGv_i64
, TCGv_i64
, TCGv_i64
))
1425 TCGv_i64 tcg_r1
, tcg_r2
;
1430 tcg_r1
= load_gpr(ctx
, a
->r1
);
1431 tcg_r2
= load_gpr(ctx
, a
->r2
);
1432 do_log(ctx
, a
->t
, tcg_r1
, tcg_r2
, a
->cf
, a
->d
, fn
);
1433 return nullify_end(ctx
);
1436 static void do_unit_addsub(DisasContext
*ctx
, unsigned rt
, TCGv_i64 in1
,
1437 TCGv_i64 in2
, unsigned cf
, bool d
,
1438 bool is_tc
, bool is_add
)
1440 TCGv_i64 dest
= tcg_temp_new_i64();
1441 uint64_t test_cb
= 0;
1444 /* Select which carry-out bits to test. */
1446 case 4: /* NDC / SDC -- 4-bit carries */
1447 test_cb
= dup_const(MO_8
, 0x88);
1449 case 5: /* NWC / SWC -- 32-bit carries */
1451 test_cb
= dup_const(MO_32
, INT32_MIN
);
1453 cf
&= 1; /* undefined -- map to never/always */
1456 case 6: /* NBC / SBC -- 8-bit carries */
1457 test_cb
= dup_const(MO_8
, INT8_MIN
);
1459 case 7: /* NHC / SHC -- 16-bit carries */
1460 test_cb
= dup_const(MO_16
, INT16_MIN
);
1464 test_cb
= (uint32_t)test_cb
;
1468 /* No need to compute carries if we don't need to test them. */
1470 tcg_gen_add_i64(dest
, in1
, in2
);
1472 tcg_gen_sub_i64(dest
, in1
, in2
);
1474 cond
= do_unit_zero_cond(cf
, d
, dest
);
1476 TCGv_i64 cb
= tcg_temp_new_i64();
1479 TCGv_i64 cb_msb
= tcg_temp_new_i64();
1481 tcg_gen_add2_i64(dest
, cb_msb
, in1
, ctx
->zero
, in2
, ctx
->zero
);
1482 tcg_gen_xor_i64(cb
, in1
, in2
);
1484 /* See do_sub, !is_b. */
1485 TCGv_i64 one
= tcg_constant_i64(1);
1486 tcg_gen_sub2_i64(dest
, cb_msb
, in1
, one
, in2
, ctx
->zero
);
1487 tcg_gen_eqv_i64(cb
, in1
, in2
);
1489 tcg_gen_xor_i64(cb
, cb
, dest
);
1490 tcg_gen_extract2_i64(cb
, cb
, cb_msb
, 1);
1493 tcg_gen_add_i64(dest
, in1
, in2
);
1494 tcg_gen_xor_i64(cb
, in1
, in2
);
1496 tcg_gen_sub_i64(dest
, in1
, in2
);
1497 tcg_gen_eqv_i64(cb
, in1
, in2
);
1499 tcg_gen_xor_i64(cb
, cb
, dest
);
1500 tcg_gen_shri_i64(cb
, cb
, 1);
1503 cond
= cond_make_ti(cf
& 1 ? TCG_COND_TSTEQ
: TCG_COND_TSTNE
,
1510 save_gpr(ctx
, rt
, dest
);
1512 ctx
->null_cond
= cond
;
1515 #ifndef CONFIG_USER_ONLY
1516 /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
1517 from the top 2 bits of the base register. There are a few system
1518 instructions that have a 3-bit space specifier, for which SR0 is
1519 not special. To handle this, pass ~SP. */
1520 static TCGv_i64
space_select(DisasContext
*ctx
, int sp
, TCGv_i64 base
)
1530 spc
= tcg_temp_new_i64();
1531 load_spr(ctx
, spc
, sp
);
1534 if (ctx
->tb_flags
& TB_FLAG_SR_SAME
) {
1538 ptr
= tcg_temp_new_ptr();
1539 tmp
= tcg_temp_new_i64();
1540 spc
= tcg_temp_new_i64();
1542 /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
1543 tcg_gen_shri_i64(tmp
, base
, (ctx
->tb_flags
& PSW_W
? 64 : 32) - 5);
1544 tcg_gen_andi_i64(tmp
, tmp
, 030);
1545 tcg_gen_trunc_i64_ptr(ptr
, tmp
);
1547 tcg_gen_add_ptr(ptr
, ptr
, tcg_env
);
1548 tcg_gen_ld_i64(spc
, ptr
, offsetof(CPUHPPAState
, sr
[4]));
1554 static void form_gva(DisasContext
*ctx
, TCGv_i64
*pgva
, TCGv_i64
*pofs
,
1555 unsigned rb
, unsigned rx
, int scale
, int64_t disp
,
1556 unsigned sp
, int modify
, bool is_phys
)
1558 TCGv_i64 base
= load_gpr(ctx
, rb
);
1562 set_insn_breg(ctx
, rb
);
1564 /* Note that RX is mutually exclusive with DISP. */
1566 ofs
= tcg_temp_new_i64();
1567 tcg_gen_shli_i64(ofs
, cpu_gr
[rx
], scale
);
1568 tcg_gen_add_i64(ofs
, ofs
, base
);
1569 } else if (disp
|| modify
) {
1570 ofs
= tcg_temp_new_i64();
1571 tcg_gen_addi_i64(ofs
, base
, disp
);
1577 *pgva
= addr
= tcg_temp_new_i64();
1578 tcg_gen_andi_i64(addr
, modify
<= 0 ? ofs
: base
,
1579 gva_offset_mask(ctx
->tb_flags
));
1580 #ifndef CONFIG_USER_ONLY
1582 tcg_gen_or_i64(addr
, addr
, space_select(ctx
, sp
, base
));
1587 /* Emit a memory load. The modify parameter should be
1588 * < 0 for pre-modify,
1589 * > 0 for post-modify,
1590 * = 0 for no base register update.
1592 static void do_load_32(DisasContext
*ctx
, TCGv_i32 dest
, unsigned rb
,
1593 unsigned rx
, int scale
, int64_t disp
,
1594 unsigned sp
, int modify
, MemOp mop
)
1599 /* Caller uses nullify_over/nullify_end. */
1600 assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
1602 form_gva(ctx
, &addr
, &ofs
, rb
, rx
, scale
, disp
, sp
, modify
,
1604 tcg_gen_qemu_ld_i32(dest
, addr
, ctx
->mmu_idx
, mop
| UNALIGN(ctx
));
1606 save_gpr(ctx
, rb
, ofs
);
1610 static void do_load_64(DisasContext
*ctx
, TCGv_i64 dest
, unsigned rb
,
1611 unsigned rx
, int scale
, int64_t disp
,
1612 unsigned sp
, int modify
, MemOp mop
)
1617 /* Caller uses nullify_over/nullify_end. */
1618 assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
1620 form_gva(ctx
, &addr
, &ofs
, rb
, rx
, scale
, disp
, sp
, modify
,
1622 tcg_gen_qemu_ld_i64(dest
, addr
, ctx
->mmu_idx
, mop
| UNALIGN(ctx
));
1624 save_gpr(ctx
, rb
, ofs
);
1628 static void do_store_32(DisasContext
*ctx
, TCGv_i32 src
, unsigned rb
,
1629 unsigned rx
, int scale
, int64_t disp
,
1630 unsigned sp
, int modify
, MemOp mop
)
1635 /* Caller uses nullify_over/nullify_end. */
1636 assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
1638 form_gva(ctx
, &addr
, &ofs
, rb
, rx
, scale
, disp
, sp
, modify
,
1640 tcg_gen_qemu_st_i32(src
, addr
, ctx
->mmu_idx
, mop
| UNALIGN(ctx
));
1642 save_gpr(ctx
, rb
, ofs
);
1646 static void do_store_64(DisasContext
*ctx
, TCGv_i64 src
, unsigned rb
,
1647 unsigned rx
, int scale
, int64_t disp
,
1648 unsigned sp
, int modify
, MemOp mop
)
1653 /* Caller uses nullify_over/nullify_end. */
1654 assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
1656 form_gva(ctx
, &addr
, &ofs
, rb
, rx
, scale
, disp
, sp
, modify
,
1658 tcg_gen_qemu_st_i64(src
, addr
, ctx
->mmu_idx
, mop
| UNALIGN(ctx
));
1660 save_gpr(ctx
, rb
, ofs
);
1664 static bool do_load(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1665 unsigned rx
, int scale
, int64_t disp
,
1666 unsigned sp
, int modify
, MemOp mop
)
1673 /* No base register update. */
1674 dest
= dest_gpr(ctx
, rt
);
1676 /* Make sure if RT == RB, we see the result of the load. */
1677 dest
= tcg_temp_new_i64();
1679 do_load_64(ctx
, dest
, rb
, rx
, scale
, disp
, sp
, modify
, mop
);
1680 save_gpr(ctx
, rt
, dest
);
1682 return nullify_end(ctx
);
1685 static bool do_floadw(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1686 unsigned rx
, int scale
, int64_t disp
,
1687 unsigned sp
, int modify
)
1693 tmp
= tcg_temp_new_i32();
1694 do_load_32(ctx
, tmp
, rb
, rx
, scale
, disp
, sp
, modify
, MO_TEUL
);
1695 save_frw_i32(rt
, tmp
);
1698 gen_helper_loaded_fr0(tcg_env
);
1701 return nullify_end(ctx
);
1704 static bool trans_fldw(DisasContext
*ctx
, arg_ldst
*a
)
1706 return do_floadw(ctx
, a
->t
, a
->b
, a
->x
, a
->scale
? 2 : 0,
1707 a
->disp
, a
->sp
, a
->m
);
1710 static bool do_floadd(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1711 unsigned rx
, int scale
, int64_t disp
,
1712 unsigned sp
, int modify
)
1718 tmp
= tcg_temp_new_i64();
1719 do_load_64(ctx
, tmp
, rb
, rx
, scale
, disp
, sp
, modify
, MO_TEUQ
);
1723 gen_helper_loaded_fr0(tcg_env
);
1726 return nullify_end(ctx
);
1729 static bool trans_fldd(DisasContext
*ctx
, arg_ldst
*a
)
1731 return do_floadd(ctx
, a
->t
, a
->b
, a
->x
, a
->scale
? 3 : 0,
1732 a
->disp
, a
->sp
, a
->m
);
1735 static bool do_store(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1736 int64_t disp
, unsigned sp
,
1737 int modify
, MemOp mop
)
1740 do_store_64(ctx
, load_gpr(ctx
, rt
), rb
, 0, 0, disp
, sp
, modify
, mop
);
1741 return nullify_end(ctx
);
1744 static bool do_fstorew(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1745 unsigned rx
, int scale
, int64_t disp
,
1746 unsigned sp
, int modify
)
1752 tmp
= load_frw_i32(rt
);
1753 do_store_32(ctx
, tmp
, rb
, rx
, scale
, disp
, sp
, modify
, MO_TEUL
);
1755 return nullify_end(ctx
);
1758 static bool trans_fstw(DisasContext
*ctx
, arg_ldst
*a
)
1760 return do_fstorew(ctx
, a
->t
, a
->b
, a
->x
, a
->scale
? 2 : 0,
1761 a
->disp
, a
->sp
, a
->m
);
1764 static bool do_fstored(DisasContext
*ctx
, unsigned rt
, unsigned rb
,
1765 unsigned rx
, int scale
, int64_t disp
,
1766 unsigned sp
, int modify
)
1773 do_store_64(ctx
, tmp
, rb
, rx
, scale
, disp
, sp
, modify
, MO_TEUQ
);
1775 return nullify_end(ctx
);
1778 static bool trans_fstd(DisasContext
*ctx
, arg_ldst
*a
)
1780 return do_fstored(ctx
, a
->t
, a
->b
, a
->x
, a
->scale
? 3 : 0,
1781 a
->disp
, a
->sp
, a
->m
);
1784 static bool do_fop_wew(DisasContext
*ctx
, unsigned rt
, unsigned ra
,
1785 void (*func
)(TCGv_i32
, TCGv_env
, TCGv_i32
))
1790 tmp
= load_frw0_i32(ra
);
1792 func(tmp
, tcg_env
, tmp
);
1794 save_frw_i32(rt
, tmp
);
1795 return nullify_end(ctx
);
1798 static bool do_fop_wed(DisasContext
*ctx
, unsigned rt
, unsigned ra
,
1799 void (*func
)(TCGv_i32
, TCGv_env
, TCGv_i64
))
1806 dst
= tcg_temp_new_i32();
1808 func(dst
, tcg_env
, src
);
1810 save_frw_i32(rt
, dst
);
1811 return nullify_end(ctx
);
1814 static bool do_fop_ded(DisasContext
*ctx
, unsigned rt
, unsigned ra
,
1815 void (*func
)(TCGv_i64
, TCGv_env
, TCGv_i64
))
1820 tmp
= load_frd0(ra
);
1822 func(tmp
, tcg_env
, tmp
);
1825 return nullify_end(ctx
);
1828 static bool do_fop_dew(DisasContext
*ctx
, unsigned rt
, unsigned ra
,
1829 void (*func
)(TCGv_i64
, TCGv_env
, TCGv_i32
))
1835 src
= load_frw0_i32(ra
);
1836 dst
= tcg_temp_new_i64();
1838 func(dst
, tcg_env
, src
);
1841 return nullify_end(ctx
);
1844 static bool do_fop_weww(DisasContext
*ctx
, unsigned rt
,
1845 unsigned ra
, unsigned rb
,
1846 void (*func
)(TCGv_i32
, TCGv_env
, TCGv_i32
, TCGv_i32
))
1851 a
= load_frw0_i32(ra
);
1852 b
= load_frw0_i32(rb
);
1854 func(a
, tcg_env
, a
, b
);
1856 save_frw_i32(rt
, a
);
1857 return nullify_end(ctx
);
1860 static bool do_fop_dedd(DisasContext
*ctx
, unsigned rt
,
1861 unsigned ra
, unsigned rb
,
1862 void (*func
)(TCGv_i64
, TCGv_env
, TCGv_i64
, TCGv_i64
))
1870 func(a
, tcg_env
, a
, b
);
1873 return nullify_end(ctx
);
1876 /* Emit an unconditional branch to a direct target, which may or may not
1877 have already had nullification handled. */
1878 static bool do_dbranch(DisasContext
*ctx
, int64_t disp
,
1879 unsigned link
, bool is_n
)
1881 ctx
->iaq_j
= iaqe_branchi(ctx
, disp
);
1883 if (ctx
->null_cond
.c
== TCG_COND_NEVER
&& ctx
->null_lab
== NULL
) {
1884 install_link(ctx
, link
, false);
1886 if (use_nullify_skip(ctx
)) {
1887 nullify_set(ctx
, 0);
1888 store_psw_xb(ctx
, 0);
1889 gen_goto_tb(ctx
, 0, &ctx
->iaq_j
, NULL
);
1890 ctx
->base
.is_jmp
= DISAS_NORETURN
;
1893 ctx
->null_cond
.c
= TCG_COND_ALWAYS
;
1895 ctx
->iaq_n
= &ctx
->iaq_j
;
1896 ctx
->psw_b_next
= true;
1900 install_link(ctx
, link
, false);
1901 if (is_n
&& use_nullify_skip(ctx
)) {
1902 nullify_set(ctx
, 0);
1903 store_psw_xb(ctx
, 0);
1904 gen_goto_tb(ctx
, 0, &ctx
->iaq_j
, NULL
);
1906 nullify_set(ctx
, is_n
);
1907 store_psw_xb(ctx
, PSW_B
);
1908 gen_goto_tb(ctx
, 0, &ctx
->iaq_b
, &ctx
->iaq_j
);
1912 nullify_set(ctx
, 0);
1913 store_psw_xb(ctx
, 0);
1914 gen_goto_tb(ctx
, 1, &ctx
->iaq_b
, NULL
);
1915 ctx
->base
.is_jmp
= DISAS_NORETURN
;
1920 /* Emit a conditional branch to a direct target. If the branch itself
1921 is nullified, we should have already used nullify_over. */
1922 static bool do_cbranch(DisasContext
*ctx
, int64_t disp
, bool is_n
,
1926 TCGLabel
*taken
= NULL
;
1927 TCGCond c
= cond
->c
;
1930 assert(ctx
->null_cond
.c
== TCG_COND_NEVER
);
1932 /* Handle TRUE and NEVER as direct branches. */
1933 if (c
== TCG_COND_ALWAYS
) {
1934 return do_dbranch(ctx
, disp
, 0, is_n
&& disp
>= 0);
1937 taken
= gen_new_label();
1938 tcg_gen_brcond_i64(c
, cond
->a0
, cond
->a1
, taken
);
1940 /* Not taken: Condition not satisfied; nullify on backward branches. */
1941 n
= is_n
&& disp
< 0;
1942 if (n
&& use_nullify_skip(ctx
)) {
1943 nullify_set(ctx
, 0);
1944 store_psw_xb(ctx
, 0);
1945 next
= iaqe_incr(&ctx
->iaq_b
, 4);
1946 gen_goto_tb(ctx
, 0, &next
, NULL
);
1948 if (!n
&& ctx
->null_lab
) {
1949 gen_set_label(ctx
->null_lab
);
1950 ctx
->null_lab
= NULL
;
1952 nullify_set(ctx
, n
);
1953 store_psw_xb(ctx
, 0);
1954 gen_goto_tb(ctx
, 0, &ctx
->iaq_b
, NULL
);
1957 gen_set_label(taken
);
1959 /* Taken: Condition satisfied; nullify on forward branches. */
1960 n
= is_n
&& disp
>= 0;
1962 next
= iaqe_branchi(ctx
, disp
);
1963 if (n
&& use_nullify_skip(ctx
)) {
1964 nullify_set(ctx
, 0);
1965 store_psw_xb(ctx
, 0);
1966 gen_goto_tb(ctx
, 1, &next
, NULL
);
1968 nullify_set(ctx
, n
);
1969 store_psw_xb(ctx
, PSW_B
);
1970 gen_goto_tb(ctx
, 1, &ctx
->iaq_b
, &next
);
1973 /* Not taken: the branch itself was nullified. */
1974 if (ctx
->null_lab
) {
1975 gen_set_label(ctx
->null_lab
);
1976 ctx
->null_lab
= NULL
;
1977 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
1979 ctx
->base
.is_jmp
= DISAS_NORETURN
;
1985 * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1986 * This handles nullification of the branch itself.
1988 static bool do_ibranch(DisasContext
*ctx
, unsigned link
,
1989 bool with_sr0
, bool is_n
)
1991 if (ctx
->null_cond
.c
== TCG_COND_NEVER
&& ctx
->null_lab
== NULL
) {
1992 install_link(ctx
, link
, with_sr0
);
1994 if (use_nullify_skip(ctx
)) {
1995 install_iaq_entries(ctx
, &ctx
->iaq_j
, NULL
);
1996 nullify_set(ctx
, 0);
1997 ctx
->base
.is_jmp
= DISAS_IAQ_N_UPDATED
;
2000 ctx
->null_cond
.c
= TCG_COND_ALWAYS
;
2002 ctx
->iaq_n
= &ctx
->iaq_j
;
2003 ctx
->psw_b_next
= true;
2009 install_link(ctx
, link
, with_sr0
);
2010 if (is_n
&& use_nullify_skip(ctx
)) {
2011 install_iaq_entries(ctx
, &ctx
->iaq_j
, NULL
);
2012 nullify_set(ctx
, 0);
2013 store_psw_xb(ctx
, 0);
2015 install_iaq_entries(ctx
, &ctx
->iaq_b
, &ctx
->iaq_j
);
2016 nullify_set(ctx
, is_n
);
2017 store_psw_xb(ctx
, PSW_B
);
2020 tcg_gen_lookup_and_goto_ptr();
2021 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2022 return nullify_end(ctx
);
2026 * if (IAOQ_Front{30..31} < GR[b]{30..31})
2027 * IAOQ_Next{30..31} ← GR[b]{30..31};
2029 * IAOQ_Next{30..31} ← IAOQ_Front{30..31};
2030 * which keeps the privilege level from being increased.
2032 static TCGv_i64
do_ibranch_priv(DisasContext
*ctx
, TCGv_i64 offset
)
2034 TCGv_i64 dest
= tcg_temp_new_i64();
2035 switch (ctx
->privilege
) {
2037 /* Privilege 0 is maximum and is allowed to decrease. */
2038 tcg_gen_mov_i64(dest
, offset
);
2041 /* Privilege 3 is minimum and is never allowed to increase. */
2042 tcg_gen_ori_i64(dest
, offset
, 3);
2045 tcg_gen_andi_i64(dest
, offset
, -4);
2046 tcg_gen_ori_i64(dest
, dest
, ctx
->privilege
);
2047 tcg_gen_umax_i64(dest
, dest
, offset
);
2053 #ifdef CONFIG_USER_ONLY
2054 /* On Linux, page zero is normally marked execute only + gateway.
2055 Therefore normal read or write is supposed to fail, but specific
2056 offsets have kernel code mapped to raise permissions to implement
2057 system calls. Handling this via an explicit check here, rather
2058 in than the "be disp(sr2,r0)" instruction that probably sent us
2059 here, is the easiest way to handle the branch delay slot on the
2060 aforementioned BE. */
2061 static void do_page_zero(DisasContext
*ctx
)
2063 assert(ctx
->iaq_f
.disp
== 0);
2065 /* If by some means we get here with PSW[N]=1, that implies that
2066 the B,GATE instruction would be skipped, and we'd fault on the
2067 next insn within the privileged page. */
2068 switch (ctx
->null_cond
.c
) {
2069 case TCG_COND_NEVER
:
2071 case TCG_COND_ALWAYS
:
2072 tcg_gen_movi_i64(cpu_psw_n
, 0);
2075 /* Since this is always the first (and only) insn within the
2076 TB, we should know the state of PSW[N] from TB->FLAGS. */
2077 g_assert_not_reached();
2080 /* If PSW[B] is set, the B,GATE insn would trap. */
2081 if (ctx
->psw_xb
& PSW_B
) {
2085 switch (ctx
->base
.pc_first
) {
2086 case 0x00: /* Null pointer call */
2087 gen_excp_1(EXCP_IMP
);
2088 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2091 case 0xb0: /* LWS */
2092 gen_excp_1(EXCP_SYSCALL_LWS
);
2093 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2096 case 0xe0: /* SET_THREAD_POINTER */
2098 DisasIAQE next
= { .base
= tcg_temp_new_i64() };
2100 tcg_gen_st_i64(cpu_gr
[26], tcg_env
,
2101 offsetof(CPUHPPAState
, cr
[27]));
2102 tcg_gen_ori_i64(next
.base
, cpu_gr
[31], PRIV_USER
);
2103 install_iaq_entries(ctx
, &next
, NULL
);
2104 ctx
->base
.is_jmp
= DISAS_IAQ_N_UPDATED
;
2108 case 0x100: /* SYSCALL */
2109 gen_excp_1(EXCP_SYSCALL
);
2110 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2115 gen_excp_1(EXCP_ILL
);
2116 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2122 static bool trans_nop(DisasContext
*ctx
, arg_nop
*a
)
2124 ctx
->null_cond
= cond_make_f();
2128 static bool trans_break(DisasContext
*ctx
, arg_break
*a
)
2130 return gen_excp_iir(ctx
, EXCP_BREAK
);
2133 static bool trans_sync(DisasContext
*ctx
, arg_sync
*a
)
2135 /* No point in nullifying the memory barrier. */
2136 tcg_gen_mb(TCG_BAR_SC
| TCG_MO_ALL
);
2138 ctx
->null_cond
= cond_make_f();
2142 static bool trans_mfia(DisasContext
*ctx
, arg_mfia
*a
)
2144 TCGv_i64 dest
= dest_gpr(ctx
, a
->t
);
2146 copy_iaoq_entry(ctx
, dest
, &ctx
->iaq_f
);
2147 tcg_gen_andi_i64(dest
, dest
, -4);
2149 save_gpr(ctx
, a
->t
, dest
);
2150 ctx
->null_cond
= cond_make_f();
2154 static bool trans_mfsp(DisasContext
*ctx
, arg_mfsp
*a
)
2157 unsigned rs
= a
->sp
;
2158 TCGv_i64 t0
= tcg_temp_new_i64();
2160 load_spr(ctx
, t0
, rs
);
2161 tcg_gen_shri_i64(t0
, t0
, 32);
2163 save_gpr(ctx
, rt
, t0
);
2165 ctx
->null_cond
= cond_make_f();
2169 static bool trans_mfctl(DisasContext
*ctx
, arg_mfctl
*a
)
2172 unsigned ctl
= a
->r
;
2178 /* MFSAR without ,W masks low 5 bits. */
2179 tmp
= dest_gpr(ctx
, rt
);
2180 tcg_gen_andi_i64(tmp
, cpu_sar
, 31);
2181 save_gpr(ctx
, rt
, tmp
);
2184 save_gpr(ctx
, rt
, cpu_sar
);
2186 case CR_IT
: /* Interval Timer */
2187 /* FIXME: Respect PSW_S bit. */
2189 tmp
= dest_gpr(ctx
, rt
);
2190 if (translator_io_start(&ctx
->base
)) {
2191 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2193 gen_helper_read_interval_timer(tmp
);
2194 save_gpr(ctx
, rt
, tmp
);
2195 return nullify_end(ctx
);
2200 /* All other control registers are privileged. */
2201 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG
);
2205 tmp
= tcg_temp_new_i64();
2206 tcg_gen_ld_i64(tmp
, tcg_env
, offsetof(CPUHPPAState
, cr
[ctl
]));
2207 save_gpr(ctx
, rt
, tmp
);
2210 ctx
->null_cond
= cond_make_f();
2214 static bool trans_mtsp(DisasContext
*ctx
, arg_mtsp
*a
)
2217 unsigned rs
= a
->sp
;
2221 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG
);
2225 tmp
= tcg_temp_new_i64();
2226 tcg_gen_shli_i64(tmp
, load_gpr(ctx
, rr
), 32);
2229 tcg_gen_st_i64(tmp
, tcg_env
, offsetof(CPUHPPAState
, sr
[rs
]));
2230 ctx
->tb_flags
&= ~TB_FLAG_SR_SAME
;
2232 tcg_gen_mov_i64(cpu_sr
[rs
], tmp
);
2235 return nullify_end(ctx
);
2238 static bool trans_mtctl(DisasContext
*ctx
, arg_mtctl
*a
)
2240 unsigned ctl
= a
->t
;
2244 if (ctl
== CR_SAR
) {
2245 reg
= load_gpr(ctx
, a
->r
);
2246 tmp
= tcg_temp_new_i64();
2247 tcg_gen_andi_i64(tmp
, reg
, ctx
->is_pa20
? 63 : 31);
2248 save_or_nullify(ctx
, cpu_sar
, tmp
);
2250 ctx
->null_cond
= cond_make_f();
2254 /* All other control registers are privileged or read-only. */
2255 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG
);
2257 #ifndef CONFIG_USER_ONLY
2261 reg
= load_gpr(ctx
, a
->r
);
2263 reg
= tcg_temp_new_i64();
2264 tcg_gen_ext32u_i64(reg
, load_gpr(ctx
, a
->r
));
2269 if (translator_io_start(&ctx
->base
)) {
2270 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2272 gen_helper_write_interval_timer(tcg_env
, reg
);
2275 /* Helper modifies interrupt lines and is therefore IO. */
2276 translator_io_start(&ctx
->base
);
2277 gen_helper_write_eirr(tcg_env
, reg
);
2278 /* Exit to re-evaluate interrupts in the main loop. */
2279 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE_EXIT
;
2284 /* FIXME: Respect PSW_Q bit */
2285 /* The write advances the queue and stores to the back element. */
2286 tmp
= tcg_temp_new_i64();
2287 tcg_gen_ld_i64(tmp
, tcg_env
,
2288 offsetof(CPUHPPAState
, cr_back
[ctl
- CR_IIASQ
]));
2289 tcg_gen_st_i64(tmp
, tcg_env
, offsetof(CPUHPPAState
, cr
[ctl
]));
2290 tcg_gen_st_i64(reg
, tcg_env
,
2291 offsetof(CPUHPPAState
, cr_back
[ctl
- CR_IIASQ
]));
2298 tcg_gen_st_i64(reg
, tcg_env
, offsetof(CPUHPPAState
, cr
[ctl
]));
2299 #ifndef CONFIG_USER_ONLY
2300 gen_helper_change_prot_id(tcg_env
);
2305 /* Exit to re-evaluate interrupts in the main loop. */
2306 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE_EXIT
;
2309 tcg_gen_st_i64(reg
, tcg_env
, offsetof(CPUHPPAState
, cr
[ctl
]));
2312 return nullify_end(ctx
);
2316 static bool trans_mtsarcm(DisasContext
*ctx
, arg_mtsarcm
*a
)
2318 TCGv_i64 tmp
= tcg_temp_new_i64();
2320 tcg_gen_not_i64(tmp
, load_gpr(ctx
, a
->r
));
2321 tcg_gen_andi_i64(tmp
, tmp
, ctx
->is_pa20
? 63 : 31);
2322 save_or_nullify(ctx
, cpu_sar
, tmp
);
2324 ctx
->null_cond
= cond_make_f();
2328 static bool trans_ldsid(DisasContext
*ctx
, arg_ldsid
*a
)
2330 TCGv_i64 dest
= dest_gpr(ctx
, a
->t
);
2332 #ifdef CONFIG_USER_ONLY
2333 /* We don't implement space registers in user mode. */
2334 tcg_gen_movi_i64(dest
, 0);
2336 tcg_gen_mov_i64(dest
, space_select(ctx
, a
->sp
, load_gpr(ctx
, a
->b
)));
2337 tcg_gen_shri_i64(dest
, dest
, 32);
2339 save_gpr(ctx
, a
->t
, dest
);
2341 ctx
->null_cond
= cond_make_f();
2345 static bool trans_rsm(DisasContext
*ctx
, arg_rsm
*a
)
2347 #ifdef CONFIG_USER_ONLY
2348 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2352 /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
2354 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2359 tmp
= tcg_temp_new_i64();
2360 tcg_gen_ld_i64(tmp
, tcg_env
, offsetof(CPUHPPAState
, psw
));
2361 tcg_gen_andi_i64(tmp
, tmp
, ~a
->i
);
2362 gen_helper_swap_system_mask(tmp
, tcg_env
, tmp
);
2363 save_gpr(ctx
, a
->t
, tmp
);
2365 /* Exit the TB to recognize new interrupts, e.g. PSW_M. */
2366 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE_EXIT
;
2367 return nullify_end(ctx
);
2371 static bool trans_ssm(DisasContext
*ctx
, arg_ssm
*a
)
2373 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2374 #ifndef CONFIG_USER_ONLY
2379 tmp
= tcg_temp_new_i64();
2380 tcg_gen_ld_i64(tmp
, tcg_env
, offsetof(CPUHPPAState
, psw
));
2381 tcg_gen_ori_i64(tmp
, tmp
, a
->i
);
2382 gen_helper_swap_system_mask(tmp
, tcg_env
, tmp
);
2383 save_gpr(ctx
, a
->t
, tmp
);
2385 /* Exit the TB to recognize new interrupts, e.g. PSW_I. */
2386 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE_EXIT
;
2387 return nullify_end(ctx
);
2391 static bool trans_mtsm(DisasContext
*ctx
, arg_mtsm
*a
)
2393 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2394 #ifndef CONFIG_USER_ONLY
2398 reg
= load_gpr(ctx
, a
->r
);
2399 tmp
= tcg_temp_new_i64();
2400 gen_helper_swap_system_mask(tmp
, tcg_env
, reg
);
2402 /* Exit the TB to recognize new interrupts. */
2403 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE_EXIT
;
2404 return nullify_end(ctx
);
2408 static bool do_rfi(DisasContext
*ctx
, bool rfi_r
)
2410 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2411 #ifndef CONFIG_USER_ONLY
2415 gen_helper_rfi_r(tcg_env
);
2417 gen_helper_rfi(tcg_env
);
2419 /* Exit the TB to recognize new interrupts. */
2420 tcg_gen_exit_tb(NULL
, 0);
2421 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2423 return nullify_end(ctx
);
2427 static bool trans_rfi(DisasContext
*ctx
, arg_rfi
*a
)
2429 return do_rfi(ctx
, false);
2432 static bool trans_rfi_r(DisasContext
*ctx
, arg_rfi_r
*a
)
2434 return do_rfi(ctx
, true);
2437 static bool trans_halt(DisasContext
*ctx
, arg_halt
*a
)
2439 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2440 #ifndef CONFIG_USER_ONLY
2443 gen_helper_halt(tcg_env
);
2444 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2445 return nullify_end(ctx
);
2449 static bool trans_reset(DisasContext
*ctx
, arg_reset
*a
)
2451 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2452 #ifndef CONFIG_USER_ONLY
2455 gen_helper_reset(tcg_env
);
2456 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2457 return nullify_end(ctx
);
2461 static bool do_getshadowregs(DisasContext
*ctx
)
2463 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2465 tcg_gen_ld_i64(cpu_gr
[1], tcg_env
, offsetof(CPUHPPAState
, shadow
[0]));
2466 tcg_gen_ld_i64(cpu_gr
[8], tcg_env
, offsetof(CPUHPPAState
, shadow
[1]));
2467 tcg_gen_ld_i64(cpu_gr
[9], tcg_env
, offsetof(CPUHPPAState
, shadow
[2]));
2468 tcg_gen_ld_i64(cpu_gr
[16], tcg_env
, offsetof(CPUHPPAState
, shadow
[3]));
2469 tcg_gen_ld_i64(cpu_gr
[17], tcg_env
, offsetof(CPUHPPAState
, shadow
[4]));
2470 tcg_gen_ld_i64(cpu_gr
[24], tcg_env
, offsetof(CPUHPPAState
, shadow
[5]));
2471 tcg_gen_ld_i64(cpu_gr
[25], tcg_env
, offsetof(CPUHPPAState
, shadow
[6]));
2472 return nullify_end(ctx
);
2475 static bool do_putshadowregs(DisasContext
*ctx
)
2477 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2479 tcg_gen_st_i64(cpu_gr
[1], tcg_env
, offsetof(CPUHPPAState
, shadow
[0]));
2480 tcg_gen_st_i64(cpu_gr
[8], tcg_env
, offsetof(CPUHPPAState
, shadow
[1]));
2481 tcg_gen_st_i64(cpu_gr
[9], tcg_env
, offsetof(CPUHPPAState
, shadow
[2]));
2482 tcg_gen_st_i64(cpu_gr
[16], tcg_env
, offsetof(CPUHPPAState
, shadow
[3]));
2483 tcg_gen_st_i64(cpu_gr
[17], tcg_env
, offsetof(CPUHPPAState
, shadow
[4]));
2484 tcg_gen_st_i64(cpu_gr
[24], tcg_env
, offsetof(CPUHPPAState
, shadow
[5]));
2485 tcg_gen_st_i64(cpu_gr
[25], tcg_env
, offsetof(CPUHPPAState
, shadow
[6]));
2486 return nullify_end(ctx
);
2489 static bool trans_getshadowregs(DisasContext
*ctx
, arg_getshadowregs
*a
)
2491 return do_getshadowregs(ctx
);
2494 static bool trans_nop_addrx(DisasContext
*ctx
, arg_ldst
*a
)
2497 TCGv_i64 dest
= dest_gpr(ctx
, a
->b
);
2498 TCGv_i64 src1
= load_gpr(ctx
, a
->b
);
2499 TCGv_i64 src2
= load_gpr(ctx
, a
->x
);
2501 /* The only thing we need to do is the base register modification. */
2502 tcg_gen_add_i64(dest
, src1
, src2
);
2503 save_gpr(ctx
, a
->b
, dest
);
2505 ctx
->null_cond
= cond_make_f();
2509 static bool trans_fic(DisasContext
*ctx
, arg_ldst
*a
)
2511 /* End TB for flush instruction cache, so we pick up new insns. */
2512 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2513 return trans_nop_addrx(ctx
, a
);
2516 static bool trans_probe(DisasContext
*ctx
, arg_probe
*a
)
2519 TCGv_i32 level
, want
;
2524 dest
= dest_gpr(ctx
, a
->t
);
2525 form_gva(ctx
, &addr
, &ofs
, a
->b
, 0, 0, 0, a
->sp
, 0, false);
2528 level
= tcg_constant_i32(a
->ri
& 3);
2530 level
= tcg_temp_new_i32();
2531 tcg_gen_extrl_i64_i32(level
, load_gpr(ctx
, a
->ri
));
2532 tcg_gen_andi_i32(level
, level
, 3);
2534 want
= tcg_constant_i32(a
->write
? PAGE_WRITE
: PAGE_READ
);
2536 gen_helper_probe(dest
, tcg_env
, addr
, level
, want
);
2538 save_gpr(ctx
, a
->t
, dest
);
2539 return nullify_end(ctx
);
2542 static bool trans_ixtlbx(DisasContext
*ctx
, arg_ixtlbx
*a
)
2547 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2548 #ifndef CONFIG_USER_ONLY
2554 form_gva(ctx
, &addr
, &ofs
, a
->b
, 0, 0, 0, a
->sp
, 0, false);
2555 reg
= load_gpr(ctx
, a
->r
);
2557 gen_helper_itlba_pa11(tcg_env
, addr
, reg
);
2559 gen_helper_itlbp_pa11(tcg_env
, addr
, reg
);
2562 /* Exit TB for TLB change if mmu is enabled. */
2563 if (ctx
->tb_flags
& PSW_C
) {
2564 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2566 return nullify_end(ctx
);
2570 static bool do_pxtlb(DisasContext
*ctx
, arg_ldst
*a
, bool local
)
2572 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2573 #ifndef CONFIG_USER_ONLY
2579 form_gva(ctx
, &addr
, &ofs
, a
->b
, a
->x
, 0, 0, a
->sp
, a
->m
, false);
2582 * Page align now, rather than later, so that we can add in the
2583 * page_size field from pa2.0 from the low 4 bits of GR[b].
2585 tcg_gen_andi_i64(addr
, addr
, TARGET_PAGE_MASK
);
2587 tcg_gen_deposit_i64(addr
, addr
, load_gpr(ctx
, a
->b
), 0, 4);
2591 gen_helper_ptlb_l(tcg_env
, addr
);
2593 gen_helper_ptlb(tcg_env
, addr
);
2597 save_gpr(ctx
, a
->b
, ofs
);
2600 /* Exit TB for TLB change if mmu is enabled. */
2601 if (ctx
->tb_flags
& PSW_C
) {
2602 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2604 return nullify_end(ctx
);
2608 static bool trans_pxtlb(DisasContext
*ctx
, arg_ldst
*a
)
2610 return do_pxtlb(ctx
, a
, false);
2613 static bool trans_pxtlb_l(DisasContext
*ctx
, arg_ldst
*a
)
2615 return ctx
->is_pa20
&& do_pxtlb(ctx
, a
, true);
2618 static bool trans_pxtlbe(DisasContext
*ctx
, arg_ldst
*a
)
2620 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2621 #ifndef CONFIG_USER_ONLY
2624 trans_nop_addrx(ctx
, a
);
2625 gen_helper_ptlbe(tcg_env
);
2627 /* Exit TB for TLB change if mmu is enabled. */
2628 if (ctx
->tb_flags
& PSW_C
) {
2629 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2631 return nullify_end(ctx
);
2636 * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
2638 * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
2639 * page 13-9 (195/206)
2641 static bool trans_ixtlbxf(DisasContext
*ctx
, arg_ixtlbxf
*a
)
2646 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2647 #ifndef CONFIG_USER_ONLY
2648 TCGv_i64 addr
, atl
, stl
;
2655 * if (not (pcxl or pcxl2))
2656 * return gen_illegal(ctx);
2659 atl
= tcg_temp_new_i64();
2660 stl
= tcg_temp_new_i64();
2661 addr
= tcg_temp_new_i64();
2663 tcg_gen_ld32u_i64(stl
, tcg_env
,
2664 a
->data
? offsetof(CPUHPPAState
, cr
[CR_ISR
])
2665 : offsetof(CPUHPPAState
, cr
[CR_IIASQ
]));
2666 tcg_gen_ld32u_i64(atl
, tcg_env
,
2667 a
->data
? offsetof(CPUHPPAState
, cr
[CR_IOR
])
2668 : offsetof(CPUHPPAState
, cr
[CR_IIAOQ
]));
2669 tcg_gen_shli_i64(stl
, stl
, 32);
2670 tcg_gen_or_i64(addr
, atl
, stl
);
2672 reg
= load_gpr(ctx
, a
->r
);
2674 gen_helper_itlba_pa11(tcg_env
, addr
, reg
);
2676 gen_helper_itlbp_pa11(tcg_env
, addr
, reg
);
2679 /* Exit TB for TLB change if mmu is enabled. */
2680 if (ctx
->tb_flags
& PSW_C
) {
2681 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2683 return nullify_end(ctx
);
2687 static bool trans_ixtlbt(DisasContext
*ctx
, arg_ixtlbt
*a
)
2689 if (!ctx
->is_pa20
) {
2692 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2693 #ifndef CONFIG_USER_ONLY
2696 TCGv_i64 src1
= load_gpr(ctx
, a
->r1
);
2697 TCGv_i64 src2
= load_gpr(ctx
, a
->r2
);
2700 gen_helper_idtlbt_pa20(tcg_env
, src1
, src2
);
2702 gen_helper_iitlbt_pa20(tcg_env
, src1
, src2
);
2705 /* Exit TB for TLB change if mmu is enabled. */
2706 if (ctx
->tb_flags
& PSW_C
) {
2707 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
2709 return nullify_end(ctx
);
2713 static bool trans_lpa(DisasContext
*ctx
, arg_ldst
*a
)
2715 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2716 #ifndef CONFIG_USER_ONLY
2718 TCGv_i64 ofs
, paddr
;
2722 form_gva(ctx
, &vaddr
, &ofs
, a
->b
, a
->x
, 0, 0, a
->sp
, a
->m
, false);
2724 paddr
= tcg_temp_new_i64();
2725 gen_helper_lpa(paddr
, tcg_env
, vaddr
);
2727 /* Note that physical address result overrides base modification. */
2729 save_gpr(ctx
, a
->b
, ofs
);
2731 save_gpr(ctx
, a
->t
, paddr
);
2733 return nullify_end(ctx
);
2737 static bool trans_lci(DisasContext
*ctx
, arg_lci
*a
)
2739 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
2741 /* The Coherence Index is an implementation-defined function of the
2742 physical address. Two addresses with the same CI have a coherent
2743 view of the cache. Our implementation is to return 0 for all,
2744 since the entire address space is coherent. */
2745 save_gpr(ctx
, a
->t
, ctx
->zero
);
2747 ctx
->null_cond
= cond_make_f();
2751 static bool trans_add(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
)
2753 return do_add_reg(ctx
, a
, false, false, false, false);
2756 static bool trans_add_l(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
)
2758 return do_add_reg(ctx
, a
, true, false, false, false);
2761 static bool trans_add_tsv(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
)
2763 return do_add_reg(ctx
, a
, false, true, false, false);
2766 static bool trans_add_c(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
)
2768 return do_add_reg(ctx
, a
, false, false, false, true);
2771 static bool trans_add_c_tsv(DisasContext
*ctx
, arg_rrr_cf_d_sh
*a
)
2773 return do_add_reg(ctx
, a
, false, true, false, true);
2776 static bool trans_sub(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2778 return do_sub_reg(ctx
, a
, false, false, false);
2781 static bool trans_sub_tsv(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2783 return do_sub_reg(ctx
, a
, true, false, false);
2786 static bool trans_sub_tc(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2788 return do_sub_reg(ctx
, a
, false, false, true);
2791 static bool trans_sub_tsv_tc(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2793 return do_sub_reg(ctx
, a
, true, false, true);
2796 static bool trans_sub_b(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2798 return do_sub_reg(ctx
, a
, false, true, false);
2801 static bool trans_sub_b_tsv(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2803 return do_sub_reg(ctx
, a
, true, true, false);
2806 static bool trans_andcm(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2808 return do_log_reg(ctx
, a
, tcg_gen_andc_i64
);
2811 static bool trans_and(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2813 return do_log_reg(ctx
, a
, tcg_gen_and_i64
);
2816 static bool trans_or(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2819 unsigned r2
= a
->r2
;
2820 unsigned r1
= a
->r1
;
2823 if (rt
== 0) { /* NOP */
2824 ctx
->null_cond
= cond_make_f();
2827 if (r2
== 0) { /* COPY */
2829 TCGv_i64 dest
= dest_gpr(ctx
, rt
);
2830 tcg_gen_movi_i64(dest
, 0);
2831 save_gpr(ctx
, rt
, dest
);
2833 save_gpr(ctx
, rt
, cpu_gr
[r1
]);
2835 ctx
->null_cond
= cond_make_f();
2838 #ifndef CONFIG_USER_ONLY
2839 /* These are QEMU extensions and are nops in the real architecture:
2841 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2842 * or %r31,%r31,%r31 -- death loop; offline cpu
2843 * currently implemented as idle.
2845 if ((rt
== 10 || rt
== 31) && r1
== rt
&& r2
== rt
) { /* PAUSE */
2846 /* No need to check for supervisor, as userland can only pause
2847 until the next timer interrupt. */
2853 /* Advance the instruction queue. */
2854 install_iaq_entries(ctx
, &ctx
->iaq_b
, NULL
);
2855 nullify_set(ctx
, 0);
2857 /* Tell the qemu main loop to halt until this cpu has work. */
2858 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env
,
2859 offsetof(CPUState
, halted
) - offsetof(HPPACPU
, env
));
2860 gen_excp_1(EXCP_HALTED
);
2861 ctx
->base
.is_jmp
= DISAS_NORETURN
;
2863 return nullify_end(ctx
);
2867 return do_log_reg(ctx
, a
, tcg_gen_or_i64
);
2870 static bool trans_xor(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2872 return do_log_reg(ctx
, a
, tcg_gen_xor_i64
);
2875 static bool trans_cmpclr(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2877 TCGv_i64 tcg_r1
, tcg_r2
;
2882 tcg_r1
= load_gpr(ctx
, a
->r1
);
2883 tcg_r2
= load_gpr(ctx
, a
->r2
);
2884 do_cmpclr(ctx
, a
->t
, tcg_r1
, tcg_r2
, a
->cf
, a
->d
);
2885 return nullify_end(ctx
);
2888 static bool trans_uxor(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2890 TCGv_i64 tcg_r1
, tcg_r2
, dest
;
2896 tcg_r1
= load_gpr(ctx
, a
->r1
);
2897 tcg_r2
= load_gpr(ctx
, a
->r2
);
2898 dest
= dest_gpr(ctx
, a
->t
);
2900 tcg_gen_xor_i64(dest
, tcg_r1
, tcg_r2
);
2901 save_gpr(ctx
, a
->t
, dest
);
2903 ctx
->null_cond
= do_unit_zero_cond(a
->cf
, a
->d
, dest
);
2904 return nullify_end(ctx
);
2907 static bool do_uaddcm(DisasContext
*ctx
, arg_rrr_cf_d
*a
, bool is_tc
)
2909 TCGv_i64 tcg_r1
, tcg_r2
, tmp
;
2912 tcg_r2
= load_gpr(ctx
, a
->r2
);
2913 tmp
= dest_gpr(ctx
, a
->t
);
2916 /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2917 tcg_gen_not_i64(tmp
, tcg_r2
);
2920 * Recall that r1 - r2 == r1 + ~r2 + 1.
2921 * Thus r1 + ~r2 == r1 - r2 - 1,
2922 * which does not require an extra temporary.
2924 tcg_r1
= load_gpr(ctx
, a
->r1
);
2925 tcg_gen_sub_i64(tmp
, tcg_r1
, tcg_r2
);
2926 tcg_gen_subi_i64(tmp
, tmp
, 1);
2928 save_gpr(ctx
, a
->t
, tmp
);
2929 ctx
->null_cond
= cond_make_f();
2934 tcg_r1
= load_gpr(ctx
, a
->r1
);
2935 tcg_r2
= load_gpr(ctx
, a
->r2
);
2936 tmp
= tcg_temp_new_i64();
2937 tcg_gen_not_i64(tmp
, tcg_r2
);
2938 do_unit_addsub(ctx
, a
->t
, tcg_r1
, tmp
, a
->cf
, a
->d
, is_tc
, true);
2939 return nullify_end(ctx
);
2942 static bool trans_uaddcm(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2944 return do_uaddcm(ctx
, a
, false);
2947 static bool trans_uaddcm_tc(DisasContext
*ctx
, arg_rrr_cf_d
*a
)
2949 return do_uaddcm(ctx
, a
, true);
2952 static bool do_dcor(DisasContext
*ctx
, arg_rr_cf_d
*a
, bool is_i
)
2958 tmp
= tcg_temp_new_i64();
2959 tcg_gen_extract2_i64(tmp
, cpu_psw_cb
, cpu_psw_cb_msb
, 4);
2961 tcg_gen_not_i64(tmp
, tmp
);
2963 tcg_gen_andi_i64(tmp
, tmp
, (uint64_t)0x1111111111111111ull
);
2964 tcg_gen_muli_i64(tmp
, tmp
, 6);
2965 do_unit_addsub(ctx
, a
->t
, load_gpr(ctx
, a
->r
), tmp
,
2966 a
->cf
, a
->d
, false, is_i
);
2967 return nullify_end(ctx
);
2970 static bool trans_dcor(DisasContext
*ctx
, arg_rr_cf_d
*a
)
2972 return do_dcor(ctx
, a
, false);
2975 static bool trans_dcor_i(DisasContext
*ctx
, arg_rr_cf_d
*a
)
2977 return do_dcor(ctx
, a
, true);
2980 static bool trans_ds(DisasContext
*ctx
, arg_rrr_cf
*a
)
2982 TCGv_i64 dest
, add1
, add2
, addc
, in1
, in2
;
2986 in1
= load_gpr(ctx
, a
->r1
);
2987 in2
= load_gpr(ctx
, a
->r2
);
2989 add1
= tcg_temp_new_i64();
2990 add2
= tcg_temp_new_i64();
2991 addc
= tcg_temp_new_i64();
2992 dest
= tcg_temp_new_i64();
2994 /* Form R1 << 1 | PSW[CB]{8}. */
2995 tcg_gen_add_i64(add1
, in1
, in1
);
2996 tcg_gen_add_i64(add1
, add1
, get_psw_carry(ctx
, false));
2999 * Add or subtract R2, depending on PSW[V]. Proper computation of
3000 * carry requires that we subtract via + ~R2 + 1, as described in
3001 * the manual. By extracting and masking V, we can produce the
3002 * proper inputs to the addition without movcond.
3004 tcg_gen_sextract_i64(addc
, cpu_psw_v
, 31, 1);
3005 tcg_gen_xor_i64(add2
, in2
, addc
);
3006 tcg_gen_andi_i64(addc
, addc
, 1);
3008 tcg_gen_add2_i64(dest
, cpu_psw_cb_msb
, add1
, ctx
->zero
, add2
, ctx
->zero
);
3009 tcg_gen_add2_i64(dest
, cpu_psw_cb_msb
, dest
, cpu_psw_cb_msb
,
3012 /* Write back the result register. */
3013 save_gpr(ctx
, a
->t
, dest
);
3015 /* Write back PSW[CB]. */
3016 tcg_gen_xor_i64(cpu_psw_cb
, add1
, add2
);
3017 tcg_gen_xor_i64(cpu_psw_cb
, cpu_psw_cb
, dest
);
3020 * Write back PSW[V] for the division step.
3021 * Shift cb{8} from where it lives in bit 32 to bit 31,
3022 * so that it overlaps r2{32} in bit 31.
3024 tcg_gen_shri_i64(cpu_psw_v
, cpu_psw_cb
, 1);
3025 tcg_gen_xor_i64(cpu_psw_v
, cpu_psw_v
, in2
);
3027 /* Install the new nullification. */
3029 TCGv_i64 sv
= NULL
, uv
= NULL
;
3030 if (cond_need_sv(a
->cf
>> 1)) {
3031 sv
= do_add_sv(ctx
, dest
, add1
, add2
, in1
, 1, false);
3032 } else if (cond_need_cb(a
->cf
>> 1)) {
3033 uv
= do_add_uv(ctx
, cpu_psw_cb
, NULL
, in1
, 1, false);
3035 ctx
->null_cond
= do_cond(ctx
, a
->cf
, false, dest
, uv
, sv
);
3038 return nullify_end(ctx
);
3041 static bool trans_addi(DisasContext
*ctx
, arg_rri_cf
*a
)
3043 return do_add_imm(ctx
, a
, false, false);
3046 static bool trans_addi_tsv(DisasContext
*ctx
, arg_rri_cf
*a
)
3048 return do_add_imm(ctx
, a
, true, false);
3051 static bool trans_addi_tc(DisasContext
*ctx
, arg_rri_cf
*a
)
3053 return do_add_imm(ctx
, a
, false, true);
3056 static bool trans_addi_tc_tsv(DisasContext
*ctx
, arg_rri_cf
*a
)
3058 return do_add_imm(ctx
, a
, true, true);
3061 static bool trans_subi(DisasContext
*ctx
, arg_rri_cf
*a
)
3063 return do_sub_imm(ctx
, a
, false);
3066 static bool trans_subi_tsv(DisasContext
*ctx
, arg_rri_cf
*a
)
3068 return do_sub_imm(ctx
, a
, true);
3071 static bool trans_cmpiclr(DisasContext
*ctx
, arg_rri_cf_d
*a
)
3073 TCGv_i64 tcg_im
, tcg_r2
;
3079 tcg_im
= tcg_constant_i64(a
->i
);
3080 tcg_r2
= load_gpr(ctx
, a
->r
);
3081 do_cmpclr(ctx
, a
->t
, tcg_im
, tcg_r2
, a
->cf
, a
->d
);
3083 return nullify_end(ctx
);
3086 static bool do_multimedia(DisasContext
*ctx
, arg_rrr
*a
,
3087 void (*fn
)(TCGv_i64
, TCGv_i64
, TCGv_i64
))
3089 TCGv_i64 r1
, r2
, dest
;
3091 if (!ctx
->is_pa20
) {
3097 r1
= load_gpr(ctx
, a
->r1
);
3098 r2
= load_gpr(ctx
, a
->r2
);
3099 dest
= dest_gpr(ctx
, a
->t
);
3102 save_gpr(ctx
, a
->t
, dest
);
3104 return nullify_end(ctx
);
3107 static bool do_multimedia_sh(DisasContext
*ctx
, arg_rri
*a
,
3108 void (*fn
)(TCGv_i64
, TCGv_i64
, int64_t))
3112 if (!ctx
->is_pa20
) {
3118 r
= load_gpr(ctx
, a
->r
);
3119 dest
= dest_gpr(ctx
, a
->t
);
3122 save_gpr(ctx
, a
->t
, dest
);
3124 return nullify_end(ctx
);
3127 static bool do_multimedia_shadd(DisasContext
*ctx
, arg_rrr_sh
*a
,
3128 void (*fn
)(TCGv_i64
, TCGv_i64
,
3129 TCGv_i64
, TCGv_i32
))
3131 TCGv_i64 r1
, r2
, dest
;
3133 if (!ctx
->is_pa20
) {
3139 r1
= load_gpr(ctx
, a
->r1
);
3140 r2
= load_gpr(ctx
, a
->r2
);
3141 dest
= dest_gpr(ctx
, a
->t
);
3143 fn(dest
, r1
, r2
, tcg_constant_i32(a
->sh
));
3144 save_gpr(ctx
, a
->t
, dest
);
3146 return nullify_end(ctx
);
3149 static bool trans_hadd(DisasContext
*ctx
, arg_rrr
*a
)
3151 return do_multimedia(ctx
, a
, tcg_gen_vec_add16_i64
);
3154 static bool trans_hadd_ss(DisasContext
*ctx
, arg_rrr
*a
)
3156 return do_multimedia(ctx
, a
, gen_helper_hadd_ss
);
3159 static bool trans_hadd_us(DisasContext
*ctx
, arg_rrr
*a
)
3161 return do_multimedia(ctx
, a
, gen_helper_hadd_us
);
3164 static bool trans_havg(DisasContext
*ctx
, arg_rrr
*a
)
3166 return do_multimedia(ctx
, a
, gen_helper_havg
);
3169 static bool trans_hshl(DisasContext
*ctx
, arg_rri
*a
)
3171 return do_multimedia_sh(ctx
, a
, tcg_gen_vec_shl16i_i64
);
3174 static bool trans_hshr_s(DisasContext
*ctx
, arg_rri
*a
)
3176 return do_multimedia_sh(ctx
, a
, tcg_gen_vec_sar16i_i64
);
3179 static bool trans_hshr_u(DisasContext
*ctx
, arg_rri
*a
)
3181 return do_multimedia_sh(ctx
, a
, tcg_gen_vec_shr16i_i64
);
3184 static bool trans_hshladd(DisasContext
*ctx
, arg_rrr_sh
*a
)
3186 return do_multimedia_shadd(ctx
, a
, gen_helper_hshladd
);
3189 static bool trans_hshradd(DisasContext
*ctx
, arg_rrr_sh
*a
)
3191 return do_multimedia_shadd(ctx
, a
, gen_helper_hshradd
);
3194 static bool trans_hsub(DisasContext
*ctx
, arg_rrr
*a
)
3196 return do_multimedia(ctx
, a
, tcg_gen_vec_sub16_i64
);
3199 static bool trans_hsub_ss(DisasContext
*ctx
, arg_rrr
*a
)
3201 return do_multimedia(ctx
, a
, gen_helper_hsub_ss
);
3204 static bool trans_hsub_us(DisasContext
*ctx
, arg_rrr
*a
)
3206 return do_multimedia(ctx
, a
, gen_helper_hsub_us
);
3209 static void gen_mixh_l(TCGv_i64 dst
, TCGv_i64 r1
, TCGv_i64 r2
)
3211 uint64_t mask
= 0xffff0000ffff0000ull
;
3212 TCGv_i64 tmp
= tcg_temp_new_i64();
3214 tcg_gen_andi_i64(tmp
, r2
, mask
);
3215 tcg_gen_andi_i64(dst
, r1
, mask
);
3216 tcg_gen_shri_i64(tmp
, tmp
, 16);
3217 tcg_gen_or_i64(dst
, dst
, tmp
);
3220 static bool trans_mixh_l(DisasContext
*ctx
, arg_rrr
*a
)
3222 return do_multimedia(ctx
, a
, gen_mixh_l
);
3225 static void gen_mixh_r(TCGv_i64 dst
, TCGv_i64 r1
, TCGv_i64 r2
)
3227 uint64_t mask
= 0x0000ffff0000ffffull
;
3228 TCGv_i64 tmp
= tcg_temp_new_i64();
3230 tcg_gen_andi_i64(tmp
, r1
, mask
);
3231 tcg_gen_andi_i64(dst
, r2
, mask
);
3232 tcg_gen_shli_i64(tmp
, tmp
, 16);
3233 tcg_gen_or_i64(dst
, dst
, tmp
);
3236 static bool trans_mixh_r(DisasContext
*ctx
, arg_rrr
*a
)
3238 return do_multimedia(ctx
, a
, gen_mixh_r
);
3241 static void gen_mixw_l(TCGv_i64 dst
, TCGv_i64 r1
, TCGv_i64 r2
)
3243 TCGv_i64 tmp
= tcg_temp_new_i64();
3245 tcg_gen_shri_i64(tmp
, r2
, 32);
3246 tcg_gen_deposit_i64(dst
, r1
, tmp
, 0, 32);
3249 static bool trans_mixw_l(DisasContext
*ctx
, arg_rrr
*a
)
3251 return do_multimedia(ctx
, a
, gen_mixw_l
);
3254 static void gen_mixw_r(TCGv_i64 dst
, TCGv_i64 r1
, TCGv_i64 r2
)
3256 tcg_gen_deposit_i64(dst
, r2
, r1
, 32, 32);
3259 static bool trans_mixw_r(DisasContext
*ctx
, arg_rrr
*a
)
3261 return do_multimedia(ctx
, a
, gen_mixw_r
);
3264 static bool trans_permh(DisasContext
*ctx
, arg_permh
*a
)
3266 TCGv_i64 r
, t0
, t1
, t2
, t3
;
3268 if (!ctx
->is_pa20
) {
3274 r
= load_gpr(ctx
, a
->r1
);
3275 t0
= tcg_temp_new_i64();
3276 t1
= tcg_temp_new_i64();
3277 t2
= tcg_temp_new_i64();
3278 t3
= tcg_temp_new_i64();
3280 tcg_gen_extract_i64(t0
, r
, (3 - a
->c0
) * 16, 16);
3281 tcg_gen_extract_i64(t1
, r
, (3 - a
->c1
) * 16, 16);
3282 tcg_gen_extract_i64(t2
, r
, (3 - a
->c2
) * 16, 16);
3283 tcg_gen_extract_i64(t3
, r
, (3 - a
->c3
) * 16, 16);
3285 tcg_gen_deposit_i64(t0
, t1
, t0
, 16, 48);
3286 tcg_gen_deposit_i64(t2
, t3
, t2
, 16, 48);
3287 tcg_gen_deposit_i64(t0
, t2
, t0
, 32, 32);
3289 save_gpr(ctx
, a
->t
, t0
);
3290 return nullify_end(ctx
);
3293 static bool trans_ld(DisasContext
*ctx
, arg_ldst
*a
)
3297 * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3298 * Any base modification still occurs.
3301 return trans_nop_addrx(ctx
, a
);
3303 } else if (a
->size
> MO_32
) {
3304 return gen_illegal(ctx
);
3306 return do_load(ctx
, a
->t
, a
->b
, a
->x
, a
->scale
? a
->size
: 0,
3307 a
->disp
, a
->sp
, a
->m
, a
->size
| MO_TE
);
3310 static bool trans_st(DisasContext
*ctx
, arg_ldst
*a
)
3312 assert(a
->x
== 0 && a
->scale
== 0);
3313 if (!ctx
->is_pa20
&& a
->size
> MO_32
) {
3314 return gen_illegal(ctx
);
3316 return do_store(ctx
, a
->t
, a
->b
, a
->disp
, a
->sp
, a
->m
, a
->size
| MO_TE
);
3319 static bool trans_ldc(DisasContext
*ctx
, arg_ldst
*a
)
3321 MemOp mop
= MO_TE
| MO_ALIGN
| a
->size
;
3325 if (!ctx
->is_pa20
&& a
->size
> MO_32
) {
3326 return gen_illegal(ctx
);
3332 /* Base register modification. Make sure if RT == RB,
3333 we see the result of the load. */
3334 dest
= tcg_temp_new_i64();
3336 dest
= dest_gpr(ctx
, a
->t
);
3339 form_gva(ctx
, &addr
, &ofs
, a
->b
, a
->x
, a
->scale
? 3 : 0,
3340 a
->disp
, a
->sp
, a
->m
, MMU_DISABLED(ctx
));
3343 * For hppa1.1, LDCW is undefined unless aligned mod 16.
3344 * However actual hardware succeeds with aligned mod 4.
3345 * Detect this case and log a GUEST_ERROR.
3347 * TODO: HPPA64 relaxes the over-alignment requirement
3348 * with the ,co completer.
3350 gen_helper_ldc_check(addr
);
3352 tcg_gen_atomic_xchg_i64(dest
, addr
, ctx
->zero
, ctx
->mmu_idx
, mop
);
3355 save_gpr(ctx
, a
->b
, ofs
);
3357 save_gpr(ctx
, a
->t
, dest
);
3359 return nullify_end(ctx
);
3362 static bool trans_stby(DisasContext
*ctx
, arg_stby
*a
)
3369 form_gva(ctx
, &addr
, &ofs
, a
->b
, 0, 0, a
->disp
, a
->sp
, a
->m
,
3371 val
= load_gpr(ctx
, a
->r
);
3373 if (tb_cflags(ctx
->base
.tb
) & CF_PARALLEL
) {
3374 gen_helper_stby_e_parallel(tcg_env
, addr
, val
);
3376 gen_helper_stby_e(tcg_env
, addr
, val
);
3379 if (tb_cflags(ctx
->base
.tb
) & CF_PARALLEL
) {
3380 gen_helper_stby_b_parallel(tcg_env
, addr
, val
);
3382 gen_helper_stby_b(tcg_env
, addr
, val
);
3386 tcg_gen_andi_i64(ofs
, ofs
, ~3);
3387 save_gpr(ctx
, a
->b
, ofs
);
3390 return nullify_end(ctx
);
3393 static bool trans_stdby(DisasContext
*ctx
, arg_stby
*a
)
3398 if (!ctx
->is_pa20
) {
3403 form_gva(ctx
, &addr
, &ofs
, a
->b
, 0, 0, a
->disp
, a
->sp
, a
->m
,
3405 val
= load_gpr(ctx
, a
->r
);
3407 if (tb_cflags(ctx
->base
.tb
) & CF_PARALLEL
) {
3408 gen_helper_stdby_e_parallel(tcg_env
, addr
, val
);
3410 gen_helper_stdby_e(tcg_env
, addr
, val
);
3413 if (tb_cflags(ctx
->base
.tb
) & CF_PARALLEL
) {
3414 gen_helper_stdby_b_parallel(tcg_env
, addr
, val
);
3416 gen_helper_stdby_b(tcg_env
, addr
, val
);
3420 tcg_gen_andi_i64(ofs
, ofs
, ~7);
3421 save_gpr(ctx
, a
->b
, ofs
);
3424 return nullify_end(ctx
);
3427 static bool trans_lda(DisasContext
*ctx
, arg_ldst
*a
)
3429 int hold_mmu_idx
= ctx
->mmu_idx
;
3431 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
3432 ctx
->mmu_idx
= ctx
->tb_flags
& PSW_W
? MMU_ABS_W_IDX
: MMU_ABS_IDX
;
3434 ctx
->mmu_idx
= hold_mmu_idx
;
3438 static bool trans_sta(DisasContext
*ctx
, arg_ldst
*a
)
3440 int hold_mmu_idx
= ctx
->mmu_idx
;
3442 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
3443 ctx
->mmu_idx
= ctx
->tb_flags
& PSW_W
? MMU_ABS_W_IDX
: MMU_ABS_IDX
;
3445 ctx
->mmu_idx
= hold_mmu_idx
;
3449 static bool trans_ldil(DisasContext
*ctx
, arg_ldil
*a
)
3451 TCGv_i64 tcg_rt
= dest_gpr(ctx
, a
->t
);
3453 tcg_gen_movi_i64(tcg_rt
, a
->i
);
3454 save_gpr(ctx
, a
->t
, tcg_rt
);
3455 ctx
->null_cond
= cond_make_f();
3459 static bool trans_addil(DisasContext
*ctx
, arg_addil
*a
)
3461 TCGv_i64 tcg_rt
= load_gpr(ctx
, a
->r
);
3462 TCGv_i64 tcg_r1
= dest_gpr(ctx
, 1);
3464 tcg_gen_addi_i64(tcg_r1
, tcg_rt
, a
->i
);
3465 save_gpr(ctx
, 1, tcg_r1
);
3466 ctx
->null_cond
= cond_make_f();
3470 static bool trans_ldo(DisasContext
*ctx
, arg_ldo
*a
)
3472 TCGv_i64 tcg_rt
= dest_gpr(ctx
, a
->t
);
3474 /* Special case rb == 0, for the LDI pseudo-op.
3475 The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */
3477 tcg_gen_movi_i64(tcg_rt
, a
->i
);
3479 tcg_gen_addi_i64(tcg_rt
, cpu_gr
[a
->b
], a
->i
);
3481 save_gpr(ctx
, a
->t
, tcg_rt
);
3482 ctx
->null_cond
= cond_make_f();
3486 static bool do_cmpb(DisasContext
*ctx
, unsigned r
, TCGv_i64 in1
,
3487 unsigned c
, unsigned f
, bool d
, unsigned n
, int disp
)
3489 TCGv_i64 dest
, in2
, sv
;
3492 in2
= load_gpr(ctx
, r
);
3493 dest
= tcg_temp_new_i64();
3495 tcg_gen_sub_i64(dest
, in1
, in2
);
3498 if (cond_need_sv(c
)) {
3499 sv
= do_sub_sv(ctx
, dest
, in1
, in2
);
3502 cond
= do_sub_cond(ctx
, c
* 2 + f
, d
, dest
, in1
, in2
, sv
);
3503 return do_cbranch(ctx
, disp
, n
, &cond
);
3506 static bool trans_cmpb(DisasContext
*ctx
, arg_cmpb
*a
)
3508 if (!ctx
->is_pa20
&& a
->d
) {
3512 return do_cmpb(ctx
, a
->r2
, load_gpr(ctx
, a
->r1
),
3513 a
->c
, a
->f
, a
->d
, a
->n
, a
->disp
);
3516 static bool trans_cmpbi(DisasContext
*ctx
, arg_cmpbi
*a
)
3518 if (!ctx
->is_pa20
&& a
->d
) {
3522 return do_cmpb(ctx
, a
->r
, tcg_constant_i64(a
->i
),
3523 a
->c
, a
->f
, a
->d
, a
->n
, a
->disp
);
3526 static bool do_addb(DisasContext
*ctx
, unsigned r
, TCGv_i64 in1
,
3527 unsigned c
, unsigned f
, unsigned n
, int disp
)
3529 TCGv_i64 dest
, in2
, sv
, cb_cond
;
3534 * For hppa64, the ADDB conditions change with PSW.W,
3535 * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3537 if (ctx
->tb_flags
& PSW_W
) {
3544 in2
= load_gpr(ctx
, r
);
3545 dest
= tcg_temp_new_i64();
3549 if (cond_need_cb(c
)) {
3550 TCGv_i64 cb
= tcg_temp_new_i64();
3551 TCGv_i64 cb_msb
= tcg_temp_new_i64();
3553 tcg_gen_movi_i64(cb_msb
, 0);
3554 tcg_gen_add2_i64(dest
, cb_msb
, in1
, cb_msb
, in2
, cb_msb
);
3555 tcg_gen_xor_i64(cb
, in1
, in2
);
3556 tcg_gen_xor_i64(cb
, cb
, dest
);
3557 cb_cond
= get_carry(ctx
, d
, cb
, cb_msb
);
3559 tcg_gen_add_i64(dest
, in1
, in2
);
3561 if (cond_need_sv(c
)) {
3562 sv
= do_add_sv(ctx
, dest
, in1
, in2
, in1
, 0, d
);
3565 cond
= do_cond(ctx
, c
* 2 + f
, d
, dest
, cb_cond
, sv
);
3566 save_gpr(ctx
, r
, dest
);
3567 return do_cbranch(ctx
, disp
, n
, &cond
);
3570 static bool trans_addb(DisasContext
*ctx
, arg_addb
*a
)
3573 return do_addb(ctx
, a
->r2
, load_gpr(ctx
, a
->r1
), a
->c
, a
->f
, a
->n
, a
->disp
);
3576 static bool trans_addbi(DisasContext
*ctx
, arg_addbi
*a
)
3579 return do_addb(ctx
, a
->r
, tcg_constant_i64(a
->i
), a
->c
, a
->f
, a
->n
, a
->disp
);
3582 static bool trans_bb_sar(DisasContext
*ctx
, arg_bb_sar
*a
)
3584 TCGv_i64 tmp
, tcg_r
;
3589 tmp
= tcg_temp_new_i64();
3590 tcg_r
= load_gpr(ctx
, a
->r
);
3592 tcg_gen_shl_i64(tmp
, tcg_r
, cpu_sar
);
3594 /* Force shift into [32,63] */
3595 tcg_gen_ori_i64(tmp
, cpu_sar
, 32);
3596 tcg_gen_shl_i64(tmp
, tcg_r
, tmp
);
3599 cond
= cond_make_ti(a
->c
? TCG_COND_GE
: TCG_COND_LT
, tmp
, 0);
3600 return do_cbranch(ctx
, a
->disp
, a
->n
, &cond
);
3603 static bool trans_bb_imm(DisasContext
*ctx
, arg_bb_imm
*a
)
3606 int p
= a
->p
| (a
->d
? 0 : 32);
3609 cond
= cond_make_vi(a
->c
? TCG_COND_TSTEQ
: TCG_COND_TSTNE
,
3610 load_gpr(ctx
, a
->r
), 1ull << (63 - p
));
3611 return do_cbranch(ctx
, a
->disp
, a
->n
, &cond
);
3614 static bool trans_movb(DisasContext
*ctx
, arg_movb
*a
)
3621 dest
= dest_gpr(ctx
, a
->r2
);
3623 tcg_gen_movi_i64(dest
, 0);
3625 tcg_gen_mov_i64(dest
, cpu_gr
[a
->r1
]);
3628 /* All MOVB conditions are 32-bit. */
3629 cond
= do_sed_cond(ctx
, a
->c
, false, dest
);
3630 return do_cbranch(ctx
, a
->disp
, a
->n
, &cond
);
3633 static bool trans_movbi(DisasContext
*ctx
, arg_movbi
*a
)
3640 dest
= dest_gpr(ctx
, a
->r
);
3641 tcg_gen_movi_i64(dest
, a
->i
);
3643 /* All MOVBI conditions are 32-bit. */
3644 cond
= do_sed_cond(ctx
, a
->c
, false, dest
);
3645 return do_cbranch(ctx
, a
->disp
, a
->n
, &cond
);
3648 static bool trans_shrp_sar(DisasContext
*ctx
, arg_shrp_sar
*a
)
3650 TCGv_i64 dest
, src2
;
3652 if (!ctx
->is_pa20
&& a
->d
) {
3659 dest
= dest_gpr(ctx
, a
->t
);
3660 src2
= load_gpr(ctx
, a
->r2
);
3663 tcg_gen_shr_i64(dest
, src2
, cpu_sar
);
3665 TCGv_i64 tmp
= tcg_temp_new_i64();
3667 tcg_gen_ext32u_i64(dest
, src2
);
3668 tcg_gen_andi_i64(tmp
, cpu_sar
, 31);
3669 tcg_gen_shr_i64(dest
, dest
, tmp
);
3671 } else if (a
->r1
== a
->r2
) {
3673 tcg_gen_rotr_i64(dest
, src2
, cpu_sar
);
3675 TCGv_i32 t32
= tcg_temp_new_i32();
3676 TCGv_i32 s32
= tcg_temp_new_i32();
3678 tcg_gen_extrl_i64_i32(t32
, src2
);
3679 tcg_gen_extrl_i64_i32(s32
, cpu_sar
);
3680 tcg_gen_andi_i32(s32
, s32
, 31);
3681 tcg_gen_rotr_i32(t32
, t32
, s32
);
3682 tcg_gen_extu_i32_i64(dest
, t32
);
3685 TCGv_i64 src1
= load_gpr(ctx
, a
->r1
);
3688 TCGv_i64 t
= tcg_temp_new_i64();
3689 TCGv_i64 n
= tcg_temp_new_i64();
3691 tcg_gen_xori_i64(n
, cpu_sar
, 63);
3692 tcg_gen_shl_i64(t
, src1
, n
);
3693 tcg_gen_shli_i64(t
, t
, 1);
3694 tcg_gen_shr_i64(dest
, src2
, cpu_sar
);
3695 tcg_gen_or_i64(dest
, dest
, t
);
3697 TCGv_i64 t
= tcg_temp_new_i64();
3698 TCGv_i64 s
= tcg_temp_new_i64();
3700 tcg_gen_concat32_i64(t
, src2
, src1
);
3701 tcg_gen_andi_i64(s
, cpu_sar
, 31);
3702 tcg_gen_shr_i64(dest
, t
, s
);
3705 save_gpr(ctx
, a
->t
, dest
);
3707 /* Install the new nullification. */
3708 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3709 return nullify_end(ctx
);
3712 static bool trans_shrp_imm(DisasContext
*ctx
, arg_shrp_imm
*a
)
3717 if (!ctx
->is_pa20
&& a
->d
) {
3724 width
= a
->d
? 64 : 32;
3725 sa
= width
- 1 - a
->cpos
;
3727 dest
= dest_gpr(ctx
, a
->t
);
3728 t2
= load_gpr(ctx
, a
->r2
);
3730 tcg_gen_extract_i64(dest
, t2
, sa
, width
- sa
);
3731 } else if (width
== TARGET_LONG_BITS
) {
3732 tcg_gen_extract2_i64(dest
, t2
, cpu_gr
[a
->r1
], sa
);
3735 if (a
->r1
== a
->r2
) {
3736 TCGv_i32 t32
= tcg_temp_new_i32();
3737 tcg_gen_extrl_i64_i32(t32
, t2
);
3738 tcg_gen_rotri_i32(t32
, t32
, sa
);
3739 tcg_gen_extu_i32_i64(dest
, t32
);
3741 tcg_gen_concat32_i64(dest
, t2
, cpu_gr
[a
->r1
]);
3742 tcg_gen_extract_i64(dest
, dest
, sa
, 32);
3745 save_gpr(ctx
, a
->t
, dest
);
3747 /* Install the new nullification. */
3748 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3749 return nullify_end(ctx
);
3752 static bool trans_extr_sar(DisasContext
*ctx
, arg_extr_sar
*a
)
3754 unsigned widthm1
= a
->d
? 63 : 31;
3755 TCGv_i64 dest
, src
, tmp
;
3757 if (!ctx
->is_pa20
&& a
->d
) {
3764 dest
= dest_gpr(ctx
, a
->t
);
3765 src
= load_gpr(ctx
, a
->r
);
3766 tmp
= tcg_temp_new_i64();
3768 /* Recall that SAR is using big-endian bit numbering. */
3769 tcg_gen_andi_i64(tmp
, cpu_sar
, widthm1
);
3770 tcg_gen_xori_i64(tmp
, tmp
, widthm1
);
3774 tcg_gen_ext32s_i64(dest
, src
);
3777 tcg_gen_sar_i64(dest
, src
, tmp
);
3778 tcg_gen_sextract_i64(dest
, dest
, 0, a
->len
);
3781 tcg_gen_ext32u_i64(dest
, src
);
3784 tcg_gen_shr_i64(dest
, src
, tmp
);
3785 tcg_gen_extract_i64(dest
, dest
, 0, a
->len
);
3787 save_gpr(ctx
, a
->t
, dest
);
3789 /* Install the new nullification. */
3790 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3791 return nullify_end(ctx
);
3794 static bool trans_extr_imm(DisasContext
*ctx
, arg_extr_imm
*a
)
3796 unsigned len
, cpos
, width
;
3799 if (!ctx
->is_pa20
&& a
->d
) {
3807 width
= a
->d
? 64 : 32;
3808 cpos
= width
- 1 - a
->pos
;
3809 if (cpos
+ len
> width
) {
3813 dest
= dest_gpr(ctx
, a
->t
);
3814 src
= load_gpr(ctx
, a
->r
);
3816 tcg_gen_sextract_i64(dest
, src
, cpos
, len
);
3818 tcg_gen_extract_i64(dest
, src
, cpos
, len
);
3820 save_gpr(ctx
, a
->t
, dest
);
3822 /* Install the new nullification. */
3823 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3824 return nullify_end(ctx
);
3827 static bool trans_depi_imm(DisasContext
*ctx
, arg_depi_imm
*a
)
3829 unsigned len
, width
;
3830 uint64_t mask0
, mask1
;
3833 if (!ctx
->is_pa20
&& a
->d
) {
3841 width
= a
->d
? 64 : 32;
3842 if (a
->cpos
+ len
> width
) {
3843 len
= width
- a
->cpos
;
3846 dest
= dest_gpr(ctx
, a
->t
);
3847 mask0
= deposit64(0, a
->cpos
, len
, a
->i
);
3848 mask1
= deposit64(-1, a
->cpos
, len
, a
->i
);
3851 TCGv_i64 src
= load_gpr(ctx
, a
->t
);
3852 tcg_gen_andi_i64(dest
, src
, mask1
);
3853 tcg_gen_ori_i64(dest
, dest
, mask0
);
3855 tcg_gen_movi_i64(dest
, mask0
);
3857 save_gpr(ctx
, a
->t
, dest
);
3859 /* Install the new nullification. */
3860 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3861 return nullify_end(ctx
);
3864 static bool trans_dep_imm(DisasContext
*ctx
, arg_dep_imm
*a
)
3866 unsigned rs
= a
->nz
? a
->t
: 0;
3867 unsigned len
, width
;
3870 if (!ctx
->is_pa20
&& a
->d
) {
3878 width
= a
->d
? 64 : 32;
3879 if (a
->cpos
+ len
> width
) {
3880 len
= width
- a
->cpos
;
3883 dest
= dest_gpr(ctx
, a
->t
);
3884 val
= load_gpr(ctx
, a
->r
);
3886 tcg_gen_deposit_z_i64(dest
, val
, a
->cpos
, len
);
3888 tcg_gen_deposit_i64(dest
, cpu_gr
[rs
], val
, a
->cpos
, len
);
3890 save_gpr(ctx
, a
->t
, dest
);
3892 /* Install the new nullification. */
3893 ctx
->null_cond
= do_sed_cond(ctx
, a
->c
, a
->d
, dest
);
3894 return nullify_end(ctx
);
3897 static bool do_dep_sar(DisasContext
*ctx
, unsigned rt
, unsigned c
,
3898 bool d
, bool nz
, unsigned len
, TCGv_i64 val
)
3900 unsigned rs
= nz
? rt
: 0;
3901 unsigned widthm1
= d
? 63 : 31;
3902 TCGv_i64 mask
, tmp
, shift
, dest
;
3903 uint64_t msb
= 1ULL << (len
- 1);
3905 dest
= dest_gpr(ctx
, rt
);
3906 shift
= tcg_temp_new_i64();
3907 tmp
= tcg_temp_new_i64();
3909 /* Convert big-endian bit numbering in SAR to left-shift. */
3910 tcg_gen_andi_i64(shift
, cpu_sar
, widthm1
);
3911 tcg_gen_xori_i64(shift
, shift
, widthm1
);
3913 mask
= tcg_temp_new_i64();
3914 tcg_gen_movi_i64(mask
, msb
+ (msb
- 1));
3915 tcg_gen_and_i64(tmp
, val
, mask
);
3917 tcg_gen_shl_i64(mask
, mask
, shift
);
3918 tcg_gen_shl_i64(tmp
, tmp
, shift
);
3919 tcg_gen_andc_i64(dest
, cpu_gr
[rs
], mask
);
3920 tcg_gen_or_i64(dest
, dest
, tmp
);
3922 tcg_gen_shl_i64(dest
, tmp
, shift
);
3924 save_gpr(ctx
, rt
, dest
);
3926 /* Install the new nullification. */
3927 ctx
->null_cond
= do_sed_cond(ctx
, c
, d
, dest
);
3928 return nullify_end(ctx
);
3931 static bool trans_dep_sar(DisasContext
*ctx
, arg_dep_sar
*a
)
3933 if (!ctx
->is_pa20
&& a
->d
) {
3939 return do_dep_sar(ctx
, a
->t
, a
->c
, a
->d
, a
->nz
, a
->len
,
3940 load_gpr(ctx
, a
->r
));
3943 static bool trans_depi_sar(DisasContext
*ctx
, arg_depi_sar
*a
)
3945 if (!ctx
->is_pa20
&& a
->d
) {
3951 return do_dep_sar(ctx
, a
->t
, a
->c
, a
->d
, a
->nz
, a
->len
,
3952 tcg_constant_i64(a
->i
));
3955 static bool trans_be(DisasContext
*ctx
, arg_be
*a
)
3957 #ifndef CONFIG_USER_ONLY
3958 ctx
->iaq_j
.space
= tcg_temp_new_i64();
3959 load_spr(ctx
, ctx
->iaq_j
.space
, a
->sp
);
3962 ctx
->iaq_j
.base
= tcg_temp_new_i64();
3963 ctx
->iaq_j
.disp
= 0;
3965 tcg_gen_addi_i64(ctx
->iaq_j
.base
, load_gpr(ctx
, a
->b
), a
->disp
);
3966 ctx
->iaq_j
.base
= do_ibranch_priv(ctx
, ctx
->iaq_j
.base
);
3968 return do_ibranch(ctx
, a
->l
, true, a
->n
);
3971 static bool trans_bl(DisasContext
*ctx
, arg_bl
*a
)
3973 return do_dbranch(ctx
, a
->disp
, a
->l
, a
->n
);
3976 static bool trans_b_gate(DisasContext
*ctx
, arg_b_gate
*a
)
3978 int64_t disp
= a
->disp
;
3979 bool indirect
= false;
3981 /* Trap if PSW[B] is set. */
3982 if (ctx
->psw_xb
& PSW_B
) {
3983 return gen_illegal(ctx
);
3988 #ifndef CONFIG_USER_ONLY
3989 if (ctx
->privilege
== 0) {
3990 /* Privilege cannot decrease. */
3991 } else if (!(ctx
->tb_flags
& PSW_C
)) {
3992 /* With paging disabled, priv becomes 0. */
3993 disp
-= ctx
->privilege
;
3995 /* Adjust the dest offset for the privilege change from the PTE. */
3996 TCGv_i64 off
= tcg_temp_new_i64();
3998 copy_iaoq_entry(ctx
, off
, &ctx
->iaq_f
);
3999 gen_helper_b_gate_priv(off
, tcg_env
, off
);
4001 ctx
->iaq_j
.base
= off
;
4002 ctx
->iaq_j
.disp
= disp
+ 8;
4008 TCGv_i64 tmp
= dest_gpr(ctx
, a
->l
);
4009 if (ctx
->privilege
< 3) {
4010 tcg_gen_andi_i64(tmp
, tmp
, -4);
4012 tcg_gen_ori_i64(tmp
, tmp
, ctx
->privilege
);
4013 save_gpr(ctx
, a
->l
, tmp
);
4017 return do_ibranch(ctx
, 0, false, a
->n
);
4019 return do_dbranch(ctx
, disp
, 0, a
->n
);
4022 static bool trans_blr(DisasContext
*ctx
, arg_blr
*a
)
4025 DisasIAQE next
= iaqe_incr(&ctx
->iaq_f
, 8);
4026 TCGv_i64 t0
= tcg_temp_new_i64();
4027 TCGv_i64 t1
= tcg_temp_new_i64();
4029 /* The computation here never changes privilege level. */
4030 copy_iaoq_entry(ctx
, t0
, &next
);
4031 tcg_gen_shli_i64(t1
, load_gpr(ctx
, a
->x
), 3);
4032 tcg_gen_add_i64(t0
, t0
, t1
);
4034 ctx
->iaq_j
= iaqe_next_absv(ctx
, t0
);
4035 return do_ibranch(ctx
, a
->l
, false, a
->n
);
4037 /* BLR R0,RX is a good way to load PC+8 into RX. */
4038 return do_dbranch(ctx
, 0, a
->l
, a
->n
);
4042 static bool trans_bv(DisasContext
*ctx
, arg_bv
*a
)
4047 dest
= load_gpr(ctx
, a
->b
);
4049 dest
= tcg_temp_new_i64();
4050 tcg_gen_shli_i64(dest
, load_gpr(ctx
, a
->x
), 3);
4051 tcg_gen_add_i64(dest
, dest
, load_gpr(ctx
, a
->b
));
4053 dest
= do_ibranch_priv(ctx
, dest
);
4054 ctx
->iaq_j
= iaqe_next_absv(ctx
, dest
);
4056 return do_ibranch(ctx
, 0, false, a
->n
);
4059 static bool trans_bve(DisasContext
*ctx
, arg_bve
*a
)
4061 TCGv_i64 b
= load_gpr(ctx
, a
->b
);
4063 #ifndef CONFIG_USER_ONLY
4064 ctx
->iaq_j
.space
= space_select(ctx
, 0, b
);
4066 ctx
->iaq_j
.base
= do_ibranch_priv(ctx
, b
);
4067 ctx
->iaq_j
.disp
= 0;
4069 return do_ibranch(ctx
, a
->l
, false, a
->n
);
4072 static bool trans_nopbts(DisasContext
*ctx
, arg_nopbts
*a
)
4074 /* All branch target stack instructions implement as nop. */
4075 return ctx
->is_pa20
;
4082 static void gen_fcpy_f(TCGv_i32 dst
, TCGv_env unused
, TCGv_i32 src
)
4084 tcg_gen_mov_i32(dst
, src
);
4087 static bool trans_fid_f(DisasContext
*ctx
, arg_fid_f
*a
)
4092 ret
= 0x13080000000000ULL
; /* PA8700 (PCX-W2) */
4094 ret
= 0x0f080000000000ULL
; /* PA7300LC (PCX-L2) */
4098 save_frd(0, tcg_constant_i64(ret
));
4099 return nullify_end(ctx
);
4102 static bool trans_fcpy_f(DisasContext
*ctx
, arg_fclass01
*a
)
4104 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_fcpy_f
);
4107 static void gen_fcpy_d(TCGv_i64 dst
, TCGv_env unused
, TCGv_i64 src
)
4109 tcg_gen_mov_i64(dst
, src
);
4112 static bool trans_fcpy_d(DisasContext
*ctx
, arg_fclass01
*a
)
4114 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_fcpy_d
);
4117 static void gen_fabs_f(TCGv_i32 dst
, TCGv_env unused
, TCGv_i32 src
)
4119 tcg_gen_andi_i32(dst
, src
, INT32_MAX
);
4122 static bool trans_fabs_f(DisasContext
*ctx
, arg_fclass01
*a
)
4124 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_fabs_f
);
4127 static void gen_fabs_d(TCGv_i64 dst
, TCGv_env unused
, TCGv_i64 src
)
4129 tcg_gen_andi_i64(dst
, src
, INT64_MAX
);
4132 static bool trans_fabs_d(DisasContext
*ctx
, arg_fclass01
*a
)
4134 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_fabs_d
);
4137 static bool trans_fsqrt_f(DisasContext
*ctx
, arg_fclass01
*a
)
4139 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fsqrt_s
);
4142 static bool trans_fsqrt_d(DisasContext
*ctx
, arg_fclass01
*a
)
4144 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fsqrt_d
);
4147 static bool trans_frnd_f(DisasContext
*ctx
, arg_fclass01
*a
)
4149 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_frnd_s
);
4152 static bool trans_frnd_d(DisasContext
*ctx
, arg_fclass01
*a
)
4154 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_frnd_d
);
4157 static void gen_fneg_f(TCGv_i32 dst
, TCGv_env unused
, TCGv_i32 src
)
4159 tcg_gen_xori_i32(dst
, src
, INT32_MIN
);
4162 static bool trans_fneg_f(DisasContext
*ctx
, arg_fclass01
*a
)
4164 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_fneg_f
);
4167 static void gen_fneg_d(TCGv_i64 dst
, TCGv_env unused
, TCGv_i64 src
)
4169 tcg_gen_xori_i64(dst
, src
, INT64_MIN
);
4172 static bool trans_fneg_d(DisasContext
*ctx
, arg_fclass01
*a
)
4174 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_fneg_d
);
4177 static void gen_fnegabs_f(TCGv_i32 dst
, TCGv_env unused
, TCGv_i32 src
)
4179 tcg_gen_ori_i32(dst
, src
, INT32_MIN
);
4182 static bool trans_fnegabs_f(DisasContext
*ctx
, arg_fclass01
*a
)
4184 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_fnegabs_f
);
4187 static void gen_fnegabs_d(TCGv_i64 dst
, TCGv_env unused
, TCGv_i64 src
)
4189 tcg_gen_ori_i64(dst
, src
, INT64_MIN
);
4192 static bool trans_fnegabs_d(DisasContext
*ctx
, arg_fclass01
*a
)
4194 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_fnegabs_d
);
4201 static bool trans_fcnv_d_f(DisasContext
*ctx
, arg_fclass01
*a
)
4203 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_d_s
);
4206 static bool trans_fcnv_f_d(DisasContext
*ctx
, arg_fclass01
*a
)
4208 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_s_d
);
4211 static bool trans_fcnv_w_f(DisasContext
*ctx
, arg_fclass01
*a
)
4213 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_w_s
);
4216 static bool trans_fcnv_q_f(DisasContext
*ctx
, arg_fclass01
*a
)
4218 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_dw_s
);
4221 static bool trans_fcnv_w_d(DisasContext
*ctx
, arg_fclass01
*a
)
4223 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_w_d
);
4226 static bool trans_fcnv_q_d(DisasContext
*ctx
, arg_fclass01
*a
)
4228 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_dw_d
);
4231 static bool trans_fcnv_f_w(DisasContext
*ctx
, arg_fclass01
*a
)
4233 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_s_w
);
4236 static bool trans_fcnv_d_w(DisasContext
*ctx
, arg_fclass01
*a
)
4238 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_d_w
);
4241 static bool trans_fcnv_f_q(DisasContext
*ctx
, arg_fclass01
*a
)
4243 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_s_dw
);
4246 static bool trans_fcnv_d_q(DisasContext
*ctx
, arg_fclass01
*a
)
4248 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_d_dw
);
4251 static bool trans_fcnv_t_f_w(DisasContext
*ctx
, arg_fclass01
*a
)
4253 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_s_w
);
4256 static bool trans_fcnv_t_d_w(DisasContext
*ctx
, arg_fclass01
*a
)
4258 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_d_w
);
4261 static bool trans_fcnv_t_f_q(DisasContext
*ctx
, arg_fclass01
*a
)
4263 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_s_dw
);
4266 static bool trans_fcnv_t_d_q(DisasContext
*ctx
, arg_fclass01
*a
)
4268 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_d_dw
);
4271 static bool trans_fcnv_uw_f(DisasContext
*ctx
, arg_fclass01
*a
)
4273 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_uw_s
);
4276 static bool trans_fcnv_uq_f(DisasContext
*ctx
, arg_fclass01
*a
)
4278 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_udw_s
);
4281 static bool trans_fcnv_uw_d(DisasContext
*ctx
, arg_fclass01
*a
)
4283 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_uw_d
);
4286 static bool trans_fcnv_uq_d(DisasContext
*ctx
, arg_fclass01
*a
)
4288 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_udw_d
);
4291 static bool trans_fcnv_f_uw(DisasContext
*ctx
, arg_fclass01
*a
)
4293 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_s_uw
);
4296 static bool trans_fcnv_d_uw(DisasContext
*ctx
, arg_fclass01
*a
)
4298 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_d_uw
);
4301 static bool trans_fcnv_f_uq(DisasContext
*ctx
, arg_fclass01
*a
)
4303 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_s_udw
);
4306 static bool trans_fcnv_d_uq(DisasContext
*ctx
, arg_fclass01
*a
)
4308 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_d_udw
);
4311 static bool trans_fcnv_t_f_uw(DisasContext
*ctx
, arg_fclass01
*a
)
4313 return do_fop_wew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_s_uw
);
4316 static bool trans_fcnv_t_d_uw(DisasContext
*ctx
, arg_fclass01
*a
)
4318 return do_fop_wed(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_d_uw
);
4321 static bool trans_fcnv_t_f_uq(DisasContext
*ctx
, arg_fclass01
*a
)
4323 return do_fop_dew(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_s_udw
);
4326 static bool trans_fcnv_t_d_uq(DisasContext
*ctx
, arg_fclass01
*a
)
4328 return do_fop_ded(ctx
, a
->t
, a
->r
, gen_helper_fcnv_t_d_udw
);
4335 static bool trans_fcmp_f(DisasContext
*ctx
, arg_fclass2
*a
)
4337 TCGv_i32 ta
, tb
, tc
, ty
;
4341 ta
= load_frw0_i32(a
->r1
);
4342 tb
= load_frw0_i32(a
->r2
);
4343 ty
= tcg_constant_i32(a
->y
);
4344 tc
= tcg_constant_i32(a
->c
);
4346 gen_helper_fcmp_s(tcg_env
, ta
, tb
, ty
, tc
);
4348 return nullify_end(ctx
);
4351 static bool trans_fcmp_d(DisasContext
*ctx
, arg_fclass2
*a
)
4358 ta
= load_frd0(a
->r1
);
4359 tb
= load_frd0(a
->r2
);
4360 ty
= tcg_constant_i32(a
->y
);
4361 tc
= tcg_constant_i32(a
->c
);
4363 gen_helper_fcmp_d(tcg_env
, ta
, tb
, ty
, tc
);
4365 return nullify_end(ctx
);
4368 static bool trans_ftest(DisasContext
*ctx
, arg_ftest
*a
)
4370 TCGCond tc
= TCG_COND_TSTNE
;
4376 t
= tcg_temp_new_i64();
4377 tcg_gen_ld32u_i64(t
, tcg_env
, offsetof(CPUHPPAState
, fr0_shadow
));
4381 case 0: /* simple */
4382 mask
= R_FPSR_C_MASK
;
4385 tc
= TCG_COND_TSTEQ
;
4388 mask
= R_FPSR_C_MASK
| R_FPSR_CQ_MASK
;
4391 tc
= TCG_COND_TSTEQ
;
4394 mask
= R_FPSR_C_MASK
| R_FPSR_CQ0_6_MASK
;
4397 mask
= R_FPSR_C_MASK
| R_FPSR_CQ0_4_MASK
;
4400 mask
= R_FPSR_C_MASK
| R_FPSR_CQ0_2_MASK
;
4403 mask
= R_FPSR_C_MASK
| R_FPSR_CQ0_MASK
;
4410 unsigned cbit
= (a
->y
^ 1) - 1;
4411 mask
= R_FPSR_CA0_MASK
>> cbit
;
4414 ctx
->null_cond
= cond_make_ti(tc
, t
, mask
);
4415 return nullify_end(ctx
);
4422 static bool trans_fadd_f(DisasContext
*ctx
, arg_fclass3
*a
)
4424 return do_fop_weww(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fadd_s
);
4427 static bool trans_fadd_d(DisasContext
*ctx
, arg_fclass3
*a
)
4429 return do_fop_dedd(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fadd_d
);
4432 static bool trans_fsub_f(DisasContext
*ctx
, arg_fclass3
*a
)
4434 return do_fop_weww(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fsub_s
);
4437 static bool trans_fsub_d(DisasContext
*ctx
, arg_fclass3
*a
)
4439 return do_fop_dedd(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fsub_d
);
4442 static bool trans_fmpy_f(DisasContext
*ctx
, arg_fclass3
*a
)
4444 return do_fop_weww(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fmpy_s
);
4447 static bool trans_fmpy_d(DisasContext
*ctx
, arg_fclass3
*a
)
4449 return do_fop_dedd(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fmpy_d
);
4452 static bool trans_fdiv_f(DisasContext
*ctx
, arg_fclass3
*a
)
4454 return do_fop_weww(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fdiv_s
);
4457 static bool trans_fdiv_d(DisasContext
*ctx
, arg_fclass3
*a
)
4459 return do_fop_dedd(ctx
, a
->t
, a
->r1
, a
->r2
, gen_helper_fdiv_d
);
4462 static bool trans_xmpyu(DisasContext
*ctx
, arg_xmpyu
*a
)
4468 x
= load_frw0_i64(a
->r1
);
4469 y
= load_frw0_i64(a
->r2
);
4470 tcg_gen_mul_i64(x
, x
, y
);
4473 return nullify_end(ctx
);
4476 /* Convert the fmpyadd single-precision register encodings to standard. */
4477 static inline int fmpyadd_s_reg(unsigned r
)
4479 return (r
& 16) * 2 + 16 + (r
& 15);
4482 static bool do_fmpyadd_s(DisasContext
*ctx
, arg_mpyadd
*a
, bool is_sub
)
4484 int tm
= fmpyadd_s_reg(a
->tm
);
4485 int ra
= fmpyadd_s_reg(a
->ra
);
4486 int ta
= fmpyadd_s_reg(a
->ta
);
4487 int rm2
= fmpyadd_s_reg(a
->rm2
);
4488 int rm1
= fmpyadd_s_reg(a
->rm1
);
4492 do_fop_weww(ctx
, tm
, rm1
, rm2
, gen_helper_fmpy_s
);
4493 do_fop_weww(ctx
, ta
, ta
, ra
,
4494 is_sub
? gen_helper_fsub_s
: gen_helper_fadd_s
);
4496 return nullify_end(ctx
);
4499 static bool trans_fmpyadd_f(DisasContext
*ctx
, arg_mpyadd
*a
)
4501 return do_fmpyadd_s(ctx
, a
, false);
4504 static bool trans_fmpysub_f(DisasContext
*ctx
, arg_mpyadd
*a
)
4506 return do_fmpyadd_s(ctx
, a
, true);
4509 static bool do_fmpyadd_d(DisasContext
*ctx
, arg_mpyadd
*a
, bool is_sub
)
4513 do_fop_dedd(ctx
, a
->tm
, a
->rm1
, a
->rm2
, gen_helper_fmpy_d
);
4514 do_fop_dedd(ctx
, a
->ta
, a
->ta
, a
->ra
,
4515 is_sub
? gen_helper_fsub_d
: gen_helper_fadd_d
);
4517 return nullify_end(ctx
);
4520 static bool trans_fmpyadd_d(DisasContext
*ctx
, arg_mpyadd
*a
)
4522 return do_fmpyadd_d(ctx
, a
, false);
4525 static bool trans_fmpysub_d(DisasContext
*ctx
, arg_mpyadd
*a
)
4527 return do_fmpyadd_d(ctx
, a
, true);
4530 static bool trans_fmpyfadd_f(DisasContext
*ctx
, arg_fmpyfadd_f
*a
)
4535 x
= load_frw0_i32(a
->rm1
);
4536 y
= load_frw0_i32(a
->rm2
);
4537 z
= load_frw0_i32(a
->ra3
);
4540 gen_helper_fmpynfadd_s(x
, tcg_env
, x
, y
, z
);
4542 gen_helper_fmpyfadd_s(x
, tcg_env
, x
, y
, z
);
4545 save_frw_i32(a
->t
, x
);
4546 return nullify_end(ctx
);
4549 static bool trans_fmpyfadd_d(DisasContext
*ctx
, arg_fmpyfadd_d
*a
)
4554 x
= load_frd0(a
->rm1
);
4555 y
= load_frd0(a
->rm2
);
4556 z
= load_frd0(a
->ra3
);
4559 gen_helper_fmpynfadd_d(x
, tcg_env
, x
, y
, z
);
4561 gen_helper_fmpyfadd_d(x
, tcg_env
, x
, y
, z
);
4565 return nullify_end(ctx
);
4568 /* Emulate PDC BTLB, called by SeaBIOS-hppa */
4569 static bool trans_diag_btlb(DisasContext
*ctx
, arg_diag_btlb
*a
)
4571 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
4572 #ifndef CONFIG_USER_ONLY
4574 gen_helper_diag_btlb(tcg_env
);
4575 return nullify_end(ctx
);
4579 /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
4580 static bool trans_diag_cout(DisasContext
*ctx
, arg_diag_cout
*a
)
4582 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
4583 #ifndef CONFIG_USER_ONLY
4585 gen_helper_diag_console_output(tcg_env
);
4586 return nullify_end(ctx
);
4590 static bool trans_diag_getshadowregs_pa1(DisasContext
*ctx
, arg_empty
*a
)
4592 return !ctx
->is_pa20
&& do_getshadowregs(ctx
);
4595 static bool trans_diag_getshadowregs_pa2(DisasContext
*ctx
, arg_empty
*a
)
4597 return ctx
->is_pa20
&& do_getshadowregs(ctx
);
4600 static bool trans_diag_putshadowregs_pa1(DisasContext
*ctx
, arg_empty
*a
)
4602 return !ctx
->is_pa20
&& do_putshadowregs(ctx
);
4605 static bool trans_diag_putshadowregs_pa2(DisasContext
*ctx
, arg_empty
*a
)
4607 return ctx
->is_pa20
&& do_putshadowregs(ctx
);
4610 static bool trans_diag_unimp(DisasContext
*ctx
, arg_diag_unimp
*a
)
4612 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR
);
4613 qemu_log_mask(LOG_UNIMP
, "DIAG opcode 0x%04x ignored\n", a
->i
);
4617 static void hppa_tr_init_disas_context(DisasContextBase
*dcbase
, CPUState
*cs
)
4619 DisasContext
*ctx
= container_of(dcbase
, DisasContext
, base
);
4624 ctx
->tb_flags
= ctx
->base
.tb
->flags
;
4625 ctx
->is_pa20
= hppa_is_pa20(cpu_env(cs
));
4626 ctx
->psw_xb
= ctx
->tb_flags
& (PSW_X
| PSW_B
);
4628 #ifdef CONFIG_USER_ONLY
4629 ctx
->privilege
= PRIV_USER
;
4630 ctx
->mmu_idx
= MMU_USER_IDX
;
4631 ctx
->unalign
= (ctx
->tb_flags
& TB_FLAG_UNALIGN
? MO_UNALN
: MO_ALIGN
);
4633 ctx
->privilege
= (ctx
->tb_flags
>> TB_FLAG_PRIV_SHIFT
) & 3;
4634 ctx
->mmu_idx
= (ctx
->tb_flags
& PSW_D
4635 ? PRIV_P_TO_MMU_IDX(ctx
->privilege
, ctx
->tb_flags
& PSW_P
)
4636 : ctx
->tb_flags
& PSW_W
? MMU_ABS_W_IDX
: MMU_ABS_IDX
);
4639 cs_base
= ctx
->base
.tb
->cs_base
;
4640 ctx
->iaoq_first
= ctx
->base
.pc_first
+ ctx
->privilege
;
4642 if (unlikely(cs_base
& CS_BASE_DIFFSPACE
)) {
4643 ctx
->iaq_b
.space
= cpu_iasq_b
;
4644 ctx
->iaq_b
.base
= cpu_iaoq_b
;
4645 } else if (unlikely(cs_base
& CS_BASE_DIFFPAGE
)) {
4646 ctx
->iaq_b
.base
= cpu_iaoq_b
;
4648 uint64_t iaoq_f_pgofs
= ctx
->iaoq_first
& ~TARGET_PAGE_MASK
;
4649 uint64_t iaoq_b_pgofs
= cs_base
& ~TARGET_PAGE_MASK
;
4650 ctx
->iaq_b
.disp
= iaoq_b_pgofs
- iaoq_f_pgofs
;
4653 ctx
->zero
= tcg_constant_i64(0);
4655 /* Bound the number of instructions by those left on the page. */
4656 bound
= -(ctx
->base
.pc_first
| TARGET_PAGE_MASK
) / 4;
4657 ctx
->base
.max_insns
= MIN(ctx
->base
.max_insns
, bound
);
4660 static void hppa_tr_tb_start(DisasContextBase
*dcbase
, CPUState
*cs
)
4662 DisasContext
*ctx
= container_of(dcbase
, DisasContext
, base
);
4664 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
4665 ctx
->null_cond
= cond_make_f();
4666 ctx
->psw_n_nonzero
= false;
4667 if (ctx
->tb_flags
& PSW_N
) {
4668 ctx
->null_cond
.c
= TCG_COND_ALWAYS
;
4669 ctx
->psw_n_nonzero
= true;
4671 ctx
->null_lab
= NULL
;
4674 static void hppa_tr_insn_start(DisasContextBase
*dcbase
, CPUState
*cs
)
4676 DisasContext
*ctx
= container_of(dcbase
, DisasContext
, base
);
4677 uint64_t iaoq_f
, iaoq_b
;
4680 tcg_debug_assert(!iaqe_variable(&ctx
->iaq_f
));
4682 iaoq_f
= ctx
->iaoq_first
+ ctx
->iaq_f
.disp
;
4683 if (iaqe_variable(&ctx
->iaq_b
)) {
4686 iaoq_b
= ctx
->iaoq_first
+ ctx
->iaq_b
.disp
;
4687 diff
= iaoq_b
- iaoq_f
;
4688 /* Direct branches can only produce a 24-bit displacement. */
4689 tcg_debug_assert(diff
== (int32_t)diff
);
4690 tcg_debug_assert(diff
!= INT32_MIN
);
4693 tcg_gen_insn_start(iaoq_f
& ~TARGET_PAGE_MASK
, diff
, 0);
4694 ctx
->insn_start_updated
= false;
4697 static void hppa_tr_translate_insn(DisasContextBase
*dcbase
, CPUState
*cs
)
4699 DisasContext
*ctx
= container_of(dcbase
, DisasContext
, base
);
4700 CPUHPPAState
*env
= cpu_env(cs
);
4703 /* Execute one insn. */
4704 #ifdef CONFIG_USER_ONLY
4705 if (ctx
->base
.pc_next
< TARGET_PAGE_SIZE
) {
4707 ret
= ctx
->base
.is_jmp
;
4708 assert(ret
!= DISAS_NEXT
);
4712 /* Always fetch the insn, even if nullified, so that we check
4713 the page permissions for execute. */
4714 uint32_t insn
= translator_ldl(env
, &ctx
->base
, ctx
->base
.pc_next
);
4717 * Set up the IA queue for the next insn.
4718 * This will be overwritten by a branch.
4721 memset(&ctx
->iaq_j
, 0, sizeof(ctx
->iaq_j
));
4722 ctx
->psw_b_next
= false;
4724 if (unlikely(ctx
->null_cond
.c
== TCG_COND_ALWAYS
)) {
4725 ctx
->null_cond
.c
= TCG_COND_NEVER
;
4729 if (!decode(ctx
, insn
)) {
4732 ret
= ctx
->base
.is_jmp
;
4733 assert(ctx
->null_lab
== NULL
);
4736 if (ret
!= DISAS_NORETURN
) {
4737 set_psw_xb(ctx
, ctx
->psw_b_next
? PSW_B
: 0);
4741 /* If the TranslationBlock must end, do so. */
4742 ctx
->base
.pc_next
+= 4;
4743 if (ret
!= DISAS_NEXT
) {
4746 /* Note this also detects a priority change. */
4747 if (iaqe_variable(&ctx
->iaq_b
)
4748 || ctx
->iaq_b
.disp
!= ctx
->iaq_f
.disp
+ 4) {
4749 ctx
->base
.is_jmp
= DISAS_IAQ_N_STALE
;
4754 * Advance the insn queue.
4755 * The only exit now is DISAS_TOO_MANY from the translator loop.
4757 ctx
->iaq_f
.disp
= ctx
->iaq_b
.disp
;
4759 ctx
->iaq_b
.disp
+= 4;
4763 * If IAQ_Next is variable in any way, we need to copy into the
4764 * IAQ_Back globals, in case the next insn raises an exception.
4766 if (ctx
->iaq_n
->base
) {
4767 copy_iaoq_entry(ctx
, cpu_iaoq_b
, ctx
->iaq_n
);
4768 ctx
->iaq_b
.base
= cpu_iaoq_b
;
4769 ctx
->iaq_b
.disp
= 0;
4771 ctx
->iaq_b
.disp
= ctx
->iaq_n
->disp
;
4773 if (ctx
->iaq_n
->space
) {
4774 tcg_gen_mov_i64(cpu_iasq_b
, ctx
->iaq_n
->space
);
4775 ctx
->iaq_b
.space
= cpu_iasq_b
;
4779 static void hppa_tr_tb_stop(DisasContextBase
*dcbase
, CPUState
*cs
)
4781 DisasContext
*ctx
= container_of(dcbase
, DisasContext
, base
);
4782 DisasJumpType is_jmp
= ctx
->base
.is_jmp
;
4783 /* Assume the insn queue has not been advanced. */
4784 DisasIAQE
*f
= &ctx
->iaq_b
;
4785 DisasIAQE
*b
= ctx
->iaq_n
;
4788 case DISAS_NORETURN
:
4790 case DISAS_TOO_MANY
:
4791 /* The insn queue has not been advanced. */
4795 case DISAS_IAQ_N_STALE
:
4796 if (use_goto_tb(ctx
, f
, b
)
4797 && (ctx
->null_cond
.c
== TCG_COND_NEVER
4798 || ctx
->null_cond
.c
== TCG_COND_ALWAYS
)) {
4799 nullify_set(ctx
, ctx
->null_cond
.c
== TCG_COND_ALWAYS
);
4800 gen_goto_tb(ctx
, 0, f
, b
);
4804 case DISAS_IAQ_N_STALE_EXIT
:
4805 install_iaq_entries(ctx
, f
, b
);
4807 if (is_jmp
== DISAS_IAQ_N_STALE_EXIT
) {
4808 tcg_gen_exit_tb(NULL
, 0);
4812 case DISAS_IAQ_N_UPDATED
:
4813 tcg_gen_lookup_and_goto_ptr();
4816 tcg_gen_exit_tb(NULL
, 0);
4819 g_assert_not_reached();
4822 for (DisasDelayException
*e
= ctx
->delay_excp_list
; e
; e
= e
->next
) {
4823 gen_set_label(e
->lab
);
4824 if (e
->set_n
>= 0) {
4825 tcg_gen_movi_i64(cpu_psw_n
, e
->set_n
);
4828 tcg_gen_st_i64(tcg_constant_i64(e
->insn
), tcg_env
,
4829 offsetof(CPUHPPAState
, cr
[CR_IIR
]));
4831 install_iaq_entries(ctx
, &e
->iaq_f
, &e
->iaq_b
);
4832 gen_excp_1(e
->excp
);
4836 #ifdef CONFIG_USER_ONLY
4837 static bool hppa_tr_disas_log(const DisasContextBase
*dcbase
,
4838 CPUState
*cs
, FILE *logfile
)
4840 target_ulong pc
= dcbase
->pc_first
;
4844 fprintf(logfile
, "IN:\n0x00000000: (null)\n");
4847 fprintf(logfile
, "IN:\n0x000000b0: light-weight-syscall\n");
4850 fprintf(logfile
, "IN:\n0x000000e0: set-thread-pointer-syscall\n");
4853 fprintf(logfile
, "IN:\n0x00000100: syscall\n");
4860 static const TranslatorOps hppa_tr_ops
= {
4861 .init_disas_context
= hppa_tr_init_disas_context
,
4862 .tb_start
= hppa_tr_tb_start
,
4863 .insn_start
= hppa_tr_insn_start
,
4864 .translate_insn
= hppa_tr_translate_insn
,
4865 .tb_stop
= hppa_tr_tb_stop
,
4866 #ifdef CONFIG_USER_ONLY
4867 .disas_log
= hppa_tr_disas_log
,
4871 void gen_intermediate_code(CPUState
*cs
, TranslationBlock
*tb
, int *max_insns
,
4872 vaddr pc
, void *host_pc
)
4874 DisasContext ctx
= { };
4875 translator_loop(cs
, tb
, max_insns
, pc
, host_pc
, &hppa_tr_ops
, &ctx
.base
);