--- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/cpu.h 2005-12-19 23:51:53.000000000 +0100 +++ qemu-0.8.0/target-mips/cpu.h 2006-04-18 16:23:57.000000000 +0200 @@ -40,16 +40,19 @@ struct CPUMIPSState { uint32_t DCR; /* ? */ #if defined(MIPS_USES_FPU) /* Floating point registers */ - fpr_t fpr[16]; - /* Floating point special purpose registers */ + fpr_t fpr[32]; +#ifndef USE_HOST_FLOAT_REGS + fpr_t ft0; + fpr_t ft1; + fpr_t ft2; +#endif + /* fpu implementation/revision register */ uint32_t fcr0; - uint32_t fcr25; - uint32_t fcr26; - uint32_t fcr28; - uint32_t fcsr; + /* fcsr */ + uint32_t fcr31; #endif #if defined(MIPS_USES_R4K_TLB) - tlb_t tlb[16]; + tlb_t tlb[MIPS_TLB_NB]; #endif uint32_t CP0_index; uint32_t CP0_random; diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/exec.h qemu-0.8.0/target-mips/exec.h --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/exec.h 2005-12-19 23:51:53.000000000 +0100 +++ qemu-0.8.0/target-mips/exec.h 2006-04-18 16:39:16.000000000 +0200 @@ -65,6 +65,10 @@ void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); void do_tlbr (void); +#ifdef MIPS_USES_FPU +void do_cfc1(int reg); +void do_ctc1(int reg); +#endif void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); uint32_t do_swl_raw (uint32_t); diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/fop_template.c qemu-0.8.0/target-mips/fop_template.c --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/fop_template.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-0.8.0/target-mips/fop_template.c 2006-04-18 15:45:34.000000000 +0200 @@ -0,0 +1,87 @@ +/* + * MIPS emulation micro-operations templates for reg load & store for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if defined(FREG) + +void glue(op_load_fpr_FT0_fpr, FREG) (void) +{ + FT0 = env->fpr[FREG].d; + RETURN(); +} + +void glue(op_store_FT0_fpr_fpr, FREG) (void) +{ + env->fpr[FREG].d = FT0; + RETURN(); +} + +void glue(op_load_fpr_FT1_fpr, FREG) (void) +{ + FT1 = env->fpr[FREG].d; + RETURN(); +} + +void glue(op_store_FT1_fpr_fpr, FREG) (void) +{ + env->fpr[FREG].d = FT1; + RETURN(); +} + +#endif + +#if defined (FTN) + +void op_set_FT0 (void) +{ + FT0 = PARAM1; + RETURN(); +} + +void op_reset_FT0 (void) +{ + FT0 = 0; + RETURN(); +} + +void op_set_FT1 (void) +{ + FT1 = PARAM1; + RETURN(); +} + +void op_reset_FT1 (void) +{ + FT1 = 0; + RETURN(); +} + +void op_set_FT2 (void) +{ + FT2 = PARAM1; + RETURN(); +} + +void op_reset_FT2 (void) +{ + FT2 = 0; + RETURN(); +} + +#endif diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/mips-defs.h qemu-0.8.0/target-mips/mips-defs.h --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/mips-defs.h 2005-12-19 23:51:53.000000000 +0100 +++ qemu-0.8.0/target-mips/mips-defs.h 2006-04-18 15:45:34.000000000 +0200 @@ -24,6 +24,8 @@ enum { /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 +/* basic FPU register support */ +#define MIPS_USES_FPU /* Have config1, runs in big-endian mode, uses TLB */ #define MIPS_CONFIG0 \ ((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \ @@ -52,7 +54,7 @@ enum { #error "MIPS CPU not defined" /* Remainder for other flags */ //#define TARGET_MIPS64 -//define MIPS_USES_FPU +//#define MIPS_USES_FPU #endif #endif /* !defined (__QEMU_MIPS_DEFS_H__) */ diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op.c qemu-0.8.0/target-mips/op.c --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op.c 2005-12-19 23:51:53.000000000 +0100 +++ qemu-0.8.0/target-mips/op.c 2006-04-18 16:39:51.000000000 +0200 @@ -149,6 +149,111 @@ CALL_FROM_TB2(func, arg0, arg1); #include "op_template.c" #undef TN +#ifdef MIPS_USES_FPU + +#define FREG 0 +#include "fop_template.c" +#undef FREG +#define FREG 1 +#include "fop_template.c" +#undef FREG +#define FREG 2 +#include "fop_template.c" +#undef FREG +#define FREG 3 +#include "fop_template.c" +#undef FREG +#define FREG 4 +#include "fop_template.c" +#undef FREG +#define FREG 5 +#include "fop_template.c" +#undef FREG +#define FREG 6 +#include "fop_template.c" +#undef FREG +#define FREG 7 +#include "fop_template.c" +#undef FREG +#define FREG 8 +#include "fop_template.c" +#undef FREG +#define FREG 9 +#include "fop_template.c" +#undef FREG +#define FREG 10 +#include "fop_template.c" +#undef FREG +#define FREG 11 +#include "fop_template.c" +#undef FREG +#define FREG 12 +#include "fop_template.c" +#undef FREG +#define FREG 13 +#include "fop_template.c" +#undef FREG +#define FREG 14 +#include "fop_template.c" +#undef FREG +#define FREG 15 +#include "fop_template.c" +#undef FREG +#define FREG 16 +#include "fop_template.c" +#undef FREG +#define FREG 17 +#include "fop_template.c" +#undef FREG +#define FREG 18 +#include "fop_template.c" +#undef FREG +#define FREG 19 +#include "fop_template.c" +#undef FREG +#define FREG 20 +#include "fop_template.c" +#undef FREG +#define FREG 21 +#include "fop_template.c" +#undef FREG +#define FREG 22 +#include "fop_template.c" +#undef FREG +#define FREG 23 +#include "fop_template.c" +#undef FREG +#define FREG 24 +#include "fop_template.c" +#undef FREG +#define FREG 25 +#include "fop_template.c" +#undef FREG +#define FREG 26 +#include "fop_template.c" +#undef FREG +#define FREG 27 +#include "fop_template.c" +#undef FREG +#define FREG 28 +#include "fop_template.c" +#undef FREG +#define FREG 29 +#include "fop_template.c" +#undef FREG +#define FREG 30 +#include "fop_template.c" +#undef FREG +#define FREG 31 +#include "fop_template.c" +#undef FREG + +#define FTN +#include "fop_template.c" +#undef FTN + +#endif + void op_dup_T0 (void) { T2 = T0; @@ -560,6 +665,21 @@ void op_mtc0 (void) RETURN(); } +#ifdef MIPS_USES_FPU +/* CP1 functions */ +void op_cfc1 (void) +{ + CALL_FROM_TB1(do_cfc1, PARAM1); + RETURN(); +} + +void op_ctc1 (void) +{ + CALL_FROM_TB1(do_ctc1, PARAM1); + RETURN(); +} +#endif + #if defined(MIPS_USES_R4K_TLB) void op_tlbwi (void) { diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op_helper.c qemu-0.8.0/target-mips/op_helper.c --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op_helper.c 2005-12-19 23:51:53.000000000 +0100 +++ qemu-0.8.0/target-mips/op_helper.c 2006-04-18 16:41:52.000000000 +0200 @@ -533,6 +533,68 @@ void do_mtc0 (int reg, int sel) return; } +#ifdef MIPS_USES_FPU +/* CP1 helpers */ +void do_cfc1 (int reg) +{ + const unsigned char *rn; + + switch (reg) { + case 0: + T0 = env->fcr0; + rn = "FCR0"; + break; + case 31: + T0 = env->fcr31; + rn = "FCR31"; + break; + default: + rn = "unknown"; + break; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x cfc1 %s => %08x (%d)\n", + env->PC, rn, T0, reg); + } +#endif + return; +} + +void do_ctc1 (int reg) +{ + const unsigned char *rn; + uint32_t val, old; + + switch (reg) { + case 0: + val = T0; + old = env->fcr0; + env->fcr0 = T0; + rn = "FCR0"; + break; + case 31: + val = T0; + old = env->fcr31; + env->fcr31 = T0; + rn = "FCR31"; + break; + default: + val = -1; + old = -1; + rn = "unknown"; + break; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %08x)\n", + env->PC, rn, T0, val, reg, old); + } +#endif + return; +} +#endif + /* TLB management */ #if defined(MIPS_USES_R4K_TLB) static void invalidate_tb (int idx) diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op_mem.c qemu-0.8.0/target-mips/op_mem.c --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/op_mem.c 2006-04-18 17:01:50.000000000 +0200 +++ qemu-0.8.0/target-mips/op_mem.c 2006-04-18 15:45:34.000000000 +0200 @@ -124,3 +124,16 @@ void glue(op_sc, MEMSUFFIX) (void) } RETURN(); } + +#ifdef MIPS_USES_FPU +void glue(op_lwc1, MEMSUFFIX) (void) +{ + FT0 = glue(ldfl, MEMSUFFIX)(T0); + RETURN(); +} +void glue(op_swc1, MEMSUFFIX) (void) +{ + glue(stfl, MEMSUFFIX)(T0, FT1); + RETURN(); +} +#endif diff -purN rpm-root/packages/BUILD/qemu-0.8.0/target-mips/translate.c qemu-0.8.0/target-mips/translate.c --- rpm-root/packages/BUILD/qemu-0.8.0/target-mips/translate.c 2006-04-18 17:01:50.000000000 +0200 +++ qemu-0.8.0/target-mips/translate.c 2006-04-18 16:53:01.000000000 +0200 @@ -218,6 +218,14 @@ enum { OPC_WAIT = 0x20 | EXT_CP0, }; +#ifdef MIPS_USES_FPU +enum { + /* Coprocessor 1 (FPU) */ + OPC_CFC1 = 0x02 | EXT_CP1, + OPC_CTC1 = 0x06 | EXT_CP1, +}; +#endif + const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", @@ -249,6 +257,35 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gp GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +#ifdef MIPS_USES_FPU +const unsigned char *fregnames[] = + { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; + +# define FGEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} +FGEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr); +FGEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr); + +FGEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr); +FGEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr); +#endif + typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; @@ -313,6 +350,20 @@ do { } \ } while (0) +#ifdef MIPS_USES_FPU + +# define GEN_LOAD_FREG_FTN(FTn, Fn) \ +do { \ + glue(gen_op_load_fpr_, FTn)(Fn); \ +} while (0) + +#define GEN_STORE_FTN_FREG(Fn, FTn) \ +do { \ + glue(glue(gen_op_store_, FTn),_fpr)(Fn); \ +} while (0) + +#endif + static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS @@ -399,6 +450,10 @@ OP_LD_TABLE(bu); OP_ST_TABLE(b); OP_LD_TABLE(l); OP_ST_TABLE(c); +#ifdef MIPS_USES_FPU +OP_LD_TABLE(wc1); +OP_ST_TABLE(wc1); +#endif /* Load and store */ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, @@ -558,6 +613,45 @@ static void gen_ldst (DisasContext *ctx, MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); } +#ifdef MIPS_USES_FPU +/* Load and store */ +static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, + int base, int16_t offset) +{ + const unsigned char *opn = "unk"; + + if (base == 0) { + GEN_LOAD_IMM_TN(T0, offset); + } else if (offset == 0) { + gen_op_load_gpr_T0(base); + } else { + gen_op_load_gpr_T0(base); + gen_op_set_T1(offset); + gen_op_add(); + } + /* Don't do NOP if destination is zero: we must perform the actual + * memory access + */ + switch (opc) { + case OPC_LWC1: + op_ldst(lwc1); + GEN_STORE_FTN_FREG(ft, FT0); + opn = "lwc1"; + break; + case OPC_SWC1: + GEN_LOAD_FREG_FTN(FT1, ft); + op_ldst(swc1); + opn = "swc1"; + break; + default: + MIPS_INVAL("float load/store"); + generate_exception(ctx, EXCP_CpU); + return; + } + MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); +} +#endif + /* Arithmetic with immediate operand */ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, int rs, int16_t imm) @@ -1274,6 +1368,54 @@ static void gen_cp0 (DisasContext *ctx, } /* Coprocessor 1 (FPU) */ +static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) +{ + const unsigned char *opn = "unk"; + + if (!(ctx->CP0_Status & (1 << CP0St_CU1))) { + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "CP1 is not usable\n"); + } + generate_exception_err (ctx, EXCP_CpU, 0); + return; + } + + switch (opc) { + case OPC_CFC1: + if (fs != 0 && fs != 31) { + MIPS_INVAL("cp1"); + generate_exception(ctx, EXCP_RI); + return; + } + gen_op_cfc1(fs); + gen_op_store_T0_gpr(rt); + opn = "cfc1"; + break; + case OPC_CTC1: + if (fs != 0 && fs != 31) { + MIPS_INVAL("cp1"); + generate_exception(ctx, EXCP_RI); + return; + } + /* If we get an exception, we want to restart at next instruction */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; + GEN_LOAD_REG_TN(T0, rt); + gen_op_ctc1(fs); + opn = "ctc1"; + break; + default: + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, + ((ctx->opcode >> 16) & 0x1F)); + } + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); +} /* ISA extensions */ /* MIPS16 extension to MIPS32 */ @@ -1450,7 +1592,7 @@ static void decode_opc (DisasContext *ct } break; case 0x01: /* B REGIMM opcode */ - op1 = ((ctx->opcode >> 16) & 0x1F); + op1 = ((ctx->opcode >> 16) & 0x1F); switch (op1) { case 0x00 ... 0x03: /* REGIMM branches */ case 0x10 ... 0x13: @@ -1508,14 +1650,32 @@ static void decode_opc (DisasContext *ct case 0x35: /* LDC1 */ case 0x39: /* SWC1 */ case 0x3D: /* SDC1 */ - case 0x11: /* CP1 opcode */ #if defined(MIPS_USES_FPU) - /* XXX: not correct */ + gen_flt_ldst(ctx, op, rt, rs, imm); #else generate_exception_err(ctx, EXCP_CpU, 1); #endif break; + case 0x11: /* CP1 opcode */ +#if defined(MIPS_USES_FPU) +printf("opcode = %x\n", ctx->opcode); + op1 = ((ctx->opcode >> 21) & 0x1F); + switch (op1) { + case 0x02: /* cfc1 */ + case 0x06: /* ctc1 */ + gen_cp1(ctx, op1 | EXT_CP1, rt, rd); + break; + default: + generate_exception_err(ctx, EXCP_CpU, 1); + break; + } + break; +#else + generate_exception_err(ctx, EXCP_CpU, 1); +#endif + break; + /* COP2. */ case 0x32: /* LWC2 */ case 0x36: /* LDC2 */