.TITLE MACPLOT		Routines for matrix-based plotter
	.SBTTL		Summary & Description

;++
;	MACPLOT.MAR:
;
;	VAX-11 MACRO routines for VPLOT:
;	by
;	M. Gooley
;	Millikin University Computer Center
;	Decatur, Illinois 62522
;
;	Copyright (C) 1981 by M. Gooley.  This software is
;	distributed without cost, and may be reproduced only
;	with the inclusion of this copyright statement.  The
;	author assumes no responsibility for the performance
;	of this software.
;
;	These routines do the dirty work for the VPLOT matrix-
;	based plotter: they provide the illusion of a huge matrix of
;	individually-addressable bits, each corresponding to one dot of
;	a PRINTRONIX plot, whilst actually fetching 120-byte blocks of
;	virtual memory only as needed (using the LIB$GET_VM library
;	procedure).  Much virtual memory is thereby saved, though at the
;	expense of CPU time; each block also requires a longword pointer
;	to its base-address, which "wastes" four bytes per block.
;
;--

	.SBTTL		Data area
	.PSECT	SMALLDAT,NOEXE

WIDTH:	.LONG			;width of plot in blocks
WTH4:	.LONG			; ...times 4
WTH4M1:	.LONG			; ...and minus 1: last character in line
LENGTH:	.LONG			; length of plot in blocks
AREA:	.LONG			; 4 times # of blocks--# of bytes in
				; table of base-addresses
