Clean up compiler warnings when compiling on 64-bit systems. These are mostly fixing...
[ffado.git] / libffado / src / libieee1394 / cycletimer.h
blobfb8b8e35743306e83626564de15fe9d596110f68
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
4 * This file is part of FFADO
5 * FFADO = Free Firewire (pro-)audio drivers for linux
7 * FFADO is based upon FreeBoB.
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* Definitions and utility macro's to handle the ISO cycle timer */
26 #ifndef __CYCLETIMER_H__
27 #define __CYCLETIMER_H__
29 #include "debugmodule/debugmodule.h"
31 #include <inttypes.h>
33 #define CSR_CYCLE_TIME 0x200
34 #define CSR_REGISTER_BASE 0xfffff0000000ULL
36 #define CYCLES_PER_SECOND 8000U
37 #define TICKS_PER_CYCLE 3072U
38 #define TICKS_PER_HALFCYCLE (3072U/2U)
39 #define TICKS_PER_SECOND 24576000UL
40 #define TICKS_PER_USEC (24.576000)
42 #define USECS_PER_TICK (1.0/TICKS_PER_USEC)
43 #define USECS_PER_CYCLE (125U)
45 #define CYCLE_TIMER_GET_SECS(x) ((((x) & 0xFE000000UL) >> 25))
46 #define CYCLE_TIMER_GET_CYCLES(x) ((((x) & 0x01FFF000UL) >> 12))
47 #define CYCLE_TIMER_GET_OFFSET(x) ((((x) & 0x00000FFFUL)))
49 #define CYCLE_TIMER_SET_SECS(v, x) (((v) & ~0xFE000000UL) | (((x) & 0x7F) << 25))
50 #define CYCLE_TIMER_SET_CYCLES(v, x) ((((v) & ~0x01FFF000UL) | (((x) & 0x1FFF) << 12)))
51 #define CYCLE_TIMER_SET_OFFSET(v, x) ((((v) & ~0x00000FFFUL) | ((x) & 0xFFF)))
54 #define CYCLE_TIMER_TO_TICKS(x) ((CYCLE_TIMER_GET_SECS(x) * TICKS_PER_SECOND) +\
55 (CYCLE_TIMER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\
56 (CYCLE_TIMER_GET_OFFSET(x) ))
58 // non-efficient versions, to be avoided in critical code
59 #define TICKS_TO_SECS(x) ((x)/TICKS_PER_SECOND)
60 #define TICKS_TO_CYCLES(x) (((x)/TICKS_PER_CYCLE) % CYCLES_PER_SECOND)
61 #define TICKS_TO_OFFSET(x) (((x)%TICKS_PER_CYCLE))
63 #define TICKS_TO_CYCLE_TIMER(x) ( ((TICKS_TO_SECS(x) & 0x7F) << 25) \
64 | ((TICKS_TO_CYCLES(x) & 0x1FFF) << 12) \
65 | ((TICKS_TO_OFFSET(x) & 0xFFF)))
67 #define TICKS_TO_SYT(x) (((TICKS_TO_CYCLES(x) & 0xF) << 12) \
68 | ((TICKS_TO_OFFSET(x) & 0xFFF)))
70 #define CYCLE_TIMER_UNWRAP_TICKS(x) (((uint64_t)(x)) \
71 + (127ULL * TICKS_PER_SECOND) \
72 + (CYCLES_PER_SECOND * TICKS_PER_CYCLE) \
73 + (TICKS_PER_CYCLE) \
75 #define CYCLE_TIMER_WRAP_TICKS(x) ((x % TICKS_PER_SECOND))
77 #define INVALID_TIMESTAMP_TICKS 0xFFFFFFFFFFFFFFFFULL
79 DECLARE_GLOBAL_DEBUG_MODULE;
81 /**
82 * @brief Wraps x to the maximum number of ticks
84 * The input value is wrapped to the maximum value of the cycle
85 * timer, in ticks (128sec * 24576000 ticks/sec).
87 * @param x time to wrap
88 * @return wrapped time
90 static inline uint64_t wrapAtMaxTicks(uint64_t x) {
91 if (x >= TICKS_PER_SECOND * 128L) {
92 x -= TICKS_PER_SECOND * 128L;
95 #ifdef DEBUG
96 if (x >= TICKS_PER_SECOND * 128L) {
97 debugWarning("insufficient wrapping: %"PRIu64"\n",x);
99 #endif
101 return x;
105 * @brief Wraps x to the minimum number of ticks
107 * The input value is wrapped to the minimum value of the cycle
108 * timer, in ticks (= 0).
110 * @param x time to wrap
111 * @return wrapped time
113 static inline int64_t wrapAtMinTicks(int64_t x) {
114 if (x < 0) {
115 x += TICKS_PER_SECOND * 128L;
118 #ifdef DEBUG
119 if (x < 0) {
120 debugWarning("insufficient wrapping: %"PRId64"\n",x);
122 #endif
124 return (int64_t)x;
128 * @brief Wraps both at minimum and maximum value for ticks
130 * The input value is wrapped to the maximum value of the cycle
131 * timer, in ticks (128sec * 24576000 ticks/sec), and
132 * to the minimum value of the cycle timer, in ticks (= 0).
134 * @param x value to wrap
135 * @return wrapped value
137 static inline int64_t wrapAtMinMaxTicks(int64_t x) {
139 if (x < 0) {
140 x += TICKS_PER_SECOND * 128L;
141 } else if (x >= (int64_t)(TICKS_PER_SECOND * 128L)) {
142 x -= TICKS_PER_SECOND * 128L;
145 #ifdef DEBUG
146 if (x >= (int64_t)(TICKS_PER_SECOND * 128L)) {
147 debugWarning("insufficient wrapping (max): %"PRIu64"\n",x);
149 if (x < 0) {
150 debugWarning("insufficient wrapping (min): %"PRId64"\n",x);
152 #endif
153 return x;
158 * @brief Computes the sum of two cycle values
160 * This function computes a sum between cycles
161 * such that it respects wrapping (at 8000 cycles).
163 * The passed arguments are assumed to be valid cycle numbers,
164 * i.e. they should be wrapped at 8000 cycles
166 * See addTicks
168 * @param x First cycle value
169 * @param y Second cycle value
170 * @return the sum x+y, wrapped
172 static inline unsigned int addCycles(unsigned int x, unsigned int y) {
173 unsigned int sum = x + y;
174 #ifdef DEBUG
175 if (x >= CYCLES_PER_SECOND || y >= CYCLES_PER_SECOND ) {
176 debugWarning("At least one argument not wrapped correctly: x=%u, y=%u\n",x,y);
178 #endif
180 // since both x and y are < CYCLES_PER_SECOND this should be enough to unwrap
181 if (sum > CYCLES_PER_SECOND) sum -= CYCLES_PER_SECOND;
182 return sum;
186 * @brief Computes a difference between cycles
188 * This function computes a difference between cycles
189 * such that it respects wrapping (at 8000 cycles).
191 * See diffTicks
193 * @param x First cycle value
194 * @param y Second cycle value
195 * @return the difference x-y, unwrapped
197 static inline int diffCycles(unsigned int x, unsigned int y) {
198 int diff = (int)x - (int)y;
200 // the maximal difference we allow (4000 cycles)
201 const int max=CYCLES_PER_SECOND/2;
203 if(diff > max) {
204 diff -= CYCLES_PER_SECOND;
205 } else if (diff < -max) {
206 diff += CYCLES_PER_SECOND;
209 return diff;
213 * @brief Computes a difference between timestamps
215 * This function computes a difference between timestamps
216 * such that it respects wrapping.
218 * If x wraps around, but y doesn't, the result of x-y is
219 * negative and very large. However the real difference is
220 * not large. It can be calculated by unwrapping x and then
221 * calculating x-y.
223 * @param x First timestamp
224 * @param y Second timestamp
225 * @return the difference x-y, unwrapped
227 static inline int64_t diffTicks(int64_t x, int64_t y) {
228 int64_t diff=(int64_t)x - (int64_t)y;
230 // the maximal difference we allow (64secs)
231 const int64_t wrapvalue=((int64_t)TICKS_PER_SECOND)*128LL;
232 const int64_t max=wrapvalue/2LL;
234 if(diff > max) {
235 // this means that y has wrapped, but
236 // x has not. we should unwrap y
237 // by adding TICKS_PER_SECOND*128L, meaning that we should substract
238 // this value from diff
239 diff -= wrapvalue;
240 } else if (diff < -max) {
241 // this means that x has wrapped, but
242 // y has not. we should unwrap x
243 // by adding TICKS_PER_SECOND*128L, meaning that we should add
244 // this value to diff
245 diff += wrapvalue;
248 #ifdef DEBUG
249 if(diff > max || diff < -max) {
250 debugWarning("difference does not make any sense\n");
251 debugWarning("diff=%"PRId64" max=%"PRId64"\n", diff, max);
254 #endif
256 return (int64_t)diff;
261 * @brief Computes a sum of timestamps
263 * This function computes a sum of timestamps in ticks,
264 * wrapping the result if necessary.
266 * @param x First timestamp
267 * @param y Second timestamp
268 * @return the sum x+y, wrapped
270 static inline uint64_t addTicks(uint64_t x, uint64_t y) {
271 uint64_t sum=x+y;
273 return wrapAtMaxTicks(sum);
277 * @brief Computes a substraction of timestamps
279 * This function computes a substraction of timestamps in ticks,
280 * wrapping the result if necessary.
282 * @param x First timestamp
283 * @param y Second timestamp
284 * @return the difference x-y, wrapped
286 static inline uint64_t substractTicks(uint64_t x, uint64_t y) {
287 int64_t subs=x-y;
289 return wrapAtMinTicks(subs);
293 * @brief Converts a received SYT timestamp to a full timestamp in ticks.
296 * @param syt_timestamp The SYT timestamp as present in the packet
297 * @param rcv_cycle The cycle this timestamp was received on
298 * @param ctr_now The current value of the cycle timer ('now')
299 * @return
301 static inline uint64_t sytRecvToFullTicks(uint64_t syt_timestamp, unsigned int rcv_cycle, uint64_t ctr_now) {
302 uint64_t timestamp;
304 debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%"PRIX64" CY=%u CTR=%08"PRIX64"\n",
305 syt_timestamp, rcv_cycle, ctr_now);
307 // reconstruct the full cycle
308 uint64_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now);
309 uint64_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now);
311 // check for bogus ctr
312 // the cycle timer should be ahead of the receive timer
313 int diff_cycles = diffCycles(cc_cycles, rcv_cycle);
314 if (diff_cycles<0) {
315 debugWarning("current cycle timer not ahead of receive cycle: rcv: %u / cc: %"PRIu64" (%d)\n",
316 rcv_cycle, cc_cycles, diff_cycles);
319 // the cycletimer has wrapped since this packet was received
320 // we want cc_seconds to reflect the 'seconds' at the point this
321 // was received
322 if (rcv_cycle>cc_cycles && (diff_cycles>=0)) {
323 if (cc_seconds) {
324 cc_seconds--;
325 } else {
326 // seconds has wrapped around, so we'd better not substract 1
327 // the good value is 127
328 cc_seconds=127;
332 // reconstruct the top part of the timestamp using the current cycle number
333 uint64_t rcv_cycle_masked=rcv_cycle & 0xF;
334 uint64_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp);
336 // if this is true, wraparound has occurred, undo this wraparound
337 if(syt_cycle<rcv_cycle_masked) syt_cycle += 0x10;
339 // this is the difference in cycles wrt the cycle the
340 // timestamp was received
341 uint64_t delta_cycles=syt_cycle-rcv_cycle_masked;
343 // reconstruct the cycle part of the timestamp
344 uint64_t new_cycles=rcv_cycle + delta_cycles;
346 // if the cycles cause a wraparound of the cycle timer,
347 // perform this wraparound
348 // and convert the timestamp into ticks
349 if(new_cycles<8000) {
350 timestamp = new_cycles * TICKS_PER_CYCLE;
351 } else {
352 debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
353 "Detected wraparound: %u + %"PRId64" = %"PRId64"\n",
354 rcv_cycle, delta_cycles, new_cycles);
356 new_cycles-=8000; // wrap around
357 #ifdef DEBUG
358 if (new_cycles >= 8000) {
359 debugWarning("insufficient unwrapping\n");
361 #endif
362 timestamp = new_cycles * TICKS_PER_CYCLE;
363 // add one second due to wraparound
364 timestamp += TICKS_PER_SECOND;
367 timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp);
369 timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND);
371 #ifdef DEBUG
372 if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) {
373 debugWarning("back-converted timestamp not equal to SYT\n");
374 debugWarning("TS=%011"PRIu64" TSC=%08"PRIX64" SYT=%04"PRIX64"\n",
375 timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp);
377 #endif
379 return timestamp;
383 * @brief Converts a received SYT timestamp to a full timestamp in ticks.
386 * @param syt_timestamp The SYT timestamp as present in the packet
387 * @param rcv_ctr The CTR value this timestamp was received on (offset can be 0)
388 * @return
390 static inline uint64_t sytRecvToFullTicks2(uint64_t syt_timestamp, uint32_t rcv_ctr) {
391 uint64_t timestamp;
393 debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%04"PRIX64" RCV_CTR=%08X\n",
394 syt_timestamp, rcv_ctr);
396 // reconstruct the top part of the timestamp using the current cycle number
397 unsigned int rcv_cycle = CYCLE_TIMER_GET_CYCLES(rcv_ctr);
398 unsigned int rcv_cycle_masked = rcv_cycle & 0xF;
399 unsigned int syt_cycle = CYCLE_TIMER_GET_CYCLES(syt_timestamp);
401 // if this is true, wraparound has occurred, undo this wraparound
402 if(syt_cycle<rcv_cycle_masked) syt_cycle += 0x10;
404 // this is the difference in cycles wrt the cycle the
405 // timestamp was received
406 unsigned int delta_cycles = syt_cycle - rcv_cycle_masked;
408 // reconstruct the cycle part of the timestamp
409 rcv_cycle += delta_cycles;
411 // if the cycles cause a wraparound of the cycle timer,
412 // perform this wraparound
413 // and convert the timestamp into ticks
414 if(rcv_cycle<8000) {
415 timestamp = rcv_cycle * TICKS_PER_CYCLE;
416 } else {
417 rcv_cycle -= 8000; // wrap around
418 #ifdef DEBUG
419 if (rcv_cycle >= 8000) {
420 debugWarning("insufficient unwrapping\n");
422 #endif
423 timestamp = rcv_cycle * TICKS_PER_CYCLE;
424 // add one second due to wraparound
425 timestamp += TICKS_PER_SECOND;
428 timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp);
430 timestamp = addTicks(timestamp, CYCLE_TIMER_GET_SECS(rcv_ctr) * TICKS_PER_SECOND);
432 #ifdef DEBUG
433 if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) {
434 debugWarning("back-converted timestamp not equal to SYT\n");
435 debugWarning("TS=%011"PRIu64" TSC=%08"PRIX64" SYT=%04"PRIX64"\n",
436 timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp);
438 #endif
440 return timestamp;
444 * @brief Converts a transmit SYT timestamp to a full timestamp in ticks.
446 * The difference between sytRecvToFullTicks and sytXmitToFullTicks is
447 * the way SYT cycle wraparound is detected: in the receive version,
448 * wraparound is present if rcv_cycle > current_cycle. In the xmit
449 * version this is when current_cycle > xmt_cycle.
451 * @param syt_timestamp The SYT timestamp as present in the packet
452 * @param xmt_cycle The cycle this timestamp was received on
453 * @param ctr_now The current value of the cycle timer ('now')
454 * @return
456 static inline uint64_t sytXmitToFullTicks(uint64_t syt_timestamp, unsigned int xmt_cycle, uint64_t ctr_now) {
457 uint64_t timestamp;
459 debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%08"PRIX64" CY=%04X CTR=%08"PRIX64"\n",
460 syt_timestamp, xmt_cycle, ctr_now);
462 // reconstruct the full cycle
463 uint64_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now);
464 uint64_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now);
466 // check for bogus CTR
467 int diff_cycles = diffCycles(xmt_cycle, cc_cycles);
468 if (diff_cycles<0) {
469 debugWarning("xmit cycle not ahead of current cycle: xmt: %u / cc: %"PRIu64" (%d)\n",
470 xmt_cycle, cc_cycles, diff_cycles);
473 // the cycletimer has wrapped since this packet was received
474 // we want cc_seconds to reflect the 'seconds' at the point this
475 // is to be transmitted
476 if (cc_cycles>xmt_cycle && (diff_cycles>=0)) {
477 if (cc_seconds) {
478 cc_seconds--;
479 } else {
480 // seconds has wrapped around, so we'd better not substract 1
481 // the good value is 127
482 cc_seconds=127;
486 // reconstruct the top part of the timestamp using the current cycle number
487 uint64_t xmt_cycle_masked=xmt_cycle & 0xF;
488 uint64_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp);
490 // if this is true, wraparound has occurred, undo this wraparound
491 if(syt_cycle<xmt_cycle_masked) syt_cycle += 0x10;
493 // this is the difference in cycles wrt the cycle the
494 // timestamp was received
495 uint64_t delta_cycles=syt_cycle-xmt_cycle_masked;
497 // reconstruct the cycle part of the timestamp
498 uint64_t new_cycles=xmt_cycle + delta_cycles;
500 // if the cycles cause a wraparound of the cycle timer,
501 // perform this wraparound
502 // and convert the timestamp into ticks
503 if(new_cycles<8000) {
504 timestamp = new_cycles * TICKS_PER_CYCLE;
505 } else {
506 debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
507 "Detected wraparound: %u + %"PRId64" = %"PRId64"\n",
508 xmt_cycle, delta_cycles, new_cycles);
510 new_cycles-=8000; // wrap around
511 #ifdef DEBUG
512 if (new_cycles >= 8000) {
513 debugWarning("insufficient unwrapping\n");
515 #endif
516 timestamp = new_cycles * TICKS_PER_CYCLE;
517 // add one second due to wraparound
518 timestamp += TICKS_PER_SECOND;
521 timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp);
523 timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND);
525 #ifdef DEBUG
526 if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) {
527 debugWarning("back-converted timestamp not equal to SYT\n");
528 debugWarning("TS=%011"PRIu64" TSC=%08"PRIX64" SYT=%04"PRIX64"\n",
529 timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp);
531 #endif
533 return timestamp;
536 #endif // __CYCLETIMER_H__