Annotation of embedaddon/ntp/util/kern.c, revision 1.1.1.1

1.1       misho       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: 
                      7: #ifdef HAVE_CONFIG_H
                      8: # include <config.h>
                      9: #endif
                     10: 
                     11: #include <stdio.h>
                     12: #include <ctype.h>
                     13: #include <math.h>
                     14: #include <sys/time.h>
                     15: 
                     16: #ifdef HAVE_TIMEX_H
                     17: # include "timex.h"
                     18: #endif
                     19: 
                     20: /*
                     21:  * Phase-lock loop definitions
                     22:  */
                     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) */
                     29: 
                     30: /*
                     31:  * Function declarations
                     32:  */
                     33: void hardupdate();
                     34: void hardclock();
                     35: void second_overflow();
                     36: 
                     37: /*
                     38:  * Kernel variables
                     39:  */
                     40: int tick;                      /* timer interrupt period (us) */
                     41: int fixtick;                   /* amortization constant (ppm) */
                     42: struct timeval timex;          /* ripoff of kernel time variable */
                     43: 
                     44: /*
                     45:  * Phase-lock loop variables
                     46:  */
                     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) */
                     58: 
                     59: /*
                     60:  * Simulation variables
                     61:  */
                     62: double timey = 0;              /* simulation time (us) */
                     63: long timez = 0;                        /* current error (us) */
                     64: long poll_interval = 0;                /* poll counter */
                     65: 
                     66: /*
                     67:  * Simulation test program
                     68:  */
                     69: int
                     70: main(
                     71:        int argc,
                     72:        char *argv[]
                     73:        )
                     74: {
                     75:        tick = 1000000 / HZ;
                     76:        fixtick = 1000000 % HZ;
                     77:        timex.tv_sec = 0;
                     78:        timex.tv_usec = MAXPHASE;
                     79:        time_freq = 0;
                     80:        time_constant = TAU;
                     81:        printf("tick %d us, fixtick %d us\n", tick, fixtick);
                     82:        printf("      time    offset      freq   _offset     _freq      _adj\n");
                     83: 
                     84:        /*
                     85:         * Grind the loop until ^C
                     86:         */
                     87:        while (1) {
                     88:                timey += (double)(1000000) / HZ;
                     89:                if (timey >= 1000000)
                     90:                    timey -= 1000000;
                     91:                hardclock();
                     92:                if (timex.tv_usec >= 1000000) {
                     93:                        timex.tv_usec -= 1000000;
                     94:                        timex.tv_sec++;
                     95:                        second_overflow();
                     96:                        poll_interval++;
                     97:                        if (!(poll_interval % POLL)) {
                     98:                                timez = (long)timey - timex.tv_usec;
                     99:                                if (timez > 500000)
                    100:                                    timez -= 1000000;
                    101:                                if (timez < -500000)
                    102:                                    timez += 1000000;
                    103:                                hardupdate(timez);
                    104:                                printf("%10li%10li%10.2f  %08lx  %08lx  %08lx\n",
                    105:                                       timex.tv_sec, timez,
                    106:                                       (double)time_freq / (1 << SHIFT_KF),
                    107:                                       time_offset, time_freq, time_adj);
                    108:                        }
                    109:                }
                    110:        }
                    111: }
                    112: 
                    113: /*
                    114:  * This routine simulates the ntp_adjtime() call
                    115:  *
                    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.
                    119:  */
                    120: void
                    121: hardupdate(
                    122:        long offset
                    123:        )
                    124: {
                    125:        long ltemp, mtemp;
                    126: 
                    127:        time_offset = offset << SHIFT_UPDATE;
                    128:        mtemp = timex.tv_sec - time_reftime;
                    129:        time_reftime = timex.tv_sec;
                    130:        if (mtemp > MAXSEC)
                    131:            mtemp = 0;
                    132: 
                    133:        /* ugly multiply should be replaced */
                    134:        if (offset < 0)
                    135:            time_freq -= (-offset * mtemp) >>
                    136:                    (time_constant + time_constant);
                    137:        else
                    138:            time_freq += (offset * mtemp) >>
                    139:                    (time_constant + time_constant);
                    140:        ltemp = time_tolerance << SHIFT_KF;
                    141:        if (time_freq > ltemp)
                    142:            time_freq = ltemp;
                    143:        else if (time_freq < -ltemp)
                    144:            time_freq = -ltemp;
                    145:        if (time_status == TIME_BAD)
                    146:            time_status = TIME_OK;
                    147: }
                    148: 
                    149: /*
                    150:  * This routine simulates the timer interrupt
                    151:  */
                    152: void
                    153: hardclock(void)
                    154: {
                    155:        int ltemp, time_update;
                    156: 
                    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;
                    163:        }
                    164:        else if (time_phase > FINEUSEC) {
                    165:                ltemp = time_phase >> SHIFT_SCALE;
                    166:                time_phase -= ltemp << SHIFT_SCALE;
                    167:                time_update += ltemp;
                    168:        }
                    169:        timex.tv_usec += time_update;
                    170: }
                    171: 
                    172: /*
                    173:  * This routine simulates the overflow of the microsecond field
                    174:  *
                    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.
                    180:  */
                    181: void
                    182: second_overflow(void)
                    183: {
                    184:        int ltemp;
                    185: 
                    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));
                    193:        } else {
                    194:                ltemp = time_offset >>
                    195:                        (SHIFT_KG + time_constant);
                    196:                time_offset -= ltemp;
                    197:                time_adj = ltemp <<
                    198:                        (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
                    199:        }
                    200:        if (time_freq < 0)
                    201:            time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
                    202:        else
                    203:            time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
                    204:        time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ);
                    205: 
                    206:        /* ugly divide should be replaced */
                    207:        if (timex.tv_sec % 86400 == 0) {
                    208:                switch (time_status) {
                    209: 
                    210:                    case TIME_INS:
                    211:                        timex.tv_sec--; /* !! */
                    212:                        time_status = TIME_OOP;
                    213:                        break;
                    214: 
                    215:                    case TIME_DEL:
                    216:                        timex.tv_sec++;
                    217:                        time_status = TIME_OK;
                    218:                        break;
                    219: 
                    220:                    case TIME_OOP:
                    221:                        time_status = TIME_OK;
                    222:                        break;
                    223:                }
                    224:        }
                    225: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>