TABEND:	.LONG			; end of table of base-addresses
BLKTAB:	.LONG			; base of table of block base-addresses
EORBLK:	.LONG			; last block of current row (in DUMP)
BITROW:	.LONG	0		; counter for row within block (in DUMP)
BLKSIZE:.LONG	120		; size of blocks, in bytes
LASTADR:.LONG			; address of last-row indicator
STRBASE:.LONG			; address of base-string
STRLEN:	.LONG			; address of string-length


	.SBTTL		The Macros
	.PSECT	MACPORTION,NOWRT

	.MACRO	OUTEST	REG,BOUND
	TSTL	REG		;test register
	BLSS	OUT		; branch to OUT if less than zero
	CMPL	REG,BOUND	; compare register with BOUND
	BGEQ	OUT		; branch to OUT if equal or greater
	.ENDM	OUTEST

	.MACRO	FREEBLK	BASE,SIZE
	PUSHL	BASE		; push register containing address of
				; memory-block
	PUSHAL	SIZE		; push addr. of longw. containing size
	CALLS	#2,LIB$FREE_VM	; return the memory block
				; take no action if it's not wanted back
	.ENDM	FREEBLK


	.SBTTL		Initialisation Routine
	.PSECT	INITIAL,NOWRT
	.ENTRY	INITIAL,^M<R2,R3,R4,R5>
				; entry mask (R0-R5 are zapped by the
				; MOVC5 instruction at the end of the
				; routine...
	MOVL	4(AP),R2	; width to R2
	MOVL	8(AP),R3	; length to R3 (arguments passed 
				; by-value)
	MOVL	12(AP),LASTADR	; address of last-row indicator
				; (by-reference)
	MOVL	16(AP),STRLEN	; address of string return-length
	MOVL	28(AP),STRBASE	; address of string base
				; (by reference)
	MULL3	R2,R3,R4	; # of blocks to R4
	MULL3	#4,R4,AREA	; 4 times that many bytes needed
LOOP1:	PUSHAL	BLKTAB		; location to receive addr. of block
	PUSHAL	AREA		; # of bytes requested
	CALLS	#2,G^LIB$GET_VM	; allocate memory
	BLBC	R0,LOOP1	; try again if memory unavailable
	MOVL	R2,WIDTH	; store width
	MULL2	#4,R2		; calculate 4 times width
	MOVL	R2,WTH4		; store it
	SUBL3	#1,R2,WTH4M1	; decrement it and store that
	MOVL	R3,LENGTH	; store length
	ADDL3	BLKTAB,AREA,TABEND
	SUBL2	#4,TABEND	; decrement to get actual location
				; TABEND=end of block-address table
	ADDL3	WTH4,BLKTAB,EORBLK
	SUBL2	#4,EORBLK	; initialise EORBLK to last block of
				; first row
	MOVC5	#0,STRLEN,#0,AREA,@BLKTAB
				; clear table of base-addresses
	RET


	.SBTTL		Matrix-loading routine
	.PSECT	LOAD
	.ENTRY	LOAD,^M<R2,R3,R4,R5,R6,R7,R8>
				; entry mask
	CLRL	R3		; clear R3 for coming EDIV    
	MOVL	8(AP),R2	; X-coord. to R2+R3
	EDIV	#40,R2,R4,R7	; X of block to R4, X-bit in block to R7
	OUTEST	R4,LENGTH	; X<0 or X>=LENGTH? If so, go to OUT
	MOVL	4(AP),R2	; Y-coord. to R2+R3
	EDIV	#24,R2,R6,R8	; Y of block to R6, Y-bit in block to R8
	OUTEST	R6,WIDTH	; Y<0 or Y>=WIDTH? If so, go to OUT
	MULL2	WIDTH,R4	; calculate the actual...
	ADDL2	R4,R6		; ...number of the block...
	MULL2	#4,R6		; ...and its displ. from table base
	ADDL2	BLKTAB,R6	; ...and the address of its base address
	MULL2	#3,R7		; calculate base byte of field
	TSTL	(R6)		; does the block exist? (is it <>0?)
	BNEQ	DOT		; if it exists, go to DOT
LOOP2:	PUSHL	R6		; address of base-address of block
	PUSHAL	BLKSIZE		; push blocksize address
	CALLS 	#2,G^LIB$GET_VM	; allocate memory
	BLBC	R0,LOOP2	; try again if there isn't any
	MOVC5	#0,STRBASE,#0,BLKSIZE,@0(R6)
				; clear new block (STRBASE serves as a
				; dummy address)
DOT:	INSV	#1,R8,#1,@0(R6)[R7]
				; insert bit at desired location
OUT:	RET


	.SBTTL		Output routine
	.PSECT	DUMP,NOWRT
	.ENTRY	DUMP,^M<R2,R3,R4,R5,R6,R7,R8>
				; entry mask
	MOVC5	#0,STRBASE,#64,#133,@STRBASE
	MOVL	#1,R2		; set end-of-line flag (R2)
	MOVL	EORBLK,R3	; last block of row to R3
	MOVL	WTH4M1,R4	; character counter set to max. (R4)
	MULL3	#3,BITROW,R5	; base-byte of blocks for this line
	CLRL	@STRLEN		; clear string-length buffer
10$:	MOVL	#18,R6		; bit-field counter
20$:	TSTL	(R3)		; does the block exist?
	BNEQ	40$		; if so, go to 40$
	ACBB	#0,#-4,R4,25$	; subtract 4 from R4; goto 25$ if >0
	BRW	60$		; BLSS 60$ impossible (displ. too large)
25$:	SUBL2	#4,R3		; point R3 to address of next block
	BRB	20$		; check next block
40$:	EXTZV	R6,#6,@0(R3)[R5],R7
				; extract value and put it in R7
	BEQL	52$		; if R7=0 go to 52$
	BLBC	R2,45$		; skip next bit if R2 clear
	ADDL3	#1,R4,R8	; index for plot-indicator
	CLRL	R2		; clear R2 flag
;************************************************************************
;************************************************************************
;*****THE FOLLOWING THREE LINES OF CODE SHOULD BE DELETED IF YOUR********
;*****PRINTER'S DEVICE HANDLER PASSES THE <DEL> CHARACTER.  SEE**********
;*****THE VPLOT GUIDE FOR FURTHER INFORMATION...*************************
;************************************************************************
45$:	CMPL	#63,R7		; contents of field=63?
	BNEQ	50$		; if not, skip next part
	MOVL	#191,R7		; substitute 191 for the field's content
;************************************************************************
;************************************************************************
50$:	ADDL2	#64,R7		; set the #7 bit required for plot-mode
	MOVB	R7,@STRBASE[R4]	; move data byte to the character-string
52$:	DECL	R4		; next character
	BLSS	57$		; branch to 57$ if out of characters
	ACBB	#0,#-6,R6,40$	; decrement field-counter; to 40$ if>=0
	CMPL	BITROW,#39	; does BITROW indicate that this is the
				; last row in the block?
	BNEQ	55$		; if not, skip this next part
	FREEBLK	R3,BLKSIZE	; call macro to return the block's
				; memory
55$:	SUBL2	#4,R3		; move block-counter to next block
	BRW	10$		; branch to 10$
57$:	CMPL	#39,BITROW	; last row in block?
	BNEQ	60$		; if not, to 60$
	FREEBLK	R3,BLKSIZE	; else, return block
60$:	INCL	BITROW		; next bit-row
	CMPL	#40, BITROW	; BITROW=40?
	BNEQ	70$		; exit if not, else...
	CLRL	BITROW		; BITROW=0
	ADDL2	WTH4,EORBLK	; set EORBLK to end of next line
	CMPL	EORBLK,TABEND	; beyond end of block-table?
	BLEQ	70$		; exit if not
	CLRB	@LASTADR	; set end-of-plot indicator
	MOVL	BLKTAB,R3
	FREEBLK	R3,AREA		; return block-table
70$:	BLBC	R2,LEAVE
	MOVL	R2,R8
LEAVE:	MOVB	#5,@STRBASE[R8]
	ADDL3	#1,R8,@STRLEN
	RET
	.END
