Category : Assembly Language Source Code
Archive   : EXCOM.ZIP
Filename : EXCOM.ASM

 
Output of file : EXCOM.ASM contained in archive : EXCOM.ZIP
title extended int 14 handler
name excom

;
; (C) 1987, Crystal Computer Consulting Inc.
; This software may be used freely, at your own risk,
; as long as this notice is not removed.
;
; Entered from Dr. Dobb's Journal, June 1987 by Kurt Schelin
;
;
_text segment word public 'code'

assume cs:_text, ss:_text, es:_text

org 0100h ;com-able

start:
jmp excom ;must be first

even
;misc constants
BUFSZ equ 0100h ;buffer size
XOFFSZ equ 00F0h ;input flow control turn off point
XONSZ equ 00E0h ;input flow control turn on point
DTR equ 001h ;select DTR input flow control
RTS equ 002h ;select RTS input flow control
XNXF equ 004h ;select XON/XOFF input flow control
OUT2 equ 008h ;bit to set OUT2
NOCTS equ 010h ;CTS not required to transmit
NODSR equ 020h ;DSR not required to transmit
B19200 equ 040h ;set baud rate to 19200
B38400 equ 080h ;set baud rate to 38400
C1MASK equ 010h ;com1 mask for 8259
C2MASK equ 008h ;com2 mask for 8259

;structure for port control blocks
pcbs struc
putptr dw ? ;points to last char put
getptr dw ? ;points to next char to get
bufcnt dw ? ;number of characters in buffer
bufend dw ? ;address past buffer end
pbase dw ? ;port address
timeout db ? ;timeout outer loop
mask db ? ;mask to enable port interrupt
rxoff db ? ;set if recv has been stopped
opts db ? ;holds extended options
lchar db ? ;holds character attributes
oldier db ? ;old interrupt enable register
oldlcr db ? ;old line control register
oldmcr db ? ;old modem control register
olddll db ? ;old baud low divisor latch
olddlm db ? ;old baud high divisor latch
buf dw BUFSZ dup (?) ;the buffer
pcbs ends

;allocate storage for port control blocks
pcb pcbs 2 dup (<>) ;array of port control blocks

old0B dd ? ;old vector for int0B
old0C dd ? ;old vector for int0C
old14 dd ? ;old vector for int14
oldmsk db ? ;old mask for 8259

;baud rate table for UART initialization
bauds dw 0417h ;divisor for 110 baud
dw 0300h ;divisor for 150 baud
dw 0180h ;divisor for 300 baud
dw 00C0h ;divisor for 600 baud
dw 0060h ;divisor for 1200 baud
dw 0030h ;divisor for 2400 baud
dw 0018h ;divisor for 4800 baud
dw 000Ch ;divisor for 9600 baud
baud19 dw 0006h ;divisor for 19200 baud
baud38 dw 0003h ;divisor for 38400 baud

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; 0Bh & 0Ch (com2 & com1) interrupt handler ;
; put characters into the appropriate buffer ;
; input flow control - stop input when buffer nears full ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

int0B:
;point to com2 port control block with ds:si
push ds
push si
mov si, cs
mov ds, si
lea si, pcb + size pcbs
jmp short a10

int0C:
;point to com1 port control block with ds:si
push ds
push si
mov si, cs
mov ds, si
lea si, pcb

a10:
push di
push dx
push bx
push ax

;read character, if this fills buffer to XOFFSZ, then send
;XOFF or drop DTR and/or RTS as indicated by extended options

mov di, [si].putptr ;buffer put pointer
mov dx, [si].pbase
in al, dx ;read character and clear interrupt
mov ah, al
cmp [si].bufcnt, XOFFSZ
jl a40 ;jump if buffer below turnoff point
cmp [si].rxoff, 0
jne a30 ;jump if receive already disabled
mov [si].rxoff, 1 ;indicat receiver now disabled
test [si].opts, XNXF
jz a20
mov al, 's' - '@'
out dx, al ;send ^s

a20:
mov bl, [si].opts
and bl, DTR or RTS
jz a30
add dx, 4
in al, dx
not bl
and al, bl
out dx, al ;drop DTR and/or RTS
sub dx, 4

a30:
;if the buffer is full, set overflow status and exit
cmp [si].bufcnt, BUFSZ
jl a40
or word ptr [di],0200h
jmp short a99

a40:
;read the port status
add dx, 5
in al, dx

