17.1 A Cortex-M kivételmodell: prioritás és vektortábla-bejegyzések

17.1.1 Motiváció: mi dönti el, melyik kezelő fut le?

Egy tipikus Cortex-M firmware-ben a fő ciklus szenzoradatot dolgoz fel, miközben egy UART-vevő megszakításkérés (interrupt request, IRQ) érkezik, egy timer lejár, és egy hiba miatt buszhitelesítési kivétel keletkezik. A processzornak el kell döntenie, melyik eseményt szolgálja ki először, melyik szoríthatja háttérbe a többit, és mi történik a megszakított kód regisztereivel. Ez a döntés nem a C kódban, hanem a Cortex-M kivételmodelljében (exception model) születik meg: a vektortábla (vector table) rögzíti, hova kell ugrani, a prioritásrendszer (priority) pedig azt, hogy egyszerre érkező események közül melyik nyer. A következő alfejezet ezt a két mechanizmust rendszerezi. Az itt tanultakra épül a következő alfejezet NVIC-konfigurációja, és erre támaszkodik az ISR-írás is.

17.1.2 Definíció: kivétel, kivételtípusok, vektortábla-bejegyzés

A Cortex-M szóhasználatában a kivétel (exception) minden olyan esemény, amely a processzort arra készteti, hogy a normál utasításfolyamot megszakítsa, és egy előre kijelölt kezelőrutinba (handler) ugorjon. A reset is kivétel: az első utasítás végrehajtása előtt a mag egy kezelőbe kerül. Az ARMv7-M architektúra a kivételeket két nagy csoportra osztja:

A kivételszám (exception number) egy egész szám, amely az egyes kivételeket azonosítja. Az 1-es a Reset, a 2-es az NMI, a 3-as a HardFault, a 4–6 a MemManage/BusFault/UsageFault, a 11 az SVCall, a 14 a PendSV, a 15 a SysTick. A 16-tól kezdődnek az IRQ-k: a 16-os az IRQ0, a 17-es az IRQ1, és így tovább. A 0-s kivételszám nem kivételhez tartozik: ez a vektortábla 0. szava, a kezdeti veremmutató.

A vektortábla (vector table) a címtér elején elhelyezkedő, 4 bájtos bejegyzésekből álló tömb. A 0. bejegyzés a kezdeti veremmutató (initial stack pointer), az 1. bejegyzés a Reset-hez tartozó kezelő címe, a 2. az NMI-é, és így tovább. A vektortábla indexe és a kivételszám közötti kapcsolat egyszerű:

vektortábla index=kivételszám \text{vektortábla index} = \text{kivételszám}

Ez azért igaz, mert a 0. index foglalja el a veremmutatót, és az 1. indextől kezdődnek a kivételvektorok. Az IRQ0 tehát a 16. indexű bejegyzés, az IRQn a (16 + n)-edik. Ez a látszólag apró eltolás a gyakori hibák egyik fő forrása: ha valaki az IRQ0-t a 0. indexre teszi, akkor a kezdeti veremmutatót írja felül, és a rendszer már a reset után hibás állapotba kerül.

A vektortábla első 16 bejegyzésének fix sorrendjét az előző alfejezet már bemutatta. Itt annyi a kiegészítés, hogy a tábla nem áll meg a 16. bejegyzésnél: az IRQ-k számára fenntartott bejegyzések a 16. indextől kezdődnek, és addig tartanak, ameddig a konkrét implementáció IRQ-t támogat. Egy adott IRQ-hoz tartozó kezelő címét tehát a (16 + IRQ-szám) indexű szó tartalmazza.

A kivételtípusok és vektortábla-pozícióik összefoglalása:

Kivételszám Név Vektortábla index Prioritás típusa
1 Reset 1 fix, -3
2 NMI 2 fix, -2
3 HardFault 3 fix, -1
4 MemManage 4 konfigurálható
5 BusFault 5 konfigurálható
6 UsageFault 6 konfigurálható
7–10 fenntartott 7–10 —
11 SVCall 11 konfigurálható
12 Debug Monitor 12 konfigurálható
13 fenntartott 13 —
14 PendSV 14 konfigurálható
15 SysTick 15 konfigurálható
16 + n IRQn 16 + n konfigurálható

A táblázatban a „fenntartott” (reserved) bejegyzések helyére a linkerscriptnek is bejegyzést kell tennie, különben a tábla elcsúszik. A gyakorlatban ezeket nullával vagy egy Default_Handler címével szokás kitölteni.

