]> Git Repo - qemu.git/blame - target/hppa/translate.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[qemu.git] / target / hppa / translate.c
CommitLineData
61766fe9
RH
1/*
2 * HPPA emulation cpu translation for qemu.
3 *
4 * Copyright (c) 2016 Richard Henderson <[email protected]>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "disas/disas.h"
23#include "qemu/host-utils.h"
24#include "exec/exec-all.h"
25#include "tcg-op.h"
26#include "exec/cpu_ldst.h"
61766fe9
RH
27#include "exec/helper-proto.h"
28#include "exec/helper-gen.h"
869051ea 29#include "exec/translator.h"
61766fe9
RH
30#include "trace-tcg.h"
31#include "exec/log.h"
32
eaa3783b
RH
33/* Since we have a distinction between register size and address size,
34 we need to redefine all of these. */
35
36#undef TCGv
37#undef tcg_temp_new
38#undef tcg_global_reg_new
39#undef tcg_global_mem_new
40#undef tcg_temp_local_new
41#undef tcg_temp_free
42
43#if TARGET_LONG_BITS == 64
44#define TCGv_tl TCGv_i64
45#define tcg_temp_new_tl tcg_temp_new_i64
46#define tcg_temp_free_tl tcg_temp_free_i64
47#if TARGET_REGISTER_BITS == 64
48#define tcg_gen_extu_reg_tl tcg_gen_mov_i64
49#else
50#define tcg_gen_extu_reg_tl tcg_gen_extu_i32_i64
51#endif
52#else
53#define TCGv_tl TCGv_i32
54#define tcg_temp_new_tl tcg_temp_new_i32
55#define tcg_temp_free_tl tcg_temp_free_i32
56#define tcg_gen_extu_reg_tl tcg_gen_mov_i32
57#endif
58
59#if TARGET_REGISTER_BITS == 64
60#define TCGv_reg TCGv_i64
61
62#define tcg_temp_new tcg_temp_new_i64
63#define tcg_global_reg_new tcg_global_reg_new_i64
64#define tcg_global_mem_new tcg_global_mem_new_i64
65#define tcg_temp_local_new tcg_temp_local_new_i64
66#define tcg_temp_free tcg_temp_free_i64
67
68#define tcg_gen_movi_reg tcg_gen_movi_i64
69#define tcg_gen_mov_reg tcg_gen_mov_i64
70#define tcg_gen_ld8u_reg tcg_gen_ld8u_i64
71#define tcg_gen_ld8s_reg tcg_gen_ld8s_i64
72#define tcg_gen_ld16u_reg tcg_gen_ld16u_i64
73#define tcg_gen_ld16s_reg tcg_gen_ld16s_i64
74#define tcg_gen_ld32u_reg tcg_gen_ld32u_i64
75#define tcg_gen_ld32s_reg tcg_gen_ld32s_i64
76#define tcg_gen_ld_reg tcg_gen_ld_i64
77#define tcg_gen_st8_reg tcg_gen_st8_i64
78#define tcg_gen_st16_reg tcg_gen_st16_i64
79#define tcg_gen_st32_reg tcg_gen_st32_i64
80#define tcg_gen_st_reg tcg_gen_st_i64
81#define tcg_gen_add_reg tcg_gen_add_i64
82#define tcg_gen_addi_reg tcg_gen_addi_i64
83#define tcg_gen_sub_reg tcg_gen_sub_i64
84#define tcg_gen_neg_reg tcg_gen_neg_i64
85#define tcg_gen_subfi_reg tcg_gen_subfi_i64
86#define tcg_gen_subi_reg tcg_gen_subi_i64
87#define tcg_gen_and_reg tcg_gen_and_i64
88#define tcg_gen_andi_reg tcg_gen_andi_i64
89#define tcg_gen_or_reg tcg_gen_or_i64
90#define tcg_gen_ori_reg tcg_gen_ori_i64
91#define tcg_gen_xor_reg tcg_gen_xor_i64
92#define tcg_gen_xori_reg tcg_gen_xori_i64
93#define tcg_gen_not_reg tcg_gen_not_i64
94#define tcg_gen_shl_reg tcg_gen_shl_i64
95#define tcg_gen_shli_reg tcg_gen_shli_i64
96#define tcg_gen_shr_reg tcg_gen_shr_i64
97#define tcg_gen_shri_reg tcg_gen_shri_i64
98#define tcg_gen_sar_reg tcg_gen_sar_i64
99#define tcg_gen_sari_reg tcg_gen_sari_i64
100#define tcg_gen_brcond_reg tcg_gen_brcond_i64
101#define tcg_gen_brcondi_reg tcg_gen_brcondi_i64
102#define tcg_gen_setcond_reg tcg_gen_setcond_i64
103#define tcg_gen_setcondi_reg tcg_gen_setcondi_i64
104#define tcg_gen_mul_reg tcg_gen_mul_i64
105#define tcg_gen_muli_reg tcg_gen_muli_i64
106#define tcg_gen_div_reg tcg_gen_div_i64
107#define tcg_gen_rem_reg tcg_gen_rem_i64
108#define tcg_gen_divu_reg tcg_gen_divu_i64
109#define tcg_gen_remu_reg tcg_gen_remu_i64
110#define tcg_gen_discard_reg tcg_gen_discard_i64
111#define tcg_gen_trunc_reg_i32 tcg_gen_extrl_i64_i32
112#define tcg_gen_trunc_i64_reg tcg_gen_mov_i64
113#define tcg_gen_extu_i32_reg tcg_gen_extu_i32_i64
114#define tcg_gen_ext_i32_reg tcg_gen_ext_i32_i64
115#define tcg_gen_extu_reg_i64 tcg_gen_mov_i64
116#define tcg_gen_ext_reg_i64 tcg_gen_mov_i64
117#define tcg_gen_ext8u_reg tcg_gen_ext8u_i64
118#define tcg_gen_ext8s_reg tcg_gen_ext8s_i64
119#define tcg_gen_ext16u_reg tcg_gen_ext16u_i64
120#define tcg_gen_ext16s_reg tcg_gen_ext16s_i64
121#define tcg_gen_ext32u_reg tcg_gen_ext32u_i64
122#define tcg_gen_ext32s_reg tcg_gen_ext32s_i64
123#define tcg_gen_bswap16_reg tcg_gen_bswap16_i64
124#define tcg_gen_bswap32_reg tcg_gen_bswap32_i64
125#define tcg_gen_bswap64_reg tcg_gen_bswap64_i64
126#define tcg_gen_concat_reg_i64 tcg_gen_concat32_i64
127#define tcg_gen_andc_reg tcg_gen_andc_i64
128#define tcg_gen_eqv_reg tcg_gen_eqv_i64
129#define tcg_gen_nand_reg tcg_gen_nand_i64
130#define tcg_gen_nor_reg tcg_gen_nor_i64
131#define tcg_gen_orc_reg tcg_gen_orc_i64
132#define tcg_gen_clz_reg tcg_gen_clz_i64
133#define tcg_gen_ctz_reg tcg_gen_ctz_i64
134#define tcg_gen_clzi_reg tcg_gen_clzi_i64
135#define tcg_gen_ctzi_reg tcg_gen_ctzi_i64
136#define tcg_gen_clrsb_reg tcg_gen_clrsb_i64
137#define tcg_gen_ctpop_reg tcg_gen_ctpop_i64
138#define tcg_gen_rotl_reg tcg_gen_rotl_i64
139#define tcg_gen_rotli_reg tcg_gen_rotli_i64
140#define tcg_gen_rotr_reg tcg_gen_rotr_i64
141#define tcg_gen_rotri_reg tcg_gen_rotri_i64
142#define tcg_gen_deposit_reg tcg_gen_deposit_i64
143#define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i64
144#define tcg_gen_extract_reg tcg_gen_extract_i64
145#define tcg_gen_sextract_reg tcg_gen_sextract_i64
146#define tcg_const_reg tcg_const_i64
147#define tcg_const_local_reg tcg_const_local_i64
148#define tcg_gen_movcond_reg tcg_gen_movcond_i64
149#define tcg_gen_add2_reg tcg_gen_add2_i64
150#define tcg_gen_sub2_reg tcg_gen_sub2_i64
151#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i64
152#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i64
153#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i64
154#if UINTPTR_MAX == UINT32_MAX
155# define tcg_gen_trunc_reg_ptr(p, r) \
156 tcg_gen_trunc_i64_i32(TCGV_PTR_TO_NAT(p), r)
157#else
158# define tcg_gen_trunc_reg_ptr(p, r) \
159 tcg_gen_mov_i64(TCGV_PTR_TO_NAT(p), r)
160#endif
161#else
162#define TCGv_reg TCGv_i32
163#define tcg_temp_new tcg_temp_new_i32
164#define tcg_global_reg_new tcg_global_reg_new_i32
165#define tcg_global_mem_new tcg_global_mem_new_i32
166#define tcg_temp_local_new tcg_temp_local_new_i32
167#define tcg_temp_free tcg_temp_free_i32
168
169#define tcg_gen_movi_reg tcg_gen_movi_i32
170#define tcg_gen_mov_reg tcg_gen_mov_i32
171#define tcg_gen_ld8u_reg tcg_gen_ld8u_i32
172#define tcg_gen_ld8s_reg tcg_gen_ld8s_i32
173#define tcg_gen_ld16u_reg tcg_gen_ld16u_i32
174#define tcg_gen_ld16s_reg tcg_gen_ld16s_i32
175#define tcg_gen_ld32u_reg tcg_gen_ld_i32
176#define tcg_gen_ld32s_reg tcg_gen_ld_i32
177#define tcg_gen_ld_reg tcg_gen_ld_i32
178#define tcg_gen_st8_reg tcg_gen_st8_i32
179#define tcg_gen_st16_reg tcg_gen_st16_i32
180#define tcg_gen_st32_reg tcg_gen_st32_i32
181#define tcg_gen_st_reg tcg_gen_st_i32
182#define tcg_gen_add_reg tcg_gen_add_i32
183#define tcg_gen_addi_reg tcg_gen_addi_i32
184#define tcg_gen_sub_reg tcg_gen_sub_i32
185#define tcg_gen_neg_reg tcg_gen_neg_i32
186#define tcg_gen_subfi_reg tcg_gen_subfi_i32
187#define tcg_gen_subi_reg tcg_gen_subi_i32
188#define tcg_gen_and_reg tcg_gen_and_i32
189#define tcg_gen_andi_reg tcg_gen_andi_i32
190#define tcg_gen_or_reg tcg_gen_or_i32
191#define tcg_gen_ori_reg tcg_gen_ori_i32
192#define tcg_gen_xor_reg tcg_gen_xor_i32
193#define tcg_gen_xori_reg tcg_gen_xori_i32
194#define tcg_gen_not_reg tcg_gen_not_i32
195#define tcg_gen_shl_reg tcg_gen_shl_i32
196#define tcg_gen_shli_reg tcg_gen_shli_i32
197#define tcg_gen_shr_reg tcg_gen_shr_i32
198#define tcg_gen_shri_reg tcg_gen_shri_i32
199#define tcg_gen_sar_reg tcg_gen_sar_i32
200#define tcg_gen_sari_reg tcg_gen_sari_i32
201#define tcg_gen_brcond_reg tcg_gen_brcond_i32
202#define tcg_gen_brcondi_reg tcg_gen_brcondi_i32
203#define tcg_gen_setcond_reg tcg_gen_setcond_i32
204#define tcg_gen_setcondi_reg tcg_gen_setcondi_i32
205#define tcg_gen_mul_reg tcg_gen_mul_i32
206#define tcg_gen_muli_reg tcg_gen_muli_i32
207#define tcg_gen_div_reg tcg_gen_div_i32
208#define tcg_gen_rem_reg tcg_gen_rem_i32
209#define tcg_gen_divu_reg tcg_gen_divu_i32
210#define tcg_gen_remu_reg tcg_gen_remu_i32
211#define tcg_gen_discard_reg tcg_gen_discard_i32
212#define tcg_gen_trunc_reg_i32 tcg_gen_mov_i32
213#define tcg_gen_trunc_i64_reg tcg_gen_extrl_i64_i32
214#define tcg_gen_extu_i32_reg tcg_gen_mov_i32
215#define tcg_gen_ext_i32_reg tcg_gen_mov_i32
216#define tcg_gen_extu_reg_i64 tcg_gen_extu_i32_i64
217#define tcg_gen_ext_reg_i64 tcg_gen_ext_i32_i64
218#define tcg_gen_ext8u_reg tcg_gen_ext8u_i32
219#define tcg_gen_ext8s_reg tcg_gen_ext8s_i32
220#define tcg_gen_ext16u_reg tcg_gen_ext16u_i32
221#define tcg_gen_ext16s_reg tcg_gen_ext16s_i32
222#define tcg_gen_ext32u_reg tcg_gen_mov_i32
223#define tcg_gen_ext32s_reg tcg_gen_mov_i32
224#define tcg_gen_bswap16_reg tcg_gen_bswap16_i32
225#define tcg_gen_bswap32_reg tcg_gen_bswap32_i32
226#define tcg_gen_concat_reg_i64 tcg_gen_concat_i32_i64
227#define tcg_gen_andc_reg tcg_gen_andc_i32
228#define tcg_gen_eqv_reg tcg_gen_eqv_i32
229#define tcg_gen_nand_reg tcg_gen_nand_i32
230#define tcg_gen_nor_reg tcg_gen_nor_i32
231#define tcg_gen_orc_reg tcg_gen_orc_i32
232#define tcg_gen_clz_reg tcg_gen_clz_i32
233#define tcg_gen_ctz_reg tcg_gen_ctz_i32
234#define tcg_gen_clzi_reg tcg_gen_clzi_i32
235#define tcg_gen_ctzi_reg tcg_gen_ctzi_i32
236#define tcg_gen_clrsb_reg tcg_gen_clrsb_i32
237#define tcg_gen_ctpop_reg tcg_gen_ctpop_i32
238#define tcg_gen_rotl_reg tcg_gen_rotl_i32
239#define tcg_gen_rotli_reg tcg_gen_rotli_i32
240#define tcg_gen_rotr_reg tcg_gen_rotr_i32
241#define tcg_gen_rotri_reg tcg_gen_rotri_i32
242#define tcg_gen_deposit_reg tcg_gen_deposit_i32
243#define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i32
244#define tcg_gen_extract_reg tcg_gen_extract_i32
245#define tcg_gen_sextract_reg tcg_gen_sextract_i32
246#define tcg_const_reg tcg_const_i32
247#define tcg_const_local_reg tcg_const_local_i32
248#define tcg_gen_movcond_reg tcg_gen_movcond_i32
249#define tcg_gen_add2_reg tcg_gen_add2_i32
250#define tcg_gen_sub2_reg tcg_gen_sub2_i32
251#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i32
252#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i32
253#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i32
254#if UINTPTR_MAX == UINT32_MAX
255# define tcg_gen_trunc_reg_ptr(p, r) \
256 tcg_gen_mov_i32(TCGV_PTR_TO_NAT(p), r)
257#else
258# define tcg_gen_trunc_reg_ptr(p, r) \
259 tcg_gen_extu_i32_i64(TCGV_PTR_TO_NAT(p), r)
260#endif
261#endif /* TARGET_REGISTER_BITS */
262
61766fe9
RH
263typedef struct DisasCond {
264 TCGCond c;
eaa3783b 265 TCGv_reg a0, a1;
61766fe9
RH
266 bool a0_is_n;
267 bool a1_is_0;
268} DisasCond;
269
270typedef struct DisasContext {
d01a3625 271 DisasContextBase base;
61766fe9
RH
272 CPUState *cs;
273
eaa3783b
RH
274 target_ureg iaoq_f;
275 target_ureg iaoq_b;
276 target_ureg iaoq_n;
277 TCGv_reg iaoq_n_var;
61766fe9 278
86f8d05f 279 int ntempr, ntempl;
5eecd37a 280 TCGv_reg tempr[8];
86f8d05f 281 TCGv_tl templ[4];
61766fe9
RH
282
283 DisasCond null_cond;
284 TCGLabel *null_lab;
285
1a19da0d 286 uint32_t insn;
494737b7 287 uint32_t tb_flags;
3d68ee7b
RH
288 int mmu_idx;
289 int privilege;
61766fe9
RH
290 bool psw_n_nonzero;
291} DisasContext;
292
869051ea
RH
293/* Target-specific return values from translate_one, indicating the
294 state of the TB. Note that DISAS_NEXT indicates that we are not
295 exiting the TB. */
61766fe9 296
869051ea
RH
297/* We are not using a goto_tb (for whatever reason), but have updated
298 the iaq (for whatever reason), so don't do it again on exit. */
299#define DISAS_IAQ_N_UPDATED DISAS_TARGET_0
61766fe9 300
869051ea
RH
301/* We are exiting the TB, but have neither emitted a goto_tb, nor
302 updated the iaq for the next instruction to be executed. */
303#define DISAS_IAQ_N_STALE DISAS_TARGET_1
61766fe9 304
e1b5a5ed
RH
305/* Similarly, but we want to return to the main loop immediately
306 to recognize unmasked interrupts. */
307#define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2
308
61766fe9
RH
309typedef struct DisasInsn {
310 uint32_t insn, mask;
869051ea
RH
311 DisasJumpType (*trans)(DisasContext *ctx, uint32_t insn,
312 const struct DisasInsn *f);
b2167459 313 union {
eaa3783b 314 void (*ttt)(TCGv_reg, TCGv_reg, TCGv_reg);
eff235eb
PB
315 void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
316 void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
317 void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
318 void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
319 void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
320 void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
321 } f;
61766fe9
RH
322} DisasInsn;
323
324/* global register indexes */
eaa3783b 325static TCGv_reg cpu_gr[32];
33423472 326static TCGv_i64 cpu_sr[4];
494737b7 327static TCGv_i64 cpu_srH;
eaa3783b
RH
328static TCGv_reg cpu_iaoq_f;
329static TCGv_reg cpu_iaoq_b;
c301f34e
RH
330static TCGv_i64 cpu_iasq_f;
331static TCGv_i64 cpu_iasq_b;
eaa3783b
RH
332static TCGv_reg cpu_sar;
333static TCGv_reg cpu_psw_n;
334static TCGv_reg cpu_psw_v;
335static TCGv_reg cpu_psw_cb;
336static TCGv_reg cpu_psw_cb_msb;
61766fe9
RH
337
338#include "exec/gen-icount.h"
339
340void hppa_translate_init(void)
341{
342#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
343
eaa3783b 344 typedef struct { TCGv_reg *var; const char *name; int ofs; } GlobalVar;
61766fe9 345 static const GlobalVar vars[] = {
35136a77 346 { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
61766fe9
RH
347 DEF_VAR(psw_n),
348 DEF_VAR(psw_v),
349 DEF_VAR(psw_cb),
350 DEF_VAR(psw_cb_msb),
351 DEF_VAR(iaoq_f),
352 DEF_VAR(iaoq_b),
353 };
354
355#undef DEF_VAR
356
357 /* Use the symbolic register names that match the disassembler. */
358 static const char gr_names[32][4] = {
359 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
360 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
361 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
362 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
363 };
33423472 364 /* SR[4-7] are not global registers so that we can index them. */
494737b7
RH
365 static const char sr_names[5][4] = {
366 "sr0", "sr1", "sr2", "sr3", "srH"
33423472 367 };
61766fe9 368
61766fe9
RH
369 int i;
370
f764718d 371 cpu_gr[0] = NULL;
61766fe9
RH
372 for (i = 1; i < 32; i++) {
373 cpu_gr[i] = tcg_global_mem_new(cpu_env,
374 offsetof(CPUHPPAState, gr[i]),
375 gr_names[i]);
376 }
33423472
RH
377 for (i = 0; i < 4; i++) {
378 cpu_sr[i] = tcg_global_mem_new_i64(cpu_env,
379 offsetof(CPUHPPAState, sr[i]),
380 sr_names[i]);
381 }
494737b7
RH
382 cpu_srH = tcg_global_mem_new_i64(cpu_env,
383 offsetof(CPUHPPAState, sr[4]),
384 sr_names[4]);
61766fe9
RH
385
386 for (i = 0; i < ARRAY_SIZE(vars); ++i) {
387 const GlobalVar *v = &vars[i];
388 *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
389 }
c301f34e
RH
390
391 cpu_iasq_f = tcg_global_mem_new_i64(cpu_env,
392 offsetof(CPUHPPAState, iasq_f),
393 "iasq_f");
394 cpu_iasq_b = tcg_global_mem_new_i64(cpu_env,
395 offsetof(CPUHPPAState, iasq_b),
396 "iasq_b");
61766fe9
RH
397}
398
129e9cc3
RH
399static DisasCond cond_make_f(void)
400{
f764718d
RH
401 return (DisasCond){
402 .c = TCG_COND_NEVER,
403 .a0 = NULL,
404 .a1 = NULL,
405 };
129e9cc3
RH
406}
407
408static DisasCond cond_make_n(void)
409{
f764718d
RH
410 return (DisasCond){
411 .c = TCG_COND_NE,
412 .a0 = cpu_psw_n,
413 .a0_is_n = true,
414 .a1 = NULL,
415 .a1_is_0 = true
416 };
129e9cc3
RH
417}
418
eaa3783b 419static DisasCond cond_make_0(TCGCond c, TCGv_reg a0)
129e9cc3 420{
f764718d 421 DisasCond r = { .c = c, .a1 = NULL, .a1_is_0 = true };
129e9cc3
RH
422
423 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
424 r.a0 = tcg_temp_new();
eaa3783b 425 tcg_gen_mov_reg(r.a0, a0);
129e9cc3
RH
426
427 return r;
428}
429
eaa3783b 430static DisasCond cond_make(TCGCond c, TCGv_reg a0, TCGv_reg a1)
129e9cc3
RH
431{
432 DisasCond r = { .c = c };
433
434 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
435 r.a0 = tcg_temp_new();
eaa3783b 436 tcg_gen_mov_reg(r.a0, a0);
129e9cc3 437 r.a1 = tcg_temp_new();
eaa3783b 438 tcg_gen_mov_reg(r.a1, a1);
129e9cc3
RH
439
440 return r;
441}
442
443static void cond_prep(DisasCond *cond)
444{
445 if (cond->a1_is_0) {
446 cond->a1_is_0 = false;
eaa3783b 447 cond->a1 = tcg_const_reg(0);
129e9cc3
RH
448 }
449}
450
451static void cond_free(DisasCond *cond)
452{
453 switch (cond->c) {
454 default:
455 if (!cond->a0_is_n) {
456 tcg_temp_free(cond->a0);
457 }
458 if (!cond->a1_is_0) {
459 tcg_temp_free(cond->a1);
460 }
461 cond->a0_is_n = false;
462 cond->a1_is_0 = false;
f764718d
RH
463 cond->a0 = NULL;
464 cond->a1 = NULL;
129e9cc3
RH
465 /* fallthru */
466 case TCG_COND_ALWAYS:
467 cond->c = TCG_COND_NEVER;
468 break;
469 case TCG_COND_NEVER:
470 break;
471 }
472}
473
eaa3783b 474static TCGv_reg get_temp(DisasContext *ctx)
61766fe9 475{
86f8d05f
RH
476 unsigned i = ctx->ntempr++;
477 g_assert(i < ARRAY_SIZE(ctx->tempr));
478 return ctx->tempr[i] = tcg_temp_new();
61766fe9
RH
479}
480
86f8d05f
RH
481#ifndef CONFIG_USER_ONLY
482static TCGv_tl get_temp_tl(DisasContext *ctx)
483{
484 unsigned i = ctx->ntempl++;
485 g_assert(i < ARRAY_SIZE(ctx->templ));
486 return ctx->templ[i] = tcg_temp_new_tl();
487}
488#endif
489
eaa3783b 490static TCGv_reg load_const(DisasContext *ctx, target_sreg v)
61766fe9 491{
eaa3783b
RH
492 TCGv_reg t = get_temp(ctx);
493 tcg_gen_movi_reg(t, v);
61766fe9
RH
494 return t;
495}
496
eaa3783b 497static TCGv_reg load_gpr(DisasContext *ctx, unsigned reg)
61766fe9
RH
498{
499 if (reg == 0) {
eaa3783b
RH
500 TCGv_reg t = get_temp(ctx);
501 tcg_gen_movi_reg(t, 0);
61766fe9
RH
502 return t;
503 } else {
504 return cpu_gr[reg];
505 }
506}
507
eaa3783b 508static TCGv_reg dest_gpr(DisasContext *ctx, unsigned reg)
61766fe9 509{
129e9cc3 510 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
61766fe9
RH
511 return get_temp(ctx);
512 } else {
513 return cpu_gr[reg];
514 }
515}
516
eaa3783b 517static void save_or_nullify(DisasContext *ctx, TCGv_reg dest, TCGv_reg t)
129e9cc3
RH
518{
519 if (ctx->null_cond.c != TCG_COND_NEVER) {
520 cond_prep(&ctx->null_cond);
eaa3783b 521 tcg_gen_movcond_reg(ctx->null_cond.c, dest, ctx->null_cond.a0,
129e9cc3
RH
522 ctx->null_cond.a1, dest, t);
523 } else {
eaa3783b 524 tcg_gen_mov_reg(dest, t);
129e9cc3
RH
525 }
526}
527
eaa3783b 528static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t)
129e9cc3
RH
529{
530 if (reg != 0) {
531 save_or_nullify(ctx, cpu_gr[reg], t);
532 }
533}
534
96d6407f
RH
535#ifdef HOST_WORDS_BIGENDIAN
536# define HI_OFS 0
537# define LO_OFS 4
538#else
539# define HI_OFS 4
540# define LO_OFS 0
541#endif
542
543static TCGv_i32 load_frw_i32(unsigned rt)
544{
545 TCGv_i32 ret = tcg_temp_new_i32();
546 tcg_gen_ld_i32(ret, cpu_env,
547 offsetof(CPUHPPAState, fr[rt & 31])
548 + (rt & 32 ? LO_OFS : HI_OFS));
549 return ret;
550}
551
ebe9383c
RH
552static TCGv_i32 load_frw0_i32(unsigned rt)
553{
554 if (rt == 0) {
555 return tcg_const_i32(0);
556 } else {
557 return load_frw_i32(rt);
558 }
559}
560
561static TCGv_i64 load_frw0_i64(unsigned rt)
562{
563 if (rt == 0) {
564 return tcg_const_i64(0);
565 } else {
566 TCGv_i64 ret = tcg_temp_new_i64();
567 tcg_gen_ld32u_i64(ret, cpu_env,
568 offsetof(CPUHPPAState, fr[rt & 31])
569 + (rt & 32 ? LO_OFS : HI_OFS));
570 return ret;
571 }
572}
573
96d6407f
RH
574static void save_frw_i32(unsigned rt, TCGv_i32 val)
575{
576 tcg_gen_st_i32(val, cpu_env,
577 offsetof(CPUHPPAState, fr[rt & 31])
578 + (rt & 32 ? LO_OFS : HI_OFS));
579}
580
581#undef HI_OFS
582#undef LO_OFS
583
584static TCGv_i64 load_frd(unsigned rt)
585{
586 TCGv_i64 ret = tcg_temp_new_i64();
587 tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
588 return ret;
589}
590
ebe9383c
RH
591static TCGv_i64 load_frd0(unsigned rt)
592{
593 if (rt == 0) {
594 return tcg_const_i64(0);
595 } else {
596 return load_frd(rt);
597 }
598}
599
96d6407f
RH
600static void save_frd(unsigned rt, TCGv_i64 val)
601{
602 tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
603}
604
33423472
RH
605static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
606{
607#ifdef CONFIG_USER_ONLY
608 tcg_gen_movi_i64(dest, 0);
609#else
610 if (reg < 4) {
611 tcg_gen_mov_i64(dest, cpu_sr[reg]);
494737b7
RH
612 } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
613 tcg_gen_mov_i64(dest, cpu_srH);
33423472
RH
614 } else {
615 tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUHPPAState, sr[reg]));
616 }
617#endif
618}
619
129e9cc3
RH
620/* Skip over the implementation of an insn that has been nullified.
621 Use this when the insn is too complex for a conditional move. */
622static void nullify_over(DisasContext *ctx)
623{
624 if (ctx->null_cond.c != TCG_COND_NEVER) {
625 /* The always condition should have been handled in the main loop. */
626 assert(ctx->null_cond.c != TCG_COND_ALWAYS);
627
628 ctx->null_lab = gen_new_label();
629 cond_prep(&ctx->null_cond);
630
631 /* If we're using PSW[N], copy it to a temp because... */
632 if (ctx->null_cond.a0_is_n) {
633 ctx->null_cond.a0_is_n = false;
634 ctx->null_cond.a0 = tcg_temp_new();
eaa3783b 635 tcg_gen_mov_reg(ctx->null_cond.a0, cpu_psw_n);
129e9cc3
RH
636 }
637 /* ... we clear it before branching over the implementation,
638 so that (1) it's clear after nullifying this insn and
639 (2) if this insn nullifies the next, PSW[N] is valid. */
640 if (ctx->psw_n_nonzero) {
641 ctx->psw_n_nonzero = false;
eaa3783b 642 tcg_gen_movi_reg(cpu_psw_n, 0);
129e9cc3
RH
643 }
644
eaa3783b 645 tcg_gen_brcond_reg(ctx->null_cond.c, ctx->null_cond.a0,
129e9cc3
RH
646 ctx->null_cond.a1, ctx->null_lab);
647 cond_free(&ctx->null_cond);
648 }
649}
650
651/* Save the current nullification state to PSW[N]. */
652static void nullify_save(DisasContext *ctx)
653{
654 if (ctx->null_cond.c == TCG_COND_NEVER) {
655 if (ctx->psw_n_nonzero) {
eaa3783b 656 tcg_gen_movi_reg(cpu_psw_n, 0);
129e9cc3
RH
657 }
658 return;
659 }
660 if (!ctx->null_cond.a0_is_n) {
661 cond_prep(&ctx->null_cond);
eaa3783b 662 tcg_gen_setcond_reg(ctx->null_cond.c, cpu_psw_n,
129e9cc3
RH
663 ctx->null_cond.a0, ctx->null_cond.a1);
664 ctx->psw_n_nonzero = true;
665 }
666 cond_free(&ctx->null_cond);
667}
668
669/* Set a PSW[N] to X. The intention is that this is used immediately
670 before a goto_tb/exit_tb, so that there is no fallthru path to other
671 code within the TB. Therefore we do not update psw_n_nonzero. */
672static void nullify_set(DisasContext *ctx, bool x)
673{
674 if (ctx->psw_n_nonzero || x) {
eaa3783b 675 tcg_gen_movi_reg(cpu_psw_n, x);
129e9cc3
RH
676 }
677}
678
679/* Mark the end of an instruction that may have been nullified.
680 This is the pair to nullify_over. */
869051ea 681static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status)
129e9cc3
RH
682{
683 TCGLabel *null_lab = ctx->null_lab;
684
f49b3537
RH
685 /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
686 For UPDATED, we cannot update on the nullified path. */
687 assert(status != DISAS_IAQ_N_UPDATED);
688
129e9cc3
RH
689 if (likely(null_lab == NULL)) {
690 /* The current insn wasn't conditional or handled the condition
691 applied to it without a branch, so the (new) setting of
692 NULL_COND can be applied directly to the next insn. */
693 return status;
694 }
695 ctx->null_lab = NULL;
696
697 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
698 /* The next instruction will be unconditional,
699 and NULL_COND already reflects that. */
700 gen_set_label(null_lab);
701 } else {
702 /* The insn that we just executed is itself nullifying the next
703 instruction. Store the condition in the PSW[N] global.
704 We asserted PSW[N] = 0 in nullify_over, so that after the
705 label we have the proper value in place. */
706 nullify_save(ctx);
707 gen_set_label(null_lab);
708 ctx->null_cond = cond_make_n();
709 }
869051ea
RH
710 if (status == DISAS_NORETURN) {
711 status = DISAS_NEXT;
129e9cc3
RH
712 }
713 return status;
714}
715
eaa3783b 716static void copy_iaoq_entry(TCGv_reg dest, target_ureg ival, TCGv_reg vval)
61766fe9
RH
717{
718 if (unlikely(ival == -1)) {
eaa3783b 719 tcg_gen_mov_reg(dest, vval);
61766fe9 720 } else {
eaa3783b 721 tcg_gen_movi_reg(dest, ival);
61766fe9
RH
722 }
723}
724
eaa3783b 725static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp)
61766fe9
RH
726{
727 return ctx->iaoq_f + disp + 8;
728}
729
730static void gen_excp_1(int exception)
731{
732 TCGv_i32 t = tcg_const_i32(exception);
733 gen_helper_excp(cpu_env, t);
734 tcg_temp_free_i32(t);
735}
736
869051ea 737static DisasJumpType gen_excp(DisasContext *ctx, int exception)
61766fe9
RH
738{
739 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
740 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
129e9cc3 741 nullify_save(ctx);
61766fe9 742 gen_excp_1(exception);
869051ea 743 return DISAS_NORETURN;
61766fe9
RH
744}
745
1a19da0d
RH
746static DisasJumpType gen_excp_iir(DisasContext *ctx, int exc)
747{
748 TCGv_reg tmp = tcg_const_reg(ctx->insn);
749 tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[CR_IIR]));
750 tcg_temp_free(tmp);
751 return gen_excp(ctx, exc);
752}
753
869051ea 754static DisasJumpType gen_illegal(DisasContext *ctx)
61766fe9 755{
129e9cc3 756 nullify_over(ctx);
1a19da0d 757 return nullify_end(ctx, gen_excp_iir(ctx, EXCP_ILL));
61766fe9
RH
758}
759
e1b5a5ed
RH
760#define CHECK_MOST_PRIVILEGED(EXCP) \
761 do { \
762 if (ctx->privilege != 0) { \
763 nullify_over(ctx); \
1a19da0d 764 return nullify_end(ctx, gen_excp_iir(ctx, EXCP)); \
e1b5a5ed
RH
765 } \
766 } while (0)
767
eaa3783b 768static bool use_goto_tb(DisasContext *ctx, target_ureg dest)
61766fe9
RH
769{
770 /* Suppress goto_tb in the case of single-steping and IO. */
c5a49c63 771 if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ctx->base.singlestep_enabled) {
61766fe9
RH
772 return false;
773 }
774 return true;
775}
776
129e9cc3
RH
777/* If the next insn is to be nullified, and it's on the same page,
778 and we're not attempting to set a breakpoint on it, then we can
779 totally skip the nullified insn. This avoids creating and
780 executing a TB that merely branches to the next TB. */
781static bool use_nullify_skip(DisasContext *ctx)
782{
783 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
784 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
785}
786
61766fe9 787static void gen_goto_tb(DisasContext *ctx, int which,
eaa3783b 788 target_ureg f, target_ureg b)
61766fe9
RH
789{
790 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
791 tcg_gen_goto_tb(which);
eaa3783b
RH
792 tcg_gen_movi_reg(cpu_iaoq_f, f);
793 tcg_gen_movi_reg(cpu_iaoq_b, b);
d01a3625 794 tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which);
61766fe9
RH
795 } else {
796 copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
797 copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
d01a3625 798 if (ctx->base.singlestep_enabled) {
61766fe9
RH
799 gen_excp_1(EXCP_DEBUG);
800 } else {
7f11636d 801 tcg_gen_lookup_and_goto_ptr();
61766fe9
RH
802 }
803 }
804}
805
b2167459
RH
806/* PA has a habit of taking the LSB of a field and using that as the sign,
807 with the rest of the field becoming the least significant bits. */
eaa3783b 808static target_sreg low_sextract(uint32_t val, int pos, int len)
b2167459 809{
eaa3783b 810 target_ureg x = -(target_ureg)extract32(val, pos, 1);
b2167459
RH
811 x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
812 return x;
813}
814
ebe9383c
RH
815static unsigned assemble_rt64(uint32_t insn)
816{
817 unsigned r1 = extract32(insn, 6, 1);
818 unsigned r0 = extract32(insn, 0, 5);
819 return r1 * 32 + r0;
820}
821
822static unsigned assemble_ra64(uint32_t insn)
823{
824 unsigned r1 = extract32(insn, 7, 1);
825 unsigned r0 = extract32(insn, 21, 5);
826 return r1 * 32 + r0;
827}
828
829static unsigned assemble_rb64(uint32_t insn)
830{
831 unsigned r1 = extract32(insn, 12, 1);
832 unsigned r0 = extract32(insn, 16, 5);
833 return r1 * 32 + r0;
834}
835
836static unsigned assemble_rc64(uint32_t insn)
837{
838 unsigned r2 = extract32(insn, 8, 1);
839 unsigned r1 = extract32(insn, 13, 3);
840 unsigned r0 = extract32(insn, 9, 2);
841 return r2 * 32 + r1 * 4 + r0;
842}
843
33423472
RH
844static unsigned assemble_sr3(uint32_t insn)
845{
846 unsigned s2 = extract32(insn, 13, 1);
847 unsigned s0 = extract32(insn, 14, 2);
848 return s2 * 4 + s0;
849}
850
eaa3783b 851static target_sreg assemble_12(uint32_t insn)
98cd9ca7 852{
eaa3783b 853 target_ureg x = -(target_ureg)(insn & 1);
98cd9ca7
RH
854 x = (x << 1) | extract32(insn, 2, 1);
855 x = (x << 10) | extract32(insn, 3, 10);
856 return x;
857}
858
eaa3783b 859static target_sreg assemble_16(uint32_t insn)
b2167459
RH
860{
861 /* Take the name from PA2.0, which produces a 16-bit number
862 only with wide mode; otherwise a 14-bit number. Since we don't
863 implement wide mode, this is always the 14-bit number. */
864 return low_sextract(insn, 0, 14);
865}
866
eaa3783b 867static target_sreg assemble_16a(uint32_t insn)
96d6407f
RH
868{
869 /* Take the name from PA2.0, which produces a 14-bit shifted number
870 only with wide mode; otherwise a 12-bit shifted number. Since we
871 don't implement wide mode, this is always the 12-bit number. */
eaa3783b 872 target_ureg x = -(target_ureg)(insn & 1);
96d6407f
RH
873 x = (x << 11) | extract32(insn, 2, 11);
874 return x << 2;
875}
876
eaa3783b 877static target_sreg assemble_17(uint32_t insn)
98cd9ca7 878{
eaa3783b 879 target_ureg x = -(target_ureg)(insn & 1);
98cd9ca7
RH
880 x = (x << 5) | extract32(insn, 16, 5);
881 x = (x << 1) | extract32(insn, 2, 1);
882 x = (x << 10) | extract32(insn, 3, 10);
883 return x << 2;
884}
885
eaa3783b 886static target_sreg assemble_21(uint32_t insn)
b2167459 887{
eaa3783b 888 target_ureg x = -(target_ureg)(insn & 1);
b2167459
RH
889 x = (x << 11) | extract32(insn, 1, 11);
890 x = (x << 2) | extract32(insn, 14, 2);
891 x = (x << 5) | extract32(insn, 16, 5);
892 x = (x << 2) | extract32(insn, 12, 2);
893 return x << 11;
894}
895
eaa3783b 896static target_sreg assemble_22(uint32_t insn)
98cd9ca7 897{
eaa3783b 898 target_ureg x = -(target_ureg)(insn & 1);
98cd9ca7
RH
899 x = (x << 10) | extract32(insn, 16, 10);
900 x = (x << 1) | extract32(insn, 2, 1);
901 x = (x << 10) | extract32(insn, 3, 10);
902 return x << 2;
903}
904
b2167459
RH
905/* The parisc documentation describes only the general interpretation of
906 the conditions, without describing their exact implementation. The
907 interpretations do not stand up well when considering ADD,C and SUB,B.
908 However, considering the Addition, Subtraction and Logical conditions
909 as a whole it would appear that these relations are similar to what
910 a traditional NZCV set of flags would produce. */
911
eaa3783b
RH
912static DisasCond do_cond(unsigned cf, TCGv_reg res,
913 TCGv_reg cb_msb, TCGv_reg sv)
b2167459
RH
914{
915 DisasCond cond;
eaa3783b 916 TCGv_reg tmp;
b2167459
RH
917
918 switch (cf >> 1) {
919 case 0: /* Never / TR */
920 cond = cond_make_f();
921 break;
922 case 1: /* = / <> (Z / !Z) */
923 cond = cond_make_0(TCG_COND_EQ, res);
924 break;
925 case 2: /* < / >= (N / !N) */
926 cond = cond_make_0(TCG_COND_LT, res);
927 break;
928 case 3: /* <= / > (N | Z / !N & !Z) */
929 cond = cond_make_0(TCG_COND_LE, res);
930 break;
931 case 4: /* NUV / UV (!C / C) */
932 cond = cond_make_0(TCG_COND_EQ, cb_msb);
933 break;
934 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */
935 tmp = tcg_temp_new();
eaa3783b
RH
936 tcg_gen_neg_reg(tmp, cb_msb);
937 tcg_gen_and_reg(tmp, tmp, res);
b2167459
RH
938 cond = cond_make_0(TCG_COND_EQ, tmp);
939 tcg_temp_free(tmp);
940 break;
941 case 6: /* SV / NSV (V / !V) */
942 cond = cond_make_0(TCG_COND_LT, sv);
943 break;
944 case 7: /* OD / EV */
945 tmp = tcg_temp_new();
eaa3783b 946 tcg_gen_andi_reg(tmp, res, 1);
b2167459
RH
947 cond = cond_make_0(TCG_COND_NE, tmp);
948 tcg_temp_free(tmp);
949 break;
950 default:
951 g_assert_not_reached();
952 }
953 if (cf & 1) {
954 cond.c = tcg_invert_cond(cond.c);
955 }
956
957 return cond;
958}
959
960/* Similar, but for the special case of subtraction without borrow, we
961 can use the inputs directly. This can allow other computation to be
962 deleted as unused. */
963
eaa3783b
RH
964static DisasCond do_sub_cond(unsigned cf, TCGv_reg res,
965 TCGv_reg in1, TCGv_reg in2, TCGv_reg sv)
b2167459
RH
966{
967 DisasCond cond;
968
969 switch (cf >> 1) {
970 case 1: /* = / <> */
971 cond = cond_make(TCG_COND_EQ, in1, in2);
972 break;
973 case 2: /* < / >= */
974 cond = cond_make(TCG_COND_LT, in1, in2);
975 break;
976 case 3: /* <= / > */
977 cond = cond_make(TCG_COND_LE, in1, in2);
978 break;
979 case 4: /* << / >>= */
980 cond = cond_make(TCG_COND_LTU, in1, in2);
981 break;
982 case 5: /* <<= / >> */
983 cond = cond_make(TCG_COND_LEU, in1, in2);
984 break;
985 default:
986 return do_cond(cf, res, sv, sv);
987 }
988 if (cf & 1) {
989 cond.c = tcg_invert_cond(cond.c);
990 }
991
992 return cond;
993}
994
995/* Similar, but for logicals, where the carry and overflow bits are not
996 computed, and use of them is undefined. */
997
eaa3783b 998static DisasCond do_log_cond(unsigned cf, TCGv_reg res)
b2167459
RH
999{
1000 switch (cf >> 1) {
1001 case 4: case 5: case 6:
1002 cf &= 1;
1003 break;
1004 }
1005 return do_cond(cf, res, res, res);
1006}
1007
98cd9ca7
RH
1008/* Similar, but for shift/extract/deposit conditions. */
1009
eaa3783b 1010static DisasCond do_sed_cond(unsigned orig, TCGv_reg res)
98cd9ca7
RH
1011{
1012 unsigned c, f;
1013
1014 /* Convert the compressed condition codes to standard.
1015 0-2 are the same as logicals (nv,<,<=), while 3 is OD.
1016 4-7 are the reverse of 0-3. */
1017 c = orig & 3;
1018 if (c == 3) {
1019 c = 7;
1020 }
1021 f = (orig & 4) / 4;
1022
1023 return do_log_cond(c * 2 + f, res);
1024}
1025
b2167459
RH
1026/* Similar, but for unit conditions. */
1027
eaa3783b
RH
1028static DisasCond do_unit_cond(unsigned cf, TCGv_reg res,
1029 TCGv_reg in1, TCGv_reg in2)
b2167459
RH
1030{
1031 DisasCond cond;
eaa3783b 1032 TCGv_reg tmp, cb = NULL;
b2167459 1033
b2167459
RH
1034 if (cf & 8) {
1035 /* Since we want to test lots of carry-out bits all at once, do not
1036 * do our normal thing and compute carry-in of bit B+1 since that
1037 * leaves us with carry bits spread across two words.
1038 */
1039 cb = tcg_temp_new();
1040 tmp = tcg_temp_new();
eaa3783b
RH
1041 tcg_gen_or_reg(cb, in1, in2);
1042 tcg_gen_and_reg(tmp, in1, in2);
1043 tcg_gen_andc_reg(cb, cb, res);
1044 tcg_gen_or_reg(cb, cb, tmp);
b2167459
RH
1045 tcg_temp_free(tmp);
1046 }
1047
1048 switch (cf >> 1) {
1049 case 0: /* never / TR */
1050 case 1: /* undefined */
1051 case 5: /* undefined */
1052 cond = cond_make_f();
1053 break;
1054
1055 case 2: /* SBZ / NBZ */
1056 /* See hasless(v,1) from
1057 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1058 */
1059 tmp = tcg_temp_new();
eaa3783b
RH
1060 tcg_gen_subi_reg(tmp, res, 0x01010101u);
1061 tcg_gen_andc_reg(tmp, tmp, res);
1062 tcg_gen_andi_reg(tmp, tmp, 0x80808080u);
b2167459
RH
1063 cond = cond_make_0(TCG_COND_NE, tmp);
1064 tcg_temp_free(tmp);
1065 break;
1066
1067 case 3: /* SHZ / NHZ */
1068 tmp = tcg_temp_new();
eaa3783b
RH
1069 tcg_gen_subi_reg(tmp, res, 0x00010001u);
1070 tcg_gen_andc_reg(tmp, tmp, res);
1071 tcg_gen_andi_reg(tmp, tmp, 0x80008000u);
b2167459
RH
1072 cond = cond_make_0(TCG_COND_NE, tmp);
1073 tcg_temp_free(tmp);
1074 break;
1075
1076 case 4: /* SDC / NDC */
eaa3783b 1077 tcg_gen_andi_reg(cb, cb, 0x88888888u);
b2167459
RH
1078 cond = cond_make_0(TCG_COND_NE, cb);
1079 break;
1080
1081 case 6: /* SBC / NBC */
eaa3783b 1082 tcg_gen_andi_reg(cb, cb, 0x80808080u);
b2167459
RH
1083 cond = cond_make_0(TCG_COND_NE, cb);
1084 break;
1085
1086 case 7: /* SHC / NHC */
eaa3783b 1087 tcg_gen_andi_reg(cb, cb, 0x80008000u);
b2167459
RH
1088 cond = cond_make_0(TCG_COND_NE, cb);
1089 break;
1090
1091 default:
1092 g_assert_not_reached();
1093 }
1094 if (cf & 8) {
1095 tcg_temp_free(cb);
1096 }
1097 if (cf & 1) {
1098 cond.c = tcg_invert_cond(cond.c);
1099 }
1100
1101 return cond;
1102}
1103
1104/* Compute signed overflow for addition. */
eaa3783b
RH
1105static TCGv_reg do_add_sv(DisasContext *ctx, TCGv_reg res,
1106 TCGv_reg in1, TCGv_reg in2)
b2167459 1107{
eaa3783b
RH
1108 TCGv_reg sv = get_temp(ctx);
1109 TCGv_reg tmp = tcg_temp_new();
b2167459 1110
eaa3783b
RH
1111 tcg_gen_xor_reg(sv, res, in1);
1112 tcg_gen_xor_reg(tmp, in1, in2);
1113 tcg_gen_andc_reg(sv, sv, tmp);
b2167459
RH
1114 tcg_temp_free(tmp);
1115
1116 return sv;
1117}
1118
1119/* Compute signed overflow for subtraction. */
eaa3783b
RH
1120static TCGv_reg do_sub_sv(DisasContext *ctx, TCGv_reg res,
1121 TCGv_reg in1, TCGv_reg in2)
b2167459 1122{
eaa3783b
RH
1123 TCGv_reg sv = get_temp(ctx);
1124 TCGv_reg tmp = tcg_temp_new();
b2167459 1125
eaa3783b
RH
1126 tcg_gen_xor_reg(sv, res, in1);
1127 tcg_gen_xor_reg(tmp, in1, in2);
1128 tcg_gen_and_reg(sv, sv, tmp);
b2167459
RH
1129 tcg_temp_free(tmp);
1130
1131 return sv;
1132}
1133
eaa3783b
RH
1134static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1135 TCGv_reg in2, unsigned shift, bool is_l,
1136 bool is_tsv, bool is_tc, bool is_c, unsigned cf)
b2167459 1137{
eaa3783b 1138 TCGv_reg dest, cb, cb_msb, sv, tmp;
b2167459
RH
1139 unsigned c = cf >> 1;
1140 DisasCond cond;
1141
1142 dest = tcg_temp_new();
f764718d
RH
1143 cb = NULL;
1144 cb_msb = NULL;
b2167459
RH
1145
1146 if (shift) {
1147 tmp = get_temp(ctx);
eaa3783b 1148 tcg_gen_shli_reg(tmp, in1, shift);
b2167459
RH
1149 in1 = tmp;
1150 }
1151
1152 if (!is_l || c == 4 || c == 5) {
eaa3783b 1153 TCGv_reg zero = tcg_const_reg(0);
b2167459 1154 cb_msb = get_temp(ctx);
eaa3783b 1155 tcg_gen_add2_reg(dest, cb_msb, in1, zero, in2, zero);
b2167459 1156 if (is_c) {
eaa3783b 1157 tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
b2167459
RH
1158 }
1159 tcg_temp_free(zero);
1160 if (!is_l) {
1161 cb = get_temp(ctx);
eaa3783b
RH
1162 tcg_gen_xor_reg(cb, in1, in2);
1163 tcg_gen_xor_reg(cb, cb, dest);
b2167459
RH
1164 }
1165 } else {
eaa3783b 1166 tcg_gen_add_reg(dest, in1, in2);
b2167459 1167 if (is_c) {
eaa3783b 1168 tcg_gen_add_reg(dest, dest, cpu_psw_cb_msb);
b2167459
RH
1169 }
1170 }
1171
1172 /* Compute signed overflow if required. */
f764718d 1173 sv = NULL;
b2167459
RH
1174 if (is_tsv || c == 6) {
1175 sv = do_add_sv(ctx, dest, in1, in2);
1176 if (is_tsv) {
1177 /* ??? Need to include overflow from shift. */
1178 gen_helper_tsv(cpu_env, sv);
1179 }
1180 }
1181
1182 /* Emit any conditional trap before any writeback. */
1183 cond = do_cond(cf, dest, cb_msb, sv);
1184 if (is_tc) {
1185 cond_prep(&cond);
1186 tmp = tcg_temp_new();
eaa3783b 1187 tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
b2167459
RH
1188 gen_helper_tcond(cpu_env, tmp);
1189 tcg_temp_free(tmp);
1190 }
1191
1192 /* Write back the result. */
1193 if (!is_l) {
1194 save_or_nullify(ctx, cpu_psw_cb, cb);
1195 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1196 }
1197 save_gpr(ctx, rt, dest);
1198 tcg_temp_free(dest);
1199
1200 /* Install the new nullification. */
1201 cond_free(&ctx->null_cond);
1202 ctx->null_cond = cond;
869051ea 1203 return DISAS_NEXT;
b2167459
RH
1204}
1205
eaa3783b
RH
1206static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1207 TCGv_reg in2, bool is_tsv, bool is_b,
1208 bool is_tc, unsigned cf)
b2167459 1209{
eaa3783b 1210 TCGv_reg dest, sv, cb, cb_msb, zero, tmp;
b2167459
RH
1211 unsigned c = cf >> 1;
1212 DisasCond cond;
1213
1214 dest = tcg_temp_new();
1215 cb = tcg_temp_new();
1216 cb_msb = tcg_temp_new();
1217
eaa3783b 1218 zero = tcg_const_reg(0);
b2167459
RH
1219 if (is_b) {
1220 /* DEST,C = IN1 + ~IN2 + C. */
eaa3783b
RH
1221 tcg_gen_not_reg(cb, in2);
1222 tcg_gen_add2_reg(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
1223 tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cb, zero);
1224 tcg_gen_xor_reg(cb, cb, in1);
1225 tcg_gen_xor_reg(cb, cb, dest);
b2167459
RH
1226 } else {
1227 /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer
1228 operations by seeding the high word with 1 and subtracting. */
eaa3783b
RH
1229 tcg_gen_movi_reg(cb_msb, 1);
1230 tcg_gen_sub2_reg(dest, cb_msb, in1, cb_msb, in2, zero);
1231 tcg_gen_eqv_reg(cb, in1, in2);
1232 tcg_gen_xor_reg(cb, cb, dest);
b2167459
RH
1233 }
1234 tcg_temp_free(zero);
1235
1236 /* Compute signed overflow if required. */
f764718d 1237 sv = NULL;
b2167459
RH
1238 if (is_tsv || c == 6) {
1239 sv = do_sub_sv(ctx, dest, in1, in2);
1240 if (is_tsv) {
1241 gen_helper_tsv(cpu_env, sv);
1242 }
1243 }
1244
1245 /* Compute the condition. We cannot use the special case for borrow. */
1246 if (!is_b) {
1247 cond = do_sub_cond(cf, dest, in1, in2, sv);
1248 } else {
1249 cond = do_cond(cf, dest, cb_msb, sv);
1250 }
1251
1252 /* Emit any conditional trap before any writeback. */
1253 if (is_tc) {
1254 cond_prep(&cond);
1255 tmp = tcg_temp_new();
eaa3783b 1256 tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
b2167459
RH
1257 gen_helper_tcond(cpu_env, tmp);
1258 tcg_temp_free(tmp);
1259 }
1260
1261 /* Write back the result. */
1262 save_or_nullify(ctx, cpu_psw_cb, cb);
1263 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1264 save_gpr(ctx, rt, dest);
1265 tcg_temp_free(dest);
1266
1267 /* Install the new nullification. */
1268 cond_free(&ctx->null_cond);
1269 ctx->null_cond = cond;
869051ea 1270 return DISAS_NEXT;
b2167459
RH
1271}
1272
eaa3783b
RH
1273static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1274 TCGv_reg in2, unsigned cf)
b2167459 1275{
eaa3783b 1276 TCGv_reg dest, sv;
b2167459
RH
1277 DisasCond cond;
1278
1279 dest = tcg_temp_new();
eaa3783b 1280 tcg_gen_sub_reg(dest, in1, in2);
b2167459
RH
1281
1282 /* Compute signed overflow if required. */
f764718d 1283 sv = NULL;
b2167459
RH
1284 if ((cf >> 1) == 6) {
1285 sv = do_sub_sv(ctx, dest, in1, in2);
1286 }
1287
1288 /* Form the condition for the compare. */
1289 cond = do_sub_cond(cf, dest, in1, in2, sv);
1290
1291 /* Clear. */
eaa3783b 1292 tcg_gen_movi_reg(dest, 0);
b2167459
RH
1293 save_gpr(ctx, rt, dest);
1294 tcg_temp_free(dest);
1295
1296 /* Install the new nullification. */
1297 cond_free(&ctx->null_cond);
1298 ctx->null_cond = cond;
869051ea 1299 return DISAS_NEXT;
b2167459
RH
1300}
1301
eaa3783b
RH
1302static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1303 TCGv_reg in2, unsigned cf,
1304 void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
b2167459 1305{
eaa3783b 1306 TCGv_reg dest = dest_gpr(ctx, rt);
b2167459
RH
1307
1308 /* Perform the operation, and writeback. */
1309 fn(dest, in1, in2);
1310 save_gpr(ctx, rt, dest);
1311
1312 /* Install the new nullification. */
1313 cond_free(&ctx->null_cond);
1314 if (cf) {
1315 ctx->null_cond = do_log_cond(cf, dest);
1316 }
869051ea 1317 return DISAS_NEXT;
b2167459
RH
1318}
1319
eaa3783b
RH
1320static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1,
1321 TCGv_reg in2, unsigned cf, bool is_tc,
1322 void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg))
b2167459 1323{
eaa3783b 1324 TCGv_reg dest;
b2167459
RH
1325 DisasCond cond;
1326
1327 if (cf == 0) {
1328 dest = dest_gpr(ctx, rt);
1329 fn(dest, in1, in2);
1330 save_gpr(ctx, rt, dest);
1331 cond_free(&ctx->null_cond);
1332 } else {
1333 dest = tcg_temp_new();
1334 fn(dest, in1, in2);
1335
1336 cond = do_unit_cond(cf, dest, in1, in2);
1337
1338 if (is_tc) {
eaa3783b 1339 TCGv_reg tmp = tcg_temp_new();
b2167459 1340 cond_prep(&cond);
eaa3783b 1341 tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1);
b2167459
RH
1342 gen_helper_tcond(cpu_env, tmp);
1343 tcg_temp_free(tmp);
1344 }
1345 save_gpr(ctx, rt, dest);
1346
1347 cond_free(&ctx->null_cond);
1348 ctx->null_cond = cond;
1349 }
869051ea 1350 return DISAS_NEXT;
b2167459
RH
1351}
1352
86f8d05f 1353#ifndef CONFIG_USER_ONLY
8d6ae7fb
RH
1354/* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
1355 from the top 2 bits of the base register. There are a few system
1356 instructions that have a 3-bit space specifier, for which SR0 is
1357 not special. To handle this, pass ~SP. */
86f8d05f
RH
1358static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base)
1359{
1360 TCGv_ptr ptr;
1361 TCGv_reg tmp;
1362 TCGv_i64 spc;
1363
1364 if (sp != 0) {
8d6ae7fb
RH
1365 if (sp < 0) {
1366 sp = ~sp;
1367 }
1368 spc = get_temp_tl(ctx);
1369 load_spr(ctx, spc, sp);
1370 return spc;
86f8d05f 1371 }
494737b7
RH
1372 if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1373 return cpu_srH;
1374 }
86f8d05f
RH
1375
1376 ptr = tcg_temp_new_ptr();
1377 tmp = tcg_temp_new();
1378 spc = get_temp_tl(ctx);
1379
1380 tcg_gen_shri_reg(tmp, base, TARGET_REGISTER_BITS - 5);
1381 tcg_gen_andi_reg(tmp, tmp, 030);
1382 tcg_gen_trunc_reg_ptr(ptr, tmp);
1383 tcg_temp_free(tmp);
1384
1385 tcg_gen_add_ptr(ptr, ptr, cpu_env);
1386 tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
1387 tcg_temp_free_ptr(ptr);
1388
1389 return spc;
1390}
1391#endif
1392
1393static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs,
1394 unsigned rb, unsigned rx, int scale, target_sreg disp,
1395 unsigned sp, int modify, bool is_phys)
1396{
1397 TCGv_reg base = load_gpr(ctx, rb);
1398 TCGv_reg ofs;
1399
1400 /* Note that RX is mutually exclusive with DISP. */
1401 if (rx) {
1402 ofs = get_temp(ctx);
1403 tcg_gen_shli_reg(ofs, cpu_gr[rx], scale);
1404 tcg_gen_add_reg(ofs, ofs, base);
1405 } else if (disp || modify) {
1406 ofs = get_temp(ctx);
1407 tcg_gen_addi_reg(ofs, base, disp);
1408 } else {
1409 ofs = base;
1410 }
1411
1412 *pofs = ofs;
1413#ifdef CONFIG_USER_ONLY
1414 *pgva = (modify <= 0 ? ofs : base);
1415#else
1416 TCGv_tl addr = get_temp_tl(ctx);
1417 tcg_gen_extu_reg_tl(addr, modify <= 0 ? ofs : base);
494737b7 1418 if (ctx->tb_flags & PSW_W) {
86f8d05f
RH
1419 tcg_gen_andi_tl(addr, addr, 0x3fffffffffffffffull);
1420 }
1421 if (!is_phys) {
1422 tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base));
1423 }
1424 *pgva = addr;
1425#endif
1426}
1427
96d6407f
RH
1428/* Emit a memory load. The modify parameter should be
1429 * < 0 for pre-modify,
1430 * > 0 for post-modify,
1431 * = 0 for no base register update.
1432 */
1433static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
eaa3783b 1434 unsigned rx, int scale, target_sreg disp,
86f8d05f 1435 unsigned sp, int modify, TCGMemOp mop)
96d6407f 1436{
86f8d05f
RH
1437 TCGv_reg ofs;
1438 TCGv_tl addr;
96d6407f
RH
1439
1440 /* Caller uses nullify_over/nullify_end. */
1441 assert(ctx->null_cond.c == TCG_COND_NEVER);
1442
86f8d05f
RH
1443 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1444 ctx->mmu_idx == MMU_PHYS_IDX);
1445 tcg_gen_qemu_ld_reg(dest, addr, ctx->mmu_idx, mop);
1446 if (modify) {
1447 save_gpr(ctx, rb, ofs);
96d6407f 1448 }
96d6407f
RH
1449}
1450
1451static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
eaa3783b 1452 unsigned rx, int scale, target_sreg disp,
86f8d05f 1453 unsigned sp, int modify, TCGMemOp mop)
96d6407f 1454{
86f8d05f
RH
1455 TCGv_reg ofs;
1456 TCGv_tl addr;
96d6407f
RH
1457
1458 /* Caller uses nullify_over/nullify_end. */
1459 assert(ctx->null_cond.c == TCG_COND_NEVER);
1460
86f8d05f
RH
1461 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1462 ctx->mmu_idx == MMU_PHYS_IDX);
1463 tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop);
1464 if (modify) {
1465 save_gpr(ctx, rb, ofs);
96d6407f 1466 }
96d6407f
RH
1467}
1468
1469static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
eaa3783b 1470 unsigned rx, int scale, target_sreg disp,
86f8d05f 1471 unsigned sp, int modify, TCGMemOp mop)
96d6407f 1472{
86f8d05f
RH
1473 TCGv_reg ofs;
1474 TCGv_tl addr;
96d6407f
RH
1475
1476 /* Caller uses nullify_over/nullify_end. */
1477 assert(ctx->null_cond.c == TCG_COND_NEVER);
1478
86f8d05f
RH
1479 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1480 ctx->mmu_idx == MMU_PHYS_IDX);
1481 tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop);
1482 if (modify) {
1483 save_gpr(ctx, rb, ofs);
96d6407f 1484 }
96d6407f
RH
1485}
1486
1487static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
eaa3783b 1488 unsigned rx, int scale, target_sreg disp,
86f8d05f 1489 unsigned sp, int modify, TCGMemOp mop)
96d6407f 1490{
86f8d05f
RH
1491 TCGv_reg ofs;
1492 TCGv_tl addr;
96d6407f
RH
1493
1494 /* Caller uses nullify_over/nullify_end. */
1495 assert(ctx->null_cond.c == TCG_COND_NEVER);
1496
86f8d05f
RH
1497 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
1498 ctx->mmu_idx == MMU_PHYS_IDX);
1499 tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop);
1500 if (modify) {
1501 save_gpr(ctx, rb, ofs);
96d6407f 1502 }
96d6407f
RH
1503}
1504
eaa3783b
RH
1505#if TARGET_REGISTER_BITS == 64
1506#define do_load_reg do_load_64
1507#define do_store_reg do_store_64
96d6407f 1508#else
eaa3783b
RH
1509#define do_load_reg do_load_32
1510#define do_store_reg do_store_32
96d6407f
RH
1511#endif
1512
869051ea 1513static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb,
eaa3783b 1514 unsigned rx, int scale, target_sreg disp,
86f8d05f 1515 unsigned sp, int modify, TCGMemOp mop)
96d6407f 1516{
eaa3783b 1517 TCGv_reg dest;
96d6407f
RH
1518
1519 nullify_over(ctx);
1520
1521 if (modify == 0) {
1522 /* No base register update. */
1523 dest = dest_gpr(ctx, rt);
1524 } else {
1525 /* Make sure if RT == RB, we see the result of the load. */
1526 dest = get_temp(ctx);
1527 }
86f8d05f 1528 do_load_reg(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
96d6407f
RH
1529 save_gpr(ctx, rt, dest);
1530
869051ea 1531 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1532}
1533
869051ea 1534static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
eaa3783b 1535 unsigned rx, int scale, target_sreg disp,
86f8d05f 1536 unsigned sp, int modify)
96d6407f
RH
1537{
1538 TCGv_i32 tmp;
1539
1540 nullify_over(ctx);
1541
1542 tmp = tcg_temp_new_i32();
86f8d05f 1543 do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
96d6407f
RH
1544 save_frw_i32(rt, tmp);
1545 tcg_temp_free_i32(tmp);
1546
1547 if (rt == 0) {
1548 gen_helper_loaded_fr0(cpu_env);
1549 }
1550
869051ea 1551 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1552}
1553
869051ea 1554static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
eaa3783b 1555 unsigned rx, int scale, target_sreg disp,
86f8d05f 1556 unsigned sp, int modify)
96d6407f
RH
1557{
1558 TCGv_i64 tmp;
1559
1560 nullify_over(ctx);
1561
1562 tmp = tcg_temp_new_i64();
86f8d05f 1563 do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
96d6407f
RH
1564 save_frd(rt, tmp);
1565 tcg_temp_free_i64(tmp);
1566
1567 if (rt == 0) {
1568 gen_helper_loaded_fr0(cpu_env);
1569 }
1570
869051ea 1571 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1572}
1573
869051ea 1574static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb,
86f8d05f
RH
1575 target_sreg disp, unsigned sp,
1576 int modify, TCGMemOp mop)
96d6407f
RH
1577{
1578 nullify_over(ctx);
86f8d05f 1579 do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
869051ea 1580 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1581}
1582
869051ea 1583static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
eaa3783b 1584 unsigned rx, int scale, target_sreg disp,
86f8d05f 1585 unsigned sp, int modify)
96d6407f
RH
1586{
1587 TCGv_i32 tmp;
1588
1589 nullify_over(ctx);
1590
1591 tmp = load_frw_i32(rt);
86f8d05f 1592 do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
96d6407f
RH
1593 tcg_temp_free_i32(tmp);
1594
869051ea 1595 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1596}
1597
869051ea 1598static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
eaa3783b 1599 unsigned rx, int scale, target_sreg disp,
86f8d05f 1600 unsigned sp, int modify)
96d6407f
RH
1601{
1602 TCGv_i64 tmp;
1603
1604 nullify_over(ctx);
1605
1606 tmp = load_frd(rt);
86f8d05f 1607 do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ);
96d6407f
RH
1608 tcg_temp_free_i64(tmp);
1609
869051ea 1610 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
1611}
1612
869051ea
RH
1613static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1614 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
ebe9383c
RH
1615{
1616 TCGv_i32 tmp;
1617
1618 nullify_over(ctx);
1619 tmp = load_frw0_i32(ra);
1620
1621 func(tmp, cpu_env, tmp);
1622
1623 save_frw_i32(rt, tmp);
1624 tcg_temp_free_i32(tmp);
869051ea 1625 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1626}
1627
869051ea
RH
1628static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1629 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
ebe9383c
RH
1630{
1631 TCGv_i32 dst;
1632 TCGv_i64 src;
1633
1634 nullify_over(ctx);
1635 src = load_frd(ra);
1636 dst = tcg_temp_new_i32();
1637
1638 func(dst, cpu_env, src);
1639
1640 tcg_temp_free_i64(src);
1641 save_frw_i32(rt, dst);
1642 tcg_temp_free_i32(dst);
869051ea 1643 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1644}
1645
869051ea
RH
1646static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1647 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
ebe9383c
RH
1648{
1649 TCGv_i64 tmp;
1650
1651 nullify_over(ctx);
1652 tmp = load_frd0(ra);
1653
1654 func(tmp, cpu_env, tmp);
1655
1656 save_frd(rt, tmp);
1657 tcg_temp_free_i64(tmp);
869051ea 1658 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1659}
1660
869051ea
RH
1661static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1662 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
ebe9383c
RH
1663{
1664 TCGv_i32 src;
1665 TCGv_i64 dst;
1666
1667 nullify_over(ctx);
1668 src = load_frw0_i32(ra);
1669 dst = tcg_temp_new_i64();
1670
1671 func(dst, cpu_env, src);
1672
1673 tcg_temp_free_i32(src);
1674 save_frd(rt, dst);
1675 tcg_temp_free_i64(dst);
869051ea 1676 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1677}
1678
869051ea
RH
1679static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt,
1680 unsigned ra, unsigned rb,
1681 void (*func)(TCGv_i32, TCGv_env,
1682 TCGv_i32, TCGv_i32))
ebe9383c
RH
1683{
1684 TCGv_i32 a, b;
1685
1686 nullify_over(ctx);
1687 a = load_frw0_i32(ra);
1688 b = load_frw0_i32(rb);
1689
1690 func(a, cpu_env, a, b);
1691
1692 tcg_temp_free_i32(b);
1693 save_frw_i32(rt, a);
1694 tcg_temp_free_i32(a);
869051ea 1695 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1696}
1697
869051ea
RH
1698static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt,
1699 unsigned ra, unsigned rb,
1700 void (*func)(TCGv_i64, TCGv_env,
1701 TCGv_i64, TCGv_i64))
ebe9383c
RH
1702{
1703 TCGv_i64 a, b;
1704
1705 nullify_over(ctx);
1706 a = load_frd0(ra);
1707 b = load_frd0(rb);
1708
1709 func(a, cpu_env, a, b);
1710
1711 tcg_temp_free_i64(b);
1712 save_frd(rt, a);
1713 tcg_temp_free_i64(a);
869051ea 1714 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
1715}
1716
98cd9ca7
RH
1717/* Emit an unconditional branch to a direct target, which may or may not
1718 have already had nullification handled. */
eaa3783b 1719static DisasJumpType do_dbranch(DisasContext *ctx, target_ureg dest,
869051ea 1720 unsigned link, bool is_n)
98cd9ca7
RH
1721{
1722 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1723 if (link != 0) {
1724 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1725 }
1726 ctx->iaoq_n = dest;
1727 if (is_n) {
1728 ctx->null_cond.c = TCG_COND_ALWAYS;
1729 }
869051ea 1730 return DISAS_NEXT;
98cd9ca7
RH
1731 } else {
1732 nullify_over(ctx);
1733
1734 if (link != 0) {
1735 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1736 }
1737
1738 if (is_n && use_nullify_skip(ctx)) {
1739 nullify_set(ctx, 0);
1740 gen_goto_tb(ctx, 0, dest, dest + 4);
1741 } else {
1742 nullify_set(ctx, is_n);
1743 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1744 }
1745
869051ea 1746 nullify_end(ctx, DISAS_NEXT);
98cd9ca7
RH
1747
1748 nullify_set(ctx, 0);
1749 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
869051ea 1750 return DISAS_NORETURN;
98cd9ca7
RH
1751 }
1752}
1753
1754/* Emit a conditional branch to a direct target. If the branch itself
1755 is nullified, we should have already used nullify_over. */
eaa3783b 1756static DisasJumpType do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n,
869051ea 1757 DisasCond *cond)
98cd9ca7 1758{
eaa3783b 1759 target_ureg dest = iaoq_dest(ctx, disp);
98cd9ca7
RH
1760 TCGLabel *taken = NULL;
1761 TCGCond c = cond->c;
98cd9ca7
RH
1762 bool n;
1763
1764 assert(ctx->null_cond.c == TCG_COND_NEVER);
1765
1766 /* Handle TRUE and NEVER as direct branches. */
1767 if (c == TCG_COND_ALWAYS) {
1768 return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
1769 }
1770 if (c == TCG_COND_NEVER) {
1771 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
1772 }
1773
1774 taken = gen_new_label();
1775 cond_prep(cond);
eaa3783b 1776 tcg_gen_brcond_reg(c, cond->a0, cond->a1, taken);
98cd9ca7
RH
1777 cond_free(cond);
1778
1779 /* Not taken: Condition not satisfied; nullify on backward branches. */
1780 n = is_n && disp < 0;
1781 if (n && use_nullify_skip(ctx)) {
1782 nullify_set(ctx, 0);
a881c8e7 1783 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
98cd9ca7
RH
1784 } else {
1785 if (!n && ctx->null_lab) {
1786 gen_set_label(ctx->null_lab);
1787 ctx->null_lab = NULL;
1788 }
1789 nullify_set(ctx, n);
c301f34e
RH
1790 if (ctx->iaoq_n == -1) {
1791 /* The temporary iaoq_n_var died at the branch above.
1792 Regenerate it here instead of saving it. */
1793 tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
1794 }
a881c8e7 1795 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
98cd9ca7
RH
1796 }
1797
1798 gen_set_label(taken);
1799
1800 /* Taken: Condition satisfied; nullify on forward branches. */
1801 n = is_n && disp >= 0;
1802 if (n && use_nullify_skip(ctx)) {
1803 nullify_set(ctx, 0);
a881c8e7 1804 gen_goto_tb(ctx, 1, dest, dest + 4);
98cd9ca7
RH
1805 } else {
1806 nullify_set(ctx, n);
a881c8e7 1807 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
98cd9ca7
RH
1808 }
1809
1810 /* Not taken: the branch itself was nullified. */
1811 if (ctx->null_lab) {
1812 gen_set_label(ctx->null_lab);
1813 ctx->null_lab = NULL;
869051ea 1814 return DISAS_IAQ_N_STALE;
98cd9ca7 1815 } else {
869051ea 1816 return DISAS_NORETURN;
98cd9ca7
RH
1817 }
1818}
1819
1820/* Emit an unconditional branch to an indirect target. This handles
1821 nullification of the branch itself. */
eaa3783b 1822static DisasJumpType do_ibranch(DisasContext *ctx, TCGv_reg dest,
869051ea 1823 unsigned link, bool is_n)
98cd9ca7 1824{
eaa3783b 1825 TCGv_reg a0, a1, next, tmp;
98cd9ca7
RH
1826 TCGCond c;
1827
1828 assert(ctx->null_lab == NULL);
1829
1830 if (ctx->null_cond.c == TCG_COND_NEVER) {
1831 if (link != 0) {
1832 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1833 }
1834 next = get_temp(ctx);
eaa3783b 1835 tcg_gen_mov_reg(next, dest);
98cd9ca7 1836 if (is_n) {
c301f34e
RH
1837 if (use_nullify_skip(ctx)) {
1838 tcg_gen_mov_reg(cpu_iaoq_f, next);
1839 tcg_gen_addi_reg(cpu_iaoq_b, next, 4);
1840 nullify_set(ctx, 0);
1841 return DISAS_IAQ_N_UPDATED;
1842 }
98cd9ca7
RH
1843 ctx->null_cond.c = TCG_COND_ALWAYS;
1844 }
c301f34e
RH
1845 ctx->iaoq_n = -1;
1846 ctx->iaoq_n_var = next;
98cd9ca7
RH
1847 } else if (is_n && use_nullify_skip(ctx)) {
1848 /* The (conditional) branch, B, nullifies the next insn, N,
1849 and we're allowed to skip execution N (no single-step or
4137cb83 1850 tracepoint in effect). Since the goto_ptr that we must use
98cd9ca7
RH
1851 for the indirect branch consumes no special resources, we
1852 can (conditionally) skip B and continue execution. */
1853 /* The use_nullify_skip test implies we have a known control path. */
1854 tcg_debug_assert(ctx->iaoq_b != -1);
1855 tcg_debug_assert(ctx->iaoq_n != -1);
1856
1857 /* We do have to handle the non-local temporary, DEST, before
1858 branching. Since IOAQ_F is not really live at this point, we
1859 can simply store DEST optimistically. Similarly with IAOQ_B. */
eaa3783b
RH
1860 tcg_gen_mov_reg(cpu_iaoq_f, dest);
1861 tcg_gen_addi_reg(cpu_iaoq_b, dest, 4);
98cd9ca7
RH
1862
1863 nullify_over(ctx);
1864 if (link != 0) {
eaa3783b 1865 tcg_gen_movi_reg(cpu_gr[link], ctx->iaoq_n);
98cd9ca7 1866 }
7f11636d 1867 tcg_gen_lookup_and_goto_ptr();
869051ea 1868 return nullify_end(ctx, DISAS_NEXT);
98cd9ca7
RH
1869 } else {
1870 cond_prep(&ctx->null_cond);
1871 c = ctx->null_cond.c;
1872 a0 = ctx->null_cond.a0;
1873 a1 = ctx->null_cond.a1;
1874
1875 tmp = tcg_temp_new();
1876 next = get_temp(ctx);
1877
1878 copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
eaa3783b 1879 tcg_gen_movcond_reg(c, next, a0, a1, tmp, dest);
98cd9ca7
RH
1880 ctx->iaoq_n = -1;
1881 ctx->iaoq_n_var = next;
1882
1883 if (link != 0) {
eaa3783b 1884 tcg_gen_movcond_reg(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
98cd9ca7
RH
1885 }
1886
1887 if (is_n) {
1888 /* The branch nullifies the next insn, which means the state of N
1889 after the branch is the inverse of the state of N that applied
1890 to the branch. */
eaa3783b 1891 tcg_gen_setcond_reg(tcg_invert_cond(c), cpu_psw_n, a0, a1);
98cd9ca7
RH
1892 cond_free(&ctx->null_cond);
1893 ctx->null_cond = cond_make_n();
1894 ctx->psw_n_nonzero = true;
1895 } else {
1896 cond_free(&ctx->null_cond);
1897 }
1898 }
1899
869051ea 1900 return DISAS_NEXT;
98cd9ca7
RH
1901}
1902
660eefe1
RH
1903/* Implement
1904 * if (IAOQ_Front{30..31} < GR[b]{30..31})
1905 * IAOQ_Next{30..31} ← GR[b]{30..31};
1906 * else
1907 * IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1908 * which keeps the privilege level from being increased.
1909 */
1910static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset)
1911{
1912#ifdef CONFIG_USER_ONLY
1913 return offset;
1914#else
1915 TCGv_reg dest;
1916 switch (ctx->privilege) {
1917 case 0:
1918 /* Privilege 0 is maximum and is allowed to decrease. */
1919 return offset;
1920 case 3:
1921 /* Privilege 3 is minimum and is never allowed increase. */
1922 dest = get_temp(ctx);
1923 tcg_gen_ori_reg(dest, offset, 3);
1924 break;
1925 default:
1926 dest = tcg_temp_new();
1927 tcg_gen_andi_reg(dest, offset, -4);
1928 tcg_gen_ori_reg(dest, dest, ctx->privilege);
1929 tcg_gen_movcond_reg(TCG_COND_GTU, dest, dest, offset, dest, offset);
1930 tcg_temp_free(dest);
1931 break;
1932 }
1933 return dest;
1934#endif
1935}
1936
ba1d0b44 1937#ifdef CONFIG_USER_ONLY
7ad439df
RH
1938/* On Linux, page zero is normally marked execute only + gateway.
1939 Therefore normal read or write is supposed to fail, but specific
1940 offsets have kernel code mapped to raise permissions to implement
1941 system calls. Handling this via an explicit check here, rather
1942 in than the "be disp(sr2,r0)" instruction that probably sent us
1943 here, is the easiest way to handle the branch delay slot on the
1944 aforementioned BE. */
869051ea 1945static DisasJumpType do_page_zero(DisasContext *ctx)
7ad439df
RH
1946{
1947 /* If by some means we get here with PSW[N]=1, that implies that
1948 the B,GATE instruction would be skipped, and we'd fault on the
1949 next insn within the privilaged page. */
1950 switch (ctx->null_cond.c) {
1951 case TCG_COND_NEVER:
1952 break;
1953 case TCG_COND_ALWAYS:
eaa3783b 1954 tcg_gen_movi_reg(cpu_psw_n, 0);
7ad439df
RH
1955 goto do_sigill;
1956 default:
1957 /* Since this is always the first (and only) insn within the
1958 TB, we should know the state of PSW[N] from TB->FLAGS. */
1959 g_assert_not_reached();
1960 }
1961
1962 /* Check that we didn't arrive here via some means that allowed
1963 non-sequential instruction execution. Normally the PSW[B] bit
1964 detects this by disallowing the B,GATE instruction to execute
1965 under such conditions. */
1966 if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1967 goto do_sigill;
1968 }
1969
1970 switch (ctx->iaoq_f) {
1971 case 0x00: /* Null pointer call */
2986721d 1972 gen_excp_1(EXCP_IMP);
869051ea 1973 return DISAS_NORETURN;
7ad439df
RH
1974
1975 case 0xb0: /* LWS */
1976 gen_excp_1(EXCP_SYSCALL_LWS);
869051ea 1977 return DISAS_NORETURN;
7ad439df
RH
1978
1979 case 0xe0: /* SET_THREAD_POINTER */
35136a77 1980 tcg_gen_st_reg(cpu_gr[26], cpu_env, offsetof(CPUHPPAState, cr[27]));
eaa3783b
RH
1981 tcg_gen_mov_reg(cpu_iaoq_f, cpu_gr[31]);
1982 tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
869051ea 1983 return DISAS_IAQ_N_UPDATED;
7ad439df
RH
1984
1985 case 0x100: /* SYSCALL */
1986 gen_excp_1(EXCP_SYSCALL);
869051ea 1987 return DISAS_NORETURN;
7ad439df
RH
1988
1989 default:
1990 do_sigill:
2986721d 1991 gen_excp_1(EXCP_ILL);
869051ea 1992 return DISAS_NORETURN;
7ad439df
RH
1993 }
1994}
ba1d0b44 1995#endif
7ad439df 1996
869051ea
RH
1997static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn,
1998 const DisasInsn *di)
b2167459
RH
1999{
2000 cond_free(&ctx->null_cond);
869051ea 2001 return DISAS_NEXT;
b2167459
RH
2002}
2003
869051ea
RH
2004static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn,
2005 const DisasInsn *di)
98a9cb79
RH
2006{
2007 nullify_over(ctx);
1a19da0d 2008 return nullify_end(ctx, gen_excp_iir(ctx, EXCP_BREAK));
98a9cb79
RH
2009}
2010
869051ea
RH
2011static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn,
2012 const DisasInsn *di)
98a9cb79
RH
2013{
2014 /* No point in nullifying the memory barrier. */
2015 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
2016
2017 cond_free(&ctx->null_cond);
869051ea 2018 return DISAS_NEXT;
98a9cb79
RH
2019}
2020
869051ea
RH
2021static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn,
2022 const DisasInsn *di)
98a9cb79
RH
2023{
2024 unsigned rt = extract32(insn, 0, 5);
eaa3783b
RH
2025 TCGv_reg tmp = dest_gpr(ctx, rt);
2026 tcg_gen_movi_reg(tmp, ctx->iaoq_f);
98a9cb79
RH
2027 save_gpr(ctx, rt, tmp);
2028
2029 cond_free(&ctx->null_cond);
869051ea 2030 return DISAS_NEXT;
98a9cb79
RH
2031}
2032
869051ea
RH
2033static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn,
2034 const DisasInsn *di)
98a9cb79
RH
2035{
2036 unsigned rt = extract32(insn, 0, 5);
33423472
RH
2037 unsigned rs = assemble_sr3(insn);
2038 TCGv_i64 t0 = tcg_temp_new_i64();
2039 TCGv_reg t1 = tcg_temp_new();
98a9cb79 2040
33423472
RH
2041 load_spr(ctx, t0, rs);
2042 tcg_gen_shri_i64(t0, t0, 32);
2043 tcg_gen_trunc_i64_reg(t1, t0);
2044
2045 save_gpr(ctx, rt, t1);
2046 tcg_temp_free(t1);
2047 tcg_temp_free_i64(t0);
98a9cb79
RH
2048
2049 cond_free(&ctx->null_cond);
869051ea 2050 return DISAS_NEXT;
98a9cb79
RH
2051}
2052
869051ea
RH
2053static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn,
2054 const DisasInsn *di)
98a9cb79
RH
2055{
2056 unsigned rt = extract32(insn, 0, 5);
2057 unsigned ctl = extract32(insn, 21, 5);
eaa3783b 2058 TCGv_reg tmp;
49c29d6c 2059 DisasJumpType ret;
98a9cb79
RH
2060
2061 switch (ctl) {
35136a77 2062 case CR_SAR:
98a9cb79
RH
2063#ifdef TARGET_HPPA64
2064 if (extract32(insn, 14, 1) == 0) {
2065 /* MFSAR without ,W masks low 5 bits. */
2066 tmp = dest_gpr(ctx, rt);
eaa3783b 2067 tcg_gen_andi_reg(tmp, cpu_sar, 31);
98a9cb79 2068 save_gpr(ctx, rt, tmp);
35136a77 2069 goto done;
98a9cb79
RH
2070 }
2071#endif
2072 save_gpr(ctx, rt, cpu_sar);
35136a77
RH
2073 goto done;
2074 case CR_IT: /* Interval Timer */
2075 /* FIXME: Respect PSW_S bit. */
2076 nullify_over(ctx);
98a9cb79 2077 tmp = dest_gpr(ctx, rt);
49c29d6c
RH
2078 if (ctx->base.tb->cflags & CF_USE_ICOUNT) {
2079 gen_io_start();
2080 gen_helper_read_interval_timer(tmp);
2081 gen_io_end();
2082 ret = DISAS_IAQ_N_STALE;
2083 } else {
2084 gen_helper_read_interval_timer(tmp);
2085 ret = DISAS_NEXT;
2086 }
98a9cb79 2087 save_gpr(ctx, rt, tmp);
49c29d6c 2088 return nullify_end(ctx, ret);
98a9cb79 2089 case 26:
98a9cb79 2090 case 27:
98a9cb79
RH
2091 break;
2092 default:
2093 /* All other control registers are privileged. */
35136a77
RH
2094 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2095 break;
98a9cb79
RH
2096 }
2097
35136a77
RH
2098 tmp = get_temp(ctx);
2099 tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
2100 save_gpr(ctx, rt, tmp);
2101
2102 done:
98a9cb79 2103 cond_free(&ctx->null_cond);
869051ea 2104 return DISAS_NEXT;
98a9cb79
RH
2105}
2106
33423472
RH
2107static DisasJumpType trans_mtsp(DisasContext *ctx, uint32_t insn,
2108 const DisasInsn *di)
2109{
2110 unsigned rr = extract32(insn, 16, 5);
2111 unsigned rs = assemble_sr3(insn);
2112 TCGv_i64 t64;
2113
2114 if (rs >= 5) {
2115 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2116 }
2117 nullify_over(ctx);
2118
2119 t64 = tcg_temp_new_i64();
2120 tcg_gen_extu_reg_i64(t64, load_gpr(ctx, rr));
2121 tcg_gen_shli_i64(t64, t64, 32);
2122
2123 if (rs >= 4) {
2124 tcg_gen_st_i64(t64, cpu_env, offsetof(CPUHPPAState, sr[rs]));
494737b7 2125 ctx->tb_flags &= ~TB_FLAG_SR_SAME;
33423472
RH
2126 } else {
2127 tcg_gen_mov_i64(cpu_sr[rs], t64);
2128 }
2129 tcg_temp_free_i64(t64);
2130
2131 return nullify_end(ctx, DISAS_NEXT);
2132}
2133
869051ea
RH
2134static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn,
2135 const DisasInsn *di)
98a9cb79
RH
2136{
2137 unsigned rin = extract32(insn, 16, 5);
2138 unsigned ctl = extract32(insn, 21, 5);
35136a77 2139 TCGv_reg reg = load_gpr(ctx, rin);
eaa3783b 2140 TCGv_reg tmp;
98a9cb79 2141
35136a77 2142 if (ctl == CR_SAR) {
98a9cb79 2143 tmp = tcg_temp_new();
35136a77 2144 tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1);
98a9cb79
RH
2145 save_or_nullify(ctx, cpu_sar, tmp);
2146 tcg_temp_free(tmp);
35136a77
RH
2147
2148 cond_free(&ctx->null_cond);
2149 return DISAS_NEXT;
98a9cb79
RH
2150 }
2151
35136a77
RH
2152 /* All other control registers are privileged or read-only. */
2153 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
2154
4f5f2548
RH
2155#ifdef CONFIG_USER_ONLY
2156 g_assert_not_reached();
2157#else
2158 DisasJumpType ret = DISAS_NEXT;
2159
35136a77
RH
2160 nullify_over(ctx);
2161 switch (ctl) {
2162 case CR_IT:
49c29d6c 2163 gen_helper_write_interval_timer(cpu_env, reg);
35136a77 2164 break;
4f5f2548
RH
2165 case CR_EIRR:
2166 gen_helper_write_eirr(cpu_env, reg);
2167 break;
2168 case CR_EIEM:
2169 gen_helper_write_eiem(cpu_env, reg);
2170 ret = DISAS_IAQ_N_STALE_EXIT;
2171 break;
2172
35136a77
RH
2173 case CR_IIASQ:
2174 case CR_IIAOQ:
2175 /* FIXME: Respect PSW_Q bit */
2176 /* The write advances the queue and stores to the back element. */
2177 tmp = get_temp(ctx);
2178 tcg_gen_ld_reg(tmp, cpu_env,
2179 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
2180 tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
2181 tcg_gen_st_reg(reg, cpu_env,
2182 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
2183 break;
2184
2185 default:
2186 tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl]));
2187 break;
2188 }
4f5f2548
RH
2189 return nullify_end(ctx, ret);
2190#endif
98a9cb79
RH
2191}
2192
869051ea
RH
2193static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn,
2194 const DisasInsn *di)
98a9cb79
RH
2195{
2196 unsigned rin = extract32(insn, 16, 5);
eaa3783b 2197 TCGv_reg tmp = tcg_temp_new();
98a9cb79 2198
eaa3783b
RH
2199 tcg_gen_not_reg(tmp, load_gpr(ctx, rin));
2200 tcg_gen_andi_reg(tmp, tmp, TARGET_REGISTER_BITS - 1);
98a9cb79
RH
2201 save_or_nullify(ctx, cpu_sar, tmp);
2202 tcg_temp_free(tmp);
2203
2204 cond_free(&ctx->null_cond);
869051ea 2205 return DISAS_NEXT;
98a9cb79
RH
2206}
2207
869051ea
RH
2208static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn,
2209 const DisasInsn *di)
98a9cb79
RH
2210{
2211 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2212 TCGv_reg dest = dest_gpr(ctx, rt);
98a9cb79 2213
2330504c
HD
2214#ifdef CONFIG_USER_ONLY
2215 /* We don't implement space registers in user mode. */
eaa3783b 2216 tcg_gen_movi_reg(dest, 0);
2330504c
HD
2217#else
2218 unsigned rb = extract32(insn, 21, 5);
2219 unsigned sp = extract32(insn, 14, 2);
2220 TCGv_i64 t0 = tcg_temp_new_i64();
2221
2222 tcg_gen_mov_i64(t0, space_select(ctx, sp, load_gpr(ctx, rb)));
2223 tcg_gen_shri_i64(t0, t0, 32);
2224 tcg_gen_trunc_i64_reg(dest, t0);
2225
2226 tcg_temp_free_i64(t0);
2227#endif
98a9cb79
RH
2228 save_gpr(ctx, rt, dest);
2229
2230 cond_free(&ctx->null_cond);
869051ea 2231 return DISAS_NEXT;
98a9cb79
RH
2232}
2233
e1b5a5ed
RH
2234#ifndef CONFIG_USER_ONLY
2235/* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */
2236static target_ureg extract_sm_imm(uint32_t insn)
2237{
2238 target_ureg val = extract32(insn, 16, 10);
2239
2240 if (val & PSW_SM_E) {
2241 val = (val & ~PSW_SM_E) | PSW_E;
2242 }
2243 if (val & PSW_SM_W) {
2244 val = (val & ~PSW_SM_W) | PSW_W;
2245 }
2246 return val;
2247}
2248
2249static DisasJumpType trans_rsm(DisasContext *ctx, uint32_t insn,
2250 const DisasInsn *di)
2251{
2252 unsigned rt = extract32(insn, 0, 5);
2253 target_ureg sm = extract_sm_imm(insn);
2254 TCGv_reg tmp;
2255
2256 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2257 nullify_over(ctx);
2258
2259 tmp = get_temp(ctx);
2260 tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw));
2261 tcg_gen_andi_reg(tmp, tmp, ~sm);
2262 gen_helper_swap_system_mask(tmp, cpu_env, tmp);
2263 save_gpr(ctx, rt, tmp);
2264
2265 /* Exit the TB to recognize new interrupts, e.g. PSW_M. */
2266 return nullify_end(ctx, DISAS_IAQ_N_STALE_EXIT);
2267}
2268
2269static DisasJumpType trans_ssm(DisasContext *ctx, uint32_t insn,
2270 const DisasInsn *di)
2271{
2272 unsigned rt = extract32(insn, 0, 5);
2273 target_ureg sm = extract_sm_imm(insn);
2274 TCGv_reg tmp;
2275
2276 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2277 nullify_over(ctx);
2278
2279 tmp = get_temp(ctx);
2280 tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw));
2281 tcg_gen_ori_reg(tmp, tmp, sm);
2282 gen_helper_swap_system_mask(tmp, cpu_env, tmp);
2283 save_gpr(ctx, rt, tmp);
2284
2285 /* Exit the TB to recognize new interrupts, e.g. PSW_I. */
2286 return nullify_end(ctx, DISAS_IAQ_N_STALE_EXIT);
2287}
2288
2289static DisasJumpType trans_mtsm(DisasContext *ctx, uint32_t insn,
2290 const DisasInsn *di)
2291{
2292 unsigned rr = extract32(insn, 16, 5);
2293 TCGv_reg tmp, reg;
2294
2295 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2296 nullify_over(ctx);
2297
2298 reg = load_gpr(ctx, rr);
2299 tmp = get_temp(ctx);
2300 gen_helper_swap_system_mask(tmp, cpu_env, reg);
2301
2302 /* Exit the TB to recognize new interrupts. */
2303 return nullify_end(ctx, DISAS_IAQ_N_STALE_EXIT);
2304}
f49b3537
RH
2305
2306static DisasJumpType trans_rfi(DisasContext *ctx, uint32_t insn,
2307 const DisasInsn *di)
2308{
2309 unsigned comp = extract32(insn, 5, 4);
2310
2311 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2312 nullify_over(ctx);
2313
2314 if (comp == 5) {
2315 gen_helper_rfi_r(cpu_env);
2316 } else {
2317 gen_helper_rfi(cpu_env);
2318 }
2319 if (ctx->base.singlestep_enabled) {
2320 gen_excp_1(EXCP_DEBUG);
2321 } else {
2322 tcg_gen_exit_tb(0);
2323 }
2324
2325 /* Exit the TB to recognize new interrupts. */
2326 return nullify_end(ctx, DISAS_NORETURN);
2327}
6210db05
HD
2328
2329static DisasJumpType gen_hlt(DisasContext *ctx, int reset)
2330{
2331 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2332 nullify_over(ctx);
2333 if (reset) {
2334 gen_helper_reset(cpu_env);
2335 } else {
2336 gen_helper_halt(cpu_env);
2337 }
2338 return nullify_end(ctx, DISAS_NORETURN);
2339}
e1b5a5ed
RH
2340#endif /* !CONFIG_USER_ONLY */
2341
98a9cb79
RH
2342static const DisasInsn table_system[] = {
2343 { 0x00000000u, 0xfc001fe0u, trans_break },
33423472 2344 { 0x00001820u, 0xffe01fffu, trans_mtsp },
98a9cb79
RH
2345 { 0x00001840u, 0xfc00ffffu, trans_mtctl },
2346 { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
2347 { 0x000014a0u, 0xffffffe0u, trans_mfia },
2348 { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
7f221b07 2349 { 0x000008a0u, 0xfc1fbfe0u, trans_mfctl },
e216a77e
RH
2350 { 0x00000400u, 0xffffffffu, trans_sync }, /* sync */
2351 { 0x00100400u, 0xffffffffu, trans_sync }, /* syncdma */
98a9cb79 2352 { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
e1b5a5ed
RH
2353#ifndef CONFIG_USER_ONLY
2354 { 0x00000e60u, 0xfc00ffe0u, trans_rsm },
2355 { 0x00000d60u, 0xfc00ffe0u, trans_ssm },
2356 { 0x00001860u, 0xffe0ffffu, trans_mtsm },
f49b3537 2357 { 0x00000c00u, 0xfffffe1fu, trans_rfi },
e1b5a5ed 2358#endif
98a9cb79
RH
2359};
2360
869051ea
RH
2361static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
2362 const DisasInsn *di)
98a9cb79
RH
2363{
2364 unsigned rb = extract32(insn, 21, 5);
2365 unsigned rx = extract32(insn, 16, 5);
eaa3783b
RH
2366 TCGv_reg dest = dest_gpr(ctx, rb);
2367 TCGv_reg src1 = load_gpr(ctx, rb);
2368 TCGv_reg src2 = load_gpr(ctx, rx);
98a9cb79
RH
2369
2370 /* The only thing we need to do is the base register modification. */
eaa3783b 2371 tcg_gen_add_reg(dest, src1, src2);
98a9cb79
RH
2372 save_gpr(ctx, rb, dest);
2373
2374 cond_free(&ctx->null_cond);
869051ea 2375 return DISAS_NEXT;
98a9cb79
RH
2376}
2377
869051ea
RH
2378static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
2379 const DisasInsn *di)
98a9cb79
RH
2380{
2381 unsigned rt = extract32(insn, 0, 5);
86f8d05f 2382 unsigned sp = extract32(insn, 14, 2);
eed14219 2383 unsigned rr = extract32(insn, 16, 5);
98a9cb79
RH
2384 unsigned rb = extract32(insn, 21, 5);
2385 unsigned is_write = extract32(insn, 6, 1);
eed14219 2386 unsigned is_imm = extract32(insn, 13, 1);
86f8d05f 2387 TCGv_reg dest, ofs;
eed14219 2388 TCGv_i32 level, want;
86f8d05f 2389 TCGv_tl addr;
98a9cb79
RH
2390
2391 nullify_over(ctx);
2392
98a9cb79 2393 dest = dest_gpr(ctx, rt);
86f8d05f 2394 form_gva(ctx, &addr, &ofs, rb, 0, 0, 0, sp, 0, false);
eed14219
RH
2395
2396 if (is_imm) {
2397 level = tcg_const_i32(extract32(insn, 16, 2));
98a9cb79 2398 } else {
eed14219
RH
2399 level = tcg_temp_new_i32();
2400 tcg_gen_trunc_reg_i32(level, load_gpr(ctx, rr));
2401 tcg_gen_andi_i32(level, level, 3);
98a9cb79 2402 }
eed14219
RH
2403 want = tcg_const_i32(is_write ? PAGE_WRITE : PAGE_READ);
2404
2405 gen_helper_probe(dest, cpu_env, addr, level, want);
2406
2407 tcg_temp_free_i32(want);
2408 tcg_temp_free_i32(level);
2409
98a9cb79 2410 save_gpr(ctx, rt, dest);
869051ea 2411 return nullify_end(ctx, DISAS_NEXT);
98a9cb79
RH
2412}
2413
8d6ae7fb
RH
2414#ifndef CONFIG_USER_ONLY
2415static DisasJumpType trans_ixtlbx(DisasContext *ctx, uint32_t insn,
2416 const DisasInsn *di)
2417{
2418 unsigned sp;
2419 unsigned rr = extract32(insn, 16, 5);
2420 unsigned rb = extract32(insn, 21, 5);
2421 unsigned is_data = insn & 0x1000;
2422 unsigned is_addr = insn & 0x40;
2423 TCGv_tl addr;
2424 TCGv_reg ofs, reg;
2425
2426 if (is_data) {
2427 sp = extract32(insn, 14, 2);
2428 } else {
2429 sp = ~assemble_sr3(insn);
2430 }
2431
2432 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2433 nullify_over(ctx);
2434
2435 form_gva(ctx, &addr, &ofs, rb, 0, 0, 0, sp, 0, false);
2436 reg = load_gpr(ctx, rr);
2437 if (is_addr) {
2438 gen_helper_itlba(cpu_env, addr, reg);
2439 } else {
2440 gen_helper_itlbp(cpu_env, addr, reg);
2441 }
2442
2443 /* Exit TB for ITLB change if mmu is enabled. This *should* not be
2444 the case, since the OS TLB fill handler runs with mmu disabled. */
494737b7 2445 return nullify_end(ctx, !is_data && (ctx->tb_flags & PSW_C)
8d6ae7fb
RH
2446 ? DISAS_IAQ_N_STALE : DISAS_NEXT);
2447}
63300a00
RH
2448
2449static DisasJumpType trans_pxtlbx(DisasContext *ctx, uint32_t insn,
2450 const DisasInsn *di)
2451{
2452 unsigned m = extract32(insn, 5, 1);
2453 unsigned sp;
2454 unsigned rx = extract32(insn, 16, 5);
2455 unsigned rb = extract32(insn, 21, 5);
2456 unsigned is_data = insn & 0x1000;
2457 unsigned is_local = insn & 0x40;
2458 TCGv_tl addr;
2459 TCGv_reg ofs;
2460
2461 if (is_data) {
2462 sp = extract32(insn, 14, 2);
2463 } else {
2464 sp = ~assemble_sr3(insn);
2465 }
2466
2467 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2468 nullify_over(ctx);
2469
2470 form_gva(ctx, &addr, &ofs, rb, rx, 0, 0, sp, m, false);
2471 if (m) {
2472 save_gpr(ctx, rb, ofs);
2473 }
2474 if (is_local) {
2475 gen_helper_ptlbe(cpu_env);
2476 } else {
2477 gen_helper_ptlb(cpu_env, addr);
2478 }
2479
2480 /* Exit TB for TLB change if mmu is enabled. */
494737b7 2481 return nullify_end(ctx, !is_data && (ctx->tb_flags & PSW_C)
63300a00
RH
2482 ? DISAS_IAQ_N_STALE : DISAS_NEXT);
2483}
2dfcca9f
RH
2484
2485static DisasJumpType trans_lpa(DisasContext *ctx, uint32_t insn,
2486 const DisasInsn *di)
2487{
2488 unsigned rt = extract32(insn, 0, 5);
2489 unsigned m = extract32(insn, 5, 1);
2490 unsigned sp = extract32(insn, 14, 2);
2491 unsigned rx = extract32(insn, 16, 5);
2492 unsigned rb = extract32(insn, 21, 5);
2493 TCGv_tl vaddr;
2494 TCGv_reg ofs, paddr;
2495
2496 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2497 nullify_over(ctx);
2498
2499 form_gva(ctx, &vaddr, &ofs, rb, rx, 0, 0, sp, m, false);
2500
2501 paddr = tcg_temp_new();
2502 gen_helper_lpa(paddr, cpu_env, vaddr);
2503
2504 /* Note that physical address result overrides base modification. */
2505 if (m) {
2506 save_gpr(ctx, rb, ofs);
2507 }
2508 save_gpr(ctx, rt, paddr);
2509 tcg_temp_free(paddr);
2510
2511 return nullify_end(ctx, DISAS_NEXT);
2512}
43a97b81
RH
2513
2514static DisasJumpType trans_lci(DisasContext *ctx, uint32_t insn,
2515 const DisasInsn *di)
2516{
2517 unsigned rt = extract32(insn, 0, 5);
2518 TCGv_reg ci;
2519
2520 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2521
2522 /* The Coherence Index is an implementation-defined function of the
2523 physical address. Two addresses with the same CI have a coherent
2524 view of the cache. Our implementation is to return 0 for all,
2525 since the entire address space is coherent. */
2526 ci = tcg_const_reg(0);
2527 save_gpr(ctx, rt, ci);
2528 tcg_temp_free(ci);
2529
2530 return DISAS_NEXT;
2531}
8d6ae7fb
RH
2532#endif /* !CONFIG_USER_ONLY */
2533
98a9cb79
RH
2534static const DisasInsn table_mem_mgmt[] = {
2535 { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */
2536 { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */
2537 { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
2538 { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */
2539 { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
2540 { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */
2541 { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
2542 { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */
2543 { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
2544 { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */
2545 { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
2546 { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */
2547 { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
2548 { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */
2549 { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */
8d6ae7fb
RH
2550#ifndef CONFIG_USER_ONLY
2551 { 0x04000000u, 0xfc001fffu, trans_ixtlbx }, /* iitlbp */
2552 { 0x04000040u, 0xfc001fffu, trans_ixtlbx }, /* iitlba */
2553 { 0x04001000u, 0xfc001fffu, trans_ixtlbx }, /* idtlbp */
2554 { 0x04001040u, 0xfc001fffu, trans_ixtlbx }, /* idtlba */
63300a00
RH
2555 { 0x04000200u, 0xfc001fdfu, trans_pxtlbx }, /* pitlb */
2556 { 0x04000240u, 0xfc001fdfu, trans_pxtlbx }, /* pitlbe */
2557 { 0x04001200u, 0xfc001fdfu, trans_pxtlbx }, /* pdtlb */
2558 { 0x04001240u, 0xfc001fdfu, trans_pxtlbx }, /* pdtlbe */
2dfcca9f 2559 { 0x04001340u, 0xfc003fc0u, trans_lpa },
43a97b81 2560 { 0x04001300u, 0xfc003fe0u, trans_lci },
8d6ae7fb 2561#endif
98a9cb79
RH
2562};
2563
869051ea
RH
2564static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
2565 const DisasInsn *di)
b2167459
RH
2566{
2567 unsigned r2 = extract32(insn, 21, 5);
2568 unsigned r1 = extract32(insn, 16, 5);
2569 unsigned cf = extract32(insn, 12, 4);
2570 unsigned ext = extract32(insn, 8, 4);
2571 unsigned shift = extract32(insn, 6, 2);
2572 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2573 TCGv_reg tcg_r1, tcg_r2;
b2167459
RH
2574 bool is_c = false;
2575 bool is_l = false;
2576 bool is_tc = false;
2577 bool is_tsv = false;
869051ea 2578 DisasJumpType ret;
b2167459
RH
2579
2580 switch (ext) {
2581 case 0x6: /* ADD, SHLADD */
2582 break;
2583 case 0xa: /* ADD,L, SHLADD,L */
2584 is_l = true;
2585 break;
2586 case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
2587 is_tsv = true;
2588 break;
2589 case 0x7: /* ADD,C */
2590 is_c = true;
2591 break;
2592 case 0xf: /* ADD,C,TSV */
2593 is_c = is_tsv = true;
2594 break;
2595 default:
2596 return gen_illegal(ctx);
2597 }
2598
2599 if (cf) {
2600 nullify_over(ctx);
2601 }
2602 tcg_r1 = load_gpr(ctx, r1);
2603 tcg_r2 = load_gpr(ctx, r2);
2604 ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
2605 return nullify_end(ctx, ret);
2606}
2607
869051ea
RH
2608static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
2609 const DisasInsn *di)
b2167459
RH
2610{
2611 unsigned r2 = extract32(insn, 21, 5);
2612 unsigned r1 = extract32(insn, 16, 5);
2613 unsigned cf = extract32(insn, 12, 4);
2614 unsigned ext = extract32(insn, 6, 6);
2615 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2616 TCGv_reg tcg_r1, tcg_r2;
b2167459
RH
2617 bool is_b = false;
2618 bool is_tc = false;
2619 bool is_tsv = false;
869051ea 2620 DisasJumpType ret;
b2167459
RH
2621
2622 switch (ext) {
2623 case 0x10: /* SUB */
2624 break;
2625 case 0x30: /* SUB,TSV */
2626 is_tsv = true;
2627 break;
2628 case 0x14: /* SUB,B */
2629 is_b = true;
2630 break;
2631 case 0x34: /* SUB,B,TSV */
2632 is_b = is_tsv = true;
2633 break;
2634 case 0x13: /* SUB,TC */
2635 is_tc = true;
2636 break;
2637 case 0x33: /* SUB,TSV,TC */
2638 is_tc = is_tsv = true;
2639 break;
2640 default:
2641 return gen_illegal(ctx);
2642 }
2643
2644 if (cf) {
2645 nullify_over(ctx);
2646 }
2647 tcg_r1 = load_gpr(ctx, r1);
2648 tcg_r2 = load_gpr(ctx, r2);
2649 ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
2650 return nullify_end(ctx, ret);
2651}
2652
869051ea
RH
2653static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
2654 const DisasInsn *di)
b2167459
RH
2655{
2656 unsigned r2 = extract32(insn, 21, 5);
2657 unsigned r1 = extract32(insn, 16, 5);
2658 unsigned cf = extract32(insn, 12, 4);
2659 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2660 TCGv_reg tcg_r1, tcg_r2;
869051ea 2661 DisasJumpType ret;
b2167459
RH
2662
2663 if (cf) {
2664 nullify_over(ctx);
2665 }
2666 tcg_r1 = load_gpr(ctx, r1);
2667 tcg_r2 = load_gpr(ctx, r2);
eff235eb 2668 ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
b2167459
RH
2669 return nullify_end(ctx, ret);
2670}
2671
2672/* OR r,0,t -> COPY (according to gas) */
869051ea
RH
2673static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
2674 const DisasInsn *di)
b2167459
RH
2675{
2676 unsigned r1 = extract32(insn, 16, 5);
2677 unsigned rt = extract32(insn, 0, 5);
2678
2679 if (r1 == 0) {
eaa3783b
RH
2680 TCGv_reg dest = dest_gpr(ctx, rt);
2681 tcg_gen_movi_reg(dest, 0);
b2167459
RH
2682 save_gpr(ctx, rt, dest);
2683 } else {
2684 save_gpr(ctx, rt, cpu_gr[r1]);
2685 }
2686 cond_free(&ctx->null_cond);
869051ea 2687 return DISAS_NEXT;
b2167459
RH
2688}
2689
869051ea
RH
2690static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
2691 const DisasInsn *di)
b2167459
RH
2692{
2693 unsigned r2 = extract32(insn, 21, 5);
2694 unsigned r1 = extract32(insn, 16, 5);
2695 unsigned cf = extract32(insn, 12, 4);
2696 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2697 TCGv_reg tcg_r1, tcg_r2;
869051ea 2698 DisasJumpType ret;
b2167459
RH
2699
2700 if (cf) {
2701 nullify_over(ctx);
2702 }
2703 tcg_r1 = load_gpr(ctx, r1);
2704 tcg_r2 = load_gpr(ctx, r2);
2705 ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
2706 return nullify_end(ctx, ret);
2707}
2708
869051ea
RH
2709static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
2710 const DisasInsn *di)
b2167459
RH
2711{
2712 unsigned r2 = extract32(insn, 21, 5);
2713 unsigned r1 = extract32(insn, 16, 5);
2714 unsigned cf = extract32(insn, 12, 4);
2715 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2716 TCGv_reg tcg_r1, tcg_r2;
869051ea 2717 DisasJumpType ret;
b2167459
RH
2718
2719 if (cf) {
2720 nullify_over(ctx);
2721 }
2722 tcg_r1 = load_gpr(ctx, r1);
2723 tcg_r2 = load_gpr(ctx, r2);
eaa3783b 2724 ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_reg);
b2167459
RH
2725 return nullify_end(ctx, ret);
2726}
2727
869051ea
RH
2728static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
2729 const DisasInsn *di)
b2167459
RH
2730{
2731 unsigned r2 = extract32(insn, 21, 5);
2732 unsigned r1 = extract32(insn, 16, 5);
2733 unsigned cf = extract32(insn, 12, 4);
2734 unsigned is_tc = extract32(insn, 6, 1);
2735 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2736 TCGv_reg tcg_r1, tcg_r2, tmp;
869051ea 2737 DisasJumpType ret;
b2167459
RH
2738
2739 if (cf) {
2740 nullify_over(ctx);
2741 }
2742 tcg_r1 = load_gpr(ctx, r1);
2743 tcg_r2 = load_gpr(ctx, r2);
2744 tmp = get_temp(ctx);
eaa3783b
RH
2745 tcg_gen_not_reg(tmp, tcg_r2);
2746 ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_reg);
b2167459
RH
2747 return nullify_end(ctx, ret);
2748}
2749
869051ea
RH
2750static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
2751 const DisasInsn *di)
b2167459
RH
2752{
2753 unsigned r2 = extract32(insn, 21, 5);
2754 unsigned cf = extract32(insn, 12, 4);
2755 unsigned is_i = extract32(insn, 6, 1);
2756 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2757 TCGv_reg tmp;
869051ea 2758 DisasJumpType ret;
b2167459
RH
2759
2760 nullify_over(ctx);
2761
2762 tmp = get_temp(ctx);
eaa3783b 2763 tcg_gen_shri_reg(tmp, cpu_psw_cb, 3);
b2167459 2764 if (!is_i) {
eaa3783b 2765 tcg_gen_not_reg(tmp, tmp);
b2167459 2766 }
eaa3783b
RH
2767 tcg_gen_andi_reg(tmp, tmp, 0x11111111);
2768 tcg_gen_muli_reg(tmp, tmp, 6);
b2167459 2769 ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
eaa3783b 2770 is_i ? tcg_gen_add_reg : tcg_gen_sub_reg);
b2167459
RH
2771
2772 return nullify_end(ctx, ret);
2773}
2774
869051ea
RH
2775static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2776 const DisasInsn *di)
b2167459
RH
2777{
2778 unsigned r2 = extract32(insn, 21, 5);
2779 unsigned r1 = extract32(insn, 16, 5);
2780 unsigned cf = extract32(insn, 12, 4);
2781 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2782 TCGv_reg dest, add1, add2, addc, zero, in1, in2;
b2167459
RH
2783
2784 nullify_over(ctx);
2785
2786 in1 = load_gpr(ctx, r1);
2787 in2 = load_gpr(ctx, r2);
2788
2789 add1 = tcg_temp_new();
2790 add2 = tcg_temp_new();
2791 addc = tcg_temp_new();
2792 dest = tcg_temp_new();
eaa3783b 2793 zero = tcg_const_reg(0);
b2167459
RH
2794
2795 /* Form R1 << 1 | PSW[CB]{8}. */
eaa3783b
RH
2796 tcg_gen_add_reg(add1, in1, in1);
2797 tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb);
b2167459
RH
2798
2799 /* Add or subtract R2, depending on PSW[V]. Proper computation of
2800 carry{8} requires that we subtract via + ~R2 + 1, as described in
2801 the manual. By extracting and masking V, we can produce the
2802 proper inputs to the addition without movcond. */
eaa3783b
RH
2803 tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1);
2804 tcg_gen_xor_reg(add2, in2, addc);
2805 tcg_gen_andi_reg(addc, addc, 1);
b2167459
RH
2806 /* ??? This is only correct for 32-bit. */
2807 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2808 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2809
2810 tcg_temp_free(addc);
2811 tcg_temp_free(zero);
2812
2813 /* Write back the result register. */
2814 save_gpr(ctx, rt, dest);
2815
2816 /* Write back PSW[CB]. */
eaa3783b
RH
2817 tcg_gen_xor_reg(cpu_psw_cb, add1, add2);
2818 tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest);
b2167459
RH
2819
2820 /* Write back PSW[V] for the division step. */
eaa3783b
RH
2821 tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb);
2822 tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2);
b2167459
RH
2823
2824 /* Install the new nullification. */
2825 if (cf) {
eaa3783b 2826 TCGv_reg sv = NULL;
b2167459
RH
2827 if (cf >> 1 == 6) {
2828 /* ??? The lshift is supposed to contribute to overflow. */
2829 sv = do_add_sv(ctx, dest, add1, add2);
2830 }
2831 ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2832 }
2833
2834 tcg_temp_free(add1);
2835 tcg_temp_free(add2);
2836 tcg_temp_free(dest);
2837
869051ea 2838 return nullify_end(ctx, DISAS_NEXT);
b2167459
RH
2839}
2840
b49572d3
RH
2841#ifndef CONFIG_USER_ONLY
2842/* These are QEMU extensions and are nops in the real architecture:
2843 *
2844 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2845 * or %r31,%r31,%r31 -- death loop; offline cpu
2846 * currently implemented as idle.
2847 */
2848static DisasJumpType trans_pause(DisasContext *ctx, uint32_t insn,
2849 const DisasInsn *di)
2850{
2851 TCGv_i32 tmp;
2852
2853 /* No need to check for supervisor, as userland can only pause
2854 until the next timer interrupt. */
2855 nullify_over(ctx);
2856
2857 /* Advance the instruction queue. */
2858 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2859 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
2860 nullify_set(ctx, 0);
2861
2862 /* Tell the qemu main loop to halt until this cpu has work. */
2863 tmp = tcg_const_i32(1);
2864 tcg_gen_st_i32(tmp, cpu_env, -offsetof(HPPACPU, env) +
2865 offsetof(CPUState, halted));
2866 tcg_temp_free_i32(tmp);
2867 gen_excp_1(EXCP_HALTED);
2868
2869 return nullify_end(ctx, DISAS_NORETURN);
2870}
2871#endif
2872
b2167459
RH
2873static const DisasInsn table_arith_log[] = {
2874 { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */
2875 { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
b49572d3
RH
2876#ifndef CONFIG_USER_ONLY
2877 { 0x094a024au, 0xffffffffu, trans_pause }, /* or r10,r10,r10 */
2878 { 0x0bff025fu, 0xffffffffu, trans_pause }, /* or r31,r31,r31 */
2879#endif
eaa3783b
RH
2880 { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_reg },
2881 { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_reg },
2882 { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_reg },
2883 { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_reg },
b2167459
RH
2884 { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2885 { 0x08000380u, 0xfc000fe0u, trans_uxor },
2886 { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2887 { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2888 { 0x08000440u, 0xfc000fe0u, trans_ds },
2889 { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2890 { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2891 { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2892 { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2893};
2894
869051ea 2895static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
b2167459 2896{
eaa3783b 2897 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2898 unsigned e1 = extract32(insn, 11, 1);
2899 unsigned cf = extract32(insn, 12, 4);
2900 unsigned rt = extract32(insn, 16, 5);
2901 unsigned r2 = extract32(insn, 21, 5);
2902 unsigned o1 = extract32(insn, 26, 1);
eaa3783b 2903 TCGv_reg tcg_im, tcg_r2;
869051ea 2904 DisasJumpType ret;
b2167459
RH
2905
2906 if (cf) {
2907 nullify_over(ctx);
2908 }
2909
2910 tcg_im = load_const(ctx, im);
2911 tcg_r2 = load_gpr(ctx, r2);
2912 ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2913
2914 return nullify_end(ctx, ret);
2915}
2916
869051ea 2917static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
b2167459 2918{
eaa3783b 2919 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2920 unsigned e1 = extract32(insn, 11, 1);
2921 unsigned cf = extract32(insn, 12, 4);
2922 unsigned rt = extract32(insn, 16, 5);
2923 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 2924 TCGv_reg tcg_im, tcg_r2;
869051ea 2925 DisasJumpType ret;
b2167459
RH
2926
2927 if (cf) {
2928 nullify_over(ctx);
2929 }
2930
2931 tcg_im = load_const(ctx, im);
2932 tcg_r2 = load_gpr(ctx, r2);
2933 ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2934
2935 return nullify_end(ctx, ret);
2936}
2937
869051ea 2938static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
b2167459 2939{
eaa3783b 2940 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2941 unsigned cf = extract32(insn, 12, 4);
2942 unsigned rt = extract32(insn, 16, 5);
2943 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 2944 TCGv_reg tcg_im, tcg_r2;
869051ea 2945 DisasJumpType ret;
b2167459
RH
2946
2947 if (cf) {
2948 nullify_over(ctx);
2949 }
2950
2951 tcg_im = load_const(ctx, im);
2952 tcg_r2 = load_gpr(ctx, r2);
2953 ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2954
2955 return nullify_end(ctx, ret);
2956}
2957
869051ea
RH
2958static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2959 const DisasInsn *di)
96d6407f
RH
2960{
2961 unsigned rt = extract32(insn, 0, 5);
2962 unsigned m = extract32(insn, 5, 1);
2963 unsigned sz = extract32(insn, 6, 2);
2964 unsigned a = extract32(insn, 13, 1);
86f8d05f 2965 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2966 int disp = low_sextract(insn, 16, 5);
2967 unsigned rb = extract32(insn, 21, 5);
2968 int modify = (m ? (a ? -1 : 1) : 0);
2969 TCGMemOp mop = MO_TE | sz;
2970
86f8d05f 2971 return do_load(ctx, rt, rb, 0, 0, disp, sp, modify, mop);
96d6407f
RH
2972}
2973
869051ea
RH
2974static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2975 const DisasInsn *di)
96d6407f
RH
2976{
2977 unsigned rt = extract32(insn, 0, 5);
2978 unsigned m = extract32(insn, 5, 1);
2979 unsigned sz = extract32(insn, 6, 2);
2980 unsigned u = extract32(insn, 13, 1);
86f8d05f 2981 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2982 unsigned rx = extract32(insn, 16, 5);
2983 unsigned rb = extract32(insn, 21, 5);
2984 TCGMemOp mop = MO_TE | sz;
2985
86f8d05f 2986 return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, sp, m, mop);
96d6407f
RH
2987}
2988
869051ea
RH
2989static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2990 const DisasInsn *di)
96d6407f
RH
2991{
2992 int disp = low_sextract(insn, 0, 5);
2993 unsigned m = extract32(insn, 5, 1);
2994 unsigned sz = extract32(insn, 6, 2);
2995 unsigned a = extract32(insn, 13, 1);
86f8d05f 2996 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2997 unsigned rr = extract32(insn, 16, 5);
2998 unsigned rb = extract32(insn, 21, 5);
2999 int modify = (m ? (a ? -1 : 1) : 0);
3000 TCGMemOp mop = MO_TE | sz;
3001
86f8d05f 3002 return do_store(ctx, rr, rb, disp, sp, modify, mop);
96d6407f
RH
3003}
3004
869051ea
RH
3005static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
3006 const DisasInsn *di)
96d6407f
RH
3007{
3008 unsigned rt = extract32(insn, 0, 5);
3009 unsigned m = extract32(insn, 5, 1);
3010 unsigned i = extract32(insn, 12, 1);
3011 unsigned au = extract32(insn, 13, 1);
86f8d05f 3012 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3013 unsigned rx = extract32(insn, 16, 5);
3014 unsigned rb = extract32(insn, 21, 5);
3015 TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
86f8d05f
RH
3016 TCGv_reg zero, dest, ofs;
3017 TCGv_tl addr;
96d6407f
RH
3018 int modify, disp = 0, scale = 0;
3019
3020 nullify_over(ctx);
3021
96d6407f
RH
3022 if (i) {
3023 modify = (m ? (au ? -1 : 1) : 0);
3024 disp = low_sextract(rx, 0, 5);
3025 rx = 0;
3026 } else {
3027 modify = m;
3028 if (au) {
3029 scale = mop & MO_SIZE;
3030 }
3031 }
3032 if (modify) {
86f8d05f
RH
3033 /* Base register modification. Make sure if RT == RB,
3034 we see the result of the load. */
96d6407f
RH
3035 dest = get_temp(ctx);
3036 } else {
3037 dest = dest_gpr(ctx, rt);
3038 }
3039
86f8d05f
RH
3040 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
3041 ctx->mmu_idx == MMU_PHYS_IDX);
eaa3783b 3042 zero = tcg_const_reg(0);
86f8d05f 3043 tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop);
96d6407f 3044 if (modify) {
86f8d05f 3045 save_gpr(ctx, rb, ofs);
96d6407f
RH
3046 }
3047 save_gpr(ctx, rt, dest);
3048
869051ea 3049 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
3050}
3051
869051ea
RH
3052static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
3053 const DisasInsn *di)
96d6407f 3054{
eaa3783b 3055 target_sreg disp = low_sextract(insn, 0, 5);
96d6407f
RH
3056 unsigned m = extract32(insn, 5, 1);
3057 unsigned a = extract32(insn, 13, 1);
86f8d05f 3058 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3059 unsigned rt = extract32(insn, 16, 5);
3060 unsigned rb = extract32(insn, 21, 5);
86f8d05f
RH
3061 TCGv_reg ofs, val;
3062 TCGv_tl addr;
96d6407f
RH
3063
3064 nullify_over(ctx);
3065
86f8d05f
RH
3066 form_gva(ctx, &addr, &ofs, rb, 0, 0, disp, sp, m,
3067 ctx->mmu_idx == MMU_PHYS_IDX);
96d6407f 3068 val = load_gpr(ctx, rt);
96d6407f 3069 if (a) {
f9f46db4
EC
3070 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3071 gen_helper_stby_e_parallel(cpu_env, addr, val);
3072 } else {
3073 gen_helper_stby_e(cpu_env, addr, val);
3074 }
96d6407f 3075 } else {
f9f46db4
EC
3076 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3077 gen_helper_stby_b_parallel(cpu_env, addr, val);
3078 } else {
3079 gen_helper_stby_b(cpu_env, addr, val);
3080 }
96d6407f
RH
3081 }
3082
3083 if (m) {
86f8d05f
RH
3084 tcg_gen_andi_reg(ofs, ofs, ~3);
3085 save_gpr(ctx, rb, ofs);
96d6407f 3086 }
96d6407f 3087
869051ea 3088 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
3089}
3090
d0a851cc
RH
3091#ifndef CONFIG_USER_ONLY
3092static DisasJumpType trans_ldwa_idx_i(DisasContext *ctx, uint32_t insn,
3093 const DisasInsn *di)
3094{
3095 int hold_mmu_idx = ctx->mmu_idx;
3096 DisasJumpType ret;
3097
3098 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3099
3100 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3101 format wrt the sub-opcode in bits 6:9. */
3102 ctx->mmu_idx = MMU_PHYS_IDX;
3103 ret = trans_ld_idx_i(ctx, insn, di);
3104 ctx->mmu_idx = hold_mmu_idx;
3105 return ret;
3106}
3107
3108static DisasJumpType trans_ldwa_idx_x(DisasContext *ctx, uint32_t insn,
3109 const DisasInsn *di)
3110{
3111 int hold_mmu_idx = ctx->mmu_idx;
3112 DisasJumpType ret;
3113
3114 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3115
3116 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3117 format wrt the sub-opcode in bits 6:9. */
3118 ctx->mmu_idx = MMU_PHYS_IDX;
3119 ret = trans_ld_idx_x(ctx, insn, di);
3120 ctx->mmu_idx = hold_mmu_idx;
3121 return ret;
3122}
95412a61
RH
3123
3124static DisasJumpType trans_stwa_idx_i(DisasContext *ctx, uint32_t insn,
3125 const DisasInsn *di)
3126{
3127 int hold_mmu_idx = ctx->mmu_idx;
3128 DisasJumpType ret;
3129
3130 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3131
3132 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3133 format wrt the sub-opcode in bits 6:9. */
3134 ctx->mmu_idx = MMU_PHYS_IDX;
3135 ret = trans_st_idx_i(ctx, insn, di);
3136 ctx->mmu_idx = hold_mmu_idx;
3137 return ret;
3138}
d0a851cc
RH
3139#endif
3140
96d6407f
RH
3141static const DisasInsn table_index_mem[] = {
3142 { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
3143 { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
3144 { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
3145 { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
3146 { 0x0c001300u, 0xfc0013c0, trans_stby },
d0a851cc 3147#ifndef CONFIG_USER_ONLY
d0a851cc 3148 { 0x0c000180u, 0xfc00d3c0, trans_ldwa_idx_x }, /* LDWA, rx */
95412a61
RH
3149 { 0x0c001180u, 0xfc00d3c0, trans_ldwa_idx_i }, /* LDWA, im */
3150 { 0x0c001380u, 0xfc00d3c0, trans_stwa_idx_i }, /* STWA, im */
d0a851cc 3151#endif
96d6407f
RH
3152};
3153
869051ea 3154static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
b2167459
RH
3155{
3156 unsigned rt = extract32(insn, 21, 5);
eaa3783b
RH
3157 target_sreg i = assemble_21(insn);
3158 TCGv_reg tcg_rt = dest_gpr(ctx, rt);
b2167459 3159
eaa3783b 3160 tcg_gen_movi_reg(tcg_rt, i);
b2167459
RH
3161 save_gpr(ctx, rt, tcg_rt);
3162 cond_free(&ctx->null_cond);
3163
869051ea 3164 return DISAS_NEXT;
b2167459
RH
3165}
3166
869051ea 3167static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
b2167459
RH
3168{
3169 unsigned rt = extract32(insn, 21, 5);
eaa3783b
RH
3170 target_sreg i = assemble_21(insn);
3171 TCGv_reg tcg_rt = load_gpr(ctx, rt);
3172 TCGv_reg tcg_r1 = dest_gpr(ctx, 1);
b2167459 3173
eaa3783b 3174 tcg_gen_addi_reg(tcg_r1, tcg_rt, i);
b2167459
RH
3175 save_gpr(ctx, 1, tcg_r1);
3176 cond_free(&ctx->null_cond);
3177
869051ea 3178 return DISAS_NEXT;
b2167459
RH
3179}
3180
869051ea 3181static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
b2167459
RH
3182{
3183 unsigned rb = extract32(insn, 21, 5);
3184 unsigned rt = extract32(insn, 16, 5);
eaa3783b
RH
3185 target_sreg i = assemble_16(insn);
3186 TCGv_reg tcg_rt = dest_gpr(ctx, rt);
b2167459
RH
3187
3188 /* Special case rb == 0, for the LDI pseudo-op.
3189 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
3190 if (rb == 0) {
eaa3783b 3191 tcg_gen_movi_reg(tcg_rt, i);
b2167459 3192 } else {
eaa3783b 3193 tcg_gen_addi_reg(tcg_rt, cpu_gr[rb], i);
b2167459
RH
3194 }
3195 save_gpr(ctx, rt, tcg_rt);
3196 cond_free(&ctx->null_cond);
3197
869051ea 3198 return DISAS_NEXT;
b2167459
RH
3199}
3200
869051ea
RH
3201static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
3202 bool is_mod, TCGMemOp mop)
96d6407f
RH
3203{
3204 unsigned rb = extract32(insn, 21, 5);
3205 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3206 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3207 target_sreg i = assemble_16(insn);
96d6407f 3208
86f8d05f
RH
3209 return do_load(ctx, rt, rb, 0, 0, i, sp,
3210 is_mod ? (i < 0 ? -1 : 1) : 0, mop);
96d6407f
RH
3211}
3212
869051ea 3213static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3214{
3215 unsigned rb = extract32(insn, 21, 5);
3216 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3217 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3218 target_sreg i = assemble_16a(insn);
96d6407f
RH
3219 unsigned ext2 = extract32(insn, 1, 2);
3220
3221 switch (ext2) {
3222 case 0:
3223 case 1:
3224 /* FLDW without modification. */
86f8d05f 3225 return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
96d6407f
RH
3226 case 2:
3227 /* LDW with modification. Note that the sign of I selects
3228 post-dec vs pre-inc. */
86f8d05f 3229 return do_load(ctx, rt, rb, 0, 0, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
96d6407f
RH
3230 default:
3231 return gen_illegal(ctx);
3232 }
3233}
3234
869051ea 3235static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
96d6407f 3236{
eaa3783b 3237 target_sreg i = assemble_16a(insn);
96d6407f
RH
3238 unsigned t1 = extract32(insn, 1, 1);
3239 unsigned a = extract32(insn, 2, 1);
86f8d05f 3240 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3241 unsigned t0 = extract32(insn, 16, 5);
3242 unsigned rb = extract32(insn, 21, 5);
3243
3244 /* FLDW with modification. */
86f8d05f 3245 return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
96d6407f
RH
3246}
3247
869051ea
RH
3248static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
3249 bool is_mod, TCGMemOp mop)
96d6407f
RH
3250{
3251 unsigned rb = extract32(insn, 21, 5);
3252 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3253 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3254 target_sreg i = assemble_16(insn);
96d6407f 3255
86f8d05f 3256 return do_store(ctx, rt, rb, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
96d6407f
RH
3257}
3258
869051ea 3259static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3260{
3261 unsigned rb = extract32(insn, 21, 5);
3262 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3263 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3264 target_sreg i = assemble_16a(insn);
96d6407f
RH
3265 unsigned ext2 = extract32(insn, 1, 2);
3266
3267 switch (ext2) {
3268 case 0:
3269 case 1:
3270 /* FSTW without modification. */
86f8d05f 3271 return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
96d6407f 3272 case 2:
3f7367e2 3273 /* STW with modification. */
86f8d05f 3274 return do_store(ctx, rt, rb, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
96d6407f
RH
3275 default:
3276 return gen_illegal(ctx);
3277 }
3278}
3279
869051ea 3280static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
96d6407f 3281{
eaa3783b 3282 target_sreg i = assemble_16a(insn);
96d6407f
RH
3283 unsigned t1 = extract32(insn, 1, 1);
3284 unsigned a = extract32(insn, 2, 1);
86f8d05f 3285 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3286 unsigned t0 = extract32(insn, 16, 5);
3287 unsigned rb = extract32(insn, 21, 5);
3288
3289 /* FSTW with modification. */
86f8d05f 3290 return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
96d6407f
RH
3291}
3292
869051ea 3293static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3294{
3295 unsigned t0 = extract32(insn, 0, 5);
3296 unsigned m = extract32(insn, 5, 1);
3297 unsigned t1 = extract32(insn, 6, 1);
3298 unsigned ext3 = extract32(insn, 7, 3);
3299 /* unsigned cc = extract32(insn, 10, 2); */
3300 unsigned i = extract32(insn, 12, 1);
3301 unsigned ua = extract32(insn, 13, 1);
86f8d05f 3302 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3303 unsigned rx = extract32(insn, 16, 5);
3304 unsigned rb = extract32(insn, 21, 5);
3305 unsigned rt = t1 * 32 + t0;
3306 int modify = (m ? (ua ? -1 : 1) : 0);
3307 int disp, scale;
3308
3309 if (i == 0) {
3310 scale = (ua ? 2 : 0);
3311 disp = 0;
3312 modify = m;
3313 } else {
3314 disp = low_sextract(rx, 0, 5);
3315 scale = 0;
3316 rx = 0;
3317 modify = (m ? (ua ? -1 : 1) : 0);
3318 }
3319
3320 switch (ext3) {
3321 case 0: /* FLDW */
86f8d05f 3322 return do_floadw(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f 3323 case 4: /* FSTW */
86f8d05f 3324 return do_fstorew(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f
RH
3325 }
3326 return gen_illegal(ctx);
3327}
3328
869051ea 3329static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3330{
3331 unsigned rt = extract32(insn, 0, 5);
3332 unsigned m = extract32(insn, 5, 1);
3333 unsigned ext4 = extract32(insn, 6, 4);
3334 /* unsigned cc = extract32(insn, 10, 2); */
3335 unsigned i = extract32(insn, 12, 1);
3336 unsigned ua = extract32(insn, 13, 1);
86f8d05f 3337 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3338 unsigned rx = extract32(insn, 16, 5);
3339 unsigned rb = extract32(insn, 21, 5);
3340 int modify = (m ? (ua ? -1 : 1) : 0);
3341 int disp, scale;
3342
3343 if (i == 0) {
3344 scale = (ua ? 3 : 0);
3345 disp = 0;
3346 modify = m;
3347 } else {
3348 disp = low_sextract(rx, 0, 5);
3349 scale = 0;
3350 rx = 0;
3351 modify = (m ? (ua ? -1 : 1) : 0);
3352 }
3353
3354 switch (ext4) {
3355 case 0: /* FLDD */
86f8d05f 3356 return do_floadd(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f 3357 case 8: /* FSTD */
86f8d05f 3358 return do_fstored(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f
RH
3359 default:
3360 return gen_illegal(ctx);
3361 }
3362}
3363
869051ea
RH
3364static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
3365 bool is_true, bool is_imm, bool is_dw)
98cd9ca7 3366{
eaa3783b 3367 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3368 unsigned n = extract32(insn, 1, 1);
3369 unsigned c = extract32(insn, 13, 3);
3370 unsigned r = extract32(insn, 21, 5);
3371 unsigned cf = c * 2 + !is_true;
eaa3783b 3372 TCGv_reg dest, in1, in2, sv;
98cd9ca7
RH
3373 DisasCond cond;
3374
3375 nullify_over(ctx);
3376
3377 if (is_imm) {
3378 in1 = load_const(ctx, low_sextract(insn, 16, 5));
3379 } else {
3380 in1 = load_gpr(ctx, extract32(insn, 16, 5));
3381 }
3382 in2 = load_gpr(ctx, r);
3383 dest = get_temp(ctx);
3384
eaa3783b 3385 tcg_gen_sub_reg(dest, in1, in2);
98cd9ca7 3386
f764718d 3387 sv = NULL;
98cd9ca7
RH
3388 if (c == 6) {
3389 sv = do_sub_sv(ctx, dest, in1, in2);
3390 }
3391
3392 cond = do_sub_cond(cf, dest, in1, in2, sv);
3393 return do_cbranch(ctx, disp, n, &cond);
3394}
3395
869051ea
RH
3396static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
3397 bool is_true, bool is_imm)
98cd9ca7 3398{
eaa3783b 3399 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3400 unsigned n = extract32(insn, 1, 1);
3401 unsigned c = extract32(insn, 13, 3);
3402 unsigned r = extract32(insn, 21, 5);
3403 unsigned cf = c * 2 + !is_true;
eaa3783b 3404 TCGv_reg dest, in1, in2, sv, cb_msb;
98cd9ca7
RH
3405 DisasCond cond;
3406
3407 nullify_over(ctx);
3408
3409 if (is_imm) {
3410 in1 = load_const(ctx, low_sextract(insn, 16, 5));
3411 } else {
3412 in1 = load_gpr(ctx, extract32(insn, 16, 5));
3413 }
3414 in2 = load_gpr(ctx, r);
3415 dest = dest_gpr(ctx, r);
f764718d
RH
3416 sv = NULL;
3417 cb_msb = NULL;
98cd9ca7
RH
3418
3419 switch (c) {
3420 default:
eaa3783b 3421 tcg_gen_add_reg(dest, in1, in2);
98cd9ca7
RH
3422 break;
3423 case 4: case 5:
3424 cb_msb = get_temp(ctx);
eaa3783b
RH
3425 tcg_gen_movi_reg(cb_msb, 0);
3426 tcg_gen_add2_reg(dest, cb_msb, in1, cb_msb, in2, cb_msb);
98cd9ca7
RH
3427 break;
3428 case 6:
eaa3783b 3429 tcg_gen_add_reg(dest, in1, in2);
98cd9ca7
RH
3430 sv = do_add_sv(ctx, dest, in1, in2);
3431 break;
3432 }
3433
3434 cond = do_cond(cf, dest, cb_msb, sv);
3435 return do_cbranch(ctx, disp, n, &cond);
3436}
3437
869051ea 3438static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
98cd9ca7 3439{
eaa3783b 3440 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3441 unsigned n = extract32(insn, 1, 1);
3442 unsigned c = extract32(insn, 15, 1);
3443 unsigned r = extract32(insn, 16, 5);
3444 unsigned p = extract32(insn, 21, 5);
3445 unsigned i = extract32(insn, 26, 1);
eaa3783b 3446 TCGv_reg tmp, tcg_r;
98cd9ca7
RH
3447 DisasCond cond;
3448
3449 nullify_over(ctx);
3450
3451 tmp = tcg_temp_new();
3452 tcg_r = load_gpr(ctx, r);
3453 if (i) {
eaa3783b 3454 tcg_gen_shli_reg(tmp, tcg_r, p);
98cd9ca7 3455 } else {
eaa3783b 3456 tcg_gen_shl_reg(tmp, tcg_r, cpu_sar);
98cd9ca7
RH
3457 }
3458
3459 cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
3460 tcg_temp_free(tmp);
3461 return do_cbranch(ctx, disp, n, &cond);
3462}
3463
869051ea 3464static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
98cd9ca7 3465{
eaa3783b 3466 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3467 unsigned n = extract32(insn, 1, 1);
3468 unsigned c = extract32(insn, 13, 3);
3469 unsigned t = extract32(insn, 16, 5);
3470 unsigned r = extract32(insn, 21, 5);
eaa3783b 3471 TCGv_reg dest;
98cd9ca7
RH
3472 DisasCond cond;
3473
3474 nullify_over(ctx);
3475
3476 dest = dest_gpr(ctx, r);
3477 if (is_imm) {
eaa3783b 3478 tcg_gen_movi_reg(dest, low_sextract(t, 0, 5));
98cd9ca7 3479 } else if (t == 0) {
eaa3783b 3480 tcg_gen_movi_reg(dest, 0);
98cd9ca7 3481 } else {
eaa3783b 3482 tcg_gen_mov_reg(dest, cpu_gr[t]);
98cd9ca7
RH
3483 }
3484
3485 cond = do_sed_cond(c, dest);
3486 return do_cbranch(ctx, disp, n, &cond);
3487}
3488
869051ea
RH
3489static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
3490 const DisasInsn *di)
0b1347d2
RH
3491{
3492 unsigned rt = extract32(insn, 0, 5);
3493 unsigned c = extract32(insn, 13, 3);
3494 unsigned r1 = extract32(insn, 16, 5);
3495 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 3496 TCGv_reg dest;
0b1347d2
RH
3497
3498 if (c) {
3499 nullify_over(ctx);
3500 }
3501
3502 dest = dest_gpr(ctx, rt);
3503 if (r1 == 0) {
eaa3783b
RH
3504 tcg_gen_ext32u_reg(dest, load_gpr(ctx, r2));
3505 tcg_gen_shr_reg(dest, dest, cpu_sar);
0b1347d2
RH
3506 } else if (r1 == r2) {
3507 TCGv_i32 t32 = tcg_temp_new_i32();
eaa3783b 3508 tcg_gen_trunc_reg_i32(t32, load_gpr(ctx, r2));
0b1347d2 3509 tcg_gen_rotr_i32(t32, t32, cpu_sar);
eaa3783b 3510 tcg_gen_extu_i32_reg(dest, t32);
0b1347d2
RH
3511 tcg_temp_free_i32(t32);
3512 } else {
3513 TCGv_i64 t = tcg_temp_new_i64();
3514 TCGv_i64 s = tcg_temp_new_i64();
3515
eaa3783b
RH
3516 tcg_gen_concat_reg_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
3517 tcg_gen_extu_reg_i64(s, cpu_sar);
0b1347d2 3518 tcg_gen_shr_i64(t, t, s);
eaa3783b 3519 tcg_gen_trunc_i64_reg(dest, t);
0b1347d2
RH
3520
3521 tcg_temp_free_i64(t);
3522 tcg_temp_free_i64(s);
3523 }
3524 save_gpr(ctx, rt, dest);
3525
3526 /* Install the new nullification. */
3527 cond_free(&ctx->null_cond);
3528 if (c) {
3529 ctx->null_cond = do_sed_cond(c, dest);
3530 }
869051ea 3531 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3532}
3533
869051ea
RH
3534static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
3535 const DisasInsn *di)
0b1347d2
RH
3536{
3537 unsigned rt = extract32(insn, 0, 5);
3538 unsigned cpos = extract32(insn, 5, 5);
3539 unsigned c = extract32(insn, 13, 3);
3540 unsigned r1 = extract32(insn, 16, 5);
3541 unsigned r2 = extract32(insn, 21, 5);
3542 unsigned sa = 31 - cpos;
eaa3783b 3543 TCGv_reg dest, t2;
0b1347d2
RH
3544
3545 if (c) {
3546 nullify_over(ctx);
3547 }
3548
3549 dest = dest_gpr(ctx, rt);
3550 t2 = load_gpr(ctx, r2);
3551 if (r1 == r2) {
3552 TCGv_i32 t32 = tcg_temp_new_i32();
eaa3783b 3553 tcg_gen_trunc_reg_i32(t32, t2);
0b1347d2 3554 tcg_gen_rotri_i32(t32, t32, sa);
eaa3783b 3555 tcg_gen_extu_i32_reg(dest, t32);
0b1347d2
RH
3556 tcg_temp_free_i32(t32);
3557 } else if (r1 == 0) {
eaa3783b 3558 tcg_gen_extract_reg(dest, t2, sa, 32 - sa);
0b1347d2 3559 } else {
eaa3783b
RH
3560 TCGv_reg t0 = tcg_temp_new();
3561 tcg_gen_extract_reg(t0, t2, sa, 32 - sa);
3562 tcg_gen_deposit_reg(dest, t0, cpu_gr[r1], 32 - sa, sa);
0b1347d2
RH
3563 tcg_temp_free(t0);
3564 }
3565 save_gpr(ctx, rt, dest);
3566
3567 /* Install the new nullification. */
3568 cond_free(&ctx->null_cond);
3569 if (c) {
3570 ctx->null_cond = do_sed_cond(c, dest);
3571 }
869051ea 3572 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3573}
3574
869051ea
RH
3575static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
3576 const DisasInsn *di)
0b1347d2
RH
3577{
3578 unsigned clen = extract32(insn, 0, 5);
3579 unsigned is_se = extract32(insn, 10, 1);
3580 unsigned c = extract32(insn, 13, 3);
3581 unsigned rt = extract32(insn, 16, 5);
3582 unsigned rr = extract32(insn, 21, 5);
3583 unsigned len = 32 - clen;
eaa3783b 3584 TCGv_reg dest, src, tmp;
0b1347d2
RH
3585
3586 if (c) {
3587 nullify_over(ctx);
3588 }
3589
3590 dest = dest_gpr(ctx, rt);
3591 src = load_gpr(ctx, rr);
3592 tmp = tcg_temp_new();
3593
3594 /* Recall that SAR is using big-endian bit numbering. */
eaa3783b 3595 tcg_gen_xori_reg(tmp, cpu_sar, TARGET_REGISTER_BITS - 1);
0b1347d2 3596 if (is_se) {
eaa3783b
RH
3597 tcg_gen_sar_reg(dest, src, tmp);
3598 tcg_gen_sextract_reg(dest, dest, 0, len);
0b1347d2 3599 } else {
eaa3783b
RH
3600 tcg_gen_shr_reg(dest, src, tmp);
3601 tcg_gen_extract_reg(dest, dest, 0, len);
0b1347d2
RH
3602 }
3603 tcg_temp_free(tmp);
3604 save_gpr(ctx, rt, dest);
3605
3606 /* Install the new nullification. */
3607 cond_free(&ctx->null_cond);
3608 if (c) {
3609 ctx->null_cond = do_sed_cond(c, dest);
3610 }
869051ea 3611 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3612}
3613
869051ea
RH
3614static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
3615 const DisasInsn *di)
0b1347d2
RH
3616{
3617 unsigned clen = extract32(insn, 0, 5);
3618 unsigned pos = extract32(insn, 5, 5);
3619 unsigned is_se = extract32(insn, 10, 1);
3620 unsigned c = extract32(insn, 13, 3);
3621 unsigned rt = extract32(insn, 16, 5);
3622 unsigned rr = extract32(insn, 21, 5);
3623 unsigned len = 32 - clen;
3624 unsigned cpos = 31 - pos;
eaa3783b 3625 TCGv_reg dest, src;
0b1347d2
RH
3626
3627 if (c) {
3628 nullify_over(ctx);
3629 }
3630
3631 dest = dest_gpr(ctx, rt);
3632 src = load_gpr(ctx, rr);
3633 if (is_se) {
eaa3783b 3634 tcg_gen_sextract_reg(dest, src, cpos, len);
0b1347d2 3635 } else {
eaa3783b 3636 tcg_gen_extract_reg(dest, src, cpos, len);
0b1347d2
RH
3637 }
3638 save_gpr(ctx, rt, dest);
3639
3640 /* Install the new nullification. */
3641 cond_free(&ctx->null_cond);
3642 if (c) {
3643 ctx->null_cond = do_sed_cond(c, dest);
3644 }
869051ea 3645 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3646}
3647
3648static const DisasInsn table_sh_ex[] = {
3649 { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
3650 { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
3651 { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
3652 { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
3653};
3654
869051ea
RH
3655static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
3656 const DisasInsn *di)
0b1347d2
RH
3657{
3658 unsigned clen = extract32(insn, 0, 5);
3659 unsigned cpos = extract32(insn, 5, 5);
3660 unsigned nz = extract32(insn, 10, 1);
3661 unsigned c = extract32(insn, 13, 3);
eaa3783b 3662 target_sreg val = low_sextract(insn, 16, 5);
0b1347d2
RH
3663 unsigned rt = extract32(insn, 21, 5);
3664 unsigned len = 32 - clen;
eaa3783b
RH
3665 target_sreg mask0, mask1;
3666 TCGv_reg dest;
0b1347d2
RH
3667
3668 if (c) {
3669 nullify_over(ctx);
3670 }
3671 if (cpos + len > 32) {
3672 len = 32 - cpos;
3673 }
3674
3675 dest = dest_gpr(ctx, rt);
3676 mask0 = deposit64(0, cpos, len, val);
3677 mask1 = deposit64(-1, cpos, len, val);
3678
3679 if (nz) {
eaa3783b 3680 TCGv_reg src = load_gpr(ctx, rt);
0b1347d2 3681 if (mask1 != -1) {
eaa3783b 3682 tcg_gen_andi_reg(dest, src, mask1);
0b1347d2
RH
3683 src = dest;
3684 }
eaa3783b 3685 tcg_gen_ori_reg(dest, src, mask0);
0b1347d2 3686 } else {
eaa3783b 3687 tcg_gen_movi_reg(dest, mask0);
0b1347d2
RH
3688 }
3689 save_gpr(ctx, rt, dest);
3690
3691 /* Install the new nullification. */
3692 cond_free(&ctx->null_cond);
3693 if (c) {
3694 ctx->null_cond = do_sed_cond(c, dest);
3695 }
869051ea 3696 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3697}
3698
869051ea
RH
3699static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
3700 const DisasInsn *di)
0b1347d2
RH
3701{
3702 unsigned clen = extract32(insn, 0, 5);
3703 unsigned cpos = extract32(insn, 5, 5);
3704 unsigned nz = extract32(insn, 10, 1);
3705 unsigned c = extract32(insn, 13, 3);
3706 unsigned rr = extract32(insn, 16, 5);
3707 unsigned rt = extract32(insn, 21, 5);
3708 unsigned rs = nz ? rt : 0;
3709 unsigned len = 32 - clen;
eaa3783b 3710 TCGv_reg dest, val;
0b1347d2
RH
3711
3712 if (c) {
3713 nullify_over(ctx);
3714 }
3715 if (cpos + len > 32) {
3716 len = 32 - cpos;
3717 }
3718
3719 dest = dest_gpr(ctx, rt);
3720 val = load_gpr(ctx, rr);
3721 if (rs == 0) {
eaa3783b 3722 tcg_gen_deposit_z_reg(dest, val, cpos, len);
0b1347d2 3723 } else {
eaa3783b 3724 tcg_gen_deposit_reg(dest, cpu_gr[rs], val, cpos, len);
0b1347d2
RH
3725 }
3726 save_gpr(ctx, rt, dest);
3727
3728 /* Install the new nullification. */
3729 cond_free(&ctx->null_cond);
3730 if (c) {
3731 ctx->null_cond = do_sed_cond(c, dest);
3732 }
869051ea 3733 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3734}
3735
869051ea
RH
3736static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
3737 const DisasInsn *di)
0b1347d2
RH
3738{
3739 unsigned clen = extract32(insn, 0, 5);
3740 unsigned nz = extract32(insn, 10, 1);
3741 unsigned i = extract32(insn, 12, 1);
3742 unsigned c = extract32(insn, 13, 3);
3743 unsigned rt = extract32(insn, 21, 5);
3744 unsigned rs = nz ? rt : 0;
3745 unsigned len = 32 - clen;
eaa3783b 3746 TCGv_reg val, mask, tmp, shift, dest;
0b1347d2
RH
3747 unsigned msb = 1U << (len - 1);
3748
3749 if (c) {
3750 nullify_over(ctx);
3751 }
3752
3753 if (i) {
3754 val = load_const(ctx, low_sextract(insn, 16, 5));
3755 } else {
3756 val = load_gpr(ctx, extract32(insn, 16, 5));
3757 }
3758 dest = dest_gpr(ctx, rt);
3759 shift = tcg_temp_new();
3760 tmp = tcg_temp_new();
3761
3762 /* Convert big-endian bit numbering in SAR to left-shift. */
eaa3783b 3763 tcg_gen_xori_reg(shift, cpu_sar, TARGET_REGISTER_BITS - 1);
0b1347d2 3764
eaa3783b
RH
3765 mask = tcg_const_reg(msb + (msb - 1));
3766 tcg_gen_and_reg(tmp, val, mask);
0b1347d2 3767 if (rs) {
eaa3783b
RH
3768 tcg_gen_shl_reg(mask, mask, shift);
3769 tcg_gen_shl_reg(tmp, tmp, shift);
3770 tcg_gen_andc_reg(dest, cpu_gr[rs], mask);
3771 tcg_gen_or_reg(dest, dest, tmp);
0b1347d2 3772 } else {
eaa3783b 3773 tcg_gen_shl_reg(dest, tmp, shift);
0b1347d2
RH
3774 }
3775 tcg_temp_free(shift);
3776 tcg_temp_free(mask);
3777 tcg_temp_free(tmp);
3778 save_gpr(ctx, rt, dest);
3779
3780 /* Install the new nullification. */
3781 cond_free(&ctx->null_cond);
3782 if (c) {
3783 ctx->null_cond = do_sed_cond(c, dest);
3784 }
869051ea 3785 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3786}
3787
3788static const DisasInsn table_depw[] = {
3789 { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
3790 { 0xd4000800u, 0xfc001800u, trans_depw_imm },
3791 { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
3792};
3793
869051ea 3794static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
98cd9ca7
RH
3795{
3796 unsigned n = extract32(insn, 1, 1);
3797 unsigned b = extract32(insn, 21, 5);
eaa3783b 3798 target_sreg disp = assemble_17(insn);
660eefe1 3799 TCGv_reg tmp;
98cd9ca7 3800
c301f34e 3801#ifdef CONFIG_USER_ONLY
98cd9ca7
RH
3802 /* ??? It seems like there should be a good way of using
3803 "be disp(sr2, r0)", the canonical gateway entry mechanism
3804 to our advantage. But that appears to be inconvenient to
3805 manage along side branch delay slots. Therefore we handle
3806 entry into the gateway page via absolute address. */
98cd9ca7
RH
3807 /* Since we don't implement spaces, just branch. Do notice the special
3808 case of "be disp(*,r0)" using a direct branch to disp, so that we can
3809 goto_tb to the TB containing the syscall. */
3810 if (b == 0) {
3811 return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
98cd9ca7 3812 }
c301f34e
RH
3813#else
3814 int sp = assemble_sr3(insn);
3815 nullify_over(ctx);
660eefe1
RH
3816#endif
3817
3818 tmp = get_temp(ctx);
3819 tcg_gen_addi_reg(tmp, load_gpr(ctx, b), disp);
3820 tmp = do_ibranch_priv(ctx, tmp);
c301f34e
RH
3821
3822#ifdef CONFIG_USER_ONLY
660eefe1 3823 return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
c301f34e
RH
3824#else
3825 TCGv_i64 new_spc = tcg_temp_new_i64();
3826
3827 load_spr(ctx, new_spc, sp);
3828 if (is_l) {
3829 copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3830 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3831 }
3832 if (n && use_nullify_skip(ctx)) {
3833 tcg_gen_mov_reg(cpu_iaoq_f, tmp);
3834 tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
3835 tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3836 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3837 } else {
3838 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3839 if (ctx->iaoq_b == -1) {
3840 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3841 }
3842 tcg_gen_mov_reg(cpu_iaoq_b, tmp);
3843 tcg_gen_mov_i64(cpu_iasq_b, new_spc);
3844 nullify_set(ctx, n);
3845 }
3846 tcg_temp_free_i64(new_spc);
3847 tcg_gen_lookup_and_goto_ptr();
3848 return nullify_end(ctx, DISAS_NORETURN);
3849#endif
98cd9ca7
RH
3850}
3851
869051ea
RH
3852static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
3853 const DisasInsn *di)
98cd9ca7
RH
3854{
3855 unsigned n = extract32(insn, 1, 1);
3856 unsigned link = extract32(insn, 21, 5);
eaa3783b 3857 target_sreg disp = assemble_17(insn);
98cd9ca7
RH
3858
3859 return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
3860}
3861
43e05652
RH
3862static DisasJumpType trans_b_gate(DisasContext *ctx, uint32_t insn,
3863 const DisasInsn *di)
3864{
3865 unsigned n = extract32(insn, 1, 1);
3866 unsigned link = extract32(insn, 21, 5);
3867 target_sreg disp = assemble_17(insn);
3868 target_ureg dest = iaoq_dest(ctx, disp);
3869
3870 /* Make sure the caller hasn't done something weird with the queue.
3871 * ??? This is not quite the same as the PSW[B] bit, which would be
3872 * expensive to track. Real hardware will trap for
3873 * b gateway
3874 * b gateway+4 (in delay slot of first branch)
3875 * However, checking for a non-sequential instruction queue *will*
3876 * diagnose the security hole
3877 * b gateway
3878 * b evil
3879 * in which instructions at evil would run with increased privs.
3880 */
3881 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
3882 return gen_illegal(ctx);
3883 }
3884
3885#ifndef CONFIG_USER_ONLY
3886 if (ctx->tb_flags & PSW_C) {
3887 CPUHPPAState *env = ctx->cs->env_ptr;
3888 int type = hppa_artype_for_page(env, ctx->base.pc_next);
3889 /* If we could not find a TLB entry, then we need to generate an
3890 ITLB miss exception so the kernel will provide it.
3891 The resulting TLB fill operation will invalidate this TB and
3892 we will re-translate, at which point we *will* be able to find
3893 the TLB entry and determine if this is in fact a gateway page. */
3894 if (type < 0) {
3895 return gen_excp(ctx, EXCP_ITLB_MISS);
3896 }
3897 /* No change for non-gateway pages or for priv decrease. */
3898 if (type >= 4 && type - 4 < ctx->privilege) {
3899 dest = deposit32(dest, 0, 2, type - 4);
3900 }
3901 } else {
3902 dest &= -4; /* priv = 0 */
3903 }
3904#endif
3905
3906 return do_dbranch(ctx, dest, link, n);
3907}
3908
869051ea
RH
3909static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
3910 const DisasInsn *di)
98cd9ca7
RH
3911{
3912 unsigned n = extract32(insn, 1, 1);
eaa3783b 3913 target_sreg disp = assemble_22(insn);
98cd9ca7
RH
3914
3915 return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
3916}
3917
869051ea
RH
3918static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
3919 const DisasInsn *di)
98cd9ca7
RH
3920{
3921 unsigned n = extract32(insn, 1, 1);
3922 unsigned rx = extract32(insn, 16, 5);
3923 unsigned link = extract32(insn, 21, 5);
eaa3783b 3924 TCGv_reg tmp = get_temp(ctx);
98cd9ca7 3925
eaa3783b
RH
3926 tcg_gen_shli_reg(tmp, load_gpr(ctx, rx), 3);
3927 tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
660eefe1 3928 /* The computation here never changes privilege level. */
98cd9ca7
RH
3929 return do_ibranch(ctx, tmp, link, n);
3930}
3931
869051ea
RH
3932static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
3933 const DisasInsn *di)
98cd9ca7
RH
3934{
3935 unsigned n = extract32(insn, 1, 1);
3936 unsigned rx = extract32(insn, 16, 5);
3937 unsigned rb = extract32(insn, 21, 5);
eaa3783b 3938 TCGv_reg dest;
98cd9ca7
RH
3939
3940 if (rx == 0) {
3941 dest = load_gpr(ctx, rb);
3942 } else {
3943 dest = get_temp(ctx);
eaa3783b
RH
3944 tcg_gen_shli_reg(dest, load_gpr(ctx, rx), 3);
3945 tcg_gen_add_reg(dest, dest, load_gpr(ctx, rb));
98cd9ca7 3946 }
660eefe1 3947 dest = do_ibranch_priv(ctx, dest);
98cd9ca7
RH
3948 return do_ibranch(ctx, dest, 0, n);
3949}
3950
869051ea
RH
3951static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
3952 const DisasInsn *di)
98cd9ca7
RH
3953{
3954 unsigned n = extract32(insn, 1, 1);
3955 unsigned rb = extract32(insn, 21, 5);
3956 unsigned link = extract32(insn, 13, 1) ? 2 : 0;
660eefe1 3957 TCGv_reg dest;
98cd9ca7 3958
c301f34e 3959#ifdef CONFIG_USER_ONLY
660eefe1
RH
3960 dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
3961 return do_ibranch(ctx, dest, link, n);
c301f34e
RH
3962#else
3963 nullify_over(ctx);
3964 dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
3965
3966 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3967 if (ctx->iaoq_b == -1) {
3968 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3969 }
3970 copy_iaoq_entry(cpu_iaoq_b, -1, dest);
3971 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
3972 if (link) {
3973 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
3974 }
3975 nullify_set(ctx, n);
3976 tcg_gen_lookup_and_goto_ptr();
3977 return nullify_end(ctx, DISAS_NORETURN);
3978#endif
98cd9ca7
RH
3979}
3980
3981static const DisasInsn table_branch[] = {
3982 { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3983 { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3984 { 0xe8004000u, 0xfc00fffdu, trans_blr },
3985 { 0xe800c000u, 0xfc00fffdu, trans_bv },
3986 { 0xe800d000u, 0xfc00dffcu, trans_bve },
43e05652 3987 { 0xe8002000u, 0xfc00e000u, trans_b_gate },
98cd9ca7
RH
3988};
3989
869051ea
RH
3990static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3991 const DisasInsn *di)
ebe9383c
RH
3992{
3993 unsigned rt = extract32(insn, 0, 5);
3994 unsigned ra = extract32(insn, 21, 5);
eff235eb 3995 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
3996}
3997
869051ea
RH
3998static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3999 const DisasInsn *di)
ebe9383c
RH
4000{
4001 unsigned rt = assemble_rt64(insn);
4002 unsigned ra = assemble_ra64(insn);
eff235eb 4003 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
4004}
4005
869051ea
RH
4006static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
4007 const DisasInsn *di)
ebe9383c
RH
4008{
4009 unsigned rt = extract32(insn, 0, 5);
4010 unsigned ra = extract32(insn, 21, 5);
eff235eb 4011 return do_fop_ded(ctx, rt, ra, di->f.ded);
ebe9383c
RH
4012}
4013
869051ea
RH
4014static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
4015 const DisasInsn *di)
ebe9383c
RH
4016{
4017 unsigned rt = extract32(insn, 0, 5);
4018 unsigned ra = extract32(insn, 21, 5);
eff235eb 4019 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
4020}
4021
869051ea
RH
4022static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
4023 const DisasInsn *di)
ebe9383c
RH
4024{
4025 unsigned rt = assemble_rt64(insn);
4026 unsigned ra = extract32(insn, 21, 5);
eff235eb 4027 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
4028}
4029
869051ea
RH
4030static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
4031 const DisasInsn *di)
ebe9383c
RH
4032{
4033 unsigned rt = extract32(insn, 0, 5);
4034 unsigned ra = extract32(insn, 21, 5);
eff235eb 4035 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
4036}
4037
869051ea
RH
4038static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
4039 const DisasInsn *di)
ebe9383c
RH
4040{
4041 unsigned rt = extract32(insn, 0, 5);
4042 unsigned ra = assemble_ra64(insn);
eff235eb 4043 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
4044}
4045
869051ea
RH
4046static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
4047 const DisasInsn *di)
ebe9383c
RH
4048{
4049 unsigned rt = extract32(insn, 0, 5);
4050 unsigned rb = extract32(insn, 16, 5);
4051 unsigned ra = extract32(insn, 21, 5);
eff235eb 4052 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
4053}
4054
869051ea
RH
4055static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
4056 const DisasInsn *di)
ebe9383c
RH
4057{
4058 unsigned rt = assemble_rt64(insn);
4059 unsigned rb = assemble_rb64(insn);
4060 unsigned ra = assemble_ra64(insn);
eff235eb 4061 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
4062}
4063
869051ea
RH
4064static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
4065 const DisasInsn *di)
ebe9383c
RH
4066{
4067 unsigned rt = extract32(insn, 0, 5);
4068 unsigned rb = extract32(insn, 16, 5);
4069 unsigned ra = extract32(insn, 21, 5);
eff235eb 4070 return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
ebe9383c
RH
4071}
4072
4073static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4074{
4075 tcg_gen_mov_i32(dst, src);
4076}
4077
4078static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4079{
4080 tcg_gen_mov_i64(dst, src);
4081}
4082
4083static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4084{
4085 tcg_gen_andi_i32(dst, src, INT32_MAX);
4086}
4087
4088static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4089{
4090 tcg_gen_andi_i64(dst, src, INT64_MAX);
4091}
4092
4093static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4094{
4095 tcg_gen_xori_i32(dst, src, INT32_MIN);
4096}
4097
4098static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4099{
4100 tcg_gen_xori_i64(dst, src, INT64_MIN);
4101}
4102
4103static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4104{
4105 tcg_gen_ori_i32(dst, src, INT32_MIN);
4106}
4107
4108static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4109{
4110 tcg_gen_ori_i64(dst, src, INT64_MIN);
4111}
4112
869051ea
RH
4113static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
4114 unsigned y, unsigned c)
ebe9383c
RH
4115{
4116 TCGv_i32 ta, tb, tc, ty;
4117
4118 nullify_over(ctx);
4119
4120 ta = load_frw0_i32(ra);
4121 tb = load_frw0_i32(rb);
4122 ty = tcg_const_i32(y);
4123 tc = tcg_const_i32(c);
4124
4125 gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
4126
4127 tcg_temp_free_i32(ta);
4128 tcg_temp_free_i32(tb);
4129 tcg_temp_free_i32(ty);
4130 tcg_temp_free_i32(tc);
4131
869051ea 4132 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4133}
4134
869051ea
RH
4135static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
4136 const DisasInsn *di)
ebe9383c
RH
4137{
4138 unsigned c = extract32(insn, 0, 5);
4139 unsigned y = extract32(insn, 13, 3);
4140 unsigned rb = extract32(insn, 16, 5);
4141 unsigned ra = extract32(insn, 21, 5);
4142 return do_fcmp_s(ctx, ra, rb, y, c);
4143}
4144
869051ea
RH
4145static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
4146 const DisasInsn *di)
ebe9383c
RH
4147{
4148 unsigned c = extract32(insn, 0, 5);
4149 unsigned y = extract32(insn, 13, 3);
4150 unsigned rb = assemble_rb64(insn);
4151 unsigned ra = assemble_ra64(insn);
4152 return do_fcmp_s(ctx, ra, rb, y, c);
4153}
4154
869051ea
RH
4155static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
4156 const DisasInsn *di)
ebe9383c
RH
4157{
4158 unsigned c = extract32(insn, 0, 5);
4159 unsigned y = extract32(insn, 13, 3);
4160 unsigned rb = extract32(insn, 16, 5);
4161 unsigned ra = extract32(insn, 21, 5);
4162 TCGv_i64 ta, tb;
4163 TCGv_i32 tc, ty;
4164
4165 nullify_over(ctx);
4166
4167 ta = load_frd0(ra);
4168 tb = load_frd0(rb);
4169 ty = tcg_const_i32(y);
4170 tc = tcg_const_i32(c);
4171
4172 gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
4173
4174 tcg_temp_free_i64(ta);
4175 tcg_temp_free_i64(tb);
4176 tcg_temp_free_i32(ty);
4177 tcg_temp_free_i32(tc);
4178
869051ea 4179 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4180}
4181
869051ea
RH
4182static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
4183 const DisasInsn *di)
ebe9383c
RH
4184{
4185 unsigned y = extract32(insn, 13, 3);
4186 unsigned cbit = (y ^ 1) - 1;
eaa3783b 4187 TCGv_reg t;
ebe9383c
RH
4188
4189 nullify_over(ctx);
4190
4191 t = tcg_temp_new();
eaa3783b
RH
4192 tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
4193 tcg_gen_extract_reg(t, t, 21 - cbit, 1);
ebe9383c
RH
4194 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4195 tcg_temp_free(t);
4196
869051ea 4197 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4198}
4199
869051ea
RH
4200static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
4201 const DisasInsn *di)
ebe9383c
RH
4202{
4203 unsigned c = extract32(insn, 0, 5);
4204 int mask;
4205 bool inv = false;
eaa3783b 4206 TCGv_reg t;
ebe9383c
RH
4207
4208 nullify_over(ctx);
4209
4210 t = tcg_temp_new();
eaa3783b 4211 tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
ebe9383c
RH
4212
4213 switch (c) {
4214 case 0: /* simple */
eaa3783b 4215 tcg_gen_andi_reg(t, t, 0x4000000);
ebe9383c
RH
4216 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4217 goto done;
4218 case 2: /* rej */
4219 inv = true;
4220 /* fallthru */
4221 case 1: /* acc */
4222 mask = 0x43ff800;
4223 break;
4224 case 6: /* rej8 */
4225 inv = true;
4226 /* fallthru */
4227 case 5: /* acc8 */
4228 mask = 0x43f8000;
4229 break;
4230 case 9: /* acc6 */
4231 mask = 0x43e0000;
4232 break;
4233 case 13: /* acc4 */
4234 mask = 0x4380000;
4235 break;
4236 case 17: /* acc2 */
4237 mask = 0x4200000;
4238 break;
4239 default:
4240 return gen_illegal(ctx);
4241 }
4242 if (inv) {
eaa3783b
RH
4243 TCGv_reg c = load_const(ctx, mask);
4244 tcg_gen_or_reg(t, t, c);
ebe9383c
RH
4245 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4246 } else {
eaa3783b 4247 tcg_gen_andi_reg(t, t, mask);
ebe9383c
RH
4248 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4249 }
4250 done:
869051ea 4251 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4252}
4253
869051ea
RH
4254static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
4255 const DisasInsn *di)
ebe9383c
RH
4256{
4257 unsigned rt = extract32(insn, 0, 5);
4258 unsigned rb = assemble_rb64(insn);
4259 unsigned ra = assemble_ra64(insn);
4260 TCGv_i64 a, b;
4261
4262 nullify_over(ctx);
4263
4264 a = load_frw0_i64(ra);
4265 b = load_frw0_i64(rb);
4266 tcg_gen_mul_i64(a, a, b);
4267 save_frd(rt, a);
4268 tcg_temp_free_i64(a);
4269 tcg_temp_free_i64(b);
4270
869051ea 4271 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4272}
4273
eff235eb
PB
4274#define FOP_DED trans_fop_ded, .f.ded
4275#define FOP_DEDD trans_fop_dedd, .f.dedd
ebe9383c 4276
eff235eb
PB
4277#define FOP_WEW trans_fop_wew_0c, .f.wew
4278#define FOP_DEW trans_fop_dew_0c, .f.dew
4279#define FOP_WED trans_fop_wed_0c, .f.wed
4280#define FOP_WEWW trans_fop_weww_0c, .f.weww
ebe9383c
RH
4281
4282static const DisasInsn table_float_0c[] = {
4283 /* floating point class zero */
4284 { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
4285 { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
4286 { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
4287 { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
4288 { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
4289 { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
4290
4291 { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
4292 { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4293 { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4294 { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4295 { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4296 { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4297
4298 /* floating point class three */
4299 { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
4300 { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
4301 { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
4302 { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
4303
4304 { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4305 { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4306 { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4307 { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4308
4309 /* floating point class one */
4310 /* float/float */
4311 { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
4312 { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
4313 /* int/float */
4314 { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
4315 { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
4316 { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
4317 { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4318 /* float/int */
4319 { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
4320 { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
4321 { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
4322 { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4323 /* float/int truncate */
4324 { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
4325 { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
4326 { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
4327 { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4328 /* uint/float */
4329 { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
4330 { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
4331 { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
4332 { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4333 /* float/uint */
4334 { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
4335 { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
4336 { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
4337 { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4338 /* float/uint truncate */
4339 { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
4340 { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
4341 { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
4342 { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4343
4344 /* floating point class two */
4345 { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
4346 { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
4347 { 0x30002420, 0xffffffe0, trans_ftest_q },
4348 { 0x30000420, 0xffff1fff, trans_ftest_t },
4349
4350 /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
4351 This is machine/revision == 0, which is reserved for simulator. */
4352 { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
4353};
4354
4355#undef FOP_WEW
4356#undef FOP_DEW
4357#undef FOP_WED
4358#undef FOP_WEWW
eff235eb
PB
4359#define FOP_WEW trans_fop_wew_0e, .f.wew
4360#define FOP_DEW trans_fop_dew_0e, .f.dew
4361#define FOP_WED trans_fop_wed_0e, .f.wed
4362#define FOP_WEWW trans_fop_weww_0e, .f.weww
ebe9383c
RH
4363
4364static const DisasInsn table_float_0e[] = {
4365 /* floating point class zero */
4366 { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
4367 { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
4368 { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
4369 { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
4370 { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
4371 { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
4372
4373 { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
4374 { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4375 { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4376 { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4377 { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4378 { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4379
4380 /* floating point class three */
4381 { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
4382 { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
4383 { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
4384 { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
4385
4386 { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4387 { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4388 { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4389 { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4390
4391 { 0x38004700, 0xfc00ef60, trans_xmpyu },
4392
4393 /* floating point class one */
4394 /* float/float */
4395 { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
fe0a69cc 4396 { 0x38002200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_d },
ebe9383c 4397 /* int/float */
fe0a69cc 4398 { 0x38008200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_w_s },
ebe9383c
RH
4399 { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
4400 { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
4401 { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4402 /* float/int */
fe0a69cc 4403 { 0x38010200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_w },
ebe9383c
RH
4404 { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
4405 { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
4406 { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4407 /* float/int truncate */
fe0a69cc 4408 { 0x38018200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_w },
ebe9383c
RH
4409 { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
4410 { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
4411 { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4412 /* uint/float */
fe0a69cc 4413 { 0x38028200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_uw_s },
ebe9383c
RH
4414 { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
4415 { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
4416 { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4417 /* float/uint */
fe0a69cc 4418 { 0x38030200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_uw },
ebe9383c
RH
4419 { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
4420 { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
4421 { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4422 /* float/uint truncate */
fe0a69cc 4423 { 0x38038200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_uw },
ebe9383c
RH
4424 { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
4425 { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
4426 { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4427
4428 /* floating point class two */
4429 { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
4430 { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
4431};
4432
4433#undef FOP_WEW
4434#undef FOP_DEW
4435#undef FOP_WED
4436#undef FOP_WEWW
4437#undef FOP_DED
4438#undef FOP_DEDD
4439
4440/* Convert the fmpyadd single-precision register encodings to standard. */
4441static inline int fmpyadd_s_reg(unsigned r)
4442{
4443 return (r & 16) * 2 + 16 + (r & 15);
4444}
4445
869051ea
RH
4446static DisasJumpType trans_fmpyadd(DisasContext *ctx,
4447 uint32_t insn, bool is_sub)
ebe9383c
RH
4448{
4449 unsigned tm = extract32(insn, 0, 5);
4450 unsigned f = extract32(insn, 5, 1);
4451 unsigned ra = extract32(insn, 6, 5);
4452 unsigned ta = extract32(insn, 11, 5);
4453 unsigned rm2 = extract32(insn, 16, 5);
4454 unsigned rm1 = extract32(insn, 21, 5);
4455
4456 nullify_over(ctx);
4457
4458 /* Independent multiply & add/sub, with undefined behaviour
4459 if outputs overlap inputs. */
4460 if (f == 0) {
4461 tm = fmpyadd_s_reg(tm);
4462 ra = fmpyadd_s_reg(ra);
4463 ta = fmpyadd_s_reg(ta);
4464 rm2 = fmpyadd_s_reg(rm2);
4465 rm1 = fmpyadd_s_reg(rm1);
4466 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4467 do_fop_weww(ctx, ta, ta, ra,
4468 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4469 } else {
4470 do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
4471 do_fop_dedd(ctx, ta, ta, ra,
4472 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4473 }
4474
869051ea 4475 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4476}
4477
869051ea
RH
4478static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
4479 const DisasInsn *di)
ebe9383c
RH
4480{
4481 unsigned rt = assemble_rt64(insn);
4482 unsigned neg = extract32(insn, 5, 1);
4483 unsigned rm1 = assemble_ra64(insn);
4484 unsigned rm2 = assemble_rb64(insn);
4485 unsigned ra3 = assemble_rc64(insn);
4486 TCGv_i32 a, b, c;
4487
4488 nullify_over(ctx);
4489 a = load_frw0_i32(rm1);
4490 b = load_frw0_i32(rm2);
4491 c = load_frw0_i32(ra3);
4492
4493 if (neg) {
4494 gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
4495 } else {
4496 gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
4497 }
4498
4499 tcg_temp_free_i32(b);
4500 tcg_temp_free_i32(c);
4501 save_frw_i32(rt, a);
4502 tcg_temp_free_i32(a);
869051ea 4503 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4504}
4505
869051ea
RH
4506static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
4507 const DisasInsn *di)
ebe9383c
RH
4508{
4509 unsigned rt = extract32(insn, 0, 5);
4510 unsigned neg = extract32(insn, 5, 1);
4511 unsigned rm1 = extract32(insn, 21, 5);
4512 unsigned rm2 = extract32(insn, 16, 5);
4513 unsigned ra3 = assemble_rc64(insn);
4514 TCGv_i64 a, b, c;
4515
4516 nullify_over(ctx);
4517 a = load_frd0(rm1);
4518 b = load_frd0(rm2);
4519 c = load_frd0(ra3);
4520
4521 if (neg) {
4522 gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
4523 } else {
4524 gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
4525 }
4526
4527 tcg_temp_free_i64(b);
4528 tcg_temp_free_i64(c);
4529 save_frd(rt, a);
4530 tcg_temp_free_i64(a);
869051ea 4531 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4532}
4533
4534static const DisasInsn table_fp_fused[] = {
4535 { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
4536 { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
4537};
4538
869051ea
RH
4539static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
4540 const DisasInsn table[], size_t n)
61766fe9
RH
4541{
4542 size_t i;
4543 for (i = 0; i < n; ++i) {
4544 if ((insn & table[i].mask) == table[i].insn) {
4545 return table[i].trans(ctx, insn, &table[i]);
4546 }
4547 }
b36942a6
RH
4548 qemu_log_mask(LOG_UNIMP, "UNIMP insn %08x @ " TARGET_FMT_lx "\n",
4549 insn, ctx->base.pc_next);
61766fe9
RH
4550 return gen_illegal(ctx);
4551}
4552
4553#define translate_table(ctx, insn, table) \
4554 translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
4555
869051ea 4556static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
61766fe9
RH
4557{
4558 uint32_t opc = extract32(insn, 26, 6);
4559
4560 switch (opc) {
98a9cb79
RH
4561 case 0x00: /* system op */
4562 return translate_table(ctx, insn, table_system);
4563 case 0x01:
4564 return translate_table(ctx, insn, table_mem_mgmt);
b2167459
RH
4565 case 0x02:
4566 return translate_table(ctx, insn, table_arith_log);
96d6407f
RH
4567 case 0x03:
4568 return translate_table(ctx, insn, table_index_mem);
ebe9383c
RH
4569 case 0x06:
4570 return trans_fmpyadd(ctx, insn, false);
b2167459
RH
4571 case 0x08:
4572 return trans_ldil(ctx, insn);
96d6407f
RH
4573 case 0x09:
4574 return trans_copr_w(ctx, insn);
b2167459
RH
4575 case 0x0A:
4576 return trans_addil(ctx, insn);
96d6407f
RH
4577 case 0x0B:
4578 return trans_copr_dw(ctx, insn);
ebe9383c
RH
4579 case 0x0C:
4580 return translate_table(ctx, insn, table_float_0c);
b2167459
RH
4581 case 0x0D:
4582 return trans_ldo(ctx, insn);
ebe9383c
RH
4583 case 0x0E:
4584 return translate_table(ctx, insn, table_float_0e);
96d6407f
RH
4585
4586 case 0x10:
4587 return trans_load(ctx, insn, false, MO_UB);
4588 case 0x11:
4589 return trans_load(ctx, insn, false, MO_TEUW);
4590 case 0x12:
4591 return trans_load(ctx, insn, false, MO_TEUL);
4592 case 0x13:
4593 return trans_load(ctx, insn, true, MO_TEUL);
4594 case 0x16:
4595 return trans_fload_mod(ctx, insn);
4596 case 0x17:
4597 return trans_load_w(ctx, insn);
4598 case 0x18:
4599 return trans_store(ctx, insn, false, MO_UB);
4600 case 0x19:
4601 return trans_store(ctx, insn, false, MO_TEUW);
4602 case 0x1A:
4603 return trans_store(ctx, insn, false, MO_TEUL);
4604 case 0x1B:
4605 return trans_store(ctx, insn, true, MO_TEUL);
4606 case 0x1E:
4607 return trans_fstore_mod(ctx, insn);
4608 case 0x1F:
4609 return trans_store_w(ctx, insn);
4610
98cd9ca7
RH
4611 case 0x20:
4612 return trans_cmpb(ctx, insn, true, false, false);
4613 case 0x21:
4614 return trans_cmpb(ctx, insn, true, true, false);
4615 case 0x22:
4616 return trans_cmpb(ctx, insn, false, false, false);
4617 case 0x23:
4618 return trans_cmpb(ctx, insn, false, true, false);
b2167459
RH
4619 case 0x24:
4620 return trans_cmpiclr(ctx, insn);
4621 case 0x25:
4622 return trans_subi(ctx, insn);
ebe9383c
RH
4623 case 0x26:
4624 return trans_fmpyadd(ctx, insn, true);
98cd9ca7
RH
4625 case 0x27:
4626 return trans_cmpb(ctx, insn, true, false, true);
4627 case 0x28:
4628 return trans_addb(ctx, insn, true, false);
4629 case 0x29:
4630 return trans_addb(ctx, insn, true, true);
4631 case 0x2A:
4632 return trans_addb(ctx, insn, false, false);
4633 case 0x2B:
4634 return trans_addb(ctx, insn, false, true);
b2167459
RH
4635 case 0x2C:
4636 case 0x2D:
4637 return trans_addi(ctx, insn);
ebe9383c
RH
4638 case 0x2E:
4639 return translate_table(ctx, insn, table_fp_fused);
98cd9ca7
RH
4640 case 0x2F:
4641 return trans_cmpb(ctx, insn, false, false, true);
96d6407f 4642
98cd9ca7
RH
4643 case 0x30:
4644 case 0x31:
4645 return trans_bb(ctx, insn);
4646 case 0x32:
4647 return trans_movb(ctx, insn, false);
4648 case 0x33:
4649 return trans_movb(ctx, insn, true);
0b1347d2
RH
4650 case 0x34:
4651 return translate_table(ctx, insn, table_sh_ex);
4652 case 0x35:
4653 return translate_table(ctx, insn, table_depw);
98cd9ca7
RH
4654 case 0x38:
4655 return trans_be(ctx, insn, false);
4656 case 0x39:
4657 return trans_be(ctx, insn, true);
4658 case 0x3A:
4659 return translate_table(ctx, insn, table_branch);
96d6407f
RH
4660
4661 case 0x04: /* spopn */
4662 case 0x05: /* diag */
4663 case 0x0F: /* product specific */
4664 break;
4665
4666 case 0x07: /* unassigned */
4667 case 0x15: /* unassigned */
4668 case 0x1D: /* unassigned */
4669 case 0x37: /* unassigned */
6210db05
HD
4670 break;
4671 case 0x3F:
4672#ifndef CONFIG_USER_ONLY
4673 /* Unassigned, but use as system-halt. */
4674 if (insn == 0xfffdead0) {
4675 return gen_hlt(ctx, 0); /* halt system */
4676 }
4677 if (insn == 0xfffdead1) {
4678 return gen_hlt(ctx, 1); /* reset system */
4679 }
4680#endif
4681 break;
61766fe9
RH
4682 default:
4683 break;
4684 }
4685 return gen_illegal(ctx);
4686}
4687
51b061fb
RH
4688static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
4689 CPUState *cs, int max_insns)
61766fe9 4690{
51b061fb 4691 DisasContext *ctx = container_of(dcbase, DisasContext, base);
f764718d 4692 int bound;
61766fe9 4693
51b061fb 4694 ctx->cs = cs;
494737b7 4695 ctx->tb_flags = ctx->base.tb->flags;
3d68ee7b
RH
4696
4697#ifdef CONFIG_USER_ONLY
4698 ctx->privilege = MMU_USER_IDX;
4699 ctx->mmu_idx = MMU_USER_IDX;
c301f34e
RH
4700 ctx->iaoq_f = ctx->base.pc_first;
4701 ctx->iaoq_b = ctx->base.tb->cs_base;
3d68ee7b 4702#else
494737b7
RH
4703 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4704 ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX);
3d68ee7b 4705
c301f34e
RH
4706 /* Recover the IAOQ values from the GVA + PRIV. */
4707 uint64_t cs_base = ctx->base.tb->cs_base;
4708 uint64_t iasq_f = cs_base & ~0xffffffffull;
4709 int32_t diff = cs_base;
4710
4711 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4712 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4713#endif
51b061fb 4714 ctx->iaoq_n = -1;
f764718d 4715 ctx->iaoq_n_var = NULL;
61766fe9 4716
3d68ee7b
RH
4717 /* Bound the number of instructions by those left on the page. */
4718 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4719 bound = MIN(max_insns, bound);
4720
86f8d05f
RH
4721 ctx->ntempr = 0;
4722 ctx->ntempl = 0;
4723 memset(ctx->tempr, 0, sizeof(ctx->tempr));
4724 memset(ctx->templ, 0, sizeof(ctx->templ));
61766fe9 4725
3d68ee7b 4726 return bound;
51b061fb 4727}
61766fe9 4728
51b061fb
RH
4729static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
4730{
4731 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4732
3d68ee7b 4733 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
51b061fb
RH
4734 ctx->null_cond = cond_make_f();
4735 ctx->psw_n_nonzero = false;
494737b7 4736 if (ctx->tb_flags & PSW_N) {
51b061fb
RH
4737 ctx->null_cond.c = TCG_COND_ALWAYS;
4738 ctx->psw_n_nonzero = true;
129e9cc3 4739 }
51b061fb
RH
4740 ctx->null_lab = NULL;
4741}
129e9cc3 4742
51b061fb
RH
4743static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
4744{
4745 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4746
51b061fb
RH
4747 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
4748}
4749
4750static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
4751 const CPUBreakpoint *bp)
4752{
4753 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4754
51b061fb 4755 ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
c301f34e 4756 ctx->base.pc_next += 4;
51b061fb
RH
4757 return true;
4758}
4759
4760static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
4761{
4762 DisasContext *ctx = container_of(dcbase, DisasContext, base);
4763 CPUHPPAState *env = cs->env_ptr;
4764 DisasJumpType ret;
4765 int i, n;
4766
4767 /* Execute one insn. */
ba1d0b44 4768#ifdef CONFIG_USER_ONLY
c301f34e 4769 if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
51b061fb
RH
4770 ret = do_page_zero(ctx);
4771 assert(ret != DISAS_NEXT);
ba1d0b44
RH
4772 } else
4773#endif
4774 {
51b061fb
RH
4775 /* Always fetch the insn, even if nullified, so that we check
4776 the page permissions for execute. */
c301f34e 4777 uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
51b061fb
RH
4778
4779 /* Set up the IA queue for the next insn.
4780 This will be overwritten by a branch. */
4781 if (ctx->iaoq_b == -1) {
4782 ctx->iaoq_n = -1;
4783 ctx->iaoq_n_var = get_temp(ctx);
eaa3783b 4784 tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
7ad439df 4785 } else {
51b061fb 4786 ctx->iaoq_n = ctx->iaoq_b + 4;
f764718d 4787 ctx->iaoq_n_var = NULL;
61766fe9
RH
4788 }
4789
51b061fb
RH
4790 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
4791 ctx->null_cond.c = TCG_COND_NEVER;
4792 ret = DISAS_NEXT;
4793 } else {
1a19da0d 4794 ctx->insn = insn;
51b061fb
RH
4795 ret = translate_one(ctx, insn);
4796 assert(ctx->null_lab == NULL);
61766fe9 4797 }
51b061fb 4798 }
61766fe9 4799
51b061fb 4800 /* Free any temporaries allocated. */
86f8d05f
RH
4801 for (i = 0, n = ctx->ntempr; i < n; ++i) {
4802 tcg_temp_free(ctx->tempr[i]);
4803 ctx->tempr[i] = NULL;
4804 }
4805 for (i = 0, n = ctx->ntempl; i < n; ++i) {
4806 tcg_temp_free_tl(ctx->templ[i]);
4807 ctx->templ[i] = NULL;
51b061fb 4808 }
86f8d05f
RH
4809 ctx->ntempr = 0;
4810 ctx->ntempl = 0;
61766fe9 4811
3d68ee7b
RH
4812 /* Advance the insn queue. Note that this check also detects
4813 a priority change within the instruction queue. */
51b061fb 4814 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
c301f34e
RH
4815 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4816 && use_goto_tb(ctx, ctx->iaoq_b)
4817 && (ctx->null_cond.c == TCG_COND_NEVER
4818 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
51b061fb
RH
4819 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4820 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
4821 ret = DISAS_NORETURN;
4822 } else {
4823 ret = DISAS_IAQ_N_STALE;
c301f34e 4824 }
61766fe9 4825 }
51b061fb
RH
4826 ctx->iaoq_f = ctx->iaoq_b;
4827 ctx->iaoq_b = ctx->iaoq_n;
4828 ctx->base.is_jmp = ret;
c301f34e 4829 ctx->base.pc_next += 4;
51b061fb
RH
4830
4831 if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
4832 return;
4833 }
4834 if (ctx->iaoq_f == -1) {
eaa3783b 4835 tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b);
51b061fb 4836 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e
RH
4837#ifndef CONFIG_USER_ONLY
4838 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4839#endif
51b061fb
RH
4840 nullify_save(ctx);
4841 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
4842 } else if (ctx->iaoq_b == -1) {
eaa3783b 4843 tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var);
51b061fb
RH
4844 }
4845}
4846
4847static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
4848{
4849 DisasContext *ctx = container_of(dcbase, DisasContext, base);
e1b5a5ed 4850 DisasJumpType is_jmp = ctx->base.is_jmp;
61766fe9 4851
e1b5a5ed 4852 switch (is_jmp) {
869051ea 4853 case DISAS_NORETURN:
61766fe9 4854 break;
51b061fb 4855 case DISAS_TOO_MANY:
869051ea 4856 case DISAS_IAQ_N_STALE:
e1b5a5ed 4857 case DISAS_IAQ_N_STALE_EXIT:
51b061fb
RH
4858 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4859 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
4860 nullify_save(ctx);
61766fe9 4861 /* FALLTHRU */
869051ea 4862 case DISAS_IAQ_N_UPDATED:
51b061fb 4863 if (ctx->base.singlestep_enabled) {
61766fe9 4864 gen_excp_1(EXCP_DEBUG);
e1b5a5ed
RH
4865 } else if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4866 tcg_gen_exit_tb(0);
61766fe9 4867 } else {
7f11636d 4868 tcg_gen_lookup_and_goto_ptr();
61766fe9
RH
4869 }
4870 break;
4871 default:
51b061fb 4872 g_assert_not_reached();
61766fe9 4873 }
51b061fb 4874}
61766fe9 4875
51b061fb
RH
4876static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
4877{
c301f34e 4878 target_ulong pc = dcbase->pc_first;
61766fe9 4879
ba1d0b44
RH
4880#ifdef CONFIG_USER_ONLY
4881 switch (pc) {
51b061fb
RH
4882 case 0x00:
4883 qemu_log("IN:\n0x00000000: (null)\n");
ba1d0b44 4884 return;
51b061fb
RH
4885 case 0xb0:
4886 qemu_log("IN:\n0x000000b0: light-weight-syscall\n");
ba1d0b44 4887 return;
51b061fb
RH
4888 case 0xe0:
4889 qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n");
ba1d0b44 4890 return;
51b061fb
RH
4891 case 0x100:
4892 qemu_log("IN:\n0x00000100: syscall\n");
ba1d0b44 4893 return;
61766fe9 4894 }
ba1d0b44
RH
4895#endif
4896
4897 qemu_log("IN: %s\n", lookup_symbol(pc));
eaa3783b 4898 log_target_disas(cs, pc, dcbase->tb->size);
51b061fb
RH
4899}
4900
4901static const TranslatorOps hppa_tr_ops = {
4902 .init_disas_context = hppa_tr_init_disas_context,
4903 .tb_start = hppa_tr_tb_start,
4904 .insn_start = hppa_tr_insn_start,
4905 .breakpoint_check = hppa_tr_breakpoint_check,
4906 .translate_insn = hppa_tr_translate_insn,
4907 .tb_stop = hppa_tr_tb_stop,
4908 .disas_log = hppa_tr_disas_log,
4909};
4910
4911void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
4912
4913{
4914 DisasContext ctx;
4915 translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
61766fe9
RH
4916}
4917
4918void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
4919 target_ulong *data)
4920{
4921 env->iaoq_f = data[0];
86f8d05f 4922 if (data[1] != (target_ureg)-1) {
61766fe9
RH
4923 env->iaoq_b = data[1];
4924 }
4925 /* Since we were executing the instruction at IAOQ_F, and took some
4926 sort of action that provoked the cpu_restore_state, we can infer
4927 that the instruction was not nullified. */
4928 env->psw_n = 0;
4929}
This page took 0.767841 seconds and 4 git commands to generate.