#include <stdio.h>	/***/
#include <dos.h>
#include <setjmp.h>
/*
	Machine or compiler-dependent portions of kernel
	Atari ST / Lattice C 5.5 version - DFN
*/

#include "global.h"
#include "proc.h"
#include "commands.h"

static unsigned short oldNull;
static unsigned short *oldNullp;
static int  stkutil(struct proc *pp);
       void init_psetup(struct proc *pp);
       
struct JMP_BUF {
		int	jmp_d2;
		int	jmp_d3;
		int	jmp_d4;
		int	jmp_d5;
		int	jmp_d6;
		int	jmp_d7;  
		int	jmp_pc;
		int	jmp_a2;
		int	jmp_a3;
		int	jmp_a4;
		int	jmp_a5;
		int	jmp_a6;
		int	jmp_a7;
		};
  
void kinit(void)
{
	/* Remember location 0 pattern to detect null pointer derefs */
#ifndef ATARI           /* Access to location 0 causes bus error on ATARI */
	oldNullp = NULL;
	oldNull = *oldNullp;
#endif
}


/* Print process table info
 * Since things can change while ps is running, the ready proceses are
 * displayed last. This is because an interrupt can make a process ready,
 * but a ready process won't spontaneously become unready. Therefore a
 * process that changes during ps may show up twice, but this is better
 * than not having it showing up at all.
 */
int
ps(int argc, char *argv[], void *p)
{
	register struct proc *pp;
	register struct JMP_BUF *ep;
	unsigned short i;

	tprintf("PID       SP        stksize   maxstk    event     fl  in out name\n");

	for(pp = Susptab;pp != NULLPROC;pp = pp->next){
		ep = (struct JMP_BUF *)&pp->env;
		if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %2d %2d  %s\n",
		 pp,				/* process */
		 ep->jmp_a7,			/* stack pointer */
		 pp->stksize,			/* stack size */
		 stkutil(pp),			/* maxstk */
		 pp->event,			/* event */
		 pp->i_state ? 'I' : ' ',	/* flags */
		 (pp->state & WAITING) ? 'W' : ' ',
		 (pp->state & SUSPEND) ? 'S' : ' ',
		 pp->input, pp->output,		/* input, output sockets */
		 pp->name) == EOF)		/* name */
			return 0;
	}

	for(i=0;i<PHASH;i++){
		for(pp = Waittab[i];pp != NULLPROC;pp = pp->next){
			ep = (struct JMP_BUF *)&pp->env;
			if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %2d %2d  %s\n",
			 pp,			/* process */
			 ep->jmp_a7,			/* stack pointer */
			 pp->stksize,			/* stack size */
			 stkutil(pp),			/* maxstk */
			 pp->event,			/* event */
			 pp->i_state ? 'I' : ' ',	/* flags */
			 (pp->state & WAITING) ? 'W' : ' ',
			 (pp->state & SUSPEND) ? 'S' : ' ',
			 pp->input, pp->output,
			 pp->name) == EOF)		/* name */
				return 0;
		}
	}

	for(pp = Rdytab;pp != NULLPROC;pp = pp->next){
		ep = (struct JMP_BUF *)&pp->env;
		if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %2d %2d  %s\n",
		 pp,			/* process */
		 ep->jmp_a7,			/* stack pointer */
		 pp->stksize,			/* stack size */
		 stkutil(pp),			/* maxstk */
		 pp->event,			/* event */
		 pp->i_state ? 'I' : ' ',	/* flags */
		 (pp->state & WAITING) ? 'W' : ' ',
		 (pp->state & SUSPEND) ? 'S' : ' ',
		 pp->input, pp->output,
		 pp->name) == EOF)		/* name */
			return 0;
	}

	if(Curproc != NULLPROC){
		pp = Curproc;
		if(tprintf("%-10lx%-10lx%-10u%-10u%-10lx%c%c%c %2d %2d  %s\n",
		 pp,			/* process */
		 ep->jmp_a7,			/* stack pointer */
		 pp->stksize,			/* stack size */
		 stkutil(pp),			/* maxstk */
		 pp->event,			/* event */
		 pp->i_state ? 'I' : ' ',	/* flags */
		 (pp->state & WAITING) ? 'W' : ' ',
		 (pp->state & SUSPEND) ? 'S' : ' ',
		 pp->input, pp->output,
		 pp->name) == EOF)		/* name */
			return 0;
	}
	return 0;
}

