Revision 6ea83fed

b/configure
819 819
  echo "TARGET_ARCH=mips" >> $config_mak
820 820
  echo "#define TARGET_ARCH \"mips\"" >> $config_h
821 821
  echo "#define TARGET_MIPS 1" >> $config_h
822
  echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
823
  echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
822 824
elif test "$target_cpu" = "sh4" ; then
823 825
  echo "TARGET_ARCH=sh4" >> $config_mak
824 826
  echo "#define TARGET_ARCH \"sh4\"" >> $config_h
b/target-mips/cpu.h
10 10

  
11 11
typedef union fpr_t fpr_t;
12 12
union fpr_t {
13
    double d;
14
    float  f;
15
    uint32_t u[2];
13
    float64  fd;   /* ieee double precision */
14
    float32  fs[2];/* ieee single precision */
15
    uint64_t d;    /* binary single fixed-point */
16
    uint32_t w[2]; /* binary single fixed-point */
16 17
};
18
/* define FP_ENDIAN_IDX to access the same location
19
 * in the fpr_t union regardless of the host endianess
20
 */
21
#if defined(WORDS_BIGENDIAN)
22
#  define FP_ENDIAN_IDX 1
23
#else
24
#  define FP_ENDIAN_IDX 0
25
#endif
17 26

  
18 27
#if defined(MIPS_USES_R4K_TLB)
19 28
typedef struct tlb_t tlb_t;
......
44 53
#if defined(MIPS_USES_FPU)
45 54
    /* Floating point registers */
46 55
    fpr_t fpr[16];
47
    /* Floating point special purpose registers */
56
#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2])
57
#define FPR_FD(cpu, n) (FPR(cpu, n)->fd)
58
#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX])
59
#define FPR_D(cpu, n)  (FPR(cpu, n)->d)
60
#define FPR_W(cpu, n)  (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX])
61

  
62
#ifndef USE_HOST_FLOAT_REGS
63
    fpr_t ft0;
64
    fpr_t ft1;
65
    fpr_t ft2;
66
#endif
67
    float_status fp_status;
68
    /* fpu implementation/revision register */
48 69
    uint32_t fcr0;
49
    uint32_t fcr25;
50
    uint32_t fcr26;
51
    uint32_t fcr28;
52
    uint32_t fcsr;
70
    /* fcsr */
71
    uint32_t fcr31;
72
#define SET_FP_COND(reg)     do { (reg) |= (1<<23); } while(0)
73
#define CLEAR_FP_COND(reg)   do { (reg) &= ~(1<<23); } while(0)
74
#define IS_FP_COND_SET(reg)  (((reg) & (1<<23)) != 0)
75
#define GET_FP_CAUSE(reg)    (((reg) >> 12) & 0x3f)
76
#define GET_FP_ENABLE(reg)   (((reg) >>  7) & 0x1f)
77
#define GET_FP_FLAGS(reg)    (((reg) >>  2) & 0x1f)
78
#define SET_FP_CAUSE(reg,v)  do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0)
79
#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f <<  7)) | ((v) << 7); } while(0)
80
#define SET_FP_FLAGS(reg,v)  do { (reg) = ((reg) & ~(0x1f <<  2)) | ((v) << 2); } while(0)
81
#define FP_INEXACT        1
82
#define FP_UNDERFLOW      2
83
#define FP_OVERFLOW       4
84
#define FP_DIV0           8
85
#define FP_INVALID        16
86
#define FP_UNIMPLEMENTED  32
87
		
53 88
#endif
54 89
#if defined(MIPS_USES_R4K_TLB)
55 90
    tlb_t tlb[16];
......
71 106
#define CP0St_CU1   29
72 107
#define CP0St_CU0   28
73 108
#define CP0St_RP    27
109
#define CP0St_FR    26
74 110
#define CP0St_RE    25
75 111
#define CP0St_BEV   22
76 112
#define CP0St_TS    21
......
138 174
    uint32_t CP0_ErrorEPC;
139 175
    uint32_t CP0_DESAVE;
140 176
    /* Qemu */
141
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
142
    double ft0, ft1, ft2;
143
#endif
144 177
    struct QEMUTimer *timer; /* Internal timer */
145 178
    int interrupt_request;
146 179
    jmp_buf jmp_env;
b/target-mips/exec.h
21 21
register host_uint_t T2 asm(AREG3);
22 22

  
23 23
#if defined (USE_HOST_FLOAT_REGS)
24
register double FT0 asm(FREG0);
25
register double FT1 asm(FREG1);
26
register double FT2 asm(FREG2);
24
#error "implement me."
27 25
#else
28
#define FT0 (env->ft0.d)
29
#define FT1 (env->ft1.d)
30
#define FT2 (env->ft2.d)
26
#define FDT0 (env->ft0.fd)
27
#define FDT1 (env->ft1.fd)
28
#define FDT2 (env->ft2.fd)
29
#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
30
#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
31
#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
32
#define DT0 (env->ft0.d)
33
#define DT1 (env->ft1.d)
34
#define DT2 (env->ft2.d)
35
#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
36
#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
37
#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
31 38
#endif
32 39

  
33 40
#if defined (DEBUG_OP)
......
65 72
void do_tlbwr (void);
66 73
void do_tlbp (void);
67 74
void do_tlbr (void);
75
#ifdef MIPS_USES_FPU
76
void dump_fpu(CPUState *env);
77
void fpu_dump_state(CPUState *env, FILE *f, 
78
                    int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
79
                    int flags);
80
#endif
81
void dump_sc (void);
68 82
void do_lwl_raw (uint32_t);
69 83
void do_lwr_raw (uint32_t);
70 84
uint32_t do_swl_raw (uint32_t);
b/target-mips/fop_template.c
1
/*
2
 * MIPS emulation micro-operations templates for floating point reg 
3
 * load & store for qemu.
4
 * 
5
 * Copyright (c) 2006 Marius Groeger
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21

  
22
#if defined(SFREG)
23

  
24
#define OP_WLOAD_FREG(treg, tregname, SFREG)      \
25
    void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
26
    {                                                   \
27
        treg = FPR_W(env, SFREG);     \
28
        RETURN();                                       \
29
    }
30

  
31
#define OP_WSTORE_FREG(treg, tregname, SFREG)            \
32
    void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
33
    {                                                   \
34
        FPR_W(env, SFREG) = treg;     \
35
        RETURN();                                       \
36
    }
37

  
38
/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */
39
OP_WLOAD_FREG(WT0, WT0_fpr, SFREG)
40
/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */
41
OP_WSTORE_FREG(WT0, WT0_fpr, SFREG)
42

  
43
OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
44
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
45

  
46
OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
47
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
48

  
49
#endif
50

  
51
#if defined(DFREG)
52

  
53
#define OP_DLOAD_FREG(treg, tregname, DFREG)      \
54
    void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
