summaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/cpu.h25
-rw-r--r--target-mips/helper.c33
-rw-r--r--target-mips/helper.h1
-rw-r--r--target-mips/op_helper.c34
-rw-r--r--target-mips/translate.c44
-rw-r--r--target-mips/translate_init.c4
6 files changed, 105 insertions, 36 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 81051aa004..19511d7f02 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -525,6 +525,29 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
env->active_tc.gpr[2] = 0;
}
+static inline int cpu_mips_hw_interrupts_pending(CPUState *env)
+{
+ int32_t pending;
+ int32_t status;
+ int r;
+
+ pending = env->CP0_Cause & CP0Ca_IP_mask;
+ status = env->CP0_Status & CP0Ca_IP_mask;
+
+ if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
+ /* A MIPS configured with a vectorizing external interrupt controller
+ will feed a vector into the Cause pending lines. The core treats
+ the status lines as a vector level, not as indiviual masks. */
+ r = pending > status;
+ } else {
+ /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
+ treats the pending lines as individual interrupt lines, the status
+ lines are individual masks. */
+ r = pending & status;
+ }
+ return r;
+}
+
#include "cpu-all.h"
/* Memory access type :
@@ -598,7 +621,7 @@ void cpu_mips_start_count(CPUState *env);
void cpu_mips_stop_count(CPUState *env);
/* mips_int.c */
-void cpu_mips_update_irq (CPUState *env);
+void cpu_mips_soft_irq(CPUState *env, int irq, int level);
/* helper.c */
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
diff --git a/target-mips/helper.c b/target-mips/helper.c
index ea221ab53f..bdc1e53669 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -478,6 +478,33 @@ void do_interrupt (CPUState *env)
cause = 0;
if (env->CP0_Cause & (1 << CP0Ca_IV))
offset = 0x200;
+
+ if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) {
+ /* Vectored Interrupts. */
+ unsigned int spacing;
+ unsigned int vector;
+ unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
+
+ /* Compute the Vector Spacing. */
+ spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
+ spacing <<= 5;
+
+ if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
+ /* For VInt mode, the MIPS computes the vector internally. */
+ for (vector = 0; vector < 8; vector++) {
+ if (pending & 1) {
+ /* Found it. */
+ break;
+ }
+ pending >>= 1;
+ }
+ } else {
+ /* For VEIC mode, the external interrupt controller feeds the
+ vector throught the CP0Cause IP lines. */
+ vector = pending;
+ }
+ offset = 0x200 + vector * spacing;
+ }
goto set_EPC;
case EXCP_LTLBL:
cause = 1;
@@ -491,7 +518,8 @@ void do_interrupt (CPUState *env)
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
- if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
+ if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
+ (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
offset = 0x080;
else
#endif
@@ -507,7 +535,8 @@ void do_interrupt (CPUState *env)
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
- if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
+ if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
+ (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
offset = 0x080;
else
#endif
diff --git a/target-mips/helper.h b/target-mips/helper.h
index a6ba75dfbc..cb13fb2352 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -2,7 +2,6 @@
DEF_HELPER_2(raise_exception_err, void, i32, int)
DEF_HELPER_1(raise_exception, void, i32)
-DEF_HELPER_0(interrupt_restart, void)
#ifdef TARGET_MIPS64
DEF_HELPER_3(ldl, tl, tl, tl, int)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 8ae510adc1..41abd575f9 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -46,18 +46,6 @@ void helper_raise_exception (uint32_t exception)
helper_raise_exception_err(exception, 0);
}
-void helper_interrupt_restart (void)
-{
- if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- (env->CP0_Status & (1 << CP0St_IE)) &&
- (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
- env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
- helper_raise_exception(EXCP_EXT_INTERRUPT);
- }
-}
-
#if !defined(CONFIG_USER_ONLY)
static void do_restore_state (void *pc_ptr)
{
@@ -1313,7 +1301,6 @@ void helper_mtc0_status (target_ulong arg1)
default: cpu_abort(env, "Invalid MMU mode!\n"); break;
}
}
- cpu_mips_update_irq(env);
}
void helper_mttc0_status(target_ulong arg1)
@@ -1347,6 +1334,7 @@ void helper_mtc0_cause (target_ulong arg1)
{
uint32_t mask = 0x00C00300;
uint32_t old = env->CP0_Cause;
+ int i;
if (env->insn_flags & ISA_MIPS32R2)
mask |= 1 << CP0Ca_DC;
@@ -1360,18 +1348,18 @@ void helper_mtc0_cause (target_ulong arg1)
cpu_mips_start_count(env);
}
- /* Handle the software interrupt as an hardware one, as they
- are very similar */
- if (arg1 & CP0Ca_IP_mask) {
- cpu_mips_update_irq(env);
+ /* Set/reset software interrupts */
+ for (i = 0 ; i < 2 ; i++) {
+ if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+ cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+ }
}
}
void helper_mtc0_ebase (target_ulong arg1)
{
/* vectored interrupts not implemented */
- /* Multi-CPU not implemented */
- env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
+ env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}
void helper_mtc0_config0 (target_ulong arg1)
@@ -1610,8 +1598,10 @@ void helper_fork(target_ulong arg1, target_ulong arg2)
// TODO: store to TC register
}
-target_ulong helper_yield(target_ulong arg1)
+target_ulong helper_yield(target_ulong arg)
{
+ target_long arg1 = arg;
+
if (arg1 < 0) {
/* No scheduling policy implemented. */
if (arg1 != -2) {
@@ -1793,8 +1783,6 @@ target_ulong helper_di (void)
target_ulong t0 = env->CP0_Status;
env->CP0_Status = t0 & ~(1 << CP0St_IE);
- cpu_mips_update_irq(env);
-
return t0;
}
@@ -1803,8 +1791,6 @@ target_ulong helper_ei (void)
target_ulong t0 = env->CP0_Status;
env->CP0_Status = t0 | (1 << CP0St_IE);
- cpu_mips_update_irq(env);
-
return t0;
}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 7168273381..d62c6158fc 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1153,6 +1153,7 @@ static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "ll";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -1212,6 +1213,7 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
opn = "swr";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -1247,6 +1249,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
opn = "sc";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
tcg_temp_free(t1);
tcg_temp_free(t0);
@@ -1312,6 +1315,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
generate_exception(ctx, EXCP_RI);
goto out;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
out:
tcg_temp_free(t0);
@@ -1412,6 +1416,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
break;
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
}
@@ -1454,6 +1459,7 @@ static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t
opn = "lui";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
}
@@ -1481,6 +1487,7 @@ static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t im
opn = "sltiu";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
tcg_temp_free(t0);
}
@@ -1572,6 +1579,7 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
break;
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
tcg_temp_free(t0);
}
@@ -1752,6 +1760,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "mul";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}
@@ -1789,6 +1798,7 @@ static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt)
tcg_gen_movi_tl(cpu_gpr[rd], 0);
gen_set_label(l1);
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}
@@ -1849,6 +1859,7 @@ static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt)
opn = "xor";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}
@@ -1878,6 +1889,7 @@ static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt)
opn = "sltu";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -1958,6 +1970,7 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
break;
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -1997,6 +2010,7 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
opn = "mtlo";
break;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s", opn, regnames[reg]);
}
@@ -2229,6 +2243,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
generate_exception(ctx, EXCP_RI);
goto out;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
out:
tcg_temp_free(t0);
@@ -2308,6 +2323,7 @@ static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
goto out;
}
gen_store_gpr(t0, rd);
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
out:
@@ -2348,6 +2364,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
break;
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
tcg_temp_free(t0);
}
@@ -2561,6 +2578,7 @@ static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -3730,6 +3748,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
default:
goto die;
}
+ (void)rn; /* avoid a compiler warning */
LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
return;
@@ -4320,6 +4339,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s
default:
goto die;
}
+ (void)rn; /* avoid a compiler warning */
LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
/* For simplicity assume that all writes can cause interrupts. */
if (use_icount) {
@@ -4892,6 +4912,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
default:
goto die;
}
+ (void)rn; /* avoid a compiler warning */
LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
return;
@@ -5190,7 +5211,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
+ /* Mark as an IO operation because we may trigger a software
+ interrupt. */
+ if (use_icount) {
+ gen_io_start();
+ }
gen_helper_mtc0_cause(arg);
+ if (use_icount) {
+ gen_io_end();
+ }
+ /* Stop translation as we may have triggered an intetrupt */
+ ctx->bstate = BS_STOP;
rn = "Cause";
break;
default:
@@ -5473,6 +5504,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int
default:
goto die;
}
+ (void)rn; /* avoid a compiler warning */
LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
/* For simplicity assume that all writes can cause interrupts. */
if (use_icount) {
@@ -5933,6 +5965,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
generate_exception(ctx, EXCP_RI);
return;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
}
#endif /* !CONFIG_USER_ONLY */
@@ -6042,6 +6075,7 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
generate_exception (ctx, EXCP_RI);
goto out;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
ctx->hflags, btarget);
ctx->btarget = btarget;
@@ -6271,6 +6305,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
generate_exception (ctx, EXCP_RI);
goto out;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
out:
@@ -7598,6 +7633,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
generate_exception (ctx, EXCP_RI);
return;
}
+ (void)opn; /* avoid a compiler warning */
switch (optype) {
case BINOP:
MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
@@ -7710,6 +7746,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
break;
}
tcg_temp_free(t0);
+ (void)opn; (void)store; /* avoid compiler warnings */
MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
regnames[index], regnames[base]);
}
@@ -7983,6 +8020,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
generate_exception (ctx, EXCP_RI);
return;
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
fregnames[fs], fregnames[ft]);
}
@@ -9961,6 +9999,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
break;
#endif
}
+ (void)opn; /* avoid a compiler warning */
MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
tcg_temp_free(t0);
tcg_temp_free(t1);
@@ -12365,7 +12404,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
} else {
switch (ctx.bstate) {
case BS_STOP:
- gen_helper_interrupt_restart();
gen_goto_tb(&ctx, 0, ctx.pc);
break;
case BS_NONE:
@@ -12373,7 +12411,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
gen_goto_tb(&ctx, 0, ctx.pc);
break;
case BS_EXCP:
- gen_helper_interrupt_restart();
tcg_gen_exit_tb(0);
break;
case BS_BRANCH:
@@ -12671,8 +12708,7 @@ void cpu_reset (CPUMIPSState *env)
env->CP0_Random = env->tlb->nb_tlb - 1;
env->tlb->tlb_in_use = env->tlb->nb_tlb;
env->CP0_Wired = 0;
- /* SMP not implemented */
- env->CP0_EBase = 0x80000000;
+ env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF);
env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
/* vectored interrupts not implemented, timer on int 7,
no performance counters. */
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 0d9899e1bd..8d1ece704d 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -45,10 +45,6 @@
(0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
(0 << CP0C3_SM) | (0 << CP0C3_TL))
-/* Define a implementation number of 1.
- Define a major version 1, minor version 0. */
-#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
-
/* MMU types, the first four entries have the same layout as the
CP0C0_MT field. */
enum mips_mmu_types {