;get new buffer pointer, adjust for wrap around if required
inc di
inc di
cmp di, [si].bufend
jne a50
lea di, [si].buf

a50:
;store new buffer pointer and put status:data into the buffer
mov [si].putptr, di
xchg ah, al
mov [di],ax
inc [si].bufcnt

a99:
;send interrupt complete command to interrupt controller
mov al, 020h
out 020h, al
pop ax
pop bx
pop dx
pop di
pop si
pop ds
iret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; 14h interrupt handler ;
; emulate pc bios functions plus extensions ;
; ;
; dx is used to select the port for all calls ;
; dx = 0 for com1, dx = 1 for com2 ;
; ;
; ah = 0 initialize the port, parameters in al ;
; al bits 7-5 set the baud rate ;
; ;
; 000 - 110, 001 - 1050, 010 - 300, 011 - 600 ;
; 100 - 1200, 101 - 2400, 110 - 4800, 111 - 9600 ;
; ;
; al bits 4-3 set the parity ;
; ;
; 00 - none, 01 - odd, 11 - even ;
; ;
; al bit 2 is number of stop bits ;
; ;
; 0 - 1 stop bit, 1 - 2 stop bits ;
; ;
; al bits 1-0 set the word length ;
; ;
; 00 - 5, 01 - 6, 10 - 7, 11 - 8 ;
; ;
; returns ah & al as per comm status (ah-3) below ;
; example: ah = 10101110 is 2400 baud, ;
; odd parity, 2 stop bits, 7 bit characters ;
; ;
; ah = 1 transmit the character in al, al preserved ;
; returns ah as per comm status (ah-3) below ;
; ;
; ah = 2 return receive character in al ;
; returns ah as per comm status (ah-3) below ;
; only bits 1-2-3-4-7 can be set ;
; ah having any bits set is a recive error or timeout ;
; ;
; ah = 3 return comm port status in ah & al ;
; ah bits are: ;
; b0 = data ready b1 = overrun ;
; b2 = parity error b3 = framing error ;
; b4 = break detect b5 = xmit holding reg empty ;
; b6 = xmit shift reg empty b7 = timeout ;
; al bits are: ;
; b0 = delta CTS b1 = delta DSR ;
; b2 = trail edge ring b3 = delta recv detect ;
; b4 = CTS b5 = DSR ;
; b6 = ring indicator b7 = recv singnal detect ;
; ;
; ah = 4 extended options ;
; returns 05A5A in ax, used to identify excom ;
; al contains options as follows: ;
; bit 0 enables DTR input flow control ;
; bit 1 enables RTS input flow control ;
; bit 2 enables XON/XOFF input flow control ;
; bit 4 don't require CTS to transmit ;
; bit 5 don't require DSR to transmit ;
; bit 6 sets baud rate to 19200 ;
; bit 7 sets baud rate to 38400 ;
; ;
; ah = 5 remove excom, restore old vectors, release memory ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

int14:
sti
push ds
push si
push dx
push cs
push bx
;point to selected com port control block with ds:si
mov bx, cs
mov ds, bx
lea si, pcb
or dx, dx
jz b00
add si, size pcbs

b00:
;get port address in dx, return if port not installed
mov dx, [si].pbase
or dx, dx
jz b40

;ah has request type, jmp to selected routine
or ah, ah ;initialize
jz b000
dec ah
jz b100 ;transmit a char
dec ah
jnz b10
jmp b200 ;receive a char

b10:
dec ah
jnz b20
jmp b300 ;get status

b20:
dec ah
jnz b30
jmp b400 ;extended initialize

b30:
dec ah
jnz b40
jmp b500 ;remove excom

b40:
pop bx
pop cx
pop dx
pop si
pop ds
iret
;
; ah = 0
;initialize the port

b000:
push ax

;initialize the pcb, this empties the input buffers
lea ax, [si].buf
mov [si].putptr, ax
inc ax
inc ax
mov [si].getptr, ax
add ax, BUFSZ * 2
mov [si]. bufend, ax
sub ax, ax
mov [si].bufcnt, ax
mov [si].rxoff, al

;assert flow control signals and enable port interrupts
add dx, 4
mov al, DTR or RTS or OUT2
out dx, al
cli
in al, 021h
and al, [si].mask ;unmask com port on int controller
sti
sub dx, 3
mov al, 1
out dx, al ;enable receive int on UART

