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