I don't have Dave Hudson's email address handy.  Sorry for posting
this to everyone.  The two files included have the implementation
of the interpretted ISR routines I am using.
Dave,
    I forgot to include those two files at the end of the response.
Here they are.
                                    Tim N.
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	isr.c
#	isr.h
#
echo x - isr.c
sed 's/^X//' >isr.c << 'END-of-isr.c'
X
X/*
X * isr.c
X *	Routines for connecting interrupts to the messaging interface
X */
X#include <sys/types.h>
X#include <mach/isr.h>
X#include <sys/fs.h>
X#include <sys/port.h>
X#include <sys/mutex.h>
X#include <sys/percpu.h>
X#include <sys/proc.h>
X#include <sys/thread.h>
X#include <mach/machreg.h>
X#include <sys/assert.h>
X#include <mach/cia.h>
X#include <mach/custom.h>
X#include <sys/malloc.h>
X#include <sys/vm.h>
X
Xextern volatile struct CIA *CIAAbase, *CIABbase;
Xextern volatile struct Custom *CUSTOMbase;
X
X/*
X * Per-IRQ information on who to call when an IRQ is entered
X */
Xstruct isr_msg {
X	struct port *i_port;
X	struct sysmsg i_msg;
X};
Xstatic struct isr_msg handler[MAX_ISR];
Xchar handlers[MAX_ISR];
Xulong strayintr = 0, dupintr = 0;
X
X/*
X * ISR-routine tables 
X */
X#define NUM_ISR_ROUTINES	8
X#define ISR_PORTS_TAB		0
X#define ISR_EXTER_TAB		1
X#define NUM_ISR_TABLES		2
X#define isr_to_tab(x)	((x) == ISR_PORTS ? ISR_PORTS_TAB : ISR_EXTER_TAB)
X#define tab_to_isr(x)	((x) == ISR_PORTS_TAB ? ISR_PORTS : ISR_EXTER)
X
Xstruct isr_routine {
X	struct port *i_port;
X	struct sysmsg i_msg;
X	u_int *code;
X};
Xstatic struct isr_routine routines[NUM_ISR_TABLES][NUM_ISR_ROUTINES];
X
X/*
X * masks of enabled interupts.  start off with all disabled
X */
Xushort custom_mask = 0x0000;
Xushort ciaa_mask = 0x00;
Xushort ciab_mask = 0x00;
X
X/*
X * Mask determining who can do these sort of operations
X */
X#define IOPRIV_ISR (1)		/* Can vector ISR's */
X#define IOPRIV_IO (2)		/* Can do I/O instructions */
Xstruct prot io_prot = {
X	2,
X	0,
X	{1, 1},
X	{0, IOPRIV_ISR | IOPRIV_IO}
X};
X
X/*
X * isr_interupts()
X *	Turn on/off Interupts for an ISR
X *
X * keep the interupt masks updated.
X * XXX should we use a table instead?
X */
Xisr_interrupts(int isr, int on)
X{
X	unsigned char ciabit;
X	unsigned long intena;
X
X	switch(isr) {
X	case ISR_TBE:	intena = INTF_TBE; break;
X	case ISR_DSKBLK: intena = INTF_DSKBLK; break;
X	case ISR_SOFTINT: intena = INTF_SOFTINT; break;
X	case ISR_PORTS: intena = INTF_PORTS; break;
X
X	/* CIA A */
X	case ISR_A_TA:
X	case ISR_A_TB:
X	case ISR_A_ALARM:
X	case ISR_A_SP:
X	case ISR_A_FLG:
X		ciabit = 1 << (isr - ISR_A_TA);
X		if(on) {
X			ciabit |= CIA_ICR_IR_SC;
X			ciaa_mask |= ciabit;
X		} else
X			ciaa_mask &= ~ciabit;
X		CIAAbase->icr = ciabit;
X		intena = INTF_PORTS;
X		break;
X
X	case ISR_BLIT: intena = INTF_BLIT; break;
X	case ISR_COPER: intena = INTF_COPER; break;
X	case ISR_VERTB: intena = INTF_VERTB; break;
X	case ISR_AUD0: intena = INTF_AUD0; break;
X	case ISR_AUD1: intena = INTF_AUD1; break;
X	case ISR_AUD2: intena = INTF_AUD2; break;
X	case ISR_AUD3: intena = INTF_AUD3; break;
X	case ISR_RBF: intena = INTF_RBF; break;
X	case ISR_DSKSYNC: intena = INTF_DSKSYNC; break;
X	case ISR_EXTER: intena = INTF_EXTER; break;
X
X	/* CIA B */
X	case ISR_B_TA:
X	case ISR_B_TB:
X	case ISR_B_ALARM:
X	case ISR_B_SP:
X	case ISR_B_FLG:
X		ciabit = 1 << (isr - ISR_B_TA);
X		if(on) {
X			ciabit |= CIA_ICR_IR_SC;
X			ciab_mask |= ciabit;
X		} else
X			ciab_mask &= ~ciabit;
X		CIABbase->icr = ciabit;
X		intena = INTF_EXTER;
X		break;
X
X	case ISR_NMI: /* not maskable */
X		break;
X	}
X
X	if(on) {
X		intena |= INTF_SETCLR;
X		custom_mask |= intena;
X	} else
X		custom_mask &= intena;
X	CUSTOMbase->intena = intena;
X}
X
X/*
X * enable_isr()
X *	Connect an ISR to a port
X */
Xenable_isr(port_t arg_port, int isr)
X{
X	struct sysmsg *sm;
X	struct port *port;
X	int error = 0;
X	struct proc *p = curthread->t_proc;
X	extern struct port *find_port();
X
X	/*
X	 * Check for permission
X	 */
X	if (!issys()) {
X		return(-1);
X	}
X
X	/*
X	 * Validate port, lock it
X	 */
X	port = find_port(p, arg_port);
X	if (!port) {
X		return(-1);
X	}
X
X	/*
X	 * Check ISR #, make sure the slot's available
X	 * note: ISR_PORTS and ISR_EXTER are special
X	 */
X	if ((isr < 0) || (isr >= MAX_ISR) ||
X	    (isr == ISR_PORTS) || (isr == ISR_EXTER)) {
X		error = err(EINVAL);
X		goto out;
X	}
X	if (handlers[isr]) {
X		error = err(EBUSY);
X		goto out;
X	}
X
X	/*
X	 * Initialize the message
X	 */
X	sm = &handler[isr].i_msg;
X	sm->m_op = 0;
X	sm->m_nseg = sm->m_arg = sm->m_arg1 = 0;
X	sm->m_sender = 0;
X
X	/*
X	 * Put it in the handler slot
X	 */
X	handler[isr].i_port = port;
X
X	/*
X	 * Flag port as having an IRQ handler
X	 */
X	port->p_flags |= P_ISR;
X	handlers[isr] = 1;
X
X	/*
X	 * Enable this interrupt vector
X	 */
X	isr_interrupts(isr, 1);
X
Xout:
X	v_lock(&port->p_lock, SPL0);
X	v_sema(&port->p_sema);
X	return(error);
X}
X
X/*
X * enable isr and install an isr routine
X */
Xenable_isr_routine(port_t arg_port, int isr, void *code, int len)
X{
X	struct sysmsg *sm;
X	struct port *port;
X	struct isr_routine *table;
X	int i, error = 0;
X	struct proc *p = curthread->t_proc;
X	extern struct port *find_port();
X
X	/*
X	 * Check for permission
X	 */
X	if (!issys()) {
X		return(-1);
X	}
X
X	/*
X	 * Validate port, lock it
X	 */
X	port = find_port(p, arg_port);
X	if (!port) {
X		return(-1);
X	}
X
X	/* 
X	 * get table 
X	 */
X	if(isr != ISR_PORTS && isr != ISR_EXTER) {
X		error = err(EINVAL);
X		goto out;
X	}
X	table = routines[isr_to_tab(isr)];
X
X	/* 
X	 * find empty slot in table 
X	 */
X	for(i = 0; i < NUM_ISR_ROUTINES; i++) {
X		if(table[i].code == 0)
X			break;
X	}
X	if(i == NUM_ISR_ROUTINES) {
X		error = err(EBUSY);
X		goto out;
X	}
X
X	/*
X	 * copy in the code
X	 */
X	table[i].code = (u_int *)MALLOC(len * 4, 0); 	/* XXX type */
X	if(copyin(code, table[i].code, len * 4)) {
X		FREE(table[i].code, 0);		/* XXX type */
X		table[i].code = 0;
X		error = err(EFAULT);
X		goto out;
X	}
X	
X	/*
X	 * Initialize the message
X	 */
X	sm = &table[i].i_msg;
X	sm->m_op = 0;
X	sm->m_nseg = sm->m_arg = sm->m_arg1 = 0;
X	sm->m_sender = 0;
X
X	/*
X	 * hook up the port
X	 */
X	table[i].i_port = port;
X
X	/*
X	 * Flag port as having an IRQ handler
X	 */
X	port->p_flags |= P_ISR;
X	handlers[isr]++;
X
X	/*
X	 * Enable this interrupt vector if not done already
X	 */
X	if(handlers[isr] > 1)
X		isr_interrupts(isr, 1);
X
Xout:
X	v_lock(&port->p_lock, SPL0);
X	v_sema(&port->p_sema);
X	return(error);
X}
X
X/*
X * disable_isr()
X *	Disable all ISR reporting to the given port
X */
Xvoid
Xdisable_isr(struct port *port)
X{
X	int x, tab, isr;
X	struct isr_msg *i;
X	struct isr_routine *ir;
X
X	for (x = 0, i = handler; x < MAX_ISR; ++x,++i) {
X		if (i->i_port == port) {
X			/*
X			 * Shut off this interrupt vector
X			 */
X			isr_interrupts(x, 0);
X
X			/*
X			 * Remove handler
X			 */
X			handlers[x] = 0;
X			i->i_port = 0;
X		}
X	}
X
X	/*
X	 * Check isr-routines
X	 */
X	for(tab = 0; tab < NUM_ISR_TABLES; tab++) {
X		isr = tab_to_isr(tab);
X
X		for(x = 0; x < NUM_ISR_ROUTINES; x++) {
X			ir = &routines[tab][x];
X			if(ir->i_port == port) {
X				/*
X				 * decrement references
X				 * and disable if last handler
X				 */
X				handlers[isr]--;
X				if(handlers[isr] == 0)
X					isr_interrupts(isr, 0);
X				FREE(ir->code, 0);	/* XXX type */
X				ir->code = 0;
X				ir->i_port = 0;
X			}
X		}
X	}
X}
X
X#ifdef nope
X/*
X * enable_io()
X *	Enable I/O instructions for the current thread
X *
X * For now, just use the IOPL field of the user's eflags.  We *could*
X * use the I/O bitmap, but I hear it has bugs, and I don't feel like
X * chasing them just yet.
X */
Xenable_io(int arg_low, int arg_high)
X{
X	struct trapframe *f = curthread->t_uregs;
X	struct proc *p = curthread->t_proc;
X
X	ASSERT(f, "enable_io: no uregs");
X
X	/*
X	 * Check for permission
X	 */
X	p_sema(&p->p_sema, PRILO);
X	if (!(perm_calc(p->p_ids, PROCPERMS, &io_prot) & IOPRIV_IO)) {
X		v_sema(&p->p_sema);
X		return(err(EPERM));
X	}
X	v_sema(&p->p_sema);
X
X	/*
X	 * He checks out--turn on all bits in IOPL--this means
X	 * level 3 (user mode) can do I/O instructions.
X	 */
X	f->eflags |= F_IOPL;
X	return(0);
X}
X#endif /* nope */
X
X/*
X * deliver_isr_routine()
X *	Run each ISR routine for this isr and deliver an ISR
X *
X * Unlike deliver_isr we pass a return value from the return
X * with the ISR message in the arg1 field.  deliver_isr keeps
X * a count of the number of undelivered interupts in this field
X */
Xdeliver_isr_routine(int isr)
X{
X	int i, tab, ret, found;
X	struct isr_routine *ir;
X	struct sysmsg *sm;
X	extern void queue_msg();
X
X	ASSERT_DEBUG(isr == ISR_EXTER || isr == ISR_PORTS, 
X		"deliver_isr_routine: bad isr"); 
X	tab = isr_to_tab(isr);
X
X	found = 0;
X	ir = &routines[tab][0];
X	for(i = 0; i < NUM_ISR_ROUTINES; i++, ir++) {
X		if(ir->code) {
X			found = run_pcode(ir->code, &ret);
X			if(found)
X				break;
X		}
X	}
X
X	if(found) {
X		/*
X		 * If the m_op field is 0, this message isn't currently
X		 * queued.  Set m_op and queue it.
X		 */
X		sm = &ir->i_msg;
X		if (sm->m_op == 0) {
X			sm->m_op = M_ISR;
X			sm->m_arg = isr;
X			sm->m_arg1 = ret;
X			queue_msg(ir->i_port, sm);
X			return(1);
X		} else {
X			/* 
X			 * nothing we can do here
X			 * normally we would increment arg1
X			 * to keep count of undelivered ints
X			 * but we had to steal arg1 for ret value
X			 */
X			return(1);
X		}
X	}
X	return(0);
X}
X
X/*
X * deliver_isr()
X *	See if given ISR has a handler; call it if so
X *
X * Return 1 if a handler was found, 0 otherwise.
X */
Xdeliver_isr(int isr)
X{
X	struct sysmsg *sm;
X	extern void queue_msg();
X
X	/*
X	 * Check if ISR is too big
X	 */
Xif(isr > MAX_ISR) 
X  printf("isr %d\n", isr);
X	ASSERT_DEBUG(isr <= MAX_ISR, "deliver_isr: bad isr");
X
X	/*
X	 * Anybody registered?
X	 */
X	if (handlers[isr] == 0) {
Xprintf("[%d]", isr);
Xreturn(0);
X		ASSERT(handlers[isr], "deliver isr: no handler");
X		strayintr += 1;
X		return(0);
X	}
X
X	/*
X	 * If the m_op field is 0, this message isn't currently
X	 * queued.  Set m_op and queue it.
X	 */
X	sm = &handler[isr].i_msg;
X	if (sm->m_op == 0) {
X		sm->m_op = M_ISR;
X		sm->m_arg = isr;
X		sm->m_arg1 = 1;
X		queue_msg(handler[isr].i_port, sm);
X		return(1);
X	}
X
X	/*
X	 * Otherwise it's still languishing there.  Bump the
X	 * m_arg field to tell them how many times they missed.
X	 */
X	sm->m_arg1 += 1;
X	dupintr += 1;
X	return(1);
X}
X
X/*
X * start_clock()
X *	Enable clock ticks now that we're ready
X */
Xvoid
Xstart_clock(void)
X{
X	ushort interval;
X	uchar x;
X
X	/* we should already be at spl 7 */
X	spl(7);
X
X#ifdef PAL
X	interval = (709379 / HZ) - 1;
X#else /* NTSC */
X	interval = (715909 / HZ) - 1;
X#endif
X
X	/* load interval */
X	CIABbase->talo = interval & 0xff;
X	CIABbase->tahi = interval >> 8;
X
X	/* 
X	 * timer on - 
X	 * allow Timer A interrupts from CIA B 
X	 * make sure all other CIA B interrupts
X	 * are off
X	 */
X	CIABbase->cra = 0x01;
X	CIABbase->crb = 0x00;
X	CIABbase->icr = ~CIA_ICR_IR_SC;
X	isr_interrupts(ISR_B_TA, 1);
X
X	/* clear any pending interrupts */
X	x = CIABbase->icr;
X
X	/* allow interupts */
X	spl(0);
X}
X
X/*
X * Interpret Code and return true or false
X * in addition on a true return the retvalue
X * may bet set to something meaningful
X */
Xint
Xrun_pcode(buf, retval)
Xu_int *buf, *retval;
X{
X	u_int i = 0, accum = 0;
X	u_int *ip;
X	u_short *sp;
X	u_char *cp;
X
X	i = 0;
X	while(1) switch(buf[i++]) {
X	case P_NOP:
X		break;
X	case P_RETURN_MINE:
X		*retval = 0;
X		return(1);
X	case P_RETURN_NOTMINE:
X		return(0);
X	case P_RETURN_MINE_DATA:
X		*retval = buf[i++];
X		return(1);
X	case P_RETURN_MINE_ACC:
X		*retval = accum;
X		return(1);
X	case P_READ_ADDR_1:
X		cp = (u_char *)ptov(buf[i++]);
X		accum = *cp;
X		break;
X	case P_READ_ADDR_2:
X		sp = (u_short *)ptov(buf[i++]);
X		accum = *sp;
X		break;
X	case P_READ_ADDR_4:
X		ip = (u_int *)ptov(buf[i++]);
X		accum = *ip;
X		break;
X	case P_WRITE_ADDR_1:
X		cp = (u_char *)ptov(buf[i++]);
X		*cp = accum;
X		break;
X	case P_WRITE_ADDR_2:
X		sp = (u_short *)ptov(buf[i++]);
X		*sp = accum;
X		break;
X	case P_WRITE_ADDR_4:
X		ip = (u_int *)ptov(buf[i++]);
X		*ip = accum;
X		break;
X	case P_AND_DATA:
X		accum &= buf[i++];
X		break;
X	case P_OR_DATA:
X		accum |= buf[i++];
X		break;
X	case P_IF_TRUE:
X		if(accum == 0)
X			i++;
X		break;
X	case P_IF_FALSE:
X		if(accum != 0)
X			i++;
X		break;
X	case P_DATA:
X		accum = buf[i++];
X		break;
X	default:
X		printf("run_pcode: unknown opcode %x\n", buf[i-1]);
X		return(0);
X	}
X}
X
END-of-isr.c
echo x - isr.h
sed 's/^X//' >isr.h << 'END-of-isr.h'
X#ifndef _MACHISR_H
X#define _MACHISR_H
X/*
X * isr.h
X *	Breakdown of possible interupts
X */
X
X/* interupt vectors */
X#define LOINT	24
X#define HIINT	31
X
X/* 
X * registerable interupts 
X * of these, ISR_PORTS and ISR_EXTER are
X * special.  To use them register an isr routine
X */
X#define ISR_TBE		1	/* serial transmit buffer empty */
X#define ISR_DSKBLK	2	/* disk block transfered */
X#define ISR_SOFTINT	3	/* software interupt */
X#define ISR_PORTS	4	/* unspecified PORTS interupt */
X#define ISR_A_TA	5	/* PORTS CIA A timer A */
X#define ISR_A_TB	6	/* CIA A timer B */
X#define ISR_A_ALARM	7	/* CIA A alarm */
X#define ISR_A_SP	8	/* CIA A serial port */
X#define ISR_A_FLG	9	/* CIA A flag */
X#define ISR_BLIT	10	/* blitter */
X#define ISR_COPER	11	/* copper */
X#define ISR_VERTB	12	/* vertical blank */
X#define ISR_AUD0	13	/* audio channel 0 */
X#define ISR_AUD1	14	/* audio channel 1 */
X#define ISR_AUD2	15	/* audio channel 2 */
X#define ISR_AUD3	16	/* audio channel 3 */
X#define ISR_RBF		17	/* serial receive buffer full */
X#define ISR_DSKSYNC	18	/* disk sync pattern found */
X#define ISR_EXTER	19	/* unspecified EXTER interupt */
X#define ISR_B_TA	20	/* EXTER CIA B timer A - *** used by system */
X#define ISR_B_TB	21	/* CIA B timer B */
X#define ISR_B_ALARM	22	/* CIA B alarm */
X#define ISR_B_SP	23	/* CIA B serial port */
X#define ISR_B_FLG	24	/* CIA B flag */
X#define ISR_NMI		25	/* non-maskable interupt */
X#define MAX_ISR		ISR_NMI
X
X/*
X * ISR Routine Pseudo-Code Opcodes.
X */
X#define P_NOP			0	/* 0 args */
X#define P_RETURN_MINE		1	/* 0 args */
X#define P_RETURN_NOTMINE	2	/* 0 args */
X#define P_RETURN_MINE_DATA	3	/* 1 arg */
X#define P_RETURN_MINE_ACC	4	/* 0 args */
X#define P_READ_ADDR_1		5	/* 1 arg */
X#define P_READ_ADDR_2		6	/* 1 arg */
X#define P_READ_ADDR_4		7	/* 1 arg */
X#define P_WRITE_ADDR_1		8	/* 1 arg */
X#define P_WRITE_ADDR_2		9	/* 1 arg */
X#define P_WRITE_ADDR_4		10	/* 1 arg */
X#define P_AND_DATA		11	/* 1 arg */
X#define P_OR_DATA		12	/* 1 arg */
X#define P_IF_TRUE		13	/* 1 arg - instruction */
X#define P_IF_FALSE		14	/* 1 arg - instruction */
X#define P_DATA			15	/* 1 arg */
X
X#endif /* _MACHISR_H */
END-of-isr.h
exit
Received on Tue Feb  7 11:38:12 1995
This archive was generated by hypermail 2.1.8 : Thu Sep 22 2005 - 15:12:17 PDT