55
    {                                                   \
56
        treg = FPR_D(env, DFREG);                    \
57
        RETURN();                                       \
58
    }
59

  
60
#define OP_DSTORE_FREG(treg, tregname, DFREG)            \
61
    void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
62
    {                                                   \
63
        FPR_D(env, DFREG) = treg;                    \
64
        RETURN();                                       \
65
    }
66

  
67
OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
68
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
69

  
70
OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
71
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
72

  
73
OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
74
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
75

  
76
#endif
77

  
78
#if defined (FTN)
79

  
80
#define SET_RESET(treg, tregname)    \
81
    void glue(op_set, tregname)(void)    \
82
    {                                \
83
        treg = PARAM1;               \
84
        RETURN();                    \
85
    }                                \
86
    void glue(op_reset, tregname)(void)  \
87
    {                                \
88
        treg = 0;                    \
89
        RETURN();                    \
90
    }                                \
91

  
92
SET_RESET(WT0, _WT0)
93
SET_RESET(WT1, _WT1)
94
SET_RESET(WT2, _WT2)
95
SET_RESET(DT0, _DT0)
96
SET_RESET(DT1, _DT1)
97
SET_RESET(DT2, _DT2)
98

  
99
#endif
b/target-mips/mips-defs.h
24 24
/* Uses MIPS R4Kc TLB model */
25 25
#define MIPS_USES_R4K_TLB
26 26
#define MIPS_TLB_NB 16
27
/* basic FPU register support */
28
#define MIPS_USES_FPU 1
29
/* Define a implementation number of 1.
30
 * Define a major version 1, minor version 0.
31
 */
32
#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
27 33
/* Have config1, runs in big-endian mode, uses TLB */
28 34
#define MIPS_CONFIG0                                            \
29 35
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) |  \
......
31 37
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
32 38
 * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
33 39
 * no performance counters, watch registers present, no code compression,
34
 * EJTAG present, no FPU
40
 * EJTAG present, FPU enable bit depending on MIPS_USES_FPU
35 41
 */
