Revision 4f3adfb2
b/target-s390x/translate.c | ||
---|---|---|
79 | 79 |
static uint64_t inline_branch_miss[CC_OP_MAX]; |
80 | 80 |
#endif |
81 | 81 |
|
82 |
static inline void debug_insn(uint64_t insn) |
|
83 |
{ |
|
84 |
LOG_DISAS("insn: 0x%" PRIx64 "\n", insn); |
|
85 |
} |
|
86 |
|
|
87 |
static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) |
|
82 |
static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) |
|
88 | 83 |
{ |
89 | 84 |
if (!(s->tb->flags & FLAG_MASK_64)) { |
90 | 85 |
if (s->tb->flags & FLAG_MASK_32) { |
... | ... | |
200 | 195 |
#include "helper.h" |
201 | 196 |
} |
202 | 197 |
|
203 |
static inline TCGv_i64 load_reg(int reg)
|
|
198 |
static TCGv_i64 load_reg(int reg) |
|
204 | 199 |
{ |
205 | 200 |
TCGv_i64 r = tcg_temp_new_i64(); |
206 | 201 |
tcg_gen_mov_i64(r, regs[reg]); |
207 | 202 |
return r; |
208 | 203 |
} |
209 | 204 |
|
210 |
static inline TCGv_i64 load_freg(int reg) |
|
211 |
{ |
|
212 |
TCGv_i64 r = tcg_temp_new_i64(); |
|
213 |
tcg_gen_mov_i64(r, fregs[reg]); |
|
214 |
return r; |
|
215 |
} |
|
216 |
|
|
217 |
static inline TCGv_i32 load_freg32(int reg) |
|
218 |
{ |
|
219 |
TCGv_i32 r = tcg_temp_new_i32(); |
|
220 |
#if HOST_LONG_BITS == 32 |
|
221 |
tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg])); |
|
222 |
#else |
|
223 |
tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32); |
|
224 |
#endif |
|
225 |
return r; |
|
226 |
} |
|
227 |
|
|
228 |
static inline TCGv_i64 load_freg32_i64(int reg) |
|
205 |
static TCGv_i64 load_freg32_i64(int reg) |
|
229 | 206 |
{ |
230 | 207 |
TCGv_i64 r = tcg_temp_new_i64(); |
231 | 208 |
tcg_gen_shri_i64(r, fregs[reg], 32); |
232 | 209 |
return r; |
233 | 210 |
} |
234 | 211 |
|
235 |
static inline TCGv_i32 load_reg32(int reg) |
|
236 |
{ |
|
237 |
TCGv_i32 r = tcg_temp_new_i32(); |
|
238 |
tcg_gen_trunc_i64_i32(r, regs[reg]); |
|
239 |
return r; |
|
240 |
} |
|
241 |
|
|
242 |
static inline TCGv_i64 load_reg32_i64(int reg) |
|
243 |
{ |
|
244 |
TCGv_i64 r = tcg_temp_new_i64(); |
|
245 |
tcg_gen_ext32s_i64(r, regs[reg]); |
|
246 |
return r; |
|
247 |
} |
|
248 |
|
|
249 |
static inline void store_reg(int reg, TCGv_i64 v) |
|
212 |
static void store_reg(int reg, TCGv_i64 v) |
|
250 | 213 |
{ |
251 | 214 |
tcg_gen_mov_i64(regs[reg], v); |
252 | 215 |
} |
253 | 216 |
|
254 |
static inline void store_freg(int reg, TCGv_i64 v)
|
|
217 |
static void store_freg(int reg, TCGv_i64 v) |
|
255 | 218 |
{ |
256 | 219 |
tcg_gen_mov_i64(fregs[reg], v); |
257 | 220 |
} |
258 | 221 |
|
259 |
static inline void store_reg32(int reg, TCGv_i32 v) |
|
260 |
{ |
|
261 |
/* 32 bit register writes keep the upper half */ |
|
262 |
#if HOST_LONG_BITS == 32 |
|
263 |
tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); |
|
264 |
#else |
|
265 |
tcg_gen_deposit_i64(regs[reg], regs[reg], |
|
266 |
MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32); |
|
267 |
#endif |
|
268 |
} |
|
269 |
|
|
270 |
static inline void store_reg32_i64(int reg, TCGv_i64 v) |
|
222 |
static void store_reg32_i64(int reg, TCGv_i64 v) |
|
271 | 223 |
{ |
272 | 224 |
/* 32 bit register writes keep the upper half */ |
273 | 225 |
tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); |
274 | 226 |
} |
275 | 227 |
|
276 |
static inline void store_reg32h_i64(int reg, TCGv_i64 v)
|
|
228 |
static void store_reg32h_i64(int reg, TCGv_i64 v) |
|
277 | 229 |
{ |
278 | 230 |
tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); |
279 | 231 |
} |
280 | 232 |
|
281 |
static inline void store_freg32(int reg, TCGv_i32 v) |
|
282 |
{ |
|
283 |
/* 32 bit register writes keep the lower half */ |
|
284 |
#if HOST_LONG_BITS == 32 |
|
285 |
tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v); |
|
286 |
#else |
|
287 |
tcg_gen_deposit_i64(fregs[reg], fregs[reg], |
|
288 |
MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32); |
|
289 |
#endif |
|
290 |
} |
|
291 |
|
|
292 |
static inline void store_freg32_i64(int reg, TCGv_i64 v) |
|
233 |
static void store_freg32_i64(int reg, TCGv_i64 v) |
|
293 | 234 |
{ |
294 | 235 |
tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); |
295 | 236 |
} |
296 | 237 |
|
297 |
static inline void return_low128(TCGv_i64 dest)
|
|
238 |
static void return_low128(TCGv_i64 dest) |
|
298 | 239 |
{ |
299 | 240 |
tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); |
300 | 241 |
} |
301 | 242 |
|
302 |
static inline void update_psw_addr(DisasContext *s)
|
|
243 |
static void update_psw_addr(DisasContext *s) |
|
303 | 244 |
{ |
304 | 245 |
/* psw.addr */ |
305 | 246 |
tcg_gen_movi_i64(psw_addr, s->pc); |
306 | 247 |
} |
307 | 248 |
|
308 |
static inline void potential_page_fault(DisasContext *s)
|
|
249 |
static void potential_page_fault(DisasContext *s) |
|
309 | 250 |
{ |
310 | 251 |
#ifndef CONFIG_USER_ONLY |
311 | 252 |
update_psw_addr(s); |
... | ... | |
328 | 269 |
return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); |
329 | 270 |
} |
330 | 271 |
|
331 |
static inline int get_mem_index(DisasContext *s)
|
|
272 |
static int get_mem_index(DisasContext *s) |
|
332 | 273 |
{ |
333 | 274 |
switch (s->tb->flags & FLAG_MASK_ASC) { |
334 | 275 |
case PSW_ASC_PRIMARY >> 32: |
... | ... | |
440 | 381 |
s->cc_op = op; |
441 | 382 |
} |
442 | 383 |
|
443 |
static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst) |
|
444 |
{ |
|
445 |
tcg_gen_discard_i64(cc_src); |
|
446 |
tcg_gen_extu_i32_i64(cc_dst, dst); |
|
447 |
tcg_gen_discard_i64(cc_vr); |
|
448 |
s->cc_op = op; |
|
449 |
} |
|
450 |
|
|
451 | 384 |
static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, |
452 | 385 |
TCGv_i64 dst) |
453 | 386 |
{ |
... | ... | |
457 | 390 |
s->cc_op = op; |
458 | 391 |
} |
459 | 392 |
|
460 |
static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, |
|
461 |
TCGv_i32 dst) |
|
462 |
{ |
|
463 |
tcg_gen_extu_i32_i64(cc_src, src); |
|
464 |
tcg_gen_extu_i32_i64(cc_dst, dst); |
|
465 |
tcg_gen_discard_i64(cc_vr); |
|
466 |
s->cc_op = op; |
|
467 |
} |
|
468 |
|
|
469 | 393 |
static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, |
470 | 394 |
TCGv_i64 dst, TCGv_i64 vr) |
471 | 395 |
{ |
... | ... | |
475 | 399 |
s->cc_op = op; |
476 | 400 |
} |
477 | 401 |
|
478 |
static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) |
|
479 |
{ |
|
480 |
gen_op_update1_cc_i32(s, CC_OP_NZ, val); |
|
481 |
} |
|
482 |
|
|
483 |
static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) |
|
402 |
static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) |
|
484 | 403 |
{ |
485 | 404 |
gen_op_update1_cc_i64(s, CC_OP_NZ, val); |
486 | 405 |
} |
487 | 406 |
|
488 |
static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val)
|
|
407 |
static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) |
|
489 | 408 |
{ |
490 | 409 |
gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); |
491 | 410 |
} |
492 | 411 |
|
493 |
static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val)
|
|
412 |
static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) |
|
494 | 413 |
{ |
495 | 414 |
gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); |
496 | 415 |
} |
497 | 416 |
|
498 |
static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl)
|
|
417 |
static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) |
|
499 | 418 |
{ |
500 | 419 |
gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); |
501 | 420 |
} |
502 | 421 |
|
503 |
static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, |
|
504 |
enum cc_op cond) |
|
505 |
{ |
|
506 |
gen_op_update2_cc_i32(s, cond, v1, v2); |
|
507 |
} |
|
508 |
|
|
509 |
static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, |
|
510 |
enum cc_op cond) |
|
511 |
{ |
|
512 |
gen_op_update2_cc_i64(s, cond, v1, v2); |
|
513 |
} |
|
514 |
|
|
515 |
static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) |
|
516 |
{ |
|
517 |
cmp_32(s, v1, v2, CC_OP_LTGT_32); |
|
518 |
} |
|
519 |
|
|
520 |
static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) |
|
521 |
{ |
|
522 |
cmp_32(s, v1, v2, CC_OP_LTUGTU_32); |
|
523 |
} |
|
524 |
|
|
525 |
static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2) |
|
526 |
{ |
|
527 |
/* XXX optimize for the constant? put it in s? */ |
|
528 |
TCGv_i32 tmp = tcg_const_i32(v2); |
|
529 |
cmp_32(s, v1, tmp, CC_OP_LTGT_32); |
|
530 |
tcg_temp_free_i32(tmp); |
|
531 |
} |
|
532 |
|
|
533 |
static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2) |
|
534 |
{ |
|
535 |
TCGv_i32 tmp = tcg_const_i32(v2); |
|
536 |
cmp_32(s, v1, tmp, CC_OP_LTUGTU_32); |
|
537 |
tcg_temp_free_i32(tmp); |
|
538 |
} |
|
539 |
|
|
540 |
static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) |
|
541 |
{ |
|
542 |
cmp_64(s, v1, v2, CC_OP_LTGT_64); |
|
543 |
} |
|
544 |
|
|
545 |
static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) |
|
546 |
{ |
|
547 |
cmp_64(s, v1, v2, CC_OP_LTUGTU_64); |
|
548 |
} |
|
549 |
|
|
550 |
static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2) |
|
551 |
{ |
|
552 |
TCGv_i64 tmp = tcg_const_i64(v2); |
|
553 |
cmp_s64(s, v1, tmp); |
|
554 |
tcg_temp_free_i64(tmp); |
|
555 |
} |
|
556 |
|
|
557 |
static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2) |
|
558 |
{ |
|
559 |
TCGv_i64 tmp = tcg_const_i64(v2); |
|
560 |
cmp_u64(s, v1, tmp); |
|
561 |
tcg_temp_free_i64(tmp); |
|
562 |
} |
|
563 |
|
|
564 |
static inline void set_cc_s32(DisasContext *s, TCGv_i32 val) |
|
565 |
{ |
|
566 |
gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val); |
|
567 |
} |
|
568 |
|
|
569 |
static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) |
|
570 |
{ |
|
571 |
gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); |
|
572 |
} |
|
573 |
|
|
574 | 422 |
/* CC value is in env->cc_op */ |
575 |
static inline void set_cc_static(DisasContext *s)
|
|
423 |
static void set_cc_static(DisasContext *s) |
|
576 | 424 |
{ |
577 | 425 |
tcg_gen_discard_i64(cc_src); |
578 | 426 |
tcg_gen_discard_i64(cc_dst); |
... | ... | |
580 | 428 |
s->cc_op = CC_OP_STATIC; |
581 | 429 |
} |
582 | 430 |
|
583 |
static inline void gen_op_set_cc_op(DisasContext *s)
|
|
431 |
static void gen_op_set_cc_op(DisasContext *s) |
|
584 | 432 |
{ |
585 | 433 |
if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { |
586 | 434 |
tcg_gen_movi_i32(cc_op, s->cc_op); |
587 | 435 |
} |
588 | 436 |
} |
589 | 437 |
|
590 |
static inline void gen_update_cc_op(DisasContext *s)
|
|
438 |
static void gen_update_cc_op(DisasContext *s) |
|
591 | 439 |
{ |
592 | 440 |
gen_op_set_cc_op(s); |
593 | 441 |
} |
... | ... | |
667 | 515 |
set_cc_static(s); |
668 | 516 |
} |
669 | 517 |
|
670 |
static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2) |
|
671 |
{ |
|
672 |
debug_insn(insn); |
|
673 |
|
|
674 |
*r1 = (insn >> 4) & 0xf; |
|
675 |
*r2 = insn & 0xf; |
|
676 |
} |
|
677 |
|
|
678 |
static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1, |
|
679 |
int *x2, int *b2, int *d2) |
|
680 |
{ |
|
681 |
debug_insn(insn); |
|
682 |
|
|
683 |
*r1 = (insn >> 20) & 0xf; |
|
684 |
*x2 = (insn >> 16) & 0xf; |
|
685 |
*b2 = (insn >> 12) & 0xf; |
|
686 |
*d2 = insn & 0xfff; |
|
687 |
|
|
688 |
return get_address(s, *x2, *b2, *d2); |
|
689 |
} |
|
690 |
|
|
691 |
static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3, |
|
692 |
int *b2, int *d2) |
|
693 |
{ |
|
694 |
debug_insn(insn); |
|
695 |
|
|
696 |
*r1 = (insn >> 20) & 0xf; |
|
697 |
/* aka m3 */ |
|
698 |
*r3 = (insn >> 16) & 0xf; |
|
699 |
*b2 = (insn >> 12) & 0xf; |
|
700 |
*d2 = insn & 0xfff; |
|
701 |
} |
|
702 |
|
|
703 |
static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, |
|
704 |
int *b1, int *d1) |
|
705 |
{ |
|
706 |
debug_insn(insn); |
|
707 |
|
|
708 |
*i2 = (insn >> 16) & 0xff; |
|
709 |
*b1 = (insn >> 12) & 0xf; |
|
710 |
*d1 = insn & 0xfff; |
|
711 |
|
|
712 |
return get_address(s, 0, *b1, *d1); |
|
713 |
} |
|
714 |
|
|
715 | 518 |
static int use_goto_tb(DisasContext *s, uint64_t dest) |
716 | 519 |
{ |
717 | 520 |
/* NOTE: we handle the case where the TB spans two pages here */ |
... | ... | |
721 | 524 |
&& !(s->tb->cflags & CF_LAST_IO)); |
722 | 525 |
} |
723 | 526 |
|
724 |
static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) |
|
725 |
{ |
|
726 |
gen_update_cc_op(s); |
|
727 |
|
|
728 |
if (use_goto_tb(s, pc)) { |
|
729 |
tcg_gen_goto_tb(tb_num); |
|
730 |
tcg_gen_movi_i64(psw_addr, pc); |
|
731 |
tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num); |
|
732 |
} else { |
|
733 |
/* jump to another page: currently not optimized */ |
|
734 |
tcg_gen_movi_i64(psw_addr, pc); |
|
735 |
tcg_gen_exit_tb(0); |
|
736 |
} |
|
737 |
} |
|
738 |
|
|
739 |
static inline void account_noninline_branch(DisasContext *s, int cc_op) |
|
527 |
static void account_noninline_branch(DisasContext *s, int cc_op) |
|
740 | 528 |
{ |
741 | 529 |
#ifdef DEBUG_INLINE_BRANCHES |
742 | 530 |
inline_branch_miss[cc_op]++; |
743 | 531 |
#endif |
744 | 532 |
} |
745 | 533 |
|
746 |
static inline void account_inline_branch(DisasContext *s, int cc_op)
|
|
534 |
static void account_inline_branch(DisasContext *s, int cc_op) |
|
747 | 535 |
{ |
748 | 536 |
#ifdef DEBUG_INLINE_BRANCHES |
749 | 537 |
inline_branch_hit[cc_op]++; |
... | ... | |
1018 | 806 |
} |
1019 | 807 |
} |
1020 | 808 |
|
1021 |
static void disas_b2(CPUS390XState *env, DisasContext *s, int op, |
|
1022 |
uint32_t insn) |
|
1023 |
{ |
|
1024 |
#ifndef CONFIG_USER_ONLY |
|
1025 |
switch (op) { |
|
1026 |
default: |
|
1027 |
#endif |
|
1028 |
LOG_DISAS("illegal b2 operation 0x%x\n", op); |
|
1029 |
gen_illegal_opcode(s); |
|
1030 |
#ifndef CONFIG_USER_ONLY |
|
1031 |
break; |
|
1032 |
} |
|
1033 |
#endif |
|
1034 |
} |
|
1035 |
|
|
1036 |
static void disas_s390_insn(CPUS390XState *env, DisasContext *s) |
|
1037 |
{ |
|
1038 |
unsigned char opc; |
|
1039 |
uint64_t insn; |
|
1040 |
int op; |
|
1041 |
|
|
1042 |
opc = cpu_ldub_code(env, s->pc); |
|
1043 |
LOG_DISAS("opc 0x%x\n", opc); |
|
1044 |
|
|
1045 |
switch (opc) { |
|
1046 |
case 0xb2: |
|
1047 |
insn = ld_code4(env, s->pc); |
|
1048 |
op = (insn >> 16) & 0xff; |
|
1049 |
disas_b2(env, s, op, insn); |
|
1050 |
break; |
|
1051 |
default: |
|
1052 |
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); |
|
1053 |
gen_illegal_opcode(s); |
|
1054 |
break; |
|
1055 |
} |
|
1056 |
} |
|
1057 |
|
|
1058 | 809 |
/* ====================================================================== */ |
1059 | 810 |
/* Define the insn format enumeration. */ |
1060 | 811 |
#define F0(N) FMT_##N, |
... | ... | |
4108 | 3859 |
DisasFields f; |
4109 | 3860 |
DisasOps o; |
4110 | 3861 |
|
3862 |
/* Search for the insn in the table. */ |
|
4111 | 3863 |
insn = extract_insn(env, s, &f); |
4112 | 3864 |
|
4113 |
/* If not found, try the old interpreter. This includes ILLOPC. */
|
|
3865 |
/* Not found means unimplemented/illegal opcode. */
|
|
4114 | 3866 |
if (insn == NULL) { |
4115 |
disas_s390_insn(env, s); |
|
4116 |
switch (s->is_jmp) { |
|
4117 |
case DISAS_NEXT: |
|
4118 |
ret = NO_EXIT; |
|
4119 |
break; |
|
4120 |
case DISAS_TB_JUMP: |
|
4121 |
ret = EXIT_GOTO_TB; |
|
4122 |
break; |
|
4123 |
case DISAS_JUMP: |
|
4124 |
ret = EXIT_PC_UPDATED; |
|
4125 |
break; |
|
4126 |
case DISAS_EXCP: |
|
4127 |
ret = EXIT_NORETURN; |
|
4128 |
break; |
|
4129 |
default: |
|
4130 |
abort(); |
|
4131 |
} |
|
4132 |
|
|
4133 |
s->pc = s->next_pc; |
|
4134 |
return ret; |
|
3867 |
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n", |
|
3868 |
f.op, f.op2); |
|
3869 |
gen_illegal_opcode(s); |
|
3870 |
return EXIT_NORETURN; |
|
4135 | 3871 |
} |
4136 | 3872 |
|
4137 | 3873 |
/* Set up the strutures we use to communicate with the helpers. */ |
Also available in: Unified diff