home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
ccdos
/
ccgibm.asm
< prev
next >
Wrap
Assembly Source File
|
2020-01-01
|
96KB
|
2,069 lines
Name ccgibm
; File CCGIBM.ASM
; Tektronix emulator for use with MS Kermit/IBM.
;CHINESE
ifdef MSDOS
include msgibm.dat
else
include ccgibm.dat
endif
code segment public 'code'
extrn outchr:near, beep:near, scrseg:near, cmblnk:near
extrn clrmod:near, savescr:near, cptchr:near, pcwait:near
extrn restscr:near, getflgs:near, clrbuf:near, vtans52:near
extrn iseof:near, beep:near
assume cs:code, ds:datas, es:nothing
; Initialise TEK mode by setting high resolution screen, etc
tekini PROC NEAR
push ax ; do presence tests
push bx
push cx
push dx
push si
push di
push es
mov bx,portval ; get port flow control chars:
mov bx,[bx].flowc ; bh=xon, bl=xoff or both are nulls
mov flow,bx ; save here
mov ax,bx ; get flow control word
cmp al,0 ; able to do xoff?
je tekin0 ; e = no
call outmodem ; tell host xoff while we change modes
tekin0: mov bx,vtemu.att_ptr ; emulator screen color ptr
mov al,[bx]
mov gfcol,al ; save foreground color
and gfcol,0fh ; save just foreground bits
and al,70h ; select background color, no bold
mov cl,4
shr al,cl ; get background colors
mov gbcol,al ; set graphics background color
mov ah,15 ; get current screen mode
int screen
cmp al,3 ; in a mono/color text mode (2/3)?
jbe tekin1 ; be = yes
cmp al,mono ; mono text mode (7)?
je tekin1 ; e = yes
cmp tekflg,0 ; are we active as Tek device now?
je tekin1 ; e = no
jmp tekin13 ; yes, don't redo graphics setup
tekin1: mov curmode,al ; save mode here
mov ah,3 ; get cursor position
xor bh,bh ; page 0
int screen
mov cursor,dx ; save position
call savescr ; save text screen
; Presence tests.
tekin2: mov graph_mode,cga ; Color. Assume CGA
mov segscn,segcga ; assume cga screen segment
mov gpage,0 ; graphics page 0 but no page 1
mov putc,offset gputc ; CGA character display routine
mov gcplot,offset gcgen ; General character plot routine
mov psetup,offset psetupc ; CGA plot setup routine
mov plotptr,offset pltcga ; CGA dot plot routine
mov pincy,offset pincyc ; CGA inc y routine
mov xmult,5 ; CGA. Scale TEK to PC by 640/1024
mov xdiv,8 ; so that 0-1023 converts to 0-639
mov xmax,640-8 ; x-coord of rightmost character
mov ymult,10 ; vertical scale for IBM is 200/780
mov ydiv,39 ;
mov ybot,199 ; Bottom of screen is Y=199
mov al,tekgraf ; user video board specification
cmp al,0 ; auto-sensing?
je tekin2c ; e = yes (default)
cmp al,1 ; user wants CGA?
jne tekin2a ; ne = no
jmp tekin13 ; do CGA
tekin2a:cmp al,4 ; user wants Hercules?
jne tekin2b ; ne = no
jmp tekin8 ; do Hercules
tekin2b:cmp al,5 ; user wants AT&T style?
jne tekin2c ; ne = no
jmp tekin7 ; do AT&T kind
; do auto-sensing of display board
; test for EGA
tekin2c:mov ax,1200H ; EGA: Bios alternate select
mov bl,10H ; Ask for EGA info
mov bh,0ffH ; Bad info, for testing
mov cl,0fH ; Reserved switch settings
int screen ; EGA, are you there?
and cl,0fh ; four lower switches
cmp cl,0cH ; Test reserved switch settings
jb tekin3 ; b = ega present
jmp tekin7 ; else no EGA, check other adapters
tekin3: mov ax,40h ; check Bios 40:87h for ega being
mov es,ax ; the active display adapter
test byte ptr es:[87h],8 ; is ega active?
jz tekin3a ; z = yes
jmp tekin7 ; ega is inactive, check others
tekin3a:cmp bl,1 ; is there 128KB on ega board?
jb tekin4 ; b = less, so no screen saves
mov gpage,1 ; >=128 KB, use two graphics pages
tekin4: mov graph_mode,ega ; assume high resolution color
cmp cl,3 ; high resolution color?
je tekin5 ; e = yes
cmp cl,9 ; high resolution color?
je tekin5 ; e = yes
mov graph_mode,monoega ; assume mono monitor on ega board
test bh,1 ; ega mono mode in effect?
jnz tekin5 ; nz = yes
mov graph_mode,colorega ; say ordinary cga on ega board, 64KB
mov gpage,1 ; is enough memory with 200 scan lines
jmp short tekin5a ; use current cga parameters
tekin5: mov ybot,349 ; text screen bottom is 349 on EGA
mov ymult,35 ;
mov ydiv,78 ; scale y by 350/780
tekin5a:mov segscn,segega ; use ega screen segment
mov psetup,offset psetupe ; plot setup routine
mov plotptr,offset pltega ; ega dot plot routine
mov pincy,offset pincye ; inc y routine
mov putc,offset gputc ; character display routine
mov gcplot,offset gcega ; EGA character plot routine
call fixcolor ; correct color mapping for some bds
jmp tekin13 ; end of EGA part, do VGA tests below
tekin7: mov ax,0fc00h ; Olivetti/AT&T 6300, check rom id
mov es,ax
mov di,0 ; start here
mov graph_mode,olivetti ; Olivetti
mov cx,attlen ; length of logo
mov si,offset ATTLOGO ; master string
repe cmpsb ; do a match
je tekin7c ; e = a match
mov di,0050h ; look here too
mov si,offset ATTLOGO
mov cx,attlen
repe cmpsb
je tekin7c ; e = a match
mov di,2014h ; and look here
mov si,offset ATTLOGO
mov cx,attlen
repe cmpsb ; do a match
je tekin7c ; e = a match, else try other types
tekin7a:mov graph_mode,toshiba
mov ax,0f000h ; Check for Toshiba T3100, rom scan
mov es,ax
mov di,0014h ; start here
mov si,offset TOSHLOGO ; master string
mov cx,toshlen ; length
repe cmpsb ; do a match
je tekin7c ; e = a match, else try other types
tekin7b:mov graph_mode,vaxmate ; DEC VAXmate II
mov ax,0f000h ; Check for VAXmate II rom signature
mov es,ax
mov di,0e000h ; start here
mov si,offset DECLOGO ; master string
mov cx,declen ; length
repe cmpsb ; do a match
jne tekin7d ; ne = mismatch, try other types
; Olivetti/AT&T, Toshiba, VAXmate
tekin7c:mov gpage,0 ; only page 0 with 640 by 400 mode
mov segscn,segcga ; use cga screen segment (0b800h)
mov psetup,offset psetupo ; plot setup routine
mov plotptr,offset pltcga ; cga dot plot routine
mov pincy,offset pincyh ; inc y routine (Herc style addresses)
mov putc,offset gputc ; character display routine
mov gcplot,offset gcgen ; General character plot routine
mov ybot,399 ; bottom of screen is y = 399
mov ymult,20 ; vertical scale = 400/780
mov ydiv,39 ; same as cga setup
jmp tekin13
tekin7d:cmp curmode,mono ; mono text mode?
je tekin8 ; e = yes
jmp tekin11 ; ne = no, try cga
; test for Hercules
tekin8: call scrseg ; get screen segment, test Environment
cmp tv_mode,0 ; Environment active?
je tekin8a ; e = no, ok to test for Hercules
jmp tekin10 ; don't do Herc mode, do Mono
tekin8a:mov dx,hstatus ; Herc status port
in al,dx ; read it
mov bl,al ; save here
and bl,80h ; remember retrace bit
mov cx,0ffffh ; do many times (for fast machines)
tekin8b:mov dx,hstatus ; check status port
in al,dx
and al,80h ; select bit
jmp $+2 ; use a little time
cmp bl,al ; did it change?
loope tekin8b ; test again if not
je tekin10 ; e = no change in bit, not Herc
mov graph_mode,hercules ; say have Herc board
mov segscn,seghga ; assume hga screen segment
mov putc,offset gputc ; character display routine
mov gcplot,offset gcgen ; General character plot routine
mov psetup,offset psetuph ; plot setup routine to use
mov plotptr,offset pltcga ; use cga dot plot routine for Herc
mov pincy,offset pincyh ; inc y routine
mov xmult,45 ; Scale TEK to Hercules by 720/1024
mov xdiv,64 ; so that 0-1023 converts to 0-719
mov xmax,720-8 ; x-coord of rightmost character
mov ymult,87 ; vertical scale for Hercules is
mov ydiv,195 ; 348/780
mov ybot,347 ; bottom of screen is y = 347
mov ax,seghga ; segment of Herc video display
mov es,ax
mov al,es:[8000h] ; read original contents, page 1
not byte ptr es:[8000h] ; write new pattern
mov ah,es:[8000h] ; read back
not byte ptr es:[8000h] ; restore original contents
not ah ; invert this too
cmp ah,al ; same (memory present?)
jne tekin9 ; ne = not same, no memory there
mov gpage,1 ; say two pages of display memory
tekin9: jmp tekin13
; set to MONO
tekin10:mov graph_mode,mono ; force monochrome adapter text
mov segscn,segmono ; assume mono screen segment
call scrseg ; Environments: get virtual screen
mov segscn,ax ; seg returned in ax and es:di
mov gpage,0
mov putc,offset mputc ; character display routine
mov psetup,offset psetupm ; plot setup routine to use
mov plotptr,offset pltmon ; use hga dot plot routine
mov pincy,offset pincym ; inc y routine
mov xmult,5 ; Scale TEK to mono by 640/1024
mov xdiv,8 ; so that 0-1023 converts to 0-639
mov xmax,640-8 ; x-coord of rightmost character
mov ymult,10 ; vertical scale for mono is 200/780
mov ydiv,39
mov ybot,200 ; bottom of screen is y = 200 for Bios
jmp tekin13 ; Uses TEXT mode, for safety
; test for CGA
tekin11:mov graph_mode,cga ; set CGA high resolution graphics
mov segscn,segcga ; CGA screen segment
jmp tekin13
; Set Graphics mode
tekin13:cmp graph_mode,hercules ; Hercules?
jne tekin14 ; ne = no
call hgraf ; set Herc graphics mode, clear regen
jmp short tekin16 ; restore screen
tekin14:mov ah,0 ; set screen mode
mov al,graph_mode ; to this screen mode
cmp tekgraf,3 ; user wants "VGA" modes (640x480)?
jne tekin14a ; ne = no
cmp al,monoega ; yes, allow high resolution stuff?
jb tekin14a ; b = no
cmp al,ega ; ditto
ja tekin14a ; a = no
add al,2 ; use modes 17(b/w) and 18(10)(color)
mov ybot,479 ; text screen bottom is 479 on VGA
mov ymult,48
tekin14a:cmp gpage,0 ; only page 0 available?
je tekin15 ; e = yes, and watch for Bios errors
cmp inited,0 ; first time through?
je tekin15 ; e = yes, clear the page of old junk
or al,80h ; save regen buffer (save area too)
tekin15:int screen ; Bios Set Mode.
tekin16:mov tekflg,1 ; starting Tek sub mode
cmp inited,0 ; inited yet?
jne tekin19 ; ne = yes, restore screen
mov ttstate,offset tektxt ; do displayable text
mov prestate,offset tektxt ; set a previous state of text
mov inited,1 ; say we have initialized
mov al,gfcol
mov tfcol,al ; remember current coloring
mov al,gbcol
mov tbcol,al
call tekcls ; clear screen, for ega coloring
jmp short tekin20
tekin19:call tekrest ; restore old graphics screen
mov al,tfcol ; and coloring
mov gfcol,al
mov al,tbcol
mov gbcol,al
tekin20:mov ax,flow ; get flow control word
xchg ah,al ; get xon into al
cmp al,0 ; able to send xon?
je tekin21 ; e = no
call outmodem ; tell host xon
tekin21:clc ; clear carry for success
jmp short tekin23
tekin22:stc ; set carry for failure
tekin23:pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
tekini ENDP
TEKRINT proc near ; Tek reinitialization entry point
mov inited,0 ; do complete reinitialization
jmp tekini
TEKRINT endp
;Terminal emulation. Enter with received character in AL.
TEKEMU PROC NEAR ; main emulator
cmp tekflg,0 ; Tek mode active yet? (msz call)
jne tektt1 ; ne = yes
call tekini ; init now
mov ttstate,offset tektxt ; initial state
mov prestate,offset tektxt ; set a previous state of text
jnc tektt1 ; nc = succeeded
ret ; else failed to init, just return
tektt1: and al,7fh ; force Tek chars to be 7 bits
cmp al,0 ; NUL char?
je tekign ; e = yes, ignore it before logging
push ax
call getflgs ; get msy yflags into al
mov yflags,al
test al,capt ; capturing output?
pop ax
jz tektt4 ; z = no, forget this part
push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
tektt4: test yflags,trnctl ; debug? if so use tty mode
jz tektt5 ; z = no
cmp al,DEL ; DEL char?
jne tektt4a ; ne = no
mov al,5eh ; make DEL a caret query mark
call outscrn
mov al,3fh ; the query mark
call outscrn
jmp short tekign
tektt4a:cmp al,' ' ; control char?
jae tektt4b ; ne = no
push ax
mov al,5eh ; caret
call outscrn
pop ax
add al,'A'-1 ; make char printable
tektt4b:call outscrn
tekign: ret ; Ignore this character
tektt5: call tkscan ; scan for "ESC [ ? 3 8 l" exit code
tektt5a:cmp al,0 ; null char response?
je tekign ; e = yes, ignore the character
cmp al,' ' ; control code?
jb tektt6 ; b = yes, decode
jmp ttstate ; no, do current state
; Control characters:
tektt6: cmp al,GS ; Line plot command?
jne tektt7 ; ne = no
mov visible,0 ; Next move is invisible
and status,not txtmode ; set status report byte
mov ttstate,offset tekline ; expect coordinates next
jmp tektt12
tektt7: cmp al,RS ; Incremental dot command?
jne tektt8 ; ne = no
and status,not txtmode ; set status report
mov ttstate,offset tekrlin ; expect pen command next
jmp tektt12
tektt8: cmp al,FS ; Point plot command?
jne tektt9 ; ne = no
mov visible,0 ; next move is invisible
and status,not txtmode ; set status report byte
mov ttstate,offset tekpnt
jmp tektt12
tektt9: cmp al,US ; assert text mode? [bjh]
jne tektt10 ; ne = no
or status,txtmode ; set status report byte
mov ttstate,offset tektxt ; Go to TEKTXT next time
mov bypass,0 ; reset bypass condition
jmp tektt12
tektt10:cmp al,ESCAPE ; Escape?
jne tektt11 ; ne = no
or status,txtmode ; set status report byte
cmp ttstate,offset tekesc ; already in escape state?
je tektt14 ; e = yes, nest no further
push ttstate ; current state
pop prestate ; save here as previous state
mov ttstate,offset tekesc ; next state parses escapes
ret
tektt11:cmp al,CAN ; Control X? (exits Tek sub mode)
jne tektt13 ; ne = no, stay in current state
cmp ttstate,offset tekesc ; ESC Control-X?
je tektt13 ; yes, parse it in tekesc code
mov ttstate,offset tektxt ; back to text mode
test flags.vtflg,tttek ; main Tek emulator?
jnz tektt12 ; nz = yes, ignore the ^X
call tekend ; else exit sub mode
mov tekflg,0 ; clear Tek sub mode flag
tektt12:mov prestate,offset tektxt ; make previous state text
tektt14:ret
tektt13:jmp ttstate ; let someone else worry about this
TEKEMU ENDP
; End TEK emulation, recover previous screen
TEKEND PROC NEAR
cmp tekflg,0 ; Tek sub mode active?
jne teknd0 ; ne = yes
ret ; else return as is.
teknd0: call teksave ; save graphics screen to page 1
cmp graph_mode,hercules ; Hercules?
jne teknd1 ; ne = no
call htext ; yes then set up Hercules text mode
teknd1: mov ah,0 ; set video mode
mov al,curmode ; restore previous screen mode
int screen ; revert to text screen
call restscr ; restore text screen
mov dx,cursor ; saved cursor position
mov bh,0 ; page 0
mov ah,2 ; set cursor
int screen
ret
TEKEND ENDP
; State machine active while Tek is active. Senses ESC [ ? 3 8 l to exit
; Tek mode and return to either non-sub mode terminal or to a VT102.
; Plays back unmatched escape sequences. Enter with character in al.
tkscan proc near
and al,7fh ; strip high bit
cmp al,byte ptr tkoff ; start of Tek Off sequence?
jne tkscn1 ; ne = no
call tkscn4 ; playback previously matched chars
mov tkcnt,1 ; count matched chars (one now)
mov tkoffs,al ; save full character, with high bit
mov al,0 ; our temporary response
jmp short tkscnx ; and exit
tkscn1: push bx ; check for char in Tek Off sequence
mov bx,tkcnt ; number of chars matched in Tek Off
mov tkoffs[bx],al ; save this char
cmp al,byte ptr tkoff[bx] ; match expected char in sequence?
pop bx
jne tkscn3 ; ne = no, play back partial match
inc tkcnt ; count new match
mov al,0 ; our temporary response
cmp tkcnt,tkofflen ; matched all char in sequence?
jne tkscnx ; ne = not yet, wait for more
mov tkcnt,0 ; clear counter
cmp flags.vtflg,tttek ; are we a full Tek terminal now?
jne tkscn2 ; ne = no, a submode
call vtans52 ; toggle terminal type, in msyibm
tkscn2: mov al,CAN ; simulate arrival of Control-X
jmp short tkscnx ; all done
tkscn3: call tkscn4 ; playback previously matched chars
mov tkcnt,0 ; reset to no match and exit
tkscnx: ret ; common exit
; local worker procedure
tkscn4: push ax ; save break char (in al)
push cx ; playback partial sequence to screen
mov cx,tkcnt ; number of chars matched before break
jcxz tkscn4b ; z = none
push si
mov si,offset tkoffs ; string to be played back
tkscn4a:cld
lodsb ; get a char into al
push cx
push si ; save these around tektt5a work
call tektt5a ; use it
pop si
pop cx
loop tkscn4a ; do all that came in previously
pop si
tkscn4b:pop cx
pop ax ; recover break char
ret
tkscan endp
TEKTXT proc near ; Dispatch on text characters
cmp al,DEL ; RUBOUT?
jne tektx1 ; ne = no
mov al,bs ; make BS
jmp short tektx7
tektx1: cmp al,CR ; carriage return (^M)?
je tektx9 ; e = yes
tektx2: cmp al,LF ; line feed (^J)?
je tektx9 ; e = yes
tektx3: cmp al,FF ; form feed (^L)?
jne tektx4 ; ne = no
call tekcls ; clear the screen
jmp short tektx8
tektx4: cmp al,VT ; vertical tab (^K)?
je tektx7
cmp al,bell ; bell (^G)?
jne tektx5 ; ne = no
call beep
mov bypass,0 ; clear GIN mode bypass condition
jmp short tektx8
tektx5: cmp al,tab ; horizontal tab (^I)?
je tektx7 ; e = yes
tektx6: cmp al,BS ; backspace (^H)?
je tektx7 ; e = yes
cmp al,' ' ; control char?
jb tektx8 ; b = yes, ignore it
tektx7: cmp bypass,0 ; bypass mode off?
jne tektx8 ; ne = no, it's on so skip display
call OUTSCRN ; output character to the screen
tektx8: ret
tektx9: mov bypass,0 ; clear GIN mode bypass condition
jmp short tektx7
TEKTXT endp
; Process escape sequences. Callable from msz terminal emulator.
; Enter with received character in AL. Escape sequences are generally
; treated as interruptions to the current plotting/text command. Screen
; clearing is the exception by causing a general emulator reset.
TEKESC PROC NEAR
mov bypass,0 ; clear GIN mode bypass condition
mov ttstate,offset tekesc ; in case get here from msz file
cmp tekflg,0 ; Tek mode active yet? (msz call)
jne tekesc1 ; ne = yes
call tekini ; init now
mov prestate,offset tektxt ; set a previous state of text
jnc tekesc1 ; nc = succeeded
ret ; else failed to init, just return
tekesc1:cmp al,'Z' ; ESC-Z Identify?
jne tekesc2 ; ne = no
call SENDID ; Send terminal identification
jmp tekescx
tekesc2:cmp al,FF ; ESC-FF Clear screen?
jne tekesc3 ; ne = no
call tekcls ; Clear screen
mov prestate,offset tektxt ; make previous state text mode
jmp tekescx ; Return to text mode after ESC-FF
tekesc3:cmp al,ESCZ ; ESC-^Z Enter GIN mode?
jne tekesc4 ; ne = no
cmp graph_mode,mono ; Monochrome text mode?
je tekesc3a ; e = yes, no crosshairs in text mode
mov bypass,1 ; turn on GIN mode bypass conditon
call CROSHAIR ; Activate the cross-hairs
jmp tekescx
tekesc3a:call beep ; tell the user we are unhappy
jmp tekescx ; and ignore the command
tekesc4:cmp al,ENQ ; ESC-^E Enquiry for cursor position?
jne tekesc5 ; ne = no
mov bypass,1 ; set bypass mode
call SENDSTAT ; send status
jmp tekescx
tekesc5:cmp al,CAN ; ESC Control-X?
jne tekesc6 ; ne = no
mov bypass,1 ; set bypass condition
jmp tekescx
tekesc6:cmp al,3fh ; query mark? (ESC ? means DEL)
jne tekesc7 ; ne = no
mov al,DEL ; replace with DEL code
jmp tekescx ; and process it as if received.
tekesc7:cmp al,accent ; accent grave, line pattern series?
jb tekesc8 ; b = no
cmp al,65h ; lowercase e?
ja tekescx ; a = beyond line pattern series
push bx
mov bl,al
sub bl,accent ; remove bias
and bl,7 ; eight patterns, roll over excess
mov bh,0
shl bx,1 ; make this a word index
mov bx,linetab[bx] ; get line pattern word
mov linepat,bx ; save in active word
pop bx ; return to previous mode
tekesc8:cmp al,5bh ; right square bracket?
jne tekescx ; ne = no
jmp tekcol ; start coloring scan
tekescx:push ax
mov ax,prestate ; get previous state
mov ttstate,ax ; restore it
or ax,ax ; test for none
pop ax
jz go2text ; z = none, use text mode
clc
ret ; resume previous state
go2text:mov ttstate,offset tektxt ; Go to TEKTXT next time
mov lastc,0 ; clear last drawing coordinate flag
or status,txtmode ; set text mode in status byte
clc
ret
TEKESC ENDP
; Parse ESC [ Pn ; Pn m
; where Pn = 30-37 foreground color, 40-47 background color, ANSI standard
TEKCOL proc near
mov word ptr lastd,0 ; clear parsing flags used below
mov ttstate,offset tekco1 ; resume parsing below
clc
ret
tekco1: cmp lastd,'3' ; units digit in 30 series?
jne tekco2 ; ne = no
inc lastd+1 ; count argument
sub al,'0' ; ascii to binary
cmp al,7 ; numeric?
jbe tekco1a ; be = yes
jmp tekco10 ; a = no, error
tekco1a:push bx
mov bl,al
mov bh,0
mov al,byte ptr colortb[bx] ; reverse coloring
pop bx
and tfcol,not (7) ; retain intensity bit
or tfcol,al ; remember foreground color
mov lastd,0 ; clear parsing flag
ret
tekco2: cmp lastd,'4' ; units digit in 40 series?
jne tekco4 ; ne = no
inc lastd+1 ; count argument
sub al,'0'
cmp al,7 ; numeric?
ja tekco10 ; a = no, error
push bx
mov bl,al
mov bh,0
mov al,byte ptr colortb[bx] ; reverse coloring
pop bx
mov tbcol,al ; remember background color
mov lastd,0 ; clear parsing flag
ret
tekco4: cmp lastd,0 ; looking for tens digit?
jne tekco10 ; ne = yes, error
cmp al,';' ; separator?
jne tekco5 ; ne = no
ret ; ignore it
tekco5: cmp al,'0' ; remove intensity, set b/w?
jne tekco6 ; ne = no
mov tfcol,7 ; regular white
mov tbcol,0 ; on black
inc lastd+1 ; count argument
ret
tekco6: cmp al,'1' ; intensity bit?
jne tekco7 ; ne = no
and tfcol,not (8)
or tfcol,8 ; set foreground intensity
inc lastd+1 ; count argument
ret
tekco7: cmp al,'m' ; end of sequence
je tekco8 ; e = yes
cmp al,'3'
jb tekco10 ; b = not allowed tens digit
cmp al,'4'
ja tekco10 ; a = not allowed tens digit
mov lastd,al ; remember tens digit
inc lastd+1 ; count argument
ret
tekco8: cmp lastd+1,0 ; number of ansi arguments, zero?
ja tekco9 ; a = no, got some
mov tbcol,0 ; none is same as 0, set b/w
mov tfcol,7
tekco9: mov al,tbcol ; success, store coloring
mov gbcol,al ; set background color
mov al,tfcol
mov gfcol,al ; set foreground color
tekco10:mov word ptr lastd,0 ; clear argument and number of args
call fixcolor ; do special ega corrections
mov al,gfcol ; update these in case error
mov tfcol,al
mov al,gbcol
mov tbcol,al
jmp tekescx ; finish escape state
TEKCOL endp
; Revise screen color codes for ega boards with mono displays and limited
; memory.
fixcolor proc near
cmp graph_mode,ega ; one of these ega modes?
je fixcol0 ; e = yes
cmp graph_mode,colorega
je fixcol0
cmp graph_mode,monoega
je fixcol0
ret ; else ignore color corrections
fixcol0:mov ah,gfcol
mov al,gbcol
cmp graph_mode,monoega ; monochrome display?
jne fixcol3 ; ne = no
test al,7 ; bright backgound?
jnz fixcol1 ; nz = yes
mov ah,1 ; normal foreground
test gfcol,8 ; intensity on?
jz fixcol1 ; z = no
mov ah,5 ; say bright foreground
fixcol1:test al,7 ; black backgound?
jz fixcol2 ; z = yes
mov al,1 ; regular video
fixcol2:cmp ah,al ; same color in both?
jne fixcol3 ; ne = no
mov ah,1 ; make foreground regular
mov al,0 ; and background black
fixcol3:mov gfcol,ah
mov gbcol,al
cmp gpage,0 ; minimal memory (64KB mono and ega)?
ja fixcol4 ; a = no, enough, else strange mapping
mov al,gfcol ; fix coloring to map planes C0 to C1
and al,5 ; and C2 to C3 (as 0, 3, 0Ch, or 0Fh)
mov ah,al ; make a copy
shl ah,1 ; duplicate planes C0, C2 in C1, C3
or al,ah ; merge the bits
mov gfcol,al ; store proper foreground color
mov al,gbcol ; repeat for background color
and al,5
mov ah,al
shl ah,1
or al,ah
mov gbcol,al
fixcol4:ret
fixcolor endp
TEKLINE proc near ; GS line drawing
call tekxyc ; parse coordinates from input bytes
jnc teklin1 ; nc = not done yet
mov cl,visible ; get moveto or drawto variable
call tekdraw ; move that point
mov visible,1 ; say next time we draw
teklin1:ret
TEKLINE endp
TEKPNT proc near ; FS plot single point
call tekxyc ; parse coordinates
jnc tekpnt1 ; nc = not done yet
mov cl,0 ; do not draw
call tekdraw ; move to the point
mov ax,si ; copy starting point to end point
mov bx,di ; ax,bx,si,di are in PC coordinates
mov cl,1 ; make plot visible
call line ; draw the dot
mov visible,0 ; return to invisibility
tekpnt1:ret
TEKPNT endp
; Decode graphics x,y components. Returns carry set to say have all
; components for a line, else carry clear. Understands 4014 lsb extensions.
; Permits embedded escape sequences.
TEKXYC proc near
cmp al,CR ; Exit drawing on CR,LF,RS,US,FS,CAN
je tekghx ; e = yes, a cr
cmp al,LF ; these terminate line drawing cmds
je tekghx
cmp al,FS ; <FS>
je tekghx
cmp al,RS ; <RS>
je tekghx
cmp al,US ; <US>
je tekghx
cmp al,CAN ; and <CAN>
je tekghx ; BUT ignore other control chars
cmp al,20h ; Control char?
jb tekgh0 ; b = yes, ignore it
cmp al,40h
jb tekgh2 ; 20-3F are HIX or HIY
cmp al,60h ; 40-5F are LOX (causes beam movement)
jb tekgh4 ; 60-7F are LOY
; Extract low-order 5 bits of Y coord
mov ah,tek_loy ; Copy previous LOY to MSB (4014)
mov tek_lsb,ah
and al,1Fh ; LOY is 5 bits
mov tek_loy,al
cmp lastc,loy ; 2nd LOY in a row?
je tekgh1 ; Yes, then LSB is valid
mov tek_lsb,0 ; 1st one, clear LSB
tekgh1: mov lastc,loy ; LOY seen, expect HIX (instead of HIY)
tekgh0: clc ; c clear = not completed yet
ret
tekghx: jmp go2text
; Extract high-order 5 bits (X or Y, depending on lastc)
tekgh2: and ax,1Fh ; Just 5 bits
mov cl,5
shl ax,cl ; Shift over 5 bits
cmp lastc,loy ; was last coordinate a low-y?
je tekgh3 ; e = yes, parse hix
mov tek_hiy,ax ; this byte has HIY
mov lastc,hiy
clc
ret
tekgh3: mov tek_hix,ax ; This byte has HIX
mov lastc,hix
clc
ret
tekgh4: and al,1Fh ; Just 5 bits
mov tek_lox,al
mov lastc,lox
mov ax,tek_hix ; Combine HIX*32
or al,tek_lox ; with LOX
mov bx,tek_hiy ; Same for Y
or bl,tek_loy
stc ; set c to say completed operation
ret
TEKXYC endp
TEKRLIN proc near ; RS relative line drawing
cmp al,' ' ; Pen up command?
jne tekrli1 ; ne = no, try pen down
mov visible,0 ; do invisible movements
jmp short tekrli2 ; do the command
tekrli1:cmp al,'P' ; pen down command?
jne tekrli3 ; ne = no, return to text mode
mov visible,1 ; set visible moves
tekrli2:mov ax,x_coord ; PC x coordinate of pen
mov bx,y_coord ; y coordinate
call pctotek ; get current pen position in Tek coor
mov cl,0 ; invisible, moveto
call tekdraw ; move that point, set oldx and oldy
mov ttstate,offset tekinc ; next get incremental movement cmds
ret
tekrli3:mov visible,0 ; bad char, reset visibility
push prestate
pop ttstate ; restore previous state
jmp tektt5 ; deal with the break char
TEKRLIN endp
; interpret RS inc plot command byte
TEKINC proc near ; get movement character and do cmd
cmp al,'A' ; move right?
jne tekinc1 ; ne = no
inc oldx ; adjust beam position
jmp short tekinc9
tekinc1:cmp al,'E' ; move right and up?
jne tekinc2 ; ne = no
inc oldx
inc oldy
jmp short tekinc9
tekinc2:cmp al,'D' ; move up?
jne tekinc3 ; ne = no
inc oldy
jmp short tekinc9
tekinc3:cmp al,'F' ; move left and up?
jne tekinc4 ; ne = no
dec oldx
inc oldy
jmp short tekinc9
tekinc4:cmp al,'B' ; move left?
jne tekinc5 ; ne = no
dec oldx
jmp short tekinc9
tekinc5:cmp al,'J' ; move left and down?
jne tekinc6 ; ne = no
dec oldx
dec oldy
jmp short tekinc9
tekinc6:cmp al,'H' ; move down?
jne tekinc7 ; ne = no
dec oldy
jmp short tekinc9
tekinc7:cmp al,'I' ; move right and down?
jne tekincb ; ne = no, bad command
inc oldx
dec oldy
tekinc9:cmp oldx,0 ; too far left?
jge tekinc10 ; ge = no
mov oldx,0 ; else stop at the left margin
tekinc10:cmp oldx,maxtekx-1 ; too far left?
jle tekinc11 ; le = no
mov oldx,maxtekx-1 ; else stop that the left margin
tekinc11:cmp oldy,maxteky-1 ; above the top?
jle tekinc12 ; le = no
mov oldy,maxteky-1 ; else stop at the top
tekinc12:cmp oldy,0 ; below the bottom?
jge tekinc13 ; ge = no
mov oldy,0 ; else stop at the bottom
tekinc13:mov ax,oldx ; ax is vector x end point
mov bx,oldy ; bx is vector y end point
mov cl,visible
call tekdraw ; move/draw to that point
ret
tekincb:push prestate ; bad character, exit inc plot mode
pop ttstate ; new state is previous state
mov visible,0
jmp tektt5 ; reparse the bad char
TEKINC endp
; Routine to trigger the crosshairs, wait for a key to be struck, and send
; the typed char (if printable ascii) plus four Tek encoded x,y position
; coordinates and then a carriage return.
; ax, cx, xcross, ycross operate in PC coordinates.
CROSHAIR PROC NEAR
push linepat ; save line drawing pattern
mov linepat,0ffffh ; reset line type to solid
mov ax,xmax ; right margin minus 7 dots
add ax,7
mov temp,ax ; right margin dot
crosha1:call crosdraw ; draw the cross-hairs
call iseof ; is stdin at EOF?
jc crosha2 ; c = yes, exit this mode now
mov ah,coninq ; DOS, quiet read char
int dos
push ax ; save char for later
call crosdraw ; erase cross hairs
pop ax
or al,al ; ascii or scan code returned
jnz arrow5 ; nz = ascii char returned
call iseof ; is stdin at EOF?
jc crosha2 ; c = yes, exit this mode now
mov ah,coninq ; read scan code
int dos
cmp al,0 ; Control-Break?
jne crosha3 ; ne = no, something else
crosha2:pop linepat ; restore line pattern
ret ; exit crosshairs mode
crosha3:cmp al,homscn ; is it 'home'?
jne arrow1 ; ne = no, try other keys
mov ax,temp ; right margin
shr ax,1 ; central position
mov xcross,ax ; save PC coord for crosshair
mov ax,ybot ; last scan line
shr ax,1
mov ycross,ax ; this is the center of the screen
jmp crosha1 ; home the crosshairs
arrow1: cmp al,lftarr ; left arrow?
jne arrow2 ; ne = no
mov cx,-1 ; left shift
jmp short xkeys
arrow2: cmp al,rgtarr ; right arrow?
jne arrow3 ; ne = no
mov cx,1 ; right shift
jmp short xkeys
arrow3: cmp al,uparr ; up arrow?
jne arrow4 ; ne = no
mov cx,-1 ; up shift
jmp short vertkey
arrow4: cmp al,dnarr ; down arrow?
jne badkey ; ne = no, ignore it
mov cx,1 ; down shift
jmp short vertkey
badkey: call beep ; tell user we don't understand
jmp crosha1 ; keep going
; Shifted keys yield ascii keycodes
arrow5: cmp al,'C' and 1fh ; Control-C?
je crosha2 ; e = yes, exit crosshairs mode now
cmp al,shlftarr ; shifted left arrow?
jne arrow6 ; ne = no
mov cx,-10 ; big left shift
jmp short xkeys
arrow6: cmp al,shrgtarr ; shifted right arrow?
jne arrow7 ; ne = no
mov cx,10 ; big right shift
jmp short xkeys
arrow7: cmp al,shuparr ; shifted up arrow?
jne arrow8 ; ne = no
mov cx,-10 ; big up shift
jmp short vertkey
arrow8: cmp al,shdnarr ; shifted down arrow?
jne charkey ; ne = no, send this key as is
mov cx,10 ; big down shift
jmp short vertkey
xkeys: add cx,xcross ; add increment
jns noxc ; gone too far negative?
mov cx,0 ; yes - then make it 0
noxc: cmp cx,temp ; too far right?
jb xdraw9 ; b = no
mov cx,temp ; yes - then make it the right
xdraw9: mov xcross,cx ; new x value for cross hairs
jmp crosha1 ; and redraw
vertkey:add cx,ycross ; adjust cx
jns noyc ; gone negative?
mov cx,0 ; yes then make 0
noyc: cmp cx,ybot ; too high?
jb yok
mov cx,ybot ; make it maximum
yok: mov ycross,cx ; save new y crosshair
jmp crosha1 ; and redraw
charkey:call clrbuf ; purge received data to date
call outmodem ; send the break character
mov ax,xcross ; set beam to xcross,ycross
mov bx,ycross ; must convert to Tek coordinates
call pctotek ; scale from PC screen coord to Tek
push ax ; save around drawing
push bx
mov cx,0 ; just a move
call tekdraw ; moveto ax,bx in Tek coord
pop bx ; recover Tek y
pop ax ; recover Tek x
call sendpos ; send position report to host
pop linepat ; recover current line drawing pattern
mov ttstate,offset tektxt ; Go to TEKTXT next time
mov lastc,0 ; clear last drawing coordinate flag
or status,txtmode ; set text mode in status byte
ret
CROSHAIR ENDP
; CROSDRAW draws cross-hairs by XORing cross with picture.
; xcross and ycross are in PC coordinates.
CROSDRAW PROC NEAR
mov si,xcross ; move to (xcross, ycross-10)
mov di,ycross
sub di,10 ; half the size of the cross
jns crosd1 ; no sign bit means ok
mov di,0 ; else limit to start of screen
crosd1: mov ax,si ; next, draw to (xcross, ycross+10)
mov bx,ycross ; make bottom stroke
add bx,10
cmp bx,ybot ; too large?
jbe crosd2 ; be = no
mov bx,ybot ; vertical line to (xcross,ybot)
crosd2: mov cx,0ffh ; invert pixels
call line ; and draw vertical
sub si,12 ; move to (xcross-12, ycross)
jns crosd3 ; no sign means ok
mov si,0 ; else limit to start of line
crosd3: mov di,ycross
mov bx,di
mov ax,xcross ; draw to (xcross+12, ycross)
add ax,12
cmp ax,temp ; temp is right margin, too large?
jbe crosd4 ; be = no, ok
mov ax,temp ; max x value
crosd4: mov cx,0ffh ; set XOR code
call line ; draw to (xcross+12, ycross)
ret
CROSDRAW ENDP
; SENDPOS sends position of cross-hairs to the host.
; ax has Tek X and bx has Tek Y coord of center of crosshair
SENDPOS PROC NEAR
push bx ; preserve register
call sendxy ; send x coord
pop ax
call sendxy ; send y coord
mov al,cr ; follow up with cr
call outmodem
ret
SENDPOS ENDP
; SENDXY sends value of ax as Tek encoded bytes
; ax is in Tek coordinates
SENDXY PROC NEAR
shl ax,1
shl ax,1 ; move all but lower 5 bits to ah
shl ax,1
shr al,1
shr al,1 ; move low five bits to low 5 bits
shr al,1
or ah,20h ; make it a printing char as per TEK
xchg al,ah ; send high 5 bits first
call outmodem
xchg al,ah ; then low five bits
or al,20h
call outmodem
xchg ah,al ; al is first sent byte
ret
SENDXY ENDP
SENDID PROC NEAR ; Pretend VT100 with graphics option
mov bx,IDSEQ ; Get addr of string
sndid1: mov al,[bx] ; Get char from sequence
cmp al,0 ; End of sequence?
jz sndid0 ; Yes, return
call OUTMODEM ; Send it out the port
inc bx
jmp sndid1
sndid0: ret
SENDID ENDP
; SENDSTAT - send status and cursor position to host
SENDSTAT PROC NEAR
mov al,STATUS ; get tek status
or al,20h ; make it printable
call OUTMODEM ; and send it
mov ax,oldx ; now send x coordinate (oldx is Tek)
call SENDXY
mov ax,oldy ; and y coordinate (oldy is Tek coord)
call SENDXY
mov al,cr ; end with a cr
call OUTMODEM
ret
SENDSTAT ENDP
; routine to send al to the modem port
OUTMODEM PROC NEAR
push ax
mov ah,al
call outchr ; outchr reads from ah
nop ; ignore errors
nop
nop
pop ax
ret
OUTMODEM ENDP
; Convert X and Y from PC coordinates to Tek coordinates. AX = X, BX = Y
; for both input and output.
pctotek proc near
mul xdiv ; scale from PC screen coord to Tek
div xmult
xchg bx,ax ; save Tek x coord in bx
neg ax ; y axis. Turn upside down for Tek
add ax,ybot
mul ydiv ; scale y from PC screen coord to Tek
div ymult
xchg ax,bx ; ax has X, bx has Y in Tek coords
ret
pctotek endp
; Routine to output character in AL to the screen.
OUTSCRN PROC NEAR ; Output one character to the screen
cmp bypass,0 ; GIN mode bypass off?
je outscp ; e = yes
ret ; else ignore characters
outscp: ; Set Translation Input filter
cmp rxtable+256,0 ; translation turned off?
je outsct ; e = yes, no translation
push bx
mov bx,offset rxtable ; address of translate table
xlatb ; new char is in al
and al,7fh ; retain only lower seven bits
pop bx
outsct: mov si,ybot ; get last scan line
inc si ; number of scan lines
sub si,y_coord ; minus where char bottom needs to go
jnc outscc ; nc = enough space for char
; else give "More >" message
push ax ; save current char
push cx
mov cx,mormsglen ; characters in More message
mov ax,cx
shl ax,1
shl ax,1
shl ax,1 ; times 8 bits/character
neg ax ; (note: leave last char cell empty)
add ax,xmax ; right justify
mov x_coord,ax ; set starting x dot
mov ax,ybot
mov y_coord,ax ; set starting y line
mov ccode,1 ; write in foreground colors
push cx
mov al,DEL ; fill all pixels
outscm1:call putc ; write
loop outscm1
pop cx
push cx
mov al,BS ; backup to overwrite with More text
outscm2:call putc
loop outscm2
pop cx
mov ccode,0 ; main text in background colors
mov si,offset moremsg ; give More message
outsclf:cld
lodsb ; read a byte from string
call putc ; display the string
loop outsclf ; repeat for all string chars
pop cx
mov ccode,1 ; restore normal foreground coloring
call iseof ; EOF on redirected stdin?
jc outscl3 ; c = yes, proceed anyway
mov ah,coninq ; read keyboad via DOS
int dos ; wait for keystroke
or al,al ; scan code being returned?
jne outscl3 ; ne = no
mov ah,coninq ; clear away scan code too
int dos
outscl3:call tekcls ; clear the screen
pop ax ; recover current character
cmp al,lf ; just a line feed?
jne outscc ; ne = no, display it
ret ; else ignore the line feed
outscc: push ax
mov ax,xmax
cmp x_coord,ax ; beyond right margin?
jbe outsc3 ; be = no
mov al,cr ; else simulate cr/lf
call putc ; before displaying current char
mov al,lf
call putc
outsc3: pop ax
call putc ; routine to draw characters
ret
OUTSCRN ENDP
; TEKCLS routine to clear the screen.
; Entry point tekcls1 clears screen without resetting current point.
TEKCLS PROC NEAR
cmp tekflg,0 ; Tek sub mode active yet?
jne tekcls0 ; ne = yes
ret ; else ignore this call
tekcls0:mov x_coord,0 ; starting text coordinates
mov y_coord,8
mov oldx,0 ; assumed cursor starting location
mov oldy,maxteky ; top right corner (Tek coord)
mov scalex,0 ; clear last plotted point (PC coord)
mov scaley,0
mov lastc,0 ; last parsed x,y coordinate
mov visible,0 ; make lines invisible
mov linepat,0ffffh ; reset line pattern to solid
mov ccode,1 ; reset to ordinary writing
mov bypass,0 ; clear bypass condition
mov ttstate,offset tektxt ; do displayable text
push ax
mov ax,xmax ; right margin minus 7 dots
add ax,7 ; right most dot
shr ax,1 ; central position
mov xcross,ax ; save PC coord for crosshair
mov ax,ybot ; last scan line
shr ax,1
mov ycross,ax ; this is the center of the screen
pop ax
tekcls1:push ax ; save registers
push cx
cmp graph_mode,hercules ; Hercules?
jne tekcls2 ; ne = no
call hgraf ; set Hercules board to Graphics mode
jmp tekcls7
tekcls2:mov di,0 ; point to start of screen, di=row
call psetup ; setup graphics routine and es:di
mov cx,4000h ; CGA, 200 lines times 80 bytes worth
cmp graph_mode,cga ; cga?
je tekcls3 ; e = yes
mov cx,8000h ; Olivetti, 400 lines times 80 bytes
cmp graph_mode,olivetti ; AT&T-Olivetti?
je tekcls3 ; e = yes
cmp graph_mode,toshiba ; Toshiba?
je tekcls3 ; e = yes
cmp graph_mode,vaxmate ; VAXmate?
jne tekcls4 ; ne = no
tekcls3:cld ; clear screen directly of text stuff
mov al,0 ; color is black
rep stosb ; clear the bytes
jmp short tekcls7
tekcls4:cmp graph_mode,ega ; EGA?
je tekcls5 ; e = yes
cmp graph_mode,monoega ; EGA with mono display?
je tekcls5 ; e = yes
cmp graph_mode,colorega ; EGA with medium resolution monitor?
je tekcls5 ; e = yes
jmp short tekcls6 ; else use Bios
tekcls5: ; EGA clear screen quickly
mov ax,0ff08h ; set all 8 bits to be changed
call ega_gc ; set bit mask register accordingly
mov cx,ybot ; last scan line
inc cx ; number of scan lines
mov ax,80 ; bytes per scan line
mul cx
mov cx,ax ; cx = number of bytes to clear
mov al,gbcol ; select background colour
cld
rep stosb ; write backgound color
jmp short tekcls7
tekcls6:push es ; clear screen by scrolling up
call cmblnk ; clear screen, for Environments
pop es
tekcls7:mov si,0 ; starting x (in case screen is
mov di,0 ; starting y cleared by user)
pop cx
pop ax
ret
TEKCLS ENDP
; Routine to draw a line on the screen, using TEKTRONIX coordinates.
; X coordinate in AX, 0=left edge of screen, 1023=right edge of screen.
; Y coordinate in BX, 0=bottom of screen, 779=top of screen.
; CL=0 - invisible move, CL=1 - draw a line, CL=0FFh - invert pixels on line
TEKDRAW PROC NEAR
mov si,scalex ; get old x already scaled
mov di,scaley ; get old y already scaled
call scale ; scale new end point to PC coords
cmp cl,0 ; invisible drawing?
je moveto ; z = just move, skip draw part
call LINE ; draw the line
moveto: mov x_coord,ax ; update text coordinates to match
mov y_coord,bx ; last drawn point
ret
TEKDRAW ENDP
; Scale TEKTRONIX coordinates to the currently defined screen coordinates
; AX holds X axis, BX holds Y axis. Both are changed from Tektronix coord
; to PC coordinates by this procedure.
SCALE PROC NEAR
push dx
push si
mov oldx,ax ; save current Tek x for next draw
mov oldy,bx ; save current Tek y for next draw
mul xmult ; scale x-coord
mov si,xdiv ; get the divisor
shr si,1 ; halve it
add ax,si ; add in - to round to nearest integer
adc dx,0
div xdiv
push ax
mov ax,bx
mul ymult ; scale y-coord
mov si,ydiv ; get divisor
shr si,1 ; halve it
add ax,si ; add in - to round to nearest integer
adc dx,0
div ydiv
mov bx,ybot
sub bx,ax ; Put new Y in right reg
jns scale3 ; ns = not too far
mov bx,0
scale3: pop ax ; Put new X in right reg
mov scalex,ax ; save scaled values
mov scaley,bx
pop si
pop dx
ret
SCALE ENDP
; LINE Subroutine to plot a line with endpoints in AX,BX and SI,DI.
; fast line drawing routine for the IBM PC
;
; Registers at CALL
; -----------------
; SI=Start X coord, all in PC coordinates
; DI=Start Y coord
; AX=End X coord
; BX=End Y coord
; CL=Color code: 1=draw foreground, 0=draw background, 0ffh=invert
; BP= line drawing pattern (is changed here by rotation)
; registers are all unchanged
LINE PROC NEAR
push ax
push bx
push cx
push dx
push si
push di
push es
mov bp,linepat ; store active line pattern word in BP
mov ccode,cl ; save color code in ccode for use by plot()
; first get coord to achieve increasing x; deltax >= 0
sub ax,si ; deltax = x2 - x1
jge line1 ; ge = going to the right, as desired
neg ax ; make deltax non-negative
sub si,ax ; swap the x coordinates
xchg bx,di ; swap the y coordinates too
; second, compute deltay. ax = deltax, si = x1
line1: sub bx,di ; deltay = y2 - y1
call psetup ; setup display adapter for plotting
; and setup es:di to screen memory
; Choose algorithm based on |deltay| < |deltax| (use shallow) else steep.
; We arrange matters such that both deltas are non-negative.
cmp bx,0 ; deltay
jge line2 ; ge = non-negative
neg linelen
neg bx ; make non-negative
line2: cmp bx,ax ; |deltay| versus |deltax|
jbe shallow ; be = do shallow algorithm
jmp steep ; else do steep algorithm
; shallow algorithm, move along x, di=y1, bx=deltay, si=x1, ax=deltax
shallow:add bx,bx ; bx = 2*deltay
mov cx,ax ; cx = number of steps (deltax here)
inc cx ; loop dec's cx before testing
mov dx,bx ; dx holds error
sub dx,ax ; error = 2*deltay - deltax
add ax,ax ; ax = 2*|deltax|
shal1: call plotptr ; Plot(x,y)
cmp dx,0
jle shal2 ; le = error <= 0
call pincy ; increment y by one scan line
sub dx,ax ; error = error - 2*deltax
shal2: add dx,bx ; error = error + 2*deltay
inc si ; x = next dot right
loop shal1
shal3: jmp short plotex
; steep algorithm, move along y, di=y1, bx=deltay, si=x1, ax=deltax
steep: add ax,ax ; ax = 2*deltax
mov dx,ax ; dx holds error
sub dx,bx ; error = 2*deltax(bx) - deltay (bx)
mov cx,bx ; cx = number of steps (deltay here)
inc cx ; loop dec's cx before testing
add bx,bx ; bx = 2*|deltay|
stee1: call plotptr ; Plot(x,y) x = ax, y = di
cmp dx,0
jle stee2 ; le error <= 0
inc si ; x = next dot right
sub dx,bx ; error = error - 2*deltay
stee2: add dx,ax ; error = error + 2*deltax
call pincy ; increment y
loop stee1
stee3:;;;jmp plotex
plotex: mov ccode,1 ; reset to do foreground coloring
pop es
pop di
pop si
pop dx ; restore the world
pop cx
pop bx
pop ax
ret
LINE ENDP
;;;;;;; EGA plot support routines
psetupe proc near ; EGA setup for plotting
push ax
mov linelen,80 ; for y going down screen by pincy
mov ax,segscn ; set es to screen memory segment
mov es,ax
mov ax,0205h ; mode: write mode 2
call ega_gc
mov ax,0003h ; assume writing bits directly
cmp ccode,0ffh ; inverting bits?
jne psete2 ; ne = no
mov ax,1803h ; then say XOR the bits
psete2: call ega_gc ; set controller
mov ax,80 ; compute starting point in regen buff
mul di
mov di,ax ; di = di * 80
pop ax
ret
psetupe endp
pincye proc near ; EGA inc y
add di,linelen ; includes sign of deltay
ret
pincye endp
pltega proc near ; EGA plot(x,y). x is in si, y is in di
rol bp,1 ; rotate line pattern
jnc pltega1 ; nc = no bit to be plotted
push bx
push si
push di
mov bx,si ; want si/8 for bytes along line
shr si,1
shr si,1
shr si,1
add di,si ; starting point in regen buffer
and bx,0007h ; leave lower 3 bits for bit in byte
mov bh,masktab[bx] ; 0-7 into bit mask in byte, x pos
mov bl,ccode ; get line type code
call ega_plt
pop di
pop si
pop bx
pltega1:ret
pltega endp
;;;;;;;; CGA plot support routines
; The CGA graphics memory mapping in mode 6 (640 by 200) is 8 dots per byte,
; left most dot in the high bit, 80 bytes per scan line, scan line segments
; alternating between 0b800h (even lines 0, 2, ...) and 0ba00h (odd lines).
psetupc proc near ; CGA setup for plotting
push ax
push cx
mov linelen,80 ; 80 bytes per scan line
mov cx,segscn
mov es,cx
mov cx,di ; save copy of di, start y line
; compute starting point in regen buff
shr di,1 ; half the lines in each bank
mov ax,80 ; 80 bytes per line
mul di
mov di,ax ; di = di * 80 / 2
test cx,1 ; even or odd line
jz psetc1 ; z = even
add di,2000h ; offset to odd bank (seg 0ba00h)
psetc1: and di,3fffh
pop cx
pop ax
ret
psetupc endp
pincyc proc near ; CGA inc y
cmp linelen,0 ; increasing or decreasing y?
jl pinyc2 ; l = decreasing
cmp di,2000h ; in upper bank now?
jb pinyc1 ; b = no, in lower bank
add di,linelen ; add a line
pinyc1: add di,2000h ; switch banks
and di,3fffh ; roll over address
ret
pinyc2: cmp di,2000h ; in upper bank now?
jae pinyc4 ; ae = yes
add di,linelen ; subtract a line
pinyc4: add di,2000h ; switch banks
and di,3fffh ; roll over address
ret
pincyc endp
pltcga proc near ; CGA plot(x,y). x is in si, y is in di
push bx ; used for HGA plot also.
push si
push di
rol bp,1 ; rotate line pattern
jnc pltcg3 ; nc = no bit to be plotted
mov bx,si ; want si/8 for bytes along line
shr si,1
shr si,1
shr si,1
add di,si ; starting point in regen buffer
and bx,0007h ; leave lower 3 bits for bit in byte
; di = offset in regen buffer
mov bh,masktab[bx] ; 0-7 into bit mask in byte. x position
mov bl,ccode ; get line type code
cmp bl,1 ; draw the bit?
jne pltcg1 ; ne = no
or es:[di],bh ; drawn
jmp short pltcg3
pltcg1: cmp bl,0 ; draw in background (erase)?
jne pltcg2 ; ne = no
not bh
and es:[di],bh ; erase the dots
jmp short pltcg3
pltcg2: xor es:[di],bh ; xor in this color
pltcg3: pop di
pop si
pop bx
ret
pltcga endp
;;;;;;; HGA plot support routines
; The HGA graphics memory mapping in mode 255 (720 by 348) is 8 dots per byte,
; left most dot in the high bit, 90 bytes per scan line, scan line segments
; sequence as 0b000h, 0b200h, 0b400h, 0b800h for lines 0-3 and repeat 90 bytes
; higher for the rest.
psetuph proc near ; HGA setup for plotting
push ax
push cx
mov linelen,90 ; for y going down screen by incy
mov ax,segscn ; base segment of display memory
mov es,ax
mov cx,di ; save copy of di, start y line
; compute starting point in regen buff
shr di,1 ; quarter the lines in each bank
shr di,1
mov ax,90
mul di
mov di,ax ; di = di * 90 / 4
and cx,3 ; compute bank from 2 lsb of line num
jcxz pseth2 ; z means it is in bank 0 (0b000h)
pseth1: add di,2000h ; add offset for each bank
loop pseth1 ; do cx times
pseth2: pop cx
pop ax
ret
psetuph endp
pincyh proc near ; HGA inc y, step offset of line
cmp linelen,0 ; increasing y?
jg pinyh2 ; g = yes
cmp di,2000h ; in lowest for four banks?
ja pinyh1 ; a = no
add di,linelen ; yes, add a line
pinyh1: add di,6000h ; move back by adding a lot
and di,7fffh ; roll over address
ret
pinyh2: cmp di,6000h ; in top most bank?
jb pinyh4 ; b = no
add di,linelen ; yes, first add a line
pinyh4: add di,2000h ; switch to next bank
and di,7fffh ; roll over address
ret
pincyh endp
;;;;;;; AT&T-Olivetti, Toshiba, VAXmate Graphics Adapter plot support routines
; The graphics memory mapping in 640 by 400 mode is 8 dots per byte,
; left most dot in the high bit, 80 bytes per scan line, scan line segments
; sequence as 0b800h, 0ba00h, 0bc00h, 0be00h for lines 0-3 and repeat 80 bytes
; higher for the rest. Use Hercules line incrementing (inc y) and CGA dot
; writing. This is a monographic display.
psetupo proc near ; setup for plotting
push ax
push cx
mov linelen,80 ; for y going down screen by incy
mov ax,segscn ; base segment of display memory
mov es,ax
mov cx,di ; save copy of di, start y line
; compute starting point in regen buff
shr di,1 ; quarter the lines in each bank
shr di,1
mov ax,80
mul di
mov di,ax ; di = di * 80 / 4
and cx,3 ; compute bank from 2 lsb of line num
jcxz pseto2 ; z means it is in bank 0 (0b800h)
pseto1: add di,2000h ; add offset for each bank
loop pseto1 ; do cx times
pseto2: pop cx
pop ax
ret
psetupo endp
;;;;;;;; Monochrome, simulate dots with text char
psetupm proc near
mov linelen,1 ; 80 characters but one line
ret
psetupm endp
pltmon proc near ; Monochrome dot plot
mov x_coord,si ; put dot at row=di, col=si, PC Coord
mov y_coord,di
push ax
mov al,'+' ; our dot character
call mputc ; display text char
pop ax
ret
pltmon endp
pincym proc near ; Monochrome inc y
add di,linelen ; includes sign
ret
pincym endp
; GPUTC - a routine to send text characters from font to true graphics boards
; such as EGA, Hercules or CGA. Char is in al. Drawing routine ptr is gcplot.
gputc proc near
cmp al,' ' ; control character?
jae gputc1 ; ae = no, display the char
jmp putctrl ; else handle controls at putctrl
gputc1: push ax ; first save some registers
push bx
push cx
push es
push di
mov bl,al ; now BL has char to be displayed
and bl,7fh ; no high bits allowed here
; set board mode
mov di,y_coord ; get current y coord (char bottom)
sub di,8 ; start 8 lines higher
jnc gputc2 ; nc = ok
mov di,0 ; move up to first line
mov y_coord,8 ; and reset scan line indicator
gputc2: call psetup ; enter with di=line number, sets es:di to
; start of line in display buf and
; sets byte-wide plot mode
mov ax,x_coord ; compute regen buffer byte
shr ax,1 ; want x_coord/8 for bytes along line
shr ax,1
shr ax,1
add di,ax ; byte in regen buffer
xor bh,bh
sub bx,32 ; characters in font start at 32
shl bx,1
shl bx,1 ; 8 bytes per char - hence * 8
shl bx,1
mov cx,8 ; 8 bytes (scan lines) to transfer
call gcplot ; call character plot routine
call incx ; move to next char position
pop di
pop es
pop cx
pop bx
pop ax
ret
gputc endp
putctrl proc near ; CONTROL CHARS = cursor movement
push ax ; save character
cmp al,FF ; formfeed?
jne putct0 ; ne = no
call TEKCLS ; FF clears the screen
jmp putctx
putct0: cmp al,BS ; BS? sends (logical) cursor back one
jne putct2 ; ne = no, try next
mov ax,x_coord
sub ax,8 ; so delete 8 dots (move left)
jns putct1 ; ns = non-negative
mov ax,0 ; but not less than 0
putct1: mov x_coord,ax ; and replace x coordinate
mov al,' ' ; send a space
call putc
sub x_coord,8 ; restore cursor
jmp putctx
putct2: cmp al,tab ; tabs move forward one char position
jne putct4 ; ne = not a tab
call incx ; let incx move cursor right one col
jmp putctx
putct3: mov x_coord,ax
jmp putctx
putct4: cmp al,cr ; <CR> means go to beginning of line
jne putct5
mov x_coord,0 ; zero the x coordinate
jmp putctx
putct5: cmp al,lf ; <LF> means go down 8 pixels (1 line)
jne putct7 ; ne = not LF
add y_coord,8 ; border managed by outscrn and incx
jmp putctx
putct7: cmp al,vt ; <VT> move up screen 1 line (8 pixels)
jne putctx
sub y_coord,8 ; subtract one line (8 pixels)
jnc putctx ; nc = space left
mov y_coord,8 ; else set to top of screen
putctx: pop ax
ret
putctrl endp
mputc proc near ; MONO put char in AL via Bios
push ax ; updates x_coord,y_coord with
push bx ; new cursor position
push cx
push dx
mov ah,0 ; marker for cursor setting not needed
cmp al,' ' ; control code?
jae mputc1 ; ae = no, printable
call putctrl ; do cursor arithmetic
mov ah,1 ; marker to set cursor but no display
mputc1: push ax ; save char and marker
mov cl,3 ; char cell is 8 x 8 dots
mov ax,x_coord ; get resulting cursor PC positions
shr ax,cl
mov dl,al ; column
mov ax,y_coord
sub ax,8 ; minus 8 dots, like other modes
jnc mputc2 ; nc = non-negative
mov ax,0 ; else start at the top
mov y_coord,8 ; here too
mputc2: shr ax,cl
mov dh,al ; row
mov ah,2 ; set cursor to x_coord,y_coord
mov bh,0 ; page 0
int screen
pop ax
cmp ah,0 ; write a char in al?
jne mputcx ; ne = no
mov ah,09h ; write char at cursor postion
mov cx,1 ; just one char
mov bh,0 ; page 0
mov bl,gfcol ; foreground coloring
int screen
inc dl ; next column
mov ah,2 ; set real cursor ahead of last char
int screen
call incx ; move logical cursor
mputcx: pop dx
pop cx
pop bx
pop ax
ret
mputc endp
incx proc near ; move the logical cursor right
mov ax,x_coord ; shift the (logical) cursor right
add ax,8 ; one character cell
mov x_coord,ax
cmp ax,xmax ; at end of the line?
jbe incx1 ; b = no
mov x_coord,0 ; wrap to next line
add y_coord,8 ; next row
mov ax,ybot ; last scan line
cmp ax,y_coord ; below bottom line?
jge incx1 ; ge = no
mov y_coord,ax ; set to bottom row
mov al,lf ; simulate a line feed operation
call outscrn ; invoke More message
incx1: ret
incx endp
; EGA Character plot routine. Enter with bx pointing at font array for char
; cx = number of bytes in char font, es:di = screen memory. Worker for gputc.
; ccode: 0=plot in background colors, 1=foreground, 0ffh=xor with screen
gcega proc near
gcega1: mov al,font[bx] ; EGA byte plot: get bits from font
push bx
;;;;; mov bh,0ffh ; write these bits to clear field
;;;;; mov bl,0 ; in background coloring
;;;;; call ega_plt ; plot a byte
mov bh,al ; set bit pattern of character
mov bl,ccode ; plot in back/fore/xor (ccode) colors
call ega_plt ; byte plot routine for EGA systems
pop bx
inc bx ; next byte of char pattern
call pincy ; next scan line (linelen is preset)
loop gcega1
ret
gcega endp
; General Character plot routine. Enter with bx pointing at font array for
; char, cx = number of bytes in char font, es:di = screen memory.
; Worker for gputc.
gcgen proc near
gcgen1: mov al,font[bx] ; Non-EGA systems: get bits from font
cmp ccode,1 ; write in foreground?
je gcgen2 ; e = yes
xor es:[di],al ; background or xor (same)
jmp short gcgen3
;;;; mov es:[di],al ; write desired pattern (no overwrite)
gcgen2: OR es:[di],al ; write desired pattern (no overwrite)
gcgen3: inc bx ; point to next byte of char pattern
call pincy ; next scan line (linelen is preset)
loop gcgen1 ; and repeat until complete
ret
gcgen endp
; routines to manipulate ega graphics controller and mode register
; command code in al, value in ah - destroys al and dx
ega_gc proc near ; ega graphics controller
mov dx,3ceh
out dx,al ; output command code
inc dx ; dx is now data port
mov al,ah ; get value to al
out dx,al ; output value
ret
ega_gc endp
ega_md proc near ; ega mode controller
mov dx,3c4h
out dx,al ; output command code
inc dx ; dx is now data port
mov al,ah ; get value to al
out dx,al ; output value
ret
ega_md endp
; Plot eight pixels using an EGA board
; Enter with ES:[DI] pointing to screen address of byte,
; bh has pattern of bits to be set, bl has attributes:
; 0 = draw in background color, 1 = draw in foreground color,
; 0ffh = XOR with current dot colors.
; registers preserved
ega_plt proc near
push ax
push dx
mov al,8 ; command to set bit mask register
mov ah,bh ; get bits to be modified (1)
call ega_gc ; unprotect those bit positions
mov ah,gfcol ; get foreground colour
cmp bl,1 ; draw in foreground?
je ega2 ; ne = no
mov ah,gbcol ; get grahics background colour
cmp bl,0ffh ; do an XOR?
jne ega2 ; ne = no
mov ah,0ffh ; XOR, touch all color bits
ega2: mov al,es:[di] ; latch byte
mov es:[di],ah ; set the byte
pop dx
pop ax
ret
ega_plt endp
; routine to set Hercules card to graphics mode - both pages are enabled
HGRAF PROC NEAR
push ax
push bx ; save used registers
push cx
push si
mov al,grph ; graph mode
lea si,gtable ; requires graphics table
mov bx,0
mov cx,4000h ; clear 4000h words
call setmd ; and set the mode
pop si
pop cx
pop bx
pop ax
ret
HGRAF ENDP
; set Hercules card to text mode
HTEXT PROC NEAR
push ax
push bx
push cx
push si
mov al,text ; text mode
lea si,ttable ; requires text table
mov bx,0720h ; blank value (space, white on black)
mov cx,2000 ; whole screen to clear (80*25)
call setmd ; set the mode
pop si
pop cx
pop bx
pop ax
ret
HTEXT ENDP
; Hercules mode set - called from HTEXT and HGRAF
SETMD PROC NEAR
push dx
push ax
mov dx,config ; configuration port
mov al,genable ; allow graphics mode to be set
out dx,al
pop ax
push ax
push cx ; save count
mov dx,cntrl ; control port
out dx,al ; set to text or graphics
mov dx,index ; send 12 bytes from table to 6845
mov cx,12 ; number of registers to load
xor ah,ah ; start with register 0 of 6845
cld
setmd1: jmp $+2 ; small pause for hardware
mov al,ah ; ah is counter
out dx,al ; set register
inc dx ; point to data port
lodsb ; get next byte in table
jmp $+2 ; small pause for hardware
out dx,al ; and send to 6845
inc ah ; next register
dec dx ; point to register port
loop setmd1 ; and continue 'til cx=0
pop cx ; recover count
cld
push di
push es
mov ax,segscn ; start of screen
mov es,ax
xor di,di
mov ax,bx ; get blanking character
rep stosw ; store blanking char in whole screen
pop es
pop di
mov dx,cntrl ; now to re-enable screen
pop ax ; get mode
or al,scrn_on ; enable screen
out dx,al
pop dx
ret
SETMD ENDP
teksave proc near ; saves graphics screen from page 0 to page 1
push si
push di
cmp gpage,0 ; only graphics page 0 on display board?
je teksavx ; e = yes, no saving possible here
mov si,segscn ; segment (!) of current screen
cmp graph_mode,ega
je teksav1
cmp graph_mode,monoega
je teksav1
cmp graph_mode,colorega
je teksav1
cmp graph_mode,hercules
je teksav2
jmp short teksavx ; else nothing
teksav1:mov di,segega+800h ; EGA page 1 screen segment
call egasr ; call common save/restore code
jmp short teksavx
teksav2:mov di,seghga+800h ; Hercules page 1 screen segment
call hgasr ; call common save/restore code
teksavx:pop di
pop si
ret
teksave endp
tekrest proc near ; saves graphics screen of page 0 in page 1
push si
push di
cmp gpage,0 ; only graphics page 0 on display board?
jne tekres0 ; ne = no, more so work to do here
call tekcls1 ; else clear the screen to color it
jmp short tekresx ; and exit
tekres0:mov di,segscn ; segment (!) of new graphics screen
cmp graph_mode,ega
je tekres1
cmp graph_mode,monoega
je tekres1
cmp graph_mode,colorega
je tekres1
cmp graph_mode,hercules
je tekres2
jmp short tekresx ; else nothing
tekres1:mov si,segega+800h ; segment of EGA page 1
call egasr ; call common save/restore code
jmp short tekresx
tekres2:mov si,seghga+800h ; segment of Hercules page 1
call hgasr ; call common save/restore code
tekresx:pop di
pop si
ret
tekrest endp
egasr proc near ; common code for Tek ega save/restore ops
push ax
push cx
push dx
mov ax,0f00h ; enable 4 plane set/resets
call ega_gc ; set controller
mov ax,0f01h ; enable Set/Reset register
call ega_gc
mov ax,0f02h ; set color compare register for 4 planes
call ega_gc
mov ax,0905h ; set mode reg: write latches, read mode
call ega_gc
mov ax,0ff02h ; enable all planes
call ega_md
mov cx,ybot ; last scan line
inc cx ; number of scan lines
mov ax,80 ; bytes per scan line
mul cx
mov cx,ax
push es ; save es
push ds ; save ds
mov es,di ; destination, set es to video memory
mov ds,si ; source, set ds to video memory
xor si,si ; clear offset fields
xor di,di
cld
rep movsb ; copy from page [si] to page [di]
pop ds ; recover ds
pop es ; and other registers
mov ax,0000h ; disable 4 plane set/resets
call ega_gc ; set controller
mov ax,0001h ; disable Set/Reset register
call ega_gc ; set controller
mov ax,0002h ; disable color compare register
call ega_gc
mov ax,1005h ; set mode reg: write latches, odd/even
call ega_gc
pop dx
pop cx
pop ax
ret
egasr endp
hgasr proc near ; Hercules save restore screen
push cx
mov cx,4000h ; number of words to move
push es ; save es
push ds ; save ds
mov es,di ; destination, set es to video memory
mov ds,si ; source, set ds to video memory
xor si,si ; clear offset fields
xor di,di
cld
rep movsw ; copy from page [si] to page [di]
pop ds ; recover ds
pop es ; and other registers
pop cx
ret
hgasr endp
code ends
end