36 42
#define MIPS_CONFIG1                                            \
37 43
((15 << CP0C1_MMU) |                                            \
38 44
 (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
39 45
 (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
40 46
 (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) |          \
41
 (1 << CP0C1_EP) | (0 << CP0C1_FP))
47
 (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
42 48
#elif defined (MIPS_CPU == MIPS_R4Kp)
43 49
/* 32 bits target */
44 50
#define TARGET_LONG_BITS 32
......
52 58
#error "MIPS CPU not defined"
53 59
/* Remainder for other flags */
54 60
//#define TARGET_MIPS64
55
//define MIPS_USES_FPU
61
//#define MIPS_USES_FPU
56 62
#endif
57 63

  
58 64
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
b/target-mips/op.c
2 2
 *  MIPS emulation micro-operations for qemu.
3 3
 * 
4 4
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5
 *  Copyright (c) 2006 Marius Groeger (FPU operations)
5 6
 *
6 7
 * This library is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
......
149 150
#include "op_template.c"
150 151
#undef TN
151 152

  
153
#ifdef MIPS_USES_FPU
154

  
155
#define SFREG 0
156
#define DFREG 0
157
#include "fop_template.c"
158
#undef SFREG
159
#undef DFREG
160
#define SFREG 1
161
#include "fop_template.c"
162
#undef SFREG
163
#define SFREG 2
164
#define DFREG 2
165
#include "fop_template.c"
166
#undef SFREG
167
#undef DFREG
168
#define SFREG 3
169
#include "fop_template.c"
170
#undef SFREG
171
#define SFREG 4
172
#define DFREG 4
173
#include "fop_template.c"
174
#undef SFREG
175
#undef DFREG
176
#define SFREG 5
177
#include "fop_template.c"
178
#undef SFREG
179
#define SFREG 6
180
#define DFREG 6
181
#include "fop_template.c"
182
#undef SFREG
183
#undef DFREG
184
#define SFREG 7
185
#include "fop_template.c"
186
#undef SFREG
187
#define SFREG 8
188
#define DFREG 8
189
#include "fop_template.c"
190
#undef SFREG
191
#undef DFREG
192
#define SFREG 9
193
#include "fop_template.c"
194
#undef SFREG
195
#define SFREG 10
196
#define DFREG 10
197
#include "fop_template.c"
198
#undef SFREG
199
#undef DFREG
200
#define SFREG 11
201
#include "fop_template.c"
202
#undef SFREG
203
#define SFREG 12
204
#define DFREG 12
205
#include "fop_template.c"
206
#undef SFREG
207
#undef DFREG
208
#define SFREG 13
209
#include "fop_template.c"
210
#undef SFREG
211
#define SFREG 14
212
#define DFREG 14
213
#include "fop_template.c"
214
#undef SFREG
215
#undef DFREG
216
#define SFREG 15
217
#include "fop_template.c"
218
#undef SFREG
219
#define SFREG 16
220
#define DFREG 16
221
#include "fop_template.c"
222
#undef SFREG
223
#undef DFREG
224
#define SFREG 17
225
#include "fop_template.c"
226
#undef SFREG
227
#define SFREG 18
228
#define DFREG 18
229
#include "fop_template.c"
230
#undef SFREG
231
#undef DFREG
232
#define SFREG 19
233
#include "fop_template.c"
234
#undef SFREG
235
#define SFREG 20
236
#define DFREG 20
237
#include "fop_template.c"
238
#undef SFREG
239
#undef DFREG
240
#define SFREG 21
241
#include "fop_template.c"
242
#undef SFREG
243
#define SFREG 22
244
#define DFREG 22
245
#include "fop_template.c"
246
#undef SFREG
247
#undef DFREG
248
#define SFREG 23
249
#include "fop_template.c"
250
#undef SFREG
251
#define SFREG 24
252
#define DFREG 24
253
#include "fop_template.c"
254
#undef SFREG
255
#undef DFREG
256
#define SFREG 25
257
#include "fop_template.c"
258
#undef SFREG
259
#define SFREG 26
260
#define DFREG 26
261
#include "fop_template.c"
262
#undef SFREG
263
#undef DFREG
264
#define SFREG 27
265
#include "fop_template.c"
266
#undef SFREG
267
#define SFREG 28
268
#define DFREG 28
269
#include "fop_template.c"
270
#undef SFREG
271
#undef DFREG
272
#define SFREG 29
273
#include "fop_template.c"
274
#undef SFREG
275
#define SFREG 30
276
#define DFREG 30
277
#include "fop_template.c"
278
#undef SFREG
279
#undef DFREG
280
#define SFREG 31
281
#include "fop_template.c"
282
#undef SFREG
283

  
284
#define FTN
285
#include "fop_template.c"
286
#undef FTN
287

  
288
#endif
289

  
152 290
void op_dup_T0 (void)
153 291
{
154 292
    T2 = T0;
......
562 700
    RETURN();
563 701
}
564 702

  
703
#ifdef MIPS_USES_FPU
704

  
705
#if 0
706
# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
707
#else
708
# define DEBUG_FPU_STATE() do { } while(0)
709
#endif
710

  
711
void op_cp1_enabled(void)
712
{
713
    if (!(env->CP0_Status & (1 << CP0St_CU1))) {
714
        CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
715
    }
716
    RETURN();
717
}
718

  
719
/* CP1 functions */
720
void op_cfc1 (void)
721
{
722
    if (T1 == 0) {
723
        T0 = env->fcr0;
724
    }
725
    else {
726
        /* fetch fcr31, masking unused bits */
727
        T0 = env->fcr31 & 0x0183FFFF;
728
    }
729
    DEBUG_FPU_STATE();
730
    RETURN();
731
}
732

  
733
/* convert MIPS rounding mode in FCR31 to IEEE library */
734
unsigned int ieee_rm[] = { 
735
    float_round_nearest_even,
736
    float_round_to_zero,
737
    float_round_up,
738
    float_round_down
739
};
740

  
741
#define RESTORE_ROUNDING_MODE \
742
    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
743

  
744
void op_ctc1 (void)
745
{
746
    if (T1 == 0) {
747
        /* XXX should this throw an exception?
748
         * don't write to FCR0.
749
         * env->fcr0 = T0; 
750
         */
751
    }
752
    else {
753
        /* store new fcr31, masking unused bits */  
754
        env->fcr31 = T0 & 0x0183FFFF;
755

  
756
        /* set rounding mode */
757
        RESTORE_ROUNDING_MODE;
758

  
759
#ifndef CONFIG_SOFTFLOAT
760
        /* no floating point exception for native float */
761
        SET_FP_ENABLE(env->fcr31, 0);
762
#endif
763
    }
764
    DEBUG_FPU_STATE();
765
    RETURN();
766
}
767

  
768
void op_mfc1 (void)
769
{
770
    T0 = WT0;
771
    DEBUG_FPU_STATE();
772
    RETURN();
773
}
774

  
775
void op_mtc1 (void)
776
{
777
    WT0 = T0;
778
    DEBUG_FPU_STATE();
779
    RETURN();
780
}
781

  
782
/* Float support.
783
   Single precition routines have a "s" suffix, double precision a
784
   "d" suffix.  */
785

  
786
#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
787

  
788
FLOAT_OP(cvtd, w)
789
{
790
    FDT2 = int32_to_float64(WT0, &env->fp_status);
791
    DEBUG_FPU_STATE();
792
    RETURN();
793
}
794
FLOAT_OP(cvts, w)
795
{
796
    FST2 = int32_to_float32(WT0, &env->fp_status);
797
    DEBUG_FPU_STATE();
798
    RETURN();
799
}
800
FLOAT_OP(cvtw, s)
801
{
802
    WT2 = float32_to_int32(FST0, &env->fp_status);
803
    DEBUG_FPU_STATE();
804
    RETURN();
805
}
806
FLOAT_OP(cvtw, d)
807
{
808
    WT2 = float64_to_int32(FDT0, &env->fp_status);
809
    DEBUG_FPU_STATE();
810
    RETURN();
811
}
812

  
813
FLOAT_OP(roundw, d)
814
{
815
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
816
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
817
    RESTORE_ROUNDING_MODE;
818

  
819
    DEBUG_FPU_STATE();
820
    RETURN();
821
}
822
FLOAT_OP(roundw, s)
823
{
824
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
825
    WT2 = float32_round_to_int(FST0, &env->fp_status);
826
    RESTORE_ROUNDING_MODE;
827
    DEBUG_FPU_STATE();
828
    RETURN();
829
}
830

  
831
FLOAT_OP(truncw, d)
832
{
833
    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
834
    DEBUG_FPU_STATE();
835
    RETURN();
836
}
837
FLOAT_OP(truncw, s)
838
{
839
    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
840
    DEBUG_FPU_STATE();
841
    RETURN();
842
}
843

  
844
FLOAT_OP(ceilw, d)
845
{
846
    set_float_rounding_mode(float_round_up, &env->fp_status);
847
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
848
    RESTORE_ROUNDING_MODE;
849

  
850
    DEBUG_FPU_STATE();
851
    RETURN();
852
}
853
FLOAT_OP(ceilw, s)
854
{
855
    set_float_rounding_mode(float_round_up, &env->fp_status);
856
    WT2 = float32_round_to_int(FST0, &env->fp_status);
857
    RESTORE_ROUNDING_MODE;
858
    DEBUG_FPU_STATE();
859
    RETURN();
860
}
861

  
862
FLOAT_OP(floorw, d)
863
{
864
    set_float_rounding_mode(float_round_down, &env->fp_status);
865
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
866
    RESTORE_ROUNDING_MODE;
867

  
868
    DEBUG_FPU_STATE();
869
    RETURN();
870
}
871
FLOAT_OP(floorw, s)
872
{
873
    set_float_rounding_mode(float_round_down, &env->fp_status);
874
    WT2 = float32_round_to_int(FST0, &env->fp_status);
875
    RESTORE_ROUNDING_MODE;
876
    DEBUG_FPU_STATE();
877
    RETURN();
878
}
879

  
880
/* binary operations */
881
#define FLOAT_BINOP(name) \
882
FLOAT_OP(name, d)         \
883
{                         \
884
    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
885
    DEBUG_FPU_STATE();    \
886
}                         \
887
FLOAT_OP(name, s)         \
888
{                         \
889
    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
890
    DEBUG_FPU_STATE();    \
891
}
892
FLOAT_BINOP(add)
893
FLOAT_BINOP(sub)
894
FLOAT_BINOP(mul)
895
FLOAT_BINOP(div)
896
#undef FLOAT_BINOP
897

  
898
/* unary operations, modifying fp status  */
899
#define FLOAT_UNOP(name)  \
900
FLOAT_OP(name, d)         \
901
{                         \
902
    FDT2 = float64_ ## name(FDT0, &env->fp_status);   \
903
    DEBUG_FPU_STATE();    \
904
}                         \
905
FLOAT_OP(name, s)         \
906
{                         \
907
    FST2 = float32_ ## name(FST0, &env->fp_status);   \
908
    DEBUG_FPU_STATE();    \
909
}
910
FLOAT_UNOP(sqrt)
911
#undef FLOAT_UNOP
912

  
913
/* unary operations, not modifying fp status  */
914
#define FLOAT_UNOP(name)  \
915
FLOAT_OP(name, d)         \
916
{                         \
917
    FDT2 = float64_ ## name(FDT0);   \
918
    DEBUG_FPU_STATE();    \
919
}                         \
920
FLOAT_OP(name, s)         \
921
{                         \
922
    FST2 = float32_ ## name(FST0);   \
923
    DEBUG_FPU_STATE();    \
924
}
925
FLOAT_UNOP(abs)
926
FLOAT_UNOP(chs)
927
#undef FLOAT_UNOP
928

  
929
FLOAT_OP(mov, d)
930
{
931
    FDT2 = FDT0;
932
    DEBUG_FPU_STATE();
933
    RETURN();
934
}
935
FLOAT_OP(mov, s)
936
{
937
    FST2 = FST0;
938
    DEBUG_FPU_STATE();
939
    RETURN();
940
}
941

  
942
#ifdef CONFIG_SOFTFLOAT
943
#define clear_invalid() do {                                \
944
    int flags = get_float_exception_flags(&env->fp_status); \
945
    flags &= ~float_flag_invalid;                           \
946
    set_float_exception_flags(flags, &env->fp_status);      \
947
} while(0)
948
#else
949
#define clear_invalid() do { } while(0)
950
#endif
951

  
952
extern void dump_fpu_s(CPUState *env);
953

  
954
#define FOP_COND(fmt, op, sig, cond)           \
955
void op_cmp_ ## fmt ## _ ## op (void)          \
956
{                                              \
957
    if (cond)                                  \
958
        SET_FP_COND(env->fcr31);               \
959
    else                                       \
960
        CLEAR_FP_COND(env->fcr31);             \
961
    if (!sig)                                  \
962
        clear_invalid();                       \
963
    /*CALL_FROM_TB1(dump_fpu_s, env);*/ \
964
    DEBUG_FPU_STATE();                         \
965
    RETURN();                                  \
966
}
967

  
968
flag float64_is_unordered(float64 a, float64 b STATUS_PARAM)
969
{
970
    extern flag float64_is_nan( float64 a );
971
    if (float64_is_nan(a) || float64_is_nan(b)) {
972
        float_raise(float_flag_invalid, status);
973
        return 1;
974
    }
975
    else {
976
        return 0;
977
    }
978
}
979

  
980
FOP_COND(d, f,   0,                                                      0) 
981
FOP_COND(d, un,  0, float64_is_unordered(FDT1, FDT0, &env->fp_status))
982
FOP_COND(d, eq,  0,                                                      float64_eq(FDT0, FDT1, &env->fp_status))
983
FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
984
FOP_COND(d, olt, 0,                                                      float64_lt(FDT0, FDT1, &env->fp_status))
985
FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
986
FOP_COND(d, ole, 0,                                                      float64_le(FDT0, FDT1, &env->fp_status))
987
FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
988
/* NOTE: the comma operator will make "cond" to eval to false,
989
 * but float*_is_unordered() is still called
990
 */
991
FOP_COND(d, sf,  1,                                                      (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0))
992
FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status))
993
FOP_COND(d, seq, 1,                                                      float64_eq(FDT0, FDT1, &env->fp_status))
994
FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
995
FOP_COND(d, lt,  1,                                                      float64_lt(FDT0, FDT1, &env->fp_status))
996
FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
997
FOP_COND(d, le,  1,                                                      float64_le(FDT0, FDT1, &env->fp_status))
998
FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
999

  
1000
flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
1001
{
1002
    extern flag float32_is_nan( float32 a );
1003
    if (float32_is_nan(a) || float32_is_nan(b)) {
1004
        float_raise(float_flag_invalid, status);
1005
        return 1;
1006
    }
1007
    else {
1008
        return 0;
1009
    }
1010
}
1011

  
1012
/* NOTE: the comma operator will make "cond" to eval to false,
1013
 * but float*_is_unordered() is still called
1014
 */
