target-tricore: Add instructions of ABS, ABSB opcode format
Add instructions of ABS, ABSB opcode format. Add microcode generator functions for ld/st of two 32bit reg as one 64bit value. Add microcode generator functions for ldmst and swap. Add helper ldlcx, lducx, stlcx and stucx. Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
		
							parent
							
								
									030c58dfb7
								
							
						
					
					
						commit
						59543d4ee1
					
				|  | @ -23,3 +23,7 @@ DEF_HELPER_2(call, void, env, i32) | |||
| DEF_HELPER_1(ret, void, env) | ||||
| DEF_HELPER_2(bisr, void, env, i32) | ||||
| DEF_HELPER_1(rfe, void, env) | ||||
| DEF_HELPER_2(ldlcx, void, env, i32) | ||||
| DEF_HELPER_2(lducx, void, env, i32) | ||||
| DEF_HELPER_2(stlcx, void, env, i32) | ||||
| DEF_HELPER_2(stucx, void, env, i32) | ||||
|  |  | |||
|  | @ -175,6 +175,27 @@ static void restore_context_upper(CPUTriCoreState *env, int ea, | |||
|     env->gpr_d[15] = cpu_ldl_data(env, ea+60); | ||||
| } | ||||
| 
 | ||||
| static void restore_context_lower(CPUTriCoreState *env, int ea, | ||||
|                                   target_ulong *ra, target_ulong *pcxi) | ||||
| { | ||||
|     *pcxi = cpu_ldl_data(env, ea); | ||||
|     *ra = cpu_ldl_data(env, ea+4); | ||||
|     env->gpr_a[2] = cpu_ldl_data(env, ea+8); | ||||
|     env->gpr_a[3] = cpu_ldl_data(env, ea+12); | ||||
|     env->gpr_d[0] = cpu_ldl_data(env, ea+16); | ||||
|     env->gpr_d[1] = cpu_ldl_data(env, ea+20); | ||||
|     env->gpr_d[2] = cpu_ldl_data(env, ea+24); | ||||
|     env->gpr_d[3] = cpu_ldl_data(env, ea+28); | ||||
|     env->gpr_a[4] = cpu_ldl_data(env, ea+32); | ||||
|     env->gpr_a[5] = cpu_ldl_data(env, ea+36); | ||||
|     env->gpr_a[6] = cpu_ldl_data(env, ea+40); | ||||
|     env->gpr_a[7] = cpu_ldl_data(env, ea+44); | ||||
|     env->gpr_d[4] = cpu_ldl_data(env, ea+48); | ||||
|     env->gpr_d[5] = cpu_ldl_data(env, ea+52); | ||||
|     env->gpr_d[6] = cpu_ldl_data(env, ea+56); | ||||
|     env->gpr_d[7] = cpu_ldl_data(env, ea+60); | ||||
| } | ||||
| 
 | ||||
| void helper_call(CPUTriCoreState *env, uint32_t next_pc) | ||||
| { | ||||
|     target_ulong tmp_FCX; | ||||
|  | @ -356,6 +377,30 @@ void helper_rfe(CPUTriCoreState *env) | |||
|     psw_write(env, new_PSW); | ||||
| } | ||||
| 
 | ||||
| void helper_ldlcx(CPUTriCoreState *env, uint32_t ea) | ||||
| { | ||||
|     uint32_t dummy; | ||||
|     /* insn doesn't load PCXI and RA */ | ||||
|     restore_context_lower(env, ea, &dummy, &dummy); | ||||
| } | ||||
| 
 | ||||
| void helper_lducx(CPUTriCoreState *env, uint32_t ea) | ||||
| { | ||||
|     uint32_t dummy; | ||||
|     /* insn doesn't load PCXI and PSW */ | ||||
|     restore_context_upper(env, ea, &dummy, &dummy); | ||||
| } | ||||
| 
 | ||||
| void helper_stlcx(CPUTriCoreState *env, uint32_t ea) | ||||
| { | ||||
|     save_context_lower(env, ea); | ||||
| } | ||||
| 
 | ||||
| void helper_stucx(CPUTriCoreState *env, uint32_t ea) | ||||
| { | ||||
|     save_context_upper(env, ea); | ||||
| } | ||||
| 
 | ||||
| static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env, | ||||
|                                                         uint32_t exception, | ||||
|                                                         int error_code, | ||||
|  |  | |||
|  | @ -115,6 +115,8 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f, | |||
|     tcg_temp_free_i32(helper_tmp);                                \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF)) | ||||
| 
 | ||||
| /* Functions for load/save to/from memory */ | ||||
| 
 | ||||
| static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2, | ||||
|  | @ -135,6 +137,62 @@ static inline void gen_offset_st(DisasContext *ctx, TCGv r1, TCGv r2, | |||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void gen_st_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx) | ||||
| { | ||||
|     TCGv_i64 temp = tcg_temp_new_i64(); | ||||
| 
 | ||||
|     tcg_gen_concat_i32_i64(temp, rl, rh); | ||||
|     tcg_gen_qemu_st_i64(temp, address, ctx->mem_idx, MO_LEQ); | ||||
| 
 | ||||
|     tcg_temp_free_i64(temp); | ||||
| } | ||||
| 
 | ||||
