load_store.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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