Date: Sun, 26 Oct 1997 18:50:44 +0000
From: Richard Hirst <richard@sleepie.demon.co.uk>
To: linux-m68k@lists.linux-m68k.org
Subject: Re: L68K: FPU Emulation patches
References: <19971026172812.59385@sleepie.demon.co.uk>
In-Reply-To: <19971026172812.59385@sleepie.demon.co.uk>; from Richard Hirst on Sun, Oct 26, 1997 at 05:28:12PM +0000
Sender: owner-linux-m68k@phil.uni-sb.de

On Sun, Oct 26, 1997 at 05:28:12PM +0000, Richard Hirst wrote:

...and then at 18:45 he wrote again including the patches (see below)!!!

> Hi,
>   Below are some patches for the fpu emulation code
> "ftp://ftp.nocrew.pp.se/pub/linux/mathemu-2.0.21.diff.gz".
> NOTE the diffs are not made from the head of the source tree.  I guess
> you want to 'cd arch/m68k/math-emu' and 'patch -p1' - sorry about that.
> 
> With these patches in a 2.0.29 tree, I can boot to multi-user, and the
> system is pretty stable.  It is not perfect; I have a perl script which
> doesn't run.  YMMV.
> 
> Without these patches I couldn't boot multi-user, and certainly couldn't
> run two simple programs which both use floating point at the same time.
> 
> I run this on a 68LC040 on a Motorola MVME162 board, so don't ask me to
> build you Atari/Amiga kernels with FPU emulation ;)
> 
> I fully support the idea of developing a new emulator, but given 
> constraints on my time, I figured it was worth fixing a few bugs in the
> existing code.
> 
> Richard.
> 


diff -cr orig/fpu_calc.c tidy/fpu_calc.c
*** orig/fpu_calc.c	Sat Sep 20 00:02:22 1997
--- tidy/fpu_calc.c	Sat Sep 20 00:20:02 1997
***************
*** 437,447 ****
                      
                      /* LC040 does a predecrement on its own; we don't need to do it*/
                      
                      if(m68k_is040or060 != 4)
                      		*reg -= step;
                      ea->ea_tdisp = 0;
                }
! 	    
  	     /* fix LC040 so that postincr= predecr+postincr */
  	     if ((ea->ea_flags & EA_POSTINCR) && (m68k_is040or060 == 4)) {
  #ifdef DEBUG
--- 437,451 ----
                      
                      /* LC040 does a predecrement on its own; we don't need to do it*/
                      
+ #ifdef LC040_DOES_PREDECREMENT
+ 		    /* Maybe some LC040s do predecrement, but mine certainly
+ 		     * doesn't.  Richard Hirst,  970920. */
                      if(m68k_is040or060 != 4)
+ #endif
                      		*reg -= step;
                      ea->ea_tdisp = 0;
                }
! #ifdef LC040_DOES_PREDECREMENT    
  	     /* fix LC040 so that postincr= predecr+postincr */
  	     if ((ea->ea_flags & EA_POSTINCR) && (m68k_is040or060 == 4)) {
  #ifdef DEBUG
***************
*** 454,460 ****
                      
                      		*reg -= step;
                }
! 
                /* Grab the register contents. */
                src = (char *)*reg;
  #ifdef DEBUG
--- 458,464 ----
                      
                      		*reg -= step;
                }
! #endif
                /* Grab the register contents. */
                src = (char *)*reg;
  #ifdef DEBUG
***************
*** 607,619 ****
                }
  #endif			
                      
                 /* LC040 does a predecrement on its own; we don't need to do it*/
                      
                 if(m68k_is040or060 != 4)
                      *reg -= step;
                 ea->ea_tdisp = 0;
            }
! 	    
  	  /* fix LC040 so that postincr= predecr+postincr */
  	  if ((ea->ea_flags & EA_POSTINCR) && (m68k_is040or060 == 4)) {
  #ifdef DEBUG
--- 611,625 ----
                }
  #endif			
                      
+ #ifdef LC040_DOES_PREDECREMENT    
                 /* LC040 does a predecrement on its own; we don't need to do it*/
                      
                 if(m68k_is040or060 != 4)
+ #endif
                      *reg -= step;
                 ea->ea_tdisp = 0;
            }
! #ifdef LC040_DOES_PREDECREMENT    
  	  /* fix LC040 so that postincr= predecr+postincr */
  	  if ((ea->ea_flags & EA_POSTINCR) && (m68k_is040or060 == 4)) {
  #ifdef DEBUG
***************
*** 626,633 ****
                      
                      		*reg -= step;
            }
