]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/metal/cpu.h
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_FreedomStudio / freedom-metal / metal / cpu.h
1 /* Copyright 2018 SiFive, Inc */
2
3 /* SPDX-License-Identifier: Apache-2.0 */
4
5 /*! @file cpu.h
6  *  @brief API for accessing CPU capabilities.
7  */
8
9 #ifndef METAL__CPU_H
10 #define METAL__CPU_H
11
12 #include <stdint.h>
13 #include <metal/interrupt.h>
14
15 struct metal_cpu;
16
17 /*!
18  * @brief Function signature for exception handlers
19  */
20 typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
21
22 struct metal_cpu_vtable {
23     unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
24     unsigned long long (*timebase_get)(struct metal_cpu *cpu);
25     unsigned long long (*mtime_get)(struct metal_cpu *cpu);
26     int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
27     struct metal_interrupt* (*tmr_controller_interrupt)(struct metal_cpu *cpu);
28     int (*get_tmr_interrupt_id)(struct metal_cpu *cpu);
29     struct metal_interrupt* (*sw_controller_interrupt)(struct metal_cpu *cpu);
30     int (*get_sw_interrupt_id)(struct metal_cpu *cpu);
31     int (*set_sw_ipi)(struct metal_cpu *cpu, int hartid);
32     int (*clear_sw_ipi)(struct metal_cpu *cpu, int hartid);
33     int (*get_msip)(struct metal_cpu *cpu, int hartid);
34     struct metal_interrupt* (*controller_interrupt)(struct metal_cpu *cpu);
35     int (*exception_register)(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
36     int (*get_ilen)(struct metal_cpu *cpu, uintptr_t epc);
37     uintptr_t (*get_epc)(struct metal_cpu *cpu);
38     int (*set_epc)(struct metal_cpu *cpu, uintptr_t epc);
39 };
40
41 /*! @brief A device handle for a CPU hart
42  */
43 struct metal_cpu {
44     const struct metal_cpu_vtable *vtable;
45 };
46
47 /*! @brief Get a reference to a CPU hart
48  *
49  * @param hartid The ID of the desired CPU hart
50  * @return A pointer to the CPU device handle
51  */
52 struct metal_cpu* metal_cpu_get(unsigned int hartid);
53
54 /*! @brief Get the hartid of the CPU hart executing this function
55  *
56  * @return The hartid of the current CPU hart */
57 int metal_cpu_get_current_hartid(void);
58
59 /*! @brief Get the number of CPU harts
60  * 
61  * @return The number of CPU harts */
62 int metal_cpu_get_num_harts(void);
63
64 /*! @brief Get the CPU cycle count timer value
65  *
66  * Get the value of the cycle count timer for a given CPU
67  *
68  * @param cpu The CPU device handle
69  * @return The value of the CPU cycle count timer
70  */
71 __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
72 { return cpu->vtable->mcycle_get(cpu); }
73
74 /*! @brief Get the timebase of the CPU
75  *
76  * Get the value of the timebase of the cycle count timer
77  *
78  * @param cpu The CPU device handle
79  * @return The value of the cycle count timer timebase
80  */
81 __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
82 { return cpu->vtable->timebase_get(cpu); }
83
84 /*! @brief Get the value of the mtime RTC
85  *
86  * Get the value of the mtime real-time clock. The CPU interrupt controller
87  * must be initialized before this function is called or the return value
88  * will be 0.
89  *
90  * @param cpu The CPU device handle
91  * @return The value of mtime, or 0 if failure
92  */
93 __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
94 { return cpu->vtable->mtime_get(cpu); }
95
96 /*! @brief Set the value of the RTC mtimecmp RTC
97  *
98  * Set the value of the mtime real-time clock compare register. The CPU
99  * interrupt controller must be initialized before this function is called
100  * or the return value will be -1;
101  *
102  * @param cpu The CPU device handle
103  * @param time The value to set the compare register to
104  * @return The value of mtimecmp or -1 if error
105  */
106 __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
107 { return cpu->vtable->mtimecmp_set(cpu, time); }
108
109 /*! @brief Get a reference to RTC timer interrupt controller
110  *
111  * Get a reference to the interrupt controller for the real-time clock interrupt.
112  * The controller returned by this function must be initialized before any interrupts
113  * are registered or enabled with it.
114  *
115  * @param cpu The CPU device handle
116  * @return A pointer to the timer interrupt handle
117  */
118 __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
119 { return cpu->vtable->tmr_controller_interrupt(cpu); }
120
121 /*! @brief Get the RTC timer interrupt id
122  *
123  * Get the interrupt ID of the real-time clock interrupt
124  *
125  * @param cpu The CPU device handle
126  * @return The timer interrupt ID
127  */
128 __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
129 { return cpu->vtable->get_tmr_interrupt_id(cpu); }
130
131 /*! @brief Get a reference to the software interrupt controller
132  *
133  * Get a reference to the interrupt controller for the software/inter-process
134  * interrupt. The controller returned by this function must be initialized before
135  * any interrupts are registered or enabled with it.
136  *
137  * @param cpu The CPU device handle
138  * @return A pointer to the software interrupt handle
139  */
140 __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
141 { return cpu->vtable->sw_controller_interrupt(cpu); }
142
143 /*! @brief Get the software interrupt id
144  *
145  * Get the interrupt ID for the software/inter-process interrupt
146  *
147  * @param cpu The CPU device handle
148  * @return the software interrupt ID
149  */
150 __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
151 { return cpu->vtable->get_sw_interrupt_id(cpu); }
152
153 /*!
154  * @brief Set the inter-process interrupt for a hart
155  *
156  * Trigger a software/inter-process interrupt for a hart. The CPU interrupt
157  * controller for the CPU handle passed to this function must be initialized
158  * before this function is called.
159  *
160  * @param cpu The CPU device handle
161  * @param hartid The CPU hart ID to be interrupted
162  * @return 0 upon success
163  */
164 __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
165 { return cpu->vtable->set_sw_ipi(cpu, hartid); }
166
167 /*!
168  * @brief Clear the inter-process interrupt for a hart
169  *
170  * Clear the software/inter-process interrupt for a hart. The CPU interrupt
171  * controller for the CPU handle passed to this function must be initialized
172  * before this function is called.
173  *
174  * @param cpu The CPU device handle
175  * @param hartid The CPU hart ID to clear
176  * @return 0 upon success
177  */
178 __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
179 { return cpu->vtable->clear_sw_ipi(cpu, hartid); }
180
181 /*!
182  * @brief Get the value of MSIP for the given hart
183  *
184  * Get the value of the machine software interrupt pending bit for
185  * the given hart. The CPU interrupt controller for the CPU handle passed
186  * as argument to this function must be initialized before this function
187  * is called.
188  *
189  * @param cpu the CPU device handle
190  * @param hartid The CPU hart to read
191  * @return 0 upon success
192  */
193 __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
194 { return cpu->vtable->get_msip(cpu, hartid); }
195
196 /*!
197  * @brief Get the interrupt controller for the CPU
198  *
199  * Get the CPU interrupt controller. The controller returned by this
200  * function must be initialized before any interrupts are registered
201  * or enabled and before any exception handlers are registered with
202  * this CPU.
203  *
204  * @param cpu The CPU device handle
205  * @return The handle for the CPU interrupt controller
206  */
207 __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
208 { return cpu->vtable->controller_interrupt(cpu); }
209
210 /*!
211  * @brief Register an exception handler
212  * 
213  * Register an exception handler for the CPU. The CPU interrupt controller must be initialized
214  * before this function is called.
215  *
216  * @param cpu The CPU device handle
217  * @param ecode The exception code to register a handler for
218  * @param handler Callback function for the exception handler
219  * @return 0 upon success
220  */
221 __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
222 { return cpu->vtable->exception_register(cpu, ecode, handler); }
223
224 /*!
225  * @brief Get the length of an instruction in bytes
226  *
227  * Get the length of an instruction in bytes.
228  *
229  * On RISC-V platforms, this is useful for detecting whether an instruction is
230  * compressed (2 bytes long) or uncompressed (4 bytes long).
231  *
232  * This function is useful in conjuction with `metal_cpu_get_exception_pc()`
233  * and `metal_cpu_set_exception_pc()` in order to cause the exception handler to
234  * return execution after the faulting instruction.
235  *
236  * @param cpu The CPU device handle
237  * @param epc The address of the instruction to measure
238  * @return the length of the instruction in bytes
239  */
240 __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
241 { return cpu->vtable->get_ilen(cpu, epc); }
242
243 /*!
244  * @brief Get the program counter of the current exception.
245  *
246  * This function must be called within an exception handler. The behavior is
247  * undefined outside of an exception handler.
248  *
249  * @param cpu The CPU device handle
250  * @return The value of the program counter at the time of the exception
251  */
252 __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
253 { return cpu->vtable->get_epc(cpu); }
254
255 /*!
256  * @brief Set the exception program counter
257  *
258  * This function must be called within an exception handler. The behavior
259  * is undefined outside of an exception handler.
260  *
261  * This function can be used to cause an exception handler to return execution
262  * to an address other than the one that caused the exception.
263  *
264  * @param cpu the CPU device handle
265  * @param epc The address to set the exception program counter to
266  * @return 0 upon success
267  */
268 __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
269 { return cpu->vtable->set_epc(cpu, epc); }
270
271 #endif