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

andrewparlane wrote on Friday, November 30, 2018:

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 (__ram_exceptions_start = 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 (__ram_exceptions_end = ABSOLUTE(.));
} > foobar

Then in the bsp alt_irq_entry.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 (__ram_exceptions_start, 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 (__ram_exceptions_end, ABSOLUTE (.))
[!provide] PROVIDE (__flash_exceptions_start, LOADADDR (.exceptions))

Which shows how the code gets mashed together.

Finally looking at the objdump we can the final code:

00000020 <alt_exception>:
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 <save_sp_to_pxCurrentTCB>:
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 <hw_irq_handler>:
124: 00002480 call 248 <alt_irq_handler>
128: 00002480 call 248 <alt_irq_handler>

alt_irq_handler 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?

rtel wrote on Sunday, December 02, 2018:

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.

andrewparlane wrote on Sunday, December 02, 2018:

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.

rtel wrote on Sunday, December 02, 2018:

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…

andrewparlane wrote on Sunday, December 02, 2018:

I have temporarily removed the alt_irq_entry.S and alt_exception_entry.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.