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