root/drivers/FPU-emu/load_store.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. load_store_instr

   1 /*---------------------------------------------------------------------------+
   2  |  load_store.c                                                             |
   3  |                                                                           |
   4  | This file contains most of the code to interpret the FPU instructions     |
   5  | which load and store from user memory.                                    |
   6  |                                                                           |
   7  | Copyright (C) 1992,1993,1994                                              |
   8  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   9  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  10  |                                                                           |
  11  |                                                                           |
  12  +---------------------------------------------------------------------------*/
  13 
  14 /*---------------------------------------------------------------------------+
  15  | Note:                                                                     |
  16  |    The file contains code which accesses user memory.                     |
  17  |    Emulator static data may change when user memory is accessed, due to   |
  18  |    other processes using the emulator while swapping is in progress.      |
  19  +---------------------------------------------------------------------------*/
  20 
  21 #include <asm/segment.h>
  22 
  23 #include "fpu_system.h"
  24 #include "exception.h"
  25 #include "fpu_emu.h"
  26 #include "status_w.h"
  27 #include "control_w.h"
  28 
  29 
  30 #define _NONE_ 0   /* st0_ptr etc not needed */
  31 #define _REG0_ 1   /* Will be storing st(0) */
  32 #define _PUSH_ 3   /* Need to check for space to push onto stack */
  33 #define _null_ 4   /* Function illegal or not implemented */
  34 
  35 #define pop_0() { st0_ptr->tag = TW_Empty; top++; }
  36 
  37 
  38 static unsigned char const type_table[32] = {
  39   _PUSH_, _PUSH_, _PUSH_, _PUSH_,
  40   _null_, _null_, _null_, _null_,
  41   _REG0_, _REG0_, _REG0_, _REG0_,
  42   _REG0_, _REG0_, _REG0_, _REG0_,
  43   _NONE_, _null_, _NONE_, _PUSH_,
  44   _NONE_, _PUSH_, _null_, _PUSH_,
  45   _NONE_, _null_, _NONE_, _REG0_,
  46   _NONE_, _REG0_, _NONE_, _REG0_
  47   };
  48 
  49 unsigned char const data_sizes_16[32] = {
  50   4,  4,  8,  2,  0,  0,  0,  0,
  51   4,  4,  8,  2,  4,  4,  8,  2,
  52   14, 0, 94, 10,  2, 10,  0,  8,  
  53   14, 0, 94, 10,  2, 10,  2,  8
  54 };
  55 
  56 unsigned char const data_sizes_32[32] = {
  57   4,  4,  8,  2,  0,  0,  0,  0,
  58   4,  4,  8,  2,  4,  4,  8,  2,
  59   28, 0,108, 10,  2, 10,  0,  8,  
  60   28, 0,108, 10,  2, 10,  2,  8
  61 };
  62 
  63 int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
     /* [previous][next][first][last][top][bottom][index][help] */
  64                      void *data_address)
  65 {
  66   FPU_REG loaded_data;
  67   FPU_REG *st0_ptr;
  68 
  69   st0_ptr = NULL;    /* Initialized just to stop compiler warnings. */
  70 
  71   if ( addr_modes.default_mode & PROTECTED )
  72     {
  73       if ( addr_modes.default_mode == SEG32 )
  74         {
  75           if ( access_limit < data_sizes_32[type] )
  76             math_abort(FPU_info,SIGSEGV);
  77         }
  78       else if ( addr_modes.default_mode == PM16 )
  79         {
  80           if ( access_limit < data_sizes_16[type] )
  81             math_abort(FPU_info,SIGSEGV);
  82         }
  83 #ifdef PARANOID
  84       else
  85         EXCEPTION(EX_INTERNAL|0x140);
  86 #endif PARANOID
  87     }
  88 
  89   switch ( type_table[type] )
  90     {
  91     case _NONE_:
  92       break;
  93     case _REG0_:
  94       st0_ptr = &st(0);       /* Some of these instructions pop after
  95                                  storing */
  96       break;
  97     case _PUSH_:
  98       {
  99         st0_ptr = &st(-1);
 100         if ( st0_ptr->tag != TW_Empty )
 101           { stack_overflow(); return 0; }
 102         top--;
 103       }
 104       break;
 105     case _null_:
 106       FPU_illegal();
 107       return 0;
 108 #ifdef PARANOID
 109     default:
 110       EXCEPTION(EX_INTERNAL|0x141);
 111       return 0;
 112 #endif PARANOID
 113     }
 114 
 115   switch ( type )
 116     {
 117     case 000:       /* fld m32real */
 118       clear_C1();
 119       reg_load_single((float *)data_address, &loaded_data);
 120       if ( (loaded_data.tag == TW_NaN) &&
 121           real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
 122         {
 123           top++;
 124           break;
 125         }
 126       reg_move(&loaded_data, st0_ptr);
 127       break;
 128     case 001:      /* fild m32int */
 129       clear_C1();
 130       reg_load_int32((long *)data_address, st0_ptr);
 131       break;
 132     case 002:      /* fld m64real */
 133       clear_C1();
 134       reg_load_double((double *)data_address, &loaded_data);
 135       if ( (loaded_data.tag == TW_NaN) &&
 136           real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
 137         {
 138           top++;
 139           break;
 140         }
 141       reg_move(&loaded_data, st0_ptr);
 142       break;
 143     case 003:      /* fild m16int */
 144       clear_C1();
 145       reg_load_int16((short *)data_address, st0_ptr);
 146       break;
 147     case 010:      /* fst m32real */
 148       clear_C1();
 149       reg_store_single((float *)data_address, st0_ptr);
 150       break;
 151     case 011:      /* fist m32int */
 152       clear_C1();
 153       reg_store_int32((long *)data_address, st0_ptr);
 154       break;
 155     case 012:     /* fst m64real */
 156       clear_C1();
 157       reg_store_double((double *)data_address, st0_ptr);
 158       break;
 159     case 013:     /* fist m16int */
 160       clear_C1();
 161       reg_store_int16((short *)data_address, st0_ptr);
 162       break;
 163     case 014:     /* fstp m32real */
 164       clear_C1();
 165       if ( reg_store_single((float *)data_address, st0_ptr) )
 166         pop_0();  /* pop only if the number was actually stored
 167                      (see the 80486 manual p16-28) */
 168       break;
 169     case 015:     /* fistp m32int */
 170       clear_C1();
 171       if ( reg_store_int32((long *)data_address, st0_ptr) )
 172         pop_0();  /* pop only if the number was actually stored
 173                      (see the 80486 manual p16-28) */
 174       break;
 175     case 016:     /* fstp m64real */
 176       clear_C1();
 177       if ( reg_store_double((double *)data_address, st0_ptr) )
 178         pop_0();  /* pop only if the number was actually stored
 179                      (see the 80486 manual p16-28) */
 180       break;
 181     case 017:     /* fistp m16int */
 182       clear_C1();
 183       if ( reg_store_int16((short *)data_address, st0_ptr) )
 184         pop_0();  /* pop only if the number was actually stored
 185                      (see the 80486 manual p16-28) */
 186       break;
 187     case 020:     /* fldenv  m14/28byte */
 188       fldenv(addr_modes, (char *)data_address);
 189       /* Ensure that the values just loaded are not changed by
 190          fix-up operations. */
 191       return 1;
 192     case 022:     /* frstor m94/108byte */
 193       frstor(addr_modes, (char *)data_address);
 194       /* Ensure that the values just loaded are not changed by
 195          fix-up operations. */
 196       return 1;
 197     case 023:     /* fbld m80dec */
 198       clear_C1();
 199       reg_load_bcd((char *)data_address, st0_ptr);
 200       break;
 201     case 024:     /* fldcw */
 202       RE_ENTRANT_CHECK_OFF;
 203       FPU_verify_area(VERIFY_READ, data_address, 2);
 204       control_word = get_fs_word((unsigned short *) data_address);
 205       RE_ENTRANT_CHECK_ON;
 206       if ( partial_status & ~control_word & CW_Exceptions )
 207         partial_status |= (SW_Summary | SW_Backward);
 208       else
 209         partial_status &= ~(SW_Summary | SW_Backward);
 210 #ifdef PECULIAR_486
 211       control_word |= 0x40;  /* An 80486 appears to always set this bit */
 212 #endif PECULIAR_486
 213       return 1;
 214     case 025:      /* fld m80real */
 215       clear_C1();
 216       reg_load_extended((long double *)data_address, st0_ptr);
 217       break;
 218     case 027:      /* fild m64int */
 219       clear_C1();
 220       reg_load_int64((long long *)data_address, st0_ptr);
 221       break;
 222     case 030:     /* fstenv  m14/28byte */
 223       fstenv(addr_modes, (char *)data_address);
 224       return 1;
 225     case 032:      /* fsave */
 226       fsave(addr_modes, (char *)data_address);
 227       return 1;
 228     case 033:      /* fbstp m80dec */
 229       clear_C1();
 230       if ( reg_store_bcd((char *)data_address, st0_ptr) )
 231         pop_0();  /* pop only if the number was actually stored
 232                      (see the 80486 manual p16-28) */
 233       break;
 234     case 034:      /* fstcw m16int */
 235       RE_ENTRANT_CHECK_OFF;
 236       FPU_verify_area(VERIFY_WRITE,data_address,2);
 237       put_fs_word(control_word, (short *) data_address);
 238       RE_ENTRANT_CHECK_ON;
 239       return 1;
 240     case 035:      /* fstp m80real */
 241       clear_C1();
 242       if ( reg_store_extended((long double *)data_address, st0_ptr) )
 243         pop_0();  /* pop only if the number was actually stored
 244                      (see the 80486 manual p16-28) */
 245       break;
 246     case 036:      /* fstsw m2byte */
 247       RE_ENTRANT_CHECK_OFF;
 248       FPU_verify_area(VERIFY_WRITE,data_address,2);
 249       put_fs_word(status_word(),(short *) data_address);
 250       RE_ENTRANT_CHECK_ON;
 251       return 1;
 252     case 037:      /* fistp m64int */
 253       clear_C1();
 254       if ( reg_store_int64((long long *)data_address, st0_ptr) )
 255         pop_0();  /* pop only if the number was actually stored
 256                      (see the 80486 manual p16-28) */
 257       break;
 258     }
 259   return 0;
 260 }

/* [previous][next][first][last][top][bottom][index][help] */