/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define KERNEL
#include "ixemul.h"

#undef DEBUG 

#ifdef DEBUG
#define DP(a) kprintf a
#else
#define DP(a)
#endif

#ifndef AFF_68030
#define AFF_68030	(1L<<2)
#define AFF_68040	(1L<<3)
#endif

/*
 * Note: these functions don't really return void, this is just to
 *       declare them as functions, so that the table below is generated
 *       right.
 */

extern void __adddf3_20(), __addsf3_20(), __cmpdf2_20(), __cmpsf2_20(),
            __divdf3_20(), __divsf3_20(), __divsi3_20(), __extendsfdf2_20(), 
            __fabs_20(), __fixdfsi_20(), __fixunsdfsi_20(), __floatsidf_20(), 
            frexp_20(), ldexp_20(), modf_20(), __modsi3_20(), __muldf3_20(),
            __mulsf3_20(), __mulsi3_20(), __negdf2_20(), __negsf2_20(), 
            __subdf3_20(), __subsf3_20(), __truncdfsf2_20(), __udivsi3_20(), 
            __umodsi3_20(), __umulsi3_20();

/*
 * Property flags. These characterize the used machine, and enable alternate
 * functions specified in the following table.
 * The MMU properties are for the later implementation of virtual memory ;-))
 */

/* requires a 68030 MMU (this works for the 68851 as well, no TT regs are used */
#define PF_FULL_MMU	(1<<0)
/* this works with a 68040 MMU.
 * NOTE: a 68030 can use this function as well, but a 68040 can't use PF_MMU_30
 */
#define PF_REDU_MMU	(1<<1)

/* a 68020 or higher required */
#define PF_32BITCPU	(1<<5)
/* an fpu required. */
#define PF_FPU		(1<<6)


/*
 * This table defines, which library functions should be replaced by an alternate
 * function, this replacement should happen, if one of the specified flags is
 * true for the current system configuration
 */

struct patch_table {
  enum _syscall_ pt_entry;	/* the slot to replace */
  void		 (*pt_func)();	/* some `prototype', no void result required */
  u_int		 pt_flags;	/* all needed properties */
} ix_patch_table[] = {
  SYS___adddf3,		__adddf3_20,		PF_FPU,
  SYS___addsf3,		__addsf3_20,		PF_FPU,
  SYS___cmpdf2,		__cmpdf2_20,		PF_FPU,
  SYS___cmpsf2,		__cmpsf2_20,		PF_FPU,
  SYS___divdf3,		__divdf3_20,		PF_FPU,
  SYS___divsf3,		__divsf3_20,		PF_FPU,
  SYS___divsi3,		__divsi3_20,		PF_32BITCPU,
  SYS___extendsfdf2,	__extendsfdf2_20,	PF_FPU,
  SYS___fixdfsi,	__fixdfsi_20,		PF_FPU,
  SYS___fixunsdfsi,	__fixunsdfsi_20,	PF_FPU,
  SYS___floatsidf,	__floatsidf_20,		PF_FPU,
  SYS_frexp,		frexp_20,		PF_FPU,
  SYS_ldexp,		ldexp_20,		PF_FPU,
  SYS_modf,		modf_20,		PF_FPU,
  SYS___modsi3,		__modsi3_20,		PF_32BITCPU,
  SYS___muldf3,		__muldf3_20,		PF_FPU,
  SYS___mulsf3,		__mulsf3_20,		PF_FPU,
  SYS___mulsi3,		__mulsi3_20,		PF_32BITCPU,
  SYS___negdf2,		__negdf2_20,		PF_FPU,
  SYS___negsf2,		__negsf2_20,		PF_FPU,
  SYS___subdf3,		__subdf3_20,		PF_FPU,
  SYS___subsf3,		__subsf3_20,		PF_FPU,
  SYS___truncdfsf2,	__truncdfsf2_20,	PF_FPU,
  SYS___udivsi3,	__udivsi3_20,		PF_32BITCPU,
  SYS___umodsi3,	__umodsi3_20,		PF_32BITCPU,
};

void
ix_patch_functions (struct ixemul_base *ixbase)
{
  struct ExecBase *SysBase = *(struct ExecBase **)4;
  u_int pflags;
  struct patch_table *pt;

  pflags = 0;

  /* try to figure out properties from the AttnFlags in ExecBase. Later on
   * we'll have to decide as well on some user-specified flags (for example
   * whether virtual memory should be enabled, and probably others as well ;-))
   */

  /* AFF_68020 is set for any 68020, 68030, 68040... */
  if (SysBase->AttnFlags & AFF_68020)
    pflags |= PF_32BITCPU;
    
  if (SysBase->AttnFlags & AFF_68040)
    pflags |= PF_REDU_MMU | PF_FPU;
  else 
    {
      /* currently the 68851 is not supported, I'm too lazy to find out
       * whether there's a 68851 or not... */
      if (SysBase->AttnFlags & AFF_68030)
	pflags |= PF_FULL_MMU;

      /* set for either 68881 or 68882 */
      if (SysBase->AttnFlags & AFF_68881)
        pflags |= PF_FPU;
    }

  /*
   * if the machine hasn't any special properties, just return
   */
  if (! pflags) return;

  for (pt = ix_patch_table; 
       pt < &ix_patch_table[sizeof (ix_patch_table)/sizeof (struct patch_table)];
       pt++)
    if (pt->pt_flags & pflags)
      {
        /* -6*(s + 4) converts syscall# into _LVO */
        SetFunction ((struct Library *)ixbase, -6*(pt->pt_entry + 4), pt->pt_func);
        DP(("Patching vector %ld.\n", pt->pt_entry));
      }
}
