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