home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msk230s1.zip
/
MSGIBM.ASM
next >
Wrap
Assembly Source File
|
1988-02-12
|
110KB
|
2,240 lines
Name msgibm
; File MSGIBM.ASM
; Tektronix emulator for use with MS Kermit/IBM.
; Edit history:
; Last edit 1 Jan 1988
; 1 Jan 1988 version 2.30
; 31 Dec 1987 change name from msvibm to msgibm for final release. [jrd]
; 29 Dec 1987 Add ESC [ ? 3 8 l as exit Tek mode command, from VT340's.[jrd]
; 26 Dec 1987 Add test to absorb echo of crosshairs report. [jrd]
; 22 Dec 1987 Revise parsing rules to make an escape sequence be a temporary
; interruption to the current command (except Clear Screen seq). [jrd]
; Add Control-C and Control-Break as non-reporting exits from GIN mode. [jrd]
; 21 Dec 1987 Add AT&T 6300, Olivetti M24 presence tests and run code. [jrd]
; 16 Dec 1987 Correct screen coloring for 64KB mono/med res color egas. [jrd]
; 4 Dec 1987 Add quirks for Environments, such as TopView, Windows. [jrd]
; 3 Dec 1987 Let 128KB EGA boards save screens. [jrd]
; 30 Nov 1987 Add relative plotting, thanks to help from Bob Parks. [jrd]
; 24 Nov 1987 Add dashed line patterns. [jrd]
; 21 Nov 1987 Add full color background. [jrd]
; 15 Nov 1987 Do screen clears manually because a Bios mode-set keeps
; interrupts off long enough to miss serial port characters. Make crosshairs
; smaller. [jrd]
; 8 Nov 1987 Modularize line drawing using Bresneham's algorithm, use pointers
; to action routines for different board types. Add screen save/restore.
; Do display board presence tests. Add FS as point plot introducer. Allow
; for virtual screens when operating under Environments (Windows, etc). [jrd]
; 1 Nov 1987 Heavy rewrite to integrate code into regular MS Kermit/IBM
; material. [jrd]
;==============================================================================
; Original version for TI Pro computers by
; 12-Dec-84 Joe Smith, CSM Computing Center, Golden CO 80401
; Converted to IBM PCs by Brian Holley, Cambridge Univ.
; Upgraded and integrated into MS Kermit 2.30 by Joe Doupnik, Utah State Univ.
;
; Description of Tektronix commands
;
; ESCAPE-CONTROL-E (ENQ) requests a status report
; ESCAPE-FORMFEED erases the screen.
; ESCAPE-CONTROL-Z turns on the crosshairs (not on 4006 or 4025)
; ESCAPE [ ? 3 8 l exits Tek mode and returns to host text terminal type
; (VT102 if none defined yet). This is an extension from DEC VT340's.
; CONTROL-] (GS) turns on plot mode, the first move will be with beam off.
; CONTROL-^ (RS) turns on incremental plot mode. RS space means move pen up
; RS P means move pen down, following letters:A, E, D, F, B, J, H, I mean
; move right, right and up, up, left and up, left, left and down, down, and
; right and down, respectively. Ex: RS <space> J J J means move three Tek
; positions left and down with the pen up (invisibly).
; CONTROL-UNDERLINE (US) turns off plot mode, as does CR (for all but 4025).
; CONTROL-X switches from TEKTRONIX sub mode to NORMAL alpha mode but is
; ignored if we are emulating a full Tek terminal rather than a sub mode
; of DEC or Heath.
; FF erases screen.
; ESCAPE letter, where letter is accent grave (`), a-e sets the line drawing
; pattern until reset to solid lines (same as escape accent) by command or
; a terminal reset.
; where
; ENQ = Control E
; ESC = Control [ (left square bracket)
; FF = Control L
; FS = Control \ (backslash)
; GS = Control ] (right square bracket)
; RS = Control ^ (caret)
; US = Control _ (underscore)
;
; The plot commands are characters which specify the absolute position to move
; the beam. All moves except the one immediately after the GS character
; (Control-]) are with a visible trace.
;
; For 4010-like devices - The positions are from 0 to 1023 for both X and Y,
; although only 0 to 780 are visible for Y due to screen geometry. The screen
; is 10.23 by 7.80 inches, and coordinates are sent as 1 to 4 characters.
;
; For 4014-like devices - The positions are from 0 to 4096, but each movement
; is a multiple of 4 positions unless the high-resolution LSBXY are sent. This
; makes it compatible with the 4010 in that a full sized plot fills the screen.
;
; HIX,HIY = High-order 5 bits of position
; LOX,LOY = Middle-order 5 bits of position
; LSBXY = Low-order 2 bits of X + low-order 2 bits of Y (4014 mode)
;
; Hi Y Lo Y Hi X LSBXY Characters sent (Lo-X always sent)
; ---- ---- ---- ----- ----------------------------------
; Same Same Same Same Lo-X
; Same Same Same Diff LSB, Lo-Y, Lo-X 4014
; Same Same Diff Same Lo-Y, Hi-X, Lo-X
; Same Same Diff Diff LSB, Lo-Y, Hi-X, Lo-X 4014
; Same Diff Same Same Lo-Y, Lo-X
; Same Diff Same Diff LSB, Lo-Y, Lo-X 4014
; Same Diff Diff Same Lo-Y, Hi-X, Lo-X
; Same Diff Diff Diff LSB, Lo-Y, Hi-X, Lo-X 4014
; Diff Same Same Same Hi-Y, Lo-X
; Diff Same Same Diff Hi-Y, LSB, Lo-Y, Lo-X 4014
; Diff Same Diff Same Hi-Y, Lo-Y, Hi-X, Lo-X
; Diff Same Diff Diff Hi-Y, LSB, Lo-Y, Hi-X, Lo-X 4014
; Diff Diff Same Same Hi-Y, Lo-Y, Lo-X
; Diff Diff Same Diff Hi-Y, LSB, Lo-Y, Lo-X 4014
; Diff Diff Diff Same Hi-y, Lo-Y, Hi-X, Lo-X
; Diff Diff Diff Diff Hi-y, LSB, Lo-Y, Hi-X, Lo-X 4014
; Offset for byte: 20h 60h 60h 20h 40h
;
; Note that LO-Y must be sent if HI-X has changed so that the TEKTRONIX knows
; the HI-X byte (in the range of 20h-3fh) is HI-X and not HI-Y. LO-Y must
; also be sent if LSBXY has changed, so that the 4010 will ignore LSBXY and
; accept LO-Y. The LSBXY byte is 60h + MARGIN*10h + LSBY*4 + LSBX. (MARGIN=0)
;
;==============================================================================
;
; External variable tekflg and calls to tekini, tekemu, tekesc, tekcls:
; Byte TEKFLG is non-zero when the Tek emulator is active; it is set by the
; startup code in tekini and is maintained in this file. Internal variable
; inited remembers if we have a graphics screen saved, etc.
; TEKINI must be called when entering the emulator to establish the graphics
; screen mode and to calculate the screen dimensions.
; TEKESC is called from say mszibm.asm to invoke Tek emulation when the
; external procedures have detected an Escape Control-L sequence. An implicit
; initialization is done if necessary.
; TEKEMU is the normal entry point to pass a received character to the emulator.
; It too will do an implicit initialization, if required.
; TEKCLS clears the graphics screen, but only if the emulator is active.
; The emulator remains active during Connect mode Help, Status, and other
; interrupts which do not change the terminal type.
; =============================================================================
;
; - ctrl-g (BEL) from line gives beep in tek mode
; - characters better placed in relation to current beam position
; in EGA and Hercules modes
; characters OR-ed into place rather than overwriting
; - add SET TERMINAL GRAPHICS NONE - this ignores the start-up ESC-FF
; for Tektronix
; - add MonoEGA mode for monochrome graphics on an EGA
;
; version 2.29/t3
; changes - stop control characters from echoing to screen in TEKEMU
; - show version on name in MSSDEF.H
; version 2.29b
; changes with this version: - faster line drawing, using direct write to
; memory rather than BIOS calls
; - support for Hercules, Olivetti, EGA
; - minor bug fixes
; adapted to IBM PC June 1987 by Brian Holley,
; Faculty of Economics and Politics
; University of Cambridge, England
; Email: BJH6@UK.AC.CAM.PHX
public tekemu,tekini,tekend ; Terminal emulation routines
public tekcls, tekesc, tekflg ; used by msz file
include mssdef.h
ENQ equ 05h ; ^E ENQ for TEK enquiries
CAN equ 18h ; ^X to return to ANSI mode
ESCZ equ 1Ah ; SUB, ESC-^Z triggers crosshairs
VT equ 0bh ; ^K go up one line
FS equ 1ch ; ^\ for point plot mode
GS equ 1Dh ; ^] draw line (1st move is invisible)
RS equ 1Eh ; ^^ for incremental line plot mode
US equ 1Fh ; ^_ (underscore) returns to text mode
accent equ 60h ; accent grave
txtmode equ 4 ; text mode for TEKTRONIX status
maxtekx equ 1024 ; horizontal and
maxteky equ 780 ; vertical resolution of TEK 4010
screen equ 10h ; bios screen call
uparr equ 72 ; DOS scan codes for arrow keys
dnarr equ 80
lftarr equ 75
rgtarr equ 77
homscn equ 71 ; DOS home screen scan code
shuparr equ '8' ; ascii codes for shifted arrows
shdnarr equ '2'
shlftarr equ '4'
shrgtarr equ '6'
; Graph_mode for different systems:
cga equ 6 ; highest resolution mode for CGA
mono equ 7 ; real monochrome display adapter
colorega equ 14 ; Low-res mode, color EGA
monoega equ 15 ; mono ega needs mode 15
ega equ 16 ; Hi-res mode - EGA
olivetti equ 72 ; Olivetti's Hi-res - 50 lines text
hercules equ 255 ; pseudo mode for Hercules graphics
; Note: IBM VGA mode 18, 640 by 480, can be used by setting "ega" above
; to 18 and modify ybot to be 479 and ymult to be 48 at label tekin5.
; The code will scale everything appropriately for the new screen size, but
; there will be insufficient memory to retain the entire graphics image.
; Do this at your own risk, please, until PS/2 Tech Refs are available. [jrd]
segega equ 0a000h ; segments of display memory, EGA
segcga equ 0b800h ; CGA, AT&T/Olivetti
seghga equ 0b000h ; HGA
segmono equ 0b000h ; Monochrome
; Hercules equates:
index equ 03b4h ; 6845 index register
cntrl equ 03b8h ; Display mode control port
hstatus equ 03bah ; status port
scrn_on equ 8 ; bit to turn screen on
grph equ 2 ; graphics mode
text equ 20h ; text mode
config equ 03bfh ; configuration port
genable equ 1 ; enable graphics, page 0 only
hiy equ 1 ; codes for Tek graphics components
loy equ 2
hix equ 4
lox equ 3
datas segment public 'datas'
extrn flags:byte, portval:word, rxtable:byte, vtemu:byte
extrn tv_mode:byte
xmult dw ? ; scaling factor for x is
xdiv dw ? ; xmult/xdiv
ymult dw ? ; scaling factor for y is
ydiv dw ? ; ymult/ydiv
xmax dw ? ;
ybot dw ? ;
; required for Hercules screen handling
gtable db 35h,2dh,2eh,07h ; bytes for 6845 controller
db 5bh,02h,57h,57h ; - graphics mode
db 02h,03h,0,0
ttable db 61h,50h,52h,0fh ; bytes for 6845 controller
db 19h,06h,19h,19h ; - text mode
db 02h,0dh,0bh,0ch
attlogo db 'OLIVETTI' ; Olivetti M24, AT&T 6300 rom id
attlen equ $-attlogo ; length
ttstate dw tektxt ; state machine control pointer
prestate dw 0 ; previous state, across interruptions
visible db 0 ; 0 to move, 1 to draw a line
tek_hiy dw 0 ; Y coordinate in Tektronix mode
tek_loy db 0
tek_hix dw 0 ; X coordinate in Tektronix mode
tek_lox db 0
tek_lsb db 0 ; Low-order 2 bits of X + low Y
; (4014 mode)
status db 0
lastc db 0 ; last x/y coord fragment seen
masktab db 80h,40h,20h,10h,8,4,2,1 ; quicker than calculations!
; dashed line patterns
linetab dw 0ffffh ; ESC accent 11111111 11111111
dw 0aaaah ; ESC a 10101010 10101010
dw 0f0f0h ; ESC b 11110000 11110000
dw 0fafah ; ESC c 11111010 11111010
dw 0ffcch ; ESC d 11111111 11001100
dw 0fc92h ; ESC e 11111100 10010010
linepat dw 0ffffh ; active line pattern, from above
;End of init data
IDSEQ dw tekem ; address of response to terminal
CTLTAB dw 0 ; .. inquiry
tekem db 'IBM_TEK' ; .. and the response
db escape,'/Z',0
x_coord dw 0 ; Tek text char X coordinate
y_coord dw 8 ; Tek text char Y coordinate
xcross dw 0 ; cross hairs to start at centre
ycross dw 0
oldx dw 0 ; Tek coordinates of last point
oldy dw 767 ; initially top left
scalex dw 0 ; PC coord for scaled x value
scaley dw 0 ; for scaled y value
curmode db 0 ; screen mode before graphics
; local variables for LINE plotting routine
graph_mode db 0 ; graphics video mode, default is none
cursor dw 0 ; saved text cursor
inited db 0 ; non-zero if inited (retains page)
tekflg db 0 ; Tek mode active flag
yflags db 0 ; flags byte from msy
flow dw 0 ; flow control word
gpage db 0 ; display adapter graphics page
gfcol db 15 ; graphics foreground colour
gbcol db 0 ; graphics background color
moremsg db ' More >'
mormsglen equ $-moremsg ; length of message
ccode db 0 ; temp for holding plot color code
linelen dw 0 ; offset increment between scan lines
putc dw mputc ; ptr to plot a character routine
psetup dw psetupm ; ptr to plot setup routine
pfin dw pfinm ; ptr to plot cleanup routine
pincy dw pincym ; ptr to inc y routine
plotptr dw pltmon ; ptr to dot plot routine
segscn dw 0b800h ; actual screen segment to use
; ANSI Escape sequence to turn off Media Copy (Print Controller Off)
tkoff db escape,'[?38l' ; Exit Tek mode escape sequence
tkofflen equ $-tkoff ; length of sequence
tkoffs db 6 dup (0) ; received chars in rcv'd sequence
tkcnt dw 0 ; counter of matched char in tkoffs
repbuf db 6 dup (0) ; crosshairs report buf
repcnt db 0 ; number of untouched chars in repbuf
temp dw 0
; 8*8 font for Hercules, CGA, and EGA TEK mode
; - allows 43 lines, and 80 (90 for Hercules) chars per line.
; all printing (?) characters from <space> to <del> - two characters per line
; 8 bits per scan line, given top line first, 8 scan lines.
font db 0,0,0,0,0,0,0,0, 18h,18h,18h,18h,18h,0,18h,0
db 6ch,6ch,6ch,0,0,0,0,0, 36h,36h,7fh,36h,7fh,36h,36h,0
db 0ch,3fh,68h,3eh,0bh,7eh,18h,0, 60h,66h,0ch,18h,30h,66h,06h,0
db 38h,6ch,6ch,38h,6dh,66h,3bh,0, 0ch,18h,30h,0,0,0,0,0
db 0ch,18h,30h,30h,30h,18h,0ch,0, 30h,18h,0ch,0ch,0ch,18h,30h,0
db 0,18h,7eh,3ch,7eh,18h,0,0, 0,18h,18h,7eh,18h,18h,0,0
db 0,0,0,0,0,18h,18h,30h, 0,0,0,7eh,0,0,0,0
db 0,0,0,0,0,18h,18h,0, 0,06h,0ch,18h,30h,60h,0,0
db 3ch,66h,6eh,7eh,76h,66h,3ch,0, 18h,38h,18h,18h,18h,18h,7eh,0
db 3ch,66h,06h,0ch,18h,30h,7eh,0, 3ch,66h,06h,1ch,06h,66h,3ch,0
db 0ch,1ch,3ch,6ch,7eh,0ch,0ch,0, 7eh,60h,7ch,06h,06h,66h,3ch,0
db 1ch,30h,60h,7ch,66h,66h,3ch,0, 7eh,06h,0ch,18h,30h,30h,30h,0
db 3ch,66h,66h,3ch,66h,66h,3ch,0, 3ch,66h,66h,3eh,06h,0ch,38h,0
db 0,0,18h,18h,0,18h,18h,0, 0,0,18h,18h,0,18h,18h,30h
db 0ch,18h,30h,60h,30h,18h,0ch, 0,0,0,7eh,0,7eh,0,0,0
db 30h,18h,0ch,06h,0ch,18h,30h, 0,3ch,66h,0ch,18h,18h,0,18h,0
db 3ch,66h,6eh,6ah,6eh,60h,3ch, 0,3ch,66h,66h,7eh,66h,66h,66h,0
db 7ch,66h,66h,7ch,66h,66h,7ch, 0,3ch,66h,60h,60h,60h,66h,3ch,0
db 78h,6ch,66h,66h,66h,6ch,78h, 0,7eh,60h,60h,7ch,60h,60h,7eh,0
db 7eh,60h,60h,7ch,60h,60h,60h, 0,3ch,66h,60h,6eh,66h,66h,3ch,0
db 66h,66h,66h,7eh,66h,66h,66h, 0,7eh,18h,18h,18h,18h,18h,7eh,0
db 3eh,0ch,0ch,0ch,0ch,6ch,38h, 0,66h,6ch,78h,70h,78h,6ch,66h,0
db 60h,60h,60h,60h,60h,60h,7eh, 0,63h,77h,7fh,6bh,6bh,63h,63h,0
db 66h,66h,76h,7eh,6eh,66h,66h, 0,3ch,66h,66h,66h,66h,66h,3ch,0
db 7ch,66h,66h,7ch,60h,60h,60h, 0,3ch,66h,66h,66h,6ah,6ch,36h,0
db 7ch,66h,66h,7ch,6ch,66h,66h, 0,3ch,66h,60h,3ch,06h,66h,3ch,0
db 7eh,18h,18h,18h,18h,18h,18h, 0,66h,66h,66h,66h,66h,66h,3ch,0
db 66h,66h,66h,66h,66h,3ch,18h, 0,63h,63h,6bh,6bh,7fh,77h,63h,0
db 66h,66h,3ch,18h,3ch,66h,66h, 0,66h,66h,66h,3ch,18h,18h,18h,0
db 7eh,06h,0ch,18h,30h,60h,7eh, 0,7ch,60h,60h,60h,60h,60h,7ch,0
db 0,60h,30h,18h,0ch,06h,0,0, 3eh,06h,06h,06h,06h,06h,3eh,0
db 18h,3ch,66h,42h,0,0,0,0, 0,0,0,0,0,0,0,0ffh
db 30h,18h,0ch,0,0,0,0,0, 0,0,3ch,06h,3eh,66h,3eh,0
db 60h,60h,7ch,66h,66h,66h,7ch,0, 0,0,3ch,66h,60h,66h,3ch,0
db 06h,06h,3eh,66h,66h,66h,3eh,0, 0,0,3ch,66h,7eh,60h,3ch,0
db 0eh,18h,18h,3ch,18h,18h,18h,0, 0,0,3eh,66h,66h,3eh,06h,3ch
db 60h,60h,7ch,66h,66h,66h,66h,0, 18h,0,38h,18h,18h,18h,3ch,0
db 18h,0,38h,18h,18h,18h,18h,70h, 60h,60h,66h,6ch,78h,6ch,66h,0
db 38h,18h,18h,18h,18h,18h,3ch,0, 0,0,76h,7fh,6bh,6bh,63h,0
db 0,0,7ch,66h,66h,66h,66h,0, 0,0,3ch,66h,66h,66h,3ch,0
db 0,0,7ch,66h,66h,7ch,60h,60h,0, 0,3eh,66h,66h,3eh,06h,07h
db 0,0,6ch,76h,60h,60h,60h,0, 0,0,3eh,60h,3ch,06h,7ch,0
db 30h,30h,7ch,30h,30h,30h,1ch,0, 0,0,66h,66h,66h,66h,3eh,0
db 0,0,66h,66h,66h,3ch,18h,0, 0,0,63h,6bh,6bh,7fh,36h,0
db 0,0,66h,3ch,18h,3ch,66h,0, 0,0,66h,66h,66h,3eh,06h,3ch
db 0,0,7eh,0ch,18h,30h,7eh,0, 0ch,18h,18h,70h,18h,18h,0ch,0
db 18h,18h,18h,0,18h,18h,18h,0, 30h,18h,18h,0eh,18h,18h,30h,0
db 31h,6bh,46h,0,0,0,0,0, 8 dup (0ffh)
datas ends
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
assume cs:code, ds:datas, es:nothing
; Initialise TEK mode by setting high resolution screen, etc
;The IBM PC CGA card has (639,199) as the coordinate of the lower-right corner.
;Calculate endpoint X=(5/8)*(HIX*32+LOX), Y=199-(10/39)*(HIY*32+LOY)
;The Olivetti has (639,399) as the coordinate of the lower-right corner.
;Calculate endpoint X=(5/8)*(HIX*32+LOX), Y=399-(20/39)*(HIY*32+LOY)
;The Hercules card has (719,347) as the coordinate of the lower-right corner.
;Calculate endpoint X=(45/64)*(HIX*32+LOX), Y=347-(29/65)*(HIY*32+LOY)
; The EGA card has (639,349) as the coordinates of the lower-right corner
;Calculate endpoint X=(45/64)*(HIX*32+LOX), Y=349-(35/78)*(HIY*32+LOY)
tekini PROC NEAR
push ax ; do presence tests. [jrd]
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 psetup,offset psetupc ; CGA plot setup routine
mov plotptr,offset pltcga ; CGA dot plot routine
mov pfin,offset pfinc ; CGA cleanup 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
; test for EGA
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 pfin,offset pfine ; cleanup routine
mov pincy,offset pincye ; inc y routine
mov putc,offset gputc ; character display routine
mov ah,gfcol
mov al,gbcol
cmp graph_mode,monoega ; monochrome display?
jne tekin5d ; ne = no
test al,7 ; bright backgound?
jnz tekin5b ; nz = yes
mov ah,1 ; normal foreground
test gfcol,8 ; intensity on?
jz tekin5b ; z = no
mov ah,5 ; say bright foreground
tekin5b:test al,7 ; black backgound?
jz tekin5c ; z = yes
mov al,1 ; regular video
tekin5c:cmp ah,al ; same color in both?
jne tekin5d ; ne = no
mov ah,1 ; make foreground regular
mov al,0 ; and background black
tekin5d:mov gfcol,ah
mov gbcol,al
cmp gpage,0 ; minimal memory (64KB mono and ega)?
ja tekin5e ; 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
tekin5e:jmp tekin13 ; end of ega tests.
tekin7: mov ax,0fc00h ; Olivetti/AT&T 6300, check rom id
mov es,ax ; look in 0fc00:050h for logo
mov di,50h ; 'OLIVETTI' logo should be here
mov si,offset ATTLOGO ; master string
mov cx,attlen ; length of it
cld
repe cmpsb ; do a match
jne tekin7a ; ne = mismatch, check other adapters
mov graph_mode,olivetti ; Olivetti
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 for Olivetti
mov plotptr,offset pltcga ; cga dot plot routine
mov pfin,offset pfinc ; cleanup routine
mov pincy,offset pincyh ; inc y routine (Herc style addresses)
mov putc,offset gputc ; character display routine
mov ybot,399 ; bottom of screen is y = 399
mov ymult,20 ; Olivetti vertical scale = 400/780
mov ydiv,39 ; same as cga setup
jmp tekin13
tekin7a: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 psetup,offset psetuph ; plot setup routine to use
mov plotptr,offset plthga ; use hga dot plot routine
mov pfin,offset pfinh ; cleanup routine
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
; test for 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 pfin,offset pfinm ; cleanup 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 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
call tekcls ; clear screen, for ega coloring
jmp short tekin20
tekin19:call tekrest ; restore old graphics screen
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
;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
cmp al,0 ; null char response?
je tekign ; e = yes, ignore the character
; check for echo of crosshair report
cmp repcnt,0 ; any chars need matching in report?
je tektt5a ; e = no
push bx ; yes
mov bx,6 ; number of bytes in crosshairs rpt
sub bl,repcnt ; number of chars needing matching
cmp al,repbuf[bx] ; received same as current rpt char?
pop bx
jne tektt5a ; ne = mismatch, stop echo test
dec repcnt ; say one more matched
clc ; absorb without comment
ret ; stay in this state
tektt5a:mov repcnt,0 ; clear report count
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
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
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 printer
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>
tektx1: cmp al,CR ; ^M Carriage return?
je tektx7 ; e = yes
tektx2: cmp al,LF ; ^J LineFeed?
je tektx7 ; e = yes
tektx3: cmp al,FF ; ^L Formfeed?
jne tektx4 ; ne = no
call tekcls ; clear the screen
jmp short tektx8
tektx4: cmp al,VT ; ^K vertical tab?
je tektx7
cmp al,bell ; ^G bell on line?
jne tektx5 ; ne = no
call beep
jmp short tektx8
tektx5: cmp al,Tab ; Tab?
jne tektx6 ; ne = no
mov al,' ' ; make it a space
tektx6: cmp al,BS ; ^H backspace?
je tektx7 ; e = yes
cmp al,' ' ; control char?
jb tektx8 ; b = yes, ignore it
tektx7: call OUTSCRN ; output character to the screen
tektx8: ret
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 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
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
call SENDSTAT ; send status
jmp tekescx
tekesc5:cmp al,accent ; accent grave, line pattern series?
jb tekescx ; b = no
cmp al,65h ; lowercase e?
ja tekescx ; a = beyond line pattern series
push bx
mov bl,al
sub bl,accent ; remove bias
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
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
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 go2text ; e = yes, a cr
cmp al,LF ; these terminate line drawing cmds
je go2text
cmp al,FS ; <FS>
je go2text
cmp al,RS ; <RS>
je go2text
cmp al,US ; <US>
je go2text
cmp al,CAN ; and <CAN>
je go2text ; 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
; 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, by, xcross, ycross operate in PC coordinates.
CROSHAIR PROC NEAR
push linepat ; save line drawing pattern
mov linepat,0ffffh ; reset line type to solid
crosha0:mov ax,xmax ; right margin minus 7 dots
add ax,7
mov temp,ax ; right margin 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
crosha1:call crosdraw ; draw the cross-hairs
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
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'?
je crosha0 ; e = yes
jmp short arrow1 ; else try the arrow keys
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,-64 ; big left shift
jmp short xkeys
arrow6: cmp al,shrgtarr ; shifted right arrow?
jne arrow7 ; ne = no
mov cx,64 ; big right shift
jmp short xkeys
arrow7: cmp al,shuparr ; shifted up arrow?
jne arrow8 ; ne = no
mov cx,-32 ; big up shift
jmp short vertkey
arrow8: cmp al,shdnarr ; shifted down arrow?
jne charkey ; ne = no, send this key as is
mov cx,32 ; 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
mov repcnt,6 ; set length of report string
mov repbuf,al ; store first report character
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
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-12)
mov di,ycross
sub di,12 ; 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+12)
mov bx,ycross ; make bottom stroke
add bx,12
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
mov word ptr repbuf+1,ax ; first word
pop ax
call sendxy ; send y coord
mov word ptr repbuf+3,ax ; second word
mov al,cr ; follow up with cr
mov repbuf+5,al ; last report character
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
; 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
mov ax,mormsglen ; characters in More message
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 ah,gfcol ; get screen coloring
mov al,gbcol
push ax ; save it
xchg ah,al ; interchange colors for message
mov gfcol,ah
mov gbcol,al
mov si,offset moremsg ; give More message
push cx
mov cx,mormsglen
outsclf:cld
lodsb ; read a byte from string
call putc ; display the string
loop outsclf ; repeat for all string chars
pop cx
pop ax ; restore normal video
mov gfcol,ah
mov gbcol,al
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 ttstate,offset tektxt ; do displayable text
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?
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 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: call pfin ; cleanup boards after plotting
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
pfine proc near ; EGA end of plot board cleanup
mov ax,0003h ; restore write bits directly mode
call ega_gc ; set controller
ret
pfine 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
pfinc proc near ; CGA end of plot board cleanup
ret
pfinc 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
plthga proc near ; HGA plot(x,y). x is in si, y is in di.
jmp pltcga ; use CGA routine for plotting
plthga 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
pfinh proc near ; HGA end of plot board cleanup
ret
pfinh endp
;;;;;;;;;;;;;;; AT&T-Olivetti Graphics Adapter plot support routines
; The OGA graphics memory mapping in mode 48h (640 by 400) 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 ; OGA 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,'+'
call mputc ; display text char
pop ax
ret
pltmon endp
pincym proc near ; Monochrome inc y
add di,linelen ; includes sign
ret
pincym endp
pfinm proc near ; Monochrome end of plot cleanup
ret
pfinm endp
; GPUTC - a routine to send text characters from font to true graphics boards
; such as EGA, Hercules or CGA. Char is in al.
gputc proc near
cmp al,' ' ; control character?
jae gputc1 ; ae = no, display the char
jmp putctrl ; else handle controls at putctrl
gputc1: push bx ; first save some registers
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
cmp graph_mode,cga ; CGA. medium color display and board?
je gputc4 ; e = yes
cmp graph_mode,hercules ; Hercules?
je gputc4 ; e = yes
cmp graph_mode,olivetti ; AT&T-Olivetti?
je gputc4 ; e = yes
gputc3: 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,1 ; plot in foreground colors this time
call ega_plt ; byte plot routine for EGA systems
pop bx
inc bx ; next byte of char pattern
call pincy ; next scan line
loop gputc3
jmp short gputx
gputc4: mov al,font[bx] ; Non-EGA systems: get bits from font
mov es:[di],al ; write desired pattern (no overwrite)
inc bx ; point to next byte of char pattern
call pincy ; inc to next line (linelen is preset)
loop gputc4 ; and repeat 'til complete
gputx: call incx ; move to next char position
pop di
pop es
pop cx
pop bx
ret
gputc endp
putctrl proc near ; CONTROL CHARS = cursor movement
cmp al,FF ; formfeed?
jne putct0 ; ne = no
call TEKCLS ; FF clears the screen
ret
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
ret
putct2: cmp al,tab ; tabs move forward one char position
jne putct4 ; ne = not a tab
mov ax,x_coord
add ax,8 ; so add 8
cmp ax,xmax ; zero if off edge of screen
jbe putct3
mov x_coord,0
mov al,lf
jmp short putct5 ; process our new line feed
putct3: mov x_coord,ax
ret
putct4: cmp al,cr ; <CR> means go to beginning of line
jne putct5
mov x_coord,0 ; zero the x coordinate
ret
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
ret
putct7: cmp al,vt ; <VT> move up screen 1 line (8 pixels)
jne putctx
sub y_coord,8 ; - so subtract 8
jnc putctx ; nc = space left
mov y_coord,8 ; else set to top of screen
putctx: 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
; 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 - only page 0 is
; enabled and used
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