home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
norge.freeshell.org (192.94.73.8)
/
192.94.73.8.tar
/
192.94.73.8
/
pub
/
computers
/
cpm
/
alphatronic
/
CGRAPH.ZIP
/
PLOT.MAC
< prev
next >
Wrap
Text File
|
1998-07-30
|
26KB
|
1,424 lines
;*************************************************************************
;
; GENERAL PURPOSE GRAPHICS PRINTER PLOTTING PACKAGE
;
; Plotting Subroutines/Procedures
; compatible with the following high level languages:
;
; . BASIC,
; . PASCAL/Z,
; . and JRT PASCAL
;
; which support the following printers
;
; . BASE-2
; . IDS-560
;
; Assemble using Microsoft M80.COM assembler.
;
; 10 February 1983
;
; Ver: 2.2
;
; Courtesty: Clermont Computer Consultants
; RD 1 Box 316
; Cape May Court House, NJ 08210
; (609) 263 7511
;
;*************************************************************************
.Z80
;
; EQUATES FOR ALL SUBROUTINES
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
LIFEBT EQU FALSE
ZENITH EQU FALSE
CDR EQU TRUE ; assemble for CDR SYSTEMS BIOS
;
BASE2 EQU FALSE
IDS560 EQU TRUE ; assemble for IDS-560
;
BASIC EQU FALSE
PAS.Z EQU FALSE
PAS.J EQU TRUE ; assemble for JRT PASCAL
;
IF LIFEBT
BASE EQU 4200H
ENDIF
;
IF NOT LIFEBT
BASE EQU 0000H
ENDIF
;
BDOS EQU BASE+5
;
; ========================================================================
;
; Change LINES equate to produce a plot area of a given size
;
; LINES = int(#dots/7) + 1
;
LINES EQU 59 ; produces 413 x 413 image
;
; ========================================================================
;
DOTS EQU LINES*7 ; number of vertical dots in plot
NLINES EQU DOTS/8 + 1 ; number of lines in image area
LENGTH EQU DOTS ; number of horizontal dots in plot
IF BASE2
;
FILL1 EQU (576-LENGTH)/2 ; fill for left margin
FILL2 EQU 576-LENGTH-FILL1; 576 dots per line in 96 char/line mode
ENDIF
;
IF IDS560
;
FILL1 EQU 126 ; 1.5 inch left margin
ENDIF
;
AREA EQU NLINES*LENGTH ; number of bytes for plot area
;
IF LIFEBT
TMEM EQU 0DF00H ; lower bound of CP/M (48K ORG 4200H)
ENDIF
;
IF NOT LIFEBT
TMEM EQU 0DC00H ; lower bound of ORG 0 versions
ENDIF
;
IF BASIC
;
BOTTOM EQU TMEM-AREA-06EAH ; leave room for prog + plot area
; and start at next lowest page boundary
ORIGIN EQU (BOTTOM AND 0FF00H)
ENDIF
;
IF2
IF PAS.Z
;
.PRINTX/ PASCAL/Z version/
ENDIF
;
IF PAS.J
;
.PRINTX/ JRT PASCAL version/
ENDIF
;
IF BASIC
;
.PRINTX/ BASIC version/
ENDIF
;
IF BASE2
;
.PRINTX/ For BASE-2 printer/
ENDIF
;
IF IDS560
;
.PRINTX/ For IDS-560 printer/
ENDIF
;
ENDIF
IF BASIC
;*************************************************************************
;
; Subroutine to link the parameters passed from BASIC
;
DTLNK:
;
LD A,(DE) ; fetch # bytes
SLA B ; 2*(# parameters)
CP B ; are they =?
JR NZ,STERR ; no, an error in BASIC
INC DE ; point to string address
EX DE,HL
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL ; HL points to first byte in string
LD DE,P1
DTLNK1: LD A,(HL) ; transfer 2*(# param's) bytes of data
LD (DE),A
INC HL
INC DE
DJNZ DTLNK1
RET
;
ENDIF
IF PAS.J
;******************************************************************************
;
; PARAMETER LINKAGE ROUTINE FOR JRT PASCAL
;
; All calls to plot functions must be via this parameter linkage
; routine. JRT PASCAL expects each external .INT file to contain
; a single unique function or procedure. All of the plot procedures
; must be treated as a single entity with one entry parameter acting
; as a pointer to the desired sub-procedure.
;
JPLOT:
; entry code
;
; DEFB 95,06,00 ; int vmcode
DEFB 92 ; lpn vmcode
DEFB 00 ; mode vmcode
;
; hl = base
; de = current
; bc = tos
;
LD BC,6
ADD HL,BC ; HL = IMAGE address
LD (IMGPTR),HL ; store for later use
;
EX DE,HL
DEC HL
DEC HL ; point to length
LD A,(HL) ; get length
CP 0FH ; see if correct
JP NZ,JERR ; bad procedure call
DEC HL ; do each parameter in reverse order
LD D,(HL)
DEC HL
LD E,(HL)
LD (P7),DE ; DE = parameter 7
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P6),DE ; DE = parameter 6
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P5),DE ; DE = parameter 5
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P4),DE ; DE = parameter 4
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P3),DE ; DE = parameter 3
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P2),DE ; DE = parameter 2
DEC HL
LD D,(HL)
DEC HL
LD E,(HL)
LD (P1),DE ; DE = parameter 1
DEC HL
LD A,(HL) ; A = type
CP 'A'
JP Z,AXIS
CP 'a'
JP Z,AXIS ; vector AXIS procedure
CP 'L'
JP Z,LINE
CP 'l'
JP Z,LINE ; vector LINE procedure
CP 'P'
JP Z,PLOT
CP 'p'
JP Z,PLOT ; vector PLOT procedure
CP 'D'
JP Z,POINT
CP 'd'
JP Z,POINT ; vector POINT procedure
CP 'I'
JP Z,INIT
CP 'i'
JP Z,INIT ; vector INIT procedure
CP 'C'
JP Z,CIRCLE
CP 'c'
JP Z,CIRCLE ; vector CIRCLE procedure
CP 'T'
JP Z,XFRPLT
CP 't'
JP Z,XFRPLT ; vector XFRPLT procedure
JERR:
JP STERR + 1 ; bad procedure call
; print error message & return
ENDIF
;******************************************************************************
;
; Test & failure message subroutines
;
YTEST:
LD DE,DOTS-1 ; y <-- DOTS-1-y
OR A
EX DE,HL
SBC HL,DE
;
TEST: ; limits the bounds on x and y to
; be 0 <= HL <= DOTS-1
XOR A ; clear test flag
LD B,A
LD A,H
AND 80H ; is HL negative?
JR Z,NNEG ; no
LD HL,0 ; yes, set lower limit of 0
DEC B ; set test flag
RET
NNEG: LD DE,DOTS-1 ; test HL>=DOTS
OR A
EX DE,HL
SBC HL,DE
JR NC,UPOK ; no carry, DE within bounds
LD HL,DOTS-1
DEC B ; set test flag
RET
UPOK: EX DE,HL
RET
;
;
STERR: POP HL ; modify stack to eliminate the return
LD DE,STERR$ ; from DTLINK
MSG: LD C,9 ; print the buffer under CP/M
JP BDOS ; and return to interpreter when done
;
STERR$: DEFB 13,10,'Improper Number of Parameters',13,10,10,'$'
;
;******************************************************************************
;
; INIT: image initialization subroutine
;
INIT: ; CALL & USR entry point, no parameters
IF PAS.Z
;
ENTRY INIT
ENDIF
;
LD HL,(IMGPTR) ; HL = first address of IMAGE
PUSH HL
POP DE
INC DE ; DE = second address of IMAGE
LD BC,AREA-1
LD (HL),0 ; set all bytes to 00
LDIR
;
IF PAS.Z
;
XOR A ; flag valid subroutine call
ENDIF
;
RET
;
;*************************************************************************
;
; Plot Subroutine:
;
PLOT: ; USR entry point
IF PAS.Z
;
ENTRY PLOT
POP BC ; fetch return address
POP HL ; fetch y: integer
LD (P2),HL
POP HL ; fetch x: integer
LD (P1),HL
PUSH BC ; restore return address
ENDIF
;
IF BASIC
;
LD B,2 ; transfer data from string buffer
CALL DTLNK ; and test/limit to boundaries
ENDIF
;
LD HL,(P1)
CALL TEST
BIT 7,B ; if out-of-bounds
JP NZ,SETRET ; do not plot point
LD (STARTX+2),HL
LD HL,(P2)
CALL YTEST
BIT 7,B
JP NZ,SETRET
LD (STARTY+2),HL
JP SET1
;
SET0: LD HL,(STARTX+2) ; entry point for subr call
CALL TEST ; when point may be outside boundaries
BIT 7,B ; if out-of-bounds
RET NZ ; do not plot point
LD (STARTX+2),HL
LD HL,(STARTY+2)
CALL TEST ; if out-of-bounds
BIT 7,B ; do not plot point
RET NZ
LD (STARTY+2),HL
SET1: LD B,0 ; entry point for subr call
LD HL,(STARTY+2) ; when point is within boundaries
; Determine address and bit number of pixel
; ADDR = LENGTH*(INT(Y/8) + X
; BIT = 2^(8 - (Y MOD 8))
;
LD DE,8
OR A
DIV8: SBC HL,DE
JR C,DONDIV
INC B
JR DIV8
DONDIV: ADD HL,DE
LD C,L
INC B
LD DE,LENGTH
LD HL,(IMGPTR)
OR A ; clear carry
SBC HL,DE ; HL = IMAGE - LENGTH
SMULT: ADD HL,DE
DJNZ SMULT
LD DE,(STARTX+2)
ADD HL,DE ; HL = ADDR
LD B,C
INC B
LD DE,TABLE-1
FINDT: INC DE
DJNZ FINDT
LD A,(DE) ; A has proper bit set
OR (HL)
LD (HL),A
;
SETRET:
IF PAS.Z
;
XOR A ; flag valid subroutine call
ENDIF
;
RET
;
TABLE: DEFB 80H ; bit position table
DEFB 40H
DEFB 20H
DEFB 10H
DEFB 08H
DEFB 04H
DEFB 02H
DEFB 01H
;
;*************************************************************************
; Point Subroutine:
;
POINT: ; CALL entry point
IF PAS.Z
;
ENTRY POINT
POP BC ; fetch return address
POP HL ; fetch y: integer
LD (P2),HL
POP HL ; fetch x: integer
LD (P1),HL
PUSH BC ; restore return address
ENDIF
;
IF BASIC
;
LD B,2
CALL DTLNK
ENDIF
;
LD HL,(P1)
CALL TEST
LD (P1),HL
LD HL,(P2)
CALL YTEST
LD (P2),HL
LD HL,(P1)
DEC HL
LD (STARTX+2),HL
LD HL,(P2)
DEC HL
LD (STARTY+2),HL
CALL SET0
LD HL,(P1)
LD (STARTX+2),HL
CALL SET0
LD HL,(P1)
INC HL
LD (STARTX+2),HL
CALL SET0
LD HL,(P2)
LD (STARTY+2),HL
CALL SET0
LD HL,(P2)
INC HL
LD (STARTY+2),HL
CALL SET0
LD HL,(P1)
LD (STARTX+2),HL
CALL SET0
LD HL,(P1)
DEC HL
LD (STARTX+2),HL
CALL SET0
LD HL,(P2)
LD (STARTY+2),HL
CALL SET0
;
IF PAS.Z
;
XOR A ; flag valid subroutine call
ENDIF
;
RET
;
;*************************************************************************
;
; Line Subroutine:
;
LINE: ; CALL entry point
IF PAS.Z
;
ENTRY LINE
POP BC ; fetch return address
POP HL ; fetch y2: integer
LD (P4),HL
POP HL ; fetch x2: integer
LD (P3),HL
POP HL ; fetch y1: integer
LD (P2),HL
POP HL ; fetch x1: integer
LD (P1),HL
PUSH BC ; restore return address
ENDIF
;
IF BASIC
;
LD B,4 ; 4 parameters in the CALL list
CALL DTLNK ; fetch the values P1, P2, P3, P4
ENDIF
;
LD HL,(P1) ; test for boundary conditions & transfer
CALL TEST ; to working storage
LD (STARTX+2),HL ; X1 <-- P1
LD HL,(P2)
CALL YTEST
LD (STARTY+2),HL ; Y1 <-- P2
LD HL,(P3)
CALL TEST
LD (ENDX+2),HL ; X2 <-- P3
LD HL,(P4)
CALL YTEST
LD (ENDY+2),HL ; Y2 <-- P4
LD HL,(ENDX+2) ; test for ENDX = STARTX
LD BC,(STARTX+2)
OR A ; 0-->carry
SBC HL,BC
JR NZ,LINE1 ; ENDS<>STARTX
LD HL,(ENDY+2) ; same for ENDY, STARTY
OR A
LD BC,(STARTY+2)
SBC HL,BC
JP Z,SET1 ; co-resident points, just plot single point
LINE1: ; entry point for other subroutine calls
LD HL,(ENDX+2) ; evaluate 32 bit fixed point
LD DE,(STARTX+2) ; numbers: DIRX & DIRY
OR A
SBC HL,DE
LD (DIRX),HL ; DIRX <- ENDX - STARTX; fractional part
BIT 7,H ; extend sign of .DIRX to integer part
JR Z,X0
LD HL,-1
JR X1
;
X0: LD HL,0
X1: LD (DIRX+2),HL ; do same for DIRY
LD HL,(ENDY+2)
LD DE,(STARTY+2)
OR A
SBC HL,DE
LD (DIRY),HL
BIT 7,H
JR Z,Y0
LD HL,-1
JR Y1
Y0: LD HL,0
Y1: LD (DIRY+2),HL
LD HL,(DIRX) ; HL <- .DIRX
LD DE,(DIRY) ; DE <- .DIRY
LD A,H
AND 80H
LD B,A ; B <- sgn(.DIRX)
LD A,D
AND 80H
LD C,A ; C <- sgn(.DIRY)
SHLFT: SLA L ; multiply HL, DE by 2
RL H ; until sign change occurs
SLA E ; on one or the other
RL D
LD A,H
AND 80H
CP B
JR NZ,DSHLFT
LD A,D
AND 80H
CP C
JR NZ,DSHLFT
JR SHLFT
DSHLFT: LD (DIRX),HL ; restore .DIRX & .DIRY with one equal
LD (DIRY),DE ; to 1/2 & the other less (magnitudes)
LD HL,8000H ; HL <- 1/2
LD (STARTX),HL ; round up STARTX, STARTY by 1/2
LD (STARTY),HL
NXTBL: CALL SET1
OR A
LD HL,(ENDX+2)
LD DE,(STARTX+2)
SBC HL,DE
JR Z,NXTBL2 ;STARTX = ENDX
NXTBL1: LD HL,(STARTX)
LD DE,(DIRX)
ADD HL,DE ;.STARTX = .STARTX + .DIRX
LD (STARTX),HL
LD HL,(STARTX+2)
LD DE,(DIRX+2)
ADC HL,DE ;STARTX. = STARTX. + DIRX. + .CY
LD (STARTX+2),HL
LD HL,(STARTY)
LD DE,(DIRY)
ADD HL,DE ;.STARTY = .STARTY + .DIRY
LD (STARTY),HL
LD HL,(STARTY+2)
LD DE,(DIRY+2)
ADC HL,DE ;STARTY. = STARTY. + DIRY. + .CY
LD (STARTY+2),HL
JR NXTBL
NXTBL2: OR A
LD HL,(ENDY+2)
LD DE,(STARTY+2)
SBC HL,DE
JR NZ,NXTBL1 ;STARTY. <> ENDY.
;
IF PAS.Z
;
XOR A ; flag valid subroutine call
ENDIF
;
RET
;
; ************************************************************************
;
; CIRCLE Subroutine:
;
CIRCLE:
IF PAS.Z
;
ENTRY CIRCLE
POP BC
POP HL ; R VALUE
LD (P3),HL
POP HL ; Y VALUE
LD (P2),HL
POP HL , X VALUE
LD (P1),HL
PUSH BC
PUSH IX
PUSH IY
ENDIF
;
IF BASIC
;
LD B,3
CALL DTLNK
ENDIF
;
LD HL,(P1)
CALL TEST
LD (P1),HL
LD HL,(P2)
CALL YTEST
LD (P2),HL
LD IX,SINTBL
LD IY,COSTBL
LD B,45
CIRC0:
PUSH BC ; SAVE COUNTER
LD D,(IX+1) ; SIN->(DE)
LD E,(IX)
LD BC,(P3) ; R->(BC)
CALL MULT
LD (RSIN),DE ; PROD->RSIN
LD D,(IY+1)
LD E,(IY)
LD BC,(P3)
CALL MULT
LD (RCOS),DE ; PROD->RCOS
LD HL,(P1) ;X->HL
ADD HL,DE
CALL CIRC1 ; X+RCOS ,Y+RSIN
LD DE,(RSIN)
ADD HL,DE
CALL CIRC2
; X+RSIN, Y+RCOS
LD DE,(RSIN)
ADD HL,DE
CALL CIRC1
LD DE,(RCOS)
ADD HL,DE
CALL CIRC2
; X-RSIN, Y+RCOS
LD DE,(RSIN)
OR A
SBC HL,DE
CALL CIRC1
LD DE,(RCOS)
ADD HL,DE
CALL CIRC2
; X-RCOS, Y+RSIN
LD DE,(RCOS)
OR A
SBC HL,DE
CALL CIRC1
LD DE,(RSIN)
ADD HL,DE
CALL CIRC2
; X-RCOS, Y-RSIN
LD DE,(RCOS)
OR A
SBC HL,DE
CALL CIRC1
LD DE,(RSIN)
OR A
SBC HL,DE
CALL CIRC2
; X-RSIN, Y-RCOS
LD DE,(RSIN)
OR A
SBC HL,DE
CALL CIRC1
LD DE,(RCOS)
OR A
SBC HL,DE
CALL CIRC2
; X+RCOS, Y-RSIN
LD DE,(RCOS)
ADD HL,DE
CALL CIRC1
LD DE,(RSIN)
OR A
SBC HL,DE
CALL CIRC2
; X+RSIN, Y-RCOS
LD DE,(RSIN)
ADD HL,DE
CALL CIRC1
LD DE,(RCOS)
OR A
SBC HL,DE
CALL CIRC2
INC IX
INC IX
INC IY
INC IY
POP BC
DEC B
JP NZ,CIRC0
LD HL,(P1) ; X+R, Y
LD DE,(P3)
ADD HL,DE
CALL CIRC1
CALL CIRC2
; X-R, Y
LD DE,(P3)
OR A
SBC HL,DE
CALL CIRC1
CALL CIRC2
; X, Y+R
CALL CIRC1
LD DE,(P3)
ADD HL,DE
CALL CIRC2
;X, Y-R
CALL CIRC1
LD DE,(P3)
OR A
SBC HL,DE
CALL CIRC2
;
IF PAS.Z
;
POP IY
POP IX
XOR A
ENDIF
;
RET
;
CIRC1: LD (STARTX+2),HL
LD HL,(P2)
RET
;
CIRC2: LD (STARTY+2),HL
CALL SET0
LD HL,(P1)
RET
;
RSIN: DEFW 0
RCOS: DEFW 0
; MULT: from ELECTRONICS/Feb 24, 1982 Designer's Casebook
; article by Jerry L. Goodrich
; performs a 2-byte by 2-byte integer multiply
; (BC)*(DE)-->(DE),(HL)
;
MULT:
LD A,E ;load lowest-order byte of multiplier
PUSH DE ;save highes-order byte multiplier
CALL BMULT ;do 1-byte multiply
EX (SP),HL ;save lowest-order bytes product,get multiplier
PUSH AF ;store highes-order byte of first product
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 highes-order byte of first product
ADD A,H ;update third byte of product
LD E,A ;and put in E
JP NC,NC1 ;don't incr D if no carry
INC D ;incr D if carry
NC1:
LD H,L ;relocate lowest-order bytes of sec. prod.
LD L,0
POP BC ;get lowest-order bytes of sec. prod.
ADD HL,BC ;get final product lowest-order 2 bytes
JR NC,NC2 ;done if no carry
INC DE ;otherwise update highest-order 2 bytes
NC2:
BIT 7,H ;round up if frac part => .5
RET Z
INC DE
RET
;
; BMULT performs a 1-byte by 2-byte multiply
; (A)*(BC)-->(A),(BC)
;
BMULT:
LD HL,0 ;zero partial product
LD DE,7 ;D=0,E=bit counter
ADD A,A ;get first mulitplier 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
JR NZ,LOOP1 ;loop until done
RET NC ;done if no carry
ADD HL,BC ;otherwise do last add
ADC A,D
RET ;and return
; COSTBL and SINTBL are tables of cosine and sine values
; specified as 16-bit fractions. Each table is 45 units
; (degrees) long.
;
COSTBL:
DEFW 65526 ;1 DEG
DEFW 65496 ;2
DEFW 65446 ;3
DEFW 65376 ;4
DEFW 65287 ;5
DEFW 65177 ;6
DEFW 65048 ;7
DEFW 64898 ;8
DEFW 64729 ;9
DEFW 64540 ;10
DEFW 64332 ;11
DEFW 64104 ;12
DEFW 63856 ;13
DEFW 63589 ;14
DEFW 63303 ;15
DEFW 62997 ;16
DEFW 62672 ;17
DEFW 62328 ;18
DEFW 61966 ;19
DEFW 61584 ;20
DEFW 61183 ;21
DEFW 60764 ;22
DEFW 60326 ;23
DEFW 59870 ;24
DEFW 59396 ;25
DEFW 58903 ;26
DEFW 58393 ;27
DEFW 57865 ;28
DEFW 57319 ;29
DEFW 56756 ;30
DEFW 56175 ;31
DEFW 55578 ;32
DEFW 54963 ;33
DEFW 54332 ;34
DEFW 53684 ;35
DEFW 53020 ;36
DEFW 52339 ;37
DEFW 51643 ;38
DEFW 50931 ;39
DEFW 50203 ;40
DEFW 49461 ;41
DEFW 48703 ;42
DEFW 47930 ;43
DEFW 47143 ;44
DEFW 46341 ;45
SINTBL:
DEFW 1144 ;1 DEG
DEFW 2287 ;2
DEFW 3430 ;3
DEFW 4572 ;4
DEFW 5712 ;5
DEFW 6850 ;6
DEFW 7987 ;7
DEFW 9121 ;8
DEFW 10252 ;9
DEFW 11380 ;10
DEFW 12505 ;11
DEFW 13626 ;12
DEFW 14742 ;13
DEFW 15855 ;14
DEFW 16962 ;15
DEFW 18064 ;16
DEFW 19161 ;17
DEFW 20252 ;18
DEFW 21336 ;19
DEFW 22415 ;20
DEFW 23486 ;21
DEFW 24550 ;22
DEFW 25607 ;23
DEFW 26656 ;24
DEFW 27697 ;25
DEFW 28729 ;26
DEFW 29753 ;27
DEFW 30767 ;28
DEFW 31772 ;29
DEFW 32768 ;30
DEFW 33754 ;31
DEFW 34729 ;32
DEFW 35693 ;33
DEFW 36647 ;34
DEFW 37590 ;35
DEFW 38521 ;36
DEFW 39441 ;37
DEFW 40348 ;38
DEFW 41243 ;39
DEFW 42126 ;40
DEFW 42995 ;41
DEFW 43852 ;42
DEFW 44695 ;43
DEFW 45525 ;44
DEFW 46341 ;45
;*************************************************************************
;
; Axis Subroutine
;
AXIS:
IF PAS.Z
;
ENTRY AXIS
POP BC ;fetch return address
LD HL,0
ADD HL,SP
LD L,(HL) ;fetch GRID: boolean
LD (P7),HL
INC SP
POP HL ;fetch YB: integer
LD (P6),HL
POP HL ;fetch XB: integer
LD (P5),HL
POP HL ;fetch YA: integer
LD (P4),HL
POP HL ;fetch XA: integer
LD (P3),HL
POP HL ;fetch Y0: integer
LD (P2),HL
POP HL ;fetch X0: integer
LD (P1),HL
PUSH BC
ENDIF
;
IF BASIC
;
LD B,7 ; pass seven parameters
CALL DTLNK
ENDIF
;
LD HL,(P1)
CALL TEST ; keep within x,y bounds
LD (P1),HL
LD (STARTX+2),HL
LD (ENDX+2),HL
LD HL,0
LD (STARTY+2),HL
LD HL,DOTS-1
LD (ENDY+2),HL
CALL LINE1 ; draw Y axis
LD HL,(P2)
CALL YTEST
LD (P2),HL
LD (STARTY+2),HL
LD (ENDY+2),HL
LD HL,0
LD (STARTX+2),HL
LD HL,DOTS-1
LD (ENDX+2),HL
CALL LINE1 ; draw X axis
IF PAS.Z
;
PUSH IX ; save IX, IY for PAS.Z/Z
PUSH IY
ENDIF
;
LD IX,STARTX+2 ; point to Xt, Yt positions
LD IY,STARTY+2
LD HL,(P3) ; fetch X tick minor
LD (TM),HL
LD A,L
OR H
JR Z,XTMAJ ; skip if Xt minor=0
LD HL,(P1)
LD (TAXIS),HL
LD HL,(P2)
LD (CAXIS),HL
CALL TICK ; fill in tick marks
CALL MINOR
XTMAJ:
LD HL,(P5) ; fetch X tick major
LD (TM),HL
LD A,L
OR H
JR Z,YTMIN ; skip if Xt major =0
LD HL,(P1)
LD (TAXIS),HL
LD HL,(P2)
LD (CAXIS),HL
CALL TICK ; fill in tick marks
LD (XGRID),HL
CALL MAJOR
YTMIN:
LD IX,STARTY+2 ; same as above, but rotate axis
LD IY,STARTX+2
LD HL,(P4) ; fetch Y tick minor
LD (TM),HL
LD A,L
OR H
JR Z,YTMAJ ; skip if Y tick minor=0
LD HL,(P2)
LD (TAXIS),HL
LD HL,(P1)
LD (CAXIS),HL
CALL TICK ; fill in tick marks
CALL MINOR
YTMAJ:
LD HL,(P6) ; fetch Y tick major
LD (TM),HL
LD A,L
OR H
RET Z ; all done no Y tick major
LD HL,(P2)
LD (TAXIS),HL
LD HL,(P1)
LD (CAXIS),HL
CALL TICK ; fill in tick marks
LD (YGRID),HL
CALL MAJOR
CALL GRID
IF PAS.Z
;
POP IY ; restore IX, IY
POP IX
XOR A ; indicate valid external procedure call
ENDIF
;
RET
;
TICK: LD HL,DOTS-1 ; find largest value for tick mark
LD DE,(TAXIS)
OR A
SBC HL,DE
LD DE,(TM)
TICK0: SBC HL,DE
JR NC,TICK0
ADD HL,DE
LD DE,DOTS-1
EX DE,HL
OR A
SBC HL,DE ; HL = highest value for tick mark
RET
;
MINOR: LD (IX+0),L ; plot minor tick marks on indicated axis
LD (IX+1),H
LD HL,(CAXIS)
DEC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
INC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD L,(IX+0)
LD H,(IX+1)
LD DE,(TM)
OR A
SBC HL,DE
JR NC,MINOR
RET
MAJOR: LD (IX+0),L ; plot major tick marks on indicated axis
LD (IX+1),H
LD HL,(CAXIS)
DEC HL
DEC HL
DEC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
DEC HL
DEC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
DEC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
INC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
INC HL
INC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD HL,(CAXIS)
INC HL
INC HL
INC HL
LD (IY+0),L
LD (IY+1),H
CALL SET0
LD L,(IX+0)
LD H,(IX+1)
LD DE,(TM)
OR A
SBC HL,DE
JR NC,MAJOR
RET
GRID:
LD HL,(P7) ; plot x, y grid marks if required
LD A,H
OR L
RET Z ; no grid required
LD HL,(P5)
LD A,H
OR L
RET Z ; impossible x grid
LD HL,(P6)
LD A,H
OR L
RET Z ; impossible y grid
LD HL,(XGRID) ; put grid marks at intersections of
GRID0: LD (STARTX+2),HL ; axis major tick marks
LD HL,(YGRID)
GRID1: LD (STARTY+2),HL
CALL SET1
LD HL,(STARTY+2)
LD DE,(P6)
OR A
SBC HL,DE
JR NC,GRID1
LD HL,(STARTX+2)
LD DE,(P5)
OR A
SBC HL,DE
JR NC,GRID0
RET
;******************************************************************************
;
; CPM INTERFACE DRIVERS
;
PRNTR:
CALL CPMOUT
;
IF BASE2
;
LD B,32
DELAY: DJNZ DELAY ; give BASE2 some more time
ENDIF
;
RET
;
CPMOUT:
PUSH AF ; NOTE: some BIOS implementations
PUSH BC ; will alter IX & IY
PUSH DE ; so save all the Z-80 registers
PUSH HL
PUSH IX
PUSH IY
LD E,A
LD C,5
CALL BDOS
POP IY
POP IX
POP HL
POP DE
POP BC
POP AF
RET
;*************************************************************************
;
; XFRPLT: transfer image-to-printer subroutine
;
XFRPLT: ; CALL & USR entry point, no parameters
IF PAS.Z
;
ENTRY XFRPLT
PUSH IX ; save IX, IY for PAS.Z/Z
PUSH IY
ENDIF
;
IF BASE2
;
LD A,27 ; set up PRNTR for:
CALL PRNTR ; 96 characters/inch
LD A,50 ; 14 vertical half-dots/inch
CALL PRNTR
LD A,27
CALL PRNTR
LD A,98
CALL PRNTR
LD A,14
CALL PRNTR
ENDIF
;
IF IDS560
;
LD A,03 ; send ETX character
CALL PRNTR
ENDIF
;
; row: continous sequence of memory locations of length LENGTH
; line: continous sequence of graphic characters of length LENGTH
; shift: number of 16 bit left shifts required to recover graphic
; character from 16 bit word formed from location
; plot+i (IX)->H, and plot+i+LENGTH (IY)->L
;
LD IX,(IMGPTR) ; IX = IMAGE
LD IY,(IMGPTR)
LD DE,LENGTH
ADD IY,DE ; IY = IMAGE + LENGTH
LD C,LINES ; transfer this number of print lines
XFR0: LD D,7 ; # shifts in first group
;
XFR1:
IF BASE2
;
LD A,27 ; set up for graphics
CALL PRNTR
LD A,99
CALL PRNTR
ENDIF
PUSH BC ; save line counter
LD B,FILL1 ; & fill left margin with blanks
XFR10: LD A,128
CALL PRNTR
DJNZ XFR10
LD BC,LENGTH ; transfer the graphics characters
XFR2: LD H,(IX+0)
LD L,(IY+0)
CALL ROTL
;
IF BASE2
;
CALL PRINTER
ENDIF
;
IF IDS560
;
PUSH AF
CALL PRNTR
POP AF
CP 03 ; was ETX sent?
CALL Z,PRNTR ; yes, must be sent twice
ENDIF
;
INC IX ; increment image pointers
INC IY
DEC BC ; decrement character counter
LD A,C
OR B
JR NZ,XFR2 ; do entire line of graphic characters
;
IF BASE2
;
LD B,FILL2
XFR20: LD A,128 ; fill right margin with blanks
CALL PRNTR
DJNZ XFR20
LD A,10 ; terminate with line feed
CALL PRNTR
ENDIF
IF IDS560
;
LD A,03 ; send line terminator sequence
CALL PRNTR
LD A,14
CALL PRNTR
ENDIF
;
DEC D ; do one less shift on next line
LD A,D ; test for D=6, special case
CP 6
JR NZ,XFR21
LD BC,-LENGTH ; if D=6 then repeat row for next line
ADD IX,BC
ADD IY,BC
XFR21: POP BC
DEC C ; decrement line counter
JR Z,XFRDN ; all lines done, exit from loop
LD A,D ; shifts 7 --> 0 done?
CP -1
JR NZ,XFR1 ; no, do next shift
JR XFR0 ; yes, next row, line, shifts 7-->0
XFRDN:
IF BASE2
;
LD A,27 ; reset printer to normal
CALL PRNTR
LD A,98
CALL PRNTR
LD A,24
CALL PRNTR
ENDIF
;
IF IDS560
;
LD A,03
CALL PRNTR
LD A,14
CALL PRNTR
LD A,03
CALL PRNTR
LD A,02 ; return to NORMAL mode
CALL PRNTR
ENDIF
;
IF PAS.Z
;
POP IY ; restore IX, IY for PAS.Z
POP IX
ENDIF
;
RET
;
ROTL: PUSH DE ; save DE, BC
PUSH BC
XOR A ; test for case 0
CP D
JR Z,ROTL1 ; no shifts for case 0
LD A,D ; test for case 7
CP 7
JR NZ,ROTL0
SRL H ; if D=7, then one shift right
JR ROTL1
ROTL0: SLA L
RL H ; 16 bit rotate D bits to left
DEC D
JR NZ,ROTL0
ROTL1: XOR A ; reverse bit order for PRNTR
LD B,7
ROTL2: SRL H
RLA
DJNZ ROTL2
POP BC ; restore BC, DE
POP DE
RET ; & return graphic char in Accum
;*************************************************************************
;
; working storage locations
;
STARTX: DEFW 0 ; X1, 16 bit integer, 16 bit fraction
DEFW 0
STARTY: DEFW 0 ; Y1, same
DEFW 0
ENDX: DEFW 0 ; X2, same
DEFW 0
ENDY: DEFW 0 ; Y2, same
DEFW 0
DIRX: DEFW 0 ; (X2 - X1)/256, same formate as X1
DEFW 0
DIRY: DEFW 0 ; (Y2 - Y1)/256, same
DEFW 0
;
; passed parameters storage
;
P1: DEFW 0 ; memory reserved for passing up to
P2: DEFW 0 ; eight parameters from BASIC via
P3: DEFW 0 ; CALL subr(P1,P2,P3,P4,P5,P6,P7,P8)
P4: DEFW 0
P5: DEFW 0
P6: DEFW 0
P7: DEFW 0
P8: DEFW 0
;
TM: DEFW 0 ; reserved for AXIS routine temp storage
TAXIS: DEFW 0
CAXIS: DEFW 0
;
XGRID: DEFW 0
YGRID: DEFW 0
;
IMGPTR: DEFW IMAGE
IMAGE EQU $
;
IF PAS.Z
;
DEFS AREA
ENDIF
;
END