# root/trunk/libffado/src/libieee1394/cycletimer.h

Revision 1763, 17.0 kB (checked in by ppalmers, 11 years ago) |
---|

Line | |
---|---|

1 | /* |

2 | * Copyright (C) 2005-2008 by Pieter Palmers |

3 | * |

4 | * This file is part of FFADO |

5 | * FFADO = Free Firewire (pro-)audio drivers for linux |

6 | * |

7 | * FFADO is based upon FreeBoB. |

8 | * |

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. |

13 | * |

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. |

18 | * |

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/>. |

21 | * |

22 | */ |

23 | |

24 | /* Definitions and utility macro's to handle the ISO cycle timer */ |

25 | |

26 | #ifndef __CYCLETIMER_H__ |

27 | #define __CYCLETIMER_H__ |

28 | |

29 | #include "debugmodule/debugmodule.h" |

30 | |

31 | #include <inttypes.h> |

32 | |

33 | #define CSR_CYCLE_TIME 0x200 |

34 | #define CSR_REGISTER_BASE 0xfffff0000000ULL |

35 | |

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) |

41 | |

42 | #define USECS_PER_TICK (1.0/TICKS_PER_USEC) |

43 | #define USECS_PER_CYCLE (125U) |

44 | |

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))) |

48 | |

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))) |

52 | |

53 | |

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) )) |

57 | |

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)) |

62 | |

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))) |

66 | |

67 | #define TICKS_TO_SYT(x) (((TICKS_TO_CYCLES(x) & 0xF) << 12) \ |

68 | | ((TICKS_TO_OFFSET(x) & 0xFFF))) |

69 | |

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) \ |

74 | ) |

75 | #define CYCLE_TIMER_WRAP_TICKS(x) ((x % TICKS_PER_SECOND)) |

76 | |

77 | #define INVALID_TIMESTAMP_TICKS 0xFFFFFFFFFFFFFFFFULL |

78 | |

79 | DECLARE_GLOBAL_DEBUG_MODULE; |

80 | |

81 | /** |

82 | * @brief Wraps x to the maximum number of ticks |

83 | * |

84 | * The input value is wrapped to the maximum value of the cycle |

85 | * timer, in ticks (128sec * 24576000 ticks/sec). |

86 | * |

87 | * @param x time to wrap |

88 | * @return wrapped time |

89 | */ |

90 | static inline uint64_t wrapAtMaxTicks(uint64_t x) { |

91 | if (x >= TICKS_PER_SECOND * 128L) { |

92 | x -= TICKS_PER_SECOND * 128L; |

93 | } |

94 | |

95 | #ifdef DEBUG |

96 | if (x >= TICKS_PER_SECOND * 128L) { |

97 | debugWarning("insufficient wrapping: %"PRIu64"\n",x); |

98 | } |

99 | #endif |

100 | |

101 | return x; |

102 | } |

103 | |

104 | /** |

105 | * @brief Wraps x to the minimum number of ticks |

106 | * |

107 | * The input value is wrapped to the minimum value of the cycle |

108 | * timer, in ticks (= 0). |

109 | * |

110 | * @param x time to wrap |

111 | * @return wrapped time |

112 | */ |

113 | static inline int64_t wrapAtMinTicks(int64_t x) { |

114 | if (x < 0) { |

115 | x += TICKS_PER_SECOND * 128L; |

116 | } |

117 | |

118 | #ifdef DEBUG |

119 | if (x < 0) { |

120 | debugWarning("insufficient wrapping: %"PRId64"\n",x); |

121 | } |

122 | #endif |

123 | |

124 | return (int64_t)x; |

125 | } |

126 | |

127 | /** |

128 | * @brief Wraps both at minimum and maximum value for ticks |

129 | * |

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). |

133 | * |

134 | * @param x value to wrap |

135 | * @return wrapped value |

136 | */ |

137 | static inline int64_t wrapAtMinMaxTicks(int64_t x) { |

138 | |

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; |

143 | } |

144 | |

145 | #ifdef DEBUG |

146 | if (x >= (int64_t)(TICKS_PER_SECOND * 128L)) { |

147 | debugWarning("insufficient wrapping (max): %"PRIu64"\n",x); |

148 | } |

