Commit bb2fa17f authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/bkoppelmann/tags/pull-tricore-20150522' into staging



TriCore v1.6.1 ISA and missing v1.6 instructions

# gpg: Signature made Fri May 22 16:02:45 2015 BST using RSA key ID 6B69CA14
# gpg: Good signature from "Bastian Koppelmann <kbastian@mail.uni-paderborn.de>"

* remotes/bkoppelmann/tags/pull-tricore-20150522:
  target-tricore: add RR_DIV and RR_DIV_U instructions of the v1.6 ISA
  target-tricore: add FRET instructions of the v1.6 ISA
  target-tricore: add FCALL instructions of the v1.6 ISA
  target-tricore: add SYS_RESTORE instruction of the v1.6 ISA
  target-tricore: add RR_CRC32 instruction of the v1.6.1 ISA
  target-tricore: add SWAPMSK instructions of the v1.6.1 ISA
  target-tricore: add CMPSWP instructions of the v1.6.1 ISA
  target-tricore: Add SRC_MOV_E instruction of the v1.6 ISA
  target-tricore: introduce ISA v1.6.1 feature
  target-tricore: Add ISA v1.3.1 cpu and fix tc1796 to using v1.3

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 8b6db32a 93715571
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -68,6 +68,10 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)
    CPUTriCoreState *env = &cpu->env;

    /* Some features automatically imply others */
    if (tricore_feature(env, TRICORE_FEATURE_161)) {
        set_feature(env, TRICORE_FEATURE_16);
    }

    if (tricore_feature(env, TRICORE_FEATURE_16)) {
        set_feature(env, TRICORE_FEATURE_131);
    }
@@ -118,14 +122,21 @@ static void tc1796_initfn(Object *obj)
{
    TriCoreCPU *cpu = TRICORE_CPU(obj);

    set_feature(&cpu->env, TRICORE_FEATURE_13);
}

static void tc1797_initfn(Object *obj)
{
    TriCoreCPU *cpu = TRICORE_CPU(obj);

    set_feature(&cpu->env, TRICORE_FEATURE_131);
}

static void aurix_initfn(Object *obj)
static void tc27x_initfn(Object *obj)
{
    TriCoreCPU *cpu = TRICORE_CPU(obj);

    set_feature(&cpu->env, TRICORE_FEATURE_16);
    set_feature(&cpu->env, TRICORE_FEATURE_161);
}

