/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *  Portions Copyright (C) 1994 Rafael W. Luebbert
 *
 *  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.
 *
 *  $Id: ix_patch_functions.c,v 1.5 1994/06/25 11:58:21 rluebbert Exp $
 *
 *  $Log: ix_patch_functions.c,v $
 *  Revision 1.5  1994/06/25  11:58:21  rluebbert
 *  Moved pow to within ifndef __HAVE_68881
 *
 *  Revision 1.4  1994/06/19  15:13:10  rluebbert
 *  *** empty log message ***
 *
 *  Revision 1.2  1992/08/09  20:54:44  amiga
 *  add panic functions for systems not having some math librar{ies,y}
 *
 *  Revision 1.1  1992/05/14  19:55:40  mwild
 *  Initial revision
 *
 */

#define KERNEL
#include "ixemul.h"

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

extern struct ExecBase *SysBase;

extern void *MathIeeeDoubTransBase, *MathIeeeDoubBasBase, *MathIeeeSingBasBase;


/*
 * Note: these functions don't really return void, this is just to
 *       declare them as functions, so that the table below is generated
 *       right.
 */
#if 0 /* now automatically included when building ixemul.library with -m68881 */
extern void __divsi3_20(), __udivsi3_20(),  __umodsi3_20(),  __modsi3_20(), 
	__mulsi3_20(), __umulsi3_20();
extern void __adddf3_20(), __addsf3_20(), __cmpdf2_20(), __cmpsf2_20(),
            __divdf3_20(), __divsf3_20(),  __extendsfdf2_20(), 
            __fabs_20(), __fixdfsi_20(), __fixunsdfsi_20(), __floatsidf_20(), 
            frexp_20(), ldexp_20(), modf_20(), __muldf3_20(),
            __mulsf3_20(), __negdf2_20(), __negsf2_20(), 
            __subdf3_20(), __subsf3_20(), __truncdfsf2_20();
#endif

/*
 * 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_FULL_MMU
 */
#define PF_REDU_MMU	(1<<1)

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

/* these are `negative' property flags, they indicate that an optional library
   is missing. */
/* no mathieeedoubtrans.library */
#define PF_NODT		(1<<29)
/* no mathieeedoubbas.library */
#define PF_NODB		(1<<30)
/* no mathieeesingbas.library */
#define PF_NOSB		(1<<31)

/* panic functions if a function requiring a not available library is invoked */
static void panic_nodt () { ix_panic ("mathieeedoubtrans.library required!"); _exit (1); }
static void panic_nodb () { ix_panic ("mathieeedoubbas.library required!"); _exit (1); }
static void panic_nosb () { ix_panic ("mathieeesingbas.library required!"); _exit (1); }


/*
 * 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
 *
 * Place panic stubs for not available libraries before cpu replacements, that
 * way you can get away without mathieeesingbas.library if you have an fpu, for
 * example.
 */

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[] = {
  /* basic math support requiring mathieee{sing,doub}bas.library */
#ifndef __HAVE_68881
  SYS___adddf3,		panic_nodb,		PF_NODB,
  SYS___addsf3,		panic_nosb,		PF_NOSB,
  SYS___cmpdf2,		panic_nodb,		PF_NODB,
  SYS___cmpsf2,		panic_nosb,		PF_NOSB,
  SYS___divdf3,		panic_nodb,		PF_NODB,
  SYS___divsf3,		panic_nosb,		PF_NOSB,
  SYS___extendsfdf2,	panic_nodb,		PF_NODB,
  SYS___fixdfsi,	panic_nodb,		PF_NODB,
  SYS___fixunsdfsi,	panic_nodb,		PF_NODB,
  SYS___floatsidf,	panic_nodb,		PF_NODB,
  SYS_frexp,		panic_nodb,		PF_NODB,
  SYS_ldexp,		panic_nodb,		PF_NODB,
  SYS_modf,		panic_nodb,		PF_NODB,
  SYS___muldf3,		panic_nodb,		PF_NODB,
  SYS___mulsf3,		panic_nosb,		PF_NOSB,
  SYS___negdf2,		panic_nodb,		PF_NODB,
  SYS___negsf2,		panic_nosb,		PF_NOSB,
  SYS___subdf3,		panic_nodb,		PF_NODB,
  SYS___subsf3,		panic_nosb,		PF_NOSB,
  SYS___truncdfsf2,	panic_nodb,		PF_NODB,

  /* transcendental functions, mathieeedoubtrans.library */
  SYS_atan,		panic_nodt,		PF_NODT,
  SYS_sin,		panic_nodt,		PF_NODT,
  SYS_cos,		panic_nodt,		PF_NODT,
  SYS_tan,		panic_nodt,		PF_NODT,
  SYS_sinh,		panic_nodt,		PF_NODT,
  SYS_cosh,		panic_nodt,		PF_NODT,
  SYS_tanh,		panic_nodt,		PF_NODT,
  SYS_exp,		panic_nodt,		PF_NODT,
  SYS_log,		panic_nodt,		PF_NODT,
  SYS_sqrt,		panic_nodt,		PF_NODT,
  SYS_asin,		panic_nodt,		PF_NODT,
  SYS_acos,		panic_nodt,		PF_NODT,
  SYS_log10,		panic_nodt,		PF_NODT,
  SYS_floor,		panic_nodb,		PF_NODB,
  SYS_ceil,		panic_nodb,		PF_NODB,
  SYS_pow,		panic_nodt,		PF_NODT,
#endif
  SYS_sincos,		panic_nodt,		PF_NODT,

  /* fpu/mmu support */
#if 0 /* included in build, no longer needed */
  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___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___muldf3,		__muldf3_20,		PF_FPU,
  SYS___mulsf3,		__mulsf3_20,		PF_FPU,
  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,
#endif

#if 0 /* Included in build if 68020 or higher; no longer needed. */
  SYS___divsi3,		__divsi3_20,		PF_32BITCPU,
  SYS___modsi3,		__modsi3_20,		PF_32BITCPU,
  SYS___mulsi3,		__mulsi3_20,		PF_32BITCPU,
  SYS___udivsi3,	__udivsi3_20,		PF_32BITCPU,
  SYS___umodsi3,	__umodsi3_20,		PF_32BITCPU,
#endif
};

void
ix_patch_functions (struct ixemul_base *ixbase)
{
  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 defined (m68020) || defined (m68030) || defined (m68040) || defined (m68060)
    pflags |= PF_32BITCPU;
#endif
#ifdef __HAVE_68881
    pflags |= PF_FPU;
#endif

  /* add negative property flags */
  if (! MathIeeeDoubTransBase)
    pflags |= PF_NODT;
  if (! MathIeeeDoubBasBase)
    pflags |= PF_NODB;
  if (! MathIeeeSingBasBase)
    pflags |= PF_NOSB;

  /*
   * 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)
        SetFunction ((struct Library *)ixbase, -6*(pt->pt_entry + 4), (unsigned long (*)()) pt->pt_func);
        /* -6*(s + 4) converts syscall# into _LVO */
}
