mirror of https://gitee.com/openkylin/qemu.git
Dynamically translate MIPS mfc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2222 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
6ae817752b
commit
873eb01234
|
@ -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);
|
||||
|
|
162
target-mips/op.c
162
target-mips/op.c
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
T0 = cpu_mips_get_random(env);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue