Annotation of embedaddon/ntp/util/kern.c, revision 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>