pcs/realio.asm

1903 lines
67 KiB
NASM
Raw Permalink Normal View History

2023-05-20 05:57:06 -04:00
; =====> REALIO.ASM
;*****************************************************
;* TIPC Scheme Runtime Support *
;* Real Mode I/O Routines *
;* *
;* (C) Copyright 1985 by Texas *
;* Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Date Written: November 1987 (tc) *
;* Last Modification: *
;*****************************************************
include schemed.equ ;for port defs
include screen.equ
.286c
;
; Local equates
;
RETURN equ 0Dh ; Carriage Return Character
LINEFEED equ 0Ah ; Line Feed Character
DOS equ 021h ; Dos function request
WRITEFILE equ 040h ; Write Fiel function request
DISK_FULL equ -1 ; Disk full error designator
TIPC equ 1 ; Designates machine type as TIPC
TI_CRT equ 049h
IBM_CRT equ 010h
;
; Segment Definitions
;
PGROUP group PROG
DGROUP group DATA
; This stack is used for the standard XLI interface. However, a different
; stack (i.e. PCS's) is used during calls to a graphics driver.
STACK segment word stack 'STACK'
stackstart = $
dw 16 dup (?)
stacksize = $ - stackstart
STACK ends
;
; Data definitions
;
DATA segment byte public 'DATA'
assume DS:DGROUP
datastart = $
callers_ds dw ?
callers_es dw ?
;-----------------------------------------------------------------------------
; Type/Monitor info
;-----------------------------------------------------------------------------
PC_MAKE dw 0
VID_MODE dw 3
MAX_ROWS db DEFAULT_NUM_ROWS
MAX_COLS db DEFAULT_NUM_COLS
CHAR_HGT dw 8
;-----------------------------------------------------------------------------
; Jump table for handler based on op_code
;-----------------------------------------------------------------------------
OP_CODE dw BELL ; 0 - Sound Bell
dw CLEAR ; 1 - Clear Screen
dw BORDER ; 2 - Draw Border
dw SAVE_SCR ; 3 - Save Screen
dw REST_SCR ; 4 - Restore Screen
dw ? ; 5 - was turn cursor on
dw ? ; 6 - was turn cursor off
dw ? ; 7 - was position cursor
dw PUTCHAR ; 8 - Put Character on screen
dw SCROLLUP ; 9 - Scroll Screen Up 1 Line
dw SCROLLDN ; 10 - Scroll Screen Dn 1 Line
dw ? ; 11 - was ega cursor emulation
dw CHGMODE ; 12 - Note Change to Video Mode
dw WSTRING ; 13 - Write string to output port
dw WBLOCK ; 14 - Write string to display
table_len equ $ - OP_CODE
;-----------------------------------------------------------------------------
; XLI Setup
;-----------------------------------------------------------------------------
;;; ----- Equates -----
; offsets into the PSP
term_addr equ 0Ah
fb_addr equ 5Ch
;;; ----- Data structures -----
; file block
file_block label word
dw 4252h
dw 10011b ;flags = sysint,0,0,16-bit,near
dw offset lookup_table, seg lookup_table
dw offset parm_block, seg parm_block
; reserved area of file block
dw 100h ;sysint# (256=%graphics)
dw offset handler, seg handler ;ISR entry point
dw 0,0,0,0,0
; parameter block
parm_block label word ;not used
dw 0
; lookup table
lookup_table label word
db '//' ;not used
; other needed values
psp dw ? ;PSP segment address
psize dw ? ;size of program in paragraphs
xwait dw 2 dup (?) ;XLI wait address
xbye dw 2 dup (?) ;XLI bye address
; ___ __ __
; + -| |- _|_ | -- | __| |__ | | (extra)
map_tab db 0c5h,0b4h,0c3h,0c1h,0c2h,0c4h,0b3h,0d9h,0c0h,0bfh,0dah,0dah
map_tabx equ $
trns_tab db 0dah,0c2h,0c3h,0c5h,0c3h,0c2h,0c2h,0c5h,0c3h,0c5h,0c5h
db 0c2h,0bfh,0c5h,0b4h,0b4h,0c2h,0c2h,0c5h,0c5h,0b4h,0c5h
db 0c3h,0c5h,0c0h,0c1h,0c3h,0c1h,0c5h,0c1h,0c3h,0c5h,0c5h
db 0c5h,0b4h,0c1h,0d9h,0b4h,0c1h,0c5h,0c1h,0c5h,0b4h,0c5h
db 0c3h,0b4h,0c3h,0b4h,0b3h,0c5h,0c5h,0c5h,0c3h,0b4h,0c5h
db 0c2h,0c2h,0c1h,0c1h,0c5h,0c4h,0c2h,0c1h,0c5h,0c5h,0c5h
m14_attr equ $
;33-60 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; <
db 1,0,2,2,1,4,2,0,0,3,3,7,3,5,6,2,6,6,5,3,5,2,1,2,2,1,7,3
;61-88 = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X
db 2,6,1,2,2,0,3,0,0,0,3,1,0,4,0,0,1,1,3,0,3,0,2,0,1,3,1,1
;89-116 Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t
db 0,1,0,0,0,3,7,1,5,0,3,4,3,3,3,0,6,6,0,0,2,2,3,2,3,2,3,2
;117-126 u v w x y z { | } ~
db 2,3,3,2,2,2,3,1,0,1
;127-191
db 64 dup (0)
;192-197
db 5,2,0,0,0,4
;198-218
db 20 dup (0)
;219-220
db 2,5
m16_attr equ $
;33-60 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; <
db 3,1,4,4,4,7,4,2,2,6,6,11,6,9,9,4,10,10,9,6,9,4,2,4,4,3,10,6
;61-88 = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X
db 5,10,3,4,5,2,5,2,2,2,5,2,2,8,2,2,2,2,5,2,5,2,4,2,2,5,2,2
;89-116 Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t
db 2,2,2,2,2,3,12,2,9,2,6,7,6,6,6,2,10,11,2,2,5,5,6,5,6,5,6,4
;117-126 u v w x y z { | } ~
db 5,5,5,5,5,5,6,2,2,3
db 64 dup (0)
db 7,2,0,0,0,7
db 20 dup (0)
db 2,7
public m18_attr
m18_attr equ $
;33-60 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; <
db 2,1,4,4,8,8,4,2,2,6,6,10,9,10,05,4,10,10,10,6,10,4,2,4,4,10,10,6
;61-88 = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X
db 9,06,2,4,4,2,6,2,2,2,6,2,2,8,2,2,2,2,6,2,6,2,4,2,2,6,2,2
;89-116 Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t
db 2,2,2,3,2,3,13,2,10,2,6,8,6,6,6,2,10,12,2,2,5,5,6,5,6,5,6,4
;117-126 u v w x y z { | } ~
db 5,6,6,5,5,5,6,2,2,2
db 64 dup (0)
db 10,4,0,0,0,8
db 20 dup (0)
db 8,8
;
; The following jump table is used wstring to handle control characters
; written to the screen.
;
wn_handle dw wwin_default ;00 - Null character
dw wwin_default ;01 -
dw wwin_default ;02 -
dw wwin_default ;03 -
dw wwin_default ;04 -
dw wwin_default ;05 -
dw wwin_default ;06 -
dw wwin_bell ;07 - Bell
dw wwin_backspace ;08 - Backspace
dw wwin_tab ;09 - Tab
dw wwin_linefeed ;0A - Linefeed
dw wwin_default ;0B -
dw wwin_default ;0C -
dw wwin_creturn ;0C - Carriage Return
;
; The following jump table is used by wstring to handle control characters
; written to disk.
;
ds_handle dw wfil_default ;00 - Null character
dw wfil_default ;01 -
dw wfil_default ;02 -
dw wfil_default ;03 -
dw wfil_default ;04 -
dw wfil_default ;05 -
dw wfil_default ;06 -
dw wfil_default ;07 -
dw wfil_backspace ;08 - Backspace
dw wfil_tab ;09 - Tab
dw wfil_newline ;0A - Linefeed
dw wfil_default ;0B -
dw wfil_default ;0C -
dw wfil_newline ;0D - Carriage Return
last_char db 0dbh
c_col dw 0
c_row dw 0
c_len dw 0
c_nrows dw 0
sav_di dw 0
datasize = $-datastart
DATA ends
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
PROG segment byte public 'PROG'
assume CS:PGROUP,DS:DGROUP
progstart = $
;-----------------------------------------------------------------------------
; name HANDLER -- Interface Handler to IO routines
;
; AX will contain error indicator (-1) if error encountered
;
hand_args struc
dw ? ; callers bp
dd ? ; return address (far)
opcode dw ? ; IO operation to perform
hand_args ends
public handler
handler proc far
mov BX,DS ; temp save caller's DS
mov AX,data
mov DS,AX ; establish local data segment
mov callers_ds,bx ; save callers data seg
mov callers_es,es ; and extra seg
mov ES,AX
; Load sub opcode
push bp
mov bp,sp
mov BX,[BP].opcode ; load operation code
pop bp
add BX,BX ; adjust for index into jump table
cmp BX,table_len ; bad op_code?
jae bad_op
; Jump desired IO handler
call OP_CODE[BX]
jmp short hand_ret
bad_op: mov AX,-1
; Return to caller
hand_ret:
push callers_ds
pop ds ; restore caller's data seg
push callers_es
pop es ; restore caller's data seg
ret ; return to caller
handler endp
;************************************************************************
;* Generate a Bell Character *
;* *
;* Purpose: To generate a "bell character" (i.e., make a noise) to *
;* simulate the effect of outputting a bell character *
;* (control-G) in the output stream. *
;* *
;* Calling Sequence: zbell(); *
;* *
;* Input Parameters: None. *
;* *
;* Output Parameters: None. *
;* *
;************************************************************************
public bell
bell proc near
cmp PC_MAKE,TIPC ; If not tipc
jne zbmbell ; then jump
zbwait: mov AH,1 ; Get speaker status
int 48h
jnz zbwait ; wait for bell to turn off
mov AH,2 ; Set speaker frequency
mov CX,1563 ; Value for 1.25MHz/800Hz (system beep)
int 48h
mov AX,000Ah ; Turn speaker on for AL*25-ms. 0Ah = .25-sec
int 48h
xor ax,ax
ret ; return to caller
;
zbmbell: mov BX,080h ; ****Copied from IBM-PC/XT BIOS listing****
in AL,61h
push AX ; Save
beep_cycle: and AL,0FCh ; Turn off timer gate and speaker data
out 61h,AL ; output to control
mov CX,48h ; Half cycle time for TONE
here: loop here ; speaker off
or AL,2 ; Turn speaker on
out 61h,AL
mov CX,48h
here2: loop here2
dec BX ; Decrease cycle count
jnz beep_cycle
pop AX
out 61h,AL
xor ax,ax
ret
bell endp
;************************************************************************
;* Clear a Window *
;************************************************************************
cl_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
cl_op dw ? ; clear window op code
cl_row dw ? ; upper left hand corner row number
cl_col dw ? ; upper left hand corner column number
cl_nrows dw ? ; number of rows
cl_len dw ? ; line length (number of characters)
cl_attrib dw ? ; character attributes
cl_args ends
public clear
clear proc near
push BP ; save caller's BP
mov BP,SP
; Put cursor at beginning of next row
c_loop: mov DL,byte ptr [BP].cl_row ; load current row number
mov DH,byte ptr [BP].cl_col ; load starting column number
xor BH,BH ; page number (0 if in graphics mode)
mov AH,02H ; load "put cursor" code
call crt_dsr ; position the cursor
; Write line of blanks at current cursor position
mov AX,0920h ; load write char/attr code + blank (= 20h)
xor BH,BH ; (for IBM-PC BH=display page #)
mov BL,byte ptr [BP].cl_attrib ; load attribute flag
cmp vid_mode,14 ; IBM EGA modes?
jl c_01
cmp BL,87h ; attribute is rv white?
jne c_22
mov AX,09dbh ; use the block character not the blank
and BL,7fh ; strip off the xor bit
c_01: mov CX,[BP].cl_len ; load number of times to write the blank
call crt_dsr ; perform the write
; Increment row number, decrement row count, test, loop
inc [BP].cl_row ; increment row number
dec [BP].cl_nrows ; decrement row count
jg c_loop ; if more rows, loop (jump)
; Return to caller
c_end: pop BP ; restore caller's BP
xor ax,ax ; return status
ret ; return
; clear out the line by writing directly to the graphics planes
c_22:
mov AX,[BP].cl_nrows
mov c_nrows,ax
mov AX,[BP].cl_row ; set AX to the row
mov c_row,AX
mov AX,[BP].cl_col ; add in the starting column
mov c_col,AX
mov AX,[BP].cl_len ; number of columns to blank
mov c_len,AX
call z_ega ; restore counter
jmp c_end ; return
clear endp
;************************************************************************
;* Draw Border *
;************************************************************************
b_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
b_opcode dw ? ; border opcode
b_line dw ? ; upper left corner line number
b_col dw ? ; upper left corner column number
b_nlines dw ? ; number of lines
b_ncols dw ? ; number of columns
b_battr dw ? ; border attributes
b_label dw ? ; pointer to label text
b_args ends
public border
border proc near
;;; int 3
push BP ; save caller's BP
mov BP,SP
; output corners
mov BL,byte ptr [BP].b_battr ; load attribute bits
mov DH,byte ptr [BP].b_col ; load left column number
mov DL,byte ptr [BP].b_line ; load left line number
dec DL
dec DH
mov AL,0DAh ; load upper left corner character
call zcorner
inc DH
add DH,byte ptr [BP].b_ncols
mov AL,0BFh ; load upper right corner character
call zcorner
inc DL
add DL,byte ptr [BP].b_nlines
mov AL,0D9h ; load lower right corner character
call zcorner
dec DH
sub DH,byte ptr [BP].b_ncols
mov AL,0C0h ; load lower left corner character
call zcorner
; output sides
mov DH,byte ptr [BP].b_col ; reload upper left column number
mov DL,byte ptr [BP].b_line ; and line number
dec DH ; decrement column number
mov CX,[BP].b_nlines
call zside ; draw the left hand border
mov DH,byte ptr [BP].b_col ; reload upper left column number
mov DL,byte ptr [BP].b_line ; and line number
add DH,byte ptr [BP].b_ncols ; add in line length
mov CX,[BP].b_nlines
call zside ; draw the right hand border
; Output the top of the border
mov DL,byte ptr [BP].b_line ; load upper left row number
dec DL
jl z_no_top ; if row negative, skip write
mov DH,byte ptr [BP].b_col ; load upper left column number
mov CX,[BP].b_ncols
call ztop
; Put the label in the top left corner of the border, if it'll fit
mov BX,[BP].b_label ; get segment of label
cmp BX,0
je z_no_top ; jump, if NULL pointer
mov ES,BX
mov BX,0 ; ES:BX => label
mov DX,[BP].b_ncols ; load window width
xor CX,CX ; zero the character counter
b_loop: cmp byte ptr ES:[BX],0 ; end of string?
je b_eos ; if end of string, jump
inc CX ; increment the character count
inc BX ; increment the character string pointer
cmp CX,DX ; compare to window width
jl b_loop ; if label still shorter than window, loop
b_eos: jcxz z_no_top ; if no label, jump
push CX ; save label length
; Write the label
mov DL,byte ptr [BP].b_line ; load upper left row number
mov DH,byte ptr [BP].b_col ; load upper left column number
dec DL ; decrement row number
xor BH,BH ; IBMism (page 0 for text-mode)
mov AH,02h ; load "put cursor" code
call CRT_DSR ; put cursor in upper left corner of border
pop CX ; restore label's character count
cmp PC_MAKE,TIPC
jne ibm_cblk
mov AH,011h ; load "write block of characters" code
mov DX,ES ; load segment address
mov BX,0 ; load label offset
int TI_CRT ; write the label
jmp short z_no_top
;
ibm_cblk: mov AL,byte ptr [BP].b_col
add AL,CL
cmp AL,MAX_COLS
jle b_sml ; jump if label length is OK
sub AL,MAX_COLS
sub CL,AL ; force label to remain within 80-col screen
b_sml: mov DI,0 ; load label offset
lbl_loop: mov AH,0Eh ; Write ASCII Teletype
mov AL,byte ptr ES:[DI]
mov BL,byte ptr [BP].b_battr ; load attribute bits just in case
xor BH,BH ; page # for alpha mode
push CX
push DI
int IBM_CRT
pop DI
pop CX
inc DI
loop lbl_loop ; DECrement CX and jump if != 0
; Output the bottom of the border
z_no_top:
mov dx,ds
mov es,dx
mov BL,byte ptr [BP].b_battr ; load attribute bits
mov DL,byte ptr [BP].b_line
add DL,byte ptr [BP].b_nlines
mov DH,byte ptr [BP].b_col ; load upper left column number
mov CX,[BP].b_ncols
call ztop
; return to caller
pop BP ; restore caller's BP
xor ax,ax
ret ; return
border endp
;************************************************************************
;* Local Support: Draw a single character at cursor position *
;* *
;* Input Registers: AL - the character to be output *
;* BL - the character attributes for the write *
;* DH - column *
;* DL - row *
;* *
;* Registers Modified: AX,CX,SI,DI *
;************************************************************************
zcorner proc near ; draw a single corner character
cmp DH,MAX_COLS
jae zcornret
cmp DL,MAX_ROWS
jae zcornret
push DX ; save cursor coordinates
push AX ; save character to be output
xor BH,BH ; page number (=0 for graphics mode also)
mov AH,02h ; load "put cursor" code
call CRT_DSR ; position the cursor
; read the character in this screen position
; ** This is tricky 'cause DH/DL are correct but
; ** will be swapped back (to incorrect) by CRT_DSR proc
; ** if using an IBM!!!
cmp PC_MAKE,TIPC
je no_swap
xchg DH,DL
xor BH,BH ; IBM display page
no_swap: mov AH,08h
call CRT_DSR
; see if it's one of the borderline characters
call map_char
mov SI,AX
pop AX ; recover character to be output
cmp SI,0
jl zcornput
; map corner to border character
call map_char
mov DL,map_tabx-map_tab-1
mul DL
add SI,AX
mov AL,trns_tab+[SI]
; output the corner character
zcornput: mov AH,09h ; load "write character/attribute" code
mov CX,1 ; number of characters = 1
xor BH,BH ; Display page for IBM text mode (=0)
call CRT_DSR ; write it to the screen at cursor position
pop DX ; restore cursor coordinates
zcornret: ret ; return
zcorner endp
;************************************************************************
;* Local Support: Draw a border sides *
;* *
;* Input Registers: DH - column *
;* DL - row *
;* CX - number of rows *
;* *
;* Registers Modified: AX,CX,DL *
;************************************************************************
zside proc near
cmp DH,MAX_COLS ; is column within the CRT's boundaries?
jae zsideret ; if not, jump
zside_lp: mov AL,0B3h ; load "|" border character
push CX ; save line count
push DX ; save next cursor position
call zcorner ; output the border character
pop DX ; restore current cursor position
pop CX ; restore line counter
inc DL ; increment the row number
loop zside_lp ; loop until side is drawn
zsideret: ret
zside endp
;************************************************************************
;* Local Support: Draw a border - Top or Bottom *
;* *
;* Input Registers: DH - column *
;* DL - row *
;* CX - number of columns *
;* *
;* Registers Modified: AX,CX *
;************************************************************************
ztop proc near
cmp DL,MAX_ROWS ; is row within the CRT's boundaries?
jae ztopret ; if not, jump
ztop_lp: mov AL,0C4h ; load "-" border character
push CX ; save line count
push DX ; save next cursor position
call zcorner ; output the border character
pop DX ; restore current cursor position
pop CX ; restore line counter
inc DH ; increment the column number
loop ztop_lp ; loop until top/bottom is drawn
ztopret: ret
ztop endp
;************************************************************************
;* Local Support: return character mapping *
;* *
;* Input Registers: AL = character *
;* *
;* Registers Modified: CX,DI *
;************************************************************************
map_char proc near
mov CX,map_tabx-map_tab
mov DI,offset map_tab
repne scasb
mov AX,CX
dec AX
ret
map_char endp
;************************************************************************
;* Save Screen Contents *
;* *
;* Purpose: To save a rectangular region of the CRT in a string data *
;* object. *
;* *
;* Calling Sequence: save_scr(str_reg, ul_row, ul_col, n_rows, ncols) *
;* where str_reg - pointer to string data object *
;* which is to receive the screen *
;* contents *
;* ul_row - row number of the upper left *
;* corner of the region to be *
;* saved *
;* ul_col - column number of the upper left *
;* corner of the region to be *
;* saved *
;* n_rows - number of rows in the region to *
;* be saved *
;* n_cols - number of columns in the region *
;* to be saved *
;************************************************************************
sv_args struc
dw ? ; caller's BP
dw ? ; caller's ES
dw ? ; return address
dd ? ; caller's return address
sv_op dw ? ; save screen opcode
sv_str dw ? ; address of register pointing to string
sv_ulrow dw ? ; upper left hand corner's row number
sv_ulcol dw ? ; upper left hand corner's column number
sv_nrow dw ? ; number of rows
sv_ncol dw ? ; number of columns
sv_args ends
public save_scr
save_scr proc near
;;; int 3
push ES
push BP ; save the caller's BP register
mov BP,SP ; and establish local addressability
; create a pointer to the string object
;;; mov BX,[BP].sv_str ; load address of register
;;; mov DI,[BX].C_disp ; load the string
;;; mov BX,[BX].C_page ; pointer
;;; %LoadPage ES,BX ; load string page's paragraph address
;;; mov ES,pagetabl+[BX] ; load string page's paragraph address
;;; add DI,BLK_OVHD ; advance pointer past string header
mov ES,[BP].sv_str
xor DI,DI ;ES:DI => string
; store number of rows and columns into the first two bytes of the string
mov AL,byte ptr [BP].sv_nrow
stosb
mov AL,byte ptr [BP].sv_ncol
stosb
; adjust number of lines/columns for test conditions
mov AX,[BP].sv_ulrow
add [BP].sv_nrow,AX
mov AX,[BP].sv_ulcol
add [BP].sv_ncol,AX
; loop until all rows processed
mov DL,byte ptr [BP].sv_ulrow
rw_loop: mov DH,byte ptr [BP].sv_ulcol
; position cursor
cl_loop: push DX ; save current position
mov AH,02h ; load "put cursor" function id
xor BH,BH ; IBMism (page number for cursor)
call crt_dsr ; position the cursor
; read character/attributes at current screen position
mov AH,08h ; load "read char/attribute" function id
xor BH,BH ; IBMism (display page #)
call crt_dsr ; read said
;*******
cmp vid_mode,14
jl sav_01 ; not graphics modes
cmp AL,0 ; don't bother with attributes if nul
je sav_01
; cmp AL,07fh ; is it above the first 128 characters ?
; jno sav_00 ; no
cmp AL,0dah
jbe sav_00
; test AL,010h ; look for D0-DF
; je sav_00
xor AL,AL ; set to nul
jmp sav_01
sav_00: call graph_attr ; mode 14 and 16 attribute function
;******
sav_01: stosw ; store char/attr into output string
; increment column number, test, branch
pop DX
inc DH
cmp DH,byte ptr [BP].sv_ncol
jl cl_loop
; increment row number, test, branch
inc DL
cmp DL,byte ptr [BP].sv_nrow
jl rw_loop
; return to caller
pop BP
pop ES
xor ax,ax
ret ; return to caller
save_scr endp
;************************************************************************
;* Restore Screen Contents *
;* *
;* Purpose: To restore a rectangular region of the CRT from a string *
;* data object. *
;* *
;* Calling Sequence: rest_scr(str_reg, ul_row, ul_col) *
;* where str_reg - pointer to string data object *
;* which contains the screen *
;* contents *
;* ul_row - row number of the upper left *
;* corner of the region to be *
;* restored *
;* ul_col - column number of the upper left *
;* corner of the region to be *
;* restored *
;************************************************************************
rs_args struc
rs_nrow dw ? ; number of rows in saved data
rs_ncol dw ? ; number of columns in saved data
rs_BP dw ? ; caller's BP
dw ? ; caller's ES
dw ? ; return address
dd ? ; callers return address
rs_op dw ? ; restore screen opcode
rs_str dw ? ; segment address of string
rs_ulrow dw ? ; upper left hand corner's row number
rs_ulcol dw ? ; upper left hand corner's column number
rs_mrow dw ? ; number of rows in new window
rs_mcol dw ? ; number of columns in new window
rs_args ends
public rest_scr
rest_scr proc near
int 3
push ES
push BP ; save the caller's BP register
sub SP,offset rs_BP
mov BP,SP ; and establish local addressability
; address the string
mov ES,[BP].rs_str
xor SI,SI ; ES:SI => string
; get number of rows and columns from screen object
xor AH,AH
lods byte ptr ES:[SI]
add AX,[BP].rs_ulrow
mov [BP].rs_nrow,AX
xor AH,AH
lods byte ptr ES:[SI]
add AX,[BP].rs_ulcol
mov [BP].rs_ncol,AX
; adjust number of lines/columns for test conditions
mov AX,[BP].rs_ulrow
add [BP].rs_mrow,AX
mov AX,[BP].rs_ulcol
add [BP].rs_mcol,AX
; loop until all rows processed
mov DL,byte ptr [BP].rs_ulrow
xw_loop: mov DH,byte ptr [BP].rs_ulcol
; position cursor
xl_loop: cmp DH,byte ptr [BP].rs_mcol ; column too long for new window?
jge x_long ; if too long, jump
push DX ; save current position
mov AH,02h ; load "put cursor" function id
xor BH,BH ; IBMism (page number/0 in graphic mode)
call crt_dsr ; position the cursor
; read character/attributes at current screen position
lods word ptr ES:[SI] ; fetch the character and attribute
;;;;;;;; cmp AL,20h
;;;;;;;; je x_sp ; if a space skip
mov BL,AH ; and copy attribute to BL
mov AH,09h ; load "write char/attribute" function id
xor BH,BH ; IBMism (page number)
mov CX,1 ; character count = 1
call crt_dsr ; read said
; increment column number, test, branch
x_sp: pop DX ; recover the row/column coordinates
x_more: inc DH ; increment the column number
cmp DH,byte ptr [BP].rs_ncol ; more characters in this row?
jl xl_loop ; if so, jump
; increment row number, test, branch
inc DL ; increment the row number
cmp DL,byte ptr [BP].rs_mrow ; check against new window boundary
jge rs_fin ; if all rows filled, jump
cmp DL,byte ptr [BP].rs_nrow ; check against saved data
jl xw_loop ; if more lines, jump
; return to caller
rs_fin: add SP,offset rs_BP ; deallocate local storage
pop BP ; restore the caller's BP register
pop ES ; restore the caller's ES register
xor ax,ax
ret ; return to caller
;
x_long: inc SI ; increment index into saved screen
inc SI ; buffer
jmp short x_more ; continue processing row
rest_scr endp
;************************************************************************
;* Output Character To Window *
;************************************************************************
pch_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
p_op dw ? ; putchar opcode
p_line dw ? ; cursor position - line number
p_col dw ? ; cursor position - column number
p_char dw ? ; character to write
p_attr dw ? ; character's attributes
pch_args ends
public putchar
putchar proc near
push BP ; save caller's BP
mov BP,SP
; position cursor for write
mov DL,byte ptr [BP].p_line ; load line number
mov DH,byte ptr [BP].p_col ; load column number
xor BH,BH ; IBMism
mov AH,02h ; load "put cursor" code
call crt_dsr ; positio the cursor
mov BL,byte ptr [BP].p_attr ; load its attributes
cmp vid_mode,14 ; only attribute for EGA modes is a
jl pchar_1 ; simulated reverse video
mov BH,BL ; save the attribute
and BH,80h ; reverse video?
jz pchar_1 ; zero indicates bit 8 not set
pchar_2: and BL,7fh ; strip off high bit
mov CX,1 ; character count
xor BH,BH ; video page number
mov AL,0dbh ; block character
mov AH,09h
call crt_dsr
or BL,80h ; set xor bit
; write the characters with attributes
pchar_1: mov AL,byte ptr [BP].p_char ; load the character
xor BH,BH ; IBMism
mov CX,1 ; repeat count = 1
mov AH,09h ; load write char/attribute code
call crt_dsr
; return to caller
xor ax,ax
pop BP
ret
putchar endp
;************************************************************************
;* Scroll Window Up one line *
;************************************************************************
su_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
su_op dw ? ; scroll opcode
su_line dw ? ; upper left hand corner line number
su_col dw ? ; upper left hand corner column number
su_nline dw ? ; number of lines
su_ncols dw ? ; number of columns
su_attr dw ? ; text attributes (used for blanking)
su_args ends
public scrollup
scrollup proc near
push BP ; save caller's BP
mov BP,SP
; scroll window's text up one line
mov CL,byte ptr [BP].su_nline ; load number of lines
dec CL ; decrease number of lines by one
jz blank1 ; Jump if scrolling 1-line and just blank it
mov CH,byte ptr [BP].su_ncols ; load number of columns
mov DL,byte ptr [BP].su_line ; load upper left line number
mov DH,byte ptr [BP].su_col ; load upper left column number
mov AX,0601h ; load "scroll text" code with no blanking
cmp DGROUP:PC_MAKE,TIPC
je ti_scrl
cmp vid_mode,4 ; Are we in graphics mode?
jl txt_mod ; If we are then fix blank fill attributes
cmp vid_mode,7 ; so that the bar characters don't show up
je txt_mod
xor BH,BH ; zero attribute for fill blanks
jmp short rite_atr
txt_mod: mov BH,byte ptr [BP].su_attr ; Blanked lines' attribute txt mode
rite_atr: xchg CX,DX ; CX=Upper left corner
xchg CH,CL ; Row,column instead of TI's column,row
xchg DH,DL ; ditto
add DX,CX ; DX=Lower right corner
dec DL ; adjust column count (0 is first column)
int IBM_CRT
jmp short z_quit ; IFF IBM is in graphics mode weird char's
; are used for blanks when scrolling. Do
; as TIPC does and "manual" blank 'em.
;
ti_scrl: mov BX,DX ; copy destination coordinates
inc DL ; compute source by incrementing line number
int TI_CRT ; perform block move
; paint the last line of the window with blank of proper attributes
blank1: mov DH,byte ptr [BP].su_col ; load starting column number
mov DL,byte ptr [BP].su_line ; load upper line number
add DL,byte ptr [BP].su_nline ; add the number of lines and
dec DL ; subtract offf one
mov AH,02h ; load "put cursor" code
xor BH,BH ; IBMism
call crt_dsr ; position cursor for write
mov AX,0920h ; load "write char/attr" code, write a blank
mov BL,byte ptr [BP].su_attr ; load attribute bit setting
cmp vid_mode,14 ; ega mode?
jl z_scr01
mov BH,BL
and BH,80h
cmp BH,80h ; reverse video?
jne z_scr01
mov AX,09dbh ; change for block character
and BL,7fh ; strip off xor bit
z_scr01: xor BH,BH ; IBMism
mov CX,[BP].su_ncols ; load line length
call crt_dsr ; write a line of blanks
; return to caller
z_quit: pop BP
xor ax,ax
ret
scrollup endp
;************************************************************************
;* Scroll Window Down one line *
;************************************************************************
sd_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
sd_op dw ? ; op code
sd_line dw ? ; upper left hand corner line number
sd_col dw ? ; upper left hand corner column number
sd_nline dw ? ; number of lines
sd_ncols dw ? ; number of columns
sd_attr dw ? ; text attributes (used for blanking)
sd_args ends
scrolldn proc near
push BP ; save caller's BP
mov BP,SP
; scroll window's text down one line
mov CL,byte ptr [BP].sd_nline ; load number of lines
dec CL ; decrease number of lines by one
jz blank ; Jump if scrolling 1-line and just blank it
mov CH,byte ptr [BP].sd_ncols ; load number of columns
mov DL,byte ptr [BP].sd_line ; load upper left line number
mov DH,byte ptr [BP].sd_col ; load upper left column number
mov AX,0701h ; load "scroll text" code with no blanking
cmp DGROUP:PC_MAKE,TIPC
je ti_down
push AX ; else
mov AH,0Fh
int IBM_CRT ; Are we in graphics mode?
cmp AL,4 ; If we are then fix blank fill attributes
jl text_m ; so that the bar characters don't show up
cmp AL,7
je text_m
xor BH,BH ; zero attribute for fill blanks
jmp short wrte_atr
text_m: mov BH,byte ptr [BP].sd_attr ; Blanked lines' attribute txt mode
wrte_atr: pop AX
xchg CX,DX ; CX=Upper left corner
xchg CH,CL ; Row,column instead of TI's column,row
xchg DH,DL ; ditto
add DX,CX ; DX=Lower right corner
dec DL ; adjust column count (0 is first column)
int IBM_CRT
jmp short quit ; IFF IBM is in graphics mode weird char's
; are used for blanks when scrolling. Do
; as TIPC does and "manual" blank 'em.
;
ti_down: mov BX,DX ; copy destination coordinates
inc BL ; compute dest by incrementing line number
int TI_CRT ; perform the block move
; paint the first line of the window with blank of proper attributes
blank: mov DH,byte ptr [BP].sd_col ; load starting column number
mov DL,byte ptr [BP].sd_line ; load upper line number
mov AH,02h ; load the "put cursor" code
xor BH,BH ; IBMism
call crt_dsr ; position cursor for write
mov AX,0920h ; load "write char/attr" code, write a blank
mov BL,byte ptr [BP].sd_attr ; load attribute bit setting
xor BH,BH ; IBMism
mov CX,[BP].sd_ncols ; load line length
call crt_dsr ; write a line of blanks
; return to caller
quit: pop BP ; restore caller's BP
xor ax,ax
ret
scrolldn endp
;****************************************************************************
;* *
;* Change Video Mode *
;* *
;* Purpose: to note changes to video mode. *
;* *
;****************************************************************************
chgvmode struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
chg_op dw ? ; op code
chg_chgt dw ? ; new character height
chg_mode dw ? ; new video mode
chg_rows dw ? ; new max rows for screen
chgvmode ends
public chgmode
chgmode proc near
int 3
push bp
mov bp,sp
mov ax,[bp].chg_mode
mov VID_MODE,ax
mov ax,[bp].chg_chgt
mov CHAR_HGT,ax
mov ax,[bp].chg_rows
mov MAX_ROWS,al
pop bp
xor ax,ax
ret
chgmode endp
;****************************************************************************
;* *
;* WRITE BLOCK OF CHARACTERS *
;* *
;* Purpose: Write a character string to the display *
;* *
;****************************************************************************
wblk_args struc
dw ? ;caller's BP
dw ? ;return address
dd ? ;caller's return address
blk_op dw ? ;op code
blk_len dw ? ;length of block to write
blk_buf db 100 dup (?) ;buffer to write
blk_txt dw ? ;text attributes
blk_cur dw ? ;cursor position
wblk_args ends
public wblock
wblock proc near
int 3
push bp
mov bp,sp
mov ah,02h ;load "put cursor" code
xor bh,bh ;IBMism - page 0 for text mode
mov dx,[bp].blk_cur ;dx = cursor coordinates
call crt_dsr ;position the cursor
mov cx,[bp].blk_len ;cx = number of characters
cmp PC_MAKE,TIPC ;on what flavor PC are we running?
jne blk_ibm ;if an IBM, jump
; Write line to TIPC's screen
mov al,byte ptr [bp].blk_txt ;load text attributes
mov ah,010h ;load "write block w/ attr" code
mov dx,ss ;load segment address
mov bx,bp ;load buffer offset in segment
add bx,blk_buf
int TI_CRT
jmp blk_end
; Write line to IBM's screen
blk_ibm: mov di,bp
add di,blk_buf ;load buffer offset
mov dx,[bp].blk_cur ;reverse row/column coordinates
xchg dl,dh
mov [bp].blk_cur,dx
push cx ; save
jmp short blk_imidl ;jump into middle of loop
blk_iloop:
push cx ;save the character counter
mov dx,[bp].blk_cur ;load the previous cursor coordinates,
inc dl ;increment the column number
mov [bp].blk_cur,dx ;and save new coordinates
xor bh,bh ;page number (0 for graphics mode) IBMism
mov ah,02h ;load "put cursor" code
push di
int IBM_CRT ;position the cursor
pop di
blk_imidl:
mov ah,09h ;load "write char w/ attributes" code
mov al,byte ptr ss:[di] ;load character from buffer
mov BL,byte ptr [bp].blk_txt ;load attribute bits
xor bh,bh ;page # for alpha mode
mov cx,1 ;load repeat count = 1
pop dx ;restore character count
; test to see if we buy anything by using a repeat count
blk_imore:
cmp dx,1 ;more characters to display?
jle blk_ibotm ;if no more characters, jump
cmp al,byte ptr ss:[di]+1 ;is next character the same as previous?
jne blk_ibotm ;if not same character, jump
inc cx ;increment the repeat count
inc di ;increment the output buffer index
inc byte ptr [bp].blk_cur ;increment the cursor position
dec dx ;decrement the character count
jmp blk_imore ;try for another
blk_ibotm:
; output the character(s)
push dx ;save the adjusted character count
push di ;save the output buffer index
int IBM_CRT ;output the char(s)
pop di ;restore the output buffer index
pop cx ;restore character counter
inc di ;increment buffer pointer
loop blk_iloop ;continue 'til all characters output
blk_end:
pop bp ;restore stack
ret ; and return
wblock endp
;****************************************************************************
;* *
;* WRITE CHARACTER STRING *
;* *
;* Purpose: Write a character string to the given port object *
;* *
;****************************************************************************
wstr_args struc
dw ? ; caller's BP
dw ? ; return address
dd ? ; caller's return address
wrt_op dw ? ; op code
;;; wrt_newl dw ? ; newline before writing
wrt_wrap dw ? ; check wrap before writing string
wrt_offs dw ? ; string offset
wrt_seg dw ? ; string segment
wrt_len dw ? ; # characters
wrt_port dw ? ; port object
wstr_args ends
public wstring
wstring proc near
int 3
push bp
mov bp,sp
cmp [bp].wrt_len,0 ;anything to write?
jg wst_10 ; yes, continue
jmp wst_fin
wst_10:
cmp [bp+wrt_wrap],0 ;check wrap before writing?
je wst_15 ; no, continue
xor ax,ax ;ax = wrap indicator (0 = no)
mov bx,[bp+wrt_port].pt_ncols ;bx = line length
cmp bx,0 ;maintaining line length?
je wst_15 ; no, jump
mov cx,[bp+wrt_port].pt_ccol ;cx = current column
cmp cx,1 ;in first column already?
jle wst_15 ; yes, jump
sub bx,cx ;determine space remaining
cmp bx,[bp+wrt_len] ;room left on current line?
jge wst_15 ; yes, jump
inc ax ;set wrap indicator
wst_15:
mov [bp+wrt_wrap],ax ;update wrap indicator
mov bx,[bp+wrt_port].pt_pflgs ;get window flags
test bx,OPEN ;is port open for writing?
jz wst_esc ; no, get outa here
test bx,STRIO ;is port a string?
jnz wst_esc ; yes, return
test bx,WINDOW ;is port a window?
jnz wst_win ; yes, go to window code
jmp wst_fil ; no, go to file code
wst_esc: jmp wst_fin
;*****************************************************************************
; We have a valid window port. Write the string to the display.
;*****************************************************************************
wst_win:
les di,dword ptr [bp+wrt_offs] ;es:di => string buffer
mov bx,[bp+wrt_port].pt_cline ;bx = current line
mov ax,[bp+wrt_port].pt_ccol ;ax = current column
mov dx,[bp+wrt_port].pt_ullin ;dx = upper left line #
cmp [bp+wrt_wrap],0 ;wrap before writing string?
je wwin_start ; no, jump
xor ax,ax ;clear current column
inc bx ;bump current line
cmp bx,[bp+wrt_port].pt_nline ;exceeded number of lines?
jl wwst_w10 ;no, skip scroll
int 3
call scrollit ;scroll the display
wwst_w10:
push ax
push di
push es:[di] ;next character
call isspace ;determine if whitespace
pop di
or ax,ax ;is it?
pop ax
jz wwin_start ; no, jump
inc di
dec [bp+wrt_len] ;decrement string length
jnz wwin_start ;if non-zero, go
mov [bp+wrt_port].pt_cline,bx ;save current cursor line number
mov [bp+wrt_port].pt_ccol,ax ;save current cursor column number
jmp wst_fin ; else return
wwin_start:
mov cx,[bp+wrt_len]
;
; loop through the chars, writing them to the display
;
wwin_loop:
push cx
push di
mov cl,es:[di]
cmp cl,RETURN ;if char = carriage return
;;;;;;;; je wwin_creturn ; then jump
ja wwin_default ;if not control char, jump
xor ch,ch
mov si,cx
shl si,1 ;get index into jump table
jmp [wn_handle+si] ;go to handler
; default character handler
;
wwin_default:
cmp ax,[bp+wrt_port].pt_ncols ;are we in the last column?
jl wwin_linechk ; no, jump
test [bp+wrt_port].pt_wflgs,W_WRAP ;wrap option on?
jnz wwin_scrl ; yes, jump
inc ax ;clip - bump column
jmp wwin_100 ; continue
wwin_linechk:
cmp bx,[bp+wrt_port].pt_nline ;out of lines?
jl wwin_wchar ;no, return
wwin_scrl:
inc bx ;bump current line
xor ax,ax ;clear column
cmp bx,[bp+wrt_port].pt_nline ;exceeded number of lines?
jl wwin_wchar ; no, jump
call scrollit
wwin_wchar:
push ax ;save current column
push bx ;save current line
cmp vid_mode,3
jne wwin_gen
cmp pc_make,1
je wwin_gen
xchg ax,bx
add ax,[bp+wrt_port].pt_ullin
mov ah,80
mul ah
add ax,bx
add ax,[bp+wrt_port].pt_ulcol
shl ax,1
mov si,ax
mov ch,byte ptr [bp+wrt_port].pt_text
push ds
push 0B800h
pop ds
mov [si],cx
pop ds
jmp wwin_nxt
wwin_go:
jmp wwin_loop
wwin_gen:
push [bp+wrt_port].pt_text ;push text character attribute
push es:[di] ;push the character
add ax,[bp+wrt_port].pt_ulcol
push ax ;column number to console
add bx,[bp+wrt_port].pt_ullin
push bx ;line number to console
sub sp,6
call putchar ;display character
add sp,14 ;dump args off stack
wwin_nxt:
pop bx ;restore current line
pop ax ;restore current column
inc ax ;increment current column
wwin_100: mov [bp+wrt_port].pt_cline,bx ;save current cursor line number
wwin_120: mov [bp+wrt_port].pt_ccol,ax ;save current cursor column number
pop di
inc di
pop cx
loop wwin_go
;;;; loop wwin_loop ;if more chars, loop
jmp wst_fin ; else go home
;
; Handlers for special characters (RETURN,LINEFEED,TAB,BACKSPACE)
;
; Carriage return character handler
wwin_creturn:
mov cl,LINEFEED ;fall thru to linefeed handler
; Line Feed character handler
wwin_linefeed:
xor ax,ax ;clear column
inc bx ;bump line number
cmp bx,[bp+wrt_port].pt_nline ;exceeded number of lines?
jl wwin_100 ; no, jump
call scrollit ; yes, scroll
jmp wwin_100
; Backspace character handler
wwin_backspace:
dec AX ;decrement current column
cmp AX,0 ;if column now positive
jge wwin_120 ; then return
xor AX,AX ;cur_col = 0
jmp wwin_120 ;return
; Bell character handler
wwin_bell:
push ax
push bx
call bell ;sound the alarm
pop bx
pop ax
jmp wwin_120 ;and return
; Tab character handler
wwin_tab:
mov cx,ax ;cx = current column
mov dx,8 ;dl = 8
div dl ;ah = (cur_col % 8)
sub dl,ah
add cx,dx
mov ax,cx ;update current column
jmp wwin_120 ;and return
;*****************************************************************************
; We have a valid file port. Write the string to the disk.
;*****************************************************************************
wst_fil:
int 3
xor ax,ax ;clear ax for char later
les di,dword ptr [bp+wrt_offs] ;es:di => string buffer
test [bp+wrt_port].pt_pflgs,BINARY ;binary file?
jnz wfil_start ; yes, skip newline
cmp [bp+wrt_wrap],0 ;wrap before writing string?
je wfil_start ; no, go write chars to disk
mov al,RETURN ; yes, write CR/LF to file
call write_char
xor ax,ax ;set current column to 0
call upd_port ;update port object
mov al,LINEFEED
call write_char
xor ax,ax ;set current column to 0
call upd_port ;update port object
push di
push es:[di]
call isspace ;determine next char whitespace
pop di
or ax,ax ;is it?
jz wfil_start ; no, jump
inc di ;
dec [bp+wrt_len] ;decrement string length
jnz wfil_start ;if non-zero, continue
jmp wst_fin ; else return
wfil_start:
mov cx,[bp+wrt_len]
;
; loop through the chars, writing them to the display
;
wfil_loop:
push cx ;save length
push di ;save index to string
mov cl,es:[di] ;get character just written
cmp cl,RETURN ;test for control char
ja wfil_default ; if not, handle as default case
je wfil_newline ; if return, go handle
xor ch,ch ;clear high byte
mov si,cx ;move char to index reg
shl si,1 ;get index into jump table
jmp [ds_handle+si] ;go to handler
wfil_default:
mov cx,1 ;cx = length
mov bx,[bp+wrt_port].pt_handl ;bx = handle
mov dx,di ;dx = offset
mov ax,es ;ax = segment
call diskout
mov ax,[bp+wrt_port].pt_ccol ;ax = current column
cmp ax,[bp+wrt_port].pt_ncols ;have we exceeded line length
jl wfil_10 ; no, jump
xor ax,ax ;clear current column
jmp wfil_upd ;go update port data
wfil_10: inc ax ;bump current column
wfil_upd: call upd_port
pop di ;restore string index
inc di ;and increment
pop cx ;restore length
loop wfil_loop ;loop if more
wst_fin:
xor ax,ax
pop bp
ret ;return to caller
;
; Handlers for special characters (RETURN,LINEFEED,TAB,BACKSPACE)
;
; Carriage return or linefeed character handler
wfil_newline:
test [bp+wrt_port].pt_pflgs,BINARY ;binary file?
jnz wfil_default ; yes, output char
mov al,RETURN ; no, output cr/lf
call write_char
xor ax,ax ;set current column to 0
call upd_port ;update port object
mov al,LINEFEED
call write_char
xor ax,ax
jmp wfil_upd
; backspace character handler
wfil_backspace:
test [bp+wrt_port].pt_pflgs,BINARY ;binary file?
jnz wfil_10 ;yes, output char
mov al,byte ptr es:[di] ;al = backspace char
call write_char ;write it out
mov ax,[bp+wrt_port].pt_ccol ;ax = current column
dec ax ;decrement it
cmp ax,0
jge wfil_upd
xor ax,ax
jmp wfil_upd
; tab character handler
wfil_tab:
test [bp+wrt_port].pt_pflgs,BINARY ;binary file?
jnz wfil_10 ;yes, jump
mov al,byte ptr es:[di] ;al = tab char
call write_char ;write it out
mov ax,[bp+wrt_port].pt_ccol ;ax = current column
mov cx,ax
mov dx,8
div dl ; ah = (cur_col % 8)
sub dl,ah
add cx,dx
mov ax,cx
jmp wfil_upd
;*****************************************************************************
; Utilty routines for writing characters to display or disk
;*****************************************************************************
;UPD_PORT - update port object
; entry: ax = current column
upd_port proc near
cmp [bp+wrt_port].pt_ncols,0 ;if line length = 0
je upd_05 ; then don't maintain column
mov [bp+wrt_port].pt_ccol,ax ;save current column
upd_05:
mov ax,[bp+wrt_port].pt_bfpos ;get current buffer position
inc ax ;bump the position
cmp ax,256 ;crossed chunk boundary?
jle upd_10 ; no, jump
sub ax,256 ;ax=excess above chunk
inc [bp+wrt_port].pt_chunk ;update chunk number
upd_10: mov [bp+wrt_port].pt_bfpos,ax ;update buffer position
ret
upd_port endp
;WRITE_CHAR - write character to port
; entry: ax = character to write to port
write_char proc near
mov cx,1 ;length
mov bx,[bp+wrt_port].pt_handl ;handle
push ax
mov dx,sp
mov ax,ss
call diskout
pop ax
ret
write_char endp
;DISKOUT - output char(s) to disk
; entry: ax=segment, bx=handle, cx=buffer length, dx=offset
; exit: carry set = error, ax=status
; errors will return to the caller of wstring
diskout proc near
push ds
mov ds,ax
mov ah,WRITEFILE
int DOS ;perform disk write
pop ds
jc diskerr
cmp ax,cx ;everything written?
je diskret ; yes, return
mov ax,DISK_FULL ;note disk full error
jmp derr_ret
diskerr:
int 3
;;;
;;; For some reason, the following doesn't work. Must be a failure by
;;; AI Architects support of Get Extended Error. In the interim, just
;;; use the return value in ax. Returning is easy, just dump local
;;; storage from the stack, pop the callers bp, and return.
;;;
;;; xor bx,bx
;;; mov AH,059h ;GET_EXTENDED_ERROR
;;; int DOS ;Extended error code in AX
derr_ret: mov sp,bp ;dump everything off stack
pop bp ;return to handler, error in ax
diskret:
ret
diskout endp
;ISSPACE - determine if character is whitespace
;
isspace proc near
pop di
pop ax
cmp al,' '
je issp
cmp al,9
jb isntsp
cmp al,13
jbe issp
isntsp: xor ax,ax
issp: jmp di
isspace endp
;Scrollit - local support to scroll window
; entry: ax = column, bx = line
; exit: ax = column, bx = line
scrollit proc near
cmp bx,[bp+wrt_port].pt_nline ;out of lines?
jl scrl_ret ;no, return
push [bp+wrt_port].pt_text
push [bp+wrt_port].pt_ncols
push [bp+wrt_port].pt_nline
push [bp+wrt_port].pt_ulcol
push [bp+wrt_port].pt_ullin
sub sp,6 ;dummy args for scroll
call scrollup ;scroll window up one line
add sp,16 ;dump args off stack
mov bx,[bp+wrt_port].pt_nline ;bx = number of lines
dec bx ;bx = line number
xor ax,ax ;ax = column
scrl_ret:
ret
scrollit endp
wstring endp
;************************************************************************
;* Perform appropriate VIDEO I/O interrupt *
;* Any difference in register definition should be handled by *
;* the caller except where DH,DL contain row,col information. *
;************************************************************************
public crt_dsr
crt_dsr proc near
cmp PC_MAKE,TIPC
jne ibm_dsr
int TI_CRT
ret
ibm_dsr: xchg DH,DL ; Do this now instead of making special checks
int IBM_CRT ; IBM's row,col is diff'rnt from TI's col,row
ret
crt_dsr endp
z_ega proc near
mov AX,0A000h
mov ES,AX ; set ES to the video plane
mov AX,c_row ; set AX to the row
mul char_hgt ; multiply by the character height
mov BX,80 ; multiply by 80 bytes per line
mul BX
add AX,c_col ; add in the starting column
mov sav_di,AX ; save the starting value
xor BX,BX ; use BX as a counter
mov DX,c_len ; number of columns to blank
zc_03: mov CX,DX ; restore counter
mov DI,sav_di ; restore index
mov AH,0fh
xor AX,AX ; clear AX
cld
rep stosb
add sav_di,80 ; next line
inc BX ; increment counter
cmp BX,char_hgt ; done with this row?
jne zc_03
xor BX,BX ; clear counter
dec c_nrows ; decrement row count
jg zc_03 ; if more rows, loop (jump)
ret
z_ega endp
;************************************************************************
;* Graphics Character Attribute *
;* *
;* Purpose: To retrieve the attribute of a character on an IBM screen *
;* in a graphics mode, either 14 or 16. *
;* *
;************************************************************************
public graph_attr
graph_attr proc near
cmp AL,20h ; skip if a space
je grphend
cmp AL,00h ; skip if a null
je grphend
cmp AL,0dbh ; block character?
je grphend
push ES
push SI
push AX ; save character
push DX ; save row and column
xor AH,AH ; clear AH
mov SI,AX ; use SI as an index
sub SI,21h
mov AL,DL ; row
mul char_hgt ; pixels per character
xor BX,BX
mov BL,byte ptr m18_attr[SI] ; default mode 18 adjustment
cmp vid_mode,18 ; are we in mode 18?
je grph_02 ; yes, jump
mov BL,byte ptr m16_attr[SI] ; default mode 16 adjustment
cmp vid_mode,16 ; are we in mode 16?
je grph_02 ; yes, jump
mov BL,byte ptr m14_attr[SI] ; must be mode 14
grph_02:
add AX,BX
mov BX,80 ; 80 bytes per line
mul BX
pop DX ; restore the column
xor DL,DL ; clear the row
xchg DH,DL ; set AX to the row
add AX,DX
mov SI,AX ; put result in SI
mov AX,0a000h ; load in graphics plane
mov ES,AX
xor CX,CX ; clear CX
mov CH,01
mov AH,0
grph_03: call get_val
shl CH,1 ; shift mask one bit to the left
inc AH ; next plane
cmp AH,3
jbe grph_03
pop AX ; retrieve character
mov AH,CL ; set attribute byte
pop SI
pop ES
grphend: ret
graph_attr endp
get_val proc near
push AX ; save AH
mov DX,3ceh ; port addr of sequencer
mov AL,04h ; index to other map mask register
out DX,AL ; set index register
inc DX
xchg AL,AH
out DX,AL ; enable bank
pop AX ; restore AH
mov AL,ES:[SI]
or AL,AL
jz get_end
or CL,CH ; set attribute bit
get_end: ret
get_val endp
; PCTYPE
; Determine type of PC we are running on and initialize screen.
;
; Returns upon exit:
; Machine Type
; 1 for TIPC or Business Pro in TI mode
; FF for IBM-PC
; FE for IBM-PC/XT
; FD for IBM-PC/jr
; FC for IBM-PC/AT or B-P in IBM mode
; F8 for PS2 Model 80
; 0 for undeterminable
; Video Mode
; Character Height
;
pctype proc near
push es ; preserve regs for later
push ds
mov ax,0FC00h ; move paragraph address of copyright
pc_002: mov es,ax ; notice into ES
xor di,di ; Clear DI; 0 is lowest address in ROM @ES:
xor bx,bx ; Flag for "PC_MAKE"
mov cx,40h ; This'll be as far as I go...
mov al,'T' ; look for beginning of "Texas Instruments"
cli ; Stop interrupts - bug in old 8088's
again:
repne scas byte ptr es:[di] ; SEARCH
or cx,cx ; Reach my limit?
jz short pc_005 ; quit if we've exhausted search
cmp byte ptr es:[di],'e' ; make sure this is it
jne again ; use defaults if not found
cmp byte ptr es:[di]+1,'x' ; really make sure this is it
jne again
push ds
mov ds,bx ; 0->DS for addressing low mem.
inc bx ; BX==1 => TIPC
mov ax,ds:word ptr [01A2h] ; If TIPC then what kind?
pop ds ; get DS back
add al,ah ; checkout vector 68 bytes 2 & 3
cmp al,0F0h ; if AL==F0 then TIPC=Business Pro
jne pc_010 ; jump if not a B-P
in al,068h ; Read from port
push ax ; Save for later
and al,0FBh ; Enable CMOS
out 068h,al ; Write back out
mov dx,8296h ; I/O address for B-P's mode byte
in al,dx ; TI or IBM Mode on the B-P?
cmp al,0 ; if not zero then B-P emulates a TIPC
pop ax ; Restore original port value
out 068h,al ; and write back out
jne pc_010 ; jump if TIPC else IBM machine code is
; where it should be.
jmp short pc_007
pc_005: mov ax,es
cmp ah,0FEh ; test for segment offset FE00
jae pc_007 ; two checks made? if so, jump
add ah,2 ; go back and check segment offset
jmp pc_002 ; FE00
pc_007: mov ax,0F000h
mov es,ax
mov al,byte ptr es:0FFFEh ; IBM's machine code is @F000:FFFE
cmp al,0f0h ; Is this suckah an IBM?
jb pc_010 ; Jump if AL is below F0 (BX will be 0)
mov bl,al
pc_010:
sti ; Turn interrups back on
cmp bx,1 ; TIPC?
jne not_ti ; no, jump
; tipc, initialize graphics
mov di,0DF01h
mov es,di ; clear graphics planes
xor di,di
mov byte ptr es:[di],0AAh ; set red palette
mov byte ptr es:[di]+16,0CCh ; set green palette
mov byte ptr es:[di]+32,0F0h ; set blue palette
mov ax,0DF82h
mov es,ax
mov byte ptr es:[di],040h ; turn text on
mov ax,3 ; ax = video mode
; bx = pc type code
mov cx,8 ; cx = character height
jmp pc_020
; ibm, (assumed) get current video mode
not_ti:
push bx ; save pc type code around bios calls
mov ax,0500h ; set active display page (for alpha modes)
int 10h ; bios int
mov ah,15 ; get current video mode
int 10h ; bios int
xor ah,ah ; ax = video mode
pop bx ; bx = pc type code
mov cx,8 ; cx = character height
cmp ax,16 ; if video mode = 16
jle pc_020 ; then
mov cx,14 ; reset character height
pc_020:
pop ds ; restore local data seg
pop es ; es:di addresses transaction buffer
xor di,di
mov PC_MAKE,bx ; put PC_MAKE in transaction buffer
mov VID_MODE,ax ; ditto video mode
mov CHAR_HGT,cx ; ditto char height
ret
pctype endp
page
;-----------------------------------------------------------------------------
; The XLI interface.
;-----------------------------------------------------------------------------
main proc far ;this file's initial entry point
mov AX,data
mov DS,AX
; mov AX,stack ;establish local stack
; mov SS,AX
call pctype ;initialize type/monitor info
mov psp,ES ;save PSP@
mov word ptr ES:fb_addr,offset file_block ;poke file block@
mov word ptr ES:fb_addr+2,seg file_block ;into PSP
mov AX,ES:term_addr ;calc ptrs in PCS to jump to
add AX,3
mov xwait,AX
add AX,3
mov xbye,AX
mov AX,ES:term_addr+2
mov xwait+2,AX
mov xbye+2,AX
mov psize,plen ;calc program size
push psp
push psize
call dword ptr [xwait] ;connect with PCS
; Since this is a XLI SYSINT routine, no XCALL's ever cause a return.
; The only time we return is to terminate.
pop AX
pop AX
call dword ptr [xbye] ;disconnect from PCS
main endp
progsize = $-progstart
plen equ (progsize+datasize+stacksize+100h+10h)/16
PROG ends
end main