It sort of depends on what you mean by "boot". At the lowest level, the boot process is what the MCU does when first powered on, before it begins actually executing user code. At a higher level, "booting" may refer to what you, as the developer, instruct the device to do before launching the actual application program.
Before the MCU can execute any instructions, it must know where to find those instructions. On ARM parts, the processor expects to first read the vector table. This is a list of at least four pointers:
- The initial stack pointer
- The reset routine location
- The NMI ISR location
- The Hard Fault ISR location
- Additional ISR locations, for whatever interrupts the device happens to implement (technically these are optional)
This information is given in the ARM documentation
The vector table will typically be at the very beginning of your executable binary, so the processor will load the initial stack address into its stack pointer, and then jump to the location of the reset routine (the reset vector).
Normally, the processor expects to find the vector table at the beginning of flash memory. Some MCUs have dedicated configuration memory that can be used to instruct the MCU to look for the vector table at a different location. Some of these parts have built-in bootloaders in dedicated ROM, separate from the normal flash, and can be configured to run these bootloaders before starting the application to allow for updating the firmware without using a debug probe. However, it doesn't look like the S32K146 has these options, from a quick look. THis means that the MCU will always look for the vector table at the beginning of flash whenever it is powered on or otherwise reset. You would need to dig into the documentation, particularly the Reference Manual, to verify this. For an example of a processor that does have this feature, you might look at the STM32F4 series from ST.
At a higher level, you are free to write your own boot code, that runs when the device first starts up, and then "boots" into the application. This is a conventional bootloader architecture, where you place your bootloader at the beginning of flash, and when you're ready to run the actual application, the bootloader can do that by:
- Updating the Vector Table Offset Register to the address of the new vector table (usually at the beginning of your application, wherever that's stored)
- Updating the stack pointer to the first value in the new vector table
- Jumping to the reset vector
At that point, the processor will begin executing your application, almost as if it had booted from that location in the first place. I say almost because it is important to realize that this sort of boot process will NOT reset the state of the MCU (in particular the state of peripherals) to their power-on values. This is one reason why a defensive programmer will be very thorough in their initialization routines.
One additional thing to note, on platforms like ARM, it is possible to execute code stored just about anywhere. So it is possible, for instance, to have a bootloader that loads an application from an external memory into the MCU's RAM, and then execute the application from RAM. This capability is sometimes exploited by debug tools, which can write a small application into RAM to do things like load data into an external flash memory.