FreeRTOS with Altera / Intel NIOS II, exception handling clash.

I have a NIOS II softcore design running on a cyclone V FPGA. I would like to run FreeRTOS but have been having some weird issues with spurious interrupts. Looking into it further it appears that both FreeRTOS and the NIOS BSP contain interrupt handling code, which the linker script merges together into some horrendous mismash of code. Specifically the linker script contains:
.exceptions : { PROVIDE (ramexceptionsstart = ABSOLUTE(.)); . = ALIGN(0x20); KEEP ((.irq)); KEEP ((.exceptions.entry.label)); KEEP ((.exceptions.entry.user)); KEEP ((.exceptions.entry.ecc_fatal)); KEEP (*(.exceptions.entry)); KEEP (*(.exceptions.irqtest.user)); KEEP (*(.exceptions.irqtest)); KEEP (*(.exceptions.irqhandler.user)); KEEP (*(.exceptions.irqhandler)); KEEP (*(.exceptions.irqreturn.user)); KEEP (*(.exceptions.irqreturn)); KEEP (*(.exceptions.notirq.label)); KEEP (*(.exceptions.notirq.user)); KEEP (*(.exceptions.notirq)); KEEP (*(.exceptions.soft.user)); KEEP (*(.exceptions.soft)); KEEP (*(.exceptions.unknown.user)); KEEP (*(.exceptions.unknown)); KEEP (*(.exceptions.exit.label)); KEEP (*(.exceptions.exit.user)); KEEP (*(.exceptions.exit)); KEEP (*(.exceptions)); PROVIDE (ramexceptionsend = ABSOLUTE(.)); } > foobar
Then in the bsp altirqentry.S there is some code that gets put in to some of those sections. Specifically:
Line 54: .section .exceptions.entry.label, “xa” Line 62: .section .exceptions.irqtest, “xa” Line 85: .section .exceptions.irqhandler, “xa” Line 93: .section .exceptions.irqreturn, “xa” Line 97: .section .exceptions.notirq.label, “xa” Line 106: .section .exceptions.exit.label
Then FreeRTOS port_asm.S has other code which is put into these sections too:
Line 36: .section .exceptions.entry, “xa”
Line 78: .section .exceptions.irqtest, “xa”
Line 90: .section .exceptions.irqhandler, “xa” Line 94: .section .exceptions.irqreturn, “xa” Line 135: .section .exceptions.soft, “xa”
The map file created by the linker contains:
.exceptions 0x0000000000000020 0x2fc [!provide] PROVIDE (ramexceptionsstart, ABSOLUTE (.)) 0x0000000000000020 . = ALIGN (0x20) *(.irq) *(.exceptions.entry.label) .exceptions.entry.label 0x0000000000000020 0x0 ../bsp/libhal_bsp.a(alt_irq_entry.o) 0x0000000000000020 alt_irq_entry .exceptions.entry.label 0x0000000000000020 0x0 ../bsp/libhal_bsp.a(alt_exception_entry.o) 0x0000000000000020 alt_exception *(.exceptions.entry.user) *(.exceptions.entry.ecc_fatal) *(.exceptions.entry) .exceptions.entry 0x0000000000000020 0x8c obj/default/FreeRTOSv10.1.1/Source/portable/GCC/NiosII/port_asm.o .exceptions.entry 0x00000000000000ac 0x54 ../bsp/libhal_bsp.a(alt_exception_entry.o) *(.exceptions.irqtest.user) *(.exceptions.irqtest) .exceptions.irqtest 0x0000000000000100 0x14 obj/default/FreeRTOSv10.1.1/Source/portable/GCC/NiosII/port_asm.o .exceptions.irqtest 0x0000000000000114 0x10 ../bsp/libhal_bsp.a(alt_irq_entry.o) *(.exceptions.irqhandler.user) *(.exceptions.irqhandler) .exceptions.irqhandler 0x0000000000000124 0x4 obj/default/FreeRTOSv10.1.1/Source/portable/GCC/NiosII/port_asm.o .exceptions.irqhandler 0x0000000000000128 0x4 ../bsp/libhal_bsp.a(alt_irq_entry.o) *(.exceptions.irqreturn.user) *(.exceptions.irqreturn) .exceptions.irqreturn 0x000000000000012c 0x8c obj/default/FreeRTOSv10.1.1/Source/portable/GCC/NiosII/port_asm.o 0x000000000000012c restore_sp_from_pxCurrentTCB .exceptions.irqreturn 0x00000000000001b8 0x4 ../bsp/libhal_bsp.a(alt_irq_entry.o) *(.exceptions.notirq.label) .exceptions.notirq.label 0x00000000000001bc 0x0 ../bsp/libhal_bsp.a(alt_irq_entry.o) *(.exceptions.notirq.user) *(.exceptions.notirq) .exceptions.notirq 0x00000000000001bc 0x8 ../bsp/libhal_bsp.a(alt_exception_entry.o) *(.exceptions.soft.user) *(.exceptions.soft) .exceptions.soft 0x00000000000001c4 0x2c obj/default/FreeRTOSv10.1.1/Source/portable/GCC/NiosII/port_asm.o *(.exceptions.unknown.user) *(.exceptions.unknown) .exceptions.unknown 0x00000000000001f0 0x4 ../bsp/libhal_bsp.a(alt_exception_entry.o) *(.exceptions.exit.label) .exceptions.exit.label 0x00000000000001f4 0x0 ../bsp/libhal_bsp.a(alt_irq_entry.o) .exceptions.exit.label 0x00000000000001f4 0x0 ../bsp/libhal_bsp.a(alt_exception_entry.o) *(.exceptions.exit.user) *(.exceptions.exit) .exceptions.exit 0x00000000000001f4 0x54 ../bsp/libhal_bsp.a(alt_exception_entry.o) *(.exceptions) .exceptions 0x0000000000000248 0xd4 ../bsp/libhal_bsp.a(alt_irq_handler.o) 0x0000000000000248 alt_irq_handler [!provide] PROVIDE (ramexceptionsend, ABSOLUTE (.)) [!provide] PROVIDE (__flashexceptionsstart, LOADADDR (.exceptions))
Which shows how the code gets mashed together. Finally looking at the objdump we can the final code:
00000020 : 20: ef7fff04 addi ea,ea,-4 24: deffe304 addi sp,sp,-116 28: dfc00015 stw ra,0(sp) 2c: d8400215 stw at,8(sp) 30: d8800315 stw r2,12(sp) 34: d8c00415 stw r3,16(sp) 38: d9000515 stw r4,20(sp) 3c: d9400615 stw r5,24(sp) 40: d9800715 stw r6,28(sp) 44: d9c00815 stw r7,32(sp) 48: da000915 stw r8,36(sp) 4c: da400a15 stw r9,40(sp) 50: da800b15 stw r10,44(sp) 54: dac00c15 stw r11,48(sp) 58: db000d15 stw r12,52(sp) 5c: db400e15 stw r13,56(sp) 60: db800f15 stw r14,60(sp) 64: dbc01015 stw r15,64(sp) 68: 000b307a rdctl r5,estatus 6c: d9401115 stw r5,68(sp) 70: df401215 stw ea,72(sp) 74: dc001315 stw r16,76(sp) 78: dc401415 stw r17,80(sp) 7c: dc801515 stw r18,84(sp) 80: dcc01615 stw r19,88(sp) 84: dd001715 stw r20,92(sp) 88: dd401815 stw r21,96(sp) 8c: dd801915 stw r22,100(sp) 90: ddc01a15 stw r23,104(sp) 94: de801b15 stw gp,108(sp) 98: df001c15 stw fp,112(sp) 0000009c : 9c: 06000074 movhi et,1 a0: c61ef004 addi et,et,31680 a4: c6000017 ldw et,0(et) a8: c6c00015 stw sp,0(et) ac: deffed04 addi sp,sp,-76 b0: dfc00015 stw ra,0(sp) b4: d8400215 stw at,8(sp) b8: d8800315 stw r2,12(sp) bc: d8c00415 stw r3,16(sp) c0: d9000515 stw r4,20(sp) c4: d9400615 stw r5,24(sp) c8: d9800715 stw r6,28(sp) cc: d9c00815 stw r7,32(sp) d0: 000b307a rdctl r5,estatus d4: da000915 stw r8,36(sp) d8: da400a15 stw r9,40(sp) dc: da800b15 stw r10,44(sp) e0: dac00c15 stw r11,48(sp) e4: db000d15 stw r12,52(sp) e8: db400e15 stw r13,56(sp) ec: db800f15 stw r14,60(sp) f0: dbc01015 stw r15,64(sp) f4: d9401115 stw r5,68(sp) f8: ebffff04 addi r15,ea,-4 fc: dbc01215 stw r15,72(sp)
addresses 20 – a8 are from FreeRTOS code, and ac – fc is the BSP code. Note how the ea register is handled by both chunks of code. An even more obvoious example is:
00000124 : 124: 00002480 call 248 128: 00002480 call 248
altirqhandler is in the BSP and is written in such a way that if the ipending register is 0, it locks up. Which is guaranteed to happen the second time it’s called, because interupts are disabled and the first call should handle all of the pending interrupts. So that sumarizes the issue pretty well (I think), the question is what to do about this. One option is to delete the exception handling code from the BSP, but that’s auto generated and would get replaced every time you generate the BSP. I could write a patch that auto delets it on generation, but that seems a bit hacky. Any ideas?