149 | if (x < 0) { |

150 | debugWarning("insufficient wrapping (min): %"PRId64"\n",x); |

151 | } |

152 | #endif |

153 | return x; |

154 | |

155 | } |

156 | |

157 | /** |

158 | * @brief Computes the sum of two cycle values |

159 | * |

160 | * This function computes a sum between cycles |

161 | * such that it respects wrapping (at 8000 cycles). |

162 | * |

163 | * The passed arguments are assumed to be valid cycle numbers, |

164 | * i.e. they should be wrapped at 8000 cycles |

165 | * |

166 | * See addTicks |

167 | * |

168 | * @param x First cycle value |

169 | * @param y Second cycle value |

170 | * @return the sum x+y, wrapped |

171 | */ |

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); |

177 | } |

178 | #endif |

179 | |

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; |

183 | } |

184 | |

185 | /** |

186 | * @brief Computes a difference between cycles |

187 | * |

188 | * This function computes a difference between cycles |

189 | * such that it respects wrapping (at 8000 cycles). |

190 | * |

191 | * See diffTicks |

192 | * |

193 | * @param x First cycle value |

194 | * @param y Second cycle value |

195 | * @return the difference x-y, unwrapped |

196 | */ |

197 | static inline int diffCycles(unsigned int x, unsigned int y) { |

198 | int diff = (int)x - (int)y; |

199 | |

200 | // the maximal difference we allow (4000 cycles) |

201 | const int max=CYCLES_PER_SECOND/2; |

202 | |

203 | if(diff > max) { |

204 | diff -= CYCLES_PER_SECOND; |

205 | } else if (diff < -max) { |

206 | diff += CYCLES_PER_SECOND; |

207 | } |

208 | |

209 | return diff; |

210 | } |

211 | |

212 | /** |

213 | * @brief Computes a difference between timestamps |

214 | * |

215 | * This function computes a difference between timestamps |

216 | * such that it respects wrapping. |

217 | * |

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. |

222 | * |

223 | * @param x First timestamp |

224 | * @param y Second timestamp |

225 | * @return the difference x-y, unwrapped |

226 | */ |

227 | static inline int64_t diffTicks(int64_t x, int64_t y) { |

228 | int64_t diff=(int64_t)x - (int64_t)y; |

229 | |

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; |

233 | |

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; |

246 | } |

247 | |

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); |

252 | |

253 | } |

254 | #endif |

255 | |

256 | return (int64_t)diff; |

257 | |

258 | } |

259 | |

260 | /** |

261 | * @brief Computes a sum of timestamps |

262 | * |

263 | * This function computes a sum of timestamps in ticks, |

264 | * wrapping the result if necessary. |

265 | * |

266 | * @param x First timestamp |

267 | * @param y Second timestamp |

268 | * @return the sum x+y, wrapped |

269 | */ |

270 | static inline uint64_t addTicks(uint64_t x, uint64_t y) { |

271 | uint64_t sum=x+y; |

272 | |

273 | return wrapAtMaxTicks(sum); |

274 | } |

275 | |

276 | /** |

277 | * @brief Computes a substraction of timestamps |

278 | * |

279 | * This function computes a substraction of timestamps in ticks, |

280 | * wrapping the result if necessary. |

281 | * |

282 | * @param x First timestamp |

283 | * @param y Second timestamp |

284 | * @return the difference x-y, wrapped |

285 | */ |

286 | static inline uint64_t substractTicks(uint64_t x, uint64_t y) { |

287 | int64_t subs=x-y; |

288 | |

289 | return wrapAtMinTicks(subs); |

290 | } |

291 | |

292 | /** |

293 | * @brief Converts a received SYT timestamp to a full timestamp in ticks. |

294 | * |

295 | * |

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 |

300 | */ |

301 | static inline uint64_t sytRecvToFullTicks(uint64_t syt_timestamp, unsigned int rcv_cycle, uint64_t ctr_now) { |

302 | uint64_t timestamp; |

303 | |

304 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%"PRIX64" CY=%u CTR=%08"PRIX64"\n", |

305 | syt_timestamp, rcv_cycle, ctr_now); |

306 | |

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); |

310 | |

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); |

317 | } |

318 | |

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; |

