aboutsummaryrefslogtreecommitdiff
path: root/arch/all/core-sh/include/smachine.h
blob: bb31634d3a5a1a91e17607177efd4fe37535e89a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* ****************************************************************************
 * smachine.h -- SuperH intrinsics, privileged mode.
 * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
 *
 * This file is part of the 'all/core-sh' module in libcarrot, an experimental
 * modular libc project.
 *
 * This file is governed by the CeCILL-C license under French law and abiding
 * by the rules of distribution of free software. You can use, modify and or
 * redistribute it under the terms of the CeCILL-C license as circulated by
 * CEA, CNRS and INRIA at the following URL: http://www.cecill.info
 *
 * As a counterpart to the access to the source code and rights to copy, modify
 * and redistribute granted by the license, users are provided only with a
 * limited warranty and the software's author, the holder of the economic
 * rights, and the successive licensors have only limited liability.
 *
 * In this respect, the user's attention is drawn to the risks associated with
 * loading, using, modifying and/or developing and reproducing the software by
 * the user in light of its specific status of free software, that may mean
 * that it is complicated to manipulate, and that also therefore means that it
 * is reserved for developers and experienced professionals having in-depth
 * computer knowledge. Users are therefore encouraged to load and test the
 * software's suitability as regards their requirements in conditions enabling
 * the security of their systems and/or data to be ensured and, more generally,
 * to use and operate it in the same conditions as regards security.
 *
 * The fact that you are presently reading this means you have had knowledge of
 * the CeCILL-C license and that you accept its terms.
 * ************************************************************************* */
#include <cdefs.h>
#include <stdint.h>
#include <builtin.h>
#include <fixed.h>
__BEGIN_DECLS

/* ************************************************************************* */
/*  Status register management                                               */
/* ************************************************************************* */
/* The status register is basically the main control register of the SuperH
 * architecture. */

#if __RENESAS_PREREQ(1, 0)
# define set_cr(_CR) _builtin_set_cr(_CR)
# define get_cr()    _builtin_get_cr()

#elif __GNUC_ASM
static __inline __uint32_t __get_sr(void) {
	uint32_t __ret; asm("stc sr, %0" : "=r"(__ret)); return (__ret); }
static __inline void __set_sr(uint32_t __sr) {
	asm("ldc %0, sr" :: "r"(__sr)); }

# define set_cr(_CR) __set_sr(_CR)
# define set_sr(_CR) __set_sr(_CR)
# define get_cr()    __get_sr()
# define get_sr()    __get_sr()
#endif

/* You can also set the saved status register (SSR) using this interface!
 * Here are the macro definitions. */

#if __GNUC_ASM
static __inline __uint32_t __get_ssr(void) {
	__uint32_t __ret; asm("stc ssr, %0" :: "=r"(__ret)); return (__ret); }
static __inline void __set_ssr(__uint32_t __ssr) {
	asm("ldc %0, ssr" :: "r"(__ssr)); }

# define set_ssr(_SSR) __set_ssr(_SSR)
# define get_ssr()     __get_ssr()
#else
extern __uint32_t __asm_get_ssr OF((void));
extern void       __asm_set_ssr OF((__uint32_t __ssr));

# define set_ssr(_SSR) __asm_set_ssr(_SSR)
# define get_ssr()     __asm_get_ssr(_SSR)
#endif
/* ************************************************************************* */
/*  Interrupt mask level management                                          */
/* ************************************************************************* */
/* An interrupt whose priority is equal to or less than the IMASK is masked.
 * Here are the macros to set and get this value: */

#if __RENESAS_PREREQ(1, 0)
# define set_imask(_IMASK) _builtin_set_imask(_IMASK)
# define get_imask()       _builtin_get_imask()

#elif __GNUC_ASM
# define set_imask(_IMASK) \
	set_cr((get_cr() & ~0xF0) | (((_IMASK) & 0x0F) << 4))
# define get_imask() \
	((get_cr() >> 4) & 0x0F)
#endif
/* ************************************************************************* */
/*  Vector base register management                                          */
/* ************************************************************************* */
/* The vector base is the address from which is calculated the addresses of the
 * interrupt, exception and MMU exception handlers. */

#if __RENESAS_PREREQ(1, 0)
# define set_vbr(_VBR) _builtin_set_vbr(_VBR)
# define get_vbr()     _builtin_get_vbr()

#elif __GNUC_ASM
static __inline __uint32_t __get_vbr(void) {
	__uint32_t __vbr; __asm("ldc.l vbr, %0":"=r"(__vbr):); return (__vbr); }
static __inline void __set_vbr(__uint32_t __vbr) {
	__asm("stc.l %0, vbr"::"r"(__vbr)); }

# define set_vbr(_VBR) __set_vbr(_VBR)
# define get_vbr()     __get_vbr()
#endif
/* ************************************************************************* */
/*  Miscallenous instructions                                                */
/* ************************************************************************* */
/* Sleep: wait for an interruption. */

#if __RENESAS_PREREQ(1, 0)
# define sleep() _builtin_sleep()
#elif defined(__GNUC__)
# define sleep() __asm("sleep")
#endif

/* Load TLB page from Page Table Entry High/Low (PTEH/PTEL). */

#if !defined(_SH3) && !defined(_SH3DSP) && !defined(_SH4) && !defined(_SH4A) \
	&& !defined(_SH4ALDSP)
#elif __RENESAS_PREREQ(9, 4)
# define ldtlb() _builtin_ldtlb()
#elif defined(__GNUC__)
# define ldtlb() __asm("ldtlb")
#endif
/* ************************************************************************* */
/*  Specify and cancel modulo addressing                                     */
/* ************************************************************************* */
/* I don't know what these are. FIXME */

#if (!defined(_SH2DSP) && !defined(_SH3DSP) && !defined(_SH4ALDSP)) \
	|| !defined(_DSPC)
#elif __RENESAS_PREREQ(1, 0)
# define set_circ_x(_ARRAY, _SIZE) _builtin_set_circ_x(_ARRAY, _SIZE)
# define set_circ_y(_ARRAY, _SIZE) _builtin_set_circ_y(_ARRAY, _SIZE)
# define clr_circ()                _builtin_clr_circ()

#elif __GNUC_ASM
static __asm_inline void __clr_circ(void) {
	set_cr(get_cr() & ~0xC00); }

# define set_circ_x(_ARRAY, _SIZE) ((void)0)
# define set_circ_y(_ARRAY, _SIZE) ((void)0)
# define clr_circ()                __clr_circ()
#endif
/* ************************************************************************* */
/* Set the interrupt mask level and jump to subroutine                       */
/* ************************************************************************* */
/* If I am right on the macro signification, then I don't understand why
 * it's useful. I thought it was basically there to force the 'store to control
 * register' to be in the delayed branch of the 'jump to subroutine', which
 * may not be enforced by default by Hitachi's compiler...? */

#if __RENESAS_PREREQ(9, 4)
# define sr_jsr(_FUNC, _IMASK) _builtin_sr_jsr(_FUNC, _IMASK)

#elif __GNUC_ASM
# define sr_jsr(_FUNC, _IMASK) __asm("jsr %1\r\n" "stc.l %0" \
	:: "r"((get_cr() & ~0xF0) | ((_IMASK) << 4)), "r"(_FUNC))
#endif

__END_DECLS