]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.18 1.1.18
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:31 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:31 +0000 (15:09 -0500)
41 files changed:
Makefile
drivers/FPU-emu/Makefile
drivers/FPU-emu/README
drivers/FPU-emu/errors.c
drivers/FPU-emu/fpu_arith.c
drivers/FPU-emu/fpu_aux.c
drivers/FPU-emu/fpu_emu.h
drivers/FPU-emu/fpu_entry.c
drivers/FPU-emu/fpu_etc.c
drivers/FPU-emu/fpu_proto.h
drivers/FPU-emu/fpu_system.h
drivers/FPU-emu/fpu_trig.c
drivers/FPU-emu/get_address.c
drivers/FPU-emu/load_store.c
drivers/FPU-emu/poly_atan.c
drivers/FPU-emu/reg_compare.c
drivers/FPU-emu/reg_constant.c
drivers/FPU-emu/reg_div.S
drivers/FPU-emu/reg_ld_str.c
drivers/FPU-emu/reg_round.S
drivers/FPU-emu/reg_u_div.S
drivers/FPU-emu/reg_u_mul.S
drivers/FPU-emu/version.h
drivers/FPU-emu/wm_sqrt.S
drivers/block/README.sbpcd
drivers/block/blk.h
drivers/block/ll_rw_blk.c
drivers/block/sbpcd.c
drivers/net/Space.c
drivers/net/ppp.c
drivers/scsi/buslogic.c
fs/buffer.c
include/linux/sbpcd.h
kernel/Makefile
kernel/sched.c
kernel/time.c
mm/memory.c
net/inet/af_inet.c
net/inet/arp.c
net/inet/dev.c
net/inet/ip.c

index 094edc39cadbc9f5a182438c58d894d3d70758f6..d5c87f4ecba1fdfc9f4d6522b974fd1737adf265 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 17
+SUBLEVEL = 18
 
 all:   Version zImage
 
index 3563c1d4b9681c4e667a0eaeb2158cdc5feb05b8..544c357cec6248751a1a8a3d1082d21e42d80759 100644 (file)
@@ -5,14 +5,13 @@
 #DEBUG = -DDEBUGGING
 DEBUG  =
 PARANOID = -DPARANOID
-REENTRANT      = -DREENTRANT_FPU
 CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
 
 .c.o:
        $(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
 
 .S.o:
-       $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
+       $(CC) -D__ASSEMBLER__ $(PARANOID) -c $<
 
 .s.o:
        $(CC) -c $<
index efe0367528c1e4edcfc0fc752c7ab64da43cb049..032f8d1d52ce0dd77a96f6c5ca3bada256cf16f8 100644 (file)
@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
 
 
 --Bill Metzenthen
-  March 1994
+  June 1994
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -80,20 +80,24 @@ emulate each FPU instruction to completion without interruption.
 However, it may happen that when the emulator is accessing the user
 memory space, swapping may be needed. In this case the emulator may be
 temporarily suspended while disk i/o takes place. During this time
-another process may use the emulator, thereby changing some static
-variables (eg FPU_st0_ptr, etc). The code which accesses user memory
-is confined to five files:
+another process may use the emulator, thereby perhaps changing static
+variables. The code which accesses user memory is confined to five
+files:
     fpu_entry.c
     reg_ld_str.c
     load_store.c
     get_address.c
     errors.c
+As from version 1.12 of the emulator, no static variables are used
+(apart from those in the kernel's per-process tables). The emulator is
+therefore now fully re-entrant, rather than having just the restricted
+form of re-entrancy which is required by the Linux kernel.
 
 ----------------------- Limitations of wm-FPU-emu -----------------------
 
 There are a number of differences between the current wm-FPU-emu
-(version beta 1.11) and the 80486 FPU (apart from bugs). Some of the
-more important differences are listed below:
+(version 1.12) and the 80486 FPU (apart from bugs). Some of the more
+important differences are listed below:
 
 The Roundup flag does not have much meaning for the transcendental
 functions and its 80486 value with these functions is likely to differ
@@ -154,6 +158,11 @@ crashes dosemu under Linux and also brings Windows down with a general
 protection fault message when run under the MS-DOS prompt of Windows
 3.1. (The program simply reads data from a valid address).
 
+The emulator supports 16-bit protected mode, with one difference from
+an 80486DX.  A 80486DX will allow some floating point instructions to
+write a few bytes below the lowest address of the stack.  The emulator
+will not allow this in 16-bit protected mode: no instructions are
+allowed to write outside the bounds set by the protection.
 
 ----------------------- Performance of wm-FPU-emu -----------------------
 
@@ -322,6 +331,7 @@ Hamish Coleman, t933093@minyos.xx.rmit.oz.au
 Bruce Evans, bde@kralizec.zeta.org.au
 Timo Korvola, Timo.Korvola@hut.fi
 Rick Lyons, rick@razorback.brisnet.org.au
+Rick, jrs@world.std.com
  
 ...and numerous others who responded to my request for help with
 a real 80486.
index f8f9554bc67c86e810bfc115ad41873334026228..ddc589a952a23487354a9b7b82f46cc24c88e815 100644 (file)
@@ -42,20 +42,28 @@ void Un_impl(void)
   RE_ENTRANT_CHECK_OFF;
   /* No need to verify_area(), we have previously fetched these bytes. */
   printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
-  while ( 1 )
+  if ( FPU_CS == USER_CS )
     {
-      byte1 = get_fs_byte((unsigned char *) address);
-      if ( (byte1 & 0xf8) == 0xd8 ) break;
-      printk("[%02x]", byte1);
-      address++;
+      while ( 1 )
+       {
+         byte1 = get_fs_byte((unsigned char *) address);
+         if ( (byte1 & 0xf8) == 0xd8 ) break;
+         printk("[%02x]", byte1);
+         address++;
+       }
+      printk("%02x ", byte1);
+      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+      
+      if (FPU_modrm >= 0300)
+       printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+      else
+       printk("/%d\n", (FPU_modrm >> 3) & 7);
     }
-  printk("%02x ", byte1);
-  FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
-
-  if (FPU_modrm >= 0300)
-    printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
   else
-    printk("/%d\n", (FPU_modrm >> 3) & 7);
+    {
+      printk("cs selector = %04x\n", FPU_CS);
+    }
+
   RE_ENTRANT_CHECK_ON;
 
   EXCEPTION(EX_Invalid);
@@ -85,29 +93,36 @@ void emu_printall()
   RE_ENTRANT_CHECK_OFF;
   /* No need to verify_area(), we have previously fetched these bytes. */
   printk("At %p:", (void *) address);
-#define MAX_PRINTED_BYTES 20
-  for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
+  if ( FPU_CS == USER_CS )
     {
-      byte1 = get_fs_byte((unsigned char *) address);
-      if ( (byte1 & 0xf8) == 0xd8 )
+#define MAX_PRINTED_BYTES 20
+      for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
        {
-         printk(" %02x", byte1);
-         break;
+         byte1 = get_fs_byte((unsigned char *) address);
+         if ( (byte1 & 0xf8) == 0xd8 )
+           {
+             printk(" %02x", byte1);
+             break;
+           }
+         printk(" [%02x]", byte1);
+         address++;
+       }
+      if ( i == MAX_PRINTED_BYTES )
+       printk(" [more..]\n");
+      else
+       {
+         FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+         
+         if (FPU_modrm >= 0300)
+           printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+         else
+           printk(" /%d, mod=%d rm=%d\n",
+                  (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
        }
-      printk(" [%02x]", byte1);
-      address++;
     }
-  if ( i == MAX_PRINTED_BYTES )
-    printk(" [more..]\n");
   else
     {
-      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
-
-      if (FPU_modrm >= 0300)
-       printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
-      else
-       printk(" /%d, mod=%d rm=%d\n",
-              (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+      printk("%04x\n", FPU_CS);
     }
 
   partial_status = status_word();
@@ -181,6 +196,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
       printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
     }
 
+#ifdef OBSOLETE
   printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
         FPU_loaded_data.sign ? '-' : '+',
         (long)(FPU_loaded_data.sigh >> 16),
@@ -189,6 +205,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
         (long)(FPU_loaded_data.sigl & 0xFFFF),
         FPU_loaded_data.exp - EXP_BIAS + 1);
   printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
+#endif OBSOLETE
   RE_ENTRANT_CHECK_ON;
 
 }
@@ -214,7 +231,6 @@ static struct {
  error was detected.
 
  Internal error types:
-       0      in load_store.c
        0x14   in fpu_etc.c
        0x1nn  in a *.c file:
               0x101  in reg_add_sub.c
@@ -244,7 +260,13 @@ static struct {
              0x126  in fpu_entry.c
              0x127  in poly_2xm1.c
              0x128  in fpu_entry.c
+             0x129  in fpu_entry.c
              0x130  in get_address.c
+             0x131  in get_address.c
+             0x132  in get_address.c
+             0x133  in get_address.c
+             0x140  in load_store.c
+             0x141  in load_store.c
        0x2nn  in an *.S file:
               0x201  in reg_u_add.S
               0x202  in reg_u_div.S
@@ -583,7 +605,7 @@ void stack_overflow(void)
     {
       /* The masked response */
       top--;
-      reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
+      reg_move(&CONST_QNaN, &st(0));
     }
 
   EXCEPTION(EX_StackOver);
@@ -599,7 +621,7 @@ void stack_underflow(void)
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, FPU_st0_ptr);
+      reg_move(&CONST_QNaN, &st(0));
     }
 
   EXCEPTION(EX_StackUnder);
index 3871a56a7243b49030d0332af6b3566667c7933b..96e6bd89ba6fece43cb78af05a18fefa302e4aad 100644 (file)
@@ -20,7 +20,7 @@ void fadd__()
 {
   /* fadd st,st(i) */
   clear_C1();
-  reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_add(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -28,7 +28,7 @@ void fmul__()
 {
   /* fmul st,st(i) */
   clear_C1();
-  reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_mul(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -37,7 +37,7 @@ void fsub__()
 {
   /* fsub st,st(i) */
   clear_C1();
-  reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_sub(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -45,7 +45,7 @@ void fsubr_()
 {
   /* fsubr st,st(i) */
   clear_C1();
-  reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+  reg_sub(&st(FPU_rm), &st(0), &st(0), control_word);
 }
 
 
@@ -53,7 +53,7 @@ void fdiv__()
 {
   /* fdiv st,st(i) */
   clear_C1();
-  reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+  reg_div(&st(0), &st(FPU_rm), &st(0), control_word);
 }
 
 
@@ -61,7 +61,7 @@ void fdivr_()
 {
   /* fdivr st,st(i) */
   clear_C1();
-  reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+  reg_div(&st(FPU_rm), &st(0), &st(0), control_word);
 }
 
 
@@ -70,7 +70,7 @@ void fadd_i()
 {
   /* fadd st(i),st */
   clear_C1();
-  reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -78,7 +78,7 @@ void fmul_i()
 {
   /* fmul st(i),st */
   clear_C1();
-  reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -86,9 +86,9 @@ void fsubri()
 {
   /* fsubr st(i),st */
   /* This is the sense of the 80486 manual
-     reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
+     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -96,9 +96,9 @@ void fsub_i()
 {
   /* fsub st(i),st */
   /* This is the sense of the 80486 manual
-     reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
+     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+  reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
 }
 
 
@@ -106,7 +106,7 @@ void fdivri()
 {
   /* fdivr st(i),st */
   clear_C1();
-  reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+  reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word);
 }
 
 
@@ -114,7 +114,7 @@ void fdiv_i()
 {
   /* fdiv st(i),st */
   clear_C1();
-  reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+  reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word);
 }
 
 
@@ -123,7 +123,7 @@ void faddp_()
 {
   /* faddp st(i),st */
   clear_C1();
-  if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -132,7 +132,7 @@ void fmulp_()
 {
   /* fmulp st(i),st */
   clear_C1();
-  if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -142,9 +142,9 @@ void fsubrp()
 {
   /* fsubrp st(i),st */
   /* This is the sense of the 80486 manual
-     reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */
+     reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -153,9 +153,9 @@ void fsubp_()
 {
   /* fsubp st(i),st */
   /* This is the sense of the 80486 manual
-     reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */
+     reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */
   clear_C1();
-  if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
+  if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -164,7 +164,7 @@ void fdivrp()
 {
   /* fdivrp st(i),st */
   clear_C1();
-  if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) )
+  if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) )
     pop();
 }
 
@@ -173,7 +173,7 @@ void fdivp_()
 {
   /* fdivp st(i),st */
   clear_C1();
-  if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) )
+  if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) )
     pop();
 }
 
index d9f3a22085012cf9f226acf3f9f607900bff7b1d..0d35fe19b706227228f23f849f38a2b7dab46e35 100644 (file)
@@ -26,8 +26,7 @@ void fclex(void)
   partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
                   SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
                   SW_Invalid);
-  NO_NET_DATA_EFFECT;
-  FPU_entry_eip = ip_offset;               /* We want no net effect */
+  no_ip_update = 1;
 }
 
 /* Needs to be externally visible */
@@ -43,11 +42,12 @@ void finit()
     }
   /* The behaviour is different to that detailed in
      Section 15.1.6 of the Intel manual */
-  data_operand_offset = 0;
-  operand_selector = 0;
-  NO_NET_DATA_EFFECT;
-  FPU_entry_op_cs = 0;
-  FPU_entry_eip = ip_offset = 0;
+  operand_address.offset = 0;
+  operand_address.selector = 0;
+  instruction_address.offset = 0;
+  instruction_address.selector = 0;
+  instruction_address.opcode = 0;
+  no_ip_update = 1;
 }
 
 /*
@@ -71,7 +71,7 @@ void finit_()
 static void fstsw_ax(void)
 {
   *(short *) &FPU_EAX = status_word();
-  NO_NET_INSTR_EFFECT;
+  no_ip_update = 1;
 }
 
 static FUNC const fstsw_table[] = {
@@ -108,10 +108,9 @@ void fld_i_()
     { reg_move(&st(FPU_rm), st_new_ptr); push(); }
   else
     {
-      if ( control_word & EX_Invalid )
+      if ( control_word & CW_Invalid )
        {
          /* The masked response */
-         push();
          stack_underflow();
        }
       else
@@ -125,9 +124,9 @@ void fxch_i()
 {
   /* fxch st(i) */
   FPU_REG t;
-  register FPU_REG *sti_ptr = &st(FPU_rm);
+  register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0);
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_ptr->tag == TW_Empty )
     {
       if ( sti_ptr->tag == TW_Empty )
        {
@@ -136,20 +135,20 @@ void fxch_i()
          return;
        }
       if ( control_word & CW_Invalid )
-       reg_move(sti_ptr, FPU_st0_ptr);   /* Masked response */
+       reg_move(sti_ptr, st0_ptr);   /* Masked response */
       stack_underflow_i(FPU_rm);
       return;
     }
   if ( sti_ptr->tag == TW_Empty )
     {
       if ( control_word & CW_Invalid )
-       reg_move(FPU_st0_ptr, sti_ptr);   /* Masked response */
+       reg_move(st0_ptr, sti_ptr);   /* Masked response */
       stack_underflow();
       return;
     }
   clear_C1();
-  reg_move(FPU_st0_ptr, &t);
-  reg_move(sti_ptr, FPU_st0_ptr);
+  reg_move(st0_ptr, &t);
+  reg_move(sti_ptr, st0_ptr);
   reg_move(&t, sti_ptr);
 }
 
@@ -172,14 +171,14 @@ void ffreep()
 void fst_i_()
 {
   /* fst st(i) */
-  reg_move(FPU_st0_ptr, &st(FPU_rm));
+  reg_move(&st(0), &st(FPU_rm));
 }
 
 
 void fstp_i()
 {
   /* fstp st(i) */
-  reg_move(FPU_st0_ptr, &st(FPU_rm));
+  reg_move(&st(0), &st(FPU_rm));
   pop();
 }
 
index f4921c5b284dbb7336a78d813c89d108bc6a54bc..a0d1387d521dd00b950852fde54092cd192957dc 100644 (file)
 #include <linux/math_emu.h>
 #include <linux/linkage.h>
 
-#ifdef PARANOID
+/*
+#define RE_ENTRANT_CHECKING
+ */
+
+#ifdef RE_ENTRANT_CHECKING
 extern char emulating;
 #  define RE_ENTRANT_CHECK_OFF emulating = 0
 #  define RE_ENTRANT_CHECK_ON emulating = 1
 #else
 #  define RE_ENTRANT_CHECK_OFF
 #  define RE_ENTRANT_CHECK_ON
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
 #define FWAIT_OPCODE 0x9b
 #define OP_SIZE_PREFIX 0x66
@@ -89,46 +93,43 @@ extern char emulating;
 #define PREFIX_SS_ 6
 #define PREFIX_DEFAULT 7
 
-/* These are to defeat the default action, giving the instruction
-   no net effect: */
-#define NO_NET_DATA_EFFECT \
-      { FPU_data_address = (void *)data_operand_offset; \
-       FPU_data_selector = operand_selector; }
-#define NO_NET_INSTR_EFFECT \
-      { FPU_entry_eip = ip_offset; \
-       FPU_entry_op_cs = cs_selector; }
-
-
+struct address {
+  unsigned int offset;
+  unsigned int selector:16;
+  unsigned int opcode:11;
+  unsigned int empty:5;
+};
 typedef void (*FUNC)(void);
 typedef struct fpu_reg FPU_REG;
+typedef void (*FUNC_ST0)(FPU_REG *st0_ptr);
 typedef struct { unsigned char address_size, operand_size, segment; }
         overrides;
-/* This structure is 48 bits: */
+/* This structure is 32 bits: */
 typedef struct { overrides override;
-                unsigned char mode16, vm86, p286; } fpu_addr_modes;
+                unsigned char default_mode; } fpu_addr_modes;
+/* PROTECTED has a restricted meaning in the emulator; it is used
+   to signal that the emulator needs to do special things to ensure
+   that protection is respected in a segmented model. */
+#define PROTECTED 4
+#define SIXTEEN   1         /* We rely upon this being 1 (true) */
+#define VM86      SIXTEEN
+#define PM16      (SIXTEEN | PROTECTED)
+#define SEG32     PROTECTED
+extern unsigned char const data_sizes_16[32];
 
 #define        st(x)   ( regs[((top+x) &7 )] )
 
 #define        STACK_OVERFLOW  (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
 #define        NOT_EMPTY(i)    (st(i).tag != TW_Empty)
-#define        NOT_EMPTY_0     (FPU_st0_tag ^ TW_Empty)
-
-extern unsigned char FPU_rm;
-
-extern char    FPU_st0_tag;
-extern FPU_REG *FPU_st0_ptr;
-
-/* ###### These need to be shifted to somewhere safe. */
-/* extern void  *FPU_data_address; has been shifted */
-extern unsigned short FPU_data_selector;
-extern unsigned long FPU_entry_op_cs;
-
-extern  FPU_REG  FPU_loaded_data;
+#define        NOT_EMPTY_ST0   (st0_tag ^ TW_Empty)
 
-#define pop()  { FPU_st0_ptr->tag = TW_Empty; top++; }
+#define pop()  { regs[(top++ & 7 )].tag = TW_Empty; }
+#define poppop() { regs[((top + 1) & 7 )].tag \
+                    = regs[(top & 7 )].tag = TW_Empty; \
+                  top += 2; }
 
 /* push() does not affect the tags */
-#define push() { top--; FPU_st0_ptr = st_new_ptr; }
+#define push() { top--; }
 
 
 #define reg_move(x, y) { \
index f68b13936f3fc94c9dbdf104ca5737501566a2e6..994733133efa00236a07b1e83feb3e3d09f9eb48 100644 (file)
@@ -122,39 +122,36 @@ static unsigned char const type_table[64] = {
 #endif NO_UNDOC_CODE
 
 
-/* Be careful when using any of these global variables...
-   they might change if swapping is triggered */
-unsigned char  FPU_rm;
-char          FPU_st0_tag;
-FPU_REG       *FPU_st0_ptr;
-
-/* ######## To be shifted */
-unsigned long FPU_entry_op_cs;
-unsigned short FPU_data_selector;
-
-
-#ifdef PARANOID
+#ifdef RE_ENTRANT_CHECKING
 char emulating=0;
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
                        overrides *override);
 
-
 asmlinkage void math_emulate(long arg)
 {
   unsigned char  FPU_modrm, byte1;
   unsigned short code;
   fpu_addr_modes addr_modes;
   int unmasked;
-
-#ifdef PARANOID
+  FPU_REG loaded_data;
+  void *data_address;
+  struct address data_sel_off;
+  struct address entry_sel_off;
+  unsigned long code_base = 0;
+  unsigned long code_limit = 0;  /* Initialized to stop compiler warnings */
+  char        st0_tag;
+  FPU_REG      *st0_ptr;
+  struct desc_struct code_descriptor;
+
+#ifdef RE_ENTRANT_CHECKING
   if ( emulating )
     {
       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
     }
   RE_ENTRANT_CHECK_ON;
-#endif PARANOID
+#endif RE_ENTRANT_CHECKING
 
   if (!current->used_math)
     {
@@ -172,34 +169,51 @@ asmlinkage void math_emulate(long arg)
 
   SETUP_DATA_AREA(arg);
 
-  addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
-  addr_modes.p286 = (!addr_modes.vm86
-                    && current->ldt
-                    && (current->ldt[FPU_CS >> 3].b & 0xf000) == 0xf000
-                    && (current->ldt[FPU_CS >> 3].b & (1 << 22)) == 0);
-  addr_modes.mode16 = addr_modes.vm86 | addr_modes.p286;
-
-  if ( addr_modes.vm86 )
-    FPU_EIP += FPU_CS << 4;
-  else if ( addr_modes.p286 )
-    FPU_EIP += LDT_BASE_ADDR(FPU_CS);
-
   FPU_ORIG_EIP = FPU_EIP;
 
-  if ( !addr_modes.mode16 )
+  if ( (FPU_EFLAGS & 0x00020000) != 0 )
+    {
+      /* Virtual 8086 mode */
+      addr_modes.default_mode = VM86;
+      FPU_EIP += code_base = FPU_CS << 4;
+      code_limit = code_base + 0xffff;  /* Assumes code_base <= 0xffff0000 */
+    }
+  else if ( FPU_CS == USER_CS && FPU_DS == USER_DS )
+    {
+      addr_modes.default_mode = 0;
+    }
+  else if ( FPU_CS == KERNEL_CS )
+    {
+      printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
+      panic("Math emulation needed in kernel");
+    }
+  else
     {
-      /* user code space? */
-      if (FPU_CS == KERNEL_CS)
+
+      if ( (FPU_CS & 4) != 4 )   /* Must be in the LDT */
        {
-         printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
-         panic("Math emulation needed in kernel");
+         /* Can only handle segmented addressing via the LDT
+            for now, and it must be 16 bit */
+         printk("FPU emulator: Unsupported addressing mode\n");
+         math_abort(FPU_info, SIGILL);
        }
 
-      /* We cannot handle multiple segments yet */
-      if (FPU_CS != USER_CS || FPU_DS != USER_DS)
+      if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
+       {
+         /* The above test may be wrong, the book is not clear */
+         /* Segmented 32 bit protected mode */
+         addr_modes.default_mode = SEG32;
+       }
+      else
        {
-         math_abort(FPU_info,SIGILL);
+         /* 16 bit protected mode */
+         addr_modes.default_mode = PM16;
        }
+      FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
+      code_limit = code_base
+       + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
+         - 1;
+      if ( code_limit < code_base ) code_limit = 0xffffffff;
     }
 
   FPU_lookahead = 1;
@@ -220,14 +234,17 @@ asmlinkage void math_emulate(long arg)
 
 do_another_FPU_instruction:
 
+  no_ip_update = 0;
+
   FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
 
-#ifdef PECULIAR_486
-  /* It would be more logical to do this only in get_address(),
-     but although it is supposed to be undefined for many fpu
-     instructions, an 80486 behaves as if this were done here: */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
+  if ( addr_modes.default_mode )
+    {
+      /* This checks for the minimum instruction bytes.
+        We also need to check any extra (address mode) code access. */
+      if ( FPU_EIP > code_limit )
+       math_abort(FPU_info,SIGSEGV);
+    }
 
   if ( (byte1 & 0xf8) != 0xd8 )
     {
@@ -273,9 +290,8 @@ do_another_FPU_instruction:
           *  via the cs selector and operand selector, so we do the same.
           */
        do_the_FPU_interrupt:
-         cs_selector &= 0xffff0000;
-         cs_selector |= status_word();
-         operand_selector = tag_word();
+         instruction_address.selector = status_word();
+         operand_address.selector = tag_word();
          partial_status = 0;
          top = 0;
          {
@@ -288,11 +304,6 @@ do_another_FPU_instruction:
 
          FPU_EIP = FPU_ORIG_EIP;       /* Point to current FPU instruction. */
 
-         if ( addr_modes.vm86 )
-           FPU_EIP -= FPU_CS << 4;
-         else if ( addr_modes.p286 )
-           FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
-
          RE_ENTRANT_CHECK_OFF;
          current->tss.trap_no = 16;
          current->tss.error_code = 0;
@@ -301,57 +312,74 @@ do_another_FPU_instruction:
        }
     }
 
-  FPU_entry_eip = FPU_ORIG_EIP;
-
-  FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
+  entry_sel_off.offset = FPU_ORIG_EIP;
+  entry_sel_off.selector = FPU_CS;
+  entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
 
   FPU_rm = FPU_modrm & 7;
 
   if ( FPU_modrm < 0300 )
     {
       /* All of these instructions use the mod/rm byte to get a data address */
-      if ( addr_modes.vm86
+
+      if ( (addr_modes.default_mode & SIXTEEN)
          ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
-       get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
+       data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
+                                     addr_modes);
       else
-       get_address(FPU_modrm, &FPU_EIP, addr_modes);
+       data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
+                                  addr_modes);
+
+      if ( addr_modes.default_mode )
+       {
+         if ( FPU_EIP-1 > code_limit )
+           math_abort(FPU_info,SIGSEGV);
+       }
 
       if ( !(byte1 & 1) )
        {
          unsigned short status1 = partial_status;
-         FPU_st0_ptr = &st(0);
-         FPU_st0_tag = FPU_st0_ptr->tag;
+
+         st0_ptr = &st(0);
+         st0_tag = st0_ptr->tag;
 
          /* Stack underflow has priority */
-         if ( NOT_EMPTY_0 )
+         if ( NOT_EMPTY_ST0 )
            {
+             if ( addr_modes.default_mode & PROTECTED )
+               {
+                 /* This table works for 16 and 32 bit protected mode */
+                 if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
+                   math_abort(FPU_info,SIGSEGV);
+               }
+
              unmasked = 0;  /* Do this here to stop compiler warnings. */
              switch ( (byte1 >> 1) & 3 )
                {
                case 0:
-                 unmasked = reg_load_single();
+                 unmasked = reg_load_single((float *)data_address,
+                                            &loaded_data);
                  break;
                case 1:
-                 reg_load_int32();
+                 reg_load_int32((long *)data_address, &loaded_data);
                  break;
                case 2:
-                 unmasked = reg_load_double();
+                 unmasked = reg_load_double((double *)data_address,
+                                            &loaded_data);
                  break;
                case 3:
-                 reg_load_int16();
+                 reg_load_int16((short *)data_address, &loaded_data);
                  break;
                }
              
              /* No more access to user memory, it is safe
                 to use static data now */
-             FPU_st0_ptr = &st(0);
-             FPU_st0_tag = FPU_st0_ptr->tag;
 
              /* NaN operands have the next priority. */
              /* We have to delay looking at st(0) until after
                 loading the data, because that data might contain an SNaN */
-             if ( (FPU_st0_tag == TW_NaN) ||
-                 (FPU_loaded_data.tag == TW_NaN) )
+             if ( (st0_tag == TW_NaN) ||
+                 (loaded_data.tag == TW_NaN) )
                {
                  /* Restore the status word; we might have loaded a
                     denormal. */
@@ -371,13 +399,13 @@ do_another_FPU_instruction:
                         identical to an 80486 */
                      if ( (FPU_modrm & 0x28) == 0x20 )
                        /* fdiv or fsub */
-                       real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
-                                    FPU_st0_ptr);
+                       real_2op_NaN(&loaded_data, st0_ptr,
+                                    st0_ptr);
                      else
 #endif PECULIAR_486
                        /* fadd, fdivr, fmul, or fsubr */
-                       real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
-                                    FPU_st0_ptr);
+                       real_2op_NaN(st0_ptr, &loaded_data,
+                                    st0_ptr);
                    }
                  goto reg_mem_instr_done;
                }
@@ -388,11 +416,11 @@ do_another_FPU_instruction:
                  if ( (FPU_modrm & 0x38) == 0x38 )
                    {
                      /* fdivr */
-                     if ( (FPU_st0_tag == TW_Zero) &&
-                         (FPU_loaded_data.tag == TW_Valid) )
+                     if ( (st0_tag == TW_Zero) &&
+                         (loaded_data.tag == TW_Valid) )
                        {
-                         if ( divide_by_zero(FPU_loaded_data.sign,
-                                             FPU_st0_ptr) )
+                         if ( divide_by_zero(loaded_data.sign,
+                                             st0_ptr) )
                            {
                              /* We use the fact here that the unmasked
                                 exception in the loaded data was for a
@@ -410,42 +438,42 @@ do_another_FPU_instruction:
                {
                case 0:         /* fadd */
                  clear_C1();
-                 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+                 reg_add(st0_ptr, &loaded_data, st0_ptr,
                          control_word);
                  break;
                case 1:         /* fmul */
                  clear_C1();
-                 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+                 reg_mul(st0_ptr, &loaded_data, st0_ptr,
                          control_word);
                  break;
                case 2:         /* fcom */
-                 compare_st_data();
+                 compare_st_data(&loaded_data);
                  break;
                case 3:         /* fcomp */
-                 if ( !compare_st_data() && !unmasked )
+                 if ( !compare_st_data(&loaded_data) && !unmasked )
                    pop();
                  break;
                case 4:         /* fsub */
                  clear_C1();
-                 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+                 reg_sub(st0_ptr, &loaded_data, st0_ptr,
                          control_word);
                  break;
                case 5:         /* fsubr */
                  clear_C1();
-                 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
+                 reg_sub(&loaded_data, st0_ptr, st0_ptr,
                          control_word);
                  break;
                case 6:         /* fdiv */
                  clear_C1();
-                 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
+                 reg_div(st0_ptr, &loaded_data, st0_ptr,
                          control_word);
                  break;
                case 7:         /* fdivr */
                  clear_C1();
-                 if ( FPU_st0_tag == TW_Zero )
+                 if ( st0_tag == TW_Zero )
                    partial_status = status1;  /* Undo any denorm tag,
                                               zero-divide has priority. */
-                 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
+                 reg_div(&loaded_data, st0_ptr, st0_ptr,
                          control_word);
                  break;
                }
@@ -463,19 +491,19 @@ do_another_FPU_instruction:
              else
                stack_underflow();
            }
+       reg_mem_instr_done:
+         operand_address = data_sel_off;
        }
       else
        {
-         load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
-                          addr_modes);
+         if ( !(no_ip_update =
+                load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+                                 addr_modes, data_address)) )
+           {
+             operand_address = data_sel_off;
+           }
        }
 
