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