1/*
2 * Copyright (c) 2022 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8#include <lk/asm.h>
9#include <arch/riscv.h>
10#include <arch/riscv/asm.h>
11
12#if RISCV_FPU
13
14// enable full use of all of the fpu instructions
15#if __riscv_xlen == 32
16.attribute arch, "rv32imafdc"
17#elif __riscv_xlen == 64
18.attribute arch, "rv64imafdc"
19#else
20#error unknown xlen
21#endif
22
23// conditionally use fcvt or fmv based on 32 or 64bit ISA
24.macro ZERO_FPU_REG reg, width
25#if __riscv_xlen == 32
26    fcvt.\width\().w \reg, zero
27#elif __riscv_xlen == 64
28    fmv.\width\().x \reg, zero
29#endif
30.endm
31
32// called just before entering user space for the first time.
33// must not use the stack and is okay to be called with interrupts disabled.
34FUNCTION(riscv_fpu_zero)
35    // zero out the fpu state
36    // TODO: handle single precision implementations
37    csrw fcsr, zero
38    ZERO_FPU_REG f0, d
39    ZERO_FPU_REG f1, d
40    ZERO_FPU_REG f2, d
41    ZERO_FPU_REG f3, d
42    ZERO_FPU_REG f4, d
43    ZERO_FPU_REG f5, d
44    ZERO_FPU_REG f6, d
45    ZERO_FPU_REG f7, d
46    ZERO_FPU_REG f8, d
47    ZERO_FPU_REG f9, d
48    ZERO_FPU_REG f10, d
49    ZERO_FPU_REG f11, d
50    ZERO_FPU_REG f12, d
51    ZERO_FPU_REG f13, d
52    ZERO_FPU_REG f14, d
53    ZERO_FPU_REG f15, d
54    ZERO_FPU_REG f16, d
55    ZERO_FPU_REG f17, d
56    ZERO_FPU_REG f18, d
57    ZERO_FPU_REG f19, d
58    ZERO_FPU_REG f20, d
59    ZERO_FPU_REG f21, d
60    ZERO_FPU_REG f22, d
61    ZERO_FPU_REG f23, d
62    ZERO_FPU_REG f24, d
63    ZERO_FPU_REG f25, d
64    ZERO_FPU_REG f26, d
65    ZERO_FPU_REG f27, d
66    ZERO_FPU_REG f28, d
67    ZERO_FPU_REG f29, d
68    ZERO_FPU_REG f30, d
69    ZERO_FPU_REG f31, d
70
71    // put the hardware in the initial state
72    // FS[1:0] == 1 set in two steps: one to set bit 0, second one to clear bit 1
73    // this ensures it doesn't go through the disabled state (00)
74    li  a0, (1 << 13)
75    csrs RISCV_CSR_XSTATUS, a0
76    li   a0, (1 << 14)
77    csrc RISCV_CSR_XSTATUS, a0
78
79    ret
80END_FUNCTION(riscv_fpu_zero)
81
82// void riscv_fpu_save(struct riscv_fpu_state *state);
83FUNCTION(riscv_fpu_save)
84    fsd  f0, 0*8(a0)
85    fsd  f1, 1*8(a0)
86    fsd  f2, 2*8(a0)
87    fsd  f3, 3*8(a0)
88    fsd  f4, 4*8(a0)
89    fsd  f5, 5*8(a0)
90    fsd  f6, 6*8(a0)
91    fsd  f7, 7*8(a0)
92    fsd  f8, 8*8(a0)
93    fsd  f9, 9*8(a0)
94    fsd  f10, 10*8(a0)
95    fsd  f11, 11*8(a0)
96    fsd  f12, 12*8(a0)
97    fsd  f13, 13*8(a0)
98    fsd  f14, 14*8(a0)
99    fsd  f15, 15*8(a0)
100    fsd  f16, 16*8(a0)
101    fsd  f17, 17*8(a0)
102    fsd  f18, 18*8(a0)
103    fsd  f19, 19*8(a0)
104    fsd  f20, 20*8(a0)
105    fsd  f21, 21*8(a0)
106    fsd  f22, 22*8(a0)
107    fsd  f23, 23*8(a0)
108    fsd  f24, 24*8(a0)
109    fsd  f25, 25*8(a0)
110    fsd  f26, 26*8(a0)
111    fsd  f27, 27*8(a0)
112    fsd  f28, 28*8(a0)
113    fsd  f29, 29*8(a0)
114    fsd  f30, 30*8(a0)
115    fsd  f31, 31*8(a0)
116    csrr a1, fcsr
117    sw   a1, 32*8(a0)
118    ret
119END_FUNCTION(riscv_fpu_save)
120
121// void riscv_fpu_restore(struct riscv_fpu_state *state);
122FUNCTION(riscv_fpu_restore)
123    fld  f0, 0*8(a0)
124    fld  f1, 1*8(a0)
125    fld  f2, 2*8(a0)
126    fld  f3, 3*8(a0)
127    fld  f4, 4*8(a0)
128    fld  f5, 5*8(a0)
129    fld  f6, 6*8(a0)
130    fld  f7, 7*8(a0)
131    fld  f8, 8*8(a0)
132    fld  f9, 9*8(a0)
133    fld  f10, 10*8(a0)
134    fld  f11, 11*8(a0)
135    fld  f12, 12*8(a0)
136    fld  f13, 13*8(a0)
137    fld  f14, 14*8(a0)
138    fld  f15, 15*8(a0)
139    fld  f16, 16*8(a0)
140    fld  f17, 17*8(a0)
141    fld  f18, 18*8(a0)
142    fld  f19, 19*8(a0)
143    fld  f20, 20*8(a0)
144    fld  f21, 21*8(a0)
145    fld  f22, 22*8(a0)
146    fld  f23, 23*8(a0)
147    fld  f24, 24*8(a0)
148    fld  f25, 25*8(a0)
149    fld  f26, 26*8(a0)
150    fld  f27, 27*8(a0)
151    fld  f28, 28*8(a0)
152    fld  f29, 29*8(a0)
153    fld  f30, 30*8(a0)
154    fld  f31, 31*8(a0)
155    lw   a1, 32*8(a0)
156    csrw fcsr, a1
157    ret
158END_FUNCTION(riscv_fpu_restore)
159#endif // RISCV_FPU
160