4 * This program simulates a first-order, type-II phase-lock loop using
5 * actual code segments from modified kernel distributions for SunOS,
6 * Ultrix and OSF/1 kernels. These segments do not use any licensed code.
23 * Phase-lock loop definitions
25 #define HZ 100 /* timer interrupt frequency (Hz) */
26 #define MAXPHASE 512000 /* max phase error (us) */
27 #define MAXFREQ 200 /* max frequency error (ppm) */
28 #define TAU 2 /* time constant (shift 0 - 6) */
29 #define POLL 16 /* interval between updates (s) */
30 #define MAXSEC 1200 /* max interval between updates (s) */
33 * Function declarations
37 void second_overflow();
42 int tick
; /* timer interrupt period (us) */
43 int fixtick
; /* amortization constant (ppm) */
44 struct timeval timex
; /* ripoff of kernel time variable */
47 * Phase-lock loop variables
49 int time_status
= TIME_BAD
; /* clock synchronization status */
50 long time_offset
= 0; /* time adjustment (us) */
51 long time_constant
= 0; /* pll time constant */
52 long time_tolerance
= MAXFREQ
; /* frequency tolerance (ppm) */
53 long time_precision
= 1000000 / HZ
; /* clock precision (us) */
54 long time_maxerror
= MAXPHASE
; /* maximum error (us) */
55 long time_esterror
= MAXPHASE
; /* estimated error (us) */
56 long time_phase
= 0; /* phase offset (scaled us) */
57 long time_freq
= 0; /* frequency offset (scaled ppm) */
58 long time_adj
= 0; /* tick adjust (scaled 1 / HZ) */
59 long time_reftime
= 0; /* time at last adjustment (s) */
62 * Simulation variables
64 double timey
= 0; /* simulation time (us) */
65 long timez
= 0; /* current error (us) */
66 long poll_interval
= 0; /* poll counter */
69 * Simulation test program
78 fixtick
= 1000000 % HZ
;
80 timex
.tv_usec
= MAXPHASE
;
83 printf("tick %d us, fixtick %d us\n", tick
, fixtick
);
84 printf(" time offset freq _offset _freq _adj\n");
87 * Grind the loop until ^C
90 timey
+= (double)(1000000) / HZ
;
94 if (timex
.tv_usec
>= 1000000) {
95 timex
.tv_usec
-= 1000000;
99 if (!(poll_interval
% POLL
)) {
100 timez
= (long)timey
- timex
.tv_usec
;
106 printf("%10li%10li%10.2f %08lx %08lx %08lx\n",
108 (double)time_freq
/ (1 << SHIFT_KF
),
109 time_offset
, time_freq
, time_adj
);
116 * This routine simulates the ntp_adjtime() call
118 * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the
119 * maximum interval between updates is 4096 s and the maximum frequency
120 * offset is +-31.25 ms/s.
129 time_offset
= offset
<< SHIFT_UPDATE
;
130 mtemp
= timex
.tv_sec
- time_reftime
;
131 time_reftime
= timex
.tv_sec
;
135 /* ugly multiply should be replaced */
137 time_freq
-= (-offset
* mtemp
) >>
138 (time_constant
+ time_constant
);
140 time_freq
+= (offset
* mtemp
) >>
141 (time_constant
+ time_constant
);
142 ltemp
= time_tolerance
<< SHIFT_KF
;
143 if (time_freq
> ltemp
)
145 else if (time_freq
< -ltemp
)
147 if (time_status
== TIME_BAD
)
148 time_status
= TIME_OK
;
152 * This routine simulates the timer interrupt
157 int ltemp
, time_update
;
159 time_update
= tick
; /* computed by adjtime() */
160 time_phase
+= time_adj
;
161 if (time_phase
< -FINEUSEC
) {
162 ltemp
= -time_phase
>> SHIFT_SCALE
;
163 time_phase
+= ltemp
<< SHIFT_SCALE
;
164 time_update
-= ltemp
;
166 else if (time_phase
> FINEUSEC
) {
167 ltemp
= time_phase
>> SHIFT_SCALE
;
168 time_phase
-= ltemp
<< SHIFT_SCALE
;
169 time_update
+= ltemp
;
171 timex
.tv_usec
+= time_update
;
175 * This routine simulates the overflow of the microsecond field
177 * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us
178 * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time
179 * contribution is shifted right a minimum of two bits, while the frequency
180 * contribution is a right shift. Thus, overflow is prevented if the
181 * frequency contribution is limited to half the maximum or 15.625 ms/s.
184 second_overflow(void)
188 time_maxerror
+= time_tolerance
;
189 if (time_offset
< 0) {
190 ltemp
= -time_offset
>>
191 (SHIFT_KG
+ time_constant
);
192 time_offset
+= ltemp
;
193 time_adj
= -(ltemp
<<
194 (SHIFT_SCALE
- SHIFT_HZ
- SHIFT_UPDATE
));
196 ltemp
= time_offset
>>
197 (SHIFT_KG
+ time_constant
);
198 time_offset
-= ltemp
;
200 (SHIFT_SCALE
- SHIFT_HZ
- SHIFT_UPDATE
);
203 time_adj
-= -time_freq
>> (SHIFT_KF
+ SHIFT_HZ
- SHIFT_SCALE
);
205 time_adj
+= time_freq
>> (SHIFT_KF
+ SHIFT_HZ
- SHIFT_SCALE
);
206 time_adj
+= fixtick
<< (SHIFT_SCALE
- SHIFT_HZ
);
208 /* ugly divide should be replaced */
209 if (timex
.tv_sec
% 86400 == 0) {
210 switch (time_status
) {
213 timex
.tv_sec
--; /* !! */
214 time_status
= TIME_OOP
;
219 time_status
= TIME_OK
;
223 time_status
= TIME_OK
;