]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_GCC/freedom-metal/src/drivers/riscv_cpu.c
88175eb18ffae87aa4bd5c59cce4cbebf3afeafc
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_GCC / freedom-metal / src / drivers / riscv_cpu.c
1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
3
4 #include <stdint.h>
5 #include <metal/io.h>
6 #include <metal/shutdown.h>
7 #include <metal/machine.h>
8
9 unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu);
10 int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time);
11
12 struct metal_cpu *__metal_driver_cpu_get(int hartid)
13 {
14     if (hartid < __METAL_DT_MAX_HARTS) {
15         return &(__metal_cpu_table[hartid]->cpu);
16     }
17     return (struct metal_cpu *)NULL;
18 }
19
20 uintptr_t __metal_myhart_id (void)
21 {
22     uintptr_t myhart;
23     asm volatile ("csrr %0, mhartid" : "=r"(myhart));
24     return myhart;
25 }
26
27 void __metal_zero_memory (unsigned char *base, unsigned int size)
28 {
29     volatile unsigned char *ptr;
30     for (ptr = base; ptr < (base + size); ptr++){
31         *ptr = 0;
32     }
33 }
34
35 void __metal_interrupt_global_enable (void) {
36     uintptr_t m;
37     asm volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
38 }
39
40 void __metal_interrupt_global_disable (void) {
41     uintptr_t m;
42     asm volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
43 }
44
45 void __metal_interrupt_software_enable (void) {
46     uintptr_t m;
47     asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
48 }
49
50 void __metal_interrupt_software_disable (void) {
51     uintptr_t m;
52     asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
53 }
54
55 void __metal_interrupt_timer_enable (void) {
56     uintptr_t m;
57     asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
58 }
59
60 void __metal_interrupt_timer_disable (void) {
61     uintptr_t m;
62     asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
63 }
64
65 void __metal_interrupt_external_enable (void) {
66     uintptr_t m;
67     asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
68 }
69
70 void __metal_interrupt_external_disable (void) {
71     unsigned long m;
72     asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
73 }
74
75 void __metal_interrupt_local_enable (int id) {
76     uintptr_t b = 1 << id;
77     uintptr_t m;
78     asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
79 }
80
81 void __metal_interrupt_local_disable (int id) {
82     uintptr_t b = 1 << id;
83     uintptr_t m;
84     asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
85 }
86
87 void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
88     metal_shutdown(100);
89 }
90
91 void __metal_default_interrupt_handler (int id, void *priv) {
92     metal_shutdown(200);
93 }
94
95 void __metal_default_sw_handler (int id, void *priv) {
96     uintptr_t mcause;
97     struct __metal_driver_riscv_cpu_intc *intc;
98     struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
99
100     asm volatile ("csrr %0, mcause" : "=r"(mcause));
101     if ( cpu ) {
102         intc = (struct __metal_driver_riscv_cpu_intc *)
103           __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
104         intc->metal_exception_table[mcause & METAL_MCAUSE_CAUSE]((struct metal_cpu *)cpu, id);
105     }
106 }
107
108 void __metal_default_timer_handler (int id, void *priv) {
109     struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id());
110     unsigned long long time = __metal_driver_cpu_mtime_get(cpu);
111
112     /* Set a 10 cycle timer */
113     __metal_driver_cpu_mtimecmp_set(cpu, time + 10);
114 }
115
116 void __metal_exception_handler(void) __attribute__((interrupt, aligned(128)));
117 void __metal_exception_handler (void) {
118     int id;
119     void *priv;
120     uintptr_t mcause, mepc, mtval, mtvec;
121     struct __metal_driver_riscv_cpu_intc *intc;
122     struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
123
124     asm volatile ("csrr %0, mcause" : "=r"(mcause));
125     asm volatile ("csrr %0, mepc" : "=r"(mepc));
126     asm volatile ("csrr %0, mtval" : "=r"(mtval));
127     asm volatile ("csrr %0, mtvec" : "=r"(mtvec));
128
129     if ( cpu ) {
130         intc = (struct __metal_driver_riscv_cpu_intc *)
131           __metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
132         id = mcause & METAL_MCAUSE_CAUSE;
133         if (mcause & METAL_MCAUSE_INTR) {
134             if ((id < METAL_INTERRUPT_ID_LC0) ||
135                ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) {
136                 priv = intc->metal_int_table[id].exint_data;
137                 intc->metal_int_table[id].handler(id, priv);
138                 return;
139             }
140             if ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_CLIC) {
141                 uintptr_t mtvt;
142                 metal_interrupt_handler_t mtvt_handler;
143
144                 asm volatile ("csrr %0, mtvt" : "=r"(mtvt));
145                 priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
146                 mtvt_handler = (metal_interrupt_handler_t)mtvt;
147                 mtvt_handler(id, priv);
148                 return;
149             }
150         } else {
151             intc->metal_exception_table[id]((struct metal_cpu *)cpu, id);
152         }
153     }
154 }
155
156 void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
157 {  
158     uintptr_t trap_entry, val;
159
160     asm volatile ("csrr %0, mtvec" : "=r"(val));
161     val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED);
162     trap_entry = (uintptr_t)vec_table;
163
164     switch (mode) {
165     case METAL_SELECTIVE_VECTOR_MODE:
166         asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC));
167         asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
168         break;
169     case METAL_HARDWARE_VECTOR_MODE:
170         asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC_VECTORED));
171         asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
172         break;
173     case METAL_VECTOR_MODE:
174         asm volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
175         break;
176     case METAL_DIRECT_MODE:
177         asm volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
178         break;
179     }
180 }
181
182 int __metal_valid_interrupt_id (int id)
183 {
184     switch (id) {
185     case METAL_INTERRUPT_ID_SW:
186     case METAL_INTERRUPT_ID_TMR:
187     case METAL_INTERRUPT_ID_EXT:
188     case METAL_INTERRUPT_ID_LC0:
189     case METAL_INTERRUPT_ID_LC1:
190     case METAL_INTERRUPT_ID_LC2:
191     case METAL_INTERRUPT_ID_LC3:
192     case METAL_INTERRUPT_ID_LC4:
193     case METAL_INTERRUPT_ID_LC5:
194     case METAL_INTERRUPT_ID_LC6:
195     case METAL_INTERRUPT_ID_LC7:
196     case METAL_INTERRUPT_ID_LC8:
197     case METAL_INTERRUPT_ID_LC9:
198     case METAL_INTERRUPT_ID_LC10:
199     case METAL_INTERRUPT_ID_LC11:
200     case METAL_INTERRUPT_ID_LC12:
201     case METAL_INTERRUPT_ID_LC13:
202     case METAL_INTERRUPT_ID_LC14:
203     case METAL_INTERRUPT_ID_LC15:
204         return 1;
205     default:
206         break;
207     }
208
209     return 0;
210 }
211
212  
213 int __metal_local_interrupt_enable (struct metal_interrupt *controller,
214                                   metal_interrupt_id_e id, int enable)
215 {
216     int rc = 0;
217   
218     if ( !controller) {
219         return -1;
220     }
221
222     switch (id) {
223     case METAL_INTERRUPT_ID_BASE:
224         if (enable) {
225             __metal_interrupt_global_enable();
226         } else {
227             __metal_interrupt_global_disable();
228         }
229         break;
230     case METAL_INTERRUPT_ID_SW:
231         if (enable) {
232             __metal_interrupt_software_enable();
233         } else {
234             __metal_interrupt_software_disable();
235         }
236         break;
237     case METAL_INTERRUPT_ID_TMR:
238         if (enable) {
239             __metal_interrupt_timer_enable();
240         } else {
241             __metal_interrupt_timer_disable();
242         }
243         break;
244     case METAL_INTERRUPT_ID_EXT:
245         if (enable) {
246             __metal_interrupt_external_enable();
247         } else {
248             __metal_interrupt_external_disable();
249         }
250         break;
251     case METAL_INTERRUPT_ID_LC0:
252     case METAL_INTERRUPT_ID_LC1:
253     case METAL_INTERRUPT_ID_LC2:
254     case METAL_INTERRUPT_ID_LC3:
255     case METAL_INTERRUPT_ID_LC4:
256     case METAL_INTERRUPT_ID_LC5:
257     case METAL_INTERRUPT_ID_LC6:
258     case METAL_INTERRUPT_ID_LC7:
259     case METAL_INTERRUPT_ID_LC8:
260     case METAL_INTERRUPT_ID_LC9:
261     case METAL_INTERRUPT_ID_LC10:
262     case METAL_INTERRUPT_ID_LC11:
263     case METAL_INTERRUPT_ID_LC12:
264     case METAL_INTERRUPT_ID_LC13:
265     case METAL_INTERRUPT_ID_LC14:
266     case METAL_INTERRUPT_ID_LC15:
267         if (enable) {
268             __metal_interrupt_local_enable(id);
269         } else {
270             __metal_interrupt_local_disable(id);
271         }
272         break;
273     defaut:
274         rc = -1;
275     }
276     return rc;
277 }
278
279 int __metal_exception_register (struct metal_interrupt *controller,
280                               int ecode, metal_exception_handler_t isr)
281 {
282     struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
283
284     if ((ecode < METAL_MAX_EXCEPTION_CODE) && isr) {
285         intc->metal_exception_table[ecode] = isr;
286         return 0;
287     }
288     return -1;
289 }
290
291 void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt *controller)
292 {
293     struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
294     uintptr_t val;
295
296     if ( !intc->init_done ) {
297         /* Disable and clear all interrupt sources */
298         asm volatile ("csrc mie, %0" :: "r"(-1));
299         asm volatile ("csrc mip, %0" :: "r"(-1));
300
301         /* Read the misa CSR to determine if the delegation registers exist */
302         uintptr_t misa;
303         asm volatile ("csrr %0, misa" : "=r" (misa));
304
305         /* The delegation CSRs exist if user mode interrupts (N extension) or
306          * supervisor mode (S extension) are supported */
307         if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) {
308             /* Disable interrupt and exception delegation */
309             asm volatile ("csrc mideleg, %0" :: "r"(-1));
310             asm volatile ("csrc medeleg, %0" :: "r"(-1));
311         }
312
313         /* The satp CSR exists if supervisor mode (S extension) is supported */
314         if(misa & METAL_ISA_S_EXTENSIONS) {
315             /* Clear the entire CSR to make sure that satp.MODE = 0 */
316             asm volatile ("csrc satp, %0" :: "r"(-1));
317         }
318
319         /* Default to use direct interrupt, setup sw cb table*/
320         for (int i = 0; i < METAL_MAX_MI; i++) {
321             intc->metal_int_table[i].handler = NULL;
322             intc->metal_int_table[i].sub_int = NULL;
323             intc->metal_int_table[i].exint_data = NULL;
324         }
325         for (int i = 0; i < METAL_MAX_ME; i++) {
326             intc->metal_exception_table[i] = __metal_default_exception_handler;
327         }
328         __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
329         asm volatile ("csrr %0, misa" : "=r"(val));
330         if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) {
331             /* Floating point architecture, so turn on FP register saving*/
332             asm volatile ("csrr %0, mstatus" : "=r"(val));
333             asm volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
334         }
335         intc->init_done = 1;
336     }
337 }
338
339 int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrupt *controller,
340                                                          int id, metal_interrupt_handler_t isr,
341                                                          void *priv)
342 {
343     int rc = 0;
344     struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
345  
346     if ( !__metal_valid_interrupt_id(id) ) {
347         return -11;
348     }
349
350     if (isr) {
351         intc->metal_int_table[id].handler = isr;
352         intc->metal_int_table[id].exint_data = priv;
353     } else {
354         switch (id) {
355         case METAL_INTERRUPT_ID_SW:
356             intc->metal_int_table[id].handler = __metal_default_sw_handler;
357             intc->metal_int_table[id].sub_int = priv;
358           break;
359         case METAL_INTERRUPT_ID_TMR:
360             intc->metal_int_table[id].handler = __metal_default_timer_handler;
361             intc->metal_int_table[id].sub_int = priv;
362           break;
363         case METAL_INTERRUPT_ID_EXT:
364         case METAL_INTERRUPT_ID_LC0:
365         case METAL_INTERRUPT_ID_LC1:
366         case METAL_INTERRUPT_ID_LC2:
367         case METAL_INTERRUPT_ID_LC3:
368         case METAL_INTERRUPT_ID_LC4:
369         case METAL_INTERRUPT_ID_LC5:
370         case METAL_INTERRUPT_ID_LC6:
371         case METAL_INTERRUPT_ID_LC7:
372         case METAL_INTERRUPT_ID_LC8:
373         case METAL_INTERRUPT_ID_LC9:
374         case METAL_INTERRUPT_ID_LC10:
375         case METAL_INTERRUPT_ID_LC11:
376         case METAL_INTERRUPT_ID_LC12:
377         case METAL_INTERRUPT_ID_LC13:
378         case METAL_INTERRUPT_ID_LC14:
379         case METAL_INTERRUPT_ID_LC15:
380             intc->metal_int_table[id].handler = __metal_default_interrupt_handler;
381             intc->metal_int_table[id].sub_int = priv;
382           break;
383         defaut:
384           rc = -12;
385         }
386     }
387     return rc;
388 }
389
390 int __metal_driver_riscv_cpu_controller_interrupt_enable (struct metal_interrupt *controller,
391                                                         int id)
392 {
393     return __metal_local_interrupt_enable(controller, id, METAL_ENABLE);
394 }
395
396 int __metal_driver_riscv_cpu_controller_interrupt_disable (struct metal_interrupt *controller,
397                                                          int id)
398 {   
399     return __metal_local_interrupt_enable(controller, id, METAL_DISABLE);
400 }
401
402 int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_interrupt *controller,
403                                                              int id, metal_vector_mode mode)
404 {
405     struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
406
407     if (id == METAL_INTERRUPT_ID_BASE) {
408         if (mode == METAL_DIRECT_MODE) {
409             __metal_controller_interrupt_vector(mode, &__metal_exception_handler);
410             return 0;
411         }   
412         if (mode == METAL_VECTOR_MODE) {
413             __metal_controller_interrupt_vector(mode, &intc->metal_mtvec_table);
414             return 0;
415         }
416     }
417     return -1;
418 }
419
420 int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller,
421                                                               int id)
422 {
423     struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
424
425     if (id == METAL_INTERRUPT_ID_BASE) {
426         __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
427         return 0;
428     }
429     return -1;
430 }
431
432 int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller,
433                                                        int cmd, void *data)
434 {
435     /* NOP for now, unless local interrupt lines the like of clic, clint, plic */
436     return 0;
437 }
438
439 extern inline int __metal_controller_interrupt_is_selective_vectored(void);
440
441 /* CPU driver !!! */
442
443 unsigned long long __metal_driver_cpu_timer_get(struct metal_cpu *cpu)
444 {
445     unsigned long long val = 0;
446
447 #if __riscv_xlen == 32
448     unsigned long hi, hi1, lo;
449
450     asm volatile ("csrr %0, mcycleh" : "=r"(hi));
451     asm volatile ("csrr %0, mcycle" : "=r"(lo));
452     asm volatile ("csrr %0, mcycleh" : "=r"(hi1));
453     if (hi == hi1) {
454         val = ((unsigned long long)hi << 32) | lo;
455     }
456 #else
457     asm volatile ("csrr %0, mcycle" : "=r"(val));
458 #endif
459
460     return val;
461 }
462
463 unsigned long long __metal_driver_cpu_timebase_get(struct metal_cpu *cpu)
464 {
465   int timebase;
466     if (!cpu) {
467         return 0;
468     }
469
470     timebase = __metal_driver_cpu_timebase((struct metal_cpu *)cpu);
471     return timebase;
472 }
473
474 unsigned long long  __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
475 {
476     unsigned long long time = 0;
477     struct metal_interrupt *tmr_intc;
478     struct __metal_driver_riscv_cpu_intc *intc =
479         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
480     struct __metal_driver_cpu *_cpu = (void *)cpu;
481
482     if (intc) {
483         tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
484         if (tmr_intc) {
485             tmr_intc->vtable->command_request(tmr_intc,
486                                               METAL_TIMER_MTIME_GET, &time);
487         }
488     }
489     return time;
490 }
491
492 int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long time)
493 {
494     int rc = -1;
495     struct metal_interrupt *tmr_intc;
496     struct __metal_driver_riscv_cpu_intc *intc =
497         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
498     struct __metal_driver_cpu *_cpu = (void *)cpu;
499
500     if (intc) {
501         tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
502         if (tmr_intc) {
503             rc = tmr_intc->vtable->mtimecmp_set(tmr_intc,
504                                                 __metal_driver_cpu_hartid(cpu),
505                                                 time);
506         }
507     }
508     return rc;
509 }
510
511 struct metal_interrupt *
512 __metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
513 {
514 #ifdef __METAL_DT_RISCV_CLINT0_HANDLE
515     return __METAL_DT_RISCV_CLINT0_HANDLE;
516 #else
517 #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
518     return __METAL_DT_SIFIVE_CLIC0_HANDLE;
519 #else
520 #warning "There is no interrupt controller for Timer interrupt"
521     return NULL;
522 #endif
523 #endif
524 }
525
526 int __metal_driver_cpu_get_timer_interrupt_id(struct metal_cpu *cpu)
527 {
528     return METAL_INTERRUPT_ID_TMR;
529 }
530
531 struct metal_interrupt *
532 __metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
533 {
534 #ifdef __METAL_DT_RISCV_CLINT0_HANDLE
535     return __METAL_DT_RISCV_CLINT0_HANDLE;
536 #else
537 #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
538     return __METAL_DT_SIFIVE_CLIC0_HANDLE;
539 #else
540 #warning "There is no interrupt controller for Software interrupt"
541     return NULL;
542 #endif
543 #endif
544 }
545
546 int __metal_driver_cpu_get_sw_interrupt_id(struct metal_cpu *cpu)
547 {
548     return METAL_INTERRUPT_ID_SW;
549 }
550
551 int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
552 {
553     int rc = -1;
554     struct metal_interrupt *sw_intc;
555     struct __metal_driver_riscv_cpu_intc *intc = 
556         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
557     struct __metal_driver_cpu *_cpu = (void *)cpu;
558
559     if (intc) {
560         sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
561         if (sw_intc) {
562             rc = sw_intc->vtable->command_request(sw_intc,
563                                                   METAL_SOFTWARE_IPI_SET, &hartid);
564         }
565     }
566     return rc;
567 }
568
569 int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
570 {
571     int rc = -1;
572     struct metal_interrupt *sw_intc;
573     struct __metal_driver_riscv_cpu_intc *intc =
574         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
575     struct __metal_driver_cpu *_cpu = (void *)cpu;
576
577     if (intc) {
578         sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
579         if (sw_intc) {
580             rc = sw_intc->vtable->command_request(sw_intc,
581                                                   METAL_SOFTWARE_IPI_CLEAR, &hartid);
582         }
583     }
584     return rc;
585 }
586
587 int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
588 {
589     int rc = 0;
590     struct metal_interrupt *sw_intc;
591     struct __metal_driver_riscv_cpu_intc *intc =
592         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
593     struct __metal_driver_cpu *_cpu = (void *)cpu;
594
595     if (intc) {
596         sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
597         if (sw_intc) {
598             rc = sw_intc->vtable->command_request(sw_intc,
599                                                   METAL_SOFTWARE_MSIP_GET, &hartid);
600         }
601     }
602     return rc;
603 }
604
605 struct metal_interrupt *
606 __metal_driver_cpu_controller_interrupt(struct metal_cpu *cpu)
607 {
608     return __metal_driver_cpu_interrupt_controller(cpu);
609 }
610
611 int __metal_driver_cpu_enable_interrupt(struct metal_cpu *cpu, void *priv)
612 {
613     if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
614         /* Only support machine mode for now */
615         __metal_interrupt_global_enable();
616         return 0;
617     }
618     return -1;
619 }
620
621 int __metal_driver_cpu_disable_interrupt(struct metal_cpu *cpu, void *priv)
622 {
623     if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
624         /* Only support machine mode for now */
625         __metal_interrupt_global_disable();
626         return 0;
627     }
628     return -1;
629 }
630
631 int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
632                                         metal_exception_handler_t isr)
633 {
634     struct __metal_driver_riscv_cpu_intc *intc =
635         (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
636
637     if (intc) {
638         return __metal_exception_register((struct metal_interrupt *)intc, ecode, isr);
639     }
640     return -1;
641 }
642
643 int  __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
644 {
645     /* Per ISA compressed instruction has last two bits of opcode set */
646     return (*(unsigned short*)epc & 3) ? 4 : 2;
647 }
648
649 uintptr_t  __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu)
650 {
651     uintptr_t mepc;
652     asm volatile ("csrr %0, mepc" : "=r"(mepc));
653     return mepc;
654 }
655
656 int  __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
657 {
658     asm volatile ("csrw mepc, %0" :: "r"(mepc));
659     return 0;
660 }
661
662 __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = {
663     .controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
664     .controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register,
665     .controller_vtable.interrupt_enable   = __metal_driver_riscv_cpu_controller_interrupt_enable,
666     .controller_vtable.interrupt_disable  = __metal_driver_riscv_cpu_controller_interrupt_disable,
667     .controller_vtable.interrupt_vector_enable   = __metal_driver_riscv_cpu_controller_interrupt_enable_vector,
668     .controller_vtable.interrupt_vector_disable  = __metal_driver_riscv_cpu_controller_interrupt_disable_vector,
669     .controller_vtable.command_request    = __metal_driver_riscv_cpu_controller_command_request,
670 };
671
672 __METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = {
673     .cpu_vtable.timer_get     = __metal_driver_cpu_timer_get,
674     .cpu_vtable.timebase_get  = __metal_driver_cpu_timebase_get,
675     .cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get,
676     .cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set,
677     .cpu_vtable.tmr_controller_interrupt = __metal_driver_cpu_timer_controller_interrupt,
678     .cpu_vtable.get_tmr_interrupt_id = __metal_driver_cpu_get_timer_interrupt_id,
679     .cpu_vtable.sw_controller_interrupt = __metal_driver_cpu_sw_controller_interrupt,
680     .cpu_vtable.get_sw_interrupt_id = __metal_driver_cpu_get_sw_interrupt_id,
681     .cpu_vtable.set_sw_ipi = __metal_driver_cpu_set_sw_ipi,
682     .cpu_vtable.clear_sw_ipi = __metal_driver_cpu_clear_sw_ipi,
683     .cpu_vtable.get_msip = __metal_driver_cpu_get_msip,
684     .cpu_vtable.controller_interrupt = __metal_driver_cpu_controller_interrupt,
685     .cpu_vtable.exception_register = __metal_driver_cpu_exception_register,
686     .cpu_vtable.get_ilen = __metal_driver_cpu_get_instruction_length,
687     .cpu_vtable.get_epc = __metal_driver_cpu_get_exception_pc,
688     .cpu_vtable.set_epc = __metal_driver_cpu_set_exception_pc,
689 };
690