!           
!           
  
            /* calculate the effective address */
            sig = calc_ea(ea, (char *)*reg, &dst);
--- 632,638 ----
                      
                      		*reg -= step;
            }
! #endif
  
            /* calculate the effective address */
            sig = calc_ea(ea, (char *)*reg, &dst);
diff -cr orig/fpu_emul.c tidy/fpu_emul.c
*** orig/fpu_emul.c	Sat Sep 20 00:02:22 1997
--- tidy/fpu_emul.c	Sat Sep 20 00:33:17 1997
***************
*** 89,97 ****
  
  int fpu_emulate(struct frame *frame, struct fpframe *fpf)
  {
!     static struct instruction insn;
!     static struct fpemu fe;
      int word, optype, sig;
  
  
      globlframe= frame;
--- 89,98 ----
  
  int fpu_emulate(struct frame *frame, struct fpframe *fpf)
  {
!     struct instruction insn;
!     struct fpemu fe;
      int word, optype, sig;
+     static int fpu_state_frame = 0;
  
  
      globlframe= frame;
***************
*** 147,152 ****
--- 148,162 ----
      insn.is_opcode = word;
      optype = (word & 0x01C0);
  
+     /*
+      * If this isn't an fsave/frestore, then the FPU is now in the
+      * IDLE state, not the NULL state.  The value 0x01000100 is chosen
+      * such that it should work for all CPU types.
+      */
+ 
+     if (optype != 0x0100 && optype != 0x0140)
+       fpu_state_frame = 0x01000100;
+ 
      word = fusword(frame->f_pc + 2);
  #ifdef DEBUG
      if (word < 0) {
***************
*** 234,246 ****
      } else if (optype == 0x0100) {
  
  
!           /* type 4: fsave (privileged): store NULL frame */
  	 	if((frame->f_sr &0x2000) !=0) {
  			insn.is_advance = 2;  /* 2 bytes long */
  			sig=fpu_decode_ea(frame, &insn, &insn.is_ea0,insn.is_opcode);
                  	insn.is_datasize=0x4;
! 			word= 0;   /* This is the actual NULL frame */	
! 			sig=fpu_store_ea(frame,&insn,&insn.is_ea0,(char*) &word);
  #ifdef DEBUG
  			if (fpu_debug_level & DL_INSN)
  				printk("  fpu_emulate: fsave\n");
--- 244,255 ----
      } else if (optype == 0x0100) {
  
  
!           /* type 4: fsave (privileged): store state frame */
  	 	if((frame->f_sr &0x2000) !=0) {
  			insn.is_advance = 2;  /* 2 bytes long */
  			sig=fpu_decode_ea(frame, &insn, &insn.is_ea0,insn.is_opcode);
                  	insn.is_datasize=0x4;
! 			sig=fpu_store_ea(frame,&insn,&insn.is_ea0,(char*) &fpu_state_frame);
  #ifdef DEBUG
  			if (fpu_debug_level & DL_INSN)
  				printk("  fpu_emulate: fsave\n");
***************
*** 258,266 ****
  			insn.is_advance = 2;   /* 2 bytes long */
  			sig=fpu_decode_ea(frame,&insn,&insn.is_ea0,insn.is_opcode);
  			insn.is_datasize=0x4;
! 			/* Restore a NULL frame. Note that this can be the
!  			 * only type that needs to be restored */
! 			sig=fpu_load_ea(frame,&insn,&insn.is_ea0,(char*) &word);
  #ifdef DEBUG
  			if (fpu_debug_level & DL_INSN)
  				printk("  fpu_emulate: frestore\n");
--- 267,274 ----
  			insn.is_advance = 2;   /* 2 bytes long */
  			sig=fpu_decode_ea(frame,&insn,&insn.is_ea0,insn.is_opcode);
  			insn.is_datasize=0x4;
! 			/* Restore a state frame */
! 			sig=fpu_load_ea(frame,&insn,&insn.is_ea0,(char*) &fpu_state_frame);
  #ifdef DEBUG
  			if (fpu_debug_level & DL_INSN)
  				printk("  fpu_emulate: frestore\n");
***************
*** 414,419 ****
--- 422,428 ----
      int sig;
      int reglist;
      int fpu_to_mem;
+     int mask;
  
      /* move to/from control registers */
      reglist = (insn->is_word1 & 0x1c00) >> 10;
***************
*** 434,490 ****
            return SIGILL;
      }
  
!     if (reglist & 4) {
!           /* fpcr */
!           if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
!               insn->is_ea0.ea_regnum >= 8 /* address reg */) {
!               /* attempted to copy FPCR to An */
! #ifdef DEBUG
!               printk("  fpu_emul_fmovmcr: tried to copy FPCR from/to A%d\n",
!                        insn->is_ea0.ea_regnum & 7);
! #endif
!               return SIGILL;
!           }
!           if (fpu_to_mem) {
!               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                      (char *)&fpf->fpf_fpcr);
!           } else {
!               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                     (char *)&fpf->fpf_fpcr);
!           }
!     }
!     if (sig) { return sig; }
! 
!     if (reglist & 2) {
!           /* fpsr */
!           if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
!               insn->is_ea0.ea_regnum >= 8 /* address reg */) {
!               /* attempted to copy FPSR to An */
! #ifdef DEBUG
!               printk("  fpu_emul_fmovmcr: tried to copy FPSR from/to A%d\n",
!                        insn->is_ea0.ea_regnum & 7);
! #endif
!               return SIGILL;
!           }
!           if (fpu_to_mem) {
!               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                      (char *)&fpf->fpf_fpsr);
!           } else {
!               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                     (char *)&fpf->fpf_fpsr);
!           }
!     }
!     if (sig) { return sig; }
!   
!     if (reglist & 1) {
!           /* fpiar - can be moved to/from An */
!           if (fpu_to_mem) {
!               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                      (char *)&fpf->fpf_fpiar);
!           } else {
!               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                     (char *)&fpf->fpf_fpiar);
!           }
      }
      return sig;
  }
