Statistics
| Branch: | Revision:

root / linux-user / arm / nwfpe / fpa11.c @ 70539e18

History | View | Annotate | Download (5.6 kB)

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, see <http://www.gnu.org/licenses/>.
19
*/
20

    
21
#include "fpa11.h"
22

    
23
#include "fpopcode.h"
24

    
25
//#include "fpmodule.h"
26
//#include "fpmodule.inl"
27

    
28
//#include <asm/system.h>
29

    
30
#include <stdio.h>
31

    
32
FPA11* qemufpa = NULL;
33
CPUARMState* user_registers;
34

    
35
/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
36
void resetFPA11(void)
37
{
38
  int i;
39
  FPA11 *fpa11 = GET_FPA11();
40

    
41
  /* initialize the register type array */
42
  for (i=0;i<=7;i++)
43
  {
44
    fpa11->fType[i] = typeNone;
45
  }
46

    
47
  /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
48
  fpa11->fpsr = FP_EMULATOR | BIT_AC;
49

    
50
  /* FPCR: set SB, AB and DA bits, clear all others */
51
#ifdef MAINTAIN_FPCR
52
  fpa11->fpcr = MASK_RESET;
53
#endif
54
}
55

    
56
void SetRoundingMode(const unsigned int opcode)
57
{
58
    int rounding_mode;
59
   FPA11 *fpa11 = GET_FPA11();
60

    
61
#ifdef MAINTAIN_FPCR
62
   fpa11->fpcr &= ~MASK_ROUNDING_MODE;
63
#endif
64
   switch (opcode & MASK_ROUNDING_MODE)
65
   {
66
      default:
67
      case ROUND_TO_NEAREST:
68
         rounding_mode = float_round_nearest_even;
69
#ifdef MAINTAIN_FPCR
70
         fpa11->fpcr |= ROUND_TO_NEAREST;
71
#endif
72
      break;
73

    
74
      case ROUND_TO_PLUS_INFINITY:
75
         rounding_mode = float_round_up;
76
#ifdef MAINTAIN_FPCR
77
         fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
78
#endif
79
      break;
80

    
81
      case ROUND_TO_MINUS_INFINITY:
82
         rounding_mode = float_round_down;
83
#ifdef MAINTAIN_FPCR
84
         fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
85
#endif
86
      break;
87

    
88
      case ROUND_TO_ZERO:
89
         rounding_mode = float_round_to_zero;
90
#ifdef MAINTAIN_FPCR
91
         fpa11->fpcr |= ROUND_TO_ZERO;
92
#endif
93
      break;
94
  }
95
   set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
96
}
97

    
98
void SetRoundingPrecision(const unsigned int opcode)
99
{
100
    int rounding_precision;
101
   FPA11 *fpa11 = GET_FPA11();
102
#ifdef MAINTAIN_FPCR
103
   fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
104
#endif
105
   switch (opcode & MASK_ROUNDING_PRECISION)
106
   {
107
      case ROUND_SINGLE:
108
         rounding_precision = 32;
109
#ifdef MAINTAIN_FPCR
110
         fpa11->fpcr |= ROUND_SINGLE;
111
#endif
112
      break;
113

    
114
      case ROUND_DOUBLE:
115
         rounding_precision = 64;
116
#ifdef MAINTAIN_FPCR
117
         fpa11->fpcr |= ROUND_DOUBLE;
118
#endif
119
      break;
120

    
121
      case ROUND_EXTENDED:
122
         rounding_precision = 80;
123
#ifdef MAINTAIN_FPCR
124
         fpa11->fpcr |= ROUND_EXTENDED;
125
#endif
126
      break;
127

    
128
      default: rounding_precision = 80;
129
  }
130
   set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
131
}
132

    
133
/* Emulate the instruction in the opcode. */
134
/* ??? This is not thread safe.  */
135
unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* 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
  set_float_exception_flags(0, &fpa11->fp_status);
160

    
161
  if (TEST_OPCODE(opcode,MASK_CPRT))
162
  {
163
    //fprintf(stderr,"emulating CPRT\n");
164
    /* Emulate conversion opcodes. */
165
    /* Emulate register transfer opcodes. */
166
    /* Emulate comparison opcodes. */
167
    nRc = EmulateCPRT(opcode);
168
  }
169
  else if (TEST_OPCODE(opcode,MASK_CPDO))
170
  {
171
    //fprintf(stderr,"emulating CPDO\n");
172
    /* Emulate monadic arithmetic opcodes. */
173
    /* Emulate dyadic arithmetic opcodes. */
174
    nRc = EmulateCPDO(opcode);
175
  }
176
  else if (TEST_OPCODE(opcode,MASK_CPDT))
177
  {
178
    //fprintf(stderr,"emulating CPDT\n");
179
    /* Emulate load/store opcodes. */
180
    /* Emulate load/store multiple opcodes. */
181
    nRc = EmulateCPDT(opcode);
182
  }
183
  else
184
  {
185
    /* Invalid instruction detected.  Return FALSE. */
186
    nRc = 0;
187
  }
188

    
189
//  restore_flags(flags);
190
  if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status))
191
  {
192
    //printf("fef 0x%x\n",float_exception_flags);
193
    nRc = -get_float_exception_flags(&fpa11->fp_status);
194
  }
195

    
196
  //printf("returning %d\n",nRc);
197
  return(nRc);
198
}
199

    
200
#if 0
201
unsigned int EmulateAll1(unsigned int opcode)
202
{
203
  switch ((opcode >> 24) & 0xf)
204
  {
205
     case 0xc:
206
     case 0xd:
207
       if ((opcode >> 20) & 0x1)
208
       {
209
          switch ((opcode >> 8) & 0xf)
210
          {
211
             case 0x1: return PerformLDF(opcode); break;
212
             case 0x2: return PerformLFM(opcode); break;
213
             default: return 0;
214
          }
215
       }
216
       else
217
       {
218
          switch ((opcode >> 8) & 0xf)
219
          {
220
             case 0x1: return PerformSTF(opcode); break;
221
             case 0x2: return PerformSFM(opcode); break;
222
             default: return 0;
223
          }
224
      }
225
     break;
226

227
     case 0xe:
228
       if (opcode & 0x10)
229
         return EmulateCPDO(opcode);
230
       else
231
         return EmulateCPRT(opcode);
232
     break;
233

234
     default: return 0;
235
  }
236
}
237
#endif