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.
21 * Phase-lock loop definitions
23 #define HZ 100 /* timer interrupt frequency (Hz) */
24 #define MAXPHASE 512000 /* max phase error (us) */
25 #define MAXFREQ 200 /* max frequency error (ppm) */
26 #define TAU 2 /* time constant (shift 0 - 6) */
27 #define POLL 16 /* interval between updates (s) */
28 #define MAXSEC 1200 /* max interval between updates (s) */
31 * Function declarations
35 void second_overflow();
40 int tick; /* timer interrupt period (us) */
41 int fixtick; /* amortization constant (ppm) */
42 struct timeval timex; /* ripoff of kernel time variable */
45 * Phase-lock loop variables
47 int time_status = TIME_BAD; /* clock synchronization status */
48 long time_offset = 0; /* time adjustment (us) */
49 long time_constant = 0; /* pll time constant */
50 long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
51 long time_precision = 1000000 / HZ; /* clock precision (us) */
52 long time_maxerror = MAXPHASE; /* maximum error (us) */
53 long time_esterror = MAXPHASE; /* estimated error (us) */
54 long time_phase = 0; /* phase offset (scaled us) */
55 long time_freq = 0; /* frequency offset (scaled ppm) */
56 long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
57 long time_reftime = 0; /* time at last adjustment (s) */
60 * Simulation variables
62 double timey = 0; /* simulation time (us) */
63 long timez = 0; /* current error (us) */
64 long poll_interval = 0; /* poll counter */
67 * Simulation test program
76 fixtick = 1000000 % HZ;
78 timex.tv_usec = MAXPHASE;
81 printf("tick %d us, fixtick %d us\n", tick, fixtick);
82 printf(" time offset freq _offset _freq _adj\n");
85 * Grind the loop until ^C
88 timey += (double)(1000000) / HZ;
92 if (timex.tv_usec >= 1000000) {
93 timex.tv_usec -= 1000000;
97 if (!(poll_interval % POLL)) {
98 timez = (long)timey - timex.tv_usec;
104 printf("%10li%10li%10.2f %08lx %08lx %08lx\n",
106 (double)time_freq / (1 << SHIFT_KF),
107 time_offset, time_freq, time_adj);
114 * This routine simulates the ntp_adjtime() call
116 * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the
117 * maximum interval between updates is 4096 s and the maximum frequency
118 * offset is +-31.25 ms/s.
127 time_offset = offset << SHIFT_UPDATE;
128 mtemp = timex.tv_sec - time_reftime;
129 time_reftime = timex.tv_sec;
133 /* ugly multiply should be replaced */
135 time_freq -= (-offset * mtemp) >>
136 (time_constant + time_constant);
138 time_freq += (offset * mtemp) >>
139 (time_constant + time_constant);
140 ltemp = time_tolerance << SHIFT_KF;
141 if (time_freq > ltemp)
143 else if (time_freq < -ltemp)
145 if (time_status == TIME_BAD)
146 time_status = TIME_OK;
150 * This routine simulates the timer interrupt
155 int ltemp, time_update;
157 time_update = tick; /* computed by adjtime() */
158 time_phase += time_adj;
159 if (time_phase < -FINEUSEC) {
160 ltemp = -time_phase >> SHIFT_SCALE;
161 time_phase += ltemp << SHIFT_SCALE;
162 time_update -= ltemp;
164 else if (time_phase > FINEUSEC) {
165 ltemp = time_phase >> SHIFT_SCALE;
166 time_phase -= ltemp << SHIFT_SCALE;
167 time_update += ltemp;
169 timex.tv_usec += time_update;
173 * This routine simulates the overflow of the microsecond field
175 * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us
176 * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time
177 * contribution is shifted right a minimum of two bits, while the frequency
178 * contribution is a right shift. Thus, overflow is prevented if the
179 * frequency contribution is limited to half the maximum or 15.625 ms/s.
182 second_overflow(void)
186 time_maxerror += time_tolerance;
187 if (time_offset < 0) {
188 ltemp = -time_offset >>
189 (SHIFT_KG + time_constant);
190 time_offset += ltemp;
191 time_adj = -(ltemp <<
192 (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE));
194 ltemp = time_offset >>
195 (SHIFT_KG + time_constant);
196 time_offset -= ltemp;
198 (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
201 time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
203 time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
204 time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ);
206 /* ugly divide should be replaced */
207 if (timex.tv_sec % 86400 == 0) {
208 switch (time_status) {
211 timex.tv_sec--; /* !! */
212 time_status = TIME_OOP;
217 time_status = TIME_OK;
221 time_status = TIME_OK;