--- 443,507 ----
            return SIGILL;
      }
  
!     if (insn->is_ea0.ea_flags & EA_PREDECR)
! 	mask = 1;
!     else
! 	mask = 4;
! 
!     while (!sig && mask >= 1 && mask <= 4)
!     {
!         if (mask == 4 && (reglist & 4)) {
!               /* fpcr */
!               if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
!                   insn->is_ea0.ea_regnum >= 8 /* address reg */) {
!                   /* attempted to copy FPCR to An */
! #ifdef DEBUG
!                   printk("  fpu_emul_fmovmcr: tried to copy FPCR from/to A%d\n",
!                            insn->is_ea0.ea_regnum & 7);
! #endif
!                   return SIGILL;
!               }
!               if (fpu_to_mem) {
!                   sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                          (char *)&fe->fe_fpcr);
!               } else {
!                   sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                         (char *)&fe->fe_fpcr);
!               }
!         }
!         else if (mask == 2 && (reglist & 2)) {
!               /* fpsr */
!               if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
!                   insn->is_ea0.ea_regnum >= 8 /* address reg */) {
!                   /* attempted to copy FPSR to An */
! #ifdef DEBUG
!                   printk("  fpu_emul_fmovmcr: tried to copy FPSR from/to A%d\n",
!                            insn->is_ea0.ea_regnum & 7);
! #endif
!                   return SIGILL;
!               }
!               if (fpu_to_mem) {
!                   sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                          (char *)&fe->fe_fpsr);
!               } else {
!                   sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                         (char *)&fe->fe_fpsr);
!               }
!         }
!         else if (mask == 1 && (reglist & 1)) {
!               /* fpiar - can be moved to/from An */
!               if (fpu_to_mem) {
!                   sig = fpu_store_ea(frame, insn, &insn->is_ea0,
!                                          (char *)&fpf->fpf_fpiar);
!               } else {
!                   sig = fpu_load_ea(frame, insn, &insn->is_ea0,
!                                         (char *)&fpf->fpf_fpiar);
!               }
!         }
!         if (insn->is_ea0.ea_flags & EA_PREDECR)
! 	      mask <<= 1;
! 	else
! 	      mask >>= 1;
      }
      return sig;
  }
***************
*** 549,555 ****
      }
  
      while ((0 <= regnum) && (regnum < 8)) {
!           regmask = 1 << regnum;
            if (regmask & reglist) {
                if (fpu_to_mem) {
                      sig = fpu_store_ea(frame, insn, &insn->is_ea0,
--- 566,575 ----
      }
  
      while ((0 <= regnum) && (regnum < 8)) {
!           if (order < 0)
! 	      regmask = 1 << regnum;
! 	  else
! 	      regmask = 1 << (7 - regnum);
            if (regmask & reglist) {
                if (fpu_to_mem) {
                      sig = fpu_store_ea(frame, insn, &insn->is_ea0,
Only in tidy: fpu_emul.c.swp

-- 

Home:  richard@sleepie.demon.co.uk      Work:  Richard.Hirst@net-tel.co.uk
www:   http://www.sleepie.demon.co.uk   Home of the MVME166 Linux Port!
