source: rtems/cpukit/score/cpu/or1k/include/rtems/score/cpu.h @ 0a1f5df9

5
Last change on this file since 0a1f5df9 was 0a1f5df9, checked in by Sebastian Huber <sebastian.huber@…>, on 05/03/18 at 11:03:27

Simplify _CPU_Counter_difference()

In order to simplify the use of CPU counter values it is beneficial to
have monotonic increasing values within the range of the CPU counter
ticks data type, e.g. 32-bit unsigned integer. This eases the use of
CPU counter timestamps in external tools which do not know the details
of the CPU counter hardware. The CPU counter is the fastest way to get
a time on an RTEMS system.

Such a CPU counter may be also used as the timecounter. Use it on SPARC
for this purpose to simplify the clock drivers.

Update #3456.

  • Property mode set to 100644
File size: 20.8 KB
Line 
1/**
2 * @file rtems/score/cpu.h
3 */
4
5/*
6 *  This include file contains macros pertaining to the Opencores
7 *  or1k processor family.
8 *
9 *  COPYRIGHT (c) 2014 Hesham ALMatary <heshamelmatary@gmail.com>
10 *  COPYRIGHT (c) 1989-1999.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 *
17 *  This file adapted from no_cpu example of the RTEMS distribution.
18 *  The body has been modified for the Opencores OR1k implementation by
19 *  Chris Ziomkowski. <chris@asics.ws>
20 *
21 */
22
23#ifndef _OR1K_CPU_H
24#define _OR1K_CPU_H
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30
31#include <rtems/score/or1k.h>            /* pick up machine definitions */
32#include <rtems/score/or1k-utility.h>
33#include <rtems/score/basedefs.h>
34#ifndef ASM
35#include <rtems/bspIo.h>
36#include <stdint.h>
37#include <stdio.h> /* for printk */
38#endif
39
40/* conditional compilation parameters */
41
42/*
43 *  Does the RTEMS invoke the user's ISR with the vector number and
44 *  a pointer to the saved interrupt frame (1) or just the vector
45 *  number (0)?
46 *
47 */
48
49#define CPU_ISR_PASSES_FRAME_POINTER TRUE
50
51/*
52 *  Does the CPU have hardware floating point?
53 *
54 *  If TRUE, then the RTEMS_FLOATING_POINT task attribute is supported.
55 *  If FALSE, then the RTEMS_FLOATING_POINT task attribute is ignored.
56 *
57 *  If there is a FP coprocessor such as the i387 or mc68881, then
58 *  the answer is TRUE.
59 *
60 *  The macro name "OR1K_HAS_FPU" should be made CPU specific.
61 *  It indicates whether or not this CPU model has FP support.  For
62 *  example, it would be possible to have an i386_nofp CPU model
63 *  which set this to false to indicate that you have an i386 without
64 *  an i387 and wish to leave floating point support out of RTEMS.
65 *
66 *  The CPU_SOFTWARE_FP is used to indicate whether or not there
67 *  is software implemented floating point that must be context
68 *  switched.  The determination of whether or not this applies
69 *  is very tool specific and the state saved/restored is also
70 *  compiler specific.
71 *
72 *  Or1k Specific Information:
73 *
74 *  At this time there are no implementations of Or1k that are
75 *  expected to implement floating point. More importantly, the
76 *  floating point architecture is expected to change significantly
77 *  before such chips are fabricated.
78 */
79
80#define CPU_HARDWARE_FP     FALSE
81#define CPU_SOFTWARE_FP     FALSE
82
83/*
84 *  Are all tasks RTEMS_FLOATING_POINT tasks implicitly?
85 *
86 *  If TRUE, then the RTEMS_FLOATING_POINT task attribute is assumed.
87 *  If FALSE, then the RTEMS_FLOATING_POINT task attribute is followed.
88 *
89 *  If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
90 *
91 */
92
93#define CPU_ALL_TASKS_ARE_FP     FALSE
94
95/*
96 *  Should the IDLE task have a floating point context?
97 *
98 *  If TRUE, then the IDLE task is created as a RTEMS_FLOATING_POINT task
99 *  and it has a floating point context which is switched in and out.
100 *  If FALSE, then the IDLE task does not have a floating point context.
101 *
102 *  Setting this to TRUE negatively impacts the time required to preempt
103 *  the IDLE task from an interrupt because the floating point context
104 *  must be saved as part of the preemption.
105 *
106 */
107
108#define CPU_IDLE_TASK_IS_FP      FALSE
109
110/*
111 *  Should the saving of the floating point registers be deferred
112 *  until a context switch is made to another different floating point
113 *  task?
114 *
115 *  If TRUE, then the floating point context will not be stored until
116 *  necessary.  It will remain in the floating point registers and not
117 *  disturned until another floating point task is switched to.
118 *
119 *  If FALSE, then the floating point context is saved when a floating
120 *  point task is switched out and restored when the next floating point
121 *  task is restored.  The state of the floating point registers between
122 *  those two operations is not specified.
123 *
124 *  If the floating point context does NOT have to be saved as part of
125 *  interrupt dispatching, then it should be safe to set this to TRUE.
126 *
127 *  Setting this flag to TRUE results in using a different algorithm
128 *  for deciding when to save and restore the floating point context.
129 *  The deferred FP switch algorithm minimizes the number of times
130 *  the FP context is saved and restored.  The FP context is not saved
131 *  until a context switch is made to another, different FP task.
132 *  Thus in a system with only one FP task, the FP context will never
133 *  be saved or restored.
134 *
135 */
136
137#define CPU_USE_DEFERRED_FP_SWITCH       TRUE
138
139#define CPU_ENABLE_ROBUST_THREAD_DISPATCH FALSE
140
141/*
142 *  Does the stack grow up (toward higher addresses) or down
143 *  (toward lower addresses)?
144 *
145 *  If TRUE, then the grows upward.
146 *  If FALSE, then the grows toward smaller addresses.
147 *
148 */
149
150#define CPU_STACK_GROWS_UP               FALSE
151
152/* FIXME: Is this the right value? */
153#define CPU_CACHE_LINE_BYTES 32
154
155#define CPU_STRUCTURE_ALIGNMENT RTEMS_ALIGNED( CPU_CACHE_LINE_BYTES )
156
157/*
158 *  The following defines the number of bits actually used in the
159 *  interrupt field of the task mode.  How those bits map to the
160 *  CPU interrupt levels is defined by the routine _CPU_ISR_Set_level().
161 *
162 */
163
164#define CPU_MODES_INTERRUPT_MASK   0x00000001
165
166/*
167 *  Processor defined structures required for cpukit/score.
168 */
169
170
171/*
172 * Contexts
173 *
174 *  Generally there are 2 types of context to save.
175 *     1. Interrupt registers to save
176 *     2. Task level registers to save
177 *
178 *  This means we have the following 3 context items:
179 *     1. task level context stuff::  Context_Control
180 *     2. floating point task stuff:: Context_Control_fp
181 *     3. special interrupt level context :: Context_Control_interrupt
182 *
183 *  On some processors, it is cost-effective to save only the callee
184 *  preserved registers during a task context switch.  This means
185 *  that the ISR code needs to save those registers which do not
186 *  persist across function calls.  It is not mandatory to make this
187 *  distinctions between the caller/callee saves registers for the
188 *  purpose of minimizing context saved during task switch and on interrupts.
189 *  If the cost of saving extra registers is minimal, simplicity is the
190 *  choice.  Save the same context on interrupt entry as for tasks in
191 *  this case.
192 *
193 *  Additionally, if gdb is to be made aware of RTEMS tasks for this CPU, then
194 *  care should be used in designing the context area.
195 *
196 *  On some CPUs with hardware floating point support, the Context_Control_fp
197 *  structure will not be used or it simply consist of an array of a
198 *  fixed number of bytes.   This is done when the floating point context
199 *  is dumped by a "FP save context" type instruction and the format
200 *  is not really defined by the CPU.  In this case, there is no need
201 *  to figure out the exact format -- only the size.  Of course, although
202 *  this is enough information for RTEMS, it is probably not enough for
203 *  a debugger such as gdb.  But that is another problem.
204 *
205 *
206 */
207#ifndef ASM
208#ifdef OR1K_64BIT_ARCH
209#define or1kreg uint64_t
210#else
211#define or1kreg uint32_t
212#endif
213
214typedef struct {
215  uint32_t  r1;     /* Stack pointer */
216  uint32_t  r2;     /* Frame pointer */
217  uint32_t  r3;
218  uint32_t  r4;
219  uint32_t  r5;
220  uint32_t  r6;
221  uint32_t  r7;
222  uint32_t  r8;
223  uint32_t  r9;
224  uint32_t  r10;
225  uint32_t  r11;
226  uint32_t  r12;
227  uint32_t  r13;
228  uint32_t  r14;
229  uint32_t  r15;
230  uint32_t  r16;
231  uint32_t  r17;
232  uint32_t  r18;
233  uint32_t  r19;
234  uint32_t  r20;
235  uint32_t  r21;
236  uint32_t  r22;
237  uint32_t  r23;
238  uint32_t  r24;
239  uint32_t  r25;
240  uint32_t  r26;
241  uint32_t  r27;
242  uint32_t  r28;
243  uint32_t  r29;
244  uint32_t  r30;
245  uint32_t  r31;
246
247  uint32_t  sr;  /* Current supervision register non persistent values */
248  uint32_t  epcr;
249  uint32_t  eear;
250  uint32_t  esr;
251} Context_Control;
252
253#define _CPU_Context_Get_SP( _context ) \
254  (_context)->r1
255
256typedef struct {
257  /** FPU registers are listed here */
258  double      some_float_register;
259} Context_Control_fp;
260
261typedef Context_Control CPU_Interrupt_frame;
262
263/*
264 *  The size of the floating point context area.  On some CPUs this
265 *  will not be a "sizeof" because the format of the floating point
266 *  area is not defined -- only the size is.  This is usually on
267 *  CPUs with a "floating point save context" instruction.
268 *
269 *  Or1k Specific Information:
270 *
271 */
272
273#define CPU_CONTEXT_FP_SIZE  0
274
275/*
276 *  Amount of extra stack (above minimum stack size) required by
277 *  MPCI receive server thread.  Remember that in a multiprocessor
278 *  system this thread must exist and be able to process all directives.
279 *
280 */
281
282#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
283
284/*
285 *  Should be large enough to run all RTEMS tests.  This insures
286 *  that a "reasonable" small application should not have any problems.
287 *
288 */
289
290#define CPU_STACK_MINIMUM_SIZE  4096
291
292/*
293 *  CPU's worst alignment requirement for data types on a byte boundary.  This
294 *  alignment does not take into account the requirements for the stack.
295 *
296 */
297
298#define CPU_ALIGNMENT  8
299
300/*
301 *  This is defined if the port has a special way to report the ISR nesting
302 *  level.  Most ports maintain the variable _ISR_Nest_level.
303 */
304#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
305
306/**
307 * Size of a pointer.
308 *
309 * This must be an integer literal that can be used by the assembler.  This
310 * value will be used to calculate offsets of structure members.  These
311 * offsets will be used in assembler code.
312 */
313#define CPU_SIZEOF_POINTER         4
314
315/*
316 *  This number corresponds to the byte alignment requirement for the
317 *  heap handler.  This alignment requirement may be stricter than that
318 *  for the data types alignment specified by CPU_ALIGNMENT.  It is
319 *  common for the heap to follow the same alignment requirement as
320 *  CPU_ALIGNMENT.  If the CPU_ALIGNMENT is strict enough for the heap,
321 *  then this should be set to CPU_ALIGNMENT.
322 *
323 *  NOTE:  This does not have to be a power of 2 although it should be
324 *         a multiple of 2 greater than or equal to 2.  The requirement
325 *         to be a multiple of 2 is because the heap uses the least
326 *         significant field of the front and back flags to indicate
327 *         that a block is in use or free.  So you do not want any odd
328 *         length blocks really putting length data in that bit.
329 *
330 *         On byte oriented architectures, CPU_HEAP_ALIGNMENT normally will
331 *         have to be greater or equal to than CPU_ALIGNMENT to ensure that
332 *         elements allocated from the heap meet all restrictions.
333 *
334 */
335
336#define CPU_HEAP_ALIGNMENT         CPU_ALIGNMENT
337
338/*
339 *  This number corresponds to the byte alignment requirement for the
340 *  stack.  This alignment requirement may be stricter than that for the
341 *  data types alignment specified by CPU_ALIGNMENT.  If the CPU_ALIGNMENT
342 *  is strict enough for the stack, then this should be set to 0.
343 *
344 *  NOTE:  This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
345 *
346 */
347
348#define CPU_STACK_ALIGNMENT        0
349
350#define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
351
352/* ISR handler macros */
353
354/*
355 *  Support routine to initialize the RTEMS vector table after it is allocated.
356 *
357 *  NO_CPU Specific Information:
358 *
359 *  XXX document implementation including references if appropriate
360 */
361
362#define _CPU_Initialize_vectors()
363
364/*
365 *  Disable all interrupts for an RTEMS critical section.  The previous
366 *  level is returned in _level.
367 *
368 */
369
370static inline uint32_t or1k_interrupt_disable( void )
371{
372  uint32_t sr;
373  sr = _OR1K_mfspr(CPU_OR1K_SPR_SR);
374
375  _OR1K_mtspr(CPU_OR1K_SPR_SR, (sr & ~CPU_OR1K_SPR_SR_IEE));
376
377  return sr;
378}
379
380static inline void or1k_interrupt_enable(uint32_t level)
381{
382  uint32_t sr;
383
384  /* Enable interrupts and restore rs */
385  sr = level | CPU_OR1K_SPR_SR_IEE | CPU_OR1K_SPR_SR_TEE;
386  _OR1K_mtspr(CPU_OR1K_SPR_SR, sr);
387
388}
389
390#define _CPU_ISR_Disable( _level ) \
391    _level = or1k_interrupt_disable()
392
393
394/*
395 *  Enable interrupts to the previous level (returned by _CPU_ISR_Disable).
396 *  This indicates the end of an RTEMS critical section.  The parameter
397 *  _level is not modified.
398 *
399 */
400
401#define _CPU_ISR_Enable( _level )  \
402  or1k_interrupt_enable( _level )
403
404/*
405 *  This temporarily restores the interrupt to _level before immediately
406 *  disabling them again.  This is used to divide long RTEMS critical
407 *  sections into two or more parts.  The parameter _level is not
408 *  modified.
409 *
410 */
411
412#define _CPU_ISR_Flash( _level ) \
413  do{ \
414      _CPU_ISR_Enable( _level ); \
415      _OR1K_mtspr(CPU_OR1K_SPR_SR, (_level & ~CPU_OR1K_SPR_SR_IEE)); \
416    } while(0)
417
418RTEMS_INLINE_ROUTINE bool _CPU_ISR_Is_enabled( uint32_t level )
419{
420  return ( level & CPU_OR1K_SPR_SR ) != 0;
421}
422
423/*
424 *  Map interrupt level in task mode onto the hardware that the CPU
425 *  actually provides.  Currently, interrupt levels which do not
426 *  map onto the CPU in a generic fashion are undefined.  Someday,
427 *  it would be nice if these were "mapped" by the application
428 *  via a callout.  For example, m68k has 8 levels 0 - 7, levels
429 *  8 - 255 would be available for bsp/application specific meaning.
430 *  This could be used to manage a programmable interrupt controller
431 *  via the rtems_task_mode directive.
432 *
433 *  The get routine usually must be implemented as a subroutine.
434 *
435 */
436
437void _CPU_ISR_Set_level( uint32_t level );
438
439uint32_t _CPU_ISR_Get_level( void );
440
441/* end of ISR handler macros */
442
443/* Context handler macros */
444
445#define OR1K_FAST_CONTEXT_SWITCH_ENABLED FALSE
446/*
447 *  Initialize the context to a state suitable for starting a
448 *  task after a context restore operation.  Generally, this
449 *  involves:
450 *
451 *     - setting a starting address
452 *     - preparing the stack
453 *     - preparing the stack and frame pointers
454 *     - setting the proper interrupt level in the context
455 *     - initializing the floating point context
456 *
457 *  This routine generally does not set any unnecessary register
458 *  in the context.  The state of the "general data" registers is
459 *  undefined at task start time.
460 *
461 *  NOTE: This is_fp parameter is TRUE if the thread is to be a floating
462 *        point thread.  This is typically only used on CPUs where the
463 *        FPU may be easily disabled by software such as on the SPARC
464 *        where the PSR contains an enable FPU bit.
465 *
466 */
467
468/**
469 * @brief Initializes the CPU context.
470 *
471 * The following steps are performed:
472 *  - setting a starting address
473 *  - preparing the stack
474 *  - preparing the stack and frame pointers
475 *  - setting the proper interrupt level in the context
476 *
477 * @param[in] context points to the context area
478 * @param[in] stack_area_begin is the low address of the allocated stack area
479 * @param[in] stack_area_size is the size of the stack area in bytes
480 * @param[in] new_level is the interrupt level for the task
481 * @param[in] entry_point is the task's entry point
482 * @param[in] is_fp is set to @c true if the task is a floating point task
483 * @param[in] tls_area is the thread-local storage (TLS) area
484 */
485void _CPU_Context_Initialize(
486  Context_Control *context,
487  void *stack_area_begin,
488  size_t stack_area_size,
489  uint32_t new_level,
490  void (*entry_point)( void ),
491  bool is_fp,
492  void *tls_area
493);
494
495/*
496 *  This routine is responsible for somehow restarting the currently
497 *  executing task.  If you are lucky, then all that is necessary
498 *  is restoring the context.  Otherwise, there will need to be
499 *  a special assembly routine which does something special in this
500 *  case.  Context_Restore should work most of the time.  It will
501 *  not work if restarting self conflicts with the stack frame
502 *  assumptions of restoring a context.
503 *
504 */
505
506#define _CPU_Context_Restart_self( _the_context ) \
507   _CPU_Context_restore( (_the_context) );
508
509/*
510 *  This routine is responsible to initialize the FP context.
511 *
512 *  The FP area pointer is passed by reference to allow the initial pointer
513 *  into a floating point context area (used to save the floating point
514 *  context) to be at an arbitrary place in the floating point context area.
515 *
516 *  This is necessary because some FP units are designed to have
517 *  their context saved as a stack which grows into lower addresses.
518 *  Other FP units can be saved by simply moving registers into offsets
519 *  from the base of the context area.  Finally some FP units provide
520 *  a "dump context" instruction which could fill in from high to low
521 *  or low to high based on the whim of the CPU designers.
522 */
523#define _CPU_Context_Initialize_fp( _fp_area_p ) \
524  memset( *( _fp_area_p ), 0, CPU_CONTEXT_FP_SIZE )
525
526/* end of Context handler macros */
527
528/* Fatal Error manager macros */
529
530/*
531 *  This routine copies _error into a known place -- typically a stack
532 *  location or a register, optionally disables interrupts, and
533 *  halts/stops the CPU.
534 *
535 */
536
537#include <inttypes.h>
538
539#define _CPU_Fatal_halt(_source, _error ) \
540        printk("Fatal Error %d.%" PRId32 " Halted\n",_source, _error); \
541        _OR1KSIM_CPU_Halt(); \
542        for(;;)
543
544/* end of Fatal Error manager macros */
545
546#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
547
548#endif /* ASM */
549
550#define CPU_SIZEOF_POINTER 4
551
552#define CPU_MAXIMUM_PROCESSORS 32
553
554#ifndef ASM
555typedef struct {
556  uint32_t r[32];
557
558  /* The following registers must be saved if we have
559  fast context switch disabled and nested interrupt
560  levels are enabled.
561  */
562#if !OR1K_FAST_CONTEXT_SWITCH_ENABLED
563  uint32_t epcr; /* exception PC register */
564  uint32_t eear; /* exception effective address register */
565  uint32_t esr; /* exception supervision register */
566#endif
567
568} CPU_Exception_frame;
569
570/**
571 * @brief Prints the exception frame via printk().
572 *
573 * @see rtems_fatal() and RTEMS_FATAL_SOURCE_EXCEPTION.
574 */
575void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
576
577
578/* end of Priority handler macros */
579
580/* functions */
581
582/*
583 *  _CPU_Initialize
584 *
585 *  This routine performs CPU dependent initialization.
586 *
587 */
588
589void _CPU_Initialize(
590  void
591);
592
593typedef void ( *CPU_ISR_raw_handler )( uint32_t, CPU_Exception_frame * );
594
595void _CPU_ISR_install_raw_handler(
596  uint32_t             vector,
597  CPU_ISR_raw_handler  new_handler,
598  CPU_ISR_raw_handler *old_handler
599);
600
601typedef void ( *CPU_ISR_handler )( uint32_t );
602
603RTEMS_INLINE_ROUTINE void _CPU_ISR_install_vector(
604  uint32_t         vector,
605  CPU_ISR_handler  new_handler,
606  CPU_ISR_handler *old_handler
607)
608{
609  _CPU_ISR_install_raw_handler(
610    vector,
611    (CPU_ISR_raw_handler) new_handler,
612    (CPU_ISR_raw_handler *) old_handler
613  );
614}
615
616void *_CPU_Thread_Idle_body( uintptr_t ignored );
617
618/*
619 *  _CPU_Context_switch
620 *
621 *  This routine switches from the run context to the heir context.
622 *
623 *  Or1k Specific Information:
624 *
625 *  Please see the comments in the .c file for a description of how
626 *  this function works. There are several things to be aware of.
627 */
628
629void _CPU_Context_switch(
630  Context_Control  *run,
631  Context_Control  *heir
632);
633
634/*
635 *  _CPU_Context_restore
636 *
637 *  This routine is generally used only to restart self in an
638 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
639 *
640 *  NOTE: May be unnecessary to reload some registers.
641 *
642 */
643
644void _CPU_Context_restore(
645  Context_Control *new_context
646) RTEMS_NO_RETURN;
647
648/*
649 *  _CPU_Context_save_fp
650 *
651 *  This routine saves the floating point context passed to it.
652 *
653 */
654
655void _CPU_Context_save_fp(
656  void **fp_context_ptr
657);
658
659/*
660 *  _CPU_Context_restore_fp
661 *
662 *  This routine restores the floating point context passed to it.
663 *
664 */
665
666void _CPU_Context_restore_fp(
667  void **fp_context_ptr
668);
669
670/*  The following routine swaps the endian format of an unsigned int.
671 *  It must be static because it is referenced indirectly.
672 *
673 *  This version will work on any processor, but if there is a better
674 *  way for your CPU PLEASE use it.  The most common way to do this is to:
675 *
676 *     swap least significant two bytes with 16-bit rotate
677 *     swap upper and lower 16-bits
678 *     swap most significant two bytes with 16-bit rotate
679 *
680 *  Some CPUs have special instructions which swap a 32-bit quantity in
681 *  a single instruction (e.g. i486).  It is probably best to avoid
682 *  an "endian swapping control bit" in the CPU.  One good reason is
683 *  that interrupts would probably have to be disabled to insure that
684 *  an interrupt does not try to access the same "chunk" with the wrong
685 *  endian.  Another good reason is that on some CPUs, the endian bit
686 *  endianness for ALL fetches -- both code and data -- so the code
687 *  will be fetched incorrectly.
688 *
689 */
690
691static inline unsigned int CPU_swap_u32(
692  unsigned int value
693)
694{
695  uint32_t   byte1, byte2, byte3, byte4, swapped;
696
697  byte4 = (value >> 24) & 0xff;
698  byte3 = (value >> 16) & 0xff;
699  byte2 = (value >> 8)  & 0xff;
700  byte1 =  value        & 0xff;
701
702  swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
703  return( swapped );
704}
705
706#define CPU_swap_u16( value ) \
707  (((value&0xff) << 8) | ((value >> 8)&0xff))
708
709typedef uint32_t CPU_Counter_ticks;
710
711uint32_t _CPU_Counter_frequency( void );
712
713CPU_Counter_ticks _CPU_Counter_read( void );
714
715static inline CPU_Counter_ticks _CPU_Counter_difference(
716  CPU_Counter_ticks second,
717  CPU_Counter_ticks first
718)
719{
720  return second - first;
721}
722
723/** Type that can store a 32-bit integer or a pointer. */
724typedef uintptr_t CPU_Uint32ptr;
725
726#endif /* ASM */
727
728#ifdef __cplusplus
729}
730#endif
731
732#endif
Note: See TracBrowser for help on using the repository browser.