Short answer first:
i.MXRT1052 does not have a flag that says "this image is XIP or non‑XIP".
The ROM infers XIP vs non‑XIP entirely from the IVT fields (especially Boot Data and Entry) and the memory addresses they point to.
Let's break it down ROM‑behavior‑accurately.
1. Key idea (one sentence)
RT1052 decides XIP vs non‑XIP by where the image is loaded and where the Entry points , not by any explicit mode bit.
2. What the ROM actually looks at
From the IVT, the ROM reads:
-
Boot Data
-
start -
size -
plugin
-
-
Entry address
That's it.
There is no "XIP" flag anywhere.
3. How Boot Data drives the decision
Boot Data structure (simplified)
typedef struct {
uint32_t start; // Image load/start address
uint32_t size; // Image size
uint32_t plugin; // Usually 0
} boot_data_t;
The critical rule
ROM checks whether boot_data.startbelongs to a memory that supports direct execution.
For RT1052, that means:
| Memory | Address range | Executable |
|---|---|---|
| FlexSPI NOR | 0x6000_0000 |
✅ Yes (XIP) |
| OCRAM | 0x2000_0000 |
✅ Yes |
| SDRAM | 0x8000_0000 |
✅ Yes |
| Internal ROM | 0x0020_0000 |
❌ No |
4. XIP case (most common: FlexSPI NOR)
Typical IVT fields
boot_data.start = 0x60000000; // FlexSPI NOR base
entry = 0x60002000; // Reset handler in NOR
ROM behavior
-
Configures FlexSPI (via FCB)
-
Reads IVT + Boot Data
-
Does NOT copy the image
-
Leaves image where it is (NOR)
-
Jumps directly to
entry
✅ This is XIP
✅ Code is fetched directly over FlexSPI
✅ Fast boot, no copy
👉 ROM infers XIP because:
boot_data.startis in FlexSPI address space
5. Non‑XIP case (copy-to-RAM boot)
Typical IVT fields
boot_data.start = 0x20000000; // OCRAM
entry = 0x20002000; // Reset handler in OCRAM
ROM behavior
-
Configures boot device
-
Reads image from flash / SD / USB
-
Copies image to RAM (boot_data.start)
-
Jumps to
entry
✅ This is non‑XIP ✅ Execution happens from RAM ✅ Slower boot, faster execution
👉 ROM infers non‑XIP because:
boot_data.startis RAM, not flash
6. Entry address is the second confirmation
ROM also checks:
- Is
entryin the same target memory asboot_data.start?
Typical patterns:
| Boot type | boot_data.start | entry |
|---|---|---|
| XIP | 0x6000_xxxx |
0x6000_xxxx |
| Non‑XIP | 0x2000_xxxx |
0x2000_xxxx |
If you mix them:
boot_data.start = 0x60000000;
entry = 0x20002000;
💥 Result: undefined / boot failure
7. No copy vs copy: what actually triggers it?
ROM decision logic (conceptual)
if (boot_data.start is executable flash memory) {
// XIP
do not copy
} else {
// non-XIP
copy image to boot_data.start
}
jump to entry
There is:
-
❌ no XIP flag
-
❌ no "executeInPlace" bit
-
✅ only memory address classification
8. What DCD and FCB do not control
Very important:
| Block | Can it force XIP? |
|---|---|
| FCB | ❌ No |
| DCD | ❌ No |
| LUT | ❌ No |
They only:
-
Make flash readable
-
Configure clocks/memory
XIP vs non‑XIP is purely an IVT/Boot Data contract with ROM.
9. Common mistakes (seen in real projects)
❌ "XIP is enabled by FlexSPI config"
No. FlexSPI config only makes flash readable.
XIP happens only if ROM decides not to copy.
❌ "Entry alone determines XIP"
Wrong.
ROM looks at Boot Data first, then Entry.
❌ "plugin = 1 means non‑XIP"
No.
Plugin means custom loader logic, not XIP.
10. How to intentionally choose XIP or non‑XIP
To force XIP:
-
boot_data.start→ FlexSPI address -
entry→ FlexSPI address
To force non‑XIP:
-
boot_data.start→ RAM -
entry→ same RAM region
That's it.
11. One‑line mental model
RT1052 does not know "what your image is".
It only knows "where you want it to live".
12. Summary table
| Mechanism | XIP | Non‑XIP |
|---|---|---|
| Explicit flag | ❌ | ❌ |
| Boot Data start | FlexSPI | RAM |
| Image copy | ❌ | ✅ |
| Entry location | Flash | RAM |
| ROM decision | Address‑based | Address‑based |