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