1015
FOP_COND(s, f,   0,                                                      0) 
1016
FOP_COND(s, un,  0, float32_is_unordered(FST1, FST0, &env->fp_status))
1017
FOP_COND(s, eq,  0,                                                      float32_eq(FST0, FST1, &env->fp_status))
1018
FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
1019
FOP_COND(s, olt, 0,                                                      float32_lt(FST0, FST1, &env->fp_status))
1020
FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
1021
FOP_COND(s, ole, 0,                                                      float32_le(FST0, FST1, &env->fp_status))
1022
FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
1023
/* NOTE: the comma operator will make "cond" to eval to false,
1024
 * but float*_is_unordered() is still called
1025
 */
1026
FOP_COND(s, sf,  1,                                                      (float32_is_unordered(FST0, FST1, &env->fp_status), 0))
1027
FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status))
1028
FOP_COND(s, seq, 1,                                                      float32_eq(FST0, FST1, &env->fp_status))
1029
FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
1030
FOP_COND(s, lt,  1,                                                      float32_lt(FST0, FST1, &env->fp_status))
1031
FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
1032
FOP_COND(s, le,  1,                                                      float32_le(FST0, FST1, &env->fp_status))
1033
FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
1034

  
1035
void op_bc1f (void)
1036
{
1037
    T0 = ! IS_FP_COND_SET(env->fcr31);
1038
    DEBUG_FPU_STATE();
1039
    RETURN();
1040
}
1041

  
1042
void op_bc1t (void)
1043
{
1044
    T0 = IS_FP_COND_SET(env->fcr31);
1045
    DEBUG_FPU_STATE();
1046
    RETURN();
1047
}
1048
#endif /* MIPS_USES_FPU */
1049

  
565 1050
#if defined(MIPS_USES_R4K_TLB)
566 1051
void op_tlbwi (void)
567 1052
{
b/target-mips/op_helper.c
529 529
    return;
530 530
}
531 531

  
532
#ifdef MIPS_USES_FPU
533
#include "softfloat.h"
534

  
535
void fpu_handle_exception(void)
536
{
537
#ifdef CONFIG_SOFTFLOAT
538
    int flags = get_float_exception_flags(&env->fp_status);
539
    unsigned int cpuflags = 0, enable, cause = 0;
540

  
541
    enable = GET_FP_ENABLE(env->fcr31);
542

  
543
    /* determine current flags */   
544
    if (flags & float_flag_invalid) {
545
        cpuflags |= FP_INVALID;
546
        cause |= FP_INVALID & enable;
547
    }
548
    if (flags & float_flag_divbyzero) {
549
        cpuflags |= FP_DIV0;    
550
        cause |= FP_DIV0 & enable;
551
    }
552
    if (flags & float_flag_overflow) {
553
        cpuflags |= FP_OVERFLOW;    
554
        cause |= FP_OVERFLOW & enable;
555
    }
556
    if (flags & float_flag_underflow) {
557
        cpuflags |= FP_UNDERFLOW;   
558
        cause |= FP_UNDERFLOW & enable;
559
    }
560
    if (flags & float_flag_inexact) {
561
        cpuflags |= FP_INEXACT; 
562
        cause |= FP_INEXACT & enable;
563
    }
564
    SET_FP_FLAGS(env->fcr31, cpuflags);
565
    SET_FP_CAUSE(env->fcr31, cause);
566
#else
567
    SET_FP_FLAGS(env->fcr31, 0);
568
    SET_FP_CAUSE(env->fcr31, 0);
569
#endif
570
}
571
#endif /* MIPS_USES_FPU */
572

  
532 573
/* TLB management */
533 574
#if defined(MIPS_USES_R4K_TLB)
534 575
static void invalidate_tlb (int idx)
b/target-mips/op_mem.c
118 118
    }