17.1.3 Prioritás: a számozás fordított viszonya

A Cortex-M prioritásrendszerének legfontosabb szabálya: a kisebb prioritásszám magasabb prioritást jelent. A Reset prioritása -3, az NMI-é -2, a HardFaulté -1. Ezek fix, negatív értékek; nem konfigurálhatók, és minden konfigurálható kivételnél magasabb rendűek. A konfigurálható kivételek prioritásszáma 0 és egy felső határ között mozog. A 0 a legmagasabb konfigurálható prioritás.

A prioritásszám nem feltétlenül használja ki a teljes 8 bites tartományt. Hogy hány bitet valósít meg a mag, az implementációs választás: az Armv7-M 3 és 8 bit között engedi meg, és a Cortex-M3-at beépítő gyártó dönti el (sok mikrokontrolleren 3 vagy 4 bit). Ez tehát nem általános Cortex-M3-tulajdonság, hanem a konkrét futtatókörnyezet paramétere. CMSIS-ben a __NVIC_PRIO_BITS, ebben a könyvben a LAB_NVIC_PRIO_BITS laborparaméter rögzíti, és a NVIC-konfiguráció visszaolvasásos próbája méri meg. A könyv két futtatókörnyezete eltér. A QEMU stable-8.2 mps2-an385 NVIC-modellje Armv7-M-en 8 bitet valósít meg (ott a 0xFF visszaolvasva 0xFF); ezt a QEMU forrásából tudjuk, a laborban a visszaolvasás igazolja. A könyv számpéldái és a tools/cm-run.py alapértelmezése egy 3 bites modellt követnek, amely sok mikrokontrolleren valós érték. Az alábbi táblázat mindkettőt mutatja. Négy dolgot kell külön kezelni:

Fogalom Mi ez Példa (LAB_NVIC_PRIO_BITS = 3, 3 bites modell) Példa (LAB_NVIC_PRIO_BITS = 8, QEMU 8.2 mps2-an385)
nyers prioritásbájt a regiszterben tárolt 8 bites érték 0xA0 0xA0
megvalósított bitek a bájt felső LAB_NVIC_PRIO_BITS bitje; a többi olvasáskor 0, írása hatástalan a 7:5 bitek; 0xFF visszaolvasva 0xE0 mind a 8 bit; 0xFF visszaolvasva 0xFF
logikai prioritás a megvalósított bitek értéke: nyers >> (8 − LAB_NVIC_PRIO_BITS) 0xA0 >> 5 = 5 0xA0 >> 0 = 160
csoport- és alprioritás az AIRCR.PRIGROUP (0–7) kettévágja a bájtot: a [7 : PRIGROUP+1] bitek a csoportprioritás, a [PRIGROUP : 0] bitek az alprioritás (mindkettő a megvalósított bitekből) PRIGROUP = 4 (vagy kisebb): a 3 bit mind csoportprioritás, csoport = 5, alprioritás = 0; PRIGROUP = 5: csoport = 0xA0 >> 6 = 2, alprioritás = (0xA0 >> 5) & 1 = 1 PRIGROUP = 4: csoport = 0xA0 >> 5 = 5, alprioritás = 0xA0 & 0x1F = 0; PRIGROUP = 5: csoport = 0xA0 >> 6 = 2, alprioritás = 0xA0 & 0x3F = 32
legalacsonyabb konfigurálható prioritás a visszaolvasott maszk (0xFF írása után olvasott érték) 0xE0 0xFF

A csoportprioritás tehát a két esetben azonos, mert ugyanazokból a felső bitekből jön; az alprioritás és a logikai érték viszont a megvalósított bitek számától függ. A sorrend (melyik kivétel előbb) mindkét esetben ugyanaz, amíg a nyers bájtok csak megvalósított biteket használnak.

A 0xA0 tehát csak ismert bitszám mellett jelent „5”-öt: 3 megvalósított bitnél a felső három bit 101. Ha ugyanaz a mag 8 bitet valósítana meg, a 0xA0 logikai prioritása 160 lenne, 4 bitnél pedig 0xA0 >> 4 = 10. A nyers bájt és a logikai érték összekeverése a másik gyakori félreértés.

A preemptálásról csak a csoportprioritás dönt: egy futó kezelőt az a kivétel szakíthat meg, amelynek csoportprioritása szigorúan magasabb rendű (kisebb szám). Az alprioritás és a kivételszám csak azt dönti el, hogy több egyidejűleg függő kivétel közül melyik kerül sorra először. Reset után PRIGROUP = 0, ami 3 megvalósított bit mellett azt jelenti, hogy mindhárom bit csoportprioritás.

