Commit 873eb012 authored by Thiemo Seufer's avatar Thiemo Seufer
Browse files

Dynamically translate MIPS mfc0 instructions.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2222 c046a42c-6fe2-441c-8c8c-71466251a162
parent 6ae81775
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ void do_maddu (void);
void do_msub (void);
void do_msubu (void);
#endif
void do_mfc0(int reg, int sel);
void do_mfc0_random(void);
void do_mfc0_count(void);
void do_mtc0(int reg, int sel);
void do_tlbwi (void);
void do_tlbwr (void);
+160 −2
Original line number Diff line number Diff line
@@ -688,9 +688,167 @@ void op_jnz_T2 (void)
}

/* CP0 functions */
void op_mfc0 (void)
void op_mfc0_index (void)
{
    CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
    T0 = env->CP0_index;
    RETURN();
}

void op_mfc0_random (void)
{
    CALL_FROM_TB0(do_mfc0_random);
    RETURN();
}

void op_mfc0_entrylo0 (void)
{
    T0 = env->CP0_EntryLo0;
    RETURN();
}

void op_mfc0_entrylo1 (void)
{
    T0 = env->CP0_EntryLo1;
    RETURN();
}

void op_mfc0_context (void)
{
    T0 = env->CP0_Context;
    RETURN();
}

void op_mfc0_pagemask (void)
{
    T0 = env->CP0_PageMask;
    RETURN();
}

void op_mfc0_wired (void)
{
    T0 = env->CP0_Wired;
    RETURN();
}

void op_mfc0_badvaddr (void)
{
    T0 = env->CP0_BadVAddr;
    RETURN();
}

void op_mfc0_count (void)
{
    CALL_FROM_TB0(do_mfc0_count);
    RETURN();
}

void op_mfc0_entryhi (void)
{
    T0 = env->CP0_EntryHi;
    RETURN();
}

void op_mfc0_compare (void)
{
    T0 = env->CP0_Compare;
    RETURN();
}

void op_mfc0_status (void)
{
    T0 = env->CP0_Status;
    if (env->hflags & MIPS_HFLAG_UM)
        T0 |= (1 << CP0St_UM);
    if (env->hflags & MIPS_HFLAG_ERL)
        T0 |= (1 << CP0St_ERL);
    if (env->hflags & MIPS_HFLAG_EXL)
        T0 |= (1 << CP0St_EXL);
    RETURN();
}

void op_mfc0_cause (void)
{
    T0 = env->CP0_Cause;
    RETURN();
}

void op_mfc0_epc (void)
{
    T0 = env->CP0_EPC;
    RETURN();
}

void op_mfc0_prid (void)
{
    T0 = env->CP0_PRid;
    RETURN();
}

void op_mfc0_config0 (void)
{
    T0 = env->CP0_Config0;
    RETURN();
}

void op_mfc0_config1 (void)
{
    T0 = env->CP0_Config1;
    RETURN();
}

void op_mfc0_lladdr (void)
{
    T0 = env->CP0_LLAddr >> 4;
    RETURN();
}

void op_mfc0_watchlo (void)
{
    T0 = env->CP0_WatchLo;
    RETURN();
}

void op_mfc0_watchhi (void)
{
    T0 = env->CP0_WatchHi;
    RETURN();
}

void op_mfc0_debug (void)
{
    T0 = env->CP0_Debug;
    if (env->hflags & MIPS_HFLAG_DM)
        T0 |= 1 << CP0DB_DM;
    RETURN();
}

void op_mfc0_depc (void)
{
    T0 = env->CP0_DEPC;
    RETURN();
}

void op_mfc0_taglo (void)
{
    T0 = env->CP0_TagLo;
    RETURN();
}

void op_mfc0_datalo (void)
{
    T0 = env->CP0_DataLo;
    RETURN();
}

void op_mfc0_errorepc (void)
{
    T0 = env->CP0_ErrorEPC;
    RETURN();
}

void op_mfc0_desave (void)
{
    T0 = env->CP0_DESAVE;
    RETURN();
}

