Fix: Interrut Handler Register Function and Exception Process (#41)
Signed-off-by: shiode <shiode@aptpod.co.jp>
Co-authored-by: Cobus van Eeden <35851496+cobusve@users.noreply.github.com>
Co-authored-by: David Chalco <59750547+dachalco@users.noreply.github.com>
Co-authored-by: Joseph Julicher <jjulicher@mac.com>
diff --git a/portable/GCC/NiosII/port.c b/portable/GCC/NiosII/port.c
index 7dc6f81..cc68ed0 100644
--- a/portable/GCC/NiosII/port.c
+++ b/portable/GCC/NiosII/port.c
@@ -36,6 +36,7 @@
/* Altera includes. */
#include "sys/alt_irq.h"
+#include "sys/alt_exceptions.h"
#include "altera_avalon_timer_regs.h"
#include "priv/alt_irq_table.h"
@@ -46,6 +47,8 @@
/* Interrupts are enabled. */
#define portINITIAL_ESTATUS ( StackType_t ) 0x01
+int _alt_ic_isr_register(alt_u32 ic_id, alt_u32 irq, alt_isr_func isr,
+ void *isr_context, void *flags);
/*-----------------------------------------------------------*/
/*
@@ -56,7 +59,7 @@
/*
* Call back for the alarm function.
*/
-void vPortSysTickHandler( void * context, alt_u32 id );
+void vPortSysTickHandler( void * context);
/*-----------------------------------------------------------*/
@@ -137,7 +140,7 @@
void prvSetupTimerInterrupt( void )
{
/* Try to register the interrupt handler. */
- if ( -EINVAL == alt_irq_register( SYS_CLK_IRQ, 0x0, vPortSysTickHandler ) )
+ if ( -EINVAL == _alt_ic_isr_register( SYS_CLK_IRQ_INTERRUPT_CONTROLLER_ID, SYS_CLK_IRQ, vPortSysTickHandler, 0x0, 0x0 ) )
{
/* Failed to install the Interrupt Handler. */
asm( "break" );
@@ -156,7 +159,7 @@
}
/*-----------------------------------------------------------*/
-void vPortSysTickHandler( void * context, alt_u32 id )
+void vPortSysTickHandler( void * context)
{
/* Increment the kernel tick. */
if( xTaskIncrementTick() != pdFALSE )
@@ -175,25 +178,27 @@
* kernel has its scheduler started so that contexts are saved and switched
* correctly.
*/
-int alt_irq_register( alt_u32 id, void* context, void (*handler)(void*, alt_u32) )
+int _alt_ic_isr_register(alt_u32 ic_id, alt_u32 irq, alt_isr_func isr,
+ void *isr_context, void *flags)
{
int rc = -EINVAL;
alt_irq_context status;
+ int id = irq; /* IRQ interpreted as the interrupt ID. */
if (id < ALT_NIRQ)
{
/*
* interrupts are disabled while the handler tables are updated to ensure
- * that an interrupt doesn't occur while the tables are in an inconsistent
+ * that an interrupt doesn't occur while the tables are in an inconsistant
* state.
*/
status = alt_irq_disable_all ();
- alt_irq[id].handler = handler;
- alt_irq[id].context = context;
+ alt_irq[id].handler = isr;
+ alt_irq[id].context = isr_context;
- rc = (handler) ? alt_irq_enable (id): alt_irq_disable (id);
+ rc = (isr) ? alt_ic_irq_enable(ic_id, id) : alt_ic_irq_disable(ic_id, id);
/* alt_irq_enable_all(status); This line is removed to prevent the interrupt from being immediately enabled. */
}
diff --git a/portable/GCC/NiosII/port_asm.S b/portable/GCC/NiosII/port_asm.S
index 9fd2998..06cf5d2 100644
--- a/portable/GCC/NiosII/port_asm.S
+++ b/portable/GCC/NiosII/port_asm.S
@@ -34,11 +34,10 @@
.globl restore_sp_from_pxCurrentTCB
# Entry point for exceptions.
-.section .exceptions.entry, "xa"
+.section .exceptions.entry.user, "xa"
# Save the entire context of a task.
save_context:
- addi ea, ea, -4 # Point to the next instruction.
addi sp, sp, -116 # Create space on the stack.
stw ra, 0(sp)
# Leave a gap for muldiv 0
@@ -59,7 +58,8 @@
stw r15, 64(sp)
rdctl r5, estatus # Save the eStatus
stw r5, 68(sp)
- stw ea, 72(sp) # Save the PC
+ addi r15, ea, -4 # Instruction that caused exception
+ stw r15, 72(sp) # Save as EA
stw r16, 76(sp) # Save the remaining registers
stw r17, 80(sp)
stw r18, 84(sp)
@@ -75,24 +75,13 @@
movia et, pxCurrentTCB # Load the address of the pxCurrentTCB pointer
ldw et, (et) # Load the value of the pxCurrentTCB pointer
stw sp, (et) # Store the stack pointer into the top of the TCB
-
- .section .exceptions.irqtest, "xa"
-hw_irq_test:
- /*
- * Test to see if the exception was a software exception or caused
- * by an external interrupt, and vector accordingly.
- */
- rdctl r4, ipending # Load the Pending Interrupts indication
- rdctl r5, estatus # Load the eStatus (enabled interrupts).
- andi r2, r5, 1 # Are interrupts enabled globally.
- beq r2, zero, soft_exceptions # Interrupts are not enabled.
- beq r4, zero, soft_exceptions # There are no interrupts triggered.
- .section .exceptions.irqhandler, "xa"
-hw_irq_handler:
- call alt_irq_handler # Call the alt_irq_handler to deliver to the registered interrupt handler.
+ br irq_test_user # skip the section .exceptions.entry
- .section .exceptions.irqreturn, "xa"
+ .section .exceptions.irqtest, "xa"
+irq_test_user:
+
+ .section .exceptions.exit.user, "xa"
restore_sp_from_pxCurrentTCB:
movia et, pxCurrentTCB # Load the address of the pxCurrentTCB pointer
ldw et, (et) # Load the value of the pxCurrentTCB pointer
@@ -135,16 +124,16 @@
.section .exceptions.soft, "xa"
soft_exceptions:
- ldw et, 0(ea) # Load the instruction where the interrupt occured.
- movhi at, %hi(0x003B683A) # Load the registers with the trap instruction code
- ori at, at, %lo(0x003B683A)
- cmpne et, et, at # Compare the trap instruction code to the last excuted instruction
- beq et, r0, call_scheduler # its a trap so switchcontext
- break # This is an un-implemented instruction or muldiv problem.
- br restore_context # its something else
+ movhi r3, 0x003b /* upper half of trap opcode */
+ ori r3, r3, 0x683a /* lower half of trap opcode */
+ beq r2, r3, call_scheduler
+ br exceptions_unknown_user # its something else
call_scheduler:
- addi ea, ea, 4 # A trap was called, increment the program counter so it is not called again.
- stw ea, 72(sp) # Save the new program counter to the context.
+ stw ea, 72(sp) # EA is PC+4 so will skip over instruction causing exception
call vTaskSwitchContext # Pick the next context.
br restore_sp_from_pxCurrentTCB # Switch in the task context and restore.
+
+ .section .exceptions.unknown.user
+exceptions_unknown_user:
+