A prioritások közötti döntés menete:

  1. A mag a legmagasabb prioritású, függőben lévő (pending) kivételt választja.
  2. Azonos csoportprioritás esetén az alprioritás, ha az is egyenlő, az alacsonyabb kivételszám nyer (tie-break szabály).
  3. Egy futó kezelőt csak szigorúan magasabb csoportprioritású kivétel szakíthat meg; azonos csoportprioritású (akár kisebb alprioritású) nem preemptál.
  4. A HardFault fix −1 prioritású, minden konfigurálható prioritású kivételnél magasabb rendű, és nem konfigurálható: az SCB SHPR1–3 regiszterei csak a MemManage, BusFault, UsageFault, SVCall, DebugMonitor, PendSV és SysTick prioritását tartalmazzák. A „mindig kiszolgálható” állításnak azonban vannak korlátai. A PRIMASK nem maszkolja a HardFaultot, a FAULTMASK = 1 viszont a végrehajtási prioritást −1-re emeli, így a HardFault sem tud belépni (csak az NMI). Ha pedig HardFault vagy NMI kezelése közben (−1 vagy −2 prioritáson) újabb szinkron hiba keletkezik, nincs magasabb kezelő, ahová eszkalálódhatna: a mag lockup állapotba kerül, és nem hajt végre több utasítást.

A prioritásszám tehát nem „erősség”, hanem rangsor: minél kisebb, annál előrébb van a sorban. Ezt a szemléletet érdemes a C kód prioritásdefinícióiban is következetesen alkalmazni.

17.1.4 Thread mód és Handler mód

A Cortex-M két végrehajtási módot ismer. Thread módban fut a normál alkalmazáskód: a fő ciklus, a segédfüggvények, a háttérlogika. Handler módban futnak a kivételkezelők. A mag a kivétel belépésekor automatikusan Handler módba vált, és a kivételkezelőből való visszatéréskor tér vissza Thread módba. Handler módban a végrehajtás mindig privilegizált szintű; Thread módban lehet privilegizált vagy nem privilegizált, attól függően, hogyan konfiguráltuk a CONTROL regisztert.

A visszatérés mechanizmusa a Cortex-M sajátossága, és két réteget érdemes szétválasztani.

A hardveres réteg: EXC_RETURN. A kivétel belépésekor az LR (link register) egy speciális EXC_RETURN értéket kap (például 0xFFFFFFF9). Ez nem visszatérési cím, hanem kódolt érték, amely megmondja a magnak, melyik verem keretét kell visszatölteni, és milyen módba kell visszatérni. A kivétel-visszatérést az váltja ki, hogy Handler módban egy EXC_RETURN-mintájú érték kerül a PC-be egy erre megengedett utasítással. Ilyen a BX LR, de ugyanígy a POP {..., PC}, az LDM a PC-vel a listában, vagy egy LDR PC, [...], ha a visszatöltött érték az EXC_RETURN.

A fordítói réteg: a C-függvény prológusa és epilógusa. Egy C-ben írt kezelő a fordító szemében közönséges void f(void) függvény. Ha nem hív mást, jellemzően BX LR-rel zárul. Ha hív, a prológus PUSH {..., LR}-rel menti az LR-ben lévő EXC_RETURN-t, az epilógus pedig POP {..., PC}-vel tölti vissza, és ez maga a kivétel-visszatérés. A kezelőt tehát nem kell kézzel BX LR-rel zárni, és nem kell külön attribútum sem. A feltétel csak az, hogy az LR-ben kapott értéket a kód ne írja felül végleg, és változatlanul juttassa a PC-be. A GCC __attribute__((interrupt)) Armv7-M-en érvényes, de mást jelent, mint A-profile-on: a kivételtípust figyelmen kívül hagyja, és azt jelzi, hogy a függvény csak 4 bájtra igazított SP-vel is meghívódhat, ezért a fordító a prológusban 8 bájtra igazítja a vermet. Ha a mag a belépéskor maga igazít (CCR.STKALIGN = 1, ami a Cortex-M3 r2p0-tól a reset utáni alapállapot), a sima void f(void) is AAPCS-helyes.

17.1.5 Verem és automatikus context-mentés

