; MPattern.asm -- Data pattern generator initialized by MDEBUG.BCPL and
; used in the "Test" overlay and elsewhere.  MUST BE RESIDENT because
; RanTab has to be resident.
;	Last editted 5 June 1979

.get "MAsmCommon.d"

; MASM
.bextz MSave2,MCount

; MDATA
.bextz ShouldBe,DataWas,BitsChecked
.bextz LoopCount,CurrentAddress,NDWords
.bext BitsPicked,BitsDropped,AddrUnion,AddrIntersect,TestFailures

; Defined here
.bext NextData,CheckData,RanTab,RanLen,IncV
.bextz RANDIX,PATTERN

.zrel

RANDIX:		33.
PATTERN:	0

.srel

NextData:	.NextData	; Procedure to generate next data pattern
CheckData:	.CheckData	; Procedure to check results
IncV:		.IncV		; Vector loaded with a 1 in the right-most
RanTab:		.RanTab		; Random number data vector
RanLen:		33.		; Length of random no. data vector

.nrel

;and CheckData() = valof
;[	DoubleAdd(LoopCount,LongOne)
;	for I = 0 to NDWords-1 do
;	[ if ((ShouldBe!I xor DataWas!I) & BitsChecked!I) ne 0 then
;	  [ DoubleAdd(TestFailures,LongOne)
;	    for J = 0 to 1 do
;	    [ AddrUnion!J = AddrUnion!J % CurrentAddress!J
;	      AddrIntersect!J = AddrIntersect!J & CurrentAddress!J
;	    ]
;	    for J = 0 to NDWords-1 do
;	    [ BitsPicked!J = BitsPicked!J % (DataWas!J & not ShouldBe!J)
;	      BitsDropped!J = BitsDropped!J % (ShouldBe!J & not DataWas!J)
;	    ]
;	    resultis true
;	  ]
;	]
;	resultis false
;]

.CheckData:
	sta 3 1 2
	lda 3 LoopCount
	isz 1 3		; Increment LoopCount (double-precision)
	jmp .+3
	isz 0 3
	jmp .+1
	lda 0 NDWords
	sta 0 2 2

CDlp1:	lda 3 DataWas
	lda 0 2 2	; Word count
	add 0 3
	lda 1 -1 3	; 1/ DataWas!I
	lda 3 ShouldBe
	add 0 3
	lda 0 -1 3	; 0/ ShouldBe!I
	mov 0 3		; Xor = A+B-2*(A & B)
	andzl 1 3
	add 1 0
	sub 3 0		; 0/ ShouldBe!I xor DataWas!I
	lda 3 BitsChecked
	lda 1 2 2
	add 1 3
	lda 1 -1 3	; 1/ BitsChecked!I
	and# 1 0 szr	; (DataWas!I xor ShouldBe!I) & (BitsChecked!I eq 0)
	jmp CDfail
	dsz 2 2
	jmp CDlp1
	jmp CDret

CDfail:	sta 2 MSave2
	lda 3 CurrentAddress
	lda 2 @lvAddrIntersect
	lda 0 0 2	; AddrIntersect = AddrIntersect & CurrentAddess
	lda 1 0 3
	and 1 0
	sta 0 0 2
	lda 0 1 2
	lda 1 1 3
	and 1 0
	sta 0 1 2

	lda 2 @lvAddrUnion
	lda 0 0 2	; AddrUnion = AddrUnion % CurrentAddress
	lda 1 0 3
	com 0 0
	and 0 1
	adc 0 1
	sta 1 0 2
	lda 0 1 2
	lda 1 1 3
	com 0 0
	and 0 1
	adc 0 1
	sta 1 1 2

	lda 0 NDWords
	sta 0 MCount
CDlp2:	lda 0 MCount
	lda 2 ShouldBe
	add 0 2
	lda 1 -1 2	; ShouldBe!J
	lda 3 DataWas
	add 0 3
	lda 0 -1 3	; DataWas!J
	com 0 2
	and 1 2		; 2/ Dropped = ShouldBe!J & not DataWas!J
	com 1 1
	and 1 0		; 0/ Picked = DataWas!J & not ShouldBe!J
	lda 3 @lvBitsPicked
	lda 1 MCount
	add 1 3
	lda 1 -1 3	; BitsPicked!J
	com 0 0
	and 0 1
	adc 0 1
	sta 1 -1 3	; BitsPicked!J = BitsPicked!J % Picked!J
	lda 3 @lvBitsDropped
	lda 1 MCount
	add 1 3
	lda 1 -1 3	; BitsDropped!J
	com 2 0
	and 0 1
	adc 0 1
	sta 1 -1 3	; BitsDropped!J = BitsDropped!J % Dropped!J
	dsz MCount
	jmp CDlp2
	lda 3 @lvFailures
	isz 1 3
	jmp CDFx
	isz 0 3
	jmp CDFx
