source: rtems/cpukit/score/cpu/v850/include/rtems/score/cpu.h

Last change on this file was a660e9dc, checked in by Sebastian Huber <sebastian.huber@…>, on 09/08/22 at 08:37:05

Do not use RTEMS_INLINE_ROUTINE

Directly use "static inline" which is available in C99 and later. This brings
the RTEMS implementation closer to standard C.

Close #3935.

  • Property mode set to 100644
File size: 20.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @brief V850 CPU Department Source
7 *
8 * This include file contains information pertaining to the v850
9 * processor.
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2012.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifndef _RTEMS_SCORE_CPU_H
39#define _RTEMS_SCORE_CPU_H
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45#include <rtems/score/basedefs.h>
46#include <rtems/score/v850.h>
47
48/* conditional compilation parameters */
49
50/**
51 * Does the CPU follow the simple vectored interrupt model?
52 *
53 * If TRUE, then RTEMS allocates the vector table it internally manages.
54 * If FALSE, then the BSP is assumed to allocate and manage the vector
55 * table
56 *
57 * Port Specific Information:
58 *
59 * This port uses the Progammable Interrupt Controller interrupt model.
60 */
61#define CPU_SIMPLE_VECTORED_INTERRUPTS FALSE
62
63#define CPU_HARDWARE_FP FALSE
64
65#define CPU_SOFTWARE_FP FALSE
66
67#define CPU_ALL_TASKS_ARE_FP FALSE
68
69#define CPU_IDLE_TASK_IS_FP FALSE
70
71#define CPU_USE_DEFERRED_FP_SWITCH FALSE
72
73#define CPU_ENABLE_ROBUST_THREAD_DISPATCH FALSE
74
75/**
76 * Does the stack grow up (toward higher addresses) or down
77 * (toward lower addresses)?
78 *
79 * If TRUE, then the grows upward.
80 * If FALSE, then the grows toward smaller addresses.
81 *
82 * Port Specific Information:
83 *
84 * The v850 stack grows from high addresses to low addresses.
85 */
86#define CPU_STACK_GROWS_UP               FALSE
87
88/* FIXME: Is this the right value? */
89#define CPU_CACHE_LINE_BYTES 32
90
91#define CPU_STRUCTURE_ALIGNMENT
92
93/**
94 * @addtogroup RTEMSScoreCPUV850CPUInterrupt
95 * The following defines the number of bits actually used in the
96 * interrupt field of the task mode.  How those bits map to the
97 * CPU interrupt levels is defined by the routine @ref _CPU_ISR_Set_level.
98 *
99 * Port Specific Information:
100 *
101 * The v850 only has a single bit in the CPU for interrupt disable/enable.
102 */
103#define CPU_MODES_INTERRUPT_MASK   0x00000001
104
105#define CPU_MAXIMUM_PROCESSORS 32
106
107/**
108 * @defgroup RTEMSScoreCPUV850CPUContext Processor Dependent Context Management
109 *
110 * @ingroup RTEMSScoreCPUV850
111 *
112 * From the highest level viewpoint, there are 2 types of context to save.
113 *
114 *    -# Interrupt registers to save
115 *    -# Task level registers to save
116 *
117 * Since RTEMS handles integer and floating point contexts separately, this
118 * means we have the following 3 context items:
119 *
120 *    -# task level context stuff::  Context_Control
121 *    -# floating point task stuff:: Context_Control_fp
122 *    -# special interrupt level context :: CPU_Interrupt_frame
123 *
124 * On some processors, it is cost-effective to save only the callee
125 * preserved registers during a task context switch.  This means
126 * that the ISR code needs to save those registers which do not
127 * persist across function calls.  It is not mandatory to make this
128 * distinctions between the caller/callee saves registers for the
129 * purpose of minimizing context saved during task switch and on interrupts.
130 * If the cost of saving extra registers is minimal, simplicity is the
131 * choice.  Save the same context on interrupt entry as for tasks in
132 * this case.
133 *
134 * Additionally, if gdb is to be made aware of RTEMS tasks for this CPU, then
135 * care should be used in designing the context area.
136 *
137 * On some CPUs with hardware floating point support, the Context_Control_fp
138 * structure will not be used or it simply consist of an array of a
139 * fixed number of bytes.   This is done when the floating point context
140 * is dumped by a "FP save context" type instruction and the format
141 * is not really defined by the CPU.  In this case, there is no need
142 * to figure out the exact format -- only the size.  Of course, although
143 * this is enough information for RTEMS, it is probably not enough for
144 * a debugger such as gdb.  But that is another problem.
145 *
146 * Port Specific Information:
147 *
148 * On the v850, this port saves special registers and those that are
149 * callee saved.
150 */
151/** @{ **/
152
153/**
154 * This defines the minimal set of integer and processor state registers
155 * that must be saved during a voluntary context switch from one thread
156 * to another.
157 */
158typedef struct {
159    uint32_t   r1;
160    /** This field is the stack pointer (e.g. r3).  */
161    uint32_t   r3_stack_pointer;
162    uint32_t   r20;
163    uint32_t   r21;
164    uint32_t   r22;
165    uint32_t   r23;
166    uint32_t   r24;
167    uint32_t   r25;
168    uint32_t   r26;
169    uint32_t   r27;
170    uint32_t   r28;
171    uint32_t   r29;
172    uint32_t   r31;
173    uint32_t   psw;
174} Context_Control;
175
176/**
177 * This macro returns the stack pointer associated with @a _context.
178 *
179 * @param[in] _context is the thread context area to access
180 *
181 * @return This method returns the stack pointer.
182 */
183#define _CPU_Context_Get_SP( _context ) \
184  (_context)->r3_stack_pointer
185
186/**
187 * This defines the set of integer and processor state registers that must
188 * be saved during an interrupt.  This set does not include any which are
189 * in @ref Context_Control.
190 */
191typedef struct {
192    /** This field is a hint that a port will have a number of integer
193     * registers that need to be saved when an interrupt occurs or
194     * when a context switch occurs at the end of an ISR.
195     */
196    uint32_t   special_interrupt_register;
197} CPU_Interrupt_frame;
198
199/** @} */
200
201/**
202 * @defgroup RTEMSScoreCPUV850CPUInterrupt Processor Dependent Interrupt Management
203 *
204 * @ingroup RTEMSScoreCPUV850
205 */
206/** @{ **/
207
208/**
209 * Amount of extra stack (above minimum stack size) required by
210 * MPCI receive server thread.  Remember that in a multiprocessor
211 * system this thread must exist and be able to process all directives.
212 *
213 * Port Specific Information:
214 *
215 * There is no reason to think the v850 needs extra MPCI receive
216 * server stack.
217 */
218#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
219
220/**
221 * This is defined if the port has a special way to report the ISR nesting
222 * level.  Most ports maintain the variable @a _ISR_Nest_level.
223 */
224#define CPU_PROVIDES_ISR_IS_IN_PROGRESS FALSE
225
226/** @} */
227
228/**
229 * @addtogroup RTEMSScoreCPUV850CPUContext
230 * Should be large enough to run all RTEMS tests.  This ensures
231 * that a "reasonable" small application should not have any problems.
232 *
233 * Port Specific Information:
234 *
235 * This should be very conservative on the v850.
236 */
237#define CPU_STACK_MINIMUM_SIZE          (1024*4)
238
239#define CPU_SIZEOF_POINTER 4
240
241/**
242 * CPU's worst alignment requirement for data types on a byte boundary.  This
243 * alignment does not take into account the requirements for the stack.
244 *
245 * Port Specific Information:
246 *
247 * There is no apparent reason why this should be larger than 8.
248 */
249#define CPU_ALIGNMENT              8
250
251/**
252 * This number corresponds to the byte alignment requirement for the
253 * heap handler.  This alignment requirement may be stricter than that
254 * for the data types alignment specified by @ref CPU_ALIGNMENT.  It is
255 * common for the heap to follow the same alignment requirement as
256 * @ref CPU_ALIGNMENT.  If the @ref CPU_ALIGNMENT is strict enough for
257 * the heap, then this should be set to @ref CPU_ALIGNMENT.
258 *
259 * @note  This does not have to be a power of 2 although it should be
260 *        a multiple of 2 greater than or equal to 2.  The requirement
261 *        to be a multiple of 2 is because the heap uses the least
262 *        significant field of the front and back flags to indicate
263 *        that a block is in use or free.  So you do not want any odd
264 *        length blocks really putting length data in that bit.
265 *
266 *        On byte oriented architectures, @ref CPU_HEAP_ALIGNMENT normally will
267 *        have to be greater or equal to than @ref CPU_ALIGNMENT to ensure that
268 *        elements allocated from the heap meet all restrictions.
269 *
270 * Port Specific Information:
271 *
272 * There is no apparent reason why this should be larger than CPU_ALIGNMENT.
273 */
274#define CPU_HEAP_ALIGNMENT         CPU_ALIGNMENT
275
276/**
277 * The v850 has enough RAM where alignment to 16 may be desirable depending
278 * on the cache properties. But this remains to be demonstrated.
279 */
280#define CPU_STACK_ALIGNMENT        8
281
282#define CPU_INTERRUPT_STACK_ALIGNMENT CPU_CACHE_LINE_BYTES
283
284/*
285 *  ISR handler macros
286 */
287
288/**
289 * @addtogroup RTEMSScoreCPUV850CPUInterrupt
290 */
291/** @{ **/
292
293/**
294 * Disable all interrupts for an RTEMS critical section.  The previous
295 * level is returned in @a _isr_cookie.
296 *
297 * @param[out] _isr_cookie will contain the previous level cookie
298 *
299 * Port Specific Information:
300 *
301 * On the v850, we need to save the PSW and use "di" to disable interrupts.
302 */
303#define _CPU_ISR_Disable( _isr_cookie ) \
304  do { \
305    unsigned int _psw; \
306    \
307    v850_get_psw( _psw ); \
308    __asm__ __volatile__( "di" ); \
309    _isr_cookie = _psw; \
310  } while (0)
311
312/**
313 * Enable interrupts to the previous level (returned by _CPU_ISR_Disable).
314 * This indicates the end of an RTEMS critical section.  The parameter
315 * @a _isr_cookie is not modified.
316 *
317 * @param[in] _isr_cookie contain the previous level cookie
318 *
319 * Port Specific Information:
320 *
321 * On the v850, we simply need to restore the PSW.
322 */
323#define _CPU_ISR_Enable( _isr_cookie )  \
324  do { \
325    unsigned int _psw = (_isr_cookie); \
326    \
327    v850_set_psw( _psw ); \
328  } while (0)
329
330/**
331 * This temporarily restores the interrupt to @a _isr_cookie before immediately
332 * disabling them again.  This is used to divide long RTEMS critical
333 * sections into two or more parts.  The parameter @a _isr_cookie is not
334 * modified.
335 *
336 * @param[in] _isr_cookie contain the previous level cookie
337 *
338 * Port Specific Information:
339 *
340 * This saves at least one instruction over using enable/disable back to back.
341 */
342#define _CPU_ISR_Flash( _isr_cookie ) \
343  do { \
344    unsigned int _psw = (_isr_cookie); \
345    v850_set_psw( _psw ); \
346    __asm__ __volatile__( "di" ); \
347  } while (0)
348
349static inline bool _CPU_ISR_Is_enabled( uint32_t level )
350{
351  return ( level & V850_PSW_INTERRUPT_DISABLE_MASK )
352    != V850_PSW_INTERRUPT_DISABLE;
353}
354
355/**
356 * This routine and @ref _CPU_ISR_Get_level
357 * Map the interrupt level in task mode onto the hardware that the CPU
358 * actually provides.  Currently, interrupt levels which do not
359 * map onto the CPU in a generic fashion are undefined.  Someday,
360 * it would be nice if these were "mapped" by the application
361 * via a callout.  For example, m68k has 8 levels 0 - 7, levels
362 * 8 - 255 would be available for bsp/application specific meaning.
363 * This could be used to manage a programmable interrupt controller
364 * via the rtems_task_mode directive.
365 *
366 * Port Specific Information:
367 *
368 * On the v850, level 0 is enabled. Non-zero is disabled.
369 */
370#define _CPU_ISR_Set_level( new_level ) \
371  do { \
372    if ( new_level ) \
373      __asm__ __volatile__( "di" ); \
374    else \
375      __asm__ __volatile__( "ei" ); \
376  } while (0)
377
378/**
379 * Return the current interrupt disable level for this task in
380 * the format used by the interrupt level portion of the task mode.
381 *
382 * @note This routine usually must be implemented as a subroutine.
383 *
384 * Port Specific Information:
385 *
386 * This method is implemented in C on the v850.
387 */
388uint32_t   _CPU_ISR_Get_level( void );
389
390/* end of ISR handler macros */
391
392/** @} */
393
394/* Context handler macros */
395
396/**
397 * @addtogroup RTEMSScoreCPUV850CPUContext
398 * Initialize the context to a state suitable for starting a
399 * task after a context restore operation.  Generally, this
400 * involves:
401 *
402 *    - setting a starting address
403 *    - preparing the stack
404 *    - preparing the stack and frame pointers
405 *    - setting the proper interrupt level in the context
406 *    - initializing the floating point context
407 *
408 * This routine generally does not set any unnecessary register
409 * in the context.  The state of the "general data" registers is
410 * undefined at task start time.
411 *
412 * @param[in] _the_context is the context structure to be initialized
413 * @param[in] _stack_base is the lowest physical address of this task's stack
414 * @param[in] _size is the size of this task's stack
415 * @param[in] _isr is the interrupt disable level
416 * @param[in] _entry_point is the thread's entry point.  This is
417 *        always @a _Thread_Handler
418 * @param[in] _is_fp is TRUE if the thread is to be a floating
419 *       point thread.  This is typically only used on CPUs where the
420 *       FPU may be easily disabled by software such as on the SPARC
421 *       where the PSR contains an enable FPU bit.
422 * @param[in] tls_area is the thread-local storage (TLS) area
423 *
424 * Port Specific Information:
425 *
426 * This method is implemented in C on the v850.
427 */
428void _CPU_Context_Initialize(
429  Context_Control  *the_context,
430  uint32_t         *stack_base,
431  uint32_t          size,
432  uint32_t          new_level,
433  void             *entry_point,
434  bool              is_fp,
435  void             *tls_area
436);
437
438/**
439 * This routine is responsible for somehow restarting the currently
440 * executing task.  If you are lucky, then all that is necessary
441 * is restoring the context.  Otherwise, there will need to be
442 * a special assembly routine which does something special in this
443 * case.  For many ports, simply adding a label to the restore path
444 * of @ref _CPU_Context_switch will work.  On other ports, it may be
445 * possibly to load a few arguments and jump to the restore path. It will
446 * not work if restarting self conflicts with the stack frame
447 * assumptions of restoring a context.
448 *
449 * Port Specific Information:
450 *
451 * On the v850, we require a special entry point to restart a task.
452 */
453#define _CPU_Context_Restart_self( _the_context ) \
454   _CPU_Context_restore( (_the_context) );
455
456/* XXX this should be possible to remove */
457#if 0
458/**
459 * This routine initializes the FP context area passed to it to.
460 * There are a few standard ways in which to initialize the
461 * floating point context.  The code included for this macro assumes
462 * that this is a CPU in which a "initial" FP context was saved into
463 * @a _CPU_Null_fp_context and it simply copies it to the destination
464 * context passed to it.
465 *
466 * Other floating point context save/restore models include:
467 *   -# not doing anything, and
468 *   -# putting a "null FP status word" in the correct place in the FP context.
469 *
470 * @param[in] _destination is the floating point context area
471 *
472 * Port Specific Information:
473 *
474 * XXX document implementation including references if appropriate
475 */
476#define _CPU_Context_Initialize_fp( _destination ) \
477  { \
478  }
479#endif
480
481/* end of Context handler macros */
482
483#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
484
485#define CPU_USE_LIBC_INIT_FINI_ARRAY FALSE
486
487/* functions */
488
489/**
490 * @brief CPU initialize.
491 * This routine performs CPU dependent initialization.
492 *
493 * Port Specific Information:
494 *
495 * This is implemented in C.
496 *
497 * v850 CPU Dependent Source
498 */
499void _CPU_Initialize(void);
500
501void *_CPU_Thread_Idle_body( uintptr_t ignored );
502
503/**
504 * @addtogroup RTEMSScoreCPUV850CPUContext
505 */
506/**@{**/
507
508/**
509 * This routine switches from the run context to the heir context.
510 *
511 * @param[in] run points to the context of the currently executing task
512 * @param[in] heir points to the context of the heir task
513 *
514 * Port Specific Information:
515 *
516 * This is implemented in assembly on the v850.
517 */
518void _CPU_Context_switch(
519  Context_Control  *run,
520  Context_Control  *heir
521);
522
523/**
524 * This routine is generally used only to restart self in an
525 * efficient manner.  It may simply be a label in @ref _CPU_Context_switch.
526 *
527 * @param[in] new_context points to the context to be restored.
528 *
529 * @note May be unnecessary to reload some registers.
530 *
531 * Port Specific Information:
532 *
533 * This is implemented in assembly on the v850.
534 */
535RTEMS_NO_RETURN void _CPU_Context_restore( Context_Control *new_context );
536
537/* XXX this should be possible to remove */
538#if 0
539/**
540 * This routine saves the floating point context passed to it.
541 *
542 * @param[in] fp_context_ptr is a pointer to a pointer to a floating
543 * point context area
544 *
545 * @return on output @a *fp_context_ptr will contain the address that
546 * should be used with @ref _CPU_Context_restore_fp to restore this context.
547 *
548 * Port Specific Information:
549 *
550 * XXX document implementation including references if appropriate
551 */
552void _CPU_Context_save_fp(
553  Context_Control_fp **fp_context_ptr
554);
555#endif
556
557/* XXX this should be possible to remove */
558#if 0
559/**
560 * This routine restores the floating point context passed to it.
561 *
562 * @param[in] fp_context_ptr is a pointer to a pointer to a floating
563 * point context area to restore
564 *
565 * @return on output @a *fp_context_ptr will contain the address that
566 * should be used with @ref _CPU_Context_save_fp to save this context.
567 *
568 * Port Specific Information:
569 *
570 * XXX document implementation including references if appropriate
571 */
572void _CPU_Context_restore_fp(
573  Context_Control_fp **fp_context_ptr
574);
575#endif
576
577/** @} */
578
579/* FIXME */
580typedef CPU_Interrupt_frame CPU_Exception_frame;
581
582void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
583
584/**
585 * @defgroup RTEMSScoreCPUV850CPUEndian CPUEndian
586 *
587 * @ingroup RTEMSScoreCPUV850
588 *
589 * @brief CPUEndian
590 */
591/** @{ */
592
593/**
594 * The following routine swaps the endian format of an unsigned int.
595 * It must be static because it is referenced indirectly.
596 *
597 * This version will work on any processor, but if there is a better
598 * way for your CPU PLEASE use it.  The most common way to do this is to:
599 *
600 *    swap least significant two bytes with 16-bit rotate
601 *    swap upper and lower 16-bits
602 *    swap most significant two bytes with 16-bit rotate
603 *
604 * Some CPUs have special instructions which swap a 32-bit quantity in
605 * a single instruction (e.g. i486).  It is probably best to avoid
606 * an "endian swapping control bit" in the CPU.  One good reason is
607 * that interrupts would probably have to be disabled to ensure that
608 * an interrupt does not try to access the same "chunk" with the wrong
609 * endian.  Another good reason is that on some CPUs, the endian bit
610 * endianness for ALL fetches -- both code and data -- so the code
611 * will be fetched incorrectly.
612 *
613 * @param[in] value is the value to be swapped
614 * @return the value after being endian swapped
615 *
616 * Port Specific Information:
617 *
618 * The v850 has a single instruction to swap endianness on a 32 bit quantity.
619 */
620static inline uint32_t CPU_swap_u32(
621  uint32_t value
622)
623{
624  unsigned int swapped;
625
626  #if (V850_HAS_BYTE_SWAP_INSTRUCTION == 1)
627    unsigned int v;
628
629    v = value;
630    __asm__ __volatile__ ("bsw %0, %1" : "=r" (v), "=&r" (swapped) );
631  #else
632    uint32_t byte1, byte2, byte3, byte4;
633
634    byte4 = (value >> 24) & 0xff;
635    byte3 = (value >> 16) & 0xff;
636    byte2 = (value >> 8)  & 0xff;
637    byte1 =  value        & 0xff;
638
639    swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
640  #endif
641  return swapped;
642}
643
644/**
645 * This routine swaps a 16 bir quantity.
646 *
647 * @param[in] value is the value to be swapped
648 * @return the value after being endian swapped
649 *
650 * Port Specific Information:
651 *
652 * The v850 has a single instruction to swap endianness on a 16 bit quantity.
653 */
654static inline uint16_t CPU_swap_u16( uint16_t value )
655{
656  unsigned int swapped;
657
658  #if (V850_HAS_BYTE_SWAP_INSTRUCTION == 1)
659    unsigned int v;
660
661    v = value;
662    __asm__ __volatile__ ("bsh %0, %1" : "=r" (v), "=&r" (swapped) );
663  #else
664    swapped = ((value & 0xff) << 8) | ((value >> 8) & 0xff);
665  #endif
666  return swapped;
667}
668
669/** @} */
670
671typedef uint32_t CPU_Counter_ticks;
672
673uint32_t _CPU_Counter_frequency( void );
674
675CPU_Counter_ticks _CPU_Counter_read( void );
676
677/** Type that can store a 32-bit integer or a pointer. */
678typedef uintptr_t CPU_Uint32ptr;
679
680#ifdef __cplusplus
681}
682#endif
683
684#endif
Note: See TracBrowser for help on using the repository browser.