Annotation of embedaddon/ntp/clockstuff/chutest.c, revision 1.1.1.1
1.1 misho 1: /* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp
2: * chutest - test the CHU clock
3: */
4:
5: #include <stdio.h>
6: #include <sys/types.h>
7: #include <sys/socket.h>
8: #include <netinet/in.h>
9: #include <sys/ioctl.h>
10: #include <sys/time.h>
11: #include <sys/file.h>
12: #include <sgtty.h>
13:
14: #include "../include/ntp_fp.h"
15: #include "../include/ntp.h"
16: #include "../include/ntp_unixtime.h"
17:
18: #ifdef CHULDISC
19: #ifdef STREAM
20: # ifdef HAVE_SYS_CHUDEFS_H
21: #include <sys/chudefs.h>
22: #endif
23: #include <stropts.h>
24: #endif
25: #endif
26:
27: #ifdef CHULDISC
28: # ifdef HAVE_SYS_CHUDEFS_H
29: #include <sys/chudefs.h>
30: #endif
31: #endif
32:
33: #ifndef CHULDISC
34: #ifndef STREAM
35: #define NCHUCHARS (10)
36:
37: struct chucode {
38: u_char codechars[NCHUCHARS]; /* code characters */
39: u_char ncodechars; /* number of code characters */
40: u_char chustatus; /* not used currently */
41: struct timeval codetimes[NCHUCHARS]; /* arrival times */
42: };
43: #endif
44: #endif
45:
46: #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
47:
48: char *progname;
49: int debug;
50:
51: int dofilter = 0; /* set to 1 when we should run filter algorithm */
52: int showtimes = 0; /* set to 1 when we should show char arrival times */
53: int doprocess = 0; /* set to 1 when we do processing analogous to driver */
54: #ifdef CHULDISC
55: int usechuldisc = 0; /* set to 1 when CHU line discipline should be used */
56: #endif
57: #ifdef STREAM
58: int usechuldisc = 0; /* set to 1 when CHU line discipline should be used */
59: #endif
60:
61: struct timeval lasttv;
62: struct chucode chudata;
63:
64: extern u_long ustotslo[];
65: extern u_long ustotsmid[];
66: extern u_long ustotshi[];
67:
68: /*
69: * main - parse arguments and handle options
70: */
71: int
72: main(
73: int argc,
74: char *argv[]
75: )
76: {
77: int c;
78: int errflg = 0;
79: extern int ntp_optind;
80: extern char *ntp_optarg;
81: void init_chu();
82:
83: progname = argv[0];
84: while ((c = ntp_getopt(argc, argv, "cdfpt")) != EOF)
85: switch (c) {
86: case 'c':
87: #ifdef STREAM
88: usechuldisc = 1;
89: break;
90: #endif
91: #ifdef CHULDISC
92: usechuldisc = 1;
93: break;
94: #endif
95: #ifndef STREAM
96: #ifndef CHULDISC
97: (void) fprintf(stderr,
98: "%s: CHU line discipline not available on this machine\n",
99: progname);
100: exit(2);
101: #endif
102: #endif
103: case 'd':
104: ++debug;
105: break;
106: case 'f':
107: dofilter = 1;
108: break;
109: case 'p':
110: doprocess = 1;
111: case 't':
112: showtimes = 1;
113: break;
114: default:
115: errflg++;
116: break;
117: }
118: if (errflg || ntp_optind+1 != argc) {
119: #ifdef STREAM
120: (void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
121: progname);
122: #endif
123: #ifdef CHULDISC
124: (void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
125: progname);
126: #endif
127: #ifndef STREAM
128: #ifndef CHULDISC
129: (void) fprintf(stderr, "usage: %s [-cdft] tty_device\n",
130: progname);
131: #endif
132: #endif
133: exit(2);
134: }
135:
136: (void) gettimeofday(&lasttv, (struct timezone *)0);
137: c = openterm(argv[ntp_optind]);
138: init_chu();
139: #ifdef STREAM
140: if (usechuldisc)
141: process_ldisc(c);
142: else
143: #endif
144: #ifdef CHULDISC
145: if (usechuldisc)
146: process_ldisc(c);
147: else
148: #endif
149: process_raw(c);
150: /*NOTREACHED*/
151: }
152:
153:
154: /*
155: * openterm - open a port to the CHU clock
156: */
157: int
158: openterm(
159: char *dev
160: )
161: {
162: int s;
163: struct sgttyb ttyb;
164:
165: if (debug)
166: (void) fprintf(stderr, "Doing open...");
167: if ((s = open(dev, O_RDONLY, 0777)) < 0)
168: error("open(%s)", dev, "");
169: if (debug)
170: (void) fprintf(stderr, "open okay\n");
171:
172: if (debug)
173: (void) fprintf(stderr, "Setting exclusive use...");
174: if (ioctl(s, TIOCEXCL, (char *)0) < 0)
175: error("ioctl(TIOCEXCL)", "", "");
176: if (debug)
177: (void) fprintf(stderr, "done\n");
178:
179: ttyb.sg_ispeed = ttyb.sg_ospeed = B300;
180: ttyb.sg_erase = ttyb.sg_kill = 0;
181: ttyb.sg_flags = EVENP|ODDP|RAW;
182: if (debug)
183: (void) fprintf(stderr, "Setting baud rate et al...");
184: if (ioctl(s, TIOCSETP, (char *)&ttyb) < 0)
185: error("ioctl(TIOCSETP, raw)", "", "");
186: if (debug)
187: (void) fprintf(stderr, "done\n");
188:
189: #ifdef CHULDISC
190: if (usechuldisc) {
191: int ldisc;
192:
193: if (debug)
194: (void) fprintf(stderr, "Switching to CHU ldisc...");
195: ldisc = CHULDISC;
196: if (ioctl(s, TIOCSETD, (char *)&ldisc) < 0)
197: error("ioctl(TIOCSETD, CHULDISC)", "", "");
198: if (debug)
199: (void) fprintf(stderr, "okay\n");
200: }
201: #endif
202: #ifdef STREAM
203: if (usechuldisc) {
204:
205: if (debug)
206: (void) fprintf(stderr, "Poping off streams...");
207: while (ioctl(s, I_POP, 0) >=0) ;
208: if (debug)
209: (void) fprintf(stderr, "okay\n");
210: if (debug)
211: (void) fprintf(stderr, "Pushing CHU stream...");
212: if (ioctl(s, I_PUSH, "chu") < 0)
213: error("ioctl(I_PUSH, \"chu\")", "", "");
214: if (debug)
215: (void) fprintf(stderr, "okay\n");
216: }
217: #endif
218: return s;
219: }
220:
221:
222: /*
223: * process_raw - process characters in raw mode
224: */
225: int
226: process_raw(
227: int s
228: )
229: {
230: u_char c;
231: int n;
232: struct timeval tv;
233: struct timeval difftv;
234:
235: while ((n = read(s, &c, sizeof(char))) > 0) {
236: (void) gettimeofday(&tv, (struct timezone *)0);
237: if (dofilter)
238: raw_filter((unsigned int)c, &tv);
239: else {
240: difftv.tv_sec = tv.tv_sec - lasttv.tv_sec;
241: difftv.tv_usec = tv.tv_usec - lasttv.tv_usec;
242: if (difftv.tv_usec < 0) {
243: difftv.tv_sec--;
244: difftv.tv_usec += 1000000;
245: }
246: (void) printf("%02x\t%lu.%06lu\t%lu.%06lu\n",
247: c, tv.tv_sec, tv.tv_usec, difftv.tv_sec,
248: difftv.tv_usec);
249: lasttv = tv;
250: }
251: }
252:
253: if (n == 0) {
254: (void) fprintf(stderr, "%s: zero returned on read\n", progname);
255: exit(1);
256: } else
257: error("read()", "", "");
258: }
259:
260:
261: /*
262: * raw_filter - run the line discipline filter over raw data
263: */
264: int
265: raw_filter(
266: unsigned int c,
267: struct timeval *tv
268: )
269: {
270: static struct timeval diffs[10] = { 0 };
271: struct timeval diff;
272: l_fp ts;
273: void chufilter();
274:
275: if ((c & 0xf) > 9 || ((c>>4)&0xf) > 9) {
276: if (debug)
277: (void) fprintf(stderr,
278: "character %02x failed BCD test\n");
279: chudata.ncodechars = 0;
280: return;
281: }
282:
283: if (chudata.ncodechars > 0) {
284: diff.tv_sec = tv->tv_sec
285: - chudata.codetimes[chudata.ncodechars].tv_sec;
286: diff.tv_usec = tv->tv_usec
287: - chudata.codetimes[chudata.ncodechars].tv_usec;
288: if (diff.tv_usec < 0) {
289: diff.tv_sec--;
290: diff.tv_usec += 1000000;
291: } /*
292: if (diff.tv_sec != 0 || diff.tv_usec > 900000) {
293: if (debug)
294: (void) fprintf(stderr,
295: "character %02x failed time test\n");
296: chudata.ncodechars = 0;
297: return;
298: } */
299: }
300:
301: chudata.codechars[chudata.ncodechars] = c;
302: chudata.codetimes[chudata.ncodechars] = *tv;
303: if (chudata.ncodechars > 0)
304: diffs[chudata.ncodechars] = diff;
305: if (++chudata.ncodechars == 10) {
306: if (doprocess) {
307: TVTOTS(&chudata.codetimes[NCHUCHARS-1], &ts);
308: ts.l_ui += JAN_1970;
309: chufilter(&chudata, &chudata.codetimes[NCHUCHARS-1]);
310: } else {
311: register int i;
312:
313: for (i = 0; i < chudata.ncodechars; i++) {
314: (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
315: chudata.codechars[i] & 0xf,
316: (chudata.codechars[i] >>4 ) & 0xf,
317: chudata.codetimes[i].tv_sec,
318: chudata.codetimes[i].tv_usec,
319: diffs[i].tv_sec, diffs[i].tv_usec);
320: }
321: }
322: chudata.ncodechars = 0;
323: }
324: }
325:
326:
327: /* #ifdef CHULDISC*/
328: /*
329: * process_ldisc - process line discipline
330: */
331: int
332: process_ldisc(
333: int s
334: )
335: {
336: struct chucode chu;
337: int n;
338: register int i;
339: struct timeval diff;
340: l_fp ts;
341: void chufilter();
342:
343: while ((n = read(s, (char *)&chu, sizeof chu)) > 0) {
344: if (n != sizeof chu) {
345: (void) fprintf(stderr, "Expected %d, got %d\n",
346: sizeof chu, n);
347: continue;
348: }
349:
350: if (doprocess) {
351: TVTOTS(&chu.codetimes[NCHUCHARS-1], &ts);
352: ts.l_ui += JAN_1970;
353: chufilter(&chu, &ts);
354: } else {
355: for (i = 0; i < NCHUCHARS; i++) {
356: if (i == 0)
357: diff.tv_sec = diff.tv_usec = 0;
358: else {
359: diff.tv_sec = chu.codetimes[i].tv_sec
360: - chu.codetimes[i-1].tv_sec;
361: diff.tv_usec = chu.codetimes[i].tv_usec
362: - chu.codetimes[i-1].tv_usec;
363: if (diff.tv_usec < 0) {
364: diff.tv_sec--;
365: diff.tv_usec += 1000000;
366: }
367: }
368: (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
369: chu.codechars[i] & 0xf, (chu.codechars[i]>>4)&0xf,
370: chu.codetimes[i].tv_sec, chu.codetimes[i].tv_usec,
371: diff.tv_sec, diff.tv_usec);
372: }
373: }
374: }
375: if (n == 0) {
376: (void) fprintf(stderr, "%s: zero returned on read\n", progname);
377: exit(1);
378: } else
379: error("read()", "", "");
380: }
381: /*#endif*/
382:
383:
384: /*
385: * error - print an error message
386: */
387: void
388: error(
389: char *fmt,
390: char *s1,
391: char *s2
392: )
393: {
394: (void) fprintf(stderr, "%s: ", progname);
395: (void) fprintf(stderr, fmt, s1, s2);
396: (void) fprintf(stderr, ": ");
397: perror("");
398: exit(1);
399: }
400:
401: /*
402: * Definitions
403: */
404: #define MAXUNITS 4 /* maximum number of CHU units permitted */
405: #define CHUDEV "/dev/chu%d" /* device we open. %d is unit number */
406: #define NCHUCODES 9 /* expect 9 CHU codes per minute */
407:
408: /*
409: * When CHU is operating optimally we want the primary clock distance
410: * to come out at 300 ms. Thus, peer.distance in the CHU peer structure
411: * is set to 290 ms and we compute delays which are at least 10 ms long.
412: * The following are 290 ms and 10 ms expressed in u_fp format
413: */
414: #define CHUDISTANCE 0x00004a3d
415: #define CHUBASEDELAY 0x0000028f
416:
417: /*
418: * To compute a quality for the estimate (a pseudo delay) we add a
419: * fixed 10 ms for each missing code in the minute and add to this
420: * the sum of the differences between the remaining offsets and the
421: * estimated sample offset.
422: */
423: #define CHUDELAYPENALTY 0x0000028f
424:
425: /*
426: * Other constant stuff
427: */
428: #define CHUPRECISION (-9) /* what the heck */
429: #define CHUREFID "CHU\0"
430:
431: /*
432: * Default fudge factors
433: */
434: #define DEFPROPDELAY 0x00624dd3 /* 0.0015 seconds, 1.5 ms */
435: #define DEFFILTFUDGE 0x000d1b71 /* 0.0002 seconds, 200 us */
436:
437: /*
438: * Hacks to avoid excercising the multiplier. I have no pride.
439: */
440: #define MULBY10(x) (((x)<<3) + ((x)<<1))
441: #define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */
442: #define MULBY24(x) (((x)<<4) + ((x)<<3))
443:
444: /*
445: * Constants for use when multiplying by 0.1. ZEROPTONE is 0.1
446: * as an l_fp fraction, NZPOBITS is the number of significant bits
447: * in ZEROPTONE.
448: */
449: #define ZEROPTONE 0x1999999a
450: #define NZPOBITS 29
451:
452: /*
453: * The CHU table. This gives the expected time of arrival of each
454: * character after the on-time second and is computed as follows:
455: * The CHU time code is sent at 300 bps. Your average UART will
456: * synchronize at the edge of the start bit and will consider the
457: * character complete at the center of the first stop bit, i.e.
458: * 0.031667 ms later. Thus the expected time of each interrupt
459: * is the start bit time plus 0.031667 seconds. These times are
460: * in chutable[]. To this we add such things as propagation delay
461: * and delay fudge factor.
462: */
463: #define CHARDELAY 0x081b4e80
464:
465: static u_long chutable[NCHUCHARS] = {
466: 0x2147ae14 + CHARDELAY, /* 0.130 (exactly) */
467: 0x2ac08312 + CHARDELAY, /* 0.167 (exactly) */
468: 0x34395810 + CHARDELAY, /* 0.204 (exactly) */
469: 0x3db22d0e + CHARDELAY, /* 0.241 (exactly) */
470: 0x472b020c + CHARDELAY, /* 0.278 (exactly) */
471: 0x50a3d70a + CHARDELAY, /* 0.315 (exactly) */
472: 0x5a1cac08 + CHARDELAY, /* 0.352 (exactly) */
473: 0x63958106 + CHARDELAY, /* 0.389 (exactly) */
474: 0x6d0e5604 + CHARDELAY, /* 0.426 (exactly) */
475: 0x76872b02 + CHARDELAY, /* 0.463 (exactly) */
476: };
477:
478: /*
479: * Keep the fudge factors separately so they can be set even
480: * when no clock is configured.
481: */
482: static l_fp propagation_delay;
483: static l_fp fudgefactor;
484: static l_fp offset_fudge;
485:
486: /*
487: * We keep track of the start of the year, watching for changes.
488: * We also keep track of whether the year is a leap year or not.
489: * All because stupid CHU doesn't include the year in the time code.
490: */
491: static u_long yearstart;
492:
493: /*
494: * Imported from the timer module
495: */
496: extern u_long current_time;
497: extern struct event timerqueue[];
498:
499: /*
500: * Time conversion tables imported from the library
501: */
502: extern u_long ustotslo[];
503: extern u_long ustotsmid[];
504: extern u_long ustotshi[];
505:
506:
507: /*
508: * init_chu - initialize internal chu driver data
509: */
510: void
511: init_chu(void)
512: {
513:
514: /*
515: * Initialize fudge factors to default.
516: */
517: propagation_delay.l_ui = 0;
518: propagation_delay.l_uf = DEFPROPDELAY;
519: fudgefactor.l_ui = 0;
520: fudgefactor.l_uf = DEFFILTFUDGE;
521: offset_fudge = propagation_delay;
522: L_ADD(&offset_fudge, &fudgefactor);
523:
524: yearstart = 0;
525: }
526:
527:
528: void
529: chufilter(
530: struct chucode *chuc,
531: l_fp *rtime
532: )
533: {
534: register int i;
535: register u_long date_ui;
536: register u_long tmp;
537: register u_char *code;
538: int isneg;
539: int imin;
540: int imax;
541: u_long reftime;
542: l_fp off[NCHUCHARS];
543: l_fp ts;
544: int day, hour, minute, second;
545: static u_char lastcode[NCHUCHARS];
546: extern u_long calyearstart();
547: extern char *mfptoa();
548: void chu_process();
549: extern char *prettydate();
550:
551: /*
552: * We'll skip the checks made in the kernel, but assume they've
553: * been done. This means that all characters are BCD and
554: * the intercharacter spacing isn't unreasonable.
555: */
556:
557: /*
558: * print the code
559: */
560: for (i = 0; i < NCHUCHARS; i++)
561: printf("%c%c", (chuc->codechars[i] & 0xf) + '0',
562: ((chuc->codechars[i]>>4) & 0xf) + '0');
563: printf("\n");
564:
565: /*
566: * Format check. Make sure the two halves match.
567: */
568: for (i = 0; i < NCHUCHARS/2; i++)
569: if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
570: (void) printf("Bad format, halves don't match\n");
571: return;
572: }
573:
574: /*
575: * Break out the code into the BCD nibbles. Only need to fiddle
576: * with the first half since both are identical. Note the first
577: * BCD character is the low order nibble, the second the high order.
578: */
579: code = lastcode;
580: for (i = 0; i < NCHUCHARS/2; i++) {
581: *code++ = chuc->codechars[i] & 0xf;
582: *code++ = (chuc->codechars[i] >> 4) & 0xf;
583: }
584:
585: /*
586: * If the first nibble isn't a 6, we're up the creek
587: */
588: code = lastcode;
589: if (*code++ != 6) {
590: (void) printf("Bad format, no 6 at start\n");
591: return;
592: }
593:
594: /*
595: * Collect the day, the hour, the minute and the second.
596: */
597: day = *code++;
598: day = MULBY10(day) + *code++;
599: day = MULBY10(day) + *code++;
600: hour = *code++;
601: hour = MULBY10(hour) + *code++;
602: minute = *code++;
603: minute = MULBY10(minute) + *code++;
604: second = *code++;
605: second = MULBY10(second) + *code++;
606:
607: /*
608: * Sanity check the day and time. Note that this
609: * only occurs on the 31st through the 39th second
610: * of the minute.
611: */
612: if (day < 1 || day > 366
613: || hour > 23 || minute > 59
614: || second < 31 || second > 39) {
615: (void) printf("Failed date sanity check: %d %d %d %d\n",
616: day, hour, minute, second);
617: return;
618: }
619:
620: /*
621: * Compute seconds into the year.
622: */
623: tmp = (u_long)(MULBY24((day-1)) + hour); /* hours */
624: tmp = MULBY60(tmp) + (u_long)minute; /* minutes */
625: tmp = MULBY60(tmp) + (u_long)second; /* seconds */
626:
627: /*
628: * Now the fun begins. We demand that the received time code
629: * be within CLOCK_WAYTOOBIG of the receive timestamp, but
630: * there is uncertainty about the year the timestamp is in.
631: * Use the current year start for the first check, this should
632: * work most of the time.
633: */
634: date_ui = tmp + yearstart;
635: if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
636: && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
637: goto codeokay; /* looks good */
638:
639: /*
640: * Trouble. Next check is to see if the year rolled over and, if
641: * so, try again with the new year's start.
642: */
643: date_ui = calyearstart(rtime->l_ui);
644: if (date_ui != yearstart) {
645: yearstart = date_ui;
646: date_ui += tmp;
647: (void) printf("time %u, code %u, difference %d\n",
648: date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui);
649: if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
650: && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
651: goto codeokay; /* okay this time */
652: }
653:
654: ts.l_uf = 0;
655: ts.l_ui = yearstart;
656: printf("yearstart %s\n", prettydate(&ts));
657: printf("received %s\n", prettydate(rtime));
658: ts.l_ui = date_ui;
659: printf("date_ui %s\n", prettydate(&ts));
660:
661: /*
662: * Here we know the year start matches the current system
663: * time. One remaining possibility is that the time code
664: * is in the year previous to that of the system time. This
665: * is only worth checking if the receive timestamp is less
666: * than CLOCK_WAYTOOBIG seconds into the new year.
667: */
668: if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) {
669: date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG);
670: if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG)
671: goto codeokay;
672: }
673:
674: /*
675: * One last possibility is that the time stamp is in the year
676: * following the year the system is in. Try this one before
677: * giving up.
678: */
679: date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */
680: if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) {
681: printf("Date hopelessly off\n");
682: return; /* hopeless, let it sync to other peers */
683: }
684:
685: codeokay:
686: reftime = date_ui;
687: /*
688: * We've now got the integral seconds part of the time code (we hope).
689: * The fractional part comes from the table. We next compute
690: * the offsets for each character.
691: */
692: for (i = 0; i < NCHUCHARS; i++) {
693: register u_long tmp2;
694:
695: off[i].l_ui = date_ui;
696: off[i].l_uf = chutable[i];
697: tmp = chuc->codetimes[i].tv_sec + JAN_1970;
698: TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2);
699: M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
700: }
701:
702: /*
703: * Here is a *big* problem. What one would normally
704: * do here on a machine with lots of clock bits (say
705: * a Vax or the gizmo board) is pick the most positive
706: * offset and the estimate, since this is the one that
707: * is most likely suffered the smallest interrupt delay.
708: * The trouble is that the low order clock bit on an IBM
709: * RT, which is the machine I had in mind when doing this,
710: * ticks at just under the millisecond mark. This isn't
711: * precise enough. What we can do to improve this is to
712: * average all 10 samples and rely on the second level
713: * filtering to pick the least delayed estimate. Trouble
714: * is, this means we have to divide a 64 bit fixed point
715: * number by 10, a procedure which really sucks. Oh, well.
716: * First compute the sum.
717: */
718: date_ui = 0;
719: tmp = 0;
720: for (i = 0; i < NCHUCHARS; i++)
721: M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf);
722: if (M_ISNEG(date_ui, tmp))
723: isneg = 1;
724: else
725: isneg = 0;
726:
727: /*
728: * Here is a multiply-by-0.1 optimization that should apply
729: * just about everywhere. If the magnitude of the sum
730: * is less than 9 we don't have to worry about overflow
731: * out of a 64 bit product, even after rounding.
732: */
733: if (date_ui < 9 || date_ui > 0xfffffff7) {
734: register u_long prod_ui;
735: register u_long prod_uf;
736:
737: prod_ui = prod_uf = 0;
738: /*
739: * This code knows the low order bit in 0.1 is zero
740: */
741: for (i = 1; i < NZPOBITS; i++) {
742: M_LSHIFT(date_ui, tmp);
743: if (ZEROPTONE & (1<<i))
744: M_ADD(prod_ui, prod_uf, date_ui, tmp);
745: }
746:
747: /*
748: * Done, round it correctly. Prod_ui contains the
749: * fraction.
750: */
751: if (prod_uf & 0x80000000)
752: prod_ui++;
753: if (isneg)
754: date_ui = 0xffffffff;
755: else
756: date_ui = 0;
757: tmp = prod_ui;
758: /*
759: * date_ui is integral part, tmp is fraction.
760: */
761: } else {
762: register u_long prod_ovr;
763: register u_long prod_ui;
764: register u_long prod_uf;
765: register u_long highbits;
766:
767: prod_ovr = prod_ui = prod_uf = 0;
768: if (isneg)
769: highbits = 0xffffffff; /* sign extend */
770: else
771: highbits = 0;
772: /*
773: * This code knows the low order bit in 0.1 is zero
774: */
775: for (i = 1; i < NZPOBITS; i++) {
776: M_LSHIFT3(highbits, date_ui, tmp);
777: if (ZEROPTONE & (1<<i))
778: M_ADD3(prod_ovr, prod_uf, prod_ui,
779: highbits, date_ui, tmp);
780: }
781:
782: if (prod_uf & 0x80000000)
783: M_ADDUF(prod_ovr, prod_ui, (u_long)1);
784: date_ui = prod_ovr;
785: tmp = prod_ui;
786: }
787:
788: /*
789: * At this point we have the mean offset, with the integral
790: * part in date_ui and the fractional part in tmp. Store
791: * it in the structure.
792: */
793: /*
794: * Add in fudge factor.
795: */
796: M_ADD(date_ui, tmp, offset_fudge.l_ui, offset_fudge.l_uf);
797:
798: /*
799: * Find the minimun and maximum offset
800: */
801: imin = imax = 0;
802: for (i = 1; i < NCHUCHARS; i++) {
803: if (L_ISGEQ(&off[i], &off[imax])) {
804: imax = i;
805: } else if (L_ISGEQ(&off[imin], &off[i])) {
806: imin = i;
807: }
808: }
809:
810: L_ADD(&off[imin], &offset_fudge);
811: if (imin != imax)
812: L_ADD(&off[imax], &offset_fudge);
813: (void) printf("mean %s, min %s, max %s\n",
814: mfptoa(date_ui, tmp, 8), lfptoa(&off[imin], 8),
815: lfptoa(&off[imax], 8));
816: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>