; @(#)follow.11	1.1 (mg@ukc) 4/9/88
; Follow light pen around with a blob

; Constants about machine.

COREND	= 8.*1024.	; First unusable word
WIDTH	= 1024.		; Height of display
HEIGHT	= 768.		; Width of display

; Address of registers.

DPC     = 172000        ; VT40 Program counter
DSR     = 172002        ; VT40 Status register
XSR     = 172004        ; X status register
YSR     = 172006        ; Y status register

; Addresses of interrupt vectors
STOPVEC = 320
LPVEC	= 324

; Recommended mnemomics for Display processor instructions

CHAR    = 100000        ; Character mode
SHORTV  = 104000        ; Short vector mode
LONGV   = 110000        ; Long vector mode
POINT   = 114000        ; Point mode
GRAPHX  = 120000        ; Graphplot X mode
GRAPHY  = 124000        ; Graphplot Y mode
RELATV  = 130000        ; Relative point mode

INT0    = 2000          ; Intensity modes
INT1    = 2200
INT2    = 2400
INT3    = 2600
INT4    = 3000
INT5    = 3200
INT6    = 3400
INT7    = 3600

LPOFF   = 100           ; Light pen off
LPON    = 140           ; and on

BLKOFF  = 20            ; Blink off
BLKON   = 30            ; and on

LINE0   = 4             ; Solid line
LINE1   = 5             ; Long dash
LINE2   = 6             ; Short dash
LINE3   = 7             ; Dot dash

DJMP    = 160000        ; Display jump
DNOP    = 164000        ; Display NOP

STATSA  = 170000        ; Load status A
DSTOP   = 173400        ; Display stop and interrupt

SINON   = 1400          ; Stop interrupt on
SINOFF  = 1000          ; Stop interrupt off
LPLITE  = 200           ; Light pen hit on
LPDARK  = 300           ; and off

ITAL0   = 40            ; Italics off
ITAL1   = 60            ; and on

SYNC    = 4             ; Halt and resume in Sync

STATSB  = 174000        ; Load status B
INCR    = 100           ; Graphplot increment

INTX    = 40000         ; Intensify vector or point
MAXX    = 1777          ; Max delta-x
MAXY    = 1377          ; Max delta-y

MINUSX  = 20000         ; -ve delta-x
MINUSY  = 20000         ; -ve delta-y

MAXSX   = 17600         ; Max delta-x in short mode
MAXSY   = 77            ; Max delta-y

MISVX   = 20000         ; -ve delta-x
MISVY   = 100           ; -ve delta-y

        .PSECT

;       Simple PDP-11 program

	MOV	#COREND-2,SP	; Set up stack

	; set up interrupt vectors
	MOV	#LPINTR,@#LPVEC	; light pen hit
	MOV	#200,@#LPVEC+2	; new priority = BR4 (exclude further DPU interrupts)

	MOV	#STOPINTR,@#STOPVEC	; display proram stop
	MOV	#200,@#STOPVEC+2	; new priority = BR4

	CLR	XACC
	CLR	YACC
	CLR	NHIT

	; start it off
	MOV	#DLOOP,R5	; restart address
	MOV	#DPC,R4		; cache addr of DPC
	MOV	#DPROG,@#DPC

IDLE:	WAIT		; and hang around
	BR	IDLE

	; Strategy: draw eight lines from around the current centre to the
	; current centre point.  If the pen is pointing at the centre, this
	; will cause 8 light pen hits per display.Add them up, divide by N,
 	; and this gives you the centre of the light pen hit area.

	; total of x- and y-coords of light pen hits (up to eight hits)
XACC:	.WORD	1
YACC:	.WORD	1
NHIT:	.WORD	1	; number of LP hits thie display

LPINTR:
	; Find position of hit
	MOV	@#XSR,R0
	MOV	@#YSR,R1
	; and start display processor again ASAP
	MOV	#1,@R4

	BIC	#176000,R0	; mask out the X position from bits 0..9
	ADD	R0,@#XACC

	BIC	#176000,R1	; mask out the Y position from bits 0..9
	ADD	R1,@#YACC

	INC	@#NHIT

	RTI

; all done.  should have got up to 8 light pen hits during a single display
STOPINTR:
	MOV	NHIT,R1
	BEQ	ENDINTR

	MOV	XACC,R0
	JSR	PC,DIVIDE
	MOV	R0,@#CX

	MOV	@#YACC,R0
	JSR	PC,DIVIDE
	MOV	R0,@#CY

	CLR	XACC
	CLR	YACC
	CLR	NHIT

ENDINTR:
	MOV	R5,@R4	; continue
	RTI


	; R0 := R0 / R1, remainder in R2, R1 is positivised
	; R0 is top, shifted into R2 one bit at a time.
	; R3 is the loop counter.
DIVIDE:
	MOV	R2,-(SP)
	MOV	R3,-(SP)
	TST	R1	; Validate divisor
	BEQ	DIV0	; divide by 0!
	BPL	DIV1
	NEG	R1
DIV1:
	CLR	R2
	MOV	#15.,R3		; 16 iterations
DIV2:
	ASL	R0
	ROL	R2
	CMP	R2,R1		; can we subtract bottom from top?
	BCS	DIV3		; no
	SUB	R1,R2		; yes - do it.
	BIS	#1,R0
DIV3:	DEC	R3
	BPL	DIV2

DIVEND:	MOV	(SP)+,R3
	MOV	(SP)+,R2
	RTS	PC

DIV0:	; divide by 0.  return 0. (any other ideas?)
	CLR	R0
	BR	DIVEND
; end of DIVIDE


DPROG:	STATSA+LPLITE

; Values to change the position by one gooby
DX	= 4000
DY	= 20


DLOOP:	POINT+LPON
CX:	WIDTH/2		; start in the middle
CY:	HEIGHT/2

	; draw 8 radial lines
	SHORTV+INT7
	STATSA+SYNC		; to avoid too-quick refresh

	MISVX+DX+DY+DY		; top left (-1,+2) ...
	INTX+DX+MISVY+DY+DY	; ... and draw to centre

	DX+DY+DY		; top right(+1,+2)
	INTX+MISVX+DX+MISVY+DY+DY

	DX+DX+DY		; right top (+2,+1)
	INTX+MISVX+DX+DX+MISVY+DY

	DX+DX+MISVY+DY		; right bottom (+2,-1)
	INTX+MISVX+DX+DX+DY

	DX+MISVY+DY+DY		; bottom right (+1,-2)
	INTX+MISVX+DX+DY+DY
	
	MISVX+DX+MISVY+DY+DY	; bottom left (-1,-2)
	INTX+DX+DY+DY

	MISVX+DX+DX+MISVY+DY	; left bottom (-2,-1)
	INTX+DX+DX+DY

	MISVX+DX+DX+DY		; left top (-2,+1)
	INTX+DX+DX+MISVY+DY

	DSTOP

	DJMP
	DLOOP

	.END
