home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
modem
/
asm_term.arc
/
TERM.ASM
next >
Wrap
Assembly Source File
|
1988-04-18
|
14KB
|
382 lines
; /-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\
; | |
; | Terminal in assembler, A86 format |
; | Interrupt driven reception |
; | -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
; | Weefus on GEnie or |
; | Keith Rolland 1:321/112.5 |
; | (!) Copywrong 1988 |
; | |
; \-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-/
;
;
jmp BEGIN_PRG ;jump over our data area to the real beginning
MESSAGE1 db 07h,0dh,0ah,0ah,0ah,"Press <alt>-q to quit.......",0dh,0ah,0ah,"$"
MESSAGE2 db " Arrgg, I spent HOW much time on this?!? $"
BUFFER_BOT equ $
BUFFER db 0ffh DUP 00h ;the actual incoming buffer, 255 bytes
BUFFER_TOP equ $
BUFFER_TAIL dw 0000h ;used to control where characters are put
BUFFER_HEAD dw 0000h ;into and taken from the buffer
LINE_CTL_REG = 03fbh ;various memory locations for rs232 registers
MODEM_CTL_REG = 03fch
LINE_STAT_REG = 03fdh
MODEM_STAT_REG = 03feh
CHAR_HOLDING_REG = 03f8h
BOX_TLCOR = 0c9h ;Ascii graphic characters used for
BOX_TRCOR = 0bbh ;making the box.
BOX_BLCOR = 0c8H ;TLCOR = TopLeftCORner and so on....
BOX_BRCOR = 0bch
BOX_VERT = 0bah
BOX_HORZ = 0cdh
SPACE = 020h
SCROLL_COUNT db 00h
;============================================================================
BEGIN_PRG:
mov w[BUFFER_TAIL], offset BUFFER ;set up buffer pointer variables
mov w[BUFFER_HEAD], offset BUFFER ;for our circular buffer
call CLEAR_SCREEN ;routine that will....... (guess :)
call BOX_MAKE ;make our superneato ascii box and message
call SETUP ;set up rs232 and new interrupt routines
;*****************************************************************************
MAIN_LOOP:
call CHECK_INCOMING ;check the buffer, and print any waiting characters
call CHECK_OUTGOING ;see if any keystrokes are waiting in the keyboard queue
jnc MAIN_LOOP ;if carry flag not set, jump to main loop
;*****************************************************************************
cli ;the carry flag is set, indicating an exit request
in al,021h ;reset the com1 interrupt bit in the IMR
or al,010h ;so that no more com1 ints are performed
out 021h,al ;put it back
mov dx,LINE_CTL_REG ;line control reg
in al,dx ;get byte
and al,07fh ;clear bit 7, com1 interrupt enable bit
out dx,al ;put it back
mov al,00h ;tell the modem we no longer will be operating.....
mov dx,MODEM_CTL_REG ;clear modem control reg
out dx,al ;do it
sti ;re-enable interrupts
int 20h ;standard end program interrupt
;-----------------------
SETUP: ;direct set-up of registers, no bios or dos calls
;my mom said it was ok............:)
mov dx,LINE_CTL_REG ;point to the line control register, it controls a lot.
mov al,080h ;turn on bit 7
out dx,al ;send byte
dec dx ;point to msb of baud rate divisor
dec dx
mov al,00h ;msb for any rate > 1200 baud is 00h
out dx,al ;send byte
dec dx ;point to lsb of baud rate divisor
mov al,060h ;lsb for 1200 bps is 60h, use 30h for 2400 bps
out dx,al ;send byte
mov dx,LINE_CTL_REG ;line control register
mov al,0ah ;7/E/1 settings=0ah /use 03h for 8/n/1
out dx,al ;send byte
mov dx,offset NEW_INT ;point com1 interrupt to our new routine, NEW_INT
mov al,0ch ;interrupt to replace = COM1
mov ah,025h ;dos function number for change-a-vector
int 21h ;call dos to change vector
in al,021h ;this will enable interrupts by setting the
and al,0efh ;com1 interrupt bit in the IMR (don't ask! :)
out 021h,al ;IMR is the Interrupt Mask Register
cli ;we don't want to be disturbed during this...
mov dx,LINE_CTL_REG ;point to line control register, rs232
in al,dx ;get byte
and al,07fh ;set high bit
out dx,al ;and put it back
dec dx
dec dx ;move to the rs232 interrupt enable register
mov al,01h ;set it to interrupt when data recieved
out dx,al ;put it back
inc dx
inc dx ;move to modem control register |could have done ....|
inc dx ;set it for using interrupts |mov dx,MODEM_CTL_REG|
mov al,08h ;bit #3 high
out dx,al ;put it back
sti ;re-enable normal interrupts
mov dx,offset MESSAGE1 ;print how-to-exit message
mov ah,09h ;via dos
int 21h
ret ;end of set-up
;-----------------------
CHECK_INCOMING:
mov bx,w[BUFFER_TAIL] ;check to see if anything
cmp bx,w[BUFFER_HEAD] ;is in the buffer....
je ret ;jump if nothing ready
mov al,b[bx] ;character is ready, get it in al
inc bx
cmp bx,BUFFER_TOP ;if buffer_head is at the top of the
jne >L17 ;buffer, we must point it to the other end
mov bx,BUFFER_BOT
L17:
mov w[BUFFER_TAIL],bx ;place new buffer tail in storage
cmp al,1bh ;is char an <escape>?
jne >L13 ;no, so jump, otherwise.....
mov al,0dbh ;change it to a graphic char. No vt100/ansi stuff allowed!
L13: ; this is a *real* simple program! :)
mov dl,al ;dos wants the char in dl to print it
mov ah,02h ;dos print function
int 21h ;call dos
ret ;end check_incoming
;-----------------------
CHECK_OUTGOING:
call CK_FOR_KEY ;subroutine checks for keypress via bios interrupt
je ret ;no key pressed, return to main_loop
jnc >L4 ;no exit request pending so jump ahead
ret ;carry set, so just return and main_loop will act on it
L4:
push bx ;push these on stack
push dx ;as they will be used
push cx ;here internally
mov bl,al ;put keypress in bl temporarily
mov dx,MODEM_CTL_REG ;point to modem control register
mov al,0bh ;tell modem we want to send
out dx,al ;put byte in the register
mov dx,MODEM_STAT_REG ;point to modem status register
WAIT_FOR_CLR:
in al,dx ;get modem status
test al,010h ;test for modems 'clear-to-send' line (bit #4)
jne >L5 ;no problems so jump
loop WAIT_FOR_CLR ;wait for ok (modem is presently busy)
L5:
mov dx,LINE_STAT_REG ;point to line status register
OK_STATUS:
in al,dx ;get status byte
test al,020h ;test bit #5, 'transmit register empty'
jne >L6 ;it's empty,so it's ready for another character
loop OK_STATUS ;it is full, so loop until it is empty
L6:
mov al,bl ;put keypress in al
mov dx,CHAR_HOLDING_REG ;point to transmitter holding register
out dx,al ;put keypress in transmit register, where it
pop cx ;automagicly will be sent upon it's way
pop dx ;restore these from stack
pop bx
ret ;end check_outgoing
;-----------------------
NEW_INT: ;Our New Interrupt Handler
cli ;this interrupt routine is called by the hardware
push ax ;every time a character is recieved via rs232
push bx
push dx ;save registers on stack
push si
push ds
mov ax,cs ;make sure data seg is code seg
mov ds,ax
mov dx,CHAR_HOLDING_REG ;recieve register, the incoming char is held here
in al,dx ;get byte, the incoming character, from register
mov bx,w[BUFFER_HEAD] ;get present buffer head position in bx
mov si,bx ;and then increase bx to point to where
inc bx ;the next character will be placed
cmp bx,BUFFER_TOP ;if BUFFER_HEAD=BUFFER_TOP, we make it BUFFER_BOT
jne >L10 ;next char goes somewhere in the middle of the buffer
mov bx,BUFFER_BOT ;here we reset BUFFER_HEAD to BUFFER_BOT
L10:
cmp bx,w[BUFFER_TAIL] ;if BUFFER_HEAD=BUFFER_TAIL, we have no more room
je >L9 ;in the buffer, ie a buffer overrun has occured!
;in this case, we don't store the incoming char.
;ideally, at this point we should call an error
;handling routine, but you can write that. :)
mov b[si],al ;put byte in buffer if everything is ok
mov w[BUFFER_HEAD],bx ;point buffer_head to new head-of-buffer
L9:
mov al,020h ;tell the hardware we are through with this interrupt
out 020h,al ;by doing this. Only with hardware related ints.
pop ds
pop si
pop dx
pop bx
pop ax
sti
iret ;end new_int
;-----------------------
CK_FOR_KEY:
mov ah,01h ;use int 16h function #01 to test for
int 16h ;keypress available
je ret ;none ready yet so return
pushf
mov ah,00h ;use function #0 to get the keypress
int 16h
popf
clc ;clear it before testing
cmp al,00h ;is the keypress an extended code?
jne ret ;no, so return to check_outgoing
cmp ah,010h ;we have an extended code now- is it <alt>-q?
jne ret ;no, so we will let the odd code go through for now
stc ;yes, it is <alt>-q, so we set the carry flag and return
ret ;end ck_for_key
;-----------------------
CLEAR_SCREEN: ;the hard way!
mov ah,02h ;use bios video to
mov bh,00h ;set cursor position to top left
mov dx,00h ;of screen
int 10h ;bios function 02h
;
mov ah,09h ;now using function 09h
mov cx,0800h ;print a space char 0800h times, ~2000d...
mov al,20h ;20h = space char
mov bl,07h ;attribute of character
int 10h ;clear it!
;
mov ah,02h ;now let's put the
mov bh,00h ;cursor back up in
mov dx,00h ;the upper left corner
int 10h ;bios video function
ret ;end clear_screen
;-------------------------------------------------
;*******************************
;* Following are used to make *
;* the ascii box. Is it worth *
;* all of the programming? *
;*******************************
PRINT_MANY:
mov ah,02h ;load dl with character to be printed
PRINT_MORE:
int 21h ;and cx with the number of times it
dec cx
jcxz ret ;should be printed
jmp PRINT_MORE
;-----------------------
PRINT_ONE:
mov ah,02h ;load dl with character
int 21h
ret
;-----------------------
POSITION:
MOV dl,SPACE
mov cx,0ah
call PRINT_MANY
ret
;-----------------------
CR_LF:
mov ah,02h
mov dl,0dh
int 21h
mov dl,0ah
int 21h
ret
;-----------------------
SIDES: ;symbols make for good reading!
call POSITION
mov dl,BOX_VERT
call PRINT_ONE
mov dl,SPACE
mov cx,03ah
call PRINT_MANY
mov dl,BOX_VERT
call PRINT_ONE
call CR_LF
ret
;-----------------------
BOX_TOP:
call POSITION
mov dl,BOX_TLCOR
call PRINT_ONE
mov dl,BOX_HORZ
mov cx,03ah
call PRINT_MANY
mov dl,BOX_TRCOR
call PRINT_ONE
call CR_LF
ret
;-----------------------
BOX_BOT:
call POSITION
mov dl,BOX_BLCOR
call PRINT_ONE
mov dl,BOX_HORZ
mov cx,03ah
call PRINT_MANY
mov dl,BOX_BRCOR
call PRINT_ONE
ret
;-----------------------
BOX_MAKE:
call CR_LF
call CR_LF
call BOX_TOP
call SIDES
call POSITION
mov dl,BOX_VERT
call PRINT_ONE
lea dx,MESSAGE2 ;set up for dos' print-string routine
mov ah,09h ;dos function number for same
int 21h ;do it
mov dl,BOX_VERT
call PRINT_ONE
call CR_LF
call SIDES
call BOX_BOT
call CR_LF
call SCROLL_DOWN
call SCROLL_UP
ret ;end box_make. Not exactly elegant, huh? :)
;-----------------------
SCROLL_UP:
mov SCROLL_COUNT,0fh ;number of lines to scroll
DO_SCROLL:
mov ah,00h ;get time of day
int 01ah ;tod interrupt
add dx,01h ;delay value
mov bx,dx ;store ending value in bx
push ax
push bx
mov ah,06h ;scroll up using bios function 6
mov al,01h ;number of rows to scroll up
mov cx,00h ;cl=top left row cl=top left col
mov dh,018h ;b r row
mov dl,050h ;b r col
mov bh,07h ;attribute of cleared line
int 10h ;do it
pop bx
pop ax
WAIT_HERE:
int 01ah ;check tod to see if delay is over
cmp dx,bx
jne WAIT_HERE
dec SCROLL_COUNT
mov al,SCROLL_COUNT
jnz DO_SCROLL
ret
;-----------------------
SCROLL_DOWN:
mov SCROLL_COUNT,0fh ;number of lines to scroll
DO_SCROLL2:
mov ah,00h ;get time of day
int 01ah ;tod interrupt
add dx,01h ;delay value
mov bx,dx ;store ending value in bx
push ax
push bx
mov ah,07h ;scroll down using bios function 7
mov al,01h ;number of rows to scroll down
mov cx,00h ;cl=top left row cl=top left col
mov dh,018h ;b r row
mov dl,050h ;b r col
mov bh,07h ;attribute of cleared line
int 10h ;do it
pop bx
pop ax
WAIT_HERE2:
int 01ah ;check tod to see if delay is over
cmp dx,bx
jne WAIT_HERE2
dec SCROLL_COUNT
mov al,SCROLL_COUNT
jnz DO_SCROLL2
ret
;-----------------------