home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
DUMBTERM.ZIP
/
DUMBTERM.ASM
Wrap
Assembly Source File
|
1989-03-20
|
16KB
|
635 lines
;«OF4»«RM76»«FD66»«PL55,60,50»«RHA«OF4»«RM76»«MDBO»
PAGE «PN»«MDBO»/«MDNM»«FR»«MDBO»
«MDNM»»«RFA«OF4»«RM76»
«LD-»«FR»«MDBO»MORE«MDNM»
»
------------------------------------------------------------------
;«MDBO» DUMBTERM«MDNM»
; «MDBO»Author: CJ Dunford«MDNM»
; «MDBO»Rev.: 09/12/83«MDNM»
; «MDBO»Source: DUMBTERM.ASM«MDNM»
; «MDBO»Object: DUMBTERM.OBJ«MDNM»
; «MDBO»Code: DUMBTERM.EXE«MDNM»
; «MDBO»O/S: PCDOS 1.1, 2.0«MDNM»
;
; Note that the program assumes that the RS232 port is configured
; as COM1. It will have to be modified to use COM2. Also,
; the communications parameters are set as 300 baud, 7 data bits,
; 1 stop bit, even parity. This can be changed--see the INIT
; procedure. DUMBTERM will easily keep up with 1200 baud or more.
;
; Assembly/link:
; Assemble: MASM dumbterm;
; Link: LINK dumbterm;
;
; Execution:
; (from DOS prompt): DUMBTERM
;------------------------------------------------------------------
; * * * * * * * * * * * * * * *
; EQUATES & DEFINITIONS
; * * * * * * * * * * * * * * *
; ----- Define size of buffer
BUFSIZE equ 4096 ; 4K--can be adjusted
; ----- ASCII codes
LF equ 0AH ; Line feed
CR equ 0DH ; Carriage return
ESC equ 1BH ; Escape
; ----- BIOS calls
RS232 equ 14H ; RS232 service
kbd_io equ 16H ; Keyboard service
; ----- INS8250 ACE registers
THR equ 3F8H ; Trans holding register (write)
RBR equ 3F8H ; Receiver buffer register (read)
IER equ 3F9H ; Interrupt enable register
LCR equ 3FBH ; Line control register.
; Bit 7 of LCR is "DLAB". DLAB must
; be zero to access THR, RBR, IER.
MCR equ 3FCH ; Modem control register
LSR equ 3FDH ; Line status register
MSR equ 3FEH ; Modem status register
; ----- Comm parameter definition
; Refer to IBM Tech Ref, page A-20
; See proc INIT for usage
commparm record baud:3, parity:2, stopbits:1, wordbits:2
; Baud rates
B110 equ 000B
B150 equ 001B
B300 equ 010B
B600 equ 011B
B1200 equ 100B
B2400 equ 101B
B4800 equ 110B
B9600 equ 111B
; Parity
no_parity equ 00B
odd_parity equ 01B
even_parity equ 11B
; Stop bits
stop1 equ 0
stop2 equ 1
; Data bits
data7 equ 10B
data8 equ 11B
; * * * * * * * * * * * * * * *
; MACROS
; * * * * * * * * * * * * * * *
@bioscall MACRO call_num, parm
;; Generates an 'INT call_num', with parm in AH
IFNB <parm>
mov ah,parm
ENDIF
int call_num
ENDM
@doscall MACRO function,parm
;; Generates a DOS function call with parm in AL
IFNB <parm>
mov al,parm
ENDIF
@bioscall 21H,function
endm
; * * * * * * * * * * * * * *
; DATA & STACK SEGMENTS
; * * * * * * * * * * * * * *
data segment para public 'data'
; ----- The string section
sgreeting db '--- ONLINE ---',CR,LF,'$'
sgoodbye db CR,LF,'--- OFFLINE ---',CR,LF,'$'
serr1 db '<R>$' ; RS232 receive error
serr2 db '<S>$' ; RS232 send error
serr3 db '<B>$' ; Receive buffer overflow error
; ----- Flags
brcv_err db 0 ; Nonzero on RS232 receive error
boverflow db 0 ; Nonzero on buffer overflow
bdoneflag db 0 ; Nonzero after ESC from kbd
; ----- Received data buffer and associated pointers
; >> Buffer is empty if head pointer = tail pointer
wbufhead dw buffer ; Pointer to head of buffer
wbuftail dw buffer ; Pointer to tail of buffer
buffer db BUFSIZE dup (?)
bufend equ $
data ends
; ----- Stack
stack segment para stack 'stack'
db 256 dup (?)
stack ends
; * * * * * * * * * * * * *
; PROGRAM MAINLINE
; * * * * * * * * * * * * *
code segment para public 'code'
assume cs:code, ds:data, ss:stack
main proc far
; ----- Initialize
push ds ; Set up long ret to DOS
sub ax,ax
push ax
call init ; Rest of initialization
; ----- Main program loop
M100:
call buffer_check ; Check RS232 bfr. Display if not empty
call kb_check ; Check kbd. Send to RS232.
test bdoneflag,0FFH ; Non-zero if done
jz M100 ; Loop till ESC received
; ----- ESC received. Clean up interrupt & exit
call cleanup ; Clean up
ret ; Return to DOS
main endp
; * * * * * * * * * * * * * * *
; PRIMARY BLOCKS
; * * * * * * * * * * * * * * *
; ----- INIT ------------------------------
; Program initialization:
; -- Set up RS232
; -- Set up vector for RS232 interrupt (INT 0CH)
; -- Enable IRQ4
; -- Enable RS232 interrupt on data ready
;
; NOTE: The communications parameters are established
; here. To use other parameters, change the parameters
; in the 'mov al,commparm' statement below. See the
; communications parameters record definition (above)
; for the correct abbreviations.
;
; Examples:
; 1200,N,8,1: mov al,commparm <B1200,no_parity,stop1,data8>
; 4800,O,7,2: mov al,commparm <B4800,odd_parity,stop2,data7>
; -----------------------------------------
init proc near
; ----- Initialize RS232: 300,8,N,1
mov dx,0 ; COM1
mov al,commparm <B300,no_parity,stop1,data8>
@bioscall RS232,0
; ----- Set up INT x'0C' for IRQ4
cli ; Interrupts off during setup
push ds ; Save DS
mov dx,offset ISR ; Point to RS232 ISR in DS:DX
push cs
pop ds
@doscall 25H,0CH ; Set int vctr for IRQ4
pop ds ; Restore DS
; ----- Enable IRQ4 on 8259 interrupt controller
in al,21H ; Get current masks
and al,11101111B ; Reset IRQ4 mask
out 21H,al ; And restore to IMR
; ----- Enable 8250 data ready interrupt
mov dx,LCR ; DX ==> LCR
in al,dx ; Reset DLAB for IER access
and al,01111111B
out dx,al
mov dx,IER ; Address IER
mov al,00000001B ; Enable 'data-ready' interrupt
out dx,al
; ----- Enable OUT2 on 8250
mov dx,MCR ; Address MCR
mov al,00001000B ; Enable OUT2
out dx,al
sti
; ----- Display greeting & return
mov ax,data ; Establish data seg address
mov ds,ax
mov dx,offset sgreeting ; Point to greeting
call strdisp ; Display it
ret
init endp
; ---- BUFFER_CHECK -----------------------
; RS232 buffer check
;
; This block checks the received data buffer.
; It functions as follows:
;
; IF the RS232 input buffer is not empty
; Get the first character
; Display the character
; Update buffer pointer
; IF the RS232 receive error flag is nonzero
; Display an error indicator
; IF the buffer overflow flag is nonzero
; Display an error indicator
;
; Entry:
; No requirement
; Exit:
; AX, BX, DX destroyed
; -----------------------------------------
buffer_check proc near
; ----- Check buffer status
mov bx,wbufhead ; Buffer head pointer
cmp bx,wbuftail ; Buffer empty if head = tail
je BC100 ; Jump if empty
; ----- Something in buffer--get 1st char, fix pointers
mov al,[bx] ; Get the char
call incptr ; Bump buffer head pointer
mov wbufhead,bx
; ----- Display character received. Filter CR/LF
cmp al,LF ; Is it a line feed?
je BC100 ; Skip display if yes
call chdisp ; Display if no
cmp al,CR ; Is it a CR?
jne BC100 ; Jump if not
mov al,LF ; Send LF if yes
call chdisp
; ----- Test RS232 receive status; display errors
BC100:
test brcv_err,0FFH ; Flag nonzero if errors
jz BC200 ; Jump if no errors
mov dx,offset serr1 ; Point to error msg
call strdisp
mov brcv_err,0 ; Clear error flag
; ----- Test for buffer overflow; display errors
BC200:
test boverflow,0FFH
jz BC300 ; Z if no overflow
mov boverflow,0 ; Clear the flag
mov dx,offset serr3 ; Point to error msg
call strdisp ; And display
BC300:
ret
buffer_check endp
; ----- KB_CHECK --------------------------
; Check keyboard. Functions as follows:
;
; Check the keyboard status
; IF a character is available
; IF the character is ESC
; set the 'done' flag
; ELSE
; send it to RS232 and watch for errors
;
; Note that this routine does not echo the KB characters
; to the display. Display occurs only when the characters
; are echoed back by the remote terminal.
;
; Entry:
; No requirement
; Exit:
; AX, DX destroyed
; -----------------------------------------
kb_check proc near
; ----- Poll keyboard, check chars received
call kb_poll ; Poll the keyboard
jz KBC900 ; Kbd clear, exit
cmp al,ESC ; Escape?
jne KBC100 ; No, continue
mov bdoneflag,0FFH ; Yes, set termination flag
jmp short KBC900
; ----- Send the received char, watch for errors
KBC100:
call RS232_out ; Send it
test ah,80H ; Time out?
jz KBC900 ; No, sent OK
mov dx,offset serr2 ; Point to error msg
call strdisp ; And display it
KBC900:
ret
kb_check endp
; ----- ISR -------------------------------
; This is the RS232 interrupt service routine. It
; is entered whenever the RS232 port interrupts on a
; 'data ready' condition. The routine simply reads
; the data from the asynch chip and stuffs it in the
; buffer. Note that the process of reading the
; received data register in the 8250 clears IRQ4.
; However, the 8259 must be told specifically that the
; interrupt service is complete.
;
; This replaces the function 2 of BIOS interrupt 14H
; (receive a character over the comm line). Since
; it cannot return errors in a register, it puts the
; error marker in memory at 'brcv_err'. The error
; flag is 'sticky'--a successful read will NOT clear a
; prior error indication. This allows the program
; mainline to examine the error status at its
; leisure. Error bits are the same as in RS232OUT,
; above, except that ONLY the error bits are set,
; and bit 7 is not used (always 0). In other words,
; brcv_err is nonzero only on an error. Timeout
; errors are not possible here.
;
; The ISR will set the overflow flag if the buffer
; should overflow. Shouldn't happen.
; -----------------------------------------
ISR proc near
sti ; Allow other interrupts
push ax ; Save all regs used
push bx
push dx
push si
push ds
; ----- Establish data addressability
mov ax,data
mov ds,ax
; ----- Get error bits
mov dx,LSR ; Base address of RS232
in al,dx ; Get status
and al,00011110B ; Mask non-error bits
jz ISR010 ; Skip error set if OK
mov brcv_err,al ; Set error indicator
; ----- Get incoming character and buffer it
ISR010:
mov dx,RBR ; Receiver buffer
in al,dx ; Get input character
mov bx,wbuftail ; Buffer input pointer
mov si,bx ; Save pointer b4 increment
call incptr ; Bump input pointer
cmp bx,wbufhead ; Overflow if head = tail
je ISR020 ; Overflow
mov [si],al ; No overflow, save char in buffer
mov wbuftail,bx ; And new input pointer
jmp short ISR999
ISR020:
mov boverflow,0FFH ; Set overflow flag
; ----- Signal end of interrupt to 8259
ISR999:
cli
mov al,20H ; Non-specific EOI
out 20H,al ; Send it
; ----- Restore regs & return. IRET reenables interrupts
pop ds
pop si
pop dx
pop bx
pop ax
iret
ISR endp
; ----- CLEANUP --------------------------
; End of program housekeeping
; -- Disable IRQ4
; -- Disable 8250 interrupts
; -- Disable OUT2
; -- Display offline message
; ----------------------------------------
cleanup proc near
; ----- Disable IRQ4 on 8259
cli
in al,21H ; IMR
or al,00010000B ; Mask bit 4--IRQ4
out 21H,al
; ----- Disable 8250 data ready interrupt
mov dx,LCR ; DX ==> LCR
in al,dx ; Reset DLAB for IER access
and al,01111111B
out dx,al
mov dx,IER ; Address IER
mov al,0 ; Disable all 8250 interrupts
out dx,al
; ----- Disable OUT2 on 8250
mov dx,MCR ; Address MCR
mov al,0 ; Disable OUT2
out dx,al
sti
; ----- Display bye-bye
mov dx,offset sgoodbye
call strdisp
ret
cleanup endp
; * * * * * * * * * * * * * * * *
; I/O & GENERAL SUBROUTINES
; * * * * * * * * * * * * * * * *
; ----- KB_POLL ---------------------------
; Set/reset Z flag on keyboard buffer status.
;
; Entry:
; No requirements
; Exit:
; Z = 1 if nothing available
; Z = 0 if char available from kbd
; IF Z = 0
; AL = char
; AH = scan code
; Other regs preserved
; -----------------------------------------
kb_poll proc near
@bioscall kbd_io,1 ; Poll KB. Sets Z flag if KB bfr empty
jz KB999 ; Nothing there
pushf ; Save flag status
@bioscall kbd_io,0 ; Something there; get it
popf
KB999:
ret
kb_poll endp
; --- RS232_out --------------------------
; RS232 output routine
;
; This routine sends one character to the RS232 port.
; It replaces function 1 of BIOS int 14H. This is
; necessary because BIOS will disable the RS232
; interrupt (by disabling OUT2) every time it is
; called.
;
; Entry:
; AL = character to be transmitted
; Exit:
; AH = send status
; Bit 7 = 1 if RS232 timeout occurred
; IF bit 7 = 0
; bit 6: trans shift register empty
; bit 5: trans holding register empty
; bit 4: break detect
; bit 3: framing error
; bit 2: parity error
; bit 1: overrun error
; bit 0: data ready
; Other regs preserved
; ----------------------------------------
RS232_out proc near
push bx ; Save regs used
push cx
push dx
; ----- Set up RS232
mov bl,al ; Save char to BL temporarily
mov dx,MCR ; Modem Control Register
mov al,00001011B ; OUT2, DTR, RTS
out dx,al
sub cx,cx ; Initialize timeout count
mov dx,MSR ; Modem Status Register
; ----- Wait for DSR
RS100:
in al,dx
test al,20H ; Data set ready?
jnz RS150 ; Yes
loop RS100 ; No, retry till timeout
mov ah,80H ; Set timeout
jmp short RSXIT ; And quit
; ----- Wait for CTS
RS150:
sub cx,cx ; Another timeout count
RS200:
in al,dx
test al,10H ; Clear to send?
jnz RS250 ; Yes
loop RS200 ; No, loop till timeout
mov ah,80H ; Timeout, set flag
jmp short RSXIT ; And quit
; ----- Wait for THRE
RS250:
mov dx,LSR ; Line Status Register
sub cx,cx ; Yet another timeout count
RS300:
in al,dx ; LSR status
test al,20H ; Transmit holding reg empty?
jnz RS350 ; Yes
loop RS300 ; No, loop till timeout
mov ah,80H ; Timeout, set flag
jmp short RSXIT
; ----- Get line status, send char
RS350:
mov ah,al ; Get line status for return
and ah,01111111B ; Mask out bit 7
mov al,bl ; Restore char to AL
mov dx,THR ; Trasnmit holding register
out dx,al ; Output it to RS232
RSXIT:
pop dx
pop cx
pop bx
ret
RS232_out endp
; ----- CHDISP ----------------------------
; Display the character in AL on the CRT
; Entry:
; AL = char
; Exit:
; All regs restored
; -----------------------------------------
chdisp proc near
push ax
push dx
mov dl,al
@doscall 2
pop dx
pop ax
ret
chdisp endp
; ----- STRDISP ---------------------------
; Display the string at DS:DX on the CRT
; Entry:
; DS:DX ==> string
; Exit:
; All regs restored
; -----------------------------------------
strdisp proc near
push ax
@doscall 9
pop ax
ret
strdisp endp
; ----- INCPTR ----------------------------
; Increment the buffer pointer in reg BX.
; If the pointer goes beyond the end of the
; buffer, wrap around to start.
;
; Entry:
; BX = buffer pointer
; Exit:
; BX = advanced buffer pointer
; Other regs restored
; -----------------------------------------
incptr proc near
inc bx ; Bump pointer
cmp bx,offset bufend ; Past end?
jne IP100 ; Jump if not
mov bx,offset buffer ; Else point to start
IP100:
ret
incptr endp
code ends
end main