-    reg_mem_instr_done:
-
-#ifndef PECULIAR_486
-      *(unsigned short *)&operand_selector = FPU_data_selector;
-#endif PECULIAR_486
-      ;
     }
   else
     {
@@ -485,38 +513,39 @@ do_another_FPU_instruction:
 #ifdef PECULIAR_486
       /* This is supposed to be undefined, but a real 80486 seems
         to do this: */
-      FPU_data_address = 0;
+      operand_address.offset = 0;
+      operand_address.selector = FPU_DS;
 #endif PECULIAR_486
 
-      FPU_st0_ptr = &st(0);
-      FPU_st0_tag = FPU_st0_ptr->tag;
+      st0_ptr = &st(0);
+      st0_tag = st0_ptr->tag;
       switch ( type_table[(int) instr_index] )
        {
        case _NONE_:   /* also _REGIc: _REGIn */
          break;
        case _REG0_:
-         if ( !NOT_EMPTY_0 )
+         if ( !NOT_EMPTY_ST0 )
            {
              stack_underflow();
              goto FPU_instruction_done;
            }
          break;
        case _REGIi:
-         if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+         if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
            {
              stack_underflow_i(FPU_rm);
              goto FPU_instruction_done;
            }
          break;
        case _REGIp:
-         if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+         if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
            {
              stack_underflow_pop(FPU_rm);
              goto FPU_instruction_done;
            }
          break;
        case _REGI_:
-         if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
+         if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
            {
              stack_underflow();
              goto FPU_instruction_done;
@@ -532,17 +561,14 @@ do_another_FPU_instruction:
          goto FPU_instruction_done;
        }
       (*st_instr_table[(int) instr_index])();
-    }
 
 FPU_instruction_done:
+      ;
+    }
+
+  if ( ! no_ip_update )
+    instruction_address = entry_sel_off;
 
-  ip_offset = FPU_entry_eip;
-  cs_selector = FPU_entry_op_cs;
-  data_operand_offset = (unsigned long)FPU_data_address;
-#ifdef PECULIAR_486
-  *(unsigned short *)&operand_selector = FPU_data_selector;
-#endif PECULIAR_486
-  
 FPU_fwait_done:
 
 #ifdef DEBUG
@@ -553,16 +579,14 @@ FPU_fwait_done:
 
   if (FPU_lookahead && !need_resched)
     {
-      FPU_ORIG_EIP = FPU_EIP;
+      FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
                        &addr_modes.override) )
        goto do_another_FPU_instruction;
     }
 
-  if ( addr_modes.vm86 )
-    FPU_EIP -= FPU_CS << 4;
-  else if ( addr_modes.p286 )
-    FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
+  if ( addr_modes.default_mode )
+    FPU_EIP -= code_base;
 
   RE_ENTRANT_CHECK_OFF;
 }
index b7e1154cbd3e49a5cf5ff9d0c294a87de1b73dd5..c1e113a7f6fc65d7dab869a4dd6cde92d056a486 100644 (file)
 #include "reg_constant.h"
 
 
-static void fchs(void)
+static void fchs(FPU_REG *st0_ptr)
 {
-  if ( NOT_EMPTY_0 )
+  if ( st0_ptr->tag ^ TW_Empty )
     {
-      FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
+      st0_ptr->sign ^= SIGN_POS^SIGN_NEG;
       clear_C1();
     }
   else
     stack_underflow();
 }
 
-static void fabs(void)
+static void fabs(FPU_REG *st0_ptr)
 {
-  if ( FPU_st0_tag ^ TW_Empty )
+  if ( st0_ptr->tag ^ TW_Empty )
     {
-      FPU_st0_ptr->sign = SIGN_POS;
+      st0_ptr->sign = SIGN_POS;
       clear_C1();
     }
   else
@@ -40,25 +40,25 @@ static void fabs(void)
 }
 
 
-static void ftst_(void)
+static void ftst_(FPU_REG *st0_ptr)
 {
-  switch (FPU_st0_tag)
+  switch (st0_ptr->tag)
     {
     case TW_Zero:
       setcc(SW_C3);
       break;
     case TW_Valid:
-      if (FPU_st0_ptr->sign == SIGN_POS)
+      if (st0_ptr->sign == SIGN_POS)
         setcc(0);
       else
         setcc(SW_C0);
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
        {
 #ifdef PECULIAR_486
          /* This is wierd! */
-         if (FPU_st0_ptr->sign == SIGN_POS)
+         if (st0_ptr->sign == SIGN_POS)
            setcc(SW_C3);
 #endif PECULIAR_486
          return;
@@ -71,7 +71,7 @@ static void ftst_(void)
       EXCEPTION(EX_Invalid);
       break;
     case TW_Infinity:
-      if (FPU_st0_ptr->sign == SIGN_POS)
+      if (st0_ptr->sign == SIGN_POS)
         setcc(0);
       else
         setcc(SW_C0);
@@ -87,10 +87,10 @@ static void ftst_(void)
     }
 }
 
-static void fxam(void)
+static void fxam(FPU_REG *st0_ptr)
 {
   int c=0;
-  switch (FPU_st0_tag)
+  switch (st0_ptr->tag)
     {
     case TW_Empty:
       c = SW_C3|SW_C0;
@@ -100,7 +100,7 @@ static void fxam(void)
       break;
     case TW_Valid:
       /* This will need to be changed if TW_Denormal is ever used. */
-      if ( FPU_st0_ptr->exp <= EXP_UNDER )
+      if ( st0_ptr->exp <= EXP_UNDER )
         c = SW_C2|SW_C3;  /* Denormal */
       else
         c = SW_C2;
@@ -112,16 +112,18 @@ static void fxam(void)
       c = SW_C2|SW_C0;
       break;
     }
-  if (FPU_st0_ptr->sign == SIGN_NEG)
+  if (st0_ptr->sign == SIGN_NEG)
     c |= SW_C1;
   setcc(c);
 }
 
-static FUNC const fp_etc_table[] = {
-  fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal
+
+static FUNC_ST0 const fp_etc_table[] = {
+  fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
+  ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
 };
 
 void fp_etc()
 {
-  (fp_etc_table[FPU_rm])();
+  (fp_etc_table[FPU_rm])(&st(0));
 }
index 5003cca447b1c82452b6e165760acaa146283fd1..a5a4650fc24816b24203572dc709790969daf99f 100644 (file)
@@ -63,13 +63,16 @@ extern void trig_a(void);
 extern void trig_b(void);
 
 /* get_address.c */
-extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
-                       fpu_addr_modes);
-extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
-                          fpu_addr_modes);
+extern void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+                        struct address *addr,
+                        fpu_addr_modes);
+extern void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+                           struct address *addr,
+                           fpu_addr_modes);
 
 /* load_store.c */
-extern void load_store_instr(char type, fpu_addr_modes addr_modes);
+extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
+                            void *address);
 
 /* poly_2xm1.c */
 extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
@@ -96,7 +99,7 @@ extern int reg_sub(FPU_REG const *a, FPU_REG const *b,
 
 /* reg_compare.c */
 extern int compare(FPU_REG const *b);
-extern int compare_st_data(void);
+extern int compare_st_data(FPU_REG const *b);
 extern void fcom_st(void);
 extern void fcompst(void);
 extern void fcompp(void);
@@ -108,26 +111,26 @@ extern void fucompp(void);
 extern void fconst(void);
 
 /* reg_ld_str.c */
-extern int reg_load_extended(void);
-extern int reg_load_double(void);
-extern int reg_load_single(void);
-extern void reg_load_int64(void);
-extern void reg_load_int32(void);
-extern void reg_load_int16(void);
-extern void reg_load_bcd(void);
-extern int reg_store_extended(void);
-extern int reg_store_double(void);
-extern int reg_store_single(void);
-extern int reg_store_int64(void);
-extern int reg_store_int32(void);
-extern int reg_store_int16(void);
-extern int reg_store_bcd(void);
+extern int reg_load_extended(long double *addr, FPU_REG *loaded_data);
+extern int reg_load_double(double *dfloat, FPU_REG *loaded_data);
+extern int reg_load_single(float *single, FPU_REG *loaded_data);
+extern void reg_load_int64(long long *_s, FPU_REG *loaded_data);
+extern void reg_load_int32(long *_s, FPU_REG *loaded_data);
+extern void reg_load_int16(short *_s, FPU_REG *loaded_data);
+extern void reg_load_bcd(char *s, FPU_REG *loaded_data);
+extern int reg_store_extended(long double *d, FPU_REG *st0_ptr);
+extern int reg_store_double(double *dfloat, FPU_REG *st0_ptr);
+extern int reg_store_single(float *single, FPU_REG *st0_ptr);
+extern int reg_store_int64(long long *d, FPU_REG *st0_ptr);
+extern int reg_store_int32(long *d, FPU_REG *st0_ptr);
+extern int reg_store_int16(short *d, FPU_REG *st0_ptr);
+extern int reg_store_bcd(char *d, FPU_REG *st0_ptr);
 extern int round_to_int(FPU_REG *r);
-extern char *fldenv(fpu_addr_modes addr_modes);
-extern void frstor(fpu_addr_modes addr_modes);
+extern char *fldenv(fpu_addr_modes addr_modes, char *address);
+extern void frstor(fpu_addr_modes addr_modes, char *address);
 extern unsigned short tag_word(void);
-extern char *fstenv(fpu_addr_modes addr_modes);
-extern void fsave(fpu_addr_modes addr_modes);
+extern char *fstenv(fpu_addr_modes addr_modes, char *address);
+extern void fsave(fpu_addr_modes addr_modes, char *address);
 
 /* reg_mul.c */
 extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
index 24ba92d1f6e35a1325ed98625be96f509515a80b..e09e08b15b6a2aa72f5a0e1933834a16881d8501 100644 (file)
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)    FPU_info = (struct info *) &arg
 
+#define LDT_DESCRIPTOR(s)       (current->ldt[(s) >> 3])
+#define SEG_D_SIZE(x)           ((x).b & (3 << 21))
+#define SEG_G_BIT(x)            ((x).b & (1 << 23))
+#define SEG_GRANULARITY(x)      (((x).b & (1 << 23)) ? 4096 : 1)
+#define SEG_286_MODE(x)         ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23)))
+#define SEG_BASE_ADDR(s)        (((s).b & 0xff000000) \
+                                | (((s).b & 0xff) << 16) | ((s).a >> 16))
+#define SEG_LIMIT(s)            (((s).b & 0xff0000) | ((s).a & 0xffff))
+#define SEG_EXECUTE_ONLY(s)     (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11))
+#define SEG_WRITE_PERM(s)       (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9))
+#define SEG_EXPAND_DOWN(s)      (((s).b & ((1 << 11) | (1 << 10))) \
+                                == (1 << 10))
+
 #define I387                   (current->tss.i387)
 #define FPU_info               (I387.soft.info)
 
 #define FPU_EIP                        (FPU_info->___eip)
 #define FPU_ORIG_EIP           (FPU_info->___orig_eip)
 
-#define LDT_BASE_ADDR(s)       ((current->ldt[(s) >> 3].b & 0xff000000)     \
-                                | ((current->ldt[(s) >> 3].b & 0xff) << 16) \
-                                | (current->ldt[(s) >> 3].a >> 16))
-
 #define FPU_lookahead           (I387.soft.lookahead)
-#define FPU_entry_eip           (I387.soft.entry_eip)
+
+/* nz if ip_offset and cs_selector are not to be set for the current
+   instruction. */
+#define no_ip_update            (((char *)&(I387.soft.twd))[0])
+#define FPU_rm                  (((unsigned char *)&(I387.soft.twd))[1])
+
+/* Number of bytes of data which can be legally accessed by the current
+   instruction. This only needs to hold a number <= 108, so a byte will do. */
+#define access_limit            (((unsigned char *)&(I387.soft.twd))[2])
 
 #define partial_status         (I387.soft.swd)
 #define control_word           (I387.soft.cwd)
 #define regs                   (I387.soft.regs)
 #define top                    (I387.soft.top)
 
-#define ip_offset              (I387.soft.fip)
-#define cs_selector            (I387.soft.fcs)
-#define data_operand_offset    (I387.soft.foo)
-#define operand_selector       (I387.soft.fos)
+#define instruction_address     (*(struct address *)&I387.soft.fip)
+#define operand_address         (*(struct address *)&I387.soft.foo)
 
 #define FPU_verify_area(x,y,z)  if ( verify_area(x,y,z) ) \
                                 math_abort(FPU_info,SIGSEGV)
@@ -64,7 +79,4 @@
 #define        FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
 #endif
 
-/* ######## temporary and ugly ;-) */
-#define FPU_data_address        ((void *)(I387.soft.twd))
-
 #endif
index 1de4317a5c375fff704e498780de2b4d4b1a8895..a368a2e77ca34c2af81f8d855156df63eedca273 100644 (file)
@@ -166,16 +166,16 @@ void convert_l2reg(long const *arg, FPU_REG *dest)
 }
 
 
-static void single_arg_error(void)
+static void single_arg_error(FPU_REG *st0_ptr)
 {
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_NaN:
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
+      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
        {
          EXCEPTION(EX_Invalid);
          if ( control_word & CW_Invalid )
-           FPU_st0_ptr->sigh |= 0x40000000;      /* Convert to a QNaN */
+           st0_ptr->sigh |= 0x40000000;          /* Convert to a QNaN */
        }
       break;              /* return with a NaN in st(0) */
     case TW_Empty:
@@ -189,24 +189,24 @@ static void single_arg_error(void)
 }
 
 
-static void single_arg_2_error(void)
+static void single_arg_2_error(FPU_REG *st0_ptr)
 {
   FPU_REG *st_new_ptr;
 
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_NaN:
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
+      if ( !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
        {
          EXCEPTION(EX_Invalid);
          if ( control_word & CW_Invalid )
            {
              /* The masked response */
              /* Convert to a QNaN */
-             FPU_st0_ptr->sigh |= 0x40000000;
+             st0_ptr->sigh |= 0x40000000;
              st_new_ptr = &st(-1);
              push();
-             reg_move(&st(1), FPU_st0_ptr);
+             reg_move(&st(1), st_new_ptr);
            }
        }
       else
@@ -214,7 +214,7 @@ static void single_arg_2_error(void)
          /* A QNaN */
          st_new_ptr = &st(-1);
          push();
-         reg_move(&st(1), FPU_st0_ptr);
+         reg_move(&st(1), st_new_ptr);
        }
       break;              /* return with a NaN in st(0) */
 #ifdef PARANOID
@@ -227,48 +227,48 @@ static void single_arg_2_error(void)
 
 /*---------------------------------------------------------------------------*/
 
-static void f2xm1(void)
+static void f2xm1(FPU_REG *st0_ptr)
 {
   clear_C1();
-  switch ( FPU_st0_tag )
+  switch ( st0_ptr->tag )
     {
     case TW_Valid:
       {
        FPU_REG rv, tmp;
 
-       if ( FPU_st0_ptr->exp >= 0 )
+       if ( st0_ptr->exp >= 0 )
          {
            /* For an 80486 FPU, the result is undefined. */
          }
-       else if ( FPU_st0_ptr->exp >= -64 )
+       else if ( st0_ptr->exp >= -64 )
          {
-           if ( FPU_st0_ptr->sign == SIGN_POS )
+           if ( st0_ptr->sign == SIGN_POS )
              {
                /* poly_2xm1(x) requires 0 < x < 1. */
-               poly_2xm1(FPU_st0_ptr, &rv);
-               reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+               poly_2xm1(st0_ptr, &rv);
+               reg_mul(&rv, st0_ptr, st0_ptr, FULL_PRECISION);
              }
            else
              {
                /* poly_2xm1(x) doesn't handle negative numbers yet. */
                /* So we compute z=poly_2xm1(-x), and the answer is
                   then -z/(1+z) */
-               FPU_st0_ptr->sign = SIGN_POS;
-               poly_2xm1(FPU_st0_ptr, &rv);
-               reg_mul(&rv, FPU_st0_ptr, &rv, FULL_PRECISION);
+               st0_ptr->sign = SIGN_POS;
+               poly_2xm1(st0_ptr, &rv);
+               reg_mul(&rv, st0_ptr, &rv, FULL_PRECISION);
                reg_add(&rv, &CONST_1, &tmp, FULL_PRECISION);
-               reg_div(&rv, &tmp, FPU_st0_ptr, FULL_PRECISION);
-               FPU_st0_ptr->sign = SIGN_NEG;
+               reg_div(&rv, &tmp, st0_ptr, FULL_PRECISION);
+               st0_ptr->sign = SIGN_NEG;
              }
          }
        else
          {
 #ifdef DENORM_OPERAND
-           if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+           if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
              return;
 #endif DENORM_OPERAND
            /* For very small arguments, this is accurate enough. */
-           reg_mul(&CONST_LN2, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+           reg_mul(&CONST_LN2, st0_ptr, st0_ptr, FULL_PRECISION);
          }
        set_precision_flag_up();
        return;
@@ -276,27 +276,28 @@ static void f2xm1(void)
     case TW_Zero:
       return;
     case TW_Infinity:
-      if ( FPU_st0_ptr->sign == SIGN_NEG )
+      if ( st0_ptr->sign == SIGN_NEG )
        {
          /* -infinity gives -1 (p16-10) */
-         reg_move(&CONST_1, FPU_st0_ptr);
-         FPU_st0_ptr->sign = SIGN_NEG;
+         reg_move(&CONST_1, st0_ptr);
+         st0_ptr->sign = SIGN_NEG;
        }
       return;
     default:
-      single_arg_error();
+      single_arg_error(st0_ptr);
     }
 }
 
 
-static void fptan(void)
+static void fptan(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   int q;
-  char arg_sign = FPU_st0_ptr->sign;
+  char arg_sign = st0_ptr->sign;
 
   /* Stack underflow has higher priority */
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
@@ -311,24 +312,24 @@ static void fptan(void)
   if ( STACK_OVERFLOW )
     { stack_overflow(); return; }
 
-  switch ( FPU_st0_tag )
+  switch ( st0_tag )
     {
     case TW_Valid:
 
-      if ( FPU_st0_ptr->exp > EXP_BIAS - 40 )
+      if ( st0_ptr->exp > EXP_BIAS - 40 )
        {
-         FPU_st0_ptr->sign = SIGN_POS;
-         if ( (q = trig_arg(FPU_st0_ptr, FPTAN)) != -1 )
+         st0_ptr->sign = SIGN_POS;
+         if ( (q = trig_arg(st0_ptr, FPTAN)) != -1 )
            {
-             reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr,
+             reg_div(st0_ptr, &CONST_PI2, st0_ptr,
                      FULL_PRECISION);
-             poly_tan(FPU_st0_ptr, FPU_st0_ptr, q & FCOS);
-             FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
+             poly_tan(st0_ptr, st0_ptr, q & FCOS);
+             st0_ptr->sign = (q & 1) ^ arg_sign;
            }
          else
            {
              /* Operand is out of range */
-             FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
+             st0_ptr->sign = arg_sign;         /* restore st(0) */
              return;
            }
        }
@@ -337,7 +338,7 @@ static void fptan(void)
          /* For a small arg, the result == the argument */
          /* Underflow may happen */
 
-         if ( FPU_st0_ptr->exp <= EXP_UNDER )
+         if ( st0_ptr->exp <= EXP_UNDER )
            {
 #ifdef DENORM_OPERAND
              if ( denormal_operand() )
@@ -346,90 +347,91 @@ static void fptan(void)
              /* A denormal result has been produced.
                 Precision must have been lost, this is always
                 an underflow. */
-             if ( arith_underflow(FPU_st0_ptr) )
+             if ( arith_underflow(st0_ptr) )
                return;
            }
          else
            set_precision_flag_up();  /* Must be up. */
        }
       push();
-      reg_move(&CONST_1, FPU_st0_ptr);
+      reg_move(&CONST_1, st_new_ptr);
       return;
       break;
     case TW_Infinity:
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(st0_ptr);
       if ( control_word & CW_Invalid )
        {
          st_new_ptr = &st(-1);
          push();
-         arith_invalid(FPU_st0_ptr);
+         arith_invalid(st_new_ptr);
        }
       return;
     case TW_Zero:
       push();
-      reg_move(&CONST_1, FPU_st0_ptr);
+      reg_move(&CONST_1, st_new_ptr);
       setcc(0);
       break;
     default:
-      single_arg_2_error();
+      single_arg_2_error(st0_ptr);
       break;
     }
 }
 
 
-static void fxtract(void)
+static void fxtract(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
-  register FPU_REG *st1_ptr = FPU_st0_ptr;  /* anticipate */
+  register FPU_REG *st1_ptr = st0_ptr;  /* anticipate */
 
   if ( STACK_OVERFLOW )
     {  stack_overflow(); return; }
   clear_C1();
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
       long e;
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
          
       push();
-      reg_move(st1_ptr, FPU_st0_ptr);
-      FPU_st0_ptr->exp = EXP_BIAS;
+      reg_move(st1_ptr, st_new_ptr);
+      st_new_ptr->exp = EXP_BIAS;
       e = st1_ptr->exp - EXP_BIAS;
       convert_l2reg(&e, st1_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
-      char sign = FPU_st0_ptr->sign;
-      if ( divide_by_zero(SIGN_NEG, FPU_st0_ptr) )
+      char sign = st0_ptr->sign;
+      if ( divide_by_zero(SIGN_NEG, st0_ptr) )
        return;
       push();
-      reg_move(&CONST_Z, FPU_st0_ptr);
-      FPU_st0_ptr->sign = sign;
+      reg_move(&CONST_Z, st_new_ptr);
+      st_new_ptr->sign = sign;
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      char sign = FPU_st0_ptr->sign;
-      FPU_st0_ptr->sign = SIGN_POS;
+      char sign = st0_ptr->sign;
+      st0_ptr->sign = SIGN_POS;
       push();
-      reg_move(&CONST_INF, FPU_st0_ptr);
-      FPU_st0_ptr->sign = sign;
+      reg_move(&CONST_INF, st_new_ptr);
+      st_new_ptr->sign = sign;
       return;
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
-      if ( real_2op_NaN(FPU_st0_ptr, FPU_st0_ptr, FPU_st0_ptr) )
+      if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) )
        return;
       push();
-      reg_move(st1_ptr, FPU_st0_ptr);
+      reg_move(st1_ptr, st_new_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Is this the correct behaviour? */
       if ( control_word & EX_Invalid )
@@ -448,110 +450,114 @@ static void fxtract(void)
 }
 
 
-static void fdecstp(void)
+static void fdecstp(FPU_REG *st0_ptr)
 {
   clear_C1();
-  top--;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
+  top--;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
-static void fincstp(void)
+static void fincstp(FPU_REG *st0_ptr)
 {
   clear_C1();
-  top++;  /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
+  top++;  /* st0_ptr will be fixed in math_emulate() before the next instr */
 }
 
 
-static void fsqrt_(void)
+static void fsqrt_(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
+
   clear_C1();
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
       int expon;
       
-      if (FPU_st0_ptr->sign == SIGN_NEG)
+      if (st0_ptr->sign == SIGN_NEG)
        {
-         arith_invalid(FPU_st0_ptr);  /* sqrt(negative) is invalid */
+         arith_invalid(st0_ptr);  /* sqrt(negative) is invalid */
          return;
        }
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
 
-      expon = FPU_st0_ptr->exp - EXP_BIAS;
-      FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
+      expon = st0_ptr->exp - EXP_BIAS;
+      st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
       
-      wm_sqrt(FPU_st0_ptr, control_word);      /* Do the computation */
+      wm_sqrt(st0_ptr, control_word);  /* Do the computation */
       
-      FPU_st0_ptr->exp += expon >> 1;
-      FPU_st0_ptr->sign = SIGN_POS;
+      st0_ptr->exp += expon >> 1;
+      st0_ptr->sign = SIGN_POS;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     return;
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      if ( FPU_st0_ptr->sign == SIGN_NEG )
-       arith_invalid(FPU_st0_ptr);  /* sqrt(-Infinity) is invalid */
+      if ( st0_ptr->sign == SIGN_NEG )
+       arith_invalid(st0_ptr);  /* sqrt(-Infinity) is invalid */
       return;
     }
   else
-    { single_arg_error(); return; }
+    { single_arg_error(st0_ptr); return; }
 
 }
 
 
-static void frndint_(void)
+static void frndint_(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   int flags;
 
-  if ( !(FPU_st0_tag ^ TW_Valid) )
+  if ( !(st0_tag ^ TW_Valid) )
     {
-      if (FPU_st0_ptr->exp > EXP_BIAS+63)
+      if (st0_ptr->exp > EXP_BIAS+63)
        return;
 
 #ifdef DENORM_OPERAND
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
 
       /* Fortunately, this can't overflow to 2^64 */
-      if ( (flags = round_to_int(FPU_st0_ptr)) )
+      if ( (flags = round_to_int(st0_ptr)) )
        set_precision_flag(flags);
 
-      FPU_st0_ptr->exp = EXP_BIAS + 63;
-      normalize(FPU_st0_ptr);
+      st0_ptr->exp = EXP_BIAS + 63;
+      normalize(st0_ptr);
       return;
     }
-  else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) )
+  else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) )
     return;
   else