| static void gen_ld_2regs_64(TCGv rh, TCGv rl, TCGv address, DisasContext *ctx) | ||||
| { | ||||
|     TCGv_i64 temp = tcg_temp_new_i64(); | ||||
| 
 | ||||
|     tcg_gen_qemu_ld_i64(temp, address, ctx->mem_idx, MO_LEQ); | ||||
|     /* write back to two 32 bit regs */ | ||||
|     tcg_gen_extr_i64_i32(rl, rh, temp); | ||||
| 
 | ||||
|     tcg_temp_free_i64(temp); | ||||
| } | ||||
| 
 | ||||
| /* M(EA, word) = (M(EA, word) & ~E[a][63:32]) | (E[a][31:0] & E[a][63:32]); */ | ||||
| static void gen_ldmst(DisasContext *ctx, int ereg, TCGv ea) | ||||
| { | ||||
|     TCGv temp = tcg_temp_new(); | ||||
|     TCGv temp2 = tcg_temp_new(); | ||||
| 
 | ||||
|     /* temp = (M(EA, word) */ | ||||
|     tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); | ||||
|     /* temp = temp & ~E[a][63:32]) */ | ||||
|     tcg_gen_andc_tl(temp, temp, cpu_gpr_d[ereg+1]); | ||||
|     /* temp2 = (E[a][31:0] & E[a][63:32]); */ | ||||
|     tcg_gen_and_tl(temp2, cpu_gpr_d[ereg], cpu_gpr_d[ereg+1]); | ||||
|     /* temp = temp | temp2; */ | ||||
|     tcg_gen_or_tl(temp, temp, temp2); | ||||
|     /* M(EA, word) = temp; */ | ||||
|     tcg_gen_qemu_st_tl(temp, ea, ctx->mem_idx, MO_LEUL); | ||||
| 
 | ||||
|     tcg_temp_free(temp); | ||||
|     tcg_temp_free(temp2); | ||||
| } | ||||
| 
 | ||||
| /* tmp = M(EA, word);
 | ||||
|    M(EA, word) = D[a]; | ||||
|    D[a] = tmp[31:0];*/ | ||||
| static void gen_swap(DisasContext *ctx, int reg, TCGv ea) | ||||
| { | ||||
|     TCGv temp = tcg_temp_new(); | ||||
| 
 | ||||
|     tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); | ||||
|     tcg_gen_qemu_st_tl(cpu_gpr_d[reg], ea, ctx->mem_idx, MO_LEUL); | ||||
|     tcg_gen_mov_tl(cpu_gpr_d[reg], temp); | ||||
| 
 | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| /* Functions for arithmetic instructions  */ | ||||
| 
 | ||||
| static inline void gen_add_d(TCGv ret, TCGv r1, TCGv r2) | ||||
|  | @ -1099,8 +1157,253 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 32 bit instructions | ||||
|  */ | ||||
| 
 | ||||
| /* ABS-format */ | ||||
| static void decode_abs_ldw(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int32_t op2; | ||||
|     int32_t r1; | ||||
|     uint32_t address; | ||||
|     TCGv temp; | ||||
| 
 | ||||
|     r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|     address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2 = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_LD_A: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_D: | ||||
|         gen_ld_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_DA: | ||||
|         gen_ld_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_W: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void decode_abs_ldb(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int32_t op2; | ||||
|     int32_t r1; | ||||
|     uint32_t address; | ||||
|     TCGv temp; | ||||
| 
 | ||||
|     r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|     address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2 = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_LD_B: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_SB); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_BU: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_UB); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_H: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESW); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LD_HU: | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void decode_abs_ldst_swap(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int32_t op2; | ||||
|     int32_t r1; | ||||
|     uint32_t address; | ||||
|     TCGv temp; | ||||
| 
 | ||||
|     r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|     address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2 = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_LDMST: | ||||
|         gen_ldmst(ctx, r1, temp); | ||||
|         break; | ||||
|     case OPC2_32_ABS_SWAP_W: | ||||
|         gen_swap(ctx, r1, temp); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void decode_abs_ldst_context(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     uint32_t op2; | ||||
|     int32_t off18; | ||||
| 
 | ||||
|     off18 = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2   = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_LDLCX: | ||||
|         gen_helper_1arg(ldlcx, EA_ABS_FORMAT(off18)); | ||||
|         break; | ||||
|     case OPC2_32_ABS_LDUCX: | ||||
|         gen_helper_1arg(lducx, EA_ABS_FORMAT(off18)); | ||||
|         break; | ||||
|     case OPC2_32_ABS_STLCX: | ||||
|         gen_helper_1arg(stlcx, EA_ABS_FORMAT(off18)); | ||||
|         break; | ||||
|     case OPC2_32_ABS_STUCX: | ||||
|         gen_helper_1arg(stucx, EA_ABS_FORMAT(off18)); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void decode_abs_store(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int32_t op2; | ||||
|     int32_t r1; | ||||
|     uint32_t address; | ||||
|     TCGv temp; | ||||
| 
 | ||||
|     r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|     address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2 = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_ST_A: | ||||
|         tcg_gen_qemu_st_tl(cpu_gpr_a[r1], temp, ctx->mem_idx, MO_LESL); | ||||
|         break; | ||||
|     case OPC2_32_ABS_ST_D: | ||||
|         gen_st_2regs_64(cpu_gpr_d[r1+1], cpu_gpr_d[r1], temp, ctx); | ||||
|         break; | ||||
|     case OPC2_32_ABS_ST_DA: | ||||
|         gen_st_2regs_64(cpu_gpr_a[r1+1], cpu_gpr_a[r1], temp, ctx); | ||||
|         break; | ||||
|     case OPC2_32_ABS_ST_W: | ||||
|         tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LESL); | ||||
|         break; | ||||
| 
 | ||||
|     } | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void decode_abs_storeb_h(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int32_t op2; | ||||
|     int32_t r1; | ||||
|     uint32_t address; | ||||
|     TCGv temp; | ||||
| 
 | ||||
|     r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|     address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|     op2 = MASK_OP_ABS_OP2(ctx->opcode); | ||||
| 
 | ||||
|     temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|     switch (op2) { | ||||
|     case OPC2_32_ABS_ST_B: | ||||
|         tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_UB); | ||||
|         break; | ||||
|     case OPC2_32_ABS_ST_H: | ||||
|         tcg_gen_qemu_st_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); | ||||
|         break; | ||||
|     } | ||||
|     tcg_temp_free(temp); | ||||
| } | ||||
| 
 | ||||
