Date : Tue, 02 Dec 1986 18:49:32 GMT
From : Jon Mandrell <jon@amc.uucp>
Subject: Re: Interrupts on the N* Advantage
Sorry, I tried to mail this, but it got bounced.
If the UART which you are using is a Z80 SIO or DART, then the interrupts
are easy. If you have something like and 8251, then things get a bit worse.
All of the following assumes that you have a Z80 device out there:
The Z80 actually has 3 interrupt modes:
Mode 0:
A device toggles the INTR line, and the Z80 reads one byte off of the data
bus and executes it. This instruction is usually a RST, since these are one-
byte CALLs (so they can be forced easily). The RST instructions run you to
one of 8 locations in low memory (0000, 0008, 0010, 0018, 0020, 0028, 0030,
or 0038). Actually, you can force any instruction onto the bus, but it doesn't
really make sense to do a INC or whatever when an interrupt happens.
This is not the mode you would be using.
Mode 1:
A device toggles the INTR line, and the Z80 branches to location 0038. It
pushes the current PC onto the stack, so that you can perform an RET and get
back to your program. This mode is rarely used.
Mode 2:
Welcome to the real power of interrupts. In this mode, the I register
contains the top 8 bits of an address. When a device toggles the INTR line,
the Z80 acknowledges it, and then reads in one byte. This is the bottom
8 bits of an address.
((I reg) * 256) + (byte read in)
The Z80 goes to the calculated address, and grabs the word there. This is
the address vector of the interrupt routine. Perhaps an example would help.
Suppose you had the following code at location XX00 (any page boundary):
; channel B of the SIO
dw chbtx ; transmitter empty
dw chbstat ; external status change
dw chbrx ; receive char available
dw chbspec ; special receive condition
; channel A of the SIO
dw chatx ; transmitter empty
dw chastat ; external status change
dw charx ; receive char available
dw chaspec ; special receive condition
Then, if you perform the following code:
ld a,XX ; the page number of the interrupt table
ld i,a ; setup the interrupt register
Any interrupt vectors that are placed on the bus will access the above
table. Still with me?
Now, you need to set the SIO up. You might want to find a DART or SIO
manual for this code to make sense, but here goes. I use the OTIR to
output a block of data to the same port. You need to know the ports that
the SIO resides at.
ld hl,table ; the address of the table
ld b,tlen ; the length of the table
ld c,SIO_PORT ; the port address
otir
with a table that looks like this:
table:
db 0 ; junk. Make sure we are at register 0
db 18h ; reset the SIO
db 4 ; switch to register 4
db 44h ; X16 clock, 1 stop, no parity
db 3 ; switch to register 3
db 0c1h ; rx 8 bits, rx enable
db 5 ; switch to register 5
db 0eah ; dtr, tx 8 bits, tx enable, RTS
db 1 ; register 1 (interrupt enable)
; set Y to 1 if you want a transmitter interrupt, or to 0 if you want to
; poll. 0 is probably the way you want to go. Note that the value given
; below disables interrupts for special receive conditions, and for status
; changes (modem signals), so that the entries into the interrupt table above
; need not have them.
db 000110Y0b ; rx int on all chars
; if this is channel B of the SIO which you are initializing, add the following
db 2 ; switch to register 2
db 0 ; vector value
tlen equ $-table ; calculate the length of the table
If you are not initializing channel B with the above code, you need to send
a 2 and a 0 to channel B's control port also.
Well, that is the very basics. Make sure your interrupt routines end with
the RETI instruction, instead of a RET. If you have any questions, send
me some mail, or give me a call at (206) 882-5252.
--
Jon Mandrell (ihnp4!uw-beaver!tikal!amc!jon)
Applied Microsystems Corp.
"flames >& /dev/null" - me