+15 −143
Original line number Diff line number Diff line
@@ -131,10 +131,16 @@ void do_msubu (void)
#endif

#if defined(CONFIG_USER_ONLY) 
void do_mfc0 (int reg, int sel)
void do_mfc0_random (void)
{
    cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
    cpu_abort(env, "mfc0 random\n");
}

void do_mfc0_count (void)
{
    cpu_abort(env, "mfc0 count\n");
}

void do_mtc0 (int reg, int sel)
{
    cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
@@ -159,152 +165,18 @@ void do_tlbr (void)
{
    cpu_abort(env, "tlbr\n");
}

#else

/* CP0 helpers */
void do_mfc0 (int reg, int sel)
void do_mfc0_random (void)
{
    const unsigned char *rn;

    if (sel != 0 && reg != 16 && reg != 28) {
        rn = "invalid";
        goto print;
    }
    switch (reg) {
    case 0:
        T0 = env->CP0_index;
        rn = "Index";
        break;
    case 1:
    T0 = cpu_mips_get_random(env);
        rn = "Random";
        break;
    case 2:
        T0 = env->CP0_EntryLo0;
        rn = "EntryLo0";
        break;
    case 3:
        T0 = env->CP0_EntryLo1;
        rn = "EntryLo1";
        break;
    case 4:
        T0 = env->CP0_Context;
        rn = "Context";
        break;
    case 5:
        T0 = env->CP0_PageMask;
        rn = "PageMask";
        break;
    case 6:
        T0 = env->CP0_Wired;
        rn = "Wired";
        break;
    case 8:
        T0 = env->CP0_BadVAddr;
        rn = "BadVaddr";
        break;
    case 9:
        T0 = cpu_mips_get_count(env);
        rn = "Count";
        break;
    case 10:
        T0 = env->CP0_EntryHi;
        rn = "EntryHi";
        break;
    case 11:
        T0 = env->CP0_Compare;
        rn = "Compare";
        break;
    case 12:
        T0 = env->CP0_Status;
        if (env->hflags & MIPS_HFLAG_UM)
            T0 |= (1 << CP0St_UM);
        rn = "Status";
        break;
    case 13:
        T0 = env->CP0_Cause;
        rn = "Cause";
        break;
    case 14:
        T0 = env->CP0_EPC;
        rn = "EPC";
        break;
    case 15:
        T0 = env->CP0_PRid;
        rn = "PRid";
        break;
    case 16:
        switch (sel) {
        case 0:
            T0 = env->CP0_Config0;
            rn = "Config";
            break;
        case 1:
            T0 = env->CP0_Config1;
            rn = "Config1";
            break;
        default:
            rn = "Unknown config register";
            break;
}
        break;
    case 17:
        T0 = env->CP0_LLAddr >> 4;
        rn = "LLAddr";
        break;
    case 18:
        T0 = env->CP0_WatchLo;
        rn = "WatchLo";
        break;
    case 19:
        T0 = env->CP0_WatchHi;
        rn = "WatchHi";
        break;
    case 23:
        T0 = env->CP0_Debug;
        if (env->hflags & MIPS_HFLAG_DM)
            T0 |= 1 << CP0DB_DM;
        rn = "Debug";
        break;
    case 24:
        T0 = env->CP0_DEPC;
        rn = "DEPC";
        break;
    case 28:
        switch (sel) {
        case 0:
            T0 = env->CP0_TagLo;
            rn = "TagLo";
            break;
        case 1:
            T0 = env->CP0_DataLo;
            rn = "DataLo";
            break;
        default:
            rn = "unknown sel";
            break;
        }
        break;
    case 30:
        T0 = env->CP0_ErrorEPC;
        rn = "ErrorEPC";
        break;
    case 31:
        T0 = env->CP0_DESAVE;
        rn = "DESAVE";
        break;
    default:
        rn = "unknown";
        break;
    }
 print:
#if defined MIPS_DEBUG_DISAS
    if (loglevel & CPU_LOG_TB_IN_ASM) {
        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
                env->PC, rn, T0, reg, sel);
    }
#endif
    return;

void do_mfc0_count (void)
{
    T0 = cpu_mips_get_count(env);
}

void do_mtc0 (int reg, int sel)
+150 −1
Original line number Diff line number Diff line
@@ -1349,6 +1349,155 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
}

