target-microblaze: lwx/swx: first implementation
Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						Edgar E. Iglesias
					
				
			
			
				
	
			
			
			
						parent
						
							9c92bf7f6c
						
					
				
				
					commit
					8cc9b43f7c
				
			@@ -39,6 +39,7 @@ static void mb_cpu_reset(CPUState *s)
 | 
				
			|||||||
    mcc->parent_reset(s);
 | 
					    mcc->parent_reset(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(env, 0, offsetof(CPUMBState, breakpoints));
 | 
					    memset(env, 0, offsetof(CPUMBState, breakpoints));
 | 
				
			||||||
 | 
					    env->res_addr = RES_ADDR_NONE;
 | 
				
			||||||
    tlb_flush(env, 1);
 | 
					    tlb_flush(env, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Disable stack protector.  */
 | 
					    /* Disable stack protector.  */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -243,6 +243,10 @@ struct CPUMBState {
 | 
				
			|||||||
    /* Stack protectors. Yes, it's a hw feature.  */
 | 
					    /* Stack protectors. Yes, it's a hw feature.  */
 | 
				
			||||||
    uint32_t slr, shr;
 | 
					    uint32_t slr, shr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* lwx/swx reserved address */
 | 
				
			||||||
 | 
					#define RES_ADDR_NONE 0xffffffff /* Use 0xffffffff to indicate no reservation */
 | 
				
			||||||
 | 
					    uint32_t res_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Internal flags.  */
 | 
					    /* Internal flags.  */
 | 
				
			||||||
#define IMM_FLAG	4
 | 
					#define IMM_FLAG	4
 | 
				
			||||||
#define MSR_EE_FLAG     (1 << 8)
 | 
					#define MSR_EE_FLAG     (1 << 8)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
void do_interrupt (CPUMBState *env)
 | 
					void do_interrupt (CPUMBState *env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    env->exception_index = -1;
 | 
					    env->exception_index = -1;
 | 
				
			||||||
 | 
					    env->res_addr = RES_ADDR_NONE;
 | 
				
			||||||
    env->regs[14] = env->sregs[SR_PC];
 | 
					    env->regs[14] = env->sregs[SR_PC];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,6 +117,7 @@ void do_interrupt(CPUMBState *env)
 | 
				
			|||||||
    assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
 | 
					    assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
 | 
				
			||||||
    assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
 | 
					    assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
 | 
				
			||||||
/*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
 | 
					/*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
 | 
				
			||||||
 | 
					    env->res_addr = RES_ADDR_NONE;
 | 
				
			||||||
    switch (env->exception_index) {
 | 
					    switch (env->exception_index) {
 | 
				
			||||||
        case EXCP_HW_EXCP:
 | 
					        case EXCP_HW_EXCP:
 | 
				
			||||||
            if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
 | 
					            if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,6 +162,14 @@ static void write_carry(DisasContext *dc, TCGv v)
 | 
				
			|||||||
    tcg_temp_free(t0);
 | 
					    tcg_temp_free(t0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void write_carryi(DisasContext *dc, int carry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TCGv t0 = tcg_temp_new();
 | 
				
			||||||
 | 
					    tcg_gen_movi_tl(t0, carry ? 1 : 0);
 | 
				
			||||||
 | 
					    write_carry(dc, t0);
 | 
				
			||||||
 | 
					    tcg_temp_free(t0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* True if ALU operand b is a small immediate that may deserve
 | 
					/* True if ALU operand b is a small immediate that may deserve
 | 
				
			||||||
   faster treatment.  */
 | 
					   faster treatment.  */
 | 
				
			||||||
static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
 | 
					static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
 | 
				
			||||||
@@ -948,12 +956,13 @@ static inline void dec_byteswap(DisasContext *dc, TCGv dst, TCGv src, int size)
 | 
				
			|||||||
static void dec_load(DisasContext *dc)
 | 
					static void dec_load(DisasContext *dc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    TCGv t, *addr;
 | 
					    TCGv t, *addr;
 | 
				
			||||||
    unsigned int size, rev = 0;
 | 
					    unsigned int size, rev = 0, ex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size = 1 << (dc->opcode & 3);
 | 
					    size = 1 << (dc->opcode & 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!dc->type_b) {
 | 
					    if (!dc->type_b) {
 | 
				
			||||||
        rev = (dc->ir >> 9) & 1;
 | 
					        rev = (dc->ir >> 9) & 1;
 | 
				
			||||||
 | 
					        ex = (dc->ir >> 10) & 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
 | 
					    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
 | 
				
			||||||
@@ -963,7 +972,8 @@ static void dec_load(DisasContext *dc)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOG_DIS("l%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
 | 
					    LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
 | 
				
			||||||
 | 
					                                                        ex ? "x" : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    t_sync_flags(dc);
 | 
					    t_sync_flags(dc);
 | 
				
			||||||
    addr = compute_ldst_addr(dc, &t);
 | 
					    addr = compute_ldst_addr(dc, &t);
 | 
				
			||||||
@@ -1019,6 +1029,17 @@ static void dec_load(DisasContext *dc)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* lwx does not throw unaligned access errors, so force alignment */
 | 
				
			||||||
 | 
					    if (ex) {
 | 
				
			||||||
 | 
					        /* Force addr into the temp.  */
 | 
				
			||||||
 | 
					        if (addr != &t) {
 | 
				
			||||||
 | 
					            t = tcg_temp_new();
 | 
				
			||||||
 | 
					            tcg_gen_mov_tl(t, *addr);
 | 
				
			||||||
 | 
					            addr = &t;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tcg_gen_andi_tl(t, t, ~3);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
 | 
					    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
 | 
				
			||||||
    sync_jmpstate(dc);
 | 
					    sync_jmpstate(dc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1057,6 +1078,12 @@ static void dec_load(DisasContext *dc)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ex) { /* lwx */
 | 
				
			||||||
 | 
					        /* no support for for AXI exclusive so always clear C */
 | 
				
			||||||
 | 
					        write_carryi(dc, 0);
 | 
				
			||||||
 | 
					        tcg_gen_st_tl(*addr, cpu_env, offsetof(CPUMBState, res_addr));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (addr == &t)
 | 
					    if (addr == &t)
 | 
				
			||||||
        tcg_temp_free(t);
 | 
					        tcg_temp_free(t);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1078,12 +1105,14 @@ static void gen_store(DisasContext *dc, TCGv addr, TCGv val,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void dec_store(DisasContext *dc)
 | 
					static void dec_store(DisasContext *dc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    TCGv t, *addr;
 | 
					    TCGv t, *addr, swx_addr, r_check = 0;
 | 
				
			||||||
    unsigned int size, rev = 0;
 | 
					    int swx_skip = 0;
 | 
				
			||||||
 | 
					    unsigned int size, rev = 0, ex = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size = 1 << (dc->opcode & 3);
 | 
					    size = 1 << (dc->opcode & 3);
 | 
				
			||||||
    if (!dc->type_b) {
 | 
					    if (!dc->type_b) {
 | 
				
			||||||
        rev = (dc->ir >> 9) & 1;
 | 
					        rev = (dc->ir >> 9) & 1;
 | 
				
			||||||
 | 
					        ex = (dc->ir >> 10) & 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
 | 
					    if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
 | 
				
			||||||
@@ -1093,12 +1122,30 @@ static void dec_store(DisasContext *dc)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LOG_DIS("s%d%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "");
 | 
					    LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
 | 
				
			||||||
 | 
					                                                        ex ? "x" : "");
 | 
				
			||||||
    t_sync_flags(dc);
 | 
					    t_sync_flags(dc);
 | 
				
			||||||
    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
 | 
					    /* If we get a fault on a dslot, the jmpstate better be in sync.  */
 | 
				
			||||||
    sync_jmpstate(dc);
 | 
					    sync_jmpstate(dc);
 | 
				
			||||||
    addr = compute_ldst_addr(dc, &t);
 | 
					    addr = compute_ldst_addr(dc, &t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ex) { /* swx */
 | 
				
			||||||
 | 
					        r_check = tcg_temp_new();
 | 
				
			||||||
 | 
					        swx_addr = tcg_temp_local_new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Force addr into the swx_addr. */
 | 
				
			||||||
 | 
					        tcg_gen_mov_tl(swx_addr, *addr);
 | 
				
			||||||
 | 
					        addr = &swx_addr;
 | 
				
			||||||
 | 
					        /* swx does not throw unaligned access errors, so force alignment */
 | 
				
			||||||
 | 
					        tcg_gen_andi_tl(swx_addr, swx_addr, ~3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tcg_gen_ld_tl(r_check, cpu_env, offsetof(CPUMBState, res_addr));
 | 
				
			||||||
 | 
					        write_carryi(dc, 1);
 | 
				
			||||||
 | 
					        swx_skip = gen_new_label();
 | 
				
			||||||
 | 
					        tcg_gen_brcond_tl(TCG_COND_NE, r_check, swx_addr, swx_skip);
 | 
				
			||||||
 | 
					        write_carryi(dc, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rev && size != 4) {
 | 
					    if (rev && size != 4) {
 | 
				
			||||||
        /* Endian reverse the address. t is addr.  */
 | 
					        /* Endian reverse the address. t is addr.  */
 | 
				
			||||||
        switch (size) {
 | 
					        switch (size) {
 | 
				
			||||||
@@ -1174,6 +1221,11 @@ static void dec_store(DisasContext *dc)
 | 
				
			|||||||
        gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
 | 
					        gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
 | 
				
			||||||
                            tcg_const_tl(1), tcg_const_tl(size - 1));
 | 
					                            tcg_const_tl(1), tcg_const_tl(size - 1));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (ex) {
 | 
				
			||||||
 | 
					        gen_set_label(swx_skip);
 | 
				
			||||||
 | 
					        tcg_temp_free(r_check);
 | 
				
			||||||
 | 
					        tcg_temp_free(swx_addr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (addr == &t)
 | 
					    if (addr == &t)
 | 
				
			||||||
        tcg_temp_free(t);
 | 
					        tcg_temp_free(t);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user