96 lines
2.6 KiB
ArmAsm
96 lines
2.6 KiB
ArmAsm
/*
|
|
* Copyright (c) 2018 Foundries.io Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <offsets.h>
|
|
#include <toolchain.h>
|
|
|
|
#include <soc.h>
|
|
|
|
/* Exports */
|
|
GTEXT(__soc_is_irq)
|
|
GTEXT(__soc_handle_irq)
|
|
#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
|
|
GTEXT(__soc_save_context)
|
|
GTEXT(__soc_restore_context)
|
|
#endif
|
|
|
|
/*
|
|
* Whether we're in an IRQ is bog-standard RISC-V on this SoC:
|
|
* yes if the top mcause bit is set, otherwise no.
|
|
*/
|
|
SECTION_FUNC(exception.other, __soc_is_irq)
|
|
csrr a0, mcause
|
|
srli a0, a0, 31
|
|
ret
|
|
|
|
/*
|
|
* With a0 == irq_num, this is equivalent to:
|
|
*
|
|
* EVENT_UNIT->INTPTPENDCLEAR = (1U << irq_num);
|
|
*
|
|
* We could write this routine in C, but the assembly
|
|
* that's calling us requires that a0 still contain irq_num
|
|
* on return, and assuming nobody would ever change a
|
|
* C implementation in a way that silently clobbers it
|
|
* is playing with fire. Instead, we play tricks in
|
|
* soc_context.h so that offsets.h contains a pointer to
|
|
* INTPTPENDCLEAR.
|
|
*/
|
|
SECTION_FUNC(exception.other, __soc_handle_irq)
|
|
la t0, __EVENT0_INTPTPENDCLEAR
|
|
li t1, 1
|
|
sll t1, t1, a0
|
|
sw t1, 0x00(t0)
|
|
ret
|
|
|
|
#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
|
|
/*
|
|
* The RI5CY core has ISA extensions for faster loop performance
|
|
* that use extra registers.
|
|
*
|
|
* If the toolchain generates instructions that use them, they must be saved
|
|
* prior to handling an interrupt/exception. This case is handled using
|
|
* Zephyr's generic RISC-V mechanism for soc-specific context.
|
|
*
|
|
* For details, see the Kconfig help for CONFIG_RISCV_SOC_CONTEXT_SAVE.
|
|
*/
|
|
SECTION_FUNC(exception.other, __soc_save_context)
|
|
#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY
|
|
csrr t0, RI5CY_LPSTART0
|
|
csrr t1, RI5CY_LPEND0
|
|
csrr t2, RI5CY_LPCOUNT0
|
|
sw t0, __soc_esf_t_lpstart0_OFFSET(a0)
|
|
sw t1, __soc_esf_t_lpend0_OFFSET(a0)
|
|
sw t2, __soc_esf_t_lpcount0_OFFSET(a0)
|
|
csrr t0, RI5CY_LPSTART1
|
|
csrr t1, RI5CY_LPEND1
|
|
csrr t2, RI5CY_LPCOUNT1
|
|
sw t0, __soc_esf_t_lpstart1_OFFSET(a0)
|
|
sw t1, __soc_esf_t_lpend1_OFFSET(a0)
|
|
sw t2, __soc_esf_t_lpcount1_OFFSET(a0)
|
|
#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */
|
|
|
|
ret
|
|
|
|
SECTION_FUNC(exception.other, __soc_restore_context)
|
|
#ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY
|
|
lw t0, __soc_esf_t_lpstart0_OFFSET(a0)
|
|
lw t1, __soc_esf_t_lpend0_OFFSET(a0)
|
|
lw t2, __soc_esf_t_lpcount0_OFFSET(a0)
|
|
csrw RI5CY_LPSTART0, t0
|
|
csrw RI5CY_LPEND0, t1
|
|
csrw RI5CY_LPCOUNT0, t2
|
|
lw t0, __soc_esf_t_lpstart1_OFFSET(a0)
|
|
lw t1, __soc_esf_t_lpend1_OFFSET(a0)
|
|
lw t2, __soc_esf_t_lpcount1_OFFSET(a0)
|
|
csrw RI5CY_LPSTART1, t0
|
|
csrw RI5CY_LPEND1, t1
|
|
csrw RI5CY_LPCOUNT1, t2
|
|
#endif /* CONFIG_SOC_OPENISA_RV32M1_RI5CY */
|
|
|
|
ret
|
|
#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */
|