| static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx) | ||||
| { | ||||
|     int op1; | ||||
|     int32_t r1; | ||||
|     int32_t address; | ||||
|     int8_t b; | ||||
|     int32_t bpos; | ||||
|     TCGv temp, temp2; | ||||
| 
 | ||||
|     op1 = MASK_OP_MAJOR(ctx->opcode); | ||||
| 
 | ||||
|     switch (op1) { | ||||
| /* ABS-format */ | ||||
|     case OPCM_32_ABS_LDW: | ||||
|         decode_abs_ldw(env, ctx); | ||||
|         break; | ||||
|     case OPCM_32_ABS_LDB: | ||||
|         decode_abs_ldb(env, ctx); | ||||
|         break; | ||||
|     case OPCM_32_ABS_LDMST_SWAP: | ||||
|         decode_abs_ldst_swap(env, ctx); | ||||
|         break; | ||||
|     case OPCM_32_ABS_LDST_CONTEXT: | ||||
|         decode_abs_ldst_context(env, ctx); | ||||
|         break; | ||||
|     case OPCM_32_ABS_STORE: | ||||
|         decode_abs_store(env, ctx); | ||||
|         break; | ||||
|     case OPCM_32_ABS_STOREB_H: | ||||
|         decode_abs_storeb_h(env, ctx); | ||||
|         break; | ||||
|     case OPC1_32_ABS_STOREQ: | ||||
|         address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|         r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|         temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
|         temp2 = tcg_temp_new(); | ||||
| 
 | ||||
|         tcg_gen_shri_tl(temp2, cpu_gpr_d[r1], 16); | ||||
|         tcg_gen_qemu_st_tl(temp2, temp, ctx->mem_idx, MO_LEUW); | ||||
| 
 | ||||
|         tcg_temp_free(temp2); | ||||
|         tcg_temp_free(temp); | ||||
|         break; | ||||
|     case OPC1_32_ABS_LD_Q: | ||||
|         address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|         r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|         temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
| 
 | ||||
|         tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); | ||||
|         tcg_gen_shli_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 16); | ||||
| 
 | ||||
|         tcg_temp_free(temp); | ||||
|         break; | ||||
|     case OPC1_32_ABS_LEA: | ||||
|         address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|         r1 = MASK_OP_ABS_S1D(ctx->opcode); | ||||
|         tcg_gen_movi_tl(cpu_gpr_a[r1], EA_ABS_FORMAT(address)); | ||||
|         break; | ||||
| /* ABSB-format */ | ||||
|     case OPC1_32_ABSB_ST_T: | ||||
|         address = MASK_OP_ABS_OFF18(ctx->opcode); | ||||
|         b = MASK_OP_ABSB_B(ctx->opcode); | ||||
|         bpos = MASK_OP_ABSB_BPOS(ctx->opcode); | ||||
| 
 | ||||
|         temp = tcg_const_i32(EA_ABS_FORMAT(address)); | ||||
|         temp2 = tcg_temp_new(); | ||||
| 
 | ||||
|         tcg_gen_qemu_ld_tl(temp2, temp, ctx->mem_idx, MO_UB); | ||||
|         tcg_gen_andi_tl(temp2, temp2, ~(0x1u << bpos)); | ||||
|         tcg_gen_ori_tl(temp2, temp2, (b << bpos)); | ||||
|         tcg_gen_qemu_st_tl(temp2, temp, ctx->mem_idx, MO_UB); | ||||
| 
 | ||||
|         tcg_temp_free(temp); | ||||
|         tcg_temp_free(temp2); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bastian Koppelmann
						Bastian Koppelmann