Category : Communication (modem) tools and utilities
Archive   : MCTERMV2.ZIP
Filename : MCTERMV2.ASM

Output of file : MCTERMV2.ASM contained in archive : MCTERMV2.ZIP

; Not copyrighted. Free, free, free! Utterly, giveaway, down and dirty
; absolutely no charge.
; Written, in its entirety, liberally plagiarizing from every possible source,
; shamelessly pilfering any disassemblable file, by Michael Curry, 01/11/88.
; Everything in this assembly language file is completely obvious, and totally
; understandable. Especially after you spend two hours debugging on account of
; one lousy 'jz' instruction. Therefore, all questions go to Ray Kester. If
; you need his home phone number, just ask.
; Oh yeah. A86 assembler, of course. Better than MASM, *faster* than MASM, and
; a damn sight easier to use, too.
; UART (8250) registers
data_io equ 3f8h ;communications data port
int_nabl equ 3f9h ;interrupt enable register
int_id equ 3fah ;interrupt identification register
lin_ctl equ 3fbh ;line control register
mod_ctl equ 3fch ;modem control register
lin_stat equ 3fdh ;line status register
mod_stat equ 3feh ;modem status register
baudlsb equ 3f8h ;baudrate register (when lin_ctl bit 7 = 1)
baudmsb equ 3f9h ;baudrate msb register

; Bit values (masks) for Line Control Register (lin_ctl)

dat7bits equ 02h ;seven bit word
dat8bits equ 03h ;eight bit word
stop1bit equ 00h ;one stop bit = bit 2 LO
stop2bit equ 04h ;bit 2 HI (1.5 bits for 5 bit word)
nopar equ 00h ;bit 3 LO = no parity
oddpar equ 08h ;bit 3 HI = odd parity
evenpar equ 18h ;bit 3 & 4 HI = even parity
baudbit equ 80h ;divisor latch access bit

; Baudrate divisor table

