Sorry for noticing only now, but there is a missing return here as well I think: On 13 December 2013 20:17, Peter Maydell <peter.maydell@xxxxxxxxxx> wrote: > From: Alex Bennée <alex.bennee@xxxxxxxxxx> > > Implement the non-carry forms of addition and subtraction > (immediate, extended register and shifted register). > This includes the code to calculate NZCV if the instruction > calls for setting the flags. > > Signed-off-by: Alex Bennée <alex.bennee@xxxxxxxxxx> > Signed-off-by: Peter Maydell <peter.maydell@xxxxxxxxxx> > Reviewed-by: Richard Henderson <rth@xxxxxxxxxxx> > --- > target-arm/translate-a64.c | 291 ++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 285 insertions(+), 6 deletions(-) > > diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c > index 1b34a98..00dd369 100644 > --- a/target-arm/translate-a64.c > +++ b/target-arm/translate-a64.c > @@ -297,6 +297,102 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result) > tcg_gen_movi_i32(cpu_VF, 0); > } > > +/* dest = T0 + T1; compute C, N, V and Z flags */ > +static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) > +{ > + if (sf) { > + TCGv_i64 result, flag, tmp; > + result = tcg_temp_new_i64(); > + flag = tcg_temp_new_i64(); > + tmp = tcg_temp_new_i64(); > + > + tcg_gen_movi_i64(tmp, 0); > + tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp); > + > + tcg_gen_trunc_i64_i32(cpu_CF, flag); > + > + gen_set_NZ64(result); > + > + tcg_gen_xor_i64(flag, result, t0); > + tcg_gen_xor_i64(tmp, t0, t1); > + tcg_gen_andc_i64(flag, flag, tmp); > + tcg_temp_free_i64(tmp); > + tcg_gen_shri_i64(flag, flag, 32); > + tcg_gen_trunc_i64_i32(cpu_VF, flag); > + > + tcg_gen_mov_i64(dest, result); > + tcg_temp_free_i64(result); > + tcg_temp_free_i64(flag); > + } else { > + /* 32 bit arithmetic */ > + TCGv_i32 t0_32 = tcg_temp_new_i32(); > + TCGv_i32 t1_32 = tcg_temp_new_i32(); > + TCGv_i32 tmp = tcg_temp_new_i32(); > + > + tcg_gen_movi_i32(tmp, 0); > + tcg_gen_trunc_i64_i32(t0_32, t0); > + tcg_gen_trunc_i64_i32(t1_32, t1); > + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp); > + tcg_gen_mov_i32(cpu_ZF, cpu_NF); > + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32); > + tcg_gen_xor_i32(tmp, t0_32, t1_32); > + tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp); > + tcg_gen_extu_i32_i64(dest, cpu_NF); > + > + tcg_temp_free_i32(tmp); > + tcg_temp_free_i32(t0_32); > + tcg_temp_free_i32(t1_32); > + } > +} > + > +/* dest = T0 - T1; compute C, N, V and Z flags */ > +static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) > +{ > + if (sf) { > + /* 64 bit arithmetic */ > + TCGv_i64 result, flag, tmp; > + > + result = tcg_temp_new_i64(); > + flag = tcg_temp_new_i64(); > + tcg_gen_sub_i64(result, t0, t1); > + > + gen_set_NZ64(result); > + > + tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1); > + tcg_gen_trunc_i64_i32(cpu_CF, flag); > + > + tcg_gen_xor_i64(flag, result, t0); > + tmp = tcg_temp_new_i64(); > + tcg_gen_xor_i64(tmp, t0, t1); > + tcg_gen_and_i64(flag, flag, tmp); > + tcg_temp_free_i64(tmp); > + tcg_gen_shri_i64(flag, flag, 32); > + tcg_gen_trunc_i64_i32(cpu_VF, flag); > + tcg_gen_mov_i64(dest, result); > + tcg_temp_free_i64(flag); > + tcg_temp_free_i64(result); > + } else { > + /* 32 bit arithmetic */ > + TCGv_i32 t0_32 = tcg_temp_new_i32(); > + TCGv_i32 t1_32 = tcg_temp_new_i32(); > + TCGv_i32 tmp; > + > + tcg_gen_trunc_i64_i32(t0_32, t0); > + tcg_gen_trunc_i64_i32(t1_32, t1); > + tcg_gen_sub_i32(cpu_NF, t0_32, t1_32); > + tcg_gen_mov_i32(cpu_ZF, cpu_NF); > + tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32); > + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32); > + tmp = tcg_temp_new_i32(); > + tcg_gen_xor_i32(tmp, t0_32, t1_32); > + tcg_temp_free_i32(t0_32); > + tcg_temp_free_i32(t1_32); > + tcg_gen_and_i32(cpu_VF, cpu_VF, tmp); > + tcg_temp_free_i32(tmp); > + tcg_gen_extu_i32_i64(dest, cpu_NF); > + } > +} > + > /* > * Load/Store generators > */ > @@ -1326,10 +1422,67 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) > tcg_gen_movi_i64(cpu_reg(s, rd), base + offset); > } > > -/* Add/subtract (immediate) */ > +/* > + * C3.4.1 Add/subtract (immediate) > + * > + * 31 30 29 28 24 23 22 21 10 9 5 4 0 > + * +--+--+--+-----------+-----+-------------+-----+-----+ > + * |sf|op| S| 1 0 0 0 1 |shift| imm12 | Rn | Rd | > + * +--+--+--+-----------+-----+-------------+-----+-----+ > + * > + * sf: 0 -> 32bit, 1 -> 64bit > + * op: 0 -> add , 1 -> sub > + * S: 1 -> set flags > + * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12 > + */ > static void disas_add_sub_imm(DisasContext *s, uint32_t insn) > { > - unsupported_encoding(s, insn); > + int rd = extract32(insn, 0, 5); > + int rn = extract32(insn, 5, 5); > + uint64_t imm = extract32(insn, 10, 12); > + int shift = extract32(insn, 22, 2); > + bool setflags = extract32(insn, 29, 1); > + bool sub_op = extract32(insn, 30, 1); > + bool is_64bit = extract32(insn, 31, 1); > + > + TCGv_i64 tcg_rn = cpu_reg_sp(s, rn); > + TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd); > + TCGv_i64 tcg_result; > + > + switch (shift) { > + case 0x0: > + break; > + case 0x1: > + imm <<= 12; > + break; > + default: > + unallocated_encoding(s); should return; here I think. > + } > + > + tcg_result = tcg_temp_new_i64(); > + if (!setflags) { > + if (sub_op) { > + tcg_gen_subi_i64(tcg_result, tcg_rn, imm); > + } else { > + tcg_gen_addi_i64(tcg_result, tcg_rn, imm); > + } > + } else { > + TCGv_i64 tcg_imm = tcg_const_i64(imm); > + if (sub_op) { > + gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); > + } else { > + gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); > + } > + tcg_temp_free_i64(tcg_imm); > + } > + > + if (is_64bit) { > + tcg_gen_mov_i64(tcg_rd, tcg_result); > + } else { > + tcg_gen_ext32u_i64(tcg_rd, tcg_result); > + } > + > + tcg_temp_free_i64(tcg_result); > } > > /* The input should be a value in the bottom e bits (with higher > @@ -1787,16 +1940,142 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn) > } > } > > -/* Add/subtract (extended register) */ > +/* > + * C3.5.1 Add/subtract (extended register) > + * > + * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0| > + * +--+--+--+-----------+-----+--+-------+------+------+----+----+ > + * |sf|op| S| 0 1 0 1 1 | opt | 1| Rm |option| imm3 | Rn | Rd | > + * +--+--+--+-----------+-----+--+-------+------+------+----+----+ > + * > + * sf: 0 -> 32bit, 1 -> 64bit > + * op: 0 -> add , 1 -> sub > + * S: 1 -> set flags > + * opt: 00 > + * option: extension type (see DecodeRegExtend) > + * imm3: optional shift to Rm > + * > + * Rd = Rn + LSL(extend(Rm), amount) > + */ > static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) > { > - unsupported_encoding(s, insn); > + int rd = extract32(insn, 0, 5); > + int rn = extract32(insn, 5, 5); > + int imm3 = extract32(insn, 10, 3); > + int option = extract32(insn, 13, 3); > + int rm = extract32(insn, 16, 5); > + bool setflags = extract32(insn, 29, 1); > + bool sub_op = extract32(insn, 30, 1); > + bool sf = extract32(insn, 31, 1); > + > + TCGv_i64 tcg_rm, tcg_rn; /* temps */ > + TCGv_i64 tcg_rd; > + TCGv_i64 tcg_result; > + > + if (imm3 > 4) { > + unallocated_encoding(s); > + return; > + } > + > + /* non-flag setting ops may use SP */ > + if (!setflags) { > + tcg_rn = read_cpu_reg_sp(s, rn, sf); > + tcg_rd = cpu_reg_sp(s, rd); > + } else { > + tcg_rn = read_cpu_reg(s, rn, sf); > + tcg_rd = cpu_reg(s, rd); > + } > + > + tcg_rm = read_cpu_reg(s, rm, sf); > + ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3); > + > + tcg_result = tcg_temp_new_i64(); > + > + if (!setflags) { > + if (sub_op) { > + tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm); > + } else { > + tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm); > + } > + } else { > + if (sub_op) { > + gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm); > + } else { > + gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm); > + } > + } > + > + if (sf) { > + tcg_gen_mov_i64(tcg_rd, tcg_result); > + } else { > + tcg_gen_ext32u_i64(tcg_rd, tcg_result); > + } > + > + tcg_temp_free_i64(tcg_result); > } > > -/* Add/subtract (shifted register) */ > +/* > + * C3.5.2 Add/subtract (shifted register) > + * > + * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0 > + * +--+--+--+-----------+-----+--+-------+---------+------+------+ > + * |sf|op| S| 0 1 0 1 1 |shift| 0| Rm | imm6 | Rn | Rd | > + * +--+--+--+-----------+-----+--+-------+---------+------+------+ > + * > + * sf: 0 -> 32bit, 1 -> 64bit > + * op: 0 -> add , 1 -> sub > + * S: 1 -> set flags > + * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED > + * imm6: Shift amount to apply to Rm before the add/sub > + */ > static void disas_add_sub_reg(DisasContext *s, uint32_t insn) > { > - unsupported_encoding(s, insn); > + int rd = extract32(insn, 0, 5); > + int rn = extract32(insn, 5, 5); > + int imm6 = extract32(insn, 10, 6); > + int rm = extract32(insn, 16, 5); > + int shift_type = extract32(insn, 22, 2); > + bool setflags = extract32(insn, 29, 1); > + bool sub_op = extract32(insn, 30, 1); > + bool sf = extract32(insn, 31, 1); > + > + TCGv_i64 tcg_rd = cpu_reg(s, rd); > + TCGv_i64 tcg_rn, tcg_rm; > + TCGv_i64 tcg_result; > + > + if ((shift_type == 3) || (!sf && (imm6 > 31))) { > + unallocated_encoding(s); > + return; > + } > + > + tcg_rn = read_cpu_reg(s, rn, sf); > + tcg_rm = read_cpu_reg(s, rm, sf); > + > + shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6); > + > + tcg_result = tcg_temp_new_i64(); > + > + if (!setflags) { > + if (sub_op) { > + tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm); > + } else { > + tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm); > + } > + } else { > + if (sub_op) { > + gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm); > + } else { > + gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm); > + } > + } > + > + if (sf) { > + tcg_gen_mov_i64(tcg_rd, tcg_result); > + } else { > + tcg_gen_ext32u_i64(tcg_rd, tcg_result); > + } > + > + tcg_temp_free_i64(tcg_result); > } > > /* Data-processing (3 source) */ > -- > 1.8.5 > _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm