; SwatSpyA.asm -- Binary Search -- Companion file is SwatSpyB.bcpl
; Copyright Xerox Corporation 1979, 1981, 1982, 1983
; Last modified October 12, 1983  11:24 AM by Taft

	.titl SwatSpyA

; Ranges[0...Ncounts-1] is an ordered vector of locations
; spy will add into Counts[i] how often pc was found in
; [ Range[i]...Range[i+1] ).
; Appropriate guards are inserted by Swat code
; SwatSpyB.bcpl knows the offsets of variables in this code.

.ent Mul, Div
.bext spyCode, spyCodeEnd

	.srel

spyCode:	.spyCode
spyCodeEnd:	.spyCodeEnd

Mul:		.Mul
Div:		.Div

	.nrel

; *** offsets of these variables is known to SwatSpyB.bcpl ***
.spyCode:
bRanges:	0	; beginning of Ranges
eRanges:	0	; end (+1)  "   "
delta:		0	; Counts-bRanges
ipt:		1	; interrupts per tally 
itnt:		1	; ints till next tally
xmEnabled:	0	; nonzero if XM features are enabled
; *** offsets of these variables is known to SwatSpyB.bcpl ***

start:	dsz itnt	; tally this time?
	 bri		; no
	sta 0 s0	; save Acs and carry
	sta 1 s1
	sta 2 s2
	sta 3 s3
	subcl 0 0
	sta 0 sc
	lda 0 ipt	; restore itnt
	sta 0 itnt
	lda 0 @lvInterruptPC  ; get pc
	lda 1 xmEnabled	; XM features enabled?
	mov# 1 1 snr
	 jmp notXM	; no
	lda 1 lvInterruptXJmp  ; yes, pointing to XM interrupt loc?
	se 0 1
	 jmp intFr0	; no, interrupt from bank 0
	lda 0 @lvInterruptXPC  ; yes, get bank-relative PC
	lda 1 @lvInterruptXJmp  ; get XJMP b instruction
	movr 1 1	; get high 16 bits of 18-bit real PC
	movr 0 0
	movr 1 1
	movr 0 0
	jmp notXM
intFr0:	movzr 0 0	; interrupt from bank 0, just zero bank number
	movzr 0 0
notXM:	lda 1 bRanges	; ac1 = low
	lda 2 eRanges	; ac2 = high = probe
	jmp lower	; look below probe
higher:	inc 2 1		; look above probe (low = probe+1)
	lda 2 shigh
lower:	sgtu 2 1
	 jmp done	; if hi le low then done
	sta 2 shigh
	addzr 1 2	; probe
	lda 3 0,2
	sgeu 0 3	 
	 jmp lower	; missed -- look below probe
	lda 3 1,2	; if key ge probe!0 then maybe found
	sltu 0 3	 
	 jmp higher	; missed -- look above probe
	lda 3 delta	; if key ls probe!1 then found
	add 2 3		; ac3 ← tally location
	isz 0,3		; tally pc
	 jmp done
	lda 2 bRanges	; OVERFLOW of a tally (at least 20 mins.)
	lda 1 eRanges	; Divide all Counts by 2
	lda 0 delta
	add 0 1
	add 0 2
loop1:	sltu 2 1
	 jmp done1
	lda 0 0,2
	movzr 0 0
	sta 0 0,2
	inc 2 2
	jmp loop1
done1:	lda 0 ipt	; and double
	movzl 0 0	; sampling interval
	sta 0 ipt
	sta 0 itnt
	sub 0 0		; set overflower
	movor 0 0	; to 100000b
	sta 0 0,3
done:	lda 0 sc	; restore carry and ACs
	movr 0 0
	lda 0 s0
	lda 1 s1
	lda 2 s2
	lda 3 s3
	bri		; dismiss

s0:		0
s1:		0
s2:		0
s3:		0
sc:		0

shigh:		0
lvInterruptPC:	500
lvInterruptXJmp: 627	; XM: XJMP b -- interruptPC points here
lvInterruptXPC:	630	; XM: real PC (in bank b)
.spyCodeEnd:	0


; Mul(addend, multiplicand, multiplier, lvResult)
; Gives direct access to the "mul" instruction.
; Computes addend + (multiplicand*multiplier) and puts the
; 32-bit unsigned result in @lvResult

.Mul:	sta 3 1,2
	mov 2 3			; put stack pointer here
	lda 2 3,3		; get extra args word
	add 3 2			; compute absolute pointer
	sta 2 3,3		; put it back
	lda 2 3,2		; get third arg (multiplier)
	mul			; ac0 + (ac1*ac2) -> (ac0, ac1)
	mov 3 2			; restore stack pointer
	lda 3 3,2		; get extra args pointer
	lda 3 4,3		; get lvResult
	sta 0 0,3		; store result
	sta 1 1,3
	lda 3 1,2
	jmp 1,3

; Div(lvDividend, divisor, lvRemainder) = quotient
; Gives direct access to the "div" instruction
; @lvDividend is the 32-bit unsigned dividend.
; Computes (@lvDivident)/divisor, puts the remainder in @lvRemainder
; and returns the quotient

.Div:	sta 3 1,2
	sta 1 2,2		; save divisor
	mov 0 3			; lvDividend
	lda 0 0,3		; get dividend into ac0 and ac1
	lda 1 1,3
	mov 2 3			; preserve stack pointer
	lda 2 2,3		; get divisor
	div
	 77400
	mov 3 2			; restore stack pointer
	sta 0 @3,2		; @lvRemainder ← remainder
	mov 1 0
	lda 3 1,2
	jmp 1,3

	.end