-    single_arg_error();
+    single_arg_error(st0_ptr);
 }
 
 
-static void fsin(void)
+static void fsin(FPU_REG *st0_ptr)
 {
-  char arg_sign = FPU_st0_ptr->sign;
+  char st0_tag = st0_ptr->tag;
+  char arg_sign = st0_ptr->sign;
 
-  if ( FPU_st0_tag == TW_Valid )
+  if ( st0_tag == TW_Valid )
     {
       FPU_REG rv;
       int q;
 
-      if ( FPU_st0_ptr->exp > EXP_BIAS - 40 )
+      if ( st0_ptr->exp > EXP_BIAS - 40 )
        {
-         FPU_st0_ptr->sign = SIGN_POS;
-         if ( (q = trig_arg(FPU_st0_ptr, 0)) != -1 )
+         st0_ptr->sign = SIGN_POS;
+         if ( (q = trig_arg(st0_ptr, 0)) != -1 )
            {
-             reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, FULL_PRECISION);
+             reg_div(st0_ptr, &CONST_PI2, st0_ptr, FULL_PRECISION);
 
-             poly_sine(FPU_st0_ptr, &rv);
+             poly_sine(st0_ptr, &rv);
 
              if (q & 2)
                rv.sign ^= SIGN_POS ^ SIGN_NEG;
              rv.sign ^= arg_sign;
-             reg_move(&rv, FPU_st0_ptr);
+             reg_move(&rv, st0_ptr);
 
              /* We do not really know if up or down */
              set_precision_flag_up();
@@ -560,7 +566,7 @@ static void fsin(void)
          else
            {
              /* Operand is out of range */
-             FPU_st0_ptr->sign = arg_sign;         /* restore st(0) */
+             st0_ptr->sign = arg_sign;         /* restore st(0) */
              return;
            }
        }
@@ -569,7 +575,7 @@ static void fsin(void)
          /* For a small arg, the result == the argument */
          /* Underflow may happen */
 
-         if ( FPU_st0_ptr->exp <= EXP_UNDER )
+         if ( st0_ptr->exp <= EXP_UNDER )
            {
 #ifdef DENORM_OPERAND
              if ( denormal_operand() )
@@ -578,26 +584,26 @@ static void fsin(void)
              /* A denormal result has been produced.
                 Precision must have been lost, this is always
                 an underflow. */
-             arith_underflow(FPU_st0_ptr);
+             arith_underflow(st0_ptr);
              return;
            }
 
          set_precision_flag_up();  /* Must be up. */
        }
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       setcc(0);
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(st0_ptr);
       return;
     }
   else
-    single_arg_error();
+    single_arg_error(st0_ptr);
 }
 
 
@@ -658,33 +664,34 @@ static int f_cos(FPU_REG *arg)
       setcc(0);
       return 0;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( arg->tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      arith_invalid(FPU_st0_ptr);
+      arith_invalid(arg);
       return 1;
     }
   else
     {
-      single_arg_error();  /* requires arg == &st(0) */
+      single_arg_error(arg);  /* requires arg == &st(0) */
       return 1;
     }
 }
 
 
-static void fcos(void)
+static void fcos(FPU_REG *st0_ptr)
 {
-  f_cos(FPU_st0_ptr);
+  f_cos(st0_ptr);
 }
 
 
-static void fsincos(void)
+static void fsincos(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st_new_ptr;
   FPU_REG arg;
 
   /* Stack underflow has higher priority */
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       stack_underflow();  /* Puts a QNaN in st(0) */
       if ( control_word & CW_Invalid )
@@ -699,29 +706,29 @@ static void fsincos(void)
   if ( STACK_OVERFLOW )
     { stack_overflow(); return; }
 
-  if ( FPU_st0_tag == TW_NaN )
+  if ( st0_tag == TW_NaN )
     {
-      single_arg_2_error();
+      single_arg_2_error(st0_ptr);
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       /* The 80486 treats infinity as an invalid operand */
-      if ( !arith_invalid(FPU_st0_ptr) )
+      if ( !arith_invalid(st0_ptr) )
        {
          /* unmasked response */
          push();
-         arith_invalid(FPU_st0_ptr);
+         arith_invalid(st_new_ptr);
        }
       return;
     }
 
-  reg_move(FPU_st0_ptr,&arg);
+  reg_move(st0_ptr,&arg);
   if ( !f_cos(&arg) )
     {
-      fsin();
+      fsin(st0_ptr);
       push();
-      reg_move(&arg,FPU_st0_ptr);
+      reg_move(&arg,st_new_ptr);
     }
 
 }
@@ -760,23 +767,24 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
 /* Remainder of st(0) / st(1) */
 /* This routine produces exact results, i.e. there is never any
    rounding or truncation, etc of the result. */
-static void do_fprem(int round)
+static void do_fprem(FPU_REG *st0_ptr, int round)
 {
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
-  char sign = FPU_st0_ptr->sign;
+  char st0_tag = st0_ptr->tag;
+  char sign = st0_ptr->sign;
 
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       FPU_REG tmp;
       int old_cw = control_word;
-      int expdif = FPU_st0_ptr->exp - st1_ptr->exp;
+      int expdif = st0_ptr->exp - st1_ptr->exp;
       long long q;
       unsigned short saved_status;
       int cc = 0;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
            (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
@@ -793,7 +801,7 @@ static void do_fprem(int round)
 
          if ( expdif > -2 )
            {
-             reg_div(FPU_st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
+             reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f);
 
              if ( tmp.exp >= EXP_BIAS )
                {
@@ -801,7 +809,7 @@ static void do_fprem(int round)
                                          to 2^64 */
                  q = significand(&tmp);
 
-                 rem_kernel(significand(FPU_st0_ptr),
+                 rem_kernel(significand(st0_ptr),
                             &significand(&tmp),
                             significand(st1_ptr),
                             q, expdif);
@@ -810,7 +818,7 @@ static void do_fprem(int round)
                }
              else
                {
-                 reg_move(FPU_st0_ptr, &tmp);
+                 reg_move(st0_ptr, &tmp);
                  q = 0;
                }
              tmp.sign = sign;
@@ -858,7 +866,7 @@ static void do_fprem(int round)
 
          /* prevent overflow here */
          /* N is 'a number between 32 and 63' (p26-113) */
-         reg_move(FPU_st0_ptr, &tmp);
+         reg_move(st0_ptr, &tmp);
          tmp.exp = EXP_BIAS + 56;
          exp_1 = st1_ptr->exp;      st1_ptr->exp = EXP_BIAS;
          expdif -= 56;
@@ -868,7 +876,7 @@ static void do_fprem(int round)
 
          round_to_int(&tmp);  /* Fortunately, this can't overflow to 2^64 */
 
-         rem_kernel(significand(FPU_st0_ptr),
+         rem_kernel(significand(st0_ptr),
                     &significand(&tmp),
                     significand(st1_ptr),
                     significand(&tmp),
@@ -887,8 +895,8 @@ static void do_fprem(int round)
              /* The result is zero */
              control_word = old_cw;
              partial_status = saved_status;
-             reg_move(&CONST_Z, FPU_st0_ptr);
-             FPU_st0_ptr->sign = sign;
+             reg_move(&CONST_Z, st0_ptr);
+             st0_ptr->sign = sign;
 #ifdef PECULIAR_486
              setcc(SW_C2);
 #else
@@ -902,23 +910,23 @@ static void do_fprem(int round)
       control_word = old_cw;
       partial_status = saved_status;
       normalize_nuo(&tmp);
-      reg_move(&tmp, FPU_st0_ptr);
+      reg_move(&tmp, st0_ptr);
       setcc(cc);
 
       /* The only condition to be looked for is underflow,
         and it can occur here only if underflow is unmasked. */
-      if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (FPU_st0_ptr->tag != TW_Zero)
+      if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero)
          && !(control_word & CW_Underflow) )
-       arith_underflow(FPU_st0_ptr);
+       arith_underflow(st0_ptr);
 
       return;
     }
-  else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
     {
       stack_underflow();
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag == TW_Valid )
        {
@@ -930,21 +938,21 @@ static void do_fprem(int round)
          setcc(0); return;
        }
       else if ( st1_tag == TW_Zero )
-       { arith_invalid(FPU_st0_ptr); return; } /* fprem(?,0) always invalid */
+       { arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */
       else if ( st1_tag == TW_Infinity )
        { setcc(0); return; }
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
        {
-         arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is invalid */
+         arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */
          return;
        }
       else if ( st1_tag != TW_NaN )
        {
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
 
@@ -955,11 +963,11 @@ static void do_fprem(int round)
            }
        }
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag != TW_NaN )
        {
-         arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is invalid */
+         arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */
          return;
        }
     }
@@ -967,30 +975,31 @@ static void do_fprem(int round)
   /* One of the registers must contain a NaN is we got here. */
 
 #ifdef PARANOID
-  if ( (FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
+  if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) )
       EXCEPTION(EX_INTERNAL | 0x118);
 #endif PARANOID
 
-  real_2op_NaN(st1_ptr, FPU_st0_ptr, FPU_st0_ptr);
+  real_2op_NaN(st1_ptr, st0_ptr, st0_ptr);
 
 }
 
 
 /* ST(1) <- ST(1) * log ST;  pop ST */
