; Calendar.asm -- formerly called ReadTmer.asm
; Copyright Xerox Corporation 1979
; Last modified March 28, 1980  11:31 AM by Taft

; Assembly code for reading 1 ms and 1 second calendar clocks
; 	P. Deutsch  31-DEC-74
; Modified by Sproull for Alto I/Alto II compatibility.
; Modified by Taft and Boggs for new Alto time standard.
; Subroutines for converting date-and-time into more useful formats
;  for human consumption are available elsewhere - See Time package.

;outgoing procedures
	.ent ReadCalendar, SetCalendar, Timer
	.ent DayTime, SetDayTime

;incoming procedures
	.bext UpdateTimer

	.srel

ReadCalendar: .ReadCalendar
SetCalendar: .SetCalendar
Timer:	.Timer

SetDayTime: .SetDayTime
DayTime: .DayTime

	.nrel

swat = 77400

;-----------------------------------------------------------------------------
; Timer(tv)
; Reads the 32-bit millisecond timer into tv!0 and tv!1.
; Returns tv!1 as its value.
;-----------------------------------------------------------------------------
.Timer:	sta 3 1,2
	sta 0 3,2	; Save pointer to vector
	lda 1 CMIL0	; Read milliseconds calendar
	jsr GetCal	; Read a calendar and do RCLK
	mov 2 3
	lda 2 MSDIV
	div		; Guaranteed no overflow, Q<~1100
	 swat
; FOLLOWING CODE REMOVED when clock constant changed to 25,,41600
; For exact result, you must subtract 1 from Q if R<0.672Q,
; but under-correcting will still preserve monotonicity
;	movzl 0 2
;	addzr 2 0
;	subz# 0 1 sbn	; Test 1.5R<Q, i.e. R<0.667Q
;	 jmp .+3
;	neg 1 1
;	com 1 1
	mov 3 2
	lda 3 3,2	; Add Q to result
	lda 0 1,3
	addz 1 0,szc	; 32+16 bit add
	 isz 0,3
	 jmp .+1
	sta 0 1,3	; Return low bits
	lda 3 1,2
	jmp 1,3

;-----------------------------------------------------------------------------
; ReadCalendar(dv)
; Reads the current date-and-time (32 bits, with a grain of 1 second)
;  into dv!0 and dv!1.
; Returns dv as its value.
;-----------------------------------------------------------------------------
.DayTime:		; *** Backward compatibility
.ReadCalendar:
	sta 3 1,2
	sta 0 3,2	; Save pointer to vector
	lda 1 CSEC0	; Read seconds calendar
	jsr GetCal
	lda 0 3,2	; Return vector
	lda 3 1,2
	jmp 1,3

;-----------------------------------------------------------------------------
; SetCalendar(dv)
; Set the current date-and-time from dv!0 and dv!1.
;-----------------------------------------------------------------------------
.SetDayTime:		; **** Backward compatibility
.SetCalendar:
	sta 3 1,2
	mov 0 3
	rclk
	sta 0 @RTB0
	lda 0 RTMSK
	and 0 1
	sta 1 @RTB1	; Guarantees no increments of calendar for 1 second
	lda 0 0,3
	sta 0 @CSEC0
	lda 1 1,3
	sta 1 @CSEC1
	sub 0 0
	mov 2 3
	lda 2 THOU
	mul
	sta 1 @CMIL1	; Compute ms calendar
	lda 1 @CSEC0
	mul
	sta 1 @CMIL0
	mov 3 2
	lda 3 1,2
	jmp 1,3

;-----------------------------------------------------------------------------
; GetCalendar - internal subroutine.
;	AC0 => vector for results (v) -- saves in 3,2
;	AC1 => 2 addresses for timer
; Returns additional time in (AC0,AC1) in units of .595 microsec
; *** May retry the call, by starting at call -1 ***
;-----------------------------------------------------------------------------

GetCal:	sta 3 2,2	; Save return address
	sub 0 0
	sio		; See what vintage machine we are on
	movl 0 0 szc
	 jmp AltoI	; "Old" microcode
	vers		; Read version
	lda 3 AltoIIMask
	and 3 0 szr
	 mkzero 3 3 skp	; Alto II
AltoI:	mkminusone 3 3	; Alto I
	dir
	sta 3 AltoType
	sta 1 TEMP	; Pointer to calendar
	lda 3 3,2	; Restore pointer to vector
	lda 0 @TEMP	; First word of calendar
	sta 0 0,3
	isz TEMP
	lda 0 @TEMP	; Second word of calendar
	sta 0 1,3
	rclk
	lda 3 @RTB0
	adc 3 0
	isz AltoType
	 jmp SHL4	; Alto II -- go shift left 4 bits
MSK:	lda 3 RTMSK
	and 3 1
	lda 3 @RTB1
	eir		; Now have all clock values in regs or core
	subz 3 1 szc	; 32-bit subtract
	 inc 0 0
	lda 3 SECHI	; See if need to move seconds
	adcz# 3 0 snc
	 jmp @2,2	; NO -- Return
	dir
	jsrii UDT	; Go move seconds to calendar when needed
TEMP:	 0
	lda 3 2,2
	jmp -2,3	; ***

SHL4:	movzl 1 1
	movzl 1 1
	movzl 1 1
	movzl 1 1
	jmp MSK

AltoType:	0
AltoIIMask:	020000	; 2 or 3 => Alto-II format
			; 0, 1, 4, or 5 => Alto-I format
UDT:		UpdateTimer

; Pointers to reserved page 1 locations
CSEC0:	572	; Seconds calendar
CSEC1:	573
CMIL0:	574	; Milliseconds calendar
CMIL1:	575
RTB0:	576	; Base for RTC
RTB1:	577

; Funny constants
SECHI:	25.	; 1 sec in units of .595 usecs (high order 16 bits)
THOU:	1000.
RTMSK:	-100	; Mask for lower half of hardware clock
MSDIV:	1680.	; 1 ms in units of .595 mics

	.END