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