added arm nwfpe support (initial patch by Ulrich Hecht)
[qemu] / target-arm / nwfpe / fpa11.c
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 /* forward declarations */
34 unsigned int EmulateCPDO(const unsigned int);
35 unsigned int EmulateCPDT(const unsigned int);
36 unsigned int EmulateCPRT(const unsigned int);
37
38 FPA11* qemufpa=0;
39 unsigned int* user_registers=0;
40
41 /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
42 void resetFPA11(void)
43 {
44   int i;
45   FPA11 *fpa11 = GET_FPA11();
46   
47   /* initialize the register type array */
48   for (i=0;i<=7;i++)
49   {
50     fpa11->fType[i] = typeNone;
51   }
52   
53   /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
54   fpa11->fpsr = FP_EMULATOR | BIT_AC;
55   
56   /* FPCR: set SB, AB and DA bits, clear all others */
57 #if MAINTAIN_FPCR
58   fpa11->fpcr = MASK_RESET;
59 #endif
60 }
61
62 void SetRoundingMode(const unsigned int opcode)
63 {
64 #if MAINTAIN_FPCR
65    FPA11 *fpa11 = GET_FPA11();
66    fpa11->fpcr &= ~MASK_ROUNDING_MODE;
67 #endif   
68    switch (opcode & MASK_ROUNDING_MODE)
69    {
70       default:
71       case ROUND_TO_NEAREST:
72          float_rounding_mode = float_round_nearest_even;
73 #if MAINTAIN_FPCR         
74          fpa11->fpcr |= ROUND_TO_NEAREST;
75 #endif         
76       break;
77       
78       case ROUND_TO_PLUS_INFINITY:
79          float_rounding_mode = float_round_up;
80 #if MAINTAIN_FPCR         
81          fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
82 #endif         
83       break;
84       
85       case ROUND_TO_MINUS_INFINITY:
86          float_rounding_mode = float_round_down;
87 #if MAINTAIN_FPCR         
88          fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
89 #endif         
90       break;
91       
92       case ROUND_TO_ZERO:
93          float_rounding_mode = float_round_to_zero;
94 #if MAINTAIN_FPCR         
95          fpa11->fpcr |= ROUND_TO_ZERO;
96 #endif         
97       break;
98   }
99 }
100
101 void SetRoundingPrecision(const unsigned int opcode)
102 {
103 #if MAINTAIN_FPCR
104    FPA11 *fpa11 = GET_FPA11();
105    fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
106 #endif   
107    switch (opcode & MASK_ROUNDING_PRECISION)
108    {
109       case ROUND_SINGLE:
110          floatx80_rounding_precision = 32;
111 #if MAINTAIN_FPCR         
112          fpa11->fpcr |= ROUND_SINGLE;
113 #endif         
114       break;
115       
116       case ROUND_DOUBLE:
117          floatx80_rounding_precision = 64;
118 #if MAINTAIN_FPCR         
119          fpa11->fpcr |= ROUND_DOUBLE;
120 #endif         
121       break;
122       
123       case ROUND_EXTENDED:
124          floatx80_rounding_precision = 80;
125 #if MAINTAIN_FPCR         
126          fpa11->fpcr |= ROUND_EXTENDED;
127 #endif         
128       break;
129       
130       default: floatx80_rounding_precision = 80;
131   }
132 }
133
134 /* Emulate the instruction in the opcode. */
135 unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs)
136 {
137   unsigned int nRc = 0;
138 //  unsigned long flags;
139   FPA11 *fpa11; 
140 //  save_flags(flags); sti();
141
142   qemufpa=qfpa;
143   user_registers=qregs;
144   
145 #if 0
146   fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
147           opcode, qregs[REG_PC]);
148 #endif
149   fpa11 = GET_FPA11();
150
151   if (fpa11->initflag == 0)             /* good place for __builtin_expect */
152   {
153     resetFPA11();
154     SetRoundingMode(ROUND_TO_NEAREST);
155     SetRoundingPrecision(ROUND_EXTENDED);
156     fpa11->initflag = 1;
157   }
158
159   if (TEST_OPCODE(opcode,MASK_CPRT))
160   {
161     //fprintf(stderr,"emulating CPRT\n");
162     /* Emulate conversion opcodes. */
163     /* Emulate register transfer opcodes. */
164     /* Emulate comparison opcodes. */
165     nRc = EmulateCPRT(opcode);
166   }
167   else if (TEST_OPCODE(opcode,MASK_CPDO))
168   {
169     //fprintf(stderr,"emulating CPDO\n");
170     /* Emulate monadic arithmetic opcodes. */
171     /* Emulate dyadic arithmetic opcodes. */
172     nRc = EmulateCPDO(opcode);
173   }
174   else if (TEST_OPCODE(opcode,MASK_CPDT))
175   {
176     //fprintf(stderr,"emulating CPDT\n");
177     /* Emulate load/store opcodes. */
178     /* Emulate load/store multiple opcodes. */
179     nRc = EmulateCPDT(opcode);
180   }
181   else
182   {
183     /* Invalid instruction detected.  Return FALSE. */
184     nRc = 0;
185   }
186
187 //  restore_flags(flags);
188
189   //printf("returning %d\n",nRc);
190   return(nRc);
191 }
192
193 #if 0
194 unsigned int EmulateAll1(unsigned int opcode)
195 {
196   switch ((opcode >> 24) & 0xf)
197   {
198      case 0xc:
199      case 0xd:
200        if ((opcode >> 20) & 0x1)
201        {
202           switch ((opcode >> 8) & 0xf)
203           {
204              case 0x1: return PerformLDF(opcode); break;
205              case 0x2: return PerformLFM(opcode); break;
206              default: return 0;
207           }
208        }
209        else
210        {
211           switch ((opcode >> 8) & 0xf)
212           {
213              case 0x1: return PerformSTF(opcode); break;
214              case 0x2: return PerformSFM(opcode); break;
215              default: return 0;
216           }
217       }
218      break;
219      
220      case 0xe: 
221        if (opcode & 0x10)
222          return EmulateCPDO(opcode);
223        else
224          return EmulateCPRT(opcode);
225      break;
226   
227      default: return 0;
228   }
229 }
230 #endif
231