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