; setup baud rates and character attributes
add dx, 2
pop ax
mov bl, al
and al, 01Fh
mov [si].lchar, al
mov al, [si].opts
and al, B19200 or B38400
jz b010
call b440 ;init only character attributes
jmp short b020

b010:
mov cl, 4
rol bl, cl
and bx, 0Eh ;isolate baud rate selection
call b430 ;init baud and char attributes

b020:
sub dx, 3
jmp b300 ;return status

;
; ah = 1
; transmitg the character in al

b100:
push ax
add dx, 6
mov bh, [si].opts
not bh
and bh, NODSR or NOCTS

; optionally wait for DSR and/or CTS
call b130
jnz b110
dec dx
mov bh, 020h

;wait for the transmitter to be ready
call b130
jnz b110
sub dx, 5
pop ax
push ax

;actually send the character
out dx, al
call b310
jmp short b120

b110:
;restore al and indicate a timeout (bit 7 of status, ah)
call b310
or ah, 080h

b120:
pop cx
mov al, cl
jmp b40
;
;wait for selected status, bh is status, dx is port address

b130:
mov bl, [si].timeout ;delay counter

b140:
sub cx, cx

b150:
in al, dx
and al, bh
cmp al, bh
jz b160 ;status match
loop b150
dec bl
jnz b140
or bh, bh ;timeout, set non-zero

b160:
ret

;
; ah = 2
; receive a character, put in al

b200:
cmp [si].bufcnt, 0
jne b230 ;chars in buffer, return one

;wait for a character to appear in the buffer, or return timeout
mov al, [si].timeout
add al, al ;shorter timeout loop, so loop more

b210:
sub cx, cx

b220:
cmp [si].bufcnt, 0
jne b230
loop b220
dec al
jnz b210
mov ax, 08000h ;timeout return value
jmp b40

b230:
;if receiver is disabled and room now exists, enable receiver
cmp [si].rxoff, 0
je b250 ;receive is already enabled
cmp [si].bufcnt, XONSZ
jg b250 ;buffer fuller that turn on point
test [si].opts, XNXF
jz b240
mov [si].rxoff, 0 ;indicate receiver enabled
mov al, 'Q' - '@'
out dx, al ;send ^Q

b240:
;it's easier to just assert DTR & RTS rather than see if needed
add dx, 4
in al, dx
or al, DTR or RTS
out dx, al ;assert DTR and RTS

b250:
;get the char from the buffer and update buffer get pointer
call b310
and ah, 01Eh ;status reported with a receive
inc bx
inc bx
cmp bx, [si].bufend
jne b260
lea bx, [si].buf

b260:
mov [si].getptr, bx ;updated pointer
dec [si].bufcnt
jmp b40

;
; ah = 3
; get port status

b300:
call b310
inc dx
in al, dx ;modem status
jmp b40

;
;get line status from input buffer and/or hardware into ah

b310:
mov dx, [si].pbase
add dx, 5
in al, dx ;line status
mov ah, al
cmp [si].bufcnt, 0
je b320

;when chars in buffer, fix status as per status in buffer
; return as above plus bx = getptr, al = character

mov cl, al
mov bx, [si].getptr
mov ax, [bx] ;status:data (ah:al)
mov ch, 01Eh ;these status bits from buffer
and ah, ch
not ch
and cl, ch
or ah, cl
or ah, 1 ;char in buffer, show data ready

b320:
ret

;
; ah = 4
; extended initialization

b400:
;save the options in the pcb
mov [si].opts, al

;if an extended baud rate, set up the UART
add dx, 3
test al, b19200
jz b410
mov bx, baud19 - bauds
call b430
jmp short b420

b410:
test al, b38400
jz b420
mov bx, baud38 - bauds
call b430

b420:
mov ax, 05A5Ah ;magic value to identify excom
jmp b40

;
;init the baud rate and character attributes

b430:
mov al, 080h
out dx, al
mov ax, [bx+bauds]
sub dx, 3
out dx, al ;set low order divisor on UART
inc dx
mov al, ah
out dx, al ;set high order divisor on UART
inc dx
inc dx

b440:
mov al, [si].lchar
out dx, al ;set char attributes
ret


;
; ah = 5
; remove excom

b500:
push ds
push ds

