]> Git Repo - qemu.git/blame - target/hppa/translate.c
hw/hppa: Add MAINTAINERS entry
[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);
98a9cb79
RH
2383 unsigned rb = extract32(insn, 21, 5);
2384 unsigned is_write = extract32(insn, 6, 1);
86f8d05f
RH
2385 TCGv_reg dest, ofs;
2386 TCGv_tl addr;
98a9cb79
RH
2387
2388 nullify_over(ctx);
2389
2390 /* ??? Do something with priv level operand. */
2391 dest = dest_gpr(ctx, rt);
86f8d05f 2392 form_gva(ctx, &addr, &ofs, rb, 0, 0, 0, sp, 0, false);
98a9cb79 2393 if (is_write) {
86f8d05f 2394 gen_helper_probe_w(dest, addr);
98a9cb79 2395 } else {
86f8d05f 2396 gen_helper_probe_r(dest, addr);
98a9cb79
RH
2397 }
2398 save_gpr(ctx, rt, dest);
869051ea 2399 return nullify_end(ctx, DISAS_NEXT);
98a9cb79
RH
2400}
2401
8d6ae7fb
RH
2402#ifndef CONFIG_USER_ONLY
2403static DisasJumpType trans_ixtlbx(DisasContext *ctx, uint32_t insn,
2404 const DisasInsn *di)
2405{
2406 unsigned sp;
2407 unsigned rr = extract32(insn, 16, 5);
2408 unsigned rb = extract32(insn, 21, 5);
2409 unsigned is_data = insn & 0x1000;
2410 unsigned is_addr = insn & 0x40;
2411 TCGv_tl addr;
2412 TCGv_reg ofs, reg;
2413
2414 if (is_data) {
2415 sp = extract32(insn, 14, 2);
2416 } else {
2417 sp = ~assemble_sr3(insn);
2418 }
2419
2420 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2421 nullify_over(ctx);
2422
2423 form_gva(ctx, &addr, &ofs, rb, 0, 0, 0, sp, 0, false);
2424 reg = load_gpr(ctx, rr);
2425 if (is_addr) {
2426 gen_helper_itlba(cpu_env, addr, reg);
2427 } else {
2428 gen_helper_itlbp(cpu_env, addr, reg);
2429 }
2430
2431 /* Exit TB for ITLB change if mmu is enabled. This *should* not be
2432 the case, since the OS TLB fill handler runs with mmu disabled. */
494737b7 2433 return nullify_end(ctx, !is_data && (ctx->tb_flags & PSW_C)
8d6ae7fb
RH
2434 ? DISAS_IAQ_N_STALE : DISAS_NEXT);
2435}
63300a00
RH
2436
2437static DisasJumpType trans_pxtlbx(DisasContext *ctx, uint32_t insn,
2438 const DisasInsn *di)
2439{
2440 unsigned m = extract32(insn, 5, 1);
2441 unsigned sp;
2442 unsigned rx = extract32(insn, 16, 5);
2443 unsigned rb = extract32(insn, 21, 5);
2444 unsigned is_data = insn & 0x1000;
2445 unsigned is_local = insn & 0x40;
2446 TCGv_tl addr;
2447 TCGv_reg ofs;
2448
2449 if (is_data) {
2450 sp = extract32(insn, 14, 2);
2451 } else {
2452 sp = ~assemble_sr3(insn);
2453 }
2454
2455 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2456 nullify_over(ctx);
2457
2458 form_gva(ctx, &addr, &ofs, rb, rx, 0, 0, sp, m, false);
2459 if (m) {
2460 save_gpr(ctx, rb, ofs);
2461 }
2462 if (is_local) {
2463 gen_helper_ptlbe(cpu_env);
2464 } else {
2465 gen_helper_ptlb(cpu_env, addr);
2466 }
2467
2468 /* Exit TB for TLB change if mmu is enabled. */
494737b7 2469 return nullify_end(ctx, !is_data && (ctx->tb_flags & PSW_C)
63300a00
RH
2470 ? DISAS_IAQ_N_STALE : DISAS_NEXT);
2471}
2dfcca9f
RH
2472
2473static DisasJumpType trans_lpa(DisasContext *ctx, uint32_t insn,
2474 const DisasInsn *di)
2475{
2476 unsigned rt = extract32(insn, 0, 5);
2477 unsigned m = extract32(insn, 5, 1);
2478 unsigned sp = extract32(insn, 14, 2);
2479 unsigned rx = extract32(insn, 16, 5);
2480 unsigned rb = extract32(insn, 21, 5);
2481 TCGv_tl vaddr;
2482 TCGv_reg ofs, paddr;
2483
2484 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2485 nullify_over(ctx);
2486
2487 form_gva(ctx, &vaddr, &ofs, rb, rx, 0, 0, sp, m, false);
2488
2489 paddr = tcg_temp_new();
2490 gen_helper_lpa(paddr, cpu_env, vaddr);
2491
2492 /* Note that physical address result overrides base modification. */
2493 if (m) {
2494 save_gpr(ctx, rb, ofs);
2495 }
2496 save_gpr(ctx, rt, paddr);
2497 tcg_temp_free(paddr);
2498
2499 return nullify_end(ctx, DISAS_NEXT);
2500}
43a97b81
RH
2501
2502static DisasJumpType trans_lci(DisasContext *ctx, uint32_t insn,
2503 const DisasInsn *di)
2504{
2505 unsigned rt = extract32(insn, 0, 5);
2506 TCGv_reg ci;
2507
2508 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2509
2510 /* The Coherence Index is an implementation-defined function of the
2511 physical address. Two addresses with the same CI have a coherent
2512 view of the cache. Our implementation is to return 0 for all,
2513 since the entire address space is coherent. */
2514 ci = tcg_const_reg(0);
2515 save_gpr(ctx, rt, ci);
2516 tcg_temp_free(ci);
2517
2518 return DISAS_NEXT;
2519}
8d6ae7fb
RH
2520#endif /* !CONFIG_USER_ONLY */
2521
98a9cb79
RH
2522static const DisasInsn table_mem_mgmt[] = {
2523 { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */
2524 { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */
2525 { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
2526 { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */
2527 { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
2528 { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */
2529 { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
2530 { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */
2531 { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
2532 { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */
2533 { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
2534 { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */
2535 { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
2536 { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */
2537 { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */
8d6ae7fb
RH
2538#ifndef CONFIG_USER_ONLY
2539 { 0x04000000u, 0xfc001fffu, trans_ixtlbx }, /* iitlbp */
2540 { 0x04000040u, 0xfc001fffu, trans_ixtlbx }, /* iitlba */
2541 { 0x04001000u, 0xfc001fffu, trans_ixtlbx }, /* idtlbp */
2542 { 0x04001040u, 0xfc001fffu, trans_ixtlbx }, /* idtlba */
63300a00
RH
2543 { 0x04000200u, 0xfc001fdfu, trans_pxtlbx }, /* pitlb */
2544 { 0x04000240u, 0xfc001fdfu, trans_pxtlbx }, /* pitlbe */
2545 { 0x04001200u, 0xfc001fdfu, trans_pxtlbx }, /* pdtlb */
2546 { 0x04001240u, 0xfc001fdfu, trans_pxtlbx }, /* pdtlbe */
2dfcca9f 2547 { 0x04001340u, 0xfc003fc0u, trans_lpa },
43a97b81 2548 { 0x04001300u, 0xfc003fe0u, trans_lci },
8d6ae7fb 2549#endif
98a9cb79
RH
2550};
2551
869051ea
RH
2552static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
2553 const DisasInsn *di)
b2167459
RH
2554{
2555 unsigned r2 = extract32(insn, 21, 5);
2556 unsigned r1 = extract32(insn, 16, 5);
2557 unsigned cf = extract32(insn, 12, 4);
2558 unsigned ext = extract32(insn, 8, 4);
2559 unsigned shift = extract32(insn, 6, 2);
2560 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2561 TCGv_reg tcg_r1, tcg_r2;
b2167459
RH
2562 bool is_c = false;
2563 bool is_l = false;
2564 bool is_tc = false;
2565 bool is_tsv = false;
869051ea 2566 DisasJumpType ret;
b2167459
RH
2567
2568 switch (ext) {
2569 case 0x6: /* ADD, SHLADD */
2570 break;
2571 case 0xa: /* ADD,L, SHLADD,L */
2572 is_l = true;
2573 break;
2574 case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
2575 is_tsv = true;
2576 break;
2577 case 0x7: /* ADD,C */
2578 is_c = true;
2579 break;
2580 case 0xf: /* ADD,C,TSV */
2581 is_c = is_tsv = true;
2582 break;
2583 default:
2584 return gen_illegal(ctx);
2585 }
2586
2587 if (cf) {
2588 nullify_over(ctx);
2589 }
2590 tcg_r1 = load_gpr(ctx, r1);
2591 tcg_r2 = load_gpr(ctx, r2);
2592 ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
2593 return nullify_end(ctx, ret);
2594}
2595
869051ea
RH
2596static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
2597 const DisasInsn *di)
b2167459
RH
2598{
2599 unsigned r2 = extract32(insn, 21, 5);
2600 unsigned r1 = extract32(insn, 16, 5);
2601 unsigned cf = extract32(insn, 12, 4);
2602 unsigned ext = extract32(insn, 6, 6);
2603 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2604 TCGv_reg tcg_r1, tcg_r2;
b2167459
RH
2605 bool is_b = false;
2606 bool is_tc = false;
2607 bool is_tsv = false;
869051ea 2608 DisasJumpType ret;
b2167459
RH
2609
2610 switch (ext) {
2611 case 0x10: /* SUB */
2612 break;
2613 case 0x30: /* SUB,TSV */
2614 is_tsv = true;
2615 break;
2616 case 0x14: /* SUB,B */
2617 is_b = true;
2618 break;
2619 case 0x34: /* SUB,B,TSV */
2620 is_b = is_tsv = true;
2621 break;
2622 case 0x13: /* SUB,TC */
2623 is_tc = true;
2624 break;
2625 case 0x33: /* SUB,TSV,TC */
2626 is_tc = is_tsv = true;
2627 break;
2628 default:
2629 return gen_illegal(ctx);
2630 }
2631
2632 if (cf) {
2633 nullify_over(ctx);
2634 }
2635 tcg_r1 = load_gpr(ctx, r1);
2636 tcg_r2 = load_gpr(ctx, r2);
2637 ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
2638 return nullify_end(ctx, ret);
2639}
2640
869051ea
RH
2641static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
2642 const DisasInsn *di)
b2167459
RH
2643{
2644 unsigned r2 = extract32(insn, 21, 5);
2645 unsigned r1 = extract32(insn, 16, 5);
2646 unsigned cf = extract32(insn, 12, 4);
2647 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2648 TCGv_reg tcg_r1, tcg_r2;
869051ea 2649 DisasJumpType ret;
b2167459
RH
2650
2651 if (cf) {
2652 nullify_over(ctx);
2653 }
2654 tcg_r1 = load_gpr(ctx, r1);
2655 tcg_r2 = load_gpr(ctx, r2);
eff235eb 2656 ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
b2167459
RH
2657 return nullify_end(ctx, ret);
2658}
2659
2660/* OR r,0,t -> COPY (according to gas) */
869051ea
RH
2661static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
2662 const DisasInsn *di)
b2167459
RH
2663{
2664 unsigned r1 = extract32(insn, 16, 5);
2665 unsigned rt = extract32(insn, 0, 5);
2666
2667 if (r1 == 0) {
eaa3783b
RH
2668 TCGv_reg dest = dest_gpr(ctx, rt);
2669 tcg_gen_movi_reg(dest, 0);
b2167459
RH
2670 save_gpr(ctx, rt, dest);
2671 } else {
2672 save_gpr(ctx, rt, cpu_gr[r1]);
2673 }
2674 cond_free(&ctx->null_cond);
869051ea 2675 return DISAS_NEXT;
b2167459
RH
2676}
2677
869051ea
RH
2678static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
2679 const DisasInsn *di)
b2167459
RH
2680{
2681 unsigned r2 = extract32(insn, 21, 5);
2682 unsigned r1 = extract32(insn, 16, 5);
2683 unsigned cf = extract32(insn, 12, 4);
2684 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2685 TCGv_reg tcg_r1, tcg_r2;
869051ea 2686 DisasJumpType ret;
b2167459
RH
2687
2688 if (cf) {
2689 nullify_over(ctx);
2690 }
2691 tcg_r1 = load_gpr(ctx, r1);
2692 tcg_r2 = load_gpr(ctx, r2);
2693 ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
2694 return nullify_end(ctx, ret);
2695}
2696
869051ea
RH
2697static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
2698 const DisasInsn *di)
b2167459
RH
2699{
2700 unsigned r2 = extract32(insn, 21, 5);
2701 unsigned r1 = extract32(insn, 16, 5);
2702 unsigned cf = extract32(insn, 12, 4);
2703 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2704 TCGv_reg tcg_r1, tcg_r2;
869051ea 2705 DisasJumpType ret;
b2167459
RH
2706
2707 if (cf) {
2708 nullify_over(ctx);
2709 }
2710 tcg_r1 = load_gpr(ctx, r1);
2711 tcg_r2 = load_gpr(ctx, r2);
eaa3783b 2712 ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_reg);
b2167459
RH
2713 return nullify_end(ctx, ret);
2714}
2715
869051ea
RH
2716static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
2717 const DisasInsn *di)
b2167459
RH
2718{
2719 unsigned r2 = extract32(insn, 21, 5);
2720 unsigned r1 = extract32(insn, 16, 5);
2721 unsigned cf = extract32(insn, 12, 4);
2722 unsigned is_tc = extract32(insn, 6, 1);
2723 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2724 TCGv_reg tcg_r1, tcg_r2, tmp;
869051ea 2725 DisasJumpType ret;
b2167459
RH
2726
2727 if (cf) {
2728 nullify_over(ctx);
2729 }
2730 tcg_r1 = load_gpr(ctx, r1);
2731 tcg_r2 = load_gpr(ctx, r2);
2732 tmp = get_temp(ctx);
eaa3783b
RH
2733 tcg_gen_not_reg(tmp, tcg_r2);
2734 ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_reg);
b2167459
RH
2735 return nullify_end(ctx, ret);
2736}
2737
869051ea
RH
2738static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
2739 const DisasInsn *di)
b2167459
RH
2740{
2741 unsigned r2 = extract32(insn, 21, 5);
2742 unsigned cf = extract32(insn, 12, 4);
2743 unsigned is_i = extract32(insn, 6, 1);
2744 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2745 TCGv_reg tmp;
869051ea 2746 DisasJumpType ret;
b2167459
RH
2747
2748 nullify_over(ctx);
2749
2750 tmp = get_temp(ctx);
eaa3783b 2751 tcg_gen_shri_reg(tmp, cpu_psw_cb, 3);
b2167459 2752 if (!is_i) {
eaa3783b 2753 tcg_gen_not_reg(tmp, tmp);
b2167459 2754 }
eaa3783b
RH
2755 tcg_gen_andi_reg(tmp, tmp, 0x11111111);
2756 tcg_gen_muli_reg(tmp, tmp, 6);
b2167459 2757 ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
eaa3783b 2758 is_i ? tcg_gen_add_reg : tcg_gen_sub_reg);
b2167459
RH
2759
2760 return nullify_end(ctx, ret);
2761}
2762
869051ea
RH
2763static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2764 const DisasInsn *di)
b2167459
RH
2765{
2766 unsigned r2 = extract32(insn, 21, 5);
2767 unsigned r1 = extract32(insn, 16, 5);
2768 unsigned cf = extract32(insn, 12, 4);
2769 unsigned rt = extract32(insn, 0, 5);
eaa3783b 2770 TCGv_reg dest, add1, add2, addc, zero, in1, in2;
b2167459
RH
2771
2772 nullify_over(ctx);
2773
2774 in1 = load_gpr(ctx, r1);
2775 in2 = load_gpr(ctx, r2);
2776
2777 add1 = tcg_temp_new();
2778 add2 = tcg_temp_new();
2779 addc = tcg_temp_new();
2780 dest = tcg_temp_new();
eaa3783b 2781 zero = tcg_const_reg(0);
b2167459
RH
2782
2783 /* Form R1 << 1 | PSW[CB]{8}. */
eaa3783b
RH
2784 tcg_gen_add_reg(add1, in1, in1);
2785 tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb);
b2167459
RH
2786
2787 /* Add or subtract R2, depending on PSW[V]. Proper computation of
2788 carry{8} requires that we subtract via + ~R2 + 1, as described in
2789 the manual. By extracting and masking V, we can produce the
2790 proper inputs to the addition without movcond. */
eaa3783b
RH
2791 tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1);
2792 tcg_gen_xor_reg(add2, in2, addc);
2793 tcg_gen_andi_reg(addc, addc, 1);
b2167459
RH
2794 /* ??? This is only correct for 32-bit. */
2795 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2796 tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2797
2798 tcg_temp_free(addc);
2799 tcg_temp_free(zero);
2800
2801 /* Write back the result register. */
2802 save_gpr(ctx, rt, dest);
2803
2804 /* Write back PSW[CB]. */
eaa3783b
RH
2805 tcg_gen_xor_reg(cpu_psw_cb, add1, add2);
2806 tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest);
b2167459
RH
2807
2808 /* Write back PSW[V] for the division step. */
eaa3783b
RH
2809 tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb);
2810 tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2);
b2167459
RH
2811
2812 /* Install the new nullification. */
2813 if (cf) {
eaa3783b 2814 TCGv_reg sv = NULL;
b2167459
RH
2815 if (cf >> 1 == 6) {
2816 /* ??? The lshift is supposed to contribute to overflow. */
2817 sv = do_add_sv(ctx, dest, add1, add2);
2818 }
2819 ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2820 }
2821
2822 tcg_temp_free(add1);
2823 tcg_temp_free(add2);
2824 tcg_temp_free(dest);
2825
869051ea 2826 return nullify_end(ctx, DISAS_NEXT);
b2167459
RH
2827}
2828
b49572d3
RH
2829#ifndef CONFIG_USER_ONLY
2830/* These are QEMU extensions and are nops in the real architecture:
2831 *
2832 * or %r10,%r10,%r10 -- idle loop; wait for interrupt
2833 * or %r31,%r31,%r31 -- death loop; offline cpu
2834 * currently implemented as idle.
2835 */
2836static DisasJumpType trans_pause(DisasContext *ctx, uint32_t insn,
2837 const DisasInsn *di)
2838{
2839 TCGv_i32 tmp;
2840
2841 /* No need to check for supervisor, as userland can only pause
2842 until the next timer interrupt. */
2843 nullify_over(ctx);
2844
2845 /* Advance the instruction queue. */
2846 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
2847 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
2848 nullify_set(ctx, 0);
2849
2850 /* Tell the qemu main loop to halt until this cpu has work. */
2851 tmp = tcg_const_i32(1);
2852 tcg_gen_st_i32(tmp, cpu_env, -offsetof(HPPACPU, env) +
2853 offsetof(CPUState, halted));
2854 tcg_temp_free_i32(tmp);
2855 gen_excp_1(EXCP_HALTED);
2856
2857 return nullify_end(ctx, DISAS_NORETURN);
2858}
2859#endif
2860
b2167459
RH
2861static const DisasInsn table_arith_log[] = {
2862 { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */
2863 { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
b49572d3
RH
2864#ifndef CONFIG_USER_ONLY
2865 { 0x094a024au, 0xffffffffu, trans_pause }, /* or r10,r10,r10 */
2866 { 0x0bff025fu, 0xffffffffu, trans_pause }, /* or r31,r31,r31 */
2867#endif
eaa3783b
RH
2868 { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_reg },
2869 { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_reg },
2870 { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_reg },
2871 { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_reg },
b2167459
RH
2872 { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2873 { 0x08000380u, 0xfc000fe0u, trans_uxor },
2874 { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2875 { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2876 { 0x08000440u, 0xfc000fe0u, trans_ds },
2877 { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2878 { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2879 { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2880 { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2881};
2882
869051ea 2883static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
b2167459 2884{
eaa3783b 2885 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2886 unsigned e1 = extract32(insn, 11, 1);
2887 unsigned cf = extract32(insn, 12, 4);
2888 unsigned rt = extract32(insn, 16, 5);
2889 unsigned r2 = extract32(insn, 21, 5);
2890 unsigned o1 = extract32(insn, 26, 1);
eaa3783b 2891 TCGv_reg tcg_im, tcg_r2;
869051ea 2892 DisasJumpType ret;
b2167459
RH
2893
2894 if (cf) {
2895 nullify_over(ctx);
2896 }
2897
2898 tcg_im = load_const(ctx, im);
2899 tcg_r2 = load_gpr(ctx, r2);
2900 ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2901
2902 return nullify_end(ctx, ret);
2903}
2904
869051ea 2905static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
b2167459 2906{
eaa3783b 2907 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2908 unsigned e1 = extract32(insn, 11, 1);
2909 unsigned cf = extract32(insn, 12, 4);
2910 unsigned rt = extract32(insn, 16, 5);
2911 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 2912 TCGv_reg tcg_im, tcg_r2;
869051ea 2913 DisasJumpType ret;
b2167459
RH
2914
2915 if (cf) {
2916 nullify_over(ctx);
2917 }
2918
2919 tcg_im = load_const(ctx, im);
2920 tcg_r2 = load_gpr(ctx, r2);
2921 ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2922
2923 return nullify_end(ctx, ret);
2924}
2925
869051ea 2926static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
b2167459 2927{
eaa3783b 2928 target_sreg im = low_sextract(insn, 0, 11);
b2167459
RH
2929 unsigned cf = extract32(insn, 12, 4);
2930 unsigned rt = extract32(insn, 16, 5);
2931 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 2932 TCGv_reg tcg_im, tcg_r2;
869051ea 2933 DisasJumpType ret;
b2167459
RH
2934
2935 if (cf) {
2936 nullify_over(ctx);
2937 }
2938
2939 tcg_im = load_const(ctx, im);
2940 tcg_r2 = load_gpr(ctx, r2);
2941 ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2942
2943 return nullify_end(ctx, ret);
2944}
2945
869051ea
RH
2946static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2947 const DisasInsn *di)
96d6407f
RH
2948{
2949 unsigned rt = extract32(insn, 0, 5);
2950 unsigned m = extract32(insn, 5, 1);
2951 unsigned sz = extract32(insn, 6, 2);
2952 unsigned a = extract32(insn, 13, 1);
86f8d05f 2953 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2954 int disp = low_sextract(insn, 16, 5);
2955 unsigned rb = extract32(insn, 21, 5);
2956 int modify = (m ? (a ? -1 : 1) : 0);
2957 TCGMemOp mop = MO_TE | sz;
2958
86f8d05f 2959 return do_load(ctx, rt, rb, 0, 0, disp, sp, modify, mop);
96d6407f
RH
2960}
2961
869051ea
RH
2962static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2963 const DisasInsn *di)
96d6407f
RH
2964{
2965 unsigned rt = extract32(insn, 0, 5);
2966 unsigned m = extract32(insn, 5, 1);
2967 unsigned sz = extract32(insn, 6, 2);
2968 unsigned u = extract32(insn, 13, 1);
86f8d05f 2969 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2970 unsigned rx = extract32(insn, 16, 5);
2971 unsigned rb = extract32(insn, 21, 5);
2972 TCGMemOp mop = MO_TE | sz;
2973
86f8d05f 2974 return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, sp, m, mop);
96d6407f
RH
2975}
2976
869051ea
RH
2977static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2978 const DisasInsn *di)
96d6407f
RH
2979{
2980 int disp = low_sextract(insn, 0, 5);
2981 unsigned m = extract32(insn, 5, 1);
2982 unsigned sz = extract32(insn, 6, 2);
2983 unsigned a = extract32(insn, 13, 1);
86f8d05f 2984 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
2985 unsigned rr = extract32(insn, 16, 5);
2986 unsigned rb = extract32(insn, 21, 5);
2987 int modify = (m ? (a ? -1 : 1) : 0);
2988 TCGMemOp mop = MO_TE | sz;
2989
86f8d05f 2990 return do_store(ctx, rr, rb, disp, sp, modify, mop);
96d6407f
RH
2991}
2992
869051ea
RH
2993static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
2994 const DisasInsn *di)
96d6407f
RH
2995{
2996 unsigned rt = extract32(insn, 0, 5);
2997 unsigned m = extract32(insn, 5, 1);
2998 unsigned i = extract32(insn, 12, 1);
2999 unsigned au = extract32(insn, 13, 1);
86f8d05f 3000 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3001 unsigned rx = extract32(insn, 16, 5);
3002 unsigned rb = extract32(insn, 21, 5);
3003 TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
86f8d05f
RH
3004 TCGv_reg zero, dest, ofs;
3005 TCGv_tl addr;
96d6407f
RH
3006 int modify, disp = 0, scale = 0;
3007
3008 nullify_over(ctx);
3009
96d6407f
RH
3010 if (i) {
3011 modify = (m ? (au ? -1 : 1) : 0);
3012 disp = low_sextract(rx, 0, 5);
3013 rx = 0;
3014 } else {
3015 modify = m;
3016 if (au) {
3017 scale = mop & MO_SIZE;
3018 }
3019 }
3020 if (modify) {
86f8d05f
RH
3021 /* Base register modification. Make sure if RT == RB,
3022 we see the result of the load. */
96d6407f
RH
3023 dest = get_temp(ctx);
3024 } else {
3025 dest = dest_gpr(ctx, rt);
3026 }
3027
86f8d05f
RH
3028 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
3029 ctx->mmu_idx == MMU_PHYS_IDX);
eaa3783b 3030 zero = tcg_const_reg(0);
86f8d05f 3031 tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop);
96d6407f 3032 if (modify) {
86f8d05f 3033 save_gpr(ctx, rb, ofs);
96d6407f
RH
3034 }
3035 save_gpr(ctx, rt, dest);
3036
869051ea 3037 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
3038}
3039
869051ea
RH
3040static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
3041 const DisasInsn *di)
96d6407f 3042{
eaa3783b 3043 target_sreg disp = low_sextract(insn, 0, 5);
96d6407f
RH
3044 unsigned m = extract32(insn, 5, 1);
3045 unsigned a = extract32(insn, 13, 1);
86f8d05f 3046 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3047 unsigned rt = extract32(insn, 16, 5);
3048 unsigned rb = extract32(insn, 21, 5);
86f8d05f
RH
3049 TCGv_reg ofs, val;
3050 TCGv_tl addr;
96d6407f
RH
3051
3052 nullify_over(ctx);
3053
86f8d05f
RH
3054 form_gva(ctx, &addr, &ofs, rb, 0, 0, disp, sp, m,
3055 ctx->mmu_idx == MMU_PHYS_IDX);
96d6407f 3056 val = load_gpr(ctx, rt);
96d6407f 3057 if (a) {
f9f46db4
EC
3058 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3059 gen_helper_stby_e_parallel(cpu_env, addr, val);
3060 } else {
3061 gen_helper_stby_e(cpu_env, addr, val);
3062 }
96d6407f 3063 } else {
f9f46db4
EC
3064 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3065 gen_helper_stby_b_parallel(cpu_env, addr, val);
3066 } else {
3067 gen_helper_stby_b(cpu_env, addr, val);
3068 }
96d6407f
RH
3069 }
3070
3071 if (m) {
86f8d05f
RH
3072 tcg_gen_andi_reg(ofs, ofs, ~3);
3073 save_gpr(ctx, rb, ofs);
96d6407f 3074 }
96d6407f 3075
869051ea 3076 return nullify_end(ctx, DISAS_NEXT);
96d6407f
RH
3077}
3078
d0a851cc
RH
3079#ifndef CONFIG_USER_ONLY
3080static DisasJumpType trans_ldwa_idx_i(DisasContext *ctx, uint32_t insn,
3081 const DisasInsn *di)
3082{
3083 int hold_mmu_idx = ctx->mmu_idx;
3084 DisasJumpType ret;
3085
3086 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3087
3088 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3089 format wrt the sub-opcode in bits 6:9. */
3090 ctx->mmu_idx = MMU_PHYS_IDX;
3091 ret = trans_ld_idx_i(ctx, insn, di);
3092 ctx->mmu_idx = hold_mmu_idx;
3093 return ret;
3094}
3095
3096static DisasJumpType trans_ldwa_idx_x(DisasContext *ctx, uint32_t insn,
3097 const DisasInsn *di)
3098{
3099 int hold_mmu_idx = ctx->mmu_idx;
3100 DisasJumpType ret;
3101
3102 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3103
3104 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3105 format wrt the sub-opcode in bits 6:9. */
3106 ctx->mmu_idx = MMU_PHYS_IDX;
3107 ret = trans_ld_idx_x(ctx, insn, di);
3108 ctx->mmu_idx = hold_mmu_idx;
3109 return ret;
3110}
95412a61
RH
3111
3112static DisasJumpType trans_stwa_idx_i(DisasContext *ctx, uint32_t insn,
3113 const DisasInsn *di)
3114{
3115 int hold_mmu_idx = ctx->mmu_idx;
3116 DisasJumpType ret;
3117
3118 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3119
3120 /* ??? needs fixing for hppa64 -- ldda does not follow the same
3121 format wrt the sub-opcode in bits 6:9. */
3122 ctx->mmu_idx = MMU_PHYS_IDX;
3123 ret = trans_st_idx_i(ctx, insn, di);
3124 ctx->mmu_idx = hold_mmu_idx;
3125 return ret;
3126}
d0a851cc
RH
3127#endif
3128
96d6407f
RH
3129static const DisasInsn table_index_mem[] = {
3130 { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
3131 { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
3132 { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
3133 { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
3134 { 0x0c001300u, 0xfc0013c0, trans_stby },
d0a851cc 3135#ifndef CONFIG_USER_ONLY
d0a851cc 3136 { 0x0c000180u, 0xfc00d3c0, trans_ldwa_idx_x }, /* LDWA, rx */
95412a61
RH
3137 { 0x0c001180u, 0xfc00d3c0, trans_ldwa_idx_i }, /* LDWA, im */
3138 { 0x0c001380u, 0xfc00d3c0, trans_stwa_idx_i }, /* STWA, im */
d0a851cc 3139#endif
96d6407f
RH
3140};
3141
869051ea 3142static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
b2167459
RH
3143{
3144 unsigned rt = extract32(insn, 21, 5);
eaa3783b
RH
3145 target_sreg i = assemble_21(insn);
3146 TCGv_reg tcg_rt = dest_gpr(ctx, rt);
b2167459 3147
eaa3783b 3148 tcg_gen_movi_reg(tcg_rt, i);
b2167459
RH
3149 save_gpr(ctx, rt, tcg_rt);
3150 cond_free(&ctx->null_cond);
3151
869051ea 3152 return DISAS_NEXT;
b2167459
RH
3153}
3154
869051ea 3155static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
b2167459
RH
3156{
3157 unsigned rt = extract32(insn, 21, 5);
eaa3783b
RH
3158 target_sreg i = assemble_21(insn);
3159 TCGv_reg tcg_rt = load_gpr(ctx, rt);
3160 TCGv_reg tcg_r1 = dest_gpr(ctx, 1);
b2167459 3161
eaa3783b 3162 tcg_gen_addi_reg(tcg_r1, tcg_rt, i);
b2167459
RH
3163 save_gpr(ctx, 1, tcg_r1);
3164 cond_free(&ctx->null_cond);
3165
869051ea 3166 return DISAS_NEXT;
b2167459
RH
3167}
3168
869051ea 3169static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
b2167459
RH
3170{
3171 unsigned rb = extract32(insn, 21, 5);
3172 unsigned rt = extract32(insn, 16, 5);
eaa3783b
RH
3173 target_sreg i = assemble_16(insn);
3174 TCGv_reg tcg_rt = dest_gpr(ctx, rt);
b2167459
RH
3175
3176 /* Special case rb == 0, for the LDI pseudo-op.
3177 The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */
3178 if (rb == 0) {
eaa3783b 3179 tcg_gen_movi_reg(tcg_rt, i);
b2167459 3180 } else {
eaa3783b 3181 tcg_gen_addi_reg(tcg_rt, cpu_gr[rb], i);
b2167459
RH
3182 }
3183 save_gpr(ctx, rt, tcg_rt);
3184 cond_free(&ctx->null_cond);
3185
869051ea 3186 return DISAS_NEXT;
b2167459
RH
3187}
3188
869051ea
RH
3189static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
3190 bool is_mod, TCGMemOp mop)
96d6407f
RH
3191{
3192 unsigned rb = extract32(insn, 21, 5);
3193 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3194 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3195 target_sreg i = assemble_16(insn);
96d6407f 3196
86f8d05f
RH
3197 return do_load(ctx, rt, rb, 0, 0, i, sp,
3198 is_mod ? (i < 0 ? -1 : 1) : 0, mop);
96d6407f
RH
3199}
3200
869051ea 3201static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3202{
3203 unsigned rb = extract32(insn, 21, 5);
3204 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3205 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3206 target_sreg i = assemble_16a(insn);
96d6407f
RH
3207 unsigned ext2 = extract32(insn, 1, 2);
3208
3209 switch (ext2) {
3210 case 0:
3211 case 1:
3212 /* FLDW without modification. */
86f8d05f 3213 return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
96d6407f
RH
3214 case 2:
3215 /* LDW with modification. Note that the sign of I selects
3216 post-dec vs pre-inc. */
86f8d05f 3217 return do_load(ctx, rt, rb, 0, 0, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
96d6407f
RH
3218 default:
3219 return gen_illegal(ctx);
3220 }
3221}
3222
869051ea 3223static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
96d6407f 3224{
eaa3783b 3225 target_sreg i = assemble_16a(insn);
96d6407f
RH
3226 unsigned t1 = extract32(insn, 1, 1);
3227 unsigned a = extract32(insn, 2, 1);
86f8d05f 3228 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3229 unsigned t0 = extract32(insn, 16, 5);
3230 unsigned rb = extract32(insn, 21, 5);
3231
3232 /* FLDW with modification. */
86f8d05f 3233 return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
96d6407f
RH
3234}
3235
869051ea
RH
3236static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
3237 bool is_mod, TCGMemOp mop)
96d6407f
RH
3238{
3239 unsigned rb = extract32(insn, 21, 5);
3240 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3241 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3242 target_sreg i = assemble_16(insn);
96d6407f 3243
86f8d05f 3244 return do_store(ctx, rt, rb, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
96d6407f
RH
3245}
3246
869051ea 3247static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3248{
3249 unsigned rb = extract32(insn, 21, 5);
3250 unsigned rt = extract32(insn, 16, 5);
86f8d05f 3251 unsigned sp = extract32(insn, 14, 2);
eaa3783b 3252 target_sreg i = assemble_16a(insn);
96d6407f
RH
3253 unsigned ext2 = extract32(insn, 1, 2);
3254
3255 switch (ext2) {
3256 case 0:
3257 case 1:
3258 /* FSTW without modification. */
86f8d05f 3259 return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0);
96d6407f 3260 case 2:
3f7367e2 3261 /* STW with modification. */
86f8d05f 3262 return do_store(ctx, rt, rb, i, sp, (i < 0 ? 1 : -1), MO_TEUL);
96d6407f
RH
3263 default:
3264 return gen_illegal(ctx);
3265 }
3266}
3267
869051ea 3268static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
96d6407f 3269{
eaa3783b 3270 target_sreg i = assemble_16a(insn);
96d6407f
RH
3271 unsigned t1 = extract32(insn, 1, 1);
3272 unsigned a = extract32(insn, 2, 1);
86f8d05f 3273 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3274 unsigned t0 = extract32(insn, 16, 5);
3275 unsigned rb = extract32(insn, 21, 5);
3276
3277 /* FSTW with modification. */
86f8d05f 3278 return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1));
96d6407f
RH
3279}
3280
869051ea 3281static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3282{
3283 unsigned t0 = extract32(insn, 0, 5);
3284 unsigned m = extract32(insn, 5, 1);
3285 unsigned t1 = extract32(insn, 6, 1);
3286 unsigned ext3 = extract32(insn, 7, 3);
3287 /* unsigned cc = extract32(insn, 10, 2); */
3288 unsigned i = extract32(insn, 12, 1);
3289 unsigned ua = extract32(insn, 13, 1);
86f8d05f 3290 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3291 unsigned rx = extract32(insn, 16, 5);
3292 unsigned rb = extract32(insn, 21, 5);
3293 unsigned rt = t1 * 32 + t0;
3294 int modify = (m ? (ua ? -1 : 1) : 0);
3295 int disp, scale;
3296
3297 if (i == 0) {
3298 scale = (ua ? 2 : 0);
3299 disp = 0;
3300 modify = m;
3301 } else {
3302 disp = low_sextract(rx, 0, 5);
3303 scale = 0;
3304 rx = 0;
3305 modify = (m ? (ua ? -1 : 1) : 0);
3306 }
3307
3308 switch (ext3) {
3309 case 0: /* FLDW */
86f8d05f 3310 return do_floadw(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f 3311 case 4: /* FSTW */
86f8d05f 3312 return do_fstorew(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f
RH
3313 }
3314 return gen_illegal(ctx);
3315}
3316
869051ea 3317static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
96d6407f
RH
3318{
3319 unsigned rt = extract32(insn, 0, 5);
3320 unsigned m = extract32(insn, 5, 1);
3321 unsigned ext4 = extract32(insn, 6, 4);
3322 /* unsigned cc = extract32(insn, 10, 2); */
3323 unsigned i = extract32(insn, 12, 1);
3324 unsigned ua = extract32(insn, 13, 1);
86f8d05f 3325 unsigned sp = extract32(insn, 14, 2);
96d6407f
RH
3326 unsigned rx = extract32(insn, 16, 5);
3327 unsigned rb = extract32(insn, 21, 5);
3328 int modify = (m ? (ua ? -1 : 1) : 0);
3329 int disp, scale;
3330
3331 if (i == 0) {
3332 scale = (ua ? 3 : 0);
3333 disp = 0;
3334 modify = m;
3335 } else {
3336 disp = low_sextract(rx, 0, 5);
3337 scale = 0;
3338 rx = 0;
3339 modify = (m ? (ua ? -1 : 1) : 0);
3340 }
3341
3342 switch (ext4) {
3343 case 0: /* FLDD */
86f8d05f 3344 return do_floadd(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f 3345 case 8: /* FSTD */
86f8d05f 3346 return do_fstored(ctx, rt, rb, rx, scale, disp, sp, modify);
96d6407f
RH
3347 default:
3348 return gen_illegal(ctx);
3349 }
3350}
3351
869051ea
RH
3352static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
3353 bool is_true, bool is_imm, bool is_dw)
98cd9ca7 3354{
eaa3783b 3355 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3356 unsigned n = extract32(insn, 1, 1);
3357 unsigned c = extract32(insn, 13, 3);
3358 unsigned r = extract32(insn, 21, 5);
3359 unsigned cf = c * 2 + !is_true;
eaa3783b 3360 TCGv_reg dest, in1, in2, sv;
98cd9ca7
RH
3361 DisasCond cond;
3362
3363 nullify_over(ctx);
3364
3365 if (is_imm) {
3366 in1 = load_const(ctx, low_sextract(insn, 16, 5));
3367 } else {
3368 in1 = load_gpr(ctx, extract32(insn, 16, 5));
3369 }
3370 in2 = load_gpr(ctx, r);
3371 dest = get_temp(ctx);
3372
eaa3783b 3373 tcg_gen_sub_reg(dest, in1, in2);
98cd9ca7 3374
f764718d 3375 sv = NULL;
98cd9ca7
RH
3376 if (c == 6) {
3377 sv = do_sub_sv(ctx, dest, in1, in2);
3378 }
3379
3380 cond = do_sub_cond(cf, dest, in1, in2, sv);
3381 return do_cbranch(ctx, disp, n, &cond);
3382}
3383
869051ea
RH
3384static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
3385 bool is_true, bool is_imm)
98cd9ca7 3386{
eaa3783b 3387 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3388 unsigned n = extract32(insn, 1, 1);
3389 unsigned c = extract32(insn, 13, 3);
3390 unsigned r = extract32(insn, 21, 5);
3391 unsigned cf = c * 2 + !is_true;
eaa3783b 3392 TCGv_reg dest, in1, in2, sv, cb_msb;
98cd9ca7
RH
3393 DisasCond cond;
3394
3395 nullify_over(ctx);
3396
3397 if (is_imm) {
3398 in1 = load_const(ctx, low_sextract(insn, 16, 5));
3399 } else {
3400 in1 = load_gpr(ctx, extract32(insn, 16, 5));
3401 }
3402 in2 = load_gpr(ctx, r);
3403 dest = dest_gpr(ctx, r);
f764718d
RH
3404 sv = NULL;
3405 cb_msb = NULL;
98cd9ca7
RH
3406
3407 switch (c) {
3408 default:
eaa3783b 3409 tcg_gen_add_reg(dest, in1, in2);
98cd9ca7
RH
3410 break;
3411 case 4: case 5:
3412 cb_msb = get_temp(ctx);
eaa3783b
RH
3413 tcg_gen_movi_reg(cb_msb, 0);
3414 tcg_gen_add2_reg(dest, cb_msb, in1, cb_msb, in2, cb_msb);
98cd9ca7
RH
3415 break;
3416 case 6:
eaa3783b 3417 tcg_gen_add_reg(dest, in1, in2);
98cd9ca7
RH
3418 sv = do_add_sv(ctx, dest, in1, in2);
3419 break;
3420 }
3421
3422 cond = do_cond(cf, dest, cb_msb, sv);
3423 return do_cbranch(ctx, disp, n, &cond);
3424}
3425
869051ea 3426static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
98cd9ca7 3427{
eaa3783b 3428 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3429 unsigned n = extract32(insn, 1, 1);
3430 unsigned c = extract32(insn, 15, 1);
3431 unsigned r = extract32(insn, 16, 5);
3432 unsigned p = extract32(insn, 21, 5);
3433 unsigned i = extract32(insn, 26, 1);
eaa3783b 3434 TCGv_reg tmp, tcg_r;
98cd9ca7
RH
3435 DisasCond cond;
3436
3437 nullify_over(ctx);
3438
3439 tmp = tcg_temp_new();
3440 tcg_r = load_gpr(ctx, r);
3441 if (i) {
eaa3783b 3442 tcg_gen_shli_reg(tmp, tcg_r, p);
98cd9ca7 3443 } else {
eaa3783b 3444 tcg_gen_shl_reg(tmp, tcg_r, cpu_sar);
98cd9ca7
RH
3445 }
3446
3447 cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
3448 tcg_temp_free(tmp);
3449 return do_cbranch(ctx, disp, n, &cond);
3450}
3451
869051ea 3452static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
98cd9ca7 3453{
eaa3783b 3454 target_sreg disp = assemble_12(insn) * 4;
98cd9ca7
RH
3455 unsigned n = extract32(insn, 1, 1);
3456 unsigned c = extract32(insn, 13, 3);
3457 unsigned t = extract32(insn, 16, 5);
3458 unsigned r = extract32(insn, 21, 5);
eaa3783b 3459 TCGv_reg dest;
98cd9ca7
RH
3460 DisasCond cond;
3461
3462 nullify_over(ctx);
3463
3464 dest = dest_gpr(ctx, r);
3465 if (is_imm) {
eaa3783b 3466 tcg_gen_movi_reg(dest, low_sextract(t, 0, 5));
98cd9ca7 3467 } else if (t == 0) {
eaa3783b 3468 tcg_gen_movi_reg(dest, 0);
98cd9ca7 3469 } else {
eaa3783b 3470 tcg_gen_mov_reg(dest, cpu_gr[t]);
98cd9ca7
RH
3471 }
3472
3473 cond = do_sed_cond(c, dest);
3474 return do_cbranch(ctx, disp, n, &cond);
3475}
3476
869051ea
RH
3477static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
3478 const DisasInsn *di)
0b1347d2
RH
3479{
3480 unsigned rt = extract32(insn, 0, 5);
3481 unsigned c = extract32(insn, 13, 3);
3482 unsigned r1 = extract32(insn, 16, 5);
3483 unsigned r2 = extract32(insn, 21, 5);
eaa3783b 3484 TCGv_reg dest;
0b1347d2
RH
3485
3486 if (c) {
3487 nullify_over(ctx);
3488 }
3489
3490 dest = dest_gpr(ctx, rt);
3491 if (r1 == 0) {
eaa3783b
RH
3492 tcg_gen_ext32u_reg(dest, load_gpr(ctx, r2));
3493 tcg_gen_shr_reg(dest, dest, cpu_sar);
0b1347d2
RH
3494 } else if (r1 == r2) {
3495 TCGv_i32 t32 = tcg_temp_new_i32();
eaa3783b 3496 tcg_gen_trunc_reg_i32(t32, load_gpr(ctx, r2));
0b1347d2 3497 tcg_gen_rotr_i32(t32, t32, cpu_sar);
eaa3783b 3498 tcg_gen_extu_i32_reg(dest, t32);
0b1347d2
RH
3499 tcg_temp_free_i32(t32);
3500 } else {
3501 TCGv_i64 t = tcg_temp_new_i64();
3502 TCGv_i64 s = tcg_temp_new_i64();
3503
eaa3783b
RH
3504 tcg_gen_concat_reg_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
3505 tcg_gen_extu_reg_i64(s, cpu_sar);
0b1347d2 3506 tcg_gen_shr_i64(t, t, s);
eaa3783b 3507 tcg_gen_trunc_i64_reg(dest, t);
0b1347d2
RH
3508
3509 tcg_temp_free_i64(t);
3510 tcg_temp_free_i64(s);
3511 }
3512 save_gpr(ctx, rt, dest);
3513
3514 /* Install the new nullification. */
3515 cond_free(&ctx->null_cond);
3516 if (c) {
3517 ctx->null_cond = do_sed_cond(c, dest);
3518 }
869051ea 3519 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3520}
3521
869051ea
RH
3522static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
3523 const DisasInsn *di)
0b1347d2
RH
3524{
3525 unsigned rt = extract32(insn, 0, 5);
3526 unsigned cpos = extract32(insn, 5, 5);
3527 unsigned c = extract32(insn, 13, 3);
3528 unsigned r1 = extract32(insn, 16, 5);
3529 unsigned r2 = extract32(insn, 21, 5);
3530 unsigned sa = 31 - cpos;
eaa3783b 3531 TCGv_reg dest, t2;
0b1347d2
RH
3532
3533 if (c) {
3534 nullify_over(ctx);
3535 }
3536
3537 dest = dest_gpr(ctx, rt);
3538 t2 = load_gpr(ctx, r2);
3539 if (r1 == r2) {
3540 TCGv_i32 t32 = tcg_temp_new_i32();
eaa3783b 3541 tcg_gen_trunc_reg_i32(t32, t2);
0b1347d2 3542 tcg_gen_rotri_i32(t32, t32, sa);
eaa3783b 3543 tcg_gen_extu_i32_reg(dest, t32);
0b1347d2
RH
3544 tcg_temp_free_i32(t32);
3545 } else if (r1 == 0) {
eaa3783b 3546 tcg_gen_extract_reg(dest, t2, sa, 32 - sa);
0b1347d2 3547 } else {
eaa3783b
RH
3548 TCGv_reg t0 = tcg_temp_new();
3549 tcg_gen_extract_reg(t0, t2, sa, 32 - sa);
3550 tcg_gen_deposit_reg(dest, t0, cpu_gr[r1], 32 - sa, sa);
0b1347d2
RH
3551 tcg_temp_free(t0);
3552 }
3553 save_gpr(ctx, rt, dest);
3554
3555 /* Install the new nullification. */
3556 cond_free(&ctx->null_cond);
3557 if (c) {
3558 ctx->null_cond = do_sed_cond(c, dest);
3559 }
869051ea 3560 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3561}
3562
869051ea
RH
3563static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
3564 const DisasInsn *di)
0b1347d2
RH
3565{
3566 unsigned clen = extract32(insn, 0, 5);
3567 unsigned is_se = extract32(insn, 10, 1);
3568 unsigned c = extract32(insn, 13, 3);
3569 unsigned rt = extract32(insn, 16, 5);
3570 unsigned rr = extract32(insn, 21, 5);
3571 unsigned len = 32 - clen;
eaa3783b 3572 TCGv_reg dest, src, tmp;
0b1347d2
RH
3573
3574 if (c) {
3575 nullify_over(ctx);
3576 }
3577
3578 dest = dest_gpr(ctx, rt);
3579 src = load_gpr(ctx, rr);
3580 tmp = tcg_temp_new();
3581
3582 /* Recall that SAR is using big-endian bit numbering. */
eaa3783b 3583 tcg_gen_xori_reg(tmp, cpu_sar, TARGET_REGISTER_BITS - 1);
0b1347d2 3584 if (is_se) {
eaa3783b
RH
3585 tcg_gen_sar_reg(dest, src, tmp);
3586 tcg_gen_sextract_reg(dest, dest, 0, len);
0b1347d2 3587 } else {
eaa3783b
RH
3588 tcg_gen_shr_reg(dest, src, tmp);
3589 tcg_gen_extract_reg(dest, dest, 0, len);
0b1347d2
RH
3590 }
3591 tcg_temp_free(tmp);
3592 save_gpr(ctx, rt, dest);
3593
3594 /* Install the new nullification. */
3595 cond_free(&ctx->null_cond);
3596 if (c) {
3597 ctx->null_cond = do_sed_cond(c, dest);
3598 }
869051ea 3599 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3600}
3601
869051ea
RH
3602static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
3603 const DisasInsn *di)
0b1347d2
RH
3604{
3605 unsigned clen = extract32(insn, 0, 5);
3606 unsigned pos = extract32(insn, 5, 5);
3607 unsigned is_se = extract32(insn, 10, 1);
3608 unsigned c = extract32(insn, 13, 3);
3609 unsigned rt = extract32(insn, 16, 5);
3610 unsigned rr = extract32(insn, 21, 5);
3611 unsigned len = 32 - clen;
3612 unsigned cpos = 31 - pos;
eaa3783b 3613 TCGv_reg dest, src;
0b1347d2
RH
3614
3615 if (c) {
3616 nullify_over(ctx);
3617 }
3618
3619 dest = dest_gpr(ctx, rt);
3620 src = load_gpr(ctx, rr);
3621 if (is_se) {
eaa3783b 3622 tcg_gen_sextract_reg(dest, src, cpos, len);
0b1347d2 3623 } else {
eaa3783b 3624 tcg_gen_extract_reg(dest, src, cpos, len);
0b1347d2
RH
3625 }
3626 save_gpr(ctx, rt, dest);
3627
3628 /* Install the new nullification. */
3629 cond_free(&ctx->null_cond);
3630 if (c) {
3631 ctx->null_cond = do_sed_cond(c, dest);
3632 }
869051ea 3633 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3634}
3635
3636static const DisasInsn table_sh_ex[] = {
3637 { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
3638 { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
3639 { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
3640 { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
3641};
3642
869051ea
RH
3643static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
3644 const DisasInsn *di)
0b1347d2
RH
3645{
3646 unsigned clen = extract32(insn, 0, 5);
3647 unsigned cpos = extract32(insn, 5, 5);
3648 unsigned nz = extract32(insn, 10, 1);
3649 unsigned c = extract32(insn, 13, 3);
eaa3783b 3650 target_sreg val = low_sextract(insn, 16, 5);
0b1347d2
RH
3651 unsigned rt = extract32(insn, 21, 5);
3652 unsigned len = 32 - clen;
eaa3783b
RH
3653 target_sreg mask0, mask1;
3654 TCGv_reg dest;
0b1347d2
RH
3655
3656 if (c) {
3657 nullify_over(ctx);
3658 }
3659 if (cpos + len > 32) {
3660 len = 32 - cpos;
3661 }
3662
3663 dest = dest_gpr(ctx, rt);
3664 mask0 = deposit64(0, cpos, len, val);
3665 mask1 = deposit64(-1, cpos, len, val);
3666
3667 if (nz) {
eaa3783b 3668 TCGv_reg src = load_gpr(ctx, rt);
0b1347d2 3669 if (mask1 != -1) {
eaa3783b 3670 tcg_gen_andi_reg(dest, src, mask1);
0b1347d2
RH
3671 src = dest;
3672 }
eaa3783b 3673 tcg_gen_ori_reg(dest, src, mask0);
0b1347d2 3674 } else {
eaa3783b 3675 tcg_gen_movi_reg(dest, mask0);
0b1347d2
RH
3676 }
3677 save_gpr(ctx, rt, dest);
3678
3679 /* Install the new nullification. */
3680 cond_free(&ctx->null_cond);
3681 if (c) {
3682 ctx->null_cond = do_sed_cond(c, dest);
3683 }
869051ea 3684 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3685}
3686
869051ea
RH
3687static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
3688 const DisasInsn *di)
0b1347d2
RH
3689{
3690 unsigned clen = extract32(insn, 0, 5);
3691 unsigned cpos = extract32(insn, 5, 5);
3692 unsigned nz = extract32(insn, 10, 1);
3693 unsigned c = extract32(insn, 13, 3);
3694 unsigned rr = extract32(insn, 16, 5);
3695 unsigned rt = extract32(insn, 21, 5);
3696 unsigned rs = nz ? rt : 0;
3697 unsigned len = 32 - clen;
eaa3783b 3698 TCGv_reg dest, val;
0b1347d2
RH
3699
3700 if (c) {
3701 nullify_over(ctx);
3702 }
3703 if (cpos + len > 32) {
3704 len = 32 - cpos;
3705 }
3706
3707 dest = dest_gpr(ctx, rt);
3708 val = load_gpr(ctx, rr);
3709 if (rs == 0) {
eaa3783b 3710 tcg_gen_deposit_z_reg(dest, val, cpos, len);
0b1347d2 3711 } else {
eaa3783b 3712 tcg_gen_deposit_reg(dest, cpu_gr[rs], val, cpos, len);
0b1347d2
RH
3713 }
3714 save_gpr(ctx, rt, dest);
3715
3716 /* Install the new nullification. */
3717 cond_free(&ctx->null_cond);
3718 if (c) {
3719 ctx->null_cond = do_sed_cond(c, dest);
3720 }
869051ea 3721 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3722}
3723
869051ea
RH
3724static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
3725 const DisasInsn *di)
0b1347d2
RH
3726{
3727 unsigned clen = extract32(insn, 0, 5);
3728 unsigned nz = extract32(insn, 10, 1);
3729 unsigned i = extract32(insn, 12, 1);
3730 unsigned c = extract32(insn, 13, 3);
3731 unsigned rt = extract32(insn, 21, 5);
3732 unsigned rs = nz ? rt : 0;
3733 unsigned len = 32 - clen;
eaa3783b 3734 TCGv_reg val, mask, tmp, shift, dest;
0b1347d2
RH
3735 unsigned msb = 1U << (len - 1);
3736
3737 if (c) {
3738 nullify_over(ctx);
3739 }
3740
3741 if (i) {
3742 val = load_const(ctx, low_sextract(insn, 16, 5));
3743 } else {
3744 val = load_gpr(ctx, extract32(insn, 16, 5));
3745 }
3746 dest = dest_gpr(ctx, rt);
3747 shift = tcg_temp_new();
3748 tmp = tcg_temp_new();
3749
3750 /* Convert big-endian bit numbering in SAR to left-shift. */
eaa3783b 3751 tcg_gen_xori_reg(shift, cpu_sar, TARGET_REGISTER_BITS - 1);
0b1347d2 3752
eaa3783b
RH
3753 mask = tcg_const_reg(msb + (msb - 1));
3754 tcg_gen_and_reg(tmp, val, mask);
0b1347d2 3755 if (rs) {
eaa3783b
RH
3756 tcg_gen_shl_reg(mask, mask, shift);
3757 tcg_gen_shl_reg(tmp, tmp, shift);
3758 tcg_gen_andc_reg(dest, cpu_gr[rs], mask);
3759 tcg_gen_or_reg(dest, dest, tmp);
0b1347d2 3760 } else {
eaa3783b 3761 tcg_gen_shl_reg(dest, tmp, shift);
0b1347d2
RH
3762 }
3763 tcg_temp_free(shift);
3764 tcg_temp_free(mask);
3765 tcg_temp_free(tmp);
3766 save_gpr(ctx, rt, dest);
3767
3768 /* Install the new nullification. */
3769 cond_free(&ctx->null_cond);
3770 if (c) {
3771 ctx->null_cond = do_sed_cond(c, dest);
3772 }
869051ea 3773 return nullify_end(ctx, DISAS_NEXT);
0b1347d2
RH
3774}
3775
3776static const DisasInsn table_depw[] = {
3777 { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
3778 { 0xd4000800u, 0xfc001800u, trans_depw_imm },
3779 { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
3780};
3781
869051ea 3782static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
98cd9ca7
RH
3783{
3784 unsigned n = extract32(insn, 1, 1);
3785 unsigned b = extract32(insn, 21, 5);
eaa3783b 3786 target_sreg disp = assemble_17(insn);
660eefe1 3787 TCGv_reg tmp;
98cd9ca7 3788
c301f34e 3789#ifdef CONFIG_USER_ONLY
98cd9ca7
RH
3790 /* ??? It seems like there should be a good way of using
3791 "be disp(sr2, r0)", the canonical gateway entry mechanism
3792 to our advantage. But that appears to be inconvenient to
3793 manage along side branch delay slots. Therefore we handle
3794 entry into the gateway page via absolute address. */
98cd9ca7
RH
3795 /* Since we don't implement spaces, just branch. Do notice the special
3796 case of "be disp(*,r0)" using a direct branch to disp, so that we can
3797 goto_tb to the TB containing the syscall. */
3798 if (b == 0) {
3799 return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
98cd9ca7 3800 }
c301f34e
RH
3801#else
3802 int sp = assemble_sr3(insn);
3803 nullify_over(ctx);
660eefe1
RH
3804#endif
3805
3806 tmp = get_temp(ctx);
3807 tcg_gen_addi_reg(tmp, load_gpr(ctx, b), disp);
3808 tmp = do_ibranch_priv(ctx, tmp);
c301f34e
RH
3809
3810#ifdef CONFIG_USER_ONLY
660eefe1 3811 return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
c301f34e
RH
3812#else
3813 TCGv_i64 new_spc = tcg_temp_new_i64();
3814
3815 load_spr(ctx, new_spc, sp);
3816 if (is_l) {
3817 copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
3818 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
3819 }
3820 if (n && use_nullify_skip(ctx)) {
3821 tcg_gen_mov_reg(cpu_iaoq_f, tmp);
3822 tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
3823 tcg_gen_mov_i64(cpu_iasq_f, new_spc);
3824 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f);
3825 } else {
3826 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3827 if (ctx->iaoq_b == -1) {
3828 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3829 }
3830 tcg_gen_mov_reg(cpu_iaoq_b, tmp);
3831 tcg_gen_mov_i64(cpu_iasq_b, new_spc);
3832 nullify_set(ctx, n);
3833 }
3834 tcg_temp_free_i64(new_spc);
3835 tcg_gen_lookup_and_goto_ptr();
3836 return nullify_end(ctx, DISAS_NORETURN);
3837#endif
98cd9ca7
RH
3838}
3839
869051ea
RH
3840static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
3841 const DisasInsn *di)
98cd9ca7
RH
3842{
3843 unsigned n = extract32(insn, 1, 1);
3844 unsigned link = extract32(insn, 21, 5);
eaa3783b 3845 target_sreg disp = assemble_17(insn);
98cd9ca7
RH
3846
3847 return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
3848}
3849
43e05652
RH
3850static DisasJumpType trans_b_gate(DisasContext *ctx, uint32_t insn,
3851 const DisasInsn *di)
3852{
3853 unsigned n = extract32(insn, 1, 1);
3854 unsigned link = extract32(insn, 21, 5);
3855 target_sreg disp = assemble_17(insn);
3856 target_ureg dest = iaoq_dest(ctx, disp);
3857
3858 /* Make sure the caller hasn't done something weird with the queue.
3859 * ??? This is not quite the same as the PSW[B] bit, which would be
3860 * expensive to track. Real hardware will trap for
3861 * b gateway
3862 * b gateway+4 (in delay slot of first branch)
3863 * However, checking for a non-sequential instruction queue *will*
3864 * diagnose the security hole
3865 * b gateway
3866 * b evil
3867 * in which instructions at evil would run with increased privs.
3868 */
3869 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
3870 return gen_illegal(ctx);
3871 }
3872
3873#ifndef CONFIG_USER_ONLY
3874 if (ctx->tb_flags & PSW_C) {
3875 CPUHPPAState *env = ctx->cs->env_ptr;
3876 int type = hppa_artype_for_page(env, ctx->base.pc_next);
3877 /* If we could not find a TLB entry, then we need to generate an
3878 ITLB miss exception so the kernel will provide it.
3879 The resulting TLB fill operation will invalidate this TB and
3880 we will re-translate, at which point we *will* be able to find
3881 the TLB entry and determine if this is in fact a gateway page. */
3882 if (type < 0) {
3883 return gen_excp(ctx, EXCP_ITLB_MISS);
3884 }
3885 /* No change for non-gateway pages or for priv decrease. */
3886 if (type >= 4 && type - 4 < ctx->privilege) {
3887 dest = deposit32(dest, 0, 2, type - 4);
3888 }
3889 } else {
3890 dest &= -4; /* priv = 0 */
3891 }
3892#endif
3893
3894 return do_dbranch(ctx, dest, link, n);
3895}
3896
869051ea
RH
3897static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
3898 const DisasInsn *di)
98cd9ca7
RH
3899{
3900 unsigned n = extract32(insn, 1, 1);
eaa3783b 3901 target_sreg disp = assemble_22(insn);
98cd9ca7
RH
3902
3903 return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
3904}
3905
869051ea
RH
3906static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
3907 const DisasInsn *di)
98cd9ca7
RH
3908{
3909 unsigned n = extract32(insn, 1, 1);
3910 unsigned rx = extract32(insn, 16, 5);
3911 unsigned link = extract32(insn, 21, 5);
eaa3783b 3912 TCGv_reg tmp = get_temp(ctx);
98cd9ca7 3913
eaa3783b
RH
3914 tcg_gen_shli_reg(tmp, load_gpr(ctx, rx), 3);
3915 tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
660eefe1 3916 /* The computation here never changes privilege level. */
98cd9ca7
RH
3917 return do_ibranch(ctx, tmp, link, n);
3918}
3919
869051ea
RH
3920static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
3921 const DisasInsn *di)
98cd9ca7
RH
3922{
3923 unsigned n = extract32(insn, 1, 1);
3924 unsigned rx = extract32(insn, 16, 5);
3925 unsigned rb = extract32(insn, 21, 5);
eaa3783b 3926 TCGv_reg dest;
98cd9ca7
RH
3927
3928 if (rx == 0) {
3929 dest = load_gpr(ctx, rb);
3930 } else {
3931 dest = get_temp(ctx);
eaa3783b
RH
3932 tcg_gen_shli_reg(dest, load_gpr(ctx, rx), 3);
3933 tcg_gen_add_reg(dest, dest, load_gpr(ctx, rb));
98cd9ca7 3934 }
660eefe1 3935 dest = do_ibranch_priv(ctx, dest);
98cd9ca7
RH
3936 return do_ibranch(ctx, dest, 0, n);
3937}
3938
869051ea
RH
3939static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
3940 const DisasInsn *di)
98cd9ca7
RH
3941{
3942 unsigned n = extract32(insn, 1, 1);
3943 unsigned rb = extract32(insn, 21, 5);
3944 unsigned link = extract32(insn, 13, 1) ? 2 : 0;
660eefe1 3945 TCGv_reg dest;
98cd9ca7 3946
c301f34e 3947#ifdef CONFIG_USER_ONLY
660eefe1
RH
3948 dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
3949 return do_ibranch(ctx, dest, link, n);
c301f34e
RH
3950#else
3951 nullify_over(ctx);
3952 dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
3953
3954 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
3955 if (ctx->iaoq_b == -1) {
3956 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
3957 }
3958 copy_iaoq_entry(cpu_iaoq_b, -1, dest);
3959 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
3960 if (link) {
3961 copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
3962 }
3963 nullify_set(ctx, n);
3964 tcg_gen_lookup_and_goto_ptr();
3965 return nullify_end(ctx, DISAS_NORETURN);
3966#endif
98cd9ca7
RH
3967}
3968
3969static const DisasInsn table_branch[] = {
3970 { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3971 { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3972 { 0xe8004000u, 0xfc00fffdu, trans_blr },
3973 { 0xe800c000u, 0xfc00fffdu, trans_bv },
3974 { 0xe800d000u, 0xfc00dffcu, trans_bve },
43e05652 3975 { 0xe8002000u, 0xfc00e000u, trans_b_gate },
98cd9ca7
RH
3976};
3977
869051ea
RH
3978static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3979 const DisasInsn *di)
ebe9383c
RH
3980{
3981 unsigned rt = extract32(insn, 0, 5);
3982 unsigned ra = extract32(insn, 21, 5);
eff235eb 3983 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
3984}
3985
869051ea
RH
3986static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3987 const DisasInsn *di)
ebe9383c
RH
3988{
3989 unsigned rt = assemble_rt64(insn);
3990 unsigned ra = assemble_ra64(insn);
eff235eb 3991 return do_fop_wew(ctx, rt, ra, di->f.wew);
ebe9383c
RH
3992}
3993
869051ea
RH
3994static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
3995 const DisasInsn *di)
ebe9383c
RH
3996{
3997 unsigned rt = extract32(insn, 0, 5);
3998 unsigned ra = extract32(insn, 21, 5);
eff235eb 3999 return do_fop_ded(ctx, rt, ra, di->f.ded);
ebe9383c
RH
4000}
4001
869051ea
RH
4002static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
4003 const DisasInsn *di)
ebe9383c
RH
4004{
4005 unsigned rt = extract32(insn, 0, 5);
4006 unsigned ra = extract32(insn, 21, 5);
eff235eb 4007 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
4008}
4009
869051ea
RH
4010static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
4011 const DisasInsn *di)
ebe9383c
RH
4012{
4013 unsigned rt = assemble_rt64(insn);
4014 unsigned ra = extract32(insn, 21, 5);
eff235eb 4015 return do_fop_wed(ctx, rt, ra, di->f.wed);
ebe9383c
RH
4016}
4017
869051ea
RH
4018static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
4019 const DisasInsn *di)
ebe9383c
RH
4020{
4021 unsigned rt = extract32(insn, 0, 5);
4022 unsigned ra = extract32(insn, 21, 5);
eff235eb 4023 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
4024}
4025
869051ea
RH
4026static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
4027 const DisasInsn *di)
ebe9383c
RH
4028{
4029 unsigned rt = extract32(insn, 0, 5);
4030 unsigned ra = assemble_ra64(insn);
eff235eb 4031 return do_fop_dew(ctx, rt, ra, di->f.dew);
ebe9383c
RH
4032}
4033
869051ea
RH
4034static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
4035 const DisasInsn *di)
ebe9383c
RH
4036{
4037 unsigned rt = extract32(insn, 0, 5);
4038 unsigned rb = extract32(insn, 16, 5);
4039 unsigned ra = extract32(insn, 21, 5);
eff235eb 4040 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
4041}
4042
869051ea
RH
4043static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
4044 const DisasInsn *di)
ebe9383c
RH
4045{
4046 unsigned rt = assemble_rt64(insn);
4047 unsigned rb = assemble_rb64(insn);
4048 unsigned ra = assemble_ra64(insn);
eff235eb 4049 return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
ebe9383c
RH
4050}
4051
869051ea
RH
4052static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
4053 const DisasInsn *di)
ebe9383c
RH
4054{
4055 unsigned rt = extract32(insn, 0, 5);
4056 unsigned rb = extract32(insn, 16, 5);
4057 unsigned ra = extract32(insn, 21, 5);
eff235eb 4058 return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
ebe9383c
RH
4059}
4060
4061static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4062{
4063 tcg_gen_mov_i32(dst, src);
4064}
4065
4066static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4067{
4068 tcg_gen_mov_i64(dst, src);
4069}
4070
4071static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4072{
4073 tcg_gen_andi_i32(dst, src, INT32_MAX);
4074}
4075
4076static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4077{
4078 tcg_gen_andi_i64(dst, src, INT64_MAX);
4079}
4080
4081static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4082{
4083 tcg_gen_xori_i32(dst, src, INT32_MIN);
4084}
4085
4086static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4087{
4088 tcg_gen_xori_i64(dst, src, INT64_MIN);
4089}
4090
4091static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4092{
4093 tcg_gen_ori_i32(dst, src, INT32_MIN);
4094}
4095
4096static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4097{
4098 tcg_gen_ori_i64(dst, src, INT64_MIN);
4099}
4100
869051ea
RH
4101static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
4102 unsigned y, unsigned c)
ebe9383c
RH
4103{
4104 TCGv_i32 ta, tb, tc, ty;
4105
4106 nullify_over(ctx);
4107
4108 ta = load_frw0_i32(ra);
4109 tb = load_frw0_i32(rb);
4110 ty = tcg_const_i32(y);
4111 tc = tcg_const_i32(c);
4112
4113 gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
4114
4115 tcg_temp_free_i32(ta);
4116 tcg_temp_free_i32(tb);
4117 tcg_temp_free_i32(ty);
4118 tcg_temp_free_i32(tc);
4119
869051ea 4120 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4121}
4122
869051ea
RH
4123static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
4124 const DisasInsn *di)
ebe9383c
RH
4125{
4126 unsigned c = extract32(insn, 0, 5);
4127 unsigned y = extract32(insn, 13, 3);
4128 unsigned rb = extract32(insn, 16, 5);
4129 unsigned ra = extract32(insn, 21, 5);
4130 return do_fcmp_s(ctx, ra, rb, y, c);
4131}
4132
869051ea
RH
4133static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
4134 const DisasInsn *di)
ebe9383c
RH
4135{
4136 unsigned c = extract32(insn, 0, 5);
4137 unsigned y = extract32(insn, 13, 3);
4138 unsigned rb = assemble_rb64(insn);
4139 unsigned ra = assemble_ra64(insn);
4140 return do_fcmp_s(ctx, ra, rb, y, c);
4141}
4142
869051ea
RH
4143static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
4144 const DisasInsn *di)
ebe9383c
RH
4145{
4146 unsigned c = extract32(insn, 0, 5);
4147 unsigned y = extract32(insn, 13, 3);
4148 unsigned rb = extract32(insn, 16, 5);
4149 unsigned ra = extract32(insn, 21, 5);
4150 TCGv_i64 ta, tb;
4151 TCGv_i32 tc, ty;
4152
4153 nullify_over(ctx);
4154
4155 ta = load_frd0(ra);
4156 tb = load_frd0(rb);
4157 ty = tcg_const_i32(y);
4158 tc = tcg_const_i32(c);
4159
4160 gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
4161
4162 tcg_temp_free_i64(ta);
4163 tcg_temp_free_i64(tb);
4164 tcg_temp_free_i32(ty);
4165 tcg_temp_free_i32(tc);
4166
869051ea 4167 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4168}
4169
869051ea
RH
4170static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
4171 const DisasInsn *di)
ebe9383c
RH
4172{
4173 unsigned y = extract32(insn, 13, 3);
4174 unsigned cbit = (y ^ 1) - 1;
eaa3783b 4175 TCGv_reg t;
ebe9383c
RH
4176
4177 nullify_over(ctx);
4178
4179 t = tcg_temp_new();
eaa3783b
RH
4180 tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
4181 tcg_gen_extract_reg(t, t, 21 - cbit, 1);
ebe9383c
RH
4182 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4183 tcg_temp_free(t);
4184
869051ea 4185 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4186}
4187
869051ea
RH
4188static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
4189 const DisasInsn *di)
ebe9383c
RH
4190{
4191 unsigned c = extract32(insn, 0, 5);
4192 int mask;
4193 bool inv = false;
eaa3783b 4194 TCGv_reg t;
ebe9383c
RH
4195
4196 nullify_over(ctx);
4197
4198 t = tcg_temp_new();
eaa3783b 4199 tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
ebe9383c
RH
4200
4201 switch (c) {
4202 case 0: /* simple */
eaa3783b 4203 tcg_gen_andi_reg(t, t, 0x4000000);
ebe9383c
RH
4204 ctx->null_cond = cond_make_0(TCG_COND_NE, t);
4205 goto done;
4206 case 2: /* rej */
4207 inv = true;
4208 /* fallthru */
4209 case 1: /* acc */
4210 mask = 0x43ff800;
4211 break;
4212 case 6: /* rej8 */
4213 inv = true;
4214 /* fallthru */
4215 case 5: /* acc8 */
4216 mask = 0x43f8000;
4217 break;
4218 case 9: /* acc6 */
4219 mask = 0x43e0000;
4220 break;
4221 case 13: /* acc4 */
4222 mask = 0x4380000;
4223 break;
4224 case 17: /* acc2 */
4225 mask = 0x4200000;
4226 break;
4227 default:
4228 return gen_illegal(ctx);
4229 }
4230 if (inv) {
eaa3783b
RH
4231 TCGv_reg c = load_const(ctx, mask);
4232 tcg_gen_or_reg(t, t, c);
ebe9383c
RH
4233 ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
4234 } else {
eaa3783b 4235 tcg_gen_andi_reg(t, t, mask);
ebe9383c
RH
4236 ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
4237 }
4238 done:
869051ea 4239 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4240}
4241
869051ea
RH
4242static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
4243 const DisasInsn *di)
ebe9383c
RH
4244{
4245 unsigned rt = extract32(insn, 0, 5);
4246 unsigned rb = assemble_rb64(insn);
4247 unsigned ra = assemble_ra64(insn);
4248 TCGv_i64 a, b;
4249
4250 nullify_over(ctx);
4251
4252 a = load_frw0_i64(ra);
4253 b = load_frw0_i64(rb);
4254 tcg_gen_mul_i64(a, a, b);
4255 save_frd(rt, a);
4256 tcg_temp_free_i64(a);
4257 tcg_temp_free_i64(b);
4258
869051ea 4259 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4260}
4261
eff235eb
PB
4262#define FOP_DED trans_fop_ded, .f.ded
4263#define FOP_DEDD trans_fop_dedd, .f.dedd
ebe9383c 4264
eff235eb
PB
4265#define FOP_WEW trans_fop_wew_0c, .f.wew
4266#define FOP_DEW trans_fop_dew_0c, .f.dew
4267#define FOP_WED trans_fop_wed_0c, .f.wed
4268#define FOP_WEWW trans_fop_weww_0c, .f.weww
ebe9383c
RH
4269
4270static const DisasInsn table_float_0c[] = {
4271 /* floating point class zero */
4272 { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
4273 { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
4274 { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
4275 { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
4276 { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
4277 { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
4278
4279 { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
4280 { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4281 { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4282 { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4283 { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4284 { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4285
4286 /* floating point class three */
4287 { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
4288 { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
4289 { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
4290 { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
4291
4292 { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4293 { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4294 { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4295 { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4296
4297 /* floating point class one */
4298 /* float/float */
4299 { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
4300 { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
4301 /* int/float */
4302 { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
4303 { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
4304 { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
4305 { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4306 /* float/int */
4307 { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
4308 { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
4309 { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
4310 { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4311 /* float/int truncate */
4312 { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
4313 { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
4314 { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
4315 { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4316 /* uint/float */
4317 { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
4318 { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
4319 { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
4320 { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4321 /* float/uint */
4322 { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
4323 { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
4324 { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
4325 { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4326 /* float/uint truncate */
4327 { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
4328 { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
4329 { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
4330 { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4331
4332 /* floating point class two */
4333 { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
4334 { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
4335 { 0x30002420, 0xffffffe0, trans_ftest_q },
4336 { 0x30000420, 0xffff1fff, trans_ftest_t },
4337
4338 /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0.
4339 This is machine/revision == 0, which is reserved for simulator. */
4340 { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
4341};
4342
4343#undef FOP_WEW
4344#undef FOP_DEW
4345#undef FOP_WED
4346#undef FOP_WEWW
eff235eb
PB
4347#define FOP_WEW trans_fop_wew_0e, .f.wew
4348#define FOP_DEW trans_fop_dew_0e, .f.dew
4349#define FOP_WED trans_fop_wed_0e, .f.wed
4350#define FOP_WEWW trans_fop_weww_0e, .f.weww
ebe9383c
RH
4351
4352static const DisasInsn table_float_0e[] = {
4353 /* floating point class zero */
4354 { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
4355 { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
4356 { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
4357 { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
4358 { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
4359 { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
4360
4361 { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
4362 { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
4363 { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
4364 { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
4365 { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
4366 { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
4367
4368 /* floating point class three */
4369 { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
4370 { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
4371 { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
4372 { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
4373
4374 { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
4375 { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
4376 { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
4377 { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
4378
4379 { 0x38004700, 0xfc00ef60, trans_xmpyu },
4380
4381 /* floating point class one */
4382 /* float/float */
4383 { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
4384 { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
4385 /* int/float */
4386 { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
4387 { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
4388 { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
4389 { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
4390 /* float/int */
4391 { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
4392 { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
4393 { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
4394 { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
4395 /* float/int truncate */
4396 { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
4397 { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
4398 { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
4399 { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
4400 /* uint/float */
4401 { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
4402 { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
4403 { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
4404 { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
4405 /* float/uint */
4406 { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
4407 { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
4408 { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
4409 { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
4410 /* float/uint truncate */
4411 { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
4412 { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
4413 { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
4414 { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
4415
4416 /* floating point class two */
4417 { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
4418 { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
4419};
4420
4421#undef FOP_WEW
4422#undef FOP_DEW
4423#undef FOP_WED
4424#undef FOP_WEWW
4425#undef FOP_DED
4426#undef FOP_DEDD
4427
4428/* Convert the fmpyadd single-precision register encodings to standard. */
4429static inline int fmpyadd_s_reg(unsigned r)
4430{
4431 return (r & 16) * 2 + 16 + (r & 15);
4432}
4433
869051ea
RH
4434static DisasJumpType trans_fmpyadd(DisasContext *ctx,
4435 uint32_t insn, bool is_sub)
ebe9383c
RH
4436{
4437 unsigned tm = extract32(insn, 0, 5);
4438 unsigned f = extract32(insn, 5, 1);
4439 unsigned ra = extract32(insn, 6, 5);
4440 unsigned ta = extract32(insn, 11, 5);
4441 unsigned rm2 = extract32(insn, 16, 5);
4442 unsigned rm1 = extract32(insn, 21, 5);
4443
4444 nullify_over(ctx);
4445
4446 /* Independent multiply & add/sub, with undefined behaviour
4447 if outputs overlap inputs. */
4448 if (f == 0) {
4449 tm = fmpyadd_s_reg(tm);
4450 ra = fmpyadd_s_reg(ra);
4451 ta = fmpyadd_s_reg(ta);
4452 rm2 = fmpyadd_s_reg(rm2);
4453 rm1 = fmpyadd_s_reg(rm1);
4454 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4455 do_fop_weww(ctx, ta, ta, ra,
4456 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4457 } else {
4458 do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
4459 do_fop_dedd(ctx, ta, ta, ra,
4460 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4461 }
4462
869051ea 4463 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4464}
4465
869051ea
RH
4466static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
4467 const DisasInsn *di)
ebe9383c
RH
4468{
4469 unsigned rt = assemble_rt64(insn);
4470 unsigned neg = extract32(insn, 5, 1);
4471 unsigned rm1 = assemble_ra64(insn);
4472 unsigned rm2 = assemble_rb64(insn);
4473 unsigned ra3 = assemble_rc64(insn);
4474 TCGv_i32 a, b, c;
4475
4476 nullify_over(ctx);
4477 a = load_frw0_i32(rm1);
4478 b = load_frw0_i32(rm2);
4479 c = load_frw0_i32(ra3);
4480
4481 if (neg) {
4482 gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
4483 } else {
4484 gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
4485 }
4486
4487 tcg_temp_free_i32(b);
4488 tcg_temp_free_i32(c);
4489 save_frw_i32(rt, a);
4490 tcg_temp_free_i32(a);
869051ea 4491 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4492}
4493
869051ea
RH
4494static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
4495 const DisasInsn *di)
ebe9383c
RH
4496{
4497 unsigned rt = extract32(insn, 0, 5);
4498 unsigned neg = extract32(insn, 5, 1);
4499 unsigned rm1 = extract32(insn, 21, 5);
4500 unsigned rm2 = extract32(insn, 16, 5);
4501 unsigned ra3 = assemble_rc64(insn);
4502 TCGv_i64 a, b, c;
4503
4504 nullify_over(ctx);
4505 a = load_frd0(rm1);
4506 b = load_frd0(rm2);
4507 c = load_frd0(ra3);
4508
4509 if (neg) {
4510 gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
4511 } else {
4512 gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
4513 }
4514
4515 tcg_temp_free_i64(b);
4516 tcg_temp_free_i64(c);
4517 save_frd(rt, a);
4518 tcg_temp_free_i64(a);
869051ea 4519 return nullify_end(ctx, DISAS_NEXT);
ebe9383c
RH
4520}
4521
4522static const DisasInsn table_fp_fused[] = {
4523 { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
4524 { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
4525};
4526
869051ea
RH
4527static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
4528 const DisasInsn table[], size_t n)
61766fe9
RH
4529{
4530 size_t i;
4531 for (i = 0; i < n; ++i) {
4532 if ((insn & table[i].mask) == table[i].insn) {
4533 return table[i].trans(ctx, insn, &table[i]);
4534 }
4535 }
b36942a6
RH
4536 qemu_log_mask(LOG_UNIMP, "UNIMP insn %08x @ " TARGET_FMT_lx "\n",
4537 insn, ctx->base.pc_next);
61766fe9
RH
4538 return gen_illegal(ctx);
4539}
4540
4541#define translate_table(ctx, insn, table) \
4542 translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
4543
869051ea 4544static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
61766fe9
RH
4545{
4546 uint32_t opc = extract32(insn, 26, 6);
4547
4548 switch (opc) {
98a9cb79
RH
4549 case 0x00: /* system op */
4550 return translate_table(ctx, insn, table_system);
4551 case 0x01:
4552 return translate_table(ctx, insn, table_mem_mgmt);
b2167459
RH
4553 case 0x02:
4554 return translate_table(ctx, insn, table_arith_log);
96d6407f
RH
4555 case 0x03:
4556 return translate_table(ctx, insn, table_index_mem);
ebe9383c
RH
4557 case 0x06:
4558 return trans_fmpyadd(ctx, insn, false);
b2167459
RH
4559 case 0x08:
4560 return trans_ldil(ctx, insn);
96d6407f
RH
4561 case 0x09:
4562 return trans_copr_w(ctx, insn);
b2167459
RH
4563 case 0x0A:
4564 return trans_addil(ctx, insn);
96d6407f
RH
4565 case 0x0B:
4566 return trans_copr_dw(ctx, insn);
ebe9383c
RH
4567 case 0x0C:
4568 return translate_table(ctx, insn, table_float_0c);
b2167459
RH
4569 case 0x0D:
4570 return trans_ldo(ctx, insn);
ebe9383c
RH
4571 case 0x0E:
4572 return translate_table(ctx, insn, table_float_0e);
96d6407f
RH
4573
4574 case 0x10:
4575 return trans_load(ctx, insn, false, MO_UB);
4576 case 0x11:
4577 return trans_load(ctx, insn, false, MO_TEUW);
4578 case 0x12:
4579 return trans_load(ctx, insn, false, MO_TEUL);
4580 case 0x13:
4581 return trans_load(ctx, insn, true, MO_TEUL);
4582 case 0x16:
4583 return trans_fload_mod(ctx, insn);
4584 case 0x17:
4585 return trans_load_w(ctx, insn);
4586 case 0x18:
4587 return trans_store(ctx, insn, false, MO_UB);
4588 case 0x19:
4589 return trans_store(ctx, insn, false, MO_TEUW);
4590 case 0x1A:
4591 return trans_store(ctx, insn, false, MO_TEUL);
4592 case 0x1B:
4593 return trans_store(ctx, insn, true, MO_TEUL);
4594 case 0x1E:
4595 return trans_fstore_mod(ctx, insn);
4596 case 0x1F:
4597 return trans_store_w(ctx, insn);
4598
98cd9ca7
RH
4599 case 0x20:
4600 return trans_cmpb(ctx, insn, true, false, false);
4601 case 0x21:
4602 return trans_cmpb(ctx, insn, true, true, false);
4603 case 0x22:
4604 return trans_cmpb(ctx, insn, false, false, false);
4605 case 0x23:
4606 return trans_cmpb(ctx, insn, false, true, false);
b2167459
RH
4607 case 0x24:
4608 return trans_cmpiclr(ctx, insn);
4609 case 0x25:
4610 return trans_subi(ctx, insn);
ebe9383c
RH
4611 case 0x26:
4612 return trans_fmpyadd(ctx, insn, true);
98cd9ca7
RH
4613 case 0x27:
4614 return trans_cmpb(ctx, insn, true, false, true);
4615 case 0x28:
4616 return trans_addb(ctx, insn, true, false);
4617 case 0x29:
4618 return trans_addb(ctx, insn, true, true);
4619 case 0x2A:
4620 return trans_addb(ctx, insn, false, false);
4621 case 0x2B:
4622 return trans_addb(ctx, insn, false, true);
b2167459
RH
4623 case 0x2C:
4624 case 0x2D:
4625 return trans_addi(ctx, insn);
ebe9383c
RH
4626 case 0x2E:
4627 return translate_table(ctx, insn, table_fp_fused);
98cd9ca7
RH
4628 case 0x2F:
4629 return trans_cmpb(ctx, insn, false, false, true);
96d6407f 4630
98cd9ca7
RH
4631 case 0x30:
4632 case 0x31:
4633 return trans_bb(ctx, insn);
4634 case 0x32:
4635 return trans_movb(ctx, insn, false);
4636 case 0x33:
4637 return trans_movb(ctx, insn, true);
0b1347d2
RH
4638 case 0x34:
4639 return translate_table(ctx, insn, table_sh_ex);
4640 case 0x35:
4641 return translate_table(ctx, insn, table_depw);
98cd9ca7
RH
4642 case 0x38:
4643 return trans_be(ctx, insn, false);
4644 case 0x39:
4645 return trans_be(ctx, insn, true);
4646 case 0x3A:
4647 return translate_table(ctx, insn, table_branch);
96d6407f
RH
4648
4649 case 0x04: /* spopn */
4650 case 0x05: /* diag */
4651 case 0x0F: /* product specific */
4652 break;
4653
4654 case 0x07: /* unassigned */
4655 case 0x15: /* unassigned */
4656 case 0x1D: /* unassigned */
4657 case 0x37: /* unassigned */
6210db05
HD
4658 break;
4659 case 0x3F:
4660#ifndef CONFIG_USER_ONLY
4661 /* Unassigned, but use as system-halt. */
4662 if (insn == 0xfffdead0) {
4663 return gen_hlt(ctx, 0); /* halt system */
4664 }
4665 if (insn == 0xfffdead1) {
4666 return gen_hlt(ctx, 1); /* reset system */
4667 }
4668#endif
4669 break;
61766fe9
RH
4670 default:
4671 break;
4672 }
4673 return gen_illegal(ctx);
4674}
4675
51b061fb
RH
4676static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
4677 CPUState *cs, int max_insns)
61766fe9 4678{
51b061fb 4679 DisasContext *ctx = container_of(dcbase, DisasContext, base);
f764718d 4680 int bound;
61766fe9 4681
51b061fb 4682 ctx->cs = cs;
494737b7 4683 ctx->tb_flags = ctx->base.tb->flags;
3d68ee7b
RH
4684
4685#ifdef CONFIG_USER_ONLY
4686 ctx->privilege = MMU_USER_IDX;
4687 ctx->mmu_idx = MMU_USER_IDX;
c301f34e
RH
4688 ctx->iaoq_f = ctx->base.pc_first;
4689 ctx->iaoq_b = ctx->base.tb->cs_base;
3d68ee7b 4690#else
494737b7
RH
4691 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4692 ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX);
3d68ee7b 4693
c301f34e
RH
4694 /* Recover the IAOQ values from the GVA + PRIV. */
4695 uint64_t cs_base = ctx->base.tb->cs_base;
4696 uint64_t iasq_f = cs_base & ~0xffffffffull;
4697 int32_t diff = cs_base;
4698
4699 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege;
4700 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1);
4701#endif
51b061fb 4702 ctx->iaoq_n = -1;
f764718d 4703 ctx->iaoq_n_var = NULL;
61766fe9 4704
3d68ee7b
RH
4705 /* Bound the number of instructions by those left on the page. */
4706 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4707 bound = MIN(max_insns, bound);
4708
86f8d05f
RH
4709 ctx->ntempr = 0;
4710 ctx->ntempl = 0;
4711 memset(ctx->tempr, 0, sizeof(ctx->tempr));
4712 memset(ctx->templ, 0, sizeof(ctx->templ));
61766fe9 4713
3d68ee7b 4714 return bound;
51b061fb 4715}
61766fe9 4716
51b061fb
RH
4717static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
4718{
4719 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4720
3d68ee7b 4721 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */
51b061fb
RH
4722 ctx->null_cond = cond_make_f();
4723 ctx->psw_n_nonzero = false;
494737b7 4724 if (ctx->tb_flags & PSW_N) {
51b061fb
RH
4725 ctx->null_cond.c = TCG_COND_ALWAYS;
4726 ctx->psw_n_nonzero = true;
129e9cc3 4727 }
51b061fb
RH
4728 ctx->null_lab = NULL;
4729}
129e9cc3 4730
51b061fb
RH
4731static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
4732{
4733 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4734
51b061fb
RH
4735 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
4736}
4737
4738static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
4739 const CPUBreakpoint *bp)
4740{
4741 DisasContext *ctx = container_of(dcbase, DisasContext, base);
61766fe9 4742
51b061fb 4743 ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
c301f34e 4744 ctx->base.pc_next += 4;
51b061fb
RH
4745 return true;
4746}
4747
4748static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
4749{
4750 DisasContext *ctx = container_of(dcbase, DisasContext, base);
4751 CPUHPPAState *env = cs->env_ptr;
4752 DisasJumpType ret;
4753 int i, n;
4754
4755 /* Execute one insn. */
ba1d0b44 4756#ifdef CONFIG_USER_ONLY
c301f34e 4757 if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
51b061fb
RH
4758 ret = do_page_zero(ctx);
4759 assert(ret != DISAS_NEXT);
ba1d0b44
RH
4760 } else
4761#endif
4762 {
51b061fb
RH
4763 /* Always fetch the insn, even if nullified, so that we check
4764 the page permissions for execute. */
c301f34e 4765 uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
51b061fb
RH
4766
4767 /* Set up the IA queue for the next insn.
4768 This will be overwritten by a branch. */
4769 if (ctx->iaoq_b == -1) {
4770 ctx->iaoq_n = -1;
4771 ctx->iaoq_n_var = get_temp(ctx);
eaa3783b 4772 tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4);
7ad439df 4773 } else {
51b061fb 4774 ctx->iaoq_n = ctx->iaoq_b + 4;
f764718d 4775 ctx->iaoq_n_var = NULL;
61766fe9
RH
4776 }
4777
51b061fb
RH
4778 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
4779 ctx->null_cond.c = TCG_COND_NEVER;
4780 ret = DISAS_NEXT;
4781 } else {
1a19da0d 4782 ctx->insn = insn;
51b061fb
RH
4783 ret = translate_one(ctx, insn);
4784 assert(ctx->null_lab == NULL);
61766fe9 4785 }
51b061fb 4786 }
61766fe9 4787
51b061fb 4788 /* Free any temporaries allocated. */
86f8d05f
RH
4789 for (i = 0, n = ctx->ntempr; i < n; ++i) {
4790 tcg_temp_free(ctx->tempr[i]);
4791 ctx->tempr[i] = NULL;
4792 }
4793 for (i = 0, n = ctx->ntempl; i < n; ++i) {
4794 tcg_temp_free_tl(ctx->templ[i]);
4795 ctx->templ[i] = NULL;
51b061fb 4796 }
86f8d05f
RH
4797 ctx->ntempr = 0;
4798 ctx->ntempl = 0;
61766fe9 4799
3d68ee7b
RH
4800 /* Advance the insn queue. Note that this check also detects
4801 a priority change within the instruction queue. */
51b061fb 4802 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
c301f34e
RH
4803 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1
4804 && use_goto_tb(ctx, ctx->iaoq_b)
4805 && (ctx->null_cond.c == TCG_COND_NEVER
4806 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
51b061fb
RH
4807 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4808 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
4809 ret = DISAS_NORETURN;
4810 } else {
4811 ret = DISAS_IAQ_N_STALE;
c301f34e 4812 }
61766fe9 4813 }
51b061fb
RH
4814 ctx->iaoq_f = ctx->iaoq_b;
4815 ctx->iaoq_b = ctx->iaoq_n;
4816 ctx->base.is_jmp = ret;
c301f34e 4817 ctx->base.pc_next += 4;
51b061fb
RH
4818
4819 if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
4820 return;
4821 }
4822 if (ctx->iaoq_f == -1) {
eaa3783b 4823 tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b);
51b061fb 4824 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
c301f34e
RH
4825#ifndef CONFIG_USER_ONLY
4826 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
4827#endif
51b061fb
RH
4828 nullify_save(ctx);
4829 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
4830 } else if (ctx->iaoq_b == -1) {
eaa3783b 4831 tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var);
51b061fb
RH
4832 }
4833}
4834
4835static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
4836{
4837 DisasContext *ctx = container_of(dcbase, DisasContext, base);
e1b5a5ed 4838 DisasJumpType is_jmp = ctx->base.is_jmp;
61766fe9 4839
e1b5a5ed 4840 switch (is_jmp) {
869051ea 4841 case DISAS_NORETURN:
61766fe9 4842 break;
51b061fb 4843 case DISAS_TOO_MANY:
869051ea 4844 case DISAS_IAQ_N_STALE:
e1b5a5ed 4845 case DISAS_IAQ_N_STALE_EXIT:
51b061fb
RH
4846 copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
4847 copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
4848 nullify_save(ctx);
61766fe9 4849 /* FALLTHRU */
869051ea 4850 case DISAS_IAQ_N_UPDATED:
51b061fb 4851 if (ctx->base.singlestep_enabled) {
61766fe9 4852 gen_excp_1(EXCP_DEBUG);
e1b5a5ed
RH
4853 } else if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4854 tcg_gen_exit_tb(0);
61766fe9 4855 } else {
7f11636d 4856 tcg_gen_lookup_and_goto_ptr();
61766fe9
RH
4857 }
4858 break;
4859 default:
51b061fb 4860 g_assert_not_reached();
61766fe9 4861 }
51b061fb 4862}
61766fe9 4863
51b061fb
RH
4864static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
4865{
c301f34e 4866 target_ulong pc = dcbase->pc_first;
61766fe9 4867
ba1d0b44
RH
4868#ifdef CONFIG_USER_ONLY
4869 switch (pc) {
51b061fb
RH
4870 case 0x00:
4871 qemu_log("IN:\n0x00000000: (null)\n");
ba1d0b44 4872 return;
51b061fb
RH
4873 case 0xb0:
4874 qemu_log("IN:\n0x000000b0: light-weight-syscall\n");
ba1d0b44 4875 return;
51b061fb
RH
4876 case 0xe0:
4877 qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n");
ba1d0b44 4878 return;
51b061fb
RH
4879 case 0x100:
4880 qemu_log("IN:\n0x00000100: syscall\n");
ba1d0b44 4881 return;
61766fe9 4882 }
ba1d0b44
RH
4883#endif
4884
4885 qemu_log("IN: %s\n", lookup_symbol(pc));
eaa3783b 4886 log_target_disas(cs, pc, dcbase->tb->size);
51b061fb
RH
4887}
4888
4889static const TranslatorOps hppa_tr_ops = {
4890 .init_disas_context = hppa_tr_init_disas_context,
4891 .tb_start = hppa_tr_tb_start,
4892 .insn_start = hppa_tr_insn_start,
4893 .breakpoint_check = hppa_tr_breakpoint_check,
4894 .translate_insn = hppa_tr_translate_insn,
4895 .tb_stop = hppa_tr_tb_stop,
4896 .disas_log = hppa_tr_disas_log,
4897};
4898
4899void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
4900
4901{
4902 DisasContext ctx;
4903 translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
61766fe9
RH
4904}
4905
4906void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
4907 target_ulong *data)
4908{
4909 env->iaoq_f = data[0];
86f8d05f 4910 if (data[1] != (target_ureg)-1) {
61766fe9
RH
4911 env->iaoq_b = data[1];
4912 }
4913 /* Since we were executing the instruction at IAOQ_F, and took some
4914 sort of action that provoked the cpu_restore_state, we can infer
4915 that the instruction was not nullified. */
4916 env->psw_n = 0;
4917}
This page took 0.732918 seconds and 4 git commands to generate.