329 | } |

330 | } |

331 | |

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); |

335 | |

336 | // if this is true, wraparound has occurred, undo this wraparound |

337 | if(syt_cycle<rcv_cycle_masked) syt_cycle += 0x10; |

338 | |

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; |

342 | |

343 | // reconstruct the cycle part of the timestamp |

344 | uint64_t new_cycles=rcv_cycle + delta_cycles; |

345 | |

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); |

355 | |

356 | new_cycles-=8000; // wrap around |

357 | #ifdef DEBUG |

358 | if (new_cycles >= 8000) { |

359 | debugWarning("insufficient unwrapping\n"); |

360 | } |

361 | #endif |

362 | timestamp = new_cycles * TICKS_PER_CYCLE; |

363 | // add one second due to wraparound |

364 | timestamp += TICKS_PER_SECOND; |

365 | } |

366 | |

367 | timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); |

368 | |

369 | timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND); |

370 | |

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); |

376 | } |

377 | #endif |

378 | |

379 | return timestamp; |

380 | } |

381 | |

382 | /** |

383 | * @brief Converts a received SYT timestamp to a full timestamp in ticks. |

384 | * |

385 | * |

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 |

389 | */ |

390 | static inline uint64_t sytRecvToFullTicks2(uint64_t syt_timestamp, uint32_t rcv_ctr) { |

391 | uint64_t timestamp; |

392 | |

393 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%04"PRIX64" RCV_CTR=%08X\n", |

394 | syt_timestamp, rcv_ctr); |

395 | |

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); |

400 | |

401 | // if this is true, wraparound has occurred, undo this wraparound |

402 | if(syt_cycle<rcv_cycle_masked) syt_cycle += 0x10; |

403 | |

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; |

407 | |

408 | // reconstruct the cycle part of the timestamp |

409 | rcv_cycle += delta_cycles; |

410 | |

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"); |

421 | } |

422 | #endif |

423 | timestamp = rcv_cycle * TICKS_PER_CYCLE; |

424 | // add one second due to wraparound |

425 | timestamp += TICKS_PER_SECOND; |

426 | } |

427 | |

428 | timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); |

429 | |

430 | timestamp = addTicks(timestamp, CYCLE_TIMER_GET_SECS(rcv_ctr) * TICKS_PER_SECOND); |

431 | |

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); |

437 | } |

438 | #endif |

439 | |

440 | return timestamp; |

441 | } |

442 | |

443 | /** |

444 | * @brief Converts a transmit SYT timestamp to a full timestamp in ticks. |

445 | * |

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. |

450 | * |

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 |

455 | */ |

456 | static inline uint64_t sytXmitToFullTicks(uint64_t syt_timestamp, unsigned int xmt_cycle, uint64_t ctr_now) { |

457 | uint64_t timestamp; |

458 | |

459 | debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%08"PRIX64" CY=%04X CTR=%08"PRIX64"\n", |

460 | syt_timestamp, xmt_cycle, ctr_now); |

461 | |

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); |

465 | |

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); |

471 | } |

472 | |

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; |

483 | } |

484 | } |

485 | |

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); |

489 | |

490 | // if this is true, wraparound has occurred, undo this wraparound |

491 | if(syt_cycle<xmt_cycle_masked) syt_cycle += 0x10; |

492 | |

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; |

496 | |

497 | // reconstruct the cycle part of the timestamp |

498 | uint64_t new_cycles=xmt_cycle + delta_cycles; |

499 | |

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); |

509 | |

510 | new_cycles-=8000; // wrap around |

511 | #ifdef DEBUG |

512 | if (new_cycles >= 8000) { |

513 | debugWarning("insufficient unwrapping\n"); |

514 | } |

515 | #endif |

516 | timestamp = new_cycles * TICKS_PER_CYCLE; |

517 | // add one second due to wraparound |

518 | timestamp += TICKS_PER_SECOND; |

519 | } |

520 | |

521 | timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); |

522 | |

523 | timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND); |

524 | |

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); |

530 | } |

531 | #endif |

532 | |

533 | return timestamp; |

534 | } |

535 | |

536 | #endif // __CYCLETIMER_H__ |

**Note:**See TracBrowser for help on using the browser.