xref: /openbmc/qemu/target/hppa/translate.c (revision 8340f5341e7562c0328703f1baa9af88ead4d775)
161766fe9SRichard Henderson /*
261766fe9SRichard Henderson  * HPPA emulation cpu translation for qemu.
361766fe9SRichard Henderson  *
461766fe9SRichard Henderson  * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
561766fe9SRichard Henderson  *
661766fe9SRichard Henderson  * This library is free software; you can redistribute it and/or
761766fe9SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
861766fe9SRichard Henderson  * License as published by the Free Software Foundation; either
961766fe9SRichard Henderson  * version 2 of the License, or (at your option) any later version.
1061766fe9SRichard Henderson  *
1161766fe9SRichard Henderson  * This library is distributed in the hope that it will be useful,
1261766fe9SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1361766fe9SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1461766fe9SRichard Henderson  * Lesser General Public License for more details.
1561766fe9SRichard Henderson  *
1661766fe9SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
1761766fe9SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1861766fe9SRichard Henderson  */
1961766fe9SRichard Henderson 
2061766fe9SRichard Henderson #include "qemu/osdep.h"
2161766fe9SRichard Henderson #include "cpu.h"
2261766fe9SRichard Henderson #include "disas/disas.h"
2361766fe9SRichard Henderson #include "qemu/host-utils.h"
2461766fe9SRichard Henderson #include "exec/exec-all.h"
2561766fe9SRichard Henderson #include "tcg-op.h"
2661766fe9SRichard Henderson #include "exec/cpu_ldst.h"
2761766fe9SRichard Henderson #include "exec/helper-proto.h"
2861766fe9SRichard Henderson #include "exec/helper-gen.h"
29869051eaSRichard Henderson #include "exec/translator.h"
3061766fe9SRichard Henderson #include "trace-tcg.h"
3161766fe9SRichard Henderson #include "exec/log.h"
3261766fe9SRichard Henderson 
33eaa3783bSRichard Henderson /* Since we have a distinction between register size and address size,
34eaa3783bSRichard Henderson    we need to redefine all of these.  */
35eaa3783bSRichard Henderson 
36eaa3783bSRichard Henderson #undef TCGv
37eaa3783bSRichard Henderson #undef tcg_temp_new
38eaa3783bSRichard Henderson #undef tcg_global_reg_new
39eaa3783bSRichard Henderson #undef tcg_global_mem_new
40eaa3783bSRichard Henderson #undef tcg_temp_local_new
41eaa3783bSRichard Henderson #undef tcg_temp_free
42eaa3783bSRichard Henderson 
43eaa3783bSRichard Henderson #if TARGET_LONG_BITS == 64
44eaa3783bSRichard Henderson #define TCGv_tl              TCGv_i64
45eaa3783bSRichard Henderson #define tcg_temp_new_tl      tcg_temp_new_i64
46eaa3783bSRichard Henderson #define tcg_temp_free_tl     tcg_temp_free_i64
47eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64
48eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl  tcg_gen_mov_i64
49eaa3783bSRichard Henderson #else
50eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl  tcg_gen_extu_i32_i64
51eaa3783bSRichard Henderson #endif
52eaa3783bSRichard Henderson #else
53eaa3783bSRichard Henderson #define TCGv_tl              TCGv_i32
54eaa3783bSRichard Henderson #define tcg_temp_new_tl      tcg_temp_new_i32
55eaa3783bSRichard Henderson #define tcg_temp_free_tl     tcg_temp_free_i32
56eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl  tcg_gen_mov_i32
57eaa3783bSRichard Henderson #endif
58eaa3783bSRichard Henderson 
59eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64
60eaa3783bSRichard Henderson #define TCGv_reg             TCGv_i64
61eaa3783bSRichard Henderson 
62eaa3783bSRichard Henderson #define tcg_temp_new         tcg_temp_new_i64
63eaa3783bSRichard Henderson #define tcg_global_reg_new   tcg_global_reg_new_i64
64eaa3783bSRichard Henderson #define tcg_global_mem_new   tcg_global_mem_new_i64
65eaa3783bSRichard Henderson #define tcg_temp_local_new   tcg_temp_local_new_i64
66eaa3783bSRichard Henderson #define tcg_temp_free        tcg_temp_free_i64
67eaa3783bSRichard Henderson 
68eaa3783bSRichard Henderson #define tcg_gen_movi_reg     tcg_gen_movi_i64
69eaa3783bSRichard Henderson #define tcg_gen_mov_reg      tcg_gen_mov_i64
70eaa3783bSRichard Henderson #define tcg_gen_ld8u_reg     tcg_gen_ld8u_i64
71eaa3783bSRichard Henderson #define tcg_gen_ld8s_reg     tcg_gen_ld8s_i64
72eaa3783bSRichard Henderson #define tcg_gen_ld16u_reg    tcg_gen_ld16u_i64
73eaa3783bSRichard Henderson #define tcg_gen_ld16s_reg    tcg_gen_ld16s_i64
74eaa3783bSRichard Henderson #define tcg_gen_ld32u_reg    tcg_gen_ld32u_i64
75eaa3783bSRichard Henderson #define tcg_gen_ld32s_reg    tcg_gen_ld32s_i64
76eaa3783bSRichard Henderson #define tcg_gen_ld_reg       tcg_gen_ld_i64
77eaa3783bSRichard Henderson #define tcg_gen_st8_reg      tcg_gen_st8_i64
78eaa3783bSRichard Henderson #define tcg_gen_st16_reg     tcg_gen_st16_i64
79eaa3783bSRichard Henderson #define tcg_gen_st32_reg     tcg_gen_st32_i64
80eaa3783bSRichard Henderson #define tcg_gen_st_reg       tcg_gen_st_i64
81eaa3783bSRichard Henderson #define tcg_gen_add_reg      tcg_gen_add_i64
82eaa3783bSRichard Henderson #define tcg_gen_addi_reg     tcg_gen_addi_i64
83eaa3783bSRichard Henderson #define tcg_gen_sub_reg      tcg_gen_sub_i64
84eaa3783bSRichard Henderson #define tcg_gen_neg_reg      tcg_gen_neg_i64
85eaa3783bSRichard Henderson #define tcg_gen_subfi_reg    tcg_gen_subfi_i64
86eaa3783bSRichard Henderson #define tcg_gen_subi_reg     tcg_gen_subi_i64
87eaa3783bSRichard Henderson #define tcg_gen_and_reg      tcg_gen_and_i64
88eaa3783bSRichard Henderson #define tcg_gen_andi_reg     tcg_gen_andi_i64
89eaa3783bSRichard Henderson #define tcg_gen_or_reg       tcg_gen_or_i64
90eaa3783bSRichard Henderson #define tcg_gen_ori_reg      tcg_gen_ori_i64
91eaa3783bSRichard Henderson #define tcg_gen_xor_reg      tcg_gen_xor_i64
92eaa3783bSRichard Henderson #define tcg_gen_xori_reg     tcg_gen_xori_i64
93eaa3783bSRichard Henderson #define tcg_gen_not_reg      tcg_gen_not_i64
94eaa3783bSRichard Henderson #define tcg_gen_shl_reg      tcg_gen_shl_i64
95eaa3783bSRichard Henderson #define tcg_gen_shli_reg     tcg_gen_shli_i64
96eaa3783bSRichard Henderson #define tcg_gen_shr_reg      tcg_gen_shr_i64
97eaa3783bSRichard Henderson #define tcg_gen_shri_reg     tcg_gen_shri_i64
98eaa3783bSRichard Henderson #define tcg_gen_sar_reg      tcg_gen_sar_i64
99eaa3783bSRichard Henderson #define tcg_gen_sari_reg     tcg_gen_sari_i64
100eaa3783bSRichard Henderson #define tcg_gen_brcond_reg   tcg_gen_brcond_i64
101eaa3783bSRichard Henderson #define tcg_gen_brcondi_reg  tcg_gen_brcondi_i64
102eaa3783bSRichard Henderson #define tcg_gen_setcond_reg  tcg_gen_setcond_i64
103eaa3783bSRichard Henderson #define tcg_gen_setcondi_reg tcg_gen_setcondi_i64
104eaa3783bSRichard Henderson #define tcg_gen_mul_reg      tcg_gen_mul_i64
105eaa3783bSRichard Henderson #define tcg_gen_muli_reg     tcg_gen_muli_i64
106eaa3783bSRichard Henderson #define tcg_gen_div_reg      tcg_gen_div_i64
107eaa3783bSRichard Henderson #define tcg_gen_rem_reg      tcg_gen_rem_i64
108eaa3783bSRichard Henderson #define tcg_gen_divu_reg     tcg_gen_divu_i64
109eaa3783bSRichard Henderson #define tcg_gen_remu_reg     tcg_gen_remu_i64
110eaa3783bSRichard Henderson #define tcg_gen_discard_reg  tcg_gen_discard_i64
111eaa3783bSRichard Henderson #define tcg_gen_trunc_reg_i32 tcg_gen_extrl_i64_i32
112eaa3783bSRichard Henderson #define tcg_gen_trunc_i64_reg tcg_gen_mov_i64
113eaa3783bSRichard Henderson #define tcg_gen_extu_i32_reg tcg_gen_extu_i32_i64
114eaa3783bSRichard Henderson #define tcg_gen_ext_i32_reg  tcg_gen_ext_i32_i64
115eaa3783bSRichard Henderson #define tcg_gen_extu_reg_i64 tcg_gen_mov_i64
116eaa3783bSRichard Henderson #define tcg_gen_ext_reg_i64  tcg_gen_mov_i64
117eaa3783bSRichard Henderson #define tcg_gen_ext8u_reg    tcg_gen_ext8u_i64
118eaa3783bSRichard Henderson #define tcg_gen_ext8s_reg    tcg_gen_ext8s_i64
119eaa3783bSRichard Henderson #define tcg_gen_ext16u_reg   tcg_gen_ext16u_i64
120eaa3783bSRichard Henderson #define tcg_gen_ext16s_reg   tcg_gen_ext16s_i64
121eaa3783bSRichard Henderson #define tcg_gen_ext32u_reg   tcg_gen_ext32u_i64
122eaa3783bSRichard Henderson #define tcg_gen_ext32s_reg   tcg_gen_ext32s_i64
123eaa3783bSRichard Henderson #define tcg_gen_bswap16_reg  tcg_gen_bswap16_i64
124eaa3783bSRichard Henderson #define tcg_gen_bswap32_reg  tcg_gen_bswap32_i64
125eaa3783bSRichard Henderson #define tcg_gen_bswap64_reg  tcg_gen_bswap64_i64
126eaa3783bSRichard Henderson #define tcg_gen_concat_reg_i64 tcg_gen_concat32_i64
127eaa3783bSRichard Henderson #define tcg_gen_andc_reg     tcg_gen_andc_i64
128eaa3783bSRichard Henderson #define tcg_gen_eqv_reg      tcg_gen_eqv_i64
129eaa3783bSRichard Henderson #define tcg_gen_nand_reg     tcg_gen_nand_i64
130eaa3783bSRichard Henderson #define tcg_gen_nor_reg      tcg_gen_nor_i64
131eaa3783bSRichard Henderson #define tcg_gen_orc_reg      tcg_gen_orc_i64
132eaa3783bSRichard Henderson #define tcg_gen_clz_reg      tcg_gen_clz_i64
133eaa3783bSRichard Henderson #define tcg_gen_ctz_reg      tcg_gen_ctz_i64
134eaa3783bSRichard Henderson #define tcg_gen_clzi_reg     tcg_gen_clzi_i64
135eaa3783bSRichard Henderson #define tcg_gen_ctzi_reg     tcg_gen_ctzi_i64
136eaa3783bSRichard Henderson #define tcg_gen_clrsb_reg    tcg_gen_clrsb_i64
137eaa3783bSRichard Henderson #define tcg_gen_ctpop_reg    tcg_gen_ctpop_i64
138eaa3783bSRichard Henderson #define tcg_gen_rotl_reg     tcg_gen_rotl_i64
139eaa3783bSRichard Henderson #define tcg_gen_rotli_reg    tcg_gen_rotli_i64
140eaa3783bSRichard Henderson #define tcg_gen_rotr_reg     tcg_gen_rotr_i64
141eaa3783bSRichard Henderson #define tcg_gen_rotri_reg    tcg_gen_rotri_i64
142eaa3783bSRichard Henderson #define tcg_gen_deposit_reg  tcg_gen_deposit_i64
143eaa3783bSRichard Henderson #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i64
144eaa3783bSRichard Henderson #define tcg_gen_extract_reg  tcg_gen_extract_i64
145eaa3783bSRichard Henderson #define tcg_gen_sextract_reg tcg_gen_sextract_i64
146eaa3783bSRichard Henderson #define tcg_const_reg        tcg_const_i64
147eaa3783bSRichard Henderson #define tcg_const_local_reg  tcg_const_local_i64
148eaa3783bSRichard Henderson #define tcg_gen_movcond_reg  tcg_gen_movcond_i64
149eaa3783bSRichard Henderson #define tcg_gen_add2_reg     tcg_gen_add2_i64
150eaa3783bSRichard Henderson #define tcg_gen_sub2_reg     tcg_gen_sub2_i64
151eaa3783bSRichard Henderson #define tcg_gen_qemu_ld_reg  tcg_gen_qemu_ld_i64
152eaa3783bSRichard Henderson #define tcg_gen_qemu_st_reg  tcg_gen_qemu_st_i64
153eaa3783bSRichard Henderson #define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i64
1545bfa8034SRichard Henderson #define tcg_gen_trunc_reg_ptr   tcg_gen_trunc_i64_ptr
155eaa3783bSRichard Henderson #else
156eaa3783bSRichard Henderson #define TCGv_reg             TCGv_i32
157eaa3783bSRichard Henderson #define tcg_temp_new         tcg_temp_new_i32
158eaa3783bSRichard Henderson #define tcg_global_reg_new   tcg_global_reg_new_i32
159eaa3783bSRichard Henderson #define tcg_global_mem_new   tcg_global_mem_new_i32
160eaa3783bSRichard Henderson #define tcg_temp_local_new   tcg_temp_local_new_i32
161eaa3783bSRichard Henderson #define tcg_temp_free        tcg_temp_free_i32
162eaa3783bSRichard Henderson 
163eaa3783bSRichard Henderson #define tcg_gen_movi_reg     tcg_gen_movi_i32
164eaa3783bSRichard Henderson #define tcg_gen_mov_reg      tcg_gen_mov_i32
165eaa3783bSRichard Henderson #define tcg_gen_ld8u_reg     tcg_gen_ld8u_i32
166eaa3783bSRichard Henderson #define tcg_gen_ld8s_reg     tcg_gen_ld8s_i32
167eaa3783bSRichard Henderson #define tcg_gen_ld16u_reg    tcg_gen_ld16u_i32
168eaa3783bSRichard Henderson #define tcg_gen_ld16s_reg    tcg_gen_ld16s_i32
169eaa3783bSRichard Henderson #define tcg_gen_ld32u_reg    tcg_gen_ld_i32
170eaa3783bSRichard Henderson #define tcg_gen_ld32s_reg    tcg_gen_ld_i32
171eaa3783bSRichard Henderson #define tcg_gen_ld_reg       tcg_gen_ld_i32
172eaa3783bSRichard Henderson #define tcg_gen_st8_reg      tcg_gen_st8_i32
173eaa3783bSRichard Henderson #define tcg_gen_st16_reg     tcg_gen_st16_i32
174eaa3783bSRichard Henderson #define tcg_gen_st32_reg     tcg_gen_st32_i32
175eaa3783bSRichard Henderson #define tcg_gen_st_reg       tcg_gen_st_i32
176eaa3783bSRichard Henderson #define tcg_gen_add_reg      tcg_gen_add_i32
177eaa3783bSRichard Henderson #define tcg_gen_addi_reg     tcg_gen_addi_i32
178eaa3783bSRichard Henderson #define tcg_gen_sub_reg      tcg_gen_sub_i32
179eaa3783bSRichard Henderson #define tcg_gen_neg_reg      tcg_gen_neg_i32
180eaa3783bSRichard Henderson #define tcg_gen_subfi_reg    tcg_gen_subfi_i32
181eaa3783bSRichard Henderson #define tcg_gen_subi_reg     tcg_gen_subi_i32
182eaa3783bSRichard Henderson #define tcg_gen_and_reg      tcg_gen_and_i32
183eaa3783bSRichard Henderson #define tcg_gen_andi_reg     tcg_gen_andi_i32
184eaa3783bSRichard Henderson #define tcg_gen_or_reg       tcg_gen_or_i32
185eaa3783bSRichard Henderson #define tcg_gen_ori_reg      tcg_gen_ori_i32
186eaa3783bSRichard Henderson #define tcg_gen_xor_reg      tcg_gen_xor_i32
187eaa3783bSRichard Henderson #define tcg_gen_xori_reg     tcg_gen_xori_i32
188eaa3783bSRichard Henderson #define tcg_gen_not_reg      tcg_gen_not_i32
189eaa3783bSRichard Henderson #define tcg_gen_shl_reg      tcg_gen_shl_i32
190eaa3783bSRichard Henderson #define tcg_gen_shli_reg     tcg_gen_shli_i32
191eaa3783bSRichard Henderson #define tcg_gen_shr_reg      tcg_gen_shr_i32
192eaa3783bSRichard Henderson #define tcg_gen_shri_reg     tcg_gen_shri_i32
193eaa3783bSRichard Henderson #define tcg_gen_sar_reg      tcg_gen_sar_i32
194eaa3783bSRichard Henderson #define tcg_gen_sari_reg     tcg_gen_sari_i32
195eaa3783bSRichard Henderson #define tcg_gen_brcond_reg   tcg_gen_brcond_i32
196eaa3783bSRichard Henderson #define tcg_gen_brcondi_reg  tcg_gen_brcondi_i32
197eaa3783bSRichard Henderson #define tcg_gen_setcond_reg  tcg_gen_setcond_i32
198eaa3783bSRichard Henderson #define tcg_gen_setcondi_reg tcg_gen_setcondi_i32
199eaa3783bSRichard Henderson #define tcg_gen_mul_reg      tcg_gen_mul_i32
200eaa3783bSRichard Henderson #define tcg_gen_muli_reg     tcg_gen_muli_i32
201eaa3783bSRichard Henderson #define tcg_gen_div_reg      tcg_gen_div_i32
202eaa3783bSRichard Henderson #define tcg_gen_rem_reg      tcg_gen_rem_i32
203eaa3783bSRichard Henderson #define tcg_gen_divu_reg     tcg_gen_divu_i32
204eaa3783bSRichard Henderson #define tcg_gen_remu_reg     tcg_gen_remu_i32
205eaa3783bSRichard Henderson #define tcg_gen_discard_reg  tcg_gen_discard_i32
206eaa3783bSRichard Henderson #define tcg_gen_trunc_reg_i32 tcg_gen_mov_i32
207eaa3783bSRichard Henderson #define tcg_gen_trunc_i64_reg tcg_gen_extrl_i64_i32
208eaa3783bSRichard Henderson #define tcg_gen_extu_i32_reg tcg_gen_mov_i32
209eaa3783bSRichard Henderson #define tcg_gen_ext_i32_reg  tcg_gen_mov_i32
210eaa3783bSRichard Henderson #define tcg_gen_extu_reg_i64 tcg_gen_extu_i32_i64
211eaa3783bSRichard Henderson #define tcg_gen_ext_reg_i64  tcg_gen_ext_i32_i64
212eaa3783bSRichard Henderson #define tcg_gen_ext8u_reg    tcg_gen_ext8u_i32
213eaa3783bSRichard Henderson #define tcg_gen_ext8s_reg    tcg_gen_ext8s_i32
214eaa3783bSRichard Henderson #define tcg_gen_ext16u_reg   tcg_gen_ext16u_i32
215eaa3783bSRichard Henderson #define tcg_gen_ext16s_reg   tcg_gen_ext16s_i32
216eaa3783bSRichard Henderson #define tcg_gen_ext32u_reg   tcg_gen_mov_i32
217eaa3783bSRichard Henderson #define tcg_gen_ext32s_reg   tcg_gen_mov_i32
218eaa3783bSRichard Henderson #define tcg_gen_bswap16_reg  tcg_gen_bswap16_i32
219eaa3783bSRichard Henderson #define tcg_gen_bswap32_reg  tcg_gen_bswap32_i32
220eaa3783bSRichard Henderson #define tcg_gen_concat_reg_i64 tcg_gen_concat_i32_i64
221eaa3783bSRichard Henderson #define tcg_gen_andc_reg     tcg_gen_andc_i32
222eaa3783bSRichard Henderson #define tcg_gen_eqv_reg      tcg_gen_eqv_i32
223eaa3783bSRichard Henderson #define tcg_gen_nand_reg     tcg_gen_nand_i32
224eaa3783bSRichard Henderson #define tcg_gen_nor_reg      tcg_gen_nor_i32
225eaa3783bSRichard Henderson #define tcg_gen_orc_reg      tcg_gen_orc_i32
226eaa3783bSRichard Henderson #define tcg_gen_clz_reg      tcg_gen_clz_i32
227eaa3783bSRichard Henderson #define tcg_gen_ctz_reg      tcg_gen_ctz_i32
228eaa3783bSRichard Henderson #define tcg_gen_clzi_reg     tcg_gen_clzi_i32
229eaa3783bSRichard Henderson #define tcg_gen_ctzi_reg     tcg_gen_ctzi_i32
230eaa3783bSRichard Henderson #define tcg_gen_clrsb_reg    tcg_gen_clrsb_i32
231eaa3783bSRichard Henderson #define tcg_gen_ctpop_reg    tcg_gen_ctpop_i32
232eaa3783bSRichard Henderson #define tcg_gen_rotl_reg     tcg_gen_rotl_i32
233eaa3783bSRichard Henderson #define tcg_gen_rotli_reg    tcg_gen_rotli_i32
234eaa3783bSRichard Henderson #define tcg_gen_rotr_reg     tcg_gen_rotr_i32
235eaa3783bSRichard Henderson #define tcg_gen_rotri_reg    tcg_gen_rotri_i32
236eaa3783bSRichard Henderson #define tcg_gen_deposit_reg  tcg_gen_deposit_i32
237eaa3783bSRichard Henderson #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i32
238eaa3783bSRichard Henderson #define tcg_gen_extract_reg  tcg_gen_extract_i32
239eaa3783bSRichard Henderson #define tcg_gen_sextract_reg tcg_gen_sextract_i32
240eaa3783bSRichard Henderson #define tcg_const_reg        tcg_const_i32
241eaa3783bSRichard Henderson #define tcg_const_local_reg  tcg_const_local_i32
242eaa3783bSRichard Henderson #define tcg_gen_movcond_reg  tcg_gen_movcond_i32
243eaa3783bSRichard Henderson #define tcg_gen_add2_reg     tcg_gen_add2_i32
244eaa3783bSRichard Henderson #define tcg_gen_sub2_reg     tcg_gen_sub2_i32
245eaa3783bSRichard Henderson #define tcg_gen_qemu_ld_reg  tcg_gen_qemu_ld_i32
246eaa3783bSRichard Henderson #define tcg_gen_qemu_st_reg  tcg_gen_qemu_st_i32
247eaa3783bSRichard Henderson #define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i32
2485bfa8034SRichard Henderson #define tcg_gen_trunc_reg_ptr   tcg_gen_ext_i32_ptr
249eaa3783bSRichard Henderson #endif /* TARGET_REGISTER_BITS */
250eaa3783bSRichard Henderson 
25161766fe9SRichard Henderson typedef struct DisasCond {
25261766fe9SRichard Henderson     TCGCond c;
253eaa3783bSRichard Henderson     TCGv_reg a0, a1;
25461766fe9SRichard Henderson     bool a0_is_n;
25561766fe9SRichard Henderson     bool a1_is_0;
25661766fe9SRichard Henderson } DisasCond;
25761766fe9SRichard Henderson 
25861766fe9SRichard Henderson typedef struct DisasContext {
259d01a3625SRichard Henderson     DisasContextBase base;
26061766fe9SRichard Henderson     CPUState *cs;
26161766fe9SRichard Henderson 
262eaa3783bSRichard Henderson     target_ureg iaoq_f;
263eaa3783bSRichard Henderson     target_ureg iaoq_b;
264eaa3783bSRichard Henderson     target_ureg iaoq_n;
265eaa3783bSRichard Henderson     TCGv_reg iaoq_n_var;
26661766fe9SRichard Henderson 
26786f8d05fSRichard Henderson     int ntempr, ntempl;
2685eecd37aSRichard Henderson     TCGv_reg tempr[8];
26986f8d05fSRichard Henderson     TCGv_tl  templ[4];
27061766fe9SRichard Henderson 
27161766fe9SRichard Henderson     DisasCond null_cond;
27261766fe9SRichard Henderson     TCGLabel *null_lab;
27361766fe9SRichard Henderson 
2741a19da0dSRichard Henderson     uint32_t insn;
275494737b7SRichard Henderson     uint32_t tb_flags;
2763d68ee7bSRichard Henderson     int mmu_idx;
2773d68ee7bSRichard Henderson     int privilege;
27861766fe9SRichard Henderson     bool psw_n_nonzero;
27961766fe9SRichard Henderson } DisasContext;
28061766fe9SRichard Henderson 
281e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
282e36f27efSRichard Henderson static int expand_sm_imm(int val)
283e36f27efSRichard Henderson {
284e36f27efSRichard Henderson     if (val & PSW_SM_E) {
285e36f27efSRichard Henderson         val = (val & ~PSW_SM_E) | PSW_E;
286e36f27efSRichard Henderson     }
287e36f27efSRichard Henderson     if (val & PSW_SM_W) {
288e36f27efSRichard Henderson         val = (val & ~PSW_SM_W) | PSW_W;
289e36f27efSRichard Henderson     }
290e36f27efSRichard Henderson     return val;
291e36f27efSRichard Henderson }
292e36f27efSRichard Henderson 
293deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
294deee69a1SRichard Henderson static int expand_sr3x(int val)
295deee69a1SRichard Henderson {
296deee69a1SRichard Henderson     return ~val;
297deee69a1SRichard Henderson }
298deee69a1SRichard Henderson 
2991cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
3001cd012a5SRichard Henderson    we use for the final M.  */
3011cd012a5SRichard Henderson static int ma_to_m(int val)
3021cd012a5SRichard Henderson {
3031cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
3041cd012a5SRichard Henderson }
3051cd012a5SRichard Henderson 
30601afb7beSRichard Henderson /* Used for branch targets.  */
30701afb7beSRichard Henderson static int expand_shl2(int val)
30801afb7beSRichard Henderson {
30901afb7beSRichard Henderson     return val << 2;
31001afb7beSRichard Henderson }
31101afb7beSRichard Henderson 
31201afb7beSRichard Henderson 
31340f9f908SRichard Henderson /* Include the auto-generated decoder.  */
31440f9f908SRichard Henderson #include "decode.inc.c"
31540f9f908SRichard Henderson 
31661766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
31761766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
318869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
31961766fe9SRichard Henderson 
32061766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
32161766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
322869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
32361766fe9SRichard Henderson 
324e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
325e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
326e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
327e1b5a5edSRichard Henderson 
32861766fe9SRichard Henderson typedef struct DisasInsn {
32961766fe9SRichard Henderson     uint32_t insn, mask;
33031234768SRichard Henderson     bool (*trans)(DisasContext *ctx, uint32_t insn,
33161766fe9SRichard Henderson                   const struct DisasInsn *f);
332b2167459SRichard Henderson     union {
333eaa3783bSRichard Henderson         void (*ttt)(TCGv_reg, TCGv_reg, TCGv_reg);
334eff235ebSPaolo Bonzini         void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
335eff235ebSPaolo Bonzini         void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
336eff235ebSPaolo Bonzini         void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
337eff235ebSPaolo Bonzini         void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
338eff235ebSPaolo Bonzini         void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
339eff235ebSPaolo Bonzini         void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
340eff235ebSPaolo Bonzini     } f;
34161766fe9SRichard Henderson } DisasInsn;
34261766fe9SRichard Henderson 
34361766fe9SRichard Henderson /* global register indexes */
344eaa3783bSRichard Henderson static TCGv_reg cpu_gr[32];
34533423472SRichard Henderson static TCGv_i64 cpu_sr[4];
346494737b7SRichard Henderson static TCGv_i64 cpu_srH;
347eaa3783bSRichard Henderson static TCGv_reg cpu_iaoq_f;
348eaa3783bSRichard Henderson static TCGv_reg cpu_iaoq_b;
349c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
350c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
351eaa3783bSRichard Henderson static TCGv_reg cpu_sar;
352eaa3783bSRichard Henderson static TCGv_reg cpu_psw_n;
353eaa3783bSRichard Henderson static TCGv_reg cpu_psw_v;
354eaa3783bSRichard Henderson static TCGv_reg cpu_psw_cb;
355eaa3783bSRichard Henderson static TCGv_reg cpu_psw_cb_msb;
35661766fe9SRichard Henderson 
35761766fe9SRichard Henderson #include "exec/gen-icount.h"
35861766fe9SRichard Henderson 
35961766fe9SRichard Henderson void hppa_translate_init(void)
36061766fe9SRichard Henderson {
36161766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
36261766fe9SRichard Henderson 
363eaa3783bSRichard Henderson     typedef struct { TCGv_reg *var; const char *name; int ofs; } GlobalVar;
36461766fe9SRichard Henderson     static const GlobalVar vars[] = {
36535136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
36661766fe9SRichard Henderson         DEF_VAR(psw_n),
36761766fe9SRichard Henderson         DEF_VAR(psw_v),
36861766fe9SRichard Henderson         DEF_VAR(psw_cb),
36961766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
37061766fe9SRichard Henderson         DEF_VAR(iaoq_f),
37161766fe9SRichard Henderson         DEF_VAR(iaoq_b),
37261766fe9SRichard Henderson     };
37361766fe9SRichard Henderson 
37461766fe9SRichard Henderson #undef DEF_VAR
37561766fe9SRichard Henderson 
37661766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
37761766fe9SRichard Henderson     static const char gr_names[32][4] = {
37861766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
37961766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
38061766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
38161766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
38261766fe9SRichard Henderson     };
38333423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
384494737b7SRichard Henderson     static const char sr_names[5][4] = {
385494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
38633423472SRichard Henderson     };
38761766fe9SRichard Henderson 
38861766fe9SRichard Henderson     int i;
38961766fe9SRichard Henderson 
390f764718dSRichard Henderson     cpu_gr[0] = NULL;
39161766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
39261766fe9SRichard Henderson         cpu_gr[i] = tcg_global_mem_new(cpu_env,
39361766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
39461766fe9SRichard Henderson                                        gr_names[i]);
39561766fe9SRichard Henderson     }
39633423472SRichard Henderson     for (i = 0; i < 4; i++) {
39733423472SRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(cpu_env,
39833423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
39933423472SRichard Henderson                                            sr_names[i]);
40033423472SRichard Henderson     }
401494737b7SRichard Henderson     cpu_srH = tcg_global_mem_new_i64(cpu_env,
402494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
403494737b7SRichard Henderson                                      sr_names[4]);
40461766fe9SRichard Henderson 
40561766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
40661766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
40761766fe9SRichard Henderson         *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
40861766fe9SRichard Henderson     }
409c301f34eSRichard Henderson 
410c301f34eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(cpu_env,
411c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
412c301f34eSRichard Henderson                                         "iasq_f");
413c301f34eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(cpu_env,
414c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
415c301f34eSRichard Henderson                                         "iasq_b");
41661766fe9SRichard Henderson }
41761766fe9SRichard Henderson 
418129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
419129e9cc3SRichard Henderson {
420f764718dSRichard Henderson     return (DisasCond){
421f764718dSRichard Henderson         .c = TCG_COND_NEVER,
422f764718dSRichard Henderson         .a0 = NULL,
423f764718dSRichard Henderson         .a1 = NULL,
424f764718dSRichard Henderson     };
425129e9cc3SRichard Henderson }
426129e9cc3SRichard Henderson 
427129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
428129e9cc3SRichard Henderson {
429f764718dSRichard Henderson     return (DisasCond){
430f764718dSRichard Henderson         .c = TCG_COND_NE,
431f764718dSRichard Henderson         .a0 = cpu_psw_n,
432f764718dSRichard Henderson         .a0_is_n = true,
433f764718dSRichard Henderson         .a1 = NULL,
434f764718dSRichard Henderson         .a1_is_0 = true
435f764718dSRichard Henderson     };
436129e9cc3SRichard Henderson }
437129e9cc3SRichard Henderson 
438eaa3783bSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_reg a0)
439129e9cc3SRichard Henderson {
440f764718dSRichard Henderson     DisasCond r = { .c = c, .a1 = NULL, .a1_is_0 = true };
441129e9cc3SRichard Henderson 
442129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
443129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
444eaa3783bSRichard Henderson     tcg_gen_mov_reg(r.a0, a0);
445129e9cc3SRichard Henderson 
446129e9cc3SRichard Henderson     return r;
447129e9cc3SRichard Henderson }
448129e9cc3SRichard Henderson 
449eaa3783bSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_reg a0, TCGv_reg a1)
450129e9cc3SRichard Henderson {
451129e9cc3SRichard Henderson     DisasCond r = { .c = c };
452129e9cc3SRichard Henderson 
453129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
454129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
455eaa3783bSRichard Henderson     tcg_gen_mov_reg(r.a0, a0);
456129e9cc3SRichard Henderson     r.a1 = tcg_temp_new();
457eaa3783bSRichard Henderson     tcg_gen_mov_reg(r.a1, a1);
458129e9cc3SRichard Henderson 
459129e9cc3SRichard Henderson     return r;
460129e9cc3SRichard Henderson }
461129e9cc3SRichard Henderson 
462129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond)
463129e9cc3SRichard Henderson {
464129e9cc3SRichard Henderson     if (cond->a1_is_0) {
465129e9cc3SRichard Henderson         cond->a1_is_0 = false;
466eaa3783bSRichard Henderson         cond->a1 = tcg_const_reg(0);
467129e9cc3SRichard Henderson     }
468129e9cc3SRichard Henderson }
469129e9cc3SRichard Henderson 
470129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
471129e9cc3SRichard Henderson {
472129e9cc3SRichard Henderson     switch (cond->c) {
473129e9cc3SRichard Henderson     default:
474129e9cc3SRichard Henderson         if (!cond->a0_is_n) {
475129e9cc3SRichard Henderson             tcg_temp_free(cond->a0);
476129e9cc3SRichard Henderson         }
477129e9cc3SRichard Henderson         if (!cond->a1_is_0) {
478129e9cc3SRichard Henderson             tcg_temp_free(cond->a1);
479129e9cc3SRichard Henderson         }
480129e9cc3SRichard Henderson         cond->a0_is_n = false;
481129e9cc3SRichard Henderson         cond->a1_is_0 = false;
482f764718dSRichard Henderson         cond->a0 = NULL;
483f764718dSRichard Henderson         cond->a1 = NULL;
484129e9cc3SRichard Henderson         /* fallthru */
485129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
486129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
487129e9cc3SRichard Henderson         break;
488129e9cc3SRichard Henderson     case TCG_COND_NEVER:
489129e9cc3SRichard Henderson         break;
490129e9cc3SRichard Henderson     }
491129e9cc3SRichard Henderson }
492129e9cc3SRichard Henderson 
493eaa3783bSRichard Henderson static TCGv_reg get_temp(DisasContext *ctx)
49461766fe9SRichard Henderson {
49586f8d05fSRichard Henderson     unsigned i = ctx->ntempr++;
49686f8d05fSRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->tempr));
49786f8d05fSRichard Henderson     return ctx->tempr[i] = tcg_temp_new();
49861766fe9SRichard Henderson }
49961766fe9SRichard Henderson 
50086f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
50186f8d05fSRichard Henderson static TCGv_tl get_temp_tl(DisasContext *ctx)
50286f8d05fSRichard Henderson {
50386f8d05fSRichard Henderson     unsigned i = ctx->ntempl++;
50486f8d05fSRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->templ));
50586f8d05fSRichard Henderson     return ctx->templ[i] = tcg_temp_new_tl();
50686f8d05fSRichard Henderson }
50786f8d05fSRichard Henderson #endif
50886f8d05fSRichard Henderson 
509eaa3783bSRichard Henderson static TCGv_reg load_const(DisasContext *ctx, target_sreg v)
51061766fe9SRichard Henderson {
511eaa3783bSRichard Henderson     TCGv_reg t = get_temp(ctx);
512eaa3783bSRichard Henderson     tcg_gen_movi_reg(t, v);
51361766fe9SRichard Henderson     return t;
51461766fe9SRichard Henderson }
51561766fe9SRichard Henderson 
516eaa3783bSRichard Henderson static TCGv_reg load_gpr(DisasContext *ctx, unsigned reg)
51761766fe9SRichard Henderson {
51861766fe9SRichard Henderson     if (reg == 0) {
519eaa3783bSRichard Henderson         TCGv_reg t = get_temp(ctx);
520eaa3783bSRichard Henderson         tcg_gen_movi_reg(t, 0);
52161766fe9SRichard Henderson         return t;
52261766fe9SRichard Henderson     } else {
52361766fe9SRichard Henderson         return cpu_gr[reg];
52461766fe9SRichard Henderson     }
52561766fe9SRichard Henderson }
52661766fe9SRichard Henderson 
527eaa3783bSRichard Henderson static TCGv_reg dest_gpr(DisasContext *ctx, unsigned reg)
52861766fe9SRichard Henderson {
529129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
53061766fe9SRichard Henderson         return get_temp(ctx);
53161766fe9SRichard Henderson     } else {
53261766fe9SRichard Henderson         return cpu_gr[reg];
53361766fe9SRichard Henderson     }
53461766fe9SRichard Henderson }
53561766fe9SRichard Henderson 
536eaa3783bSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_reg dest, TCGv_reg t)
537129e9cc3SRichard Henderson {
538129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
539129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
540eaa3783bSRichard Henderson         tcg_gen_movcond_reg(ctx->null_cond.c, dest, ctx->null_cond.a0,
541129e9cc3SRichard Henderson                            ctx->null_cond.a1, dest, t);
542129e9cc3SRichard Henderson     } else {
543eaa3783bSRichard Henderson         tcg_gen_mov_reg(dest, t);
544129e9cc3SRichard Henderson     }
545129e9cc3SRichard Henderson }
546129e9cc3SRichard Henderson 
547eaa3783bSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t)
548129e9cc3SRichard Henderson {
549129e9cc3SRichard Henderson     if (reg != 0) {
550129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
551129e9cc3SRichard Henderson     }
552129e9cc3SRichard Henderson }
553129e9cc3SRichard Henderson 
55496d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
55596d6407fSRichard Henderson # define HI_OFS  0
55696d6407fSRichard Henderson # define LO_OFS  4
55796d6407fSRichard Henderson #else
55896d6407fSRichard Henderson # define HI_OFS  4
55996d6407fSRichard Henderson # define LO_OFS  0
56096d6407fSRichard Henderson #endif
56196d6407fSRichard Henderson 
56296d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
56396d6407fSRichard Henderson {
56496d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
56596d6407fSRichard Henderson     tcg_gen_ld_i32(ret, cpu_env,
56696d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
56796d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
56896d6407fSRichard Henderson     return ret;
56996d6407fSRichard Henderson }
57096d6407fSRichard Henderson 
571ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
572ebe9383cSRichard Henderson {
573ebe9383cSRichard Henderson     if (rt == 0) {
574ebe9383cSRichard Henderson         return tcg_const_i32(0);
575ebe9383cSRichard Henderson     } else {
576ebe9383cSRichard Henderson         return load_frw_i32(rt);
577ebe9383cSRichard Henderson     }
578ebe9383cSRichard Henderson }
579ebe9383cSRichard Henderson 
580ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
581ebe9383cSRichard Henderson {
582ebe9383cSRichard Henderson     if (rt == 0) {
583ebe9383cSRichard Henderson         return tcg_const_i64(0);
584ebe9383cSRichard Henderson     } else {
585ebe9383cSRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
586ebe9383cSRichard Henderson         tcg_gen_ld32u_i64(ret, cpu_env,
587ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
588ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
589ebe9383cSRichard Henderson         return ret;
590ebe9383cSRichard Henderson     }
591ebe9383cSRichard Henderson }
592ebe9383cSRichard Henderson 
59396d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
59496d6407fSRichard Henderson {
59596d6407fSRichard Henderson     tcg_gen_st_i32(val, cpu_env,
59696d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
59796d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
59896d6407fSRichard Henderson }
59996d6407fSRichard Henderson 
60096d6407fSRichard Henderson #undef HI_OFS
60196d6407fSRichard Henderson #undef LO_OFS
60296d6407fSRichard Henderson 
60396d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
60496d6407fSRichard Henderson {
60596d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
60696d6407fSRichard Henderson     tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
60796d6407fSRichard Henderson     return ret;
60896d6407fSRichard Henderson }
60996d6407fSRichard Henderson 
610ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
611ebe9383cSRichard Henderson {
612ebe9383cSRichard Henderson     if (rt == 0) {
613ebe9383cSRichard Henderson         return tcg_const_i64(0);
614ebe9383cSRichard Henderson     } else {
615ebe9383cSRichard Henderson         return load_frd(rt);
616ebe9383cSRichard Henderson     }
617ebe9383cSRichard Henderson }
618ebe9383cSRichard Henderson 
61996d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
62096d6407fSRichard Henderson {
62196d6407fSRichard Henderson     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
62296d6407fSRichard Henderson }
62396d6407fSRichard Henderson 
62433423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
62533423472SRichard Henderson {
62633423472SRichard Henderson #ifdef CONFIG_USER_ONLY
62733423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
62833423472SRichard Henderson #else
62933423472SRichard Henderson     if (reg < 4) {
63033423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
631494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
632494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
63333423472SRichard Henderson     } else {
63433423472SRichard Henderson         tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUHPPAState, sr[reg]));
63533423472SRichard Henderson     }
63633423472SRichard Henderson #endif
63733423472SRichard Henderson }
63833423472SRichard Henderson 
639129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
640129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
641129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
642129e9cc3SRichard Henderson {
643129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
644129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
645129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
646129e9cc3SRichard Henderson 
647129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
648129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
649129e9cc3SRichard Henderson 
650129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
651129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
652129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
653129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
654eaa3783bSRichard Henderson             tcg_gen_mov_reg(ctx->null_cond.a0, cpu_psw_n);
655129e9cc3SRichard Henderson         }
656129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
657129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
658129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
659129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
660129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
661eaa3783bSRichard Henderson             tcg_gen_movi_reg(cpu_psw_n, 0);
662129e9cc3SRichard Henderson         }
663129e9cc3SRichard Henderson 
664eaa3783bSRichard Henderson         tcg_gen_brcond_reg(ctx->null_cond.c, ctx->null_cond.a0,
665129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
666129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
667129e9cc3SRichard Henderson     }
668129e9cc3SRichard Henderson }
669129e9cc3SRichard Henderson 
670129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
671129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
672129e9cc3SRichard Henderson {
673129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
674129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
675eaa3783bSRichard Henderson             tcg_gen_movi_reg(cpu_psw_n, 0);
676129e9cc3SRichard Henderson         }
677129e9cc3SRichard Henderson         return;
678129e9cc3SRichard Henderson     }
679129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
680129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
681eaa3783bSRichard Henderson         tcg_gen_setcond_reg(ctx->null_cond.c, cpu_psw_n,
682129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
683129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
684129e9cc3SRichard Henderson     }
685129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
686129e9cc3SRichard Henderson }
687129e9cc3SRichard Henderson 
688129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
689129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
690129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
691129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
692129e9cc3SRichard Henderson {
693129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
694eaa3783bSRichard Henderson         tcg_gen_movi_reg(cpu_psw_n, x);
695129e9cc3SRichard Henderson     }
696129e9cc3SRichard Henderson }
697129e9cc3SRichard Henderson 
698129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
69940f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
70040f9f908SRichard Henderson    it may be tail-called from a translate function.  */
70131234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
702129e9cc3SRichard Henderson {
703129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
70431234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
705129e9cc3SRichard Henderson 
706f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
707f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
708f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
709f49b3537SRichard Henderson 
710129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
711129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
712129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
713129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
71431234768SRichard Henderson         return true;
715129e9cc3SRichard Henderson     }
716129e9cc3SRichard Henderson     ctx->null_lab = NULL;
717129e9cc3SRichard Henderson 
718129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
719129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
720129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
721129e9cc3SRichard Henderson         gen_set_label(null_lab);
722129e9cc3SRichard Henderson     } else {
723129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
724129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
725129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
726129e9cc3SRichard Henderson            label we have the proper value in place.  */
727129e9cc3SRichard Henderson         nullify_save(ctx);
728129e9cc3SRichard Henderson         gen_set_label(null_lab);
729129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
730129e9cc3SRichard Henderson     }
731869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
73231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
733129e9cc3SRichard Henderson     }
73431234768SRichard Henderson     return true;
735129e9cc3SRichard Henderson }
736129e9cc3SRichard Henderson 
737eaa3783bSRichard Henderson static void copy_iaoq_entry(TCGv_reg dest, target_ureg ival, TCGv_reg vval)
73861766fe9SRichard Henderson {
73961766fe9SRichard Henderson     if (unlikely(ival == -1)) {
740eaa3783bSRichard Henderson         tcg_gen_mov_reg(dest, vval);
74161766fe9SRichard Henderson     } else {
742eaa3783bSRichard Henderson         tcg_gen_movi_reg(dest, ival);
74361766fe9SRichard Henderson     }
74461766fe9SRichard Henderson }
74561766fe9SRichard Henderson 
746eaa3783bSRichard Henderson static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp)
74761766fe9SRichard Henderson {
74861766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
74961766fe9SRichard Henderson }
75061766fe9SRichard Henderson 
75161766fe9SRichard Henderson static void gen_excp_1(int exception)
75261766fe9SRichard Henderson {
75361766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
75461766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
75561766fe9SRichard Henderson     tcg_temp_free_i32(t);
75661766fe9SRichard Henderson }
75761766fe9SRichard Henderson 
75831234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
75961766fe9SRichard Henderson {
76061766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
76161766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
762129e9cc3SRichard Henderson     nullify_save(ctx);
76361766fe9SRichard Henderson     gen_excp_1(exception);
76431234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
76561766fe9SRichard Henderson }
76661766fe9SRichard Henderson 
76731234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
7681a19da0dSRichard Henderson {
76931234768SRichard Henderson     TCGv_reg tmp;
77031234768SRichard Henderson 
77131234768SRichard Henderson     nullify_over(ctx);
77231234768SRichard Henderson     tmp = tcg_const_reg(ctx->insn);
7731a19da0dSRichard Henderson     tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[CR_IIR]));
7741a19da0dSRichard Henderson     tcg_temp_free(tmp);
77531234768SRichard Henderson     gen_excp(ctx, exc);
77631234768SRichard Henderson     return nullify_end(ctx);
7771a19da0dSRichard Henderson }
7781a19da0dSRichard Henderson 
77931234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
78061766fe9SRichard Henderson {
78131234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
78261766fe9SRichard Henderson }
78361766fe9SRichard Henderson 
78440f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
78540f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
78640f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
78740f9f908SRichard Henderson #else
788e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
789e1b5a5edSRichard Henderson     do {                                     \
790e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
79131234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
792e1b5a5edSRichard Henderson         }                                    \
793e1b5a5edSRichard Henderson     } while (0)
79440f9f908SRichard Henderson #endif
795e1b5a5edSRichard Henderson 
796eaa3783bSRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
79761766fe9SRichard Henderson {
79861766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
79931234768SRichard Henderson     if ((tb_cflags(ctx->base.tb) & CF_LAST_IO)
80031234768SRichard Henderson         || ctx->base.singlestep_enabled) {
80161766fe9SRichard Henderson         return false;
80261766fe9SRichard Henderson     }
80361766fe9SRichard Henderson     return true;
80461766fe9SRichard Henderson }
80561766fe9SRichard Henderson 
806129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
807129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
808129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
809129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
810129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
811129e9cc3SRichard Henderson {
812129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
813129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
814129e9cc3SRichard Henderson }
815129e9cc3SRichard Henderson 
81661766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
817eaa3783bSRichard Henderson                         target_ureg f, target_ureg b)
81861766fe9SRichard Henderson {
81961766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
82061766fe9SRichard Henderson         tcg_gen_goto_tb(which);
821eaa3783bSRichard Henderson         tcg_gen_movi_reg(cpu_iaoq_f, f);
822eaa3783bSRichard Henderson         tcg_gen_movi_reg(cpu_iaoq_b, b);
82307ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
82461766fe9SRichard Henderson     } else {
82561766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
82661766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
827d01a3625SRichard Henderson         if (ctx->base.singlestep_enabled) {
82861766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
82961766fe9SRichard Henderson         } else {
8307f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
83161766fe9SRichard Henderson         }
83261766fe9SRichard Henderson     }
83361766fe9SRichard Henderson }
83461766fe9SRichard Henderson 
835b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
836b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
837eaa3783bSRichard Henderson static target_sreg low_sextract(uint32_t val, int pos, int len)
838b2167459SRichard Henderson {
839eaa3783bSRichard Henderson     target_ureg x = -(target_ureg)extract32(val, pos, 1);
840b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
841b2167459SRichard Henderson     return x;
842b2167459SRichard Henderson }
843b2167459SRichard Henderson 
844ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn)
845ebe9383cSRichard Henderson {
846ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 6, 1);
847ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 0, 5);
848ebe9383cSRichard Henderson     return r1 * 32 + r0;
849ebe9383cSRichard Henderson }
850ebe9383cSRichard Henderson 
851ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn)
852ebe9383cSRichard Henderson {
853ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 7, 1);
854ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 21, 5);
855ebe9383cSRichard Henderson     return r1 * 32 + r0;
856ebe9383cSRichard Henderson }
857ebe9383cSRichard Henderson 
858ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn)
859ebe9383cSRichard Henderson {
860ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 12, 1);
861ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 16, 5);
862ebe9383cSRichard Henderson     return r1 * 32 + r0;
863ebe9383cSRichard Henderson }
864ebe9383cSRichard Henderson 
865ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn)
866ebe9383cSRichard Henderson {
867ebe9383cSRichard Henderson     unsigned r2 = extract32(insn, 8, 1);
868ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 13, 3);
869ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 9, 2);
870ebe9383cSRichard Henderson     return r2 * 32 + r1 * 4 + r0;
871ebe9383cSRichard Henderson }
872ebe9383cSRichard Henderson 
873c603e14aSRichard Henderson static inline unsigned assemble_sr3(uint32_t insn)
87433423472SRichard Henderson {
87533423472SRichard Henderson     unsigned s2 = extract32(insn, 13, 1);
87633423472SRichard Henderson     unsigned s0 = extract32(insn, 14, 2);
87733423472SRichard Henderson     return s2 * 4 + s0;
87833423472SRichard Henderson }
87933423472SRichard Henderson 
880eaa3783bSRichard Henderson static target_sreg assemble_16(uint32_t insn)
881b2167459SRichard Henderson {
882b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
883b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
884b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
885b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
886b2167459SRichard Henderson }
887b2167459SRichard Henderson 
888eaa3783bSRichard Henderson static target_sreg assemble_16a(uint32_t insn)
88996d6407fSRichard Henderson {
89096d6407fSRichard Henderson     /* Take the name from PA2.0, which produces a 14-bit shifted number
89196d6407fSRichard Henderson        only with wide mode; otherwise a 12-bit shifted number.  Since we
89296d6407fSRichard Henderson        don't implement wide mode, this is always the 12-bit number.  */
893eaa3783bSRichard Henderson     target_ureg x = -(target_ureg)(insn & 1);
89496d6407fSRichard Henderson     x = (x << 11) | extract32(insn, 2, 11);
89596d6407fSRichard Henderson     return x << 2;
89696d6407fSRichard Henderson }
89796d6407fSRichard Henderson 
898eaa3783bSRichard Henderson static target_sreg assemble_21(uint32_t insn)
899b2167459SRichard Henderson {
900eaa3783bSRichard Henderson     target_ureg x = -(target_ureg)(insn & 1);
901b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
902b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
903b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
904b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
905b2167459SRichard Henderson     return x << 11;
906b2167459SRichard Henderson }
907b2167459SRichard Henderson 
908b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
909b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
910b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
911b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
912b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
913b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
914b2167459SRichard Henderson 
915eaa3783bSRichard Henderson static DisasCond do_cond(unsigned cf, TCGv_reg res,
916eaa3783bSRichard Henderson                          TCGv_reg cb_msb, TCGv_reg sv)
917b2167459SRichard Henderson {
918b2167459SRichard Henderson     DisasCond cond;
919eaa3783bSRichard Henderson     TCGv_reg tmp;
920b2167459SRichard Henderson 
921b2167459SRichard Henderson     switch (cf >> 1) {
922b2167459SRichard Henderson     case 0: /* Never / TR */
923b2167459SRichard Henderson         cond = cond_make_f();
924b2167459SRichard Henderson         break;
925b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
926b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
927b2167459SRichard Henderson         break;
928b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
929b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
930b2167459SRichard Henderson         break;
931b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
932b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
933b2167459SRichard Henderson         break;
934b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
935b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
936b2167459SRichard Henderson         break;
937b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
938b2167459SRichard Henderson         tmp = tcg_temp_new();
939eaa3783bSRichard Henderson         tcg_gen_neg_reg(tmp, cb_msb);
940eaa3783bSRichard Henderson         tcg_gen_and_reg(tmp, tmp, res);
941b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
942b2167459SRichard Henderson         tcg_temp_free(tmp);
943b2167459SRichard Henderson         break;
944b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
945b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
946b2167459SRichard Henderson         break;
947b2167459SRichard Henderson     case 7: /* OD / EV */
948b2167459SRichard Henderson         tmp = tcg_temp_new();
949eaa3783bSRichard Henderson         tcg_gen_andi_reg(tmp, res, 1);
950b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
951b2167459SRichard Henderson         tcg_temp_free(tmp);
952b2167459SRichard Henderson         break;
953b2167459SRichard Henderson     default:
954b2167459SRichard Henderson         g_assert_not_reached();
955b2167459SRichard Henderson     }
956b2167459SRichard Henderson     if (cf & 1) {
957b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
958b2167459SRichard Henderson     }
959b2167459SRichard Henderson 
960b2167459SRichard Henderson     return cond;
961b2167459SRichard Henderson }
962b2167459SRichard Henderson 
963b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
964b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
965b2167459SRichard Henderson    deleted as unused.  */
966b2167459SRichard Henderson 
967eaa3783bSRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv_reg res,
968eaa3783bSRichard Henderson                              TCGv_reg in1, TCGv_reg in2, TCGv_reg sv)
969b2167459SRichard Henderson {
970b2167459SRichard Henderson     DisasCond cond;
971b2167459SRichard Henderson 
972b2167459SRichard Henderson     switch (cf >> 1) {
973b2167459SRichard Henderson     case 1: /* = / <> */
974b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
975b2167459SRichard Henderson         break;
976b2167459SRichard Henderson     case 2: /* < / >= */
977b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
978b2167459SRichard Henderson         break;
979b2167459SRichard Henderson     case 3: /* <= / > */
980b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
981b2167459SRichard Henderson         break;
982b2167459SRichard Henderson     case 4: /* << / >>= */
983b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
984b2167459SRichard Henderson         break;
985b2167459SRichard Henderson     case 5: /* <<= / >> */
986b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
987b2167459SRichard Henderson         break;
988b2167459SRichard Henderson     default:
989b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
990b2167459SRichard Henderson     }
991b2167459SRichard Henderson     if (cf & 1) {
992b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
993b2167459SRichard Henderson     }
994b2167459SRichard Henderson 
995b2167459SRichard Henderson     return cond;
996b2167459SRichard Henderson }
997b2167459SRichard Henderson 
998b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
999b2167459SRichard Henderson    computed, and use of them is undefined.  */
1000b2167459SRichard Henderson 
1001eaa3783bSRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv_reg res)
1002b2167459SRichard Henderson {
1003b2167459SRichard Henderson     switch (cf >> 1) {
1004b2167459SRichard Henderson     case 4: case 5: case 6:
1005b2167459SRichard Henderson         cf &= 1;
1006b2167459SRichard Henderson         break;
1007b2167459SRichard Henderson     }
1008b2167459SRichard Henderson     return do_cond(cf, res, res, res);
1009b2167459SRichard Henderson }
1010b2167459SRichard Henderson 
101198cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
101298cd9ca7SRichard Henderson 
1013eaa3783bSRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv_reg res)
101498cd9ca7SRichard Henderson {
101598cd9ca7SRichard Henderson     unsigned c, f;
101698cd9ca7SRichard Henderson 
101798cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
101898cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
101998cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
102098cd9ca7SRichard Henderson     c = orig & 3;
102198cd9ca7SRichard Henderson     if (c == 3) {
102298cd9ca7SRichard Henderson         c = 7;
102398cd9ca7SRichard Henderson     }
102498cd9ca7SRichard Henderson     f = (orig & 4) / 4;
102598cd9ca7SRichard Henderson 
102698cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
102798cd9ca7SRichard Henderson }
102898cd9ca7SRichard Henderson 
1029b2167459SRichard Henderson /* Similar, but for unit conditions.  */
1030b2167459SRichard Henderson 
1031eaa3783bSRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
1032eaa3783bSRichard Henderson                               TCGv_reg in1, TCGv_reg in2)
1033b2167459SRichard Henderson {
1034b2167459SRichard Henderson     DisasCond cond;
1035eaa3783bSRichard Henderson     TCGv_reg tmp, cb = NULL;
1036b2167459SRichard Henderson 
1037b2167459SRichard Henderson     if (cf & 8) {
1038b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
1039b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
1040b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
1041b2167459SRichard Henderson          */
1042b2167459SRichard Henderson         cb = tcg_temp_new();
1043b2167459SRichard Henderson         tmp = tcg_temp_new();
1044eaa3783bSRichard Henderson         tcg_gen_or_reg(cb, in1, in2);
1045eaa3783bSRichard Henderson         tcg_gen_and_reg(tmp, in1, in2);
1046eaa3783bSRichard Henderson         tcg_gen_andc_reg(cb, cb, res);
1047eaa3783bSRichard Henderson         tcg_gen_or_reg(cb, cb, tmp);
1048b2167459SRichard Henderson         tcg_temp_free(tmp);
1049b2167459SRichard Henderson     }
1050b2167459SRichard Henderson 
1051b2167459SRichard Henderson     switch (cf >> 1) {
1052b2167459SRichard Henderson     case 0: /* never / TR */
1053b2167459SRichard Henderson     case 1: /* undefined */
1054b2167459SRichard Henderson     case 5: /* undefined */
1055b2167459SRichard Henderson         cond = cond_make_f();
1056b2167459SRichard Henderson         break;
1057b2167459SRichard Henderson 
1058b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
1059b2167459SRichard Henderson         /* See hasless(v,1) from
1060b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1061b2167459SRichard Henderson          */
1062b2167459SRichard Henderson         tmp = tcg_temp_new();
1063eaa3783bSRichard Henderson         tcg_gen_subi_reg(tmp, res, 0x01010101u);
1064eaa3783bSRichard Henderson         tcg_gen_andc_reg(tmp, tmp, res);
1065eaa3783bSRichard Henderson         tcg_gen_andi_reg(tmp, tmp, 0x80808080u);
1066b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
1067b2167459SRichard Henderson         tcg_temp_free(tmp);
1068b2167459SRichard Henderson         break;
1069b2167459SRichard Henderson 
1070b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
1071b2167459SRichard Henderson         tmp = tcg_temp_new();
1072eaa3783bSRichard Henderson         tcg_gen_subi_reg(tmp, res, 0x00010001u);
1073eaa3783bSRichard Henderson         tcg_gen_andc_reg(tmp, tmp, res);
1074eaa3783bSRichard Henderson         tcg_gen_andi_reg(tmp, tmp, 0x80008000u);
1075b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
1076b2167459SRichard Henderson         tcg_temp_free(tmp);
1077b2167459SRichard Henderson         break;
1078b2167459SRichard Henderson 
1079b2167459SRichard Henderson     case 4: /* SDC / NDC */
1080eaa3783bSRichard Henderson         tcg_gen_andi_reg(cb, cb, 0x88888888u);
1081b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
1082b2167459SRichard Henderson         break;
1083b2167459SRichard Henderson 
1084b2167459SRichard Henderson     case 6: /* SBC / NBC */
1085eaa3783bSRichard Henderson         tcg_gen_andi_reg(cb, cb, 0x80808080u);
1086b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
1087b2167459SRichard Henderson         break;
1088b2167459SRichard Henderson 
1089b2167459SRichard Henderson     case 7: /* SHC / NHC */
1090eaa3783bSRichard Henderson         tcg_gen_andi_reg(cb, cb, 0x80008000u);
1091b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
1092b2167459SRichard Henderson         break;
1093b2167459SRichard Henderson 
1094b2167459SRichard Henderson     default:
1095b2167459SRichard Henderson         g_assert_not_reached();
1096b2167459SRichard Henderson     }
1097b2167459SRichard Henderson     if (cf & 8) {
1098b2167459SRichard Henderson         tcg_temp_free(cb);
1099b2167459SRichard Henderson     }
1100b2167459SRichard Henderson     if (cf & 1) {
1101b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
1102b2167459SRichard Henderson     }
1103b2167459SRichard Henderson 
1104b2167459SRichard Henderson     return cond;
1105b2167459SRichard Henderson }
1106b2167459SRichard Henderson 
1107b2167459SRichard Henderson /* Compute signed overflow for addition.  */
1108eaa3783bSRichard Henderson static TCGv_reg do_add_sv(DisasContext *ctx, TCGv_reg res,
1109eaa3783bSRichard Henderson                           TCGv_reg in1, TCGv_reg in2)
1110b2167459SRichard Henderson {
1111eaa3783bSRichard Henderson     TCGv_reg sv = get_temp(ctx);
1112eaa3783bSRichard Henderson     TCGv_reg tmp = tcg_temp_new();
1113b2167459SRichard Henderson 
1114eaa3783bSRichard Henderson     tcg_gen_xor_reg(sv, res, in1);
1115eaa3783bSRichard Henderson     tcg_gen_xor_reg(tmp, in1, in2);
1116eaa3783bSRichard Henderson     tcg_gen_andc_reg(sv, sv, tmp);
1117b2167459SRichard Henderson     tcg_temp_free(tmp);
1118b2167459SRichard Henderson 
1119b2167459SRichard Henderson     return sv;
1120b2167459SRichard Henderson }
1121b2167459SRichard Henderson 
1122b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
1123eaa3783bSRichard Henderson static TCGv_reg do_sub_sv(DisasContext *ctx, TCGv_reg res,
1124eaa3783bSRichard Henderson                           TCGv_reg in1, TCGv_reg in2)
1125b2167459SRichard Henderson {
1126eaa3783bSRichard Henderson     TCGv_reg sv = get_temp(ctx);
1127eaa3783bSRichard Henderson     TCGv_reg tmp = tcg_temp_new();
1128b2167459SRichard Henderson 
1129eaa3783bSRichard Henderson     tcg_gen_xor_reg(sv, res, in1);
1130eaa3783bSRichard Henderson     tcg_gen_xor_reg(tmp, in1, in2);
1131eaa3783bSRichard Henderson     tcg_gen_and_reg(sv, sv, tmp);
1132b2167459SRichard Henderson     tcg_temp_free(tmp);
1133b2167459SRichard Henderson 
1134b2167459SRichard Henderson     return sv;
1135b2167459SRichard Henderson }
1136b2167459SRichard Henderson 
113731234768SRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1138eaa3783bSRichard Henderson                    TCGv_reg in2, unsigned shift, bool is_l,
1139eaa3783bSRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf)
1140b2167459SRichard Henderson {
1141eaa3783bSRichard Henderson     TCGv_reg dest, cb, cb_msb, sv, tmp;
1142b2167459SRichard Henderson     unsigned c = cf >> 1;
1143b2167459SRichard Henderson     DisasCond cond;
1144b2167459SRichard Henderson 
1145b2167459SRichard Henderson     dest = tcg_temp_new();
1146f764718dSRichard Henderson     cb = NULL;
1147f764718dSRichard Henderson     cb_msb = NULL;
1148b2167459SRichard Henderson 
1149b2167459SRichard Henderson     if (shift) {
1150b2167459SRichard Henderson         tmp = get_temp(ctx);
1151eaa3783bSRichard Henderson         tcg_gen_shli_reg(tmp, in1, shift);
1152b2167459SRichard Henderson         in1 = tmp;
1153b2167459SRichard Henderson     }
1154b2167459SRichard Henderson 
1155b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
1156eaa3783bSRichard Henderson         TCGv_reg zero = tcg_const_reg(0);
1157b2167459SRichard Henderson         cb_msb = get_temp(ctx);
1158eaa3783bSRichard Henderson         tcg_gen_add2_reg(dest, cb_msb, in1, zero, in2, zero);
1159b2167459SRichard Henderson         if (is_c) {
1160eaa3783bSRichard Henderson             tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
1161b2167459SRichard Henderson         }
1162b2167459SRichard Henderson         tcg_temp_free(zero);
1163b2167459SRichard Henderson         if (!is_l) {
1164b2167459SRichard Henderson             cb = get_temp(ctx);
1165eaa3783bSRichard Henderson             tcg_gen_xor_reg(cb, in1, in2);
1166eaa3783bSRichard Henderson             tcg_gen_xor_reg(cb, cb, dest);
1167b2167459SRichard Henderson         }
1168b2167459SRichard Henderson     } else {
1169eaa3783bSRichard Henderson         tcg_gen_add_reg(dest, in1, in2);
1170b2167459SRichard Henderson         if (is_c) {
1171eaa3783bSRichard Henderson             tcg_gen_add_reg(dest, dest, cpu_psw_cb_msb);
1172b2167459SRichard Henderson         }
1173b2167459SRichard Henderson     }
1174b2167459SRichard Henderson 
1175b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1176f764718dSRichard Henderson     sv = NULL;
1177b2167459SRichard Henderson     if (is_tsv || c == 6) {
1178b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
1179b2167459SRichard Henderson         if (is_tsv) {
1180b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
1181b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
1182b2167459SRichard Henderson         }
1183b2167459SRichard Henderson     }
1184b2167459SRichard Henderson 
1185b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1186b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
1187b2167459SRichard Henderson     if (is_tc) {
1188b2167459SRichard Henderson         cond_prep(&cond);
1189b2167459SRichard Henderson         tmp = tcg_temp_new();
1190eaa3783bSRichard Henderson         tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
1191b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
1192b2167459SRichard Henderson         tcg_temp_free(tmp);
1193b2167459SRichard Henderson     }
1194b2167459SRichard Henderson 
1195b2167459SRichard Henderson     /* Write back the result.  */
1196b2167459SRichard Henderson     if (!is_l) {
1197b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1198b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1199b2167459SRichard Henderson     }
1200b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1201b2167459SRichard Henderson     tcg_temp_free(dest);
1202b2167459SRichard Henderson 
1203b2167459SRichard Henderson     /* Install the new nullification.  */
1204b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1205b2167459SRichard Henderson     ctx->null_cond = cond;
1206b2167459SRichard Henderson }
1207b2167459SRichard Henderson 
12080c982a28SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_sh *a,
12090c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
12100c982a28SRichard Henderson {
12110c982a28SRichard Henderson     TCGv_reg tcg_r1, tcg_r2;
12120c982a28SRichard Henderson 
12130c982a28SRichard Henderson     if (a->cf) {
12140c982a28SRichard Henderson         nullify_over(ctx);
12150c982a28SRichard Henderson     }
12160c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12170c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
12180c982a28SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, is_tsv, is_tc, is_c, a->cf);
12190c982a28SRichard Henderson     return nullify_end(ctx);
12200c982a28SRichard Henderson }
12210c982a28SRichard Henderson 
122231234768SRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1223eaa3783bSRichard Henderson                    TCGv_reg in2, bool is_tsv, bool is_b,
1224eaa3783bSRichard Henderson                    bool is_tc, unsigned cf)
1225b2167459SRichard Henderson {
1226eaa3783bSRichard Henderson     TCGv_reg dest, sv, cb, cb_msb, zero, tmp;
1227b2167459SRichard Henderson     unsigned c = cf >> 1;
1228b2167459SRichard Henderson     DisasCond cond;
1229b2167459SRichard Henderson 
1230b2167459SRichard Henderson     dest = tcg_temp_new();
1231b2167459SRichard Henderson     cb = tcg_temp_new();
1232b2167459SRichard Henderson     cb_msb = tcg_temp_new();
1233b2167459SRichard Henderson 
1234eaa3783bSRichard Henderson     zero = tcg_const_reg(0);
1235b2167459SRichard Henderson     if (is_b) {
1236b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
1237eaa3783bSRichard Henderson         tcg_gen_not_reg(cb, in2);
1238eaa3783bSRichard Henderson         tcg_gen_add2_reg(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
1239eaa3783bSRichard Henderson         tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cb, zero);
1240eaa3783bSRichard Henderson         tcg_gen_xor_reg(cb, cb, in1);
1241eaa3783bSRichard Henderson         tcg_gen_xor_reg(cb, cb, dest);
1242b2167459SRichard Henderson     } else {
1243b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1244b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
1245eaa3783bSRichard Henderson         tcg_gen_movi_reg(cb_msb, 1);
1246eaa3783bSRichard Henderson         tcg_gen_sub2_reg(dest, cb_msb, in1, cb_msb, in2, zero);
1247eaa3783bSRichard Henderson         tcg_gen_eqv_reg(cb, in1, in2);
1248eaa3783bSRichard Henderson         tcg_gen_xor_reg(cb, cb, dest);
1249b2167459SRichard Henderson     }
1250b2167459SRichard Henderson     tcg_temp_free(zero);
1251b2167459SRichard Henderson 
1252b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1253f764718dSRichard Henderson     sv = NULL;
1254b2167459SRichard Henderson     if (is_tsv || c == 6) {
1255b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1256b2167459SRichard Henderson         if (is_tsv) {
1257b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
1258b2167459SRichard Henderson         }
1259b2167459SRichard Henderson     }
1260b2167459SRichard Henderson 
1261b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1262b2167459SRichard Henderson     if (!is_b) {
1263b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
1264b2167459SRichard Henderson     } else {
1265b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
1266b2167459SRichard Henderson     }
1267b2167459SRichard Henderson 
1268b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1269b2167459SRichard Henderson     if (is_tc) {
1270b2167459SRichard Henderson         cond_prep(&cond);
1271b2167459SRichard Henderson         tmp = tcg_temp_new();
1272eaa3783bSRichard Henderson         tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
1273b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
1274b2167459SRichard Henderson         tcg_temp_free(tmp);
1275b2167459SRichard Henderson     }
1276b2167459SRichard Henderson 
1277b2167459SRichard Henderson     /* Write back the result.  */
1278b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1279b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1280b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1281b2167459SRichard Henderson     tcg_temp_free(dest);
1282b2167459SRichard Henderson 
1283b2167459SRichard Henderson     /* Install the new nullification.  */
1284b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1285b2167459SRichard Henderson     ctx->null_cond = cond;
1286b2167459SRichard Henderson }
1287b2167459SRichard Henderson 
12880c982a28SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf *a,
12890c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
12900c982a28SRichard Henderson {
12910c982a28SRichard Henderson     TCGv_reg tcg_r1, tcg_r2;
12920c982a28SRichard Henderson 
12930c982a28SRichard Henderson     if (a->cf) {
12940c982a28SRichard Henderson         nullify_over(ctx);
12950c982a28SRichard Henderson     }
12960c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12970c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
12980c982a28SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf);
12990c982a28SRichard Henderson     return nullify_end(ctx);
13000c982a28SRichard Henderson }
13010c982a28SRichard Henderson 
130231234768SRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1303eaa3783bSRichard Henderson                       TCGv_reg in2, unsigned cf)
1304b2167459SRichard Henderson {
1305eaa3783bSRichard Henderson     TCGv_reg dest, sv;
1306b2167459SRichard Henderson     DisasCond cond;
1307b2167459SRichard Henderson 
1308b2167459SRichard Henderson     dest = tcg_temp_new();
1309eaa3783bSRichard Henderson     tcg_gen_sub_reg(dest, in1, in2);
1310b2167459SRichard Henderson 
1311b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1312f764718dSRichard Henderson     sv = NULL;
1313b2167459SRichard Henderson     if ((cf >> 1) == 6) {
1314b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1315b2167459SRichard Henderson     }
1316b2167459SRichard Henderson 
1317b2167459SRichard Henderson     /* Form the condition for the compare.  */
1318b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
1319b2167459SRichard Henderson 
1320b2167459SRichard Henderson     /* Clear.  */
1321eaa3783bSRichard Henderson     tcg_gen_movi_reg(dest, 0);
1322b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1323b2167459SRichard Henderson     tcg_temp_free(dest);
1324b2167459SRichard Henderson 
1325b2167459SRichard Henderson     /* Install the new nullification.  */
1326b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1327b2167459SRichard Henderson     ctx->null_cond = cond;
1328b2167459SRichard Henderson }
1329b2167459SRichard Henderson 
133031234768SRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1331eaa3783bSRichard Henderson                    TCGv_reg in2, unsigned cf,
1332eaa3783bSRichard Henderson                    void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
1333b2167459SRichard Henderson {
1334eaa3783bSRichard Henderson     TCGv_reg dest = dest_gpr(ctx, rt);
1335b2167459SRichard Henderson 
1336b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1337b2167459SRichard Henderson     fn(dest, in1, in2);
1338b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1339b2167459SRichard Henderson 
1340b2167459SRichard Henderson     /* Install the new nullification.  */
1341b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1342b2167459SRichard Henderson     if (cf) {
1343b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
1344b2167459SRichard Henderson     }
1345b2167459SRichard Henderson }
1346b2167459SRichard Henderson 
13470c982a28SRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf *a,
13480c982a28SRichard Henderson                        void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
13490c982a28SRichard Henderson {
13500c982a28SRichard Henderson     TCGv_reg tcg_r1, tcg_r2;
13510c982a28SRichard Henderson 
13520c982a28SRichard Henderson     if (a->cf) {
13530c982a28SRichard Henderson         nullify_over(ctx);
13540c982a28SRichard Henderson     }
13550c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13560c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
13570c982a28SRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, fn);
13580c982a28SRichard Henderson     return nullify_end(ctx);
13590c982a28SRichard Henderson }
13600c982a28SRichard Henderson 
136131234768SRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1362eaa3783bSRichard Henderson                     TCGv_reg in2, unsigned cf, bool is_tc,
1363eaa3783bSRichard Henderson                     void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
1364b2167459SRichard Henderson {
1365eaa3783bSRichard Henderson     TCGv_reg dest;
1366b2167459SRichard Henderson     DisasCond cond;
1367b2167459SRichard Henderson 
1368b2167459SRichard Henderson     if (cf == 0) {
1369b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1370b2167459SRichard Henderson         fn(dest, in1, in2);
1371b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1372b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1373b2167459SRichard Henderson     } else {
1374b2167459SRichard Henderson         dest = tcg_temp_new();
1375b2167459SRichard Henderson         fn(dest, in1, in2);
1376b2167459SRichard Henderson 
1377b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
1378b2167459SRichard Henderson 
1379b2167459SRichard Henderson         if (is_tc) {
1380eaa3783bSRichard Henderson             TCGv_reg tmp = tcg_temp_new();
1381b2167459SRichard Henderson             cond_prep(&cond);
1382eaa3783bSRichard Henderson             tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
1383b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
1384b2167459SRichard Henderson             tcg_temp_free(tmp);
1385b2167459SRichard Henderson         }
1386b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1387b2167459SRichard Henderson 
1388b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1389b2167459SRichard Henderson         ctx->null_cond = cond;
1390b2167459SRichard Henderson     }
1391b2167459SRichard Henderson }
1392b2167459SRichard Henderson 
139386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
13948d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
13958d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
13968d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
13978d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
139886f8d05fSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base)
139986f8d05fSRichard Henderson {
140086f8d05fSRichard Henderson     TCGv_ptr ptr;
140186f8d05fSRichard Henderson     TCGv_reg tmp;
140286f8d05fSRichard Henderson     TCGv_i64 spc;
140386f8d05fSRichard Henderson 
140486f8d05fSRichard Henderson     if (sp != 0) {
14058d6ae7fbSRichard Henderson         if (sp < 0) {
14068d6ae7fbSRichard Henderson             sp = ~sp;
14078d6ae7fbSRichard Henderson         }
14088d6ae7fbSRichard Henderson         spc = get_temp_tl(ctx);
14098d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14108d6ae7fbSRichard Henderson         return spc;
141186f8d05fSRichard Henderson     }
1412494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1413494737b7SRichard Henderson         return cpu_srH;
1414494737b7SRichard Henderson     }
141586f8d05fSRichard Henderson 
141686f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
141786f8d05fSRichard Henderson     tmp = tcg_temp_new();
141886f8d05fSRichard Henderson     spc = get_temp_tl(ctx);
141986f8d05fSRichard Henderson 
142086f8d05fSRichard Henderson     tcg_gen_shri_reg(tmp, base, TARGET_REGISTER_BITS - 5);
142186f8d05fSRichard Henderson     tcg_gen_andi_reg(tmp, tmp, 030);
142286f8d05fSRichard Henderson     tcg_gen_trunc_reg_ptr(ptr, tmp);
142386f8d05fSRichard Henderson     tcg_temp_free(tmp);
142486f8d05fSRichard Henderson 
142586f8d05fSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, cpu_env);
142686f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
142786f8d05fSRichard Henderson     tcg_temp_free_ptr(ptr);
142886f8d05fSRichard Henderson 
142986f8d05fSRichard Henderson     return spc;
143086f8d05fSRichard Henderson }
143186f8d05fSRichard Henderson #endif
143286f8d05fSRichard Henderson 
143386f8d05fSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs,
143486f8d05fSRichard Henderson                      unsigned rb, unsigned rx, int scale, target_sreg disp,
143586f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
143686f8d05fSRichard Henderson {
143786f8d05fSRichard Henderson     TCGv_reg base = load_gpr(ctx, rb);
143886f8d05fSRichard Henderson     TCGv_reg ofs;
143986f8d05fSRichard Henderson 
144086f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
144186f8d05fSRichard Henderson     if (rx) {
144286f8d05fSRichard Henderson         ofs = get_temp(ctx);
144386f8d05fSRichard Henderson         tcg_gen_shli_reg(ofs, cpu_gr[rx], scale);
144486f8d05fSRichard Henderson         tcg_gen_add_reg(ofs, ofs, base);
144586f8d05fSRichard Henderson     } else if (disp || modify) {
144686f8d05fSRichard Henderson         ofs = get_temp(ctx);
144786f8d05fSRichard Henderson         tcg_gen_addi_reg(ofs, base, disp);
144886f8d05fSRichard Henderson     } else {
144986f8d05fSRichard Henderson         ofs = base;
145086f8d05fSRichard Henderson     }
145186f8d05fSRichard Henderson 
145286f8d05fSRichard Henderson     *pofs = ofs;
145386f8d05fSRichard Henderson #ifdef CONFIG_USER_ONLY
145486f8d05fSRichard Henderson     *pgva = (modify <= 0 ? ofs : base);
145586f8d05fSRichard Henderson #else
145686f8d05fSRichard Henderson     TCGv_tl addr = get_temp_tl(ctx);
145786f8d05fSRichard Henderson     tcg_gen_extu_reg_tl(addr, modify <= 0 ? ofs : base);
1458494737b7SRichard Henderson     if (ctx->tb_flags & PSW_W) {
145986f8d05fSRichard Henderson         tcg_gen_andi_tl(addr, addr, 0x3fffffffffffffffull);
146086f8d05fSRichard Henderson     }
146186f8d05fSRichard Henderson     if (!is_phys) {
146286f8d05fSRichard Henderson         tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
146386f8d05fSRichard Henderson     }
146486f8d05fSRichard Henderson     *pgva = addr;
146586f8d05fSRichard Henderson #endif
146686f8d05fSRichard Henderson }
146786f8d05fSRichard Henderson 
146896d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
146996d6407fSRichard Henderson  * < 0 for pre-modify,
147096d6407fSRichard Henderson  * > 0 for post-modify,
147196d6407fSRichard Henderson  * = 0 for no base register update.
147296d6407fSRichard Henderson  */
147396d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1474eaa3783bSRichard Henderson                        unsigned rx, int scale, target_sreg disp,
147586f8d05fSRichard Henderson                        unsigned sp, int modify, TCGMemOp mop)
147696d6407fSRichard Henderson {
147786f8d05fSRichard Henderson     TCGv_reg ofs;
147886f8d05fSRichard Henderson     TCGv_tl addr;
147996d6407fSRichard Henderson 
148096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
148196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
148296d6407fSRichard Henderson 
148386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
148486f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
148586f8d05fSRichard Henderson     tcg_gen_qemu_ld_reg(dest, addr, ctx->mmu_idx, mop);
148686f8d05fSRichard Henderson     if (modify) {
148786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
148896d6407fSRichard Henderson     }
148996d6407fSRichard Henderson }
149096d6407fSRichard Henderson 
149196d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1492eaa3783bSRichard Henderson                        unsigned rx, int scale, target_sreg disp,
149386f8d05fSRichard Henderson                        unsigned sp, int modify, TCGMemOp mop)
149496d6407fSRichard Henderson {
149586f8d05fSRichard Henderson     TCGv_reg ofs;
149686f8d05fSRichard Henderson     TCGv_tl addr;
149796d6407fSRichard Henderson 
149896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
149996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
150096d6407fSRichard Henderson 
150186f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
150286f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
15033d68ee7bSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop);
150486f8d05fSRichard Henderson     if (modify) {
150586f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
150696d6407fSRichard Henderson     }
150796d6407fSRichard Henderson }
150896d6407fSRichard Henderson 
150996d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1510eaa3783bSRichard Henderson                         unsigned rx, int scale, target_sreg disp,
151186f8d05fSRichard Henderson                         unsigned sp, int modify, TCGMemOp mop)
151296d6407fSRichard Henderson {
151386f8d05fSRichard Henderson     TCGv_reg ofs;
151486f8d05fSRichard Henderson     TCGv_tl addr;
151596d6407fSRichard Henderson 
151696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
151796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
151896d6407fSRichard Henderson 
151986f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
152086f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
152186f8d05fSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop);
152286f8d05fSRichard Henderson     if (modify) {
152386f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
152496d6407fSRichard Henderson     }
152596d6407fSRichard Henderson }
152696d6407fSRichard Henderson 
152796d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1528eaa3783bSRichard Henderson                         unsigned rx, int scale, target_sreg disp,
152986f8d05fSRichard Henderson                         unsigned sp, int modify, TCGMemOp mop)
153096d6407fSRichard Henderson {
153186f8d05fSRichard Henderson     TCGv_reg ofs;
153286f8d05fSRichard Henderson     TCGv_tl addr;
153396d6407fSRichard Henderson 
153496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
153596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
153696d6407fSRichard Henderson 
153786f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
153886f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
153986f8d05fSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop);
154086f8d05fSRichard Henderson     if (modify) {
154186f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
154296d6407fSRichard Henderson     }
154396d6407fSRichard Henderson }
154496d6407fSRichard Henderson 
1545eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64
1546eaa3783bSRichard Henderson #define do_load_reg   do_load_64
1547eaa3783bSRichard Henderson #define do_store_reg  do_store_64
154896d6407fSRichard Henderson #else
1549eaa3783bSRichard Henderson #define do_load_reg   do_load_32
1550eaa3783bSRichard Henderson #define do_store_reg  do_store_32
155196d6407fSRichard Henderson #endif
155296d6407fSRichard Henderson 
15531cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1554eaa3783bSRichard Henderson                     unsigned rx, int scale, target_sreg disp,
155586f8d05fSRichard Henderson                     unsigned sp, int modify, TCGMemOp mop)
155696d6407fSRichard Henderson {
1557eaa3783bSRichard Henderson     TCGv_reg dest;
155896d6407fSRichard Henderson 
155996d6407fSRichard Henderson     nullify_over(ctx);
156096d6407fSRichard Henderson 
156196d6407fSRichard Henderson     if (modify == 0) {
156296d6407fSRichard Henderson         /* No base register update.  */
156396d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
156496d6407fSRichard Henderson     } else {
156596d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
156696d6407fSRichard Henderson         dest = get_temp(ctx);
156796d6407fSRichard Henderson     }
156886f8d05fSRichard Henderson     do_load_reg(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
156996d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
157096d6407fSRichard Henderson 
15711cd012a5SRichard Henderson     return nullify_end(ctx);
157296d6407fSRichard Henderson }
157396d6407fSRichard Henderson 
157431234768SRichard Henderson static void do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1575eaa3783bSRichard Henderson                       unsigned rx, int scale, target_sreg disp,
157686f8d05fSRichard Henderson                       unsigned sp, int modify)
157796d6407fSRichard Henderson {
157896d6407fSRichard Henderson     TCGv_i32 tmp;
157996d6407fSRichard Henderson 
158096d6407fSRichard Henderson     nullify_over(ctx);
158196d6407fSRichard Henderson 
158296d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
158386f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
158496d6407fSRichard Henderson     save_frw_i32(rt, tmp);
158596d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
158696d6407fSRichard Henderson 
158796d6407fSRichard Henderson     if (rt == 0) {
158896d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
158996d6407fSRichard Henderson     }
159096d6407fSRichard Henderson 
159131234768SRichard Henderson     nullify_end(ctx);
159296d6407fSRichard Henderson }
159396d6407fSRichard Henderson 
159431234768SRichard Henderson static void do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1595eaa3783bSRichard Henderson                       unsigned rx, int scale, target_sreg disp,
159686f8d05fSRichard Henderson                       unsigned sp, int modify)
159796d6407fSRichard Henderson {
159896d6407fSRichard Henderson     TCGv_i64 tmp;
159996d6407fSRichard Henderson 
160096d6407fSRichard Henderson     nullify_over(ctx);
160196d6407fSRichard Henderson 
160296d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
160386f8d05fSRichard Henderson     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
160496d6407fSRichard Henderson     save_frd(rt, tmp);
160596d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
160696d6407fSRichard Henderson 
160796d6407fSRichard Henderson     if (rt == 0) {
160896d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
160996d6407fSRichard Henderson     }
161096d6407fSRichard Henderson 
161131234768SRichard Henderson     nullify_end(ctx);
161296d6407fSRichard Henderson }
161396d6407fSRichard Henderson 
16141cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
161586f8d05fSRichard Henderson                      target_sreg disp, unsigned sp,
161686f8d05fSRichard Henderson                      int modify, TCGMemOp mop)
161796d6407fSRichard Henderson {
161896d6407fSRichard Henderson     nullify_over(ctx);
161986f8d05fSRichard Henderson     do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16201cd012a5SRichard Henderson     return nullify_end(ctx);
162196d6407fSRichard Henderson }
162296d6407fSRichard Henderson 
162331234768SRichard Henderson static void do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1624eaa3783bSRichard Henderson                        unsigned rx, int scale, target_sreg disp,
162586f8d05fSRichard Henderson                        unsigned sp, int modify)
162696d6407fSRichard Henderson {
162796d6407fSRichard Henderson     TCGv_i32 tmp;
162896d6407fSRichard Henderson 
162996d6407fSRichard Henderson     nullify_over(ctx);
163096d6407fSRichard Henderson 
163196d6407fSRichard Henderson     tmp = load_frw_i32(rt);
163286f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
163396d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
163496d6407fSRichard Henderson 
163531234768SRichard Henderson     nullify_end(ctx);
163696d6407fSRichard Henderson }
163796d6407fSRichard Henderson 
163831234768SRichard Henderson static void do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1639eaa3783bSRichard Henderson                        unsigned rx, int scale, target_sreg disp,
164086f8d05fSRichard Henderson                        unsigned sp, int modify)
164196d6407fSRichard Henderson {
164296d6407fSRichard Henderson     TCGv_i64 tmp;
164396d6407fSRichard Henderson 
164496d6407fSRichard Henderson     nullify_over(ctx);
164596d6407fSRichard Henderson 
164696d6407fSRichard Henderson     tmp = load_frd(rt);
164786f8d05fSRichard Henderson     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
164896d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
164996d6407fSRichard Henderson 
165031234768SRichard Henderson     nullify_end(ctx);
165196d6407fSRichard Henderson }
165296d6407fSRichard Henderson 
165331234768SRichard Henderson static void do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1654ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1655ebe9383cSRichard Henderson {
1656ebe9383cSRichard Henderson     TCGv_i32 tmp;
1657ebe9383cSRichard Henderson 
1658ebe9383cSRichard Henderson     nullify_over(ctx);
1659ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1660ebe9383cSRichard Henderson 
1661ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1662ebe9383cSRichard Henderson 
1663ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
1664ebe9383cSRichard Henderson     tcg_temp_free_i32(tmp);
166531234768SRichard Henderson     nullify_end(ctx);
1666ebe9383cSRichard Henderson }
1667ebe9383cSRichard Henderson 
166831234768SRichard Henderson static void do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1669ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1670ebe9383cSRichard Henderson {
1671ebe9383cSRichard Henderson     TCGv_i32 dst;
1672ebe9383cSRichard Henderson     TCGv_i64 src;
1673ebe9383cSRichard Henderson 
1674ebe9383cSRichard Henderson     nullify_over(ctx);
1675ebe9383cSRichard Henderson     src = load_frd(ra);
1676ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1677ebe9383cSRichard Henderson 
1678ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1679ebe9383cSRichard Henderson 
1680ebe9383cSRichard Henderson     tcg_temp_free_i64(src);
1681ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
1682ebe9383cSRichard Henderson     tcg_temp_free_i32(dst);
168331234768SRichard Henderson     nullify_end(ctx);
1684ebe9383cSRichard Henderson }
1685ebe9383cSRichard Henderson 
168631234768SRichard Henderson static void do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1687ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1688ebe9383cSRichard Henderson {
1689ebe9383cSRichard Henderson     TCGv_i64 tmp;
1690ebe9383cSRichard Henderson 
1691ebe9383cSRichard Henderson     nullify_over(ctx);
1692ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1693ebe9383cSRichard Henderson 
1694ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1695ebe9383cSRichard Henderson 
1696ebe9383cSRichard Henderson     save_frd(rt, tmp);
1697ebe9383cSRichard Henderson     tcg_temp_free_i64(tmp);
169831234768SRichard Henderson     nullify_end(ctx);
1699ebe9383cSRichard Henderson }
1700ebe9383cSRichard Henderson 
170131234768SRichard Henderson static void do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1702ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1703ebe9383cSRichard Henderson {
1704ebe9383cSRichard Henderson     TCGv_i32 src;
1705ebe9383cSRichard Henderson     TCGv_i64 dst;
1706ebe9383cSRichard Henderson 
1707ebe9383cSRichard Henderson     nullify_over(ctx);
1708ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1709ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1710ebe9383cSRichard Henderson 
1711ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1712ebe9383cSRichard Henderson 
1713ebe9383cSRichard Henderson     tcg_temp_free_i32(src);
1714ebe9383cSRichard Henderson     save_frd(rt, dst);
1715ebe9383cSRichard Henderson     tcg_temp_free_i64(dst);
171631234768SRichard Henderson     nullify_end(ctx);
1717ebe9383cSRichard Henderson }
1718ebe9383cSRichard Henderson 
171931234768SRichard Henderson static void do_fop_weww(DisasContext *ctx, unsigned rt,
1720ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
172131234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1722ebe9383cSRichard Henderson {
1723ebe9383cSRichard Henderson     TCGv_i32 a, b;
1724ebe9383cSRichard Henderson 
1725ebe9383cSRichard Henderson     nullify_over(ctx);
1726ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1727ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1728ebe9383cSRichard Henderson 
1729ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1730ebe9383cSRichard Henderson 
1731ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
1732ebe9383cSRichard Henderson     save_frw_i32(rt, a);
1733ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
173431234768SRichard Henderson     nullify_end(ctx);
1735ebe9383cSRichard Henderson }
1736ebe9383cSRichard Henderson 
173731234768SRichard Henderson static void do_fop_dedd(DisasContext *ctx, unsigned rt,
1738ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
173931234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1740ebe9383cSRichard Henderson {
1741ebe9383cSRichard Henderson     TCGv_i64 a, b;
1742ebe9383cSRichard Henderson 
1743ebe9383cSRichard Henderson     nullify_over(ctx);
1744ebe9383cSRichard Henderson     a = load_frd0(ra);
1745ebe9383cSRichard Henderson     b = load_frd0(rb);
1746ebe9383cSRichard Henderson 
1747ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1748ebe9383cSRichard Henderson 
1749ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
1750ebe9383cSRichard Henderson     save_frd(rt, a);
1751ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
175231234768SRichard Henderson     nullify_end(ctx);
1753ebe9383cSRichard Henderson }
1754ebe9383cSRichard Henderson 
175598cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
175698cd9ca7SRichard Henderson    have already had nullification handled.  */
175701afb7beSRichard Henderson static bool do_dbranch(DisasContext *ctx, target_ureg dest,
175898cd9ca7SRichard Henderson                        unsigned link, bool is_n)
175998cd9ca7SRichard Henderson {
176098cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
176198cd9ca7SRichard Henderson         if (link != 0) {
176298cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
176398cd9ca7SRichard Henderson         }
176498cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
176598cd9ca7SRichard Henderson         if (is_n) {
176698cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
176798cd9ca7SRichard Henderson         }
176898cd9ca7SRichard Henderson     } else {
176998cd9ca7SRichard Henderson         nullify_over(ctx);
177098cd9ca7SRichard Henderson 
177198cd9ca7SRichard Henderson         if (link != 0) {
177298cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
177398cd9ca7SRichard Henderson         }
177498cd9ca7SRichard Henderson 
177598cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
177698cd9ca7SRichard Henderson             nullify_set(ctx, 0);
177798cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
177898cd9ca7SRichard Henderson         } else {
177998cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
178098cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
178198cd9ca7SRichard Henderson         }
178298cd9ca7SRichard Henderson 
178331234768SRichard Henderson         nullify_end(ctx);
178498cd9ca7SRichard Henderson 
178598cd9ca7SRichard Henderson         nullify_set(ctx, 0);
178698cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
178731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
178898cd9ca7SRichard Henderson     }
178901afb7beSRichard Henderson     return true;
179098cd9ca7SRichard Henderson }
179198cd9ca7SRichard Henderson 
179298cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
179398cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
179401afb7beSRichard Henderson static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
179598cd9ca7SRichard Henderson                        DisasCond *cond)
179698cd9ca7SRichard Henderson {
1797eaa3783bSRichard Henderson     target_ureg dest = iaoq_dest(ctx, disp);
179898cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
179998cd9ca7SRichard Henderson     TCGCond c = cond->c;
180098cd9ca7SRichard Henderson     bool n;
180198cd9ca7SRichard Henderson 
180298cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
180398cd9ca7SRichard Henderson 
180498cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
180598cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
180601afb7beSRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
180798cd9ca7SRichard Henderson     }
180898cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
180901afb7beSRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
181098cd9ca7SRichard Henderson     }
181198cd9ca7SRichard Henderson 
181298cd9ca7SRichard Henderson     taken = gen_new_label();
181398cd9ca7SRichard Henderson     cond_prep(cond);
1814eaa3783bSRichard Henderson     tcg_gen_brcond_reg(c, cond->a0, cond->a1, taken);
181598cd9ca7SRichard Henderson     cond_free(cond);
181698cd9ca7SRichard Henderson 
181798cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
181898cd9ca7SRichard Henderson     n = is_n && disp < 0;
181998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
182098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1821a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
182298cd9ca7SRichard Henderson     } else {
182398cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
182498cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
182598cd9ca7SRichard Henderson             ctx->null_lab = NULL;
182698cd9ca7SRichard Henderson         }
182798cd9ca7SRichard Henderson         nullify_set(ctx, n);
1828c301f34eSRichard Henderson         if (ctx->iaoq_n == -1) {
1829c301f34eSRichard Henderson             /* The temporary iaoq_n_var died at the branch above.
1830c301f34eSRichard Henderson                Regenerate it here instead of saving it.  */
1831c301f34eSRichard Henderson             tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1832c301f34eSRichard Henderson         }
1833a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
183498cd9ca7SRichard Henderson     }
183598cd9ca7SRichard Henderson 
183698cd9ca7SRichard Henderson     gen_set_label(taken);
183798cd9ca7SRichard Henderson 
183898cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
183998cd9ca7SRichard Henderson     n = is_n && disp >= 0;
184098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
184198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1842a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
184398cd9ca7SRichard Henderson     } else {
184498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1845a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
184698cd9ca7SRichard Henderson     }
184798cd9ca7SRichard Henderson 
184898cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
184998cd9ca7SRichard Henderson     if (ctx->null_lab) {
185098cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
185198cd9ca7SRichard Henderson         ctx->null_lab = NULL;
185231234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
185398cd9ca7SRichard Henderson     } else {
185431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
185598cd9ca7SRichard Henderson     }
185601afb7beSRichard Henderson     return true;
185798cd9ca7SRichard Henderson }
185898cd9ca7SRichard Henderson 
185998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
186098cd9ca7SRichard Henderson    nullification of the branch itself.  */
186101afb7beSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_reg dest,
186298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
186398cd9ca7SRichard Henderson {
1864eaa3783bSRichard Henderson     TCGv_reg a0, a1, next, tmp;
186598cd9ca7SRichard Henderson     TCGCond c;
186698cd9ca7SRichard Henderson 
186798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
186898cd9ca7SRichard Henderson 
186998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
187098cd9ca7SRichard Henderson         if (link != 0) {
187198cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
187298cd9ca7SRichard Henderson         }
187398cd9ca7SRichard Henderson         next = get_temp(ctx);
1874eaa3783bSRichard Henderson         tcg_gen_mov_reg(next, dest);
187598cd9ca7SRichard Henderson         if (is_n) {
1876c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1877c301f34eSRichard Henderson                 tcg_gen_mov_reg(cpu_iaoq_f, next);
1878c301f34eSRichard Henderson                 tcg_gen_addi_reg(cpu_iaoq_b, next, 4);
1879c301f34eSRichard Henderson                 nullify_set(ctx, 0);
188031234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
188101afb7beSRichard Henderson                 return true;
1882c301f34eSRichard Henderson             }
188398cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
188498cd9ca7SRichard Henderson         }
1885c301f34eSRichard Henderson         ctx->iaoq_n = -1;
1886c301f34eSRichard Henderson         ctx->iaoq_n_var = next;
188798cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
188898cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
188998cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
18904137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
189198cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
189298cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
189398cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
189498cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
189598cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
189698cd9ca7SRichard Henderson 
189798cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
189898cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
189998cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1900eaa3783bSRichard Henderson         tcg_gen_mov_reg(cpu_iaoq_f, dest);
1901eaa3783bSRichard Henderson         tcg_gen_addi_reg(cpu_iaoq_b, dest, 4);
190298cd9ca7SRichard Henderson 
190398cd9ca7SRichard Henderson         nullify_over(ctx);
190498cd9ca7SRichard Henderson         if (link != 0) {
1905eaa3783bSRichard Henderson             tcg_gen_movi_reg(cpu_gr[link], ctx->iaoq_n);
190698cd9ca7SRichard Henderson         }
19077f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
190801afb7beSRichard Henderson         return nullify_end(ctx);
190998cd9ca7SRichard Henderson     } else {
191098cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
191198cd9ca7SRichard Henderson         c = ctx->null_cond.c;
191298cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
191398cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
191498cd9ca7SRichard Henderson 
191598cd9ca7SRichard Henderson         tmp = tcg_temp_new();
191698cd9ca7SRichard Henderson         next = get_temp(ctx);
191798cd9ca7SRichard Henderson 
191898cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1919eaa3783bSRichard Henderson         tcg_gen_movcond_reg(c, next, a0, a1, tmp, dest);
192098cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
192198cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
192298cd9ca7SRichard Henderson 
192398cd9ca7SRichard Henderson         if (link != 0) {
1924eaa3783bSRichard Henderson             tcg_gen_movcond_reg(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
192598cd9ca7SRichard Henderson         }
192698cd9ca7SRichard Henderson 
192798cd9ca7SRichard Henderson         if (is_n) {
192898cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
192998cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
193098cd9ca7SRichard Henderson                to the branch.  */
1931eaa3783bSRichard Henderson             tcg_gen_setcond_reg(tcg_invert_cond(c), cpu_psw_n, a0, a1);
193298cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
193398cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
193498cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
193598cd9ca7SRichard Henderson         } else {
193698cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
193798cd9ca7SRichard Henderson         }
193898cd9ca7SRichard Henderson     }
193901afb7beSRichard Henderson     return true;
194098cd9ca7SRichard Henderson }
194198cd9ca7SRichard Henderson 
1942660eefe1SRichard Henderson /* Implement
1943660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1944660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1945660eefe1SRichard Henderson  *    else
1946660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1947660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1948660eefe1SRichard Henderson  */
1949660eefe1SRichard Henderson static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset)
1950660eefe1SRichard Henderson {
1951660eefe1SRichard Henderson     TCGv_reg dest;
1952660eefe1SRichard Henderson     switch (ctx->privilege) {
1953660eefe1SRichard Henderson     case 0:
1954660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
1955660eefe1SRichard Henderson         return offset;
1956660eefe1SRichard Henderson     case 3:
1957660eefe1SRichard Henderson         /* Privilege 3 is minimum and is never allowed increase.  */
1958660eefe1SRichard Henderson         dest = get_temp(ctx);
1959660eefe1SRichard Henderson         tcg_gen_ori_reg(dest, offset, 3);
1960660eefe1SRichard Henderson         break;
1961660eefe1SRichard Henderson     default:
1962660eefe1SRichard Henderson         dest = tcg_temp_new();
1963660eefe1SRichard Henderson         tcg_gen_andi_reg(dest, offset, -4);
1964660eefe1SRichard Henderson         tcg_gen_ori_reg(dest, dest, ctx->privilege);
1965660eefe1SRichard Henderson         tcg_gen_movcond_reg(TCG_COND_GTU, dest, dest, offset, dest, offset);
1966660eefe1SRichard Henderson         tcg_temp_free(dest);
1967660eefe1SRichard Henderson         break;
1968660eefe1SRichard Henderson     }
1969660eefe1SRichard Henderson     return dest;
1970660eefe1SRichard Henderson }
1971660eefe1SRichard Henderson 
1972ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
19737ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
19747ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
19757ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
19767ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
19777ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
19787ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
19797ad439dfSRichard Henderson    aforementioned BE.  */
198031234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
19817ad439dfSRichard Henderson {
19827ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
19837ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
19847ad439dfSRichard Henderson        next insn within the privilaged page.  */
19857ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
19867ad439dfSRichard Henderson     case TCG_COND_NEVER:
19877ad439dfSRichard Henderson         break;
19887ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
1989eaa3783bSRichard Henderson         tcg_gen_movi_reg(cpu_psw_n, 0);
19907ad439dfSRichard Henderson         goto do_sigill;
19917ad439dfSRichard Henderson     default:
19927ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
19937ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
19947ad439dfSRichard Henderson         g_assert_not_reached();
19957ad439dfSRichard Henderson     }
19967ad439dfSRichard Henderson 
19977ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
19987ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
19997ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
20007ad439dfSRichard Henderson        under such conditions.  */
20017ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
20027ad439dfSRichard Henderson         goto do_sigill;
20037ad439dfSRichard Henderson     }
20047ad439dfSRichard Henderson 
2005ebd0e151SRichard Henderson     switch (ctx->iaoq_f & -4) {
20067ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20072986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
200831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
200931234768SRichard Henderson         break;
20107ad439dfSRichard Henderson 
20117ad439dfSRichard Henderson     case 0xb0: /* LWS */
20127ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
201331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
201431234768SRichard Henderson         break;
20157ad439dfSRichard Henderson 
20167ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
201735136a77SRichard Henderson         tcg_gen_st_reg(cpu_gr[26], cpu_env, offsetof(CPUHPPAState, cr[27]));
2018ebd0e151SRichard Henderson         tcg_gen_ori_reg(cpu_iaoq_f, cpu_gr[31], 3);
2019eaa3783bSRichard Henderson         tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
202031234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
202131234768SRichard Henderson         break;
20227ad439dfSRichard Henderson 
20237ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20247ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
202531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
202631234768SRichard Henderson         break;
20277ad439dfSRichard Henderson 
20287ad439dfSRichard Henderson     default:
20297ad439dfSRichard Henderson     do_sigill:
20302986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
203131234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
203231234768SRichard Henderson         break;
20337ad439dfSRichard Henderson     }
20347ad439dfSRichard Henderson }
2035ba1d0b44SRichard Henderson #endif
20367ad439dfSRichard Henderson 
2037deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2038b2167459SRichard Henderson {
2039b2167459SRichard Henderson     cond_free(&ctx->null_cond);
204031234768SRichard Henderson     return true;
2041b2167459SRichard Henderson }
2042b2167459SRichard Henderson 
204340f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
204498a9cb79SRichard Henderson {
204531234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
204698a9cb79SRichard Henderson }
204798a9cb79SRichard Henderson 
2048e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
204998a9cb79SRichard Henderson {
205098a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
205198a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
205298a9cb79SRichard Henderson 
205398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
205431234768SRichard Henderson     return true;
205598a9cb79SRichard Henderson }
205698a9cb79SRichard Henderson 
2057c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
205898a9cb79SRichard Henderson {
2059c603e14aSRichard Henderson     unsigned rt = a->t;
2060eaa3783bSRichard Henderson     TCGv_reg tmp = dest_gpr(ctx, rt);
2061eaa3783bSRichard Henderson     tcg_gen_movi_reg(tmp, ctx->iaoq_f);
206298a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
206398a9cb79SRichard Henderson 
206498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
206531234768SRichard Henderson     return true;
206698a9cb79SRichard Henderson }
206798a9cb79SRichard Henderson 
2068c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
206998a9cb79SRichard Henderson {
2070c603e14aSRichard Henderson     unsigned rt = a->t;
2071c603e14aSRichard Henderson     unsigned rs = a->sp;
207233423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
207333423472SRichard Henderson     TCGv_reg t1 = tcg_temp_new();
207498a9cb79SRichard Henderson 
207533423472SRichard Henderson     load_spr(ctx, t0, rs);
207633423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
207733423472SRichard Henderson     tcg_gen_trunc_i64_reg(t1, t0);
207833423472SRichard Henderson 
207933423472SRichard Henderson     save_gpr(ctx, rt, t1);
208033423472SRichard Henderson     tcg_temp_free(t1);
208133423472SRichard Henderson     tcg_temp_free_i64(t0);
208298a9cb79SRichard Henderson 
208398a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
208431234768SRichard Henderson     return true;
208598a9cb79SRichard Henderson }
208698a9cb79SRichard Henderson 
2087c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
208898a9cb79SRichard Henderson {
2089c603e14aSRichard Henderson     unsigned rt = a->t;
2090c603e14aSRichard Henderson     unsigned ctl = a->r;
2091eaa3783bSRichard Henderson     TCGv_reg tmp;
209298a9cb79SRichard Henderson 
209398a9cb79SRichard Henderson     switch (ctl) {
209435136a77SRichard Henderson     case CR_SAR:
209598a9cb79SRichard Henderson #ifdef TARGET_HPPA64
2096c603e14aSRichard Henderson         if (a->e == 0) {
209798a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
209898a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
2099eaa3783bSRichard Henderson             tcg_gen_andi_reg(tmp, cpu_sar, 31);
210098a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
210135136a77SRichard Henderson             goto done;
210298a9cb79SRichard Henderson         }
210398a9cb79SRichard Henderson #endif
210498a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
210535136a77SRichard Henderson         goto done;
210635136a77SRichard Henderson     case CR_IT: /* Interval Timer */
210735136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
210835136a77SRichard Henderson         nullify_over(ctx);
210998a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
211084b41e65SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
211149c29d6cSRichard Henderson             gen_io_start();
211249c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
211349c29d6cSRichard Henderson             gen_io_end();
211431234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
211549c29d6cSRichard Henderson         } else {
211649c29d6cSRichard Henderson             gen_helper_read_interval_timer(tmp);
211749c29d6cSRichard Henderson         }
211898a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
211931234768SRichard Henderson         return nullify_end(ctx);
212098a9cb79SRichard Henderson     case 26:
212198a9cb79SRichard Henderson     case 27:
212298a9cb79SRichard Henderson         break;
212398a9cb79SRichard Henderson     default:
212498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
212535136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
212635136a77SRichard Henderson         break;
212798a9cb79SRichard Henderson     }
212898a9cb79SRichard Henderson 
212935136a77SRichard Henderson     tmp = get_temp(ctx);
213035136a77SRichard Henderson     tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
213135136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
213235136a77SRichard Henderson 
213335136a77SRichard Henderson  done:
213498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
213531234768SRichard Henderson     return true;
213698a9cb79SRichard Henderson }
213798a9cb79SRichard Henderson 
2138c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
213933423472SRichard Henderson {
2140c603e14aSRichard Henderson     unsigned rr = a->r;
2141c603e14aSRichard Henderson     unsigned rs = a->sp;
214233423472SRichard Henderson     TCGv_i64 t64;
214333423472SRichard Henderson 
214433423472SRichard Henderson     if (rs >= 5) {
214533423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
214633423472SRichard Henderson     }
214733423472SRichard Henderson     nullify_over(ctx);
214833423472SRichard Henderson 
214933423472SRichard Henderson     t64 = tcg_temp_new_i64();
215033423472SRichard Henderson     tcg_gen_extu_reg_i64(t64, load_gpr(ctx, rr));
215133423472SRichard Henderson     tcg_gen_shli_i64(t64, t64, 32);
215233423472SRichard Henderson 
215333423472SRichard Henderson     if (rs >= 4) {
215433423472SRichard Henderson         tcg_gen_st_i64(t64, cpu_env, offsetof(CPUHPPAState, sr[rs]));
2155494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
215633423472SRichard Henderson     } else {
215733423472SRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], t64);
215833423472SRichard Henderson     }
215933423472SRichard Henderson     tcg_temp_free_i64(t64);
216033423472SRichard Henderson 
216131234768SRichard Henderson     return nullify_end(ctx);
216233423472SRichard Henderson }
216333423472SRichard Henderson 
2164c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
216598a9cb79SRichard Henderson {
2166c603e14aSRichard Henderson     unsigned ctl = a->t;
2167c603e14aSRichard Henderson     TCGv_reg reg = load_gpr(ctx, a->r);
2168eaa3783bSRichard Henderson     TCGv_reg tmp;
216998a9cb79SRichard Henderson 
217035136a77SRichard Henderson     if (ctl == CR_SAR) {
217198a9cb79SRichard Henderson         tmp = tcg_temp_new();
217235136a77SRichard Henderson         tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1);
217398a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
217498a9cb79SRichard Henderson         tcg_temp_free(tmp);
217598a9cb79SRichard Henderson 
217698a9cb79SRichard Henderson         cond_free(&ctx->null_cond);
217731234768SRichard Henderson         return true;
217898a9cb79SRichard Henderson     }
217998a9cb79SRichard Henderson 
218035136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
218135136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
218235136a77SRichard Henderson 
2183c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
218435136a77SRichard Henderson     nullify_over(ctx);
218535136a77SRichard Henderson     switch (ctl) {
218635136a77SRichard Henderson     case CR_IT:
218749c29d6cSRichard Henderson         gen_helper_write_interval_timer(cpu_env, reg);
218835136a77SRichard Henderson         break;
21894f5f2548SRichard Henderson     case CR_EIRR:
21904f5f2548SRichard Henderson         gen_helper_write_eirr(cpu_env, reg);
21914f5f2548SRichard Henderson         break;
21924f5f2548SRichard Henderson     case CR_EIEM:
21934f5f2548SRichard Henderson         gen_helper_write_eiem(cpu_env, reg);
219431234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
21954f5f2548SRichard Henderson         break;
21964f5f2548SRichard Henderson 
219735136a77SRichard Henderson     case CR_IIASQ:
219835136a77SRichard Henderson     case CR_IIAOQ:
219935136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
220035136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
220135136a77SRichard Henderson         tmp = get_temp(ctx);
220235136a77SRichard Henderson         tcg_gen_ld_reg(tmp, cpu_env,
220335136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
220435136a77SRichard Henderson         tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
220535136a77SRichard Henderson         tcg_gen_st_reg(reg, cpu_env,
220635136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
220735136a77SRichard Henderson         break;
220835136a77SRichard Henderson 
220935136a77SRichard Henderson     default:
221035136a77SRichard Henderson         tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
221135136a77SRichard Henderson         break;
221235136a77SRichard Henderson     }
221331234768SRichard Henderson     return nullify_end(ctx);
22144f5f2548SRichard Henderson #endif
221535136a77SRichard Henderson }
221635136a77SRichard Henderson 
2217c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
221898a9cb79SRichard Henderson {
2219eaa3783bSRichard Henderson     TCGv_reg tmp = tcg_temp_new();
222098a9cb79SRichard Henderson 
2221c603e14aSRichard Henderson     tcg_gen_not_reg(tmp, load_gpr(ctx, a->r));
2222eaa3783bSRichard Henderson     tcg_gen_andi_reg(tmp, tmp, TARGET_REGISTER_BITS - 1);
222398a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
222498a9cb79SRichard Henderson     tcg_temp_free(tmp);
222598a9cb79SRichard Henderson 
222698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
222731234768SRichard Henderson     return true;
222898a9cb79SRichard Henderson }
222998a9cb79SRichard Henderson 
2230e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
223198a9cb79SRichard Henderson {
2232e36f27efSRichard Henderson     TCGv_reg dest = dest_gpr(ctx, a->t);
223398a9cb79SRichard Henderson 
22342330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22352330504cSHelge Deller     /* We don't implement space registers in user mode. */
2236eaa3783bSRichard Henderson     tcg_gen_movi_reg(dest, 0);
22372330504cSHelge Deller #else
22382330504cSHelge Deller     TCGv_i64 t0 = tcg_temp_new_i64();
22392330504cSHelge Deller 
2240e36f27efSRichard Henderson     tcg_gen_mov_i64(t0, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
22412330504cSHelge Deller     tcg_gen_shri_i64(t0, t0, 32);
22422330504cSHelge Deller     tcg_gen_trunc_i64_reg(dest, t0);
22432330504cSHelge Deller 
22442330504cSHelge Deller     tcg_temp_free_i64(t0);
22452330504cSHelge Deller #endif
2246e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
224798a9cb79SRichard Henderson 
224898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
224931234768SRichard Henderson     return true;
225098a9cb79SRichard Henderson }
225198a9cb79SRichard Henderson 
2252e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2253e36f27efSRichard Henderson {
2254e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2255e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY
2256e1b5a5edSRichard Henderson     TCGv_reg tmp;
2257e1b5a5edSRichard Henderson 
2258e1b5a5edSRichard Henderson     nullify_over(ctx);
2259e1b5a5edSRichard Henderson 
2260e1b5a5edSRichard Henderson     tmp = get_temp(ctx);
2261e1b5a5edSRichard Henderson     tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw));
2262e36f27efSRichard Henderson     tcg_gen_andi_reg(tmp, tmp, ~a->i);
2263e1b5a5edSRichard Henderson     gen_helper_swap_system_mask(tmp, cpu_env, tmp);
2264e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2265e1b5a5edSRichard Henderson 
2266e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
226731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
226831234768SRichard Henderson     return nullify_end(ctx);
2269e36f27efSRichard Henderson #endif
2270e1b5a5edSRichard Henderson }
2271e1b5a5edSRichard Henderson 
2272e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2273e1b5a5edSRichard Henderson {
2274e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2275e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2276e1b5a5edSRichard Henderson     TCGv_reg tmp;
2277e1b5a5edSRichard Henderson 
2278e1b5a5edSRichard Henderson     nullify_over(ctx);
2279e1b5a5edSRichard Henderson 
2280e1b5a5edSRichard Henderson     tmp = get_temp(ctx);
2281e1b5a5edSRichard Henderson     tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw));
2282e36f27efSRichard Henderson     tcg_gen_ori_reg(tmp, tmp, a->i);
2283e1b5a5edSRichard Henderson     gen_helper_swap_system_mask(tmp, cpu_env, tmp);
2284e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2285e1b5a5edSRichard Henderson 
2286e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
228731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
228831234768SRichard Henderson     return nullify_end(ctx);
2289e36f27efSRichard Henderson #endif
2290e1b5a5edSRichard Henderson }
2291e1b5a5edSRichard Henderson 
2292c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2293e1b5a5edSRichard Henderson {
2294e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2295c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
2296c603e14aSRichard Henderson     TCGv_reg tmp, reg;
2297e1b5a5edSRichard Henderson     nullify_over(ctx);
2298e1b5a5edSRichard Henderson 
2299c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2300e1b5a5edSRichard Henderson     tmp = get_temp(ctx);
2301e1b5a5edSRichard Henderson     gen_helper_swap_system_mask(tmp, cpu_env, reg);
2302e1b5a5edSRichard Henderson 
2303e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
230431234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
230531234768SRichard Henderson     return nullify_end(ctx);
2306c603e14aSRichard Henderson #endif
2307e1b5a5edSRichard Henderson }
2308f49b3537SRichard Henderson 
2309e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2310f49b3537SRichard Henderson {
2311f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2312e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2313f49b3537SRichard Henderson     nullify_over(ctx);
2314f49b3537SRichard Henderson 
2315e36f27efSRichard Henderson     if (rfi_r) {
2316f49b3537SRichard Henderson         gen_helper_rfi_r(cpu_env);
2317f49b3537SRichard Henderson     } else {
2318f49b3537SRichard Henderson         gen_helper_rfi(cpu_env);
2319f49b3537SRichard Henderson     }
232031234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
2321f49b3537SRichard Henderson     if (ctx->base.singlestep_enabled) {
2322f49b3537SRichard Henderson         gen_excp_1(EXCP_DEBUG);
2323f49b3537SRichard Henderson     } else {
232407ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
2325f49b3537SRichard Henderson     }
232631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2327f49b3537SRichard Henderson 
232831234768SRichard Henderson     return nullify_end(ctx);
2329e36f27efSRichard Henderson #endif
2330f49b3537SRichard Henderson }
23316210db05SHelge Deller 
2332e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2333e36f27efSRichard Henderson {
2334e36f27efSRichard Henderson     return do_rfi(ctx, false);
2335e36f27efSRichard Henderson }
2336e36f27efSRichard Henderson 
2337e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2338e36f27efSRichard Henderson {
2339e36f27efSRichard Henderson     return do_rfi(ctx, true);
2340e36f27efSRichard Henderson }
2341e36f27efSRichard Henderson 
2342e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
234331234768SRichard Henderson static bool gen_hlt(DisasContext *ctx, int reset)
23446210db05SHelge Deller {
23456210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23466210db05SHelge Deller     nullify_over(ctx);
23476210db05SHelge Deller     if (reset) {
23486210db05SHelge Deller         gen_helper_reset(cpu_env);
23496210db05SHelge Deller     } else {
23506210db05SHelge Deller         gen_helper_halt(cpu_env);
23516210db05SHelge Deller     }
235231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
235331234768SRichard Henderson     return nullify_end(ctx);
23546210db05SHelge Deller }
2355e1b5a5edSRichard Henderson #endif /* !CONFIG_USER_ONLY */
2356e1b5a5edSRichard Henderson 
2357deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
235898a9cb79SRichard Henderson {
2359deee69a1SRichard Henderson     if (a->m) {
2360deee69a1SRichard Henderson         TCGv_reg dest = dest_gpr(ctx, a->b);
2361deee69a1SRichard Henderson         TCGv_reg src1 = load_gpr(ctx, a->b);
2362deee69a1SRichard Henderson         TCGv_reg src2 = load_gpr(ctx, a->x);
236398a9cb79SRichard Henderson 
236498a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
2365eaa3783bSRichard Henderson         tcg_gen_add_reg(dest, src1, src2);
2366deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2367deee69a1SRichard Henderson     }
236898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
236931234768SRichard Henderson     return true;
237098a9cb79SRichard Henderson }
237198a9cb79SRichard Henderson 
2372deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
237398a9cb79SRichard Henderson {
237486f8d05fSRichard Henderson     TCGv_reg dest, ofs;
2375eed14219SRichard Henderson     TCGv_i32 level, want;
237686f8d05fSRichard Henderson     TCGv_tl addr;
237798a9cb79SRichard Henderson 
237898a9cb79SRichard Henderson     nullify_over(ctx);
237998a9cb79SRichard Henderson 
2380deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2381deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2382eed14219SRichard Henderson 
2383deee69a1SRichard Henderson     if (a->imm) {
2384deee69a1SRichard Henderson         level = tcg_const_i32(a->ri);
238598a9cb79SRichard Henderson     } else {
2386eed14219SRichard Henderson         level = tcg_temp_new_i32();
2387deee69a1SRichard Henderson         tcg_gen_trunc_reg_i32(level, load_gpr(ctx, a->ri));
2388eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
238998a9cb79SRichard Henderson     }
2390deee69a1SRichard Henderson     want = tcg_const_i32(a->write ? PAGE_WRITE : PAGE_READ);
2391eed14219SRichard Henderson 
2392eed14219SRichard Henderson     gen_helper_probe(dest, cpu_env, addr, level, want);
2393eed14219SRichard Henderson 
2394eed14219SRichard Henderson     tcg_temp_free_i32(want);
2395eed14219SRichard Henderson     tcg_temp_free_i32(level);
2396eed14219SRichard Henderson 
2397deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
239831234768SRichard Henderson     return nullify_end(ctx);
239998a9cb79SRichard Henderson }
240098a9cb79SRichard Henderson 
2401deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24028d6ae7fbSRichard Henderson {
2403deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2404deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24058d6ae7fbSRichard Henderson     TCGv_tl addr;
24068d6ae7fbSRichard Henderson     TCGv_reg ofs, reg;
24078d6ae7fbSRichard Henderson 
24088d6ae7fbSRichard Henderson     nullify_over(ctx);
24098d6ae7fbSRichard Henderson 
2410deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2411deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2412deee69a1SRichard Henderson     if (a->addr) {
24138d6ae7fbSRichard Henderson         gen_helper_itlba(cpu_env, addr, reg);
24148d6ae7fbSRichard Henderson     } else {
24158d6ae7fbSRichard Henderson         gen_helper_itlbp(cpu_env, addr, reg);
24168d6ae7fbSRichard Henderson     }
24178d6ae7fbSRichard Henderson 
24188d6ae7fbSRichard Henderson     /* Exit TB for ITLB change if mmu is enabled.  This *should* not be
24198d6ae7fbSRichard Henderson        the case, since the OS TLB fill handler runs with mmu disabled.  */
2420deee69a1SRichard Henderson     if (!a->data && (ctx->tb_flags & PSW_C)) {
242131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
242231234768SRichard Henderson     }
242331234768SRichard Henderson     return nullify_end(ctx);
2424deee69a1SRichard Henderson #endif
24258d6ae7fbSRichard Henderson }
242663300a00SRichard Henderson 
2427deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
242863300a00SRichard Henderson {
2429deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2430deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
243163300a00SRichard Henderson     TCGv_tl addr;
243263300a00SRichard Henderson     TCGv_reg ofs;
243363300a00SRichard Henderson 
243463300a00SRichard Henderson     nullify_over(ctx);
243563300a00SRichard Henderson 
2436deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2437deee69a1SRichard Henderson     if (a->m) {
2438deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
243963300a00SRichard Henderson     }
2440deee69a1SRichard Henderson     if (a->local) {
244163300a00SRichard Henderson         gen_helper_ptlbe(cpu_env);
244263300a00SRichard Henderson     } else {
244363300a00SRichard Henderson         gen_helper_ptlb(cpu_env, addr);
244463300a00SRichard Henderson     }
244563300a00SRichard Henderson 
244663300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
2447deee69a1SRichard Henderson     if (!a->data && (ctx->tb_flags & PSW_C)) {
244831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
244931234768SRichard Henderson     }
245031234768SRichard Henderson     return nullify_end(ctx);
2451deee69a1SRichard Henderson #endif
245263300a00SRichard Henderson }
24532dfcca9fSRichard Henderson 
2454deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
24552dfcca9fSRichard Henderson {
2456deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2457deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24582dfcca9fSRichard Henderson     TCGv_tl vaddr;
24592dfcca9fSRichard Henderson     TCGv_reg ofs, paddr;
24602dfcca9fSRichard Henderson 
24612dfcca9fSRichard Henderson     nullify_over(ctx);
24622dfcca9fSRichard Henderson 
2463deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
24642dfcca9fSRichard Henderson 
24652dfcca9fSRichard Henderson     paddr = tcg_temp_new();
24662dfcca9fSRichard Henderson     gen_helper_lpa(paddr, cpu_env, vaddr);
24672dfcca9fSRichard Henderson 
24682dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2469deee69a1SRichard Henderson     if (a->m) {
2470deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
24712dfcca9fSRichard Henderson     }
2472deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
24732dfcca9fSRichard Henderson     tcg_temp_free(paddr);
24742dfcca9fSRichard Henderson 
247531234768SRichard Henderson     return nullify_end(ctx);
2476deee69a1SRichard Henderson #endif
24772dfcca9fSRichard Henderson }
247843a97b81SRichard Henderson 
2479deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
248043a97b81SRichard Henderson {
248143a97b81SRichard Henderson     TCGv_reg ci;
248243a97b81SRichard Henderson 
248343a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
248443a97b81SRichard Henderson 
248543a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
248643a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
248743a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
248843a97b81SRichard Henderson        since the entire address space is coherent.  */
248943a97b81SRichard Henderson     ci = tcg_const_reg(0);
2490deee69a1SRichard Henderson     save_gpr(ctx, a->t, ci);
249143a97b81SRichard Henderson     tcg_temp_free(ci);
249243a97b81SRichard Henderson 
249331234768SRichard Henderson     cond_free(&ctx->null_cond);
249431234768SRichard Henderson     return true;
249543a97b81SRichard Henderson }
249698a9cb79SRichard Henderson 
24970c982a28SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_sh *a)
2498b2167459SRichard Henderson {
24990c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2500b2167459SRichard Henderson }
2501b2167459SRichard Henderson 
25020c982a28SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_sh *a)
2503b2167459SRichard Henderson {
25040c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2505b2167459SRichard Henderson }
2506b2167459SRichard Henderson 
25070c982a28SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_sh *a)
2508b2167459SRichard Henderson {
25090c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2510b2167459SRichard Henderson }
2511b2167459SRichard Henderson 
25120c982a28SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_sh *a)
2513b2167459SRichard Henderson {
25140c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
25150c982a28SRichard Henderson }
2516b2167459SRichard Henderson 
25170c982a28SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_sh *a)
25180c982a28SRichard Henderson {
25190c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
25200c982a28SRichard Henderson }
25210c982a28SRichard Henderson 
25220c982a28SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf *a)
25230c982a28SRichard Henderson {
25240c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
25250c982a28SRichard Henderson }
25260c982a28SRichard Henderson 
25270c982a28SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf *a)
25280c982a28SRichard Henderson {
25290c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
25300c982a28SRichard Henderson }
25310c982a28SRichard Henderson 
25320c982a28SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf *a)
25330c982a28SRichard Henderson {
25340c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
25350c982a28SRichard Henderson }
25360c982a28SRichard Henderson 
25370c982a28SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf *a)
25380c982a28SRichard Henderson {
25390c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
25400c982a28SRichard Henderson }
25410c982a28SRichard Henderson 
25420c982a28SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf *a)
25430c982a28SRichard Henderson {
25440c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
25450c982a28SRichard Henderson }
25460c982a28SRichard Henderson 
25470c982a28SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf *a)
25480c982a28SRichard Henderson {
25490c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
25500c982a28SRichard Henderson }
25510c982a28SRichard Henderson 
25520c982a28SRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf *a)
25530c982a28SRichard Henderson {
25540c982a28SRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_reg);
25550c982a28SRichard Henderson }
25560c982a28SRichard Henderson 
25570c982a28SRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf *a)
25580c982a28SRichard Henderson {
25590c982a28SRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_reg);
25600c982a28SRichard Henderson }
25610c982a28SRichard Henderson 
25620c982a28SRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf *a)
25630c982a28SRichard Henderson {
25640c982a28SRichard Henderson     if (a->cf == 0) {
25650c982a28SRichard Henderson         unsigned r2 = a->r2;
25660c982a28SRichard Henderson         unsigned r1 = a->r1;
25670c982a28SRichard Henderson         unsigned rt = a->t;
25680c982a28SRichard Henderson 
25697aee8189SRichard Henderson         if (rt == 0) { /* NOP */
25707aee8189SRichard Henderson             cond_free(&ctx->null_cond);
25717aee8189SRichard Henderson             return true;
25727aee8189SRichard Henderson         }
25737aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2574b2167459SRichard Henderson             if (r1 == 0) {
2575eaa3783bSRichard Henderson                 TCGv_reg dest = dest_gpr(ctx, rt);
2576eaa3783bSRichard Henderson                 tcg_gen_movi_reg(dest, 0);
2577b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2578b2167459SRichard Henderson             } else {
2579b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2580b2167459SRichard Henderson             }
2581b2167459SRichard Henderson             cond_free(&ctx->null_cond);
258231234768SRichard Henderson             return true;
2583b2167459SRichard Henderson         }
25847aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
25857aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
25867aee8189SRichard Henderson          *
25877aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
25887aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
25897aee8189SRichard Henderson          *                      currently implemented as idle.
25907aee8189SRichard Henderson          */
25917aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
25927aee8189SRichard Henderson             TCGv_i32 tmp;
25937aee8189SRichard Henderson 
25947aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
25957aee8189SRichard Henderson                until the next timer interrupt.  */
25967aee8189SRichard Henderson             nullify_over(ctx);
25977aee8189SRichard Henderson 
25987aee8189SRichard Henderson             /* Advance the instruction queue.  */
25997aee8189SRichard Henderson             copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
26007aee8189SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
26017aee8189SRichard Henderson             nullify_set(ctx, 0);
26027aee8189SRichard Henderson 
26037aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
26047aee8189SRichard Henderson             tmp = tcg_const_i32(1);
26057aee8189SRichard Henderson             tcg_gen_st_i32(tmp, cpu_env, -offsetof(HPPACPU, env) +
26067aee8189SRichard Henderson                                          offsetof(CPUState, halted));
26077aee8189SRichard Henderson             tcg_temp_free_i32(tmp);
26087aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
26097aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
26107aee8189SRichard Henderson 
26117aee8189SRichard Henderson             return nullify_end(ctx);
26127aee8189SRichard Henderson         }
26137aee8189SRichard Henderson #endif
26147aee8189SRichard Henderson     }
26150c982a28SRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_reg);
26167aee8189SRichard Henderson }
2617b2167459SRichard Henderson 
26180c982a28SRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf *a)
2619b2167459SRichard Henderson {
26200c982a28SRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_reg);
26210c982a28SRichard Henderson }
26220c982a28SRichard Henderson 
26230c982a28SRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf *a)
26240c982a28SRichard Henderson {
2625eaa3783bSRichard Henderson     TCGv_reg tcg_r1, tcg_r2;
2626b2167459SRichard Henderson 
26270c982a28SRichard Henderson     if (a->cf) {
2628b2167459SRichard Henderson         nullify_over(ctx);
2629b2167459SRichard Henderson     }
26300c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26310c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26320c982a28SRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf);
263331234768SRichard Henderson     return nullify_end(ctx);
2634b2167459SRichard Henderson }
2635b2167459SRichard Henderson 
26360c982a28SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf *a)
2637b2167459SRichard Henderson {
2638eaa3783bSRichard Henderson     TCGv_reg tcg_r1, tcg_r2;
2639b2167459SRichard Henderson 
26400c982a28SRichard Henderson     if (a->cf) {
2641b2167459SRichard Henderson         nullify_over(ctx);
2642b2167459SRichard Henderson     }
26430c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26440c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
26450c982a28SRichard Henderson     do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, false, tcg_gen_xor_reg);
264631234768SRichard Henderson     return nullify_end(ctx);
2647b2167459SRichard Henderson }
2648b2167459SRichard Henderson 
26490c982a28SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf *a, bool is_tc)
2650b2167459SRichard Henderson {
2651eaa3783bSRichard Henderson     TCGv_reg tcg_r1, tcg_r2, tmp;
2652b2167459SRichard Henderson 
26530c982a28SRichard Henderson     if (a->cf) {
2654b2167459SRichard Henderson         nullify_over(ctx);
2655b2167459SRichard Henderson     }
26560c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
26570c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2658b2167459SRichard Henderson     tmp = get_temp(ctx);
2659eaa3783bSRichard Henderson     tcg_gen_not_reg(tmp, tcg_r2);
26600c982a28SRichard Henderson     do_unit(ctx, a->t, tcg_r1, tmp, a->cf, is_tc, tcg_gen_add_reg);
266131234768SRichard Henderson     return nullify_end(ctx);
2662b2167459SRichard Henderson }
2663b2167459SRichard Henderson 
26640c982a28SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf *a)
2665b2167459SRichard Henderson {
26660c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
26670c982a28SRichard Henderson }
26680c982a28SRichard Henderson 
26690c982a28SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf *a)
26700c982a28SRichard Henderson {
26710c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
26720c982a28SRichard Henderson }
26730c982a28SRichard Henderson 
26740c982a28SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf *a, bool is_i)
26750c982a28SRichard Henderson {
2676eaa3783bSRichard Henderson     TCGv_reg tmp;
2677b2167459SRichard Henderson 
2678b2167459SRichard Henderson     nullify_over(ctx);
2679b2167459SRichard Henderson 
2680b2167459SRichard Henderson     tmp = get_temp(ctx);
2681eaa3783bSRichard Henderson     tcg_gen_shri_reg(tmp, cpu_psw_cb, 3);
2682b2167459SRichard Henderson     if (!is_i) {
2683eaa3783bSRichard Henderson         tcg_gen_not_reg(tmp, tmp);
2684b2167459SRichard Henderson     }
2685eaa3783bSRichard Henderson     tcg_gen_andi_reg(tmp, tmp, 0x11111111);
2686eaa3783bSRichard Henderson     tcg_gen_muli_reg(tmp, tmp, 6);
26870c982a28SRichard Henderson     do_unit(ctx, a->t, tmp, load_gpr(ctx, a->r), a->cf, false,
2688eaa3783bSRichard Henderson             is_i ? tcg_gen_add_reg : tcg_gen_sub_reg);
268931234768SRichard Henderson     return nullify_end(ctx);
2690b2167459SRichard Henderson }
2691b2167459SRichard Henderson 
26920c982a28SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf *a)
2693b2167459SRichard Henderson {
26940c982a28SRichard Henderson     return do_dcor(ctx, a, false);
26950c982a28SRichard Henderson }
26960c982a28SRichard Henderson 
26970c982a28SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf *a)
26980c982a28SRichard Henderson {
26990c982a28SRichard Henderson     return do_dcor(ctx, a, true);
27000c982a28SRichard Henderson }
27010c982a28SRichard Henderson 
27020c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
27030c982a28SRichard Henderson {
2704eaa3783bSRichard Henderson     TCGv_reg dest, add1, add2, addc, zero, in1, in2;
2705b2167459SRichard Henderson 
2706b2167459SRichard Henderson     nullify_over(ctx);
2707b2167459SRichard Henderson 
27080c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
27090c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2710b2167459SRichard Henderson 
2711b2167459SRichard Henderson     add1 = tcg_temp_new();
2712b2167459SRichard Henderson     add2 = tcg_temp_new();
2713b2167459SRichard Henderson     addc = tcg_temp_new();
2714b2167459SRichard Henderson     dest = tcg_temp_new();
2715eaa3783bSRichard Henderson     zero = tcg_const_reg(0);
2716b2167459SRichard Henderson 
2717b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
2718eaa3783bSRichard Henderson     tcg_gen_add_reg(add1, in1, in1);
2719eaa3783bSRichard Henderson     tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb);
2720b2167459SRichard Henderson 
2721b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
2722b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
2723b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
2724b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
2725eaa3783bSRichard Henderson     tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1);
2726eaa3783bSRichard Henderson     tcg_gen_xor_reg(add2, in2, addc);
2727eaa3783bSRichard Henderson     tcg_gen_andi_reg(addc, addc, 1);
2728b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
2729b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2730b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2731b2167459SRichard Henderson 
2732b2167459SRichard Henderson     tcg_temp_free(addc);
2733b2167459SRichard Henderson     tcg_temp_free(zero);
2734b2167459SRichard Henderson 
2735b2167459SRichard Henderson     /* Write back the result register.  */
27360c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2737b2167459SRichard Henderson 
2738b2167459SRichard Henderson     /* Write back PSW[CB].  */
2739eaa3783bSRichard Henderson     tcg_gen_xor_reg(cpu_psw_cb, add1, add2);
2740eaa3783bSRichard Henderson     tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest);
2741b2167459SRichard Henderson 
2742b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
2743eaa3783bSRichard Henderson     tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb);
2744eaa3783bSRichard Henderson     tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2);
2745b2167459SRichard Henderson 
2746b2167459SRichard Henderson     /* Install the new nullification.  */
27470c982a28SRichard Henderson     if (a->cf) {
2748eaa3783bSRichard Henderson         TCGv_reg sv = NULL;
27490c982a28SRichard Henderson         if (a->cf >> 1 == 6) {
2750b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2751b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2752b2167459SRichard Henderson         }
27530c982a28SRichard Henderson         ctx->null_cond = do_cond(a->cf, dest, cpu_psw_cb_msb, sv);
2754b2167459SRichard Henderson     }
2755b2167459SRichard Henderson 
2756b2167459SRichard Henderson     tcg_temp_free(add1);
2757b2167459SRichard Henderson     tcg_temp_free(add2);
2758b2167459SRichard Henderson     tcg_temp_free(dest);
2759b2167459SRichard Henderson 
276031234768SRichard Henderson     return nullify_end(ctx);
2761b2167459SRichard Henderson }
2762b2167459SRichard Henderson 
276331234768SRichard Henderson static bool trans_addi(DisasContext *ctx, uint32_t insn)
2764b2167459SRichard Henderson {
2765eaa3783bSRichard Henderson     target_sreg im = low_sextract(insn, 0, 11);
2766b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2767b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2768b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2769b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2770b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
2771eaa3783bSRichard Henderson     TCGv_reg tcg_im, tcg_r2;
2772b2167459SRichard Henderson 
2773b2167459SRichard Henderson     if (cf) {
2774b2167459SRichard Henderson         nullify_over(ctx);
2775b2167459SRichard Henderson     }
2776b2167459SRichard Henderson 
2777b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2778b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
277931234768SRichard Henderson     do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2780b2167459SRichard Henderson 
278131234768SRichard Henderson     return nullify_end(ctx);
2782b2167459SRichard Henderson }
2783b2167459SRichard Henderson 
278431234768SRichard Henderson static bool trans_subi(DisasContext *ctx, uint32_t insn)
2785b2167459SRichard Henderson {
2786eaa3783bSRichard Henderson     target_sreg im = low_sextract(insn, 0, 11);
2787b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2788b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2789b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2790b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2791eaa3783bSRichard Henderson     TCGv_reg tcg_im, tcg_r2;
2792b2167459SRichard Henderson 
2793b2167459SRichard Henderson     if (cf) {
2794b2167459SRichard Henderson         nullify_over(ctx);
2795b2167459SRichard Henderson     }
2796b2167459SRichard Henderson 
2797b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2798b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
279931234768SRichard Henderson     do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2800b2167459SRichard Henderson 
280131234768SRichard Henderson     return nullify_end(ctx);
2802b2167459SRichard Henderson }
2803b2167459SRichard Henderson 
280431234768SRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2805b2167459SRichard Henderson {
2806eaa3783bSRichard Henderson     target_sreg im = low_sextract(insn, 0, 11);
2807b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2808b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2809b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2810eaa3783bSRichard Henderson     TCGv_reg tcg_im, tcg_r2;
2811b2167459SRichard Henderson 
2812b2167459SRichard Henderson     if (cf) {
2813b2167459SRichard Henderson         nullify_over(ctx);
2814b2167459SRichard Henderson     }
2815b2167459SRichard Henderson 
2816b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2817b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
281831234768SRichard Henderson     do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2819b2167459SRichard Henderson 
282031234768SRichard Henderson     return nullify_end(ctx);
2821b2167459SRichard Henderson }
2822b2167459SRichard Henderson 
28231cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
282496d6407fSRichard Henderson {
28251cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
28261cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
282796d6407fSRichard Henderson }
282896d6407fSRichard Henderson 
28291cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
283096d6407fSRichard Henderson {
28311cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
28321cd012a5SRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
283396d6407fSRichard Henderson }
283496d6407fSRichard Henderson 
28351cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
283696d6407fSRichard Henderson {
28371cd012a5SRichard Henderson     TCGMemOp mop = MO_TEUL | MO_ALIGN_16 | a->size;
283886f8d05fSRichard Henderson     TCGv_reg zero, dest, ofs;
283986f8d05fSRichard Henderson     TCGv_tl addr;
284096d6407fSRichard Henderson 
284196d6407fSRichard Henderson     nullify_over(ctx);
284296d6407fSRichard Henderson 
28431cd012a5SRichard Henderson     if (a->m) {
284486f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
284586f8d05fSRichard Henderson            we see the result of the load.  */
284696d6407fSRichard Henderson         dest = get_temp(ctx);
284796d6407fSRichard Henderson     } else {
28481cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
284996d6407fSRichard Henderson     }
285096d6407fSRichard Henderson 
28511cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0,
28521cd012a5SRichard Henderson              a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX);
2853eaa3783bSRichard Henderson     zero = tcg_const_reg(0);
285486f8d05fSRichard Henderson     tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop);
28551cd012a5SRichard Henderson     if (a->m) {
28561cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
285796d6407fSRichard Henderson     }
28581cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
285996d6407fSRichard Henderson 
286031234768SRichard Henderson     return nullify_end(ctx);
286196d6407fSRichard Henderson }
286296d6407fSRichard Henderson 
28631cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
286496d6407fSRichard Henderson {
286586f8d05fSRichard Henderson     TCGv_reg ofs, val;
286686f8d05fSRichard Henderson     TCGv_tl addr;
286796d6407fSRichard Henderson 
286896d6407fSRichard Henderson     nullify_over(ctx);
286996d6407fSRichard Henderson 
28701cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
287186f8d05fSRichard Henderson              ctx->mmu_idx == MMU_PHYS_IDX);
28721cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
28731cd012a5SRichard Henderson     if (a->a) {
2874f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2875f9f46db4SEmilio G. Cota             gen_helper_stby_e_parallel(cpu_env, addr, val);
2876f9f46db4SEmilio G. Cota         } else {
287796d6407fSRichard Henderson             gen_helper_stby_e(cpu_env, addr, val);
2878f9f46db4SEmilio G. Cota         }
2879f9f46db4SEmilio G. Cota     } else {
2880f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2881f9f46db4SEmilio G. Cota             gen_helper_stby_b_parallel(cpu_env, addr, val);
288296d6407fSRichard Henderson         } else {
288396d6407fSRichard Henderson             gen_helper_stby_b(cpu_env, addr, val);
288496d6407fSRichard Henderson         }
2885f9f46db4SEmilio G. Cota     }
28861cd012a5SRichard Henderson     if (a->m) {
288786f8d05fSRichard Henderson         tcg_gen_andi_reg(ofs, ofs, ~3);
28881cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
288996d6407fSRichard Henderson     }
289096d6407fSRichard Henderson 
289131234768SRichard Henderson     return nullify_end(ctx);
289296d6407fSRichard Henderson }
289396d6407fSRichard Henderson 
28941cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
2895d0a851ccSRichard Henderson {
2896d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2897d0a851ccSRichard Henderson 
2898d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2899d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29001cd012a5SRichard Henderson     trans_ld(ctx, a);
2901d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
290231234768SRichard Henderson     return true;
2903d0a851ccSRichard Henderson }
2904d0a851ccSRichard Henderson 
29051cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
2906d0a851ccSRichard Henderson {
2907d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
2908d0a851ccSRichard Henderson 
2909d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2910d0a851ccSRichard Henderson     ctx->mmu_idx = MMU_PHYS_IDX;
29111cd012a5SRichard Henderson     trans_st(ctx, a);
2912d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
291331234768SRichard Henderson     return true;
2914d0a851ccSRichard Henderson }
291595412a61SRichard Henderson 
291631234768SRichard Henderson static bool trans_ldil(DisasContext *ctx, uint32_t insn)
2917b2167459SRichard Henderson {
2918b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2919eaa3783bSRichard Henderson     target_sreg i = assemble_21(insn);
2920eaa3783bSRichard Henderson     TCGv_reg tcg_rt = dest_gpr(ctx, rt);
2921b2167459SRichard Henderson 
2922eaa3783bSRichard Henderson     tcg_gen_movi_reg(tcg_rt, i);
2923b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2924b2167459SRichard Henderson     cond_free(&ctx->null_cond);
292531234768SRichard Henderson     return true;
2926b2167459SRichard Henderson }
2927b2167459SRichard Henderson 
292831234768SRichard Henderson static bool trans_addil(DisasContext *ctx, uint32_t insn)
2929b2167459SRichard Henderson {
2930b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2931eaa3783bSRichard Henderson     target_sreg i = assemble_21(insn);
2932eaa3783bSRichard Henderson     TCGv_reg tcg_rt = load_gpr(ctx, rt);
2933eaa3783bSRichard Henderson     TCGv_reg tcg_r1 = dest_gpr(ctx, 1);
2934b2167459SRichard Henderson 
2935eaa3783bSRichard Henderson     tcg_gen_addi_reg(tcg_r1, tcg_rt, i);
2936b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2937b2167459SRichard Henderson     cond_free(&ctx->null_cond);
293831234768SRichard Henderson     return true;
2939b2167459SRichard Henderson }
2940b2167459SRichard Henderson 
294131234768SRichard Henderson static bool trans_ldo(DisasContext *ctx, uint32_t insn)
2942b2167459SRichard Henderson {
2943b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
2944b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2945eaa3783bSRichard Henderson     target_sreg i = assemble_16(insn);
2946eaa3783bSRichard Henderson     TCGv_reg tcg_rt = dest_gpr(ctx, rt);
2947b2167459SRichard Henderson 
2948b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2949b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2950b2167459SRichard Henderson     if (rb == 0) {
2951eaa3783bSRichard Henderson         tcg_gen_movi_reg(tcg_rt, i);
2952b2167459SRichard Henderson     } else {
2953eaa3783bSRichard Henderson         tcg_gen_addi_reg(tcg_rt, cpu_gr[rb], i);
2954b2167459SRichard Henderson     }
2955b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2956b2167459SRichard Henderson     cond_free(&ctx->null_cond);
295731234768SRichard Henderson     return true;
2958b2167459SRichard Henderson }
2959b2167459SRichard Henderson 
296031234768SRichard Henderson static bool trans_load(DisasContext *ctx, uint32_t insn,
296196d6407fSRichard Henderson                        bool is_mod, TCGMemOp mop)
296296d6407fSRichard Henderson {
296396d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
296496d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
296586f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
2966eaa3783bSRichard Henderson     target_sreg i = assemble_16(insn);
296796d6407fSRichard Henderson 
296831234768SRichard Henderson     do_load(ctx, rt, rb, 0, 0, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
296931234768SRichard Henderson     return true;
297096d6407fSRichard Henderson }
297196d6407fSRichard Henderson 
297231234768SRichard Henderson static bool trans_load_w(DisasContext *ctx, uint32_t insn)
297396d6407fSRichard Henderson {
297496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
297596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
297686f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
2977eaa3783bSRichard Henderson     target_sreg i = assemble_16a(insn);
297896d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
297996d6407fSRichard Henderson 
298096d6407fSRichard Henderson     switch (ext2) {
298196d6407fSRichard Henderson     case 0:
298296d6407fSRichard Henderson     case 1:
298396d6407fSRichard Henderson         /* FLDW without modification.  */
298431234768SRichard Henderson         do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
298531234768SRichard Henderson         break;
298696d6407fSRichard Henderson     case 2:
298796d6407fSRichard Henderson         /* LDW with modification.  Note that the sign of I selects
298896d6407fSRichard Henderson            post-dec vs pre-inc.  */
298931234768SRichard Henderson         do_load(ctx, rt, rb, 0, 0, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
299031234768SRichard Henderson         break;
299196d6407fSRichard Henderson     default:
299296d6407fSRichard Henderson         return gen_illegal(ctx);
299396d6407fSRichard Henderson     }
299431234768SRichard Henderson     return true;
299596d6407fSRichard Henderson }
299696d6407fSRichard Henderson 
299731234768SRichard Henderson static bool trans_fload_mod(DisasContext *ctx, uint32_t insn)
299896d6407fSRichard Henderson {
2999eaa3783bSRichard Henderson     target_sreg i = assemble_16a(insn);
300096d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
300196d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
300286f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
300396d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
300496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
300596d6407fSRichard Henderson 
300696d6407fSRichard Henderson     /* FLDW with modification.  */
300731234768SRichard Henderson     do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
300831234768SRichard Henderson     return true;
300996d6407fSRichard Henderson }
301096d6407fSRichard Henderson 
301131234768SRichard Henderson static bool trans_store(DisasContext *ctx, uint32_t insn,
301296d6407fSRichard Henderson                         bool is_mod, TCGMemOp mop)
301396d6407fSRichard Henderson {
301496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
301596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
301686f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
3017eaa3783bSRichard Henderson     target_sreg i = assemble_16(insn);
301896d6407fSRichard Henderson 
301931234768SRichard Henderson     do_store(ctx, rt, rb, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
302031234768SRichard Henderson     return true;
302196d6407fSRichard Henderson }
302296d6407fSRichard Henderson 
302331234768SRichard Henderson static bool trans_store_w(DisasContext *ctx, uint32_t insn)
302496d6407fSRichard Henderson {
302596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
302696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
302786f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
3028eaa3783bSRichard Henderson     target_sreg i = assemble_16a(insn);
302996d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
303096d6407fSRichard Henderson 
303196d6407fSRichard Henderson     switch (ext2) {
303296d6407fSRichard Henderson     case 0:
303396d6407fSRichard Henderson     case 1:
303496d6407fSRichard Henderson         /* FSTW without modification.  */
303531234768SRichard Henderson         do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
303631234768SRichard Henderson         break;
303796d6407fSRichard Henderson     case 2:
30383f7367e2SHelge Deller         /* STW with modification.  */
303931234768SRichard Henderson         do_store(ctx, rt, rb, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
304031234768SRichard Henderson         break;
304196d6407fSRichard Henderson     default:
304296d6407fSRichard Henderson         return gen_illegal(ctx);
304396d6407fSRichard Henderson     }
304431234768SRichard Henderson     return true;
304596d6407fSRichard Henderson }
304696d6407fSRichard Henderson 
304731234768SRichard Henderson static bool trans_fstore_mod(DisasContext *ctx, uint32_t insn)
304896d6407fSRichard Henderson {
3049eaa3783bSRichard Henderson     target_sreg i = assemble_16a(insn);
305096d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
305196d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
305286f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
305396d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
305496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
305596d6407fSRichard Henderson 
305696d6407fSRichard Henderson     /* FSTW with modification.  */
305731234768SRichard Henderson     do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
305831234768SRichard Henderson     return true;
305996d6407fSRichard Henderson }
306096d6407fSRichard Henderson 
306131234768SRichard Henderson static bool trans_copr_w(DisasContext *ctx, uint32_t insn)
306296d6407fSRichard Henderson {
306396d6407fSRichard Henderson     unsigned t0 = extract32(insn, 0, 5);
306496d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
306596d6407fSRichard Henderson     unsigned t1 = extract32(insn, 6, 1);
306696d6407fSRichard Henderson     unsigned ext3 = extract32(insn, 7, 3);
306796d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
306896d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
306996d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
307086f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
307196d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
307296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
307396d6407fSRichard Henderson     unsigned rt = t1 * 32 + t0;
307496d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
307596d6407fSRichard Henderson     int disp, scale;
307696d6407fSRichard Henderson 
307796d6407fSRichard Henderson     if (i == 0) {
307896d6407fSRichard Henderson         scale = (ua ? 2 : 0);
307996d6407fSRichard Henderson         disp = 0;
308096d6407fSRichard Henderson         modify = m;
308196d6407fSRichard Henderson     } else {
308296d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
308396d6407fSRichard Henderson         scale = 0;
308496d6407fSRichard Henderson         rx = 0;
308596d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
308696d6407fSRichard Henderson     }
308796d6407fSRichard Henderson 
308896d6407fSRichard Henderson     switch (ext3) {
308996d6407fSRichard Henderson     case 0: /* FLDW */
309031234768SRichard Henderson         do_floadw(ctx, rt, rb, rx, scale, disp, sp, modify);
309131234768SRichard Henderson         break;
309296d6407fSRichard Henderson     case 4: /* FSTW */
309331234768SRichard Henderson         do_fstorew(ctx, rt, rb, rx, scale, disp, sp, modify);
309431234768SRichard Henderson         break;
309531234768SRichard Henderson     default:
309696d6407fSRichard Henderson         return gen_illegal(ctx);
309796d6407fSRichard Henderson     }
309831234768SRichard Henderson     return true;
309931234768SRichard Henderson }
310096d6407fSRichard Henderson 
310131234768SRichard Henderson static bool trans_copr_dw(DisasContext *ctx, uint32_t insn)
310296d6407fSRichard Henderson {
310396d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
310496d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
310596d6407fSRichard Henderson     unsigned ext4 = extract32(insn, 6, 4);
310696d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
310796d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
310896d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
310986f8d05fSRichard Henderson     unsigned sp = extract32(insn, 14, 2);
311096d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
311196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
311296d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
311396d6407fSRichard Henderson     int disp, scale;
311496d6407fSRichard Henderson 
311596d6407fSRichard Henderson     if (i == 0) {
311696d6407fSRichard Henderson         scale = (ua ? 3 : 0);
311796d6407fSRichard Henderson         disp = 0;
311896d6407fSRichard Henderson         modify = m;
311996d6407fSRichard Henderson     } else {
312096d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
312196d6407fSRichard Henderson         scale = 0;
312296d6407fSRichard Henderson         rx = 0;
312396d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
312496d6407fSRichard Henderson     }
312596d6407fSRichard Henderson 
312696d6407fSRichard Henderson     switch (ext4) {
312796d6407fSRichard Henderson     case 0: /* FLDD */
312831234768SRichard Henderson         do_floadd(ctx, rt, rb, rx, scale, disp, sp, modify);
312931234768SRichard Henderson         break;
313096d6407fSRichard Henderson     case 8: /* FSTD */
313131234768SRichard Henderson         do_fstored(ctx, rt, rb, rx, scale, disp, sp, modify);
313231234768SRichard Henderson         break;
313396d6407fSRichard Henderson     default:
313496d6407fSRichard Henderson         return gen_illegal(ctx);
313596d6407fSRichard Henderson     }
313631234768SRichard Henderson     return true;
313796d6407fSRichard Henderson }
313896d6407fSRichard Henderson 
313901afb7beSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_reg in1,
314001afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
314198cd9ca7SRichard Henderson {
314201afb7beSRichard Henderson     TCGv_reg dest, in2, sv;
314398cd9ca7SRichard Henderson     DisasCond cond;
314498cd9ca7SRichard Henderson 
314598cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
314698cd9ca7SRichard Henderson     dest = get_temp(ctx);
314798cd9ca7SRichard Henderson 
3148eaa3783bSRichard Henderson     tcg_gen_sub_reg(dest, in1, in2);
314998cd9ca7SRichard Henderson 
3150f764718dSRichard Henderson     sv = NULL;
315198cd9ca7SRichard Henderson     if (c == 6) {
315298cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
315398cd9ca7SRichard Henderson     }
315498cd9ca7SRichard Henderson 
315501afb7beSRichard Henderson     cond = do_sub_cond(c * 2 + f, dest, in1, in2, sv);
315601afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
315798cd9ca7SRichard Henderson }
315898cd9ca7SRichard Henderson 
315901afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
316098cd9ca7SRichard Henderson {
316101afb7beSRichard Henderson     nullify_over(ctx);
316201afb7beSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
316301afb7beSRichard Henderson }
316401afb7beSRichard Henderson 
316501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
316601afb7beSRichard Henderson {
316701afb7beSRichard Henderson     nullify_over(ctx);
316801afb7beSRichard Henderson     return do_cmpb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp);
316901afb7beSRichard Henderson }
317001afb7beSRichard Henderson 
317101afb7beSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1,
317201afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
317301afb7beSRichard Henderson {
317401afb7beSRichard Henderson     TCGv_reg dest, in2, sv, cb_msb;
317598cd9ca7SRichard Henderson     DisasCond cond;
317698cd9ca7SRichard Henderson 
317798cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
317898cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
3179f764718dSRichard Henderson     sv = NULL;
3180f764718dSRichard Henderson     cb_msb = NULL;
318198cd9ca7SRichard Henderson 
318298cd9ca7SRichard Henderson     switch (c) {
318398cd9ca7SRichard Henderson     default:
3184eaa3783bSRichard Henderson         tcg_gen_add_reg(dest, in1, in2);
318598cd9ca7SRichard Henderson         break;
318698cd9ca7SRichard Henderson     case 4: case 5:
318798cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
3188eaa3783bSRichard Henderson         tcg_gen_movi_reg(cb_msb, 0);
3189eaa3783bSRichard Henderson         tcg_gen_add2_reg(dest, cb_msb, in1, cb_msb, in2, cb_msb);
319098cd9ca7SRichard Henderson         break;
319198cd9ca7SRichard Henderson     case 6:
3192eaa3783bSRichard Henderson         tcg_gen_add_reg(dest, in1, in2);
319398cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
319498cd9ca7SRichard Henderson         break;
319598cd9ca7SRichard Henderson     }
319698cd9ca7SRichard Henderson 
319701afb7beSRichard Henderson     cond = do_cond(c * 2 + f, dest, cb_msb, sv);
319801afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
319998cd9ca7SRichard Henderson }
320098cd9ca7SRichard Henderson 
320101afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
320298cd9ca7SRichard Henderson {
320301afb7beSRichard Henderson     nullify_over(ctx);
320401afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
320501afb7beSRichard Henderson }
320601afb7beSRichard Henderson 
320701afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
320801afb7beSRichard Henderson {
320901afb7beSRichard Henderson     nullify_over(ctx);
321001afb7beSRichard Henderson     return do_addb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp);
321101afb7beSRichard Henderson }
321201afb7beSRichard Henderson 
321301afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
321401afb7beSRichard Henderson {
3215eaa3783bSRichard Henderson     TCGv_reg tmp, tcg_r;
321698cd9ca7SRichard Henderson     DisasCond cond;
321798cd9ca7SRichard Henderson 
321898cd9ca7SRichard Henderson     nullify_over(ctx);
321998cd9ca7SRichard Henderson 
322098cd9ca7SRichard Henderson     tmp = tcg_temp_new();
322101afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
3222eaa3783bSRichard Henderson     tcg_gen_shl_reg(tmp, tcg_r, cpu_sar);
322398cd9ca7SRichard Henderson 
322401afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
322598cd9ca7SRichard Henderson     tcg_temp_free(tmp);
322601afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
322798cd9ca7SRichard Henderson }
322898cd9ca7SRichard Henderson 
322901afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
323098cd9ca7SRichard Henderson {
323101afb7beSRichard Henderson     TCGv_reg tmp, tcg_r;
323201afb7beSRichard Henderson     DisasCond cond;
323301afb7beSRichard Henderson 
323401afb7beSRichard Henderson     nullify_over(ctx);
323501afb7beSRichard Henderson 
323601afb7beSRichard Henderson     tmp = tcg_temp_new();
323701afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
323801afb7beSRichard Henderson     tcg_gen_shli_reg(tmp, tcg_r, a->p);
323901afb7beSRichard Henderson 
324001afb7beSRichard Henderson     cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp);
324101afb7beSRichard Henderson     tcg_temp_free(tmp);
324201afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
324301afb7beSRichard Henderson }
324401afb7beSRichard Henderson 
324501afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
324601afb7beSRichard Henderson {
3247eaa3783bSRichard Henderson     TCGv_reg dest;
324898cd9ca7SRichard Henderson     DisasCond cond;
324998cd9ca7SRichard Henderson 
325098cd9ca7SRichard Henderson     nullify_over(ctx);
325198cd9ca7SRichard Henderson 
325201afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
325301afb7beSRichard Henderson     if (a->r1 == 0) {
3254eaa3783bSRichard Henderson         tcg_gen_movi_reg(dest, 0);
325598cd9ca7SRichard Henderson     } else {
325601afb7beSRichard Henderson         tcg_gen_mov_reg(dest, cpu_gr[a->r1]);
325798cd9ca7SRichard Henderson     }
325898cd9ca7SRichard Henderson 
325901afb7beSRichard Henderson     cond = do_sed_cond(a->c, dest);
326001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
326101afb7beSRichard Henderson }
326201afb7beSRichard Henderson 
326301afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
326401afb7beSRichard Henderson {
326501afb7beSRichard Henderson     TCGv_reg dest;
326601afb7beSRichard Henderson     DisasCond cond;
326701afb7beSRichard Henderson 
326801afb7beSRichard Henderson     nullify_over(ctx);
326901afb7beSRichard Henderson 
327001afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
327101afb7beSRichard Henderson     tcg_gen_movi_reg(dest, a->i);
327201afb7beSRichard Henderson 
327301afb7beSRichard Henderson     cond = do_sed_cond(a->c, dest);
327401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
327598cd9ca7SRichard Henderson }
327698cd9ca7SRichard Henderson 
327730878590SRichard Henderson static bool trans_shrpw_sar(DisasContext *ctx, arg_shrpw_sar *a)
32780b1347d2SRichard Henderson {
3279eaa3783bSRichard Henderson     TCGv_reg dest;
32800b1347d2SRichard Henderson 
328130878590SRichard Henderson     if (a->c) {
32820b1347d2SRichard Henderson         nullify_over(ctx);
32830b1347d2SRichard Henderson     }
32840b1347d2SRichard Henderson 
328530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
328630878590SRichard Henderson     if (a->r1 == 0) {
328730878590SRichard Henderson         tcg_gen_ext32u_reg(dest, load_gpr(ctx, a->r2));
3288eaa3783bSRichard Henderson         tcg_gen_shr_reg(dest, dest, cpu_sar);
328930878590SRichard Henderson     } else if (a->r1 == a->r2) {
32900b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
329130878590SRichard Henderson         tcg_gen_trunc_reg_i32(t32, load_gpr(ctx, a->r2));
32920b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
3293eaa3783bSRichard Henderson         tcg_gen_extu_i32_reg(dest, t32);
32940b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
32950b1347d2SRichard Henderson     } else {
32960b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
32970b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
32980b1347d2SRichard Henderson 
329930878590SRichard Henderson         tcg_gen_concat_reg_i64(t, load_gpr(ctx, a->r2), load_gpr(ctx, a->r1));
3300eaa3783bSRichard Henderson         tcg_gen_extu_reg_i64(s, cpu_sar);
33010b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
3302eaa3783bSRichard Henderson         tcg_gen_trunc_i64_reg(dest, t);
33030b1347d2SRichard Henderson 
33040b1347d2SRichard Henderson         tcg_temp_free_i64(t);
33050b1347d2SRichard Henderson         tcg_temp_free_i64(s);
33060b1347d2SRichard Henderson     }
330730878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33080b1347d2SRichard Henderson 
33090b1347d2SRichard Henderson     /* Install the new nullification.  */
33100b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
331130878590SRichard Henderson     if (a->c) {
331230878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
33130b1347d2SRichard Henderson     }
331431234768SRichard Henderson     return nullify_end(ctx);
33150b1347d2SRichard Henderson }
33160b1347d2SRichard Henderson 
331730878590SRichard Henderson static bool trans_shrpw_imm(DisasContext *ctx, arg_shrpw_imm *a)
33180b1347d2SRichard Henderson {
331930878590SRichard Henderson     unsigned sa = 31 - a->cpos;
3320eaa3783bSRichard Henderson     TCGv_reg dest, t2;
33210b1347d2SRichard Henderson 
332230878590SRichard Henderson     if (a->c) {
33230b1347d2SRichard Henderson         nullify_over(ctx);
33240b1347d2SRichard Henderson     }
33250b1347d2SRichard Henderson 
332630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
332730878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
332830878590SRichard Henderson     if (a->r1 == a->r2) {
33290b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
3330eaa3783bSRichard Henderson         tcg_gen_trunc_reg_i32(t32, t2);
33310b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
3332eaa3783bSRichard Henderson         tcg_gen_extu_i32_reg(dest, t32);
33330b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
333430878590SRichard Henderson     } else if (a->r1 == 0) {
3335eaa3783bSRichard Henderson         tcg_gen_extract_reg(dest, t2, sa, 32 - sa);
33360b1347d2SRichard Henderson     } else {
3337eaa3783bSRichard Henderson         TCGv_reg t0 = tcg_temp_new();
3338eaa3783bSRichard Henderson         tcg_gen_extract_reg(t0, t2, sa, 32 - sa);
333930878590SRichard Henderson         tcg_gen_deposit_reg(dest, t0, cpu_gr[a->r1], 32 - sa, sa);
33400b1347d2SRichard Henderson         tcg_temp_free(t0);
33410b1347d2SRichard Henderson     }
334230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33430b1347d2SRichard Henderson 
33440b1347d2SRichard Henderson     /* Install the new nullification.  */
33450b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
334630878590SRichard Henderson     if (a->c) {
334730878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
33480b1347d2SRichard Henderson     }
334931234768SRichard Henderson     return nullify_end(ctx);
33500b1347d2SRichard Henderson }
33510b1347d2SRichard Henderson 
335230878590SRichard Henderson static bool trans_extrw_sar(DisasContext *ctx, arg_extrw_sar *a)
33530b1347d2SRichard Henderson {
335430878590SRichard Henderson     unsigned len = 32 - a->clen;
3355eaa3783bSRichard Henderson     TCGv_reg dest, src, tmp;
33560b1347d2SRichard Henderson 
335730878590SRichard Henderson     if (a->c) {
33580b1347d2SRichard Henderson         nullify_over(ctx);
33590b1347d2SRichard Henderson     }
33600b1347d2SRichard Henderson 
336130878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
336230878590SRichard Henderson     src = load_gpr(ctx, a->r);
33630b1347d2SRichard Henderson     tmp = tcg_temp_new();
33640b1347d2SRichard Henderson 
33650b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
3366eaa3783bSRichard Henderson     tcg_gen_xori_reg(tmp, cpu_sar, TARGET_REGISTER_BITS - 1);
336730878590SRichard Henderson     if (a->se) {
3368eaa3783bSRichard Henderson         tcg_gen_sar_reg(dest, src, tmp);
3369eaa3783bSRichard Henderson         tcg_gen_sextract_reg(dest, dest, 0, len);
33700b1347d2SRichard Henderson     } else {
3371eaa3783bSRichard Henderson         tcg_gen_shr_reg(dest, src, tmp);
3372eaa3783bSRichard Henderson         tcg_gen_extract_reg(dest, dest, 0, len);
33730b1347d2SRichard Henderson     }
33740b1347d2SRichard Henderson     tcg_temp_free(tmp);
337530878590SRichard Henderson     save_gpr(ctx, a->t, dest);
33760b1347d2SRichard Henderson 
33770b1347d2SRichard Henderson     /* Install the new nullification.  */
33780b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
337930878590SRichard Henderson     if (a->c) {
338030878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
33810b1347d2SRichard Henderson     }
338231234768SRichard Henderson     return nullify_end(ctx);
33830b1347d2SRichard Henderson }
33840b1347d2SRichard Henderson 
338530878590SRichard Henderson static bool trans_extrw_imm(DisasContext *ctx, arg_extrw_imm *a)
33860b1347d2SRichard Henderson {
338730878590SRichard Henderson     unsigned len = 32 - a->clen;
338830878590SRichard Henderson     unsigned cpos = 31 - a->pos;
3389eaa3783bSRichard Henderson     TCGv_reg dest, src;
33900b1347d2SRichard Henderson 
339130878590SRichard Henderson     if (a->c) {
33920b1347d2SRichard Henderson         nullify_over(ctx);
33930b1347d2SRichard Henderson     }
33940b1347d2SRichard Henderson 
339530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
339630878590SRichard Henderson     src = load_gpr(ctx, a->r);
339730878590SRichard Henderson     if (a->se) {
3398eaa3783bSRichard Henderson         tcg_gen_sextract_reg(dest, src, cpos, len);
33990b1347d2SRichard Henderson     } else {
3400eaa3783bSRichard Henderson         tcg_gen_extract_reg(dest, src, cpos, len);
34010b1347d2SRichard Henderson     }
340230878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34030b1347d2SRichard Henderson 
34040b1347d2SRichard Henderson     /* Install the new nullification.  */
34050b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
340630878590SRichard Henderson     if (a->c) {
340730878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
34080b1347d2SRichard Henderson     }
340931234768SRichard Henderson     return nullify_end(ctx);
34100b1347d2SRichard Henderson }
34110b1347d2SRichard Henderson 
341230878590SRichard Henderson static bool trans_depwi_imm(DisasContext *ctx, arg_depwi_imm *a)
34130b1347d2SRichard Henderson {
341430878590SRichard Henderson     unsigned len = 32 - a->clen;
3415eaa3783bSRichard Henderson     target_sreg mask0, mask1;
3416eaa3783bSRichard Henderson     TCGv_reg dest;
34170b1347d2SRichard Henderson 
341830878590SRichard Henderson     if (a->c) {
34190b1347d2SRichard Henderson         nullify_over(ctx);
34200b1347d2SRichard Henderson     }
342130878590SRichard Henderson     if (a->cpos + len > 32) {
342230878590SRichard Henderson         len = 32 - a->cpos;
34230b1347d2SRichard Henderson     }
34240b1347d2SRichard Henderson 
342530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
342630878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
342730878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
34280b1347d2SRichard Henderson 
342930878590SRichard Henderson     if (a->nz) {
343030878590SRichard Henderson         TCGv_reg src = load_gpr(ctx, a->t);
34310b1347d2SRichard Henderson         if (mask1 != -1) {
3432eaa3783bSRichard Henderson             tcg_gen_andi_reg(dest, src, mask1);
34330b1347d2SRichard Henderson             src = dest;
34340b1347d2SRichard Henderson         }
3435eaa3783bSRichard Henderson         tcg_gen_ori_reg(dest, src, mask0);
34360b1347d2SRichard Henderson     } else {
3437eaa3783bSRichard Henderson         tcg_gen_movi_reg(dest, mask0);
34380b1347d2SRichard Henderson     }
343930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34400b1347d2SRichard Henderson 
34410b1347d2SRichard Henderson     /* Install the new nullification.  */
34420b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
344330878590SRichard Henderson     if (a->c) {
344430878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
34450b1347d2SRichard Henderson     }
344631234768SRichard Henderson     return nullify_end(ctx);
34470b1347d2SRichard Henderson }
34480b1347d2SRichard Henderson 
344930878590SRichard Henderson static bool trans_depw_imm(DisasContext *ctx, arg_depw_imm *a)
34500b1347d2SRichard Henderson {
345130878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
345230878590SRichard Henderson     unsigned len = 32 - a->clen;
3453eaa3783bSRichard Henderson     TCGv_reg dest, val;
34540b1347d2SRichard Henderson 
345530878590SRichard Henderson     if (a->c) {
34560b1347d2SRichard Henderson         nullify_over(ctx);
34570b1347d2SRichard Henderson     }
345830878590SRichard Henderson     if (a->cpos + len > 32) {
345930878590SRichard Henderson         len = 32 - a->cpos;
34600b1347d2SRichard Henderson     }
34610b1347d2SRichard Henderson 
346230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
346330878590SRichard Henderson     val = load_gpr(ctx, a->r);
34640b1347d2SRichard Henderson     if (rs == 0) {
346530878590SRichard Henderson         tcg_gen_deposit_z_reg(dest, val, a->cpos, len);
34660b1347d2SRichard Henderson     } else {
346730878590SRichard Henderson         tcg_gen_deposit_reg(dest, cpu_gr[rs], val, a->cpos, len);
34680b1347d2SRichard Henderson     }
346930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
34700b1347d2SRichard Henderson 
34710b1347d2SRichard Henderson     /* Install the new nullification.  */
34720b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
347330878590SRichard Henderson     if (a->c) {
347430878590SRichard Henderson         ctx->null_cond = do_sed_cond(a->c, dest);
34750b1347d2SRichard Henderson     }
347631234768SRichard Henderson     return nullify_end(ctx);
34770b1347d2SRichard Henderson }
34780b1347d2SRichard Henderson 
347930878590SRichard Henderson static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c,
348030878590SRichard Henderson                         unsigned nz, unsigned clen, TCGv_reg val)
34810b1347d2SRichard Henderson {
34820b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
34830b1347d2SRichard Henderson     unsigned len = 32 - clen;
348430878590SRichard Henderson     TCGv_reg mask, tmp, shift, dest;
34850b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
34860b1347d2SRichard Henderson 
34870b1347d2SRichard Henderson     if (c) {
34880b1347d2SRichard Henderson         nullify_over(ctx);
34890b1347d2SRichard Henderson     }
34900b1347d2SRichard Henderson 
34910b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
34920b1347d2SRichard Henderson     shift = tcg_temp_new();
34930b1347d2SRichard Henderson     tmp = tcg_temp_new();
34940b1347d2SRichard Henderson 
34950b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
3496eaa3783bSRichard Henderson     tcg_gen_xori_reg(shift, cpu_sar, TARGET_REGISTER_BITS - 1);
34970b1347d2SRichard Henderson 
3498eaa3783bSRichard Henderson     mask = tcg_const_reg(msb + (msb - 1));
3499eaa3783bSRichard Henderson     tcg_gen_and_reg(tmp, val, mask);
35000b1347d2SRichard Henderson     if (rs) {
3501eaa3783bSRichard Henderson         tcg_gen_shl_reg(mask, mask, shift);
3502eaa3783bSRichard Henderson         tcg_gen_shl_reg(tmp, tmp, shift);
3503eaa3783bSRichard Henderson         tcg_gen_andc_reg(dest, cpu_gr[rs], mask);
3504eaa3783bSRichard Henderson         tcg_gen_or_reg(dest, dest, tmp);
35050b1347d2SRichard Henderson     } else {
3506eaa3783bSRichard Henderson         tcg_gen_shl_reg(dest, tmp, shift);
35070b1347d2SRichard Henderson     }
35080b1347d2SRichard Henderson     tcg_temp_free(shift);
35090b1347d2SRichard Henderson     tcg_temp_free(mask);
35100b1347d2SRichard Henderson     tcg_temp_free(tmp);
35110b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
35120b1347d2SRichard Henderson 
35130b1347d2SRichard Henderson     /* Install the new nullification.  */
35140b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
35150b1347d2SRichard Henderson     if (c) {
35160b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
35170b1347d2SRichard Henderson     }
351831234768SRichard Henderson     return nullify_end(ctx);
35190b1347d2SRichard Henderson }
35200b1347d2SRichard Henderson 
352130878590SRichard Henderson static bool trans_depw_sar(DisasContext *ctx, arg_depw_sar *a)
352230878590SRichard Henderson {
352330878590SRichard Henderson     return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_gpr(ctx, a->r));
352430878590SRichard Henderson }
352530878590SRichard Henderson 
352630878590SRichard Henderson static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a)
352730878590SRichard Henderson {
352830878590SRichard Henderson     return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i));
352930878590SRichard Henderson }
35300b1347d2SRichard Henderson 
3531*8340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
353298cd9ca7SRichard Henderson {
3533660eefe1SRichard Henderson     TCGv_reg tmp;
353498cd9ca7SRichard Henderson 
3535c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
353698cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
353798cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
353898cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
353998cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
354098cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
354198cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
354298cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
354398cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
3544*8340f534SRichard Henderson     if (a->b == 0) {
3545*8340f534SRichard Henderson         return do_dbranch(ctx, a->disp, a->l, a->n);
354698cd9ca7SRichard Henderson     }
3547c301f34eSRichard Henderson #else
3548c301f34eSRichard Henderson     nullify_over(ctx);
3549660eefe1SRichard Henderson #endif
3550660eefe1SRichard Henderson 
3551660eefe1SRichard Henderson     tmp = get_temp(ctx);
3552*8340f534SRichard Henderson     tcg_gen_addi_reg(tmp, load_gpr(ctx, a->b), a->disp);
3553660eefe1SRichard Henderson     tmp = do_ibranch_priv(ctx, tmp);
3554c301f34eSRichard Henderson 
3555c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
3556*8340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
3557c301f34eSRichard Henderson #else
3558c301f34eSRichard Henderson     TCGv_i64 new_spc = tcg_temp_new_i64();
3559c301f34eSRichard Henderson 
3560*8340f534SRichard Henderson     load_spr(ctx, new_spc, a->sp);
3561*8340f534SRichard Henderson     if (a->l) {
3562c301f34eSRichard Henderson         copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3563c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3564c301f34eSRichard Henderson     }
3565*8340f534SRichard Henderson     if (a->n && use_nullify_skip(ctx)) {
3566c301f34eSRichard Henderson         tcg_gen_mov_reg(cpu_iaoq_f, tmp);
3567c301f34eSRichard Henderson         tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
3568c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3569c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3570c301f34eSRichard Henderson     } else {
3571c301f34eSRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3572c301f34eSRichard Henderson         if (ctx->iaoq_b == -1) {
3573c301f34eSRichard Henderson             tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3574c301f34eSRichard Henderson         }
3575c301f34eSRichard Henderson         tcg_gen_mov_reg(cpu_iaoq_b, tmp);
3576c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, new_spc);
3577*8340f534SRichard Henderson         nullify_set(ctx, a->n);
3578c301f34eSRichard Henderson     }
3579c301f34eSRichard Henderson     tcg_temp_free_i64(new_spc);
3580c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
358131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
358231234768SRichard Henderson     return nullify_end(ctx);
3583c301f34eSRichard Henderson #endif
358498cd9ca7SRichard Henderson }
358598cd9ca7SRichard Henderson 
3586*8340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
358798cd9ca7SRichard Henderson {
3588*8340f534SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
358998cd9ca7SRichard Henderson }
359098cd9ca7SRichard Henderson 
3591*8340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
359243e05652SRichard Henderson {
3593*8340f534SRichard Henderson     target_ureg dest = iaoq_dest(ctx, a->disp);
359443e05652SRichard Henderson 
359543e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
359643e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
359743e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
359843e05652SRichard Henderson      *    b  gateway
359943e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
360043e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
360143e05652SRichard Henderson      * diagnose the security hole
360243e05652SRichard Henderson      *    b  gateway
360343e05652SRichard Henderson      *    b  evil
360443e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
360543e05652SRichard Henderson      */
360643e05652SRichard Henderson     if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
360743e05652SRichard Henderson         return gen_illegal(ctx);
360843e05652SRichard Henderson     }
360943e05652SRichard Henderson 
361043e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
361143e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
361243e05652SRichard Henderson         CPUHPPAState *env = ctx->cs->env_ptr;
361343e05652SRichard Henderson         int type = hppa_artype_for_page(env, ctx->base.pc_next);
361443e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
361543e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
361643e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
361743e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
361843e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
361943e05652SRichard Henderson         if (type < 0) {
362031234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
362131234768SRichard Henderson             return true;
362243e05652SRichard Henderson         }
362343e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
362443e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
362543e05652SRichard Henderson             dest = deposit32(dest, 0, 2, type - 4);
362643e05652SRichard Henderson         }
362743e05652SRichard Henderson     } else {
362843e05652SRichard Henderson         dest &= -4;  /* priv = 0 */
362943e05652SRichard Henderson     }
363043e05652SRichard Henderson #endif
363143e05652SRichard Henderson 
3632*8340f534SRichard Henderson     return do_dbranch(ctx, dest, a->l, a->n);
363343e05652SRichard Henderson }
363443e05652SRichard Henderson 
3635*8340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
363698cd9ca7SRichard Henderson {
3637eaa3783bSRichard Henderson     TCGv_reg tmp = get_temp(ctx);
363898cd9ca7SRichard Henderson 
3639*8340f534SRichard Henderson     tcg_gen_shli_reg(tmp, load_gpr(ctx, a->x), 3);
3640eaa3783bSRichard Henderson     tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
3641660eefe1SRichard Henderson     /* The computation here never changes privilege level.  */
3642*8340f534SRichard Henderson     return do_ibranch(ctx, tmp, a->l, a->n);
364398cd9ca7SRichard Henderson }
364498cd9ca7SRichard Henderson 
3645*8340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
364698cd9ca7SRichard Henderson {
3647eaa3783bSRichard Henderson     TCGv_reg dest;
364898cd9ca7SRichard Henderson 
3649*8340f534SRichard Henderson     if (a->x == 0) {
3650*8340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
365198cd9ca7SRichard Henderson     } else {
365298cd9ca7SRichard Henderson         dest = get_temp(ctx);
3653*8340f534SRichard Henderson         tcg_gen_shli_reg(dest, load_gpr(ctx, a->x), 3);
3654*8340f534SRichard Henderson         tcg_gen_add_reg(dest, dest, load_gpr(ctx, a->b));
365598cd9ca7SRichard Henderson     }
3656660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
3657*8340f534SRichard Henderson     return do_ibranch(ctx, dest, 0, a->n);
365898cd9ca7SRichard Henderson }
365998cd9ca7SRichard Henderson 
3660*8340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
366198cd9ca7SRichard Henderson {
3662660eefe1SRichard Henderson     TCGv_reg dest;
366398cd9ca7SRichard Henderson 
3664c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY
3665*8340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3666*8340f534SRichard Henderson     return do_ibranch(ctx, dest, a->l, a->n);
3667c301f34eSRichard Henderson #else
3668c301f34eSRichard Henderson     nullify_over(ctx);
3669*8340f534SRichard Henderson     dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
3670c301f34eSRichard Henderson 
3671c301f34eSRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3672c301f34eSRichard Henderson     if (ctx->iaoq_b == -1) {
3673c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3674c301f34eSRichard Henderson     }
3675c301f34eSRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, -1, dest);
3676c301f34eSRichard Henderson     tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
3677*8340f534SRichard Henderson     if (a->l) {
3678*8340f534SRichard Henderson         copy_iaoq_entry(cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
3679c301f34eSRichard Henderson     }
3680*8340f534SRichard Henderson     nullify_set(ctx, a->n);
3681c301f34eSRichard Henderson     tcg_gen_lookup_and_goto_ptr();
368231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
368331234768SRichard Henderson     return nullify_end(ctx);
3684c301f34eSRichard Henderson #endif
368598cd9ca7SRichard Henderson }
368698cd9ca7SRichard Henderson 
368731234768SRichard Henderson static bool trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3688ebe9383cSRichard Henderson                              const DisasInsn *di)
3689ebe9383cSRichard Henderson {
3690ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3691ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
369231234768SRichard Henderson     do_fop_wew(ctx, rt, ra, di->f.wew);
369331234768SRichard Henderson     return true;
3694ebe9383cSRichard Henderson }
3695ebe9383cSRichard Henderson 
369631234768SRichard Henderson static bool trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3697ebe9383cSRichard Henderson                              const DisasInsn *di)
3698ebe9383cSRichard Henderson {
3699ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3700ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
370131234768SRichard Henderson     do_fop_wew(ctx, rt, ra, di->f.wew);
370231234768SRichard Henderson     return true;
3703ebe9383cSRichard Henderson }
3704ebe9383cSRichard Henderson 
370531234768SRichard Henderson static bool trans_fop_ded(DisasContext *ctx, uint32_t insn,
3706ebe9383cSRichard Henderson                           const DisasInsn *di)
3707ebe9383cSRichard Henderson {
3708ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3709ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
371031234768SRichard Henderson     do_fop_ded(ctx, rt, ra, di->f.ded);
371131234768SRichard Henderson     return true;
3712ebe9383cSRichard Henderson }
3713ebe9383cSRichard Henderson 
371431234768SRichard Henderson static bool trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3715ebe9383cSRichard Henderson                              const DisasInsn *di)
3716ebe9383cSRichard Henderson {
3717ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3718ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
371931234768SRichard Henderson     do_fop_wed(ctx, rt, ra, di->f.wed);
372031234768SRichard Henderson     return true;
3721ebe9383cSRichard Henderson }
3722ebe9383cSRichard Henderson 
372331234768SRichard Henderson static bool trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3724ebe9383cSRichard Henderson                              const DisasInsn *di)
3725ebe9383cSRichard Henderson {
3726ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3727ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
372831234768SRichard Henderson     do_fop_wed(ctx, rt, ra, di->f.wed);
372931234768SRichard Henderson     return true;
3730ebe9383cSRichard Henderson }
3731ebe9383cSRichard Henderson 
373231234768SRichard Henderson static bool trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3733ebe9383cSRichard Henderson                              const DisasInsn *di)
3734ebe9383cSRichard Henderson {
3735ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3736ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
373731234768SRichard Henderson     do_fop_dew(ctx, rt, ra, di->f.dew);
373831234768SRichard Henderson     return true;
3739ebe9383cSRichard Henderson }
3740ebe9383cSRichard Henderson 
374131234768SRichard Henderson static bool trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3742ebe9383cSRichard Henderson                              const DisasInsn *di)
3743ebe9383cSRichard Henderson {
3744ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3745ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
374631234768SRichard Henderson     do_fop_dew(ctx, rt, ra, di->f.dew);
374731234768SRichard Henderson     return true;
3748ebe9383cSRichard Henderson }
3749ebe9383cSRichard Henderson 
375031234768SRichard Henderson static bool trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3751ebe9383cSRichard Henderson                               const DisasInsn *di)
3752ebe9383cSRichard Henderson {
3753ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3754ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3755ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
375631234768SRichard Henderson     do_fop_weww(ctx, rt, ra, rb, di->f.weww);
375731234768SRichard Henderson     return true;
3758ebe9383cSRichard Henderson }
3759ebe9383cSRichard Henderson 
376031234768SRichard Henderson static bool trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3761ebe9383cSRichard Henderson                               const DisasInsn *di)
3762ebe9383cSRichard Henderson {
3763ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3764ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3765ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
376631234768SRichard Henderson     do_fop_weww(ctx, rt, ra, rb, di->f.weww);
376731234768SRichard Henderson     return true;
3768ebe9383cSRichard Henderson }
3769ebe9383cSRichard Henderson 
377031234768SRichard Henderson static bool trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3771ebe9383cSRichard Henderson                            const DisasInsn *di)
3772ebe9383cSRichard Henderson {
3773ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3774ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3775ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
377631234768SRichard Henderson     do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
377731234768SRichard Henderson     return true;
3778ebe9383cSRichard Henderson }
3779ebe9383cSRichard Henderson 
3780ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3781ebe9383cSRichard Henderson {
3782ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3783ebe9383cSRichard Henderson }
3784ebe9383cSRichard Henderson 
3785ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3786ebe9383cSRichard Henderson {
3787ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3788ebe9383cSRichard Henderson }
3789ebe9383cSRichard Henderson 
3790ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3791ebe9383cSRichard Henderson {
3792ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3793ebe9383cSRichard Henderson }
3794ebe9383cSRichard Henderson 
3795ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3796ebe9383cSRichard Henderson {
3797ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3798ebe9383cSRichard Henderson }
3799ebe9383cSRichard Henderson 
3800ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3801ebe9383cSRichard Henderson {
3802ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3803ebe9383cSRichard Henderson }
3804ebe9383cSRichard Henderson 
3805ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3806ebe9383cSRichard Henderson {
3807ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3808ebe9383cSRichard Henderson }
3809ebe9383cSRichard Henderson 
3810ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3811ebe9383cSRichard Henderson {
3812ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3813ebe9383cSRichard Henderson }
3814ebe9383cSRichard Henderson 
3815ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3816ebe9383cSRichard Henderson {
3817ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3818ebe9383cSRichard Henderson }
3819ebe9383cSRichard Henderson 
382031234768SRichard Henderson static void do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3821ebe9383cSRichard Henderson                       unsigned y, unsigned c)
3822ebe9383cSRichard Henderson {
3823ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3824ebe9383cSRichard Henderson 
3825ebe9383cSRichard Henderson     nullify_over(ctx);
3826ebe9383cSRichard Henderson 
3827ebe9383cSRichard Henderson     ta = load_frw0_i32(ra);
3828ebe9383cSRichard Henderson     tb = load_frw0_i32(rb);
3829ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3830ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3831ebe9383cSRichard Henderson 
3832ebe9383cSRichard Henderson     gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3833ebe9383cSRichard Henderson 
3834ebe9383cSRichard Henderson     tcg_temp_free_i32(ta);
3835ebe9383cSRichard Henderson     tcg_temp_free_i32(tb);
3836ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3837ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3838ebe9383cSRichard Henderson 
383931234768SRichard Henderson     nullify_end(ctx);
3840ebe9383cSRichard Henderson }
3841ebe9383cSRichard Henderson 
384231234768SRichard Henderson static bool trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3843ebe9383cSRichard Henderson                             const DisasInsn *di)
3844ebe9383cSRichard Henderson {
3845ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3846ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3847ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3848ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
384931234768SRichard Henderson     do_fcmp_s(ctx, ra, rb, y, c);
385031234768SRichard Henderson     return true;
3851ebe9383cSRichard Henderson }
3852ebe9383cSRichard Henderson 
385331234768SRichard Henderson static bool trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3854ebe9383cSRichard Henderson                             const DisasInsn *di)
3855ebe9383cSRichard Henderson {
3856ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3857ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3858ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3859ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
386031234768SRichard Henderson     do_fcmp_s(ctx, ra, rb, y, c);
386131234768SRichard Henderson     return true;
3862ebe9383cSRichard Henderson }
3863ebe9383cSRichard Henderson 
386431234768SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
3865ebe9383cSRichard Henderson {
3866ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3867ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3868ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3869ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3870ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3871ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3872ebe9383cSRichard Henderson 
3873ebe9383cSRichard Henderson     nullify_over(ctx);
3874ebe9383cSRichard Henderson 
3875ebe9383cSRichard Henderson     ta = load_frd0(ra);
3876ebe9383cSRichard Henderson     tb = load_frd0(rb);
3877ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3878ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3879ebe9383cSRichard Henderson 
3880ebe9383cSRichard Henderson     gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3881ebe9383cSRichard Henderson 
3882ebe9383cSRichard Henderson     tcg_temp_free_i64(ta);
3883ebe9383cSRichard Henderson     tcg_temp_free_i64(tb);
3884ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3885ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3886ebe9383cSRichard Henderson 
388731234768SRichard Henderson     return nullify_end(ctx);
3888ebe9383cSRichard Henderson }
3889ebe9383cSRichard Henderson 
389031234768SRichard Henderson static bool trans_ftest_t(DisasContext *ctx, uint32_t insn,
3891ebe9383cSRichard Henderson                           const DisasInsn *di)
3892ebe9383cSRichard Henderson {
3893ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3894ebe9383cSRichard Henderson     unsigned cbit = (y ^ 1) - 1;
3895eaa3783bSRichard Henderson     TCGv_reg t;
3896ebe9383cSRichard Henderson 
3897ebe9383cSRichard Henderson     nullify_over(ctx);
3898ebe9383cSRichard Henderson 
3899ebe9383cSRichard Henderson     t = tcg_temp_new();
3900eaa3783bSRichard Henderson     tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3901eaa3783bSRichard Henderson     tcg_gen_extract_reg(t, t, 21 - cbit, 1);
3902ebe9383cSRichard Henderson     ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3903ebe9383cSRichard Henderson     tcg_temp_free(t);
3904ebe9383cSRichard Henderson 
390531234768SRichard Henderson     return nullify_end(ctx);
3906ebe9383cSRichard Henderson }
3907ebe9383cSRichard Henderson 
390831234768SRichard Henderson static bool trans_ftest_q(DisasContext *ctx, uint32_t insn,
3909ebe9383cSRichard Henderson                           const DisasInsn *di)
3910ebe9383cSRichard Henderson {
3911ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3912ebe9383cSRichard Henderson     int mask;
3913ebe9383cSRichard Henderson     bool inv = false;
3914eaa3783bSRichard Henderson     TCGv_reg t;
3915ebe9383cSRichard Henderson 
3916ebe9383cSRichard Henderson     nullify_over(ctx);
3917ebe9383cSRichard Henderson 
3918ebe9383cSRichard Henderson     t = tcg_temp_new();
3919eaa3783bSRichard Henderson     tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3920ebe9383cSRichard Henderson 
3921ebe9383cSRichard Henderson     switch (c) {
3922ebe9383cSRichard Henderson     case 0: /* simple */
3923eaa3783bSRichard Henderson         tcg_gen_andi_reg(t, t, 0x4000000);
3924ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3925ebe9383cSRichard Henderson         goto done;
3926ebe9383cSRichard Henderson     case 2: /* rej */
3927ebe9383cSRichard Henderson         inv = true;
3928ebe9383cSRichard Henderson         /* fallthru */
3929ebe9383cSRichard Henderson     case 1: /* acc */
3930ebe9383cSRichard Henderson         mask = 0x43ff800;
3931ebe9383cSRichard Henderson         break;
3932ebe9383cSRichard Henderson     case 6: /* rej8 */
3933ebe9383cSRichard Henderson         inv = true;
3934ebe9383cSRichard Henderson         /* fallthru */
3935ebe9383cSRichard Henderson     case 5: /* acc8 */
3936ebe9383cSRichard Henderson         mask = 0x43f8000;
3937ebe9383cSRichard Henderson         break;
3938ebe9383cSRichard Henderson     case 9: /* acc6 */
3939ebe9383cSRichard Henderson         mask = 0x43e0000;
3940ebe9383cSRichard Henderson         break;
3941ebe9383cSRichard Henderson     case 13: /* acc4 */
3942ebe9383cSRichard Henderson         mask = 0x4380000;
3943ebe9383cSRichard Henderson         break;
3944ebe9383cSRichard Henderson     case 17: /* acc2 */
3945ebe9383cSRichard Henderson         mask = 0x4200000;
3946ebe9383cSRichard Henderson         break;
3947ebe9383cSRichard Henderson     default:
3948ebe9383cSRichard Henderson         return gen_illegal(ctx);
3949ebe9383cSRichard Henderson     }
3950ebe9383cSRichard Henderson     if (inv) {
3951eaa3783bSRichard Henderson         TCGv_reg c = load_const(ctx, mask);
3952eaa3783bSRichard Henderson         tcg_gen_or_reg(t, t, c);
3953ebe9383cSRichard Henderson         ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3954ebe9383cSRichard Henderson     } else {
3955eaa3783bSRichard Henderson         tcg_gen_andi_reg(t, t, mask);
3956ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3957ebe9383cSRichard Henderson     }
3958ebe9383cSRichard Henderson  done:
395931234768SRichard Henderson     return nullify_end(ctx);
3960ebe9383cSRichard Henderson }
3961ebe9383cSRichard Henderson 
396231234768SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
3963ebe9383cSRichard Henderson {
3964ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3965ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3966ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3967ebe9383cSRichard Henderson     TCGv_i64 a, b;
3968ebe9383cSRichard Henderson 
3969ebe9383cSRichard Henderson     nullify_over(ctx);
3970ebe9383cSRichard Henderson 
3971ebe9383cSRichard Henderson     a = load_frw0_i64(ra);
3972ebe9383cSRichard Henderson     b = load_frw0_i64(rb);
3973ebe9383cSRichard Henderson     tcg_gen_mul_i64(a, a, b);
3974ebe9383cSRichard Henderson     save_frd(rt, a);
3975ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3976ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3977ebe9383cSRichard Henderson 
397831234768SRichard Henderson     return nullify_end(ctx);
3979ebe9383cSRichard Henderson }
3980ebe9383cSRichard Henderson 
3981eff235ebSPaolo Bonzini #define FOP_DED  trans_fop_ded, .f.ded
3982eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd
3983ebe9383cSRichard Henderson 
3984eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0c, .f.wew
3985eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0c, .f.dew
3986eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0c, .f.wed
3987eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww
3988ebe9383cSRichard Henderson 
3989ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = {
3990ebe9383cSRichard Henderson     /* floating point class zero */
3991ebe9383cSRichard Henderson     { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3992ebe9383cSRichard Henderson     { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3993ebe9383cSRichard Henderson     { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3994ebe9383cSRichard Henderson     { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3995ebe9383cSRichard Henderson     { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3996ebe9383cSRichard Henderson     { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3997ebe9383cSRichard Henderson 
3998ebe9383cSRichard Henderson     { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3999ebe9383cSRichard Henderson     { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4000ebe9383cSRichard Henderson     { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4001ebe9383cSRichard Henderson     { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4002ebe9383cSRichard Henderson     { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4003ebe9383cSRichard Henderson     { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4004ebe9383cSRichard Henderson 
4005ebe9383cSRichard Henderson     /* floating point class three */
4006ebe9383cSRichard Henderson     { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
4007ebe9383cSRichard Henderson     { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
4008ebe9383cSRichard Henderson     { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
4009ebe9383cSRichard Henderson     { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
4010ebe9383cSRichard Henderson 
4011ebe9383cSRichard Henderson     { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4012ebe9383cSRichard Henderson     { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4013ebe9383cSRichard Henderson     { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4014ebe9383cSRichard Henderson     { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4015ebe9383cSRichard Henderson 
4016ebe9383cSRichard Henderson     /* floating point class one */
4017ebe9383cSRichard Henderson     /* float/float */
4018ebe9383cSRichard Henderson     { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
4019ebe9383cSRichard Henderson     { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
4020ebe9383cSRichard Henderson     /* int/float */
4021ebe9383cSRichard Henderson     { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
4022ebe9383cSRichard Henderson     { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
4023ebe9383cSRichard Henderson     { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
4024ebe9383cSRichard Henderson     { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4025ebe9383cSRichard Henderson     /* float/int */
4026ebe9383cSRichard Henderson     { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
4027ebe9383cSRichard Henderson     { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
4028ebe9383cSRichard Henderson     { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
4029ebe9383cSRichard Henderson     { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4030ebe9383cSRichard Henderson     /* float/int truncate */
4031ebe9383cSRichard Henderson     { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
4032ebe9383cSRichard Henderson     { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
4033ebe9383cSRichard Henderson     { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
4034ebe9383cSRichard Henderson     { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4035ebe9383cSRichard Henderson     /* uint/float */
4036ebe9383cSRichard Henderson     { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
4037ebe9383cSRichard Henderson     { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
4038ebe9383cSRichard Henderson     { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
4039ebe9383cSRichard Henderson     { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4040ebe9383cSRichard Henderson     /* float/uint */
4041ebe9383cSRichard Henderson     { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
4042ebe9383cSRichard Henderson     { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
4043ebe9383cSRichard Henderson     { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
4044ebe9383cSRichard Henderson     { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4045ebe9383cSRichard Henderson     /* float/uint truncate */
4046ebe9383cSRichard Henderson     { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
4047ebe9383cSRichard Henderson     { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
4048ebe9383cSRichard Henderson     { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
4049ebe9383cSRichard Henderson     { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4050ebe9383cSRichard Henderson 
4051ebe9383cSRichard Henderson     /* floating point class two */
4052ebe9383cSRichard Henderson     { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
4053ebe9383cSRichard Henderson     { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
4054ebe9383cSRichard Henderson     { 0x30002420, 0xffffffe0, trans_ftest_q },
4055ebe9383cSRichard Henderson     { 0x30000420, 0xffff1fff, trans_ftest_t },
4056ebe9383cSRichard Henderson 
4057ebe9383cSRichard Henderson     /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
4058ebe9383cSRichard Henderson        This is machine/revision == 0, which is reserved for simulator.  */
4059ebe9383cSRichard Henderson     { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
4060ebe9383cSRichard Henderson };
4061ebe9383cSRichard Henderson 
4062ebe9383cSRichard Henderson #undef FOP_WEW
4063ebe9383cSRichard Henderson #undef FOP_DEW
4064ebe9383cSRichard Henderson #undef FOP_WED
4065ebe9383cSRichard Henderson #undef FOP_WEWW
4066eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0e, .f.wew
4067eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0e, .f.dew
4068eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0e, .f.wed
4069eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww
4070ebe9383cSRichard Henderson 
4071ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = {
4072ebe9383cSRichard Henderson     /* floating point class zero */
4073ebe9383cSRichard Henderson     { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
4074ebe9383cSRichard Henderson     { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
4075ebe9383cSRichard Henderson     { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
4076ebe9383cSRichard Henderson     { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
4077ebe9383cSRichard Henderson     { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
4078ebe9383cSRichard Henderson     { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
4079ebe9383cSRichard Henderson 
4080ebe9383cSRichard Henderson     { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
4081ebe9383cSRichard Henderson     { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4082ebe9383cSRichard Henderson     { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4083ebe9383cSRichard Henderson     { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4084ebe9383cSRichard Henderson     { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4085ebe9383cSRichard Henderson     { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4086ebe9383cSRichard Henderson 
4087ebe9383cSRichard Henderson     /* floating point class three */
4088ebe9383cSRichard Henderson     { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
4089ebe9383cSRichard Henderson     { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
4090ebe9383cSRichard Henderson     { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
4091ebe9383cSRichard Henderson     { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
4092ebe9383cSRichard Henderson 
4093ebe9383cSRichard Henderson     { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4094ebe9383cSRichard Henderson     { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4095ebe9383cSRichard Henderson     { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4096ebe9383cSRichard Henderson     { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4097ebe9383cSRichard Henderson 
4098ebe9383cSRichard Henderson     { 0x38004700, 0xfc00ef60, trans_xmpyu },
4099ebe9383cSRichard Henderson 
4100ebe9383cSRichard Henderson     /* floating point class one */
4101ebe9383cSRichard Henderson     /* float/float */
4102ebe9383cSRichard Henderson     { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
4103fe0a69ccSRichard Henderson     { 0x38002200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_d },
4104ebe9383cSRichard Henderson     /* int/float */
4105fe0a69ccSRichard Henderson     { 0x38008200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_w_s },
4106ebe9383cSRichard Henderson     { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
4107ebe9383cSRichard Henderson     { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
4108ebe9383cSRichard Henderson     { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4109ebe9383cSRichard Henderson     /* float/int */
4110fe0a69ccSRichard Henderson     { 0x38010200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_w },
4111ebe9383cSRichard Henderson     { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
4112ebe9383cSRichard Henderson     { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
4113ebe9383cSRichard Henderson     { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4114ebe9383cSRichard Henderson     /* float/int truncate */
4115fe0a69ccSRichard Henderson     { 0x38018200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_w },
4116ebe9383cSRichard Henderson     { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
4117ebe9383cSRichard Henderson     { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
4118ebe9383cSRichard Henderson     { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4119ebe9383cSRichard Henderson     /* uint/float */
4120fe0a69ccSRichard Henderson     { 0x38028200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_uw_s },
4121ebe9383cSRichard Henderson     { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
4122ebe9383cSRichard Henderson     { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
4123ebe9383cSRichard Henderson     { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4124ebe9383cSRichard Henderson     /* float/uint */
4125fe0a69ccSRichard Henderson     { 0x38030200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_uw },
4126ebe9383cSRichard Henderson     { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
4127ebe9383cSRichard Henderson     { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
4128ebe9383cSRichard Henderson     { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4129ebe9383cSRichard Henderson     /* float/uint truncate */
4130fe0a69ccSRichard Henderson     { 0x38038200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_uw },
4131ebe9383cSRichard Henderson     { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
4132ebe9383cSRichard Henderson     { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
4133ebe9383cSRichard Henderson     { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4134ebe9383cSRichard Henderson 
4135ebe9383cSRichard Henderson     /* floating point class two */
4136ebe9383cSRichard Henderson     { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
4137ebe9383cSRichard Henderson     { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
4138ebe9383cSRichard Henderson };
4139ebe9383cSRichard Henderson 
4140ebe9383cSRichard Henderson #undef FOP_WEW
4141ebe9383cSRichard Henderson #undef FOP_DEW
4142ebe9383cSRichard Henderson #undef FOP_WED
4143ebe9383cSRichard Henderson #undef FOP_WEWW
4144ebe9383cSRichard Henderson #undef FOP_DED
4145ebe9383cSRichard Henderson #undef FOP_DEDD
4146ebe9383cSRichard Henderson 
4147ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4148ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4149ebe9383cSRichard Henderson {
4150ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4151ebe9383cSRichard Henderson }
4152ebe9383cSRichard Henderson 
4153b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4154ebe9383cSRichard Henderson {
4155b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4156b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4157b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4158b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4159b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4160ebe9383cSRichard Henderson 
4161ebe9383cSRichard Henderson     nullify_over(ctx);
4162ebe9383cSRichard Henderson 
4163ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4164ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4165ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4166ebe9383cSRichard Henderson 
416731234768SRichard Henderson     return nullify_end(ctx);
4168ebe9383cSRichard Henderson }
4169ebe9383cSRichard Henderson 
4170b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4171b1e2af57SRichard Henderson {
4172b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4173b1e2af57SRichard Henderson }
4174b1e2af57SRichard Henderson 
4175b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4176b1e2af57SRichard Henderson {
4177b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4178b1e2af57SRichard Henderson }
4179b1e2af57SRichard Henderson 
4180b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4181b1e2af57SRichard Henderson {
4182b1e2af57SRichard Henderson     nullify_over(ctx);
4183b1e2af57SRichard Henderson 
4184b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4185b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4186b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4187b1e2af57SRichard Henderson 
4188b1e2af57SRichard Henderson     return nullify_end(ctx);
4189b1e2af57SRichard Henderson }
4190b1e2af57SRichard Henderson 
4191b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4192b1e2af57SRichard Henderson {
4193b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4194b1e2af57SRichard Henderson }
4195b1e2af57SRichard Henderson 
4196b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4197b1e2af57SRichard Henderson {
4198b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4199b1e2af57SRichard Henderson }
4200b1e2af57SRichard Henderson 
420131234768SRichard Henderson static bool trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
4202ebe9383cSRichard Henderson                              const DisasInsn *di)
4203ebe9383cSRichard Henderson {
4204ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
4205ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
4206ebe9383cSRichard Henderson     unsigned rm1 = assemble_ra64(insn);
4207ebe9383cSRichard Henderson     unsigned rm2 = assemble_rb64(insn);
4208ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
4209ebe9383cSRichard Henderson     TCGv_i32 a, b, c;
4210ebe9383cSRichard Henderson 
4211ebe9383cSRichard Henderson     nullify_over(ctx);
4212ebe9383cSRichard Henderson     a = load_frw0_i32(rm1);
4213ebe9383cSRichard Henderson     b = load_frw0_i32(rm2);
4214ebe9383cSRichard Henderson     c = load_frw0_i32(ra3);
4215ebe9383cSRichard Henderson 
4216ebe9383cSRichard Henderson     if (neg) {
4217ebe9383cSRichard Henderson         gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
4218ebe9383cSRichard Henderson     } else {
4219ebe9383cSRichard Henderson         gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
4220ebe9383cSRichard Henderson     }
4221ebe9383cSRichard Henderson 
4222ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
4223ebe9383cSRichard Henderson     tcg_temp_free_i32(c);
4224ebe9383cSRichard Henderson     save_frw_i32(rt, a);
4225ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
422631234768SRichard Henderson     return nullify_end(ctx);
4227ebe9383cSRichard Henderson }
4228ebe9383cSRichard Henderson 
422931234768SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
4230ebe9383cSRichard Henderson                              const DisasInsn *di)
4231ebe9383cSRichard Henderson {
4232ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
4233ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
4234ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
4235ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
4236ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
4237ebe9383cSRichard Henderson     TCGv_i64 a, b, c;
4238ebe9383cSRichard Henderson 
4239ebe9383cSRichard Henderson     nullify_over(ctx);
4240ebe9383cSRichard Henderson     a = load_frd0(rm1);
4241ebe9383cSRichard Henderson     b = load_frd0(rm2);
4242ebe9383cSRichard Henderson     c = load_frd0(ra3);
4243ebe9383cSRichard Henderson 
4244ebe9383cSRichard Henderson     if (neg) {
4245ebe9383cSRichard Henderson         gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
4246ebe9383cSRichard Henderson     } else {
4247ebe9383cSRichard Henderson         gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
4248ebe9383cSRichard Henderson     }
4249ebe9383cSRichard Henderson 
4250ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
4251ebe9383cSRichard Henderson     tcg_temp_free_i64(c);
4252ebe9383cSRichard Henderson     save_frd(rt, a);
4253ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
425431234768SRichard Henderson     return nullify_end(ctx);
4255ebe9383cSRichard Henderson }
4256ebe9383cSRichard Henderson 
4257ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = {
4258ebe9383cSRichard Henderson     { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
4259ebe9383cSRichard Henderson     { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
4260ebe9383cSRichard Henderson };
4261ebe9383cSRichard Henderson 
426231234768SRichard Henderson static void translate_table_int(DisasContext *ctx, uint32_t insn,
426361766fe9SRichard Henderson                                 const DisasInsn table[], size_t n)
426461766fe9SRichard Henderson {
426561766fe9SRichard Henderson     size_t i;
426661766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
426761766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
426831234768SRichard Henderson             table[i].trans(ctx, insn, &table[i]);
426931234768SRichard Henderson             return;
427061766fe9SRichard Henderson         }
427161766fe9SRichard Henderson     }
4272b36942a6SRichard Henderson     qemu_log_mask(LOG_UNIMP, "UNIMP insn %08x @ " TARGET_FMT_lx "\n",
4273b36942a6SRichard Henderson                   insn, ctx->base.pc_next);
427431234768SRichard Henderson     gen_illegal(ctx);
427561766fe9SRichard Henderson }
427661766fe9SRichard Henderson 
427761766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
427861766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
427961766fe9SRichard Henderson 
428031234768SRichard Henderson static void translate_one(DisasContext *ctx, uint32_t insn)
428161766fe9SRichard Henderson {
428240f9f908SRichard Henderson     uint32_t opc;
428361766fe9SRichard Henderson 
428440f9f908SRichard Henderson     /* Transition to the auto-generated decoder.  */
428540f9f908SRichard Henderson     if (decode(ctx, insn)) {
428640f9f908SRichard Henderson         return;
428740f9f908SRichard Henderson     }
428840f9f908SRichard Henderson 
428940f9f908SRichard Henderson     opc = extract32(insn, 26, 6);
429061766fe9SRichard Henderson     switch (opc) {
4291b2167459SRichard Henderson     case 0x08:
429231234768SRichard Henderson         trans_ldil(ctx, insn);
429331234768SRichard Henderson         return;
429496d6407fSRichard Henderson     case 0x09:
429531234768SRichard Henderson         trans_copr_w(ctx, insn);
429631234768SRichard Henderson         return;
4297b2167459SRichard Henderson     case 0x0A:
429831234768SRichard Henderson         trans_addil(ctx, insn);
429931234768SRichard Henderson         return;
430096d6407fSRichard Henderson     case 0x0B:
430131234768SRichard Henderson         trans_copr_dw(ctx, insn);
430231234768SRichard Henderson         return;
4303ebe9383cSRichard Henderson     case 0x0C:
430431234768SRichard Henderson         translate_table(ctx, insn, table_float_0c);
430531234768SRichard Henderson         return;
4306b2167459SRichard Henderson     case 0x0D:
430731234768SRichard Henderson         trans_ldo(ctx, insn);
430831234768SRichard Henderson         return;
4309ebe9383cSRichard Henderson     case 0x0E:
431031234768SRichard Henderson         translate_table(ctx, insn, table_float_0e);
431131234768SRichard Henderson         return;
431296d6407fSRichard Henderson 
431396d6407fSRichard Henderson     case 0x10:
431431234768SRichard Henderson         trans_load(ctx, insn, false, MO_UB);
431531234768SRichard Henderson         return;
431696d6407fSRichard Henderson     case 0x11:
431731234768SRichard Henderson         trans_load(ctx, insn, false, MO_TEUW);
431831234768SRichard Henderson         return;
431996d6407fSRichard Henderson     case 0x12:
432031234768SRichard Henderson         trans_load(ctx, insn, false, MO_TEUL);
432131234768SRichard Henderson         return;
432296d6407fSRichard Henderson     case 0x13:
432331234768SRichard Henderson         trans_load(ctx, insn, true, MO_TEUL);
432431234768SRichard Henderson         return;
432596d6407fSRichard Henderson     case 0x16:
432631234768SRichard Henderson         trans_fload_mod(ctx, insn);
432731234768SRichard Henderson         return;
432896d6407fSRichard Henderson     case 0x17:
432931234768SRichard Henderson         trans_load_w(ctx, insn);
433031234768SRichard Henderson         return;
433196d6407fSRichard Henderson     case 0x18:
433231234768SRichard Henderson         trans_store(ctx, insn, false, MO_UB);
433331234768SRichard Henderson         return;
433496d6407fSRichard Henderson     case 0x19:
433531234768SRichard Henderson         trans_store(ctx, insn, false, MO_TEUW);
433631234768SRichard Henderson         return;
433796d6407fSRichard Henderson     case 0x1A:
433831234768SRichard Henderson         trans_store(ctx, insn, false, MO_TEUL);
433931234768SRichard Henderson         return;
434096d6407fSRichard Henderson     case 0x1B:
434131234768SRichard Henderson         trans_store(ctx, insn, true, MO_TEUL);
434231234768SRichard Henderson         return;
434396d6407fSRichard Henderson     case 0x1E:
434431234768SRichard Henderson         trans_fstore_mod(ctx, insn);
434531234768SRichard Henderson         return;
434696d6407fSRichard Henderson     case 0x1F:
434731234768SRichard Henderson         trans_store_w(ctx, insn);
434831234768SRichard Henderson         return;
434996d6407fSRichard Henderson 
4350b2167459SRichard Henderson     case 0x24:
435131234768SRichard Henderson         trans_cmpiclr(ctx, insn);
435231234768SRichard Henderson         return;
4353b2167459SRichard Henderson     case 0x25:
435431234768SRichard Henderson         trans_subi(ctx, insn);
435531234768SRichard Henderson         return;
4356b2167459SRichard Henderson     case 0x2C:
4357b2167459SRichard Henderson     case 0x2D:
435831234768SRichard Henderson         trans_addi(ctx, insn);
435931234768SRichard Henderson         return;
4360ebe9383cSRichard Henderson     case 0x2E:
436131234768SRichard Henderson         translate_table(ctx, insn, table_fp_fused);
436231234768SRichard Henderson         return;
436396d6407fSRichard Henderson 
436496d6407fSRichard Henderson     case 0x04: /* spopn */
436596d6407fSRichard Henderson     case 0x05: /* diag */
436696d6407fSRichard Henderson     case 0x0F: /* product specific */
436796d6407fSRichard Henderson         break;
436896d6407fSRichard Henderson 
436996d6407fSRichard Henderson     case 0x07: /* unassigned */
437096d6407fSRichard Henderson     case 0x15: /* unassigned */
437196d6407fSRichard Henderson     case 0x1D: /* unassigned */
437296d6407fSRichard Henderson     case 0x37: /* unassigned */
43736210db05SHelge Deller         break;
43746210db05SHelge Deller     case 0x3F:
43756210db05SHelge Deller #ifndef CONFIG_USER_ONLY
43766210db05SHelge Deller         /* Unassigned, but use as system-halt.  */
43776210db05SHelge Deller         if (insn == 0xfffdead0) {
437831234768SRichard Henderson             gen_hlt(ctx, 0); /* halt system */
437931234768SRichard Henderson             return;
43806210db05SHelge Deller         }
43816210db05SHelge Deller         if (insn == 0xfffdead1) {
438231234768SRichard Henderson             gen_hlt(ctx, 1); /* reset system */
438331234768SRichard Henderson             return;
43846210db05SHelge Deller         }
43856210db05SHelge Deller #endif
43866210db05SHelge Deller         break;
438761766fe9SRichard Henderson     default:
438861766fe9SRichard Henderson         break;
438961766fe9SRichard Henderson     }
439031234768SRichard Henderson     gen_illegal(ctx);
439161766fe9SRichard Henderson }
439261766fe9SRichard Henderson 
4393b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
439461766fe9SRichard Henderson {
439551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4396f764718dSRichard Henderson     int bound;
439761766fe9SRichard Henderson 
439851b061fbSRichard Henderson     ctx->cs = cs;
4399494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
44003d68ee7bSRichard Henderson 
44013d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
44023d68ee7bSRichard Henderson     ctx->privilege = MMU_USER_IDX;
44033d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4404ebd0e151SRichard Henderson     ctx->iaoq_f = ctx->base.pc_first | MMU_USER_IDX;
4405ebd0e151SRichard Henderson     ctx->iaoq_b = ctx->base.tb->cs_base | MMU_USER_IDX;
4406c301f34eSRichard Henderson #else
4407494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4408494737b7SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX);
44093d68ee7bSRichard Henderson 
4410c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4411c301f34eSRichard Henderson     uint64_t cs_base = ctx->base.tb->cs_base;
4412c301f34eSRichard Henderson     uint64_t iasq_f = cs_base & ~0xffffffffull;
4413c301f34eSRichard Henderson     int32_t diff = cs_base;
4414c301f34eSRichard Henderson 
4415c301f34eSRichard Henderson     ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4416c301f34eSRichard Henderson     ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4417c301f34eSRichard Henderson #endif
441851b061fbSRichard Henderson     ctx->iaoq_n = -1;
4419f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
442061766fe9SRichard Henderson 
44213d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
44223d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4423b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
44243d68ee7bSRichard Henderson 
442586f8d05fSRichard Henderson     ctx->ntempr = 0;
442686f8d05fSRichard Henderson     ctx->ntempl = 0;
442786f8d05fSRichard Henderson     memset(ctx->tempr, 0, sizeof(ctx->tempr));
442886f8d05fSRichard Henderson     memset(ctx->templ, 0, sizeof(ctx->templ));
442961766fe9SRichard Henderson }
443061766fe9SRichard Henderson 
443151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
443251b061fbSRichard Henderson {
443351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
443461766fe9SRichard Henderson 
44353d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
443651b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
443751b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4438494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
443951b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
444051b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4441129e9cc3SRichard Henderson     }
444251b061fbSRichard Henderson     ctx->null_lab = NULL;
444361766fe9SRichard Henderson }
444461766fe9SRichard Henderson 
444551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
444651b061fbSRichard Henderson {
444751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
444851b061fbSRichard Henderson 
444951b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
445051b061fbSRichard Henderson }
445151b061fbSRichard Henderson 
445251b061fbSRichard Henderson static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
445351b061fbSRichard Henderson                                       const CPUBreakpoint *bp)
445451b061fbSRichard Henderson {
445551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
445651b061fbSRichard Henderson 
445731234768SRichard Henderson     gen_excp(ctx, EXCP_DEBUG);
4458c301f34eSRichard Henderson     ctx->base.pc_next += 4;
445951b061fbSRichard Henderson     return true;
446051b061fbSRichard Henderson }
446151b061fbSRichard Henderson 
446251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
446351b061fbSRichard Henderson {
446451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
446551b061fbSRichard Henderson     CPUHPPAState *env = cs->env_ptr;
446651b061fbSRichard Henderson     DisasJumpType ret;
446751b061fbSRichard Henderson     int i, n;
446851b061fbSRichard Henderson 
446951b061fbSRichard Henderson     /* Execute one insn.  */
4470ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4471c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
447231234768SRichard Henderson         do_page_zero(ctx);
447331234768SRichard Henderson         ret = ctx->base.is_jmp;
4474869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4475ba1d0b44SRichard Henderson     } else
4476ba1d0b44SRichard Henderson #endif
4477ba1d0b44SRichard Henderson     {
447861766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
447961766fe9SRichard Henderson            the page permissions for execute.  */
4480c301f34eSRichard Henderson         uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
448161766fe9SRichard Henderson 
448261766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
448361766fe9SRichard Henderson            This will be overwritten by a branch.  */
448451b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
448551b061fbSRichard Henderson             ctx->iaoq_n = -1;
448651b061fbSRichard Henderson             ctx->iaoq_n_var = get_temp(ctx);
4487eaa3783bSRichard Henderson             tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
448861766fe9SRichard Henderson         } else {
448951b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
4490f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
449161766fe9SRichard Henderson         }
449261766fe9SRichard Henderson 
449351b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
449451b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4495869051eaSRichard Henderson             ret = DISAS_NEXT;
4496129e9cc3SRichard Henderson         } else {
44971a19da0dSRichard Henderson             ctx->insn = insn;
449831234768SRichard Henderson             translate_one(ctx, insn);
449931234768SRichard Henderson             ret = ctx->base.is_jmp;
450051b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4501129e9cc3SRichard Henderson         }
450261766fe9SRichard Henderson     }
450361766fe9SRichard Henderson 
450451b061fbSRichard Henderson     /* Free any temporaries allocated.  */
450586f8d05fSRichard Henderson     for (i = 0, n = ctx->ntempr; i < n; ++i) {
450686f8d05fSRichard Henderson         tcg_temp_free(ctx->tempr[i]);
450786f8d05fSRichard Henderson         ctx->tempr[i] = NULL;
450861766fe9SRichard Henderson     }
450986f8d05fSRichard Henderson     for (i = 0, n = ctx->ntempl; i < n; ++i) {
451086f8d05fSRichard Henderson         tcg_temp_free_tl(ctx->templ[i]);
451186f8d05fSRichard Henderson         ctx->templ[i] = NULL;
451286f8d05fSRichard Henderson     }
451386f8d05fSRichard Henderson     ctx->ntempr = 0;
451486f8d05fSRichard Henderson     ctx->ntempl = 0;
451561766fe9SRichard Henderson 
45163d68ee7bSRichard Henderson     /* Advance the insn queue.  Note that this check also detects
45173d68ee7bSRichard Henderson        a priority change within the instruction queue.  */
451851b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
4519c301f34eSRichard Henderson         if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4520c301f34eSRichard Henderson             && use_goto_tb(ctx, ctx->iaoq_b)
4521c301f34eSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4522c301f34eSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
452351b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
452451b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
452531234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_NORETURN;
4526129e9cc3SRichard Henderson         } else {
452731234768SRichard Henderson             ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE;
452861766fe9SRichard Henderson         }
4529129e9cc3SRichard Henderson     }
453051b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
453151b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
4532c301f34eSRichard Henderson     ctx->base.pc_next += 4;
453361766fe9SRichard Henderson 
4534869051eaSRichard Henderson     if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
453551b061fbSRichard Henderson         return;
453661766fe9SRichard Henderson     }
453751b061fbSRichard Henderson     if (ctx->iaoq_f == -1) {
4538eaa3783bSRichard Henderson         tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b);
453951b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
4540c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY
4541c301f34eSRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4542c301f34eSRichard Henderson #endif
454351b061fbSRichard Henderson         nullify_save(ctx);
454451b061fbSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
454551b061fbSRichard Henderson     } else if (ctx->iaoq_b == -1) {
4546eaa3783bSRichard Henderson         tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var);
454761766fe9SRichard Henderson     }
454861766fe9SRichard Henderson }
454961766fe9SRichard Henderson 
455051b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
455151b061fbSRichard Henderson {
455251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4553e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
455451b061fbSRichard Henderson 
4555e1b5a5edSRichard Henderson     switch (is_jmp) {
4556869051eaSRichard Henderson     case DISAS_NORETURN:
455761766fe9SRichard Henderson         break;
455851b061fbSRichard Henderson     case DISAS_TOO_MANY:
4559869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
4560e1b5a5edSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
456151b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
456251b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
456351b061fbSRichard Henderson         nullify_save(ctx);
456461766fe9SRichard Henderson         /* FALLTHRU */
4565869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
456651b061fbSRichard Henderson         if (ctx->base.singlestep_enabled) {
456761766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
4568e1b5a5edSRichard Henderson         } else if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
456907ea28b4SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
457061766fe9SRichard Henderson         } else {
45717f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
457261766fe9SRichard Henderson         }
457361766fe9SRichard Henderson         break;
457461766fe9SRichard Henderson     default:
457551b061fbSRichard Henderson         g_assert_not_reached();
457661766fe9SRichard Henderson     }
457751b061fbSRichard Henderson }
457861766fe9SRichard Henderson 
457951b061fbSRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
458051b061fbSRichard Henderson {
4581c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
458261766fe9SRichard Henderson 
4583ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4584ba1d0b44SRichard Henderson     switch (pc) {
45857ad439dfSRichard Henderson     case 0x00:
458651b061fbSRichard Henderson         qemu_log("IN:\n0x00000000:  (null)\n");
4587ba1d0b44SRichard Henderson         return;
45887ad439dfSRichard Henderson     case 0xb0:
458951b061fbSRichard Henderson         qemu_log("IN:\n0x000000b0:  light-weight-syscall\n");
4590ba1d0b44SRichard Henderson         return;
45917ad439dfSRichard Henderson     case 0xe0:
459251b061fbSRichard Henderson         qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4593ba1d0b44SRichard Henderson         return;
45947ad439dfSRichard Henderson     case 0x100:
459551b061fbSRichard Henderson         qemu_log("IN:\n0x00000100:  syscall\n");
4596ba1d0b44SRichard Henderson         return;
45977ad439dfSRichard Henderson     }
4598ba1d0b44SRichard Henderson #endif
4599ba1d0b44SRichard Henderson 
4600ba1d0b44SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(pc));
4601eaa3783bSRichard Henderson     log_target_disas(cs, pc, dcbase->tb->size);
460261766fe9SRichard Henderson }
460351b061fbSRichard Henderson 
460451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
460551b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
460651b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
460751b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
460851b061fbSRichard Henderson     .breakpoint_check   = hppa_tr_breakpoint_check,
460951b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
461051b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
461151b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
461251b061fbSRichard Henderson };
461351b061fbSRichard Henderson 
461451b061fbSRichard Henderson void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
461551b061fbSRichard Henderson 
461651b061fbSRichard Henderson {
461751b061fbSRichard Henderson     DisasContext ctx;
461851b061fbSRichard Henderson     translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
461961766fe9SRichard Henderson }
462061766fe9SRichard Henderson 
462161766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
462261766fe9SRichard Henderson                           target_ulong *data)
462361766fe9SRichard Henderson {
462461766fe9SRichard Henderson     env->iaoq_f = data[0];
462586f8d05fSRichard Henderson     if (data[1] != (target_ureg)-1) {
462661766fe9SRichard Henderson         env->iaoq_b = data[1];
462761766fe9SRichard Henderson     }
462861766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
462961766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
463061766fe9SRichard Henderson        that the instruction was not nullified.  */
463161766fe9SRichard Henderson     env->psw_n = 0;
463261766fe9SRichard Henderson }
4633