/*********************************
**********************************
**                              **
**     $File: SetMthPatch.c$    **
**     $Datum: 06.07.95   $     **
**     $Version: 1.00     $     **
**                              **
**         Written 1995         **
**       by Andreas Wolff       **
**                              **
**********************************
*********************************/


char *dummy="$VER: SetMathPatch 1.00 (6.7.95)";


#include "exec/execbase.h"
#include "exec/types.h"
#include "exec/semaphores.h"
#include "exec/memory.h"
#include "dos/dos.h"

#include "string.h"


#define SEMANAME "SetMathPatch"
#define PATCHSIZE (ULONG)PatchEnd-(ULONG)PatchBegin


extern struct ExecBase *SysBase;
struct MathIEEEBase *MathIeeeSingBasBase = NULL;
struct MathIEEEBase *MathIeeeDoubBasBase = NULL;

struct sema_struct { 
              struct SignalSemaphore sm_sema;
              char                   sm_name[sizeof(SEMANAME)+1];
            };

struct sema_struct *sema=NULL;
int __nocommandline;


float LVOIEEESPFix(float, float);
float LVOIEEESPMul(float, float);
float LVOIEEESPDiv(float, float);
double LVOIEEEDPFix(double,double);
void PatchBegin(void);
float NewIEEESPFix(float, float);
float NewIEEESPMul(float, float);
float NewIEEESPDiv(float, float);
double NewIEEEDPFix(double,double);
void PatchEnd(void);

asm("
.globl _PatchBegin
_PatchBegin:
_NewIEEESPFix:
	fmoves	d0,fp0
	fmoveml fpcr,d1
	moveq #16,d0
	orl d1,d0
	andw #-33,d0
	fmoveml d0,fpcr
	fmovel fp0,d0
	fmoveml d1,fpcr
        rts

_NewIEEESPMul:
	fmoves	d0,fp0
	fmoves	d1,fp1
	fmulx	fp1,fp0
	fmoves	fp0,d0
	rts

_NewIEEESPDiv:
	fmoves	d0,fp0
	fmoves	d1,fp1
	fdivx	fp1,fp0
	fmoves	fp0,d0
	rts

_NewIEEEDPFix:
        movel d1,sp@-
        movel d0,sp@-
        fmoved sp@+,fp0
	fmoveml fpcr,d1
	moveq #16,d0
	orl d1,d0
	andw #-33,d0
	fmoveml d0,fpcr
	fmovel fp0,d0
	fmoveml d1,fpcr
        rts
_PatchEnd:
");


void CloseLibs(void)
{
   if(MathIeeeSingBasBase)
      CloseLibrary(MathIeeeSingBasBase);

   if(MathIeeeDoubBasBase)
      CloseLibrary(MathIeeeDoubBasBase);
}


int OpenLibs(void)
{
    MathIeeeSingBasBase = (struct MathIEEEBase *) OpenLibrary("mathieeesingbas.library",37);

    MathIeeeDoubBasBase = (struct MathIEEEBase *) OpenLibrary("mathieeedoubbas.library",37);

    if(MathIeeeSingBasBase && MathIeeeDoubBasBase)
       return(2);
    else if(MathIeeeSingBasBase)
       return(1);
    else
    {
       CloseLibs();
       return(0);
    }
}


int AllocSema(void)
{
   int ret=0;

   Forbid();
   if(!FindSemaphore(SEMANAME))
   {
      sema = (struct sema_struct *) AllocMem(sizeof(struct sema_struct), MEMF_PUBLIC | MEMF_CLEAR);
      if(sema)
      {
         sema->sm_sema.ss_Link.ln_Pri=-127;
         sema->sm_sema.ss_Link.ln_Name=(APTR)&(sema->sm_name);
         strcpy(sema->sm_sema.ss_Link.ln_Name,SEMANAME);

         AddSemaphore(sema); /* Does not work with KS < V36 */
      }
      else ret = 2;
   }
   else ret = 1;

   Permit();

   return(ret);
}


void FreeSema(void)
{
   if(sema)
   {
      RemSemaphore(sema);
      ObtainSemaphore(sema);
      ReleaseSemaphore(sema);
      FreeMem(sema, sizeof(struct sema_struct));
   }
}


int main(void)
{
   int err,openlibs;
   APTR patch;
   BPTR outp;

   outp = Output();
   if(outp)
   {
      if(SysBase->AttnFlags & AFF_68040)
      {
         err = AllocSema();
         if(err==0)
         {
            if(openlibs = OpenLibs())
            {
               patch = (APTR) AllocMem(PATCHSIZE, MEMF_PUBLIC);
               if(patch)
               {
                  CopyMem(PatchBegin,patch,PATCHSIZE);
                  CacheClearU();

                  err = SetFunction(MathIeeeSingBasBase,LVOIEEESPFix,patch+(ULONG)NewIEEESPFix-(ULONG)PatchBegin);
                  err = SetFunction(MathIeeeSingBasBase,LVOIEEESPMul,patch+(ULONG)NewIEEESPMul-(ULONG)PatchBegin);
                  err = SetFunction(MathIeeeSingBasBase,LVOIEEESPDiv,patch+(ULONG)NewIEEESPDiv-(ULONG)PatchBegin);
                  if(openlibs==2)
                     err = SetFunction(MathIeeeDoubBasBase,LVOIEEEDPFix,patch+(ULONG)NewIEEEDPFix-(ULONG)PatchBegin);

                  FPuts(outp,"SetMathPatch V1.00 (6.7.95) successfully installed. Patch list:\n");
                  FPuts(outp,"\tIEEESPFix() patch\n");
                  FPuts(outp,"\tIEEESPMul() patch\n");
                  FPuts(outp,"\tIEEESPDiv() patch\n");
                  if(openlibs==2)
                     FPuts(outp,"\tIEEEDPFix() patch\n");
                  else
                     FPuts(outp,"'mathieeedoubbas.library' v37+ not found. IEEEDPFix() nopatched.\n");

                  /* No CloseLibrary !!! */

                  return(RETURN_OK);
               }
               else
               {
                  CloseLibs();
                  FreeSema();

                  FPuts(outp,"Error: Not enough memory !\n");
                  return(RETURN_FAIL);
               }
            }
            else
            {
               FreeSema();

               FPuts(outp,"Can't open math-libraries\n");
               return(RETURN_FAIL);
            }

         } 
         else if(err==1)
         {
            FPuts(outp,"SetMathPatch is already installed !\n");
            return(RETURN_WARN);
         }
         else if(err==2)
         {
            FPuts(outp,"Error: Not enough memory !\n");
            return(RETURN_FAIL);
         }
      }
      else
      {
         FPuts(outp,"SetMathPatch is only needed for 68040 and greater !\n");
         return(RETURN_WARN);
      }
   }
   else
      return(RETURN_FAIL);
}
