jack@mcvax.UUCP (06/04/87)
I was just wondering wether any of the fancy new machines (MIPS, AMD) did anything about the stupid way interrupts are done in most modern machines. Almost all machines I know of provide a list of interrupt vectors which consist of a program counter, and (sometimes) a module base address or a PSR. Now, given most modern operating systems, this is exactly what you *don't* want. If you want to handle interrupts in a high-level language, you want all interrupts to jump to the same routine, and have the interrupt number handy somewhere. Operating Systems I'm familiar with all simulate this by either stealing a couple of bits in the PSR and go through pains to extract them again in the common interrupt routine, or, even worse, provide lots and lots of twisty little routines, all slightly different (like intvec128: push #128. jmp int_common ). Now, the sensible thing for the hardware to do seems to be to provide one vector, and push the interrupt number along with the PC, PSW and what have you. Is this scheme implemented on any machine? -- Jack Jansen, jack@cwi.nl (or jack@mcvax.uucp) The shell is my oyster.
csg@pyramid.UUCP (Carl S. Gutekunst) (06/05/87)
In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: > If you want to handle interrupts in a high-level >language, you want all interrupts to jump to the same routine, and >have the interrupt number handy somewhere. I can't for the life of me see why you'd want this. On the Pyramid, I hand the address of my interrupt handler to the device. When it needs service, it puts an interrupt request on the bus; the first available CPU responds by asking for an interrupt vector; the device then supplies the address of my interrupt handler. The CPU calls the handler, which then services whatever it was that the device was interrupting for. The handler is, of course, written in C, except for four asm() statements that set up the return-from-interrupt. What could easier than that? <csg>
mash@mips.UUCP (06/05/87)
In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: >I was just wondering wether any of the fancy new machines (MIPS, >AMD) did anything about the stupid way interrupts are done in >most modern machines....<discussion of evils thereof>... >Now, the sensible thing for the hardware to do seems to be to >provide one vector, and push the interrupt number along with the >PC, PSW and what have you. >Is this scheme implemented on any machine? Sure. The MIPS R2000 has 3 vectors: RESET, User TLBMISS (software handler for TLBmisses for the most frequent case, i.e., frequency makes it the only one worth a special case), and everything else. It does what you say. See IEEE Compcon, March 1986, SanFrancisco, 138-143. Doing an interrupt is basically (about 2 cycles): 1) Shutdown the pipeline, canceling any write-back necessary. 2) SAve previous kernel/user bit and interrupt-inhibit bits, set current ones to kernel and inhibited. 3) Save exception Pgm Cntr into on-chip register. 4) Set a Cause field in another register. 5) (In some cases) set useful values into some other special registers 6) Transfer control to the kernel interrupt vector. The general scheme is not uncommon in RISC designs. -- -john mashey DISCLAIMER: <generic disclaimer, I speak for me only, etc> UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!mash, DDD: 408-720-1700, x253 USPS: MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086
mac@uvacs.CS.VIRGINIA.EDU (Alex Colvin) (06/05/87)
In article <7408@boring.cwi.nl>, jack@cwi.nl (Jack Jansen) writes: > you want all interrupts to jump to the same routine, and > have the interrupt number handy somewhere. Operating Systems I'm > familiar with all simulate this ... > Now, the sensible thing for the hardware to do seems to be to > provide one vector, and push the interrupt number along with the > PC, PSW and what have you. > > Is this scheme implemented on any machine? Almost. The system you complain about tends to prevail on microcomputers more than mainframes. Those (Honeywell) mainframes with which I was familiar have a single interrupt entry for I/O interrupts. You are then provided a bit mask of channels attempting an interrupt. Handles the case of simultaneous interrupts nicely. Instruction faults are handled differently, each with its own entry, which makes some sense. You probably don't want to schedule these.
guy@gorodish.UUCP (06/05/87)
In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: > Now, given most modern operating systems, this is exactly what you > *don't* want. If you want to handle interrupts in a high-level > language, you want all interrupts to jump to the same routine, and > have the interrupt number handy somewhere. Operating Systems I'm > familiar with all simulate this by either stealing a couple of bits > in the PSR and go through pains to extract them again in the common > interrupt routine, or, even worse, provide lots and lots of twisty little > routines, all slightly different In the OSes I'm familiar with, all interrupts *for a given type of device* ultimately end up calling the same routine, providing a unit number as an argument, but interrupts for two different devices end up calling two different routines. I presume you're talking about the initial trap, though; the code invoked by that trap could figure out both which interrupt routine to call (i.e., which type of device is interrupting) and what unit number to pass as an argument (i.e., which of those devices is interrupting). In article <438@winchester.UUCP>, mash@mips.UUCP (John Mashey) writes: > Sure. The MIPS R2000 has 3 vectors: RESET, User TLBMISS (software handler > for TLBmisses for the most frequent case, i.e., frequency makes it > the only one worth a special case), and everything else. It does > what you say. The diagram in "Operating System Support on a RISC" shows both the Status and Cause registers. The Cause register includes a 6-bit ExtInt field, which I presume is a bitset indicating which of the 6 external interrupts are pending. To what do these 6 interrupts correspond? Do they correspond to classes of devices? I presume you are not limited to 6 different devices attached to a system containing an R2000, so you would "double up" on external interrupts as necessary. If so, how are the devices distinguished? Is this done with polled interrupts, or is some code provided in one of the other special registers? Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
shebanow@ji.Berkeley.EDU (Mike Shebanow) (06/05/87)
In article <2878@pyramid.UUCP> csg@pyramid.UUCP (Carl S. Gutekunst) writes: >In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: >> If you want to handle interrupts in a high-level >>language, you want all interrupts to jump to the same routine, and >>have the interrupt number handy somewhere. > >I can't for the life of me see why you'd want this. Here's why: Assume a machine (when it interrupts) (like a 68010, 68020) pushes the PSW, PC, and the interrupt vector number: +---------------+ SP-> | PSW | +---------------+ | PC | +---------------+ | IVECT | +---------------+ An interrupt handler could then be written once in assembly: .globl i_entry .extern i_table i_entry: movem.l ???,-(sp) * save all registers which C doesn't save move.? ivect(sp),r0 * get the interrupt vector number move.l i_table(r0),r1 * get a handler routine address push r0 * pass vector number as argument jsr (r1) * call handler add #4,sp * pop ivect number argument movem.l (sp)+,??? * unsave registers rte * return from interrupt Now all one needs to do to set up an interrupt handler (in C) is define the "i_table" contents: extern void handler_1(), handler_2()....; void (*i_table[])() = { handler_1, /* called for interrupt vector #1 */ handler_2, /* called for interrupt vector #2 */ etc..., }; The handler routines are now all pure C -- no assembly at all. Having written many many drivers, this would be a blessing. If you really want to know where this is nice, try writing a driver for a multiple UART board (one which has for example, 8 UARTs all of the same type with three interrupt service routines each -- receive, transmit, and control). I know -- I had to write one once. With standard machine architectures (68000), one has to have this asm glue code in each routine, one for each uart/interrupt (24 in all). This makes for a large asm file. If the ivect number is passed, a three common routines can be used -- the ivect number is used to tell which uart interrupted (a unique ivect is assigned to each uart). This makes life a lot easier. Mike Shebanow
rpw3@amdcad.UUCP (06/06/87)
In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: >Now, the sensible thing for the hardware to do seems to be to >provide one vector, and push the interrupt number along with the >PC, PSW and what have you. >Is this scheme implemented on any machine? Yup! (Almost.) The IBM/370 architecture (in "EC mode") provides one vector for each major class of event, where all I/O is one class, and a nice "reason" code which then tells you the specific channel/device (or interrupt cause for non-I/O), etc. (No flames about all the *other* uglinesses of 370 interrupts, please! It does what he asked...) Rob Warnock Systems Architecture Consultant UUCP: {amdcad,fortune,sun,attmail}!redwood!rpw3 ATTmail: !rpw3 DDD: (415)572-2607 USPS: 627 26th Ave, San Mateo, CA 94403
mash@mips.UUCP (06/06/87)
In article <20461@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: (regarding MIPS R2000) >The diagram in "Operating System Support on a RISC" shows both the >Status and Cause registers. The Cause register includes a 6-bit >ExtInt field, which I presume is a bitset indicating which of the 6 >external interrupts are pending. To what do these 6 interrupts >correspond? Do they correspond to classes of devices? I presume >you are not limited to 6 different devices attached to a system >containing an R2000, so you would "double up" on external interrupts >as necessary. > >If so, how are the devices distinguished? Is this done with polled >interrupts, or is some code provided in one of the other special >registers? 1) Thank goodness for people who actually read the literature! 2) The 6 bits correspond to whatever they're hooked to on the board. 3) On MIPS cpu boards, the 6 bits happen to be: Bus Error timeout profiling clock coprocessor interrupt scheduling clock onboard uarts vectored interrupts from VME 4) Some additional registers on the board record the VME interrupt info, so you can just go there and look, then take the appropriate vector. Nones of this is particularly different from anything else, i.e., the distinguishing info to identify an interrupt has to come from somewhere, and you can either do it in hardware, microcode, or software, or some combination, with RISCs confusing the issue a little, since the software is more like microcode. -- -john mashey DISCLAIMER: <generic disclaimer, I speak for me only, etc> UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!mash, DDD: 408-720-1700, x253 USPS: MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086
csg@pyramid.UUCP (06/06/87)
<<<If you want to handle interrupts in a high-level language, you want all <<<interrupts to jump to the same routine, and have the interrupt number handy <<<somewhere. << <<I can't for the life of me see why you'd want this. < <Assume a machine (when it interrupts) (like a 68010, 68020) pushes <the PSW, PC, and the interrupt vector number.... Pardon my blinders, I wasn't thinking. The Pyramid 90x, which has a register architecture, is hardly representive of the entire world. (All I had to do was go back and look at my own O/S code for PDP-11, 68000, Z80, and Z8. Gee, it would have been handy it they'd used a single interrupt entry point... *SIGH*) <csg>
John_M@spectrix.UUCP (06/07/87)
In article <7408@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes: > ... you want all interrupts to jump to the same routine, and >have the interrupt number handy somewhere. Operating Systems I'm >familiar with all simulate this by either stealing a couple of bits >in the PSR and go through pains to extract them again in the common >interrupt routine, or, even worse, provide lots and lots of twisty little >routines, all slightly different (like >intvec128: push #128. > jmp int_common ). > >Now, the sensible thing for the hardware to do seems to be to >provide one vector, and push the interrupt number along with the >PC, PSW and what have you. > >Is this scheme implemented on any machine? >-- > Jack Jansen, jack@cwi.nl (or jack@mcvax.uucp) > The shell is my oyster. The Motorola 68020 provides almost what you ask for. The exception vector pushed onto the stack contains the exception index that caused the trap. Thus you can use a common routine that does all of the shared code and then uses its "argument" in the exception vector to determine which interrupt (or other trap) actually occurred. It does not do one thing that you ask for - it does have separate vectors for each exception. You have to make them contain the same address to have a shared handler. It would have been a mistake for Motorola to do things exactly as you ask - not every operating system/ hardware design would be set up in such a way that ALL of the interrupts would be handled by a common routine. It would be as much a mistake for the hardware to insist that the software uses a common routine (which you ask for) as it is to ensure that a common routine couldn't be used (which you complain about). This is a case where the hardware should provide mechanisms which are capable of supporting any policy that the software designer chooses to use. -- --------- .signature eater food --------- John Macdonald UUCP: {mnetor,utzoo} !spectrix!jmm internet:Sorry. We're in range, but we're in no domain. Disc-claimer: (noun) any hack's source directory
jfh@killer.UUCP (John Haugh) (06/08/87)
some one stole my uppercase (maybe? do you see any? :-) ... yes, this is slower, so don't flame me for it, and besides, this code wasn't my idea anyway ... start with a vector table for a 68000. .long start ; start of startup routines .long kstack ; top of kernel stack .long buserr ; bus error address .long adredor ; address error address . . .long interupt_vec ; your interupt vector now, define a little piece of code with the name you want. vectable: .long error ; only reset uses this one .. .long error ; ... and no one uses this bsr.w trap ; call trap, push pc ... bsr.w trap ; call trap, push pc (catching on yet?) . . bsr.w trap ; even your routine goes there now i write my trap routine. it figures out the vector number and does a few other things trap: movem.l #<d0,d1,a0,a1>,-(sp) ; save those registers mov.l 16(sp),d0 ; get the stack pc ... sub.l #vectable, d0 ; ... and offset from ... lsr.l #2,d0 ; ... and make it into an index! mov.l usp,-(sp) ; stack user stack poiner for kicks mov.l d0, -(sp) ; stack interupt number jsr _trap ; call c trap routine add.w #8,sp ; pop args movem.l (sp)+,#<d0,d1,a0,a1> ; those registers again... add.w #4,sp ; waste some cycles ... rte ; ... and poof - back you go. what is so horrible about this? (no, on second thought, don't answer that.) for a cisc machine, i can't imagine doing any better. - john. .signature: can't read: forgery
radford@calgary.UUCP (06/10/87)
In article <971@killer.UUCP>, jfh@killer.UUCP (John Haugh) writes: > yes, this is slower, so don't flame me for it, and besides, this code wasn't > my idea anyway ... > ... > now i write my trap routine. it figures out the vector number and > does a few other things > > trap: > movem.l #<d0,d1,a0,a1>,-(sp) ; save those registers > mov.l 16(sp),d0 ; get the stack pc ... > sub.l #vectable, d0 ; ... and offset from ... > lsr.l #2,d0 ; ... and make it into an index! > mov.l usp,-(sp) ; stack user stack poiner for kicks > mov.l d0, -(sp) ; stack interupt number > jsr _trap ; call c trap routine > add.w #8,sp ; pop args > movem.l (sp)+,#<d0,d1,a0,a1> ; those registers again... > add.w #4,sp ; waste some cycles ... > rte ; ... and poof - back you go. > > what is so horrible about this? (no, on second thought, don't answer that.) > for a cisc machine, i can't imagine doing any better. The easiest way is to store the vector number in the unused top eight bits of the interrupt vector address. Then you can have all interrupts go directly to the same place, do a jsr to the next instruction, and fetch the interrupt number from the stack. Before you flame about using the top eight bits of the PC this way, remember that this piece of code will be inherently incompatible with the 68020 whatever you do. Radford Neal
wolfgang@haddock.UUCP (06/10/87)
As already noted, a 68000 unlike the 68010/68020 doesn't push the vector number onto the stack for you. Here is another way for you to wrestle this information from the 68000, with NO individual stubs for each vector. First notice that the 68000 discards the top 8 address bits a31-a24. (Oh oh, I can here the groans already.) We can use these 8 bits for encoding a separate value for each of the 256 vectors. (And then purify the pc of these dirty bits!) ---- | vector table .long trap .long trap + 0x01000000 .logg trap + 0x02000000 .long trap + 0x03000000 .... .long trap + 0xff000000 trap: moveml #SAVE_A0A1D0D1, -sp@ jsr _trap | this also abandons the dirty bits in the pc | check that this assembles to an absulute | value jump (and not a bsr) moveml sp@+, #RESTORE_A0A1D0D1 rte (Please no flames for typos in the 68000 assembly, I don't have a 68000 assembler on hand to run this through.) ------ I have actually used this on an old homebrew 68000 computer. The biggest problem was the so-called intelligent assembler that didn't understand the difference between jsr and bsr. (I had to hand assemble the jsr to get the jsr opcode). -- Wolfgang Rupprecht haddock.ISC.COM!wolfgang {decvax!cca|yale|ihnp4|cbosgd|bbncca|harvard}!ima!haddock!wolfgang