/* CP0 (MMU and control) */
static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
{
    const unsigned char *rn;

    if (sel != 0 && reg != 16 && reg != 28) {
        rn = "invalid";
        goto die;
    }
    switch (reg) {
    case 0:
        gen_op_mfc0_index();
        rn = "Index";
        break;
    case 1:
        gen_op_mfc0_random();
        rn = "Random";
        break;
    case 2:
        gen_op_mfc0_entrylo0();
        rn = "EntryLo0";
        break;
    case 3:
        gen_op_mfc0_entrylo1();
        rn = "EntryLo1";
        break;
    case 4:
        gen_op_mfc0_context();
        rn = "Context";
        break;
    case 5:
        gen_op_mfc0_pagemask();
        rn = "PageMask";
        break;
    case 6:
        gen_op_mfc0_wired();
        rn = "Wired";
        break;
    case 8:
        gen_op_mfc0_badvaddr();
        rn = "BadVaddr";
        break;
    case 9:
        gen_op_mfc0_count();
        rn = "Count";
        break;
    case 10:
        gen_op_mfc0_entryhi();
        rn = "EntryHi";
        break;
    case 11:
        gen_op_mfc0_compare();
        rn = "Compare";
        break;
    case 12:
        gen_op_mfc0_status();
        rn = "Status";
        break;
    case 13:
        gen_op_mfc0_cause();
        rn = "Cause";
        break;
    case 14:
        gen_op_mfc0_epc();
        rn = "EPC";
        break;
    case 15:
        gen_op_mfc0_prid();
        rn = "PRid";
        break;
    case 16:
        switch (sel) {
        case 0:
           gen_op_mfc0_config0();
            rn = "Config";
            break;
        case 1:
           gen_op_mfc0_config1();
            rn = "Config1";
            break;
        default:
            rn = "Unknown config register";
            goto die;
        }
        break;
    case 17:
        gen_op_mfc0_lladdr();
        rn = "LLAddr";
        break;
    case 18:
        gen_op_mfc0_watchlo();
        rn = "WatchLo";
        break;
    case 19:
        gen_op_mfc0_watchhi();
        rn = "WatchHi";
        break;
    case 23:
        gen_op_mfc0_debug();
        rn = "Debug";
        break;
    case 24:
        gen_op_mfc0_depc();
        rn = "DEPC";
        break;
    case 28:
        switch (sel) {
        case 0:
            gen_op_mfc0_taglo();
            rn = "TagLo";
            break;
        case 1:
            gen_op_mfc0_datalo();
            rn = "DataLo";
            break;
        default:
            rn = "unknown sel";
            goto die;
        }
        break;
    case 30:
        gen_op_mfc0_errorepc();
        rn = "ErrorEPC";
        break;
    case 31:
        gen_op_mfc0_desave();
        rn = "DESAVE";
        break;
    default:
        rn = "unknown";
       goto die;
    }
#if defined MIPS_DEBUG_DISAS
    if (loglevel & CPU_LOG_TB_IN_ASM) {
        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
                env->PC, rn, T0, reg, sel);
    }
#endif
    return;

die:
#if defined MIPS_DEBUG_DISAS
    if (loglevel & CPU_LOG_TB_IN_ASM) {
        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
                env->PC, rn, T0, reg, sel);
    }
#endif
    generate_exception(ctx, EXCP_RI);
}

static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
{
    const unsigned char *opn = "unk";
@@ -1370,7 +1519,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
            /* Treat as NOP */
            return;
        }
        gen_op_mfc0(rd, ctx->opcode & 0x7);
        gen_mfc0(ctx, rd, ctx->opcode & 0x7);
        gen_op_store_T0_gpr(rt);
        opn = "mfc0";
        break;