; TfsA.Asm -- assembly-language code
; Copyright Xerox Corporation 1979, 1980, 1981

;	Last modified May 1, 1981  3:28 PM by Taft

.ent TFSRealDA, TFSVirtualDA, TFSIncrement
.ent TFSModShift, TFSModShiftA, TFSSilentBoot

; offsets in TFSDSK structure defined in Tfs.d

nHeads = 26.
nSectors = 27.
firstVTrack = 48.
nVTracks = 49.

.srel

TFSRealDA: .TFSRealDA
TFSVirtualDA: .TFSVirtualDA
TFSIncrement: .TFSIncrement
TFSModShift: .TFSModShift
TFSModShiftA: .TFSModShiftA
TFSSilentBoot: .TFSSilentBoot

.nrel


; TFSIncrement(lvCounter)
; Increments a double-precision counter

.TFSIncrement:
	inc 0 0			; point to low-order word
	sta 0 2 2
	isz @2 2		; increment it
	 jmp 1 3		; no overflow
	dsz 2 2			; overflow, point to high-order word
	isz @2 2		; increment it
	 jmp 1 3
	jmp 1 3

; TFSModShift(num, ref)
; Calls microcode to assist with ECC correction

.TFSModShift:
	sta 0 1 2
	sta 1 2 2
	inc 2 0			; lv num
	lda 1 c21		; ram address of microcode routine
	#61010			; jmpram
	jmp 1 3

c21:	21

; TFSModShiftA(num, ref)
; Assembly-language version -- for D-machines where there is no
; microcoded routine.

.TFSModShiftA:
	sta 3 1 2
	mkzero 3 3
	sta 3 2 2		; init result to zero
modsh1:	sne 0 1			; num eq ref?
	 jmp modsh3		; yes
	movzl 0 0		; num = num lshift 1
	lda 3 c4000		; if (num & 4000B) ne 0 then...
	and# 3 0 snr
	 jmp modsh2
	lda 3 c4005		; ... num = num xor 4005B
	andzl 0 3
	sub 3 0
	lda 3 c4005
	add 3 0
modsh2:	isz 2 2			; count = count+1
	 jmp modsh1
	dsz 2 2			; return -1 if infinite loop

modsh3:	lda 0 2 2
	lda 3 1 2
	jmp 1 3

c4000:	4000
c4005:	4005

; TFSRealDA(disk, virtualDA, lvRealDA)
; Converts virtualDA to a real DA and stores it in @lvRealDA.
; Returns true iff the virtual DA appears to be legal.
; A virtual DA of eofDA (-1) results in a real DA of zero.

.TFSRealDA:
	sta 3 1 2
	com 1 3 snr		; eofDA?
	 jmp eofDA		; yes, return real DA of zero
	sta 0 2 2		; save disk in frame
	mov 2 3			; keep frame in ac3

; Compute sector
	lda 2 2 3		; disk
	lda 2 nSectors 2	; get sectors per track
	mkzero 0 0
	div			; ac0 ← remainder, ac1 ← quotient
	 #77400
	sta 0 @3 3		; store sector number here temporarily

; Compute head
	lda 2 2 3		; disk
	lda 2 nHeads 2		; get heads per cylinder
	mkzero 0 0
	div			; ac0 ← remainder, ac1 ← quotient
	 #77400
	movs 0 0		; put head number in left byte
	lda 2 @3 3		; combine with sector
	add 2 0
	lda 2 3 3		; get realDA pointer
	sta 0 1 2		; store head and sector in second word

; Compute cylinder
	lda 2 2 3		; disk
	lda 0 firstVTrack 2	; first cylinder used in file system
	add 1 0
	sta 0 @3 3		; store cylinder number in real DA

; Check legality of virtual disk address
	lda 0 nVTracks 2	; number of cylinders used in file system
	mov 3 2			; recover frame
	sge 1 0			; cylinder number in bounds?
rtrue:	 mkminusone 0 0 skp	; yes, return true
	 mkzero 0 0		; no, return false
	lda 3 1 2
	jmp 1 3

eofDA:	sta 3 @3 2		; set real DA to zero
	isz 3 2
	sta 3 @3 2
	jmp rtrue

; TFSVirtualDA(disk, lvRealDA)
; Returns virtual DA corresponding to real DA at @lvRealDA.
; Returns fillInDA if the real DA is not contained in this file system.
; Returns eofDA for physical page zero (this facilitates EOF detection).

.TFSVirtualDA:
	sta 3 1 2
	sta 0 2 2		; disk
	mov 2 3			; keep frame in ac3
	mov 1 2			; lvRealDA

; Check for physical page zero
	lda 1 0 2		; lvRealDA>>DA.track
	lda 0 1 2		; lvRealDA>>DA.head and sector
	add# 0 1 snr		; sum will be zero iff both words are zero,
				; because legal DAs have both words positive
	 jmp reofDA		; go return eofDA

; Offset track by start of file system, and check for track in bounds
	sta 0 3 3		; save head and sector for later
	lda 2 2 3		; disk
	lda 0 firstVTrack 2
	sub 0 1			; ac1 ← file system relative track
	lda 0 nVTracks 2	; in bounds?
	sltu 1 0
	 jmp fillInDA		; no

; Check for head in bounds, and compute track*nHeads + head
	lda 0 3 3		; recover head and sector
	lda 2 c377
	and 0 2			; ac2 ← sector
	subs 2 0		; ac0 ← head
	sta 2 3 3		; save sector for later
	lda 2 2 3		; head in bounds?
	lda 2 nHeads 2
	sltu 0 2
	 jmp fillInDA		; no
	mul			; ac1 ← ac1*ac2 + ac0

; Check for sector in bounds, and compute (previous result)*nSectors + sector
	lda 0 3 3		; recover sector
	lda 2 2 3		; sector in bounds?
	lda 2 nSectors 2
	sltu 0 2
	 jmp fillInDA
	mul			; ac1 ← ac1*ac2 + ac0
	mov 1 0			; this is the result
tfsvdr:	mov 3 2			; restore frame
	lda 3 1 2
	jmp 1 3

reofDA:	adc 0 0 skp		; return eofDA = -1
fillInDA: adczl 0 0		; return fillInDA = -2
	jmp tfsvdr

c377:	377


; TFSSilentBoot()
; Does a silent boot to get Trident tasks out of the Ram

.TFSSilentBoot:
	adczl 0 0		; AC0 ← #177776
	lda 1 c22
	#61010			; jmpram(22) sets BLV ← AC0
	subzr 0 0		; AC0 ← #100000
	sio			; boot the machine
	jmp 1 3

c22:	22

.end