summaryrefslogtreecommitdiffstats
path: root/libgloss/or1k/interrupts-asm.S
diff options
context:
space:
mode:
Diffstat (limited to 'libgloss/or1k/interrupts-asm.S')
-rw-r--r--libgloss/or1k/interrupts-asm.S166
1 files changed, 166 insertions, 0 deletions
diff --git a/libgloss/or1k/interrupts-asm.S b/libgloss/or1k/interrupts-asm.S
new file mode 100644
index 000000000..560035285
--- /dev/null
+++ b/libgloss/or1k/interrupts-asm.S
@@ -0,0 +1,166 @@
+/* interrupts-asm.S -- interrupt handling for OpenRISC 1000.
+ *
+ * Copyright (c) 2011, 2012, 2014 Authors
+ *
+ * Contributor Julius Baxter <juliusbaxter@gmail.com>
+ * Contributor Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+ * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+/* -------------------------------------------------------------------------- */
+/*!Generic interrupt handler function for or1k
+ */
+/* -------------------------------------------------------------------------- */
+
+#include "include/or1k-asm.h"
+#include "include/or1k-sprs.h"
+
+ .extern _or1k_interrupt_handler_table
+ .extern _or1k_interrupt_handler_data_ptr_table
+
+/* -------------------------------------------------------------------------- */
+/*!Function to call appropriate interrupt handler
+ */
+/* -------------------------------------------------------------------------- */
+
+ .section .text
+ .global _or1k_interrupt_handler
+ .type _or1k_interrupt_handler,@function
+
+_or1k_interrupt_handler:
+ /* Make room on stack, save link register */
+ l.addi r1,r1,-12
+ l.sw 0(r1),r9
+
+ /* Read PICSR */
+ l.mfspr r3,r0,OR1K_SPR_PIC_PICSR_ADDR
+
+ /* Load handler table base address */
+ l.movhi r7,hi(_or1k_interrupt_handler_table)
+ l.ori r7,r7,lo(_or1k_interrupt_handler_table)
+ /* Load data pointer table base address */
+ l.movhi r12,hi(_or1k_interrupt_handler_data_ptr_table)
+ l.ori r12,r12,lo(_or1k_interrupt_handler_data_ptr_table)
+#ifdef __OR1K_MULTICORE__
+ /* Read the addresses of the arrays of cores */
+ /* r7 = (*or1k_interrupt_handler_table) */
+ l.lwz r7,0(r7)
+ /* r12 = (*or1k_interrupt_handler_data_ptr_table) */
+ l.lwz r12,0(r12)
+ /* Generate offset in arrays */
+ /* r14 = coreid */
+ l.mfspr r14,r0,OR1K_SPR_SYS_COREID_ADDR
+ /* r14 = coreid*32*4 = off */
+ l.slli r14,r14,7
+ /* r7 = (*or1k_exception_handler_table)[coreid] */
+ l.add r7,r7,r14
+ /* r12 = (*or1k_exception_handler_table)[coreid] */
+ l.add r12,r12,r14
+#endif
+
+.L0:
+ /* Find first set bit in PICSR */
+ l.ff1 r4,r3
+ /* Any bits set? */
+ l.sfne r4,r0
+ /* If none, finish */
+ OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L2))
+ /* What is IRQ function table offset? */
+ l.addi r5,r4,-1
+ l.slli r6,r5,2
+ /* Add this to table bases */
+ l.add r14,r6,r7
+ l.add r13,r6,r12
+
+ /* Fetch handler function address */
+ l.lwz r14,0(r14)
+
+ /* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
+ l.sfne r14,r0
+ /* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
+ OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L1))
+
+ /* Pull out data pointer from table, save r3, we'll write over it */
+ l.sw 4(r1),r3
+ l.lwz r3,0(r13)
+ /* Call handler, save r5 in delay slot */
+ OR1K_DELAYED(
+ OR1K_INST(l.sw 8(r1),r5),
+ OR1K_INST(l.jalr r14)
+ )
+
+ /* Reload r3,r5 */
+ l.lwz r3,4(r1)
+ l.lwz r5,8(r1)
+.L1:
+ /* Clear bit from PICSR, return to start of checking loop */
+ l.ori r6,r0,1
+ l.sll r6,r6,r5
+ OR1K_DELAYED(
+ OR1K_INST(l.xor r3,r3,r6),
+ OR1K_INST(l.j .L0)
+ )
+
+.L2:
+ /* Finish up - write PICSR back, restore r9*/
+ l.lwz r9,0(r1)
+ l.mtspr r0,r3,OR1K_SPR_PIC_PICSR_ADDR
+ OR1K_DELAYED(
+ OR1K_INST(l.addi r1,r1,12),
+ OR1K_INST(l.jr r9)
+ )
+
+/* -------------------------------------------------------------------------- */
+/*!Function to enable an interrupt handler in the PICMR
+ */
+/* -------------------------------------------------------------------------- */
+ .global or1k_interrupt_enable
+ .type or1k_interrupt_enable,@function
+
+ /* r3 should have IRQ line for peripheral */
+or1k_interrupt_enable:
+ l.addi r1,r1,-4
+ l.sw 0(r1),r4
+ l.ori r4,r0,0x1
+ l.sll r4,r4,r3
+ l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
+ l.or r3,r3,r4
+ l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
+ l.lwz r4,0(r1)
+ OR1K_DELAYED(
+ OR1K_INST(l.addi r1,r1,4),
+ OR1K_INST(l.jr r9)
+ )
+
+/* -------------------------------------------------------------------------- */
+/*!Function to disable an interrupt handler in the PICMR
+ */
+/* -------------------------------------------------------------------------- */
+ .global or1k_interrupt_disable
+ .type or1k_interrupt_disable,@function
+
+ /* r3 should have IRQ line for peripheral */
+or1k_interrupt_disable:
+ l.addi r1,r1,-4
+ l.sw 0(r1),r4
+ l.ori r4,r0,0x1
+ l.sll r4,r4,r3
+ l.xori r4,r4,0xffff
+ l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
+ l.and r3,r3,r4
+ l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
+ l.lwz r4,0(r1)
+ OR1K_DELAYED(
+ OR1K_INST(l.addi r1,r1,4),
+ OR1K_INST(l.jr r9)
+ )