/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1991 by John E. Lloyd.				    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#if !defined(SGI_CFG) && !defined(VXWORKS_CFG)

#include <signal.h>
#include <varargs.h>
#include <sys/time.h>
#if sun
#include <machine/param.h>
#endif

#include "../h/cdefs.h"
#include "../h/rciConfig.h"
#include "../h/errorCodes.h"
#include "../h/errorStack.h"
#include "../h/rciTask.h"
#include "../rci/firstAlloc.h"

extern int rciCpu;
extern int rciTaskId;
extern int rciSimOnly;

int (*_rciSignalFxn)() = NULLF;
int (*_rciUprintfFxn)() = NULLF;
int (*_rciPrintfFxn)() = NULLF;

int (*_rciBadAddrFxn)() = NULLF;
struct timeval (*_rciWallClockFxn)() = (struct timeval(*)())NULL;
int (*_rciSetTraceFxn)() = NULLF;
int (*_rciClearTraceFxn)() = NULLF;

int (*_rciSignalAuxFxn)() = NULLF;
int (*_rciSchedAstFxn)() = NULLF;

static rciWallClockAux();

rciInKernelMode()
{
#ifdef SIMONLY_CFG 
	return (0);
#else      
	/* RCI support routine that returns TRUE if we are in
	   system kernel mode */

	int inkmode;

	if (rciCpu != ARBITER_CPU)
	 { return (1);
	 }
#if defined(vax)
	inkmode = 0x80000000 & (unsigned)&inkmode;
#endif
#if defined(sun)
	inkmode = KERNELBASE < (unsigned)&inkmode;
#endif
#if defined(sgi)
	inkmode = 0;	/* never in kmode on the SGI */
#endif
#if !defined(sun) && !defined(vax) && !defined(sgi) && !defined(linux)
	error: need to fix this for your machine
#endif
	return (inkmode);
#endif
}

rciSignal(s)
int s;
{
/* IRIX: just do a regular signal issue. Signal won't be delivered 
   right away because control task has a higher priority */

	if (s <= 0 || s >= NSIG)
	 { return (-1);
	 }
	if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { if (rciTaskId != 0)
	    { /* block the signal first */
	      sigsetmask (sigblock(0) | sigmask(s));
	    }
	   kill (getpid(), s);
	   return (1);
	 }
	else
	 { return ((*_rciSignalFxn)(ARBITER_CPU, s));
	 }
}

static int printToTerminal = NO;

rciPrintToTerminal(set)
int set;
{
/* IRIX: ignore this */

	printToTerminal = set;
}

#define MAX_PMSG	1024

rciPrintf (va_alist)
va_dcl
{
/* IRIX: turn into a printf */

	char buf[MAX_PMSG+1];
	va_list ap;
	char *fmt;

	va_start(ap);
	fmt = va_arg(ap, char*);
	vsnprintf(buf, MAX_PMSG, fmt, ap);
	va_end(ap);
	if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { printf ("%s", buf);
	 }
	else if (printToTerminal)
	 { (*_rciUprintfFxn)("%s", buf);
	 }
	else
	 { (*_rciPrintfFxn)("%s", buf);
	 }
}

rciKPrintf (va_alist)
va_dcl
{
/* IRIX: this too! */

	char buf[MAX_PMSG+1];
	va_list ap;
	char *fmt;

	va_start(ap);
	fmt = va_arg(ap, char*);
	vsnprintf(buf, MAX_PMSG, fmt, ap);
	va_end(ap);
	if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { 
	   if (rciSimOnly)
	    { printf ("%s", buf);
	    }
	   else
	    { 
#if !defined(SIMONLY_CFG) && !defined(LINUX_CFG)
	      rciKrnlExec (_rciPrintfFxn, "%s", buf);
#endif
	    }
	 }
	else
	 { (*_rciPrintfFxn)("%s", buf);
	 }
}

rciBadAddr (address, size)
void *address;
int size;
{
/* IRIX: use our own badAddr */
#ifndef LINUX_CFG
	if (!_rciBadAddrFxn || (size != 1 && size != 2 && size != 4))
	 { return (-1);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (rciKrnlExec (_rciBadAddrFxn, (int)address, size));
	 }
	else
	 { return ((*_rciBadAddrFxn)(address, size));
	 }
#endif
}

static rciWallClockAux (tvAddr)
int tvAddr;
{
	/* Routine to call wall clock function in kernel mode on the
	   ARBITER CPU. */
	
	struct timeval *tv = (struct timeval *)tvAddr;
	*tv = (*_rciWallClockFxn)();
}

struct timeval rciWallClock()
{
/* IRIX: use system clock */
#ifndef LINUX_CFG
	struct timeval tv;

	if (!_rciWallClockFxn)
	 { tv.tv_sec = tv.tv_usec = 0;
	   return (tv);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { rciKrnlExec (rciWallClockAux, (int)&tv);
	   return (tv);
	 }
	else
	 { return (*_rciWallClockFxn)();
	 }
#endif
}

rciSetTrace(c)
int c;
{
/* IRIX: use bus map */
#ifndef LINUX_CFG
	if (!_rciSetTraceFxn)
	 { return (-1);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (rciKrnlExec (_rciSetTraceFxn, c));
	 }
	else
	 { return ((*_rciSetTraceFxn)(c));
	 }
#endif
}

rciClearTrace(c)
int c;
{
/* IRIX: use bus map */
#ifndef LINUX_CFG
	if (!_rciClearTraceFxn)
	 { return (-1);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (rciKrnlExec (_rciClearTraceFxn, c));
	 }
	else
	 { return ((*_rciClearTraceFxn)(c));
	 }
#endif
}


/* Assumptions: rciMalloc pool per CPU, and &fad is lower than
   anything we are likely to allocate */
static FIRST_ALLOC_DESC fad;
static rciMallocInitDone;	/* safety check */

void *rciMallocInit (morecore, blkSize, pool, poolsize)
void *(*morecore)();
int blkSize;
void *pool;
int poolsize;
{
	/* Called by monitor initialization code to set up the
	   appropriate entry points and pool areas for rciMalloc().
	 */

	firstAllocInit (&fad, morecore, blkSize, pool, poolsize);	
	rciMallocInitDone = rciCpu;
}

void *rciMalloc (size)
int size;
{
	extern char *malloc();

	if (rciMallocInitDone != rciCpu)
	 { return (NULL);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return ((void*)malloc(size));
	 }
	else
	 { return ((void*)firstAlloc(&fad, size));
	 }
}

rciFree (mem)
void *mem;
{
	if (rciMallocInitDone != rciCpu)
	 { return (0);
	 }
	else if (rciCpu == ARBITER_CPU && !rciInKernelMode())
	 { return (free(mem));
	 }
	else
	 { return (firstFree (&fad, mem));
	 }
}

/* These functions are used internally ... */

rciSignalAux (cpu, sig)
int cpu;
int sig;
{
/* IRIX: we can ignore this */

	if (!_rciSignalAuxFxn)
	 { rciAbort (EInternal, "rciSignalAux() called in simulator mode\n");
	   return;
	 }
	(*_rciSignalAuxFxn)(cpu, sig);
}

rciSchedAst (clock, time, fxn, arg)
int clock, time;
int (*fxn)();
int arg;
{
/* IRIX: will have to write our own function here */

	if (!_rciSchedAstFxn)
	 { rciAbort (EInternal, "rciSchedAst() called in simulator mode\n");
	   return;
	 }
	(*_rciSchedAstFxn)(clock, time, fxn, arg);
}

#endif /* !defined(SGI_CFG) && !defined(VXWORKS_CFG) */