typedef struct TriCoreCPUInfo {
@@ -136,7 +147,8 @@ typedef struct TriCoreCPUInfo {

static const TriCoreCPUInfo tricore_cpus[] = {
    { .name = "tc1796",      .initfn = tc1796_initfn },
    { .name = "aurix",       .initfn = aurix_initfn },
    { .name = "tc1797",      .initfn = tc1797_initfn },
    { .name = "tc27x",       .initfn = tc27x_initfn },
    { .name = NULL }
};

+1 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ enum tricore_features {
    TRICORE_FEATURE_13,
    TRICORE_FEATURE_131,
    TRICORE_FEATURE_16,
    TRICORE_FEATURE_161,
};

static inline int tricore_feature(CPUTriCoreState *env, int feature)
+4 −0
Original line number Diff line number Diff line
@@ -113,10 +113,14 @@ DEF_HELPER_3(dvinit_h_131, i64, env, i32, i32)
DEF_HELPER_FLAGS_2(dvadj, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_2(dvstep_u, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_3(divide, i64, env, i32, i32)
DEF_HELPER_3(divide_u, i64, env, i32, i32)
/* mulh */
DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32)
/* crc32 */
DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
/* CSA */
DEF_HELPER_2(call, void, env, i32)
DEF_HELPER_1(ret, void, env)
+60 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
#include <zlib.h> /* for crc32 */

/* Addressing mode helper */

@@ -2093,6 +2094,55 @@ uint64_t helper_dvstep_u(uint64_t r1, uint32_t r2)
    return ((uint64_t)remainder << 32) | (uint32_t)dividend_quotient;
}

uint64_t helper_divide(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
    int32_t quotient, remainder;
    int32_t dividend = (int32_t)r1;
    int32_t divisor = (int32_t)r2;

    if (divisor == 0) {
        if (dividend >= 0) {
            quotient = 0x7fffffff;
            remainder = 0;
        } else {
            quotient = 0x80000000;
            remainder = 0;
        }
        env->PSW_USB_V = (1 << 31);
    } else if ((divisor == 0xffffffff) && (dividend == 0x80000000)) {
        quotient = 0x7fffffff;
        remainder = 0;
        env->PSW_USB_V = (1 << 31);
    } else {
        remainder = dividend % divisor;
        quotient = (dividend - remainder)/divisor;
        env->PSW_USB_V = 0;
    }
    env->PSW_USB_SV |= env->PSW_USB_V;
    env->PSW_USB_AV = 0;
    return ((uint64_t)remainder << 32) | (uint32_t)quotient;
}

uint64_t helper_divide_u(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
{
    uint32_t quotient, remainder;
    uint32_t dividend = r1;
    uint32_t divisor = r2;

    if (divisor == 0) {
        quotient = 0xffffffff;
        remainder = 0;
        env->PSW_USB_V = (1 << 31);
    } else {
        remainder = dividend % divisor;
        quotient = (dividend - remainder)/divisor;
        env->PSW_USB_V = 0;
    }
    env->PSW_USB_SV |= env->PSW_USB_V;
    env->PSW_USB_AV = 0;
    return ((uint64_t)remainder << 32) | quotient;
}

uint64_t helper_mul_h(uint32_t arg00, uint32_t arg01,
                      uint32_t arg10, uint32_t arg11, uint32_t n)
{
@@ -2165,6 +2215,16 @@ uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01,
    return (result1 & 0xffff0000) | (result0 >> 16);
}

uint32_t helper_crc32(uint32_t arg0, uint32_t arg1)
{
    uint8_t buf[4];
    uint32_t ret;
    stl_be_p(buf, arg0);

    ret = crc32(arg1, buf, 4);
    return ret;
}

/* context save area (CSA) related helpers */

static int cdc_increment(target_ulong *psw)
+164 −2
Original line number Diff line number Diff line
@@ -201,6 +201,15 @@ void tricore_cpu_dump_state(CPUState *cs, FILE *f,
    tcg_temp_free_i64(arg1);                                 \
} while (0)

#define GEN_HELPER_RR(name, rl, rh, arg1, arg2) do {        \
    TCGv_i64 ret = tcg_temp_new_i64();                      \
                                                            \
    gen_helper_##name(ret, cpu_env, arg1, arg2);            \
    tcg_gen_extr_i64_i32(rl, rh, ret);                      \
                                                            \
    tcg_temp_free_i64(ret);                                 \
} while (0)

#define EA_ABS_FORMAT(con) (((con & 0x3C000) << 14) + (con & 0x3FFF))
#define EA_B_ABSOLUT(con) (((offset & 0xf00000) << 8) | \
                           ((offset & 0x0fffff) << 1))
@@ -319,6 +328,39 @@ static void gen_swap(DisasContext *ctx, int reg, TCGv ea)
    tcg_temp_free(temp);
}

static void gen_cmpswap(DisasContext *ctx, int reg, TCGv ea)
{
    TCGv temp = tcg_temp_new();
    TCGv temp2 = tcg_temp_new();
    tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL);
    tcg_gen_movcond_tl(TCG_COND_EQ, temp2, cpu_gpr_d[reg+1], temp,
                       cpu_gpr_d[reg], temp);
    tcg_gen_qemu_st_tl(temp2, ea, ctx->mem_idx, MO_LEUL);
    tcg_gen_mov_tl(cpu_gpr_d[reg], temp);

    tcg_temp_free(temp);
    tcg_temp_free(temp2);
}

static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea)
{
    TCGv temp = tcg_temp_new();
    TCGv temp2 = tcg_temp_new();
    TCGv temp3 = tcg_temp_new();

    tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL);
    tcg_gen_and_tl(temp2, cpu_gpr_d[reg], cpu_gpr_d[reg+1]);
    tcg_gen_andc_tl(temp3, temp, cpu_gpr_d[reg+1]);
    tcg_gen_or_tl(temp2, temp2, temp3);
    tcg_gen_qemu_st_tl(temp2, ea, ctx->mem_idx, MO_LEUL);
    tcg_gen_mov_tl(cpu_gpr_d[reg], temp);

    tcg_temp_free(temp);
    tcg_temp_free(temp2);
    tcg_temp_free(temp3);
}


