1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
6 #include <metal/shutdown.h>
7 #include <metal/machine.h>
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);
12 struct metal_cpu *__metal_driver_cpu_get(int hartid)
14 if (hartid < __METAL_DT_MAX_HARTS) {
15 return &(__metal_cpu_table[hartid]->cpu);
17 return (struct metal_cpu *)NULL;
20 uintptr_t __metal_myhart_id (void)
23 asm volatile ("csrr %0, mhartid" : "=r"(myhart));
27 void __metal_zero_memory (unsigned char *base, unsigned int size)
29 volatile unsigned char *ptr;
30 for (ptr = base; ptr < (base + size); ptr++){
35 void __metal_interrupt_global_enable (void) {
37 asm volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
40 void __metal_interrupt_global_disable (void) {
42 asm volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
45 void __metal_interrupt_software_enable (void) {
47 asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
50 void __metal_interrupt_software_disable (void) {
52 asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
55 void __metal_interrupt_timer_enable (void) {
57 asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
60 void __metal_interrupt_timer_disable (void) {
62 asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
65 void __metal_interrupt_external_enable (void) {
67 asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
70 void __metal_interrupt_external_disable (void) {
72 asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
75 void __metal_interrupt_local_enable (int id) {
76 uintptr_t b = 1 << id;
78 asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
81 void __metal_interrupt_local_disable (int id) {
82 uintptr_t b = 1 << id;
84 asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
87 void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
91 void __metal_default_interrupt_handler (int id, void *priv) {
95 void __metal_default_sw_handler (int id, void *priv) {
97 struct __metal_driver_riscv_cpu_intc *intc;
98 struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
100 asm volatile ("csrr %0, mcause" : "=r"(mcause));
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);
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);
112 /* Set a 10 cycle timer */
113 __metal_driver_cpu_mtimecmp_set(cpu, time + 10);
116 void __metal_exception_handler(void) __attribute__((interrupt, aligned(128)));
117 void __metal_exception_handler (void) {
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()];
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));
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);
140 if ((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_CLIC) {
142 metal_interrupt_handler_t mtvt_handler;
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);
151 intc->metal_exception_table[id]((struct metal_cpu *)cpu, id);
156 void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
158 uintptr_t trap_entry, val;
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;
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));
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));
173 case METAL_VECTOR_MODE:
174 asm volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
176 case METAL_DIRECT_MODE:
177 asm volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
182 int __metal_valid_interrupt_id (int 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:
213 int __metal_local_interrupt_enable (struct metal_interrupt *controller,
214 metal_interrupt_id_e id, int enable)
223 case METAL_INTERRUPT_ID_BASE:
225 __metal_interrupt_global_enable();
227 __metal_interrupt_global_disable();
230 case METAL_INTERRUPT_ID_SW:
232 __metal_interrupt_software_enable();
234 __metal_interrupt_software_disable();
237 case METAL_INTERRUPT_ID_TMR:
239 __metal_interrupt_timer_enable();
241 __metal_interrupt_timer_disable();
244 case METAL_INTERRUPT_ID_EXT:
246 __metal_interrupt_external_enable();
248 __metal_interrupt_external_disable();
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:
268 __metal_interrupt_local_enable(id);
270 __metal_interrupt_local_disable(id);
279 int __metal_exception_register (struct metal_interrupt *controller,
280 int ecode, metal_exception_handler_t isr)
282 struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
284 if ((ecode < METAL_MAX_EXCEPTION_CODE) && isr) {
285 intc->metal_exception_table[ecode] = isr;
291 void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt *controller)
293 struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
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));
301 /* Read the misa CSR to determine if the delegation registers exist */
303 asm volatile ("csrr %0, misa" : "=r" (misa));
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));
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));
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;
325 for (int i = 0; i < METAL_MAX_ME; i++) {
326 intc->metal_exception_table[i] = __metal_default_exception_handler;
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));
339 int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrupt *controller,
340 int id, metal_interrupt_handler_t isr,
344 struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
346 if ( !__metal_valid_interrupt_id(id) ) {
351 intc->metal_int_table[id].handler = isr;
352 intc->metal_int_table[id].exint_data = priv;
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;
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;
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;
390 int __metal_driver_riscv_cpu_controller_interrupt_enable (struct metal_interrupt *controller,
393 return __metal_local_interrupt_enable(controller, id, METAL_ENABLE);
396 int __metal_driver_riscv_cpu_controller_interrupt_disable (struct metal_interrupt *controller,
399 return __metal_local_interrupt_enable(controller, id, METAL_DISABLE);
402 int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_interrupt *controller,
403 int id, metal_vector_mode mode)
405 struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
407 if (id == METAL_INTERRUPT_ID_BASE) {
408 if (mode == METAL_DIRECT_MODE) {
409 __metal_controller_interrupt_vector(mode, &__metal_exception_handler);
412 if (mode == METAL_VECTOR_MODE) {
413 __metal_controller_interrupt_vector(mode, &intc->metal_mtvec_table);
420 int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller,
423 struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
425 if (id == METAL_INTERRUPT_ID_BASE) {
426 __metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
432 int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt *controller,
435 /* NOP for now, unless local interrupt lines the like of clic, clint, plic */
439 extern inline int __metal_controller_interrupt_is_selective_vectored(void);
443 unsigned long long __metal_driver_cpu_timer_get(struct metal_cpu *cpu)
445 unsigned long long val = 0;
447 #if __riscv_xlen == 32
448 unsigned long hi, hi1, lo;
450 asm volatile ("csrr %0, mcycleh" : "=r"(hi));
451 asm volatile ("csrr %0, mcycle" : "=r"(lo));
452 asm volatile ("csrr %0, mcycleh" : "=r"(hi1));
454 val = ((unsigned long long)hi << 32) | lo;
457 asm volatile ("csrr %0, mcycle" : "=r"(val));
463 unsigned long long __metal_driver_cpu_timebase_get(struct metal_cpu *cpu)
470 timebase = __metal_driver_cpu_timebase((struct metal_cpu *)cpu);
474 unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
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;
483 tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
485 tmr_intc->vtable->command_request(tmr_intc,
486 METAL_TIMER_MTIME_GET, &time);
492 int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long time)
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;
501 tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
503 rc = tmr_intc->vtable->mtimecmp_set(tmr_intc,
504 __metal_driver_cpu_hartid(cpu),
511 struct metal_interrupt *
512 __metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
514 #ifdef __METAL_DT_RISCV_CLINT0_HANDLE
515 return __METAL_DT_RISCV_CLINT0_HANDLE;
517 #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
518 return __METAL_DT_SIFIVE_CLIC0_HANDLE;
520 #warning "There is no interrupt controller for Timer interrupt"
526 int __metal_driver_cpu_get_timer_interrupt_id(struct metal_cpu *cpu)
528 return METAL_INTERRUPT_ID_TMR;
531 struct metal_interrupt *
532 __metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
534 #ifdef __METAL_DT_RISCV_CLINT0_HANDLE
535 return __METAL_DT_RISCV_CLINT0_HANDLE;
537 #ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
538 return __METAL_DT_SIFIVE_CLIC0_HANDLE;
540 #warning "There is no interrupt controller for Software interrupt"
546 int __metal_driver_cpu_get_sw_interrupt_id(struct metal_cpu *cpu)
548 return METAL_INTERRUPT_ID_SW;
551 int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
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;
560 sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
562 rc = sw_intc->vtable->command_request(sw_intc,
563 METAL_SOFTWARE_IPI_SET, &hartid);
569 int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
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;
578 sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
580 rc = sw_intc->vtable->command_request(sw_intc,
581 METAL_SOFTWARE_IPI_CLEAR, &hartid);
587 int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
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;
596 sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
598 rc = sw_intc->vtable->command_request(sw_intc,
599 METAL_SOFTWARE_MSIP_GET, &hartid);
605 struct metal_interrupt *
606 __metal_driver_cpu_controller_interrupt(struct metal_cpu *cpu)
608 return __metal_driver_cpu_interrupt_controller(cpu);
611 int __metal_driver_cpu_enable_interrupt(struct metal_cpu *cpu, void *priv)
613 if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
614 /* Only support machine mode for now */
615 __metal_interrupt_global_enable();
621 int __metal_driver_cpu_disable_interrupt(struct metal_cpu *cpu, void *priv)
623 if ( __metal_driver_cpu_interrupt_controller(cpu) ) {
624 /* Only support machine mode for now */
625 __metal_interrupt_global_disable();
631 int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
632 metal_exception_handler_t isr)
634 struct __metal_driver_riscv_cpu_intc *intc =
635 (struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
638 return __metal_exception_register((struct metal_interrupt *)intc, ecode, isr);
643 int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
645 /* Per ISA compressed instruction has last two bits of opcode set */
646 return (*(unsigned short*)epc & 3) ? 4 : 2;
649 uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu)
652 asm volatile ("csrr %0, mepc" : "=r"(mepc));
656 int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
658 asm volatile ("csrw mepc, %0" :: "r"(mepc));
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,
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,