mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-29 16:19:23 +08:00
pps: Simplify the nsec calculation in pps_event()
Let A be the current calculation of the frequency accumulator (pps_fcount)
update in pps_event()
scale = (uint64_t)1 << 63;
scale /= captc->tc_frequency;
scale *= 2;
bt.sec = 0;
bt.frac = 0;
bintime_addx(&bt, scale * tcount);
bintime2timespec(&bt, &ts);
hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
and hardpps(..., delta_nsec):
u_nsec = delta_nsec;
if (u_nsec > (NANOSECOND >> 1))
u_nsec -= NANOSECOND;
else if (u_nsec < -(NANOSECOND >> 1))
u_nsec += NANOSECOND;
pps_fcount += u_nsec;
This change introduces a new calculation which is slightly simpler and more
straight forward. Name it B.
Consider the following sample values with a tcount of 2000000100 and a
tc_frequency of 2000000000 (2GHz).
For A, the scale is 9223372036. Then scale * tcount is 18446744994337203600
which is larger than UINT64_MAX (= 18446744073709551615). The result is
920627651984 == 18446744994337203600 % UINT64_MAX. Since all operands are
unsigned the result is well defined through modulo arithmetic. The result of
bintime2timespec(&bt, &ts) is 49. This is equal to the correct result
1000000049 % NANOSECOND.
In hardpps(), both conditional statements are not executed and pps_fcount is
incremented by 49.
For the new calculation B, we have 1000000000 * tcount is 2000000100000000000
which is less than UINT64_MAX. This yields after the division with tc_frequency
the correct result of 1000000050 for delta_nsec.
In hardpps(), the first conditional statement is executed and pps_fcount is
incremented by 50.
This shows that both methods yield roughly the same results. However, method B
is easier to understand and requires fewer conditional statements.
Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/604
This commit is contained in:
@@ -900,16 +900,10 @@ hardpps(struct timespec *tsp, long delta_nsec)
|
||||
pps_tf[0].tv_nsec = u_nsec;
|
||||
|
||||
/*
|
||||
* Compute the difference between the current and previous
|
||||
* counter values. If the difference exceeds 0.5 s, assume it
|
||||
* has wrapped around, so correct 1.0 s.
|
||||
* Update the frequency accumulator using the difference between the
|
||||
* current and previous PPS event measured directly by the timecounter.
|
||||
*/
|
||||
u_nsec = delta_nsec;
|
||||
if (u_nsec > (NANOSECOND >> 1))
|
||||
u_nsec -= NANOSECOND;
|
||||
else if (u_nsec < -(NANOSECOND >> 1))
|
||||
u_nsec += NANOSECOND;
|
||||
pps_fcount += u_nsec;
|
||||
pps_fcount += delta_nsec - NANOSECOND;
|
||||
if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)
|
||||
goto out;
|
||||
time_status &= ~STA_PPSJITTER;
|
||||
|
||||
@@ -2161,7 +2161,7 @@ pps_event(struct pps_state *pps, int event)
|
||||
struct timecounter *captc;
|
||||
uint64_t capth_scale;
|
||||
struct bintime bt;
|
||||
struct timespec ts, *tsp, *osp;
|
||||
struct timespec *tsp, *osp;
|
||||
uint32_t tcount, *pcount;
|
||||
int foff;
|
||||
pps_seq_t *pseq;
|
||||
@@ -2265,7 +2265,7 @@ pps_event(struct pps_state *pps, int event)
|
||||
|
||||
#ifdef PPS_SYNC
|
||||
if (fhard) {
|
||||
uint64_t scale;
|
||||
uint64_t delta_nsec;
|
||||
|
||||
/*
|
||||
* Feed the NTP PLL/FLL.
|
||||
@@ -2275,14 +2275,10 @@ pps_event(struct pps_state *pps, int event)
|
||||
tcount = pps->capcount - pps->ppscount[2];
|
||||
pps->ppscount[2] = pps->capcount;
|
||||
tcount &= captc->tc_counter_mask;
|
||||
scale = (uint64_t)1 << 63;
|
||||
scale /= captc->tc_frequency;
|
||||
scale *= 2;
|
||||
bt.sec = 0;
|
||||
bt.frac = 0;
|
||||
bintime_addx(&bt, scale * tcount);
|
||||
bintime2timespec(&bt, &ts);
|
||||
hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
|
||||
delta_nsec = 1000000000;
|
||||
delta_nsec *= tcount;
|
||||
delta_nsec /= captc->tc_frequency;
|
||||
hardpps(tsp, (long)delta_nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user