
.H 1 "Firefox Clock ERS"

This is a description of how the clocks on Firefox keep time and how they
are calibrated.  The clocks will be calibrated to within .1 ppm (An error
of 1 ppm would cause the clock to gain or loose 2.5 seconds/month.) at the
factory and will not drift by more than ?? ppm for the system clock and
?? ppm for the time of day (TOD) clock.  It will be possible to adjust the
calibration constants with software (in the field) but this should not be
necessary.

The system clock is used to keep time while the machine is powered up and the
TOD clock keeps time when the machine is powered down.  The TOD clock is read at
power up and set to match the system clock when the machine is powered down.


.H 2 "System Clock"

The CR16 interval timer will count at about 15 MHz (assuming that Firefox
has a 30 MHz clock).  PDC_TOD will return
a double-precision floating point value equal to the interval timer
frequency in mega-cycles/second.  This value will be used to calculate
a constant that will be added to the CR16 comparison register each time
there is a timer interrupt.  The constant is calculated by dividing
the interval timer frequency by the desired interrupt frequency (in MHz).

The last value written to CR16 needs to be saved in memory (as opposed to
just reading CR16 to get the value) to insure
that the uncertainty in the interrupt response time does not cause the clock
to drift.  The fractional part of the result of adding the count constant
to CR16 should also be saved to be added into the next value.  This will reduce
the drift due to rounding errors.

.DL
.LI
Example:  If count frequency was 15.005 MHz and the interrupt frequency
was 10 KHz the count constant would be 1500.5.  If the fractional part was
not saved the drift would be .5/1500 (333 ppm) which would be 14 minutes per
month.
.LE

.H 3 "Keeping Accurate Time"

This section discusses an algorithm for keeping accurate time with the CR16
interval timer.  There are three procedures involved.  Some constants have
to be initialized, interval timer comparison register has to be initialized
and the interval timer comparison register has to be updated.

There are four 32 bit words of memory that need to be initialize and updated:
.DS
	count - This is the number of interval timer counts between
                interrupts.
	count_fraction -  This represents the fraction number of counts
		to make it come out exact.
	count_save - This is used to save the last value loaded into
		CR16.
	fraction_save - This is the remainder from the last time the value
		to load into CR16 was calculated.
.DE

It is assumed that the following two double-precision floating point numbers
will be passed to the routine that initializes the constants:

.DS
	clock_freq - The frequency at which CR16 is counted.
	interrupt_freq - The frequency at which CR16 is to interrupt.
.DE

The following algorithm initializes count and count_fraction.  This is only
executed at power up.

.DS
	begin
{Making the most significant bit of temp1 and temp2 0 simplifies 
the algorithm}
	temp1:=(the 31 most significant bits of the fraction part of
		clock_freq)/2
	temp2:=(the 31 most significant bits of the fraction part of
		interrupt_freq)/2
	temp3:= 2 exp (mantissa of clock_freq - mantissa of interrupt_freq)
.DE
.DS
{calculate count by dividing the clock frequency by the interrupt rate}
	count := 0
	while temp3 > 0 do
		begin
		if temp2 < temp1  do
			begin
			count := count+temp3
			temp1 := temp1-temp2
			end
		temp3 := temp3/2
		temp1 := temp1*2
		end
.DE
.DS
{calculate the fractional part by dividing the remainder}
	count_fraction:=0
	temp3 := 2 exp 31
	while temp3 > 0 do
		begin
		if temp2 < temp1  do
			begin
			count_faction:= count_faction+temp3
			temp1 := temp1-temp2
			end
		temp1 := temp1*2
		temp3 := temp3/2
		end
	end
.DE

The following initializes the CR16 counter, count_save, and fraction_save.

.DS
	begin
	count_save := CR16+count
	CR16 := count_save
	fraction_save := count_fraction
	end
.DE

The following updates CR16, count_save, and fraction_save.

.DS
	begin
	fraction_save := fraction_save+count_fraction
	if overflow then count_save := count_save+1
	count_save := count_save+count
	CR16 := count_save
	end
.DE

.H 2 "TOD Clock"

The TOD clock is implemented with a National MM58274.  The data sheet should
be consulted for details on how to set and read the time.  The TOD clock
keeps time in years, months, days, hours, minutes, and seconds.  The PDC
must translate this into seconds when it reads the time and back to
the TOD format from seconds when it sets the time.  A calibration
constant will be saved in the EEPROM.  This will allow an inexpensive,
low accuracy crystal to be used with the clock chip without the problems
of a trimmer capacitor and still enable it to keep very accurate time.

.H 3 "Setting The TOD Clock"

The following things are done to set the TOD clock:
.AL
.LI
The time is received by the PDC as seconds since 00:00:00, January 1, 1970.
(The microseconds word is ignored.)
.LI
This number is multiplied by the inverse of the calibration constant.  The
inverse of the calibration constant will be stored along with the calibration
constant so that the PDC does not have to do a divide.
.LI
The seconds are converted to the TOD clock chip format.
.LI
The time is written to the TOD clock chip.
.LE

.H 3 "Reading the TOD Clock"

The following steps are taken to read the TOD clock:
.AL
.LI
The TOD clock is read.
.LI
The TOD clock chip format is converted to seconds since 00:00:00, January 1,
1970.
.LI
This value is multiplied by the calibration constant.
.LI
The microseconds word is set to zero.
.LE

If it takes a long time to read and write the clock it may be necessary
to add an offset when the clock is read and written to keep the clock
from drifting

