aboutsummaryrefslogtreecommitdiff
path: root/arch/all/core-sh/include/smachine.h
blob: f51d295122ab823cfa3b16a41335dbaa62642110 (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
/* ****************************************************************************
 * 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 free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Lesser Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * ************************************************************************* */
#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