119 119
    RETURN();
120 120
}
121

  
122
#ifdef MIPS_USES_FPU
123
void glue(op_lwc1, MEMSUFFIX) (void)
124
{
125
    WT0 = glue(ldl, MEMSUFFIX)(T0);
126
    RETURN();
127
}
128
void glue(op_swc1, MEMSUFFIX) (void)
129
{
130
    glue(stl, MEMSUFFIX)(T0, WT0);
131
    RETURN();
132
}
133
void glue(op_ldc1, MEMSUFFIX) (void)
134
{
135
    DT0 = glue(ldq, MEMSUFFIX)(T0);
136
    RETURN();
137
}
138
void glue(op_sdc1, MEMSUFFIX) (void)
139
{
140
    glue(stq, MEMSUFFIX)(T0, DT0);
141
    RETURN();
142
}
143
#endif
b/target-mips/translate.c
2 2
 *  MIPS32 emulation for qemu: main translation routines.
3 3
 * 
4 4
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5
 *  Copyright (c) 2006 Marius Groeger (FPU operations)
5 6
 *
6 7
 * This library is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
......
217 218
    OPC_WAIT     = 0x20 | EXT_CP0,
218 219
};
219 220

  
221
#ifdef MIPS_USES_FPU
222
enum {
223
    /* Coprocessor 1 (FPU) */
224
    OPC_MFC1     = 0x00 | EXT_CP1,
225
    OPC_MTC1     = 0x04 | EXT_CP1,
226
    OPC_CFC1     = 0x02 | EXT_CP1,
227
    OPC_CTC1     = 0x06 | EXT_CP1,
228
};
229
#endif
230

  
220 231
const unsigned char *regnames[] =
221 232
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
222 233
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
......
248 259
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
249 260
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
250 261

  
262
#ifdef MIPS_USES_FPU
263
const unsigned char *fregnames[] =
264
    { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
265
      "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
266
      "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
267
      "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
268

  
269
# define SFGEN32(func, NAME) \
270
static GenOpFunc *NAME ## _table [32] = {                                     \
271
NAME ## 0,  NAME ## 1,  NAME ## 2,  NAME ## 3,                                \
272
NAME ## 4,  NAME ## 5,  NAME ## 6,  NAME ## 7,                                \
273
NAME ## 8,  NAME ## 9,  NAME ## 10, NAME ## 11,                               \
274
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
275
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
276
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
277
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
278
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
279
};                                                                            \
280
static inline void func(int n)                                                \
281
{                                                                             \
282
    NAME ## _table[n]();                                                      \
283
}
284

  
285
# define DFGEN32(func, NAME) \
286
static GenOpFunc *NAME ## _table [32] = {                                     \
287
NAME ## 0,  0, NAME ## 2,  0,                                                 \
288
NAME ## 4,  0, NAME ## 6,  0,                                                 \
289
NAME ## 8,  0, NAME ## 10, 0,                                                 \
290
NAME ## 12, 0, NAME ## 14, 0,                                                 \
291
NAME ## 16, 0, NAME ## 18, 0,                                                 \
292
NAME ## 20, 0, NAME ## 22, 0,                                                 \
293
NAME ## 24, 0, NAME ## 26, 0,                                                 \
294
NAME ## 28, 0, NAME ## 30, 0,                                                 \
295
};                                                                            \
296
static inline void func(int n)                                                \
297
{                                                                             \
298
    NAME ## _table[n]();                                                      \
299
}
300

  
301
SFGEN32(gen_op_load_fpr_WT0,  gen_op_load_fpr_WT0_fpr);
302
SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
303

  
304
SFGEN32(gen_op_load_fpr_WT1,  gen_op_load_fpr_WT1_fpr);
305
SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
306

  
307
SFGEN32(gen_op_load_fpr_WT2,  gen_op_load_fpr_WT2_fpr);
308
SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
309

  
310
DFGEN32(gen_op_load_fpr_DT0,  gen_op_load_fpr_DT0_fpr);
311
DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
312

  
313
DFGEN32(gen_op_load_fpr_DT1,  gen_op_load_fpr_DT1_fpr);
314
DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
315

  
316
DFGEN32(gen_op_load_fpr_DT2,  gen_op_load_fpr_DT2_fpr);
317
DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
318

  
319
#define FOP_CONDS(fmt) \
320
static GenOpFunc * cond_ ## fmt ## _table[16] = {                       \
321
    gen_op_cmp_ ## fmt ## _f,                                           \
322
    gen_op_cmp_ ## fmt ## _un,                                          \
323
    gen_op_cmp_ ## fmt ## _eq,                                          \
324
    gen_op_cmp_ ## fmt ## _ueq,                                         \
325
    gen_op_cmp_ ## fmt ## _olt,                                         \
326
    gen_op_cmp_ ## fmt ## _ult,                                         \
327
    gen_op_cmp_ ## fmt ## _ole,                                         \
328
    gen_op_cmp_ ## fmt ## _ule,                                         \
329
    gen_op_cmp_ ## fmt ## _sf,                                          \
330
    gen_op_cmp_ ## fmt ## _ngle,                                        \
331
    gen_op_cmp_ ## fmt ## _seq,                                         \
332
    gen_op_cmp_ ## fmt ## _ngl,                                         \
333
    gen_op_cmp_ ## fmt ## _lt,                                          \
334
    gen_op_cmp_ ## fmt ## _nge,                                         \
335
    gen_op_cmp_ ## fmt ## _le,                                          \
336
    gen_op_cmp_ ## fmt ## _ngt,                                         \
