The Memory Region Definitions section described how each of the memory regions are defined. This allocates the room for each of the memory regions.
This discussion covers how the values of some of the special memory regions are created/populated. Please refer to the earlier sections for an understanding of how the reset and interrupt remapping works before proceeding through this section.
Let's take a look at each of the memory regions in order. Please note that there are two linker scripts, one for the boot loader and one for the application. In order for some of these section definitions to make sense, we will be showing excerpts from either or both of these files for any given section. Please pay close attention to which linker file we are referring to when we show an example.
1) Section (1) is the reset vector. This belongs to the boot loader space so this is located in the boot loader linker file. What we need at the reset vector is a jump to the start of the boot loader code. In the boot loader linker script:
/*
** Reset Instruction
*/
.reset :
{
SHORT(ABSOLUTE(__reset));
SHORT(0x04);
SHORT((ABSOLUTE(__reset) >> 16) & 0x7F);
SHORT(0);
} >reset
The code in this section generates a "goto __reset" instruction located in the "reset" memory section. This will cause the CPU to jump to the boot loader startup code after any device reset. This is common code that is present in any default linker script for PIC24F.
2) The second section is the IVT. In the IVT we need to jump to the user's remapped IVT table.
__APP_IVT_BASE = 0x1400; .ivt __IVT_BASE : { LONG(ABSOLUTE(__APP_IVT_BASE) + 0x004); /* __ReservedTrap0*/ LONG(ABSOLUTE(__APP_IVT_BASE) + 0x008); /* __OscillatorFail*/ LONG(ABSOLUTE(__APP_IVT_BASE) + 0x00C); /* __AddressError*/ LONG(ABSOLUTE(__APP_IVT_BASE) + 0x010); /* __StackError*/ LONG(ABSOLUTE(__APP_IVT_BASE) + 0x014); /* __MathError*/ ... LONG(ABSOLUTE(__DEFAULT_VECTOR)); /* __Interrupt116 not implemented */ LONG(ABSOLUTE(__DEFAULT_VECTOR)); /* __Interrupt117 not implemented */ } >ivt
This linker code will place the _APP_IVT_BASE constant + an offset address at each of the IVT vector entries. This will cause the CPU to jump to the specified vector in the user's remapped IVT table.
Note that each entry is 4 bytes away from the previous entry. Is is because the resulting remapped IVT will need to use "goto" instructions at each entry in order to reach the desired handler. The "goto" instruction takes two instruction words at 2 bytes of memory address each.
3) Section (3), the AIVT, is either not used or is used by the boot loader and shouldn't be used by the application. If the boot loader requires interrupts, then it uses the AIVT and switches to AIVT interrupts before starting and switches back to the IVT before jumping to the customer code. No linker modifications are required here. For boot loaders that don't require interrupts, some have the AIVT section removed since they are not remapped to the user space and not used by the boot loader.
4) Section (4), the boot loader code - the only modification required in the linker script for the boot loader code is the changes to the memory region definitions discussed previously in the Memory Region Definitions section.
5) Section (5) is the user remapped reset. This is the address where the boot loader jumps upon completion. This address needs to be at a fixed location in code that both the boot loader and the application know about. At this address there needs to be a jump to the user application code. In the application linker script:
.application_ivt __APP_IVT_BASE : { SHORT(ABSOLUTE(__reset)); SHORT(0x04); SHORT((ABSOLUTE(__reset) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__ReservedTrap0) ? ABSOLUTE(__ReservedTrap0) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__ReservedTrap0) ? (ABSOLUTE(__ReservedTrap0) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__OscillatorFail) ? ABSOLUTE(__OscillatorFail) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__OscillatorFail) ? (ABSOLUTE(__OscillatorFail) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__AddressError) ? ABSOLUTE(__AddressError) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__AddressError) ? (ABSOLUTE(__AddressError) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0);
This section of code has been added to the default linker script. This creates a section in code located at __APP_IVT_BASE address. In this case the __APP_IVT_BASE address is also defined in the application linker file:
__APP_IVT_BASE = 0x1400;
This address must match exactly between the boot loader code, boot loader linker file, and the application linker file. If any of these do not match then the linkage between the interrupt remapping or reset remapping will not work and the application will fail to run properly.
The first entry in this table is the user remapped reset. This code generates a "goto __reset" at address __APP_IVT_BASE. This allows the boot loader to jump to this fixed address to then jump to the start of the user code (located at the __reset label).
6) Section (6) is the remapped IVT table. This section allows the interrupt to be remapped from the boot loader space to the application space. In order to do this the boot loader must either know the exact address of every interrupt handler, or must have another jump table that it jumps to in order to redirect it to the correct interrupt handler. The second approach is the one used in the implemented boot loaders. This is implemented in the following table:
.application_ivt __APP_IVT_BASE : { SHORT(ABSOLUTE(__reset)); SHORT(0x04); SHORT((ABSOLUTE(__reset) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__ReservedTrap0) ? ABSOLUTE(__ReservedTrap0) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__ReservedTrap0) ? (ABSOLUTE(__ReservedTrap0) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__OscillatorFail) ? ABSOLUTE(__OscillatorFail) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__OscillatorFail) ? (ABSOLUTE(__OscillatorFail) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0); SHORT(DEFINED(__AddressError) ? ABSOLUTE(__AddressError) : ABSOLUTE(__DefaultInterrupt)); SHORT(0x04); SHORT(DEFINED(__AddressError) ? (ABSOLUTE(__AddressError) >> 16) & 0x7F : (ABSOLUTE(__DefaultInterrupt) >> 16) & 0x7F); SHORT(0);
This first entry in the table is the remapped reset vector that we just discussed. The second entry in the table is the first possible interrupt. In this case it is the ReservedTrap0 interrupt. This line of linker code will look for the __ReservedTrap0 interrupt function. If it exists it will insert a "goto __ReservedTrap0" at the second address in this table. If it doesn't find the __ReservedTrap0 function, it will put a "goto __DefaultInterrupt" at this entry in the table. In this way just by defining the appropriate interrupt handler function in the application code, the linker will automatically create the jump table entry .required.
Looking at an example application_ivt table as generated by the linker script where the ReservedTrap0 interrupt is not defined and the OscillatorFail and AddressError handlers are defined, starting at address _APP_IVT_BASE you will have the following entries in program memory:
goto __reset
goto __DefaultInterrupt
goto __OscillatorFail
goto __AddressError
...
7) Section (7), the user application code - the only modification to the linker script required for the application code is the changes to the memory region definitions discussed previously in the Memory Region Definitions section.
MLA - USB Library Help Version : 2.16
![]() |