AOH :: INTS.TXT

Comm interrupts for IBM PC's

( All page references are to the IBM Technical Reference book)
First lets look at the Async. Card:  to do anything, you must talk to 
the Line-Control Register at I/O address 03FBh for COM1: or 02FBh for 
COM2: Here are its bit designations from page 1-195 & 1-196.

+---+---+---+---+---+---+---+---+      bits 0 & 1 are word stength
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | <----  00 = 5bits  01 = 6bits
+---+---+---+---+---+---+---+---+        10 = 7bits  11 = 8bits
  ^   ^   ^   ^   ^   ^
  |   |   |   |   |   +------ 0 = 1 stop bit  1 = 2 stop bits
  |   |   |   |   +------ 0 = no parity  1 = parity
  |   |   |   +------- 0 = odd parity  1 = even parity
  |   |   +------- 0 = space parity  1 = mark parity
  |   +------- 0 = communicate  1 = space  (break)
  |
  |  I/O addresses 03F8h (02F8h for COM2:) and 03F0h (02F9h) are shared
  |
  +------- Divisor Latch Access Bit (DLAB):
I/O address     DLAB      name of 8-bit register   
03F8h (02F8h)     0     Receiver Buffer Reg. / Transmitter Holding Reg.
03F9h (02F9h)     0     Interupt Enable Register (a 4bit mask)
03F8h (02F8h)     1     Divisor Latch Least Significant byte (DDL)
03F9h (02F9h)     1     Divisor Latch Most Significant byte (DLM)

03FAh (02FAh)    n/a    Interupt Identification Register (3 bits)
03FBh (02FBh)    n/a    Line Control Register (mapped above)
03FCh (02FCh)    n/a    Modem Control Register (5 bits output)
03FDh (02FDh)    n/a    Line Status Register (7 bits input)
03FEh (02FEh)    n/a    Modem Status Register (8 bits input)

     First you set DLAB so you can load the Divisor Latch from the 
table on page 1-198 to set the baud rate. (0180h=300baud 040h=1200)
Then you clear it when you set the parity etc.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   You can control DTR and RTS from this port.

Modem Control Register (bits 5-7 = 0)   [03FCh / 02FCh]  WRITE
+---+---+---+---+---+
| 4 | 3 | 2 | 1 | 0 | <--- Data Terminal Ready  (output)
+---+---+---+---+---+
  ^   ^   ^   +----------- Request To Send  (output)
  |   |   |
  |   |   +--------------- Out 1  (user designated output)
  |   +------------------- Out 2  (user designated output)
  +----------------------- Loop   (diagnostic testing)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   You can poll the UART status through this port

Line Status Register (bit 7 = 0)  [03FDh / 02FDh]  READ ONLY
+---+---+---+---+---+---+---+
| 6 | 5 | 4 | 3 | 2 | 1 | 0 | <-- 1 = Receiver Buffer Full
+---+---+---+---+---+---+---+
  ^   ^   ^   ^   ^   +---------- 1 = Overrun Error
  |   |   |   |   +-------------- 1 = Parity Error
  |   |   |   +------------------ 1 = Framing Error
  |   |   |
  |   |   +---------------------- 1 = Break Interupt
  |   |
  |   +-------------------------- 1 = Transmitter Register Empty
  |
  +------------------------------ 1 = Transmitter Shift Register Empty

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     Some of these guys can initiate an interupt!

Modem Status Register   [03FEh / 02FEh]  READ ONLY
+---+---+---+---+---+---+---+---+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | <-- Delta Clear to Send (DCTS)
+---+---+---+---+---+---+---+---+   {1 = CTS changed since last read}
  ^   ^   ^   ^   ^   ^   ^
  |   |   |   |   |   |   +---------- Delta Data Set Read (DDSR)
  |   |   |   |   |   |             {1 = DSR changed since last read}
  |   |   |   |   |   |
  |   |   |   |   |   +---------- Trailing Edge Ring Indicator (TERI)
  |   |   |   |   |
  |   |   |   |   +-------------- Delta Received Line Signal Detect
  |   |   |   |
  |   |   |   +------------------ Clear To Send NOT   (low active)
  |   |   |
  |   |   +---------------------- Data Set Ready NOT  (low active)
  |   |
  |   +-------------------------- Ring Indicator NOT  (low active)
  |
  +------------------------------ Receive Line Signal Detect NOT

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     To enable the Interupts, first you must decide which condition(s) 
you want to cause an interupt.  Put a 1 in the bit to enable.

Interupt Enable Register  (03F9h / 02F9h DLAB must = 0!)
+---+---+---+---+
| 3 | 2 | 1 | 0 | <--- 1 = Enable Receiver Full Interupt
+---+---+---+---+
  ^   ^   +----------- 1 = Enable Transmitter Empty Interupt
  |   |    
  |   +--------------- 1 = Enable Recieved Line Status Interupts
  |                        (parity/overrun/framing/break)
  |    
  +------------------- 1 = Enable Modem Status Interupts
                           (CTS/DSR/RI/RLSD see Modem Status above)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Now when the condition(s) enabled above occur(s), it will cause an 
IRQ4 if COM1: or IRQ3 if COM2: but the IRQ's are only inputs to a 
master interupt controller (INTEL 8259A) and this guy can mask out your 
IRQ and nothing will happen.  The 8259 can be programmed in a million 
different ways, but IBM only uses one.  It is running in a "priority" 
mode and therefore only the "highest priority" interupt pending will be 
delt with, that's IRQ0 the timer (NMI goes straight to the 8088) if it 
is pending.  The 8259's mask is at I/O address 021h and it may be read 
or written to.  Bit 0 is IRQ0, Bit 1 is IRQ1 etc.  Any bit set to zero
enables that IRQ.  Setting a bit to 1 "maskes" it out.  Once you have 
an interupt occuring and vectoring to your interupt handler, you have 
to figure out what caused it!  That's the job of the: 

