Revision 8e18cde3 target-arm/translate.c
b/target-arm/translate.c | ||
---|---|---|
2648 | 2648 |
tcg_temp_free_i32(tmp); |
2649 | 2649 |
} |
2650 | 2650 |
|
2651 |
static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size) |
|
2652 |
{ |
|
2653 |
/* Load a single Neon element and replicate into a 32 bit TCG reg */ |
|
2654 |
TCGv tmp; |
|
2655 |
switch (size) { |
|
2656 |
case 0: |
|
2657 |
tmp = gen_ld8u(addr, IS_USER(s)); |
|
2658 |
gen_neon_dup_u8(tmp, 0); |
|
2659 |
break; |
|
2660 |
case 1: |
|
2661 |
tmp = gen_ld16u(addr, IS_USER(s)); |
|
2662 |
gen_neon_dup_low16(tmp); |
|
2663 |
break; |
|
2664 |
case 2: |
|
2665 |
tmp = gen_ld32(addr, IS_USER(s)); |
|
2666 |
break; |
|
2667 |
default: /* Avoid compiler warnings. */ |
|
2668 |
abort(); |
|
2669 |
} |
|
2670 |
return tmp; |
|
2671 |
} |
|
2672 |
|
|
2651 | 2673 |
/* Disassemble a VFP instruction. Returns nonzero if an error occured |
2652 | 2674 |
(ie. an undefined instruction). */ |
2653 | 2675 |
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) |
... | ... | |
3890 | 3912 |
size = (insn >> 10) & 3; |
3891 | 3913 |
if (size == 3) { |
3892 | 3914 |
/* Load single element to all lanes. */ |
3893 |
if (!load) |
|
3915 |
int a = (insn >> 4) & 1; |
|
3916 |
if (!load) { |
|
3894 | 3917 |
return 1; |
3918 |
} |
|
3895 | 3919 |
size = (insn >> 6) & 3; |
3896 | 3920 |
nregs = ((insn >> 8) & 3) + 1; |
3897 |
stride = (insn & (1 << 5)) ? 2 : 1; |
|
3898 |
load_reg_var(s, addr, rn); |
|
3899 |
for (reg = 0; reg < nregs; reg++) { |
|
3900 |
switch (size) { |
|
3901 |
case 0: |
|
3902 |
tmp = gen_ld8u(addr, IS_USER(s)); |
|
3903 |
gen_neon_dup_u8(tmp, 0); |
|
3904 |
break; |
|
3905 |
case 1: |
|
3906 |
tmp = gen_ld16u(addr, IS_USER(s)); |
|
3907 |
gen_neon_dup_low16(tmp); |
|
3908 |
break; |
|
3909 |
case 2: |
|
3910 |
tmp = gen_ld32(addr, IS_USER(s)); |
|
3911 |
break; |
|
3912 |
case 3: |
|
3921 |
|
|
3922 |
if (size == 3) { |
|
3923 |
if (nregs != 4 || a == 0) { |
|
3913 | 3924 |
return 1; |
3914 |
default: /* Avoid compiler warnings. */ |
|
3915 |
abort(); |
|
3916 | 3925 |
} |
3917 |
tcg_gen_addi_i32(addr, addr, 1 << size); |
|
3918 |
tmp2 = tcg_temp_new_i32(); |
|
3919 |
tcg_gen_mov_i32(tmp2, tmp); |
|
3920 |
neon_store_reg(rd, 0, tmp2); |
|
3921 |
neon_store_reg(rd, 1, tmp); |
|
3922 |
rd += stride; |
|
3926 |
/* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */ |
|
3927 |
size = 2; |
|
3928 |
} |
|
3929 |
if (nregs == 1 && a == 1 && size == 0) { |
|
3930 |
return 1; |
|
3931 |
} |
|
3932 |
if (nregs == 3 && a == 1) { |
|
3933 |
return 1; |
|
3934 |
} |
|
3935 |
load_reg_var(s, addr, rn); |
|
3936 |
if (nregs == 1) { |
|
3937 |
/* VLD1 to all lanes: bit 5 indicates how many Dregs to write */ |
|
3938 |
tmp = gen_load_and_replicate(s, addr, size); |
|
3939 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0)); |
|
3940 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1)); |
|
3941 |
if (insn & (1 << 5)) { |
|
3942 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0)); |
|
3943 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1)); |
|
3944 |
} |
|
3945 |
tcg_temp_free_i32(tmp); |
|
3946 |
} else { |
|
3947 |
/* VLD2/3/4 to all lanes: bit 5 indicates register stride */ |
|
3948 |
stride = (insn & (1 << 5)) ? 2 : 1; |
|
3949 |
for (reg = 0; reg < nregs; reg++) { |
|
3950 |
tmp = gen_load_and_replicate(s, addr, size); |
|
3951 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0)); |
|
3952 |
tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1)); |
|
3953 |
tcg_temp_free_i32(tmp); |
|
3954 |
tcg_gen_addi_i32(addr, addr, 1 << size); |
|
3955 |
rd += stride; |
|
3956 |
} |
|
3923 | 3957 |
} |
3924 | 3958 |
stride = (1 << size) * nregs; |
3925 | 3959 |
} else { |
Also available in: Unified diff