/*
 *      trap handler to simulate unix kernel traps
 */


#define DLV     ((struct dlvp *)0177560)
/*
#define DLV     ((struct dlvp *)0176500)
*/
#define READY   0200
#define ENXIO   6


struct dlvp {
	int     rcsr;
	int     rbuf;
	int     xcsr;
	int     xbuf;
};

struct  sys {
	int     s_args;
	int     (*s_fun)();
};

	extern  zexit(),zread(),zwrite(),nosys();

/*
 * This table is the switch used to transfer
 * to the appropriate routine for processing a system call.
 * Each row contains the number of arguments expected
 * and a pointer to the routine.
 */
struct sys sysent[] = {

	0, nosys,                      /*  0 = indir */
	0, zexit,                      /*  1 = exit */
	0, nosys,                      /*  2 = fork */
	2, zread,                      /*  3 = read */
	2, zwrite,                     /*  4 = write */
	2, nosys,                      /*  5 = open */
	0, nosys,                      /*  6 = close */
	0, nosys,                      /*  7 = wait */
	2, nosys,                      /*  8 = creat */
	2, nosys,                      /*  9 = link */
	1, nosys,                      /* 10 = unlink */
	2, nosys,                      /* 11 = exec */
	1, nosys,                      /* 12 = chdir */
	0, nosys,                      /* 13 = time */
	3, nosys,                      /* 14 = mknod */
	2, nosys,                      /* 15 = chmod */
	2, nosys,                      /* 16 = chown */
	1, nosys,                      /* 17 = break */
	2, nosys,                      /* 18 = stat */
	2, nosys,                      /* 19 = seek */
	0, nosys,                      /* 20 = getpid */
	3, nosys,                      /* 21 = mount */
	1, nosys,                      /* 22 = umount */
	0, nosys,                      /* 23 = setuid */
	0, nosys,                      /* 24 = getuid */
	0, nosys,                      /* 25 = stime */
	3, nosys,                      /* 26 = ptrace */
	0, nosys,                      /* 27 = alarm */
	1, nosys,                      /* 28 = fstat */
	0, nosys,                      /* 29 = pause */
	1, nosys,                      /* 30 = smdate; inoperative */
	1, nosys,                      /* 31 = stty */
	1, nosys,                      /* 32 = gtty */
	2, nosys,                      /* 33 = access */
	0, nosys,                      /* 34 = nice */
	0, nosys,                      /* 35 = sleep */
	0, nosys,                      /* 36 = sync */
	1, nosys,                      /* 37 = kill */
	0, nosys,                      /* 38 = switch */
	0, nosys,                      /* 39 = x */
	0, nosys,                      /* 40 = tell */
	0, nosys,                      /* 41 = dup */
	0, nosys,                      /* 42 = pipe */
	1, nosys,                      /* 43 = times */
	4, nosys,                      /* 44 = prof */
	0, nosys,                      /* 45 = tiu */
	0, nosys,                      /* 46 = setgid (nop) */
	0, nosys,                      /* 47 = getgid (nop) */
	2, nosys,                      /* 48 = sig */
	0, nosys,                      /* 49 = geteuid (16 bit effective uid) */
	0, nosys,                      /* 50 = clrtty (clear controlling tty) */
	1, nosys,                      /* 51 = nicer (nice on another job) */
	0, nosys,                      /* 52 = wakeup (for debugging) */
	0, nosys,                      /* 53 = x */
	0, nosys,                      /* 54 = x */
	0, nosys,                      /* 55 = x */
	0, nosys,                      /* 56 = x */
	0, nosys,                      /* 57 = x */
	0, nosys,                      /* 58 = x */
	0, nosys,                      /* 59 = x */
	0, nosys,                      /* 60 = x */
	0, nosys,                      /* 61 = x */
	0, nosys,                      /* 62 = x */
	0, nosys                       /* 63 = x */
};

int     u_arg[4];
int     u_error;
int     r0,r1;


_trap(cr1,cr0,pc,ps)
int cr1, cr0;
int *pc;
int ps;
{
	register int *ptrap,i;
	register struct sys *sysp;
	int type,indirect;
	ptrap = pc - 1;
	r0 = cr0;  r1 = cr1;
	indirect = 0;
	while ((type = *ptrap++ & 077) == 0) {
		indirect++;
		pc++;
		ptrap = *ptrap;
	}
	sysp = &sysent[type];
	for (i=0 ; i<sysp->s_args ; i++) {
		u_arg[i] = *ptrap++;
		if (!indirect)
			++pc;
	}
	u_error = 0;
	(*sysp->s_fun)();
	if (u_error) {
		ps |= 1;        /* set carry (error) */
		r0 = u_error;
	} else
		ps &= ~1;       /* clear carry */
	cr1 = r1;  cr0 = r0;
}

zwrite()
{
	char *cp,c;
	int n;
	if (znxio())return;
	cp = u_arg[0];
	r0 = n = u_arg[1];
	while (n--) {
		c = *cp++;
		if (c == '\n')
			zwriteone('\r');
		zwriteone(c);
	}
}

zwriteone(c)
{
	while ((DLV->xcsr & READY) == 0)
		;
	DLV->xbuf = c;
}

zread()
{
	char *cp,c;
	int n,nr;
	if (znxio()) return;
	cp = u_arg[0];
	n = u_arg[1];
	nr = 0;
	while (n--) {
		c = zreadone();
		zwriteone(c);
		if (c == '\r') {
			c = '\n';
			zwriteone(c);
		}
		*cp++ = c;
		nr++;
		if (c == '\n') break;
	}
	r0 = nr;
}

zreadone()
{
	while ((DLV->rcsr & READY) == 0);
	return(DLV->rbuf & 0177);
}

znxio()
{
	if (u_arg[1] <= 0 || r0 < 0 || r0 > 2) {
		u_error = ENXIO;
		return(1);
	}
	return(0);
}

nosys()
{
	u_error = ENXIO;
}
