GCC places instruction exception handler out of the allowed range

GCC places instruction exception handler out of the allowed range

by Alexandre Chau -
Number of replies: 6

Hi everyone,

We are currently developing a hardware sound synthesizer, in which a NIOS II CPU reads music pieces definitions (encoded as a subset of MIDI, an array of 2 words per MIDI note). The music pieces are defined in software for ease of modification (I know I could generate a memory initialization file, but I really want it to be more flexible), thus they are declared as arrays in header files which are included in the main program. It works fine for small pieces of music.

However, it seems that NIOS II GCC always places static data at the beginning of the memory, before even functions, interrupt and exception vectors: indeed, if the piece has too many notes (about 2500 seems to be the upper limit), GCC generates the following error: 

/home/vm/Documents/rtes/Lab4/src/sw/nios/fpga_sound_synthesizer_bsp/HAL/src/alt_instruction_exception_entry.c:95: warning: 
Unable to reach (null) (at 0x0403075c) from the global pointer (at 0x04028160) because the offset (34300) is out of the allowed range, -32678 to 32767.

The line marked with the error is in the HAL source file alt_instruction_exception_entry.c, at the following line:


> if(alt_instruction_exception_handler) {
/*
* Call handler. Its return value indicates whether the exception-causing
* instruction should be re-issued. The code that called us,
* alt_eceptions_entry.S, will look at this value and adjust the ea
* register as necessary
*/
return alt_instruction_exception_handler(cause, exception_pc, badaddr);
}
With alt_instruction_exception_handler defined as:

/* Function pointer to exception callback routine */
alt_exception_result (*alt_instruction_exception_handler)
(alt_exception_cause, alt_u32, alt_u32) = 0x0;

We have tried moving the includes / variable declarations around, to no avail.

The more notes we add, the larger the reported offset, which seems to confirm our suspicions.
Thus, the question is: is it possible to force NIOS II GCC to place large include data towards the end of the memory, or at least make sure that essential code such as exception / interrupt vectors and ISRs lives at memory addresses that are reachable?

Thanks a lot,

Alex
In reply to Alexandre Chau

Re: GCC places instruction exception handler out of the allowed range

by Sahand Kashani-Akhavan -

I've never seen this before, but this is an interesting problem. The warning you're getting says that the assembler cannot emit an instruction to reach the specified address from the global pointer, so it's trying to do an relative memory operation. In Nios, this is done with the ldw instruction which takes a register index and a relative offset, both encoded in the instruction format. The relative offset is 16 bits wide, which corresponds to the [-32768,+32767] range that's indicated. So at least we know specifically why the problem is occurring.

Memory layouts are handled by the linker, so I'd start by opening the BSP editor from eclipse and looking if you can move where these arrays are being stored. If your music is stored in a header file and being selectively included into the main C file, then this data should be stored in the heap. Look if you can modify the offset of the heap in the linker script tab. If yes, then hopefully that should solve the problem.

I have not tried this 2nd approach, but Example 4-2 in the document below shows how you can define a custom memory region by modifying the linker script manually. Perhaps you could try placing your music there and giving it a larger offset? I'd still try the GUI method first before going down this route though.

https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/nios2/n2sw_nii52015.pdf

In reply to Sahand Kashani-Akhavan

Re: GCC places instruction exception handler out of the allowed range

by Sahand Kashani-Akhavan -

Alex, you don't say what memory you are using. Now that I think back, I used a 10M-entry 32-bit array in lab 2 to test my accelerator with an SDRAM and the compiler never complained. The array was declared outside the main() function (in the heap).

Perhaps a workaround you could use is to declare a large array upfront in your application, then have a loop copy the actual data from the headers into this array before starting your accelerator? This may be a quick fix.

In reply to Sahand Kashani-Akhavan

Re: GCC places instruction exception handler out of the allowed range

by Alexandre Chau -

Thank you Sahand for your answer.

Ah right, I'm also using the SDRAM.
Were you also using IRQs? I'm also suspicious of the ISR function.

I have tried different variable / include placements: right now, the music is defined in a header file "music.h":

#include "bach_prelude_c.h"
#include "bach_prelude_c_poly.h"
#include "castlevania.h"
#include "mario_theme.h"
#include "wii_music.h"

/**
* List of all available music pieces
*/
#define PIECES_LENGTH 6
struct piece pieces[PIECES_LENGTH] = {
{BASE_SCALE_LENGTH, base_scale},
{BACH_PRELUDE_C_LENGTH, bach_prelude_c},
{BACH_PRELUDE_C_POLY_LENGTH, bach_prelude_c_poly},
{CASTLEVANIA_LENGTH, castlevania},
{MARIO_LENGTH, mario},
{WII_MUSIC_LENGTH, wii_music}
};

This header file gets included into main:

#include "music.h"
[... other functions and definitions using pieces]
static void controls_isr(void* context) {
    ...
}
int main {
    ...
}

I've tried instead declaring the array and instantiating in main.c directly, in the heap, in the stack (by storing a pointer to the array first), placing the definitions before or after the ISR but I guess GCC always rearranges them into the same order.

I really don't know what I could change to fix the compilation error, I've calculated the maximum array we can place is only about 8 KB in size... So for now I'm just swapping the array definition in the source code if I want to change a song but since the SDRAM is quite big, I really hope there's a way to fit so little data statically into it.

Here's a link to the repo in case my code wasn't clear: https://github.com/dialexo/epfl-rtes/tree/master/Lab4

Thanks a lot,

Alex

In reply to Alexandre Chau

Re: GCC places instruction exception handler out of the allowed range

by Sahand Kashani-Akhavan -

Hey,

I checked out your project files and built the SW on my side, and it didn't emit any warnings (see screenshot below).

Are you using a special build environment?

Attachment Screenshot_20200614_152358.png
In reply to Sahand Kashani-Akhavan

Re: GCC places instruction exception handler out of the allowed range

by Alexandre Chau -

Thank you Sahand,

Indeed the current C code fits in memory (the current songs are base scale, both Bach preludes, castlevania, mario and the wii music). However if we add a longer song to the list, the compiler fail the build (the exact error message only shows up when we're launching the code on the device, but a general compilation error is showed instead). For instance, if we change the declaration at the end of music.h by the following (I'm adding kizuna_music):

#include "bach_prelude_c.h"
#include "bach_prelude_c_poly.h"
#include "castlevania.h"
#include "mario_theme.h"
#include "wii_music.h"
#include "kizuna_music.h"

/**
 * List of all available music pieces
 */
#define PIECES_LENGTH 7
struct piece pieces[PIECES_LENGTH] = {
    {BASE_SCALE_LENGTH, base_scale},
    {BACH_PRELUDE_C_LENGTH, bach_prelude_c},
    {BACH_PRELUDE_C_POLY_LENGTH, bach_prelude_c_poly},
    {CASTLEVANIA_LENGTH, castlevania},
    {MARIO_LENGTH, mario},
    {WII_MUSIC_LENGTH, wii_music},
    {KIZUNA_MUSIC_LENGTH, kizuna_music}
};

In reply to Alexandre Chau

Re: GCC places instruction exception handler out of the allowed range

by René Beuchat -

Did you look the objdump file to verify the addresses?

In qsys, did you specify the SDRAM for reset and vectors?

see you Monday.