FreeRTOS with Altera / Intel NIOS II, exception handling clash.

The NIOS demo in the FreeRTOS download is pretty old – but how does it deal with this issue? I suspect it has done as you suggest.

FreeRTOS with Altera / Intel NIOS II, exception handling clash.

I’ve been unable to build the demo app. It includes system.h which is part of the BSP but there isn’t a BSP project. There’s a syslib project, but when I import that into the NIOS build tools (eclipse) the standard NIOS2 option isn’t in the menu to generate the BSP. I’ve been assuming that you have to have your own hardware config and then create your own BSP project from that, which I could do, but would end up having the same issues as I’m having.

FreeRTOS with Altera / Intel NIOS II, exception handling clash.

Sorry I can’t remember how the project was created – but can’t see any exception handling code in the project that would have been auto-generated so removing that from your project to see if it fixes the problem would seem to be a good suggestion – if that works then the question will be how to prevent it being auto generated again…

FreeRTOS with Altera / Intel NIOS II, exception handling clash.

I have temporarily removed the altirqentry.S and altexceptionentry.S files, and after that everything works fine. It doesn’t strike me as the best fix ever, but I can’t think of anything else that would work. Obviously those files will be replaced next time I generate the BSP, but I should be able to set up a patch to delete them each time. The other option would be to remove the exception handling from freeRTOS, but I expect that’d cause other issues.