Amikor egy kivétel belép, a hardver automatikusan elmenti a megszakított program legfontosabb regisztereit a jelenlegi verembe. Ez a context-mentés (context save) nyolc szót érint. Az elrendezést az architektúra rögzíti: a belépés után az SP a keret legalacsonyabb címére (R0) mutat, és innen mérve az offsetek mindig ugyanazok:

Offset az új SP-től Regiszter Megjegyzés
+0x00 R0
+0x04 R1
+0x08 R2
+0x0C R3
+0x10 R12
+0x14 LR a megszakított kód link registere
+0x18 PC a folytatási cím (lásd lent)
+0x1C xPSR állapotjelzők; a 9. bit jelzi az igazítási szót
+0x20 (igazítási szó, opcionális) csak ha a belépés előtti SP nem volt 8 bájtra igazított

Ha a belépés előtti SP nem volt 8 bájtra igazított, a mag egy igazítási szót hagy ki. Ez a szó a keret fölött, a magasabb címen, az xPSR és a belépés előtti SP között van, nem a keret alatt. A regiszterek offsetjei ezért nem változnak, a visszatérés pedig a mentett xPSR 9. bitjéből tudja, hogy vissza kell-e adnia a +4 bájtot.

A mentett PC általánosan a folytatási cím: az az utasítás, amellyel a kivétel-visszatérés után a végrehajtás folytatódik. Aszinkron megszakításnál ez a következő, még végre nem hajtott utasítás. SVC-nél az SVC utáni utasítás. Szinkron hibáknál (például UsageFault, precíz BusFault) jellemzően maga a hibát okozó utasítás, de nem minden hibatípusnál: egy pontatlan (imprecise) BusFault mentett PC-je egy később végrehajtott utasításra mutathat. A hibakeresésnél tehát a mentett PC a kiindulópont, nem automatikusan a hibás utasítás címe.

A Cortex-M3 nem tartalmaz FPU-t, ezért nála mindig ez a 8 szavas alapkeret jön létre. A lebegőpontos regisztereket is mentő, kiterjesztett keret csak FPU-s magokon (például Cortex-M4F, Cortex-M7) jelenik meg, és külön profilváltást igényel; ebben a fejezetben nem foglalkozunk vele.

A veremmutató a mentés során csökken, és a nyolc szó (szükség esetén az igazítási szóval együtt) bekerül a verembe. A megszakított program regiszterei tehát megőrződnek; a kezelő saját kódja szabadon használhatja őket. A visszatéréskor a hardver a nyolc szót visszatölti, és a megszakított utasításfolyam pontosan ott folytatódik, ahol abbamaradt. Ez a mechanizmus az alapja annak, hogy a C-ben írt ISR-ek látszólag „ingyen” megkapják a regisztermentést.

A context-mentés a jelenleg aktív veremmutatót használja. Thread módban ez általában a fő veremmutató (MSP) vagy a folyamat veremmutatója (PSP); Handler módban mindig az MSP. A veremhasználat és a PSP/MSP váltás részletei a következő alfejezetek témái; itt a fogalmi szint a lényeg: a hardver a kivétel belépésekor automatikusan ment, a visszatéréskor automatikusan visszaállít.

17.1.6 Kidolgozott példa: IRQ prioritásának beállítása és engedélyezése

Munkakönyvtár: ~/arm-labor/cm/a068/ — az alfejezet minden laborfájlja ide kerül, és minden parancs innen futtatandó (a könyvtárrendet a Labor-alapkörnyezet alfejezet írja le).

mkdir -p ~/arm-labor/cm/a068
cd ~/arm-labor/cm/a068

A következő példa egy külső IRQ-t konfigurál a QEMU mps2-an385 machine-en. A konkrét IRQ-számot szimbolikusan kezeljük, mert annak pontos értéke a QEMU machine és a CMSDK periféria leírásából ellenőrizendő. A regisztercímek az ARMv7-M System Control Space dokumentált címei.

A NVIC prioritásregiszterei (IPR) bájtonként címezhetők: az IRQ n prioritásbájtja a 0xE000E400 + n címen található. Az engedélyezés az ISER0 regiszteren keresztül történik, a 0xE000E100 címen.

/* Thumb-2 / Armv7-M, Cortex-M3, QEMU mps2-an385 */
.equ NVIC_ISER0, 0xE000E100
.equ NVIC_IPR_BASE, 0xE000E400

    .syntax unified
    .thumb

