kern.c revision 54359
1/*
2 * This program simulates a first-order, type-II phase-lock loop using
3 * actual code segments from modified kernel distributions for SunOS,
4 * Ultrix and OSF/1 kernels. These segments do not use any licensed code.
5 */
6#ifdef HAVE_CONFIG_H
7# include <config.h>
8#endif
9
10#include <stdio.h>
11#include <ctype.h>
12#include <math.h>
13#include <sys/time.h>
14
15#ifdef HAVE_TIMEX_H
16# include "timex.h"
17#endif
18
19/*
20 * Phase-lock loop definitions
21 */
22#define HZ 100			/* timer interrupt frequency (Hz) */
23#define MAXPHASE 512000		/* max phase error (us) */
24#define MAXFREQ 200		/* max frequency error (ppm) */
25#define TAU 2			/* time constant (shift 0 - 6) */
26#define POLL 16			/* interval between updates (s) */
27#define MAXSEC 1200		/* max interval between updates (s) */
28
29/*
30 * Function declarations
31 */
32void hardupdate();
33void hardclock();
34void second_overflow();
35
36/*
37 * Kernel variables
38 */
39int tick;			/* timer interrupt period (us) */
40int fixtick;			/* amortization constant (ppm) */
41struct timeval timex;		/* ripoff of kernel time variable */
42
43/*
44 * Phase-lock loop variables
45 */
46int time_status = TIME_BAD;	/* clock synchronization status */
47long time_offset = 0;		/* time adjustment (us) */
48long time_constant = 0;		/* pll time constant */
49long time_tolerance = MAXFREQ;	/* frequency tolerance (ppm) */
50long time_precision = 1000000 / HZ; /* clock precision (us) */
51long time_maxerror = MAXPHASE;	/* maximum error (us) */
52long time_esterror = MAXPHASE;	/* estimated error (us) */
53long time_phase = 0;		/* phase offset (scaled us) */
54long time_freq = 0;		/* frequency offset (scaled ppm) */
55long time_adj = 0;		/* tick adjust (scaled 1 / HZ) */
56long time_reftime = 0;		/* time at last adjustment (s) */
57
58/*
59 * Simulation variables
60 */
61double timey = 0;		/* simulation time (us) */
62long timez = 0;			/* current error (us) */
63long poll_interval = 0;		/* poll counter */
64
65/*
66 * Simulation test program
67 */
68int
69main(
70	int argc,
71	char *argv[]
72	)
73{
74	tick = 1000000 / HZ;
75	fixtick = 1000000 % HZ;
76	timex.tv_sec = 0;
77	timex.tv_usec = MAXPHASE;
78	time_freq = 0;
79	time_constant = TAU;
80	printf("tick %d us, fixtick %d us\n", tick, fixtick);
81	printf("      time    offset      freq   _offset     _freq      _adj\n");
82
83	/*
84	 * Grind the loop until ^C
85	 */
86	while (1) {
87		timey += (double)(1000000) / HZ;
88		if (timey >= 1000000)
89		    timey -= 1000000;
90		hardclock();
91		if (timex.tv_usec >= 1000000) {
92			timex.tv_usec -= 1000000;
93			timex.tv_sec++;
94			second_overflow();
95			poll_interval++;
96			if (!(poll_interval % POLL)) {
97				timez = (long)timey - timex.tv_usec;
98				if (timez > 500000)
99				    timez -= 1000000;
100				if (timez < -500000)
101				    timez += 1000000;
102				hardupdate(timez);
103				printf("%10li%10li%10.2f  %08lx  %08lx  %08lx\n",
104				       timex.tv_sec, timez,
105				       (double)time_freq / (1 << SHIFT_KF),
106				       time_offset, time_freq, time_adj);
107			}
108		}
109	}
110}
111
112/*
113 * This routine simulates the ntp_adjtime() call
114 *
115 * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the
116 * maximum interval between updates is 4096 s and the maximum frequency
117 * offset is +-31.25 ms/s.
118 */
119void
120hardupdate(
121	long offset
122	)
123{
124	long ltemp, mtemp;
125
126	time_offset = offset << SHIFT_UPDATE;
127	mtemp = timex.tv_sec - time_reftime;
128	time_reftime = timex.tv_sec;
129	if (mtemp > MAXSEC)
130	    mtemp = 0;
131
132	/* ugly multiply should be replaced */
133	if (offset < 0)
134	    time_freq -= (-offset * mtemp) >>
135		    (time_constant + time_constant);
136	else
137	    time_freq += (offset * mtemp) >>
138		    (time_constant + time_constant);
139	ltemp = time_tolerance << SHIFT_KF;
140	if (time_freq > ltemp)
141	    time_freq = ltemp;
142	else if (time_freq < -ltemp)
143	    time_freq = -ltemp;
144	if (time_status == TIME_BAD)
145	    time_status = TIME_OK;
146}
147
148/*
149 * This routine simulates the timer interrupt
150 */
151void
152hardclock(void)
153{
154	int ltemp, time_update;
155
156	time_update = tick;	/* computed by adjtime() */
157	time_phase += time_adj;
158	if (time_phase < -FINEUSEC) {
159		ltemp = -time_phase >> SHIFT_SCALE;
160		time_phase += ltemp << SHIFT_SCALE;
161		time_update -= ltemp;
162	}
163	else if (time_phase > FINEUSEC) {
164		ltemp = time_phase >> SHIFT_SCALE;
165		time_phase -= ltemp << SHIFT_SCALE;
166		time_update += ltemp;
167	}
168	timex.tv_usec += time_update;
169}
170
171/*
172 * This routine simulates the overflow of the microsecond field
173 *
174 * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us
175 * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time
176 * contribution is shifted right a minimum of two bits, while the frequency
177 * contribution is a right shift. Thus, overflow is prevented if the
178 * frequency contribution is limited to half the maximum or 15.625 ms/s.
179 */
180void
181second_overflow(void)
182{
183	int ltemp;
184
185	time_maxerror += time_tolerance;
186	if (time_offset < 0) {
187		ltemp = -time_offset >>
188			(SHIFT_KG + time_constant);
189		time_offset += ltemp;
190		time_adj = -(ltemp <<
191			     (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE));
192	} else {
193		ltemp = time_offset >>
194			(SHIFT_KG + time_constant);
195		time_offset -= ltemp;
196		time_adj = ltemp <<
197			(SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
198	}
199	if (time_freq < 0)
200	    time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
201	else
202	    time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
203	time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ);
204
205	/* ugly divide should be replaced */
206	if (timex.tv_sec % 86400 == 0) {
207		switch (time_status) {
208
209		    case TIME_INS:
210			timex.tv_sec--; /* !! */
211			time_status = TIME_OOP;
212			break;
213
214		    case TIME_DEL:
215			timex.tv_sec++;
216			time_status = TIME_OK;
217			break;
218
219		    case TIME_OOP:
220			time_status = TIME_OK;
221			break;
222		}
223	}
224}
225