337
};                                                                      \
338
static inline void gen_cmp_ ## fmt(int n)                               \
339
{                                                                       \
340
    cond_ ## fmt ## _table[n]();                                        \
341
}
342

  
343
FOP_CONDS(d)
344
FOP_CONDS(s)
345

  
346
#endif
347

  
251 348
typedef struct DisasContext {
252 349
    struct TranslationBlock *tb;
253 350
    target_ulong pc, saved_pc;
......
312 409
    }                                                                         \
313 410
} while (0)
314 411

  
412
#ifdef MIPS_USES_FPU
413

  
414
# define GEN_LOAD_FREG_FTN(FTn, Fn)                                           \
415
do {                                                                          \
416
    glue(gen_op_load_fpr_, FTn)(Fn);                                          \
417
} while (0)
418

  
419
#define GEN_STORE_FTN_FREG(Fn, FTn)                                           \
420
do {                                                                          \
421
    glue(gen_op_store_fpr_, FTn)(Fn);                                         \
422
} while (0)
423

  
424
#endif
425

  
315 426
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
316 427
{
317 428
#if defined MIPS_DEBUG_DISAS
......
397 508
OP_ST_TABLE(b);
398 509
OP_LD_TABLE(l);
399 510
OP_ST_TABLE(c);
511
#ifdef MIPS_USES_FPU
512
OP_LD_TABLE(wc1);
513
OP_ST_TABLE(wc1);
514
OP_LD_TABLE(dc1);
515
OP_ST_TABLE(dc1);
516
#endif
400 517

  
401 518
/* Load and store */
402 519
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
......
551 668
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
552 669
}
553 670

  
671
#ifdef MIPS_USES_FPU
672

  
673
/* Load and store */
674
static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
675
                      int base, int16_t offset)
676
{
677
    const unsigned char *opn = "unk";
678

  
679
    if (base == 0) {
680
        GEN_LOAD_IMM_TN(T0, offset);
681
    } else if (offset == 0) {
682
        gen_op_load_gpr_T0(base);
683
    } else {
684
        gen_op_load_gpr_T0(base);
685
        gen_op_set_T1(offset);
686
        gen_op_add();
687
    }
688
    /* Don't do NOP if destination is zero: we must perform the actual
689
     * memory access
690
     */
691
    switch (opc) {
692
    case OPC_LWC1:
693
        op_ldst(lwc1);
694
        GEN_STORE_FTN_FREG(ft, WT0);
695
        opn = "lwc1";
696
        break;
697
    case OPC_SWC1:
698
        GEN_LOAD_FREG_FTN(WT0, ft);
699
        op_ldst(swc1);
700
        opn = "swc1";
701
        break;
702
    case OPC_LDC1:
703
        op_ldst(ldc1);
704
        GEN_STORE_FTN_FREG(ft, DT0);
705
        opn = "ldc1";
706
        break;
707
    case OPC_SDC1:
708
        GEN_LOAD_FREG_FTN(DT0, ft);
709
        op_ldst(sdc1);
710
        opn = "sdc1";
711
        break;
712
    default:
713
        MIPS_INVAL("float load/store");
714
        generate_exception(ctx, EXCP_CpU);
715
        return;
716
    }
717
    MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
718
}
719
#endif
720

  
554 721
/* Arithmetic with immediate operand */
555 722
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
556 723
                           int rs, int16_t imm)
......
1265 1432
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1266 1433
}
1267 1434

  
1435
#ifdef MIPS_USES_FPU
1436
/* CP1 Branches (before delay slot) */
1437
static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
1438
                                 int32_t offset)
1439
{
1440
    target_ulong btarget;
1441

  
1442
    btarget = ctx->pc + 4 + offset;
1443

  
1444
    switch (cond) {
1445
    case 0x0000: /* bc1f */
1446
        gen_op_bc1f();
1447
        MIPS_DEBUG("bc1f %08x", btarget);
1448
        goto not_likely;
1449
    case 0x0002: /* bc1fl */
1450
        gen_op_bc1f();
1451
        MIPS_DEBUG("bc1fl %08x", btarget);
1452
        goto likely;
1453
    case 0x0001: /* bc1t */
1454
        gen_op_bc1t();
1455
        MIPS_DEBUG("bc1t %08x", btarget);
1456
    not_likely:
1457
        ctx->hflags |= MIPS_HFLAG_BC;
1458
        break;
1459
    case 0x0003: /* bc1tl */
1460
        gen_op_bc1t();
1461
        MIPS_DEBUG("bc1tl %08x", btarget);
1462
    likely:
1463
        ctx->hflags |= MIPS_HFLAG_BL;
1464
        break;
1465
    default:    
1466
        MIPS_INVAL("cp1 branch/jump");
1467
        generate_exception(ctx, EXCP_RI);
1468
        return;
1469
    }
1470
    gen_op_set_bcond();
1471

  
1472
    MIPS_DEBUG("enter ds: cond %02x target %08x",
1473
               ctx->hflags, btarget);
1474
    ctx->btarget = btarget;
1475

  
1476
    return;
1477
}
1478

  
1268 1479
/* Coprocessor 1 (FPU) */
1480
static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
1481
{
1482
    const unsigned char *opn = "unk";
1483

  
1484
    switch (opc) {
1485
    case OPC_MFC1:
1486
        GEN_LOAD_FREG_FTN(WT0, fs);
1487
        gen_op_mfc1();
1488
        GEN_STORE_TN_REG(rt, T0);
1489
        opn = "mfc1";
1490
        break;
1491
    case OPC_MTC1:
1492
        GEN_LOAD_REG_TN(T0, rt);
1493
        gen_op_mtc1();
1494
        GEN_STORE_FTN_FREG(fs, WT0);
1495
        opn = "mtc1";
1496
        break;
1497
    case OPC_CFC1:
1498
        if (fs != 0 && fs != 31) {
1499
            MIPS_INVAL("cfc1 freg");
1500
            generate_exception(ctx, EXCP_RI);
1501
            return;
1502
        }
1503
        GEN_LOAD_IMM_TN(T1, fs);
1504
        gen_op_cfc1();
1505
        GEN_STORE_TN_REG(rt, T0);
1506
        opn = "cfc1";
1507
        break;
1508
    case OPC_CTC1:
1509
        if (fs != 0 && fs != 31) {
1510
            MIPS_INVAL("ctc1 freg");
1511
            generate_exception(ctx, EXCP_RI);
1512
            return;
1513
        }
1514
        GEN_LOAD_IMM_TN(T1, fs);
1515
        GEN_LOAD_REG_TN(T0, rt);
1516
        gen_op_ctc1();
1517
        opn = "ctc1";
1518
        break;
1519
    default:
1520
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1521
            fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
1522
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1523
                    ((ctx->opcode >> 16) & 0x1F));
1524
        }
