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
/
BEEHIVE
/
UTILITYS
/
PLOTBEE.ARC
/
PLOT33S.Z80
< prev
next >
Wrap
Text File
|
1991-02-10
|
93KB
|
3,420 lines
.z80
aseg
;-----------------------------------------------------------------------
; program plot
;-----------------------------------------------------------------------
;
;this program reads a sequential plot command file, makes a memory image
;of the plot, and prints the plot on the printer
;
; copyright (c) 1984 by thomas e. speer. all rights reserved
; 887 briddlewood ln.
; dayton, ohio 45430
; this program is released to the public domain for
; non-commercial use only.
;
;
;revision history
;
; version 3.3bs 14th Sep 90 P. de Lacey
; extra code added for screen output for Microbee (Premium or later)
;
; version 3.3 31 jul 84 t. speer
; fixed bug in oki version of preset routine. extraneous exit
; graphics command was being sent.
;
; version 3.3 7 jul 84 t. speer
; added text comand. added quit to properly close output file.
; modified gbufout to skip totally blank lines.
;
; version 3.2b 27 jun 84 t. speer
; cross hatched color patterns fine tuned. added blinking
; status message. special patterns corrected. all subroutines
; placed in alphabetical order.
;
; version 3.2a 18 jun 84 t. speer
; color patterns changed. 15 special patterns added from
; 49 to 63. these make it easier to match patterns from
; other systems. the default patterns supplied are the same
; as used for nmos and cmos vlsi cif plots.
;
; version 3.2 28 mar 84 t. speer
; citoh modifications debugged. ids mods removed (same as oki)
; base2 mods removed (untested- not suitable for release)
;
; version 3.2 3 feb 84 t. speer
; this version adds the patterned erase, the upload (color
; codes), and extend commands.
;
; version 3.1 10 dec 83 t. speer
; added pattern fills and lines using a cross-hatched method and
; an ordered dither matrix method.
;
; version 3.0 5 nov 83 t. speer
; this version reads all x and y coordinates as
; 2 byte fixed point numbers (16 bit signed values between 0 and 1)
;
; coordinates must be between 0.0 and 1.0 to lie on plot. this
; makes the plot device independent. the fixed point values are easily
; created by the high level program by multiplying the coordinates by
; 32767 and truncating to an integer.
;
; version 2.0 t. speer
; this version used 32 bit floating point integers with a fortran
; routine patched in to do the conversion to integer raster coord.
;
; version 1.0 t. speer
; this version used 16 bit integer coordinates that were tied to
; the epson mx-80 resolution. no conversion was required.
;
;-----------------------------------------------------------------------
;
org 100h ;beginning of tpa
ld c,09h ;select print function
ld de,banner ;print banner message
call fdos
;
jp entry ;jump around variable storage area
banner: defb ' plot version 3.3 31/7/84',0dh,0ah
defb ' (c) by t. e. speer',0dh,0ah,0ah,'$'
defb ' all rights reserved',0dh,0ah,0dh,0ah,'$'
;
;
;
;========================= printer flags ==================================
;set the one that matches your printer to true, and set the others to false.
;
true equ 0ffffh
false equ not true
epson equ false ;flag for epson mx-80 with graphtrax
citoh equ false ;flag for citoh, prowriter, etc
oki equ false ;flag for okidata
screen equ true
;ids set oki flag to true- ids printers act same as oki
;gemini 10 set epson flag to true- gemini 10 acts same as epson
;nec set citoh flag to true- nec acts same as citoh
;apple dot matrix - acts same as citoh, but some <esc> sequences differ.
; set citoh flag to true and check <esc> sequences at esck,
; and in ln772 and preset subroutines.
;
;====================== printer parameters ===============================
; this section sets the specific constants for your printer.
;
;***** note ***** the maximum value for maxx that can be used is 1530.
; the maximum value for maxy that can be used is 1785. these limits
; are required to avoid arithmetic overflows.
; the size of the map ( (maxx+1)*(maxy+1)/7 ) must fit between the end of
; the program and the end of the tpa.
;
; printers seem to have two basic methods of going into graphics
; mode. the epson and citoh printers use an <esc> sequence
; followed by a specified number of graphics bytes. the okidata and ids
; printers use an <etx> to toggle into graphics mode, and then remain
; in graphics until an <etx><so> is received.
; the basic philosophy adopted here is to append the <esc>
; sequence and the number of bytes (if required) to the head of the
; graphics output buffer for those printers in the first group. printers
; in the second group are handled by putting the <etx> commands in the
; gbufout routine. all printers are kept in normal text mode, except
; when actually printing graphics.
;
if epson
maxx equ 559 ;set maximum width to dp100 low res mode
maxy equ 503 ;set maximum height to make square plot
mapsize equ 40320d ;total size of map
cwidth equ 6 ;raster width of a printed character
no8bit equ false ;set to false if your interface can
msbtop equ true ;most sig. bit is top of stroke
; set up graphic output buffer area
esck: defb 1bh,'k' ;define esc "k" character sequence
ngraph: defw 0000h ;initialize graphic counter
gbuff: defs maxx+1 ;set aside area for graphic o/p buffer
endif ;(epson)
;
if citoh
maxx equ 636 ;set maximum width for 80 dots/inch mode
maxy equ 573 ;set maximum height to make square plot
mapsize equ 52234d ;total size of map
cwidth equ 8 ;raster width of a printed character
no8bit equ false ;set to false even if 7 bit interface
msbtop equ false ;least sig. bit is top dot of stroke
; set up graphic output buffer area
esck: defb 1bh,'s',0,0,0,0 ;graphic mode select code
gbuff: defs maxx+1 ;set aside area for graphic o/p buffer
ngraph: defw 0000h ;initialize graphic counter
endif ;(citoh)
;
if oki
maxx equ 575 ;set maximum width for 72 dots/inch
maxy equ 573 ;set maximum height to make square plot
mapsize equ 47232d ;total size of map
cwidth equ 6 ;raster width of character
no8bit equ false ;should be false even if 7 bit interface
msbtop equ false ;least sig. bit is top dot of stroke
; set up graphic output buffer area
gbuff: defs maxx+1
ngraph: defw 0000h
endif ;(oki)
;
if screen
maxx equ 433 ;set maximum width
maxy equ 251 ;set maximum height to make square plot
mapsize equ 15624 ;total size of map
cwidth equ 8 ;raster width of a printed character
no8bit equ false ;set to false if your interface can
msbtop equ true ;most sig. bit is top of stroke
; set up graphic output buffer area
margin equ 42D
xcoord: defw margin
ycoord: defw 0000h
ngraph: defw 0000h ;initialize graphic counter
gbuff: defs maxx+1 ;set aside area for graphic o/p buffer
endif ;(screen)
;
;========================= data storage section ============================
;
color: defb 0
xpos: defw 0
ypos: defw 0
x: defw 0
y: defw 0
yfill: defw 0
nchar: defw 0
achar: defb 40h
pointer: defb 128d ;pointer in file buffer
pointr2: defb 00h ;pointer in output file buffer
oldstk: defw 0000h
stack: defs 80h ;set aside 128 level stack
xdot: defw 0000h ;position of dot to be plotted
ydot: defw 0000h ;position of dot to be plotted
xyaddr: defw origin ;address of x,y location
xybit: defb 00h ;bit in byte @ xyaddr for x,y
divdnd: defw 0000h ;2 byte dividend in divide
divsor: defb 00h ;1 byte divisor in divide
qotent: defb 00h ;1 byte quotient from divide
rmandr: defb 00h ;1 byte remainder from divide
blank equ ' '
nospec: defb 'no file specified',0dh,0ah,'$';error messages
nofile: defb 'file not found',0dh,0ah,'$'
eofmsg: defb 'end of file',0dh,0ah,'$'
nodir: defb 'no directory space available',0dh,0ah,'$'
noroom: defb 'disk is full',0dh,0ah,'$'
unknch: defb 'undefined command character encountered',0dh,0ah,'$'
stat1: defb ' working ... ',0dh,'$'
stat2: defb ' ... working ',0dh,'$'
stat3: defb ' printing picture ',07h,0dh,'$'
statno: defb 00h
deltax: defw 0000h ;local variables for incplt
deltay: defw 0000h ;local variables for incplt
epslnx: defw 0000h ;local variables for incplt
epslny: defw 0000h ;local variables for incplt
sx: defw 0000h ;local variables for incplt
sy: defw 0000h ;local variables for incplt
delta3: defw 0000h ;local variables for incplt
ni: defw 0000h ;local variables for incplt
;
cmask: defb 0ffh ;color mask
patrn: defs 8 ;cell storage for clrmap (erase)
plaids: defb 00h,01h,71h,13h,05h,0fh,35h,11h; cross hatched patterns
;
cifpat: defb 00h, 03h, 48h, 03h, 00h, 30h, 84h, 30h;nd
defb 00h,0cch, 00h,0cch, 00h, 00h, 00h, 00h;ni s
defb 08h, 04h, 02h, 01h, 80h, 40h, 20h, 10h;nt p
defb 11h, 30h, 71h, 30h, 11h, 03h, 17h, 03h;nc e
defb 22h, 00h, 88h, 00h, 22h, 00h, 88h, 00h;nm c
defb 0c0h, 81h, 03h, 06h, 03h, 81h,0c0h, 60h;nb p i
defb 1ch, 3eh, 36h, 3eh, 1ch, 00h, 00h, 00h;ng a a
defb 8fh, 88h, 88h, 88h,0f8h, 88h, 88h, 88h;cw t l
defb 04h, 11h, 04h, 00h, 40h, 11h, 40h, 00h;cd t
defb 02h, 04h, 08h, 10h, 20h, 40h, 80h, 01h;cp e
defb 00h, 00h, 10h, 38h, 10h, 00h, 00h, 00h;cs r
defb 66h, 99h, 99h, 66h, 66h, 99h, 99h, 66h;cc n
defb 00h, 00h, 80h, 10h, 00h, 00h, 10h, 80h;cm s
defb 81h,0c3h, 66h, 66h,0c3h, 81h, 00h, 00h;cg
defb 0fh, 0eh, 0ch, 08h, 00h, 00h, 00h, 00h;ce
;
ditharr: defb 63, 95, 71, 103, 65, 97, 73, 105; ordered
defb 111, 79, 119, 87, 113, 81, 121, 89;
defb 75, 107, 67, 99, 77, 109, 69, 101; dither
defb 123, 91, 115, 83, 125, 93, 117, 85;
defb 66, 98, 74, 106, 64, 96, 72, 104; matrix
defb 114, 82, 122, 90, 112, 80, 120, 88;
defb 78, 110, 70, 102, 76, 108, 68, 100;
defb 126, 94, 118, 86, 124, 92, 116, 84;
;
;
;
;
boot equ 0000h ;cp/m system entry point
fcb equ boot+005ch ;location of file control block
dma equ boot+0080h ;file buffer address
fdos equ boot+0005h ;entry point for cpm functions
fcb2: defs 33d ;output file control block
dma2: defs 128d ;output file buffer
opdisk: defb 00h ;output to disk flag
;
;-----------------------------------------------------------------------
;
entry: ld sp,stack+80h ;set new 128 level stack
ld a,(fcb+9) ;get first character of file type
cp blank ;is type blank?
jp nz,name ;no- type has been specified
ld a,'V' ;make default type "vec"
ld (fcb+9),a ;store default in file type area
ld a,'E'
ld (fcb+10),a ;store default in file type area
ld a,'C'
ld (fcb+11),a ;done- default is set
name: ld a,(fcb+1) ;get first char from fcb
cp blank ;is name blank?
jp nz,openop ;jump if a file name exists
ld c,09h ;select print string function
ld de,nospec ;pass error message
call fdos ;print it
jp boot ;return to cpm system level
openop: ld a,(fcb+17d) ;get 1st char of o/p file
cp blank ;is name blank?
jp z,openfil ;blank= normal print output
ld a,01h ;set o/p file flag=1 (disk o/p)
ld (opdisk),a ;store flag
;
; move o/p file name to new fcb
;
ld c,16d ;half of fcb#1 is o/p info
ld de,006ch ;start of o/p file name
ld hl,fcb2 ;set destination address
movfcb: ld a,(de) ;get name character
ld (hl),a ;store name character
inc de ;increment old name address
inc hl ;increment new name address
dec c ;decrement counter
jp nz,movfcb ;loop back if not done
;
ld a,0 ;clear accumulator
ld (fcb2+32d),a ;zero cr field in o/p fcb
;
ld a,(fcb2+9) ;get 1st char in o/p file type
cp blank ;is file type blank?
jp nz,delete ;not blank- go to delelte old
ld a,'P' ;make default 'plt'
ld (fcb2+9),a ;store default 'p'
ld a,'L'
ld (fcb2+10),a ;store default 'l'
ld a,'T'
ld (fcb2+11),a ;store default 't'
;
delete: ld de,fcb2 ;pass o/p file fcb
ld c,19d ;select delete function
call fdos ;delete old file
;
; make new o/p file
;
ld c,26d ;select set dma function
ld de,dma2 ;pass o/p file buffer address
call fdos ;set dma address
;
ld c,22d ;select make file function
ld de,fcb2 ;pass fcb for o/p
call fdos ;make new file
cp 0ffh ;is directory full?
jp nz,openfil ;no- go on with program
;
ld c,09h ;select print function
ld de,nodir ;pass no directory space msg
call fdos ;print error message
jp boot ;fatal error- quit
;
;open disk file of plot commands
;
openfil: ld c,26d ;select set dma function
ld de,dma ;pass i/p buffer location
call fdos ;set dma to i/p buffer
;
ld c,0fh ;select open file funcion
ld a,00h ;clear accumulator
ld (fcb+12),a ;clear extent counter
ld (fcb+14),a ;clear s2 parameter in fcb
ld de,fcb ;pass fcb
call fdos ;open file
cp 0ffh ;was file found?
jp nz,rewind ;if file exits, rewind it
ld c,09h ;select print function
ld de,nofile ;pass message
call fdos ;print it
jp boot ;return to cpm command level
;
rewind: ld a,00h ;clear accumulator
ld (fcb+32d),a ;rewind by setting record#=0
;
parse: call byte ;get command character
cp 60h ;is it lower case?
jp c,parse0 ;no, so skip shifting it
xor 00100000b ;shift character to upper case
;
parse0: cp 'P' ;is it a "p"?
push af ;save command character
call z,point ;p commands plot point
pop af
jp z,parse ;loop back for new char
;
call stat ;display status message
;
;
cp 'C'
push af
call z,colour ;c commands set color
pop af
jp z,parse ;loop back for new char
;
cp 'D' ;is it a "d"?
push af ;save command character
call z,plotseg ;d commands plot segment
pop af
jp z,parse ;loop back for new char
;
cp 'E'
push af
call z,clrmap ;e commands clear memory map to color
pop af
jp z,parse ;loop back for new char
;
cp 'F'
push af
call z,fill ;f commands fill area to color
pop af
jp z,parse ;loop back for new character
;
cp 'I'
push af
call z,incplt ;i commands plot incremental segment
pop af
jp z,parse ;loop back for new char
;
cp 'M' ;m commands move to coord w/o plotting
push af
call z,move
pop af
jp z,parse
;
cp 'N'
jp z,parse ;n commands a no operation loop
;
cp 'O'
push af
call z,mapout ;o commands printing of plot
pop af
jp z,parse ;loop back for new char
;
cp 'Q'
push af
call z,quit ;q commands termination of program
pop af
jp z,parse ;loop back for new char
;
cp 'S'
push af
call z,string ;s commands character string plotting
pop af
jp z,parse ;loop back for new char
;
cp 'T'
push af
call z,text ;t commands raw text output
pop af
jp z,parse ;loop back for new char
;
cp 'U'
push af
call z,upload ;u commands upload of color paterns
pop af
jp z,parse ;loop back for new char
;
cp 'X'
push af
call z,xtend ;provision for non-standard commands
pop af
jp z,parse ;loop back for new char
;
cp 0dh ;ignore carriage returns
jp z,parse
;
cp 0ah
jp z,parse ;ignore line feeds
;
; command character does not match any defined command
;
ld c,09h ;select print string function
ld de,unknch ;pass undefined character message
call fdos ;print it
jp parse ;loop up to top to get new character
;
;-----------------------------------------------------------------------
; define subroutines
;-----------------------------------------------------------------------
;
; convert binary integer to decimal ascii number
;
; inputs:
; n (binary number) in [de]
; address to store low digit in [hl]
; outputs:
; ascii number stored in memory, high byte first.
; note: the address is decremented for each char.
; register status:
; all register values preserved
; error conditions:
; none
;
if citoh
bindec: push hl ;save registers
push de
push bc
push af
;
ld a,10d ;get a ten
ld (divsor),a ;divisions will be by base 10
;
bdeclp: push hl ;save address for future use
ld a,d
ld (divdnd),a ;first divide high byte
ld a,00h
ld (divdnd+1),a ;16 bit dividend now = 8 bit n high byte
call divide ;divide by 10
ld a,(qotent)
ld d,a ;result is high byte of new n
ld hl,rmandr
ld h,(hl) ;divide remainder with low byte of n
ld l,e ;add low byte of n to remainder
ld (divdnd),hl
call divide ;divide low bytes by 10
pop hl ;retrieve address to receive character
ld a,(rmandr) ;remainder is digit
add a,30h ;convert digit to ascii
ld (hl),a ;store character
dec hl ;move pointer left
ld a,(qotent) ;get result of division
ld e,a ;result is low byte of new n
or d ;is new end = 0?
jp nz,bdeclp ;loop back up if > 0
;
pop af
pop bc
pop de
pop hl ;registers restored
ret
endif ;(citoh)
;----------------------------------------------------------------------
;
; bmult performs a 1-byte by 2-byte multiply
;
; this routine is from electronics magazine, feb 24, 1982.
; by jerry l. goodrich, penn. state u.
;
; inputs:
; 8-bit number in [a]
; 16-bit number in [bc]
; outputs:
; product in [a],[hl] (high byte in [a])
; register status:
; see inputs and outputs
; error conditions:
; none
;
bmult: ld hl,0 ;zero partial product
ld de,7 ;d=0,e=bit counter
add a,a ;get first multiplier bit
loop1: jp nc,zero ;zero skip
add hl,bc ;one-add multiplicand
adc a,d ;add carry to third byte of product
zero: add hl,hl ;shift product left
adc a,a
dec e ;decrement bit counter
jp nz,loop1 ;loop until done
ret nc ;done if no carry
add hl,bc ;otherwise do last add
adc a,d
ret ;and return
;-----------------------------------------------------------------------
; byte gets next byte in buffer
; next record is read if need be
; inputs:
; 128 character buffer @ dma
; character pointer @ pointer which is set @ last position
; outputs:
; new byte in accumulator
; register status:
; [bc],[de],[hl] registers preserved
; error conditions:
; none- if pointer exceeds 128, new record is read
;
byte: push bc ;save registers
push de
push hl
;
ld a,(pointer) ;get pointer value
cp 128d ;is pointer=128?
call z,read ;get record if last one was #128
ld a,(pointer) ;get new pointer value
inc a ;increment pointer value
ld (pointer),a ;store new pointer value
ld c,a ;save pointer value in c
ld b,0 ;make bc=c
ld hl,dma-1 ;load hl with byte before dma
add hl,bc ;calculate addr of desired byte
ld a,(hl) ;get byte
;
pop hl ;restore registers
pop de
pop bc
ret ;done-- byte is in accum.
;-----------------------------------------------------------------------
;
; printed character output
;
; inputs:
; character in register [a]
;
; outputs:
; graphic buffer is flushed
; character is put out to printer
; address in [hl] is incremented by (cwidth - 1)
; dot counter incremented by (cwidth - 1)
; the above are to account for the size of a character
; as opposed to a single dot
; register status:
; [a,psw],[bc] preserved
; [de] decremented by (cwidth -1)
; [hl] incremented by (cwidth -1)
; error conditions:
; none
;
charout: push af ;save registers
push bc
push de
push hl
;
xor 10000000b ;clear high bit of character
call gbufout ;flush graphic buffer
ld c,05h ;select list output
ld e,a ;pass character
call pdos ;send character to printer
;
pop hl ;recall registers
pop de
ld a,cwidth-1
charo1: inc hl ;increment address
dec de ;decrement dot counter
sub 1 ;decrement loop counter
jp nz,charo1
;
pop bc
pop af
ret
;
;-----------------------------------------------------------------------
;
; clear memory subroutine
;
; inputs:
; bitmap of size mapsize located at origin
; map color stored in color
; (pos = patterned, 0 = white, - = complementary)
; outputs:
; entire map area set to desired color or pattern
; registers:
; all register values destroyed
; error conditions:
; none
;
clrmap: ld a,(color) ;get color
or a ;set flage according to color
jp nz,clrnz ;is color non-white?
ld de,mapsize ;put mapsize in [de] as counter
ld hl,origin ;put start of map in [hl]
ld c,00h ;c contains image of white byte
clrlp1: ld (hl),c ;top of loop, store byte
inc hl ;increment address in map
dec de ;decrement loop counter
ld a,d ;move high byte of count. to [a]
or e ;check for 0 counter
jp nz,clrlp1 ;loop until done
ret ;finished with white erase
;
clrnz: push af ;save flag values
; now form 8 byte color pattern
ld hl,patrn+7 ;point to last in pattern sequence
ld c,07h ;initialize x counter
clrlp2: ld d,80h ;set up y bit select
ld e,07h ;initialize y counter
ld b,00h ;initialize pattern
clrlp3: call clrmsk ;form color mask based on x,y
ld a,(cmask) ;get mask
and d ;select one bit
or b ;add bit to pattern
ld b,a ;save new pattern
ld a,d ;modify bit select mask
rrca ;move select bit down one notch
ld d,a ;save new bit select
dec e ;decrement y counter
jp p,clrlp3 ;jump back if not negative (need 0 pass)
pop af ;retrieve color code flag settings
push af ;re-save flags settings
jp p,clrl31 ;positive flag means pattern is ok
ld a,b ;get pattern
cpl ;complement pattern for negative colors
ld b,a ;store pattern byte
clrl31: ld (hl),b ;save pattern for this x location
dec hl ;move memory pointer over
dec c ;decrement x coordinate/counter
jp p,clrlp2 ;only done when negative (need 0 pass)
;
; set up for clearing memory
; rotate array of pattenrx down to match
;
ld bc,(maxy+1) mod 8+1;counter for rotations due to mismatch
clrlp4: call rotpat ;rotate pattern array 1 position
dec c ;decrement counter
jp nz,clrlp4 ;loop back if not done
;
ld hl,origin ;set map pointer to start of map
ld bc,(maxy+1)/7 ;initialize line counter
clrlp5: ld de,(maxx+1)/8 ;initalize dot counter
clrl51: ld a,(patrn) ;get first byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+1) ;get second byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+2)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+3)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+4)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+5)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+6)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
ld a,(patrn+7)
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement x counter
ld a,e
or d ;is counter zero?
jp nz,clrl51 ;loop back until done
;
ld de,(maxx+1)mod 8;set counter for rest of line
ld a,d ;check to see if linesize id mult of 8
or e ;was mod 8 =0?
jp z,clrlp6 ;jump to bottom of loop if finished
ld a,(patrn) ;apply pattern to remaning 1-7 bytes
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+1) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+2) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+3) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+4) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+5) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
dec de ;decrement line length counter
ld a,e
or d ;is counter = 0?
jp z,clrlp6 ;if finished, skip to bottom of outer lp
ld a,(patrn+6) ;continue with next pattern byte
and 7fh ;clear hi bit
ld (hl),a ;store pattern in memory map
inc hl ;move memory pointer
;
clrlp6: call rotpat ;rotate pattern down to match cells
dec bc ;bottom of outer loop. dec line counter
ld a,c
or b ;is counter = 0?
jp nz,clrlp5 ;loop back up for another if req'd
;
pop af ;clean up stack
ret
;
;-----------------------------------------------------------------------
;
; color mask
;
; this subroutine forms the color mask used in plotting points
;
; method:
; the plot is divided up into 8 x 8 raster cells.
; for color values between 1 and 63, the cell is composed
; of an x pattern and a y pattern which are xor'ed with
; each other to form a "plaid" pattern
; for color values 64 and above, ordered dithering is used
; ordered dithering is a technique in which the dots in
; the cell are added in in a pre-arranged position based
; upon the "intensitiy" of the cell. the intersection of
; the point and the pattern (stored in the array "ditharr"
; determines whether or not the point is plotted
;
; for both methods, a color mask is created, which is
; all 1's if the point in the pattern plane is on, or
; all 0's if the point in the pattern plane is off.
; inputs:
; x coordinate in bc
; y coordinate in de
; outputs:
; color mask stored in cmask
; register status:
; all registers preserved
; error conditions:
; none
;
clrmsk: push af ;save registers
push bc
push de
push hl
;
ld a,c ;form x cell coordinate
and 00000111b
ld b,a
;
ld a,e ;form y cell coordinate
and 00000111b
ld c,a
;
ld a,(color) ;get color code
or a ;set flags based on basic code
jp z,whtmsk ;zero color => white mask
jp p,posclr ;color code is positive
cpl ;complement color
add a,01h ;color code is now positive
posclr: cp 64d ;is color code < 64
jp nc,dither ;code >=64 --> dithered
cp 49d ;is color code < 49
jp nc,special ;code from 49 to 63 --> cifpat's else plaid
;
push af ;save color code
and 07h ;select lower 3 bits of color code
ld hl,plaids ;get base address of basic pattern
add a,l ;add x code to base addr to find pattern
ld l,a
ld a,h
adc a,00h ;add carry to high byte of address
ld h,a
ld a,(hl) ;get x pattern for cell
inc b ;increment x coordinate to be counter
xcellp: rra ;rotate pattern bit into carry
dec b ;decrement counter
jp nz,xcellp ;loop back if not done
ld a,0ffh ;carry --> pattern bit says plot point
jp c,savxmsk
ld a,00h
savxmsk: ld b,a ;replace x cell coord with x color mask
;
pop af ;retrieve color code
and 38h ;select 2nd 3 bits for y code
rrca ;rotate bits to low order position
rrca
rrca
ld hl,plaids ;get base address of basic pattern
add a,l ;add x code to base addr to find pattern
ld l,a
ld a,h
adc a,00h ;add carry to high byte of address
ld h,a
ld a,(hl) ;get y pattern for cell
inc c ;increment y coordinate to be counter
ycellp: rra ;rotate pattern bit into carry
dec c ;decrement counter
jp nz,ycellp ;loop back if not done
ld a,0ffh ;dot will be plotted if carry set
jp c,savymsk
ld a,00h
savymsk: xor b ;final color mask-- x patrn xor y patrn
ld (cmask),a ;save color mask
;
pop hl ;restore registers
pop de
pop bc
pop af
ret ;finished -end of plaid branch
;
dither: push af ;save color code for future use
ld a,c ;multiply y cell coordinate by 8
rlca
rlca
rlca
add a,b ;offset into dither table = y*8 + x
ld hl,ditharr ;get base address of table
add a,l ;add offset to base address
ld l,a
ld a,h
adc a,00h ;add carry to high byte
ld h,a
ld a,(hl) ;get dither table value
pop de ;retrieve color code (formerly in [a])
cp d ;is dither value > color code?
ld a,0ffh ;carry--> plot point
jp c,savmsk
ld a,00h ;carry not set--> don't plot point
savmsk: ld (cmask),a ;store mask for future use
;
pop hl
pop de
pop bc
pop af ;registers restored, stack cleaned up
ret
;
;
special: sub 49d ;code is now relative to 49
rlca ;code * 8
rlca
rlca
add a,b ;add x coord to form offset into array
ld hl,cifpat ;get fwa of pattern array
add a,l ;add offset to fwa
ld l,a
ld a,h
adc a,00h ;add carry to hi byte
ld h,a ;addition complete
ld a,(hl) ;get pattern byte for this x coord.
inc c ;increment y coord to form counter
spclp: rra ;rotate pattern bit into carry
dec c ;decrement counter
jp nz,spclp ;loop back until done
ld a,0ffh ;dot will be plotted if carry set
jp c,savmsk
ld a,00h ;carry not set- don't plot point
jp savmsk
;
;
whtmsk: ld a,0ffh ;for white, always modify dot
jp savmsk ;save mask and return
;
;-----------------------------------------------------------------------
;
; define color subroutine
;
; inputs:
; buffer @ dma
; outputs:
; color value saved for future reference
; register status:
; all register values destroyed
; error condtions:
; none
;
colour: call byte ;get color value
ld (color),a ;save it
ret
;
;-----------------------------------------------------------------------
;
; this subroutine computes the next point in a line segment
; must be used with seginit to initialize all variables first.
;
; inputs:
; ni counter used by calling sub. to know when done.
; xpos,ypos present position
; dx,dy size of line segment along x,y axis
; epslnx,epslny,sx,sy,delta3 local variables
; register status:
; all register values destroyed.
; error conditions:
; none peculiar to this routine
;
compseg: ld hl,(ni) ;get counter value
inc hl ;ni<dx- continue (first incr. ni)
ld (ni),hl ;store new ni value
ld hl,(xpos) ;get xpos & put in (bc)
ld b,h ;hi byte to (b)
ld c,l ;low byte to (c)
ld hl,(ypos) ;fetch ypos
ex de,hl ;put ypos in (de)
ld hl,(epslnx) ;fetch epsilon x
add hl,bc ;add epsilon x to x position
ld (xpos),hl ;store new value
ld hl,(epslny) ;fetch epsilon y
add hl,de ;add epsilon y to y position
ld (ypos),hl ;store new value of y position
ld hl,(deltay) ;fetch delta y
ex de,hl ;put deltay in (de)
ld hl,(delta3) ;fetch delta 3
add hl,de ;add delta y to delta 3
ld (delta3),hl ;store new value of delta3
ex de,hl ;put new value of delta 3 in (de)
ld hl,(deltax) ;fetch delta x
ld a,h ;continue if delta x < delta 3
cp d ;otherwise plot point and loop
jp c,cont2 ;hi bytes first- delta3 definitely >
jp nz,dopt ;dx > d3- plot point
ld a,l ;high bytes =: look @ low bytes
cp e ;now low bytes
jp nc,dopt ;d3<=dx: plot point
cont2: ld a,e ;compute d3=d3-dx
sub l ;subtract low byte first
ld l,a ;put low byte in position for store
ld a,d ;now high byte of d3
sbc a,h ;subtract high byte
ld h,a ;put hi byte in position for store
ld (delta3),hl ;store result
ld hl,(sx) ;compute xpos=xpos+sx
ex de,hl ;put sx in (de)
ld hl,(xpos) ;fetch x position
add hl,de ;add sx to xpos
ld (xpos),hl ;store result
ld hl,(sy) ;compute ypos=ypos+sy
ex de,hl ;put sy in (de)
ld hl,(ypos) ;fetch y position
add hl,de ;add sy
ld (ypos),hl ;store new y position
dopt: ret ;return so calling sub can use position.
;
;-----------------------------------------------------------------------
; carriage return routine
;
; inputs:
; none
;
; outputs:
; printer carriage is returned and paper advanced
;
; register status:
; all values preserved
;
; error conditions:
; none
;
crlf: push af ;save all registers
push bc
push de
push hl
;
ld c,05h ;select list output
ld e,0dh ;pass carriage return character
call pdos
ld c,05h ;select list output
ld e,0ah ;pass line feed character
call pdos ;send it out
pop hl ;restore registers
pop de
pop bc
pop af
ret
;
;-----------------------------------------------------------------------
; this subroutine forms the mask for the plotting of a point
; digit= ycoord mod 7
; inputs:
; xcoord in bc
; ycoord in de
; xyaddr in hl
; outputs:
; contents of xyaddr in b
; mask (1 bit on) in c
; ycoord in de
; xyaddr in hl
; register status:
; see outputs
; error conditions:
; overflow in divide calls woops
;
digit: push hl ;save xyaddress
push de ;save ycoord
call clrmsk ;prepare color mask for future use
ex de,hl ;put ycoord in hl
ld (divdnd),hl ;calculate ycoord mod 7
ld a,07h
ld (divsor),a
call divide ;mod is divide w/o quotient
ld a,(rmandr) ;get result
or a ;set flags
call m,woops ;rmandr= -1 on overflow
ld b,a ;move # of digit to b
ld a,00h
inc b ;increment b to init for 1st dec
if msbtop
scf ;clear accum, put 1 in carry
rotmask: rla ;move mask bit 1 left
endif ;(msbtop)
;
if not msbtop
ld a,10000000b ;set high bit and rotate it right
rotmask: rrca ;move mask bit 1 right
endif ;(not msbtop)
;
dec b ;decrement # of digit
jp nz,rotmask ;loop back
ld c,a ;store mask temporarily
ld a,(cmask) ;get color mask
and c ;and bit mask with color mask- both rqd
ld c,a ;put mask in c
pop de ;bring back ycoord
pop hl ;bring back (xyaddr)
ld b,(hl) ;get byte @ (xyaddr)
ret
;
;-----------------------------------------------------------------------
; division subroutine
; inputs:
; divdnd two byte positive number
; divsor one byte positive number
; outputs:
; qotent one byte positive quotient
; rmandr one byte positive remainder or flag
; register status:
; bc,de,hl,psw registers returned to original values
; error conditions:
; rmandr=-1 if overflow occurs
;
divide: push af ;save registers
push bc
push de
push hl
ld hl,(divdnd) ;fetch dividend
ex de,hl ;put dividend into the de pair
ld a,(divsor) ;fetch divsor
ld c,a ;save in register c
ld b,8 ;loop counter in register b
divloop: ld a,e ;shift low order byte to left
and a ;clear carry
rla ;shift
ld e,a ;replace value
ld a,d ;fetch high order byte
rla ;rotate bringing in high bit
sub c ;subtract divisor
jp p,setbit ;if result was positive, jump
add a,c ;otherwise add back divisor
ld d,a ;replace high order byte
jp next ;go to increment phase
setbit: ld d,a ;replace high order byte
ld a,e ;fetch low order byte
or 1 ;set low order bit
ld e,a ;replace low order byte
next: dec b ;decrement loop counter
jp nz,divloop ;repeat until done
ld a,e ;quotient
and a ;test sign of result
jp p,ok ;if positive result is accurate
ld a,0ffh ;set overflow value
ld (rmandr),a
jp done
ok: ld (qotent),a ;save quotient
ld a,d ;remainder
ld (rmandr),a ;save remainder
done: pop hl
pop de
pop bc
pop af
ret
;
;-----------------------------------------------------------------------
;
; this subroutine plots the vertical line used to fill in areas
;
; inputs:
; xpos,ypos current position on segment
; yfill horizontal level to fill to
; outputs:
; vertical line drom (xpos,ypos) to (xpos,yfill)
; register status:
; all register values destroyed
; error conditions:
; none peculiar to this routine.
; note: all coordinate values assumed to be positive
;
filine: call stat ;update status message
ld hl,(xpos) ;get starting coordinates of line
ld (xdot),hl ;xpos will be x coord of all dots
ld hl,(ypos) ;get y coordinate
push hl ;save y position- plotdot will reset it
ex de,hl ;put y coordinate in [de]
ld hl,(yfill) ;get y fill value
;
ld a,d ;compare y coordinates for top and bot.
cp h ;compare high bytes
jp c,yfxch ;carry indicates that yfill is > ypos
jp nz,contfil ;yfill definitely less than ypos
ld a,e ;high bytes equal- compare low bytes
cp l ;is yfill above or below ypos?
jp nc,contfil ;yfill is not above ypos- continue
yfxch: ex de,hl ;switch ypos and yfill- larger val in de
contfil: ld (ydot),hl;pass y coordinate to plotdot
push de ;save registers
push hl
call plotdot ;plot point
pop hl ;retrieve registers
pop de
inc hl ;increment y position
;
ld a,d ;check to see if line is done
cp h ;compare high bytes
jp c,donefil ;carry indicates that new y is above end
jp nz,contfil ;new coordinate definitely below end
ld a,e ;high bytes equal- compare low bytes
cp l ;is it there yet?
jp c,donefil ;carry indicates that new y is above end
jp contfil ;loop back and do next point
donefil: pop hl ;retrieve line y position
ld (ypos),hl ;restore value
ret ;all finished!
;
;-----------------------------------------------------------------------
;
; this subroutine will fill an area between a line segment and
; a horizontal line
;
; inputs:
; buffer containing coordinate pairs and y coordinate of
; fill level. all five are real values
; outputs:
; xpos,ypos updated to end of line segment
; area between segment and yfill is filled with current
; color value
; register status:
; all registers destroyed
; error conditions:
; none peculiar to this routine
;
fill: call readxy ;get starting coordinates
ld hl,(x)
ld (xpos),hl ;update x position to start of segment
ld hl,(y)
ld (ypos),hl ;update y position to start of segment
call readxy ;get end coordinates
call byte ;get first byte of fixed pt. y fill
push af ;store first byte
call byte ;get second byte
ld b,a ;put high byte in [b]
pop af ;get low byte
ld c,a ;[bc] now contains fixed point y coord.
ld de,maxy*2 ;pass maximum raster address
call mult ;multiply y coord by no. of y rasters
ex de,hl ;put high bytes in [hl]
ld (yfill),hl ;save integer value of y fill level
;
call seginit ;initialize variables for seg. interp.
call filine ;fill area between first pt. & yfill
strtfil: call compseg ;compute next point in segment
ld hl,(deltax) ;top of loop- end when ni>dx
ex de,hl ;deltax is now in (de)
ld hl,(ni) ;get counter
ld a,d ;compare counter w/dx hi byte first
cp h ;compare hi bytes
ret c ;carry indicates ni hi byte>dx hi byte
jp nz,chkfil ;continue if ni definitely < dx
ld a,e ;high bytes equal- look @ low byte
cp l ;now low byte
ret c ;ni low byte>dx low byte- done w/segment
chkfil: ld hl,(xdot) ;compare xdot and xpos
ex de,hl
ld hl,(xpos) ;xpos=xdot=> this will duplicate fill
ld a,d
cp h ;are high bytes the same?
jp nz,loopfil ;go on if high bytes are not equal
ld a,e ;high bytes equal- look at low bytes
cp l ;are the two exactly the same?
jp z,strtfil ;yes- skip this position
loopfil: call filine ;fill area between segment & yfill
jp strtfil ;loop back to top
;
;-----------------------------------------------------------------------
;
; this subroutine will send a string of characters to the printer
;
; inputs:
; number-1 of characters to send in [de]
; address-1 of first character in [hl]
; outputs:
; 0 through [de] characters sent to printer
; register status:
; all registers destroyed
; error conditions:
; none detected by this routine
;
gboloop: nop
if oki
push de
push hl
ld c,05h ;send etx to start into graphic mode
ld e,03h
call pdos
pop hl
pop de
endif ;(oki)
;
kirklop: dec de ;decrement counter
inc hl ;increment address
push de ;save counter
push hl
ld e,(hl) ;get character
;
if oki ;if graphic byte is <etx>, a second
;<etx> is required for the oki printer
ld a,e
cp 03h ;is byte <etx>?
jp nz,gbolp1
push de ;save byte
ld c,05h ;select cp/m list function
call pdos
ld e,03h ;replace <etx> character sent
pop de ;save byte
endif ;(oki)
;
gbolp1: ld c,05 ;select cp/m list output function
call pdos ;send character out
pop hl ;retrieve address
pop de ;retrieve counter
ld a,e ;is counter =0?
or d ;test counter
jp nz,kirklop ;not done: loop back
if oki ;send etx-so to cancel graphics mode
push de ;save counter
push hl ;save address
ld c,05h
ld e,03h
call pdos
ld c,05h
ld e,02h
call pdos
pop hl ;retrieve address
pop de ;retrieve counter
endif ;(oki)
;
ret
;
;-----------------------------------------------------------------------
; this routine saves a byte from bit map in graphic buffer
;
; inputs:
; byte in (b)
; 2 byte counter @ ngraph
;
; outputs:
; ngraph incremented
; byte stored in buffer @ gbuff
; buffer flushed if full
;
; register status:
; all registers preserved
;
; error conditions:
; none
;
gbufin: push af ;save registers
push bc
push de
push hl
;
ld hl,(ngraph) ;get no. of bytes in buffer
inc hl ;increment ngraph
ld (ngraph),hl ;store new value
ex de,hl ;put ngraph in [de]
;
ld hl,gbuff-1 ;get buffer base address
add hl,de ;add counter to base address
ld (hl),b ;store byte
;
;
ex de,hl ;put ngraph in [hl]
ld de,0-(maxx+1) ;put -max no. of bytes in [de]
add hl,de ;[hl]=ngraph-(max no. of bytes)
ld a,h ;if [hl]=0 then buffer is full
or l ;set flags
call z,gbufout
;buffer is full- flush it to printer
;
pop hl ;restore registers
pop de
pop bc
pop af
ret
;
;-----------------------------------------------------------------------
; this subroutine flushes the graphic buffer
;
; inputs:
; graphic buffer @ gbuff
; number of valid bytes in buffer @ ngraph
; "esc k" sequence stored ahead of ngraph
;
; outputs:
; printer is placed in dot graphic mode
; graphic string transmitted byte by byte to printer
;
; register status:
; all registers preserved
;
; error conditions:
; none
;
gbufout: push af ;save registers
push bc
push de
push hl
;
gbotop: ld hl,(ngraph) ;fetch buffer counter
ex de,hl ;put buffer counter in [de]
ld a,e ;look at low byte
or d ;is counter=0?
jp z,gbufret ;if buffer is empty, don't o/p anything
;
; skip totally blank lines
;
ld bc,maxx+1 ;get length of buffer
ld a,b ;compare high bytes first
cp d
jp nz,gbo2 ;no match indicates something on this line
ld a,c ;compare low bytes next
cp e
jp nz,gbo2 ;no match indicates something on this line
;
ld hl,gbuff ;set pointer to start of buffer
gbo1: ld a,(hl) ;get byte from buffer
or a ;is it a blank stroke?
jp nz,gbo2 ;go to output section if not blank
inc hl ;point to new byte
dec bc ;decrement counter
ld a,b ;check for zero
or c
jp nz,gbo1 ;repeat until last byte has been checked
;
jp gbufret ;return w/o plotting since all were blank
;
gbo2: nop ;head of output section
;
if no8bit
ld a,e ;look at low byte of counter
or a ;set flags- is high bit set?
jp p,gbo7 ;low byte has 7 bits-o/p whole thing.
;
; the parallel interface will only transmit 7 bits. the low byte
; of the buffer counter has its high bit set, therefore, the
; buffer must be output in smaller chunks
;
push de ;save ngraph on stack
endif ;(no8bit)
if epson and no8bit
ld de,126+4 ;counter=>126 bytes + 4 for esck,ngraph
ld hl,126d ;set ngraph to 126
ld (ngraph),hl ;put new no. in printer sequence
ld hl,esck-1 ;start with escape sequence
endif ;(epson and no8bit)
;
if citoh and no8bit
ld de,126+6 ;counter=>126 bytes + 6 for esc s n3210
ld hl,esck+3 ;address of n1 byte
ld bc,126d ;set no. of bytes
ld (hl),b ;store high byte in n1
inc hl ;address of n0
ld (hl),c ;store low byte in n0
ld hl,esck-1 ;start with escape sequence
endif ;(citoh and no8bit)
;
if no8bit
call gboloop ;send out first 126 characters
;
; move characters in buffer up to replace those sent out
;
pop hl ;retrieve old value of ngraph
ld de,0ff82h ;[de]=-126d
add hl,de ;[hl]now=ngraph-126
ld (ngraph),hl ;store new value
ex de,hl ;put ngraph in [de] to act as counter
ld hl,gbuff-1 ;get base address of buffer
push hl ;save pointer for saving data
ld bc,007eh ;put 126d in [bc]
add hl,bc ;[hl] now points to new bytes
;
gbomov: inc hl ;incrment new data pointer
ld a,(hl) ;get byte from buffer
ex (sp),hl ;exchange pointers
inc hl ;increment save data pointer
ld (hl),a ;move byte up in buffer
ex (sp),hl ;exchange pointers back again
dec de ;decrement counter
ld a,e ;check to see if loop is done
or d ;is [de]=0?
jp nz,gbomov ;loop back up if not done
pop hl ;retrieve pointer to clean up stack
;
; ngraph has now been updated and data in buffer has been moved
; to replace that which has been sent out. now ready to try all
; over again with new segment of data in buffer.
;
jp gbotop
endif ;(no8bit)
;
if epson
gbo7: inc de
inc de
inc de
inc de
ld hl,esck-1 ;start with escape sequence
endif ;(epson)
;
if citoh
gbo7: ld hl,esck+2 ;address of n3 byte for graphics select
ld a,30h ;initialize number of byes to "0000"
ld (hl),a ;"0"
inc hl
ld (hl),a ;"00"
inc hl
ld (hl),a ;"000"
inc hl
ld (hl),a ;"0000"
;
call bindec ;convert n to ascii decimal and store
;
inc de ;increment counter for esc s n3-n0
inc de
inc de
inc de
inc de
inc de
ld hl,esck-1 ;start with escape sequence
endif ;(citoh)
;
if oki
gbo7: ld hl,gbuff-1
endif ;(oki)
;
call gboloop ;send out string of graphic characters
;
gbufret: ld a,00h ;clear accumulator
ld (ngraph),a ;set ngraph=0
ld (ngraph+1),a
pop hl ;restore registers
pop de
pop bc
pop af
ret
;
;-----------------------------------------------------------------------
; this subroutine plots an incremental line segment from the
; present position
; inputs:
; file buffer @ dma
; present position @ xpos,ypos
; outputs:
; xpos, ypos updated to x,y
; visible portion of line segment drawn
; register status:
; all register values destroyed
; error conditions:
; none peculiar to this routine
;
incplt: call readxy ;get end point values
call seginit ;initialize segment interpolation sub.
;
strtplt: ld hl,(deltax);top of loop- end when ni>dx
ex de,hl ;deltax is now in (de)
ld hl,(ni) ;get counter
ld a,d ;compare counter w/dx hi byte first
cp h ;compare hi bytes
ret c ;carry indicates ni hi byte>dx hi byte
jp nz,contplt ;continue if ni definitely < dx
ld a,e ;high bytes equal- look @ low byte
cp l ;now low byte
ret c ;ni low byte>dx low byte- done w/segment
contplt: call compseg ;compute xpos and ypos at next point
ld hl,(xpos) ;fetch x position
ld (xdot),hl ;pass in xdot
ld hl,(ypos) ;fetch y position
ld (ydot),hl ;pass in ydot
call plotdot ;plot it (finally)
jp strtplt ;bounce up to the top of the loop
;
;-----------------------------------------------------------------------
; line spacing subroutine
;
; inputs:
; none
; outputs:
; form feed sent
; esc a 7 sent to set the printer to 7/72" line spacing
; register status:
; all values changed
; error conditions:
; none
;
if epson
ln772: ld c,05h ;select list output
; mvi e,0ch ;pass formfeed
; call pdos ;send it out
;
; mvi c,05h ;select list output
ld e,1bh ;pass esc character
call pdos ;send it out
;
ld c,05h ;select list output
ld e,'a' ;pass "a"
call pdos ;send it out
;
ld c,05h ;select list output
ld e,07h ;pass 7 for 7/72"
call pdos
;
ret
endif ;(epson)
;
if citoh
ln772: ld c,05h ;select list output
; mvi e,0ch ;pass formfeed
; call pdos ;send it out
;
; mvi c,05h ;select list output
ld e,1bh ;pass esc character
call pdos ;send it out
;
ld c,05h ;select list output
ld e,'>' ;esc > sets unidirectional printing
call pdos ;send it out
;
ld c,05h ;select list output
ld e,1bh ;pass esc character
call pdos ;send it out
;
ld c,05h ;select list output
ld e,'t' ;pass "t"
call pdos ;send it out
;
ld c,05h
ld e,'1'
call pdos ;send out 1 as high byte
;
ld c,05h ;select list output
ld e,'4' ;pass 14 for 14/144"
call pdos
;
ret
endif ;(citoh)
;
if oki
ln772: ld c,05h
ld e,18h ;clear printer
call pdos
ld c,05h
ld e,1ch ;set 12 cpi
call pdos
ld c,05h
ld e,1bh ;esc % "9" 14 to set line spacing
call pdos
ld c,05h
ld e,25h
call pdos
ld c,05h
ld e,39h
call pdos
ld c,05h
ld e,14d ;14/144 "/line
call pdos
ret
endif ;(oki)
;
;-----------------------------------------------------------------------
; this subroutine calculates the address for an xy coordinate pair
; xyaddr= origin + xcoord + (maxy-ycoord)/7 * (maxx+1)
; inputs:
; xcoordinate in registers bc
; ycoordinate in registers de
; maximum y raster count in hl
; outputs:
; xcoordinate in registers bc
; ycoordinate in registers de
; address of x,y coordinates in hl
; address stored @ xyaddr
; register status:
; psw values changed
; error conditions:
; overflow of arithmetic calls woops
;
locdot: push de ;store y coord on stack
push bc ;store x coord on stack
ld a,l
sub e ;subtract ycoord from maxy
ld l,a
ld a,h
sbc a,d
ld h,a ;[hl] now contains (maxy - y)
ld (divdnd),hl ;pass (maxy - y) to division routine
ld a,07h ;pass 7 to division routine
ld (divsor),a
call divide ;(maxy - y)/7
ld a,(rmandr) ;rmandr is negative if overflow
or a ;set flags
call m,woops ;overflow in division
ld a,(qotent) ;get result of division
ld bc,maxx+1 ;[bc] now contains the max. no. of x's
call bmult ;[hl] has low order bytes, [a] the high
; [hl] now contains (max-ycoord)/7*(max+1)
pop bc ;put xcoord in [bc]
add hl,bc ;add to x previous term
ld de,origin ;last term
add hl,de ;final sum is in [hl]
ld (xyaddr),hl ;store result
pop de ;retrieve y coordinate
ret
;
;-----------------------------------------------------------------------
; output routine
;
; inputs:
; memory map starting @ origin
;
; outputs:
; map is dumped to printer 1 byte at a time
; mixed graphics and text are output
;
; register status:
; all values destroyed
;
; error conditions:
; none. printer will hang if it doesn't get proper input
;
mapout:
ld a,00h ;reset status counter
ld (statno),a
ld c,09h ;print printing status message
ld de,stat3
call fdos
;
if screen
call _setup
ld hl,margin
ld (xcoord),hl
ld hl,0
ld (ycoord),hl
else
call ln772 ;set printer to 7/72" line spacing
endif
ld hl,origin ;initialize start address
ld a,00h ;clear accumulator
ld (ngraph),a ;initialize graphics counter
ld (ngraph+1),a
ld c,(maxy+1)/7 ;initialize line counter
linloop:
ld de,maxx+1 ;initialize dot counter
;
bytloop:
ld b,(hl) ;get byte
ld a,b ;put byte in (a)
or a ;set flags - is it a graphic byte?
if screen
call m,scharout ;no- hi bit set therefore character
call p,screenplot ;yes- plot it on screen
else
call m,charout ;no- hi bit set therefore character
call p,gbufin ;yes- save it in graphic buffer
endif
;
inc hl ;increment address to next x location
dec de ;decrement dot counter
ld a,d
or e ;is dot counter = 0?
jp nz,bytloop ;no- so loop to top again
;
if screen
call eoline ;set x,y for next line
else
call gbufout ;at end of line- flush buffer
call crlf ;send a line feed to printer
endif
dec c ;decrement line counter
ld a,c ;get ready to test line counter
or a ;set flags on line counter
jp nz,linloop ;not done- repeat outer loop
;
if screen
call sreset ;reset screen to normal mode
else
call preset ;reset printer to normal mode
endif
;
ret ;last line finished
if screen
scharout: ;char output to screen
push af
push bc
push de
push hl
ld hl,(xcoord)
push hl
ld bc,cwidth
add hl,bc
ld (xcoord),hl
pop hl
ld de,(ycoord)
call SetChar
pop hl
pop de
ld a,cwidth-1
scharo1:
inc hl ;increment address
dec de ;decrement dot counter
sub 1 ;decrement loop counter
jp nz,scharo1
pop bc
pop af
ret
screenplot:
push af
push bc
push hl
push de
ld hl,(xcoord)
inc hl
ld (xcoord),hl
dec hl
ld de,(ycoord)
bit 6,a
call nz,Set
inc de
bit 5,a
call nz,Set
inc de
bit 4,a
call nz,Set
inc de
bit 3,a
call nz,Set
inc de
bit 2,a
call nz,Set
inc de
bit 1,a
call nz,Set
inc de
bit 0,a
call nz,Set
pop de
pop hl
pop bc
pop af
ret
eoline:
push hl
push bc
ld hl,margin
ld (xcoord),hl
ld hl,(ycoord)
ld bc,7
add hl,bc
ld (ycoord),hl
pop bc
pop hl
ret
sreset:
call _gstring
call _reset
ret
;
grf_illegal_pos equ 1 ; Printing ftext off byte boundary.
grf_out_range_x equ 2 ; X out of range.
grf_out_range_y equ 3 ; Y out of range.
vml equ 1ch
fix_y macro ;; This macro calculate Y = 255 - Y to put
ld a,e ;; the origin at the top left instead of the
cpl ;; the bottom left.
ld e,a
endm
;;
;; This macro does 16-bit negation on a register pair. The algorithim is
;; -rr = ~rr + 1. Rr is a register pair.
;; r1 = high reg, r2 = low reg, r3 = 16 bit reg.
;;
neg16 macro r1,r2,r3
ld a,r1 ;; Complement high byte.
cpl
ld r1,a
ld a,r2 ;; Complement low byte.
cpl
ld r2,a
inc r3 ;; And add one.
endm
;+
; SET: Sets the point (HL,DE) on the screen. SET adjusts the y value
; to make the origin at the top left corner.
;-
Set: push af
push bc
push de
push hl
call HSeth
pop hl
pop de
pop bc
pop af
ret
_h_set_point:
_h_setpnt:
call ld_xy ; get x and y from stack
HSet: fix_y ; Adjust origin and...
HSeth:
call HGoToxyh ; Move current point.
jp c,error ; Return if off screen.
call bytmsk ; Get byte and mask
or (hl) ; Set point.
ld (hl),a ; and put it back.
jp return ;
return: ;ld hl,0 ; 0 = OK
ret
error: ;ld hl,77 ; not 0 = error
ret
attrib equ 144 ; Value to switch in Attribute RAM.
bank0 equ 128 ; Value to switch in Bank 0 of the PCG.
screenloc equ 0f000h ; Start of screen.
pcg equ 0f800h ; Start of PCG.
;+
; BYTMSK: Finds the PCG bank, char, byte and bit required to manipulate the
; bit (HL,DE) on the hires screen. The origin is assumed to be at the top left.
; Returns with the needed bank switched in, HL containing the address of the
; byte the bit is in, and A containing a mask to access the bit. The mask is
; defined so that the OR (HL) instruction sets the bit.
;-
bytmsk: push bc ; Save temp register.
ld a,7 ; Do a divide by 8 by masking required bits.
and l ; Mask out the remainder.
ld c,a ; c = x mod 8.
add hl,hl ; Shift X so next bit in right place.
ld a,01110000B ; Keep only the needed bits.
and l ; Get them.
ld b,a ; b = ((x mod 64) div 8) * 16
add hl,hl ; Put X div 64 in H.
ld a,7 ; Specs say use mod 512, so only need bottom 3
and h ; bits.
add a,128 ; Add bit 7 for VML.
out (vml),a ; Get bank L.
ld a,e ; D = 0 since 0 <= y <= 255.
and 0fh ; Get modulos.
ld d,a ; Store y mod 16.
ld a,e ;
and 0f0h ; A = (y div 16) * 16.
rrca ;
rrca ;
rrca ;
rrca ;
ld e,c ; Move X mod 8 as BC is needed.
add a,b ; a = pcg char = ((x mod 64) div 8) + y div 16.
ld l,a ;
ld h,0 ;
add hl,hl ; * 2.
add hl,hl ; * 4.
add hl,hl ; * 8.
add hl,hl ; * 16. HL = Offset into pcg data.
ld bc,pcg ;
add hl,bc ; HL = Start address of char data.
ld c,d ; Get offset into char's data.
ld b,0 ;
add hl,bc ; HL = address of byte to be changed.
push hl ;
ld hl,bits ; Start of mask table.
ld c,e ; Get offset into mask. Is 16 bits since b = 0
add hl,bc ; still.
ld a,(hl) ; Get the mask.
pop hl ; Restore the address.
pop bc ; Restore temp register.
ret ; and that's all!
bits: defb 80h,40h,20h,10h,08h,04h,02h,01h
;-
curr_x: defs 2 ; X position of the graphics cursor.
curr_y: defs 2 ; Y position of the graphics cursor.
;+
; GOXY, GOXYH: The moves the graphics cursor to (HL,DE).
; An error occurs if this point is off the screen.
;-
_h_go_to_xy:
_h_gotoxy:
call ld_xy ; get x and y from stack
call HGoToxy ;
ret ;
HGoToxy:fix_y ; Adjust the Y value.
HGoToxyh:call rcheck ; Make sure that the points are valid.
jp c,error ; Return if not.
ld (curr_x),hl ; Store X.
ld (curr_y),de ; Store Y.
ret ;
;-
rcheck: or a ; Clear Carry.
push af ; Save A.
ld a,h ;
and 0feh ; See if any of bits 9 - 15 are set.
jr z,x_ok ; Branch if not.
pop af ;
scf ;
ld a,grf_out_range_x ; Describe error.
; jr exit ; Jump to exit.
ret ;exit would pop af again
x_ok: ld a,d ; See if bits 8-15 are set
or a ;
jr z,exit ; Branch if in range.
pop af ;
scf ;
ld a,grf_out_range_y ; Describe error.
ret ;dont fall through
exit: pop af ;
ret ; Return.
;+
; CMP16: Compares two 16-bit signed or unsigned wrds and returns the C, Z,
; and S flags accordingly. Inputs: HL = Minuend, DE = subtrahend. Is
; effectivly HL - DE.
;-
cmp16: or a ; Clear Carry.
sbc hl,de ; Subtract subtrahend from minuend.
ret po ; Return if no overflow.
ld a,h ; Overflow - Invert sign flag.
rra ; Save carry in bit 7.
xor 01000000B; Complement bit 6 (Sign bit).
scf ; Restore carry, complement sign.
adc a,a ; Z = 0 for sure.
ret ;
;+
; ld_xy get x and y from the stack on entry to subroutine.
; note that arguments are popped in the same order as
; in the call. HI-TECH C pushes them in reverse order.
;-
ld_xy: pop af ; return address
pop bc ; return address
pop hl ; x
pop de ; y
push de ;
push hl ;
push bc ; restore stack
push af ;
ret ;
;
grf_illegal_pos equ 1 ; Printing ftext off byte boundary.
grf_out_range_x equ 2 ; X out of range.
grf_out_range_y equ 3 ; Y out of range.
vml equ 1ch
fix_y macro ;; This macro calculate Y = 255 - Y to put
ld a,e ;; the origin at the top left instead of the
cpl ;; the bottom left.
ld e,a
endm
;;
;; This macro does 16-bit negation on a register pair. The algorithim is
;; -rr = ~rr + 1. Rr is a register pair.
;; r1 = high reg, r2 = low reg, r3 = 16 bit reg.
;;
neg16 macro r1,r2,r3
ld a,r1 ;; Complement high byte.
cpl
ld r1,a
ld a,r2 ;; Complement low byte.
cpl
ld r2,a
inc r3 ;; And add one.
endm
;screen equ 0f000h ; Character rom overlays screen area.
romff equ 0bh ; Port of ROM read latch.
char_height equ 16 ; Height of character definition.
HSetChar:
push af ; Save character.
fix_y ; Adjust Origin.
pop af ; Get character back.
SetChar:
call fchar1 ; get addresses
fits1s: ld a,(de) ; get byte
or (hl) ; include other bits
ld (hl),a ; replace
inc de ;
inc hl ;
dec c ; count
jr nz,fits1s ;
xor a ;
out (romff),a ; Restore screen (also clears Carry).
ret ; THE END.
;+
; common subroutine.
;-
fchar1: call HGoToxyh ; See if point is on screen.
ret c ; Return if not.
and 07fh ; Remove high bit.
push af ; Save characper.
ld a,l ; Get most of X value.
and 0f8h ; Make sure it is a multiple of 8.
ld l,a ;
ld bc,char_height ; Assume
ld a,e ; Get Y value.
cp 256-char_height ; See if all of character will fit on screen.
jr c,fits ; Branch if character will fit.
neg ; Get total number of rows that can be placed.
ld c,a ; Put it in count.
fits: call bytmsk ; Switch in bank and get start location.
ld a,1 ;
out (romff),a ; Switch in character ROM.
pop af ; Get character.
push hl ; Save destination.
ld l,a ; Make 16-bit value.
ld h,0 ;
add hl,hl ; * 2.
add hl,hl ; * 4.
add hl,hl ; * 8.
add hl,hl ; * 16. HL = Offset into character ROM.
ld de,screenloc ; Start of ROM.
add hl,de ; HL = Source of char data.
pop de ; DE = Destination
ex de,hl ; DE = Source, HL = destination
ret ;
start_x:defw 0 ; x at start of text
start_y:defw 0 ; y at start of text
count: defw 0 ; maximum no of chars
chpointer:defw 0 ; char pointer
CR equ 0dh ;
DEL equ 07fh ;
BDOS equ 5 ;
BELL equ 7 ; beep
BS equ 8 ; back space
_get_string:
_gstring:
ex af,af' ;
pop af ; return address
ex af,af' ; save it
pop af ; x
pop de ; y
pop bc ; string length
pop hl ; string pointer
push hl ;
push bc ;
push de ;
push af ;
ex af,af' ; reurn address
push af ; restore stack
ex af,af' ; x
ld (chpointer),hl ;
push af ;
pop hl ; hl = x, de = y, bc = length
ld a,l ;
and 0f0h ;
ld l,a ; fix x
ld a,e ;
and 0f8h ;
ld e,a ; fix y
ld (start_x),hl ;
ld (start_y),de ;
dec bc ;
ld (count),bc ;
call curson ; turn cursor on
call setcur ; set cursor
cloop: push hl ; save
push de ;
push bc ;
call setcur ; set cursor
rloop: ld e,0ffh ; input
ld c,06h ; direct i/o
call BDOS ; any char typed ?
or a ; set flags
jr z,rloop ; no
pop bc ;
pop de ;
pop hl ; restore
cp DEL ; Delete key ?
jr z,dodel ; yes
cp BS ; back space ?
jr z,dodel ; yes
cp CR ; Return
jr z,docr ; yes
cp ' ' ; control char ?
jr c,cloop ; yes ignore it
;+
; Put all other characters on the screen and into the return string.
; First check if the string is full.
;-
dec c ; ckunt
jr nz,ok0 ; ok
inc c ; count = 1
push de ;
push hl ;
push bc ;
push af ;
ld e,BELL ;
ld c,6 ; direct i/o
call BDOS ;
pop af ;
pop bc ;
pop hl ;
pop de ; restore y
jp cloop ; continue
ok0: push hl ; save x
ld hl,(chpointer) ;
ld (hl),a ; put in string
inc hl ;
ld (chpointer),hl ;
pop hl ; restore x
call putit ; put char on screen.
jp cloop ; continue
;+
; Delete the last char typed.
;-
dodel: push hl ;
push de ;
ld de,(start_x) ;
or a ; clear carry
sbc hl,de ; back too far ?
jp z,nobak ; yes
ld hl,(chpointer) ;
dec hl ; move back to last char
ld a,(hl) ; get character
ld (chpointer),hl ;
pop de ; y
pop hl ; x
push de ; y
ld de,-8 ; mova x back
add hl,de ;
pop de ; y
call putit ; remove from screen
push de ; y
ld de,-8 ; move x back
add hl,de ;
pop de ;
inc c ; fix count
jp cloop ; next char
nobak: pop de ; y
pop hl ; x
jp cloop
;+
; CR = end of input.
;-
docr: ld a,0 ;
ld hl,(chpointer) ;
ld (hl),a ;
call cursof ; turn cursor off
ret ;
putit: push de ;
push hl ;
push bc ;
push af ;
; call HInvertChar ; put character on screen
pop af ;
pop bc ;
pop hl ;
ld de,8 ; 8 points per char
add hl,de ; move x to right
pop de ; restore y
ret ;
;+
; Turn Cursor on.
;-
curson: push af ;
ld a,10 ; cursor sart/blink
out (12),a ; select register
ld a,00h ; no flash line 0
out (13),a ; set cursor start
ld a,11 ; cursor end
out (12),a ; select register
ld a,0fh ; line 15
out (13),a ;
pop af ;
ret
;+
; Turn Cursor off.
;-
cursof: push af ;
ld a,10 ; cursor sart/blink
out (12),a ; select registev
ld a,02fh ; no cursor
out (13),a ; set cursor start
ld a,11 ; cursor end
out (12),a ; select register
ld a,0fh ; line 15
out (13),a ;
pop af ;
ret
;+
; Set cursor position.
; HL = x, DE = y.
;-
setcur: push af ;
push bc ;
ld (xt),hl ;
ld (yt),de ;
ld l,e ;
ld h,d ; hl = y
ld a,l ;
cpl ; correct y
inc a ;
ld l,a ;
add hl,hl ; * 2
add hl,hl ; * 4
ld de,(xt) ; x
sra d ;
rr e ; / 2
sra d ;
rr e ; / 4
sra d ;
rr e ; / 8
add hl,de ; 64 * y + x
ld a,14 ; curs pos HI
out (12),a ; select register
ld c,13 ; data port
out (c),h ;
inc a ; curs pos LO
out (12),a ; select register
out (c),l ;
ld hl,(xt) ; restore x
ld de,(yt) ; restore y
pop bc ;
pop af ;
ret ;
xt: defw 0 ; x
yt: defw 0 ; y
vml equ 01ch ; Video memory latch port.
bdos equ 5 ; BDOS entry point.
attrib equ 144 ; Value to switch in Attribute RAM.
bank0 equ 128 ; Value to switch in Bank 0 of the PCG.
;screen equ 0f000h ; Start of screen.
pcg equ 0f800h ; Start of PCG.
_setup: push af
push bc
push de
ld hl,d6545 ; Load data for 64*16 mode.
ld b,16 ; Amount of data.
lp6545: ld a,b ;
dec a ;
out (0ch),a ; Tell which register.
ld a,(hl) ;
out (0dh),a ; Put data in it.
dec hl ;
djnz lp6545 ; Next.
;+
; Clear the rest of the 80*24 screen.
;-
ld hl,screenloc+1024 ; Start of second bank.
ld de,screenloc+1025 ;
ld bc,1023 ;
ld (hl),' ' ; Clear first char.
ldir ; then the rest.
;+
; Now clear all the bank of pcg.
;-
ld a,bank0 ; Start bank.
ld b,8 ; No. of banks.
clr: push bc
out (vml),a ; Get bank.
ld hl,pcg ; Start of bank.
ld de,pcg+1 ;
ld bc,2047 ; Size of bank - 1.
ld (hl),0 ; Clear first byte.
ldir ; Clear the rest.
pop bc ;
inc a ; Next bank.
djnz clr ;
;+
; Now set up attribute RAM in the save manner as in Basic.
; Registers are used as counters since the DEC r; JR NZ combination
; is faster than a PUSH BC; ...; POP BC; DJNZ version.
;-
ld a,attrib ; Switch in Attribute RAM.
out (vml),a ;
ld d,16 ; No. of lines.
ld hl,screenloc ;
fill1: xor a ; Initial Bank = 0.
ld c,8 ; No. of banks along a screen line.
fill2: ld b,8 ; No. of chars per bank per line.
fill3: ld (hl),a ; Put bank in the Attribute RAM.
inc hl ;
djnz fill3 ;
inc a ; Next bank.
dec c ;
jr nz,fill2 ;
dec d ; Next line.
jr nz,fill1 ;
ld a,bank0 ;
out (vml),a ; Put back the screen memory.
;+
; Now put PCG characters down to reflect the attribute RAM
;-
pcgs: ld hl,screenloc ; Screen again.
ld d,16 ; No of lines.
ld e,128 ; Start pcg character.
pcg1: ld c,8 ; No of banks per line.
pcg2: ld a,e ; Get start pcg char.
ld b,8 ; No of chars per bank.
pcg3: ld (hl),a ;
inc hl ;
add a,16 ; Next char.
djnz pcg3 ;
dec c ; Next Bank.
jr nz,pcg2
inc e ; Start char for next line.
dec d ;
jr nz,pcg1 ; Next line.
pop de
pop bc
pop af
ret ; That's it.
;+
; Data for Video controller for 16*64 mode.
;-
defb 107 ; Total horiz chars -1 (R0)
defb 64 ; Displayed Chars. (R1)
defb 81 ; Hor sync pos. (R2)
defb 37H ; Vert & Hor Sync wid (R3)
defb 18 ; Total Vert rows - 1 (R4)
defb 9 ; Total vert adjust (R5)
defb 16 ; Vert displayed (R6)
defb 17 ; Vert Sync Position (R7)
defb 48H ; Mode Control (R8)
defb 15 ; Scan lines per char (R9)
defb 2FH ; Cursor start & blink (R10)
defb 15 ; Cursor End (R11)
defb 00H ; Display Start HI (R12)
defb 00H ; Display Start LO (R13)
defb 00H ; Cursor pos HI (R14)
d6545: defb 00H ; Cursor pos LO (R15)
;+
; 6545 setup table for 80 * 24
;-
defb 107 ; Total horiz chars -1 (R0)
defb 80 ; Displayed Chars. (R1)
defb 87 ; Hor sync pos. (R2)
defb 37H ; Vert & Hor Sync wid (R3)
defb 27 ; Total Vert rows - 1 (R4)
defb 5 ; Total vert adjust (R5)
defb 24 ; Vert displayed (R6)
defb 25 ; Vert Sync Positimn (R7)
defb 48H ; Mode Control (R8)
defb 10 ; Scan lines per char (R9)
defb 2AH ; Cursor start & blink (R10)
defb 10 ; Cursor End (R11)
defb 20H ; Display Start HI (R12)
defb 00H ; Display Start LO (R13)
defb 00H ; Cursor pos HI (R14)
d8024: defb 00H ; Cursor pos LO (R15)
;+
; Restore normal 80 * 24 operation for C/80.
;
; First set 6545 to 80 * 25.
;-
_reset: ld hl,d8024 ; Load data for 80*24 mode.
ld b,16 ; Amount of data.
l6545: ld a,b ;
dec a ;
out (0ch),a ; Tell which register.
ld a,(hl) ;
out (0dh),a ; Put data in it.
dec hl ;
djnz l6545 ; Next.
;+
; Set attribute RAM to all zeros.
;-
ld a,attrib ; Switch in Attribute RAM.
out (vml),a ;
ld bc,2047 ; 2K RAM.
ld hl,screenloc ;
ld de,screenloc+1 ;
xor a ; zero
ld (hl),a ; first byte
ldir ; rest
;+
; Restore inverse character data in PCG bank 0
;+
ld a,bank0 ; Set PCG bank 0
out (vml),a ;
ld a,1 ;
out (0BH),a ; Set romread latch
ld hl,screenloc ; Screen and character rom
ld de,pcg ; PCG
ld b,128 ; 128 PCG characters
rest1: push bc ;
ld b,16 ; 16 bytes per pcg
rest2: ld a,(HL) ;
cpl ;
ld (de),a ;
inc hl ;
inc de ;
djnz rest2 ;
pop bc ;
djnz rest1 ;
ld a,0 ;
out (0BH),a ; Reset romread latch
ld bc,2047 ; complete screen
ld hl,screenloc ;
ld de,screenloc+1 ;
ld a,' ' ; space
ld (hl),a ; first byte
ldir ; rest
ret ; done
endif
;
;-----------------------------------------------------------------------
; this subroutine moves the present position to new coordinates
; without doing anything else
;
; inputs:
; coordinate pair in buffer
; outputs:
; xpos and ypos updated to new coordinates
; register status:
; all values destroyed
; error conditions:
; none peculiar to this routine
;
move: call readxy ;get coordinate pair
ld hl,(x) ;get x coordinate
ld (xpos),hl ;update x axis position
ld hl,(y) ;get y coordinate
ld (ypos),hl ;update y axis position
ret ;position now updated.
;
;-----------------------------------------------------------------------
;
; this subroutine multiplies two 16 bit integers
;
; this routine from electronics magazine, feb. 24, 1982.
; written by jerry l. goodrich, penn. state u.
;
;
; inputs:
; multiplicand in [bc]
; multiplier in [de]
; outputs:
; 32 bit product in [de],[hl] (most sig. bits in [de])
; register status:
; see inputs and outputs
; error conditions:
; none
;
mult: ld a,e ;load lowest order byte of multiplier
push de ;save highest order byte of multiplier
call bmult ;do 1-byte multiply
ex (sp),hl ;save lowest order bytes product, get multiplier
push af ;store highest order byte of first prod.
ld a,h ;load highest order byte of multiplier
call bmult ;do second 1-byte multiply
ld d,a ;position highest-order byte of product
pop af ;get highest order byte of first product
add a,h ;update third byte of product
ld e,a ;and put it in e
jp nc,nc1 ;dont't increment d if no carry
inc d ;increment d if carry
nc1: ld h,l ;relocate lowest order bytes of 2nd prod
ld l,0
pop bc ;get lowest order 2 bytes of first prod.
add hl,bc ;get final product lowest order 2 bytes
ret nc ;done if no carry
inc de ;otherwise update highest order 2 bytes
ret
;
;-----------------------------------------------------------------------
; print or disk o/p subroutine
;
; inputs:
; 05h in (c)
; character in (e)
; buffer pointer set to last character (pointr2)
; o/p flag in opdisk
; outputs:
; character printed if o/p flag set
; character written to disk if flag is set
; register status:
; all register values destroyed
; error conditions:
; none in this routine.
;
pdos: ld a,(opdisk) ;get disk o/p flag
cp 00h ;is flag set?
push af ;save flag
call z,fdos ;print character if it is
pop af ;retrieve flags
ret z ;return if character was printed
;
ld a,(pointr2) ;get buffer pointer
inc a ;increment pointer for new char.
ld (pointr2),a ;save new value
ld c,a ;save pointer value in (c)
ld b,0 ;clear high byte of (bc)
ld hl,dma2-1 ;get last addr. before dma2
add hl,bc ;calculate address of byte
ld (hl),e ;put character in buffer
cp 128d ;is buffer full?
call z,write ;write it out if it is.
ret ;done
;
;-----------------------------------------------------------------------
; this subroutine plots a point @ xdot,ydot
; method:
; find byte containing xdot,ydot
; form mask eg: if xdot,ydot is in #4 bit,
; mask = 00010000
; digit= 76543210
; modify byte according to color & store it back
; inputs:
; 2 byte x location stored @ xdot
; 2 byte y location stored @ ydot
; outputs:
; xpos, ypos reset to values given in xdot, ydot
; appropriate dot turned on or off in memory map
; register status:
; all register values destroyed
; error conditions:
; if xdot or ydot are outside of window, no point plotted
; xpos and ypos will still point outside window
;
plotdot: ld hl,(xdot);get x position
ld (xpos),hl ;update current position
ld b,h ;moving xdot to bc
ld c,l ;xdot now in bc
ld hl,(ydot) ;get y position
ld (ypos),hl ;update current position
ld d,h ;moving ydot to de
ld e,l ;ydot now in de
;xpos and ypos now contain last pos. attempted- may not be in window
ld hl,maxx ;put limits of x in hl
xcheck: ld a,b ;check for neg x-sign in hi byte
or a ;is xdot negative?
ret m ;xdot neg- return w/o plotting
ld a,h ;work with high byte first
cp b ;compare max & x high bytes
ret c ;x>max- therefore return
jp nz,ycheck ;x is ok- check y
ld a,l ;high bytes are= look @ low byte
cp c ;compare x & max low bytes
ret c ;x>max- return w/o plotting
ycheck: ld hl,maxy ;put limit of y in hl
ld a,d ;ydot hi byte contains sign
or a ;is ydot negative?
ret m ;ydot neg- return w/o plotting
ld a,h ;high bytes first
cp d ;compare max & y high bytes
ret c ;y>max- return w/o plotting
jp nz,xyok ;y is ok- plot dot
ld a,l ;high bytes= look @ low bytes
cp e ;compare low bytes
ret c ;y is > max- return w/o plotting
xyok: call locdot ;get address of byte for x,ydot
call digit ;form mask for plotting
ld a,b ;determine if byte is graphic
or a ;graphic?
ret m ;minus= character: return w/o plotting
ld a,(color) ;get color value
or a ;set flags
jp z,white ;0 = white
jp m,compl ;-1 = complementary color
ld a,b ;color is black
or c ;modify byte by turning bit on
ld (hl),a ;store back in memory
ret ;done- ( at last)
;
white: ld a,b ;work w/ byte containing x,y
cpl ;complement byte
or c ;modify byte by turning on bit
cpl ;complement byte back- bit 0ff
ld (hl),a ;store byte back in memory
ret ;done- (finaly)
;
compl: ld a,b ;work w/ byte containing x,y
xor c ;complement bit
ld (hl),a ;store it
ret ;done-
;
;-----------------------------------------------------------------------
; plot point routine
;
; inputs:
; buffer @ dma
; outputs:
; point plotted in memory
; register status:
; all values changed
; error conditions:
; none
;
point: call readxy ;read coordinates for point
ld hl,(x) ;fetch x location
ld (xdot),hl ;pass x to dot routine
ld hl,(y) ;fetch y location
ld (ydot),hl ;psss y to dot routine
call plotdot
ret
;
;-----------------------------------------------------------------------
; quit
; closes output file, terminates program
; inputs:
; fcb for output file @ fcb2
; disk output flag @ opdisk
; outputs:
; remainder of record set to 0, disk closed.
; register status:
; all values destroyed
; error conditions:
; none
;
quit: ld a,(opdisk) ;get disk output flag
cp 00h ;is it set?
jp z,boot ;no, so all done
;
ld a,(pointr2) ;look @ o/p pointer
cp 0 ;is o/p buffer empty?
jp z,boot ;yes- done
;
; fill remainder of o/p buffer with nulls
;
ld e,a ;save pointer value in (e)
ld d,00h ;clear high byte of (de)
ld a,128 ;set max value of pointer
sub e ;(a)= 128- pointr2
ld c,a ;(c) now is count of extra buff.
;
clrbuf: push bc ;save counter
ld e,00h ;pass a <null>
call pdos ;put it in buffer
pop bc ;retrieve counter
dec c ;counter=counter-1
jp nz,clrbuf ;loop back until buffer is full
;
ld c,10h ;select close file function
ld de,fcb2 ;pass o/p fcb
call fdos ;close file
;
jp boot ;do warm boot on exit
;
;-----------------------------------------------------------------------
; line segment routine
; inputs: file buffer @ dma
;
; outputs:
; xpos, ypos updated to x2,y2
; visible portion of line segment plotted
;
; registers:
; all registers values destroyed
; error conditions:
; no checks made in this routine
;
plotseg: call readxy ;get starting coordinates
ld hl,(x) ;fetch starting x
ld (xdot),hl ;pass to dot routine
ld hl,(y) ;fetch starting y
ld (ydot),hl ;pass to dot routine
call plotdot ;plot starting point
call incplt ;plot rest of segment
ret ;return to main program
;
;-----------------------------------------------------------------------
;
; this subroutine resets the printer to its normal mode
;
; inputs:
; none
; outputs:
; none returned
; register status:
; all registers changed
; error conditions:
; none
;
if epson
preset: ld c,05h
ld e,1bh ;pass esc character
call pdos ;send esc
ld c,05h
ld e,'2'
call pdos ;esc 2 sets line spacing to 6 lines/in.
ld c,05h
ld e,cr ;send carriage return to reset head
call pdos
ret
endif ;(epson)
;
if citoh
preset: ld c,05h
ld e,1bh ;send esc
call pdos
ld c,05h
ld e,'a' ;esc a sets line spacing to 6 lines/in.
call pdos
ld e,cr
ld c,05h
call pdos ;send carriage return to reset head
ret
endif ;(citoh)
;
if oki
preset: ld c,05h
ld e,1bh ;esc % "9" 24 to set line spacing
call pdos
ld c,05h
ld e,25h ; "%"
call pdos
ld c,05h
ld e,39h ; "9"
call pdos
ld c,05h
ld e,24d ;reset to normal line spacing
call pdos
ret
;
endif ;(oki)
;
;-----------------------------------------------------------------------
; read record subroutine
; inputs:
; opened file
; file control block @ fcb
; 128 char file buffer @ dma
; 1 byte character pointer @ pointer
; outputs:
; character pointer reset to 0
; new record in file buffer
; register status:
; all register values destroyed
; error conditions:
; eof: jump to eofexit instead of normal return
;
read: ld c,26d ;select set dma function
ld de,dma ;pass buffer address
call fdos ;set dma address to i/p buffer
;
ld c,14h ;select sequential read function
ld de,fcb ;pass fcb
call fdos ;read record into buffer @ dma
cp 00h ;read ok?
jp z,setpntr ;reset pointer if not eof
pop bc ;pop return addr off stack
jp eofexit ;goto exit instead of normal rtn
setpntr: ld a,0 ;clear accum.
ld (pointer),a ;reset pointer to 0
ret ;return-new record & pointer pos
;
eofexit: ld c,09h ;select print string function
ld de,eofmsg ;pass message
call fdos ;print eof message
jp boot ;return to cp/m command level
;-----------------------------------------------------------------------
;
; this subroutine gets an xy pair
;and converts it to raster values. the general algorithm is:
;
; integer = (fixed point) * (number of rasters) * 2/ 2^16
;
; the fixed point number is a 15 bit value in the range 0 to 1.
; when viewed as an integer, the fixed point coordinates range from
; 0 to 32767. when multiplied by the range of the raster coordinates,
; they must be divided by 32767 to represent the true value. this is
; approximated by multiplying by 2 / 65536 (2/64k). dividing by 64k
; is accomplished by simply disregarding the lower 2 bytes of the result
;
; inputs:
; 128 character buffer @ dma
; character pointer @ pointer
; outputs:
; two byte value stored @ x
; two byte value stored @ y
; register status:
; all register values destroyed
; error conditions:
; none- byte will terminate program on eof if necessary
;
readxy: call byte ;get first byte of x
push af ;store first byte
call byte ;get second byte
ld b,a ;put high byte in [b]
pop af ;get low byte
ld c,a ;[bc] now contains fixed point x coord.
ld de,maxx*2 ;pass maximum raster address
call mult ;multiply x coord by no. of x rasters
ex de,hl ;put high bytes in [hl]
ld (x),hl ;store corresponding raster x coordinate
;
call byte ;get first byte of y
push af ;store first byte
call byte ;get second byte
ld b,a ;put high byte in [b]
pop af ;get low byte
ld c,a ;[bc] now contains fixed point y coord.
ld de,maxy*2 ;pass maximum raster address
call mult ;multiply y coord by no. of y rasters
ex de,hl ;put high bytes in [hl]
ld (y),hl ;store corresponding raster y coordinate
ret
;
;---------------------------------------
;
; this subroutine rotates the patterns used for erasing to a color
;
; inputs:
; array of 8 pattern bytes stored at patrn
; outputs:
; array is rotated one bit down
; register status:
; [bc],[hl] preserved, all others destroyed
; error conditions:
; none
;
rotpat: push bc ;save counter in [bc]
push hl ;save pointer in [hl]
ld b,8d ;initialize counter
ld hl,patrn ;initialize address of head of array
rotpt1: ld a,(hl) ;get byte
if msbtop
rrca ;rotate byte
endif ;( msbtop )
if not msbtop
rlca
endif ;( not msbtop )
ld (hl),a ;store rotated byte
;
inc hl ;move pointer to next byte
dec b ;decrement counter
jp nz,rotpt1 ;loop back until done
pop hl ;retrieve saved registers
pop bc
ret
;
;-----------------------------------------------------------------------
;
; this subroutine initializes the variables used in computing a
; line segment
;
; inputs:
; xpos,ypos present position
; x,y end points of segment
; outputs:
; dx,dy x,y sizes of line segment
; epslnx,epslny,sx,sy,delta3 internal variables
; initialized
; ni counter used to determine when done
; register satus:
; all register values destroyed.
; error conditions:
; none
;
seginit: ld hl,(x) ;get x
ex de,hl ;put x in de
ld hl,(xpos) ;put present pos in hl
ld a,e ;calculate delta x
sub l
ld c,a
ld a,d
sbc a,h
ld b,a ;bc now contains delta x (dx)
ld hl,(y) ;get y end point value
ex de,hl ;put y in de
ld hl,(ypos) ;get present y position
ld a,e ;calculate delta y (dy)
sub l
ld e,a
ld a,d
sbc a,h
ld d,a ;de now contains dy
ex de,hl ;put dy in hl, ypos in de
ld (deltay),hl ;store dy
ld h,b
ld l,c
;
ld (deltax),hl ;store delta x
ld hl,0000h ;initialize variables
ld (sx),hl
ld (epslny),hl
ld hl,0001h
ld (sy),hl
ld (epslnx),hl
ld a,(deltax+1) ;get dx high byte
or a ;set flags according to dx hi byte
jp p,chkdy
ld hl,0ffffh ;change initialization for -dx
ld (epslnx),hl
ld hl,(deltax) ;change sign on dx
ld a,h
cpl ;complement high byte
ld h,a
ld a,l
cpl ;complement low byte
add a,01h ;add 1 to make it two's comp.
ld l,a
ld a,h
adc a,00h ;add carry to high byte
ld h,a
ld (deltax),hl ;store now positive dx
chkdy: ld a,(deltay+1) ;get dy high byte- contains sign
or a ;set flags on dy hi byte
jp p,chdxdy ;dy is pos- goto transpose axes
ld hl,(deltay) ;dy is negative- change sign
ld a,h
cpl ;complement hi byte
ld h,a
ld a,l
cpl
add a,01h ;complement and add 1
ld l,a
ld a,h
adc a,00h ;add carry from low byte
ld h,a
ld (deltay),hl ;store the now pos. dy
ld hl,0ffffh ;load -1 in (hl)
ld (sy),hl ;sy= -1
chdxdy: ld hl,(deltax) ;transpose axes if dx<dy
ex de,hl ;put dx in de
ld hl,(deltay) ;get delta y
ld a,d ;put high byte of dx in a
cp h ;dx < dy ? (high bytes first)
jp c,tnspos ;dx definitely < dy
jp nz,lstinit ; dx definitely > dy
ld a,e ;high bytes =, check low bytes
cp l
jp nc,lstinit ;if no carry, dx>= dy- start plotting
tnspos: ld (deltax),hl ;dy was in hl- store as dx
ex de,hl ;dx now in hl, dy now in de
ld (deltay),hl ;store old dx as new dy
ld hl,(epslnx)
ld (sx),hl ;reinitialize: sx= epsilon x
ld hl,(sy)
ld (epslny),hl ;epsilon y = sy
ld hl,0000h
ld (epslnx),hl ;epsilon x = 0
ld (sy),hl ;sy = 0
;
lstinit: scf ;clear carry -set=1, then complement
ccf
ld a,d ;calculate deltax/2 by shifting 1 right
rra ;shift
ld d,a ;store high byte deltax/2 in d
ld a,e ;now the low byte
rra ;shift (divide by 2)
ld e,a ;put low byte back.
ex de,hl ;put dx/2 in (hl)
ld (delta3),hl ;store in delta3
;
ld hl,0001h ;set ni=1
ld (ni),hl ;save counter value
ret ;done with initialization
;
;------------------------------------------------------------------------
; status message routine
;
; this routine displays a message to indicate that the program
; is working.
;
; inputs:
; current count stored in statno
; outputs:
; message displayed
; register status:
; all register values preserved
; error conditions:
; none
;
stat: push af ;save registers
push bc
push de
push hl
;
ld a,(statno) ;get counter
inc a ;update counter
ld (statno),a
ld c,09h ;select write function
cp 01h ;select message
jp nz,statm2
ld de,stat1
call fdos ;print message
jp statx ;exit subroutine
;
statm2: cp 128 ;check for other message
jp nz,statx ;not time for either message
ld de,stat2
call fdos ;print other message
;
statx: pop hl ;restore registers
pop de
pop bc
pop af
ret
;
;------------------------------------------------------------------------
; string plotting subroutine
; method:
; ascii code is stored repeatedly in the area occupied by
; the character (cwidth rasters). hi bit is set to
; indicate that the byte is ascii and not dot image.
;
; input:
; x,y in file buffer
; bytes read sequentially from buffer until carriage rtn
; is encountered.
;
; outputs:
; each character is stored in the byte containing the bit
; map coordinate indicated for the character
;
; register status:
; all register values destroyed
;
; error conditions:
; x,y locations < 0 are reset to 0
; x,y locations > max are reset to 0
;
cr equ 0dh ;cr = carriage return
string: call readxy ;get starting coordinates
strng0: call byte ;get first character
cp cr ;is character a carriage return?
ret z ;yes- so return (all done)
or 10000000b ;set high bit
ld b,a ;save byte in (b)
ld hl,(x) ;get x location
ld a,h ;look at high byte
or a ;set flags
jp m,resetx ;x is negative- reset to 0
ld de,maxx-cwidth ;get maximum x value
cp d ;compare max and x high bytes
jp c,strng1 ;max definitely > x (x is ok)
jp nz,resetx ;x definitely > max -reset x
ld a,l ;hi bytes are =: look at low bytes
cp e ;is max low byte > x low byte?
jp c,strng1 ;yes is is - x is ok
jp z,strng1 ;low bytes are =: x is barely ok
resetx: ld hl,0000h ;clear hl
ld (x),hl ;store 0 in x
strng1: ld hl,(y) ;fetch y starting location
ld a,h ;look at y high byte
or a ;set flags
jp m,resety ;negative - reset to 0
ld de,maxy ;use entire coordinate range for y
cp d ;compare max and y high bytes
jp c,strng2 ;y definitely ok
jp nz,resety ;y definitely > max - reset y
ld a,l ;hi bytes are =: look @ low bytes
cp e ;compare max and y low bytes
jp c,strng2 ;max > y - y is ok
jp z,strng2 ;y = max
resety: ld hl,0000h ;clear old value of y
ld (y),hl ;y = 0
strng2: ex de,hl ;put y in (de)
ld hl,(x) ;fetch x
push bc ;save byte temporarily
push de ;save y coord temporarily
; make x coord. a multiple of cwidth for proper printer output
ld (divdnd),hl ;compute x=(x/cwidth)*cwidth
ld a,cwidth ;get cwidth for divisor
ld (divsor),a
call divide ;divide x by cwidth
ld a,(qotent) ;get results (no overflow as 0<=x<1530)
ld bc,cwidth ;pass character width
call bmult ;[hl] now contains (x/cwidth)*cwidth
;
ld b,h ;put x in (bc)
ld c,l
pop de ;retrieve y coordinate
ld hl,maxy ;put max y in (hl)
call locdot ;get location of byte
pop bc ;retrieve byte
ld (hl),b ;put byte in address containing x,y
; store byte repeatedly to blank out entire area occupied by it
ld a,cwidth-1 ;initialize loop counter
strng3: inc hl ;increment address
ld (hl),b ;store byte
sub 1 ;decrement loop counter
jp nz,strng3 ;loop back up until finished
ld c,cwidth ;put cwidth in (c)
ld hl,(x) ;fetch x location
ld b,00h ;clear (b)
add hl,bc ;increment x location for next character
ld (x),hl ;store new x location
jp strng0 ;loop up to top
;
;-----------------------------------------------------------------------
; text
;
; this subroutine outputs text immediately to the printer
; note: text is not put into memory map
;
; inputs:
; text string in file (ends with 0 byte)
; outputs:
; text string printed
; register status:
; all register values destroyed
; error conditions:
; none peculiar to this routine
;
text: call byte ;get next character
cp 0 ;check for end of string
ret z ;return if finished
;
if not screen
ld e,a ;pass character
ld c,05 ;select cp/m lst: output
call pdos ;print it
endif
;
jp text ;loop back until done
;
;-----------------------------------------------------------------------
;
; this subroutine uploads the array defining color pallet
;
; inputs:
; 16 bit integer specifying # of data bytes to come
; data bytes in input file
; outputs:
; new color values stored in appropriate arrays
; register status:
; all register values destroyed
; error conditions:
; none
;
upload: call byte ;get low byte of integer
ld c,a ;save integer in [bc]
call byte ;get high byte
;
or a ;check value of high byte
jp nz,upbad ;for this program, hi byte must be 0
ld a,c ;look at low byte
cp 7d ;7 indicates upload plaid patterns
jp z,uplaid ;proceed to upload plaid values
cp 64d ;64 indicates upload dither matrix
jp z,updith ;proceed to upload dither matrix
cp 120d ;124 indicates upload special patterns
jp z,upcif ;proceed to upload special patterns
;
upbad: call byte ;# has unexpected value- skip bytes
dec bc ;decrement loop counter
ld a,c
or b ;is counter = 0 ?
jp nz,upbad ;loop back until finished
ret
;
uplaid: ld hl,plaids+1 ;point to plaid array (leave "0" alone)
jp uplp1 ;proceed to read-store loop
upcif: ld hl,cifpat ;set pointer at start of special patterns
jp uplp1
updith: ld hl,ditharr ;point to dither array
uplp1: call byte ;get color pattern
ld (hl),a ;store pattern
inc hl ;point to next pattern slot
dec c ;decrement counter
jp nz,uplp1 ;loop back until finished
ret
;
;-----------------------------------------------------------------------
; this subroutine is executed when overflow occurs in mult. or div
; inputs:
; none
; outputs:
; message "overflow"
; all registers pushed on stack
; in order: psw, h, d, b
; final position of stack pointer saved in oldstk
; register status:
; all input registers stored on stack, c, de, hl reg changed
; error conditions:
; none
;
woops: push af ;save all registers
push hl
push de
push bc
ld hl,0000h ;clear (hl)
add hl,sp ;get stack pointer
ld (oldstk),hl ;save stack pointer for debug
ld c,09h ;select print function
ld de,ovflmsg
call fdos ; print 'overflow'
jp boot ;return to cp/m command level
ovflmsg: defb 'overflow$'
;
;-----------------------------------------------------------------------
; write record subroutine
;
; inputs:
; opened file
; file control block @ fcb2
; buffer @ dma2
; buffer pointer @ pointr2
; outputs:
; buffer written to file
; buffer pointer reset to 0
; register status:
; all register values changed
; error conditions:
; if no space left on disk, error message written
; and program terminates.
;
write: ld c,26d ;select set dma function
ld de,dma2 ;pass o/p buffer
call fdos ;set dma address
;
ld c,21d ;select write sequential
ld de,fcb2 ;pass o/p fcb
call fdos ;write record
;
cp 00h ;was write ok?
jp nz,fullxit ;jump to error section if not
ld a,00h ;clear (a)
ld (pointr2),a ;pointr2=0
ret ;done with successful write
fullxit: ld c,09d ;select print function
ld de,noroom ;pass error message
call fdos ;print it
;
jp boot ;terminate with warm start
;
;-----------------------------------------------------------------------
;
; this subroutine is used for non-standard extensions to plot
;
; inputs:
; none
; outputs:
; none
; regsister status:
; all values preserved
; error conditions:
; none
;
xtend: push af
push bc
push de
push hl
;
call byte ;get low byte of number of data bytes
ld a,c
call byte ;get high byte of number of bytes
ld a,b ;[bc] is now 16 bit integer
or c ;is number = 0?
jp z,xtnd2 ;finished if n = 0
xtnd1: call byte ;get data byte
dec bc ;decrement counter
ld a,c
or b ;is counter = 0 ?
jp nz,xtnd1 ;loop back if more to come
xtnd2: pop hl ;restore registers
pop de
pop bc
pop af
ret ;finished
;
;-----------------------------------------------------------------------
;
origin: ;start of picture map
;
;-----------------------------------------------------------------------