home *** CD-ROM | disk | FTP | other *** search
- ;--------------------------------------------------------------------
- ; DUMBTERM
- ; Original author is CJ Dunford 09/12/83, modified by Jeff Firestone
- ; on 01/15/84. This program sets up the interrupt for COM1. It uses
- ; buffered communications. The program is based upon PC Tech Journal
- ; Jan '84, p144-186.
- ;---------------------------------------------------------------------
-
- bufsize equ 4096 ;4K Buffer
-
- LF equ 0Ah
- CR equ 0Dh
- K_ESC equ 1Bh
-
- ; ------- BIOS calls
-
- RS232 equ 14h ;RS232 service
- kbd_io equ 16h ;Keyboard service
-
- ; ------- INS8250 registers
-
- THR equ 3F8h ;Trans holding register (write)
- RBR equ 3F8h ;Recieve buffer register (read)
- IER equ 3F9h ;Interrupt inable 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 manual page A-20
- ; See PROC INIT for usage.
- ; ---------------------------------------
- commparm record baud:3, parity:2, stopbits:1, wordbits:2
-
- ; Buad 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 AH
- IFNB <parm>
- mov al,parm
- ENDIF
- @bioscall 21h,function
- ENDM
-
-
- ;******************************
- ; DATA & STACK SEGMENTS
- ;******************************
-
- data segment para public 'data'
-
- ; ----- The string section
- sgreeting db '--- ONLINE -0--',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
-
- ; ----- Receive data buffer and associated pointers
- ; >> Buffer is empty if head point4er = 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 BODY
- ;* * * * * * * * * * * * * * * * *
-
- code segment para public 'code'
- assume cs:code, ds:data, ss:stack
-
- main proc far
-
- ; ------ Initialize
- push ds ;Set up long return to DOS
- sub ax,ax
- push ax
- call init ;Rest of initialization
-
- ; ------ Main program loop
- M100: call buffer_check ;Check RS232 buffer, display if char
- 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
- 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
- ; --------------------------------------------
-
- init proc near
-
- ; ----- Initialize RS232 300,8,N,1
- mov dx,0
- mov al,commparm <B9600,even_Parity,stop1,data7>
- @bioscall RS232,0
-
- ; ----- Set up INT '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 vector intr for IRQ4
- pop ds ;Restore DS
-
- ; ------ Enable IRQ4 on 8259 interrupt controller
- in al,21h ;Get current mask
- and al,11101111b ;Reset IRQ4 mask
- out 21h,al ;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
- ;
- ; 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
-
- ; ------ 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
- jne BC100
- mov al,LF
- 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
- mov boverflow,0 ;Clear the flag
- mov dx,offset serr3 ;Point to error msg
- call strdisp
-
- BC300: ret
- buffer_check endp
-
- ; ----- KB_CHECK -----------------------------------
- ; Check the keyboard. Functions as follows
- ;
- ; Check the keyboard status
- ; If a characteris available
- ; If the character is ESC
- ; set the done flag
- ; ELSE
- ; send it to RS232 and watch for errors
- ;
- ; This routine does not echo the characters to the display.
- ;
- ; 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,K_ESC ;Escape?
- jne KBC100
- mov bdoneflag,0FFh ;Yes, set terminate flag
- jmp short KBC900
-
- ; ----- Send the received char, watch for errors
- KBC100: Call RS232_out ;Send it
- test ah,80h ;Time out?
- jz KBC900
- mov dx,offset serr2 ;Point to error msg
- call strdisp ; and display
-
- 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.
- ; This 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 ;Save 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 ;Receive buffer
- in al,dx ;Get input buffer
- mov bx,wbuftail ;Buffer input pointer
- mov si,bx ;Set pointer before increment
- call incptr ;Bump input pointer
- cmp bx,wbufhead ;Overflow if head = tail
- je ISR020 ;Overflow
- mov [si],al ;No overflow, save char in buf
- 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
- 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 14K. 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 cs
- 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 ;Yes 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 ;Transmit 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 ------------------------------
- ; Increments 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