* [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support
@ 2009-11-23 20:49 Nathan Froyd
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
` (11 more replies)
0 siblings, 12 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:49 UTC (permalink / raw)
To: qemu-devel
This patchset adds MIPS16 support to the MIPS backend. MIPS16 is a
compact encoding of a subset of the MIPS integer instructions, similar
to ARM's Thumb mode. The processor enters MIPS16 mode by executing a
special jump instruction; execution continus at the jump target in
MIPS16 mode until the processor returns to MIPS32/64 mode by executing a
special jump instruction.
The patches have been tested with GCC's testsuite and GDB's testsuite.
-Nathan
^ permalink raw reply [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
@ 2009-11-23 20:49 ` Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
` (10 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:49 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/cpu.h | 1 +
target-mips/translate.c | 2 ++
2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 82f9a38..e8febe6 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -167,6 +167,7 @@ struct TCState {
target_ulong CP0_TCContext;
target_ulong CP0_TCSchedule;
target_ulong CP0_TCScheFBack;
+ uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
int32_t CP0_Debug_tcstatus;
};
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e9d9224..b0a1b29 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -463,6 +463,7 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
target_ulong pc, saved_pc;
uint32_t opcode;
+ int isa_mode;
int singlestep_enabled;
/* Routine used to access memory */
int mem_idx;
@@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
ctx.pc = pc_start;
ctx.saved_pc = -1;
ctx.singlestep_enabled = env->singlestep_enabled;
+ ctx.isa_mode = env->active_tc.ISAMode;
ctx.tb = tb;
ctx.bstate = BS_NONE;
/* Restore delay slot state from the tb context. */
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
` (9 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
We create separate masks for the "basic" branch hflags and the
"extended" branch hflags and define MIPS_HFLAG_BMASK as the logical or
of those two. This is done to avoid churning the codebase in lots of
different places.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/cpu.h | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index e8febe6..9413be0 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -441,11 +441,17 @@ struct CPUMIPSState {
* the delay slot, record what type of branch it is so that we can
* resume translation properly. It might be possible to reduce
* this from three bits to two. */
-#define MIPS_HFLAG_BMASK 0x1C00
+#define MIPS_HFLAG_BMASK_BASE 0x1C00
#define MIPS_HFLAG_B 0x0400 /* Unconditional branch */
#define MIPS_HFLAG_BC 0x0800 /* Conditional branch */
#define MIPS_HFLAG_BL 0x0C00 /* Likely branch */
#define MIPS_HFLAG_BR 0x1000 /* branch to register (can't link TB) */
+ /* Extra flags about the current pending branch. */
+#define MIPS_HFLAG_BMASK_EXT 0xE000
+#define MIPS_HFLAG_BDS16 0x2000 /* branch requires 16-bit delay slot */
+#define MIPS_HFLAG_BDS32 0x4000 /* branch requires 32-bit delay slot */
+#define MIPS_HFLAG_BX 0x8000 /* branch exchange execution mode */
+#define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
` (8 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/helper.c | 47 ++++++++++++++++++++++++++---------------------
target-mips/op_helper.c | 10 +++++++---
2 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 4a37277..e54a31a 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -339,6 +339,20 @@ static const char * const excp_names[EXCP_LAST + 1] = {
[EXCP_CACHE] = "cache error",
};
+static target_ulong exception_resume_pc (CPUState *env)
+{
+ target_ulong bad_pc;
+
+ bad_pc = env->active_tc.PC | env->active_tc.ISAMode;
+ if (env->hflags & MIPS_HFLAG_BMASK) {
+ /* If the exception was raised from a delay slot, come back to
+ the jump. */
+ bad_pc -= (env->hflags & MIPS_HFLAG_BDS16 ? 2 : 4);
+ }
+
+ return bad_pc;
+}
+
void do_interrupt (CPUState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -366,7 +380,7 @@ void do_interrupt (CPUState *env)
resume will always occur on the next instruction
(but we assume the pc has always been updated during
code translation). */
- env->CP0_DEPC = env->active_tc.PC;
+ env->CP0_DEPC = env->active_tc.PC | env->active_tc.ISAMode;
goto enter_debug_mode;
case EXCP_DINT:
env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -383,14 +397,8 @@ void do_interrupt (CPUState *env)
case EXCP_DDBL:
env->CP0_Debug |= 1 << CP0DB_DDBL;
set_DEPC:
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
- env->CP0_DEPC = env->active_tc.PC - 4;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_DEPC = env->active_tc.PC;
- }
+ env->CP0_DEPC = exception_resume_pc(env);
+ env->hflags &= ~MIPS_HFLAG_BMASK;
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
@@ -398,6 +406,8 @@ void do_interrupt (CPUState *env)
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->active_tc.PC = (int32_t)0xBFC00480;
+ /* Exception handlers are entered in 32-bit mode. */
+ env->active_tc.ISAMode = 0;
break;
case EXCP_RESET:
cpu_reset(env);
@@ -409,20 +419,16 @@ void do_interrupt (CPUState *env)
case EXCP_NMI:
env->CP0_Status |= (1 << CP0St_NMI);
set_error_EPC:
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
- env->CP0_ErrorEPC = env->active_tc.PC - 4;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_ErrorEPC = env->active_tc.PC;
- }
+ env->CP0_ErrorEPC = exception_resume_pc(env);
+ env->hflags &= ~MIPS_HFLAG_BMASK;
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->active_tc.PC = (int32_t)0xBFC00000;
+ /* Exception handlers are entered in 32-bit mode. */
+ env->active_tc.ISAMode = 0;
break;
case EXCP_EXT_INTERRUPT:
cause = 0;
@@ -524,13 +530,10 @@ void do_interrupt (CPUState *env)
}
set_EPC:
if (!(env->CP0_Status & (1 << CP0St_EXL))) {
+ env->CP0_EPC = exception_resume_pc(env);
if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
- env->CP0_EPC = env->active_tc.PC - 4;
env->CP0_Cause |= (1 << CP0Ca_BD);
} else {
- env->CP0_EPC = env->active_tc.PC;
env->CP0_Cause &= ~(1 << CP0Ca_BD);
}
env->CP0_Status |= (1 << CP0St_EXL);
@@ -544,6 +547,8 @@ void do_interrupt (CPUState *env)
env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
env->active_tc.PC += offset;
+ /* Exception handlers are entered in 32-bit mode. */
+ env->active_tc.ISAMode = 0;
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
break;
default:
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 52d687d..d585d65 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1701,10 +1701,12 @@ void helper_eret (void)
{
debug_pre_eret();
if (env->CP0_Status & (1 << CP0St_ERL)) {
- env->active_tc.PC = env->CP0_ErrorEPC;
+ env->active_tc.PC = env->CP0_ErrorEPC & ~(target_ulong)1;
+ env->active_tc.ISAMode = env->CP0_ErrorEPC & 1;
env->CP0_Status &= ~(1 << CP0St_ERL);
} else {
- env->active_tc.PC = env->CP0_EPC;
+ env->active_tc.PC = env->CP0_EPC & ~(target_ulong)1;
+ env->active_tc.ISAMode = env->CP0_EPC & 1;
env->CP0_Status &= ~(1 << CP0St_EXL);
}
compute_hflags(env);
@@ -1715,7 +1717,9 @@ void helper_eret (void)
void helper_deret (void)
{
debug_pre_eret();
- env->active_tc.PC = env->CP0_DEPC;
+ env->active_tc.PC = env->CP0_DEPC & ~(target_ulong)1;
+ env->active_tc.ISAMode = env->CP0_DEPC & 1;
+
env->hflags &= MIPS_HFLAG_DM;
compute_hflags(env);
debug_post_eret();
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, }
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (2 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
` (7 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
It's easier to implement mips16 shift instructions if we're not
examining the opcode inside gen_shift_{imm,}. So move ROTR and ROTRV
and do the special-case handling of SRL and SRLV inside decode_opc.
Likewise for their 64-bit counterparts.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 287 ++++++++++++++++++++++++-----------------------
1 files changed, 148 insertions(+), 139 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b0a1b29..c03d1bf 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -128,18 +128,23 @@ enum {
/* SSNOP is SLL r0, r0, 1 */
/* EHB is SLL r0, r0, 3 */
OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */
+ OPC_ROTR = OPC_SRL | (1 << 21),
OPC_SRA = 0x03 | OPC_SPECIAL,
OPC_SLLV = 0x04 | OPC_SPECIAL,
OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */
+ OPC_ROTRV = OPC_SRLV | (1 << 6),
OPC_SRAV = 0x07 | OPC_SPECIAL,
OPC_DSLLV = 0x14 | OPC_SPECIAL,
OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */
+ OPC_DROTRV = OPC_DSRLV | (1 << 6),
OPC_DSRAV = 0x17 | OPC_SPECIAL,
OPC_DSLL = 0x38 | OPC_SPECIAL,
OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */
+ OPC_DROTR = OPC_DSRL | (1 << 21),
OPC_DSRA = 0x3B | OPC_SPECIAL,
OPC_DSLL32 = 0x3C | OPC_SPECIAL,
OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */
+ OPC_DROTR32 = OPC_DSRL32 | (1 << 21),
OPC_DSRA32 = 0x3F | OPC_SPECIAL,
/* Multiplication / division */
OPC_MULT = 0x18 | OPC_SPECIAL,
@@ -1447,43 +1452,24 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "sra";
break;
case OPC_SRL:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 0:
- if (uimm != 0) {
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
- } else {
- tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
- }
- opn = "srl";
- break;
- case 1:
- /* rotr is decoded as srl on non-R2 CPUs */
- if (env->insn_flags & ISA_MIPS32R2) {
- if (uimm != 0) {
- TCGv_i32 t1 = tcg_temp_new_i32();
-
- tcg_gen_trunc_tl_i32(t1, t0);
- tcg_gen_rotri_i32(t1, t1, uimm);
- tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
- tcg_temp_free_i32(t1);
- }
- opn = "rotr";
- } else {
- if (uimm != 0) {
- tcg_gen_ext32u_tl(t0, t0);
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
- } else {
- tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
- }
- opn = "srl";
- }
- break;
- default:
- MIPS_INVAL("invalid srl flag");
- generate_exception(ctx, EXCP_RI);
- break;
+ if (uimm != 0) {
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+ } else {
+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
}
+ opn = "srl";
+ break;
+ case OPC_ROTR:
+ if (uimm != 0) {
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t1, t0);
+ tcg_gen_rotri_i32(t1, t1, uimm);
+ tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
+ tcg_temp_free_i32(t1);
+ }
+ opn = "rotr";
break;
#if defined(TARGET_MIPS64)
case OPC_DSLL:
@@ -1495,28 +1481,14 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsra";
break;
case OPC_DSRL:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 0:
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
- opn = "dsrl";
- break;
- case 1:
- /* drotr is decoded as dsrl on non-R2 CPUs */
- if (env->insn_flags & ISA_MIPS32R2) {
- if (uimm != 0) {
- tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
- }
- opn = "drotr";
- } else {
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
- opn = "dsrl";
- }
- break;
- default:
- MIPS_INVAL("invalid dsrl flag");
- generate_exception(ctx, EXCP_RI);
- break;
+ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
+ opn = "dsrl";
+ break;
+ case OPC_DROTR:
+ if (uimm != 0) {
+ tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
}
+ opn = "drotr";
break;
case OPC_DSLL32:
tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32);
@@ -1527,26 +1499,12 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsra32";
break;
case OPC_DSRL32:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 0:
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
- opn = "dsrl32";
- break;
- case 1:
- /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
- if (env->insn_flags & ISA_MIPS32R2) {
- tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
- opn = "drotr32";
- } else {
- tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
- opn = "dsrl32";
- }
- break;
- default:
- MIPS_INVAL("invalid dsrl32 flag");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
+ opn = "dsrl32";
+ break;
+ case OPC_DROTR32:
+ tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
+ opn = "drotr32";
break;
#endif
}
@@ -1895,40 +1853,25 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "srav";
break;
case OPC_SRLV:
- switch ((ctx->opcode >> 6) & 0x1f) {
- case 0:
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_andi_tl(t0, t0, 0x1f);
- tcg_gen_shr_tl(t0, t1, t0);
- tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
- opn = "srlv";
- break;
- case 1:
- /* rotrv is decoded as srlv on non-R2 CPUs */
- if (env->insn_flags & ISA_MIPS32R2) {
- TCGv_i32 t2 = tcg_temp_new_i32();
- TCGv_i32 t3 = tcg_temp_new_i32();
-
- tcg_gen_trunc_tl_i32(t2, t0);
- tcg_gen_trunc_tl_i32(t3, t1);
- tcg_gen_andi_i32(t2, t2, 0x1f);
- tcg_gen_rotr_i32(t2, t3, t2);
- tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t3);
- opn = "rotrv";
- } else {
- tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_andi_tl(t0, t0, 0x1f);
- tcg_gen_shr_tl(t0, t1, t0);
- tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
- opn = "srlv";
- }
- break;
- default:
- MIPS_INVAL("invalid srlv flag");
- generate_exception(ctx, EXCP_RI);
- break;
+ tcg_gen_ext32u_tl(t1, t1);
+ tcg_gen_andi_tl(t0, t0, 0x1f);
+ tcg_gen_shr_tl(t0, t1, t0);
+ tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
+ opn = "srlv";
+ break;
+ case OPC_ROTRV:
+ {
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_andi_i32(t2, t2, 0x1f);
+ tcg_gen_rotr_i32(t2, t3, t2);
+ tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
+ opn = "rotrv";
}
break;
#if defined(TARGET_MIPS64)
@@ -1943,29 +1886,14 @@ static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc,
opn = "dsrav";
break;
case OPC_DSRLV:
- switch ((ctx->opcode >> 6) & 0x1f) {
- case 0:
- tcg_gen_andi_tl(t0, t0, 0x3f);
- tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
- opn = "dsrlv";
- break;
- case 1:
- /* drotrv is decoded as dsrlv on non-R2 CPUs */
- if (env->insn_flags & ISA_MIPS32R2) {
- tcg_gen_andi_tl(t0, t0, 0x3f);
- tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
- opn = "drotrv";
- } else {
- tcg_gen_andi_tl(t0, t0, 0x3f);
- tcg_gen_shr_tl(t0, t1, t0);
- opn = "dsrlv";
- }
- break;
- default:
- MIPS_INVAL("invalid dsrlv flag");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ tcg_gen_andi_tl(t0, t0, 0x3f);
+ tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
+ opn = "dsrlv";
+ break;
+ case OPC_DROTRV:
+ tcg_gen_andi_tl(t0, t0, 0x3f);
+ tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
+ opn = "drotrv";
break;
#endif
}
@@ -7677,9 +7605,24 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (op1) {
case OPC_SLL: /* Shift with immediate */
case OPC_SRA:
- case OPC_SRL:
gen_shift_imm(env, ctx, op1, rd, rt, sa);
break;
+ case OPC_SRL:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* rotr is decoded as srl on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_ROTR;
+ }
+ /* Fallthrough */
+ case 0:
+ gen_shift_imm(env, ctx, op1, rd, rt, sa);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
case OPC_MOVN: /* Conditional move */
case OPC_MOVZ:
check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
@@ -7689,10 +7632,25 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_arith(env, ctx, op1, rd, rs, rt);
break;
case OPC_SLLV: /* Shifts */
- case OPC_SRLV:
case OPC_SRAV:
gen_shift(env, ctx, op1, rd, rs, rt);
break;
+ case OPC_SRLV:
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 1:
+ /* rotrv is decoded as srlv on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_ROTRV;
+ }
+ /* Fallthrough */
+ case 0:
+ gen_shift(env, ctx, op1, rd, rs, rt);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
case OPC_SLT: /* Set on less than */
case OPC_SLTU:
gen_slt(env, op1, rd, rs, rt);
@@ -7770,14 +7728,48 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
/* MIPS64 specific opcodes */
case OPC_DSLL:
case OPC_DSRA:
- case OPC_DSRL:
case OPC_DSLL32:
case OPC_DSRA32:
- case OPC_DSRL32:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift_imm(env, ctx, op1, rd, rt, sa);
break;
+ case OPC_DSRL:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* drotr is decoded as dsrl on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTR;
+ }
+ /* Fallthrough */
+ case 0:
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_shift_imm(env, ctx, op1, rd, rt, sa);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_DSRL32:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTR32;
+ }
+ /* Fallthrough */
+ case 0:
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_shift_imm(env, ctx, op1, rd, rt, sa);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
case OPC_DADD ... OPC_DSUBU:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
@@ -7785,11 +7777,28 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break;
case OPC_DSLLV:
case OPC_DSRAV:
- case OPC_DSRLV:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift(env, ctx, op1, rd, rs, rt);
break;
+ case OPC_DSRLV:
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 1:
+ /* drotrv is decoded as dsrlv on non-R2 CPUs */
+ if (env->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTRV;
+ }
+ /* Fallthrough */
+ case 0:
+ check_insn(env, ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_shift(env, ctx, op1, rd, rs, rt);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
case OPC_DMULT ... OPC_DDIVU:
check_insn(env, ctx, ISA_MIPS3);
check_mips_64(ctx);
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (3 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
` (6 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index c03d1bf..1157e97 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -2406,6 +2406,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
/* Branches (before delay slot) */
static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
+ int insn_bytes,
int rs, int rt, int32_t offset)
{
target_ulong btgt = -1;
@@ -2434,7 +2435,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
gen_load_gpr(t1, rt);
bcond_compute = 1;
}
- btgt = ctx->pc + 4 + offset;
+ btgt = ctx->pc + insn_bytes + offset;
break;
case OPC_BGEZ:
case OPC_BGEZAL:
@@ -2453,12 +2454,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
gen_load_gpr(t0, rs);
bcond_compute = 1;
}
- btgt = ctx->pc + 4 + offset;
+ btgt = ctx->pc + insn_bytes + offset;
break;
case OPC_J:
case OPC_JAL:
/* Jump to immediate */
- btgt = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset;
+ btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
break;
case OPC_JR:
case OPC_JALR:
@@ -7670,7 +7671,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
gen_muldiv(ctx, op1, rs, rt);
break;
case OPC_JR ... OPC_JALR:
- gen_compute_branch(ctx, op1, rs, rd, sa);
+ gen_compute_branch(ctx, op1, 4, rs, rd, sa);
return;
case OPC_TGE ... OPC_TEQ: /* Traps */
case OPC_TNE:
@@ -7959,7 +7960,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
switch (op1) {
case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
case OPC_BLTZAL ... OPC_BGEZALL:
- gen_compute_branch(ctx, op1, rs, -1, imm << 2);
+ gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
return;
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
case OPC_TNEI:
@@ -8078,11 +8079,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break;
case OPC_J ... OPC_JAL: /* Jump */
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
- gen_compute_branch(ctx, op, rs, rt, offset);
+ gen_compute_branch(ctx, op, 4, rs, rt, offset);
return;
case OPC_BEQ ... OPC_BGTZ: /* Branch */
case OPC_BEQL ... OPC_BGTZL:
- gen_compute_branch(ctx, op, rs, rt, imm << 2);
+ gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
return;
case OPC_LB ... OPC_LWR: /* Load and stores */
case OPC_SB ... OPC_SW:
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (4 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
` (5 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
This is a common pattern in existing code. We'll also use it to
implement the mips16 SAVE/RESTORE instructions.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 40 ++++++++++++++++------------------------
1 files changed, 16 insertions(+), 24 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 1157e97..fece3c1 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -997,6 +997,19 @@ OP_ST_ATOMIC(scd,st64,ld64,0x7);
#endif
#undef OP_ST_ATOMIC
+static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
+ int base, int16_t offset)
+{
+ if (base == 0) {
+ tcg_gen_movi_tl(addr, offset);
+ } else if (offset == 0) {
+ gen_load_gpr(addr, base);
+ } else {
+ tcg_gen_movi_tl(addr, offset);
+ gen_op_addr_add(ctx, addr, addr, cpu_gpr[base]);
+ }
+}
+
/* Load and store */
static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
int base, int16_t offset)
@@ -1005,14 +1018,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- if (base == 0) {
- tcg_gen_movi_tl(t0, offset);
- } else if (offset == 0) {
- gen_load_gpr(t0, base);
- } else {
- tcg_gen_movi_tl(t0, offset);
- gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
- }
+ gen_base_offset_addr(ctx, t0, base, offset);
/* Don't do NOP if destination is zero: we must perform the actual
memory access. */
switch (opc) {
@@ -1163,14 +1169,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
t0 = tcg_temp_local_new();
- if (base == 0) {
- tcg_gen_movi_tl(t0, offset);
- } else if (offset == 0) {
- gen_load_gpr(t0, base);
- } else {
- tcg_gen_movi_tl(t0, offset);
- gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
- }
+ gen_base_offset_addr(ctx, t0, base, offset);
/* Don't do NOP if destination is zero: we must perform the actual
memory access. */
@@ -1202,14 +1201,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
const char *opn = "flt_ldst";
TCGv t0 = tcg_temp_new();
- if (base == 0) {
- tcg_gen_movi_tl(t0, offset);
- } else if (offset == 0) {
- gen_load_gpr(t0, base);
- } else {
- tcg_gen_movi_tl(t0, offset);
- gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
- }
+ gen_base_offset_addr(ctx, t0, base, offset);
/* Don't do NOP if destination is zero: we must perform the actual
memory access. */
switch (opc) {
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (5 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
` (4 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
Move delay slot handling to common code whose invocation can be
controlled from gen_intermediate_code_internal.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 134 +++++++++++++++++++++++++++-------------------
1 files changed, 79 insertions(+), 55 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index fece3c1..e7aee33 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7548,6 +7548,56 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
fregnames[fs], fregnames[ft]);
}
+static void handle_delay_slot (CPUState *env, DisasContext *ctx,
+ int insn_bytes)
+{
+ if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
+ /* Branches completion */
+ ctx->hflags &= ~MIPS_HFLAG_BMASK;
+ ctx->bstate = BS_BRANCH;
+ save_cpu_state(ctx, 0);
+ /* FIXME: Need to clear can_do_io. */
+ switch (hflags) {
+ case MIPS_HFLAG_B:
+ /* unconditional branch */
+ MIPS_DEBUG("unconditional branch");
+ gen_goto_tb(ctx, 0, ctx->btarget);
+ break;
+ case MIPS_HFLAG_BL:
+ /* blikely taken case */
+ MIPS_DEBUG("blikely branch taken");
+ gen_goto_tb(ctx, 0, ctx->btarget);
+ break;
+ case MIPS_HFLAG_BC:
+ /* Conditional branch */
+ MIPS_DEBUG("conditional branch");
+ {
+ int l1 = gen_new_label();
+
+ tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+ gen_goto_tb(ctx, 1, ctx->pc + insn_bytes);
+ gen_set_label(l1);
+ gen_goto_tb(ctx, 0, ctx->btarget);
+ }
+ break;
+ case MIPS_HFLAG_BR:
+ /* unconditional branch to register */
+ MIPS_DEBUG("branch to register");
+ tcg_gen_mov_tl(cpu_PC, btarget);
+ if (ctx->singlestep_enabled) {
+ save_cpu_state(ctx, 0);
+ gen_helper_0i(raise_exception, EXCP_DEBUG);
+ }
+ tcg_gen_exit_tb(0);
+ break;
+ default:
+ MIPS_DEBUG("unknown branch");
+ break;
+ }
+ }
+}
+
/* ISA extensions (ASEs) */
/* MIPS16 extension to MIPS32 */
/* SmartMIPS extension to MIPS32 */
@@ -7558,7 +7608,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
#endif
-static void decode_opc (CPUState *env, DisasContext *ctx)
+static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
{
int32_t offset;
int rs, rt, rd, sa;
@@ -7573,7 +7623,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
}
/* Handle blikely not taken case */
- if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
+ if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
int l1 = gen_new_label();
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
@@ -7664,7 +7714,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break;
case OPC_JR ... OPC_JALR:
gen_compute_branch(ctx, op1, 4, rs, rd, sa);
- return;
+ *is_branch = 1;
+ break;
case OPC_TGE ... OPC_TEQ: /* Traps */
case OPC_TNE:
gen_trap(ctx, op1, rs, rt, -1);
@@ -7953,7 +8004,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
case OPC_BLTZAL ... OPC_BGEZALL:
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
- return;
+ *is_branch = 1;
+ break;
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
case OPC_TNEI:
gen_trap(ctx, op1, rs, -1, imm);
@@ -8072,11 +8124,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_J ... OPC_JAL: /* Jump */
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
gen_compute_branch(ctx, op, 4, rs, rt, offset);
- return;
+ *is_branch = 1;
+ break;
case OPC_BEQ ... OPC_BGTZ: /* Branch */
case OPC_BEQL ... OPC_BGTZL:
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
- return;
+ *is_branch = 1;
+ break;
case OPC_LB ... OPC_LWR: /* Load and stores */
case OPC_SB ... OPC_SW:
case OPC_SWR:
@@ -8137,7 +8191,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_BC1:
gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
(rt >> 2) & 0x7, imm << 2);
- return;
+ *is_branch = 1;
+ break;
case OPC_S_FMT:
case OPC_D_FMT:
case OPC_W_FMT:
@@ -8242,51 +8297,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
generate_exception(ctx, EXCP_RI);
break;
}
- if (ctx->hflags & MIPS_HFLAG_BMASK) {
- int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
- /* Branches completion */
- ctx->hflags &= ~MIPS_HFLAG_BMASK;
- ctx->bstate = BS_BRANCH;
- save_cpu_state(ctx, 0);
- /* FIXME: Need to clear can_do_io. */
- switch (hflags) {
- case MIPS_HFLAG_B:
- /* unconditional branch */
- MIPS_DEBUG("unconditional branch");
- gen_goto_tb(ctx, 0, ctx->btarget);
- break;
- case MIPS_HFLAG_BL:
- /* blikely taken case */
- MIPS_DEBUG("blikely branch taken");
- gen_goto_tb(ctx, 0, ctx->btarget);
- break;
- case MIPS_HFLAG_BC:
- /* Conditional branch */
- MIPS_DEBUG("conditional branch");
- {
- int l1 = gen_new_label();
-
- tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
- gen_goto_tb(ctx, 1, ctx->pc + 4);
- gen_set_label(l1);
- gen_goto_tb(ctx, 0, ctx->btarget);
- }
- break;
- case MIPS_HFLAG_BR:
- /* unconditional branch to register */
- MIPS_DEBUG("branch to register");
- tcg_gen_mov_tl(cpu_PC, btarget);
- if (ctx->singlestep_enabled) {
- save_cpu_state(ctx, 0);
- gen_helper_0i(raise_exception, EXCP_DEBUG);
- }
- tcg_gen_exit_tb(0);
- break;
- default:
- MIPS_DEBUG("unknown branch");
- break;
- }
- }
}
static inline void
@@ -8300,6 +8310,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int j, lj = -1;
int num_insns;
int max_insns;
+ int insn_bytes;
+ int is_branch;
if (search_pc)
qemu_log("search pc %d\n", search_pc);
@@ -8360,9 +8372,21 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
}
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
- ctx.opcode = ldl_code(ctx.pc);
- decode_opc(env, &ctx);
- ctx.pc += 4;
+
+ is_branch = 0;
+ if (ctx.isa_mode == 0) {
+ ctx.opcode = ldl_code(ctx.pc);
+ insn_bytes = 4;
+ decode_opc(env, &ctx, &is_branch);
+ } else {
+ generate_exception(&ctx, EXCP_RI);
+ break;
+ }
+ if (!is_branch) {
+ handle_delay_slot(env, &ctx, insn_bytes);
+ }
+ ctx.pc += insn_bytes;
+
num_insns++;
/* Execute a branch and its delay slot as a single instruction.
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (6 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
` (3 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e7aee33..611774b 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -7600,6 +7600,118 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
/* ISA extensions (ASEs) */
/* MIPS16 extension to MIPS32 */
+
+/* MIPS16 major opcodes */
+enum {
+ M16_OPC_ADDIUSP = 0x00,
+ M16_OPC_ADDIUPC = 0x01,
+ M16_OPC_B = 0x02,
+ M16_OPC_JAL = 0x03,
+ M16_OPC_BEQZ = 0x04,
+ M16_OPC_BNEQZ = 0x05,
+ M16_OPC_SHIFT = 0x06,
+ M16_OPC_LD = 0x07,
+ M16_OPC_RRIA = 0x08,
+ M16_OPC_ADDIU8 = 0x09,
+ M16_OPC_SLTI = 0x0a,
+ M16_OPC_SLTIU = 0x0b,
+ M16_OPC_I8 = 0x0c,
+ M16_OPC_LI = 0x0d,
+ M16_OPC_CMPI = 0x0e,
+ M16_OPC_SD = 0x0f,
+ M16_OPC_LB = 0x10,
+ M16_OPC_LH = 0x11,
+ M16_OPC_LWSP = 0x12,
+ M16_OPC_LW = 0x13,
+ M16_OPC_LBU = 0x14,
+ M16_OPC_LHU = 0x15,
+ M16_OPC_LWPC = 0x16,
+ M16_OPC_LWU = 0x17,
+ M16_OPC_SB = 0x18,
+ M16_OPC_SH = 0x19,
+ M16_OPC_SWSP = 0x1a,
+ M16_OPC_SW = 0x1b,
+ M16_OPC_RRR = 0x1c,
+ M16_OPC_RR = 0x1d,
+ M16_OPC_EXTEND = 0x1e,
+ M16_OPC_I64 = 0x1f
+};
+
+/* I8 funct field */
+enum {
+ I8_BTEQZ = 0x0,
+ I8_BTNEZ = 0x1,
+ I8_SWRASP = 0x2,
+ I8_ADJSP = 0x3,
+ I8_SVRS = 0x4,
+ I8_MOV32R = 0x5,
+ I8_MOVR32 = 0x7
+};
+
+/* RRR f field */
+enum {
+ RRR_DADDU = 0x0,
+ RRR_ADDU = 0x1,
+ RRR_DSUBU = 0x2,
+ RRR_SUBU = 0x3
+};
+
+/* RR funct field */
+enum {
+ RR_JR = 0x00,
+ RR_SDBBP = 0x01,
+ RR_SLT = 0x02,
+ RR_SLTU = 0x03,
+ RR_SLLV = 0x04,
+ RR_BREAK = 0x05,
+ RR_SRLV = 0x06,
+ RR_SRAV = 0x07,
+ RR_DSRL = 0x08,
+ RR_CMP = 0x0a,
+ RR_NEG = 0x0b,
+ RR_AND = 0x0c,
+ RR_OR = 0x0d,
+ RR_XOR = 0x0e,
+ RR_NOT = 0x0f,
+ RR_MFHI = 0x10,
+ RR_CNVT = 0x11,
+ RR_MFLO = 0x12,
+ RR_DSRA = 0x13,
+ RR_DSLLV = 0x14,
+ RR_DSRLV = 0x16,
+ RR_DSRAV = 0x17,
+ RR_MULT = 0x18,
+ RR_MULTU = 0x19,
+ RR_DIV = 0x1a,
+ RR_DIVU = 0x1b,
+ RR_DMULT = 0x1c,
+ RR_DMULTU = 0x1d,
+ RR_DDIV = 0x1e,
+ RR_DDIVU = 0x1f
+};
+
+/* I64 funct field */
+enum {
+ I64_LDSP = 0x0,
+ I64_SDSP = 0x1,
+ I64_SDRASP = 0x2,
+ I64_DADJSP = 0x3,
+ I64_LDPC = 0x4,
+ I64_DADDIU = 0x5,
+ I64_DADDIUPC = 0x6,
+ I64_DADDIUSP = 0x7
+};
+
+/* RR ry field for CNVT */
+enum {
+ RR_RY_CNVT_ZEB = 0x0,
+ RR_RY_CNVT_ZEH = 0x1,
+ RR_RY_CNVT_ZEW = 0x2,
+ RR_RY_CNVT_SEB = 0x4,
+ RR_RY_CNVT_SEH = 0x5,
+ RR_RY_CNVT_SEW = 0x6,
+};
+
/* SmartMIPS extension to MIPS32 */
#if defined(TARGET_MIPS64)
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (7 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
` (2 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
There's no good way to add this incrementally, so we do it all at once.
The only changes to shared code are in handle_delay_slot. We need to
flip ISAMode when doing a jump-and-exchange. We also need to set
ISAMode the low bit of the target address for jump-to-register.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 980 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 976 insertions(+), 4 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 611774b..49d2264 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -83,6 +83,7 @@ enum {
OPC_LH = (0x21 << 26),
OPC_LWL = (0x22 << 26),
OPC_LW = (0x23 << 26),
+ OPC_LWPC = OPC_LW | 0x5,
OPC_LBU = (0x24 << 26),
OPC_LHU = (0x25 << 26),
OPC_LWR = (0x26 << 26),
@@ -173,6 +174,7 @@ enum {
/* Jumps */
OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
+ OPC_JALRC = OPC_JALR | (0x5 << 6),
/* Traps */
OPC_TGE = 0x30 | OPC_SPECIAL,
OPC_TGEU = 0x31 | OPC_SPECIAL,
@@ -1074,6 +1076,19 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
opn = "sdr";
break;
#endif
+ case OPC_LWPC:
+ save_cpu_state(ctx, 1);
+ if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;
+
+ tcg_gen_movi_tl(t1, (ctx->pc - branch_bytes) & ~(target_ulong)3);
+ } else {
+ tcg_gen_movi_tl(t1, ctx->pc & ~(target_ulong)3);
+ }
+ gen_op_addr_add(ctx, t0, t0, t1);
+ op_ldst_lw(t0, t0, ctx);
+ gen_store_gpr(t0, rt);
+ break;
case OPC_LW:
save_cpu_state(ctx, 0);
op_ldst_lw(t0, t0, ctx);
@@ -2450,11 +2465,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
break;
case OPC_J:
case OPC_JAL:
+ case OPC_JALX:
/* Jump to immediate */
btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
break;
case OPC_JR:
case OPC_JALR:
+ case OPC_JALRC:
/* Jump to register */
if (offset != 0 && offset != 16) {
/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@@ -2517,18 +2534,29 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
break;
+ case OPC_JALX:
+ ctx->hflags |= MIPS_HFLAG_BX;
+ /* Fallthrough */
case OPC_JAL:
blink = 31;
ctx->hflags |= MIPS_HFLAG_B;
+ ctx->hflags |= (ctx->isa_mode
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
break;
case OPC_JR:
ctx->hflags |= MIPS_HFLAG_BR;
+ if (ctx->isa_mode)
+ ctx->hflags |= MIPS_HFLAG_BDS16;
MIPS_DEBUG("jr %s", regnames[rs]);
break;
case OPC_JALR:
+ case OPC_JALRC:
blink = rt;
ctx->hflags |= MIPS_HFLAG_BR;
+ if (ctx->isa_mode)
+ ctx->hflags |= MIPS_HFLAG_BDS16;
MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
break;
default:
@@ -2625,7 +2653,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->btarget = btgt;
if (blink > 0) {
- tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 8);
+ int post_delay = insn_bytes;
+ int lowbit = ctx->isa_mode;
+
+ if (opc != OPC_JALRC)
+ post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
+
+ tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
}
out:
@@ -7558,10 +7592,17 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
ctx->bstate = BS_BRANCH;
save_cpu_state(ctx, 0);
/* FIXME: Need to clear can_do_io. */
- switch (hflags) {
+ switch (hflags & MIPS_HFLAG_BMASK_BASE) {
case MIPS_HFLAG_B:
/* unconditional branch */
MIPS_DEBUG("unconditional branch");
+ if (hflags & MIPS_HFLAG_BX) {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+
+ tcg_gen_movi_i32(t0, 1 - ctx->isa_mode);
+ tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, active_tc.ISAMode));
+ tcg_temp_free_i32(t0);
+ }
gen_goto_tb(ctx, 0, ctx->btarget);
break;
case MIPS_HFLAG_BL:
@@ -7584,7 +7625,20 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
case MIPS_HFLAG_BR:
/* unconditional branch to register */
MIPS_DEBUG("branch to register");
- tcg_gen_mov_tl(cpu_PC, btarget);
+ if (env->insn_flags & ASE_MIPS16) {
+ TCGv t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+
+ tcg_gen_andi_tl(t0, btarget, 0x1);
+ tcg_gen_trunc_tl_i32(t1, t0);
+ tcg_temp_free(t0);
+ tcg_gen_st_i32(t1, cpu_env, offsetof(CPUState, active_tc.ISAMode));
+ tcg_temp_free_i32(t1);
+
+ tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
+ } else {
+ tcg_gen_mov_tl(cpu_PC, btarget);
+ }
if (ctx->singlestep_enabled) {
save_cpu_state(ctx, 0);
gen_helper_0i(raise_exception, EXCP_DEBUG);
@@ -7712,6 +7766,918 @@ enum {
RR_RY_CNVT_SEW = 0x6,
};
+static int xlat (int r)
+{
+ static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+ return map[r];
+}
+
+static void gen_mips16_save (DisasContext *ctx,
+ int xsregs, int aregs,
+ int do_ra, int do_s0, int do_s1,
+ int framesize)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ int args, astatic;
+
+ switch (aregs) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 11:
+ args = 0;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ args = 1;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ args = 2;
+ break;
+ case 12:
+ case 13:
+ args = 3;
+ break;
+ case 14:
+ args = 4;
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
+ switch (args) {
+ case 4:
+ gen_base_offset_addr(ctx, t0, 29, 12);
+ gen_load_gpr(t1, 7);
+ op_ldst_sw(t1, t0, ctx);
+ /* Fall through */
+ case 3:
+ gen_base_offset_addr(ctx, t0, 29, 8);
+ gen_load_gpr(t1, 6);
+ op_ldst_sw(t1, t0, ctx);
+ /* Fall through */
+ case 2:
+ gen_base_offset_addr(ctx, t0, 29, 4);
+ gen_load_gpr(t1, 5);
+ op_ldst_sw(t1, t0, ctx);
+ /* Fall through */
+ case 1:
+ gen_base_offset_addr(ctx, t0, 29, 0);
+ gen_load_gpr(t1, 4);
+ op_ldst_sw(t1, t0, ctx);
+ }
+
+ gen_load_gpr(t0, 29);
+
+#define DECR_AND_STORE(reg) do { \
+ tcg_gen_subi_tl(t0, t0, 4); \
+ gen_load_gpr(t1, reg); \
+ op_ldst_sw(t1, t0, ctx); \
+ } while (0)
+
+ if (do_ra) {
+ DECR_AND_STORE(31);
+ }
+
+ switch (xsregs) {
+ case 7:
+ DECR_AND_STORE(30);
+ /* Fall through */
+ case 6:
+ DECR_AND_STORE(23);
+ /* Fall through */
+ case 5:
+ DECR_AND_STORE(22);
+ /* Fall through */
+ case 4:
+ DECR_AND_STORE(21);
+ /* Fall through */
+ case 3:
+ DECR_AND_STORE(20);
+ /* Fall through */
+ case 2:
+ DECR_AND_STORE(19);
+ /* Fall through */
+ case 1:
+ DECR_AND_STORE(18);
+ }
+
+ if (do_s1) {
+ DECR_AND_STORE(17);
+ }
+ if (do_s0) {
+ DECR_AND_STORE(16);
+ }
+
+ switch (aregs) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ case 14:
+ astatic = 0;
+ break;
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ astatic = 1;
+ break;
+ case 2:
+ case 6:
+ case 10:
+ astatic = 2;
+ break;
+ case 3:
+ case 7:
+ astatic = 3;
+ break;
+ case 11:
+ astatic = 4;
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
+ if (astatic > 0) {
+ DECR_AND_STORE(7);
+ if (astatic > 1) {
+ DECR_AND_STORE(6);
+ if (astatic > 2) {
+ DECR_AND_STORE(5);
+ if (astatic > 3) {
+ DECR_AND_STORE(4);
+ }
+ }
+ }
+ }
+#undef DECR_AND_STORE
+
+ tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+static void gen_mips16_restore (DisasContext *ctx,
+ int xsregs, int aregs,
+ int do_ra, int do_s0, int do_s1,
+ int framesize)
+{
+ int astatic;
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);
+
+#define DECR_AND_LOAD(reg) do { \
+ tcg_gen_subi_tl(t0, t0, 4); \
+ op_ldst_lw(t1, t0, ctx); \
+ gen_store_gpr(t1, reg); \
+ } while (0)
+
+ if (do_ra) {
+ DECR_AND_LOAD(31);
+ }
+
+ switch (xsregs) {
+ case 7:
+ DECR_AND_LOAD(30);
+ /* Fall through */
+ case 6:
+ DECR_AND_LOAD(23);
+ /* Fall through */
+ case 5:
+ DECR_AND_LOAD(22);
+ /* Fall through */
+ case 4:
+ DECR_AND_LOAD(21);
+ /* Fall through */
+ case 3:
+ DECR_AND_LOAD(20);
+ /* Fall through */
+ case 2:
+ DECR_AND_LOAD(19);
+ /* Fall through */
+ case 1:
+ DECR_AND_LOAD(18);
+ }
+
+ if (do_s1) {
+ DECR_AND_LOAD(17);
+ }
+ if (do_s0) {
+ DECR_AND_LOAD(16);
+ }
+
+ switch (aregs) {
+ case 0:
+ case 4:
+ case 8:
+ case 12:
+ case 14:
+ astatic = 0;
+ break;
+ case 1:
+ case 5:
+ case 9:
+ case 13:
+ astatic = 1;
+ break;
+ case 2:
+ case 6:
+ case 10:
+ astatic = 2;
+ break;
+ case 3:
+ case 7:
+ astatic = 3;
+ break;
+ case 11:
+ astatic = 4;
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
+ if (astatic > 0) {
+ DECR_AND_LOAD(7);
+ if (astatic > 1) {
+ DECR_AND_LOAD(6);
+ if (astatic > 2) {
+ DECR_AND_LOAD(5);
+ if (astatic > 3) {
+ DECR_AND_LOAD(4);
+ }
+ }
+ }
+ }
+#undef DECR_AND_LOAD
+
+ tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+static void gen_addiupc (DisasContext *ctx, int rx, int imm)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_movi_tl(t0, ctx->pc & ~(target_ulong)3);
+ tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
+
+ tcg_temp_free(t0);
+}
+
+static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
+ int *is_branch)
+{
+ int extend = lduw_code(ctx->pc + 2);
+ int op, rx, ry, funct, sa;
+ int16_t imm, offset;
+
+ ctx->opcode = (ctx->opcode << 16) | extend;
+ op = (ctx->opcode >> 11) & 0x1f;
+ sa = (ctx->opcode >> 22) & 0x1f;
+ funct = (ctx->opcode >> 8) & 0x7;
+ rx = xlat((ctx->opcode >> 8) & 0x7);
+ ry = xlat((ctx->opcode >> 5) & 0x7);
+ offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
+ | ((ctx->opcode >> 21) & 0x3f) << 5
+ | (ctx->opcode & 0x1f));
+
+ /* The extended opcodes cleverly reuse the opcodes from their 16-bit
+ counterparts. */
+ switch (op) {
+ case M16_OPC_ADDIUSP:
+ gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+ break;
+ case M16_OPC_ADDIUPC:
+ gen_addiupc(ctx, rx, imm);
+ break;
+ case M16_OPC_B:
+ gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_BEQZ:
+ gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_BNEQZ:
+ gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_SHIFT:
+ switch (ctx->opcode & 0x3) {
+ case 0x0:
+ gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+ break;
+ case 0x1:
+#if defined(TARGET_MIPS64)
+ gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+ generate_exception(ctx, EXCP_RI);
+#endif
+ break;
+ case 0x2:
+ gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+ break;
+ case 0x3:
+ gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+ break;
+ }
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_LD:
+ gen_ldst(ctx, OPC_LD, ry, rx, offset);
+ break;
+#endif
+ case M16_OPC_RRIA:
+ imm = ctx->opcode & 0xf;
+ imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
+ imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
+ imm = (int16_t) (imm << 1) >> 1;
+ if ((ctx->opcode >> 4) & 0x1) {
+#if defined(TARGET_MIPS64)
+ gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+ generate_exception(ctx, EXCP_RI);
+#endif
+ } else {
+ gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+ }
+ break;
+ case M16_OPC_ADDIU8:
+ gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+ break;
+ case M16_OPC_SLTI:
+ gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+ break;
+ case M16_OPC_SLTIU:
+ gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+ break;
+ case M16_OPC_I8:
+ switch (funct) {
+ case I8_BTEQZ:
+ gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
+ break;
+ case I8_BTNEZ:
+ gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
+ break;
+ case I8_SWRASP:
+ gen_ldst(ctx, OPC_SW, 31, 29, imm);
+ break;
+ case I8_ADJSP:
+ gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
+ break;
+ case I8_SVRS:
+ {
+ int xsregs = (ctx->opcode >> 24) & 0x7;
+ int aregs = (ctx->opcode >> 16) & 0xf;
+ int do_ra = (ctx->opcode >> 6) & 0x1;
+ int do_s0 = (ctx->opcode >> 5) & 0x1;
+ int do_s1 = (ctx->opcode >> 4) & 0x1;
+ int framesize = (((ctx->opcode >> 20) & 0xf) << 4
+ | (ctx->opcode & 0xf)) << 3;
+
+ if (ctx->opcode & (1 << 7)) {
+ gen_mips16_save(ctx, xsregs, aregs,
+ do_ra, do_s0, do_s1,
+ framesize);
+ } else {
+ gen_mips16_restore(ctx, xsregs, aregs,
+ do_ra, do_s0, do_s1,
+ framesize);
+ }
+ }
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case M16_OPC_LI:
+ tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
+ break;
+ case M16_OPC_CMPI:
+ tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_SD:
+ gen_ldst(ctx, OPC_SD, ry, rx, offset);
+ break;
+#endif
+ case M16_OPC_LB:
+ gen_ldst(ctx, OPC_LB, ry, rx, offset);
+ break;
+ case M16_OPC_LH:
+ gen_ldst(ctx, OPC_LH, ry, rx, offset);
+ break;
+ case M16_OPC_LWSP:
+ gen_ldst(ctx, OPC_LW, rx, 29, offset);
+ break;
+ case M16_OPC_LW:
+ gen_ldst(ctx, OPC_LW, ry, rx, offset);
+ break;
+ case M16_OPC_LBU:
+ gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+ break;
+ case M16_OPC_LHU:
+ gen_ldst(ctx, OPC_LHU, ry, rx, offset);
+ break;
+ case M16_OPC_LWPC:
+ gen_ldst(ctx, OPC_LWPC, rx, 0, offset);
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_LWU:
+ gen_ldst(ctx, OPC_LWU, ry, rx, offset);
+ break;
+#endif
+ case M16_OPC_SB:
+ gen_ldst(ctx, OPC_SB, ry, rx, offset);
+ break;
+ case M16_OPC_SH:
+ gen_ldst(ctx, OPC_SH, ry, rx, offset);
+ break;
+ case M16_OPC_SWSP:
+ gen_ldst(ctx, OPC_SW, rx, 29, offset);
+ break;
+ case M16_OPC_SW:
+ gen_ldst(ctx, OPC_SW, ry, rx, offset);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+
+ return 4;
+}
+
+static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
+ int *is_branch)
+{
+ int rx, ry;
+ int sa;
+ int op, cnvt_op, op1, offset;
+ int funct;
+ int n_bytes;
+
+ op = (ctx->opcode >> 11) & 0x1f;
+ sa = (ctx->opcode >> 2) & 0x7;
+ sa = sa == 0 ? 8 : sa;
+ rx = xlat((ctx->opcode >> 8) & 0x7);
+ cnvt_op = (ctx->opcode >> 5) & 0x7;
+ ry = xlat((ctx->opcode >> 5) & 0x7);
+ op1 = offset = ctx->opcode & 0x1f;
+
+ n_bytes = 2;
+
+ switch (op) {
+ case M16_OPC_ADDIUSP:
+ {
+ int16_t imm = ((uint8_t) ctx->opcode) << 2;
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
+ }
+ break;
+ case M16_OPC_ADDIUPC:
+ gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2);
+ break;
+ case M16_OPC_B:
+ offset = (ctx->opcode & 0x7ff) << 1;
+ offset = (int16_t)(offset << 4) >> 4;
+ gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_JAL:
+ offset = lduw_code(ctx->pc + 2);
+ offset = (((ctx->opcode & 0x1f) << 21)
+ | ((ctx->opcode >> 5) & 0x1f) << 16
+ | offset) << 2;
+ op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
+ gen_compute_branch(ctx, op, 4, rx, ry, offset);
+ n_bytes = 4;
+ *is_branch = 1;
+ break;
+ case M16_OPC_BEQZ:
+ gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_BNEQZ:
+ gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
+ /* No delay slot, so just process as a normal instruction */
+ break;
+ case M16_OPC_SHIFT:
+ switch (ctx->opcode & 0x3) {
+ case 0x0:
+ gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
+ break;
+ case 0x1:
+#if defined(TARGET_MIPS64)
+ gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
+#else
+ generate_exception(ctx, EXCP_RI);
+#endif
+ break;
+ case 0x2:
+ gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
+ break;
+ case 0x3:
+ gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
+ break;
+ }
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_LD:
+ gen_ldst(ctx, OPC_LD, ry, rx, offset << 3);
+ break;
+#endif
+ case M16_OPC_RRIA:
+ {
+ int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;
+
+ if ((ctx->opcode >> 4) & 1) {
+#if defined(TARGET_MIPS64)
+ gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
+#else
+ generate_exception(ctx, EXCP_RI);
+#endif
+ } else {
+ gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
+ }
+ }
+ break;
+ case M16_OPC_ADDIU8:
+ {
+ int16_t imm = (int8_t) ctx->opcode;
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
+ }
+ break;
+ case M16_OPC_SLTI:
+ {
+ int16_t imm = (uint8_t) ctx->opcode;
+
+ gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
+ }
+ break;
+ case M16_OPC_SLTIU:
+ {
+ int16_t imm = (uint8_t) ctx->opcode;
+
+ gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
+ }
+ break;
+ case M16_OPC_I8:
+ {
+ int reg32;
+
+ funct = (ctx->opcode >> 8) & 0x7;
+ switch (funct) {
+ case I8_BTEQZ:
+ gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
+ ((int8_t)ctx->opcode) << 1);
+ break;
+ case I8_BTNEZ:
+ gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
+ ((int8_t)ctx->opcode) << 1);
+ break;
+ case I8_SWRASP:
+ gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
+ break;
+ case I8_ADJSP:
+ gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
+ ((int8_t)ctx->opcode) << 3);
+ break;
+ case I8_SVRS:
+ {
+ int do_ra = ctx->opcode & (1 << 6);
+ int do_s0 = ctx->opcode & (1 << 5);
+ int do_s1 = ctx->opcode & (1 << 4);
+ int framesize = ctx->opcode & 0xf;
+
+ if (framesize == 0) {
+ framesize = 128;
+ } else {
+ framesize = framesize << 3;
+ }
+
+ if (ctx->opcode & (1 << 7)) {
+ gen_mips16_save(ctx, 0, 0,
+ do_ra, do_s0, do_s1, framesize);
+ } else {
+ gen_mips16_restore(ctx, 0, 0,
+ do_ra, do_s0, do_s1, framesize);
+ }
+ }
+ break;
+ case I8_MOV32R:
+ {
+ int rz = xlat(ctx->opcode & 0x7);
+
+ reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
+ ((ctx->opcode >> 5) & 0x7);
+ gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
+ }
+ break;
+ case I8_MOVR32:
+ reg32 = ctx->opcode & 0x1f;
+ gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ }
+ break;
+ case M16_OPC_LI:
+ {
+ int16_t imm = (uint8_t) ctx->opcode;
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
+ }
+ break;
+ case M16_OPC_CMPI:
+ {
+ int16_t imm = (uint8_t) ctx->opcode;
+
+ gen_logic_imm(env, OPC_XORI, 24, rx, imm);
+ }
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_SD:
+ gen_ldst(ctx, OPC_SD, ry, rx, offset << 3);
+ break;
+#endif
+ case M16_OPC_LB:
+ gen_ldst(ctx, OPC_LB, ry, rx, offset);
+ break;
+ case M16_OPC_LH:
+ gen_ldst(ctx, OPC_LH, ry, rx, offset << 1);
+ break;
+ case M16_OPC_LWSP:
+ gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+ break;
+ case M16_OPC_LW:
+ gen_ldst(ctx, OPC_LW, ry, rx, offset << 2);
+ break;
+ case M16_OPC_LBU:
+ gen_ldst(ctx, OPC_LBU, ry, rx, offset);
+ break;
+ case M16_OPC_LHU:
+ gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1);
+ break;
+ case M16_OPC_LWPC:
+ gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
+ break;
+#if defined (TARGET_MIPS64)
+ case M16_OPC_LWU:
+ gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2);
+ break;
+#endif
+ case M16_OPC_SB:
+ gen_ldst(ctx, OPC_SB, ry, rx, offset);
+ break;
+ case M16_OPC_SH:
+ gen_ldst(ctx, OPC_SH, ry, rx, offset << 1);
+ break;
+ case M16_OPC_SWSP:
+ gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
+ break;
+ case M16_OPC_SW:
+ gen_ldst(ctx, OPC_SW, ry, rx, offset << 2);
+ break;
+ case M16_OPC_RRR:
+ {
+ int rz = xlat((ctx->opcode >> 2) & 0x7);
+ int mips32_op;
+
+ switch (ctx->opcode & 0x3) {
+ case RRR_ADDU:
+ mips32_op = OPC_ADDU;
+ break;
+ case RRR_SUBU:
+ mips32_op = OPC_SUBU;
+ break;
+#if defined(TARGET_MIPS64)
+ case RRR_DADDU:
+ mips32_op = OPC_DADDU;
+ break;
+ case RRR_DSUBU:
+ mips32_op = OPC_DSUBU;
+ break;
+#endif
+ default:
+ generate_exception(ctx, EXCP_RI);
+ goto done;
+ }
+
+ gen_arith(env, ctx, mips32_op, rz, rx, ry);
+ done:
+ ;
+ }
+ break;
+ case M16_OPC_RR:
+ switch (op1) {
+ case RR_JR:
+ {
+ int nd = (ctx->opcode >> 7) & 0x1;
+ int link = (ctx->opcode >> 6) & 0x1;
+ int ra = (ctx->opcode >> 5) & 0x1;
+
+ if (link) {
+ op = nd ? OPC_JALRC : OPC_JALR;
+ } else {
+ op = OPC_JR;
+ }
+
+ gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
+ if (!nd) {
+ *is_branch = 1;
+ }
+ }
+ break;
+ case RR_SDBBP:
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(env, ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
+ break;
+ case RR_SLT:
+ gen_slt(env, OPC_SLT, 24, rx, ry);
+ break;
+ case RR_SLTU:
+ gen_slt(env, OPC_SLTU, 24, rx, ry);
+ break;
+ case RR_BREAK:
+ generate_exception(ctx, EXCP_BREAK);
+ break;
+ case RR_SLLV:
+ gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
+ break;
+ case RR_SRLV:
+ gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
+ break;
+ case RR_SRAV:
+ gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
+ break;
+#if defined (TARGET_MIPS64)
+ case RR_DSRL:
+ gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
+ break;
+#endif
+ case RR_CMP:
+ gen_logic(env, OPC_XOR, 24, rx, ry);
+ break;
+ case RR_NEG:
+ gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
+ break;
+ case RR_AND:
+ gen_logic(env, OPC_AND, rx, rx, ry);
+ break;
+ case RR_OR:
+ gen_logic(env, OPC_OR, rx, rx, ry);
+ break;
+ case RR_XOR:
+ gen_logic(env, OPC_XOR, rx, rx, ry);
+ break;
+ case RR_NOT:
+ gen_logic(env, OPC_NOR, rx, ry, 0);
+ break;
+ case RR_MFHI:
+ gen_HILO(ctx, OPC_MFHI, rx);
+ break;
+ case RR_CNVT:
+ switch (cnvt_op) {
+ case RR_RY_CNVT_ZEB:
+ tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+ case RR_RY_CNVT_ZEH:
+ tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+ case RR_RY_CNVT_SEB:
+ tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+ case RR_RY_CNVT_SEH:
+ tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+#if defined (TARGET_MIPS64)
+ case RR_RY_CNVT_ZEW:
+ tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+ case RR_RY_CNVT_SEW:
+ tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ break;
+#endif
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case RR_MFLO:
+ gen_HILO(ctx, OPC_MFLO, rx);
+ break;
+#if defined (TARGET_MIPS64)
+ case RR_DSRA:
+ gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
+ break;
+ case RR_DSLLV:
+ gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
+ case RR_DSRLV:
+ gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
+ break;
+ case RR_DSRAV:
+ gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
+ break;
+#endif
+ case RR_MULT:
+ gen_muldiv(ctx, OPC_MULT, rx, ry);
+ break;
+ case RR_MULTU:
+ gen_muldiv(ctx, OPC_MULTU, rx, ry);
+ break;
+ case RR_DIV:
+ gen_muldiv(ctx, OPC_DIV, rx, ry);
+ break;
+ case RR_DIVU:
+ gen_muldiv(ctx, OPC_DIVU, rx, ry);
+ break;
+#if defined (TARGET_MIPS64)
+ case RR_DMULT:
+ gen_muldiv(ctx, OPC_DMULT, rx, ry);
+ break;
+ case RR_DMULTU:
+ gen_muldiv(ctx, OPC_DMULTU, rx, ry);
+ break;
+ case RR_DDIV:
+ gen_muldiv(ctx, OPC_DDIV, rx, ry);
+ break;
+ case RR_DDIVU:
+ gen_muldiv(ctx, OPC_DDIVU, rx, ry);
+ break;
+#endif
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case M16_OPC_EXTEND:
+ decode_extended_mips16_opc(env, ctx, is_branch);
+ n_bytes = 4;
+ break;
+#if defined(TARGET_MIPS64)
+ case M16_OPC_I64:
+ funct = (ctx->opcode >> 8) & 0x7;
+ switch (funct) {
+ case I64_LDSP:
+ gen_ldst(ctx, OPC_LD, ry, 29, offset << 3);
+ break;
+ case I64_SDSP:
+ gen_ldst(ctx, OPC_SD, ry, 29, offset << 3);
+ break;
+ case I64_SDRASP:
+ gen_ldst(ctx, OPC_SD, 31, 29, (ctx->opcode & 0xff) << 3);
+ break;
+ case I64_DADJSP:
+ gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29,
+ ((int8_t)ctx->opcode) << 3);
+ break;
+ case I64_LDPC:
+ break;
+ case I64_DADDIU:
+ gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry,
+ ((int8_t)(offset << 3)) >> 3);
+ break;
+ case I64_DADDIUPC:
+ break;
+ case I64_DADDIUSP:
+ gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29,
+ ((int8_t)(offset << 3)) >> 1);
+ break;
+ }
+#endif
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+
+ return n_bytes;
+}
+
/* SmartMIPS extension to MIPS32 */
#if defined(TARGET_MIPS64)
@@ -8400,7 +9366,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
#endif
case OPC_JALX:
check_insn(env, ctx, ASE_MIPS16);
- /* MIPS16: Not implemented. */
+ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+ gen_compute_branch(ctx, op, 4, rs, rt, offset);
+ *is_branch = 1;
+ break;
case OPC_MDMX:
check_insn(env, ctx, ASE_MDMX);
/* MDMX: Not implemented. */
@@ -8490,6 +9459,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
ctx.opcode = ldl_code(ctx.pc);
insn_bytes = 4;
decode_opc(env, &ctx, &is_branch);
+ } else if (env->insn_flags & ASE_MIPS16) {
+ ctx.opcode = lduw_code(ctx.pc);
+ insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
} else {
generate_exception(&ctx, EXCP_RI);
break;
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (8 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
The only thing to do here is to expose ISAMode to GDB and to set ISAMode
properly when we change the PC.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
gdbstub.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/gdbstub.c b/gdbstub.c
index 055093f..58a701b 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1053,7 +1053,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
case 34: GET_REGL(env->active_tc.HI[0]);
case 35: GET_REGL(env->CP0_BadVAddr);
case 36: GET_REGL((int32_t)env->CP0_Cause);
- case 37: GET_REGL(env->active_tc.PC);
+ case 37: GET_REGL(env->active_tc.PC | env->active_tc.ISAMode);
case 72: GET_REGL(0); /* fp */
case 89: GET_REGL((int32_t)env->CP0_PRid);
}
@@ -1114,7 +1114,10 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
case 34: env->active_tc.HI[0] = tmp; break;
case 35: env->CP0_BadVAddr = tmp; break;
case 36: env->CP0_Cause = tmp; break;
- case 37: env->active_tc.PC = tmp; break;
+ case 37:
+ env->active_tc.PC = tmp & ~(target_ulong)1;
+ env->active_tc.ISAMode = tmp & 1;
+ break;
case 72: /* fp, ignored */ break;
default:
if (n > 89)
@@ -1609,7 +1612,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
#elif defined (TARGET_SH4)
s->c_cpu->pc = pc;
#elif defined (TARGET_MIPS)
- s->c_cpu->active_tc.PC = pc;
+ s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;
+ s->c_cpu->active_tc.ISAMode = pc & 1;
#elif defined (TARGET_MICROBLAZE)
s->c_cpu->sregs[SR_PC] = pc;
#elif defined (TARGET_CRIS)
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (9 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
@ 2009-11-23 20:50 ` Nathan Froyd
2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno
11 siblings, 0 replies; 18+ messages in thread
From: Nathan Froyd @ 2009-11-23 20:50 UTC (permalink / raw)
To: qemu-devel
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-mips/translate.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 49d2264..ef5e726 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4,6 +4,7 @@
* Copyright (c) 2004-2005 Jocelyn Mayer
* Copyright (c) 2006 Marius Groeger (FPU operations)
* Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ * Copyright (c) 2009 CodeSourcery (MIPS16 support)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
--
1.6.3.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware
2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
On Mon, Nov 23, 2009 at 12:50:01PM -0800, Nathan Froyd wrote:
>
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
> target-mips/helper.c | 47 ++++++++++++++++++++++++++---------------------
> target-mips/op_helper.c | 10 +++++++---
> 2 files changed, 33 insertions(+), 24 deletions(-)
>
> diff --git a/target-mips/helper.c b/target-mips/helper.c
> index 4a37277..e54a31a 100644
> --- a/target-mips/helper.c
> +++ b/target-mips/helper.c
> @@ -339,6 +339,20 @@ static const char * const excp_names[EXCP_LAST + 1] = {
> [EXCP_CACHE] = "cache error",
> };
>
> +static target_ulong exception_resume_pc (CPUState *env)
> +{
> + target_ulong bad_pc;
> +
> + bad_pc = env->active_tc.PC | env->active_tc.ISAMode;
> + if (env->hflags & MIPS_HFLAG_BMASK) {
> + /* If the exception was raised from a delay slot, come back to
> + the jump. */
> + bad_pc -= (env->hflags & MIPS_HFLAG_BDS16 ? 2 : 4);
> + }
> +
> + return bad_pc;
> +}
This function is only used on softmmu target. This breaks compilation of
linux-user targets, it should be protected with:
#if !defined(CONFIG_USER_ONLY)
#endif
> void do_interrupt (CPUState *env)
> {
> #if !defined(CONFIG_USER_ONLY)
> @@ -366,7 +380,7 @@ void do_interrupt (CPUState *env)
> resume will always occur on the next instruction
> (but we assume the pc has always been updated during
> code translation). */
> - env->CP0_DEPC = env->active_tc.PC;
> + env->CP0_DEPC = env->active_tc.PC | env->active_tc.ISAMode;
> goto enter_debug_mode;
> case EXCP_DINT:
> env->CP0_Debug |= 1 << CP0DB_DINT;
> @@ -383,14 +397,8 @@ void do_interrupt (CPUState *env)
> case EXCP_DDBL:
> env->CP0_Debug |= 1 << CP0DB_DDBL;
> set_DEPC:
> - if (env->hflags & MIPS_HFLAG_BMASK) {
> - /* If the exception was raised from a delay slot,
> - come back to the jump. */
> - env->CP0_DEPC = env->active_tc.PC - 4;
> - env->hflags &= ~MIPS_HFLAG_BMASK;
> - } else {
> - env->CP0_DEPC = env->active_tc.PC;
> - }
> + env->CP0_DEPC = exception_resume_pc(env);
> + env->hflags &= ~MIPS_HFLAG_BMASK;
> enter_debug_mode:
> env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
> env->hflags &= ~(MIPS_HFLAG_KSU);
> @@ -398,6 +406,8 @@ void do_interrupt (CPUState *env)
> if (!(env->CP0_Status & (1 << CP0St_EXL)))
> env->CP0_Cause &= ~(1 << CP0Ca_BD);
> env->active_tc.PC = (int32_t)0xBFC00480;
> + /* Exception handlers are entered in 32-bit mode. */
> + env->active_tc.ISAMode = 0;
> break;
> case EXCP_RESET:
> cpu_reset(env);
> @@ -409,20 +419,16 @@ void do_interrupt (CPUState *env)
> case EXCP_NMI:
> env->CP0_Status |= (1 << CP0St_NMI);
> set_error_EPC:
> - if (env->hflags & MIPS_HFLAG_BMASK) {
> - /* If the exception was raised from a delay slot,
> - come back to the jump. */
> - env->CP0_ErrorEPC = env->active_tc.PC - 4;
> - env->hflags &= ~MIPS_HFLAG_BMASK;
> - } else {
> - env->CP0_ErrorEPC = env->active_tc.PC;
> - }
> + env->CP0_ErrorEPC = exception_resume_pc(env);
> + env->hflags &= ~MIPS_HFLAG_BMASK;
> env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
> env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
> env->hflags &= ~(MIPS_HFLAG_KSU);
> if (!(env->CP0_Status & (1 << CP0St_EXL)))
> env->CP0_Cause &= ~(1 << CP0Ca_BD);
> env->active_tc.PC = (int32_t)0xBFC00000;
> + /* Exception handlers are entered in 32-bit mode. */
> + env->active_tc.ISAMode = 0;
> break;
> case EXCP_EXT_INTERRUPT:
> cause = 0;
> @@ -524,13 +530,10 @@ void do_interrupt (CPUState *env)
> }
> set_EPC:
> if (!(env->CP0_Status & (1 << CP0St_EXL))) {
> + env->CP0_EPC = exception_resume_pc(env);
> if (env->hflags & MIPS_HFLAG_BMASK) {
> - /* If the exception was raised from a delay slot,
> - come back to the jump. */
> - env->CP0_EPC = env->active_tc.PC - 4;
> env->CP0_Cause |= (1 << CP0Ca_BD);
> } else {
> - env->CP0_EPC = env->active_tc.PC;
> env->CP0_Cause &= ~(1 << CP0Ca_BD);
> }
> env->CP0_Status |= (1 << CP0St_EXL);
> @@ -544,6 +547,8 @@ void do_interrupt (CPUState *env)
> env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
> }
> env->active_tc.PC += offset;
> + /* Exception handlers are entered in 32-bit mode. */
> + env->active_tc.ISAMode = 0;
> env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
> break;
> default:
> diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
> index 52d687d..d585d65 100644
> --- a/target-mips/op_helper.c
> +++ b/target-mips/op_helper.c
> @@ -1701,10 +1701,12 @@ void helper_eret (void)
> {
> debug_pre_eret();
> if (env->CP0_Status & (1 << CP0St_ERL)) {
> - env->active_tc.PC = env->CP0_ErrorEPC;
> + env->active_tc.PC = env->CP0_ErrorEPC & ~(target_ulong)1;
> + env->active_tc.ISAMode = env->CP0_ErrorEPC & 1;
> env->CP0_Status &= ~(1 << CP0St_ERL);
> } else {
> - env->active_tc.PC = env->CP0_EPC;
> + env->active_tc.PC = env->CP0_EPC & ~(target_ulong)1;
> + env->active_tc.ISAMode = env->CP0_EPC & 1;
> env->CP0_Status &= ~(1 << CP0St_EXL);
> }
> compute_hflags(env);
> @@ -1715,7 +1717,9 @@ void helper_eret (void)
> void helper_deret (void)
> {
> debug_pre_eret();
> - env->active_tc.PC = env->CP0_DEPC;
> + env->active_tc.PC = env->CP0_DEPC & ~(target_ulong)1;
> + env->active_tc.ISAMode = env->CP0_DEPC & 1;
> +
> env->hflags &= MIPS_HFLAG_DM;
> compute_hflags(env);
> debug_post_eret();
> --
> 1.6.3.2
>
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding
2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
On Mon, Nov 23, 2009 at 12:50:07PM -0800, Nathan Froyd wrote:
> There's no good way to add this incrementally, so we do it all at once.
> The only changes to shared code are in handle_delay_slot. We need to
> flip ISAMode when doing a jump-and-exchange. We also need to set
> ISAMode the low bit of the target address for jump-to-register.
This patch breaks the boot of both MIPS kernel. On little endian, the
kernel crashes with the following message:
CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 00000000, ra == 80120004
On big endian, it fails before printing a single message on the console.
See also my other comments inline.
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
> target-mips/translate.c | 980 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 976 insertions(+), 4 deletions(-)
>
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 611774b..49d2264 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -83,6 +83,7 @@ enum {
> OPC_LH = (0x21 << 26),
> OPC_LWL = (0x22 << 26),
> OPC_LW = (0x23 << 26),
> + OPC_LWPC = OPC_LW | 0x5,
> OPC_LBU = (0x24 << 26),
> OPC_LHU = (0x25 << 26),
> OPC_LWR = (0x26 << 26),
> @@ -173,6 +174,7 @@ enum {
> /* Jumps */
> OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
> OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
> + OPC_JALRC = OPC_JALR | (0x5 << 6),
> /* Traps */
> OPC_TGE = 0x30 | OPC_SPECIAL,
> OPC_TGEU = 0x31 | OPC_SPECIAL,
> @@ -1074,6 +1076,19 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
> opn = "sdr";
> break;
> #endif
> + case OPC_LWPC:
> + save_cpu_state(ctx, 1);
> + if (ctx->hflags & MIPS_HFLAG_BMASK) {
> + int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;
> +
> + tcg_gen_movi_tl(t1, (ctx->pc - branch_bytes) & ~(target_ulong)3);
> + } else {
> + tcg_gen_movi_tl(t1, ctx->pc & ~(target_ulong)3);
> + }
> + gen_op_addr_add(ctx, t0, t0, t1);
> + op_ldst_lw(t0, t0, ctx);
> + gen_store_gpr(t0, rt);
> + break;
> case OPC_LW:
> save_cpu_state(ctx, 0);
> op_ldst_lw(t0, t0, ctx);
> @@ -2450,11 +2465,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
> break;
> case OPC_J:
> case OPC_JAL:
> + case OPC_JALX:
> /* Jump to immediate */
> btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
> break;
> case OPC_JR:
> case OPC_JALR:
> + case OPC_JALRC:
> /* Jump to register */
> if (offset != 0 && offset != 16) {
> /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
> @@ -2517,18 +2534,29 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
> ctx->hflags |= MIPS_HFLAG_B;
> MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
> break;
> + case OPC_JALX:
> + ctx->hflags |= MIPS_HFLAG_BX;
> + /* Fallthrough */
> case OPC_JAL:
> blink = 31;
> ctx->hflags |= MIPS_HFLAG_B;
> + ctx->hflags |= (ctx->isa_mode
> + ? MIPS_HFLAG_BDS16
> + : MIPS_HFLAG_BDS32);
> MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
> break;
> case OPC_JR:
> ctx->hflags |= MIPS_HFLAG_BR;
> + if (ctx->isa_mode)
> + ctx->hflags |= MIPS_HFLAG_BDS16;
> MIPS_DEBUG("jr %s", regnames[rs]);
> break;
> case OPC_JALR:
> + case OPC_JALRC:
> blink = rt;
> ctx->hflags |= MIPS_HFLAG_BR;
> + if (ctx->isa_mode)
> + ctx->hflags |= MIPS_HFLAG_BDS16;
> MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
> break;
> default:
> @@ -2625,7 +2653,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
>
> ctx->btarget = btgt;
> if (blink > 0) {
> - tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 8);
> + int post_delay = insn_bytes;
> + int lowbit = ctx->isa_mode;
> +
> + if (opc != OPC_JALRC)
> + post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
> +
> + tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
> }
>
> out:
> @@ -7558,10 +7592,17 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
> ctx->bstate = BS_BRANCH;
> save_cpu_state(ctx, 0);
> /* FIXME: Need to clear can_do_io. */
> - switch (hflags) {
> + switch (hflags & MIPS_HFLAG_BMASK_BASE) {
> case MIPS_HFLAG_B:
> /* unconditional branch */
> MIPS_DEBUG("unconditional branch");
> + if (hflags & MIPS_HFLAG_BX) {
> + TCGv_i32 t0 = tcg_temp_new_i32();
> +
> + tcg_gen_movi_i32(t0, 1 - ctx->isa_mode);
> + tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, active_tc.ISAMode));
> + tcg_temp_free_i32(t0);
> + }
> gen_goto_tb(ctx, 0, ctx->btarget);
> break;
> case MIPS_HFLAG_BL:
> @@ -7584,7 +7625,20 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
> case MIPS_HFLAG_BR:
> /* unconditional branch to register */
> MIPS_DEBUG("branch to register");
> - tcg_gen_mov_tl(cpu_PC, btarget);
> + if (env->insn_flags & ASE_MIPS16) {
> + TCGv t0 = tcg_temp_new();
> + TCGv_i32 t1 = tcg_temp_new_i32();
> +
> + tcg_gen_andi_tl(t0, btarget, 0x1);
> + tcg_gen_trunc_tl_i32(t1, t0);
> + tcg_temp_free(t0);
> + tcg_gen_st_i32(t1, cpu_env, offsetof(CPUState, active_tc.ISAMode));
> + tcg_temp_free_i32(t1);
> +
> + tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
> + } else {
> + tcg_gen_mov_tl(cpu_PC, btarget);
> + }
> if (ctx->singlestep_enabled) {
> save_cpu_state(ctx, 0);
> gen_helper_0i(raise_exception, EXCP_DEBUG);
> @@ -7712,6 +7766,918 @@ enum {
> RR_RY_CNVT_SEW = 0x6,
> };
>
> +static int xlat (int r)
> +{
> + static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
> +
> + return map[r];
> +}
> +
> +static void gen_mips16_save (DisasContext *ctx,
> + int xsregs, int aregs,
> + int do_ra, int do_s0, int do_s1,
> + int framesize)
> +{
> + TCGv t0 = tcg_temp_new();
> + TCGv t1 = tcg_temp_new();
> + int args, astatic;
> +
> + switch (aregs) {
> + case 0:
> + case 1:
> + case 2:
> + case 3:
> + case 11:
> + args = 0;
> + break;
> + case 4:
> + case 5:
> + case 6:
> + case 7:
> + args = 1;
> + break;
> + case 8:
> + case 9:
> + case 10:
> + args = 2;
> + break;
> + case 12:
> + case 13:
> + args = 3;
> + break;
> + case 14:
> + args = 4;
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + return;
> + }
> +
> + switch (args) {
> + case 4:
> + gen_base_offset_addr(ctx, t0, 29, 12);
> + gen_load_gpr(t1, 7);
> + op_ldst_sw(t1, t0, ctx);
> + /* Fall through */
> + case 3:
> + gen_base_offset_addr(ctx, t0, 29, 8);
> + gen_load_gpr(t1, 6);
> + op_ldst_sw(t1, t0, ctx);
> + /* Fall through */
> + case 2:
> + gen_base_offset_addr(ctx, t0, 29, 4);
> + gen_load_gpr(t1, 5);
> + op_ldst_sw(t1, t0, ctx);
> + /* Fall through */
> + case 1:
> + gen_base_offset_addr(ctx, t0, 29, 0);
> + gen_load_gpr(t1, 4);
> + op_ldst_sw(t1, t0, ctx);
> + }
> +
> + gen_load_gpr(t0, 29);
> +
> +#define DECR_AND_STORE(reg) do { \
> + tcg_gen_subi_tl(t0, t0, 4); \
> + gen_load_gpr(t1, reg); \
> + op_ldst_sw(t1, t0, ctx); \
> + } while (0)
> +
> + if (do_ra) {
> + DECR_AND_STORE(31);
> + }
> +
> + switch (xsregs) {
> + case 7:
> + DECR_AND_STORE(30);
> + /* Fall through */
> + case 6:
> + DECR_AND_STORE(23);
> + /* Fall through */
> + case 5:
> + DECR_AND_STORE(22);
> + /* Fall through */
> + case 4:
> + DECR_AND_STORE(21);
> + /* Fall through */
> + case 3:
> + DECR_AND_STORE(20);
> + /* Fall through */
> + case 2:
> + DECR_AND_STORE(19);
> + /* Fall through */
> + case 1:
> + DECR_AND_STORE(18);
> + }
> +
> + if (do_s1) {
> + DECR_AND_STORE(17);
> + }
> + if (do_s0) {
> + DECR_AND_STORE(16);
> + }
> +
> + switch (aregs) {
> + case 0:
> + case 4:
> + case 8:
> + case 12:
> + case 14:
> + astatic = 0;
> + break;
> + case 1:
> + case 5:
> + case 9:
> + case 13:
> + astatic = 1;
> + break;
> + case 2:
> + case 6:
> + case 10:
> + astatic = 2;
> + break;
> + case 3:
> + case 7:
> + astatic = 3;
> + break;
> + case 11:
> + astatic = 4;
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + return;
> + }
> +
> + if (astatic > 0) {
> + DECR_AND_STORE(7);
> + if (astatic > 1) {
> + DECR_AND_STORE(6);
> + if (astatic > 2) {
> + DECR_AND_STORE(5);
> + if (astatic > 3) {
> + DECR_AND_STORE(4);
> + }
> + }
> + }
> + }
> +#undef DECR_AND_STORE
> +
> + tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
> + tcg_temp_free(t0);
> + tcg_temp_free(t1);
> +}
> +
> +static void gen_mips16_restore (DisasContext *ctx,
> + int xsregs, int aregs,
> + int do_ra, int do_s0, int do_s1,
> + int framesize)
> +{
> + int astatic;
> + TCGv t0 = tcg_temp_new();
> + TCGv t1 = tcg_temp_new();
> +
> + tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);
> +
> +#define DECR_AND_LOAD(reg) do { \
> + tcg_gen_subi_tl(t0, t0, 4); \
> + op_ldst_lw(t1, t0, ctx); \
> + gen_store_gpr(t1, reg); \
> + } while (0)
> +
> + if (do_ra) {
> + DECR_AND_LOAD(31);
> + }
> +
> + switch (xsregs) {
> + case 7:
> + DECR_AND_LOAD(30);
> + /* Fall through */
> + case 6:
> + DECR_AND_LOAD(23);
> + /* Fall through */
> + case 5:
> + DECR_AND_LOAD(22);
> + /* Fall through */
> + case 4:
> + DECR_AND_LOAD(21);
> + /* Fall through */
> + case 3:
> + DECR_AND_LOAD(20);
> + /* Fall through */
> + case 2:
> + DECR_AND_LOAD(19);
> + /* Fall through */
> + case 1:
> + DECR_AND_LOAD(18);
> + }
> +
> + if (do_s1) {
> + DECR_AND_LOAD(17);
> + }
> + if (do_s0) {
> + DECR_AND_LOAD(16);
> + }
> +
> + switch (aregs) {
> + case 0:
> + case 4:
> + case 8:
> + case 12:
> + case 14:
> + astatic = 0;
> + break;
> + case 1:
> + case 5:
> + case 9:
> + case 13:
> + astatic = 1;
> + break;
> + case 2:
> + case 6:
> + case 10:
> + astatic = 2;
> + break;
> + case 3:
> + case 7:
> + astatic = 3;
> + break;
> + case 11:
> + astatic = 4;
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + return;
> + }
> +
> + if (astatic > 0) {
> + DECR_AND_LOAD(7);
> + if (astatic > 1) {
> + DECR_AND_LOAD(6);
> + if (astatic > 2) {
> + DECR_AND_LOAD(5);
> + if (astatic > 3) {
> + DECR_AND_LOAD(4);
> + }
> + }
> + }
> + }
> +#undef DECR_AND_LOAD
> +
> + tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
> + tcg_temp_free(t0);
> + tcg_temp_free(t1);
> +}
> +
> +static void gen_addiupc (DisasContext *ctx, int rx, int imm)
> +{
> + TCGv t0 = tcg_temp_new();
> +
> + tcg_gen_movi_tl(t0, ctx->pc & ~(target_ulong)3);
> + tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
> +
> + tcg_temp_free(t0);
> +}
> +
> +static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx,
> + int *is_branch)
> +{
> + int extend = lduw_code(ctx->pc + 2);
> + int op, rx, ry, funct, sa;
> + int16_t imm, offset;
> +
> + ctx->opcode = (ctx->opcode << 16) | extend;
> + op = (ctx->opcode >> 11) & 0x1f;
> + sa = (ctx->opcode >> 22) & 0x1f;
> + funct = (ctx->opcode >> 8) & 0x7;
> + rx = xlat((ctx->opcode >> 8) & 0x7);
> + ry = xlat((ctx->opcode >> 5) & 0x7);
> + offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
> + | ((ctx->opcode >> 21) & 0x3f) << 5
> + | (ctx->opcode & 0x1f));
> +
> + /* The extended opcodes cleverly reuse the opcodes from their 16-bit
> + counterparts. */
> + switch (op) {
> + case M16_OPC_ADDIUSP:
> + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
> + break;
> + case M16_OPC_ADDIUPC:
> + gen_addiupc(ctx, rx, imm);
> + break;
> + case M16_OPC_B:
> + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_BEQZ:
> + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_BNEQZ:
> + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_SHIFT:
> + switch (ctx->opcode & 0x3) {
> + case 0x0:
> + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
> + break;
> + case 0x1:
> +#if defined(TARGET_MIPS64)
> + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
Shouldn't this generate an exception on 64-bit CPU, but with 64-bit
instructions not enabled? The MIPS16e manual is not really clear about
that.
Same for other instructions below.
> +#else
> + generate_exception(ctx, EXCP_RI);
> +#endif
> + break;
> + case 0x2:
> + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
> + break;
> + case 0x3:
> + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
> + break;
> + }
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_LD:
> + gen_ldst(ctx, OPC_LD, ry, rx, offset);
> + break;
> +#endif
> + case M16_OPC_RRIA:
> + imm = ctx->opcode & 0xf;
> + imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
> + imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
> + imm = (int16_t) (imm << 1) >> 1;
> + if ((ctx->opcode >> 4) & 0x1) {
> +#if defined(TARGET_MIPS64)
> + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
> +#else
> + generate_exception(ctx, EXCP_RI);
> +#endif
> + } else {
> + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
> + }
> + break;
> + case M16_OPC_ADDIU8:
> + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
> + break;
> + case M16_OPC_SLTI:
> + gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
> + break;
> + case M16_OPC_SLTIU:
> + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
> + break;
> + case M16_OPC_I8:
> + switch (funct) {
> + case I8_BTEQZ:
> + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
> + break;
> + case I8_BTNEZ:
> + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
> + break;
> + case I8_SWRASP:
> + gen_ldst(ctx, OPC_SW, 31, 29, imm);
> + break;
> + case I8_ADJSP:
> + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
> + break;
> + case I8_SVRS:
> + {
> + int xsregs = (ctx->opcode >> 24) & 0x7;
> + int aregs = (ctx->opcode >> 16) & 0xf;
> + int do_ra = (ctx->opcode >> 6) & 0x1;
> + int do_s0 = (ctx->opcode >> 5) & 0x1;
> + int do_s1 = (ctx->opcode >> 4) & 0x1;
> + int framesize = (((ctx->opcode >> 20) & 0xf) << 4
> + | (ctx->opcode & 0xf)) << 3;
> +
> + if (ctx->opcode & (1 << 7)) {
> + gen_mips16_save(ctx, xsregs, aregs,
> + do_ra, do_s0, do_s1,
> + framesize);
> + } else {
> + gen_mips16_restore(ctx, xsregs, aregs,
> + do_ra, do_s0, do_s1,
> + framesize);
> + }
> + }
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + break;
> + case M16_OPC_LI:
> + tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
> + break;
> + case M16_OPC_CMPI:
> + tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_SD:
> + gen_ldst(ctx, OPC_SD, ry, rx, offset);
> + break;
> +#endif
> + case M16_OPC_LB:
> + gen_ldst(ctx, OPC_LB, ry, rx, offset);
> + break;
> + case M16_OPC_LH:
> + gen_ldst(ctx, OPC_LH, ry, rx, offset);
> + break;
> + case M16_OPC_LWSP:
> + gen_ldst(ctx, OPC_LW, rx, 29, offset);
> + break;
> + case M16_OPC_LW:
> + gen_ldst(ctx, OPC_LW, ry, rx, offset);
> + break;
> + case M16_OPC_LBU:
> + gen_ldst(ctx, OPC_LBU, ry, rx, offset);
> + break;
> + case M16_OPC_LHU:
> + gen_ldst(ctx, OPC_LHU, ry, rx, offset);
> + break;
> + case M16_OPC_LWPC:
> + gen_ldst(ctx, OPC_LWPC, rx, 0, offset);
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_LWU:
> + gen_ldst(ctx, OPC_LWU, ry, rx, offset);
> + break;
> +#endif
> + case M16_OPC_SB:
> + gen_ldst(ctx, OPC_SB, ry, rx, offset);
> + break;
> + case M16_OPC_SH:
> + gen_ldst(ctx, OPC_SH, ry, rx, offset);
> + break;
> + case M16_OPC_SWSP:
> + gen_ldst(ctx, OPC_SW, rx, 29, offset);
> + break;
> + case M16_OPC_SW:
> + gen_ldst(ctx, OPC_SW, ry, rx, offset);
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> +
> + return 4;
> +}
> +
> +static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
> + int *is_branch)
> +{
> + int rx, ry;
> + int sa;
> + int op, cnvt_op, op1, offset;
> + int funct;
> + int n_bytes;
> +
> + op = (ctx->opcode >> 11) & 0x1f;
> + sa = (ctx->opcode >> 2) & 0x7;
> + sa = sa == 0 ? 8 : sa;
> + rx = xlat((ctx->opcode >> 8) & 0x7);
> + cnvt_op = (ctx->opcode >> 5) & 0x7;
> + ry = xlat((ctx->opcode >> 5) & 0x7);
> + op1 = offset = ctx->opcode & 0x1f;
> +
> + n_bytes = 2;
> +
> + switch (op) {
> + case M16_OPC_ADDIUSP:
> + {
> + int16_t imm = ((uint8_t) ctx->opcode) << 2;
> +
> + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
> + }
> + break;
> + case M16_OPC_ADDIUPC:
> + gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2);
> + break;
> + case M16_OPC_B:
> + offset = (ctx->opcode & 0x7ff) << 1;
> + offset = (int16_t)(offset << 4) >> 4;
> + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_JAL:
> + offset = lduw_code(ctx->pc + 2);
> + offset = (((ctx->opcode & 0x1f) << 21)
> + | ((ctx->opcode >> 5) & 0x1f) << 16
> + | offset) << 2;
> + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
> + gen_compute_branch(ctx, op, 4, rx, ry, offset);
> + n_bytes = 4;
> + *is_branch = 1;
> + break;
> + case M16_OPC_BEQZ:
> + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_BNEQZ:
> + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
> + /* No delay slot, so just process as a normal instruction */
> + break;
> + case M16_OPC_SHIFT:
> + switch (ctx->opcode & 0x3) {
> + case 0x0:
> + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
> + break;
> + case 0x1:
> +#if defined(TARGET_MIPS64)
> + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
> +#else
> + generate_exception(ctx, EXCP_RI);
> +#endif
> + break;
> + case 0x2:
> + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
> + break;
> + case 0x3:
> + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
> + break;
> + }
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_LD:
> + gen_ldst(ctx, OPC_LD, ry, rx, offset << 3);
> + break;
> +#endif
> + case M16_OPC_RRIA:
> + {
> + int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;
> +
> + if ((ctx->opcode >> 4) & 1) {
> +#if defined(TARGET_MIPS64)
> + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
> +#else
> + generate_exception(ctx, EXCP_RI);
> +#endif
> + } else {
> + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
> + }
> + }
> + break;
> + case M16_OPC_ADDIU8:
> + {
> + int16_t imm = (int8_t) ctx->opcode;
> +
> + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
> + }
> + break;
> + case M16_OPC_SLTI:
> + {
> + int16_t imm = (uint8_t) ctx->opcode;
> +
> + gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
> + }
> + break;
> + case M16_OPC_SLTIU:
> + {
> + int16_t imm = (uint8_t) ctx->opcode;
> +
> + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
> + }
> + break;
> + case M16_OPC_I8:
> + {
> + int reg32;
> +
> + funct = (ctx->opcode >> 8) & 0x7;
> + switch (funct) {
> + case I8_BTEQZ:
> + gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
> + ((int8_t)ctx->opcode) << 1);
> + break;
> + case I8_BTNEZ:
> + gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
> + ((int8_t)ctx->opcode) << 1);
> + break;
> + case I8_SWRASP:
> + gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
> + break;
> + case I8_ADJSP:
> + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
> + ((int8_t)ctx->opcode) << 3);
> + break;
> + case I8_SVRS:
> + {
> + int do_ra = ctx->opcode & (1 << 6);
> + int do_s0 = ctx->opcode & (1 << 5);
> + int do_s1 = ctx->opcode & (1 << 4);
> + int framesize = ctx->opcode & 0xf;
> +
> + if (framesize == 0) {
> + framesize = 128;
> + } else {
> + framesize = framesize << 3;
> + }
> +
> + if (ctx->opcode & (1 << 7)) {
> + gen_mips16_save(ctx, 0, 0,
> + do_ra, do_s0, do_s1, framesize);
> + } else {
> + gen_mips16_restore(ctx, 0, 0,
> + do_ra, do_s0, do_s1, framesize);
> + }
> + }
> + break;
> + case I8_MOV32R:
> + {
> + int rz = xlat(ctx->opcode & 0x7);
> +
> + reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
> + ((ctx->opcode >> 5) & 0x7);
> + gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
> + }
> + break;
> + case I8_MOVR32:
> + reg32 = ctx->opcode & 0x1f;
> + gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
> + break;
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + }
> + break;
> + case M16_OPC_LI:
> + {
> + int16_t imm = (uint8_t) ctx->opcode;
> +
> + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
> + }
> + break;
> + case M16_OPC_CMPI:
> + {
> + int16_t imm = (uint8_t) ctx->opcode;
> +
> + gen_logic_imm(env, OPC_XORI, 24, rx, imm);
> + }
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_SD:
> + gen_ldst(ctx, OPC_SD, ry, rx, offset << 3);
> + break;
> +#endif
> + case M16_OPC_LB:
> + gen_ldst(ctx, OPC_LB, ry, rx, offset);
> + break;
> + case M16_OPC_LH:
> + gen_ldst(ctx, OPC_LH, ry, rx, offset << 1);
> + break;
> + case M16_OPC_LWSP:
> + gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
> + break;
> + case M16_OPC_LW:
> + gen_ldst(ctx, OPC_LW, ry, rx, offset << 2);
> + break;
> + case M16_OPC_LBU:
> + gen_ldst(ctx, OPC_LBU, ry, rx, offset);
> + break;
> + case M16_OPC_LHU:
> + gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1);
> + break;
> + case M16_OPC_LWPC:
> + gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
> + break;
> +#if defined (TARGET_MIPS64)
> + case M16_OPC_LWU:
> + gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2);
> + break;
> +#endif
> + case M16_OPC_SB:
> + gen_ldst(ctx, OPC_SB, ry, rx, offset);
> + break;
> + case M16_OPC_SH:
> + gen_ldst(ctx, OPC_SH, ry, rx, offset << 1);
> + break;
> + case M16_OPC_SWSP:
> + gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
> + break;
> + case M16_OPC_SW:
> + gen_ldst(ctx, OPC_SW, ry, rx, offset << 2);
> + break;
> + case M16_OPC_RRR:
> + {
> + int rz = xlat((ctx->opcode >> 2) & 0x7);
> + int mips32_op;
> +
> + switch (ctx->opcode & 0x3) {
> + case RRR_ADDU:
> + mips32_op = OPC_ADDU;
> + break;
> + case RRR_SUBU:
> + mips32_op = OPC_SUBU;
> + break;
> +#if defined(TARGET_MIPS64)
> + case RRR_DADDU:
> + mips32_op = OPC_DADDU;
> + break;
> + case RRR_DSUBU:
> + mips32_op = OPC_DSUBU;
> + break;
> +#endif
> + default:
> + generate_exception(ctx, EXCP_RI);
> + goto done;
> + }
> +
> + gen_arith(env, ctx, mips32_op, rz, rx, ry);
> + done:
> + ;
> + }
> + break;
> + case M16_OPC_RR:
> + switch (op1) {
> + case RR_JR:
> + {
> + int nd = (ctx->opcode >> 7) & 0x1;
> + int link = (ctx->opcode >> 6) & 0x1;
> + int ra = (ctx->opcode >> 5) & 0x1;
> +
> + if (link) {
> + op = nd ? OPC_JALRC : OPC_JALR;
> + } else {
> + op = OPC_JR;
> + }
> +
> + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
> + if (!nd) {
> + *is_branch = 1;
> + }
> + }
> + break;
> + case RR_SDBBP:
> + /* XXX: not clear which exception should be raised
> + * when in debug mode...
> + */
> + check_insn(env, ctx, ISA_MIPS32);
> + if (!(ctx->hflags & MIPS_HFLAG_DM)) {
> + generate_exception(ctx, EXCP_DBp);
> + } else {
> + generate_exception(ctx, EXCP_DBp);
> + }
> + break;
> + case RR_SLT:
> + gen_slt(env, OPC_SLT, 24, rx, ry);
> + break;
> + case RR_SLTU:
> + gen_slt(env, OPC_SLTU, 24, rx, ry);
> + break;
> + case RR_BREAK:
> + generate_exception(ctx, EXCP_BREAK);
> + break;
> + case RR_SLLV:
> + gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
> + break;
> + case RR_SRLV:
> + gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
> + break;
> + case RR_SRAV:
> + gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
> + break;
> +#if defined (TARGET_MIPS64)
> + case RR_DSRL:
> + gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
> + break;
> +#endif
> + case RR_CMP:
> + gen_logic(env, OPC_XOR, 24, rx, ry);
> + break;
> + case RR_NEG:
> + gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
> + break;
> + case RR_AND:
> + gen_logic(env, OPC_AND, rx, rx, ry);
> + break;
> + case RR_OR:
> + gen_logic(env, OPC_OR, rx, rx, ry);
> + break;
> + case RR_XOR:
> + gen_logic(env, OPC_XOR, rx, rx, ry);
> + break;
> + case RR_NOT:
> + gen_logic(env, OPC_NOR, rx, ry, 0);
> + break;
> + case RR_MFHI:
> + gen_HILO(ctx, OPC_MFHI, rx);
> + break;
> + case RR_CNVT:
> + switch (cnvt_op) {
> + case RR_RY_CNVT_ZEB:
> + tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> + case RR_RY_CNVT_ZEH:
> + tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> + case RR_RY_CNVT_SEB:
> + tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> + case RR_RY_CNVT_SEH:
> + tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> +#if defined (TARGET_MIPS64)
> + case RR_RY_CNVT_ZEW:
> + tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> + case RR_RY_CNVT_SEW:
> + tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
> + break;
> +#endif
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + break;
> + case RR_MFLO:
> + gen_HILO(ctx, OPC_MFLO, rx);
> + break;
> +#if defined (TARGET_MIPS64)
> + case RR_DSRA:
> + gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
> + break;
> + case RR_DSLLV:
> + gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
> + case RR_DSRLV:
> + gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
> + break;
> + case RR_DSRAV:
> + gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
> + break;
> +#endif
> + case RR_MULT:
> + gen_muldiv(ctx, OPC_MULT, rx, ry);
> + break;
> + case RR_MULTU:
> + gen_muldiv(ctx, OPC_MULTU, rx, ry);
> + break;
> + case RR_DIV:
> + gen_muldiv(ctx, OPC_DIV, rx, ry);
> + break;
> + case RR_DIVU:
> + gen_muldiv(ctx, OPC_DIVU, rx, ry);
> + break;
> +#if defined (TARGET_MIPS64)
> + case RR_DMULT:
> + gen_muldiv(ctx, OPC_DMULT, rx, ry);
> + break;
> + case RR_DMULTU:
> + gen_muldiv(ctx, OPC_DMULTU, rx, ry);
> + break;
> + case RR_DDIV:
> + gen_muldiv(ctx, OPC_DDIV, rx, ry);
> + break;
> + case RR_DDIVU:
> + gen_muldiv(ctx, OPC_DDIVU, rx, ry);
> + break;
> +#endif
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + break;
> + case M16_OPC_EXTEND:
> + decode_extended_mips16_opc(env, ctx, is_branch);
> + n_bytes = 4;
> + break;
> +#if defined(TARGET_MIPS64)
> + case M16_OPC_I64:
> + funct = (ctx->opcode >> 8) & 0x7;
> + switch (funct) {
> + case I64_LDSP:
> + gen_ldst(ctx, OPC_LD, ry, 29, offset << 3);
> + break;
> + case I64_SDSP:
> + gen_ldst(ctx, OPC_SD, ry, 29, offset << 3);
> + break;
> + case I64_SDRASP:
> + gen_ldst(ctx, OPC_SD, 31, 29, (ctx->opcode & 0xff) << 3);
> + break;
> + case I64_DADJSP:
> + gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29,
> + ((int8_t)ctx->opcode) << 3);
> + break;
> + case I64_LDPC:
> + break;
> + case I64_DADDIU:
> + gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry,
> + ((int8_t)(offset << 3)) >> 3);
> + break;
> + case I64_DADDIUPC:
> + break;
> + case I64_DADDIUSP:
> + gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29,
> + ((int8_t)(offset << 3)) >> 1);
> + break;
> + }
> +#endif
> + default:
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> +
> + return n_bytes;
> +}
> +
> /* SmartMIPS extension to MIPS32 */
>
> #if defined(TARGET_MIPS64)
> @@ -8400,7 +9366,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
> #endif
> case OPC_JALX:
> check_insn(env, ctx, ASE_MIPS16);
> - /* MIPS16: Not implemented. */
> + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
> + gen_compute_branch(ctx, op, 4, rs, rt, offset);
> + *is_branch = 1;
> + break;
> case OPC_MDMX:
> check_insn(env, ctx, ASE_MDMX);
> /* MDMX: Not implemented. */
> @@ -8490,6 +9459,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
> ctx.opcode = ldl_code(ctx.pc);
> insn_bytes = 4;
> decode_opc(env, &ctx, &is_branch);
> + } else if (env->insn_flags & ASE_MIPS16) {
> + ctx.opcode = lduw_code(ctx.pc);
> + insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
> } else {
> generate_exception(&ctx, EXCP_RI);
> break;
> --
> 1.6.3.2
>
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr
2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
On Mon, Nov 23, 2009 at 12:50:04PM -0800, Nathan Froyd wrote:
> This is a common pattern in existing code. We'll also use it to
> implement the mips16 SAVE/RESTORE instructions.
>
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
> target-mips/translate.c | 40 ++++++++++++++++------------------------
> 1 files changed, 16 insertions(+), 24 deletions(-)
>
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index 1157e97..fece3c1 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -997,6 +997,19 @@ OP_ST_ATOMIC(scd,st64,ld64,0x7);
> #endif
> #undef OP_ST_ATOMIC
>
> +static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
> + int base, int16_t offset)
> +{
> + if (base == 0) {
> + tcg_gen_movi_tl(addr, offset);
> + } else if (offset == 0) {
> + gen_load_gpr(addr, base);
> + } else {
> + tcg_gen_movi_tl(addr, offset);
> + gen_op_addr_add(ctx, addr, addr, cpu_gpr[base]);
I am nitpicking a bit, but it's better to keep the two last argument as
in the original version to keep the immediate value in the last
position. This saves one instruction on non-RISC hosts.
> + }
> +}
> +
> /* Load and store */
> static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
> int base, int16_t offset)
> @@ -1005,14 +1018,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
> TCGv t0 = tcg_temp_new();
> TCGv t1 = tcg_temp_new();
>
> - if (base == 0) {
> - tcg_gen_movi_tl(t0, offset);
> - } else if (offset == 0) {
> - gen_load_gpr(t0, base);
> - } else {
> - tcg_gen_movi_tl(t0, offset);
> - gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> - }
> + gen_base_offset_addr(ctx, t0, base, offset);
> /* Don't do NOP if destination is zero: we must perform the actual
> memory access. */
> switch (opc) {
> @@ -1163,14 +1169,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
>
> t0 = tcg_temp_local_new();
>
> - if (base == 0) {
> - tcg_gen_movi_tl(t0, offset);
> - } else if (offset == 0) {
> - gen_load_gpr(t0, base);
> - } else {
> - tcg_gen_movi_tl(t0, offset);
> - gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> - }
> + gen_base_offset_addr(ctx, t0, base, offset);
> /* Don't do NOP if destination is zero: we must perform the actual
> memory access. */
>
> @@ -1202,14 +1201,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
> const char *opn = "flt_ldst";
> TCGv t0 = tcg_temp_new();
>
> - if (base == 0) {
> - tcg_gen_movi_tl(t0, offset);
> - } else if (offset == 0) {
> - gen_load_gpr(t0, base);
> - } else {
> - tcg_gen_movi_tl(t0, offset);
> - gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
> - }
> + gen_base_offset_addr(ctx, t0, base, offset);
> /* Don't do NOP if destination is zero: we must perform the actual
> memory access. */
> switch (opc) {
> --
> 1.6.3.2
>
>
>
>
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
2009-11-30 17:45 ` Aurelien Jarno
0 siblings, 1 reply; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
On Mon, Nov 23, 2009 at 12:49:59PM -0800, Nathan Froyd wrote:
>
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
> target-mips/cpu.h | 1 +
> target-mips/translate.c | 2 ++
> 2 files changed, 3 insertions(+), 0 deletions(-)
>
> diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> index 82f9a38..e8febe6 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -167,6 +167,7 @@ struct TCState {
> target_ulong CP0_TCContext;
> target_ulong CP0_TCSchedule;
> target_ulong CP0_TCScheFBack;
> + uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
> int32_t CP0_Debug_tcstatus;
> };
I am fine with this.
> diff --git a/target-mips/translate.c b/target-mips/translate.c
> index e9d9224..b0a1b29 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -463,6 +463,7 @@ typedef struct DisasContext {
> struct TranslationBlock *tb;
> target_ulong pc, saved_pc;
> uint32_t opcode;
> + int isa_mode;
> int singlestep_enabled;
> /* Routine used to access memory */
> int mem_idx;
> @@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
> ctx.pc = pc_start;
> ctx.saved_pc = -1;
> ctx.singlestep_enabled = env->singlestep_enabled;
> + ctx.isa_mode = env->active_tc.ISAMode;
> ctx.tb = tb;
> ctx.bstate = BS_NONE;
> /* Restore delay slot state from the tb context. */
Instead of a new ctx value, it's probably better to use a new bit in
hflags. It is also necessary to change MIPS_HFLAG_TMASK accordingly, to
ensure a MIPS16 translation block is not later executed while ISAMode is
0 (while it should generate an exception) and vice-versa.
This also mean that hflags should be recomputed each time ISAMode is
changed.
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
` (10 preceding siblings ...)
2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
@ 2009-11-28 10:17 ` Aurelien Jarno
11 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-28 10:17 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
Hi,
On Mon, Nov 23, 2009 at 12:49:58PM -0800, Nathan Froyd wrote:
> This patchset adds MIPS16 support to the MIPS backend. MIPS16 is a
> compact encoding of a subset of the MIPS integer instructions, similar
> to ARM's Thumb mode. The processor enters MIPS16 mode by executing a
> special jump instruction; execution continus at the jump target in
> MIPS16 mode until the processor returns to MIPS32/64 mode by executing a
> special jump instruction.
>
> The patches have been tested with GCC's testsuite and GDB's testsuite.
It's nice there is someone working on items from target-mips/TODO. By
the way, this patchset misses one patch to remove the entry from this
file ;-)
More seriously, this patchset still has a few problems, but I don't
expect them difficult to solve. Please see the comments on different
patches.
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution
2009-11-28 10:17 ` Aurelien Jarno
@ 2009-11-30 17:45 ` Aurelien Jarno
0 siblings, 0 replies; 18+ messages in thread
From: Aurelien Jarno @ 2009-11-30 17:45 UTC (permalink / raw)
To: Nathan Froyd; +Cc: qemu-devel
On Sat, Nov 28, 2009 at 11:17:20AM +0100, Aurelien Jarno wrote:
> On Mon, Nov 23, 2009 at 12:49:59PM -0800, Nathan Froyd wrote:
> >
> > Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> > ---
> > target-mips/cpu.h | 1 +
> > target-mips/translate.c | 2 ++
> > 2 files changed, 3 insertions(+), 0 deletions(-)
> >
> > diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> > index 82f9a38..e8febe6 100644
> > --- a/target-mips/cpu.h
> > +++ b/target-mips/cpu.h
> > @@ -167,6 +167,7 @@ struct TCState {
> > target_ulong CP0_TCContext;
> > target_ulong CP0_TCSchedule;
> > target_ulong CP0_TCScheFBack;
> > + uint32_t ISAMode; /* MIPS32 or MIPS16 mode */
> > int32_t CP0_Debug_tcstatus;
> > };
>
> I am fine with this.
>
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index e9d9224..b0a1b29 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -463,6 +463,7 @@ typedef struct DisasContext {
> > struct TranslationBlock *tb;
> > target_ulong pc, saved_pc;
> > uint32_t opcode;
> > + int isa_mode;
> > int singlestep_enabled;
> > /* Routine used to access memory */
> > int mem_idx;
> > @@ -8306,6 +8307,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
> > ctx.pc = pc_start;
> > ctx.saved_pc = -1;
> > ctx.singlestep_enabled = env->singlestep_enabled;
> > + ctx.isa_mode = env->active_tc.ISAMode;
> > ctx.tb = tb;
> > ctx.bstate = BS_NONE;
> > /* Restore delay slot state from the tb context. */
>
> Instead of a new ctx value, it's probably better to use a new bit in
> hflags. It is also necessary to change MIPS_HFLAG_TMASK accordingly, to
> ensure a MIPS16 translation block is not later executed while ISAMode is
> 0 (while it should generate an exception) and vice-versa.
>
> This also mean that hflags should be recomputed each time ISAMode is
> changed.
>
Actually just changing ctx.hflags is enough, as it is automatically
saved to env->hflags at the end of the TB or if an exception can occur.
--
Aurelien Jarno GPG: 1024D/F1BCDB73
aurelien@aurel32.net http://www.aurel32.net
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2009-11-30 19:27 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-23 20:49 [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Nathan Froyd
2009-11-23 20:49 ` [Qemu-devel] [PATCH 01/11] target-mips: add ISAMode bits for mips16 execution Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-30 17:45 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 02/11] target-mips: add new HFLAGs for JALX and 16/32-bit delay slots Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 03/11] target-mips: change interrupt bits to be mips16-aware Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 04/11] target-mips: move ROTR and ROTRV inside gen_shift_{imm, } Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 05/11] target-mips: make gen_compute_branch 16/32-bit-aware Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 06/11] target-mips: add gen_base_offset_addr Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 07/11] target-mips: split out delay slot handling Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 08/11] target-mips: add enums for MIPS16 opcodes Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 09/11] target-mips: add mips16 instruction decoding Nathan Froyd
2009-11-28 10:17 ` Aurelien Jarno
2009-11-23 20:50 ` [Qemu-devel] [PATCH 10/11] gdbstub: add MIPS16 support Nathan Froyd
2009-11-23 20:50 ` [Qemu-devel] [PATCH 11/11] target-mips: add copyright notice for mips16 work Nathan Froyd
2009-11-28 10:17 ` [Qemu-devel] [PATCH 00/11] target-mips: add mips16 support Aurelien Jarno
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).