bd300 equ 384
bd1200 equ 96
bd2400 equ 48
bd4800 equ 24
bd9600 equ 12
bd19k equ 6
bd38k equ 3
bd56k equ 2 ;don't count on it
; Bit values for Modem Control Register (mod_ctl)
dtr equ 01h ;DTR ON
rts equ 02h ;RTS ON
out2 equ 08h ;OUT2 ON (interrupts go to system bus)
; Bit values for Line Status Register (lin_stat)
dav equ 01h ;received data ready
overun equ 02h ;overrun error
parerr equ 04h ;parity error
framerr equ 08h ;framing error
linebrk equ 10h ;line break
tbmt equ 20h ;transmit buffer (holding register) empty
; Bit values for Modem Status Register (mod_stat)
dcts equ 01h ;delta clear to send
ddsr equ 02h ;delta data set ready
dteri equ 04h ;delta ring Indicator
ddcd equ 08h ;delta carrier Detect
cts equ 10h ;clear to send
dsr equ 20h ;data set ready
ri equ 40h ;ring indicator
cd equ 80h ;carrier detect
; General purpose equates for easy recall
cr equ 0dh ;carriage return
lf equ 0ah ;linefeed
esc equ 01bh ;ascii code for Escape
pic equ 21h ;programmable Interrupt Controller address
picmask equ 10h ;pic value for IRQ4 (com1)
piceoi equ 20h ;programmable int. controller eoi address
bufsize equ 256 ;this is the size of the buffer (decimal)
start: jmp init
disptr dw 0 ;pointer for current display character
bufptr dw 0 ;initialize buffer pointer to zero
lineparm db dat8bits+nopar+stop1bit ;line parameters
baudval dw bd1200 ;baudrate divisor
oldcs dw 0 ;storage for previously existing
oldoffs dw 0 ;interrupt vector
msg1 db 'COM1 - 8/N/1 - 1200 BPS',cr,lf
db 'Hit Esc key to exit.',cr,lf,'$'
msg2 db 'Program terminated.$'
; Set baudrate, word size, parity, etc.
init: mov dx,lin_ctl ;get set to output to register
mov al,baudbit ;sets DLAB = 1
out dx,al ;out it goes
mov dx,baudlsb ;baudrate register (LSB)
mov ax,baudval ;baudrate value
out dx,al ;out it goes
inc dx ;increment port pointed to (baudmsb)
mov al,ah ;move MSB to al
out dx,al ;out it goes
mov dx,lin_ctl ;prepare to set line parameters
mov al,lineparm ;word length, parity, etc.
out dx,al ;write it
; Get the address of the old interrupt vector and save it.
mov ah,35h ;number 35 gets interrupt vector
mov al,0Ch ;0C is for async port COM1
int 21h
mov oldcs,es ;save old code segment
mov oldoffs,bx ;save old offset
; Set the new interrupt vector. The interrupt service routine is at
; end of the program. (intserv)
mov dx,offset intserv ;intserv is address of interrupt handler
mov ah,25h ;function 25 sets new interrupt address
mov al,0Ch ;0Ch is async comm port COM1
int 21h ;DOS function call.
; Enable desired interrupts and system Interrupt Controller.
mov dx,int_nabl ;point to interrupt enable register
mov al,1 ;bit 0 selects received data available
out dx,al ;out it goes
in al,pic ;programmable Interrupt Controller
and al,not picmask ;enables the interrupt we want and
;leaves the rest as they were
out pic,al ;write it back
; Turn on DTR,RTS, and send interrupts to system controller.
mov dx,mod_ctl ;point to modem control register
mov al,(dtr+rts+out2) ;turn on dtr and rts. Out2 causes 8250
;interrupts to go to system controller.
out dx,al ;out control port
; Print message of greeting
mov dx,offset msg1 ;address of message
call prntstring
; Get characters entered on the keyboard. Send to modem.
mov dx,lin_stat ;address the line status register
in al,dx ;input the line status to AL register.
test al,tbmt ;If transmit buffer is empty, tbmt = 1.
;TEST instruction ANDs tbmt mask with actual
;value input from status register. If tbmt
;flag is set, 1 AND 1 = 1, or NOT ZERO.
jz display ;if it IS zero, the transmit buffer is not
;empty, so forget it and go back to the
;display function.
mov ah,6 ;Function 6 requests input
mov dl,0ffh ;if dl = ff
int 21h ;and returns it in al register
jz display ;or sets zero flag if no character
cmp al,esc ;check for exit character (Esc key)
jz exit ;if its exit key, jump to exit routine
mov dx,data_io ;address serial i/o port
out dx,al ;output the character
; Print characters received on the console display.
mov bx,disptr ;move display pointer to bx
cmp bx,bufptr ;compare to buffer pointer
jz keyboard ;return to keyboard if they're the same (no new
;received character in buffer)
mov al,[bx+buffer] ;get the pointed to character
inc bx ;increment bx
cmp bx,bufsize ;see if at buffer top
jne roomy ;jump if still room in buffer
xor bx,bx ;zero pointer count if at top
roomy: mov disptr,bx ;store back incremented pointer
mov ah,0eh ;move print character code to ah
mov bh,0 ;video page 0
int 10h ;ROM call, print character on screen
jmp display ;as opposed to keyboard, this favors the screen
;hence recvd chars, by about 30%
exit: ;choose what you want to call on exit
; call resetmod ;reset the modem?
call disenable ;turn off interrupts?
call vectreplc ;restore COM interrupt vector?
call prntbye ;print goodbye message
mov ah,4ch ; terminate a process function
mov al,0 ; normal terminate (no errors)
int 21h ; sayonara
; Reset the modem as first part of stop procedure
mov dx,mod_ctl ;address modem control register
mov al,0 ;turn off dtr, rts, out2
out dx,al ;send it to port
; Put the Interrupt Controller back the way it was before
mov dx,int_nabl ;address interrupt enable register
mov al,0 ;disable all 8250 interrupts
out dx,al ;send to port
mov dx,pic ;address system Interrupt Controller
in al,dx ;get the interrupts that are enabled
or al,picmask ;turn off COM1 interrupt (set the bit)
out dx,al ;send back to controller
; Replace the interrupt service vector with the old vector (address)
push ds ;save the ds register
mov dx,oldoffs ;put orignal offset in dx
mov ds,oldcs ;put orignal code segment in ds
mov ah,25h ;set interrupt vector
mov al,0Ch ;async COM1
int 21h
pop ds
; Say good-bye
prntbye: mov dx, offset msg2 ;put address of ascii string in dx
prntstring: mov ah,9 ;print it
int 21h
; Here is the actual interrupt service routine.
sti ;turn interrupts back on asap, so the
;rest of the system can go about its
push ax,bx,dx,ds ;push all working registers and DS
mov ax,cs ;move current segment to the DS register
mov ds,ax ;so that our data buffer will be addressable
mov dx,data_io ;move data port address to dx
in al,dx ;input the received character
cli ;turn off interrupts during buffer pointer
;manipulation, just in case
mov bx,bufptr ;put buffer pointer in BX
mov [buffer+bx],al ;store data in pointed-to address, equal
;to address of buffer + bufptr value
inc bx ;bufptr is still in BX, increase it by one
cmp bx,bufsize ;compare to maximum, are we out of room?
jne isroom ;jump if not equal, go store pointer
xor bx,bx ;if equal, reset pointer to zero
isroom: mov bufptr,bx ;put pointer value back in bufptr slot
sti ;turn interrupts back on
mov al,20h ;end of interrupt instruction
out piceoi,al ;out to Interrupt Controller
pop ds,dx,bx,ax ;pop registers back
iret ;return from interrupt
buffer equ $ ;frankly, I prefer to 'db' the buffer, but this saves
;some program size on disk. Big deal.