#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/reg.h"
#include "../h/seg.h"

#define	EBIT	0x08	/* user err bit in psw: C-bit */
#define	SYS	0xe1	/* svc (trap) instruction */
#define	USER	0x10	/* user-mode flag added to dev */

#define	SM(i)		(i & 0xfff)
#define	SVCNO(i)	(i & 077)

/*
 * Offsets of the user's registers relative to
 * the saved r0. See reg.h
 */
int	regloc[NREGS] =
{
	R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,
	R8,  R9,  R10, R11, R12, R13, R14, R15,
	PC, RPS
};

/*
 * Called from low.s when a processor trap occurs.
 * The arguments are the words saved on the system stack
 * by the software during the trap processing.
 * Their order is dictated by the details
 * of C's calling sequence. They are peculiar in that
 * this call is not 'by value' and changed user registers
 * get copied back on return.
 * dev is the kind of trap that occurred.
 */
trap(dev, stat, r0, r1, r2, r3, r4, r5, r6, asp, rf, ps, pc, nps)
int *pc;
{
	register i;
	register *a;
	register struct sysent *callp;
	time_t syst;
	extern char *panicstr;

trace(0x02, "trap", dev);
trace(0x02, "loc", pc);

	syst = u.u_stime;
	u.u_fpsaved = 0;
	if (USERMODE(ps))
		dev |= USER;
	u.u_ar0 = &r0;
	switch(dev) {

	/*
	 * Trap not expected.
	 * Usually a kernel mode address error.
	 */
	default:
		panicstr = 1;
		printf("Useg = %x\n", useg);
		printf("PSW = %x %x\n", ps, pc);
		printf("ar0 = %x\n", &r0);
		printf("trap type %d\n", dev);
		panic("trap");

	case 0+USER: /* memory error */
		i = SIGBUS;
		break;

	case 1+USER: /* illegal instruction */
		/*
		 * Assume emulated floating-point instruction.
		 * Nonzero return from fptrap means illegal instruction or
		 * floating point error.
		 */
		if (i = fptrap(&r0, &u.u_fps))
			break;
		goto out;

	case 2+USER: /* bpt or trace */
		i = SIGTRC;
		break;

	case 3+USER: /* iot */
		i = SIGIOT;
		break;

	case 5+USER: /* emt */
		i = SIGEMT;
		break;

	case 6+USER: /* sys call */
		u.u_error = 0;
		ps &= ~EBIT;
#ifdef SVC6
		u.u_svc6 = stat&0x1000;		/* old style system call */
#endif
						/* stat is svc number */
		callp = &sysent[SVCNO(stat)];
		if (callp == sysent) { /* indirect */
			a = (int *)fuiword((caddr_t)pc);
			pc++;
			i = fuword((caddr_t)a);
			a++;
			if ((i >> 24) != SYS)
				i = 63;		/* illegal - svc 63 is nosys() */
			callp = &sysent[SVCNO(i)];
		} else {
			a = pc;
			pc += callp->sy_narg - callp->sy_nrarg;
		}
trace(0x04, "svc", callp-sysent);
		for (i=0; i<callp->sy_nrarg; i++)
			u.u_arg[i] = u.u_ar0[regloc[i]];
		for(; i<callp->sy_narg; i++)
			u.u_arg[i] = fuword((caddr_t)a++);
		u.u_dirp = (caddr_t)u.u_arg[0];
		u.u_r.r_val1 = u.u_ar0[R0];
		u.u_r.r_val2 = u.u_ar0[R1];
		u.u_ap = u.u_arg;
		if (save(u.u_qsav)) {
			if (u.u_error==0)
				u.u_error = EINTR;
		} else {
			(*callp->sy_call)();
		}
		if(u.u_error) {
			ps |= EBIT;
			u.u_ar0[R0] = u.u_error;
		} else {
			u.u_ar0[R0] = u.u_r.r_val1;
			u.u_ar0[R1] = u.u_r.r_val2;
		}
		goto out;

	case 8+USER: /* arithmetic fault */
		i = SIGFPT;
		break;

	/*
	 * If the user SP is below the stack segment,
	 * grow the stack automatically.
	 * This relies on the ability of the hardware
	 * to restart a half executed instruction.
	 * At the moment this is unimplemented (and possibly
	 * unimplementable) on the Interdata.
	 */
	case 9+USER: /* segmentation exception */
	{
/***
	register int osp;
		osp = sp;
		if(backup(u.u_ar0) == 0)
			if(grow((unsigned)osp))
				goto out;
***/

		i = SIGSEG;
		break;
	}

	case 10+USER: /* illegal svc number */
		i = SIGSYS;
		break;

	case 12+USER: /* allow cpu switch */
		goto out;

	case 13+USER: /* data format or alignment fault */
		i = SIGBUS;
		break;

	}

	psignal(u.u_procp, i);

out:
	if(issig())
		psig();
	curpri = setpri(u.u_procp);
	if (runrun)
		qswtch();
	if(u.u_prof.pr_scale)
		addupc((caddr_t)pc, &u.u_prof, (int)(u.u_stime-syst));
	if (u.u_fpsaved)
		restfp(&u.u_fps);
}

/*
 * nonexistent system call-- set fatal error code.
 */
nosys()
{
	u.u_error = EINVAL;
}

/*
 * Ignored system call
 */
nullsys()
{
}
