source: mainline/kernel/arch/arm32/src/fpu_context.c@ 123be4f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 123be4f was 4f843ded, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

arm32, fpu: Improve context save/restore assembler.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup arm32
30 * @{
31 */
32/** @file
33 * @brief arm32 FPU context
34 */
35
36#include <fpu_context.h>
37#include <arch.h>
38#include <cpu.h>
39
40#define FPSID_IMPLEMENTER(r) ((r) >> 24)
41#define FPSID_SW_ONLY_FLAG (1 << 23)
42#define FPSID_SUBACHITECTURE(r) (((r) >> 16) & 0x7f)
43#define FPSID_PART_NUMBER(r) (((r) >> 8) & 0xff)
44#define FPSID_VARIANT(r) (((r) >> 4) 0xf)
45#define FPSID_REVISION(r) (((r) >> 0) 0xf)
46enum {
47 FPU_VFPv1 = 0x00,
48 FPU_VFPv2_COMMONv1 = 0x01,
49 FPU_VFPv3_COMMONv2 = 0x02,
50 FPU_VFPv3_NO_COMMON = 0x3, /* Does not support trap */
51 FPU_VFPv3_COMMONv3 = 0x4,
52};
53
54enum {
55 FPEXC_ENABLED_FLAG = 0x40000000,
56 FPEXC_EX_FLAG = 0x80000000,
57};
58
59static inline uint32_t fpexc_read()
60{
61 uint32_t reg;
62 asm volatile (
63 "vmrs %0, fpexc\n"
64 :"=r" (reg)::
65 );
66 return reg;
67}
68
69static inline void fpexc_write(uint32_t val)
70{
71 asm volatile (
72 "vmsr fpexc, %0\n"
73 ::"r" (val):
74 );
75}
76
77static void (*save_context)(fpu_context_t *ctx);
78static void (*restore_context)(fpu_context_t *ctx);
79
80/** Saves 32 single precision fpu registers.
81 * @param ctx FPU context area.
82 * Used by VFPv1
83 */
84static void fpu_context_save_s32(fpu_context_t *ctx)
85{
86 asm volatile (
87 "vmrs r1, fpexc\n"
88 "vmrs r2, fpscr\n"
89 "stmia %0!, {r1, r2}\n"
90 "vstmia %0!, {s0-s31}\n"
91 ::"r" (ctx): "r1","r2","memory"
92 );
93}
94
95/** Restores 32 single precision fpu registers.
96 * @param ctx FPU context area.
97 * Used by VFPv1
98 */
99static void fpu_context_restore_s32(fpu_context_t *ctx)
100{
101 asm volatile (
102 "ldmia %0!, {r1, r2}\n"
103 "vmsr fpexc, r1\n"
104 "vmsr fpscr, r2\n"
105 "vldmia %0!, {s0-s31}\n"
106 ::"r" (ctx): "r1","r2"
107 );
108}
109
110/** Saves 16 double precision fpu registers.
111 * @param ctx FPU context area.
112 * Used by VFPv2, VFPv3-d16, and VFPv4-d16.
113 */
114static void fpu_context_save_d16(fpu_context_t *ctx)
115{
116 asm volatile (
117 "vmrs r1, fpexc\n"
118 "vmrs r2, fpscr\n"
119 "stmia %0!, {r1, r2}\n"
120 "vstmia %0!, {d0-d15}\n"
121 ::"r" (ctx): "r1","r2","memory"
122 );
123}
124
125/** Restores 16 double precision fpu registers.
126 * @param ctx FPU context area.
127 * Used by VFPv2, VFPv3-d16, and VFPv4-d16.
128 */
129static void fpu_context_restore_d16(fpu_context_t *ctx)
130{
131 asm volatile (
132 "ldmia %0!, {r1, r2}\n"
133 "vmsr fpexc, r1\n"
134 "vmsr fpscr, r2\n"
135 "vldmia %0!, {d0-d15}\n"
136 ::"r" (ctx): "r1","r2"
137 );
138}
139
140/** Saves 32 double precision fpu registers.
141 * @param ctx FPU context area.
142 * Used by VFPv3-d32, VFPv4-d32, and advanced SIMD.
143 */
144static void fpu_context_save_d32(fpu_context_t *ctx)
145{
146 asm volatile (
147 "vmrs r1, fpexc\n"
148 "stmia %0!, {r1}\n"
149 "vmrs r1, fpscr\n"
150 "stmia %0!, {r1}\n"
151 "vstmia %0!, {d0-d15}\n"
152 "vstmia %0!, {d16-d31}\n"
153 ::"r" (ctx): "r1","memory"
154 );
155}
156
157/** Restores 32 double precision fpu registers.
158 * @param ctx FPU context area.
159 * Used by VFPv3-d32, VFPv4-d32, and advanced SIMD.
160 */
161static void fpu_context_restore_d32(fpu_context_t *ctx)
162{
163 asm volatile (
164 "ldmia %0!, {r1}\n"
165 "vmsr fpexc, r1\n"
166 "ldmia %0!, {r1}\n"
167 "vmsr fpscr, r1\n"
168 "vldmia %0!, {d0-d15}\n"
169 "vldmia %0!, {d16-d31}\n"
170 ::"r" (ctx): "r1"
171 );
172}
173
174void fpu_init(void)
175{
176 /* Clear all fpu flags */
177 fpexc_write(0);
178 fpu_enable();
179}
180
181void fpu_setup(void)
182{
183 uint32_t fpsid = 0;
184 asm volatile (
185 "vmrs %0, fpsid\n"
186 :"=r"(fpsid)::
187 );
188 if (fpsid & FPSID_SW_ONLY_FLAG) {
189 printf("No FPU avaiable\n");
190 return;
191 }
192 switch (FPSID_SUBACHITECTURE(fpsid))
193 {
194 case FPU_VFPv1:
195 printf("Detected VFPv1\n");
196 save_context = fpu_context_save_s32;
197 restore_context = fpu_context_restore_s32;
198 break;
199 case FPU_VFPv2_COMMONv1:
200 printf("Detected VFPv2\n");
201 save_context = fpu_context_save_d16;
202 restore_context = fpu_context_restore_d16;
203 break;
204 case FPU_VFPv3_COMMONv2:
205 case FPU_VFPv3_NO_COMMON:
206 case FPU_VFPv3_COMMONv3: {
207 uint32_t mvfr0 = 0;
208 asm volatile (
209 "vmrs %0,mvfr0\n"
210 :"=r"(mvfr0)::
211 );
212 /* See page B4-1637 */
213 if ((mvfr0 & 0xf) == 0x1) {
214 printf("Detected VFPv3+ with 16 regs\n");
215 save_context = fpu_context_save_d16;
216 restore_context = fpu_context_restore_d16;
217 } else {
218 printf("Detected VFPv3+ with 32 regs\n");
219 save_context = fpu_context_save_d32;
220 restore_context = fpu_context_restore_d32;
221 }
222 break;
223 }
224
225 }
226}
227
228bool handle_if_fpu_exception(void)
229{
230 const uint32_t fpexc = fpexc_read();
231 if (fpexc & FPEXC_ENABLED_FLAG) {
232 printf("FPU exception with FPU on\n");
233 return false;
234 }
235#ifdef CONFIG_FPU_LAZY
236 scheduler_fpu_lazy_request();
237 return true;
238#else
239 return false;
240#endif
241}
242
243void fpu_enable(void)
244{
245 /* Enable FPU instructions */
246 fpexc_write(fpexc_read() | FPEXC_ENABLED_FLAG);
247}
248
249void fpu_disable(void)
250{
251 /* Disable FPU instructions */
252 fpexc_write(fpexc_read() & ~FPEXC_ENABLED_FLAG);
253}
254
255void fpu_context_save(fpu_context_t *ctx)
256{
257 const uint32_t fpexc = fpexc_read();
258
259 if (fpexc & FPEXC_EX_FLAG) {
260 printf("EX FPU flag is on, things will fail\n");
261 //TODO implement common subarch context saving
262 }
263 if (save_context)
264 save_context(ctx);
265}
266
267void fpu_context_restore(fpu_context_t *ctx)
268{
269 if (restore_context)
270 restore_context(ctx);
271}
Note: See TracBrowser for help on using the repository browser.