target-tricore: Add instructions of SB opcode format
Add instructions of SB opcode format. Add helper call/ret. Add micro-op generator functions for branches. Add makro to generate helper functions. Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> Message-id: 1409572800-4116-11-git-send-email-kbastian@mail.uni-paderborn.de Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
d279821074
commit
9a31922b08
@ -18,3 +18,6 @@
|
||||
/* Arithmetic */
|
||||
DEF_HELPER_3(add_ssov, i32, env, i32, i32)
|
||||
DEF_HELPER_3(sub_ssov, i32, env, i32, i32)
|
||||
/* CSA */
|
||||
DEF_HELPER_2(call, void, env, i32)
|
||||
DEF_HELPER_1(ret, void, env)
|
||||
|
@ -63,6 +63,186 @@ target_ulong helper_sub_ssov(CPUTriCoreState *env, target_ulong r1,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* context save area (CSA) related helpers */
|
||||
|
||||
static int cdc_increment(target_ulong *psw)
|
||||
{
|
||||
if ((*psw & MASK_PSW_CDC) == 0x7f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*psw)++;
|
||||
/* check for overflow */
|
||||
int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7));
|
||||
int mask = (1u << (7 - lo)) - 1;
|
||||
int count = *psw & mask;
|
||||
if (count == 0) {
|
||||
(*psw)--;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdc_decrement(target_ulong *psw)
|
||||
{
|
||||
if ((*psw & MASK_PSW_CDC) == 0x7f) {
|
||||
return 0;
|
||||
}
|
||||
/* check for underflow */
|
||||
int lo = clo32((*psw & MASK_PSW_CDC) << (32 - 7));
|
||||
int mask = (1u << (7 - lo)) - 1;
|
||||
int count = *psw & mask;
|
||||
if (count == 0) {
|
||||
return 1;
|
||||
}
|
||||
(*psw)--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void save_context_upper(CPUTriCoreState *env, int ea,
|
||||
target_ulong *new_FCX)
|
||||
{
|
||||
*new_FCX = cpu_ldl_data(env, ea);
|
||||
cpu_stl_data(env, ea, env->PCXI);
|
||||
cpu_stl_data(env, ea+4, env->PSW);
|
||||
cpu_stl_data(env, ea+8, env->gpr_a[10]);
|
||||
cpu_stl_data(env, ea+12, env->gpr_a[11]);
|
||||
cpu_stl_data(env, ea+16, env->gpr_d[8]);
|
||||
cpu_stl_data(env, ea+20, env->gpr_d[9]);
|
||||
cpu_stl_data(env, ea+24, env->gpr_d[10]);
|
||||
cpu_stl_data(env, ea+28, env->gpr_d[11]);
|
||||
cpu_stl_data(env, ea+32, env->gpr_a[12]);
|
||||
cpu_stl_data(env, ea+36, env->gpr_a[13]);
|
||||
cpu_stl_data(env, ea+40, env->gpr_a[14]);
|
||||
cpu_stl_data(env, ea+44, env->gpr_a[15]);
|
||||
cpu_stl_data(env, ea+48, env->gpr_d[12]);
|
||||
cpu_stl_data(env, ea+52, env->gpr_d[13]);
|
||||
cpu_stl_data(env, ea+56, env->gpr_d[14]);
|
||||
cpu_stl_data(env, ea+60, env->gpr_d[15]);
|
||||
|
||||
}
|
||||
|
||||
static void restore_context_upper(CPUTriCoreState *env, int ea,
|
||||
target_ulong *new_PCXI, target_ulong *new_PSW)
|
||||
{
|
||||
*new_PCXI = cpu_ldl_data(env, ea);
|
||||
*new_PSW = cpu_ldl_data(env, ea+4);
|
||||
env->gpr_a[10] = cpu_ldl_data(env, ea+8);
|
||||
env->gpr_a[11] = cpu_ldl_data(env, ea+12);
|
||||
env->gpr_d[8] = cpu_ldl_data(env, ea+16);
|
||||
env->gpr_d[9] = cpu_ldl_data(env, ea+20);
|
||||
env->gpr_d[10] = cpu_ldl_data(env, ea+24);
|
||||
env->gpr_d[11] = cpu_ldl_data(env, ea+28);
|
||||
env->gpr_a[12] = cpu_ldl_data(env, ea+32);
|
||||
env->gpr_a[13] = cpu_ldl_data(env, ea+36);
|
||||
env->gpr_a[14] = cpu_ldl_data(env, ea+40);
|
||||
env->gpr_a[15] = cpu_ldl_data(env, ea+44);
|
||||
env->gpr_d[12] = cpu_ldl_data(env, ea+48);
|
||||
env->gpr_d[13] = cpu_ldl_data(env, ea+52);
|
||||
env->gpr_d[14] = cpu_ldl_data(env, ea+56);
|
||||
env->gpr_d[15] = cpu_ldl_data(env, ea+60);
|
||||
cpu_stl_data(env, ea, env->FCX);
|
||||
}
|
||||
|
||||
void helper_call(CPUTriCoreState *env, uint32_t next_pc)
|
||||
{
|
||||
target_ulong tmp_FCX;
|
||||
target_ulong ea;
|
||||
target_ulong new_FCX;
|
||||
target_ulong psw;
|
||||
|
||||
psw = psw_read(env);
|
||||
/* if (FCX == 0) trap(FCU); */
|
||||
if (env->FCX == 0) {
|
||||
/* FCU trap */
|
||||
}
|
||||
/* if (PSW.CDE) then if (cdc_increment()) then trap(CDO); */
|
||||
if (psw & MASK_PSW_CDE) {
|
||||
if (cdc_increment(&psw)) {
|
||||
/* CDO trap */
|
||||
}
|
||||
}
|
||||
/* PSW.CDE = 1;*/
|
||||
psw |= MASK_PSW_CDE;
|
||||
/* tmp_FCX = FCX; */
|
||||
tmp_FCX = env->FCX;
|
||||
/* EA = {FCX.FCXS, 6'b0, FCX.FCXO, 6'b0}; */
|
||||
ea = ((env->FCX & MASK_FCX_FCXS) << 12) +
|
||||
((env->FCX & MASK_FCX_FCXO) << 6);
|
||||
/* new_FCX = M(EA, word);
|
||||
M(EA, 16 * word) = {PCXI, PSW, A[10], A[11], D[8], D[9], D[10], D[11],
|
||||
A[12], A[13], A[14], A[15], D[12], D[13], D[14],
|
||||
D[15]}; */
|
||||
save_context_upper(env, ea, &new_FCX);
|
||||
|
||||
/* PCXI.PCPN = ICR.CCPN; */
|
||||
env->PCXI = (env->PCXI & 0xffffff) +
|
||||
((env->ICR & MASK_ICR_CCPN) << 24);
|
||||
/* PCXI.PIE = ICR.IE; */
|
||||
env->PCXI = ((env->PCXI & ~MASK_PCXI_PIE) +
|
||||
((env->ICR & MASK_ICR_IE) << 15));
|
||||
/* PCXI.UL = 1; */
|
||||
env->PCXI |= MASK_PCXI_UL;
|
||||
|
||||
/* PCXI[19: 0] = FCX[19: 0]; */
|
||||
env->PCXI = (env->PCXI & 0xfff00000) + (env->FCX & 0xfffff);
|
||||
/* FCX[19: 0] = new_FCX[19: 0]; */
|
||||
env->FCX = (env->FCX & 0xfff00000) + (new_FCX & 0xfffff);
|
||||
/* A[11] = next_pc[31: 0]; */
|
||||
env->gpr_a[11] = next_pc;
|
||||
|
||||
/* if (tmp_FCX == LCX) trap(FCD);*/
|
||||
if (tmp_FCX == env->LCX) {
|
||||
/* FCD trap */
|
||||
}
|
||||
psw_write(env, psw);
|
||||
}
|
||||
|
||||
void helper_ret(CPUTriCoreState *env)
|
||||
{
|
||||
target_ulong ea;
|
||||
target_ulong new_PCXI;
|
||||
target_ulong new_PSW, psw;
|
||||
|
||||
psw = psw_read(env);
|
||||
/* if (PSW.CDE) then if (cdc_decrement()) then trap(CDU);*/
|
||||
if (env->PSW & MASK_PSW_CDE) {
|
||||
if (cdc_decrement(&(env->PSW))) {
|
||||
/* CDU trap */
|
||||
}
|
||||
}
|
||||
/* if (PCXI[19: 0] == 0) then trap(CSU); */
|
||||
if ((env->PCXI & 0xfffff) == 0) {
|
||||
/* CSU trap */
|
||||
}
|
||||
/* if (PCXI.UL == 0) then trap(CTYP); */
|
||||
if ((env->PCXI & MASK_PCXI_UL) == 0) {
|
||||
/* CTYP trap */
|
||||
}
|
||||
/* PC = {A11 [31: 1], 1’b0}; */
|
||||
env->PC = env->gpr_a[11] & 0xfffffffe;
|
||||
|
||||
/* EA = {PCXI.PCXS, 6'b0, PCXI.PCXO, 6'b0}; */
|
||||
ea = ((env->PCXI & MASK_PCXI_PCXS) << 12) +
|
||||
((env->PCXI & MASK_PCXI_PCXO) << 6);
|
||||
/* {new_PCXI, new_PSW, A[10], A[11], D[8], D[9], D[10], D[11], A[12],
|
||||
A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word);
|
||||
M(EA, word) = FCX; */
|
||||
restore_context_upper(env, ea, &new_PCXI, &new_PSW);
|
||||
/* FCX[19: 0] = PCXI[19: 0]; */
|
||||
env->FCX = (env->FCX & 0xfff00000) + (env->PCXI & 0x000fffff);
|
||||
/* PCXI = new_PCXI; */
|
||||
env->PCXI = new_PCXI;
|
||||
|
||||
if (tricore_feature(env, TRICORE_FEATURE_13)) {
|
||||
/* PSW = new_PSW */
|
||||
psw_write(env, new_PSW);
|
||||
} else {
|
||||
/* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */
|
||||
psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env,
|
||||
uint32_t exception,
|
||||
int error_code,
|
||||
|
@ -107,6 +107,14 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
* Functions to generate micro-ops
|
||||
*/
|
||||
|
||||
/* Makros for generating helpers */
|
||||
|
||||
#define gen_helper_1arg(name, arg) do { \
|
||||
TCGv_i32 helper_tmp = tcg_const_i32(arg); \
|
||||
gen_helper_##name(cpu_env, helper_tmp); \
|
||||
tcg_temp_free_i32(helper_tmp); \
|
||||
} while (0)
|
||||
|
||||
/* Functions for load/save to/from memory */
|
||||
|
||||
static inline void gen_offset_ld(DisasContext *ctx, TCGv r1, TCGv r2,
|
||||
@ -334,6 +342,78 @@ static inline void gen_subs(TCGv ret, TCGv r1, TCGv r2)
|
||||
gen_helper_sub_ssov(ret, cpu_env, r1, r2);
|
||||
}
|
||||
|
||||
/* helpers for generating program flow micro-ops */
|
||||
|
||||
static inline void gen_save_pc(target_ulong pc)
|
||||
{
|
||||
tcg_gen_movi_tl(cpu_PC, pc);
|
||||
}
|
||||
|
||||
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
tb = ctx->tb;
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
|
||||
likely(!ctx->singlestep_enabled)) {
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_save_pc(dest);
|
||||
tcg_gen_exit_tb((uintptr_t)tb + n);
|
||||
} else {
|
||||
gen_save_pc(dest);
|
||||
if (ctx->singlestep_enabled) {
|
||||
/* raise exception debug */
|
||||
}
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_branch_cond(DisasContext *ctx, TCGCond cond, TCGv r1,
|
||||
TCGv r2, int16_t address)
|
||||
{
|
||||
int jumpLabel;
|
||||
jumpLabel = gen_new_label();
|
||||
tcg_gen_brcond_tl(cond, r1, r2, jumpLabel);
|
||||
|
||||
gen_goto_tb(ctx, 1, ctx->next_pc);
|
||||
|
||||
gen_set_label(jumpLabel);
|
||||
gen_goto_tb(ctx, 0, ctx->pc + address * 2);
|
||||
}
|
||||
|
||||
static inline void gen_branch_condi(DisasContext *ctx, TCGCond cond, TCGv r1,
|
||||
int r2, int16_t address)
|
||||
{
|
||||
TCGv temp = tcg_const_i32(r2);
|
||||
gen_branch_cond(ctx, cond, r1, temp, address);
|
||||
tcg_temp_free(temp);
|
||||
}
|
||||
|
||||
static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
|
||||
int r2 , int32_t constant , int32_t offset)
|
||||
{
|
||||
switch (opc) {
|
||||
/* SB-format jumps */
|
||||
case OPC1_16_SB_J:
|
||||
case OPC1_32_B_J:
|
||||
gen_goto_tb(ctx, 0, ctx->pc + offset * 2);
|
||||
break;
|
||||
case OPC1_16_SB_CALL:
|
||||
gen_helper_1arg(call, ctx->next_pc);
|
||||
gen_goto_tb(ctx, 0, ctx->pc + offset * 2);
|
||||
break;
|
||||
case OPC1_16_SB_JZ:
|
||||
gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[15], 0, offset);
|
||||
break;
|
||||
case OPC1_16_SB_JNZ:
|
||||
gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[15], 0, offset);
|
||||
break;
|
||||
default:
|
||||
printf("Branch Error at %x\n", ctx->pc);
|
||||
}
|
||||
ctx->bstate = BS_BRANCH;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Functions for decoding instructions
|
||||
*/
|
||||
@ -535,6 +615,7 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
|
||||
int op1;
|
||||
int r1, r2;
|
||||
int32_t const16;
|
||||
int32_t address;
|
||||
TCGv temp;
|
||||
|
||||
op1 = MASK_OP_MAJOR(ctx->opcode);
|
||||
@ -627,6 +708,14 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
|
||||
const16 = MASK_OP_SLRO_OFF4(ctx->opcode);
|
||||
gen_offset_ld(ctx, cpu_gpr_d[r1], cpu_gpr_a[15], const16 * 4, MO_LESL);
|
||||
break;
|
||||
/* SB-format */
|
||||
case OPC1_16_SB_CALL:
|
||||
case OPC1_16_SB_J:
|
||||
case OPC1_16_SB_JNZ:
|
||||
case OPC1_16_SB_JZ:
|
||||
address = MASK_OP_SB_DISP8_SEXT(ctx->opcode);
|
||||
gen_compute_branch(ctx, op1, 0, 0, 0, address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,9 +770,13 @@ gen_intermediate_code_internal(TriCoreCPU *cpu, struct TranslationBlock *tb,
|
||||
num_insns++;
|
||||
|
||||
if (tcg_ctx.gen_opc_ptr >= gen_opc_end) {
|
||||
gen_save_pc(ctx.next_pc);
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
}
|
||||
if (singlestep) {
|
||||
gen_save_pc(ctx.next_pc);
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
}
|
||||
ctx.pc = ctx.next_pc;
|
||||
|
Loading…
Reference in New Issue
Block a user