int stkutil(struct proc *pp)
{
	unsigned int i;
	int16 *sp;

	i = pp->stksize;
	for(sp = pp->stack;*sp == STACKPAT && sp < pp->stack + pp->stksize;sp++)
		i--;
	return (int) i;
}

/* Verify that stack pointer for current process is within legal limits;
 * also check that no one has dereferenced a null pointer
 */
void
chkstk(void)
{
	int16 *sbase;
	int16 *stop;
	int16 *sp = (int16 *) getreg(REG_A7);  /* get current stack pointer */
					  /* this is Lattice C 5.0 specific */

	sbase = Curproc->stack;
	stop = sbase + Curproc->stksize;
	if(sp < sbase || sp >= stop){
		printf("Stack violation, process %s \n\n",Curproc->name);
		printf("SP = %lx, legal stack range [%lx,%lx) \n\n",
			sp, sbase, stop);
		fflush(stdout);
		killself();
	}
#ifndef ATARI	
	if(*oldNullp != oldNull){
		printf("WARNING: Location 0 smashed, process %s\n",Curproc->name);
		*oldNullp = oldNull;
		fflush(stdout);
	}
#endif
}

/* Machine-dependent initialization of the initial task */
void
init_psetup(pp)
	struct proc *pp;
{
	/*
	 *  The base of the stack that's allocated to this program by the
	 *  Amiga operating system has been left for us in "base" by the
	 *  C startup routine.  
	 */
	extern int16 *_base;
	register int i;

	pp->stack = _base;
	pp->stksize = (int16 *)getreg(REG_A7) - pp->stack;
	/*
	 *  Have to be careful here to only clear as much of the stack as we're 
	 *  not currently using.
	 */

	for (i=0; i<pp->stksize; i++)
		pp->stack[i] = STACKPAT;

	pp->stksize += 50;	/* slop.. there is a way to find out what this
				   really is. */
	setjmp(pp->env);
	pp->i_state = 1;
}


/* Machine-dependent initialization of a task */
void
psetup(pp,iarg,parg1,parg2,pc)
struct proc *pp;	/* Pointer to task structure */
int iarg;		/* Generic integer arg */
void *parg1;		/* Generic pointer arg #1 */
void *parg2;		/* Generic pointer arg #2 */
void (*pc)();		/* Initial execution address */
{
	register long *stktop;
	register struct JMP_BUF *ep;

	/* Set up stack to make it appear as if the user's function was called
	 * by killself() with the specified arguments. When the user returns,
	 * killself() automatically cleans up.
	 *
	 * First, push args on stack in reverse order, simulating what C
	 * does just before it calls a function.
	 */
	stktop = (long *)(pp->stack + pp->stksize);

	/* NOTE:  this only works when compiled with 32 bit integers */
	*--stktop = (long) parg2;
	*--stktop = (long) parg1;
	*--stktop = (long) iarg;
		
	/* Now push the entry address of killself(), simulating the call to
	 * the user function.
	 */
	*--stktop = (long) killself;

/*	*--stktop = 0;	*/	/* fodder for longjmp() */

	setjmp(pp->env);
	ep = (struct JMP_BUF *)&pp->env;

	ep->jmp_a7 = (long) stktop;
	ep->jmp_pc = (long) pc;
	ep->jmp_a4 = getreg(REG_A4);/* set-up base relative addressing
					   environment pointer */
/*	ep->jmp_d1 = (long) iarg;  */
/*	ep->jmp_a1 = (long) parg1; */
	ep->jmp_a2 = (long) parg2;
	ep->jmp_a3 = (long) pp;

	/* Task initially runs with interrupts on */
	pp->i_state = 1;
}

