Appendix II.1 INTERRUPT DRIVEN SERIAL INPUT/OUTPUTThis appendix is designed to show the methodology involved in driving the Sirius 1 in interrupt mode when communicating via the serial port(s). Some pitfalls are described, and tested sample routines are included. There are, currently, no system level facilities that enable this task to be accomplished easily, and some chips, namely the PIC 8259, PIT 8253, SIO 7201 and the VIA 6522 will require re-programming. It is up to the programmer to reset the machine to the original state prior to exiting the interrupt driven application. A typical interrupt driven application will normally follow the steps outlined below:
These steps will be discussed in more detail throughout the text. I.2 Interrupt Vectors There are 256 software interrupts available to the Sirius 1. Most are reserved for system functions, and diagnostics. A block of vectors from 80H through BFH are set aside for applications. I.2.1 Vectors available on the Sirius 1 00-1Fhex Intel reserved
20-3Fhex Microsoft reserved
40-7Fhex Victor reserved
80-BFhex Applications reserved
C0-FFhex Victor reserved
Vectors 40H through 47H are those belonging to devices controlled by the Programmable Interrupt Controller (PIC). 40hex Sync IRQ
41hex SIO 7201
42hex Timer 8253
43hex General Interrupt Handler (all 6522 IRQ's)
44hex IRQ4
45hex IRQ5
46hex Keyboard - keystroke
47hex 8087 math processor
I.2.2 Location of Vectors
Vectors consist of a long pointer (double word) to an interrupt service routine. This pointer is a 4 byte entry consisting of the Segment and Offset of the Interrupt Service Routine. The vectors are stored in a table that has its origin at 0000:0000. The first entry in this table is, therefore, Interrupt 0; the vector for Interrupt 1 is the second, with its vector having an origin of 0000:0004. the interrupt vector for Interrupt 41hex (the SIO 7201) will be found at location 0000:0104 (4*41hex). To set a vector into this table, the MS-DOS function 25hex can be used, but since it is desirable to restore the old vector prior to the application program exiting, it is less cumbersome to simply set the new vector "by hand", and restore the old vector when the application terminates. I.2.3 Set Vector - Assembler Example;store old vector, and set new vector for SIO
cli ;clear interrupts
xor ax,ax ;AX=0000
mov ES,ax ;access table via ES
mov ax,word ptr ES:[104h] ;get old offset
mov word ptr old_offset,ax ;save old offset in DS
mov ax,word ptr ES:[106h] ;old segment
mov word ptr old_segment,ax ;save old segment
mov ax,my_sio_isr ;get offset to my code
mov word ptr ES:[104h],ax ;set vector offset
mov word ptr ES:[106h],CS ; and the new segment
sti ;enable interrupts
ret ;all done, exit
;to replace the old vector prior to exit
cli ;clear interrupts
xor ax,ax ;AX=0000
mov ES,ax ;access table via ES
mov ax,word ptr old_offset ;get old offset
mov word ptr ES:[104h],ax ;restore old offset
mov ax,word ptr old_segment ;get old segment
mov word ptr ES:[106h],ax ;restore old segment
sti ;enable interrupts
ret ;all done, exit
I.3 Enabling Internal and External Clocks
In an asynchronous environment the transmit clock is generated internally, as opposed to a synchronous environment where the transmit clock is typically provided by an external source. Internal clocking is selected by masking off the appropriate bit in register 1 of the keyboard Versatile Interface Adaptor (VIA). The keyboard VIA, register 1, is located at E804:0001. The appropriate bits are: Bit 0 (PA0) for Port A
Bit 1 (PA1) for Port B
Thus, by setting PA0 to zero, the internal clock is enabled for port A; setting PA1 to zero will enable the internal clock for port B. Setting PA0 or PA1 to one will enable the external clock disabling the internal clock. CAUTION: Care must be taken to leave the other bits in the pre-selected state. To enable internal clocks for ports A and B then mask off the two least significant bits in register 1: mov ax,0e804h ;keyboard VIA segment
mov ES,ax ;select the segment register
and byte ptr ES:[0001],0fch ;A & B internal clocks done
To enable external clocks on either channel then set the relevant bit by OR'ing the bit in. The following sample sets the external clocks for both ports A and B: mov ax,0e804h ;keyboard VIA segment
mov ES,ax ;select the segment register
or byte ptr ES:[0001],03h ;A & B external clocks done
I.3.1 Providing Clocks
In a synchronous environment it sometimes becomes necessary to provide transmit and receive clocks from the Sirius 1. This requires that the cable used has to have pins 15, 17 and 24 jumpered at the Sirius 1 end. The Sirus 1 always has a clock on pin 24, this being provided by the internal baud rate generator; thus by jumpering pin 24 to both pins 15 and 17, this clock becomes available for both the transmitter and the receiver, at both ends of the cable. When providing clocks from the Sirius 1, the external clock must be set as well as a baud rate selected. In synchronous mode, the "divide by rate" of the PIT 8253 is 1, therefore the values used to set the required baud rate is 1/16 the values used in an asynchronous environment. (see section 3.8.2 for values). I.4 Initialising the SIOThere is little magic used in this step, but it is recommended that the programmer read the entire Intel/NEC 7201 chip data sheet. The SIO segment is found in segment location E004hex. The offsets for the data ports A and B and control ports A and B are at 0, 1, 2, 3 respectively. The following example of initialising the SIO 7201 is for Port A: cli ;disable interrupts
mov ax,0e004h ;the SIO segment
mov ES,ax ; using ES
mov byte ptr ES:[0002h],18h ;channel reset
;now delay at least 4 system clock cycles
nop
nop ;delay for 7201
mov byte ptr ES:[0002h],12h ;reset external/status
; interrupts
;and select register 2
mov byte ptr ES:[0002h],14h ;non-vectored
mov byte ptr ES:[0003h],02h ;select CR2 B
mov byte ptr ES:[0003h],00h ;set vector to 0
;set for clock rate of 16*; 1 stop bit; parity disabled
move byte ptr ES:[0002h],04h ;select CR4 A
move byte ptr ES:[0002h],44h ;
;this register defines the operation of the receiver:
;7 data bits; auto enable and receive enable
mov byte ptr ES:[0002h],03h ;select CR3 A
mov byte ptr ES:[0002h],61h ;
;CR5 controls the operation of the transmitter
;7 data bits, dtr; assumes half-duplex
mov byte ptr ES:[0002h],05h ;select CR5 A
mov byte ptr ES:[0002h],0a0h ;
;set status: affects the vector, interrupt on every character,
;enable transmitter interrupt
mov byte ptr ES:[0002h],01h ;select CR1 A
mov byte ptr ES:[0002h],17h ;
sti ;enable interrupts
I.4.1 Baud Rate for SIO
At this point, baud rate must be selected. In an asynchronous environment the PIT 8253 divides the supplied baud rate by 16; but in a synchronous environment the baud rate is divided by 1. Thus, to set the baud rate in an asynchronous environment, the value written to the PIT 8253 is 16 times the desired baud rate value. The common baud rate values, and the method of establishing the baud rates, are shown in section 3.8.2 of this manual. I.4.2 Set the PIC to Enable SIO InterruptsIn the Sirius 1 the PIC is normally initialised to operate the SIO in a polled environment. The following lines of code sets the PIC to operate the SIO in an interrupt environment: The PIC resides at segment E000hex and the register required here is at offset 0001: cli ;disable interrupts
mov ax,0e000h ;get the PIC segment
mov ES,ax ;
and byte ptr ES:[0001h],(not 02h) ;mask off bit 1
.
.
sti ;allow interrupts
Prior to exiting the interrupt driven application, the PIC should be returned to operating the SIO in polled mode. This is done by setting bit 1: cli ;disable interrupts
mov ax,0e000h ;get the PIC segment
mov ES,ax ;
or byte ptr ES:[0001h],02h ;set polled
sti ;allow interrupts
I.5 Interrupt Service Routine - ISR
When an interrupt occurs in non-vectored mode, SIO register CR2 B contains the vector number of the interrupting device. Assuming the SIO was initialised as earlier described in this appendix, CR2 B contains a value in the range 0-7, which serves as the index to the following interrupt vector table I.5.1 Sample Interrupt Service Routinedata segment public 'data'
int_vectors dw tx_int_b ;tx int for port B
dw ext_status_b ;external status changed
dw recv_int_b ;recv int port B
dw recv_err_b ;recv error port B
dw tx_int_a ;tx in for port A
dw ext_status_a ;external status changed
dw recv_int_a ;recv in port A
dw recv_err_a ;recv error port A
data ends
code segment public 'code'
assume CS:cgroup, DS:dgroup
sio_isr:
mov word ptr CS:current ss,SS ;save stack seg
mov word ptr CS:current_sp,SP ; and stack pointer
mov SS,word ptr CS:ss_origin ;internal stack
mov SP,offset dgroup:stack top ;defined in DS (dgroup)
push ax ;save environment
push bx
push cx
push dx
push bp
push DS
push ES
mov DS,dgroup ;set to internal data
mov ax,0e004h ;set SIO segment
mov ES,ax ;
mov byte ptr ES:[003h],02h ;select CR2 B
mov al,ES:[0003h] ;read int device
add al,al ;word align
mov ah,0 ; hi = 0
mov bx,offset int_vectors ;get vector table
add bx,ax ;point to entry
call [bx] ;service routine
cli ;keep disabled
;now an "end of interrupt" (EOI) must be issued to the
;SIO (port A) and to the PIC.
mov ax,0e000h ;PIC segment
mov DS,ax ;
mov byte ptr [0042h],38h ;EOI to ctrl A of SIO
mov byte ptr [0000h],61h ;EOI to PIC ctrl port A
pop ES ;restore environment
pop DS
pop bp
pop dx
pop cx
pop bx
pop ax
mov SS,word ptr CS:current_ss ;get SS
mov SP,word ptr CS:current_sp ;get SP
iret ;interrupt return
;the SS origin is stored here during initialisation
ss_origin dw 0 ;stack segment origin
current_sp dw 0 ;SP on ISR entry
current_ss dw 0 ;SS on ISR entry
NOTE: Some variables are stored within the code segment, as the CS register is the only register containing a known value at the time of interrupt. I.6 Setting Direction BitsThis function need only be performed once, and is performed by the operating system BIOS following a hardware reset. This step need not be implemented, therefore, if a standard Sirius operating system is used. If a standard operating system is not used, then this step needs to be performed immediately prior to the enable clock code. ;The offset to the data direction register is 0003hex.
cli ;disable interrupts
mov ax,0e804h ;kbd VIA segment
mov ES,ax ;
mov al,byte ptr ES:[0003h] ;get the old value
or al,03h ;set for output
;
;set the PA2-5 to zero, to enable DSR and RI input
;
and al,0c3h ;mask in
mov byte ptr ES:[0003h],al ;rewrite new value
.
.
sti ;enable interrupts
|