/* We generate loads and store to core special function register (csfr) through
   the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3
   makros R, A and E, which allow read-only, all and endinit protected access.
@@ -3242,6 +3284,32 @@ static void gen_loop(DisasContext *ctx, int r1, int32_t offset)
    gen_goto_tb(ctx, 0, ctx->next_pc);
}

static void gen_fcall_save_ctx(DisasContext *ctx)
{
    TCGv temp = tcg_temp_new();

    tcg_gen_addi_tl(temp, cpu_gpr_a[10], -4);
    tcg_gen_qemu_st_tl(cpu_gpr_a[11], temp, ctx->mem_idx, MO_LESL);
    tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc);
    tcg_gen_mov_tl(cpu_gpr_a[10], temp);

    tcg_temp_free(temp);
}

static void gen_fret(DisasContext *ctx)
{
    TCGv temp = tcg_temp_new();

    tcg_gen_andi_tl(temp, cpu_gpr_a[11], ~0x1);
    tcg_gen_qemu_ld_tl(cpu_gpr_a[11], cpu_gpr_a[10], ctx->mem_idx, MO_LESL);
    tcg_gen_addi_tl(cpu_gpr_a[10], cpu_gpr_a[10], 4);
    tcg_gen_mov_tl(cpu_PC, temp);
    tcg_gen_exit_tb(0);
    ctx->bstate = BS_BRANCH;

    tcg_temp_free(temp);
}

static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
                               int r2 , int32_t constant , int32_t offset)
{
@@ -3336,6 +3404,14 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
        gen_helper_1arg(call, ctx->next_pc);
        gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset));
        break;
    case OPC1_32_B_FCALL:
        gen_fcall_save_ctx(ctx);
        gen_goto_tb(ctx, 0, ctx->pc + offset * 2);
        break;
    case OPC1_32_B_FCALLA:
        gen_fcall_save_ctx(ctx);
        gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset));
        break;
    case OPC1_32_B_JLA:
        tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc);
        /* fall through */
@@ -3485,7 +3561,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
 * Functions for decoding instructions
 */

static void decode_src_opc(DisasContext *ctx, int op1)
static void decode_src_opc(CPUTriCoreState *env, DisasContext *ctx, int op1)
{
    int r1;
    int32_t const4;
@@ -3546,6 +3622,12 @@ static void decode_src_opc(DisasContext *ctx, int op1)
        const4 = MASK_OP_SRC_CONST4(ctx->opcode);
        tcg_gen_movi_tl(cpu_gpr_a[r1], const4);
        break;
    case OPC1_16_SRC_MOV_E:
        if (tricore_feature(env, TRICORE_FEATURE_16)) {
            tcg_gen_movi_tl(cpu_gpr_d[r1], const4);
            tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31);
        } /* TODO: else raise illegal opcode trap */
        break;
    case OPC1_16_SRC_SH:
        gen_shi(cpu_gpr_d[r1], cpu_gpr_d[r1], const4);
        break;
@@ -3810,6 +3892,8 @@ static void decode_sr_system(CPUTriCoreState *env, DisasContext *ctx)
    case OPC2_16_SR_DEBUG:
        /* raise EXCP_DEBUG */
        break;
    case OPC2_16_SR_FRET:
        gen_fret(ctx);
    }
}

@@ -3883,9 +3967,10 @@ static void decode_16Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
    case OPC1_16_SRC_LT:
    case OPC1_16_SRC_MOV:
    case OPC1_16_SRC_MOV_A:
    case OPC1_16_SRC_MOV_E:
    case OPC1_16_SRC_SH:
    case OPC1_16_SRC_SHA:
        decode_src_opc(ctx, op1);
        decode_src_opc(env, ctx, op1);
        break;
/* SRR-format */
    case OPC1_16_SRR_ADD:
@@ -5039,6 +5124,30 @@ static void decode_bo_addrmode_stctx_post_pre_base(CPUTriCoreState *env,
        tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
        gen_swap(ctx, r1, cpu_gpr_a[r2]);
        break;
    case OPC2_32_BO_CMPSWAP_W_SHORTOFF:
        tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10);
        gen_cmpswap(ctx, r1, temp);
        break;
    case OPC2_32_BO_CMPSWAP_W_POSTINC:
        gen_cmpswap(ctx, r1, cpu_gpr_a[r2]);
        tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
        break;
    case OPC2_32_BO_CMPSWAP_W_PREINC:
        tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
        gen_cmpswap(ctx, r1, cpu_gpr_a[r2]);
        break;
    case OPC2_32_BO_SWAPMSK_W_SHORTOFF:
        tcg_gen_addi_tl(temp, cpu_gpr_a[r2], off10);
        gen_swapmsk(ctx, r1, temp);
        break;
    case OPC2_32_BO_SWAPMSK_W_POSTINC:
        gen_swapmsk(ctx, r1, cpu_gpr_a[r2]);
        tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
        break;
    case OPC2_32_BO_SWAPMSK_W_PREINC:
        tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], off10);
        gen_swapmsk(ctx, r1, cpu_gpr_a[r2]);
        break;
    }
    tcg_temp_free(temp);
    tcg_temp_free(temp2);
