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