Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D5/VSCREEN.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1069 lines
30 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'Virtual Screen Handler '
;******************************************************
; *
; This module contains all code necessary for *
; full screen buffering on a serial (VT-52) *
; terminal. *
; Note: assumes m_alloc in XIOS header has been *
; initialized to reserve space for screen *
; images. *
; Last changed : 2/11/84 *
; *
;******************************************************
include vscreen.equ
include system.lib
include chrcomm.equ
include serdata.equ
eject
dseg
extrn mem_alloc:word
extrn ocdesctbl:word
public screen_image_tbl
cseg
public vs_init
public vs_conout
public default_esc
public vs_switch
public set_up_bx
extrn conout1:near
extrn serial_out:near
;************************************************
; VIRTUAL SCREEN INITIALIZATION *
;************************************************
;==========
vs_init:
;==========
mov ax, mem_alloc ; segment address given by GENCCPM
mov bx, offset scrn_image0 ; get first screen image
xor ch,ch
mov cl, nvcons ; do init for each virtual console
init_scrn: ; init each structure with the segment
mov vs_screen_seg,ax ; address of its char/attrib buffer
add bx, vs_struc_len
add ax,((crt_size + 15) shr 4) * 2
loop init_scrn
mov ah, vsa_normal ; attribute = normal
mov al, blank ; char = blank
mov bx, offset scrn_image0 ; with normal attribute byte
mov cl, nvcons
push es
clear_scrn: ; do one clear for each virtual console
push cx
mov es, vs_screen_seg ; get segment address back
sub di,di
mov cx, crt_size ; get screen size
rep stosw ; paint screen with blanks
pop cx
add bx,vs_struc_len ; index to next screen structure
loop clear_scrn
pop es ; we're done
ret
eject
;******************************************************
; *
; ENTRY POINT FOR VIRTUAL SCREEN UPDATES *
; *
;******************************************************
;===========
vs_conout:
;===========
mov bx,dx ; BL = virtual console #
shl bx,1
mov bx,screen_image_tbl[bx] ; get virtual screen structure
mov al,cl ! mov ah,dl ; Set up AX for subroutines
mov cx,0 ! push ax ; AH = console #, AL = character
call vs_escape_rt ; This is the escape handler if in middle
; of a sequence. Default is CONOUT01.
cmp cx,0 ! jne conout01 ; CX = 0 if in escape sequence
; = ffff if regular char
other_char: ; Either we're in the middle of an
; escape sequence or it's a special char.
pop cx ! mov dl,ch ; Fall through to physical output.
xor ch,ch ; Virtual update has been done.
jmp conout1
conout01:
mov di, offset spec_char_tab ; check if special char (CR,LF,BS,ESC)
mov si, offset spec_func_tab ; if so, co_look_up jmps to corresponding
call co_look_up ; function
jcxz conout02 ; else,update image with simple character
jmp other_char
conout02: ; simple character handling
pop cx ! mov dl,ch ! xor ch,ch ; restore console # and char
mov di,vs_cursor ; starting point of single char copy
push es ; BX = virtual screen structure
mov es,vs_screen_seg ; ES = segment of virtual screen
mov ah,vs_attrib ; AH -> current attribute
mov al,cl ; CL,AL -> new char
stosw
pop es ; DI pts to next attribute/char word
cmp vs_column,crt_col - 1 ; see if we need a CR-LF
jb inc_col ; no, go move cursor one to the right
test vs_mode,vsm_no_wrap ; if in wrap mode, don't do CR-LF
jz conout03 ; and continue on to physical output
call carriage_return ; else update virtual cursor,col & row
call line_feed
conout03:
jmp conout1
inc_col:
call r_right ; updates cursor by one (to the right)
jmp conout1
;************************************************
; *
; SPECIAL CHARACTER OUTPUT ROUTINES *
; *
;************************************************
;----------------
carriage_return:
;----------------
; entry: BX = screen structure
; exit : BX preserved
push dx
xor dx,dx
xchg vs_column,dl ; set column to zero
shl dx,1 ; back up cursor
sub vs_cursor,dx
pop dx
ret
;----------------
line_feed:
;----------------
; entry: BX = screen structure
; exit : BX preserved
cmp vs_row, crt_row - 1
je lf_scroll ; are we at bottom of screen?
jmp d_down ; no, move cursor down a line
lf_scroll:
push dx
xor dl,dl ; yes, adjust top & bottom pointers
mov dh, crt_row - 1
call scroll_up
pop dx
jmp erase_line
;-----------------
back_space:
;-----------------
; entry: BX = screen structure
; exit : BX = preserved
mov di,vs_cursor
test di,di ; are we at home position ?
jz bs_ret ; yes, ignore backspace
cmp vs_column,0 ; are we at the beginning of a line ?
je bs_row ; yes, try previous line
dec vs_column ; else, simple case : dec # cols
jmps bs_set_cursor
bs_row:
test vs_mode,vsm_no_wrap ; if in nowrap mode, don't back up to
jnz bs_ret ; previous line
dec vs_row ; else, dec current row and
mov vs_column,crt_col - 1 ; show column at end of line
bs_set_cursor:
sub di,2 ; DI = cursor
mov vs_cursor,di
bs_ret:
ret
;*******************************************************
;
; ESCAPE SEQUENCE ROUTINES
;
;*******************************************************
;----------
co_look_up:
;----------
; entry: BX = address of screen structure
; AH = device number
; AL = char to scan for
; DI = ptr to lookup table
; SI = function table
; exit : CX = 0ffffh if special char found
; 0 if no spec char found
; if not spec function, AX & BX preserved
mov bp,es ! mov dx,ds
mov es,dx
xor cx,cx ! mov cl,[di] ; first byte of di is length of table
mov dx,cx ! inc di
repne scasb ; cruise through table for match
mov es,bp ; restore ES
je lookup_func ; got a match, go get function
ret ; else, return with CX = 0
lookup_func:
inc cx ; CX = number matched on
sub dx,cx ! shl dx,1 ; function number
add si,dx
call word ptr [si]
xor cx,cx ! dec cx ; return with CX = 0ffffh
ret
;----------
escape_rt:
;----------
; entry: BX = screen structure
; AL = current byte in esc sequence
; exit : vs_escape_rt = address of next routine to execute
; in this sequence
mov vs_escape_rt,offset escape1
ret
escape1:
mov vs_escape_rt, offset default_esc ; assume done with escape
mov di, offset esc_tbl ; if more to do, this field
mov si, offset esc_func_tbl ; will be set by handler
push cx ; save CX to show in esc
call co_look_up ; sequence
pop cx
ret
;----------
home: ; ESC H
;----------
xor ax,ax
mov vs_cursor,ax
mov vs_column,al
mov vs_row,al
ret
;----------
right: ; ESC C
;----------
cmp vs_column,crt_col - 1 ; if at end of screen, ignore it
jb r_right
ret
r_right:
add vs_cursor,2
inc vs_column
ret
;----------
left: ; ESC D
;----------
cmp vs_column,0 ; if at beginning of screen, ignore it
ja l_left
ret
l_left:
sub vs_cursor,2
dec vs_column
ret
;----------
down: ; ESC B
;----------
cmp vs_row,crt_row - 1 ; if at bottom of screen, ignore it
jb d_down
ret
d_down:
add vs_cursor,crt_col * 2
inc vs_row
ret
;----------
up: ; ESC A
;----------
cmp vs_row,0 ; if at top of screen, ignore it
ja d_up
ret
d_up:
sub vs_cursor,crt_col * 2
dec vs_row
ret
;---------------
up_with_scroll: ; ESC I
;---------------
cmp vs_row,0 ; if not on the top line, mov the cursor
ja up ; to the top only
push dx
xor dl,dl ; else, scroll it up
mov dh,crt_row - 1 ; start row = 0, end row = screen bottom
call scroll_down ; cursor stays the same
pop dx
jmp erase_line
;----------
save: ; ESC j
;----------
mov ah,vs_row ; save row and col in xy
mov al, vs_column
mov vs_xy,ax
mov ax,vs_cursor ; save cursor
mov vs_oldcursor,ax
ret
;----------
restore: ; ESC k
;----------
mov ax,vs_xy
mov vs_column,al
mov vs_row,ah
mov ax,vs_oldcursor
mov vs_cursor,ax
ret
;-----------
x_and_y: ; ESC Y
;-----------
mov vs_escape_rt,offset xy_row ; wait for row
ret
xy_row:
sub al,32
cmp al,crt_row - 1
jbe row_ok
mov vs_escape_rt,offset xy_ret
ret
row_ok:
mov vs_row,al
mov vs_escape_rt,offset xy_col ; wait for column
ret
xy_col:
sub al,32
cmp al,crt_col - 1
jbe xy_set_col
mov al,crt_col - 1
xy_set_col:
mov vs_column,al ; Set the new column #
push cx ! push dx
xor ax,ax
mov al,vs_row ; Use new row and column to compute
mov cx,crt_col * 2 ; new cursor position.
mul cx
xor cx,cx
mov cl,vs_column
shl cx,1
add ax,cx
mov vs_cursor,ax
pop dx ! pop cx
xy_ret:
mov vs_escape_rt, offset default_esc
ret
;---------------
erase_screen: ; ESC E
;---------------
push es ! push cx
mov es, vs_screen_seg ; get virtual screen segment
mov ax, 0720H ; put normal attribute with blank
mov cx, crt_size ; do entire screen
xor di,di ; start at position zero
rep stosw
pop cx ! pop es
ret
;---------------
erase_begin: ; ESC B
;---------------
push es ! push cx
mov es, vs_screen_seg ; get virtual screen segment
mov ax,vs_cursor ; get number of words to erase from
shr ax,1 ; beginning of screen
mov cx,ax
mov ax, 0720h ; give them all normal atrributes
xor di,di ; start at top of screen
rep stosw
pop cx ! pop es
ret
;---------------
erase_end: ; ESC J
;---------------
push es ! push cx
mov es,vs_screen_seg ; get virtual screen segment
mov ax,vs_cursor
mov di,ax ; erase from cursor to the end
shr ax,1
mov cx,crt_size
sub cx,ax ; CX = total # words to erase
mov ax,0720h ; given them all normal attributes
rep stosw
pop cx ! pop es
ret
;---------------
erase_line: ; ESC l
;---------------
push es ! push cx ! push dx
mov es,vs_screen_seg ; get virtual screen segment
xor ax,ax
mov al,vs_row
mov cx,crt_col
mul cx ; get word offset of current row
shl ax,1 ; make it a byte offset
mov di,ax ; start erasing here
mov ax,0720h ; give them all normal attributes
rep stosw
pop dx ! pop cx ! pop es
ret
;---------------
erase_bol: ; ESC o
;---------------
push es! push cx ! push dx ; erase from beginning of line
mov es,vs_screen_seg
xor ax,ax
mov al,vs_row ; current row
mov cx,crt_col * 2
mul cx
mov di,ax ; beginning offset - word
xor cx,cx
mov cl,vs_column ; number of words to erase
inc cx ; on this line
mov ax,0720h ; give them all normal attributes
rep stosw
pop dx ! pop cx ! pop es
ret
;---------------
erase_eol: ; ESC K
;---------------
push es ! push cx ; erase to end of line
mov es,vs_screen_seg ; get virtual screen segment
mov di,vs_cursor ; start to erase here
mov cx,crt_col
sub cl,vs_column ; number of words to erase on this line
mov ax,0720h ; give them all normal attributes
rep stosw
pop cx ! pop es
ret
;---------------
insert_line: ; ESC L
;---------------
push ax ! push dx
mov dl,vs_row ; start row
mov dh,crt_row - 1 ; ending row
call scroll_down ; make room for the new line
call erase_line ; erase the old one
xor ax,ax
xchg al,vs_column ; set cursor
shl ax,1
sub vs_cursor,ax
pop dx ! pop ax
ret
;---------------
delete_line: ; ESC M
;---------------
;
; ENTRY : BX -> screen structure
; EXIT : BX _> same
push ax ! push dx
mov dl,vs_row ; scroll up first
mov dh,crt_row - 1
call scroll_up
mov vs_row[bx], crt_row - 1
call erase_line ; then erase the line
call carriage_return
pop dx ! pop ax
ret
;---------------
delete_char: ; ESC N
;---------------
push es ! push cx
mov es,vs_screen_seg ; get virtual screen segment
mov di,vs_cursor
mov si,di
add si,2
xor cx,cx
mov cl,crt_col - 1
sub cl,vs_column
push ds ! push es ! pop ds
rep movsw
mov 0[di],0720h ; put a blank in last column
pop ds ! pop cx ! pop es
ret
;---------------
enter_reverse: ; ESC p
;---------------
push ax ! push es ! push di
;mov es, vs_screen_seg
mov al, vs_mode
or al,vsa_reverse
mov vs_mode, al
;mov di, vs_cursor
;mov ax, es:[di]
;mov ah,vsa_reverse
;mov es:[di],ax
mov al, vsa_reverse
mov vs_attrib,al
pop di ! pop es ! pop ax
ret
;---------------
exit_reverse: ; ESC q
;---------------
push ax ! push es ! push di
;mov es, vs_screen_seg
mov al, vs_mode
and al, not vsa_reverse
mov vs_mode, al
;mov di, vs_cursor
;mov ax, es:[di]
;mov ah, vsa_normal
;mov es:[di],ax
mov al, vsa_normal
mov vs_attrib,al
pop di ! pop es ! pop ax
ret
;---------------
enter_blink: ; ESC s
;---------------
ret
;---------------
exit_blink: ; ESC t
;---------------
ret
;---------------
enter_bright: ; ESC r
;---------------
ret
;---------------
exit_bright: ; ESC u
;---------------
ret
;---------------
enable_cursor: ; ESC e
;---------------
ret
;---------------
disable_cursor: ; ESC f
;---------------
ret
;---------------
enable_wrap: ; ESC v
;---------------
and vs_mode,not vsm_no_wrap
ret
;---------------
disable_wrap: ; ESC w
;---------------
or vs_mode,vsm_no_wrap
ret
;***********************************************************
;
; SUBROUTINES FOR VIRTUAL SCREEN UPDATES
;
;***********************************************************
;----------
scroll_up: ; scroll up in the range given in AX
;----------
; entry: AH = virtual screen #
; BX = screen structure
; DL = starting row - 0 relative
; DH = ending row - 0 relative
; exit : AX,BX,ES preserved
push es ! push cx ! push dx
mov es,vs_screen_seg ; DX = start,end rows AL = virt. console #
mov cx,dx ; save copy of start,end rows
xor ax,ax ! mov al,dl ; set up SI,DI
mov dx,crt_col * 2
mul dx ! mov di,ax ; DX,AX = byte offset starting row
add ax,crt_col * 2
mov si,ax ! mov ax,cx ; SI = first word to copy from
sub ah,al ! xor al,al
xchg al,ah ; set up CX for # words to copy
mov dx,crt_col
mul dx ! mov cx,ax
push ds ! push es! pop ds
rep movsw
pop ds ! pop dx ! pop cx ! pop es
ret
;----------
scroll_down:
;----------
; entry: AH = virtual console number
; BX = screen structure
; DL = start row
; DH = end row
; exit : AX,BX,ES preserved
push ax ! push cx ! push es
mov es,vs_screen_seg
mov cx,dx
xor ax,ax
mov al,dh
inc al
push dx
mov dx,crt_col * 2
mul dx
sub ax,2
mov di,ax
sub ax,crt_col * 2
mov si,ax
std
mov ax,cx
sub ah,al
xor al,al
xchg al,ah
mov dx,crt_col
mul dx
mov cx,ax
pop dx
push ds ! push es ! pop ds
rep movsw
pop ds ! pop es ! pop cx ! pop ax
cld
ret
;----------
default_esc:
;----------
; entry : CX = 0
; exit : CX = ffffh - flag for simple char
; CX = 0 for escape or backspace
dec cx
ret
eject
;**********************************************************
; *
; SCREEN SWITCH ROUTINES *
; *
;**********************************************************
;=========
vs_switch: ; Switch Screen with full screen buffering
;=========
;
; input: dl = Vcon to switch to
; dh = Pcon to do the switch on
;
switch_init:
mov bx, dx
xor bh, bh
shl bx,1
mov bx, screen_image_tbl[bx] ;; BX -> screen structure
mov es, vs_screen_seg ;; ES -> screen image buffer
push word ptr vs_mode
push word ptr vs_column ;; save row and col for cursor
push word ptr vs_row ;; restore.
set_up:
call set_up_bx ;; BX -> output Q ctl structure
call ser_home ;; home physical cursor
call ser_clear ;; clear physical screen
call ser_ex_rev ;; just to be safe
xor di,di ;; DI -> our cursor
xor dh,dh ;; DL -> # columns done so far
mov dl, 0ffh
mov al, vsa_normal ;; AL -> attribute
xor ah,ah ;; Default attribute is normal.
switch_loop:
mov cx, es:[di] ;; CX -> new atrribute, char
cmp al,ch ;; new attribute ?
je switch_loop1 ;; no, send the char
send_esc_seq:
push dx ! push cx
test ch, vsa_reverse
jnz ent_rev
call ser_ex_rev
jmp done_esc
ent_rev:
call ser_ent_rev
done_esc:
pop cx ! pop dx
xor ah,ah
mov al,ch ;; update attribute
switch_loop1:
push dx ! push ax
xor ch,ch
call serial_out ;; send the char
inc di ! inc di ;; DI -> curr char count
pop ax ! pop dx
inc dl ;; DL -> column count
total_check:
push di ! dec di ! dec di
cmp di,(crt_size * 2) - 2 ;; DI -> total chars sent so far
pop di
jae redo_cursor
line_check:
cmp dl, crt_col - 1 ;; are we at the end of line ?
jb switch_loop ;; no, do total chars check
call car_ret ;; do the CR/LF
mov dl, 0ffh ;; reset col count to 0
jmps switch_loop
redo_cursor:
pop ax ! pop dx ;; AL -> row, DL -> col
call restore_cursor
chk_wrap:
pop dx ;; get mode back
test dl, vsm_no_wrap ;; check for wrap-around mode
jnz dis_wrap
call ser_en_wrap
jmps chk_rev
dis_wrap:
call ser_dis_wrap
chk_rev:
test dl, vsa_reverse ;; check for inverse video
jz ex_rev
call ser_ent_rev
jmps curr_vc
ex_rev:
call ser_ex_rev
curr_vc:
ret ;; back to switch module
;-----------
set_up_bx:
;-----------
xor bx, bx
mov bl, dh ;; use Pcon to index into the Xmit Q's
shl bx, 1
mov bx, ocdesctbl[bx] ;; bx -> Xmit Q control
ret
ser_ent_rev:
;-----------
; Sends Z-29/19 escape sequence for Enter Reverse Mode
;
; Entry : BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'p'
call serial_out
ret
ser_ex_rev:
;----------
; Sends Z-29/19 escape sequence for Exit Reverse Mode
;
; Entry : BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'q'
call serial_out
ret
ser_en_wrap:
;-----------
; Sends Z-29/19 escape sequence for Enable Wrap Mode
;
; Entry : BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'v'
call serial_out
ret
ser_dis_wrap:
;-----------
; Sends Z-29/19 escape sequence for Disable Wrap Mode
;
; Entry: BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'w'
call serial_out
ret
ser_home:
;--------
; Sends Z-29/19 escape sequence for Home Cursor
;
; Entry : BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'H'
call serial_out
ret
ser_clear:
;---------
; Sends Z-29/19 escape sequence for Clear Screen
;
; Entry : BX -> Xmit Q control structure
;
mov oesc_cnt[bx], 2
mov cl, esc
call serial_out
mov cl, 'E'
call serial_out
ret
car_ret:
;-----------
; Sends a carriage return/ linefeed to Z-29/19 .
;
;
push ax ! push si
mov cl, 0ah
call serial_out
mov cl, 0dh
call serial_out
pop si ! pop ax
ret
restore_cursor:
;--------------
; Sends Z-29/19 escape sequence to reposition cursor
;
; Entry : BX -> Xmit Q control structure
;
push dx ! push ax
mov oesc_cnt[bx],4
mov cl, esc
call serial_out
mov cl, 'Y'
call serial_out
pop ax ;; row #
add al, 32 ;; normalize for terminal
mov cl,al
call serial_out
pop dx ;; col #
add dl, 32 ;; move cursor 1 char past last char
mov cl,dl
call serial_out
ret
dseg
;***************************************************************
; *
; SPECIAL OUTPUT CHARACTER TABLES *
; *
;***************************************************************
spec_char_tab db 4
db cr,lf,backsp,escape
spec_func_tab dw carriage_return
dw line_feed
dw back_space
dw escape_rt
;***************************************************************
; *
; ESCAPE SEQUENCE TABLES *
; *
;***************************************************************
esc_tbl db 28
db 'H','C','D','S','A'
db 'I','j','k','Y','E'
db 'b','J','l','o','K'
db 'L','M','N','p','q'
db 'r','u','s','t','a'
db 'f','v','w'
esc_func_tbl dw home
dw right
dw left
dw down
dw up
dw up_with_scroll
dw save
dw restore
dw x_and_y
dw erase_screen
dw erase_begin
dw erase_end
dw erase_line
dw erase_bol
dw erase_eol
dw insert_line
dw delete_line
dw delete_char
dw enter_reverse
dw exit_reverse
dw enter_bright
dw exit_bright
dw enter_blink
dw exit_blink
dw enable_cursor
dw disable_cursor
dw enable_wrap
dw disable_wrap
;*****************************************************************
; *
; VIRTUAL SCREEN IMAGE TABLE *
; *
;*****************************************************************
screen_image_tbl dw scrn_image0
dw scrn_image1
dw scrn_image2
dw scrn_image3
dw scrn_image4
dw scrn_image5
dw scrn_image6
dw scrn_image7
scrn_image0 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image1 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image2 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image3 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image4 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image5 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image6 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
scrn_image7 dw 0,0 ;cursor, oldcursor
db 0,0,2 ;col, row, mode
db vsa_normal ;attribute
dw 0,0,0 ;xy, oldxy, screen segment
dw offset default_esc ;default: first char = reg char
end