@@ -5082,7 +5191,24 @@ static void decode_bo_addrmode_ldmst_bitreverse_circular(CPUTriCoreState *env,
        gen_swap(ctx, r1, temp2);
        gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3);
        break;
    case OPC2_32_BO_CMPSWAP_W_BR:
        gen_cmpswap(ctx, r1, temp2);
        gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]);
        break;
    case OPC2_32_BO_CMPSWAP_W_CIRC:
        gen_cmpswap(ctx, r1, temp2);
        gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3);
        break;
    case OPC2_32_BO_SWAPMSK_W_BR:
        gen_swapmsk(ctx, r1, temp2);
        gen_helper_br_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1]);
        break;
    case OPC2_32_BO_SWAPMSK_W_CIRC:
        gen_swapmsk(ctx, r1, temp2);
        gen_helper_circ_update(cpu_gpr_a[r2+1], cpu_gpr_a[r2+1], temp3);
        break;
    }

    tcg_temp_free(temp);
    tcg_temp_free(temp2);
    tcg_temp_free(temp3);
@@ -6230,6 +6356,10 @@ static void decode_rr_idirect(CPUTriCoreState *env, DisasContext *ctx)
        gen_helper_1arg(call, ctx->next_pc);
        tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
        break;
    case OPC2_32_RR_FCALLI:
        gen_fcall_save_ctx(ctx);
        tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1);
        break;
    }
    tcg_gen_exit_tb(0);
    ctx->bstate = BS_BRANCH;
@@ -6368,6 +6498,23 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx)
    case OPC2_32_RR_UNPACK:
        gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
        break;
    case OPC2_32_RR_CRC32:
        if (tricore_feature(env, TRICORE_FEATURE_161)) {
            gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]);
        } /* TODO: else raise illegal opcode trap */
        break;
    case OPC2_32_RR_DIV:
        if (tricore_feature(env, TRICORE_FEATURE_16)) {
            GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1],
                          cpu_gpr_d[r2]);
        } /* TODO: else raise illegal opcode trap */
        break;
    case OPC2_32_RR_DIV_U:
        if (tricore_feature(env, TRICORE_FEATURE_16)) {
            GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1],
                          cpu_gpr_d[r1], cpu_gpr_d[r2]);
        } /* TODO: else raise illegal opcode trap */
        break;
    }
}

@@ -7706,10 +7853,12 @@ static void decode_rrrw_extract_insert(CPUTriCoreState *env, DisasContext *ctx)
static void decode_sys_interrupts(CPUTriCoreState *env, DisasContext *ctx)
{
    uint32_t op2;
    uint32_t r1;
    TCGLabel *l1;
    TCGv tmp;

    op2 = MASK_OP_SYS_OP2(ctx->opcode);
    r1  = MASK_OP_SYS_S1D(ctx->opcode);

    switch (op2) {
    case OPC2_32_SYS_DEBUG:
@@ -7730,6 +7879,9 @@ static void decode_sys_interrupts(CPUTriCoreState *env, DisasContext *ctx)
    case OPC2_32_SYS_RET:
        gen_compute_branch(ctx, op2, 0, 0, 0, 0);
        break;
    case OPC2_32_SYS_FRET:
        gen_fret(ctx);
        break;
    case OPC2_32_SYS_RFE:
        gen_helper_rfe(cpu_env);
        tcg_gen_exit_tb(0);
@@ -7758,6 +7910,14 @@ static void decode_sys_interrupts(CPUTriCoreState *env, DisasContext *ctx)
    case OPC2_32_SYS_SVLCX:
        gen_helper_svlcx(cpu_env);
        break;
    case OPC2_32_SYS_RESTORE:
        if (tricore_feature(env, TRICORE_FEATURE_16)) {
            if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM ||
                (ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) {
                tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1);
            } /* else raise privilege trap */
        } /* else raise illegal opcode trap */
        break;
    case OPC2_32_SYS_TRAPSV:
        /* TODO: raise sticky overflow trap */
        break;
@@ -7850,6 +8010,8 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
/* B-format */
    case OPC1_32_B_CALL:
    case OPC1_32_B_CALLA:
    case OPC1_32_B_FCALL:
    case OPC1_32_B_FCALLA:
    case OPC1_32_B_J:
    case OPC1_32_B_JA:
    case OPC1_32_B_JL:
Loading