/* Laborparaméter: a megvalósított prioritásbitek száma (CMSIS: __NVIC_PRIO_BITS).
   A futtatókörnyezethez kell rögzíteni, az a069 visszaolvasásos próbája szerint:
   3 a könyv 3 bites modelljében (tools/cm-run.py alapértelmezés), 8 a QEMU 8.2
   mps2-an385-ön. Az alábbi várható értékek a 3 bites modellre szólnak. */
.equ LAB_NVIC_PRIO_BITS, 3
.equ LAB_IRQ12_PRIO,     5            /* logikai prioritás */

/* Az IRQ12 prioritásának beállítása: a logikai értéket a megvalósított
   felső bitekbe toljuk. 3 bitnél: 5 << 5 = 0xA0. */
    ldr r0, =NVIC_IPR_BASE + 12
    mov r1, #(LAB_IRQ12_PRIO << (8 - LAB_NVIC_PRIO_BITS))
    strb r1, [r0]

/* Az IRQ12 engedélyezése: ISER0 bit 12. */
    ldr r0, =NVIC_ISER0
    mov r1, #(1 << 12)
    str r1, [r0]

A hozzá tartozó ISR C-ben, a vektortábla pedig a 16 + 12 = 28. indexű bejegyzést tartalmazza. Az IRQ12 itt szimbolikus példa: az AN385-ön ez a UART0–2 összevont túlcsordulási vonala, nem egy egyszerű perifériakérés (a070 1. feladata a tényleges UART0 RX vonalat használja).

/* Thumb-2 / Armv7-M, Cortex-M3 */
void IRQ12_Handler(void)
{
    /* A periféria megszakításjelzőjének törlése itt történik. */
    /* ... */
}

A vektortábla megfelelő részlete assemblyben. Ez rövidített szemléltetés: a kihagyott bejegyzéseknek valódi szavaknak kell lenniük, különben az IRQ12_Handler nem a 28. indexre kerül. A teljes, kitöltött mintát a Megszakítás-vezérelt I/O kidolgozott példája és a Záróprojekt II vektortáblája adja.

/* Thumb-2 / Armv7-M, Cortex-M3 */
.section .vectors, "a", %progbits
    .word _estack
    .word Reset_Handler
    .word NMI_Handler
    .word HardFault_Handler
    /* ... a 16. indexig ... */
    .word 0             /* 16: IRQ0 */
    .word 0             /* 17: IRQ1 */
    /* ... */
    .word IRQ12_Handler /* 28: IRQ12 */

Várható állapot GDB-vel ellenőrizve, a konfiguráló kód lefutása után, a 3 bites modellben (LAB_NVIC_PRIO_BITS = 3). QEMU 8.2 alatt a paramétert 8-ra kell állítani, ekkor ugyanez a sor a nyers 0x05-öt írja be, és a visszaolvasás is 0x05:

A 0xA0 logikai prioritása 0xA0 >> (8 − 3) = 5. A reset utáni PRIGROUP = 0 mellett ez teljes egészében csoportprioritás, tehát egy másik kezelőt akkor preemptál, ha annak csoportprioritása 5-nél nagyobb szám. Ha a paramétert nem igazítjuk a futtatókörnyezethez, és a 8 bites QEMU-n is a 3-as értékkel számolunk, a beírt nyers 0xA0 ott 160-as logikai prioritást jelent; ezért kell a bitszámot a visszaolvasás alapján rögzíteni.

17.1.7 Tipikus hibák és ellenpróbák

A hibakeresés menete mindig ugyanaz: tünet → hipotézis → adatgyűjtés (GDB, objdump, NVIC-regiszterek) → egy változtatás → ellenőrzés.

17.1.8 Feladatok

  1. Magyarázó feladat. Sorolj fel négy Cortex-M kivételtípust (Reset, NMI, HardFault, egy külső IRQ), és mindegyikhez add meg a kivételszámot, a vektortábla indexet és a prioritás típusát (fix vagy konfigurálható).
  2. Implementációs feladat. Írj assembly kódrészletet, amely az IRQ3 prioritását 2-re állítja, majd engedélyezi. Add meg a prioritásregiszter pontos címét és a beírandó bájt értékét LAB_NVIC_PRIO_BITS = 3 mellett, és azt is, hogy 4 bitnél mi lenne a helyes bájt.
  3. Hibakeresési/mérési feladat. Egy IRQ kezelője soha nem fut le, pedig az ISER megfelelő bitje be van állítva. Milyen hipotéziseket vizsgálnál? Milyen regisztereket és memóriaterületeket ellenőriznél GDB-vel?

