home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
KAYPRO
/
KPNUROM.LBR
/
KVIDEO.ZQ0
/
KVIDEO.Z80
Wrap
Text File
|
2000-06-30
|
17KB
|
701 lines
title 'Revised screen handler for Kaypro 4-83 85/6/13'
; Requires z80asm to handle the external byte variables?
.z80
;
; Access to this module
entry vidinit; initialize
entry vidout; output (c) to screen
;
; System constants
extrn bitport; bank switching, Kaypro
extrn bankbit; how to bank switch
;
; Connection to other areas
extrn .kbdout; (c) to keyboard, for bells
;
; Connection to the actual video memory
extrn scrnbas; 3000h, address of 1st screen line
extrn oneline; 128, storage used per line
extrn maxln; 24, lines on screen available
;
; Computed from above, must be external for assembler
extrn endline; address of last screen line
; scrnbas + (maxln-1) * oneline
extrn line25; base address past screen shr 8
; (endline + oneline) shr 8
extrn colmask; oneline - 1
;
; This emulates the original Kaypro/ADM3A protocol, with some
; additions and refinements. The video RAM is organized as
; 24 lines of 128 chars, but chars past column 80 must not be
; written. The control and escape sequences are an amalgamation
; of those in the original Kaypro, those used with SWP's CoPower
; 88 on the Kaypro, and extensions. The characteristics of some
; control sequences are altered, e.g. control of column position,
; line wrap only occurs when a character is output past column
; 80, etc. Characters with high order bits set are used directly
; for display, not as controls.
; Copyright (c) 85/6/13 by C.B. Falconer
;
; 85/6/18. vidout now returns current cursor position in hl
;
; Control Char usage ( * all not mentioned are normally ignored)
; bel ^G Ring bell
; bs ^H cursor left (not past start of line)
; * tab ^I cursor right to tab pt (not past end of line)
; lf ^J cursor down. Scroll at bottom, keep column
; vt ^K cursor up. Scroll at top, keep column
; ff ^L cursor right one (not past end of line)
; cr ^M cursor to left of current line
; etb ^W Clear from cursor to end of screen inclusive
; can ^X clear cursor to end of line inclusive
; sub ^Z clear screen and home cursor
; esc ^[ SEE BELOW
; rs ^6 Home cursor to top left. Do not clear
; * us ^- Next single char not a control, display only
;
; Escape sequences, all begin with esc (01bh)
; * C following char used as cursor marker, flashing. Useful
; ones on Kaypro are DEL, US (=^-), and _. Any allowed
; * D following char used as cursor, not flashing. See above
; E Insert cursor line, scrolling all below down. Keep column
; R Delete cursor line, scrolling all below up. Keep column
; * e Insert blank at cursor posn. Chars off end of line lost
; * r Delete char. at cursor posn. Line closes up
; * ( Set attribute to flash. Further chars. to screen flash
; * ) Set attribute no flash. Further chars do not flash
; = Next two chars position cursor, as before and ADM3
; * other The esc is discarded, and the char. used as normal.
;
; ( * marks usage not available in original Kaypro )
; ( The esc ( and esc ) sequences are reversed from the )
; ( usage on the CoPower88. The original esc A and esc G )
; ( have been deleted. Use the ^- operation instead. )
; ( esc C, esc D, esc e, and esc r are totally new. The )
; ( tab is also new, and has stops every 8 columns. The )
; ( scroll action on ^J, ^K at screen ends is different, )
; ( as is the wrap around action at column 80. )
;
true equ -1
false equ not true
;
bell equ 07h
bs equ 08h
tab equ 09h
lf equ 0ah
vt equ 0bh
ff equ 0ch
cr equ 0dh
etb equ 17h
can equ 18h
subs equ 1ah
esc equ 1bh
rs equ 1eh
us equ 1fh
del equ 7fh
;
maxcol equ 80
;
flash equ 080h; video bit causes flashing
;
initcur equ del + flash; for light block.
; us + flash; for solid block
; '_' + flash; for original
; remove "+ flash" for steady
;
; Case table entry
table macro ch, where
db ch
dw where
endm
;
; -----------------------------------------
;
; dseg
;
extrn vstate, cursor
extrn row, cchar, cmark, attrib
;
; data area. The Kaypro Screen memory has 128 bytes of unused
; space, in 8 blocks of 16 (peculiar addressing). This storage
; should eventually be placed there for privacy.
;vstate: ds 2; init to vnorm
;cursor: ds 2; location of cursor on screen
;row: ds 1; 1st arg in "esc=yx" sequence
;cchar: ds 1; char for cursor locn
;cmark: ds 1; cursor char for screen for blank
;attrib: ds 1; Video attrib for new chars, 80h for flash
;
; ------------------------------------
;
cseg
;
; Output (c) to screen;
; Return hl as suitable chars for cursor positioning sequence
; i.e. <esc>'=',h,l will restore the cursor to present posn.
; any non executed chars (e.g. esc) will return the present
; cursor without moving it. Thus the value returned at the
; start of a cursor sequence can be used for restoration.
; a := c, f, h,l
vidout: push bc
push de
ld hl,(vstate)
call xpchl; execute per current state
ld hl,(cursor); return current cursor posn
ld de,-scrnbas
add hl,de
ld a,l
and colmask
cp maxcol
ccf; so carry if = maxcol
sbc a,0; If past eol lie, put at eol
add a,' '; so that a restore is reasonable
ld e,a; x position character
add hl,hl
ld a,h
add a,' '
ld d,a
ex de,hl; one off if past end of line
pop de
pop bc
ld a,c
ret
;
; for executing "call (hl)"
xpchl: jp (hl)
;
; -------- NORMAL processing. Everything else is frills --------
;
; output the char in (c) to the screen. 8th bits mean display
; the character without interpreting as a control code, etc.
; The video RAM itself uses the 8th bit as a "flash" attribute.
; The system never wraps a line unless there is really more data
; to be placed on the new line. Cursor is user-settable. A
; line feed (or down arrow) on the bottom line preserves the
; column location, while scrolling. Planned window scrolling.
; a,f,b,c,d,e,h,l
vnorm: ld a,c
or a
jp p,vnorm1; no, hi bit, normal use
and 07fh; remove hi bit
ld c,a
jp vdirkt; and use as is
vnorm1: inc a
and 07fh; map rub into controls
cp ' '+1
jp c,vctrl; implement control chars
; " "
; Output char. directly. No control implemention
; a,f,b,d,e,h,l
vdirkt: ld hl,vnorm
ld (vstate),hl; always reverts to normal
call clrcur; no carry if line must wrap, set hl
call nc,lnwrap; clears carry if no scroll needed
call nc,scroll; only called when off page bottom
; " "
; set character (c) into location (hl), setting cursor at next
; location. If next is past eol then set cursor at eol. At
; entry hl must NOT be outside the range 0..79, i.e. in line
; a,f,h,l
putc: ld a,(attrib)
or c; set current attribute
ld (hl),a; put char on screen
; " "
; Advance cursor hl to next position. Mark screen etc.
; a,f,h,l
advcur: inc hl
; " "
; put cursor to location hl. Range may be 0..80 (i.e. off eol)
; a,f,h,l
putcur: ld (cursor),hl; save for next use
ld a,l; (col = 80 signals off screen)
and colmask
cp maxcol
jp c,setcur; next is not off screen
dec hl
; " "
; set cursor at location (hl), known to be on screen
; a,f
setcur: ld a,(hl)
ld (cchar),a
or flash; mark as a cursor
cp ' ' + flash
jp nz,setc1
ld a,(cmark)
setc1: ld (hl),a; put it in screen display
ret
;
; --------------- CONTROL Char. Processing ----------------
;
; Control char input
vctrl: ld hl,ctbl; dont optimise, because we
call case; need this level on stack
ret; if not found, ignore the char
;
; Control char case tabel
ctbl: table bell, dobell
table bs, goleft
table tab, dotab
table lf, down
table vt, up
table ff, right
table cr, docr
table etb, clreos
table can, clreol
table subs, clrscrn
table rs, home
table us, exact
table esc, escape
db 0ffh; end marker
;
; <esc> found in input
escape: ld hl,esc1
; " "
; Set state for next input character
next: ld (vstate),hl
ret
;
; Accept next character as is, never a control
; h,l
exact: ld hl,vdirkt
jp next
;
; initialize system
; a,f,h,l
vidinit:
ld hl,vnorm
ld (vstate),hl
ld hl,scrnbas
ld (cursor),hl
ld a,' '
ld (cchar),a
ld a,initcur
ld (cmark),a
xor a
ld (attrib),a
; " "
; clear screen. Put cursor at line 0 column 0
; a,f,h,l
clrscrn:
call clrcur
ld hl,scrnbas
push hl
clrsc1: call clrln
call nxtln
jp c,clrsc1; not done yet
clrsc2: pop hl; << *** Entry from clreos **
jp putcur
;
; home cursor
home: call clrcur
ld hl,scrnbas
jp putcur
;
; clear from cursor to end of screen, inclusive
clreos: call clrcur
push hl
call c,clrel; Not at eol, clear rest if line
clres1: call nxtln
jp nc,clrsc2; done remainder
call clrln
jp clres1; and check next
;
; clear to end of line, from and including current cursor posn
; a,f,h,l
clreol: call clrcur
jp nc,advcur; at eol already, no work
push hl; save cursor for later setting
call clrel
pop hl
jp putcur; and install the marker
;
; Move cursor right
; a,f,h,l
right: call clrcur
jp advcur
;
; move cursor left, unless at line start
; a,f,h,l
goleft: ld hl,(cursor)
ld a,l
and colmask
ret z; at line left, hang
call clrcur
jp nc,putcur; was past eol, just put it back
dec hl
jp putcur
;
; move cursor up, maintaining column. May scroll screen down
; a,f,b,c,d,e,h,l
up: call clrcur; and ignore line wraps
call prvln
call nc,scrldn; at screen top. hl points to ln -1
jp putcur; put it back
;
; move cursor down, maintaining column. May scroll screen up
; a,f,b,c,d,e,h,l
down: call clrcur; but ignore line wraps
call nxtln
call nc,scroll; now must scroll, maintaining column
jp putcur
;
; put cursor at line left
; a,f,h,l
docr: call clrcur
ld a,l
and not colmask; set to column 0
ld l,a
jp putcur
;
; Tab to column modulo 8
; a,f,h,l
dotab: call clrcur
jp nc,advcur; was at eol, dont change
inc hl; at least one space
ld a,l
add a,7; max result 87, no carry
and not 7; must be <= 80
ld l,a
jp putcur
;
; -------------- ESCAPE Sequence processing -----------------
;
; 1st char after <esc> is in c
esc1: ld hl,vnorm
ld (vstate),hl; default, unless long sequence
ld hl,etbl
call case; If not found then
jp vnorm; discard esc, output char
;
; Escape sequence initial char table
etbl: table 'R', deline
table 'r', delch
table 'E', insline
table 'e', insch
table '(', setflash
table ')', clrflash
table 'C', escC
table 'D', escD
table '=', escEQ
db 0ffh; end marker
;
; Cursor with flash. Next char is cursor char
escC: ld hl,esc2c
jp next
;
; Cursor with no flash. Next char is cursor char
escD: ld hl,esc2d
jp next
;
; Cursor setting coming. Next char is row
escEQ: ld hl,esc2
jp next
;
; Insert blank at cursor position
insch: call clrcur
jp nc,advcur; already past eol, put it back
push hl
ld b,(hl)
insch1: inc hl
ld a,l
and colmask
cp maxcol
jp nc,inschx; done line move
ld a,(hl)
ld (hl),b
ld b,a
jp insch1; continue
inschx: pop hl
ld (hl),' '
jp putcur
;
; Delete char at cursor position
delch: call clrcur
jp nc,putcur; was past eol, back to end
push hl
ld d,h
ld e,l
delch1: inc hl
ld a,l
and colmask
cp maxcol
jp nc,delchx; done
ld a,(hl)
ld (de),a
inc de
jp delch1
delchx: ex de,hl
ld (hl),' '
pop hl
jp putcur
;
; insert line at current cursor position. Scroll below down
; a,f,b,c,d,e,h,l
insline:
call clrcur
push hl; save for final cursor setting
call dnscrl
pop hl
jp putcur
;
; delete line at current cursor position. Scroll below up
; a,f,b,c,d,e,h,l
deline: call clrcur
push hl; save for final cursor setting
ld b,endline shr 7; end pointer
call mvlns
ex de,hl
call clrln; clear the bottom line
pop hl
jp putcur
;
; Setting attribute for flashing
; a
setflash:
ld a,flash
ld (attrib),a
ret
;
; Setting attribute for no flashing
; a
clrflash:
xor a
ld (attrib),a
ret
;
; setting cursor on esc C (flash)
; a,f,h,l
esc2c: ld a,c
or flash
esc2x: ld (cmark),a
call clrcur
jp c,esc2xa; not past eol
inc hl
esc2xa: call putcur; update the cursor style
ld hl,vnorm
jp next
;
; setting cursor on esc D (no flash)
; a,f,h,l
esc2d: ld a,c
and not flash
jp esc2x
;
; First char after "esc =" recognized.
; a,f,h,l
esc2: ld a,c
ld (row),a; Save for next char.
ld hl,esc3
jp next
;
; Position cursor to column (c), row (row).
; a,f,c,h,l
esc3: ld hl,vnorm
ld (vstate),hl
call clrcur
ld a,c
sub ' '
esc3a: sub maxcol
jp nc,esc3a; col modulo maxcol
add a,maxcol
rla; compensate for later rra
ld c,a
ld a,(row)
sub ' '
esc3b: sub maxln
jp nc,esc3b; row modulo maxln
add a,maxln + scrnbas shr 7
or a
rra; position, save rh bit
ld h,a
ld a,c; which goes into col byte
rra
ld l,a
jp putcur
;
; ------------------ SUBROUTINES ------------------
;
; clear current cursor marker. Return hl = cursor posn
; Return no carry if past eol, when hl is decremented
; a,f,h,l
clrcur: ld hl,(cursor)
ld a,l
and colmask
cp maxcol
jp c,clrc1; Normal, no line end
dec hl
clrc1: ld a,(cchar)
ld (hl),a; Restore actual char at cursor
ret
;
; Wrap cursor hl to start of next line.
; a,f,h,l
lnwrap: ld a,l
and not colmask
ld l,a; point to line start
; " "
; advance to next line, same col. No carry for off screen
; a,f,h,l
nxtln: ld a,oneline
add a,l
ld l,a
adc a,h
sub l
ld h,a
cp line25
ret; with carry unless off screen
;
; advance BACKwards to previous line. No carry for off screen
; a,f,h,l
prvln: ld a,l
sub oneline
ld l,a
ccf; so similar to nxtln
ret c; not off screen, no cy into h
dec h; depends on page aligned screen
ld a,h
cp scrnbas shr 8; carry if too far back
ccf; now no carry means off screen
ret
;
; PROCEDURE movelines(endline, objective);
;
; WHILE endline <> objective DO BEGIN (* h <> b *)
; destination := endline; (* de := hl *)
; IF destination < objective THEN (* normal scroll *)
; endline := destination + oneline (* screen up *)
; ELSE endline := destination - oneline; (* screen down *)
; moveline(endline, destination); END;
;
; The entry hl and b values are the high bytes of the cursor for
; the respective lines, i.e. actual RAM addresses. At entry:
; hl^ is the farthest line to alter (destination).
; b is the line to empty, left shifted to hold lsb. (objective)
; returns de = start of destination line, h = d.
; a,f,d,e,h,l (*** ENTRY IN MIDDLE ***)
mvlns2: ld a,e; h > b
sub oneline
ld l,a; hl := hl - oneline
jp nc,mvlns3; no borrow
dec h
mvlns3: push bc
ld bc,maxcol
ldir; do the actual move
pop bc
; " "
mvlns: ld a,l; **** ENTRY POINT **** <<
and not colmask
ld e,a
ld d,h; de := hl masked to line start
rla
ld a,h
rla
cp b
ret z; h = b; exit move
jp nc,mvlns2; h > b
ld a,e; h < b
add a,oneline
ld l,a; hl := hl + oneline
adc a,h
sub l
ld h,a
jp mvlns3
;
; scroll complete screen down, clear first line,
; At entry from normal scroll operation, (c) is char yet
; to be placed, hl points to the start of the non-existent
; line -1. Set cursor for unchanged column on first line.
; a,f,b,c,d,e,h,l
scrldn: call nxtln
; " "
; As scrldn, except input cursor is on the final line
; a,f,b,c,d,e,h,l
dnscrl: ld a,l
push af; save final column
ld a,l
rla
ld a,h
rla
ld b,a; set destination line
ld hl,endline; 1st to modify
call mvlns
ex de,hl; point to last (garbage) line
call clrln
pop af
ld l,a; set final column
ret
;
; scroll complete screen up, clear last line,
; At entry from normal scroll operation, (c) is char yet
; to be placed, hl points to the start of the non-existent
; line 25. Set cursor for unchanged column on last line.
; a,f,b,c,d,e,h,l
scroll: call prvln
; " "
; As scroll, except input cursor is on the final line
; a,f,b,c,d,e,h,l
upscrl: ld a,l
push af; save final column
ld a,l
rla
ld a,h
rla
ld b,a; set destination line
ld hl,scrnbas; 1st line to modify is 0
call mvlns
ex de,hl; point to last (garbage) line
call clrln
pop af
ld l,a; set final column
ret
;
; clear one line
; a,f,h,l
clrln: ld a,l
and not colmask
ld l,a
; " "
; clear from cursor (in hl) inclusive to end of line
; a,f,h,l
clrel: ld a,l
and not colmask
add a,maxcol
; " "
; clear from cursor (in hl) to point marked by (a)
; f,h,l
clr: ld (hl),' '
inc hl
cp l
jp nz,clr
ret
;
; Ring the bell
; a,f,c
dobell: ld c,04h
jp .kbdout
;
; case jump via table hl^ and char in c.
; Returns only if no entry found, else return address purged.
; Therefore do NOT jump to this (will omit purgable address)
; Table structure is byte, address. Byte = 0ffh for end marker.
; a,f,h,l *** ENTRY IN MIDDLE ***
case1: inc hl
inc hl
case: ld a,(hl); <<< ** ENTRY HERE ** <<<
inc a
ret z; table end, no entry
dec a
cp c
inc hl; to low byte of address
jp nz,case1; not this entry
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ex (sp),hl; purge return, stack exu point
ret
;
; -------------- END of Screen Control System ---------------
;
end