CDFx:	lda 2 MSave2
	mkminusone 0 0 skp	; return -1 on failure
CDret:	mkzero 0 0	; return 0 on ok
	lda 3 1 2
	jmp 1 3

lvAddrUnion:		AddrUnion
lvAddrIntersect:	AddrIntersect
lvBitsPicked:		BitsPicked
lvBitsDropped:		BitsDropped
lvFailures:		TestFailures

.NextData:
	sta 3 1 2
	sta 2 MSave2
	lda 2 ShouldBe
	lda 1 NDWords
	sta 1 MCount
; Dispatch to routine for selected pattern
	jsr NData1
	 jmp NDret	; Zeroes
	 jmp NDret	; Ones
	 jmp NDcyc1	; Cyc1
	 jmp NDcyc0	; Cyc0
	 jmp NDran	; Random
	 jmp NDseq	; Sequential
	 jmp NDret	; ShouldBe
	 jmp NDalt	; AltZO
	 jmp NDalt	; AltShouldBe
NData1:	lda 0 PATTERN
	add 0 3
	jmp 0 3

NDalt:	lda 0 0 2
	com 0 0
	sta 0 0 2
	inc 2 2
	dsz MCount
	jmp NDalt
	jmp NDret

NDcyc0:	mkminusone 3 3
	lda 0 0 2
	movl# 0 0 snc	; Skip if bit cycled into low word will be 1
	jmp CopyNI	; Otherwise, reinitialize the pattern
	add 1 2		; 2/ ShouldBe+NDWords
Cyc1B:	add 3 2
	lda 0 0 2
	movol 0 0 snc
	jmp Cyc0
Cyc1:	sta 0 0 2
	dsz MCount
	jmp Cyc1B
	jmp NDret

Cyc0S:	mkminusone 3 3
	add 1 2
Cyc0B:	add 3 2
	lda 0 0 2
	movzl 0 0 szr
	jmp Cyc1
Cyc0:	sta 0 0 2
	dsz MCount
	jmp Cyc0B
	jmp NDret

lvIncV:	IncV

NDcyc1:	lda 0 0 2
	movl# 0 0 snc	; Skip if the 1 is being cycled off the left end
	jmp Cyc0S	; No, normal cycling
CopyNI:	lda 3 @lvIncV
CopyI:	lda 0 0 3
	sta 0 0 2
	inc 2 2
	inc 3 3
	dsz MCount
	jmp CopyI
	jmp NDret

NDseq:	jsr NDseq1
.IncV:	 0		; This vec is filled in with 1 in the least sig.
	 0		; bit of the DVec
	 0
	 0
	 0
	 0
	 0
; Do next sum with incoming carry = 0
sc00:	mkminusone 1 1
NDseq1:	add 1 2		; ShouldBe+NDWords
	add 1 3		; IncV+NDWords
	lda 0 -1 2	; Low-order ShouldBe word
	lda 1 -1 3	; Low-order IncV word
	addz 1 0 szc	; Low-order sum
	jmp seqc1
seqc0:	sta 0 -1 2
	dsz MCount
	jmp sc00
NDret:	lda 2 MSave2
	lda 3 1 2
	jmp 1 3

; Do next sum with incoming carry = 1
sc11:	mkminusone 1 1
	add 1 2
	add 1 3
	lda 0 -1 2
	incz 0 0
	lda 1 -1 3
	add 1 0 snc
	jmp seqc0
seqc1:	sta 0 -1 2
	dsz MCount
	jmp sc11
	jmp NDret

R7:	7

; Random no. generator does x[n] = (x[n-33] + x[n-13]) mod 2↑16
; which should have a period .g. 2↑33 and passes usual tests for
; randomness
NDran:	jsr ran1
.RanTab:
	160315
	 34255
	 43770
	104071
	 21360
	135442
	 45545
	106565
	  6714
	133667
	176741
	 12402
	114375
	 36624
	 34427
	105045
	146515
	 63276
	 36434
	 67771
	127054
	 77772
	 26244
	171113
	164223
	114267
	132355
	146005
	 44600
	 41705
	144466
	131235
	 31377

ran1:	lda 0 RANDIX	; Get index (counts toward 0)
	add 0 3		; Point to table entry +1
	lda 1 d20	; Is x[n-13] ahead or behind us in table?
	sgt 0 1
	 jmp ran2
	lda 1 -21. 3	; x[n-13] from ahead of us (lower address)
	jmp ran3

ran2:	lda 1 12. 3	; x[n-13] from behind us (higher address)
ran3:	lda 0 -1 3	; Add x[n-33]
	add 1 0
	sta 0 -1 3	; Result
	sta 0 0 2
	dsz RANDIX
	 jmp .+3
	lda 1 d33
	sta 1 RANDIX
	inc 2 2
	dsz MCount	; Loop over TValSize words
	jmp NDran
	jmp NDret

d20:	20.
d33:	33.

.end