17.1.9 Megoldások

  1. Megoldás. Reset: kivételszám 1, vektortábla index 1, prioritás fix -3. NMI: kivételszám 2, index 2, prioritás fix -2. HardFault: kivételszám 3, index 3, prioritás fix -1. IRQ0: kivételszám 16, index 16, prioritás konfigurálható. Az index minden esetben megegyezik a kivételszámmal, mert a 0. index a kezdeti veremmutatóé.

  2. Megoldás. Az IRQ3 prioritásbájtja a 0xE000E400 + 3 = 0xE000E403 címen van. A 2-es logikai prioritás LAB_NVIC_PRIO_BITS = 3 mellett 2 << 5 = 0x40 (8 bitnél, QEMU 8.2 alatt 0x02) (a felső 3 bitbe írva 010 → 0100 0000); 4 bitnél 2 << 4 = 0x20 lenne. Az engedélyezés az ISER0 0xE000E100 címén, a 3-as bit beállításával történik.

/* Thumb-2 / Armv7-M, Cortex-M3 */
ldr r0, =0xE000E403
mov r1, #0x40
strb r1, [r0]
ldr r0, =0xE000E100
mov r1, #(1 << 3)
str r1, [r0]
  1. Megoldás. Hipotézisek: (a) a megszakítások maszkolva vannak a PRIMASK (vagy FAULTMASK, BASEPRI) regiszterrel; (b) a kérés függőben van, de egy magasabb prioritású kezelő blokkolja; (c) a periféria nem generál megszakítást, csak státuszbitet állít; (d) a vektortábla bejegyzése rossz címre mutat; (e) a kezelő neve nem egyezik a linkerscriptben használt szimbólummal. Ellenőrzés: PRIMASK, ISPR, ISER, a prioritásregiszter és a vektortábla 16+IRQ indexű szava. A periféria oldalán a megszakítás-engedélyező és jelző regiszterek vizsgálata szükséges.

17.1.10 Rövid összefoglaló

A Cortex-M kivételmodellje a kivételszám és a vektortábla index közötti 1:1 megfelelést használja: a 0. index a kezdeti veremmutató, az 1. a Reset, a 3. a HardFault, a 16. pedig az IRQ0. A prioritásszám fordítottan arányos a tényleges prioritással: a kisebb szám magasabb rendet jelent, a Reset/NMI/HardFault fix negatív prioritású. A megvalósított prioritásbitek száma implementációs paraméter (LAB_NVIC_PRIO_BITS), a nyers bájtból ebből adódik a logikai prioritás, a preemptálásról pedig a PRIGROUP szerinti csoportprioritás dönt. A kivétel belépésekor a hardver automatikusan nyolc szót ment a verembe (szükség esetén egy igazítási szóval a keret fölött), és Handler módba vált. A visszatérést egy EXC_RETURN-értéknek a PC-be töltése váltja ki; egy C-függvény epilógusa (BX LR vagy POP {..., PC}) ezt külön teendő nélkül elvégzi.

Továbbhasznált definíciók: - kivételszám (exception number): a kivételt azonosító egész szám; a vektortábla indexével egyezik meg. - prioritásszám (priority number): a kivétel rangsorát kódoló érték; kisebb szám = magasabb prioritás. - automatikus context-mentés (automatic context save): a hardver által kivétel belépésekor a verembe mentett nyolc regiszter.

17.1.11 Források és ellenőrzési hiányok

Az alábbiak dokumentációs kiindulópontok (forrásállapot: nem megnyitott, lásd az Olvasói útmutató jelöléseit):

Ellenőrzési hiányok: a QEMU mps2-an385 machine-en az egyes CMSDK perifériákhoz tartozó IRQ-számok pontos értéke ebben a folyamatban nem került ellenőrzésre; a példában ezért szimbolikus IRQ-számot használtunk. A megvalósított prioritásbitek száma az Armv7-M implementációs opciója; a könyv laborparamétere (LAB_NVIC_PRIO_BITS = 3) munkafeltételezés, amelyet konkrét eszközön a gyártói dokumentáció vagy a a069 visszaolvasásos próbája (0xFF írása, visszaolvasás) dönt el. A HardFault-korlátok (FAULTMASK, lockup), a keretigazítás és a CCR.STKALIGN alapállapota az Armv7-M ARM és a Cortex-M3 műszaki leírás szerinti állítás, ebben a munkafolyamatban nem futtattuk le.