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