xref: /qemu/linux-user/arm/nwfpe/fpa11.c (revision 3ebdd119)
1*3ebdd119Saurel32 /*
2*3ebdd119Saurel32     NetWinder Floating Point Emulator
3*3ebdd119Saurel32     (c) Rebel.COM, 1998,1999
4*3ebdd119Saurel32 
5*3ebdd119Saurel32     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
6*3ebdd119Saurel32 
7*3ebdd119Saurel32     This program is free software; you can redistribute it and/or modify
8*3ebdd119Saurel32     it under the terms of the GNU General Public License as published by
9*3ebdd119Saurel32     the Free Software Foundation; either version 2 of the License, or
10*3ebdd119Saurel32     (at your option) any later version.
11*3ebdd119Saurel32 
12*3ebdd119Saurel32     This program is distributed in the hope that it will be useful,
13*3ebdd119Saurel32     but WITHOUT ANY WARRANTY; without even the implied warranty of
14*3ebdd119Saurel32     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*3ebdd119Saurel32     GNU General Public License for more details.
16*3ebdd119Saurel32 
17*3ebdd119Saurel32     You should have received a copy of the GNU General Public License
18*3ebdd119Saurel32     along with this program; if not, write to the Free Software
19*3ebdd119Saurel32     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*3ebdd119Saurel32 */
21*3ebdd119Saurel32 
22*3ebdd119Saurel32 #include "fpa11.h"
23*3ebdd119Saurel32 
24*3ebdd119Saurel32 #include "fpopcode.h"
25*3ebdd119Saurel32 
26*3ebdd119Saurel32 //#include "fpmodule.h"
27*3ebdd119Saurel32 //#include "fpmodule.inl"
28*3ebdd119Saurel32 
29*3ebdd119Saurel32 //#include <asm/system.h>
30*3ebdd119Saurel32 
31*3ebdd119Saurel32 #include <stdio.h>
32*3ebdd119Saurel32 
33*3ebdd119Saurel32 /* forward declarations */
34*3ebdd119Saurel32 unsigned int EmulateCPDO(const unsigned int);
35*3ebdd119Saurel32 unsigned int EmulateCPDT(const unsigned int);
36*3ebdd119Saurel32 unsigned int EmulateCPRT(const unsigned int);
37*3ebdd119Saurel32 
38*3ebdd119Saurel32 FPA11* qemufpa=0;
39*3ebdd119Saurel32 CPUARMState* user_registers;
40*3ebdd119Saurel32 
41*3ebdd119Saurel32 /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
42*3ebdd119Saurel32 void resetFPA11(void)
43*3ebdd119Saurel32 {
44*3ebdd119Saurel32   int i;
45*3ebdd119Saurel32   FPA11 *fpa11 = GET_FPA11();
46*3ebdd119Saurel32 
47*3ebdd119Saurel32   /* initialize the register type array */
48*3ebdd119Saurel32   for (i=0;i<=7;i++)
49*3ebdd119Saurel32   {
50*3ebdd119Saurel32     fpa11->fType[i] = typeNone;
51*3ebdd119Saurel32   }
52*3ebdd119Saurel32 
53*3ebdd119Saurel32   /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
54*3ebdd119Saurel32   fpa11->fpsr = FP_EMULATOR | BIT_AC;
55*3ebdd119Saurel32 
56*3ebdd119Saurel32   /* FPCR: set SB, AB and DA bits, clear all others */
57*3ebdd119Saurel32 #if MAINTAIN_FPCR
58*3ebdd119Saurel32   fpa11->fpcr = MASK_RESET;
59*3ebdd119Saurel32 #endif
60*3ebdd119Saurel32 }
61*3ebdd119Saurel32 
62*3ebdd119Saurel32 void SetRoundingMode(const unsigned int opcode)
63*3ebdd119Saurel32 {
64*3ebdd119Saurel32     int rounding_mode;
65*3ebdd119Saurel32    FPA11 *fpa11 = GET_FPA11();
66*3ebdd119Saurel32 
67*3ebdd119Saurel32 #if MAINTAIN_FPCR
68*3ebdd119Saurel32    fpa11->fpcr &= ~MASK_ROUNDING_MODE;
69*3ebdd119Saurel32 #endif
70*3ebdd119Saurel32    switch (opcode & MASK_ROUNDING_MODE)
71*3ebdd119Saurel32    {
72*3ebdd119Saurel32       default:
73*3ebdd119Saurel32       case ROUND_TO_NEAREST:
74*3ebdd119Saurel32          rounding_mode = float_round_nearest_even;
75*3ebdd119Saurel32 #if MAINTAIN_FPCR
76*3ebdd119Saurel32          fpa11->fpcr |= ROUND_TO_NEAREST;
77*3ebdd119Saurel32 #endif
78*3ebdd119Saurel32       break;
79*3ebdd119Saurel32 
80*3ebdd119Saurel32       case ROUND_TO_PLUS_INFINITY:
81*3ebdd119Saurel32          rounding_mode = float_round_up;
82*3ebdd119Saurel32 #if MAINTAIN_FPCR
83*3ebdd119Saurel32          fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
84*3ebdd119Saurel32 #endif
85*3ebdd119Saurel32       break;
86*3ebdd119Saurel32 
87*3ebdd119Saurel32       case ROUND_TO_MINUS_INFINITY:
88*3ebdd119Saurel32          rounding_mode = float_round_down;
89*3ebdd119Saurel32 #if MAINTAIN_FPCR
90*3ebdd119Saurel32          fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
91*3ebdd119Saurel32 #endif
92*3ebdd119Saurel32       break;
93*3ebdd119Saurel32 
94*3ebdd119Saurel32       case ROUND_TO_ZERO:
95*3ebdd119Saurel32          rounding_mode = float_round_to_zero;
96*3ebdd119Saurel32 #if MAINTAIN_FPCR
97*3ebdd119Saurel32          fpa11->fpcr |= ROUND_TO_ZERO;
98*3ebdd119Saurel32 #endif
99*3ebdd119Saurel32       break;
100*3ebdd119Saurel32   }
101*3ebdd119Saurel32    set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
102*3ebdd119Saurel32 }
103*3ebdd119Saurel32 
104*3ebdd119Saurel32 void SetRoundingPrecision(const unsigned int opcode)
105*3ebdd119Saurel32 {
106*3ebdd119Saurel32     int rounding_precision;
107*3ebdd119Saurel32    FPA11 *fpa11 = GET_FPA11();
108*3ebdd119Saurel32 #if MAINTAIN_FPCR
109*3ebdd119Saurel32    fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
110*3ebdd119Saurel32 #endif
111*3ebdd119Saurel32    switch (opcode & MASK_ROUNDING_PRECISION)
112*3ebdd119Saurel32    {
113*3ebdd119Saurel32       case ROUND_SINGLE:
114*3ebdd119Saurel32          rounding_precision = 32;
115*3ebdd119Saurel32 #if MAINTAIN_FPCR
116*3ebdd119Saurel32          fpa11->fpcr |= ROUND_SINGLE;
117*3ebdd119Saurel32 #endif
118*3ebdd119Saurel32       break;
119*3ebdd119Saurel32 
120*3ebdd119Saurel32       case ROUND_DOUBLE:
121*3ebdd119Saurel32          rounding_precision = 64;
122*3ebdd119Saurel32 #if MAINTAIN_FPCR
123*3ebdd119Saurel32          fpa11->fpcr |= ROUND_DOUBLE;
124*3ebdd119Saurel32 #endif
125*3ebdd119Saurel32       break;
126*3ebdd119Saurel32 
127*3ebdd119Saurel32       case ROUND_EXTENDED:
128*3ebdd119Saurel32          rounding_precision = 80;
129*3ebdd119Saurel32 #if MAINTAIN_FPCR
130*3ebdd119Saurel32          fpa11->fpcr |= ROUND_EXTENDED;
131*3ebdd119Saurel32 #endif
132*3ebdd119Saurel32       break;
133*3ebdd119Saurel32 
134*3ebdd119Saurel32       default: rounding_precision = 80;
135*3ebdd119Saurel32   }
136*3ebdd119Saurel32    set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
137*3ebdd119Saurel32 }
138*3ebdd119Saurel32 
139*3ebdd119Saurel32 /* Emulate the instruction in the opcode. */
140*3ebdd119Saurel32 /* ??? This is not thread safe.  */
141*3ebdd119Saurel32 unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs)
142*3ebdd119Saurel32 {
143*3ebdd119Saurel32   unsigned int nRc = 0;
144*3ebdd119Saurel32 //  unsigned long flags;
145*3ebdd119Saurel32   FPA11 *fpa11;
146*3ebdd119Saurel32 //  save_flags(flags); sti();
147*3ebdd119Saurel32 
148*3ebdd119Saurel32   qemufpa=qfpa;
149*3ebdd119Saurel32   user_registers=qregs;
150*3ebdd119Saurel32 
151*3ebdd119Saurel32 #if 0
152*3ebdd119Saurel32   fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
153*3ebdd119Saurel32           opcode, qregs[REG_PC]);
154*3ebdd119Saurel32 #endif
155*3ebdd119Saurel32   fpa11 = GET_FPA11();
156*3ebdd119Saurel32 
157*3ebdd119Saurel32   if (fpa11->initflag == 0)		/* good place for __builtin_expect */
158*3ebdd119Saurel32   {
159*3ebdd119Saurel32     resetFPA11();
160*3ebdd119Saurel32     SetRoundingMode(ROUND_TO_NEAREST);
161*3ebdd119Saurel32     SetRoundingPrecision(ROUND_EXTENDED);
162*3ebdd119Saurel32     fpa11->initflag = 1;
163*3ebdd119Saurel32   }
164*3ebdd119Saurel32 
165*3ebdd119Saurel32   set_float_exception_flags(0, &fpa11->fp_status);
166*3ebdd119Saurel32 
167*3ebdd119Saurel32   if (TEST_OPCODE(opcode,MASK_CPRT))
168*3ebdd119Saurel32   {
169*3ebdd119Saurel32     //fprintf(stderr,"emulating CPRT\n");
170*3ebdd119Saurel32     /* Emulate conversion opcodes. */
171*3ebdd119Saurel32     /* Emulate register transfer opcodes. */
172*3ebdd119Saurel32     /* Emulate comparison opcodes. */
173*3ebdd119Saurel32     nRc = EmulateCPRT(opcode);
174*3ebdd119Saurel32   }
175*3ebdd119Saurel32   else if (TEST_OPCODE(opcode,MASK_CPDO))
176*3ebdd119Saurel32   {
177*3ebdd119Saurel32     //fprintf(stderr,"emulating CPDO\n");
178*3ebdd119Saurel32     /* Emulate monadic arithmetic opcodes. */
179*3ebdd119Saurel32     /* Emulate dyadic arithmetic opcodes. */
180*3ebdd119Saurel32     nRc = EmulateCPDO(opcode);
181*3ebdd119Saurel32   }
182*3ebdd119Saurel32   else if (TEST_OPCODE(opcode,MASK_CPDT))
183*3ebdd119Saurel32   {
184*3ebdd119Saurel32     //fprintf(stderr,"emulating CPDT\n");
185*3ebdd119Saurel32     /* Emulate load/store opcodes. */
186*3ebdd119Saurel32     /* Emulate load/store multiple opcodes. */
187*3ebdd119Saurel32     nRc = EmulateCPDT(opcode);
188*3ebdd119Saurel32   }
189*3ebdd119Saurel32   else
190*3ebdd119Saurel32   {
191*3ebdd119Saurel32     /* Invalid instruction detected.  Return FALSE. */
192*3ebdd119Saurel32     nRc = 0;
193*3ebdd119Saurel32   }
194*3ebdd119Saurel32 
195*3ebdd119Saurel32 //  restore_flags(flags);
196*3ebdd119Saurel32   if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status))
197*3ebdd119Saurel32   {
198*3ebdd119Saurel32     //printf("fef 0x%x\n",float_exception_flags);
199*3ebdd119Saurel32     nRc=-get_float_exception_flags(&fpa11->fp_status);
200*3ebdd119Saurel32   }
201*3ebdd119Saurel32 
202*3ebdd119Saurel32   //printf("returning %d\n",nRc);
203*3ebdd119Saurel32   return(nRc);
204*3ebdd119Saurel32 }
205*3ebdd119Saurel32 
206*3ebdd119Saurel32 #if 0
207*3ebdd119Saurel32 unsigned int EmulateAll1(unsigned int opcode)
208*3ebdd119Saurel32 {
209*3ebdd119Saurel32   switch ((opcode >> 24) & 0xf)
210*3ebdd119Saurel32   {
211*3ebdd119Saurel32      case 0xc:
212*3ebdd119Saurel32      case 0xd:
213*3ebdd119Saurel32        if ((opcode >> 20) & 0x1)
214*3ebdd119Saurel32        {
215*3ebdd119Saurel32           switch ((opcode >> 8) & 0xf)
216*3ebdd119Saurel32           {
217*3ebdd119Saurel32              case 0x1: return PerformLDF(opcode); break;
218*3ebdd119Saurel32              case 0x2: return PerformLFM(opcode); break;
219*3ebdd119Saurel32              default: return 0;
220*3ebdd119Saurel32           }
221*3ebdd119Saurel32        }
222*3ebdd119Saurel32        else
223*3ebdd119Saurel32        {
224*3ebdd119Saurel32           switch ((opcode >> 8) & 0xf)
225*3ebdd119Saurel32           {
226*3ebdd119Saurel32              case 0x1: return PerformSTF(opcode); break;
227*3ebdd119Saurel32              case 0x2: return PerformSFM(opcode); break;
228*3ebdd119Saurel32              default: return 0;
229*3ebdd119Saurel32           }
230*3ebdd119Saurel32       }
231*3ebdd119Saurel32      break;
232*3ebdd119Saurel32 
233*3ebdd119Saurel32      case 0xe:
234*3ebdd119Saurel32        if (opcode & 0x10)
235*3ebdd119Saurel32          return EmulateCPDO(opcode);
236*3ebdd119Saurel32        else
237*3ebdd119Saurel32          return EmulateCPRT(opcode);
238*3ebdd119Saurel32      break;
239*3ebdd119Saurel32 
240*3ebdd119Saurel32      default: return 0;
241*3ebdd119Saurel32   }
242*3ebdd119Saurel32 }
243*3ebdd119Saurel32 #endif
244*3ebdd119Saurel32 
245