Execute In Place (XIP).
-Aviral Mittal avimit att yahu dat cam.
https://www.linkedin.com/in/avimit/
SITE HOME

While an embedded system starts-up from no power, the first code it will execute has to come from a non-volatile memory source e.g. Flash or ROM.
Usually there shall be a 'bootloader' program which will do the bare-minimum to get the system up and running.

When a system is booting, it has no-ram available, hence no stack available, hence no memory available to store program variables. So the first code a processor runs must do things entirely using the processor registers. The first code the processor executes also executes from where it is. That is to say it is 'executed-in-place'. It must not attempt to modify anything in the program itself, as this code may be in ROM, and the code cannot be self-modifying.
Due to the above considerations, the first program that a processor executes after power-up is usually written in assembly language, as the execution of a c-program almost always requires a 'stack' to be setup in Read/Write memory (RAM) to store variables, and at startup or power-up RAM may not be available. Tutorial 2 shows how the variables are stored on to the stack at the time of program execution.

One of the things that the boot-loader would do is to make the system RAM available for use. It can then relocate the code from flash into this ram, and then jump to the RAM to execute this copied or relocated code.

And yes, for all XIP code the load region = execution region, that is to say that XIP code is stored in the root region. Remember 'root region' by definition is the region where the load addresses are = execute addresses. (see below to understand Load/Execute regions)

Other applications of XIP:
Apart from the boot-loader code, XIP is also gaining popularity in embedded world to execute programs other than boot code directly from the Flash. NOR flash can be accessed randomly unlike NAND, hence NOR flash is the obvious choice for such XIP storage and in-place execution code. This helps save the on-chip ram area, which in turn can be cost-effective. The execution will of course will slower than RAM execution, however for many embedded applications it brings about cost advantages, and offers adequate performance.

Load Region Vs Execute Region:
In a typical embedded system, all the program & data is stored in some Non-volatile memory when the system is powered off. However some of the data or code may be moved into system SRAM (volatile mem), before it is executed (if code) or before it is used (if data), when the system is powered-ON.
When a user compiles and 'links' a program, an 'image' of that program is produced. This is a binary executable file which the system can execute.
The binary 'image' is typically divided into 'Read-Only' segment, which contains the code & read-only data and 'Read-Write' segment, which contains data, which can be initialized or zero initialized or even Un-initialized.
Usually the 'Read-Only' segment can even be placed into ROM (as opposed to flash), and does not have a requirement to be moved from where it is in the memory. it is 'executed from where it is' i.e. it is executed in place.
While the 'Read-Write' segment must be moved into system's Read/Write memory e.g. SRAM before execution begins.
Hence for certain parts of the code, the memory location where that part resides when the system is powered off is the same when the system is powered ON.
But
For certain parts of the code, the memory location where that part resides when the system in powered off is different to the memory location where that part is moved to, upon power ON.
So who moves the code?
The linker will add the code into the program which the processor will execute, and move those parts of the code, which are required to be moved into system's SRAM at power-up.
Now these sections of code have different address at 'load' time, which is in NVM than at 'execution' time, which is typically somewhere in the SRAM.
So the program image can have parts for which the 'Load Region = Execute Region', and this part of the code is 'Executed-In-Place' XIP.
For certain other parts of the code the 'Load Region is not equal to Execute Region', and this part of the code is not executed-in-place.

Example:
A user has its application code, he compiles and links it to produce binary executable called 'image.bin'. The 'image.bin' is 14,246 Bytes.
That means the system must have at least that amount of NVM available for the user to fit its binary image in the system.
Then the system will have some SRAM (say 16KB, which is quite generous in this case), and this is at location 0x2000_0000 and 0x2000_3FFF.

Now the permanent address of the image file 'image.bin' is will be in the NVM and will occupy the memory addresses 0x0000_0000 to 0x0000_37A6 in the system.
 
Hence the load address for this whole of the binary is from 0x0000_0000 to 0x0000_37A6. This can be an NVM (Flash) or can even be ROM.
But before this can be executed, as a bare minimum requirement
The system's R/W memory (say a total of 16 KB SRAM is available in the system) is somewhere else in the memory map, and say it is from 0x2000_0000 to 0x2000_3FFF (16KB).
Hence certain regions from the 'image.bin' will be moved to the memory location somewhere in between 0x2000_0000 and 0x2000_3FFF. And the stack pointer will be setup to have some memory reserved for 'stack' which will also reside between 0x2000_0000 and 0x2000_3FFF.
Hence for certain section(s) of the 'image.bin' file, the load address = execution address, and it remains permanent, and is between 0x0000_0000 and 0x0000_37A6. This is also the XIP , Execute-in-Place Region of the 'image.bin'.
Whereas for certain section(s) of the 'image.bin' file, the load address was somewhere in between 0x0000_0000 to 0x0000_37A6, and the execution address somewhere in between 0x2000_0000 and 0x2000_3FFF. i.e. for these sections, the Load Address is not equal to their execution address.

Let us take another example where the Load address is not the same as execution address:
The user has a critical function written in C. The image file that contains this function is placed in NVM. However the user wants this function to be moved into a SRAM which is very close to the processor for fast execution.
Now this function has 2 memory addresses.
1. Load Address : Where the function resides in NVM memory, when the system is powered off
2. Execution Address : Where the function resides in SRAM memory, when the system is up and running.
Again for this function the Load Address is different to its Execution address.
Hence this code will not be XIP (Executed-in-Place)

Conclusion:

Certain code in a binary image can be executed from where it is in memory. This code never 'moves' into another region of the memory and has permanent address. When this code is executed, it is executed from where it is, this is called Execute-In-Place (XIP)

So how does the user specifies where the image regions should be placed at execution time?
There are 2 mechanisms.


Click Here to Make Comments or ask Questions
                                                                      
<= PREV  : Embedded C Fundamentals                      Next => Scatter Loading                                  

SITE HOME