1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_RISCV_
8 #define _HARDWARE_RISCV_
9 
10 #include "pico.h"
11 #include "hardware/regs/rvcsr.h"
12 
13 #ifndef __ASSEMBLER__
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /** \file hardware/riscv.h
20  *  \defgroup hardware_riscv hardware_riscv
21  *
22  * \brief Accessors for standard RISC-V hardware (mainly CSRs)
23  *
24  */
25 
26 #define _riscv_read_csr(csrname) ({ \
27     uint32_t __csr_tmp_u32; \
28     asm volatile ("csrr %0, " #csrname : "=r" (__csr_tmp_u32)); \
29     __csr_tmp_u32; \
30 })
31 
32 #define _riscv_write_csr(csrname, data) ({ \
33     if (__builtin_constant_p(data) && !((data) & -32u)) { \
34         asm volatile ("csrwi " #csrname ", %0" : : "i" (data)); \
35     } else { \
36         asm volatile ("csrw " #csrname ", %0" : : "r" (data)); \
37     } \
38 })
39 
40 #define _riscv_set_csr(csrname, data) ({ \
41     if (__builtin_constant_p(data) && !((data) & -32u)) { \
42         asm volatile ("csrsi " #csrname ", %0" : : "i" (data)); \
43     } else { \
44         asm volatile ("csrs " #csrname ", %0" : : "r" (data)); \
45     } \
46 })
47 
48 #define _riscv_clear_csr(csrname, data) ({ \
49     if (__builtin_constant_p(data) && !((data) & -32u)) { \
50         asm volatile ("csrci " #csrname ", %0" : : "i" (data)); \
51     } else { \
52         asm volatile ("csrc " #csrname ", %0" : : "r" (data)); \
53     } \
54 })
55 
56 #define _riscv_read_write_csr(csrname, data) ({ \
57     uint32_t __csr_tmp_u32; \
58     if (__builtin_constant_p(data) && !((data) & -32u)) { \
59         asm volatile ("csrrwi %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \
60     } else { \
61         asm volatile ("csrrw %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \
62     } \
63     __csr_tmp_u32; \
64 })
65 
66 #define _riscv_read_set_csr(csrname, data) ({ \
67     uint32_t __csr_tmp_u32; \
68     if (__builtin_constant_p(data) && !((data) & -32u)) { \
69         asm volatile ("csrrsi %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \
70     } else { \
71         asm volatile ("csrrs %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \
72     } \
73     __csr_tmp_u32; \
74 })
75 
76 #define _riscv_read_clear_csr(csrname, data) ({ \
77     uint32_t __csr_tmp_u32; \
78     if (__builtin_constant_p(data) && !((data) & -32u)) { \
79         asm volatile ("csrrci %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \
80     } else { \
81         asm volatile ("csrrc %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \
82     } \
83     __csr_tmp_u32; \
84 })
85 
86 // Argument macro expansion layer (CSR name may be a macro that expands to a
87 // CSR number, or it may be a bare name that the assembler knows about.)
88 #define riscv_read_csr(csrname) _riscv_read_csr(csrname)
89 #define riscv_write_csr(csrname, data) _riscv_write_csr(csrname, data)
90 #define riscv_set_csr(csrname, data) _riscv_set_csr(csrname, data)
91 #define riscv_clear_csr(csrname, data) _riscv_clear_csr(csrname, data)
92 #define riscv_read_write_csr(csrname, data) _riscv_read_write_csr(csrname, data)
93 #define riscv_read_set_csr(csrname, data) _riscv_read_set_csr(csrname, data)
94 #define riscv_read_clear_csr(csrname, data) _riscv_read_clear_csr(csrname, data)
95 
96 // Helpers for encoding RISC-V immediates
97 
98 // U format, e.g. lui
riscv_encode_imm_u(uint32_t x)99 static inline uint32_t riscv_encode_imm_u(uint32_t x) {
100     return (x >> 12) << 12;
101 }
102 
103 // I format, e.g. addi
riscv_encode_imm_i(uint32_t x)104 static inline uint32_t riscv_encode_imm_i(uint32_t x) {
105     return (x & 0xfff) << 20;
106 }
107 
108 // The U-format part of a U+I 32-bit immediate:
riscv_encode_imm_u_hi(uint32_t x)109 static inline uint32_t riscv_encode_imm_u_hi(uint32_t x) {
110     // We will add a signed 12 bit constant to the "lui" value,
111     // so we need to correct for the carry here.
112     x += (x & 0x800) << 1;
113     return riscv_encode_imm_u(x);
114 }
115 
116 // B format, e.g. bgeu
riscv_encode_imm_b(uint32_t x)117 static inline uint32_t riscv_encode_imm_b(uint32_t x) {
118     return
119         (((x >> 12) & 0x01) << 31) |
120         (((x >>  5) & 0x3f) << 25) |
121         (((x >>  1) & 0x0f) <<  8) |
122         (((x >> 11) & 0x01) <<  7);
123 }
124 
125 // S format, e.g. sw
riscv_encode_imm_s(uint32_t x)126 static inline uint32_t riscv_encode_imm_s(uint32_t x) {
127     return
128         (((x >>  5) & 0x7f) << 25) |
129         (((x >>  0) & 0x1f) <<  7);
130 }
131 
132 // J format, e.g. jal
riscv_encode_imm_j(uint32_t x)133 static inline uint32_t riscv_encode_imm_j(uint32_t x) {
134     return
135         (((x >> 20) & 0x001) << 31) |
136         (((x >>  1) & 0x3ff) << 21) |
137         (((x >> 11) & 0x001) << 20) |
138         (((x >> 12) & 0x0ff) << 12);
139 }
140 
141 // CJ format, e.g. c.jal
riscv_encode_imm_cj(uint32_t x)142 static inline uint16_t riscv_encode_imm_cj(uint32_t x) {
143     return (uint16_t)(
144         (((x >> 11) & 0x1) << 12) |
145         (((x >>  4) & 0x1) << 11) |
146         (((x >>  8) & 0x3) <<  9) |
147         (((x >> 10) & 0x1) <<  8) |
148         (((x >>  6) & 0x1) <<  7) |
149         (((x >>  7) & 0x1) <<  6) |
150         (((x >>  1) & 0x7) <<  3) |
151         (((x >>  5) & 0x1) <<  2)
152     );
153 }
154 
155 // CB format, e.g. c.beqz
riscv_encode_imm_cb(uint32_t x)156 static inline uint16_t riscv_encode_imm_cb(uint32_t x) {
157     return (uint16_t)(
158         (((x >> 8) & 0x1) << 12) |
159         (((x >> 3) & 0x3) << 10) |
160         (((x >> 6) & 0x3) <<  5) |
161         (((x >> 1) & 0x3) <<  3) |
162         (((x >> 5) & 0x1) <<  2)
163     );
164 }
165 
166 // CI format, e.g. c.addi
riscv_encode_imm_ci(uint32_t x)167 static inline uint16_t riscv_encode_imm_ci(uint32_t x) {
168     return (uint16_t)(
169         (((x >> 5) & 0x01) << 12) |
170         (((x >> 0) & 0x1f) <<  2)
171     );
172 }
173 
174 #ifdef __cplusplus
175 }
176 #endif
177 
178 #endif
179 #endif
180