-static void fyl2x(void)
+static void fyl2x(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
-      if ( FPU_st0_ptr->sign == SIGN_POS )
+      if ( st0_ptr->sign == SIGN_POS )
        {
          int saved_control, saved_status;
 
 #ifdef DENORM_OPERAND
-         if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+         if ( ((st0_ptr->exp <= EXP_UNDER) ||
                (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
@@ -1001,16 +1010,16 @@ static void fyl2x(void)
          saved_control = control_word;
          control_word = FULL_PRECISION;
 
-         poly_l2(FPU_st0_ptr, FPU_st0_ptr);
+         poly_l2(st0_ptr, st0_ptr);
 
          /* Enough of the basic arithmetic is done now */
          control_word = saved_control;
          partial_status = saved_status;
 
          /* Let the multiply set the flags */
-         reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+         reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
 
-         pop(); FPU_st0_ptr = &st(0);
+         pop();
        }
       else
        {
@@ -1020,21 +1029,21 @@ static void fyl2x(void)
          return;
        }
     }
-  else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
        pop();
       return;
     }
-  else if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
+  else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
     {
       /* one of the args is zero, the other valid, or both zero */
-      if ( FPU_st0_tag == TW_Zero )
+      if ( st0_tag == TW_Zero )
        {
          if ( st1_tag == TW_Zero )
            {
@@ -1046,7 +1055,7 @@ static void fyl2x(void)
          /* This case is not specifically covered in the manual,
             but divide-by-zero would seem to be the best response.
             However, a real 80486 does it this way... */
-         else if ( FPU_st0_ptr->tag == TW_Infinity )
+         else if ( st0_ptr->tag == TW_Infinity )
            {
              reg_move(&CONST_INF, st1_ptr);
              pop();
@@ -1065,7 +1074,7 @@ static void fyl2x(void)
          /* Zero is the valid answer */
          char sign = st1_ptr->sign;
 
-         if ( FPU_st0_ptr->sign == SIGN_NEG )
+         if ( st0_ptr->sign == SIGN_NEG )
            {
              /* log(negative) */
              if ( !arith_invalid(st1_ptr) )
@@ -1074,21 +1083,21 @@ static void fyl2x(void)
            }
 
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
 
-         if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
-         pop(); FPU_st0_ptr = &st(0);
-         reg_move(&CONST_Z, FPU_st0_ptr);
-         FPU_st0_ptr->sign = sign;
+         if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS;
+         pop(); st0_ptr = &st(0);
+         reg_move(&CONST_Z, st0_ptr);
+         st0_ptr->sign = sign;
          return;
        }
     }
   /* One or both arg must be an infinity */
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
-      if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
+      if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
        {
          /* log(-infinity) or 0*log(infinity) */
          if ( !arith_invalid(st1_ptr) )
@@ -1104,20 +1113,20 @@ static void fyl2x(void)
            return;
 #endif DENORM_OPERAND
 
-         pop(); FPU_st0_ptr = &st(0);
-         reg_move(&CONST_INF, FPU_st0_ptr);
-         FPU_st0_ptr->sign = sign;
+         pop(); st0_ptr = &st(0);
+         reg_move(&CONST_INF, st0_ptr);
+         st0_ptr->sign = sign;
          return;
        }
     }
   /* st(1) must be infinity here */
-  else if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
+  else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) )
     {
-      if ( FPU_st0_ptr->exp >= EXP_BIAS )
+      if ( st0_ptr->exp >= EXP_BIAS )
        {
-         if ( (FPU_st0_ptr->exp == EXP_BIAS) &&
-             (FPU_st0_ptr->sigh == 0x80000000) &&
-             (FPU_st0_ptr->sigl == 0) )
+         if ( (st0_ptr->exp == EXP_BIAS) &&
+             (st0_ptr->sigh == 0x80000000) &&
+             (st0_ptr->sigl == 0) )
            {
              /* st(0) holds 1.0 */
              /* infinity*log(1) */
@@ -1133,7 +1142,7 @@ static void fyl2x(void)
          /* st(0) is positive and < 1.0 */
 
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
 
@@ -1145,7 +1154,7 @@ static void fyl2x(void)
   else
     {
       /* st(0) must be zero or negative */
-      if ( FPU_st0_ptr->tag == TW_Zero )
+      if ( st0_ptr->tag == TW_Zero )
        {
          /* This should be invalid, but a real 80486 is happy with it. */
 #ifndef PECULIAR_486
@@ -1167,21 +1176,22 @@ static void fyl2x(void)
 }
 
 
-static void fpatan(void)
+static void fpatan(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
-  char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign;
+  char st1_sign = st1_ptr->sign, st0_sign = st0_ptr->sign;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
       FPU_REG sum;
       char inverted;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
            (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
@@ -1191,28 +1201,28 @@ static void fpatan(void)
       saved_control = control_word;
       control_word = FULL_PRECISION;
 
-      st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
+      st1_ptr->sign = st0_ptr->sign = SIGN_POS;
       if ( (compare(st1_ptr) & ~COMP_Denormal) == COMP_A_lt_B )
        {
          inverted = 1;
-         reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
+         reg_div(st0_ptr, st1_ptr, &sum, FULL_PRECISION);
        }
       else
        {
          inverted = 0;
          if ( (st0_sign == 0) &&
-             (st1_ptr->exp - FPU_st0_ptr->exp < -64) )
+             (st1_ptr->exp - st0_ptr->exp < -64) )
            {
              control_word = saved_control;
              partial_status = saved_status;
-             reg_div(st1_ptr, FPU_st0_ptr, st1_ptr,
+             reg_div(st1_ptr, st0_ptr, st1_ptr,
                      control_word | PR_64_BITS);
              st1_ptr->sign = st1_sign;
              pop();
              set_precision_flag_down();
              return;
            }
-         reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
+         reg_div(st1_ptr, st0_ptr, &sum, FULL_PRECISION);
        }
 
       poly_atan(&sum);
@@ -1233,25 +1243,25 @@ static void fpatan(void)
 
       reg_move(&sum, st1_ptr);
     }
-  else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
+  else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
          pop();
       return;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
+  else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
     {
       char sign = st1_ptr->sign;
-      if ( FPU_st0_tag == TW_Infinity )
+      if ( st0_tag == TW_Infinity )
        {
          if ( st1_tag == TW_Infinity )
            {
-             if ( FPU_st0_ptr->sign == SIGN_POS )
+             if ( st0_ptr->sign == SIGN_POS )
                { reg_move(&CONST_PI4, st1_ptr); }
              else
                reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
@@ -1266,7 +1276,7 @@ static void fpatan(void)
                }
 #endif DENORM_OPERAND
 
-             if ( FPU_st0_ptr->sign == SIGN_POS )
+             if ( st0_ptr->sign == SIGN_POS )
                {
                  reg_move(&CONST_Z, st1_ptr);
                  st1_ptr->sign = sign;   /* An 80486 preserves the sign */
@@ -1281,9 +1291,9 @@ static void fpatan(void)
        {
          /* st(1) is infinity, st(0) not infinity */
 #ifdef DENORM_OPERAND
-         if ( FPU_st0_tag != TW_Zero )
+         if ( st0_tag != TW_Zero )
            {
-             if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+             if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
                return;
            }
 #endif DENORM_OPERAND
@@ -1298,20 +1308,20 @@ static void fpatan(void)
       char sign = st1_ptr->sign;
 
 #ifdef DENORM_OPERAND
-      if ( FPU_st0_tag != TW_Zero )
+      if ( st0_tag != TW_Zero )
        {
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
        }
 #endif DENORM_OPERAND
 
-      if ( FPU_st0_ptr->sign == SIGN_POS )
+      if ( st0_ptr->sign == SIGN_POS )
        { /* An 80486 preserves the sign */ pop(); return; }
       else
        reg_move(&CONST_PI, st1_ptr);
       st1_ptr->sign = sign;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       /* st(1) must be TW_Valid here */
       char sign = st1_ptr->sign;
@@ -1334,30 +1344,31 @@ static void fpatan(void)
 }
 
 
-static void fprem(void)
+static void fprem(FPU_REG *st0_ptr)
 {
-  do_fprem(RC_CHOP);
+  do_fprem(st0_ptr, RC_CHOP);
 }
 
 
-static void fprem1(void)
+static void fprem1(FPU_REG *st0_ptr)
 {
-  do_fprem(RC_RND);
+  do_fprem(st0_ptr, RC_RND);
 }
 
 
-static void fyl2xp1(void)
+static void fyl2xp1(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       int saved_control, saved_status;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
            (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
        return;
 #endif DENORM_OPERAND
@@ -1367,7 +1378,7 @@ static void fyl2xp1(void)
       saved_control = control_word;
       control_word = FULL_PRECISION;
 
-      if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) )
+      if ( poly_l2p1(st0_ptr, st0_ptr) )
        {
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
          st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
@@ -1386,16 +1397,16 @@ static void fyl2xp1(void)
       partial_status = saved_status;
 
       /* Let the multiply set the flags */
-      reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+      reg_mul(st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
 
       pop();
     }
-  else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
+  else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
     {
       stack_underflow_pop(1);
       return;
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag <= TW_Zero )
        {
@@ -1405,8 +1416,8 @@ static void fyl2xp1(void)
            return;
 #endif DENORM_OPERAND
          
-         FPU_st0_ptr->sign ^= st1_ptr->sign;
-         reg_move(FPU_st0_ptr, st1_ptr);
+         st0_ptr->sign ^= st1_ptr->sign;
+         reg_move(st0_ptr, st1_ptr);
        }
       else if ( st1_tag == TW_Infinity )
        {
@@ -1417,7 +1428,7 @@ static void fyl2xp1(void)
        }
       else if ( st1_tag == TW_NaN )
        {
-         if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+         if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
            pop();
          return;
        }
@@ -1430,13 +1441,13 @@ static void fyl2xp1(void)
 #endif PARANOID
       pop(); return;
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
        {
-         if ( FPU_st0_ptr->sign == SIGN_NEG )
+         if ( st0_ptr->sign == SIGN_NEG )
            {
-             if ( FPU_st0_ptr->exp >= EXP_BIAS )
+             if ( st0_ptr->exp >= EXP_BIAS )
                {
                  /* st(0) holds <= -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
@@ -1447,25 +1458,25 @@ static void fyl2xp1(void)
                  pop(); return;
                }
 #ifdef DENORM_OPERAND
-             if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+             if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
                return;
 #endif DENORM_OPERAND
              st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
              pop(); return;
            }
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
          pop(); return;
        }
       if ( st1_tag == TW_Infinity )
        {
-         if ( FPU_st0_ptr->sign == SIGN_NEG )
+         if ( st0_ptr->sign == SIGN_NEG )
            {
-             if ( (FPU_st0_ptr->exp >= EXP_BIAS) &&
-                 !((FPU_st0_ptr->sigh == 0x80000000) &&
-                   (FPU_st0_ptr->sigl == 0)) )
+             if ( (st0_ptr->exp >= EXP_BIAS) &&
+                 !((st0_ptr->sigh == 0x80000000) &&
+                   (st0_ptr->sigl == 0)) )
                {
                  /* st(0) holds < -1.0 */
 #ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
@@ -1476,40 +1487,40 @@ static void fyl2xp1(void)
                  pop(); return;
                }
 #ifdef DENORM_OPERAND
-             if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+             if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
                return;
 #endif DENORM_OPERAND
              st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
              pop(); return;
            }
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
          pop(); return;
        }
       if ( st1_tag == TW_NaN )
        {
-         if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+         if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
            pop();
          return;
        }
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
-      if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+      if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
        pop();
       return;
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag == TW_NaN )
        {
-         if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
+         if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) )
            pop();
          return;
        }
-      else if ( FPU_st0_ptr->sign == SIGN_NEG )
+      else if ( st0_ptr->sign == SIGN_NEG )
        {
          int exponent = st1_ptr->exp;
 #ifndef PECULIAR_486
@@ -1565,21 +1576,22 @@ static void fyl2xp1(void)
 }
 
 
-static void fscale(void)
+static void fscale(FPU_REG *st0_ptr)
 {
+  char st0_tag = st0_ptr->tag;
   FPU_REG *st1_ptr = &st(1);
   char st1_tag = st1_ptr->tag;
   int old_cw = control_word;
-  char sign = FPU_st0_ptr->sign;
+  char sign = st0_ptr->sign;
 
   clear_C1();
-  if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
+  if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
     {
       long scale;
       FPU_REG tmp;
 
 #ifdef DENORM_OPERAND
-      if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
+      if ( ((st0_ptr->exp <= EXP_UNDER) ||
            (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
        return;
 #endif DENORM_OPERAND
@@ -1592,16 +1604,16 @@ static void fscale(void)
          if ( st1_ptr->sign == SIGN_POS )
            {
              EXCEPTION(EX_Overflow);
-             sign = FPU_st0_ptr->sign;
-             reg_move(&CONST_INF, FPU_st0_ptr);
-             FPU_st0_ptr->sign = sign;
+             sign = st0_ptr->sign;
+             reg_move(&CONST_INF, st0_ptr);
+             st0_ptr->sign = sign;
            }
          else
            {
              EXCEPTION(EX_Underflow);
-             sign = FPU_st0_ptr->sign;
-             reg_move(&CONST_Z, FPU_st0_ptr);
-             FPU_st0_ptr->sign = sign;
+             sign = st0_ptr->sign;
+             reg_move(&CONST_Z, st0_ptr);
+             st0_ptr->sign = sign;
            }
          return;
        }
@@ -1612,21 +1624,21 @@ static void fscale(void)
       round_to_int(&tmp);               /* This can never overflow here */
       control_word = old_cw;
       scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
-      scale += FPU_st0_ptr->exp;
-      FPU_st0_ptr->exp = scale;
+      scale += st0_ptr->exp;
+      st0_ptr->exp = scale;
 
       /* Use round_reg() to properly detect under/overflow etc */
-      round_reg(FPU_st0_ptr, 0, control_word);
+      round_reg(st0_ptr, 0, control_word);
 
       return;
     }
-  else if ( FPU_st0_tag == TW_Valid )
+  else if ( st0_tag == TW_Valid )
     {
       if ( st1_tag == TW_Zero )
        {
 
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
 
@@ -1635,21 +1647,21 @@ static void fscale(void)
       if ( st1_tag == TW_Infinity )
        {
 #ifdef DENORM_OPERAND
-         if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
+         if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
            return;
 #endif DENORM_OPERAND
 
          if ( st1_ptr->sign == SIGN_POS )
-           { reg_move(&CONST_INF, FPU_st0_ptr); }
+           { reg_move(&CONST_INF, st0_ptr); }
          else
-             reg_move(&CONST_Z, FPU_st0_ptr);
-         FPU_st0_ptr->sign = sign;
+             reg_move(&CONST_Z, st0_ptr);
+         st0_ptr->sign = sign;
          return;
        }
       if ( st1_tag == TW_NaN )
-       { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+       { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_Zero )
+  else if ( st0_tag == TW_Zero )
     {
       if ( st1_tag == TW_Valid )
        {
@@ -1668,14 +1680,14 @@ static void fscale(void)
            return;
          else
            {
-             arith_invalid(FPU_st0_ptr); /* Zero scaled by +Infinity */
+             arith_invalid(st0_ptr); /* Zero scaled by +Infinity */
              return;
            }
        }
       else if ( st1_tag == TW_NaN )
-       { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+       { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_Infinity )
+  else if ( st0_tag == TW_Infinity )
     {
       if ( st1_tag == TW_Valid )
        {
@@ -1692,20 +1704,20 @@ static void fscale(void)
        return;
       else if ( st1_tag == TW_Infinity )
        {
-         arith_invalid(FPU_st0_ptr); /* Infinity scaled by -Infinity */
+         arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */
          return;
        }
       else if ( st1_tag == TW_NaN )
-       { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+       { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
-  else if ( FPU_st0_tag == TW_NaN )
+  else if ( st0_tag == TW_NaN )
     {
       if ( st1_tag != TW_Empty )
-       { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
+       { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; }
     }
 
 #ifdef PARANOID
-  if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
+  if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
     {
       EXCEPTION(EX_INTERNAL | 0x115);
       return;
@@ -1720,22 +1732,22 @@ static void fscale(void)
 
 /*---------------------------------------------------------------------------*/
 
-static FUNC const trig_table_a[] = {
+static FUNC_ST0 const trig_table_a[] = {
   f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
 };
 
 void trig_a(void)
 {
-  (trig_table_a[FPU_rm])();
+  (trig_table_a[FPU_rm])(&st(0));
 }
 
 
-static FUNC const trig_table_b[] =
+static FUNC_ST0 const trig_table_b[] =
   {
     fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
   };
 
 void trig_b(void)
 {
-  (trig_table_b[FPU_rm])();
+  (trig_table_b[FPU_rm])(&st(0));
 }
index a9c15cff1264bf842654ef272c927d7e64429690..79d01879ca4eb3566dbc6793022ab921af79aa86 100644 (file)
@@ -19,6 +19,7 @@
 
 
 #include <linux/stddef.h>
+#include <linux/head.h>
 
 #include <asm/segment.h>
 
@@ -26,6 +27,9 @@
 #include "exception.h"
 #include "fpu_emu.h"
 
+
+#define FPU_WRITE_BIT 0x10
+
 static int reg_offset[] = {
        offsetof(struct info,___eax),
        offsetof(struct info,___ecx),
@@ -52,7 +56,7 @@ static int reg_offset_vm86[] = {
 #define VM86_REG_(x) (*(unsigned short *) \
                      (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
 
-static int reg_offset_p286[] = {
+static int reg_offset_pm[] = {
        offsetof(struct info,___cs),
        offsetof(struct info,___ds),
        offsetof(struct info,___es),
@@ -62,12 +66,12 @@ static int reg_offset_p286[] = {
        offsetof(struct info,___ds)
       };
 
-#define P286_REG_(x) (*(unsigned short *) \
-                     (reg_offset_p286[((unsigned)x)]+(char *) FPU_info))
+#define PM_REG_(x) (*(unsigned short *) \
+                     (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
 
 
 /* Decode the SIB byte. This function assumes mod != 0 */
-static void *sib(int mod, unsigned long *fpu_eip)
+static int sib(int mod, unsigned long *fpu_eip)
 {
   unsigned char ss,index,base;
   long offset;
@@ -117,14 +121,14 @@ static void *sib(int mod, unsigned long *fpu_eip)
       (*fpu_eip) += 4;
     }
 
-  return (void *) offset;
+  return offset;
 }
 
 
-static unsigned long mode16_segment(fpu_addr_modes addr_modes)
+static unsigned long vm86_segment(unsigned char segment,
+                                 unsigned short *selector)
 { 
-  int segment = addr_modes.override.segment - 1;
-
+  segment--;
 #ifdef PARANOID
   if ( segment > PREFIX_SS_ )
     {
@@ -132,11 +136,61 @@ static unsigned long mode16_segment(fpu_addr_modes addr_modes)
       math_abort(FPU_info,SIGSEGV);
     }
 #endif PARANOID
-  if ( addr_modes.vm86 )
-    return (unsigned long)VM86_REG_(segment) << 4;
-  else if ( addr_modes.p286 )
-    return (unsigned long)LDT_BASE_ADDR(P286_REG_(segment));
-  return 0;
+  *selector = VM86_REG_(segment);
+  return (unsigned long)VM86_REG_(segment) << 4;
+}
+
+
+/* This should work for 16 and 32 bit protected mode. */
+static long pm_address(unsigned char FPU_modrm, unsigned char segment,
+                      unsigned short *selector, long offset)
+{ 
+  struct desc_struct descriptor;
+  unsigned long base_address, limit, address, seg_top;
+
+  segment--;
+#ifdef PARANOID
+  if ( segment > PREFIX_SS_ )
+    {
+      EXCEPTION(EX_INTERNAL|0x132);
+      math_abort(FPU_info,SIGSEGV);
+    }
+#endif PARANOID
+
+  *selector = PM_REG_(segment);
+
+  descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+  base_address = SEG_BASE_ADDR(descriptor);
+  address = base_address + offset;
+  limit = base_address
+       + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
+  if ( limit < base_address ) limit = 0xffffffff;
+
+  if ( SEG_EXPAND_DOWN(descriptor) )
+    {
+      if ( SEG_G_BIT(descriptor) )
+       seg_top = 0xffffffff;
+      else
+       {
+         seg_top = base_address + (1 << 20);
+         if ( seg_top < base_address ) seg_top = 0xffffffff;
+       }
+      access_limit =
+       (address <= limit) || (address >= seg_top) ? 0 :
+         ((seg_top-address) >= 255 ? 255 : seg_top-address);
+    }
+  else
+    {
+      access_limit =
+       (address > limit) || (address < base_address) ? 0 :
+         ((limit-address) >= 254 ? 255 : limit-address+1);
+    }
+  if ( SEG_EXECUTE_ONLY(descriptor) ||
+      (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
+    {
+      access_limit = 0;
+    }
+  return address;
 }
 
 
@@ -157,117 +211,132 @@ static unsigned long mode16_segment(fpu_addr_modes addr_modes)
 
 */
 
-void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
-                fpu_addr_modes addr_modes)
+void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+                 struct address *addr,
+/*               unsigned short *selector, unsigned long *offset, */
+                 fpu_addr_modes addr_modes)
 {
   unsigned char mod;
+  unsigned rm = FPU_modrm & 7;
   long *cpu_reg_ptr;
-  int offset = 0;     /* Initialized just to stop compiler warnings. */
-
-#ifndef PECULIAR_486
-  /* This is a reasonable place to do this */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
+  int address = 0;     /* Initialized just to stop compiler warnings. */
 
   /* Memory accessed via the cs selector is write protected
-     in protected mode. */
-#define FPU_WRITE_BIT 0x10
-  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+     in `non-segmented' 32 bit protected mode. */
+  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
       && (addr_modes.override.segment == PREFIX_CS_) )
     {
       math_abort(FPU_info,SIGSEGV);
     }
 
+  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
+
   mod = (FPU_modrm >> 6) & 3;
 
-  if (FPU_rm == 4 && mod != 3)
+  if (rm == 4 && mod != 3)
     {
-      FPU_data_address = sib(mod, fpu_eip);
-      return;
+      address = sib(mod, fpu_eip);
     }
-
-  cpu_reg_ptr = & REG_(FPU_rm);
-  switch (mod)
+  else
     {
-    case 0:
-      if (FPU_rm == 5)
+      cpu_reg_ptr = & REG_(rm);
+      switch (mod)
        {
-         /* Special case: disp32 */
+       case 0:
+         if (rm == 5)
+           {
+             /* Special case: disp32 */
+             RE_ENTRANT_CHECK_OFF;
+             FPU_code_verify_area(4);
+             address = get_fs_long((unsigned long *) (*fpu_eip));
+             (*fpu_eip) += 4;
+             RE_ENTRANT_CHECK_ON;
+             addr->offset = address;
+             return (void *) address;
+           }
+         else
+           {
+             address = *cpu_reg_ptr;  /* Just return the contents
+                                         of the cpu register */
+             addr->offset = address;
+             return (void *) address;
+           }
+       case 1:
+         /* 8 bit signed displacement */
+         RE_ENTRANT_CHECK_OFF;
+         FPU_code_verify_area(1);
+         address = (signed char) get_fs_byte((char *) (*fpu_eip));
+         RE_ENTRANT_CHECK_ON;
+         (*fpu_eip)++;
+         break;
+       case 2:
+         /* 32 bit displacement */
          RE_ENTRANT_CHECK_OFF;
          FPU_code_verify_area(4);
-         offset = get_fs_long((unsigned long *) (*fpu_eip));
+         address = (signed) get_fs_long((unsigned long *) (*fpu_eip));
          (*fpu_eip) += 4;
          RE_ENTRANT_CHECK_ON;
-         FPU_data_address = (void *) offset;
-         return;
-       }
-      else
-       {
-         FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
-                                                  of the cpu register */
-         return;
+         break;
+       case 3:
+         /* Not legal for the FPU */
+         EXCEPTION(EX_Invalid);
        }
-    case 1:
-      /* 8 bit signed displacement */
-      RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(1);
-      offset = (signed char) get_fs_byte((char *) (*fpu_eip));
-      RE_ENTRANT_CHECK_ON;
-      (*fpu_eip)++;
-      break;
-    case 2:
-      /* 32 bit displacement */
-      RE_ENTRANT_CHECK_OFF;
-      FPU_code_verify_area(4);
-      offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
-      (*fpu_eip) += 4;
-      RE_ENTRANT_CHECK_ON;
-      break;
-    case 3:
-      /* Not legal for the FPU */
-      EXCEPTION(EX_Invalid);
+      address += *cpu_reg_ptr;
     }
 
-  if ( addr_modes.mode16 )
+  addr->offset = address;
+
+  switch ( addr_modes.default_mode )
     {
-      offset += mode16_segment(addr_modes);
+    case 0:
+      break;
+    case VM86:
+      address += vm86_segment(addr_modes.override.segment,
+                             (unsigned short *)&(addr->selector));
+      break;
+    case PM16:
+    case SEG32:
+      address = pm_address(FPU_modrm, addr_modes.override.segment,
+                          (unsigned short *)&(addr->selector), address);
+      break;
+    default:
+      EXCEPTION(EX_INTERNAL|0x133);
     }
 
-  FPU_data_address = offset + (char *)*cpu_reg_ptr;
+  return (void *)address;
 }
 
 
-void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
-                     fpu_addr_modes addr_modes)
+void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+                    struct address *addr,
+/*                  unsigned short *selector, unsigned long *offset, */
+                    fpu_addr_modes addr_modes)
 {
   unsigned char mod;
-  int offset = 0;     /* Default used for mod == 0 */
-
-#ifndef PECULIAR_486
-  /* This is a reasonable place to do this */
-  FPU_data_selector = FPU_DS;
-#endif PECULIAR_486
+  unsigned rm = FPU_modrm & 7;
+  int address = 0;     /* Default used for mod == 0 */
 
   /* Memory accessed via the cs selector is write protected
-     in protected mode. */
-#define FPU_WRITE_BIT 0x10
-  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+     in `non-segmented' 32 bit protected mode. */
+  if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
       && (addr_modes.override.segment == PREFIX_CS_) )
     {
       math_abort(FPU_info,SIGSEGV);
     }
 
+  addr->selector = FPU_DS;   /* Default, for 32 bit non-segmented mode. */
+
   mod = (FPU_modrm >> 6) & 3;
 
   switch (mod)
     {
     case 0:
-      if (FPU_rm == 6)
+      if (rm == 6)
        {
          /* Special case: disp16 */
          RE_ENTRANT_CHECK_OFF;
          FPU_code_verify_area(2);
-         offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
+         address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
          (*fpu_eip) += 2;
          RE_ENTRANT_CHECK_ON;
          goto add_segment;
@@ -277,7 +346,7 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
+      address = (signed char) get_fs_byte((signed char *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
       (*fpu_eip)++;
       break;
@@ -285,7 +354,7 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
       /* 16 bit displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(2);
-      offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
+      address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
       (*fpu_eip) += 2;
       RE_ENTRANT_CHECK_ON;
       break;
@@ -294,47 +363,61 @@ void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
       EXCEPTION(EX_Invalid);
       break;
     }
-  switch ( FPU_rm )
+  switch ( rm )
     {
     case 0:
-      offset += FPU_info->___ebx + FPU_info->___esi;
+      address += FPU_info->___ebx + FPU_info->___esi;
       break;
     case 1:
-      offset += FPU_info->___ebx + FPU_info->___edi;
+      address += FPU_info->___ebx + FPU_info->___edi;
       break;
     case 2:
-      offset += FPU_info->___ebp + FPU_info->___esi;
+      address += FPU_info->___ebp + FPU_info->___esi;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
        addr_modes.override.segment = PREFIX_SS_;
       break;
     case 3:
-      offset += FPU_info->___ebp + FPU_info->___edi;
+      address += FPU_info->___ebp + FPU_info->___edi;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
        addr_modes.override.segment = PREFIX_SS_;
       break;
     case 4:
-      offset += FPU_info->___esi;
+      address += FPU_info->___esi;
       break;
     case 5:
-      offset += FPU_info->___edi;
+      address += FPU_info->___edi;
       break;
     case 6:
-      offset += FPU_info->___ebp;
+      address += FPU_info->___ebp;
       if ( addr_modes.override.segment == PREFIX_DEFAULT )
        addr_modes.override.segment = PREFIX_SS_;
       break;
     case 7:
-      offset += FPU_info->___ebx;
+      address += FPU_info->___ebx;
       break;
     }
 
  add_segment:
-  offset &= 0xffff;
+  address &= 0xffff;
+
+  addr->offset = address;
 
-  if ( addr_modes.mode16 )
+  switch ( addr_modes.default_mode )
     {
-      offset += mode16_segment(addr_modes);
+    case 0:
+      break;
+    case VM86:
+      address += vm86_segment(addr_modes.override.segment,
+                             (unsigned short *)&(addr->selector));
+      break;
+    case PM16:
+    case SEG32:
+      address = pm_address(FPU_modrm, addr_modes.override.segment,
+                          (unsigned short *)&(addr->selector), address);
+      break;
+    default:
+      EXCEPTION(EX_INTERNAL|0x131);
     }
 
-  FPU_data_address = (void *)offset ;
+  return (void *)address ;
 }
index d1c1f755b098b6bdddd704085808c72867d69b35..6f0e167d6d03fb25f69d88e5e62903cac47dfaa5 100644 (file)
 #include "control_w.h"
 
 
-#define _NONE_ 0   /* FPU_st0_ptr etc not needed */
+#define _NONE_ 0   /* st0_ptr etc not needed */
 #define _REG0_ 1   /* Will be storing st(0) */
 #define _PUSH_ 3   /* Need to check for space to push onto stack */
 #define _null_ 4   /* Function illegal or not implemented */
 
-#define pop_0()        { pop_ptr->tag = TW_Empty; top++; }
+#define pop_0()        { st0_ptr->tag = TW_Empty; top++; }
 
 
 static unsigned char const type_table[32] = {
@@ -46,192 +46,215 @@ static unsigned char const type_table[32] = {
   _NONE_, _REG0_, _NONE_, _REG0_
   };
 
-void load_store_instr(char type, fpu_addr_modes addr_modes)
+unsigned char const data_sizes_16[32] = {
+  4,  4,  8,  2,  0,  0,  0,  0,
+  4,  4,  8,  2,  4,  4,  8,  2,
+  14, 0, 94, 10,  2, 10,  0,  8,  
+  14, 0, 94, 10,  2, 10,  2,  8
+};
+
+unsigned char const data_sizes_32[32] = {
+  4,  4,  8,  2,  0,  0,  0,  0,
+  4,  4,  8,  2,  4,  4,  8,  2,
+  28, 0,108, 10,  2, 10,  0,  8,  
+  28, 0,108, 10,  2, 10,  2,  8
+};
+
+int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
+                    void *data_address)
 {
-  FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't
-                       change if the emulator is re-entered. */
+  FPU_REG loaded_data;
+  FPU_REG *st0_ptr;
+
+  st0_ptr = NULL;    /* Initialized just to stop compiler warnings. */
 
-  pop_ptr = NULL;    /* Initialized just to stop compiler warnings. */
-  switch ( type_table[(int) (unsigned) type] )
+  if ( addr_modes.default_mode & PROTECTED )
+    {
+      if ( addr_modes.default_mode == SEG32 )
+       {
+         if ( access_limit < data_sizes_32[type] )
+           math_abort(FPU_info,SIGSEGV);
+       }
+      else if ( addr_modes.default_mode == PM16 )
+       {
+         if ( access_limit < data_sizes_16[type] )
+           math_abort(FPU_info,SIGSEGV);
+       }
+#ifdef PARANOID
+      else
+       EXCEPTION(EX_INTERNAL|0x140);
+#endif PARANOID
+    }
+
+  switch ( type_table[type] )
     {
     case _NONE_:
       break;
     case _REG0_:
-      pop_ptr = &st(0);       /* Some of these instructions pop after
+      st0_ptr = &st(0);       /* Some of these instructions pop after
                                 storing */
-
-      FPU_st0_ptr = pop_ptr;      /* Set the global variables. */
-      FPU_st0_tag = FPU_st0_ptr->tag;
       break;
     case _PUSH_:
       {
-       pop_ptr = &st(-1);
-       if ( pop_ptr->tag != TW_Empty )
-         { stack_overflow(); return; }
+       st0_ptr = &st(-1);
+       if ( st0_ptr->tag != TW_Empty )
+         { stack_overflow(); return 0; }
        top--;
       }
       break;
     case _null_:
       FPU_illegal();
-      return;
+      return 0;
 #ifdef PARANOID
     default:
-      EXCEPTION(EX_INTERNAL);
-      return;
+      EXCEPTION(EX_INTERNAL|0x141);
+      return 0;
 #endif PARANOID
     }
 
-switch ( type )
-  {
-  case 000:       /* fld m32real */
-    clear_C1();
-    reg_load_single();
-    if ( (FPU_loaded_data.tag == TW_NaN) &&
-       real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
-      {
-       top++;
-       break;
-      }
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 001:      /* fild m32int */
-    clear_C1();
-    reg_load_int32();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 002:      /* fld m64real */
-    clear_C1();
-    reg_load_double();
-    if ( (FPU_loaded_data.tag == TW_NaN) &&
-       real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
-      {
-       top++;
-       break;
-      }
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 003:      /* fild m16int */
-    clear_C1();
-    reg_load_int16();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 010:      /* fst m32real */
-    clear_C1();
-    reg_store_single();
-    break;
-  case 011:      /* fist m32int */
-    clear_C1();
-    reg_store_int32();
-    break;
-  case 012:     /* fst m64real */
-    clear_C1();
-    reg_store_double();
-    break;
-  case 013:     /* fist m16int */
-    clear_C1();
-    reg_store_int16();
-    break;
-  case 014:     /* fstp m32real */
-    clear_C1();
-    if ( reg_store_single() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 015:     /* fistp m32int */
-    clear_C1();
-    if ( reg_store_int32() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 016:     /* fstp m64real */
-    clear_C1();
-    if ( reg_store_double() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 017:     /* fistp m16int */
-    clear_C1();
-    if ( reg_store_int16() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 020:     /* fldenv  m14/28byte */
-    fldenv(addr_modes);
-    break;
-  case 022:     /* frstor m94/108byte */
-    frstor(addr_modes);
-    break;
-  case 023:     /* fbld m80dec */
-    clear_C1();
-    reg_load_bcd();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 024:     /* fldcw */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_READ, FPU_data_address, 2);
-    control_word = get_fs_word((unsigned short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    if ( partial_status & ~control_word & CW_Exceptions )
-      partial_status |= (SW_Summary | SW_Backward);
-    else
-      partial_status &= ~(SW_Summary | SW_Backward);
+  switch ( type )
+    {
+    case 000:       /* fld m32real */
+      clear_C1();
+      reg_load_single((float *)data_address, &loaded_data);
+      if ( (loaded_data.tag == TW_NaN) &&
+         real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+       {
+         top++;
+         break;
+       }
+      reg_move(&loaded_data, st0_ptr);
+      break;
+    case 001:      /* fild m32int */
+      clear_C1();
+      reg_load_int32((long *)data_address, st0_ptr);
+      break;
+    case 002:      /* fld m64real */
+      clear_C1();
+      reg_load_double((double *)data_address, &loaded_data);
+      if ( (loaded_data.tag == TW_NaN) &&
+         real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) )
+       {
+         top++;
+         break;
+       }
+      reg_move(&loaded_data, st0_ptr);
+      break;
+    case 003:      /* fild m16int */
+      clear_C1();
+      reg_load_int16((short *)data_address, st0_ptr);
+      break;
+    case 010:      /* fst m32real */
+      clear_C1();
+      reg_store_single((float *)data_address, st0_ptr);
+      break;
+    case 011:      /* fist m32int */
+      clear_C1();
+      reg_store_int32((long *)data_address, st0_ptr);
+      break;
+    case 012:     /* fst m64real */
+      clear_C1();
+      reg_store_double((double *)data_address, st0_ptr);
+      break;
+    case 013:     /* fist m16int */
+      clear_C1();
+      reg_store_int16((short *)data_address, st0_ptr);
+      break;
+    case 014:     /* fstp m32real */
+      clear_C1();
+      if ( reg_store_single((float *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 015:     /* fistp m32int */
+      clear_C1();
+      if ( reg_store_int32((long *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 016:     /* fstp m64real */
+      clear_C1();
+      if ( reg_store_double((double *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 017:     /* fistp m16int */
+      clear_C1();
+      if ( reg_store_int16((short *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 020:     /* fldenv  m14/28byte */
+      fldenv(addr_modes, (char *)data_address);
+      /* Ensure that the values just loaded are not changed by
+        fix-up operations. */
+      return 1;
+    case 022:     /* frstor m94/108byte */
+      frstor(addr_modes, (char *)data_address);
+      /* Ensure that the values just loaded are not changed by
+        fix-up operations. */
+      return 1;
+    case 023:     /* fbld m80dec */
+      clear_C1();
+      reg_load_bcd((char *)data_address, st0_ptr);
+      break;
+    case 024:     /* fldcw */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_READ, data_address, 2);
+      control_word = get_fs_word((unsigned short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      if ( partial_status & ~control_word & CW_Exceptions )
+       partial_status |= (SW_Summary | SW_Backward);
+      else
+       partial_status &= ~(SW_Summary | SW_Backward);
 #ifdef PECULIAR_486
-    control_word |= 0x40;  /* An 80486 appears to always set this bit */
+      control_word |= 0x40;  /* An 80486 appears to always set this bit */
 #endif PECULIAR_486
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 025:      /* fld m80real */
-    clear_C1();
-    reg_load_extended();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 027:      /* fild m64int */
-    clear_C1();
-    reg_load_int64();
-    reg_move(&FPU_loaded_data, pop_ptr);
-    break;
-  case 030:     /* fstenv  m14/28byte */
-    fstenv(addr_modes);
-    NO_NET_DATA_EFFECT;
-    break;
-  case 032:      /* fsave */
-    fsave(addr_modes);
-    NO_NET_DATA_EFFECT;
-    break;
-  case 033:      /* fbstp m80dec */
-    clear_C1();
-    if ( reg_store_bcd() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 034:      /* fstcw m16int */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
-    put_fs_word(control_word, (short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 035:      /* fstp m80real */
-    clear_C1();
-    if ( reg_store_extended() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  case 036:      /* fstsw m2byte */
-    RE_ENTRANT_CHECK_OFF;
-    FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
-    put_fs_word(status_word(),(short *) FPU_data_address);
-    RE_ENTRANT_CHECK_ON;
-    NO_NET_DATA_EFFECT;
-    NO_NET_INSTR_EFFECT;
-    break;
-  case 037:      /* fistp m64int */
-    clear_C1();
-    if ( reg_store_int64() )
-      pop_0();  /* pop only if the number was actually stored
-                (see the 80486 manual p16-28) */
-    break;
-  }
+      return 1;
+    case 025:      /* fld m80real */
+      clear_C1();
+      reg_load_extended((long double *)data_address, st0_ptr);
+      break;
+    case 027:      /* fild m64int */
+      clear_C1();
+      reg_load_int64((long long *)data_address, st0_ptr);
+      break;
+    case 030:     /* fstenv  m14/28byte */
+      fstenv(addr_modes, (char *)data_address);
+      return 1;
+    case 032:      /* fsave */
+      fsave(addr_modes, (char *)data_address);
+      return 1;
+    case 033:      /* fbstp m80dec */
+      clear_C1();
+      if ( reg_store_bcd((char *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 034:      /* fstcw m16int */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      put_fs_word(control_word, (short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      return 1;
+    case 035:      /* fstp m80real */
+      clear_C1();
+      if ( reg_store_extended((long double *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    case 036:      /* fstsw m2byte */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,data_address,2);
+      put_fs_word(status_word(),(short *) data_address);
+      RE_ENTRANT_CHECK_ON;
+      return 1;
+    case 037:      /* fistp m64int */
+      clear_C1();
+      if ( reg_store_int64((long long *)data_address, st0_ptr) )
+       pop_0();  /* pop only if the number was actually stored
+                    (see the 80486 manual p16-28) */
+      break;
+    }
+  return 0;
 }
index ea606f9769431c9d417be49a99389e901862984f..521eeb8a8d65e8958374f5af7bfeda92caebcfc5 100644 (file)
@@ -187,16 +187,8 @@ void poly_add_1(FPU_REG *src)
    for the use of this function in poly_atan. Simple truncation
    is used here instead of round-to-nearest. */
 
-#ifdef OBSOLETE
-char round = (src->sigl & 3) == 3;
-#endif OBSOLETE
-
 shrx(&src->sigl, 1);
 
-#ifdef OBSOLETE
-if ( round ) significand(src)++;   /* Round to even */
-#endif OBSOLETE
-
 src->sigh |= 0x80000000;
 
 src->exp = EXP_BIAS;
index 020030119e0a5602fbb64a0eeba4eb28e38b3ed4..eb4a1fa999f54ca90d6ca502cbc6c5701139689c 100644 (file)
 int compare(FPU_REG const *b)
 {
   int diff;
+  char        st0_tag;
+  FPU_REG      *st0_ptr;
 
-  if ( FPU_st0_ptr->tag | b->tag )
+  st0_ptr = &st(0);
+  st0_tag = st0_ptr->tag;
+
+  if ( st0_tag | b->tag )
     {
-      if ( FPU_st0_ptr->tag == TW_Zero )
+      if ( st0_tag == TW_Zero )
        {
          if ( b->tag == TW_Zero ) return COMP_A_eq_B;
          if ( b->tag == TW_Valid )
@@ -42,23 +47,23 @@ int compare(FPU_REG const *b)
        }
       else if ( b->tag == TW_Zero )
        {
-         if ( FPU_st0_ptr->tag == TW_Valid )
+         if ( st0_tag == TW_Valid )
            {
-             return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
+             return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
                      : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
-               | ((FPU_st0_ptr->exp <= EXP_UNDER )
+               | ((st0_ptr->exp <= EXP_UNDER )
                   ? COMP_Denormal : 0 )
 #endif DENORM_OPERAND
                  ;
            }
        }
 
-      if ( FPU_st0_ptr->tag == TW_Infinity )
+      if ( st0_tag == TW_Infinity )
        {
          if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
            {
-             return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
+             return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
                      : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
              | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
@@ -69,19 +74,19 @@ int compare(FPU_REG const *b)
          else if ( b->tag == TW_Infinity )
            {
              /* The 80486 book says that infinities can be equal! */
-             return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
-               ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+             return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
+               ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
            }
          /* Fall through to the NaN code */
        }
       else if ( b->tag == TW_Infinity )
        {
-         if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
+         if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
            {
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 #ifdef DENORM_OPERAND
-               | (((FPU_st0_ptr->tag == TW_Valid)
-                   && (FPU_st0_ptr->exp <= EXP_UNDER)) ?
+               | (((st0_tag == TW_Valid)
+                   && (st0_ptr->exp <= EXP_UNDER)) ?
                   COMP_Denormal : 0)
 #endif DENORM_OPERAND
                  ;
@@ -91,9 +96,9 @@ int compare(FPU_REG const *b)
 
       /* The only possibility now should be that one of the arguments
         is a NaN */
-      if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
+      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
        {
-         if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
+         if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
              || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
            /* At least one arg is a signaling NaN */
            return COMP_No_Comp | COMP_SNaN | COMP_NaN;
@@ -106,51 +111,51 @@ int compare(FPU_REG const *b)
     }
   
 #ifdef PARANOID
-  if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
+  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
 #endif PARANOID
 
   
-  if (FPU_st0_ptr->sign != b->sign)
+  if (st0_ptr->sign != b->sign)
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
        |
-         ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+         ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
 #endif DENORM_OPERAND
            ;
     }
 
-  diff = FPU_st0_ptr->exp - b->exp;
+  diff = st0_ptr->exp - b->exp;
   if ( diff == 0 )
     {
-      diff = FPU_st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
+      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
                                              identical */
       if ( diff == 0 )
        {
-       diff = FPU_st0_ptr->sigl > b->sigl;
+       diff = st0_ptr->sigl > b->sigl;
        if ( diff == 0 )
-         diff = -(FPU_st0_ptr->sigl < b->sigl);
+         diff = -(st0_ptr->sigl < b->sigl);
        }
     }
 
   if ( diff > 0 )
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
 #ifdef DENORM_OPERAND
        |
-         ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+         ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
 #endif DENORM_OPERAND
            ;
     }
   if ( diff < 0 )
     {
-      return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
+      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
 #ifdef DENORM_OPERAND
        |
-         ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+         ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
           COMP_Denormal : 0)
 #endif DENORM_OPERAND
            ;
@@ -159,7 +164,7 @@ int compare(FPU_REG const *b)
   return COMP_A_eq_B
 #ifdef DENORM_OPERAND
     |
-      ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
+      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
        COMP_Denormal : 0)
 #endif DENORM_OPERAND
        ;
@@ -168,11 +173,11 @@ int compare(FPU_REG const *b)
 
 
 /* This function requires that st(0) is not empty */
-int compare_st_data(void)
+int compare_st_data(FPU_REG const *loaded_data)
 {
   int f, c;
 
-  c = compare(&FPU_loaded_data);
+  c = compare(loaded_data);
 
   if (c & COMP_NaN)
     {
@@ -214,7 +219,7 @@ static int compare_st_st(int nr)
 {
   int f, c;
 
-  if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
+  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
       /* Stack fault */
@@ -264,7 +269,7 @@ static int compare_u_st_st(int nr)
 {
   int f, c;
 
-  if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
+  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
     {
       setcc(SW_C3 | SW_C2 | SW_C0);
       /* Stack fault */
@@ -340,10 +345,7 @@ void fcompp()
       return;
     }
   if ( !compare_st_st(1) )
-    {
-      pop(); FPU_st0_ptr = &st(0);
-      pop();
-    }
+      poppop();
 }
 
 
@@ -369,10 +371,7 @@ void fucompp()
   if (FPU_rm == 1)
     {
       if ( !compare_u_st_st(1) )
-       {
-         pop(); FPU_st0_ptr = &st(0);
-         pop();
-       }
+       poppop();
     }
   else
     FPU_illegal();
index 29d157c8b80da45d5a055c0a7c4195debb8256d3..c1981ce2414093fb43a40aec1c683ca59acffa43 100644 (file)
@@ -66,7 +66,7 @@ static void fld_const(FPU_REG const *c)
       return;
     }
   push();
-  reg_move(c, FPU_st0_ptr);
+  reg_move(c, st_new_ptr);
   clear_C1();
 }
 
index 2727cfaff6fa7dd5747d93b45614b8e7fe5588cc..2fbc5f7c41a68d9d8fae8d08597069099eba95d7 100644 (file)
@@ -25,9 +25,9 @@
 _reg_div:
        pushl   %ebp
        movl    %esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        subl    $28,%esp        /* Needed by divide_kernel */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
        pushl   %esi
        pushl   %edi
@@ -214,11 +214,11 @@ LDiv_negative_result:
        xorl    %eax,%eax               /* Valid result */
 
 LDiv_exit:
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        leal    -40(%ebp),%esp
 #else
        leal    -12(%ebp),%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
        popl    %ebx
        popl    %edi
index dcafbe378d3443fcc32877385a36c4bc98550aec..9f8133b6b18bb844d991397c622e293c59de3448 100644 (file)
 
 static void write_to_extended(FPU_REG *rp, char *d);
 
-FPU_REG FPU_loaded_data;
-
 
 /* Get a long double from user memory */
-int reg_load_extended(void)
+int reg_load_extended(long double *s, FPU_REG *loaded_data)
 {
-  long double *s = (long double *)FPU_data_address;
   unsigned long sigl, sigh, exp;
 
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_READ, s, 10);
-  /* Use temporary variables here because FPU_loaded data is
-     static and hence re-entrancy problems can arise */
   sigl = get_fs_long((unsigned long *) s);
   sigh = get_fs_long(1 + (unsigned long *) s);
   exp = get_fs_word(4 + (unsigned short *) s);
   RE_ENTRANT_CHECK_ON;
 
-  FPU_loaded_data.tag = TW_Valid;   /* Default */
-  FPU_loaded_data.sigl = sigl;
-  FPU_loaded_data.sigh = sigh;
+  loaded_data->tag = TW_Valid;   /* Default */
+  loaded_data->sigl = sigl;
+  loaded_data->sigh = sigh;
   if (exp & 0x8000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   exp &= 0x7fff;
-  FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS;
+  loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS;
 
-  /* Assume that optimisation can keep sigl, sigh, and exp in
-     registers, otherwise it would be more efficient to work
-     with FPU_loaded_data (which is static) here. */
   if ( exp == 0 )
     {
       if ( !(sigh | sigl) )
        {
-         FPU_loaded_data.tag = TW_Zero;
+         loaded_data->tag = TW_Zero;
          return 0;
        }
       /* The number is a de-normal or pseudodenormal. */
@@ -85,15 +77,15 @@ int reg_load_extended(void)
          /* Convert it for internal use. */
          /* This is non-80486 behaviour because the number
             loses its 'denormal' identity. */
-         FPU_loaded_data.exp++;
+         loaded_data->exp++;
          return 1;
        }
       else
        {
          /* Is a denormal. */
          /* Convert it for internal use. */
-         FPU_loaded_data.exp++;
-         normalize_nuo(&FPU_loaded_data);
+         loaded_data->exp++;
+         normalize_nuo(loaded_data);
          return 0;
        }
     }
@@ -102,13 +94,13 @@ int reg_load_extended(void)
       if ( !((sigh ^ 0x80000000) | sigl) )
        {
          /* Matches the bit pattern for Infinity. */
-         FPU_loaded_data.exp = EXP_Infinity;
-         FPU_loaded_data.tag = TW_Infinity;
+         loaded_data->exp = EXP_Infinity;
+         loaded_data->tag = TW_Infinity;
          return 0;
        }
 
-      FPU_loaded_data.exp = EXP_NaN;
-      FPU_loaded_data.tag = TW_NaN;
+      loaded_data->exp = EXP_NaN;
+      loaded_data->tag = TW_NaN;
       if ( !(sigh & 0x80000000) )
        {
          /* NaNs have the ms bit set to 1. */
@@ -116,9 +108,9 @@ int reg_load_extended(void)
          /* This is non 80486 behaviour */
          /* This should generate an Invalid Operand exception
             later, so we convert it to a SNaN */
-         FPU_loaded_data.sigh = 0x80000000;
-         FPU_loaded_data.sigl = 0x00000001;
-         FPU_loaded_data.sign = SIGN_NEG;
+         loaded_data->sigh = 0x80000000;
+         loaded_data->sigl = 0x00000001;
+         loaded_data->sign = SIGN_NEG;
          return 1;
        }
       return 0;
@@ -133,11 +125,11 @@ int reg_load_extended(void)
       /* This is non-80486 behaviour */
       /* This should generate an Invalid Operand exception
         later, so we convert it to a SNaN */
-      FPU_loaded_data.sigh = 0x80000000;
-      FPU_loaded_data.sigl = 0x00000001;
-      FPU_loaded_data.sign = SIGN_NEG;
-      FPU_loaded_data.exp = EXP_NaN;
-      FPU_loaded_data.tag = TW_NaN;
+      loaded_data->sigh = 0x80000000;
+      loaded_data->sigl = 0x00000001;
+      loaded_data->sign = SIGN_NEG;
+      loaded_data->exp = EXP_NaN;
+      loaded_data->tag = TW_NaN;
       return 1;
     }
   return 0;
@@ -145,9 +137,8 @@ int reg_load_extended(void)
 
 
 /* Get a double from user memory */
-int reg_load_double(void)
+int reg_load_double(double *dfloat, FPU_REG *loaded_data)
 {
-  double *dfloat = (double *)FPU_data_address;
   int exp;
   unsigned m64, l64;
 
@@ -158,9 +149,9 @@ int reg_load_double(void)
   RE_ENTRANT_CHECK_ON;
 
   if (m64 & 0x80000000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
   m64 &= 0xfffff;
   if (exp > DOUBLE_Emax)
@@ -169,20 +160,20 @@ int reg_load_double(void)
       if ((m64 == 0) && (l64 == 0))
        {
          /* +- infinity */
-         FPU_loaded_data.sigh = 0x80000000;
-         FPU_loaded_data.sigl = 0x00000000;
-         FPU_loaded_data.exp = EXP_Infinity;
-         FPU_loaded_data.tag = TW_Infinity;
+         loaded_data->sigh = 0x80000000;
+         loaded_data->sigl = 0x00000000;
+         loaded_data->exp = EXP_Infinity;
+         loaded_data->tag = TW_Infinity;
          return 0;
        }
       else
        {
          /* Must be a signaling or quiet NaN */
-         FPU_loaded_data.exp = EXP_NaN;
-         FPU_loaded_data.tag = TW_NaN;
-         FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
-         FPU_loaded_data.sigh |= l64 >> 21;
-         FPU_loaded_data.sigl = l64 << 11;
+         loaded_data->exp = EXP_NaN;
+         loaded_data->tag = TW_NaN;
+         loaded_data->sigh = (m64 << 11) | 0x80000000;
+         loaded_data->sigh |= l64 >> 21;
+         loaded_data->sigl = l64 << 11;
          return 0; /* The calling function must look for NaNs */
        }
     }
@@ -192,30 +183,30 @@ int reg_load_double(void)
       if ((m64 == 0) && (l64 == 0))
        {
          /* Zero */
-         int c = FPU_loaded_data.sign;
-         reg_move(&CONST_Z, &FPU_loaded_data);
-         FPU_loaded_data.sign = c;
+         int c = loaded_data->sign;
+         reg_move(&CONST_Z, loaded_data);
+         loaded_data->sign = c;
          return 0;
        }
       else
        {
          /* De-normal */
-         FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
-         FPU_loaded_data.tag = TW_Valid;
-         FPU_loaded_data.sigh = m64 << 11;
-         FPU_loaded_data.sigh |= l64 >> 21;
-         FPU_loaded_data.sigl = l64 << 11;
-         normalize_nuo(&FPU_loaded_data);
+         loaded_data->exp = DOUBLE_Emin + EXP_BIAS;
+         loaded_data->tag = TW_Valid;
+         loaded_data->sigh = m64 << 11;
+         loaded_data->sigh |= l64 >> 21;
+         loaded_data->sigl = l64 << 11;
+         normalize_nuo(loaded_data);
          return denormal_operand();
        }
     }
   else
     {
-      FPU_loaded_data.exp = exp + EXP_BIAS;
-      FPU_loaded_data.tag = TW_Valid;
-      FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
-      FPU_loaded_data.sigh |= l64 >> 21;
-      FPU_loaded_data.sigl = l64 << 11;
+      loaded_data->exp = exp + EXP_BIAS;
+      loaded_data->tag = TW_Valid;
+      loaded_data->sigh = (m64 << 11) | 0x80000000;
+      loaded_data->sigh |= l64 >> 21;
+      loaded_data->sigl = l64 << 11;
 
       return 0;
     }
@@ -223,9 +214,8 @@ int reg_load_double(void)
 
 
 /* Get a float from user memory */
-int reg_load_single(void)
+int reg_load_single(float *single, FPU_REG *loaded_data)
 {
-  float *single = (float *)FPU_data_address;
   unsigned m32;
   int exp;
 
@@ -235,15 +225,15 @@ int reg_load_single(void)
   RE_ENTRANT_CHECK_ON;
 
   if (m32 & 0x80000000)
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   else
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   if (!(m32 & 0x7fffffff))
     {
       /* Zero */
-      int c = FPU_loaded_data.sign;
-      reg_move(&CONST_Z, &FPU_loaded_data);
-      FPU_loaded_data.sign = c;
+      int c = loaded_data->sign;
+      reg_move(&CONST_Z, loaded_data);
+      loaded_data->sign = c;
       return 0;
     }
   exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
@@ -251,11 +241,11 @@ int reg_load_single(void)
   if ( exp < SINGLE_Emin )
     {
       /* De-normals */
-      FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
-      FPU_loaded_data.tag = TW_Valid;
-      FPU_loaded_data.sigh = m32;
-      FPU_loaded_data.sigl = 0;
-      normalize_nuo(&FPU_loaded_data);
+      loaded_data->exp = SINGLE_Emin + EXP_BIAS;
+      loaded_data->tag = TW_Valid;
+      loaded_data->sigh = m32;
+      loaded_data->sigl = 0;
+      normalize_nuo(loaded_data);
       return denormal_operand();
     }
   else if ( exp > SINGLE_Emax )
@@ -264,37 +254,36 @@ int reg_load_single(void)
       if ( m32 == 0 )
        {
          /* +- infinity */
-         FPU_loaded_data.sigh = 0x80000000;
-         FPU_loaded_data.sigl = 0x00000000;
-         FPU_loaded_data.exp = EXP_Infinity;
-         FPU_loaded_data.tag = TW_Infinity;
+         loaded_data->sigh = 0x80000000;
+         loaded_data->sigl = 0x00000000;
+         loaded_data->exp = EXP_Infinity;
+         loaded_data->tag = TW_Infinity;
          return 0;
        }
       else
        {
          /* Must be a signaling or quiet NaN */
-         FPU_loaded_data.exp = EXP_NaN;
-         FPU_loaded_data.tag = TW_NaN;
-         FPU_loaded_data.sigh = m32 | 0x80000000;
-         FPU_loaded_data.sigl = 0;
+         loaded_data->exp = EXP_NaN;
+         loaded_data->tag = TW_NaN;
+         loaded_data->sigh = m32 | 0x80000000;
+         loaded_data->sigl = 0;
          return 0; /* The calling function must look for NaNs */
        }
     }
   else
     {
-      FPU_loaded_data.exp = exp + EXP_BIAS;
-      FPU_loaded_data.sigh = m32 | 0x80000000;
-      FPU_loaded_data.sigl = 0;
-      FPU_loaded_data.tag = TW_Valid;
+      loaded_data->exp = exp + EXP_BIAS;
+      loaded_data->sigh = m32 | 0x80000000;
+      loaded_data->sigl = 0;
+      loaded_data->tag = TW_Valid;
       return 0;
     }
 }
 
 
 /* Get a long long from user memory */
-void reg_load_int64(void)
+void reg_load_int64(long long *_s, FPU_REG *loaded_data)
 {
-  long long *_s = (long long *)FPU_data_address;
   int e;
   long long s;
 
@@ -305,28 +294,27 @@ void reg_load_int64(void)
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 63;
-  significand(&FPU_loaded_data) = s;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  significand(loaded_data) = s;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a long from user memory */
-void reg_load_int32(void)
+void reg_load_int32(long *_s, FPU_REG *loaded_data)
 {
-  long *_s = (long *)FPU_data_address;
   long s;
   int e;
 
@@ -336,29 +324,28 @@ void reg_load_int32(void)
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 31;
-  FPU_loaded_data.sigh = s;
-  FPU_loaded_data.sigl = 0;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  loaded_data->sigh = s;
+  loaded_data->sigl = 0;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a short from user memory */
-void reg_load_int16(void)
+void reg_load_int16(short *_s, FPU_REG *loaded_data)
 {
-  short *_s = (short *)FPU_data_address;
   int s, e;
 
   RE_ENTRANT_CHECK_OFF;
@@ -368,30 +355,29 @@ void reg_load_int16(void)
   RE_ENTRANT_CHECK_ON;
 
   if (s == 0)
-    { reg_move(&CONST_Z, &FPU_loaded_data); return; }
+    { reg_move(&CONST_Z, loaded_data); return; }
 
   if (s > 0)
-    FPU_loaded_data.sign = SIGN_POS;
+    loaded_data->sign = SIGN_POS;
   else
   {
     s = -s;
-    FPU_loaded_data.sign = SIGN_NEG;
+    loaded_data->sign = SIGN_NEG;
   }
 
   e = EXP_BIAS + 15;
-  FPU_loaded_data.sigh = s << 16;
+  loaded_data->sigh = s << 16;
 
-  FPU_loaded_data.sigl = 0;
-  FPU_loaded_data.exp = e;
-  FPU_loaded_data.tag = TW_Valid;
-  normalize_nuo(&FPU_loaded_data);
+  loaded_data->sigl = 0;
+  loaded_data->exp = e;
+  loaded_data->tag = TW_Valid;
+  normalize_nuo(loaded_data);
 }
 
 
 /* Get a packed bcd array from user memory */
-void reg_load_bcd(void)
+void reg_load_bcd(char *s, FPU_REG *loaded_data)
 {
-  char *s = (char *)FPU_data_address;
   int pos;
   unsigned char bcd;
   long long l=0;
@@ -409,48 +395,45 @@ void reg_load_bcd(void)
       l *= 10;
       l += bcd & 0x0f;
     }
-  
-  /* Finish all access to user memory before putting stuff into
-     the static FPU_loaded_data */
   RE_ENTRANT_CHECK_OFF;
-  FPU_loaded_data.sign =
+  loaded_data->sign =
     ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
       SIGN_NEG : SIGN_POS;
   RE_ENTRANT_CHECK_ON;
 
   if (l == 0)
     {
-      char sign = FPU_loaded_data.sign;
-      reg_move(&CONST_Z, &FPU_loaded_data);
-      FPU_loaded_data.sign = sign;
+      char sign = loaded_data->sign;
+      reg_move(&CONST_Z, loaded_data);
+      loaded_data->sign = sign;
     }
   else
     {
-      significand(&FPU_loaded_data) = l;
-      FPU_loaded_data.exp = EXP_BIAS + 63;
-      FPU_loaded_data.tag = TW_Valid;
-      normalize_nuo(&FPU_loaded_data);
+      significand(loaded_data) = l;
+      loaded_data->exp = EXP_BIAS + 63;
+      loaded_data->tag = TW_Valid;
+      normalize_nuo(loaded_data);
     }
 }
 
 /*===========================================================================*/
 
 /* Put a long double into user memory */
-int reg_store_extended(void)
+int reg_store_extended(long double *d, FPU_REG *st0_ptr)
 {
   /*
     The only exception raised by an attempt to store to an
     extended format is the Invalid Stack exception, i.e.
     attempting to store from an empty register.
    */
-  long double *d = (long double *)FPU_data_address;
 
-  if ( FPU_st0_tag != TW_Empty )
+  if ( st0_ptr->tag != TW_Empty )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE, d, 10);
       RE_ENTRANT_CHECK_ON;
-      write_to_extended(FPU_st0_ptr, (char *) FPU_data_address);
+      write_to_extended(st0_ptr, (char *) d);
       return 1;
     }
 
@@ -475,18 +458,18 @@ int reg_store_extended(void)
 
 
 /* Put a double into user memory */
-int reg_store_double(void)
+int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
 {
-  double *dfloat = (double *)FPU_data_address;
   unsigned long l[2];
   unsigned long increment = 0; /* avoid gcc warnings */
+  char st0_tag = st0_ptr->tag;
 
-  if (FPU_st0_tag == TW_Valid)
+  if (st0_tag == TW_Valid)
     {
       int exp;
       FPU_REG tmp;
 
-      reg_move(FPU_st0_ptr, &tmp);
+      reg_move(st0_ptr, &tmp);
       exp = tmp.exp - EXP_BIAS;
 
       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
@@ -497,7 +480,7 @@ int reg_store_double(void)
 #ifndef PECULIAR_486
          /* An 80486 is supposed to be able to generate
             a denormal exception here, but... */
-         if ( FPU_st0_ptr->exp <= EXP_UNDER )
+         if ( st0_ptr->exp <= EXP_UNDER )
            {
              /* Underflow has priority. */
              if ( control_word & CW_Underflow )
@@ -515,7 +498,7 @@ int reg_store_double(void)
                 that the 80486 rounds to the dest precision, then
                 converts to decide underflow. */
              if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
-                 (FPU_st0_ptr->sigl & 0x000007ff)) )
+                 (st0_ptr->sigl & 0x000007ff)) )
 #endif PECULIAR_486
                {
                  EXCEPTION(EX_Underflow);
@@ -612,23 +595,23 @@ int reg_store_double(void)
            }
        }
     }
-  else if (FPU_st0_tag == TW_Zero)
+  else if (st0_tag == TW_Zero)
     {
       /* Number is zero */
       l[0] = 0;
       l[1] = 0;
     }
-  else if (FPU_st0_tag == TW_Infinity)
+  else if (st0_tag == TW_Infinity)
     {
       l[0] = 0;
       l[1] = 0x7ff00000;
     }
-  else if (FPU_st0_tag == TW_NaN)
+  else if (st0_tag == TW_NaN)
     {
       /* See if we can get a valid NaN from the FPU_REG */
-      l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
-      l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
+      l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
+      l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
+      if ( !(st0_ptr->sigh & 0x40000000) )
        {
          /* It is a signalling NaN */
          EXCEPTION(EX_Invalid);
@@ -638,7 +621,7 @@ int reg_store_double(void)
        }
       l[1] |= 0x7ff00000;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -656,7 +639,7 @@ int reg_store_double(void)
       else
        return 0;
     }
-  if (FPU_st0_ptr->sign)
+  if ( st0_ptr->sign )
     l[1] |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
@@ -670,18 +653,18 @@ int reg_store_double(void)
 
 
 /* Put a float into user memory */
-int reg_store_single(void)
+int reg_store_single(float *single, FPU_REG *st0_ptr)
 {
-  float *single = (float *)FPU_data_address;
   long templ;
   unsigned long increment = 0;         /* avoid gcc warnings */
+  char st0_tag = st0_ptr->tag;
 
-  if (FPU_st0_tag == TW_Valid)
+  if (st0_tag == TW_Valid)
     {
       int exp;
       FPU_REG tmp;
 
-      reg_move(FPU_st0_ptr, &tmp);
+      reg_move(st0_ptr, &tmp);
       exp = tmp.exp - EXP_BIAS;
 
       if ( exp < SINGLE_Emin )
@@ -692,7 +675,7 @@ int reg_store_single(void)
 #ifndef PECULIAR_486
          /* An 80486 is supposed to be able to generate
             a denormal exception here, but... */
-         if ( FPU_st0_ptr->exp <= EXP_UNDER )
+         if ( st0_ptr->exp <= EXP_UNDER )
            {
              /* Underflow has priority. */
              if ( control_word & CW_Underflow )
@@ -710,7 +693,7 @@ int reg_store_single(void)
                 that the 80486 rounds to the dest precision, then
                 converts to decide underflow. */
              if ( !((tmp.sigl == 0x00800000) &&
-                 ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) )
+                 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
 #endif PECULIAR_486
                {
                  EXCEPTION(EX_Underflow);
@@ -800,19 +783,19 @@ int reg_store_single(void)
            templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
        }
     }
-  else if (FPU_st0_tag == TW_Zero)
+  else if (st0_tag == TW_Zero)
     {
       templ = 0;
     }
-  else if (FPU_st0_tag == TW_Infinity)
+  else if (st0_tag == TW_Infinity)
     {
       templ = 0x7f800000;
     }
-  else if (FPU_st0_tag == TW_NaN)
+  else if (st0_tag == TW_NaN)
     {
       /* See if we can get a valid NaN from the FPU_REG */
-      templ = FPU_st0_ptr->sigh >> 8;
-      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
+      templ = st0_ptr->sigh >> 8;
+      if ( !(st0_ptr->sigh & 0x40000000) )
        {
          /* It is a signalling NaN */
          EXCEPTION(EX_Invalid);
@@ -822,7 +805,7 @@ int reg_store_single(void)
        }
       templ |= 0x7f800000;
     }
-  else if ( FPU_st0_tag == TW_Empty )
+  else if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
@@ -846,7 +829,7 @@ int reg_store_single(void)
       return 0;
     }
 #endif
-  if (FPU_st0_ptr->sign)
+  if (st0_ptr->sign)
     templ |= 0x80000000;
 
   RE_ENTRANT_CHECK_OFF;
@@ -859,27 +842,27 @@ int reg_store_single(void)
 
 
 /* Put a long long into user memory */
-int reg_store_int64(void)
+int reg_store_int64(long long *d, FPU_REG *st0_ptr)
 {
-  long long *d = (long long *)FPU_data_address;
   FPU_REG t;
   long long tll;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-          (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+          (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   ((long *)&tll)[0] = t.sigl;
   ((long *)&tll)[1] = t.sigh;
@@ -918,26 +901,26 @@ int reg_store_int64(void)
 
 
 /* Put a long into user memory */
-int reg_store_int32(void)
+int reg_store_int32(long *d, FPU_REG *st0_ptr)
 {
-  long *d = (long *)FPU_data_address;
   FPU_REG t;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-          (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+          (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   if (t.sigh ||
       ((t.sigl & 0x80000000) &&
@@ -972,26 +955,26 @@ int reg_store_int32(void)
 
 
 /* Put a short into user memory */
-int reg_store_int16(void)
+int reg_store_int16(short *d, FPU_REG *st0_ptr)
 {
-  short *d = (short *)FPU_data_address;
   FPU_REG t;
   int precision_loss;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
-  else if ( (FPU_st0_tag == TW_Infinity) ||
-          (FPU_st0_tag == TW_NaN) )
+  else if ( (st0_tag == TW_Infinity) ||
+          (st0_tag == TW_NaN) )
     {
       EXCEPTION(EX_Invalid);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   if (t.sigh ||
       ((t.sigl & 0xffff8000) &&
@@ -1026,23 +1009,23 @@ int reg_store_int16(void)
 
 
 /* Put a packed bcd array into user memory */
-int reg_store_bcd(void)
+int reg_store_bcd(char *d, FPU_REG *st0_ptr)
 {
-  char *d = (char *)FPU_data_address;
   FPU_REG t;
   unsigned long long ll;
   unsigned char b;
   int i, precision_loss;
-  unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+  unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+  char st0_tag = st0_ptr->tag;
 
-  if ( FPU_st0_tag == TW_Empty )
+  if ( st0_tag == TW_Empty )
     {
       /* Empty register (stack underflow) */
       EXCEPTION(EX_StackUnder);
       goto invalid_operand;
     }
 
-  reg_move(FPU_st0_ptr, &t);
+  reg_move(st0_ptr, &t);
   precision_loss = round_to_int(&t);
   ll = significand(&t);
 
@@ -1163,36 +1146,32 @@ int round_to_int(FPU_REG *r)
 
 /*===========================================================================*/
 
-char *fldenv(fpu_addr_modes addr_modes)
+char *fldenv(fpu_addr_modes addr_modes, char *s)
 {
-  char *s = (char *)FPU_data_address;
   unsigned short tag_word = 0;
   unsigned char tag;
   int i;
 
-  if ( addr_modes.mode16
-      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+  if ( (addr_modes.default_mode == VM86) ||
+      ((addr_modes.default_mode == PM16)
+      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_READ, s, 0x0e);
       control_word = get_fs_word((unsigned short *) s);
       partial_status = get_fs_word((unsigned short *) (s+2));
       tag_word = get_fs_word((unsigned short *) (s+4));
-      ip_offset = get_fs_word((unsigned short *) (s+6));
-      cs_selector = get_fs_word((unsigned short *) (s+8));
-      data_operand_offset = get_fs_word((unsigned short *) (s+0x0a));
-      operand_selector = get_fs_word((unsigned short *) (s+0x0c));
+      instruction_address.offset = get_fs_word((unsigned short *) (s+6));
+      instruction_address.selector = get_fs_word((unsigned short *) (s+8));
+      operand_address.offset = get_fs_word((unsigned short *) (s+0x0a));
+      operand_address.selector = get_fs_word((unsigned short *) (s+0x0c));
       RE_ENTRANT_CHECK_ON;
       s += 0x0e;
-      if ( addr_modes.vm86 )
-       {
-         ip_offset += (cs_selector & 0xf000) << 4;
-         data_operand_offset += (operand_selector & 0xf000) << 4;
-       }
-      else if ( addr_modes.p286 )
+      if ( addr_modes.default_mode == VM86 )
        {
-         ip_offset += LDT_BASE_ADDR(cs_selector);
-         data_operand_offset += LDT_BASE_ADDR(operand_selector);
+         instruction_address.offset
+           += (instruction_address.selector & 0xf000) << 4;
+         operand_address.offset += (operand_address.selector & 0xf000) << 4;
        }
     }
   else
@@ -1202,10 +1181,11 @@ char *fldenv(fpu_addr_modes addr_modes)
       control_word = get_fs_word((unsigned short *) s);
       partial_status = get_fs_word((unsigned short *) (s+4));
       tag_word = get_fs_word((unsigned short *) (s+8));
-      ip_offset = get_fs_long((unsigned long *) (s+0x0c));
-      cs_selector = get_fs_long((unsigned long *) (s+0x10));
-      data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
-      operand_selector = get_fs_long((unsigned long *) (s+0x18));
+      instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c));
+      instruction_address.selector = get_fs_word((unsigned short *) (s+0x10));
+      instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12));
+      operand_address.offset = get_fs_long((unsigned long *) (s+0x14));
+      operand_address.selector = get_fs_long((unsigned long *) (s+0x18));
       RE_ENTRANT_CHECK_ON;
       s += 0x1c;
     }
@@ -1254,37 +1234,26 @@ char *fldenv(fpu_addr_modes addr_modes)
         remains correct */
     }
 
-  /* Ensure that the values just loaded are not changed by
-     fix-up operations. */
-  NO_NET_DATA_EFFECT;
-  NO_NET_INSTR_EFFECT;
-
   return s;
 }
 
 
-void frstor(fpu_addr_modes addr_modes)
+void frstor(fpu_addr_modes addr_modes, char *data_address)
 {
   int i, stnr;
   unsigned char tag;
-  char *s = fldenv(addr_modes);
+  char *s = fldenv(addr_modes, data_address);
 
   for ( i = 0; i < 8; i++ )
     {
       /* Load each register. */
-      FPU_data_address = (void *)(s+i*10);
-      reg_load_extended();
       stnr = (i+top) & 7;
-      tag = regs[stnr].tag;   /* Derived from the loaded tag word. */
-      reg_move(&FPU_loaded_data, &regs[stnr]);
+      tag = regs[stnr].tag;   /* Derived from the fldenv() loaded tag word. */
+      reg_load_extended((long double *)(s+i*10), &regs[stnr]);
       if ( tag == TW_Empty )  /* The loaded data over-rides all other cases. */
        regs[stnr].tag = tag;
     }
 
-  /* Reverse the effect which loading the registers had on the
-     data pointer */
-  NO_NET_DATA_EFFECT;
-
 }
 
 
@@ -1318,12 +1287,11 @@ unsigned short tag_word(void)
 }
 
 
-char *fstenv(fpu_addr_modes addr_modes)
+char *fstenv(fpu_addr_modes addr_modes, char *d)
 {
-  char *d = (char *)FPU_data_address;
-
-  if ( addr_modes.mode16
-      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+  if ( (addr_modes.default_mode == VM86) ||
+      ((addr_modes.default_mode == PM16)
+      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
     {
       RE_ENTRANT_CHECK_OFF;
       FPU_verify_area(VERIFY_WRITE,d,14);
@@ -1334,19 +1302,19 @@ char *fstenv(fpu_addr_modes addr_modes)
 #endif PECULIAR_486
       put_fs_word(status_word(), (unsigned short *) (d+2));
       put_fs_word(tag_word(), (unsigned short *) (d+4));
-      put_fs_word(ip_offset, (unsigned short *) (d+6));
-      put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a));
-      if ( addr_modes.vm86 )
+      put_fs_word(instruction_address.offset, (unsigned short *) (d+6));
+      put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a));
+      if ( addr_modes.default_mode == VM86 )
        {
-         put_fs_word((ip_offset & 0xf0000) >> 4,
+         put_fs_word((instruction_address.offset & 0xf0000) >> 4,
                      (unsigned short *) (d+8));
-         put_fs_word((data_operand_offset & 0xf0000) >> 4,
+         put_fs_word((operand_address.offset & 0xf0000) >> 4,
                      (unsigned short *) (d+0x0c));
        }
       else
        {
-         put_fs_word(cs_selector, (unsigned short *) (d+8));
-         put_fs_word(operand_selector, (unsigned short *) (d+0x0c));
+         put_fs_word(instruction_address.selector, (unsigned short *) (d+8));
+         put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c));
        }
       RE_ENTRANT_CHECK_ON;
       d += 0x0e;
@@ -1365,14 +1333,16 @@ char *fstenv(fpu_addr_modes addr_modes)
       put_fs_word(status_word(), (unsigned short *) (d+4));
       put_fs_word(tag_word(), (unsigned short *) (d+8));
 #endif PECULIAR_486
-      put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
-      put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
-      put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
+      put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c));
+      put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10));
+      put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12));
+      put_fs_long(operand_address.offset, (unsigned long *) (d+0x14));
 #ifdef PECULIAR_486
       /* An 80486 sets all the reserved bits to 1. */
-      put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
+      put_fs_word(operand_address.selector, (unsigned short *) (d+0x18));
+      put_fs_word(0xffff, (unsigned short *) (d+0x1a));
 #else
-      put_fs_long(operand_selector, (unsigned long *) (d+0x18));
+      put_fs_long(operand_address.selector, (unsigned long *) (d+0x18));
 #endif PECULIAR_486
       RE_ENTRANT_CHECK_ON;
       d += 0x1c;
@@ -1385,12 +1355,12 @@ char *fstenv(fpu_addr_modes addr_modes)
 }
 
 
-void fsave(fpu_addr_modes addr_modes)
+void fsave(fpu_addr_modes addr_modes, char *data_address)
 {
   char *d;
   int i;
 
-  d = fstenv(addr_modes);
+  d = fstenv(addr_modes, data_address);
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,80);
   RE_ENTRANT_CHECK_ON;
index 88a6bbd9a1d2c9070b29f3801e181b65c7bae8db..33c4bd2bb4965ba7258cc1ac37f1472ad5a004a5 100644 (file)
@@ -82,7 +82,7 @@
 #define        UNMASKED_UNDERFLOW $2
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*     Make the code re-entrant by putting
        local storage on the stack: */
 #define FPU_bits_lost  (%esp)
@@ -97,7 +97,7 @@ FPU_bits_lost:
        .byte   0
 FPU_denormal:
        .byte   0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -127,9 +127,9 @@ fpu_reg_round:                      /* Normal entry point */
 
 fpu_reg_round_sqrt:            /* Entry point from wm_sqrt.S */
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        pushl   %ebx            /* adjust the stack pointer */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 #ifdef PARANOID
 /* Cannot use this here yet */
@@ -417,9 +417,9 @@ xL_Store_significand:
        jge     L_overflow
 
 fpu_reg_round_exit:
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        popl    %ebx            /* adjust the stack pointer */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 fpu_Arith_exit:
        popl    %ebx
index 0098324d62ddb0232439224715c19d12e50108f5..328e9116ec94a03de1ea1ce18a81bc662302b088 100644 (file)
@@ -29,7 +29,7 @@
 /* #define     dSIGH(x)        4(x) */
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*
        Local storage on the stack:
        Result:         FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
@@ -65,7 +65,7 @@ FPU_result_2:
        .long   0
 FPU_ovfl_flag:
        .byte   0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -78,9 +78,9 @@ FPU_ovfl_flag:
 _reg_u_div:
        pushl   %ebp
        movl    %esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        subl    $28,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
        pushl   %esi
        pushl   %edi
index d041bf3e44807173313decaa22b699ae6cf2183a..8250666bd87904cfe36e79d0ef019c334618de65 100644 (file)
@@ -27,7 +27,7 @@
 
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*  Local storage on the stack: */
 #define FPU_accum_0    -4(%ebp)        /* ms word */
 #define FPU_accum_1    -8(%ebp)
@@ -40,7 +40,7 @@ FPU_accum_0:
        .long   0
 FPU_accum_1:
        .long   0
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -50,9 +50,9 @@ FPU_accum_1:
 _reg_u_mul:
        pushl   %ebp
        movl    %esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        subl    $8,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
        pushl   %esi
        pushl   %edi
index 83fcc74c2996fa68fe005accafb555dd1208eafb..1dc3b1a00e949085c0e030a06251abd7b91bac5a 100644 (file)
@@ -9,5 +9,4 @@
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version Beta 1.11"
-
+#define FPU_VERSION "wm-FPU-emu version 1.12"
index 7f8b6c60aad5917ecef8d71c4f491c40b96e9f5a..4e028cb80753467b0bf5b3156e57d278b4f97b39 100644 (file)
@@ -29,7 +29,7 @@
 #include "fpu_asm.h"
 
 
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
 /*     Local storage on the stack: */
 #define FPU_accum_3    -4(%ebp)        /* ms word */
 #define FPU_accum_2    -8(%ebp)
@@ -70,7 +70,7 @@ FPU_fsqrt_arg_1:
        .long   0
 FPU_fsqrt_arg_0:
        .long   0               /* ls word, at most the ms bit is set */
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
 
 
 .text
@@ -80,9 +80,9 @@ FPU_fsqrt_arg_0:
 _wm_sqrt:
        pushl   %ebp
        movl    %esp,%ebp
-#ifdef REENTRANT_FPU
+#ifndef NON_REENTRANT_FPU
        subl    $28,%esp
-#endif REENTRANT_FPU
+#endif NON_REENTRANT_FPU
        pushl   %esi
        pushl   %edi
        pushl   %ebx
index 1f8d09a6a72eaabdc014e86fd1da6f7ff30cf063..88473f34bc20fd77c2ea50a55a0282c1a28835a6 100644 (file)
@@ -1,41 +1,58 @@
-This is release 1.4 of the SoundBlaster Pro (Matsushita, Kotobuki,
-Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
+This README belongs to release 1.6 of the SoundBlaster Pro (Matsushita,
+Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of IDE-style
-Matsushita/Kotobuki/Panasonic drives (the "double speed" versions
-like CR-562 and CR-563, too), and it will work with the soundcard
-interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with
-the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...).
+Matsushita/Kotobuki/Panasonic drives (the "double speed" versions like CR-562
+and CR-563, too), and it will work with the soundcard interfaces (SB Pro,
+SB 16, Galaxy, SoundFX, ...) and/or with the "no-sound" cards (Panasonic
+CI-101P, LaserMate, Aztech, ...).
+It should work too now with the "configurable" interface "Sequoia S-1000",
+which is found on the Spea Media FX sound card.
 The interface type has to get configured in /usr/include/linux/sbpcd.h, 
 because the behavior is different.
 
-The driver respects different drive firmware releases - my old drive
-is a 2.11, but it should work with "old" drives <2.01 ... >3.00
-and with "new" drives (which count the releases around 0.75 or
-1.00).
-
-Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives
-can be mixed, but the CR-521 ones are hard-wired to drive ID 0. 
-The drives have to use different drive IDs, but the same controller 
-(it will be a little bit harder to support up to four interface cards - 
-but I plan to do it the day somebody wishes to connect a fifth drive).
-Each drive has to get a unique minor number (0...3), corresponding
-to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
-they must not be in consecutive order.
-
-The driver supports reading of data from the CD and playing of
-audio tracks. The audio part should run with WorkMan, xcdplayer,
-with the "non-X11" products CDplayer and WorkBone - tell me if
-it is not compatible with other software.
-
-MultiSession is supported (but "old" drives lack this capability),
-"ManySession" (see below) alternatively.
-Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package 
-to convert photo CD image files.
-
-The transfer rate will reach 150 kB/sec with "old" drives and
-the full 300 kB/sec with double-speed drives. XA (PhotoCD) disks
-with "old" drives are as slow as 50 kB/sec.
+The driver respects different drive firmware releases - my old drive is a 2.11,
+but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
+(which count the releases around 0.75 or 1.00).
+
+Up to 4 drives are supported. CR-52x ("old") and CR-56x ("new") drives can be
+mixed, but the CR-521 ones are hard-wired to drive ID 0. 
+
+As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible
+to change old drives to any ID, too. He writes in this sense:
+   "In order to be able to use more than one single speed drive
+   (they do not have the ID jumpers) you must add a DIP switch
+   and two resistors. The pads are already on the board next to
+   the power connector. You will see the silkscreen for the
+   switch if you remove the top cover.
+                    1 2 3 4
+             ID 0 = x F F x             O = "on"
+             ID 1 = x O F x             F = "off"
+             ID 2 = x F O x             x = "don't care"
+             ID 3 = x O O x
+   Next to the switch are the positions for R76 (7k) and R78
+   (12k). I had to play around with the resistor values - ID 3
+   did not work with other values. If the values are not good,
+   ID 3 behaves like ID 0."
+
+The drives have to use different drive IDs, but the same controller (it will
+be a little bit harder to support up to four interface cards -  but I plan to
+do it the day somebody wishes to connect a fifth drive).
+Each drive has to get a unique minor number (0...3), corresponding to it's
+drive ID. The drive IDs may be selected freely from 0 to 3 - they must not be
+in consecutive order.
+
+The driver supports reading of data from the CD and playing of audio tracks.
+The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
+CDplayer and WorkBone - tell me if it is not compatible with other software.
+
+MultiSession is supported (even my "old" CR-521 can handle it), "ManySession"
+(not recommended, see below) alternatively.
+Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's
+package to convert photo CD image files.
+
+The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
+double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
 
 This release is part of the standard kernel and consists of
 - this README file
@@ -46,43 +63,47 @@ This release is part of the standard kernel and consists of
 To install:
 -----------
 
-1. Setup your hardware parameters. Though the driver does "auto-probing"
-   now, this step is recommended for every-day use.
-   a. Go into /usr/src/linux/include/linux/sbpcd.h and configure
-      it for your hardware (near the beginning):
+1. Setup your hardware parameters. Though the driver does "auto-probing" at a
+   lot of (not all possible!) addresses, this step is recommended for
+   every-day use.
+   a. Go into /usr/src/linux/include/linux/sbpcd.h and configure it for your
+      hardware (near the beginning):
       a1. Set it up for the appropriate type of interface board.
-          Most "compatible" sound boards (for example "Highscreen",
-          "SoundFX" and "Galaxy") need the "SBPRO 0" setup. The
-          "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+          "Original" CreativeLabs sound cards need "SBPRO 1".
+          Most "compatible" sound cards (for example "Highscreen", "SoundFX"
+          and "Galaxy") need "SBPRO 0".
+          The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+          The Spea Media FX sound card needs "SBPRO 2".
           sbpcd.c holds some examples in it's auto-probe list.
-      a2. Tell the address of your CDROM_PORT.
+          If you configure "SBPRO" wrong, the playing of audio CDs will work,
+          but you will not be able to mount a data CD.
+      a2. Tell the address of your CDROM_PORT (not of the sound port).
    b. Additionally for 2.a1 and 2.a2, the setup may be done during
       boot time (via the "kernel command line" or "LILO option"):
           sbpcd=0x230,SoundBlaster
       or
           sbpcd=0x320,LaserMate
+      or
+          sbpcd=0x330,SPEA
       (these strings are case sensitive!).
-
-2. Do a "make config" and select "yes" for Matsushita CD-ROM
-   support and for ISO9660 FileSystem support.
+      This is especially useful if you install a fresh distribution.
+2. Do a "make config" and select "yes" for Matsushita CD-ROM support and for
+   ISO9660 FileSystem support.
    SCSI and/or SCSI CD-ROM support is not needed.
 
-3. Then do a "make dep", then make the kernel image ("make zlilo"
-   or else).
-
-4. Make the device file(s). The driver uses definitely and exclusive
-   the MAJOR 25, so do
+3. Then do a "make dep", then make the kernel image ("make zlilo" or else).
 
+4. Make the device file(s). The driver uses definitely and exclusive the
+   MAJOR 25, so do
         mknod /dev/sbpcd b 25 0       (if you have only drive #0)
-and/or
+   and/or
         mknod /dev/sbpcd0 b 25 0
         mknod /dev/sbpcd1 b 25 1
         mknod /dev/sbpcd2 b 25 2
         mknod /dev/sbpcd3 b 25 3
-
    to make the node(s).
-   Take care that you create a node with the same MINOR as your drive
-   id is. So, if the DOS driver tells you have drive id #3, you have to
+   Take care that you create a node with the same MINOR as your drive ID is.
+   So, if the DOS driver tells you have drive id #3, you have to
         mknod /dev/<any_name> b 25 3
    
    If you further make a link like
@@ -91,123 +112,120 @@ and/or
 
 5. Reboot with the new kernel.
 
-You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt"
-and see the contents of your CD in the /mnt directory, and/or
-hear music with "workman -c /dev/sbpcd &".
+You should now be able to do "mount -t iso9660 -o block=2048 /dev/sbpcd /mnt"
+and see the contents of your CD in the /mnt directory, and/or hear music with
+"workman -c /dev/sbpcd &".
 
 
 Things of interest:
 -------------------
 
-The driver is configured to try the SoundBlaster Pro type of
-interface at I/O port 0x0230 first. If this is not appropriate,
-sbpcd.h should get changed (you will find the right place -
-just at the beginning).
-
-No DMA and no IRQ is used, so the IRQ adjusting is not necessary,
-and the IRQ line stays free for the SB Pro sound drivers.
-
-To reduce or increase the amount of kernel messages, edit
-sbpcd.c and change the initialization of the variable
-"sbpcd_debug". This is the way to get rid of the initial
-warning message block, too.
-
-With "#define MANY_SESSION 1" (sbpcd.c), the driver can use
-"many-session" CDs. This will work only with "new" drives like 
-CR-562 or CR-563. That is NOT multisession - it is a CD
-with multiple independent sessions, each containing block
-addresses as if it were the only session. With this feature
-enabled, the driver will read the LAST session. Without it,
-the FIRST session gets read.
-If you would like the support of reading "in-between" sessions,
-drop me a mail and some food for the soul. :-)
-Those "many-session" CDs can get made by CDROM writers like
-Philips CDD 521.
-If you enable this feature, it is impossible to read true
-multisession CDs.
+The driver is configured to try the SoundBlaster Pro type of interface at
+I/O port 0x0230 first. If this is not appropriate, sbpcd.h should get changed
+(you will find the right place - just at the beginning).
+
+No DMA and no IRQ is used, so the IRQ line stays free for the SB Pro sound
+drivers.
+
+To reduce or increase the amount of kernel messages, edit sbpcd.c and change
+the initialization of the variable "sbpcd_debug". This is the way to get rid
+of the initial warning message block, too.
+
+With "#define MANY_SESSION 1" (sbpcd.c), the driver can use "many-session" CDs.
+This will work only with "new" drives like CR-562 or CR-563. That is NOT
+multisession - it is a CD with multiple independent sessions, each containing
+block addresses as if it were the only session. With this feature enabled, the
+driver will read the LAST session. Without it, the FIRST session gets read.
+If you would like the support of reading "in-between" sessions, drop me a mail
+and some food for the soul. :-)
+Those "many-session" CDs can get made by CDROM writers like Philips CDD 521.
+If you enable this feature, it is impossible to read true multisession CDs.
+
+The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
+specify "block=2048" as a mount option.
 
 
 Auto-probing at boot time:
 --------------------------
 
-The driver does auto-probing at all well-known interface card
-addresses now. The idea to do that came from Adam J. Richter 
-(YGGDRASIL).
+The driver does auto-probing at many well-known interface card addresses. The
+idea to do that came from Adam J. Richter (YGGDRASIL). Some well-known
+addresses are excluded from auto-probing because they can cause a hang if an
+ethernet card gets touched.
 
-This auto-probing looks first at the configured address resp.
-the address submitted by the kernel command line. With this,
-it is possible to use this driver within installation boot
-floppies, and for any non-standard address, too.
+This auto-probing looks first at the configured address resp. the address
+submitted by the kernel command line. With this, it is possible to use this
+driver within installation boot floppies, and for any non-standard address,
+too.
 
-Auto-probing will make an assumption about the interface type 
-("SBPRO" or not), based upon the address. That assumption may
-be wrong (initialization will be o.k., but you will get I/O
-errors during mount). In that case, use the "kernel command 
-line" feature and specify address & type at boot time to find 
-out the right setup.
+Auto-probing will make an assumption about the interface type ("SBPRO" or not),
+based upon the address. That assumption may be wrong (initialization will be
+o.k., but you will get I/O errors during mount). In that case, use the "kernel
+command line" feature and specify address & type at boot time to find out the
+right setup.
 
-SBPCD's auto-probing happens before the initialization of the
-net drivers. That makes a hang possible if an ethernet card
-gets touched.
+SBPCD's auto-probing happens before the initialization of the net drivers. That
+makes a hang possible if an ethernet card gets touched.
 
-For every-day use, address and type should get configured
-within sbpcd.h. That will stop the auto-probing due to success
-with the first try.
+For every-day use, address and type should get configured within sbpcd.h. That
+will stop the auto-probing due to success with the first try.
 
 
 Setting up address and interface type:
 --------------------------------------
 
-If your I/O port address is not 0x0230 or if you use a "no-sound"
-interface other than OmniCD, you have to look for the #defines
-near the beginning of sbpcd.h and configure them: set SBPRO to
-0 or 1, and change CDROM_PORT to the address of your CDROM I/O port.
+If your I/O port address is not 0x0230 or if you use a "no-sound" interface
+other than OmniCD, you have to look for the #defines near the beginning of
+sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and change CDROM_PORT to
+the address of your CDROM I/O port.
 
-Most of the "SoundBlaster compatible" cards behave like the
-no-sound interfaces! 
+Most of the "SoundBlaster compatible" cards behave like the no-sound
+interfaces! 
 
-With "original" SB Pro cards, an initial setting of CD_volume
-through the sound cards MIXER register gets done. That happens
-at the end of "sbpcd_init". If you are using a "compatible"
-sound card of type "LaserMate", you can change that code to get
-it done with your card, too...
+With "original" SB Pro cards, an initial setting of CD_volume through the
+sound cards MIXER register gets done. That happens at the end of "sbpcd_init".
+If you are using a "compatible" sound card of type "LaserMate", you can change
+that code to get it done with your card, too...
 
 
 Using audio CDs:
 ----------------
 
-Workman, WorkBone, xcdplayer and cdplayer should work good now,
-even with the double-speed drives.
+Workman, WorkBone, xcdplayer and cdplayer should work good now, even with the
+double-speed drives.
 
-The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer
-wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate
-links for using them without the need of supplying parameters.
+The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants
+"/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate links for using
+them without the need of supplying parameters.
 
 
 Known problems:
 ---------------
 
-Currently, the detection of disk change or removal does not
-work as good as it should.
+Currently, the detection of disk change or removal does not work as good as it
+should.
+
+The "door (un)lock" commands get done at every "(u)mount" (only the "new"
+drives support it), but after an unlock, locking again does not work properly.
 
-The "door (un)lock" commands get done at every "(u)mount" (only the
-"new" drives support it), but after an unlock, locking again does not
-work.
+All attempts to read the UPC/EAN code result in a stream of zeroes. All my
+drives are telling there is no UPC/EAN code on disk or there is, but it is an
+all-zero number.
 
-All attempts to read the UPC/EAN code result in a stream of zeroes.
-All my drives are telling there is no UPC/EAN code on disk or there
-is, but it is an all-zero number.
+My attempts to read audio tracks like data files are of no success. Contact me,
+if you have an idea, please.
 
-Bug reports, comments, wishes, donations (technical information
-is a donation, too :-) etc. to
+Bug reports, comments, wishes, donations (technical information is a donation,
+too :-) etc. to
                          emoenke@gwdg.de
  or to                   eberhard_moenkeberg@rollo.central.de
  or to my FIDO address:  Eberhard Moenkeberg, 2:2437/210.27
 
 
-SnailMail address, preferable for CD editors if they want to submit
-a free "cooperation" copy:
+SnailMail address, preferable for CD editors if they want to submit a free
+"cooperation" copy:
                          Eberhard Moenkeberg
                          Reinholdstr. 14
                          D-37083 Goettingen
                          Germany
+---
index faa5adfc527fd504767a1f6e30a561b6a134bc40..f21eb238eca0fe27b4066cc706a7c52ec3fad0ee 100644 (file)
@@ -82,6 +82,9 @@ extern int * blksize_size[MAX_BLKDEV];
 extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
 extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end);
 extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end);
+#ifdef CONFIG_SBPCD
+extern unsigned long sbpcd_init(unsigned long, unsigned long);
+#endif CONFIG_SBPCD
 extern int is_read_only(int dev);
 extern void set_device_ro(int dev,int flag);
 
index a39d1b4fe65d2e236ad6972c50d13ec7f31ad510..daae20f010addb411c745c18b55c7d1d3e8b95e2 100644 (file)
 
 #include "blk.h"
 
-#ifdef CONFIG_SBPCD
-extern u_long sbpcd_init(u_long, u_long);
-#endif CONFIG_SBPCD
-
 /*
  * The request-struct contains all necessary data
  * to load a nr of sectors into memory
index 9e2246a71c82ea6be1734db37a769d93d7e6ff88..42f7e5d98d98ab885988445337c0e4d8816333fe 100644 (file)
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 1.5.
+ *  NOTE:     This is release 1.6.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
  *       Adapt to kernel 1.1.8 change (have to explicitely include
  *       <linux/string.h> now).
  *
+ *  1.6  Trying to read audio frames as data. Impossible with the current
+ *       drive firmware levels, as it seems. Awaiting any hint. ;-)
+ *       Changed "door unlock": repeat it until success.
+ *       Changed CDROMSTOP routine (stop somewhat "softer" so that Workman
+ *       won't get confused).
+ *       Added a third interface type: Sequoia S-1000, as used with the SPEA
+ *       Media FX sound card. This interface (useable for Sony and Mitsumi 
+ *       drives, too) needs a special configuration setup and behaves like a 
+ *       LaserMate type after that. Still experimental - I do not have such
+ *       an interface.
+ *       Use the "variable BLOCK_SIZE" feature (2048). But it does only work
+ *       if you give the mount option "block=2048".
+ *       The media_check routine is currently disabled; now that it gets
+ *       called as it should I fear it must get synchronized for not to
+ *       disturb the normal driver's activity.
+ *
  *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
  *     elaborated speed-up experiments (and the fabulous results!), for
  *     the "push" towards load-free wait loops, and for the extensive mail
 #include <linux/errno.h>
 
 #include <linux/sched.h>
+/* #undef DS */
 #include <linux/timer.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/sbpcd.h>
 #include <linux/string.h>
-
-#if SBPCD_USE_IRQ
-#include <linux/signal.h>
-#endif SBPCD_USE_IRQ
-
 #include <linux/major.h> 
-
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
 #include "blk.h"
 
-#define VERSION "1.5 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "1.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
 #define XA_TEST2
 
 #define TEST_UPC 0
+#define READ_AUDIO 0 /* does not work today (the drives won't read audio) */
 
 /*==========================================================================*/
 /*==========================================================================*/
 #undef LONG_TIMING
 #define LONG_TIMING 1
 #endif
-
 /*==========================================================================*/
+#if SBPCD_DIS_IRQ
+#define SBPCD_CLI cli()
+#define SBPCD_STI sti()
+#else
+#define SBPCD_CLI
+#define SBPCD_STI
+#endif SBPCD_DIS_IRQ
 /*==========================================================================*/
 /*
  * auto-probing address list
@@ -201,6 +219,10 @@ static int autoprobe[] =
   0x650, 0, /* "sound card #9" */
   0x670, 0, /* "sound card #9" */
   0x690, 0, /* "sound card #9" */
+  0x330, 2, /* SPEA Media FX (default) */
+  0x320, 2, /* SPEA Media FX */
+  0x340, 2, /* SPEA Media FX */
+  0x350, 2, /* SPEA Media FX */
 #if 0
 /* some "hazardous" locations (ethernet cards) */
   0x330, 0, /* Lasermate, CI-101P */
@@ -227,7 +249,7 @@ static int  sbp_data(void);
  * pattern for printk selection:
  *
  * (1<<DBG_INF)  necessary information
- * (1<<DBG_IRQ)  interrupt trace
+ * (1<<DBG_BSZ)  BLOCK_SIZE trace
  * (1<<DBG_REA)  "read" status trace
  * (1<<DBG_CHK)  "media check" trace
  * (1<<DBG_TIM)  datarate timer test
@@ -250,6 +272,7 @@ static int  sbp_data(void);
  * (1<<DBG_XA)   XA mode debugging
  * (1<<DBG_LCK)  door (un)lock info
  * (1<<DBG_SQ)   dump SubQ frame
+ * (1<<DBG_AUD)  "read audio" debugging
  * (1<<DBG_000)  unnecessary information
  */
 #if 1
@@ -261,7 +284,9 @@ static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_IOC) |
                           (1<<DBG_XA)  |
                           (1<<DBG_LCK) |
-                          (1<<DBG_SQ)  |
+                          (1<<DBG_CHK) |
+                          (1<<DBG_AUD) |
+                          (1<<DBG_BSZ) |
                           (1<<DBG_IOX);
 #endif
 static int sbpcd_ioaddr = CDROM_PORT;  /* default I/O base address */
@@ -278,6 +303,7 @@ static struct cdrom_subchnl SC;
 static struct cdrom_volctrl volctrl;
 char *str_sb = "SoundBlaster";
 char *str_lm = "LaserMate";
+char *str_sp = "SPEA";
 char *type;
 
 /*==========================================================================*/
@@ -323,6 +349,8 @@ static u_char drv_pattern[4]={ 0x80, 0x80, 0x80, 0x80 }; /* auto speed */
 /*  /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
 /*  /N:... ndrives=i-'0';                             */
 
+static int sbpcd_blocksizes[NR_SBPCD] = {0, };
+
 /*==========================================================================*/
 /*
  * drive space begins here (needed separate for each unit) 
@@ -341,6 +369,12 @@ static struct {
   int sbp_read_frames;   /* Number of frames being read to buffer */
   int sbp_current;       /* Frame being currently read */
 
+  u_char mode;           /* read_mode: READ_M1, READ_M2, READ_SC, READ_AU */
+#if READ_AUDIO
+  u_char *aud_buf;                  /* Pointer to internal data buffer,
+                                 space allocated during sbpcd_init() */
+#endif READ_AUDIO
+
   u_char drv_type;
   u_char drv_options;
   u_char status_byte;
@@ -405,7 +439,7 @@ static struct {
   
   int in_SpinUp;
   
-} DriveStruct[4];
+} DriveStruct[NR_SBPCD];
 
 /*
  * drive space ends here (needed separate for each unit)
@@ -739,14 +773,10 @@ static void xx_ReadStatus(void)
   if (!new_drive) OUT(CDo_command,0x81);
   else
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       OUT(CDo_command,0x05);
       for (i=0;i<6;i++) OUT(CDo_command,0);
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
 }
 /*==========================================================================*/
@@ -791,21 +821,17 @@ int cmd_out(void)
       for (i=0;i<7;i++) DPRINTF((DBG_CMD," %02X",drvcmd[i]));
       DPRINTF((DBG_CMD,"\n"));
 
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
   if (response_count!=0)
     {
       if (cmd_type!=0)
        {
-         if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+         if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
          DPRINTF((DBG_INF,"SBPCD: misleaded to try ResponseData.\n"));
-         if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+         if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
          return (-22);
        }
       else i=ResponseInfo();
@@ -1738,7 +1764,7 @@ static int switch_drive(int num)
   d=num;
 
   i=num;
-  if (sbpro_type) i=(i&0x01)<<1|(i&0x02)>>1;
+  if (sbpro_type==1) i=(i&0x01)<<1|(i&0x02)>>1;
   OUT(CDo_enable,i);
   DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DriveStruct[d].drv_minor));
   return (0);
@@ -1951,6 +1977,10 @@ static int DiskInfo(void)
 {
   int i;
 
+#if READ_AUDIO
+      DriveStruct[d].mode=READ_M1;
+#endif READ_AUDIO
+
   i=SetSpeed();
   if (i<0)
     {
@@ -2139,6 +2169,51 @@ static int xx_PlayAudioMSF(int pos_audio_start,int pos_audio_end)
 }
 /*==========================================================================*/
 /*==========================================================================*/
+/*==========================================================================*/
+/*
+ * Called from the timer to check the results of the get-status cmd.
+ */
+static int sbp_status(void)
+{
+  int st;
+
+  st=ResponseStatus();
+  if (st<0)
+    {
+      DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
+      return (0);
+    }
+
+  if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
+
+  if (st_check) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
+      return (0);
+    }
+  if (!st_door_closed)
+    {
+      DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
+      return (0);
+    }
+  if (!st_caddy_in)
+    {
+      DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
+      return (0);
+    }
+  if (!st_diskok) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
+      return (0);
+    }
+  if (st_busy) 
+    {
+      DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
+      return (0);
+    }
+  return (1);
+}
+/*==========================================================================*/
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -2310,14 +2385,8 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
 
     case CDROMSTOP:      /* Spin down the drive */
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n"));
-      i=DriveReset();
-#if WORKMAN
-      DriveStruct[d].CD_changed=0xFF;
-      DriveStruct[d].diskstate_flags=0;
-#endif WORKMAN
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: DriveReset returns %d\n",i));
+      i=xx_Pause_Resume(1);
       DriveStruct[d].audio_state=0;
-      i=DiskInfo();
       return (0);
 
     case CDROMSTART:  /* Spin up the drive */
@@ -2396,14 +2465,238 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
               SC.cdsc_absaddr,SC.cdsc_reladdr));
       return (0);
 
+    case CDROMREADMODE1:
+      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
+      xx_ModeSelect(CD_FRAMESIZE);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M1;
+      return (0);
+
     case CDROMREADMODE2:
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n"));
-      return (-EINVAL);
+      xx_ModeSelect(CD_FRAMESIZE_XA);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M2;
+      return (0);
+
+#if READ_AUDIO
+    case CDROMREADAUDIO:
+      { /* start of CDROMREADAUDIO */
+
+      int i=0, j=0, frame, block;
+      u_int try=0;
+      u_long timeout;
+      u_char *p;
+      u_int data_tries = 0;
+      u_int data_waits = 0;
+      u_int data_retrying = 0;
+      int status_tries;
+      int error_flag;
+      struct cdrom_aud aud_arg;
+
+      error_flag=0;
+
+#if 0
+#define AUD_FRM_SIZ CD_FRAMESIZE_RAW
+#else
+#define AUD_FRM_SIZ CD_FRAMESIZE_XA
+#endif
+
+      DPRINTF((DBG_IOC,"SBPCD: read_audio: ioctl: CDROMREADAUDIO requested.\n"));
+
+      i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_aud));
+      if (i) return (i);
+      memcpy_fromfs(&aud_arg, (void *) arg, sizeof(struct cdrom_aud));
+      i=verify_area(VERIFY_WRITE, aud_arg.buf, AUD_FRM_SIZ);
+      if (i) return (i);
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: lba: %d, buffer: %08X\n", aud_arg.lba, aud_arg.buf));
+
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: before xx_ReadStatus.\n"));
+      for (data_tries=5; data_tries>0; data_tries--)
+       {
+         DPRINTF((DBG_AUD,"SBPCD: data_tries=%d ...\n", data_tries));
+         DriveStruct[d].mode=READ_AU;
+         xx_ModeSelect(AUD_FRM_SIZ);
+         xx_ModeSense();
+
+
+         for (status_tries=3; status_tries > 0; status_tries--)
+           {
+             flags_cmd_out |= f_respo3;
+             xx_ReadStatus();
+             if (sbp_status() != 0) break;
+             sbp_sleep(1);    /* wait a bit, try again */
+           }
+         if (status_tries == 0)
+           {
+             DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: failed after 3 tries.\n"));
+             continue;
+           }
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_status: ok.\n"));
+
+
+         block=aud_arg.lba;
+         flags_cmd_out = f_putcmd |
+                         f_respo2 |
+                          f_ResponseStatus |
+                          f_obey_p_check;
+
+
+
+
+         if (!new_drive)
+           {
+             flags_cmd_out |= f_lopsta | f_getsta | f_bit1;
+             cmd_type=READ_M2;
+             drvcmd[0]=0x03;   /* "read XA frames" command for old drives */
+             drvcmd[1]=(block>>16)&0x000000ff;
+             drvcmd[2]=(block>>8)&0x000000ff;
+             drvcmd[3]=block&0x000000ff;
+             drvcmd[4]=0;
+             drvcmd[5]=1;   /* # of frames */
+             drvcmd[6]=0;
+           }
+         else /* if new_drive */
+           {
+             drvcmd[0]=0x10;              /* "read frames" command for new drives */
+             lba2msf(block,&drvcmd[1]); /* msf-bin format required */
+             drvcmd[4]=0;
+             drvcmd[5]=0;
+             drvcmd[6]=1;   /* # of frames */
+           }
+
+
+
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: before giving \"read\" command.\n"));
+         for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
+
+         sbp_sleep(0);
+
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: after giving \"read\" command.\n"));
+         for (frame=1;frame<2 && !error_flag; frame++)
+           {
+             try=maxtim_data;
+             for (timeout=jiffies+900; ; )
+               {
+                 for ( ; try!=0;try--)
+                   {
+                     j=inb(CDi_status);
+                     if (!(j&s_not_data_ready)) break;
+                     if (!(j&s_not_result_ready)) break;
+                     if (!new_drive) if (j&s_attention) break;
+                   }
+                 if (try != 0 || timeout <= jiffies) break;
+                 if (data_retrying == 0) data_waits++;
+                 data_retrying = 1;
+                 sbp_sleep(1);
+                 try = 1;
+               }
+             if (try==0)
+               {
+                 DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status timeout.\n"));
+                 error_flag++;
+                 break;
+               }
+             DPRINTF((DBG_INF,"SBPCD: read_audio: sbp_data: CDi_status ok.\n"));
+             
+             if (j&s_not_data_ready)
+               {
+                 printk("SBPCD: read_audio: sbp_data: DATA_READY timeout.\n");
+                 error_flag++;
+                 break;
+               }
+             
+             DPRINTF((DBG_AUD,"SBPCD: read_audio: before reading data.\n"));
+             CLEAR_TIMER;
+             error_flag=0;
+             p = DriveStruct[d].aud_buf;
+             if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
+             READ_DATA(CDi_data, p, AUD_FRM_SIZ);
+             if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
+             data_retrying = 0;
+           }
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: after reading data.\n"));
+         if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
+           {
+             DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
+#if 0000
+             i=DriveReset();                /* ugly fix to prevent a hang */
+#endif 0000
+             continue;
+           }
+
+         if (!new_drive)
+           {
+             i=maxtim_data;
+             for (timeout=jiffies+900; timeout > jiffies; timeout--)
+               {
+                 for ( ;i!=0;i--)
+                   {
+                     j=inb(CDi_status);
+                     if (!(j&s_not_data_ready)) break;
+                     if (!(j&s_not_result_ready)) break;
+                     if (j&s_attention) break;
+                   }
+                 if (i != 0 || timeout <= jiffies) break;
+                 sbp_sleep(0);
+                 i = 1;
+               }
+             if (i==0) { DPRINTF((DBG_AUD,"SBPCD: read_audio: STATUS TIMEOUT AFTER READ")); }
+             if (!(j&s_attention))
+               {
+                 DPRINTF((DBG_AUD,"SBPCD: read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
+                 i=DriveReset();  /* ugly fix to prevent a hang */
+                 continue;
+               }
+           }
+
+         do
+           {
+             if (!new_drive) xx_ReadStatus();
+             i=ResponseStatus();  /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
+             if (i<0) { DPRINTF((DBG_AUD,
+                                 "SBPCD: read_audio: xx_ReadStatus error after read: %02X\n",
+                                 DriveStruct[d].status_byte));
+                        continue; /* FIXME */
+                      }
+           }
+         while ((!new_drive)&&(!st_check)&&(!(i&p_success_old)));
+         if (st_check)
+           {
+             i=xx_ReadError();
+             DPRINTF((DBG_AUD,"SBPCD: read_audio: xx_ReadError was necessary after read: %02X\n",i));
+             continue;
+           }
+         memcpy_tofs((u_char *) aud_arg.buf,
+                     (u_char *) DriveStruct[d].aud_buf, AUD_FRM_SIZ);
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: memcpy_tofs done.\n"));
+         break;
+       }
+      xx_ModeSelect(CD_FRAMESIZE);
+      xx_ModeSense();
+      DriveStruct[d].mode=READ_M1;
+
+
+      if (data_tries == 0)
+       {
+         DPRINTF((DBG_AUD,"SBPCD: read_audio: failed after 5 tries.\n"));
+         return (-8);
+       }
+      DPRINTF((DBG_AUD,"SBPCD: read_audio: successful return.\n"));
+      return (0);
+    } /* end of CDROMREADAUDIO */
+#endif READ_AUDIO
+
+
+
+
+    case BLKRASET:
+      if(!suser())  return -EACCES;
+      if(!inode->i_rdev) return -EINVAL;
+      if(arg > 0xff) return -EINVAL;
+      read_ahead[MAJOR(inode->i_rdev)] = arg;
+      return (0);
 
-    case CDROMREADMODE1:
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n"));
-      return (-EINVAL);
-      
     default:
       DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd));
       return (-EINVAL);
@@ -2430,63 +2723,6 @@ static void sbp_transfer(void)
     }
 }
 /*==========================================================================*/
-/*
- *  We seem to get never an interrupt.
- */
-#if SBPCD_USE_IRQ
-static void sbpcd_interrupt(int unused)
-{
-  int st;
-  
-  st = inb(CDi_status) & 0xFF;
-  DPRINTF((DBG_IRQ,"SBPCD: INTERRUPT received - CDi_status=%02X\n", st));
-}
-#endif SBPCD_USE_IRQ
-/*==========================================================================*/
-/*
- * Called from the timer to check the results of the get-status cmd.
- */
-static int sbp_status(void)
-{
-  int st;
-
-  st=ResponseStatus();
-  if (st<0)
-    {
-      DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n"));
-      return (0);
-    }
-
-  if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n"));
-
-  if (st_check) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n"));
-      return (0);
-    }
-  if (!st_door_closed)
-    {
-      DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n"));
-      return (0);
-    }
-  if (!st_caddy_in)
-    {
-      DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n"));
-      return (0);
-    }
-  if (!st_diskok) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n"));
-      return (0);
-    }
-  if (st_busy) 
-    {
-      DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n"));
-      return (0);
-    }
-  return (1);
-}
-/*==========================================================================*/
 /*
  *  I/O request routine, called from Linux kernel.
  */
@@ -2513,9 +2749,8 @@ request_loop:
   switch_drive(dev);
 
   INIT_REQUEST;
-  block = CURRENT->sector;
-  nsect = CURRENT->nr_sectors;
-
+  block = CURRENT->sector; /* always numbered as 512-byte-pieces */
+  nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */
   if (CURRENT->cmd != READ)
     {
       printk("SBPCD: bad cmd %d\n", CURRENT->cmd);
@@ -2523,11 +2758,11 @@ request_loop:
       goto request_loop;
     }
 
+  DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
   DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
-  sbp_transfer();
 
+  sbp_transfer();
   /* if we satisfied the request from the buffer, we're done. */
-
   if (CURRENT->nr_sectors == 0)
     {
       end_request(1);
@@ -2535,7 +2770,8 @@ request_loop:
     }
 
   i=prepare(0,0); /* at moment not really a hassle check, but ... */
-  if (i!=0) DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
+  if (i!=0)
+    DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i));
 
   if (!st_spinning) xx_SpinUp();
 
@@ -2674,13 +2910,9 @@ static void sbp_read_cmd(void)
       drvcmd[5]=0;
       drvcmd[6]=DriveStruct[d].sbp_read_frames;
     }
-#if SBPCD_DIS_IRQ
-  cli();
-#endif SBPCD_DIS_IRQ
+  SBPCD_CLI;
   for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-#if SBPCD_DIS_IRQ
-  sti();
-#endif SBPCD_DIS_IRQ
+  SBPCD_STI;
 
   return;
 }
@@ -2704,9 +2936,7 @@ static int sbp_data(void)
 
   for (frame=DriveStruct[d].sbp_current;frame<DriveStruct[d].sbp_read_frames&&!error_flag; frame++)
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       try=maxtim_data;
 #if LONG_TIMING
       for (timeout=jiffies+900; ; )
@@ -2742,20 +2972,17 @@ static int sbp_data(void)
          error_flag++;
          break;
        }
-      
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
 
+      SBPCD_STI;
       CLEAR_TIMER;
       error_flag=0;
       p = DriveStruct[d].sbp_buf + frame *  CD_FRAMESIZE;
 
-      if (sbpro_type) OUT(CDo_sel_d_i,0x01);
+      if (sbpro_type==1) OUT(CDo_sel_d_i,0x01);
       if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_head_buf, CD_XA_HEAD);
       READ_DATA(CDi_data, p, CD_FRAMESIZE);
       if (cmd_type==READ_M2) READ_DATA(CDi_data, xa_tail_buf, CD_XA_TAIL);
-      if (sbpro_type) OUT(CDo_sel_d_i,0x00);
+      if (sbpro_type==1) OUT(CDo_sel_d_i,0x00);
       DriveStruct[d].sbp_current++;
       if (cmd_type==READ_M2)
        {
@@ -2773,9 +3000,7 @@ static int sbp_data(void)
          data_waits = data_tries = 0;
        }
     }
-#if SBPCD_DIS_IRQ
-  sti();
-#endif SBPCD_DIS_IRQ
+  SBPCD_STI;
   
   if (error_flag)    /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
     {
@@ -2786,9 +3011,7 @@ static int sbp_data(void)
 
   if (!new_drive)
     {
-#if SBPCD_DIS_IRQ
-      cli();
-#endif SBPCD_DIS_IRQ
+      SBPCD_CLI;
       i=maxtim_data;
       for (timeout=jiffies+100; timeout > jiffies; timeout--)
        {
@@ -2808,14 +3031,10 @@ static int sbp_data(void)
        {
          DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n"));
          i=DriveReset();  /* ugly fix to prevent a hang */
-#if SBPCD_DIS_IRQ
-         sti();
-#endif SBPCD_DIS_IRQ
+         SBPCD_STI;
          return (0);
        }
-#if SBPCD_DIS_IRQ
-      sti();
-#endif SBPCD_DIS_IRQ
+      SBPCD_STI;
     }
 
   do
@@ -2916,7 +3135,12 @@ static void sbpcd_release(struct inode * ip, struct file * file)
  */
   DPRINTF((DBG_LCK,"SBPCD: open_count: %d -> %d\n",
           DriveStruct[d].open_count,DriveStruct[d].open_count-1));
-  if (--DriveStruct[d].open_count==0) yy_LockDoor(0);
+  if (--DriveStruct[d].open_count==0) 
+    {
+      do
+       i=yy_LockDoor(0);
+      while (i!=0);
+    }
 }
 /*==========================================================================*/
 /*
@@ -2932,22 +3156,11 @@ static struct file_operations sbpcd_fops =
   sbpcd_ioctl,            /* ioctl */
   NULL,                   /* mmap */
   sbpcd_open,             /* open */
-  sbpcd_release           /* release */
+  sbpcd_release,          /* release */
+  NULL,                   /* fsync */
+  NULL                    /* fasync */
 };
 /*==========================================================================*/
-/*
- *  SBP interrupt descriptor
- */
-#if SBPCD_USE_IRQ
-static struct sigaction sbpcd_sigaction =
-{
-  sbpcd_interrupt,
-  0,
-  SA_INTERRUPT,
-  NULL
-};
-#endif SBPCD_USE_IRQ
-/*==========================================================================*/
 /*
  * accept "kernel command line" parameters 
  * (suggested by Peter MacDonald with SLS 1.03)
@@ -2956,6 +3169,8 @@ static struct sigaction sbpcd_sigaction =
  *                 sbpcd=0x230,SoundBlaster
  *             or
  *                 sbpcd=0x300,LaserMate
+ *             or
+ *                 sbpcd=0x330,SPEA
  *
  * (upper/lower case sensitive here!!!).
  *
@@ -2966,8 +3181,9 @@ static struct sigaction sbpcd_sigaction =
 void sbpcd_setup(char *s, int *p)
 {
   DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s));
+  sbpro_type=0;
   if (!strcmp(s,str_sb)) sbpro_type=1;
-  else sbpro_type=0;
+  else if (!strcmp(s,str_sp)) sbpro_type=2;
   if (p[0]>0) sbpcd_ioaddr=p[1];
 
   CDo_command=sbpcd_ioaddr;
@@ -2985,6 +3201,57 @@ void sbpcd_setup(char *s, int *p)
   else CDi_data=sbpcd_ioaddr+2;
 }
 /*==========================================================================*/
+/*
+ * Sequoia S-1000 CD-ROM Interface Configuration
+ * as used within SPEA Media FX card
+ * The SPEA soundcard has to get jumpered for 
+ *     -> interface type "Matsushita/Panasonic" (not Sony or Mitsumi)
+ *     -> I/O base address (0x320, 0x330, 0x340, 0x350)
+ */
+int config_spea(void)
+{
+  int n_ports=0x10; /* 2:0x00, 8:0x10, 16:0x20, 32:0x30 */
+  int irq_number=0; /* 2:0x01, 7:0x03, 12:0x05, 15:0x07, OFF:0x00 */
+  int dma_channel=0; /* 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68, 7:0x78, OFF: 0x00 */
+  int dack_polarity=0; /* L:0x00, H:0x80 */
+  int drq_polarity=0x40; /* L:0x00, H:0x40 */
+
+  int i;
+
+#define SPEA_REG_1 sbpcd_ioaddr+4
+#define SPEA_REG_2 sbpcd_ioaddr+5
+
+  OUT(SPEA_REG_1,0xFF);
+  i=inb(SPEA_REG_1);
+  if (i!=0x0F)
+    {
+      DPRINTF((DBG_INF,"SBPCD: no SPEA interface at %04X present.\n",
+              sbpcd_ioaddr));
+      return (-1); /* no interface found */
+    }
+  OUT(SPEA_REG_1,0x04);
+  OUT(SPEA_REG_2,0xC0);
+
+  OUT(SPEA_REG_1,0x05);
+  OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity);
+
+#if 1
+#define SPEA_PATTERN 0x80
+#else
+#define SPEA_PATTERN 0x00
+#endif
+  OUT(SPEA_REG_1,0x06);
+  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+  OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN);
+
+  OUT(SPEA_REG_1,0x09);
+  i=(inb(SPEA_REG_2)&0xCF)|n_ports;
+  OUT(SPEA_REG_2,i);
+
+  sbpro_type = 0; /* acts like a LaserMate interface now */
+  return (0);
+}
+/*==========================================================================*/
 /*
  *  Test for presence of drive and initialize it.  Called at boot time.
  */
@@ -3006,6 +3273,8 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
   DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x230,SoundBlaster\n"));
   DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
   DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x300,LaserMate\n"));
+  DPRINTF((DBG_WRN,"SBPCD: or like:\n"));
+  DPRINTF((DBG_WRN,"SBPCD:    LILO boot: linux sbpcd=0x330,SPEA\n"));
   DPRINTF((DBG_WRN,"SBPCD: \n"));
   DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n"));
   DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
@@ -3021,13 +3290,19 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
       if (check_region(addr[1],4)) continue;
       DPRINTF((DBG_INI,"SBPCD: check_region done.\n"));
       if (autoprobe[port_index+1]==0) type=str_lm;
-      else type=str_sb;
+      else if (autoprobe[port_index+1]==1) type=str_sb;
+      else type=str_sp;
       sbpcd_setup(type, addr);
       DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n",
                     type, CDo_command));
 
       DPRINTF((DBG_INF,"SBPCD: - "));
       sti(); /* to avoid possible "printk" bug */
+      if (autoprobe[port_index+1]==2)
+       {
+         i=config_spea();
+         if (i<0) continue;
+       }
       i=check_drives();
       DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
       sti(); /* to avoid possible "printk" bug */
@@ -3098,62 +3373,66 @@ u_long sbpcd_init(u_long mem_start, u_long mem_end)
       if (i>=0) DriveStruct[d].CD_changed=1;
     }
 
-  if (sbpro_type)
+  if (sbpro_type==1)
     {
       OUT(MIXER_addr,MIXER_CD_Volume);
       OUT(MIXER_data,0xCC); /* one nibble per channel */
     }
   
-  if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0)
+  if (register_blkdev(MAJOR_NR, "sbpcd", &sbpcd_fops) != 0)
     {
-      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n",
-              MATSUSHITA_CDROM_MAJOR);
+      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR);
       sti(); /* to avoid possible "printk" bug */
       return (mem_start);
     }
-  blk_dev[MATSUSHITA_CDROM_MAJOR].request_fn = DEVICE_REQUEST;
-  read_ahead[MATSUSHITA_CDROM_MAJOR] = 4; /* just one frame */ 
+  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
   
   snarf_region(CDo_command,4);
 
-#if SBPCD_USE_IRQ
-  if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction))
+  for (j=0;j<NR_SBPCD;j++)
     {
-      printk("SBPCD: Can't get IRQ%d for sbpcd driver\n", SBPCD_INTR_NR);
-      sti(); /* to avoid possible "printk" bug */
-    }
-#endif SBPCD_USE_IRQ
-
+      if (DriveStruct[j].drv_minor==-1) continue;
 /*
  * allocate memory for the frame buffers
  */ 
-  for (j=0;j<NR_SBPCD;j++)
-    {
-      if (DriveStruct[j].drv_minor==-1) continue;
       DriveStruct[j].sbp_buf=(u_char *)mem_start;
       mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
+#if READ_AUDIO
+      DriveStruct[j].aud_buf=(u_char *)mem_start;
+      mem_start += CD_FRAMESIZE_RAW;
+#endif READ_AUDIO
+/*
+ * set the block size
+ */
+      sbpcd_blocksizes[j]=CD_FRAMESIZE;
     }
+  blksize_size[MAJOR_NR]=sbpcd_blocksizes;
+
   DPRINTF((DBG_INF,"SBPCD: init done.\n"));
   sti(); /* to avoid possible "printk" bug */
   return (mem_start);
 }
 /*==========================================================================*/
 /*
- * adopted from sr.c
- *
  * Check if the media has changed in the CD-ROM drive.
- * used externally (isofs/inode.c) - but still does not work.
- *
+ * used externally (isofs/inode.c, fs/buffer.c)
+ * Currently disabled (has to get "synchronized").
  */
 int check_sbpcd_media_change(int full_dev, int unused_minor)
 {
   int st;
 
-  if (MAJOR(full_dev) != MATSUSHITA_CDROM_MAJOR) 
+  DPRINTF((DBG_CHK,"SBPCD: media_check (%d) called\n", MINOR(full_dev)));
+  return (0); /* "busy" test necessary before we really can check */
+
+  if ((MAJOR(full_dev)!=MAJOR_NR)||(MINOR(full_dev)>=NR_SBPCD))
     {
-      printk("SBPCD: media_check: invalid device.\n");
+      printk("SBPCD: media_check: invalid device %04X.\n", full_dev);
       return (-1);
     }
+
+  switch_drive(MINOR(full_dev));
   
   xx_ReadStatus();                         /* command: give 1-byte status */
   st=ResponseStatus();
index 290ac256b3c50cf7eae1dfe3f8ba41fb855d6c19..91cb8e2e09bdebe1e3dedd22deaf86cb0475b2a7 100644 (file)
@@ -281,6 +281,14 @@ static struct device ppp0_dev = {
 #define NEXT_DEV (&ppp0_dev)
 #endif   /* PPP */
 
+#ifdef CONFIG_DUMMY
+    extern int dummy_init(struct device *dev);
+    static struct device dummy_dev = {
+       "dummy", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, dummy_init, };
+#   undef      NEXT_DEV
+#   define     NEXT_DEV        (&dummy_dev)
+#endif
+
 #ifdef LOOPBACK
     extern int loopback_init(struct device *dev);
     static struct device loopback_dev = {
index 8f87fa08266d3a4b2c953a16f8c26ea8509053e0..83bae0407c42140f719379c12f15b8f9dc8e8b96 100644 (file)
@@ -94,6 +94,7 @@ static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
 int ppp_init(struct device *);
 static void ppp_init_ctrl_blk(struct ppp *);
 static int ppp_dev_open(struct device *);
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr);
 static int ppp_dev_close(struct device *);
 static void ppp_kick_tty(struct ppp *);
 
@@ -264,6 +265,7 @@ ppp_init(struct device *dev)
   dev->mtu             = PPP_MTU;
   dev->hard_start_xmit = ppp_xmit;
   dev->open            = ppp_dev_open;
+  dev->do_ioctl        = ppp_dev_ioctl;
   dev->stop            = ppp_dev_close;
   dev->get_stats       = ppp_get_stats;
   dev->hard_header     = ppp_header;
@@ -601,6 +603,32 @@ ppp_dev_close(struct device *dev)
   return 0;
 }
 
+static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
+{
+  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+  int    error;
+
+  struct stats
+  {
+    struct ppp_stats  ppp_stats;
+    struct slcompress slhc;
+  } *result;
+
+  error = verify_area (VERIFY_READ,
+                      ifr->ifr_ifru.ifru_data,
+                      sizeof (struct stats));
+
+  if (error == 0) {
+    result = (struct stats *) ifr->ifr_ifru.ifru_data;
+
+    memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats));
+    if (ppp->slcomp)
+      memcpy_tofs (&result->slhc,    ppp->slcomp, sizeof (struct slcompress));
+  }
+
+  return error;
+}
+
 /*************************************************************
  * TTY OUTPUT
  *    The following function delivers a fully-formed PPP
@@ -882,6 +910,8 @@ static void ppp_receive_buf(struct tty_struct *tty, unsigned char *cp,
   if (ppp_debug >= 5) {
     ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS);
   }
+
+  ppp->stats.rbytes += count;
  
   while (count-- > 0) {
     c = *cp++;
@@ -1367,7 +1397,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i));
       temp_i = (int) get_fs_long (l);
       if (ppp->mru != temp_i)
-       ppp_changedmtu (ppp, ppp->mtu, temp_i);
+       ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
     }
     break;
 
index b8d92ba35d39d66f4c552778805c72f441f3cafe..2f80a3a335e2a8c5947133162f19f85f9903411e 100644 (file)
@@ -562,7 +562,6 @@ int buslogic_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        if (bufflen != sizeof SCpnt->sense_buffer) {
            buslogic_printk("Wrong buffer length supplied for request sense (%d)\n",
                            bufflen);
-           panic("buslogic.c: wrong buffer length for request sense");
        }
 #endif
        SCpnt->result = 0;
@@ -781,6 +780,7 @@ static int setup_mailboxes(unsigned int base, struct Scsi_Host *SHpnt)
        buslogic_printk("buslogic_detect: failed setting up mailboxes\n");
     }
     ok = TRUE;
+    return ok;
   must_be_adaptec:
     INTR_RESET(base);
     printk("- must be Adaptec\n"); /* So that the adaptec detect looks clean */
@@ -888,7 +888,6 @@ static int getconfig(unsigned int base, unsigned char *irq,
 /* Query the board to find out the model. */
 static int buslogic_query(unsigned int base, int *trans)
 {
-#if 0
     unsigned const char inquiry_cmd[] = { CMD_INQUIRY };
     unsigned char inquiry_result[4];
     int i;
@@ -899,14 +898,18 @@ static int buslogic_query(unsigned int base, int *trans)
     buslogic_out(base, inquiry_cmd, sizeof inquiry_cmd);
     buslogic_in(base, inquiry_result, 4);
     WAIT_UNTIL(INTERRUPT(base), CMDC);
+    INTR_RESET(base);
+
+    buslogic_printk("Inquiry Bytes: %X %X %X %X\n",
+                   inquiry_result[0],inquiry_result[1],
+                   inquiry_result[2],inquiry_result[3]);
     while (0) {
       fail:
-       buslogic_printk("buslogic_detect: query card type\n");
+       buslogic_printk("buslogic_query: query board settings\n");
+       return TRUE;
     }
-    INTR_RESET(base);
-#endif
 
-    *trans = BIOS_TRANSLATION_6432;    /* Default case */
+    *trans = BIOS_TRANSLATION_6432;     /* Default case */
 
     return FALSE;
 }
@@ -1018,8 +1021,13 @@ int buslogic_detect(int hostnum)
 
            host[irq - 9] = SHpnt;
            SHpnt->this_id = id;
+#ifdef CONFIG_NO_BUGGY_BUSLOGIC
            /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */
            SHpnt->unchecked_isa_dma = (bus_type == 'A');
+#else
+           /* bugs in the firmware with 16M+. Gaah */
+           SHpnt->unchecked_isa_dma = 1;
+#endif
            SHpnt->sg_tablesize = max_sg;
            if (SHpnt->sg_tablesize > BUSLOGIC_MAX_SG)
                SHpnt->sg_tablesize = BUSLOGIC_MAX_SG;
index 6cbf5ce0a97e071c9f05b587c6618d16d60becef..c6d80b6d8380a57d72fa1d9f4b86cb236fb4dede 100644 (file)
@@ -44,6 +44,9 @@ extern int check_cdu31a_media_change(int, int);
 #ifdef CONFIG_MCD
 extern int check_mcd_media_change(int, int);
 #endif
+#ifdef CONFIG_SBPCD
+extern int check_sbpcd_media_change(int, int);
+#endif
 
 #define NR_SIZES 4
 static char buffersize_index[9] = {-1,  0,  1, -1,  2, -1, -1, -1, 3};
@@ -334,6 +337,12 @@ void check_disk_change(dev_t dev)
                break;
 #endif
 
+#if defined(CONFIG_SBPCD)
+         case MATSUSHITA_CDROM_MAJOR:
+               i = check_sbpcd_media_change(dev, 0);
+               break;
+#endif
+
          default:
                return;
        };
index 48efbed62068225b770fb1d11a04ad04159168b6..4370dd099739c1db3e84c61f45c42d5f3724292a 100644 (file)
@@ -8,6 +8,8 @@
  *                                 sbpcd=0x230,SoundBlaster
  *                             or
  *                                 sbpcd=0x300,LaserMate
+ *                             or
+ *                                 sbpcd=0x330,SPEA
  * these strings are case sensitive !!!
  */
 
@@ -17,6 +19,7 @@
  * set SBPRO to 1 for "true" SoundBlaster card
  * set SBPRO to 0 for "poor" (no sound) interface cards
  *                and for "compatible" soundcards.
+ * set SBPRO to 2 for the SPEA Media FX card
  *
  * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
  * if SBPRO gets set wrong, the drive will get found - but any
@@ -33,6 +36,7 @@
  * put your CDROM port base address here:
  * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
  * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
+ * SPEA addresses are 0x320, 0x330, 0x340, 0x350
  * there are some soundcards on the market with 0x0630, 0x0650, ...
  *
  * example: if your SBPRO audio address is 0x220, specify 0x230.
@@ -52,7 +56,7 @@
  * Debug output levels
  */
 #define DBG_INF                1       /* necessary information */
-#define DBG_IRQ                2       /* interrupt trace */
+#define DBG_BSZ                2       /* BLOCK_SIZE trace */
 #define DBG_REA                3       /* "read" status trace */
 #define DBG_CHK                4       /* "media check" trace */
 #define DBG_TIM                5       /* datarate timer test */
@@ -75,7 +79,8 @@
 #define DBG_XA                 22      /* XA mode debugging */
 #define DBG_LCK                23      /* door (un)lock info */
 #define DBG_SQ                 24      /* dump SubQ frame */
-#define DBG_000                25      /* unnecessary information */
+#define DBG_AUD                25      /* "read audio" debugging */
+#define DBG_000                26      /* unnecessary information */
 
 /*==========================================================================*/
 /*==========================================================================*/
 #define READ_M1  0x01 /* "data mode 1": 2048 bytes per frame */
 #define READ_M2  0x02 /* "data mode 2": 12+2048+280 bytes per frame */
 #define READ_SC  0x04 /* "subchannel info": 96 bytes per frame */
+#define READ_AU  0x08 /* "audio frame": 2352 bytes per frame */
+
+/*
+ * preliminary extensions to cdrom.h for transfering audio frames:
+ */
+#define CDROMREADAUDIO 0xE0 /* IOCTL function (arg = &cdrom_aud) */
+
+struct cdrom_aud { u_int lba; /* frame address */
+                   u_char *buf; /* frame buffer (2352 bytes) */
+                 };
 
 /*
  * sense byte: used only if new_drive
@@ -400,17 +415,6 @@ Read XA Parameter:
  */
 #define SBPCD_DIS_IRQ 0
 
-/*
- * we don't use the IRQ line - leave it free for the sound driver
- */
-#define SBPCD_USE_IRQ  0
-
-/*
- * you can set the interrupt number of your interface board here:
- * It is not used at this time. No need to set it correctly.
- */
-#define SBPCD_INTR_NR  7            
-
 /*
  * "write byte to port"
  */
@@ -463,9 +467,3 @@ typedef union _blk
 BLK;
 
 /*==========================================================================*/
-
-
-
-
-
-
index 20bfeae17dc76618a8cd68b0d9c87b31a83c319b..fb27ea6ab95128181eeb4f46322fdbfa435998ee 100644 (file)
@@ -18,7 +18,7 @@
 
 OBJS  = sched.o sys_call.o traps.o irq.o dma.o fork.o \
        panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
-       signal.o mktime.o ptrace.o ioport.o itimer.o \
+       signal.o ptrace.o ioport.o itimer.o \
        info.o ldt.o time.o tqueue.o vm86.o
 
 all: kernel.o
index 13fd24f793f8435f79ab2880b0defa14e4d4f290..45f489cb029ef03ab52fe3b578d8dc711a96b49a 100644 (file)
@@ -517,6 +517,8 @@ static void second_overflow(void)
        if (xtime.tv_sec > last_rtc_update + 660)
          if (set_rtc_mmss(xtime.tv_sec) == 0)
            last_rtc_update = xtime.tv_sec;
+         else
+           last_rtc_update = xtime.tv_sec - 600; /* do it again in one min */
 }
 
 /*
index 3161e8f9079938feb97aaf3174fa29d3a7c76ca5..92ecbc66dac6429cb4eba77d28a5533faf2939f8 100644 (file)
@@ -14,6 +14,8 @@
  *      Created file with time related functions from sched.c and adjtimex() 
  * 08 Oct 93    Torsten Duwe
  *      adjtime interface update and CMOS clock write code
+ * 02 Jul 94   Alan Modra
+ *     fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
  */
 
 #include <linux/config.h>
 #include <linux/timex.h>
 extern struct timeval xtime;
 
-#include <linux/mktime.h>
-extern long kernel_mktime(struct mktime * time);
+/* converts date to days since 1/1/1970
+ * assumes year,mon,day in normal date format
+ * ie. 1/1/1970 => year=1970, mon=1, day=1
+ *
+ * For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.
+ *
+ * This algorithm was first published by Gauss (I think).
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+       unsigned int day, unsigned int hour,
+       unsigned int min, unsigned int sec)
+{
+       if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
+               mon += 12;      /* Puts Feb last since it has leap day */
+               year -= 1;
+       }
+       return (((
+           (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+             year*365 - 719499
+           )*24 + hour /* now have hours */
+          )*60 + min /* now have minutes */
+         )*60 + sec; /* finally seconds */
+}
 
 void time_init(void)
 {
-       struct mktime time;
+       unsigned int year, mon, day, hour, min, sec;
        int i;
 
        /* checking for Update-In-Progress could be done more elegantly
@@ -53,25 +79,26 @@ void time_init(void)
                if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
                        break;
        do { /* Isn't this overkill ? UIP above should guarantee consistency */
-               time.sec = CMOS_READ(RTC_SECONDS);
-               time.min = CMOS_READ(RTC_MINUTES);
-               time.hour = CMOS_READ(RTC_HOURS);
-               time.day = CMOS_READ(RTC_DAY_OF_MONTH);
-               time.mon = CMOS_READ(RTC_MONTH);
-               time.year = CMOS_READ(RTC_YEAR);
-       } while (time.sec != CMOS_READ(RTC_SECONDS));
+               sec = CMOS_READ(RTC_SECONDS);
+               min = CMOS_READ(RTC_MINUTES);
+               hour = CMOS_READ(RTC_HOURS);
+               day = CMOS_READ(RTC_DAY_OF_MONTH);
+               mon = CMOS_READ(RTC_MONTH);
+               year = CMOS_READ(RTC_YEAR);
+       } while (sec != CMOS_READ(RTC_SECONDS));
        if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
          {
-           BCD_TO_BIN(time.sec);
-           BCD_TO_BIN(time.min);
-           BCD_TO_BIN(time.hour);
-           BCD_TO_BIN(time.day);
-           BCD_TO_BIN(time.mon);
-           BCD_TO_BIN(time.year);
+           BCD_TO_BIN(sec);
+           BCD_TO_BIN(min);
+           BCD_TO_BIN(hour);
+           BCD_TO_BIN(day);
+           BCD_TO_BIN(mon);
+           BCD_TO_BIN(year);
          }
-       time.mon--;
-       xtime.tv_sec = kernel_mktime(&time);
-      }
+       if ((year += 1900) < 1970)
+               year += 100;
+       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+}
 /* 
  * The timezone where the local system is located.  Used as a default by some
  * programs who obtain this value by using gettimeofday.
@@ -403,8 +430,8 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
 int set_rtc_mmss(unsigned long nowtime)
 {
   int retval = 0;
-  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-  unsigned char save_control, save_freq_select, cmos_minutes;
+  int real_seconds, real_minutes, cmos_minutes;
+  unsigned char save_control, save_freq_select;
 
   save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
   CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -419,11 +446,15 @@ int set_rtc_mmss(unsigned long nowtime)
   /* since we're only adjusting minutes and seconds,
    * don't interfere with hour overflow. This avoids
    * messing with unknown time zones but requires your
-   * RTC not to be off by more than 30 minutes
+   * RTC not to be off by more than 15 minutes
    */
-  if (((cmos_minutes < real_minutes) ?
-       (real_minutes - cmos_minutes) :
-       (cmos_minutes - real_minutes)) < 30)
+  real_seconds = nowtime % 60;
+  real_minutes = nowtime / 60;
+  if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+    real_minutes += 30;                /* correct for half hour time zone */
+  real_minutes %= 60;
+
+  if (abs(real_minutes - cmos_minutes) < 30)
     {
       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
        {
index e5119c9fdfd22abdd77cd749cf56110762632fbd..0748e937699a723f262676b06c25cf4be80462f3 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 
+/*
+ * Define this if things work differently on a i386 and a i486:
+ * it will (on a i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef CONFIG_TEST_VERIFY_AREA
+
 unsigned long high_memory = 0;
 
 extern unsigned long pg0[1024];                /* page table for 0-4MB for everybody */
@@ -902,10 +909,15 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
                        } else 
                                user_esp = regs->esp;
                }
-               if (error_code & PAGE_PRESENT)
+               if (error_code & PAGE_PRESENT) {
+#ifdef CONFIG_TEST_VERIFY_AREA
+                       if (regs->cs == KERNEL_CS)
+                               printk("WP fault at %08x\n", regs->eip);
+#endif
                        do_wp_page(error_code, address, current, user_esp);
-               else
+               } else {
                        do_no_page(error_code, address, current, user_esp);
+               }
                return;
        }
        address -= TASK_SIZE;
@@ -1124,6 +1136,9 @@ void mem_init(unsigned long start_low_mem,
        invalidate();
        if (wp_works_ok < 0)
                wp_works_ok = 0;
+#ifdef CONFIG_TEST_VERIFY_AREA
+       wp_works_ok = 0;
+#endif
        return;
 }
 
index b25c5395c935259770459a3635188ee7e1329228..ee51c9726a46985008038c5b54b7ab6414153aaf 100644 (file)
@@ -1137,7 +1137,7 @@ static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
                return -EINVAL;
        if(size==0)
                return 0;
-       err=verify_area(VERIFY_READ,ubuf,size);
+       err=verify_area(VERIFY_WRITE,ubuf,size);
        if(err)
                return err;
 
@@ -1259,6 +1259,8 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCSIFMAP:
                case SIOCGIFMAP:
                case SIOCDEVPRIVATE:
+               case SIOCSIFSLAVE:
+               case SIOCGIFSLAVE:
                        return(dev_ioctl(cmd,(void *) arg));
 
                default:
index d0b6fc638113489882da1b5fe9c5cd7e6a1bfcae..f5ceb5e4f29304f4b45e930d9cc168cf531ed9fd 100644 (file)
@@ -26,6 +26,7 @@
  *             Alan Cox        :       Make ARP add its own protocol entry
  *
  *              Ross Martin     :       Rewrote arp_rcv() and arp_get_info()
+ *             Stephen Henson  :       Add AX25 support to arp_get_info()
  */
 
 #include <linux/types.h>
@@ -846,6 +847,13 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
 /*
  *     Convert hardware address to XX:XX:XX:XX ... form.
  */
+#ifdef CONFIG_AX25
+
+                       if(entry->htype==ARPHRD_AX25)
+                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+                       else {
+#endif
+
                        for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->hlen;j++)
                        {
                                hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
@@ -854,6 +862,9 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length)
                        }
                        hbuffer[--k]=0;
        
+#ifdef CONFIG_AX25
+                       }
+#endif
                        size = sprintf(buffer+len,
                                "%-17s0x%-10x0x%-10x%s\n",
                                in_ntoa(entry->ip),
@@ -926,9 +937,6 @@ static int arp_req_set(struct arpreq *req)
         */
        
        switch (r.arp_ha.sa_family) {
-               case 0:
-                       /* Moan about this. ARP family 0 is NetROM and _will_ be needed */
-                       printk("Application using old BSD convention for arp set. Please recompile it.\n");
                case ARPHRD_ETHER:
                        htype = ARPHRD_ETHER;
                        hlen = ETH_ALEN;
index c439862108075177cd690e1ee38466b589bef313..ef8dbafde510cd05ca913e873eca4e0be559c906 100644 (file)
@@ -1267,7 +1267,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                                return -ENODEV;
                        }
                        cli();
-                       if(slave->flags&(IFF_UP|IFF_RUNNING)!=(IFF_UP|IFF_RUNNING))
+                       if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING))
                        {
                                restore_flags(flags);
                                return -EINVAL;
@@ -1275,7 +1275,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                        if(dev->flags&IFF_SLAVE)
                        {
                                restore_flags(flags);
-                               return -EINVAL;
+                               return -EBUSY;
                        }
                        if(dev->slave!=NULL)
                        {
index 41bf38049bc6aa7683094b00c89bfdfd3fe2b274..87f11ce5f1f658b342d5ee90f904df2d91d56ed9 100644 (file)
@@ -90,6 +90,7 @@ extern int last_retran;
 extern void sort_send(struct sock *sk);
 
 #define min(a,b)       ((a)<(b)?(a):(b))
+#define LOOPBACK(x)    (((x) & htonl(0xff000000)) == htonl(0x7f000000))
 
 /*
  *     SNMP management statistics
@@ -226,7 +227,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
                 *      If the frame is from us and going off machine it MUST MUST MUST
                 *      have the output device ip address and never the loopback
                 */
-               if (saddr == htonl(0x7F000001L) && daddr != htonl(0x7F000001L))
+               if (LOOPBACK(saddr) && !LOOPBACK(daddr))
                        saddr = src;/*rt->rt_dev->pa_addr;*/
                raddr = rt->rt_gateway;
 
@@ -245,7 +246,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
                 *      If the frame is from us and going off machine it MUST MUST MUST
                 *      have the output device ip address and never the loopback
                 */
-               if (saddr == 0x0100007FL && daddr != 0x0100007FL) 
+               if (LOOPBACK(saddr) && !LOOPBACK(daddr))
                        saddr = src;/*rt->rt_dev->pa_addr;*/
 
                raddr = (rt == NULL) ? 0 : rt->rt_gateway;