| /* |
| * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <kernel_structs.h> |
| #include <offsets.h> |
| #include <toolchain.h> |
| #include <linker/sections.h> |
| #include <soc.h> |
| |
| /* exports */ |
| GTEXT(__soc_save_context) |
| GTEXT(__soc_restore_context) |
| GTEXT(__soc_is_irq) |
| GTEXT(__soc_handle_irq) |
| GTEXT(__soc_irq_unlock) |
| |
| /* Use ABI name of registers for the sake of simplicity */ |
| |
| /* |
| * Pulpino core has hardware loops registers that need to be saved |
| * prior to handling an interrupt/exception. |
| * |
| * NOTE: Stack space allocation is not needed here, as already allocated at |
| * architecture level with __NANO_ESF_SIZEOF value (including space for the |
| * pulpino-specific registers) |
| */ |
| SECTION_FUNC(exception.other, __soc_save_context) |
| /* Save hardware loop registers to stack */ |
| csrr t0, PULP_LPSTART0 |
| csrr t1, PULP_LPEND0 |
| csrr t2, PULP_LPCOUNT0 |
| sw t0, __NANO_ESF_lpstart0_OFFSET(sp) |
| sw t1, __NANO_ESF_lpend0_OFFSET(sp) |
| sw t2, __NANO_ESF_lpcount0_OFFSET(sp) |
| csrr t0, PULP_LPSTART1 |
| csrr t1, PULP_LPEND1 |
| csrr t2, PULP_LPCOUNT1 |
| sw t0, __NANO_ESF_lpstart1_OFFSET(sp) |
| sw t1, __NANO_ESF_lpend1_OFFSET(sp) |
| sw t2, __NANO_ESF_lpcount1_OFFSET(sp) |
| |
| /* Return */ |
| jalr x0, ra |
| |
| |
| SECTION_FUNC(exception.other, __soc_restore_context) |
| /* Restore hardloop registers from stack */ |
| lw t0, __NANO_ESF_lpstart0_OFFSET(sp) |
| lw t1, __NANO_ESF_lpend0_OFFSET(sp) |
| lw t2, __NANO_ESF_lpcount0_OFFSET(sp) |
| csrw PULP_LPSTART0, t0 |
| csrw PULP_LPEND0, t1 |
| csrw PULP_LPCOUNT0, t2 |
| lw t0, __NANO_ESF_lpstart1_OFFSET(sp) |
| lw t1, __NANO_ESF_lpend1_OFFSET(sp) |
| lw t2, __NANO_ESF_lpcount1_OFFSET(sp) |
| csrw PULP_LPSTART1, t0 |
| csrw PULP_LPEND1, t1 |
| csrw PULP_LPCOUNT1, t2 |
| |
| /* Return */ |
| jalr x0, ra |
| |
| |
| /* |
| * SOC-specific function to handle pending IRQ number generating the interrupt. |
| * |
| * The pulpino core has: |
| * 1) an ICP register, which is used to clear the pending |
| * IRQ number upon an interrupt. |
| * 2) an ECP register, which is used to clear the pending IRQ number |
| * that has woken up the CPU from sleep state. |
| * |
| * Exception number is given as parameter via register a0. |
| */ |
| SECTION_FUNC(exception.other, __soc_handle_irq) |
| /* Clear exception number from the Interrupt pending register */ |
| li t1, PULP_ICP_ADDR |
| li t2, 1 |
| sll t3, t2, a0 |
| sw t3, 0x00(t1) |
| |
| /* Clear exception number from the Event pending register */ |
| li t1, PULP_ECP_ADDR |
| sw t3, 0x00(t1) |
| |
| /* Return */ |
| jalr x0, ra |
| |
| |
| /* |
| * SOC-specific function to determine if the exception is the result of a |
| * an interrupt or an exception |
| * return 1 (interrupt) or 0 (exception) |
| */ |
| SECTION_FUNC(exception.other, __soc_is_irq) |
| /* Get exception number from the mcause CSR register. */ |
| csrr t0, mcause |
| andi t0, t0, SOC_MCAUSE_EXP_MASK |
| |
| /* if IRQ number < PULP_MIN_IRQ, not interrupt */ |
| li t1, PULP_MIN_IRQ |
| addi a0, x0, 0 |
| blt t0, t1, not_interrupt |
| addi a0, a0, 1 |
| |
| not_interrupt: |
| /* return */ |
| jalr x0, ra |