home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
async
/
comasm.asm
< prev
Wrap
Assembly Source File
|
1992-01-12
|
47KB
|
1,604 lines
PAGE 63,132 ;(63 lines long, 132 columns wide)
TITLE Mark Stout COMASM 5/10/89
.SALL
;==============================================================================
;
; Mark Stout COMASM.EXE 5/10/89
;
; COMASM is an integrated terminal emulation package combining two modes,
; VT52 and CHAT. While in the VT52 emulation mode, COMASM will impersonate
; a DEC VT52, transmitting, receiving and interpreting all escape
; sequences in this terminal's command set. While in the CHAT mode, COMASM
; allows messages to be sent between two PCs. Any characters
; may be sent, in messages up to 256 characters long.
;
; Data is transmitted and received through the PC's primary serial port,
; COM1. COMASM relies on interupts from the UART as opposed to polling
; its registers.
;
;==============================================================================
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^MACROS^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;==============================================================================
;
; DISPLAY Macro:
;
; Displays string of characters on standard output. String must be
; terminated by '$'.
;
; Format:
;
; DISPLAY message
;
; where message is the offset of the string.
;
;==============================================================================
DISPLAY MACRO MESSAGE
PUSH DX
PUSH AX
LEA DX, MESSAGE ;Point to offset of string
MOV AH, 9H ;Use DOS function 9H
INT 21H
POP AX
POP DX
ENDM
;==============================================================================
;
; BIN2ASCII Macro:
;
; Converts binary value in DX to ASCII string.
;
; Format:
;
; BIN2ASCII length, out_buffer
;
; where length is the # of characters for the output string, including
; leading spaces, and out_buffer is location of output buffer.
;
;==============================================================================
BIN2ASCII MACRO LENGTH, OUT_BUFFER
LOCAL ASCIILOOP, BLANK, NEXT, PAD ;Define local labels for multiple invocations
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV CX, LENGTH ;Set up CX as counter of ASCII digits
MOV AX, DX ;Move binary value to accumulator
MOV BX, 10 ;Set up BX as decimal base
ASCIILOOP:
MOV DI, CX ;Use DI for index relative addressing of ASCII string
CMP AX, 0 ;If accumulator = 0, pad left of string with blanks
JE BLANK
MOV DX, 0 ;Prepare DX as high word of dividend
DIV BX ;Divide remaining value by decimal base
ADD DX, 30H ;Convert remainder to ASCII for use in string
MOV [OUT_BUFFER+DI-1], DL ;Converted remainder is next least significant digit in string
JMP NEXT
BLANK: CMP CX, LENGTH ;Checks for binary value = 0
JNE PAD
MOV [OUT_BUFFER+DI-1], '0'
JMP NEXT
PAD: MOV [OUT_BUFFER+DI-1], ' ' ;Pads left of string with blanks when necessary
NEXT: LOOP ASCIILOOP ;Calculate next digit of string
POP DI
POP DX
POP CX
POP BX
POP AX
ENDM
;===============================================================================
;
; SCROLL_UP Macro:
;
; Uses BIOS function INT 10h, Subfunction 6, to scroll a pre-defined
; window a given number of lines. New lines are white foreground on
; black background.
;
; Format:
;
; SCROLL_UP lines, TL_row, TL_col, BR_row, BR_col
;
; where: lines = # of lines to scroll (0 for entire window)
; TL_row = row of top, left corner
; TL_col = column of top, left corner
; BR_row = row of bottom, right corner
; BR_col = column of bottom, right corner
;
;===============================================================================
SCROLL_UP MACRO LINES, TL_ROW, TL_COL, BR_ROW, BR_COL
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH, 6 ;Choose subfunction 6
MOV AL, LINES ;Initialize registers
MOV CH, TL_ROW
MOV CL, TL_COL
MOV DH, BR_ROW
MOV DL, BR_COL
MOV BH, 7
INT 10H
POP DX
POP CX
POP BX
POP AX
ENDM
;===============================================================================
;
; SCROLL_DOWN Macro:
;
; Uses BIOS function INT 10h, Subfunction 6, to scroll a pre-defined
; window down a given number of lines. New lines are white foreground on
; black background.
;
; Format:
;
; SCROLL_DOWN lines, TL_row, TL_col, BR_row, BR_col
;
; where: lines = # of lines to scroll (0 for entire window)
; TL_row = row of top, left corner
; TL_col = column of top, left corner
; BR_row = row of bottom, right corner
; BR_col = column of bottom, right corner
;
;===============================================================================
SCROLL_DOWN MACRO LINES, TL_ROW, TL_COL, BR_ROW, BR_COL
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH, 7 ;Choose subfunction 7
MOV AL, LINES ;Initialize registers
MOV CH, TL_ROW
MOV CL, TL_COL
MOV DH, BR_ROW
MOV DL, BR_COL
MOV BH, 7
INT 10H
POP DX
POP CX
POP BX
POP AX
ENDM
;===============================================================================
;
; LOCATE Macro:
;
; Uses BIOS function INT 10h, Subfunction 2, to position cursor.
;
; Input: DH = Row coordinate (0-24)
; DL = Column coordinate (0-79)
;
;===============================================================================
LOCATE MACRO
PUSH AX
PUSH BX
MOV AH, 2 ;Choose subfunction 2
MOV BH, 0 ;Choose video page
INT 10H
POP BX
POP AX
ENDM
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
STKSEG SEGMENT STACK ;Stack segment
DB 512 DUP(?) ;(512 bytes ought to do)
STKSEG ENDS
CSEG SEGMENT ;Code segment
ASSUME CS:CSEG, DS:CSEG, SS:STKSEG, ES:NOTHING
;==============================================================================
;
; MP3 Main Procedure:
;
; Sets up data, and calls subroutines. Also performs requested
; mode switching and exits.
;
;==============================================================================
MAIN PROC FAR
MOV AX, CSEG ;Initialize DS register
MOV DS, AX
JMP OLA ;Jump around data
; Define equates, messages and buffers
MSGCAP EQU 256
CR EQU 0DH
LF EQU 0AH
EOM EQU 0DH
ESCAPE EQU 27
XON EQU 17
XOFF EQU 19
TOP_BORDER DB "╔═════════════════ OUT ════════════════╗╔═════════════════ IN ═════════════════╗$"
BOT_BORDER DB "╚══════════════════════════════════════╝╚══════════════════════════════════════╝$"
VERT_BORDER DB "║$"
INTRO DB "CHAT MODE: Type anything. ENTER sends each message. Hit ESC to exit.$"
FULL_QUEUE DB "Warning: The transmission queue is full. Please hit ENTER to end the message.$"
INVALID_MSG DB "Warning: Invalid key was depressed.$"
TX_POSITION DW ?
RX_POSITION DW ?
VT_POSITION DW 0
LMSG DW 0
VECTOR_SEG DW ?
VECTOR_OFF DW ?
MODE DB ? ;Mode = 3 for VT52 emulation, 1 for CHAT
STATUS DB "STATUS: Baud: 1200 Parity: N Data Bits: 8 Stop Bit(s): 1$"
APPLICATION DB 0 ;Indicates numeric keypad application mode.
ESC_SEQ DB 0
DCADDRESS_LINE DB ?
COMM_PAR DB 10000011B ;Communications parameters
BAUD_PROMPT DB "Select Baud: A)110 B)150 C)300 D)600 E)1200 F)2400 G)4800 H)9600 $"
PARITY_PROMPT DB "Select Parity: N)one E)ven O)dd $"
DATA_PROMPT DB "Select Data Bits: 7)Seven 8)Eight $"
STOP_PROMPT DB "Select Stop Bits: 1)One 2)Two $"
XOFF_MSG DB "Receiced XOFF. Please stop typing.$"
FLOW DB 0
; Call subroutines.
OLA: CALL ISR_INIT ;Install new interupt service routine 0Ch
VT52:
MOV MODE, 3 ;Update mode indicator
CALL PORT_INIT
CALL VT52_SCREEN
CALL CLEAR_QUEUES
EMU: CALL VT52_INPUT
CMP AL, 0 ;Could character be for program control?
JNE NO_ALT
CMP AH, 24 ;CHAT for Alt-O
JE CHAT
CMP AH, 45 ;Exit to DOS for Alt-X
JE CIAO
NO_ALT: CALL VT52_DISPLAY
CALL FLOW_CONTROL ;Handle receipt of XOFF.
JMP EMU
CHAT:
MOV MODE, 1 ;Update mode indicator
CALL PORT_INIT
CALL CHAT_SCREEN
CALL CLEAR_QUEUES
GAB: CALL CHAT_INPUT ;Process characters in keyboard buffer
CMP AL, ESCAPE ;If escape entered, exit
JE VT52
CALL RX_DISPLAY ;Display any received character
JMP GAB ;Repeat for next character
CIAO:
SCROLL_UP 0, 0, 0, 24, 79 ;Blank screen upon exit
MOV DX, VECTOR_OFF
MOV DS, VECTOR_SEG
MOV AX, 250CH ;Install original interrupt vector
INT 21H
MOV AH,4Ch ;DOS code to exit
INT 21h ;(exit)
MAIN ENDP
;===============================================================================
;
; ISR_INIT Subroutine:
;
; Installs new INT 0Ch vector. Saves original vector for restoration.
;
;===============================================================================
ISR_INIT PROC NEAR
PUSH AX
PUSH BX
PUSH DX
PUSH ES
MOV AX, 350CH ;Get original INT 0Ch vector
INT 21H
MOV VECTOR_SEG, ES
MOV VECTOR_OFF, BX
LEA DX, ISR0C ;Find address of new interupt service routine
MOV AX, 250CH ;Install vector for new ISR
INT 21H
POP ES
POP DX
POP BX
POP AX
RET
ISR_INIT ENDP
;===============================================================================
;
; ISR0C Interupt Handler:
;
; Alerted by interupt type 0Ch. Checks for type of UART interupt, and
; acts accordingly. If RDA is true, reads character from UART. If THRE
; is true, transmits character from TX queue.
;
;===============================================================================
ISR0C PROC
PUSH AX
PUSH DX
PUSH DI
PUSH DS
MOV AX, CSEG ;Restore data segment register
MOV DS, AX
MOV DX, 03FAH ;Check Interupt
IN AL, DX ;Identification Register
TEST AL, 10B ;Was it a THRE irpt?
JNZ THRE
MOV DX, 3F8H ;Receive character
IN AL, DX
CMP AL, XOFF ;Check for XOFF
JNE ISR1
MOV FLOW, 0FFH ;Set data flow indicator
JMP ISR_DONE
ISR1: CMP AL, XON ;Check for XON
JNE ISR2
MOV FLOW, 0 ;Reset data flow indicator
JMP ISR_DONE
ISR2: LEA DI, RQ
CALL ENQUEUE ;Enqueue received character
JMP ISR_DONE
THRE:
LEA DI, TQ ;Dequeue character for transmission
CALL DEQUEUE
MOV DX, 03F8H ;Transmit character
OUT DX, AL
CMP MODE, 1 ;Disable THRE according to mode
JE CHATTER
CMP TQ.COUNT, 0 ;Any characters to be sent?
JNE ISR_DONE
MOV AL, 01B ;If not, disable THRE irpts
MOV DX, 03F9H
OUT DX, AL
JMP ISR_DONE
CHATTER:
CMP TQ.NMSGS, 0 ;Any more pending messages to be sent?
JNE ISR_DONE
MOV AL, 01B ;If no more messages pending,
MOV DX, 03F9H ;disable THRE irpts
OUT DX, AL
ISR_DONE:
MOV AL, 20H ;Inform UART that ISR is finished
OUT 20H, AL
POP DS
POP DI
POP DX
POP AX
IRET
ISR0C ENDP
;===============================================================================
;
; PORT_INIT Subroutine:
;
; Initializes primary serial port for the parameters determined by AL.
;
; Uses BIOS function INT 14h, Subfunction 0.
;
; Input: COMM_PAR has initialization bit pattern: BBBPPSLL
;
; Output: COM1 is initialized
; ALL REGISTERS PRESERVED
;
;===============================================================================
PORT_INIT PROC NEAR
PUSH AX
PUSH DX
MOV DX, 0 ;Choose primary port
MOV AH, 0 ;Indicate subfunction
MOV AL, COMM_PAR ;Get communication parameters
INT 14H ;Initialize port
MOV DX, 3FDH ;Clear out any initial garbage
IN AL, DX ;in UART register
TEST AL, 1B
JE PORT_CLEAR
MOV DX, 3F8H ;Receive garbage character
IN AL, DX
PORT_CLEAR:
MOV AL, 01B
MOV DX, 03F9H
OUT DX, AL ;Enable RDA irpts
MOV AL, 1011B ;Set OUT2 of the Modem Control Register
MOV DX, 03FCH ;so UART passes Irpts to the 8259
OUT DX, AL ;Also, initiate handshaking through DTR and RTS
SHAKE: MOV DX, 03FEH ;Check that modem has completed handshake
IN AL, DX
AND AL, 00110000B ;Is modem ready to communicate?
JZ SHAKE ;If not, wait
IN AL, 21H ;Enable IRQ4 interrupts at
AND AL, 11101111B ;the 8259 PIC
OUT 21H, AL
POP DX
POP AX
RET
PORT_INIT ENDP
;===============================================================================
;
; VT52_SCREEN Subroutine:
;
; Displays status line and positions cursor for VT52 emulation.
;
;===============================================================================
VT52_SCREEN PROC NEAR
PUSH DX
SCROLL_UP 0, 0, 0, 24, 79
MOV DX, 1800H
LOCATE
DISPLAY STATUS
MOV DX, VT_POSITION
LOCATE
POP DX
RET
VT52_SCREEN ENDP
;===============================================================================
;
; VT52_INPUT Subroutine:
;
; Uses BIOS function INT 16h to check for and retrieve characters typed
; on transmitting keyboard. Queues them into TQ.
;
;===============================================================================
VT52_INPUT PROC NEAR
PUSH BX
PUSH DI
MOV AH, 1
INT 16H
JZ VTI_RESET
MOV AH, 0 ;Accept character from keyboard
INT 16H
CMP AL, 0 ;Convert special keys, and flag invalid keys
JNE VT_IN1
CALL VT52_SPECIAL
CMP AL, 0 ;Don't enqueue invalid characters
JE DONE_IN2
VT_IN1: CMP APPLICATION, 0 ;Is keypad in application mode?
JE VT_IN2
MOV BL, AL ;If so, add 40 to ASCII value of
MOV BH, 0 ;keypad characters as part of
ADD AL, APP_CODES[BX] ;VT52 specs
PUSH AX
MOV AL, ESCAPE ;Send ESC ? before application
LEA DI, TQ ;keypad value
CALL ENQUEUE
MOV AL, "?"
CALL ENQUEUE
POP AX
VT_IN2: LEA DI, TQ ;Enqueue character for transmission
CALL ENQUEUE
PUSH AX
MOV AL, 11B ;Enable THRE irpts, as character(s)
MOV DX, 03F9H ;wait for transmission
OUT DX, AL
POP AX
JMP DONE_IN2
VTI_RESET:
MOV AX, 0 ;If no key entered reset "new key value"
DONE_IN2:
POP DI
POP BX
RET
VT52_INPUT ENDP
APP_CODES DB 12 DUP(0), 40H, 30 DUP(0), 3 DUP(40H), 0, 10 DUP(40H), 200 DUP(0)
;===============================================================================
;
; VT52_SPECIAL Subroutine:
;
; Interprets cursor movement and screen control keys.
; Transmits appropriate escape sequence.
;
;===============================================================================
VT52_SPECIAL PROC NEAR
PUSH BX
PUSH DX
PUSH DI
CMP AH, 25 ;Change comm. parameters?
JNE SPEC1
CALL LINE_SETTINGS
JMP FINI
SPEC1: CMP AH, 59 ;Don't interpret invalid key press
JB FINI
CMP AH, 118
JA FINI
MOV BL, AH ;Use look-up table of appropriate sequences
MOV BH, 0
SUB BX, 50
MOV DL, SPECIAL_CODES[BX]
CMP DL, " " ;Don't interpret invalid keys
JE FINI
MOV AL, DL ;Get ready for enqueuing sequences
PUSH AX
LEA DI, TQ
CMP AL, "J" ;Was it CLEAR SCREEN?
JNE SPEC2
MOV AL, ESCAPE ;CLEAR SCREEN is a dual escape sequence
CALL ENQUEUE
MOV AL, "H"
CALL ENQUEUE
SPEC2: MOV AL, ESCAPE ;Enqueue esc of sequence
CALL ENQUEUE
POP AX
FINI: POP DI
POP DX
POP BX
RET
VT52_SPECIAL ENDP
SPECIAL_CODES DB " PQRS HA D C KB J"
;===============================================================================
;
; VT52_DISPLAY Subroutine:
;
; Interprets and displays received characters.
;
;===============================================================================
VT52_DISPLAY PROC NEAR
PUSH AX
PUSH BX
PUSH DX
PUSH DI
CMP RQ.COUNT, 0 ;Received characters for display?
JE VTD_DONE
LEA DI, RQ ;Dequeue next available character
CALL DEQUEUE
CMP ESC_SEQ, 0 ;Part of esc sequence?
JE VTD1
CALL VTD_ESCAPE
JMP VTD_DONE
VTD1: CMP AL, ESCAPE ;Is character start of escape sequence?
JNE VTD2
MOV ESC_SEQ, 0FFH ;Store escape sequence status
JMP VTD_DONE
VTD2: MOV DX, VT_POSITION ;Position cursor
LOCATE
MOV AH, 2 ;Display new character
MOV DL, AL
INT 21H
MOV AH, 3 ;Determine new cursor location
MOV BH, 0
INT 10H
CMP DH, 24 ;Is cursor on status line?
JNE VTD3
SCROLL_UP 1, 0, 0, 23, 79 ;Scroll if necessary
MOV DH, 23
LOCATE
VTD3: MOV VT_POSITION, DX ;Store new cursor location
VTD_DONE:
POP DI
POP DX
POP BX
POP AX
RET
VT52_DISPLAY ENDP
;===============================================================================
;
; VTD_ESCAPE Subroutine:
;
; Moves cursor and/or manipulate screen according to escape sequence.
;
;===============================================================================
VTD_ESCAPE PROC NEAR
PUSH AX
PUSH DX
CMP ESC_SEQ, 0FFH ;Initial character after escape received?
JE VE1 ;Yes, jump to code for simple sequences
CMP ESC_SEQ, 0FH ;Final character of Direct Cursor Address?
JE VE2 ;Yes
SUB AL, 20H ;No, calculate specified line for LOCATE macro
CMP AL, 23 ;Check to see line is on screen
JBE VE3
MOV AL, 23
VE3: MOV DCADDRESS_LINE, AL ;Store lin specified by DCA
MOV ESC_SEQ, 0FH
JMP VE_DONE
VE2: SUB AL, 20H ;Interpret column of DCA
CMP AL, 79
JBE VE4
MOV AL, 79
VE4: MOV DL, AL
MOV DH, DCADDRESS_LINE
JMP VE_LOC ;Locate cursor
VE1: MOV DX, VT_POSITION ;Interpret simple escape sequences
CMP AL, "A" ;Up arrow?
JNE VE5
CMP DH, 0
JE VE_RESET
DEC DH
JMP VE_LOC
VE5: CMP AL, "B" ;Down arrow?
JNE VE6
CMP DH, 23
JE VE_RESET
INC DH
JMP VE_LOC
VE6: CMP AL, "C" ;Right arrow?
JNE VE7
CMP DL, 79
JE VE_RESET
INC DL
JMP VE_LOC
VE7: CMP AL, "D" ;Left arrow?
JNE VE8
CMP DL, 0
JE VE_RESET
DEC DL
JMP VE_LOC
VE8: CMP AL, "H" ;Home cursor?
JNE VE9
MOV DX, 0
JMP VE_LOC
VE9: CMP AL, "I" ;Reverse Line feed?
JNE VE10
CMP DH, 0
JE ROOM
DEC DH
JMP VE_LOC
ROOM: SCROLL_DOWN 1, 0, 0, 23, 79
JMP VE_LOC
VE_RESET: ;Reset escape sequence indicator
MOV ESC_SEQ, 0
JMP VE_DONE
VE10: CMP AL, "J" ;Erase EOS?
JNE VE11
CMP DH, 23
JE VE12
CALL CLEAR_BLOCK
VE12: CALL ERASE_EOL
JMP VE_LOC
VE11: CMP AL, "K" ;Erase EOL?
JNE VE13
CALL ERASE_EOL
JMP VE_LOC
VE13: CMP AL, "Y" ;Direct Cursor Address?
JNE VE14
MOV ESC_SEQ, 0F0H
JMP VE_DONE
VE14: CMP AL, "Z" ;Identify Terminal?
JNE VE15
CALL IDENTIFY
JMP VE_RESET
VE15: CMP AL, "=" ;Enter Application Keypad Mode?
JNE VE16
MOV APPLICATION, 0FFH
JMP VE_RESET
VE16: CMP AL, ">" ;Exit App Keypad Mode?
JNE VE_RESET
MOV APPLICATION, 0
JMP VE_RESET
VE_LOC: LOCATE ;Reposition cursor
MOV VT_POSITION, DX
JMP VE_RESET
VE_DONE:
POP DX
POP AX
RET
VTD_ESCAPE ENDP
;===============================================================================
;
; CLEAR_BLOCK Subroutine:
;
; Erases screen below cursor as part of ERASE EOS.
; Uses INT 10, Sub 6 to scroll block.
;
;===============================================================================
CLEAR_BLOCK PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH, 6 ;Choose subfunction
MOV AL, 0 ;Load parameters
MOV BH, 7
MOV CH, DH
INC CH
MOV CL, 0
MOV DX, 174FH
INT 10H ;Erase block
POP DX
POP CX
POP BX
POP AX
RET
CLEAR_BLOCK ENDP
;===============================================================================
;
; ERASE_EOL Subroutine:
;
; Erases screen to end of current line.
; Uses INT 10, Sub 6 to scroll line.
;
;================================================================================
ERASE_EOL PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH, 6 ;Choose subfunction
MOV AL, 0 ;Load parameters
MOV BH, 7
MOV CX, DX
MOV DL, 79
INT 10H ;Erase block
POP DX
POP CX
POP BX
POP AX
RET
ERASE_EOL ENDP
;===============================================================================
;
; IDENTIFY Subroutine:
;
; Sends remote computer identifying string unique to VT52: esc / Z
;
;===============================================================================
IDENTIFY PROC NEAR
PUSH AX
PUSH DI
LEA DI, TQ
MOV AL, ESCAPE ;Send esc
CALL ENQUEUE
MOV AL, "/" ;Send /
CALL ENQUEUE
MOV AL, "Z" ;Send Z
CALL ENQUEUE
POP DI
POP AX
RET
IDENTIFY ENDP
;===============================================================================
;
; LINE_SETTINGS Subroutine:
;
; Allows user to alter communication parameters. UART is reset,
; and status line updated.
;
;===============================================================================
LINE_SETTINGS PROC NEAR
PUSH AX
PUSH BX
PUSH DX
MOV DX, 1800H ;Prompt user for BAUD
LOCATE
DISPLAY BAUD_PROMPT
LS1: MOV AH, 8
INT 21H ;Get response
CMP AL, 97
JB CAPS
SUB AL, 32
CAPS: SUB AL, 65
CMP AL, 7
JA LS1
MOV BH, 0
MOV BL, AL
SHL BL, 1
MOV DX, BAUD[BX]
BIN2ASCII 4, STATUS[17] ;Update status line
SHL AL, 1 ;Update parameters for UART
SHL AL, 1
SHL AL, 1
SHL AL, 1
SHL AL, 1
MOV COMM_PAR, AL
MOV DX, 1800H ;Prompt user for PARITY
LOCATE
DISPLAY PARITY_PROMPT
LS2: MOV AH, 8 ;get response
INT 21H
CMP AL, 97 ;Interpret choice
JB CAPS2
SUB AL, 32
CAPS2: CMP AL, "E"
JE LS3
CMP AL, "O"
JE LS4
CMP AL, "N"
JE LS5
JMP LS2
LS3: OR COMM_PAR, 00011000B ;Update UART parameters
LS4: OR COMM_PAR, 00001000B
LS5: MOV STATUS[33], AL
MOV DX, 1800H ;Prompt user for data bits
LOCATE
DISPLAY DATA_PROMPT
LS6: MOV AH, 8 ;Get response
INT 21H
CMP AL, "8"
JE LS7
CMP AL, "7"
JE LS8
JMP LS6
LS7: OR COMM_PAR, 11B
LS8: OR COMM_PAR, 10B
MOV STATUS[49], AL
MOV DX, 1800H ;Prompt user for stop bits
LOCATE
DISPLAY STOP_PROMPT
LS9: MOV AH, 8
INT 21H ;Get response
CMP AL, "2"
JE LS10
CMP AL, "1"
JE LS11
JMP LS9
LS10: OR COMM_PAR, 100B
LS11: MOV STATUS[67], AL
MOV DX, 1800H ;Display new status
LOCATE
DISPLAY STATUS
MOV DX, VT_POSITION
LOCATE
CALL PORT_INIT ;Reinitialize UART
POP DX
POP BX
POP AX
RET
LINE_SETTINGS ENDP
BAUD DW 110, 150, 300, 600, 1200, 2400, 4800, 9600
;===============================================================================
;
; FLOW_CONTROL Subroutine:
;
; Implementation of XON/XOFF protocol.
;
; If XOFF received, informs user and waits for receipt of XON
; before further transmission.
;
;===============================================================================
FLOW_CONTROL PROC NEAR
PUSH DX
CMP FLOW, 0 ;XOFF received?
JE FC_DONE
MOV DX, 1800H
LOCATE
DISPLAY XOFF_MSG ;Inform user of receipt
FC1: CMP FLOW, 0FFH ;Wait for XON
JE FC1
LOCATE ;Refresh status line
DISPLAY STATUS
FC_DONE: POP DX
RET
FLOW_CONTROL ENDP
;===============================================================================
;
; CHAT_SCREEN Subroutine:
;
; Displays windows for transmission and reception of characters.
;
; Uses the DISPLAY macro to display border elements, the LOCATE macro to
; position cursor, and the SCROLL_UP macro to clear the screen.
;
;===============================================================================
CHAT_SCREEN PROC NEAR
PUSH CX
PUSH DX
SCROLL_UP 0, 0, 0, 24, 79 ;Blank screen initially
MOV DX, 0
LOCATE ;Position top border
DISPLAY TOP_BORDER
MOV DH, 23 ;Position bottom border
LOCATE
DISPLAY BOT_BORDER
MOV CX, 22 ;Draw vertical borders down 22 rows
ROW: MOV DH, CL
MOV DL, 0
LOCATE
DISPLAY VERT_BORDER
MOV DL, 39
LOCATE
DISPLAY VERT_BORDER
MOV DL, 40
LOCATE
DISPLAY VERT_BORDER
MOV DL, 79
LOCATE
DISPLAY VERT_BORDER
LOOP ROW
MOV DX, 1800H ;Greet user
LOCATE
DISPLAY INTRO
MOV TX_POSITION, 0101H
MOV RX_POSITION, 0129H
MOV DX, 0101H
LOCATE
POP DX
POP CX
RET
CHAT_SCREEN ENDP
;===============================================================================
;
; CHAT_INPUT Subroutine:
;
; Uses BIOS function INT 16h to check for and retrieve characters typed
; on transmitting keyboard.
;
; Output: AL = character typed, or 0 for invalid character
; AH DESTROYED
;
;===============================================================================
CHAT_INPUT PROC NEAR
PUSH DX
PUSH DI
MOV AH, 1
INT 16H
JZ DONE_IN
SCROLL_UP 0, 24, 0, 24, 79 ;Clear status line
MOV AH, 0 ;Accept character from keyboard
INT 16H
CMP AL, ESCAPE ;Exit for ESC
JE DONE_IN
CMP AL, 0 ;Convert cursor keys, and flag invalid keys
JNE CHAR_ENQ
CALL CURSOR_KEY
CMP AL, 0 ;Don't enqueue invalid characters
JE DONE_IN
CHAR_ENQ:
CMP AL, 9 ;Convert tabs to spaces
JNE DETABBED
MOV AL, 32
DETABBED:
LEA DI, TQ ;Enqueue character for transmission
CALL ENQUEUE
JC QUEUE_ERROR ;Alert user of full queue
CMP AL, EOM
JNE TX_SHOW
PUSH AX
MOV AL, 11B
MOV DX, 03F9H
OUT DX, AL
POP AX
TX_SHOW:
CALL TX_DISPLAY ;Display characters
DONE_IN:
POP DI
POP DX
RET
QUEUE_ERROR: ;Display warning and instruction to user
MOV DX, 1800H
LOCATE
DISPLAY FULL_QUEUE
JMP DONE_IN
CHAT_INPUT ENDP
;===============================================================================
;
; CURSOR_KEY Subroutine:
;
; Converts cursor-movement-key scan codes into unused ASCII values
; for display and transmission. Also alerts user of invalid key
; entries. Uses DISPLAY and LOCATE macros to display message.
;
; Input: AH = scan code to be converted.
;
; Output: AL = ASCII value
;
;===============================================================================
CURSOR_KEY PROC NEAR
CMP AH, 72 ;Up arrow?
JE UP_TX
CMP AH, 75 ;Left arrow?
JE LEFT_TX
CMP AH, 77 ;Right arrow?
JE RIGHT_TX
CMP AH, 80 ;Down arrow?
JE DOWN_TX
MOV AL, 0
MOV DX, 1800H
LOCATE
DISPLAY INVALID_MSG ;All other special keys are invalid
RET
UP_TX: MOV AL, 30 ;Convert cursor keys to
RET ;unused ASCII values
LEFT_TX: MOV AL, 29
RET
RIGHT_TX: MOV AL, 28
RET
DOWN_TX: MOV AL, 31
RET
CURSOR_KEY ENDP
;===============================================================================
;
; TX_DISPLAY Subroutine:
;
; Displays characters typed into keyboard for transmission. Uses DOS
; function 2, as well as LOCATE and SCROLL_UP macros for display.
; BIOS INT 10, subfunction 3 used to determine cursor location.
;
;===============================================================================
TX_DISPLAY PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV DX, TX_POSITION ;Position cursor properly in OUT window
;Interpret cursor movement keys
CMP AL, 8 ;Backspace?
JE TD_LEFT
CMP AL, 29 ;Left arrow?
JNE TD_NL
TD_LEFT: CMP DL, 1
JE TD_STEP
DEC DL
LOCATE
JMP TD_SAVE
TD_NL: CMP AL, 28 ;Right arrow?
JNE TD_NR
CMP DL, 38
JE TD_STEP
INC DL
LOCATE
JMP TD_SAVE
TD_NR: CMP AL, 30 ;Up arrow?
JNE TD_NU
CMP DH, 1
JE TD_STEP
DEC DH
LOCATE
JMP TD_SAVE
TD_STEP: LOCATE ;Used to facilitate long range, conditional jumps
JMP TD_DONE
TD_NU: CMP AL, 31 ;Down arrow?
JNE TD_ND
TD_DOWN: CMP DH, 22
JE TD_BOTTOM
INC DH
LOCATE
JMP TD_SAVE
TD_BOTTOM: SCROLL_UP 1, 1, 1, 22, 38 ;Scroll window 1 line if neccessary
LOCATE
JMP TD_DONE
TD_ND: CMP AL, CR ;Carriage return?
JNE TD_NC
MOV DL, 1
JMP TD_DOWN
TD_NC: CMP AL, LF ;Line feed? (interpret same as down arrow)
JE TD_DOWN
CMP AL, 0BH ;Vertical tab? (same as down arrow)
JE TD_DOWN
CMP AL, 0CH ;Form feed? (same as down arrow)
JE TD_DOWN
;Display non-movement characters
CMP DL, 39 ;Character on right edge of window?
JNE TD_SHOW
MOV DL, 1 ;Wrap around to next line
CMP DH, 22
JNE TD_LINE
SCROLL_UP 1, 1, 1, 22, 38 ;Scroll 1 line if neccessary
JMP TD_SHOW
TD_LINE: INC DH ;Move down a line
TD_SHOW: LOCATE
MOV AH, 2
MOV DL, AL
INT 21H ;Display Character
MOV AH, 3
MOV BH, 0
INT 10H ;Determine location of cursor
TD_SAVE:
MOV TX_POSITION, DX ;Store current location
TD_DONE:
POP DX
POP CX
POP BX
POP AX
RET
TX_DISPLAY ENDP
;===============================================================================
;
; RX_DISPLAY Subroutine:
;
; Displays any messages received from serial port. Uses DOS
; function 2, as well as LOCATE and SCROLL_UP macros for display.
; BIOS INT 10, subfunction 3 used to determine cursor location.
;
;===============================================================================
RX_DISPLAY PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
CMP RQ.NMSGS, 0 ;Pending messages for display?
JNE DEQUIT
JMP RD_DONE
DEQUIT: LEA DI, RQ ;Dequeue next available character
CALL DEQUEUE
MOV DX, RX_POSITION ;Position cursor properly in window
;Interpret cursor movement keys
CMP AL, 8 ;Backspace?
JE RD_LEFT
CMP AL, 29 ;Left arrow?
JNE RD_NL
RD_LEFT: CMP DL, 41
JE RD_STEP
DEC DL
LOCATE
JMP RD_SAVE
RD_NL: CMP AL, 28 ;Right arrow?
JNE RD_NR
CMP DL, 78
JE RD_STEP
INC DL
LOCATE
JMP RD_SAVE
RD_NR: CMP AL, 30 ;Up arrow?
JNE RD_NU
CMP DH, 1
JE RD_STEP
DEC DH
LOCATE
JMP RD_SAVE
RD_STEP: LOCATE ;Intermediate step for long range
JMP RD_DONE ;conditional jump
RD_NU: CMP AL, 31 ;Down arrow?
JNE RD_ND
RD_DOWN: CMP DH, 22
JE RD_BOTTOM
INC DH
LOCATE
JMP RD_SAVE
RD_BOTTOM: SCROLL_UP 1, 1, 41, 22, 78 ;Scroll 1 line if neccessary
LOCATE
JMP RD_DONE
RD_ND: CMP AL, CR ;Carriage return?
JNE RD_NC
MOV DL, 41
JMP RD_DOWN
RD_NC: CMP AL, LF ;Line feed? (Interpret like down arrow)
JE RD_DOWN
CMP AL, 0BH ;Vertical tab? (same as down arrow)
JE RD_DOWN
CMP AL, 0CH ;Form feed? (same as down arrow)
JE RD_DOWN
;Display non-movement characters
CMP DL, 79 ;Wrap line if neede
JNE RD_SHOW
MOV DL, 41
CMP DH, 22
JNE RD_LINE
SCROLL_UP 1, 1, 41, 22, 78 ;Scroll 1 line if needed
JMP RD_SHOW
RD_LINE: INC DH ;Move down one line for wrap
RD_SHOW: LOCATE ;Position cursor
MOV AH, 2
MOV DL, AL
INT 21H ;Display character
MOV AH, 3
MOV BH, 0
INT 10H ;Determine current location of cursor
RD_SAVE:
MOV RX_POSITION, DX ;Store location
RD_DONE:
POP DI
POP DX
POP CX
POP BX
POP AX
RET
RX_DISPLAY ENDP
;===============================================================================
;
; ENQUEUE Subroutine:
;
; Used to enqueue the character in AL into specified queue.
;
; Input: AL = character to be enqueued
; DI = pointer to queue
;
; Output: CF = 1 if attempted enqueue failed due to full queue
; CF = 0 otherwise
; [DI].REAR updated
; [DI].COUNT incremented if enqueue successful
; [DI].NMSGS incremented if character is EOM
; THRE interupts enabled if character is EOM
;
;===============================================================================
ENQUEUE PROC NEAR
PUSH DX
PUSH SI
CMP DI, OFFSET RQ ;Don't check RQ for full queue
JE ENQ1
CMP AL, EOM ;Don't check for full queue if EOM
JNE TQ_NOT_EOM
MOV LMSG, 0
JMP ENQ1
TQ_NOT_EOM:
CMP LMSG, MSGCAP ;Check TQ for full queue
STC ;Assume full queue
JNE ENQ0
JMP DONE_ENQ
ENQ0: INC LMSG ;Increment current msg length for TQ
ENQ1: MOV SI, [DI].REAR ;Adjust the rear pointer
CMP SI, [DI].QBEG
JA ENQ2
ADD SI, QCAPAC
ENQ2: DEC SI
MOV [DI].REAR, SI
MOV [SI], AL ;Enque the character
INC [DI].COUNT ;Update queue count
CMP AL, EOM
CLC
JNE DONE_ENQ
INC [DI].NMSGS ;If EOM, increment pending messages
DONE_ENQ:
POP SI
POP DX
RET
ENQUEUE ENDP
;===============================================================================
;
; DEQUEUE Subroutine:
;
; Used to dequeue a character into AL from specified queue.
;
; Input: DI = pointer to queue
;
; Output: AL = character dequeued
; [DI].FRONT updated
; [DI].COUNT decremented
; [DI].NMSGS decremented if character = EOM
;
;===============================================================================
DEQUEUE PROC NEAR
PUSH DX
PUSH SI
DEC [DI].COUNT ;Update queue counter
MOV SI, [DI].FRONT ;Adjust the front pointer
CMP SI, [DI].QBEG
JA DEQ1
ADD SI, QCAPAC
DEQ1: DEC SI
MOV [DI].FRONT, SI
MOV AL, [SI] ;Dequeue the character
CMP AL, EOM ;Check for end of message
JNE DEQ2
DEC [DI].NMSGS
DEQ2: POP SI
POP DX
RET
DEQUEUE ENDP
;===============================================================================
;
; CLEAR_QUEUES Subroutine:
;
; Wipes transmit and receive queues clear for switching modes.
;
;===============================================================================
CLEAR_QUEUES PROC NEAR
PUSH AX
MOV AX, RQ.QBEG ;Reinitialize receive queue
ADD AX, QCAPAC
MOV RQ.FRONT, AX
MOV RQ.REAR, AX
MOV RQ.COUNT, 0
MOV RQ.NMSGS, 0
MOV AX, TQ.QBEG ;Reinitialize transmit queue
ADD AX, QCAPAC
MOV TQ.FRONT, AX
MOV TQ.REAR, AX
MOV TQ.COUNT, 0
MOV TQ.NMSGS, 0
POP AX
RET
CLEAR_QUEUES ENDP
;===============================================================================
;
; Queue Structures:
;
; TQ is used to hold up to 512 characters before transmission.
; RQ is used to hold up to 512 characters, after reception, but
; before display.
;
;===============================================================================
QSTRUC STRUC
FRONT DW ? ;Ptr to last character dequeued
REAR DW ? ;Ptr to last character enqueued
QBEG DW ? ;Offset of first byte of queue
COUNT DW ? ;Number of bytes currently in queue
NMSGS DW ? ;Number of messages pending
QSTRUC ENDS
QCAPAC EQU 512
TQBEG DB QCAPAC DUP('T') ;Allocate space for queues
RQBEG DB QCAPAC DUP('R')
;Initialize queues
TQ QSTRUC <TQBEG+QCAPAC, TQBEG+QCAPAC, TQBEG, 0, 0>
RQ QSTRUC <RQBEG+QCAPAC, RQBEG+QCAPAC, RQBEG, 0, 0>
CSEG ENDS
END MAIN