1525
        generate_exception(ctx, EXCP_RI);
1526
        return;
1527
    }
1528
    MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
1529
}
1530

  
1531
/* verify if floating point register is valid; an operation is not defined
1532
 * if bit 0 of any register specification is set and the FR bit in the
1533
 * Status register equals zero, since the register numbers specify an
1534
 * even-odd pair of adjacent coprocessor general registers. When the FR bit
1535
 * in the Status register equals one, both even and odd register numbers
1536
 * are valid.
1537
 * 
1538
 * Multiple float registers can be checked by calling
1539
 * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
1540
 */
1541
#define CHECK_FR(ctx, freg) do { \
1542
        if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
1543
            generate_exception(ctx, EXCP_RI); \
1544
            return; \
1545
        } \
1546
    } while(0)
1547

  
1548
#define FOP(func, fmt) (((fmt) << 21) | (func))
1549

  
1550
static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
1551
{
1552
    const unsigned char *opn = "unk";
1553
    const char *condnames[] = {
1554
            "c.f",
1555
            "c.un",
1556
            "c.eq",
1557
            "c.ueq",
1558
            "c.olt",
1559
            "c.ult",
1560
            "c.ole",
1561
            "c.ule",
1562
            "c.sf",
1563
            "c.ngle",
1564
            "c.seq",
1565
            "c.ngl",
1566
            "c.lt",
1567
            "c.nge",
1568
            "c.le",
1569
            "c.ngt",
1570
    };
1571
    int binary = 0;
1572
    
1573
    switch (ctx->opcode & FOP(0x3f, 0x1f)) {
1574
    case FOP(0, 17):
1575
        CHECK_FR(ctx, fs | ft | fd);
1576
        GEN_LOAD_FREG_FTN(DT0, fs);
1577
        GEN_LOAD_FREG_FTN(DT1, ft);
1578
        gen_op_float_add_d();
1579
        GEN_STORE_FTN_FREG(fd, DT2);
1580
        opn = "add.d";
1581
        binary = 1;
1582
        break;
1583
    case FOP(1, 17):
1584
        CHECK_FR(ctx, fs | ft | fd);
1585
        GEN_LOAD_FREG_FTN(DT0, fs);
1586
        GEN_LOAD_FREG_FTN(DT1, ft);
1587
        gen_op_float_sub_d();
1588
        GEN_STORE_FTN_FREG(fd, DT2);
1589
        opn = "sub.d";
1590
        binary = 1;
1591
        break;
1592
    case FOP(2, 17):
1593
        CHECK_FR(ctx, fs | ft | fd);
1594
        GEN_LOAD_FREG_FTN(DT0, fs);
1595
        GEN_LOAD_FREG_FTN(DT1, ft);
1596
        gen_op_float_mul_d();
1597
        GEN_STORE_FTN_FREG(fd, DT2);
1598
        opn = "mul.d";
1599
        binary = 1;
1600
        break;
1601
    case FOP(3, 17):
1602
        CHECK_FR(ctx, fs | ft | fd);
1603
        GEN_LOAD_FREG_FTN(DT0, fs);
1604
        GEN_LOAD_FREG_FTN(DT1, ft);
1605
        gen_op_float_div_d();
1606
        GEN_STORE_FTN_FREG(fd, DT2);
1607
        opn = "div.d";
1608
        binary = 1;
1609
        break;
1610
    case FOP(4, 17):
1611
        CHECK_FR(ctx, fs | fd);
1612
        GEN_LOAD_FREG_FTN(DT0, fs);
1613
        gen_op_float_sqrt_d();
1614
        GEN_STORE_FTN_FREG(fd, DT2);
1615
        opn = "sqrt.d";
1616
        break;
1617
    case FOP(5, 17):
1618
        CHECK_FR(ctx, fs | fd);
1619
        GEN_LOAD_FREG_FTN(DT0, fs);
1620
        gen_op_float_abs_d();
1621
        GEN_STORE_FTN_FREG(fd, DT2);
1622
        opn = "abs.d";
1623
        break;
1624
    case FOP(6, 17):
1625
        CHECK_FR(ctx, fs | fd);
1626
        GEN_LOAD_FREG_FTN(DT0, fs);
1627
        gen_op_float_mov_d();
1628
        GEN_STORE_FTN_FREG(fd, DT2);
1629
        opn = "mov.d";
1630
        break;
1631
    case FOP(7, 17):
1632
        CHECK_FR(ctx, fs | fd);
1633
        GEN_LOAD_FREG_FTN(DT0, fs);
1634
        gen_op_float_chs_d();
1635
        GEN_STORE_FTN_FREG(fd, DT2);
1636
        opn = "neg.d";
1637
        break;
1638
    /*  8 - round.l */
1639
    /*  9 - trunc.l */
1640
    /* 10 - ceil.l  */
1641
    /* 11 - floor.l */
1642
    case FOP(12, 17):
1643
        CHECK_FR(ctx, fs | fd);
1644
        GEN_LOAD_FREG_FTN(DT0, fs);
1645
        gen_op_float_roundw_d();
1646
        GEN_STORE_FTN_FREG(fd, WT2);
1647
        opn = "round.w.d";
1648
        break;
1649
    case FOP(13, 17):
1650
        CHECK_FR(ctx, fs | fd);
1651
        GEN_LOAD_FREG_FTN(DT0, fs);
1652
        gen_op_float_truncw_d();
1653
        GEN_STORE_FTN_FREG(fd, WT2);
1654
        opn = "trunc.w.d";
1655
        break;
1656
    case FOP(14, 17):
1657
        CHECK_FR(ctx, fs | fd);
1658
        GEN_LOAD_FREG_FTN(DT0, fs);
1659
        gen_op_float_ceilw_d();
1660
        GEN_STORE_FTN_FREG(fd, WT2);
1661
        opn = "ceil.w.d";
1662
        break;
1663
    case FOP(15, 17):
1664
        CHECK_FR(ctx, fs | fd);
1665
        GEN_LOAD_FREG_FTN(DT0, fs);
1666
        gen_op_float_floorw_d();
1667
        GEN_STORE_FTN_FREG(fd, WT2);
1668
        opn = "ceil.w.d";
1669
        break;
1670
    case FOP(33, 20): /* cvt.d.w */
1671
        CHECK_FR(ctx, fs | fd);
1672
        GEN_LOAD_FREG_FTN(WT0, fs);
1673
        gen_op_float_cvtd_w();
1674
        GEN_STORE_FTN_FREG(fd, DT2);
1675
        opn = "cvt.d.w";
1676
        break;
1677
    case FOP(48, 17):
1678
    case FOP(49, 17):
1679
    case FOP(50, 17):
1680
    case FOP(51, 17):
1681
    case FOP(52, 17):
1682
    case FOP(53, 17):
1683
    case FOP(54, 17):
1684
    case FOP(55, 17):
1685
    case FOP(56, 17):
1686
    case FOP(57, 17):
1687
    case FOP(58, 17):
1688
    case FOP(59, 17):
1689
    case FOP(60, 17):
1690
    case FOP(61, 17):
1691
    case FOP(62, 17):
1692
    case FOP(63, 17):
1693
        CHECK_FR(ctx, fs | ft);
1694
        GEN_LOAD_FREG_FTN(DT0, fs);
1695
        GEN_LOAD_FREG_FTN(DT1, ft);
1696
        gen_cmp_d(func-48);
1697
        opn = condnames[func-48];
1698
        break;
1699
    case FOP(0, 16):
1700
        CHECK_FR(ctx, fs | ft | fd);
1701
        GEN_LOAD_FREG_FTN(WT0, fs);
1702
        GEN_LOAD_FREG_FTN(WT1, ft);
1703
        gen_op_float_add_s();
1704
        GEN_STORE_FTN_FREG(fd, WT2);
1705
        opn = "add.s";
1706
        binary = 1;
1707
        break;
1708
    case FOP(1, 16):
1709
        CHECK_FR(ctx, fs | ft | fd);
1710
        GEN_LOAD_FREG_FTN(WT0, fs);
1711
        GEN_LOAD_FREG_FTN(WT1, ft);
1712
        gen_op_float_sub_s();
1713
        GEN_STORE_FTN_FREG(fd, WT2);
1714
        opn = "sub.s";
1715
        binary = 1;
1716
        break;
1717
    case FOP(2, 16):
1718
        CHECK_FR(ctx, fs | ft | fd);
1719
        GEN_LOAD_FREG_FTN(WT0, fs);
1720
        GEN_LOAD_FREG_FTN(WT1, ft);
1721
        gen_op_float_mul_s();
1722
        GEN_STORE_FTN_FREG(fd, WT2);
1723
        opn = "mul.s";
1724
        binary = 1;
1725
        break;
1726
    case FOP(3, 16):
1727
        CHECK_FR(ctx, fs | ft | fd);
1728
        GEN_LOAD_FREG_FTN(WT0, fs);
1729
        GEN_LOAD_FREG_FTN(WT1, ft);
1730
        gen_op_float_div_s();
1731
        GEN_STORE_FTN_FREG(fd, WT2);
1732
        opn = "div.s";
1733
        binary = 1;
1734
        break;
1735
    case FOP(4, 16):
1736
        CHECK_FR(ctx, fs | fd);
1737
        GEN_LOAD_FREG_FTN(WT0, fs);
1738
        gen_op_float_sqrt_s();
1739
        GEN_STORE_FTN_FREG(fd, WT2);
1740
        opn = "sqrt.s";
1741
        break;
1742
    case FOP(5, 16):
1743
        CHECK_FR(ctx, fs | fd);
1744
        GEN_LOAD_FREG_FTN(WT0, fs);
1745
        gen_op_float_abs_s();
1746
        GEN_STORE_FTN_FREG(fd, WT2);
1747
        opn = "abs.s";
1748
        break;
1749
    case FOP(6, 16):
1750
        CHECK_FR(ctx, fs | fd);
1751
        GEN_LOAD_FREG_FTN(WT0, fs);
1752
        gen_op_float_mov_s();
1753
        GEN_STORE_FTN_FREG(fd, WT2);
1754
        opn = "mov.s";
1755
        break;
1756
    case FOP(7, 16):
1757
        CHECK_FR(ctx, fs | fd);
1758
        GEN_LOAD_FREG_FTN(WT0, fs);
1759
        gen_op_float_chs_s();
1760
        GEN_STORE_FTN_FREG(fd, WT2);
1761
        opn = "neg.s";
1762
        break;
1763
    case FOP(12, 16):
1764
        CHECK_FR(ctx, fs | fd);
1765
        GEN_LOAD_FREG_FTN(WT0, fs);
1766
        gen_op_float_roundw_s();
1767
        GEN_STORE_FTN_FREG(fd, WT2);
1768
        opn = "round.w.s";
1769
        break;
1770
    case FOP(13, 16):
1771
        CHECK_FR(ctx, fs | fd);
1772
        GEN_LOAD_FREG_FTN(WT0, fs);
1773
        gen_op_float_truncw_s();
1774
        GEN_STORE_FTN_FREG(fd, WT2);
1775
        opn = "trunc.w.s";
1776
        break;
1777
    case FOP(32, 20): /* cvt.s.w */
1778
        CHECK_FR(ctx, fs | fd);
1779
        GEN_LOAD_FREG_FTN(WT0, fs);
1780
        gen_op_float_cvts_w();
1781
        GEN_STORE_FTN_FREG(fd, WT2);
1782
        opn = "cvt.s.w";
1783
        break;
1784
    case FOP(36, 16): /* cvt.w.s */
1785
        CHECK_FR(ctx, fs | fd);
1786
        GEN_LOAD_FREG_FTN(WT0, fs);
1787
        gen_op_float_cvtw_s();
1788
        GEN_STORE_FTN_FREG(fd, WT2);
1789
        opn = "cvt.w.s";
1790
        break;
1791
    case FOP(36, 17): /* cvt.w.d */
1792
        CHECK_FR(ctx, fs | fd);
1793
        GEN_LOAD_FREG_FTN(WT0, fs);
1794
        gen_op_float_cvtw_d();
1795
        GEN_STORE_FTN_FREG(fd, WT2);
1796
        opn = "cvt.w.d";
1797
        break;
1798
    case FOP(48, 16):
1799
    case FOP(49, 16):
1800
    case FOP(50, 16):
1801
    case FOP(51, 16):
1802
    case FOP(52, 16):
1803
    case FOP(53, 16):
1804
    case FOP(54, 16):
1805
    case FOP(55, 16):
1806
    case FOP(56, 16):
1807
    case FOP(57, 16):
1808
    case FOP(58, 16):
1809
    case FOP(59, 16):
1810
    case FOP(60, 16):
1811
    case FOP(61, 16):
1812
    case FOP(62, 16):
1813
    case FOP(63, 16):
1814
        CHECK_FR(ctx, fs | ft);
1815
        GEN_LOAD_FREG_FTN(WT0, fs);
1816
        GEN_LOAD_FREG_FTN(WT1, ft);
1817
        gen_cmp_s(func-48);
1818
        opn = condnames[func-48];
1819
        break;
1820
    default:    
1821
        if (loglevel & CPU_LOG_TB_IN_ASM) {
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff