Obsah
1. Architektura mikrořadičů s jádry ARM Cortex-M3
2. Instrukční sada podporovaná jádry Cortex-M3
4. Přerušení běhu instrukcí LDM, STM, PUSH, POP atd.
6. Podmínky v instrukcích (CBZ, CBNZ)
7. Prefix IT aneb řešení mnoha problémů s podmíněnými skoky
8. Bitové operace (Booleovský procesor)
9. Booleovský procesor implementovaný v jádrech Cortex-M3
11. Procesory Atmel založené na technologii ARM
1. Architektura mikrořadičů s jádry ARM Cortex-M3
V předchozím článku jsme se zabývali popisem nejdůležitějších vlastností jader Cortex-M0 a Cortex-M0+, které tvoří základ řady Cortex-M (architektura ARM pro mikrořadiče). Připomeňme si, že se jedná (alespoň prozatím) o nejmenší procesorová jádra s architekturou ARM, která byla navržena takovým způsobem, aby dokázala cenově, z pohledu spotřeby elektrické energie, dostupností vývojových a ladicích prostředků atd. konkurovat některým typům osmibitových a šestnáctibitových mikrořadičů. Tato snaha vedla k cílenému omezení některých vlastností jader M0 a M0+, především se to týká zjednodušení instrukční sady (podmnožina instrukční sady Thumb), neexistence hardwarové děličky a samozřejmě též absence dalších koprocesorů (matematický koprocesor, NEON apod.). Pro ty aplikace, kde je vyžadován přece jen větší výpočetní výkon, jsou však určena jiná jádra navržená ve společnosti ARM. Další v pořadí (na škále od nejméně výkonných až po nejvýkonnější CPU) jsou jádra Cortex-M3, která se díky vyváženosti mezi výpočetním výkonem, cenou a spotřebou stala poměrně populární a nalezneme je například v čipech SAM3×.
Mezi základní cíl při návrhu jader Cortex-M3 patřilo vytvoření CPU s co nejmenší latencí, což znamená, že reakce na přerušení by měla proběhnout ideálně v jediném taktu. Navíc měly mít tyto procesory relativně dobrý výpočetní výkon, čehož bylo dosaženo hned několika způsoby. Především mají jádra Cortex-M3 Harvardskou architekturu umožňující mj. provádět současné čtení další instrukce společně se čtením či zápisem dat (zde ovšem závisí na konkrétním výrobci čipu, jak bude koncipovat interní sběrnice připojené k pamětem). Dále je použita pipeline se třemi řezy (klasické RISCové fetch, decode, execute) a nalezneme zde i modul určený pro dopředné čtení instrukcí (PFU – Prefetch Unit) a další modul pro pozdržení zápisu jednoho slova do datové paměti (ovšem pouze pro ty regiony paměti, které jsou označeny příznakem „bufferable“). Vlastní jádro Cortex-M3 je v případě potřeby rozšiřitelné o další moduly, zejména pak o modul MPU (Memory Protection Unit) popsaný níže, dále pak o modul DWT (Data Watchpoint and Trace Unit) usnadňující ladění či NVIC (Nested Vectored Interrupt Controller), o němž se taktéž zmíníme v navazujícím textu.
2. Instrukční sada podporovaná jádry Cortex-M3
Před podrobnějším popisem instrukční sady jader Cortex-M3 si zopakujme tabulku, s níž jsme se seznámili již minule:
# | Jádro | Architektura ARM | Architektura CPU/MCU | MPU |
---|---|---|---|---|
1 | Cortex-M0 | ARMv6-M | Von Neumann | ne |
2 | Cortex-M0+ | ARMv6-M | Von Neumann | volitelná |
3 | Cortex-M1 | ARMv6-M | Von Neumann | ne |
4 | Cortex-M3 | ARMv7-M | Harvardská | volitelná |
5 | Cortex-M4 | ARMv7E-M | Harvardská | volitelná |
6 | Cortex-M7 | ARMv7E-M | Harvardská | volitelná |
Z této tabulky mj. vyplývá, že jádra Cortex-M3 jsou založena na architektuře ARMv7-M a nikoli na architektuře ARMv6-M, jako je tomu u Cortex-M0(+). To s sebou přináší změny zejména v instrukční sadě, protože jádra Cortex-M3 plně podporují jak instrukční sadu Thumb s 16bitovými operačními kódy, tak i instrukční sadu Thumb-2, v níž nalezneme i instrukce s 32bitovým slovem (jedná se však o odlišný formát, než jaký je použit v původní RISCové instrukční sadě A32).
Přímo jsou podporovány i instrukce vykonávané hardwarovou násobičkou, která dokáže provést vlastní operaci vynásobení za jediný takt (viz též diskuzi o rozdílných vlastnostech násobičky u jader Cortex-M0 a Cortex-M0+). Tyto instrukce umožňují vynásobit dva 32bitové operandy (volitelně bez znaménka či se znaménkem) a získat 32bitový popř. 64bitový výsledek, popř. provést po vynásobení operaci součtu či rozdílu, čehož lze využít například při zpracování signálu:
# | Instrukce | Operandy | Výsledek | Operace |
---|---|---|---|---|
1 | MUL | 32bit×32bit | 32bit | násobení |
2 | MAL | 32bit×32bit | 32bit | násobení a přičtení výsledku (Multiply and Accumulate) |
3 | MLS | 32bit×32bit | 32bit | násobení a odečtení výsledku (Multiply and Subtract) |
4 | SMULL | 32bit×32bit | 64bit | násobení hodnot se znaménkem |
5 | SMLAL | 32bit×32bit | 64bit | Multiply and Accumulate |
6 | UMULL | 32bit×32bit | 64bit | násobení hodnot bez znaménka |
7 | UMLAL | 32bit×32bit | 64bit | Multiply and Accumulate |
3. Instrukce SDIV a UDIV
Na rozdíl od jednodušších jader Cortex-M0 a Cortex-M0+ se u jader Cortex-M3 setkáme se i s hardwarovou děličkou. Ta však pracuje relativně pomalu, protože operace dělení je v závislosti na konkrétních hodnotách operandů dokončena ve dvou až šestnácti cyklech (a je přerušitelná, viz též další kapitolu):
# | Instrukce | Operandy | Výsledek | Operace |
---|---|---|---|---|
1 | SDIV | 32bit×32bit | 32bit | operace dělení hodnot se znaménkem |
2 | UDIV | 32bit×32bit | 32bit | operace dělení hodnot bez znaménka |
Mimochodem, absence hardwarové děličky je u mnoha jader řady Cortex-M a dokonce i Cortex-A poměrně běžná, což nám názorně přibližuje následující tabulka:
# | Jádro | DIV (Thumb) | DIV (A32) |
---|---|---|---|
1 | Cortex-M0 | ne | nedostupné |
2 | Cortex-M0+ | ne | nedostupné |
3 | Cortex-M1 | ne | nedostupné |
4 | Cortex-M3 | ano | nedostupné |
5 | Cortex-M4 | ano | nedostupné |
6 | Cortex-R4 | ano | ne |
7 | Cortex-R5 | ano | jen s registrem r1 |
8 | Cortex-R7 | ano | ano |
9 | Cortex-A5 | ne | ne |
10 | Cortex-A7 | ano | ano |
11 | Cortex-A8 | ne | ne |
12 | Cortex-A9 | ne | ne |
13 | Cortex-A15 | ano | ano |
14 | Cortex-A53 | ano | ano |
15 | Cortex-A57 | ano | ano |
4. Přerušení běhu instrukcí LDM, STM, PUSH, POP atd.
Instrukční sada Thumb obsahuje i instrukce typu LDM a STM, pomocí nichž je možné uložit či naopak načíst celou řadu vybraných pracovních registrů, nikoli pouze registr jediný. Pro seznam registrů platí některá omezení, například že adresa pro ukládání či načítání nesmí být specifikována v registru PC, seznam ukládaných/načítaných registrů nesmí obsahovat SP, u STM nesmí seznam obsahovat ani PC a u LDM nesmí obsahovat PC v případě, že obsahuje LR (tato pravidla jsou však vcelku pochopitelná, když si uvědomíme, jak RISCový procesor uvnitř pracuje). Druhým typem instrukcí určených pro současný přenos dat do/z většího počtu registrů jsou instrukce typu PUSH a POP, které mohou v případě instrukční sady Thumb pracovat nikoli pouze s jediným registrem, ale s libovolnou kombinací (ve skutečnosti jsou PUSH a POP pouze často používaným aliasem pro jednu z variant instrukcí LDM a STM).
O těchto instrukcích se explicitně zmiňuji především z toho důvodu, že v případě příchodu přerušení či výjimky musí procesor co nejdříve pozastavit běh hlavního programu a umožnit spuštění rutiny pro obsluhu přerušení/výjimky. Pro mnoho aplikací, v nichž se používají mikrořadiče, je však neakceptovatelné čekat tak dlouho, až se dokončí výše zmíněné instrukce (či taktéž dlouhotrvající operace dělení UDIV a SDIV). To ve skutečnosti ani není zapotřebí, protože tyto operace jsou přerušitelné, takže se na přerušení reaguje s velmi nízkou latencí (1–2 takty). Tato jádra navíc podporují i takzvaný tail-chaining, který urychluje zpracování většího množství výjimek (vynechá se operace se zásobníkem na konci rutiny).
5. Instrukční sada Thumb-2
V úvodních kapitolách jsme si řekli, že procesorová jádra řady Cortex-M3 podporují kromě 16bitové instrukční sady Thumb i instrukční sadu Thumb-2. Na základě zveřejněných měření se ukazuje, že díky použití Thumb-2 se na jedné straně dosahuje jak velké hustoty kódu (code density), tak i velkého výpočetního výkonu. Thumb-2 sice může vypadat problematicky (nejedná se o čistý RISC), ovšem sami konstruktéři mikroprocesorů ARM se vyjádřili k tomu, z jakého důvodu vlastně instrukční sada Thumb-2 vznikla. Při jejím návrhu měli na mysli čtyři parametry, které se navzájem ovlivňují a vylepšení jednoho z parametrů většinou v důsledku vede ke zhoršení zbývajících třech parametrů. Jedná se o následující parametry:
- Cenu vlastního procesoru, která je kromě jiných okolností ovlivněna i jeho složitostí (existence branch prediktorů, spekulativního provádění instrukcí, …), počtem aritmeticko-logických jednotek (obecně zda jde o skalární či superskalární procesor), velikostí potřebných vyrovnávacích pamětí atd.
- Dosahovaný výpočetní výkon v reálných aplikacích. V praxi to znamená, že hodnota udávaná v jednotkách MIPS nebo MFLOPS nemusí být vždy směrodatná: je to právě příklad jednodušších instrukcí Thumb v porovnání s obecně výkonnějšími instrukcemi ARM.
- Nutný energetický příkon procesoru (závisí na technologii výroby, napájecím napětí, hodinové frekvenci, počtu ALU, velikosti vyrovnávacích paměti, struktuře pipeline, dekódovací tabulky atd.).
- Cenu za vývoj a optimalizaci aplikací (tu ovlivňuje složitost instrukční sady, nedostatky v instrukční sadě: například nutnost provádění neefektivních skoků, složitost při načítání konstant do pracovních registrů atd.).
Za povšimnutí stojí především skutečnost, že snaha o vylepšení jednoho parametru skutečně ve většině případů vede ke zhoršení ostatních parametrů. Například zvýšení výpočetního výkonu pomocí větších vyrovnávacích pamětích ovlivní jak cenu mikroprocesoru, tak i energetický příkon atd. Zajímavý je ale především význam posledního parametru: cena za vývoj a optimalizaci aplikací. Při zavádění instrukční sady Thumb (zde bez dvojky) se totiž předpokládalo, že většina kódu bude překládána právě do této sady, což zmenší počet výpadků vyrovnávacích pamětí pro srovnatelný program (binární kód), a jen přibližně deset procent kritických částí kódu bude napsáno s využitím instrukcí ARM (jedná se tedy o aplikaci známého pravidla 90:10 či 80:20). To sice může na první pohled velmi dobře fungovat, ovšem zjištění, které jsou vlastně ony kritické části kódu, se muselo mnohdy provádět až v pozdních fázích vývoje, což vedlo mj. i k rostoucí ceně za vývoj (i když popravdě řečeno se to týká skutečně oněch částí kódu, s nimiž si někdo dal tu práci a optimalizoval je ručně s využitím výsledků získaných například z profileru).
Navíc není přepínání mezi instrukcemi ARM a Thumb zcela „zadarmo“, což poněkud zmenšuje možnosti neustálého přepínání, takže se hledal způsob, jak stávající stav ještě vylepšit. Výsledkem této snahy je instrukční sada nazvaná Thumb-2. Její vznik byl umožněn postupným vylepšováním technologie výroby integrovaných obvodů (zjednodušeně řečeno tím, že bylo možné na čipu implementovat větší množství tranzistorů bez razantního nárůstu ceny a/nebo spotřeby) a navíc byl „vynucen“ tím, že se stále zvětšoval rozdíl mezi rychlostí mikroprocesorů a dobou přístupu k pamětem DRAM či u mikrořadičů do Flash ROM. Cílem tedy byl menší binární kód (instrukce s větší hustotou) a současně stále dobrá výkonnost dosažená tím, že ne všechny instrukce Thumb-2 jsou tak jednoduché či jednoúčelové, jako instrukce Thumb.
Důvodů pro vznik nové instrukční sady tedy bylo více než dost, takže se podívejme na to, co se jejím tvůrcům podařilo splnit a co nikoli. V následujícím textu budou uvedeny výsledky měření prezentované samotnou společností ARM (takže je nutné je brát s rezervou :-). V první tabulce je porovnána „hustota“ binárního strojového kódu měřená jeho délkou. Ve všech případech se jednalo o stejný algoritmus, který byl poprvé implementován s využitím instrukční sady ARM, podruhé s pomocí sady Thumb a potřetí byla použita instrukční sada Thumb-2. Za základ je přitom brána délka původního kódu používajícího instrukce ARM (tento kód odpovídá sto procentům, čím menší číslo, tím menší je i výsledný binární program a tím lepší je využití I-cache či rychlejší přístup do Flash ROM):
Instrukční sada | Délka kódu |
---|---|
ARM | 100% |
Thumb | 70% |
Thumb-2 | 74% |
Ve druhé tabulce je uveden relativní výpočetní výkon přeloženého binárního programu, přičemž 100% odpovídá nejrychlejší implementaci a 75% implementaci nejpomalejší:
Instrukční sada | Relativní výpočetní výkon |
---|---|
ARM | 100% |
Thumb | 75% |
Thumb-2 | 98% |
Z výsledků, které jsou prezentovány v předešlých dvou tabulkách tedy vyplývá, že pro testovanou aplikaci se díky použití instrukční sady Thumb-2 podařilo zmenšit velikost kódu na tři čtvrtiny původní velikosti a přitom výpočetní výkon poklesl pouze o zhruba 2% (zde se samozřejmě projevila i nižší pravděpodobnost výpadku instrukční cache, která ovšem byla nižší i u implementace využívající instrukce Thumb).
Poznámka: jako u všech podobných měření je samozřejmě nutné mít na paměti, že se jedná pouze o (reprezentativní) vzorek, který může ale taktéž nemusí odpovídat jinému typu algoritmu. Vždy záleží jen na konkrétní aplikaci, konkrétním vývojáři, jeho rozpočtu a času, zda si podobné měření udělá i v případě jím vyvíjené aplikace, nebo zda se spolehne na cizí statistiku :-) (to ovšem platí i pro výběr procesoru: opět záleží na mnoha okolnostech, včetně dosavadních zkušeností vývojáře, ceně za vývojové nástroje atd.).
6. Podmínky v instrukcích (CBZ, CBNZ)
Jednou z předností instrukční sady Thumb-2 je zavedení nových instrukcí umožňujících v programovém kódu implementovat podmínky. Ty se totiž v mnoha případech ukazují být kritickou částí kódu, protože zejména podmíněné skoky mohou přerušit jinak plynulý tok zpracovávaných instrukcí, takže se z ideálního stavu, kdy RISCové jádro díky existenci pipeline dokončí v každém cyklu jednu instrukci (v případě superskalárních čipů Cortex-A i více instrukcí) můžeme dostat do stavu, kdy podmíněný skok způsobí nutnost přerušit již zpracovávané instrukce a začít znovu (samozřejmě s latencí).
Při analýze reálných aplikací si tvůrci instrukční sady Thumb-2 všimli si, že se v programech velmi často vyskytuje sekvence instrukcí, které nejdřív porovnají obsah vybraného pracovního registru s nulou a posléze provedou podmíněný skok na základě toho, zda je onen pracovní registr skutečně nulový nebo naopak nenulový. Poměrně velké frekvenci této sekvence instrukcí se nelze ani divit, protože podobným způsobem mohou být implementovány například testy na hodnotu NULL, počítané smyčky, smyčky typu do-while v nichž je pravdivostní hodnota vyjádřena celým číslem, práce s ASCIIZ řetězci atd. Aby bylo možné zmenšit velikost binárního kódu programu a současně ho i urychlit, byly do instrukční sady Thumb-2 přidány dvě nové instrukce, které nejprve provedou porovnání pracovního registru s nulou a poté provedou skok, pokud je registr nulový či naopak není nulový. Součástí instrukčního slova je přitom i krátký offset umožňující provést skok do vzdálenosti PC+4 až PC+130.
První z těchto instrukcí provede skok, pokud je vybraný pracovní registr nulový:
CBZ Rn, offset ; compare and branch if zero
Tato instrukce je ekvivalentní delší sekvenci:
CMP Rn, #0 BEQ label
Druhá instrukce provádí skok v přesně opačném případě, tj. tehdy, když má registr nenulovou hodnotu:
CBNZ Rn, offset ; compare and branch if non zero
Ekvivalentní zápis:
CMP Rn, #0 BNE label
7. Prefix IT aneb řešení mnoha problémů s podmíněnými skoky
Tvůrci instrukční sady Thumb-2 se taktéž snažili nějakým způsobem nahradit kdysi populární kombinaci příznakových bitů, které byly součástí většiny instrukcí klasické RISCové instrukční sady A32. Z tohoto důvodu do Thumb-2 přidali jednu z nejzajímavějších instrukcí, které kdy pro RISCové mikroprocesory vznikly. Jedná se vlastně o instrukční prefix nazvaný IT podle sousloví if-then. Tento prefix může být aplikován na jednu až čtyři instrukce následující za prefixem. Ihned za prefixem IT se (bez mezery) udává, zda má být daná instrukce provedena při splnění podmínky (T – then) či naopak při jejím nesplnění (E – else). U první instrukce je automaticky předpokládáno T, tudíž se uvádí maximálně tři kombinace znaků T/E. Samozřejmě je taktéž nutné zapsat i testovanou podmínku – může se jednat o kódy používané jak u podmíněných skoků, tak i v podmínkových bitech:
Kód | Význam | Předchozí operace porovnání |
---|---|---|
EQ | Z==1 (rovno) | signed i unsigned |
NE | Z==0 (nerovno) | signed i unsigned |
CS | C==1 (větší nebo rovno) | unsigned |
CC | C==0 (menší než) | unsigned |
MI | N==1 (záporný výsledek) | signed |
PL | N==0 (kladný nebo nulový výsledek) | signed |
VS | V==1 (přetečení) | signed |
VC | V==0 (nedošlo k přetečení) | signed |
HI | C==1 & Z==0 (vetší než) | unsigned |
LS | C==0 | Z==1 (menší nebo rovno) | unsigned |
GE | N==V (větší nebo rovno) | signed |
LT | N!=V (menší než) | signed |
GT | Z==0 & N==V (větší než) | signed |
LE | Z==1 N!=V (menší nebo rovno) | signed |
V praxi to může znamenat, že zápis:
ITEEE EQ
značí, že pokud je nastaven příznak zero (rovnost), je provedena jen první instrukce následující za prefixem, kdežto další tři instrukce nebudou provedeny (třikrát „else“).
Pokud by se měly provést tři instrukce v případě kladného výsledku předchozího porovnání, použil by se zápis:
ITTT PL
Porovnejme si nyní tři identické algoritmy. První z nich je implementovaný s využitím instrukcí A32 s podmínkovými bity:
LDREQ r0,[r1] ; if EQ then LDR LDRNE r0,[r2] ; if NE then LDR ADDEQ r0, r3, r0 ; if EQ then ADD ADDNE r0, r4, r0 ; if NE then ADD
V případě použití instrukční sady Thumb musíme využít podmíněné skoky se všemi nepříjemnostmi, které z toho plynou:
BNE L1 ; opačná podmínka - přeskočení instrukce LDR r0, [r1] ADD r0, r3, r0 ; máme štěstí: můžeme prohodit pořadí instrukcí B L2 L1 LDR r0, [r2] ADD r0, r4, r0 L2
U instrukční sady Thumb-2 lze v tomto případu s výhodou použít prefixovou instrukci IT:
ITETE EQ LDR r0, [r1] LDR r0, [r2] ADD r0, r3, r0 ADD r0, r4, r0
Na závěr si ještě všechny tři implementace pro zajímavost porovnáme, a to jak z hlediska velikosti programového kódu, tak i z hlediska celkové doby trvání výpočtu:
Instrukční sada | Velikost kódu | Počet cyklů |
---|---|---|
ARM (RISC) | 16 bajtů | 4 cykly |
Thumb | 12 bajtů | 4–20 cyklů |
Thumb-2 | 10 bajtů | 4–5 cyklů |
Výsledek: pokud máme kvalitní překladač, bude instrukční sada Thumb-2 s velkou pravděpodobností lepší, než snaha o implementaci A32. Tento rozdíl bude ještě více patrný na mikrořadičích a tedy i jádrech Cortex-M3, protože zde může být program uložen v relativně pomalé Flash ROM.
8. Bitové operace (Booleovský procesor)
V oblasti mikrořadičů se již od dob slavného čipu Intel 8051 (MCS-51) můžeme setkat s implementací takzvaného Booleovského procesoru. Tímto poněkud nadneseným jménem se označuje sada instrukcí, které dokážou pracovat na úrovni jednotlivých bitů a nikoli celých slov, a to (většinou) dokonce takovým způsobem, že i přístup do paměti či do řídicích registrů periferních zařízení je prováděn po jednom bitu (například negace jediného bitu je rozdílná operace od přečtení bajtu/slova do akumulátoru, negace vybraného bitu a zápis celého bajtu/slova zpět). Jen pro zajímavost: na již zmíněném mikrořadiči MCS-51 je implementován úplný Booleovský procesor s jednobitovým akumulátorem (tím je příznak C/carry), 128 bitovou oblastí RAM a 128 bitovou oblastí speciálních řídicích registrů (SFR). Tento Booleovský procesor měl k dispozici sedmnáct instrukcí:
# | Operace | S příznakem C | S bitem v RAM či SFR |
---|---|---|---|
1 | Vynulování bitu | CLR C | CLR bit |
2 | Nastavení bitu | SETB C | SETB bit |
3 | Negace bitu | CPL C | CPL bit |
4 | Logický součin | ANL C,bit ANL C,/bit | |
5 | Logický součet | ORL C,bit ORL C,/bit | |
6 | Přesun bitu | MOV C,bit | MOV bit,C |
7 | Skok při bit=1 | JC | JB |
8 | Skok při bit=0 | JNC | JNB |
9 | Skok + vynulování | JBC |
9. Booleovský procesor implementovaný v jádrech Cortex-M3
Nyní nám již zbývá popsat, jakým způsobem je Booleovský procesor implementován na jádrech Cortex-M3. Tvůrci zvolili odlišný přístup, než tomu bylo v případě mikrořadiče 8051: namísto použití speciálních instrukcí pro manipulaci s jednotlivými bity nedošlo ke změně instrukční sady, ale k vyhrazení několika paměťových regionů, k nimž se přistupuje po bitech. Tyto regiony leží na adresách 0×20000000–0×200FFFFF a 0×40000000–0×400FFFFF. Jak je ze zadaného rozsahu patrné, má každý region velikost 1MB. Pro tento jeden megabajt existují adresové aliasy 0×22000000–0×23FFFFFF a 0×42000000–0×43FFFFFF. Ty mají zdánlivou velikost 32MB, ovšem jen z toho důvodu, že při čtení slova se ve skutečnosti přečte pouze jediný bit, takže se do registru načte hodnota 0×00000000 nebo 0×00000001. Při zápisu se naopak zapisuje pouze nejnižší bit uložený v registru, takže hodnota 0×00000000, 0×FFFFFFFE či 0×44444444 má stejný význam, stejně jako hodnoty 0×00000001, 0×FFFFFFFF atd. Jednotka pro přístup do paměti automaticky přepočte zadanou aliasovou adresu 0×22000000–0×23FFFFFF na reálnou adresu 0×20000000–0×200FFFFF a provede zápis či čtení jediného bitu.
Poznámka: ve skutečnosti je první paměťový region uložen v SRAM (a to hned na jejím začátku), kdežto druhý region je mapován do oblasti periferních zařízení. Opět se zde reflektuje situace mikrořadiče 8051, kde bylo provedeno totéž rozdělení, ovšem v mnohem menším měřítku (128 bitů SRAM a 128 bitů pro periferní zařízení versus 1 MB SRAM a 1 MB pro periferní zařízení). Další zajímavostí je fakt, že operace čtení či zápisu bitů jsou atomické a nepřerušitelné.
10. Jednotka MPU
Mezi další zajímavé prvky, kterými mohou být jádra Cortex-M3 doplněny, patří jednotka MPU neboli Memory Protection Unit. Tato jednotka neslouží k virtualizaci paměti (jako MMU), ale „pouze“ k definování až osmi paměťových regionů, u nichž lze nastavovat různá práva, zejména právo XN (Execute Never, zákaz spouštění kódu z daného regionu). Zajímavé je, že se tyto regiony dokonce mohou překrývat, v tomto případě se práva převezmou z nastavení regionu s vyšším indexem (0–7). Kromě práv je možné nastavit, zda se daná oblast má sdílet s dalšími jádry (což u většiny implementací Cortex-M3 bude postrádat význam) a zda mají být zápisy do paměti provedeny vždy v takovém pořadí, jak to odpovídá sekvenci instrukcí (to má význam především při komunikaci s periferními zařízeními).
11. Procesory Atmel založené na technologii ARM
Nastal čas podívat se na nějaký reálný mikrořadič či SoC založený na technologii Cortex-M3. Aby to bylo zajímavější, zaměříme se na čipy SAM3× vyráběné firmou Atmel. Proč se jedná o zajímavé téma? Společnou Atmel totiž některými svými dalšími čipy, zejména pak řadou AVR32, vlastně ARMovským jádrům poměrně zdárně konkuruje, nicméně ani to jí nezabraňuje, aby dokázala realizovat jedny z nejlepších integrovaných obvodů s jádrem Cortex-M3. Má to vlastně svoji logiku, protože Atmel vyniká i v implementaci periferních zařízení, které jsou pro mikrořadiče většinou nezbytné. Kombinací jádra Cortex-M3 a periferií od Atmelu (A/D převodníky, USART, SPI, CAN, I2C atd.) tak zákazníci dostávají k dispozici velmi zajímavý čip, který je navíc navržen takovým způsobem, aby jednotlivé periferie spolu dokázaly komunikovat přímo a nechat tak procesor v režimu sleep. Čipy SAM3× za sebou mají relativně dlouhý vývoj, což je patrné i z následující tabulky:
# | Čip | Rok uvedení do výroby |
---|---|---|
1 | SAM3U | 2009 |
2 | SAM3S | 2009 |
3 | SAM3N | 2010 |
4 | SAM3A | 2012 |
5 | SAM3X | 2012 |
Například na čipu Atmel SAM3X8E s hodinovou frekvencí 84 MHz použitém v populárním Arduinu Due kromě jádra Cortex-M3 nalezneme i:
- 2 × 256 kB Flash ROM
- 64 + 32 kB SRAM
- 16 kB ROM (obsahuje především bootloader rutiny pro UART a USB)
- 54 I/O pinů (12 z nich vyhrazeno pro PWM)
- 16 kanálový ADC (12 bitů), jeden rezervován pro vnitřní senzor teploty
- 2 DAC (taktéž 12bitů)
- 3× USART
- 9 kanálový 32bitový čítač
- 2 TWI (Two Wire Interface, varianta I2C)
- USB Device/Mini host
- Ethernet MAC 10/100 + podpora pro přenos dat přes DMA (to je důležité, viz problémy s Raspberry)
- True Random Number Generator (TRNG), dokáže každých 32 taktů vrátit 32bitové náhodné(?) číslo
Tento čip je použit i v počítači UDOO, s nímž se seznámíme někdy příště.
12. Odkazy na Internetu
- A tour of the Cortex-M3 core:
http://community.arm.com/groups/processors/blog/2013/11/04/a-tour-of-the-cortex-m3-core - Five things you may not know about ARM Cortex-M:
http://community.arm.com/docs/DOC-6912 - Divide and Conquer:
http://community.arm.com/docs/DOC-8059 - MCU market turns to 32-bits and ARM
http://www.eetimes.com/document.asp?doc_id=1280803 - Cortex-M0 Processor (ARM Holdings)
http://www.arm.com/products/processors/cortex-m/cortex-m0.php - Cortex-M0+ Processor (ARM Holdings)
http://www.arm.com/products/processors/cortex-m/cortex-m0plus.php - ARM Processors in a Mixed Signal World
http://www.eeweb.com/blog/arm/arm-processors-in-a-mixed-signal-world - ARM Architecture (Wikipedia)
https://en.wikipedia.org/wiki/ARM_architecture - Cortex-M0 (Wikipedia)
https://en.wikipedia.org/wiki/ARM_Cortex-M0 - Cortex-M0+ (Wikipedia)
https://en.wikipedia.org/wiki/ARM_Cortex-M#Cortex-M0.2B - Improving ARM Code Density and Performance
New Thumb Extensions to the ARM Architecture Richard Phelan - The ARM Processor Architecture
http://www.arm.com/products/processors/technologies/instruction-set-architectures.php - Thumb-2 instruction set
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344c/Beiiegaf.html - Introduction to ARM thumb
http://www.eetimes.com/discussion/other/4024632/Introduction-to-ARM-thumb - ARM, Thumb, and ThumbEE instruction sets
http://www.keil.com/support/man/docs/armasm/armasm_CEGBEIJB.htm - An Introduction to ARM Assembly Language
http://dev.emcelettronica.com/introduction-to-arm-assembly-language - Processors – ARM
http://www.arm.com/products/processors/index.php - The ARM Instruction Set
http://simplemachines.it/doc/arm_inst.pdf