target-arm: implement LDA/STL instructions
This adds support for the ARMv8 load acquire/store release instructions. Since qemu does nothing special for memory barriers, these can be emulated like their non-acquire/release counterparts. Signed-off-by: Mans Rullgard <mans@mansr.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
							parent
							
								
									81e69fb093
								
							
						
					
					
						commit
						2359bf80c1
					
				@ -7274,14 +7274,72 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
 | 
				
			|||||||
                    rd = (insn >> 12) & 0xf;
 | 
					                    rd = (insn >> 12) & 0xf;
 | 
				
			||||||
                    if (insn & (1 << 23)) {
 | 
					                    if (insn & (1 << 23)) {
 | 
				
			||||||
                        /* load/store exclusive */
 | 
					                        /* load/store exclusive */
 | 
				
			||||||
 | 
					                        int op2 = (insn >> 8) & 3;
 | 
				
			||||||
                        op1 = (insn >> 21) & 0x3;
 | 
					                        op1 = (insn >> 21) & 0x3;
 | 
				
			||||||
                        if (op1)
 | 
					
 | 
				
			||||||
 | 
					                        switch (op2) {
 | 
				
			||||||
 | 
					                        case 0: /* lda/stl */
 | 
				
			||||||
 | 
					                            if (op1 == 1) {
 | 
				
			||||||
 | 
					                                goto illegal_op;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            ARCH(8);
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 1: /* reserved */
 | 
				
			||||||
 | 
					                            goto illegal_op;
 | 
				
			||||||
 | 
					                        case 2: /* ldaex/stlex */
 | 
				
			||||||
 | 
					                            ARCH(8);
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 3: /* ldrex/strex */
 | 
				
			||||||
 | 
					                            if (op1) {
 | 
				
			||||||
                                ARCH(6K);
 | 
					                                ARCH(6K);
 | 
				
			||||||
                        else
 | 
					                            } else {
 | 
				
			||||||
                                ARCH(6);
 | 
					                                ARCH(6);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        addr = tcg_temp_local_new_i32();
 | 
					                        addr = tcg_temp_local_new_i32();
 | 
				
			||||||
                        load_reg_var(s, addr, rn);
 | 
					                        load_reg_var(s, addr, rn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        /* Since the emulation does not have barriers,
 | 
				
			||||||
 | 
					                           the acquire/release semantics need no special
 | 
				
			||||||
 | 
					                           handling */
 | 
				
			||||||
 | 
					                        if (op2 == 0) {
 | 
				
			||||||
                            if (insn & (1 << 20)) {
 | 
					                            if (insn & (1 << 20)) {
 | 
				
			||||||
 | 
					                                tmp = tcg_temp_new_i32();
 | 
				
			||||||
 | 
					                                switch (op1) {
 | 
				
			||||||
 | 
					                                case 0: /* lda */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case 2: /* ldab */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case 3: /* ldah */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                default:
 | 
				
			||||||
 | 
					                                    abort();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                store_reg(s, rd, tmp);
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                rm = insn & 0xf;
 | 
				
			||||||
 | 
					                                tmp = load_reg(s, rm);
 | 
				
			||||||
 | 
					                                switch (op1) {
 | 
				
			||||||
 | 
					                                case 0: /* stl */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case 2: /* stlb */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case 3: /* stlh */
 | 
				
			||||||
 | 
					                                    tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                default:
 | 
				
			||||||
 | 
					                                    abort();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                tcg_temp_free_i32(tmp);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } else if (insn & (1 << 20)) {
 | 
				
			||||||
                            switch (op1) {
 | 
					                            switch (op1) {
 | 
				
			||||||
                            case 0: /* ldrex */
 | 
					                            case 0: /* ldrex */
 | 
				
			||||||
                                gen_load_exclusive(s, rd, 15, addr, 2);
 | 
					                                gen_load_exclusive(s, rd, 15, addr, 2);
 | 
				
			||||||
@ -8126,7 +8184,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
 | 
				
			|||||||
                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
 | 
					                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                tcg_temp_free_i32(addr);
 | 
					                tcg_temp_free_i32(addr);
 | 
				
			||||||
            } else if ((insn & (1 << 6)) == 0) {
 | 
					            } else if ((insn & (7 << 5)) == 0) {
 | 
				
			||||||
                /* Table Branch.  */
 | 
					                /* Table Branch.  */
 | 
				
			||||||
                if (rn == 15) {
 | 
					                if (rn == 15) {
 | 
				
			||||||
                    addr = tcg_temp_new_i32();
 | 
					                    addr = tcg_temp_new_i32();
 | 
				
			||||||
@ -8152,15 +8210,66 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
 | 
				
			|||||||
                tcg_gen_addi_i32(tmp, tmp, s->pc);
 | 
					                tcg_gen_addi_i32(tmp, tmp, s->pc);
 | 
				
			||||||
                store_reg(s, 15, tmp);
 | 
					                store_reg(s, 15, tmp);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                /* Load/store exclusive byte/halfword/doubleword.  */
 | 
					                int op2 = (insn >> 6) & 0x3;
 | 
				
			||||||
                ARCH(7);
 | 
					 | 
				
			||||||
                op = (insn >> 4) & 0x3;
 | 
					                op = (insn >> 4) & 0x3;
 | 
				
			||||||
 | 
					                switch (op2) {
 | 
				
			||||||
 | 
					                case 0:
 | 
				
			||||||
 | 
					                    goto illegal_op;
 | 
				
			||||||
 | 
					                case 1:
 | 
				
			||||||
 | 
					                    /* Load/store exclusive byte/halfword/doubleword */
 | 
				
			||||||
                    if (op == 2) {
 | 
					                    if (op == 2) {
 | 
				
			||||||
                        goto illegal_op;
 | 
					                        goto illegal_op;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    ARCH(7);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 2:
 | 
				
			||||||
 | 
					                    /* Load-acquire/store-release */
 | 
				
			||||||
 | 
					                    if (op == 3) {
 | 
				
			||||||
 | 
					                        goto illegal_op;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    /* Fall through */
 | 
				
			||||||
 | 
					                case 3:
 | 
				
			||||||
 | 
					                    /* Load-acquire/store-release exclusive */
 | 
				
			||||||
 | 
					                    ARCH(8);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                addr = tcg_temp_local_new_i32();
 | 
					                addr = tcg_temp_local_new_i32();
 | 
				
			||||||
                load_reg_var(s, addr, rn);
 | 
					                load_reg_var(s, addr, rn);
 | 
				
			||||||
 | 
					                if (!(op2 & 1)) {
 | 
				
			||||||
                    if (insn & (1 << 20)) {
 | 
					                    if (insn & (1 << 20)) {
 | 
				
			||||||
 | 
					                        tmp = tcg_temp_new_i32();
 | 
				
			||||||
 | 
					                        switch (op) {
 | 
				
			||||||
 | 
					                        case 0: /* ldab */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 1: /* ldah */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 2: /* lda */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        default:
 | 
				
			||||||
 | 
					                            abort();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        store_reg(s, rs, tmp);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        tmp = load_reg(s, rs);
 | 
				
			||||||
 | 
					                        switch (op) {
 | 
				
			||||||
 | 
					                        case 0: /* stlb */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 1: /* stlh */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case 2: /* stl */
 | 
				
			||||||
 | 
					                            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        default:
 | 
				
			||||||
 | 
					                            abort();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        tcg_temp_free_i32(tmp);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else if (insn & (1 << 20)) {
 | 
				
			||||||
                    gen_load_exclusive(s, rs, rd, addr, op);
 | 
					                    gen_load_exclusive(s, rs, rd, addr, op);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
 | 
					                    gen_store_exclusive(s, rm, rs, rd, addr, op);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user