Interupt Identification Register  [03FAh / 02FAh]
+---+---+---+
| 2 | 1 | 0 | <--- 0 = Interupt is pending (has not been acknowleged)
+---+---+---+
  +---+-- ID bits:  11 = Receiver Line Status (highest priority)
                    10 = Receiver Buffer Full
                    01 = Transmitter Buffer Empty
                    00 = Modem Status   (lowest priority)

     After you find out what caused it, and do what must be done (like 
read the Receiver Buffer) now you should see bit 0 above go to 1 since 
reading the buffer will clear the IRQ4/3 condition (see pg. 1-202) But 
the 8259 doesn't know that yet!  And he won't let any more IRQ4/3's 
happen until he does!  There are two ways to tell him.  One is called a 
"specific end of interupt command".  And the other is a "non-specific 
end of interupt command".  You send this command to the: 

8259 interupt acknowledge port (OCW2) [I/O address 020h]
+---+---+---+---+---+---+---+---+ --------------------------------+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  bits 0-2 address the  IRQ      |
+---+---+---+---+---+---+---+---+  to be acknowleged: 000 = IRQ0  |
|            \       \---------------+------\         001 = IRQ1  |
|             | bits 3-4 must be 0.  |       \        010 = IRQ2  |
| bits 5-7:   +----------------------+        \       011 = IRQ3  |
|                                              \      100 = IRQ4  |
|  001 = non-specific end of interupt           \     101 = IRQ5  |
|  011 = specific end of interupt                \    110 = IRQ6  |
|                                                 \   111 = IRQ7  |
+--------------------------------------------------+--------------+

     There are a bunch of things I left out because they are not much 
use in the IBM environment, but for details see page b-76 of the INTEL 
iAPX 86,88 User's Manual (July '81).  Anyway a specific EOI will allow 
another IRQ3/4 to occur. Just send a 064h to I/O address 020h for IRQ4, 
or a 063h for IRQ3.  Warning: if you have not yet cleared the interupt 
condition (i.e. read the Receiver Buffer etc.) this will cause another 
interupt immediatly! 

     Well that just about covers it!  If I left anything out just give 
me a ring at Rainbow Technologies (714) 241-9208.      -Scott Jennings

     Here is a sample code listing:

INT_ACKNOWLEGE  EQU     020H  ;
INT_MASKER      EQU     021H  ;port address of 

COM_NUMBER      EQU     1 ;(COM1:)

COM_IRQ         EQU     00010000B/COM_NUMBER

COM_INT_ACK     EQU     01100100B-(COM_NUMBER-1)

COM_INTERUPT    EQU     00CH-(COM_NUMBER-1)  ;interupt # for COM

TRANSMIT        EQU     003F8H-((COM_NUMBER-1)*0100H)
RECIEVE         EQU     TRANSMIT

INTERUPT_ENA    EQU     003F9H-((COM_NUMBER-1)*0100H)
TRANSMIT_IENA   EQU     00000010B
MODEMSTAT_IENA  EQU     00001000B

INTERUPT_ID     EQU     003FAH-((COM_NUMBER-1)*0100H)

MODEM_CONTROL   EQU     003FCH-((COM_NUMBER-1)*0100H)
DTR             EQU     00000001B
RTS             EQU     00000010B
OUT1            EQU     00000100B
OUT2            EQU     00001000B

LINE_STATUS     EQU     003FDH-((COM_NUMBER-1)*0100H)
RECIEVE_FULL    EQU     00000001B
TRANS_EMPTY     EQU     00100000B
SHIFT_EMPTY     EQU     01000000B

MODEM_STATUS    EQU     003FEH-((COM_NUMBER-1)*0100H)
DELTA_CTS       EQU     00000001B
DELTA_DSR       EQU     00000010B
CTS             EQU     00010000B
DSR             EQU     00100000B

DOS_FUNCTION    EQU     021H  ;interupt # 021h
SET_INTERUPT    EQU     025H


       MOV     AL, COM_INTERUPT     ;***************************
       MOV     DX, OFFSET INTERUPT  ;**  set interupt vector  **
       MOV     AH, SET_INTERUPT     ;**   to go to INTERUPT   **
       INT     DOS_FUNCTION         ;***************************

       MOV     AL, NOT TRANSMIT_IENA ;**********************************
       MOV     DX, INTERUPT_ENA      ;**  enable all but trans empty  **
       OUT     DX, AL                ;**********************************

       MOV     DX, MODEM_STATUS  ;***************************
       IN      AL, DX            ;**                       **
       MOV     DX, LINE_STATUS   ;**   clear any pending   **
       IN      AL, DX            ;**  interupt conditions  **
       MOV     DX, RECIEVE       ;**                       **
       IN      AL, DX            ;***************************

       IN      AL, INT_MASKER    ;*************************
       AND     AL, NOT COM_IRQ   ;**  now enable IRQ4/3  **
       OUT     INT_MASKER, AL    ;*************************

  then in the interupt handler itself:

       IN      AL, INT_ACKNOWLEDGE    ;************************
       TEST    AL, COM_IRQ            ;**  acknowledge that  **
       JZ      RESTART  ;no interupt  ;**  the interupt has  **
       MOV     AL, COM_INT_ACK        ;**   been delt with   **
       OUT     INT_ACKNOWLEDGE, AL    ;************************

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



The entire AOH site is optimized to look best in Firefox® 3 on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986- AOH
We do not send spam. If you have received spam bearing an artofhacking.com email address, please forward it with full headers to abuse@artofhacking.com.