;restore status of interrupt controller and UARTs
cli
mov ah, oldmsk
and ah, C1MASK or C2MASK
in al, 021h
and al, not (C1MASK or C2MASK)
or al, ah
out 021h, al
sti
lea si, pcb ;com1 pcb
call b510 ;restore com1 UART status
lea si, pcb + size pcbs ; com2 pcb
call b510 ;restore com1 UART status
jmp short b530

;subroutine to restore UART status

b510:
mov dx, [si].pbase
or dx, dx
jz b520 ;no port
add dx, 3
mov al, 080h
out dx, al ;set access to baud divisors
sub dx, 3
mov al, [si].olddll
out dx, al ;baud divisor low
inc dx
mov al, [si].olddlm
out dx, al ;baud divisor high
add dx, 2
mov al, [si].oldlcr
out dx, al ;line control register
inc dx
mov al, [si].oldmcr
out dx, al ;modem control register
sub dx, 3
mov al, [si].oldier
out dx, al ;interrupt enable register

b520:
ret

b530:
;restore old int 0Bh vector
lds dx, old0B
mov ah, 025h
mov al, 0Bh
int 021h

;restore old int 0Ch vector
pop ds
lds dx, old0C
mov ah, 025h
int 021h

;restore old int 14h vetcor
pop ds
lds dx, old14
mov ah, 025h
mov al, 0ch
int 021h

;free excom's memory, this memory
push es
mov ax, cs
mov es, ax
mov ah, 049h
int 021h
pop es
jmp b40

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Installation entry point, must be at file and ;
; initialize and stay resident ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

excom:
;initialize constant parts of each pcb
mov ax, 040h
mov es, ax ;bios data segment
sub di, di ;offset to com1 base address
mov bx, 07Ch ;offset to com1 timeout
mov cl, not C1MASK ;com1 interrupt mask
lea si, pcb ;com1 pcb address
call c00 ;init com2
jmp short c10

;subroutine to initialize parts of a pcb

c00:
mov dx, es:[di] ;port base from BIOS
mov [si].pbase, dx
mov al, es:[bx]
mov [si].timeout, al ;copy timeout from BIOS
mov [si].mask, cl ;save interrupt mask
ret

c10:
;save old status of interrupt controller and UARTs
in al, 021h
mov oldmsk, al
lea si, pcb ;com1 pcb
call c20 ;save old com1 uart status
lea si, pcb + size pcbs ; com2 pcb
call c20 ;save old com1 UART status
jmp short c40


;subroutine to save UART status

c20:
mov dx, [si].pbase
or dx, dx
jz c30 ;no ports
add dx, 3
in al, dx
and al, 07Fh
mov [si].oldlcr, al ;line control register
mov al, 080h
out dx, al ;set access to baud divisors
sub dx, 3
in al, dx
mov [si].olddll, al ;baud divisor low
inc dx
in al, dx
mov [si].olddlm, al ;baud divisor high
add dx, 2
mov al, [si].oldlcr
out dx, al ;restore register access
inc dx
in al, dx
mov [si].oldmcr, al ;modem control register
sub dx, 3
in al, dx
mov [si].oldier, al ;interrupt enable register

c30:
ret

c40:
;release environment memory, not used
mov bx, 02ch
mov ax, [bx]
mov es, ax ;address of environment
mov ah, 049h
int 021h ;free memroy

;save old int0Bh vector, install new handler
push ds
mov ax, cs
mov ds, ax
mov ah, 035h
mov al, 0Bh
int 021h
mov word ptr old0B, bx
mov ax, es
mov word ptr old0B + 2, ax
lea dx, int0B
mov ah, 025h
mov al, 0Bh
int 021h

;save old int 0Ch vector, install new handler
mov ah, 035h
mov al, 0Ch
int 021h
mov word ptr old0C, bx
mov ax, es
mov word ptr old0c + 2, ax
lea dx, int0c
mov ah, 025h
mov al, 0Ch
int 021h

;save old int 14h vector, install new handler
mov ah, 035h
mov al, 014h
int 021h
mov word ptr old14, bx
mov ax, es
mov word ptr old14 + 2, ax
lea dx, int14
mov ah, 025h
mov al, 014h
int 021h
pop ds

;exit and keep everything above the entry point 'excom'
lea dx, excom
mov cl, 4
shr dx, cl
inc dx
mov ah, 031h
mov al, 0
int 021h ;terminate-and-stay-resident

_text ends
end start
endm


  3 Responses to “Category : Assembly Language Source Code
Archive   : EXCOM.ZIP
Filename : EXCOM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/