Revision 5e3f878a target-arm/translate.c
b/target-arm/translate.c | ||
---|---|---|
226 | 226 |
|
227 | 227 |
#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1]) |
228 | 228 |
|
229 |
#define gen_op_addl_T0_T1_setq() \ |
|
230 |
gen_helper_add_setq(cpu_T[0], cpu_T[0], cpu_T[1]) |
|
231 |
#define gen_op_addl_T0_T1_saturate() \ |
|
232 |
gen_helper_add_saturate(cpu_T[0], cpu_T[0], cpu_T[1]) |
|
233 |
#define gen_op_subl_T0_T1_saturate() \ |
|
234 |
gen_helper_sub_saturate(cpu_T[0], cpu_T[0], cpu_T[1]) |
|
235 |
#define gen_op_addl_T0_T1_usaturate() \ |
|
236 |
gen_helper_add_usaturate(cpu_T[0], cpu_T[0], cpu_T[1]) |
|
237 |
#define gen_op_subl_T0_T1_usaturate() \ |
|
238 |
gen_helper_sub_usaturate(cpu_T[0], cpu_T[0], cpu_T[1]) |
|
239 |
|
|
240 |
/* Copy the most significant bit of T0 to all bits of T1. */ |
|
241 |
#define gen_op_signbit_T1_T0() tcg_gen_sari_i32(cpu_T[1], cpu_T[0], 31) |
|
242 |
|
|
243 | 229 |
#define gen_set_cpsr(var, mask) gen_helper_cpsr_write(var, tcg_const_i32(mask)) |
244 | 230 |
/* Set NZCV flags from the high 4 bits of var. */ |
245 | 231 |
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) |
... | ... | |
332 | 318 |
|
333 | 319 |
/* FIXME: Most targets have native widening multiplication. |
334 | 320 |
It would be good to use that instead of a full wide multiply. */ |
321 |
/* 32x32->64 multiply. Marks inputs as dead. */ |
|
322 |
static TCGv gen_mulu_i64_i32(TCGv a, TCGv b) |
|
323 |
{ |
|
324 |
TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); |
|
325 |
TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); |
|
326 |
|
|
327 |
tcg_gen_extu_i32_i64(tmp1, a); |
|
328 |
dead_tmp(a); |
|
329 |
tcg_gen_extu_i32_i64(tmp2, b); |
|
330 |
dead_tmp(b); |
|
331 |
tcg_gen_mul_i64(tmp1, tmp1, tmp2); |
|
332 |
return tmp1; |
|
333 |
} |
|
334 |
|
|
335 |
static TCGv gen_muls_i64_i32(TCGv a, TCGv b) |
|
336 |
{ |
|
337 |
TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64); |
|
338 |
TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64); |
|
339 |
|
|
340 |
tcg_gen_ext_i32_i64(tmp1, a); |
|
341 |
dead_tmp(a); |
|
342 |
tcg_gen_ext_i32_i64(tmp2, b); |
|
343 |
dead_tmp(b); |
|
344 |
tcg_gen_mul_i64(tmp1, tmp1, tmp2); |
|
345 |
return tmp1; |
|
346 |
} |
|
347 |
|
|
335 | 348 |
/* Unsigned 32x32->64 multiply. */ |
336 | 349 |
static void gen_op_mull_T0_T1(void) |
337 | 350 |
{ |
... | ... | |
361 | 374 |
} |
362 | 375 |
#define gen_op_imull_T0_T1() gen_imull(cpu_T[0], cpu_T[1]) |
363 | 376 |
|
364 |
/* Signed 32x16 multiply, top 32 bits. */ |
|
365 |
static void gen_imulw(TCGv a, TCGv b) |
|
366 |
{ |
|
367 |
gen_imull(a, b); |
|
368 |
tcg_gen_shri_i32(a, a, 16); |
|
369 |
tcg_gen_shli_i32(b, b, 16); |
|
370 |
tcg_gen_or_i32(a, a, b); |
|
371 |
} |
|
372 |
|
|
373 | 377 |
/* Swap low and high halfwords. */ |
374 | 378 |
static void gen_swap_half(TCGv var) |
375 | 379 |
{ |
... | ... | |
865 | 869 |
load_reg_var(s, cpu_T[2], reg); |
866 | 870 |
} |
867 | 871 |
|
872 |
static inline void gen_set_pc_im(uint32_t val) |
|
873 |
{ |
|
874 |
TCGv tmp = new_tmp(); |
|
875 |
tcg_gen_movi_i32(tmp, val); |
|
876 |
store_cpu_field(tmp, regs[15]); |
|
877 |
} |
|
878 |
|
|
868 | 879 |
static inline void gen_set_pc_T0(void) |
869 | 880 |
{ |
870 | 881 |
tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15])); |
... | ... | |
3818 | 3829 |
case 1: gen_op_neon_qadd_u8(); break; |
3819 | 3830 |
case 2: gen_op_neon_qadd_s16(); break; |
3820 | 3831 |
case 3: gen_op_neon_qadd_u16(); break; |
3821 |
case 4: gen_op_addl_T0_T1_saturate(); break; |
|
3822 |
case 5: gen_op_addl_T0_T1_usaturate(); break; |
|
3832 |
case 4: |
|
3833 |
gen_helper_add_saturate(cpu_T[0], cpu_T[0], cpu_T[1]); |
|
3834 |
break; |
|
3835 |
case 5: |
|
3836 |
gen_helper_add_usaturate(cpu_T[0], cpu_T[0], cpu_T[1]); |
|
3837 |
break; |
|
3823 | 3838 |
default: abort(); |
3824 | 3839 |
} |
3825 | 3840 |
break; |
... | ... | |
3867 | 3882 |
case 1: gen_op_neon_qsub_u8(); break; |
3868 | 3883 |
case 2: gen_op_neon_qsub_s16(); break; |
3869 | 3884 |
case 3: gen_op_neon_qsub_u16(); break; |
3870 |
case 4: gen_op_subl_T0_T1_saturate(); break; |
|
3871 |
case 5: gen_op_subl_T0_T1_usaturate(); break; |
|
3885 |
case 4: |
|
3886 |
gen_helper_sub_saturate(cpu_T[0], cpu_T[0], cpu_T[1]); |
|
3887 |
break; |
|
3888 |
case 5: |
|
3889 |
gen_helper_sub_usaturate(cpu_T[0], cpu_T[0], cpu_T[1]); |
|
3890 |
break; |
|
3872 | 3891 |
default: abort(); |
3873 | 3892 |
} |
3874 | 3893 |
break; |
... | ... | |
5291 | 5310 |
} |
5292 | 5311 |
} |
5293 | 5312 |
|
5313 |
|
|
5314 |
/* Store a 64-bit value to a register pair. Clobbers val. */ |
|
5315 |
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv val) |
|
5316 |
{ |
|
5317 |
TCGv tmp; |
|
5318 |
tmp = new_tmp(); |
|
5319 |
tcg_gen_trunc_i64_i32(tmp, val); |
|
5320 |
store_reg(s, rlow, tmp); |
|
5321 |
tmp = new_tmp(); |
|
5322 |
tcg_gen_shri_i64(val, val, 32); |
|
5323 |
tcg_gen_trunc_i64_i32(tmp, val); |
|
5324 |
store_reg(s, rhigh, tmp); |
|
5325 |
} |
|
5326 |
|
|
5327 |
/* load a 32-bit value from a register and perform a 64-bit accumulate. */ |
|
5328 |
static void gen_addq_lo(DisasContext *s, TCGv val, int rlow) |
|
5329 |
{ |
|
5330 |
TCGv tmp; |
|
5331 |
TCGv tmp2; |
|
5332 |
|
|
5333 |
/* Load 64-bit value rd:rn. */ |
|
5334 |
tmp = tcg_temp_new(TCG_TYPE_I64); |
|
5335 |
tmp2 = load_reg(s, rlow); |
|
5336 |
tcg_gen_extu_i32_i64(tmp, tmp2); |
|
5337 |
dead_tmp(tmp2); |
|
5338 |
tcg_gen_add_i64(val, val, tmp); |
|
5339 |
} |
|
5340 |
|
|
5341 |
/* load and add a 64-bit value from a register pair. */ |
|
5342 |
static void gen_addq(DisasContext *s, TCGv val, int rlow, int rhigh) |
|
5343 |
{ |
|
5344 |
TCGv tmp; |
|
5345 |
TCGv tmp2; |
|
5346 |
|
|
5347 |
/* Load 64-bit value rd:rn. */ |
|
5348 |
tmp = tcg_temp_new(TCG_TYPE_I64); |
|
5349 |
tmp2 = load_reg(s, rhigh); |
|
5350 |
tcg_gen_extu_i32_i64(tmp, tmp2); |
|
5351 |
dead_tmp(tmp2); |
|
5352 |
tcg_gen_shli_i64(tmp, tmp, 32); |
|
5353 |
tcg_gen_add_i64(val, val, tmp); |
|
5354 |
|
|
5355 |
tmp2 = load_reg(s, rlow); |
|
5356 |
tcg_gen_extu_i32_i64(tmp, tmp2); |
|
5357 |
dead_tmp(tmp2); |
|
5358 |
tcg_gen_add_i64(val, val, tmp); |
|
5359 |
} |
|
5360 |
|
|
5361 |
/* Set N and Z flags from a 64-bit value. */ |
|
5362 |
static void gen_logicq_cc(TCGv val) |
|
5363 |
{ |
|
5364 |
TCGv tmp = new_tmp(); |
|
5365 |
gen_helper_logicq_cc(tmp, val); |
|
5366 |
store_cpu_field(tmp, NZF); |
|
5367 |
} |
|
5368 |
|
|
5294 | 5369 |
static void disas_arm_insn(CPUState * env, DisasContext *s) |
5295 | 5370 |
{ |
5296 | 5371 |
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; |
... | ... | |
5507 | 5582 |
val = ((insn >> 4) & 0xf000) | (insn & 0xfff); |
5508 | 5583 |
if ((insn & (1 << 22)) == 0) { |
5509 | 5584 |
/* MOVW */ |
5510 |
gen_op_movl_T0_im(val); |
|
5585 |
tmp = new_tmp(); |
|
5586 |
tcg_gen_movi_i32(tmp, val); |
|
5511 | 5587 |
} else { |
5512 | 5588 |
/* MOVT */ |
5513 |
gen_movl_T0_reg(s, rd); |
|
5514 |
gen_op_movl_T1_im(0xffff); |
|
5515 |
gen_op_andl_T0_T1(); |
|
5516 |
gen_op_movl_T1_im(val << 16); |
|
5517 |
gen_op_orl_T0_T1(); |
|
5589 |
tmp = load_reg(s, rd); |
|
5590 |
tcg_gen_andi_i32(tmp, tmp, 0xffff); |
|
5591 |
tcg_gen_ori_i32(tmp, tmp, val << 16); |
|
5518 | 5592 |
} |
5519 |
gen_movl_reg_T0(s, rd);
|
|
5593 |
store_reg(s, rd, tmp);
|
|
5520 | 5594 |
} else { |
5521 | 5595 |
if (((insn >> 12) & 0xf) != 0xf) |
5522 | 5596 |
goto illegal_op; |
... | ... | |
5601 | 5675 |
case 0x5: /* saturating add/subtract */ |
5602 | 5676 |
rd = (insn >> 12) & 0xf; |
5603 | 5677 |
rn = (insn >> 16) & 0xf; |
5604 |
gen_movl_T0_reg(s, rm);
|
|
5605 |
gen_movl_T1_reg(s, rn);
|
|
5678 |
tmp = load_reg(s, rn);
|
|
5679 |
tmp2 = load_reg(s, rn);
|
|
5606 | 5680 |
if (op1 & 2) |
5607 |
gen_helper_double_saturate(cpu_T[1], cpu_T[1]);
|
|
5681 |
gen_helper_double_saturate(tmp2, tmp2);
|
|
5608 | 5682 |
if (op1 & 1) |
5609 |
gen_op_subl_T0_T1_saturate();
|
|
5683 |
gen_helper_sub_saturate(tmp, tmp, tmp2);
|
|
5610 | 5684 |
else |
5611 |
gen_op_addl_T0_T1_saturate(); |
|
5612 |
gen_movl_reg_T0(s, rd); |
|
5685 |
gen_helper_add_saturate(tmp, tmp, tmp2); |
|
5686 |
dead_tmp(tmp2); |
|
5687 |
store_reg(s, rd, tmp); |
|
5613 | 5688 |
break; |
5614 | 5689 |
case 7: /* bkpt */ |
5615 | 5690 |
gen_set_condexec(s); |
5616 |
gen_op_movl_T0_im((long)s->pc - 4); |
|
5617 |
gen_set_pc_T0(); |
|
5691 |
gen_set_pc_im(s->pc - 4); |
|
5618 | 5692 |
gen_exception(EXCP_BKPT); |
5619 | 5693 |
s->is_jmp = DISAS_JUMP; |
5620 | 5694 |
break; |
... | ... | |
5627 | 5701 |
rd = (insn >> 16) & 0xf; |
5628 | 5702 |
if (op1 == 1) { |
5629 | 5703 |
/* (32 * 16) >> 16 */ |
5630 |
gen_movl_T0_reg(s, rm);
|
|
5631 |
gen_movl_T1_reg(s, rs);
|
|
5704 |
tmp = load_reg(s, rm);
|
|
5705 |
tmp2 = load_reg(s, rs);
|
|
5632 | 5706 |
if (sh & 4) |
5633 |
gen_op_sarl_T1_im(16);
|
|
5707 |
tcg_gen_sari_i32(tmp2, tmp2, 16);
|
|
5634 | 5708 |
else |
5635 |
gen_sxth(cpu_T[1]); |
|
5636 |
gen_imulw(cpu_T[0], cpu_T[1]); |
|
5709 |
gen_sxth(tmp2); |
|
5710 |
tmp2 = gen_muls_i64_i32(tmp, tmp2); |
|
5711 |
tcg_gen_shri_i64(tmp2, tmp2, 16); |
|
5712 |
tmp = new_tmp(); |
|
5713 |
tcg_gen_trunc_i64_i32(tmp, tmp2); |
|
5637 | 5714 |
if ((sh & 2) == 0) { |
5638 |
gen_movl_T1_reg(s, rn); |
|
5639 |
gen_op_addl_T0_T1_setq(); |
|
5715 |
tmp2 = load_reg(s, rn); |
|
5716 |
gen_helper_add_setq(tmp, tmp, tmp2); |
|
5717 |
dead_tmp(tmp2); |
|
5640 | 5718 |
} |
5641 |
gen_movl_reg_T0(s, rd);
|
|
5719 |
store_reg(s, rd, tmp);
|
|
5642 | 5720 |
} else { |
5643 | 5721 |
/* 16 * 16 */ |
5644 |
gen_movl_T0_reg(s, rm); |
|
5645 |
gen_movl_T1_reg(s, rs); |
|
5646 |
gen_mulxy(cpu_T[0], cpu_T[1], sh & 2, sh & 4); |
|
5722 |
tmp = load_reg(s, rm); |
|
5723 |
tmp2 = load_reg(s, rs); |
|
5724 |
gen_mulxy(tmp, tmp2, sh & 2, sh & 4); |
|
5725 |
dead_tmp(tmp2); |
|
5647 | 5726 |
if (op1 == 2) { |
5648 |
gen_op_signbit_T1_T0();
|
|
5649 |
gen_op_addq_T0_T1(rn, rd);
|
|
5650 |
gen_movl_reg_T0(s, rn);
|
|
5651 |
gen_movl_reg_T1(s, rd);
|
|
5727 |
tmp = tcg_temp_new(TCG_TYPE_I64);
|
|
5728 |
tcg_gen_ext_i32_i64(tmp, cpu_T[0]);
|
|
5729 |
gen_addq(s, tmp, rn, rd);
|
|
5730 |
gen_storeq_reg(s, rn, rd, tmp);
|
|
5652 | 5731 |
} else { |
5653 | 5732 |
if (op1 == 0) { |
5654 |
gen_movl_T1_reg(s, rn); |
|
5655 |
gen_op_addl_T0_T1_setq(); |
|
5733 |
tmp2 = load_reg(s, rn); |
|
5734 |
gen_helper_add_setq(tmp, tmp, tmp2); |
|
5735 |
dead_tmp(tmp2); |
|
5656 | 5736 |
} |
5657 |
gen_movl_reg_T0(s, rd);
|
|
5737 |
store_reg(s, rd, tmp);
|
|
5658 | 5738 |
} |
5659 | 5739 |
} |
5660 | 5740 |
break; |
... | ... | |
5839 | 5919 |
switch (op1) { |
5840 | 5920 |
case 0: case 1: case 2: case 3: case 6: |
5841 | 5921 |
/* 32 bit mul */ |
5842 |
gen_movl_T0_reg(s, rs); |
|
5843 |
gen_movl_T1_reg(s, rm); |
|
5844 |
gen_op_mul_T0_T1(); |
|
5922 |
tmp = load_reg(s, rs); |
|
5923 |
tmp2 = load_reg(s, rm); |
|
5924 |
tcg_gen_mul_i32(tmp, tmp, tmp2); |
|
5925 |
dead_tmp(tmp2); |
|
5845 | 5926 |
if (insn & (1 << 22)) { |
5846 | 5927 |
/* Subtract (mls) */ |
5847 | 5928 |
ARCH(6T2); |
5848 |
gen_movl_T1_reg(s, rn); |
|
5849 |
gen_op_rsbl_T0_T1(); |
|
5929 |
tmp2 = load_reg(s, rn); |
|
5930 |
tcg_gen_sub_i32(tmp, tmp2, tmp); |
|
5931 |
dead_tmp(tmp2); |
|
5850 | 5932 |
} else if (insn & (1 << 21)) { |
5851 | 5933 |
/* Add */ |
5852 |
gen_movl_T1_reg(s, rn); |
|
5853 |
gen_op_addl_T0_T1(); |
|
5934 |
tmp2 = load_reg(s, rn); |
|
5935 |
tcg_gen_add_i32(tmp, tmp, tmp2); |
|
5936 |
dead_tmp(tmp2); |
|
5854 | 5937 |
} |
5855 | 5938 |
if (insn & (1 << 20)) |
5856 |
gen_op_logic_T0_cc();
|
|
5857 |
gen_movl_reg_T0(s, rd);
|
|
5939 |
gen_logic_CC(tmp);
|
|
5940 |
store_reg(s, rd, tmp);
|
|
5858 | 5941 |
break; |
5859 | 5942 |
default: |
5860 | 5943 |
/* 64 bit mul */ |
5861 |
gen_movl_T0_reg(s, rs);
|
|
5862 |
gen_movl_T1_reg(s, rm);
|
|
5944 |
tmp = load_reg(s, rs);
|
|
5945 |
tmp2 = load_reg(s, rm);
|
|
5863 | 5946 |
if (insn & (1 << 22)) |
5864 |
gen_op_imull_T0_T1();
|
|
5947 |
tmp = gen_muls_i64_i32(tmp, tmp2);
|
|
5865 | 5948 |
else |
5866 |
gen_op_mull_T0_T1();
|
|
5949 |
tmp = gen_mulu_i64_i32(tmp, tmp2);
|
|
5867 | 5950 |
if (insn & (1 << 21)) /* mult accumulate */ |
5868 |
gen_op_addq_T0_T1(rn, rd);
|
|
5951 |
gen_addq(s, tmp, rn, rd);
|
|
5869 | 5952 |
if (!(insn & (1 << 23))) { /* double accumulate */ |
5870 | 5953 |
ARCH(6); |
5871 |
gen_op_addq_lo_T0_T1(rn);
|
|
5872 |
gen_op_addq_lo_T0_T1(rd);
|
|
5954 |
gen_addq_lo(s, tmp, rn);
|
|
5955 |
gen_addq_lo(s, tmp, rd);
|
|
5873 | 5956 |
} |
5874 | 5957 |
if (insn & (1 << 20)) |
5875 |
gen_op_logicq_cc(); |
|
5876 |
gen_movl_reg_T0(s, rn); |
|
5877 |
gen_movl_reg_T1(s, rd); |
|
5958 |
gen_logicq_cc(tmp); |
|
5959 |
gen_storeq_reg(s, rn, rd, tmp); |
|
5878 | 5960 |
break; |
5879 | 5961 |
} |
5880 | 5962 |
} else { |
... | ... | |
6060 | 6142 |
dead_tmp(tmp2); |
6061 | 6143 |
store_reg(s, rd, tmp); |
6062 | 6144 |
} else if ((insn & 0x000003e0) == 0x00000060) { |
6063 |
gen_movl_T1_reg(s, rm);
|
|
6145 |
tmp = load_reg(s, rm);
|
|
6064 | 6146 |
shift = (insn >> 10) & 3; |
6065 | 6147 |
/* ??? In many cases it's not neccessary to do a |
6066 | 6148 |
rotate, a shift is sufficient. */ |
6067 | 6149 |
if (shift != 0) |
6068 |
gen_op_rorl_T1_im(shift * 8);
|
|
6150 |
tcg_gen_rori_i32(tmp, tmp, shift * 8);
|
|
6069 | 6151 |
op1 = (insn >> 20) & 7; |
6070 | 6152 |
switch (op1) { |
6071 |
case 0: gen_sxtb16(cpu_T[1]); break;
|
|
6072 |
case 2: gen_sxtb(cpu_T[1]); break;
|
|
6073 |
case 3: gen_sxth(cpu_T[1]); break;
|
|
6074 |
case 4: gen_uxtb16(cpu_T[1]); break;
|
|
6075 |
case 6: gen_uxtb(cpu_T[1]); break;
|
|
6076 |
case 7: gen_uxth(cpu_T[1]); break;
|
|
6153 |
case 0: gen_sxtb16(tmp); break;
|
|
6154 |
case 2: gen_sxtb(tmp); break;
|
|
6155 |
case 3: gen_sxth(tmp); break;
|
|
6156 |
case 4: gen_uxtb16(tmp); break;
|
|
6157 |
case 6: gen_uxtb(tmp); break;
|
|
6158 |
case 7: gen_uxth(tmp); break;
|
|
6077 | 6159 |
default: goto illegal_op; |
6078 | 6160 |
} |
6079 | 6161 |
if (rn != 15) { |
6080 |
tmp = load_reg(s, rn); |
|
6162 |
tmp2 = load_reg(s, rn);
|
|
6081 | 6163 |
if ((op1 & 3) == 0) { |
6082 |
gen_add16(cpu_T[1], tmp);
|
|
6164 |
gen_add16(tmp, tmp2);
|
|
6083 | 6165 |
} else { |
6084 |
tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
|
|
6085 |
dead_tmp(tmp); |
|
6166 |
tcg_gen_add_i32(tmp, tmp, tmp2);
|
|
6167 |
dead_tmp(tmp2);
|
|
6086 | 6168 |
} |
6087 | 6169 |
} |
6088 |
gen_movl_reg_T1(s, rd);
|
|
6170 |
store_reg(s, rd, tmp2);
|
|
6089 | 6171 |
} else if ((insn & 0x003f0f60) == 0x003f0f20) { |
6090 | 6172 |
/* rev */ |
6091 | 6173 |
tmp = load_reg(s, rm); |
... | ... | |
6108 | 6190 |
} |
6109 | 6191 |
break; |
6110 | 6192 |
case 2: /* Multiplies (Type 3). */ |
6111 |
gen_movl_T0_reg(s, rm);
|
|
6112 |
gen_movl_T1_reg(s, rs);
|
|
6193 |
tmp = load_reg(s, rm);
|
|
6194 |
tmp2 = load_reg(s, rs);
|
|
6113 | 6195 |
if (insn & (1 << 20)) { |
6114 | 6196 |
/* Signed multiply most significant [accumulate]. */ |
6115 |
gen_op_imull_T0_T1();
|
|
6197 |
tmp2 = gen_muls_i64_i32(tmp, tmp2);
|
|
6116 | 6198 |
if (insn & (1 << 5)) |
6117 |
gen_roundqd(cpu_T[0], cpu_T[1]); |
|
6118 |
else |
|
6119 |
gen_op_movl_T0_T1(); |
|
6199 |
tcg_gen_addi_i64(tmp2, tmp2, 0x80000000u); |
|
6200 |
tcg_gen_shri_i64(tmp2, tmp2, 32); |
|
6201 |
tmp = new_tmp(); |
|
6202 |
tcg_gen_trunc_i64_i32(tmp, tmp2); |
|
6120 | 6203 |
if (rn != 15) { |
6121 |
gen_movl_T1_reg(s, rn);
|
|
6204 |
tmp2 = load_reg(s, rn);
|
|
6122 | 6205 |
if (insn & (1 << 6)) { |
6123 |
gen_op_addl_T0_T1();
|
|
6206 |
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
|
6124 | 6207 |
} else { |
6125 |
gen_op_rsbl_T0_T1();
|
|
6208 |
tcg_gen_add_i32(tmp, tmp, tmp2);
|
|
6126 | 6209 |
} |
6210 |
dead_tmp(tmp2); |
|
6127 | 6211 |
} |
6128 |
gen_movl_reg_T0(s, rd);
|
|
6212 |
store_reg(s, rd, tmp);
|
|
6129 | 6213 |
} else { |
6130 | 6214 |
if (insn & (1 << 5)) |
6131 |
gen_swap_half(cpu_T[1]); |
|
6132 |
gen_smul_dual(cpu_T[0], cpu_T[1]); |
|
6215 |
gen_swap_half(tmp2); |
|
6216 |
gen_smul_dual(tmp, tmp2); |
|
6217 |
/* This addition cannot overflow. */ |
|
6218 |
if (insn & (1 << 6)) { |
|
6219 |
tcg_gen_sub_i32(tmp, tmp, tmp2); |
|
6220 |
} else { |
|
6221 |
tcg_gen_add_i32(tmp, tmp, tmp2); |
|
6222 |
} |
|
6223 |
dead_tmp(tmp2); |
|
6133 | 6224 |
if (insn & (1 << 22)) { |
6134 |
if (insn & (1 << 6)) { |
|
6135 |
/* smlald */ |
|
6136 |
gen_op_addq_T0_T1_dual(rn, rd); |
|
6137 |
} else { |
|
6138 |
/* smlsld */ |
|
6139 |
gen_op_subq_T0_T1_dual(rn, rd); |
|
6140 |
} |
|
6225 |
/* smlald, smlsld */ |
|
6226 |
tmp2 = tcg_temp_new(TCG_TYPE_I64); |
|
6227 |
tcg_gen_ext_i32_i64(tmp2, tmp); |
|
6228 |
dead_tmp(tmp); |
|
6229 |
gen_addq(s, tmp2, rn, rd); |
|
6230 |
gen_storeq_reg(s, rn, rd, tmp2); |
|
6141 | 6231 |
} else { |
6142 |
/* This addition cannot overflow. */ |
|
6143 |
if (insn & (1 << 6)) { |
|
6144 |
/* sm[ul]sd */ |
|
6145 |
gen_op_subl_T0_T1(); |
|
6146 |
} else { |
|
6147 |
/* sm[ul]ad */ |
|
6148 |
gen_op_addl_T0_T1(); |
|
6149 |
} |
|
6232 |
/* smuad, smusd, smlad, smlsd */ |
|
6150 | 6233 |
if (rn != 15) |
6151 | 6234 |
{ |
6152 |
gen_movl_T1_reg(s, rn); |
|
6153 |
gen_op_addl_T0_T1_setq(); |
|
6235 |
tmp2 = load_reg(s, rn); |
|
6236 |
gen_helper_add_setq(tmp, tmp, tmp2); |
|
6237 |
dead_tmp(tmp2); |
|
6154 | 6238 |
} |
6155 |
gen_movl_reg_T0(s, rd);
|
|
6239 |
store_reg(s, rd, tmp);
|
|
6156 | 6240 |
} |
6157 | 6241 |
} |
6158 | 6242 |
break; |
... | ... | |
6179 | 6263 |
i = (insn >> 16) & 0x1f; |
6180 | 6264 |
i = i + 1 - shift; |
6181 | 6265 |
if (rm == 15) { |
6182 |
gen_op_movl_T1_im(0); |
|
6266 |
tmp = new_tmp(); |
|
6267 |
tcg_gen_movi_i32(tmp, 0); |
|
6183 | 6268 |
} else { |
6184 |
gen_movl_T1_reg(s, rm);
|
|
6269 |
tmp = load_reg(s, rm);
|
|
6185 | 6270 |
} |
6186 | 6271 |
if (i != 32) { |
6187 |
gen_movl_T0_reg(s, rd);
|
|
6188 |
gen_bfi(cpu_T[1], cpu_T[0], cpu_T[1],
|
|
6272 |
tmp2 = load_reg(s, rd);
|
|
6273 |
gen_bfi(tmp, tmp2, tmp,
|
|
6189 | 6274 |
shift, ((1u << i) - 1) << shift); |
6275 |
dead_tmp(tmp2); |
|
6190 | 6276 |
} |
6191 |
gen_movl_reg_T1(s, rd);
|
|
6277 |
store_reg(s, rd, tmp);
|
|
6192 | 6278 |
break; |
6193 | 6279 |
case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ |
6194 | 6280 |
case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ |
6195 |
gen_movl_T1_reg(s, rm);
|
|
6281 |
tmp = load_reg(s, rm);
|
|
6196 | 6282 |
shift = (insn >> 7) & 0x1f; |
6197 | 6283 |
i = ((insn >> 16) & 0x1f) + 1; |
6198 | 6284 |
if (shift + i > 32) |
6199 | 6285 |
goto illegal_op; |
6200 | 6286 |
if (i < 32) { |
6201 | 6287 |
if (op1 & 0x20) { |
6202 |
gen_ubfx(cpu_T[1], shift, (1u << i) - 1);
|
|
6288 |
gen_ubfx(tmp, shift, (1u << i) - 1);
|
|
6203 | 6289 |
} else { |
6204 |
gen_sbfx(cpu_T[1], shift, i);
|
|
6290 |
gen_sbfx(tmp, shift, i);
|
|
6205 | 6291 |
} |
6206 | 6292 |
} |
6207 |
gen_movl_reg_T1(s, rd);
|
|
6293 |
store_reg(s, rd, tmp);
|
|
6208 | 6294 |
break; |
6209 | 6295 |
default: |
6210 | 6296 |
goto illegal_op; |
... | ... | |
6386 | 6472 |
/* branch (and link) */ |
6387 | 6473 |
val = (int32_t)s->pc; |
6388 | 6474 |
if (insn & (1 << 24)) { |
6389 |
gen_op_movl_T0_im(val); |
|
6390 |
gen_movl_reg_T0(s, 14); |
|
6475 |
tmp = new_tmp(); |
|
6476 |
tcg_gen_movi_i32(tmp, val); |
|
6477 |
store_reg(s, 14, tmp); |
|
6391 | 6478 |
} |
6392 | 6479 |
offset = (((int32_t)insn << 8) >> 8); |
6393 | 6480 |
val += (offset << 2) + 4; |
... | ... | |
6403 | 6490 |
break; |
6404 | 6491 |
case 0xf: |
6405 | 6492 |
/* swi */ |
6406 |
gen_op_movl_T0_im((long)s->pc); |
|
6407 |
gen_set_pc_T0(); |
|
6493 |
gen_set_pc_im(s->pc); |
|
6408 | 6494 |
s->is_jmp = DISAS_SWI; |
6409 | 6495 |
break; |
6410 | 6496 |
default: |
6411 | 6497 |
illegal_op: |
6412 | 6498 |
gen_set_condexec(s); |
6413 |
gen_op_movl_T0_im((long)s->pc - 4); |
|
6414 |
gen_set_pc_T0(); |
|
6499 |
gen_set_pc_im(s->pc - 4); |
|
6415 | 6500 |
gen_exception(EXCP_UDEF); |
6416 | 6501 |
s->is_jmp = DISAS_JUMP; |
6417 | 6502 |
break; |
... | ... | |
6832 | 6917 |
gen_movl_reg_T1(s, rd); |
6833 | 6918 |
break; |
6834 | 6919 |
case 1: /* Sign/zero extend. */ |
6835 |
gen_movl_T1_reg(s, rm);
|
|
6920 |
tmp = load_reg(s, rm);
|
|
6836 | 6921 |
shift = (insn >> 4) & 3; |
6837 | 6922 |
/* ??? In many cases it's not neccessary to do a |
6838 | 6923 |
rotate, a shift is sufficient. */ |
6839 | 6924 |
if (shift != 0) |
6840 |
gen_op_rorl_T1_im(shift * 8);
|
|
6925 |
tcg_gen_rori_i32(tmp, tmp, shift * 8);
|
|
6841 | 6926 |
op = (insn >> 20) & 7; |
6842 | 6927 |
switch (op) { |
6843 |
case 0: gen_sxth(cpu_T[1]); break;
|
|
6844 |
case 1: gen_uxth(cpu_T[1]); break;
|
|
6845 |
case 2: gen_sxtb16(cpu_T[1]); break;
|
|
6846 |
case 3: gen_uxtb16(cpu_T[1]); break;
|
|
6847 |
case 4: gen_sxtb(cpu_T[1]); break;
|
|
6848 |
case 5: gen_uxtb(cpu_T[1]); break;
|
|
6928 |
case 0: gen_sxth(tmp); break;
|
|
6929 |
case 1: gen_uxth(tmp); break;
|
|
6930 |
case 2: gen_sxtb16(tmp); break;
|
|
6931 |
case 3: gen_uxtb16(tmp); break;
|
|
6932 |
case 4: gen_sxtb(tmp); break;
|
|
6933 |
case 5: gen_uxtb(tmp); break;
|
|
6849 | 6934 |
default: goto illegal_op; |
6850 | 6935 |
} |
6851 | 6936 |
if (rn != 15) { |
6852 |
tmp = load_reg(s, rn); |
|
6937 |
tmp2 = load_reg(s, rn);
|
|
6853 | 6938 |
if ((op >> 1) == 1) { |
6854 |
gen_add16(cpu_T[1], tmp);
|
|
6939 |
gen_add16(tmp, tmp2);
|
|
6855 | 6940 |
} else { |
6856 |
tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
|
|
6857 |
dead_tmp(tmp); |
|
6941 |
tcg_gen_add_i32(tmp, tmp, tmp2);
|
|
6942 |
dead_tmp(tmp2);
|
|
6858 | 6943 |
} |
6859 | 6944 |
} |
6860 |
gen_movl_reg_T1(s, rd);
|
|
6945 |
store_reg(s, rd, tmp);
|
|
6861 | 6946 |
break; |
6862 | 6947 |
case 2: /* SIMD add/subtract. */ |
6863 | 6948 |
op = (insn >> 20) & 7; |
... | ... | |
6965 | 7050 |
tcg_gen_sari_i32(tmp2, tmp2, 16); |
6966 | 7051 |
else |
6967 | 7052 |
gen_sxth(tmp2); |
6968 |
gen_imulw(tmp, tmp2); |
|
6969 |
dead_tmp(tmp2); |
|
7053 |
tmp2 = gen_muls_i64_i32(tmp, tmp2); |
|
7054 |
tcg_gen_shri_i64(tmp2, tmp2, 16); |
|
7055 |
tmp = new_tmp(); |
|
7056 |
tcg_gen_trunc_i64_i32(tmp, tmp2); |
|
6970 | 7057 |
if (rs != 15) |
6971 | 7058 |
{ |
6972 | 7059 |
tmp2 = load_reg(s, rs); |
... | ... | |
7007 | 7094 |
break; |
7008 | 7095 |
case 6: case 7: /* 64-bit multiply, Divide. */ |
7009 | 7096 |
op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); |
7010 |
gen_movl_T0_reg(s, rn);
|
|
7011 |
gen_movl_T1_reg(s, rm);
|
|
7097 |
tmp = load_reg(s, rn);
|
|
7098 |
tmp2 = load_reg(s, rm);
|
|
7012 | 7099 |
if ((op & 0x50) == 0x10) { |
7013 | 7100 |
/* sdiv, udiv */ |
7014 | 7101 |
if (!arm_feature(env, ARM_FEATURE_DIV)) |
7015 | 7102 |
goto illegal_op; |
7016 | 7103 |
if (op & 0x20) |
7017 |
gen_helper_udiv(cpu_T[0], cpu_T[0], cpu_T[1]);
|
|
7104 |
gen_helper_udiv(tmp, tmp, tmp2);
|
|
7018 | 7105 |
else |
7019 |
gen_helper_sdiv(cpu_T[0], cpu_T[0], cpu_T[1]); |
|
7020 |
gen_movl_reg_T0(s, rd); |
|
7106 |
gen_helper_sdiv(tmp, tmp, tmp2); |
|
7107 |
dead_tmp(tmp2); |
|
7108 |
store_reg(s, rd, tmp); |
|
7021 | 7109 |
} else if ((op & 0xe) == 0xc) { |
7022 | 7110 |
/* Dual multiply accumulate long. */ |
7023 | 7111 |
if (op & 1) |
7024 |
gen_swap_half(cpu_T[1]);
|
|
7025 |
gen_smul_dual(cpu_T[0], cpu_T[1]);
|
|
7112 |
gen_swap_half(tmp2);
|
|
7113 |
gen_smul_dual(tmp, tmp2);
|
|
7026 | 7114 |
if (op & 0x10) { |
7027 |
gen_op_subl_T0_T1();
|
|
7115 |
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
|
7028 | 7116 |
} else { |
7029 |
gen_op_addl_T0_T1();
|
|
7117 |
tcg_gen_add_i32(tmp, tmp, tmp2);
|
|
7030 | 7118 |
} |
7031 |
gen_op_signbit_T1_T0();
|
|
7032 |
gen_op_addq_T0_T1(rs, rd);
|
|
7033 |
gen_movl_reg_T0(s, rs);
|
|
7034 |
gen_movl_reg_T1(s, rd);
|
|
7119 |
dead_tmp(tmp2);
|
|
7120 |
tmp2 = tcg_temp_new(TCG_TYPE_I64);
|
|
7121 |
gen_addq(s, tmp, rs, rd);
|
|
7122 |
gen_storeq_reg(s, rs, rd, tmp);
|
|
7035 | 7123 |
} else { |
7036 | 7124 |
if (op & 0x20) { |
7037 | 7125 |
/* Unsigned 64-bit multiply */ |
7038 |
gen_op_mull_T0_T1();
|
|
7126 |
tmp = gen_mulu_i64_i32(tmp, tmp2);
|
|
7039 | 7127 |
} else { |
7040 | 7128 |
if (op & 8) { |
7041 | 7129 |
/* smlalxy */ |
7042 |
gen_mulxy(cpu_T[0], cpu_T[1], op & 2, op & 1); |
|
7043 |
gen_op_signbit_T1_T0(); |
|
7130 |
gen_mulxy(tmp, tmp2, op & 2, op & 1); |
|
7131 |
dead_tmp(tmp2); |
|
7132 |
tmp2 = tcg_temp_new(TCG_TYPE_I64); |
|
7133 |
tcg_gen_ext_i32_i64(tmp2, tmp); |
|
7134 |
dead_tmp(tmp); |
|
7135 |
tmp = tmp2; |
|
7044 | 7136 |
} else { |
7045 | 7137 |
/* Signed 64-bit multiply */ |
7046 |
gen_op_imull_T0_T1();
|
|
7138 |
tmp = gen_muls_i64_i32(tmp, tmp2);
|
|
7047 | 7139 |
} |
7048 | 7140 |
} |
7049 | 7141 |
if (op & 4) { |
7050 | 7142 |
/* umaal */ |
7051 |
gen_op_addq_lo_T0_T1(rs);
|
|
7052 |
gen_op_addq_lo_T0_T1(rd);
|
|
7143 |
gen_addq_lo(s, tmp, rs);
|
|
7144 |
gen_addq_lo(s, tmp, rd);
|
|
7053 | 7145 |
} else if (op & 0x40) { |
7054 | 7146 |
/* 64-bit accumulate. */ |
7055 |
gen_op_addq_T0_T1(rs, rd);
|
|
7147 |
gen_addq(s, tmp, rs, rd);
|
|
7056 | 7148 |
} |
7057 |
gen_movl_reg_T0(s, rs); |
|
7058 |
gen_movl_reg_T1(s, rd); |
|
7149 |
gen_storeq_reg(s, rs, rd, tmp); |
|
7059 | 7150 |
} |
7060 | 7151 |
break; |
7061 | 7152 |
} |
... | ... | |
7299 | 7390 |
imm |= (insn >> 4) & 0xf000; |
7300 | 7391 |
if (insn & (1 << 23)) { |
7301 | 7392 |
/* movt */ |
7302 |
gen_movl_T0_reg(s, rd);
|
|
7303 |
tcg_gen_andi_i32(cpu_T[0], cpu_T[0], 0xffff);
|
|
7304 |
tcg_gen_ori_i32(cpu_T[0], cpu_T[0], imm << 16);
|
|
7393 |
tmp = load_reg(s, rd);
|
|
7394 |
tcg_gen_andi_i32(tmp, tmp, 0xffff);
|
|
7395 |
tcg_gen_ori_i32(tmp, tmp, imm << 16);
|
|
7305 | 7396 |
} else { |
7306 | 7397 |
/* movw */ |
7307 |
gen_op_movl_T0_im(imm); |
|
7398 |
tmp = new_tmp(); |
|
7399 |
tcg_gen_movi_i32(tmp, imm); |
|
7308 | 7400 |
} |
7309 | 7401 |
} else { |
7310 | 7402 |
/* Add/sub 12-bit immediate. */ |
... | ... | |
7314 | 7406 |
offset -= imm; |
7315 | 7407 |
else |
7316 | 7408 |
offset += imm; |
7317 |
gen_op_movl_T0_im(offset); |
|
7409 |
tmp = new_tmp(); |
|
7410 |
tcg_gen_movi_i32(tmp, offset); |
|
7318 | 7411 |
} else { |
7319 |
gen_movl_T0_reg(s, rn); |
|
7320 |
gen_op_movl_T1_im(imm); |
|
7412 |
tmp = load_reg(s, rn); |
|
7321 | 7413 |
if (insn & (1 << 23)) |
7322 |
gen_op_subl_T0_T1();
|
|
7414 |
tcg_gen_subi_i32(tmp, tmp, imm);
|
|
7323 | 7415 |
else |
7324 |
gen_op_addl_T0_T1();
|
|
7416 |
tcg_gen_addi_i32(tmp, tmp, imm);
|
|
7325 | 7417 |
} |
7326 | 7418 |
} |
7327 |
gen_movl_reg_T0(s, rd);
|
|
7419 |
store_reg(s, rd, tmp);
|
|
7328 | 7420 |
} |
7329 | 7421 |
} else { |
7330 | 7422 |
int shifter_out = 0; |
... | ... | |
7882 | 7974 |
rd = (insn >> 8) & 7; |
7883 | 7975 |
if (insn & (1 << 11)) { |
7884 | 7976 |
/* SP */ |
7885 |
gen_movl_T0_reg(s, 13);
|
|
7977 |
tmp = load_reg(s, 13);
|
|
7886 | 7978 |
} else { |
7887 | 7979 |
/* PC. bit 1 is ignored. */ |
7888 |
gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2); |
|
7980 |
tmp = new_tmp(); |
|
7981 |
tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2); |
|
7889 | 7982 |
} |
7890 | 7983 |
val = (insn & 0xff) * 4; |
7891 |
gen_op_movl_T1_im(val); |
|
7892 |
gen_op_addl_T0_T1(); |
|
7893 |
gen_movl_reg_T0(s, rd); |
|
7984 |
tcg_gen_addi_i32(tmp, tmp, val); |
|
7985 |
store_reg(s, rd, tmp); |
|
7894 | 7986 |
break; |
7895 | 7987 |
|
7896 | 7988 |
case 11: |
... | ... | |
8002 | 8094 |
|
8003 | 8095 |
case 0xe: /* bkpt */ |
8004 | 8096 |
gen_set_condexec(s); |
8005 |
gen_op_movl_T0_im((long)s->pc - 2); |
|
8006 |
gen_set_pc_T0(); |
|
8097 |
gen_set_pc_im(s->pc - 2); |
|
8007 | 8098 |
gen_exception(EXCP_BKPT); |
8008 | 8099 |
s->is_jmp = DISAS_JUMP; |
8009 | 8100 |
break; |
... | ... | |
8090 | 8181 |
if (cond == 0xf) { |
8091 | 8182 |
/* swi */ |
8092 | 8183 |
gen_set_condexec(s); |
8093 |
gen_op_movl_T0_im((long)s->pc | 1); |
|
8094 |
/* Don't set r15. */ |
|
8095 |
gen_set_pc_T0(); |
|
8184 |
gen_set_pc_im(s->pc | 1); |
|
8096 | 8185 |
s->is_jmp = DISAS_SWI; |
8097 | 8186 |
break; |
8098 | 8187 |
} |
... | ... | |
8130 | 8219 |
return; |
8131 | 8220 |
undef32: |
8132 | 8221 |
gen_set_condexec(s); |
8133 |
gen_op_movl_T0_im((long)s->pc - 4); |
|
8134 |
gen_set_pc_T0(); |
|
8222 |
gen_set_pc_im(s->pc - 4); |
|
8135 | 8223 |
gen_exception(EXCP_UDEF); |
8136 | 8224 |
s->is_jmp = DISAS_JUMP; |
8137 | 8225 |
return; |
8138 | 8226 |
illegal_op: |
8139 | 8227 |
undef: |
8140 | 8228 |
gen_set_condexec(s); |
8141 |
gen_op_movl_T0_im((long)s->pc - 2); |
|
8142 |
gen_set_pc_T0(); |
|
8229 |
gen_set_pc_im(s->pc - 2); |
|
8143 | 8230 |
gen_exception(EXCP_UDEF); |
8144 | 8231 |
s->is_jmp = DISAS_JUMP; |
8145 | 8232 |
} |
... | ... | |
8209 | 8296 |
for(j = 0; j < env->nb_breakpoints; j++) { |
8210 | 8297 |
if (env->breakpoints[j] == dc->pc) { |
8211 | 8298 |
gen_set_condexec(dc); |
8212 |
gen_op_movl_T0_im((long)dc->pc); |
|
8213 |
gen_set_pc_T0(); |
|
8299 |
gen_set_pc_im(dc->pc); |
|
8214 | 8300 |
gen_exception(EXCP_DEBUG); |
8215 | 8301 |
dc->is_jmp = DISAS_JUMP; |
8216 | 8302 |
/* Advance PC so that clearing the breakpoint will |
... | ... | |
8283 | 8369 |
gen_set_label(dc->condlabel); |
8284 | 8370 |
} |
8285 | 8371 |
if (dc->condjmp || !dc->is_jmp) { |
8286 |
gen_op_movl_T0_im((long)dc->pc); |
|
8287 |
gen_set_pc_T0(); |
|
8372 |
gen_set_pc_im(dc->pc); |
|
8288 | 8373 |
dc->condjmp = 0; |
8289 | 8374 |
} |
8290 | 8375 |
gen_set_condexec(dc); |
... | ... | |
8404 | 8489 |
psr & CPSR_T ? 'T' : 'A', |
8405 | 8490 |
cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); |
8406 | 8491 |
|
8492 |
#if 0 |
|
8407 | 8493 |
for (i = 0; i < 16; i++) { |
8408 | 8494 |
d.d = env->vfp.regs[i]; |
8409 | 8495 |
s0.i = d.l.lower; |
... | ... | |
8416 | 8502 |
d0.d); |
8417 | 8503 |
} |
8418 | 8504 |
cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); |
8505 |
#endif |
|
8419 | 8506 |
} |
8420 | 8507 |
|
Also available in: Unified diff