Obsah
1. Architektura mikrořadičů s jádry ARM Cortex-M4
2. Rozdíly mezi jádry Cortex-M
3. Segmenty trhu, pro něž jsou jednotlivá jádra Cortex-M určena
4. Nejdůležitější vlastnosti mikrořadičových jader Cortex-M4
5. Instrukční sada jader Cortex-M4
7. Instrukce orientované na zpracování signálu
8. Sčítání a odečítání se saturací
12. Operace podporované matematickým koprocesorem
13. Operace ze standardu IEEE 754, které nejsou implementovány
1. Architektura mikrořadičů s jádry ARM Cortex-M4
V předchozí čtveřici článků o ARMovských (a tedy RISCových) mikrořadičových jádrech Cortex-M jsme si již popsali vlastnosti (v současnosti) nejmenších a energeticky nejméně náročných jader řady Cortex-M0 a Cortex-M0+ [1], základní vlastnosti výkonnějších jader Cortex-M3 [2], zabývali jsme se i nejvýkonnějšími jádry Cortex-M7 [3] a dokonce jsme si i popsali, v jakých aplikačních oblastech a čipech se tato mikroprocesorová jádra používají v praxi [4]. Jediná dvě „mikrořadičová“ jádra, kterými jsme se doposud podrobněji nezabývali, jsou jádra řady Cortex-M1, která dnes nachází uplatnění pouze v FPGA (a budeme se jimi zabývat v odlišně zaměřeném seriálu), a taktéž jádra řady Cortex-M4, jejichž možnosti leží na pomezí mezi řadou Cortex-M3 a Cortex-M7.
V dnešním článku tedy téma mikrořadičových RISCových jader Cortex-M uzavřeme, protože si popíšeme základní vlastnosti obvodů řady Cortex-M4 (jednodušší, levnější a energeticky méně náročná varianta) i jader Cortex-M4F (pod tímto označením nalezneme mikrořadičová jádra obsahující kromě celočíselné aritmeticko-logické jednotky i matematický koprocesor zpracovávající numerické údaje ve formátu single/float). Tato jádra se uplatní zejména v těch oblastech, kde se zpracovává číslicový signál, protože na čipech s jádry Cortex-M4 lze používat i instrukce pro sčítání a odčítání se saturací, je zde použita rychlá násobička a v případě potřeby lze zvolit mikrořadič obsahující již zmíněný matematický koprocesor.
2. Rozdíly mezi jádry Cortex-M
Vzhledem k tomu, že v tomto článku dokončíme popis všech typů procesorových (resp. přesněji řečeno mikrořadičových) jader Cortex-M, nebude na škodu si zopakovat, čím se vlastně jednotlivá „emková“ jádra od sebe odlišují. Zaměříme se především na vlastnosti samotných procesorových jednotek (CPU) a nikoli na vlastnosti periferních zařízení, protože je logické, že například minimalistická jádra Cortex-M0 a Cortex-M0+ budou v naprosté většině aplikací vybavena jen relativně malým množstvím podpůrných jednotek v porovnání s většími jádry Cortex-M7. V první tabulce jsou jednotlivá jádra všech řad Cortex-M rozdělena podle toho, do jaké architektury ARM spadají. Povšimněte si, že menší jádra používají starší, ale stále oblíbenou architekturu ARMv6-M, zatímco ta nejvýkonnější jádra přešla na novější architekturu ARMv7E-M. Na pomezí pak stojí minule popsaná jádra Cortex-M3 s architekturou ARMv7-M:
# | Jádro (řada) | Architektura ARM | Architektura CPU/MCU |
---|---|---|---|
1 | Cortex-M0 | ARMv6-M | Von Neumannova |
2 | Cortex-M0+ | ARMv6-M | Von Neumannova |
3 | Cortex-M1 | ARMv6-M | Von Neumannova |
4 | Cortex-M3 | ARMv7-M | Harvardská |
5 | Cortex-M4 | ARMv7E-M | Harvardská |
6 | Cortex-M7 | ARMv7E-M | Harvardská |
Při pohledu na druhou tabulku se dozvíme, kolik řezů mají pipeline v jednotlivých jádrech a taktéž kolik vstupů přerušení je možné maximálně obsloužit. Na tomto místě stojí za připomenutí, že větší počet řezů v RISCových procesorech na jednu stranu může zvýšit jejich výpočetní výkon (zvětšení frekvence), na stranu druhou však zvětšuje plochu samotného CPU, reakce na přerušení se musí řešit složitějším způsobem (u některých čipů dosahuje latence reakce na přerušení až 12 cyklů) a taktéž se při špatné predikci skoků může zhoršit celkový výkon. U jader Cortex-M je patrné, že se designéři snažili o vybalancování všech veličin a vlastností (právě z tohoto důvodu se například dnes namísto papírově výkonnějších jader Cortex-M0 používají jádra Cortex-M0+ s jednodušší strukturou pipeline):
# | Jádro | Pipeline | Přerušení |
---|---|---|---|
1 | Cortex-M0 | 3 řezy | 1–32 + NMI |
2 | Cortex-M0+ | 2 řezy | 1–32 + NMI |
3 | Cortex-M1 | 3 řezy | 1–32 + NMI |
4 | Cortex-M3 | 3 řezy | 1–240 + NMI |
5 | Cortex-M4 | 3 řezy | 1–240 + NMI |
6 | Cortex-M7 | 6 řezů | 1–240 + NMI |
V poslední tabulce jsou shrnuty vlastnosti instrukčních sad, které si sice jsou v některých ohledech velmi podobné (například absencí původních 32bitových „RISCových“ instrukcí ARM), ovšem je patrné, že některé vlastnosti jsou dostupné až u větších, výkonnějších a nutno říci, že taktéž energeticky náročnějších jader:
# | Jádro | Instrukční sada | HW násobička | HW dělička | Sat.ADD/SUB | DSP | FPU |
---|---|---|---|---|---|---|---|
1 | Cortex-M0 | Thumb | 32bit | ne | ne | ne | ne |
2 | Cortex-M0+ | Thumb | 32bit | ne | ne | ne | ne |
3 | Cortex-M1 | Thumb | 32bit | ne | ne | ne | ne |
4 | Cortex-M3 | Thumb+Thumb2 | 32/64bit | ano | ano | ne | ne |
5 | Cortex-M4 | Thumb+Thumb2 | 32/64bit | ano | ano | ano | opt |
6 | Cortex-M7 | Thumb+Thumb2 | 32/64bit | ano | ano | ano | opt |
Poznámky k předchozí tabulce:
- Jádra Cortex-M0/M0+/M1 obsahují většinu instrukcí Thumb kromě trojice instrukcí CBZ, CBNZ a prefixu IT. Taktéž obsahují šest vybraných instrukcí ze sady Thumb-2.
- Ve sloupci „HW násobička“ je napsáno, zda je výsledek násobení dvou 32bitových čísel taktéž 32bitový (spodní polovina výsledku) či 64bitový. U některých čipů lze zvolit, zda je násobička sériová (pomalý výpočet, malá plocha čipu, malá spotřeba) či paralelní (rychlý výpočet, ovšem na úkor větší plochy čipy a taktéž vyšší spotřeby).
3. Segmenty trhu, pro něž jsou jednotlivá jádra Cortex-M určena
Typické použití mikrořadičových jader je zobrazeno na diagramu, který je dostupný na adrese http://www.arm.com/assets/images/tpl/compare-Cortex-M-diagramLG.png. Zkusme si toto rozdělení shrnout v několika větách:
- Jádro Cortex-M0 tvoří základ pro čipy, u nichž je žádoucí dosáhnout co nejnižší výrobní ceny, malých rozměrů a především pak malého příkonu (s tím samozřejmě souvisí i příslušně nízký výpočetní výkon, ovšem možnost dlouhodobě provozovat stále relativně výkonný čip z baterie je jistě lákavá). Tato jádra by měla postupně nahrazovat některé aplikace, v nichž se nyní používají osmibitové či šestnáctibitové mikrořadiče (PIC, řada 8051, 68HC11/68HC12 atd.). Malé plochy čipu se inženýrům ze společnosti ARM skutečně podařilo dosáhnout, protože nejmenší vyráběný integrovaný obvod s jádrem Cortex-M0 má plochu přibližně 1,6×2 mm.
- Na mikrořadiče s jádry Cortex-M0+ se z pohledu programátora můžeme dívat jako na pouhá vylepšení původních jader Cortex-M0. Interně se ovšem jedná o odlišně navržená jádra, protože Cortex-M0+ obsahuje pipeline pouze se dvěma řezy a nikoli s řezy třemi (vlastně se tak vracíme na samotný začátek platformy ARM, což však u takto malých čipů má význam). Co je však pro případné uživatele důležitější – i díky zmenšenému počtu řezů pipeline se podařilo dále snížit spotřebu a přitom zachovat obousměrnou kompatibilitu s původními jádry Cortex-M0.
- 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 či mikrořadiče 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, samotné jádro rozdělení umožňuje). 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“, aby se zajistil okamžitý zápis do GPIO apod.).
- Mikrořadiče s jádry Cortex-M4 jsou popsány v navazující kapitole.
- Mikrořadičová jádra, která nesou označení Cortex-M7, jsou založena na architektuře ARMv7E-M, na rozdíl od čipů Cortex-M0/Cortex-M0+ s jednodušší architekturou ARMv6-M či Cortex-M3 s architekturou ARMv7-M. Tato jádra jsou podporována paměťovým subsystémem s cache i se zápisovým bufferem, používá se u nich matematický koprocesor, který může podporovat jak operace s operandy typu single/float, tak i s operandy typu double (což je v této aplikační oblasti poněkud neobvyklé) a podporovány jsou samozřejmě i operace používané při zpracování digitálního signálu, tj. například sčítání se saturací apod.
4. Nejdůležitější vlastnosti mikrořadičových jader Cortex-M4
Mikroprocesory a mikrořadiče s jádry Cortex-M4 jsou určeny pro ty aplikační oblasti, v nichž je vyžadováno zpracování digitálního signálu (může se jednat o osmibitové, šestnáctibitové či dokonce o 32bitové vzorky) popř. práce s daty uloženými v systému plovoucí řádové čárky (float/single). V těchto oblastech totiž již možnosti menších jader Cortex-M3 přestávají stačit a na druhou stranu jádra Cortex-M7 mohou být zbytečně drahá a/nebo mít zbytečně velké energetické nároky. Pokud je ovšem vyžadováno zpracování numerických hodnot typu double (tj. čísel s plovoucí řádovou čárkou s takzvanou dvojitou přesností), je nutné použít čipy s jádrem Cortex-M7 nebo se spokojit se softwarovou implementací všech operací s čísly typu double. Opět zde tedy můžeme vidět snahu o vybalancování vlastností se spotřebou a cenou.
Mezi další vlastnosti Cortex-M4 patří:
- Podpora pro bit-banding, tj. pro přístup k jednotlivým bitům jednoho či dvou regionů paměti. Jedná se o vylepšenou podporu Booleovského procesoru známého z řady mikrořadičů Intel 8051 (které dnes vyrábí snad prakticky všichni významní výrobci polovodičových součástek kromě Intelu :-).
- Volitelně je možné použít jednotku pro správu paměti (MPU – Memory Protection Unit). Paměť může být rozdělena do regionů s volitelnými právy přístupu (teoreticky tak lze realizovat i virtuální paměť, což však v aplikační oblasti Cortex-M4 asi nemá význam).
- Lze použít i write buffer (pro jedno zapisované slovo), čímž se zajistí, že poslední řez pipeline nebude muset čekat na skutečný zápis dat do paměti.
- Volitelně je k dispozici modul zajišťující použití konfigurovatelných watchpointů (watchpoint jde dokonce nastavit i na časovač či PC).
- Hned několik volitelných modulů je určeno pro ladění: ITM (rozhraní pro připojení čipu k počítači, kde běží debugger), FPB (Flash path and Breakpoint unit) a AHB-AP (zajišťuje ladicím prostředkům přístup do operační paměti, k řídicím registrům a dokonce i k registrům samotného CPU).
5. Instrukční sada jader Cortex-M4
Základní instrukce zpracovávané jádry Cortex-M4 jsou shodné s čipy Cortex-M3 i Cortex-M7, protože je podporována jak instrukční sada Thumb s šestnáctibitovými operačními kódy, tak i instrukční sada Thumb-2, v níž kromě šestnáctibitových operačních kódů nalezneme i instrukce s 32bitovým slovem. Naproti tomu původní „čistě RISCová“ 32bitová instrukční sada ARM podporována není. Tato vlastnost však platí pro celou řadu Cortex-M, takže to pro nás pravděpodobně nebude příliš překvapivé. Ovšem v oblasti zpracování číslicových signálů je nutné, aby aritmeticko-logická jednotka podporovala kromě základních aritmetických instrukcí s 32bitovými operandy i další instrukce, zejména pak sčítání a odčítání se saturací či mnoho kombinací násobení dvou operandů. I tyto instrukce jádra Cortex-M4 dokážou zpracovat, o čemž se ostatně přesvědčíme v navazujících kapitolách.
6. Základní instrukce
Vzhledem k tomu, že instrukční sady Thumb a Thumb-2 jsou navrženy zejména s ohledem na dosažení vysoké hustoty výsledného strojového kódu a méně už s ohledem na eleganci či dokonce ortogonalitu, je instrukční sada v porovnání s původní RISCovou instrukční sadou (dnes pro odlišení nazývanou ARM32) značně odlišná; najdeme zde mnoho ad-hoc instrukcí i některé instrukce, které už nejsou čistě RISCové. To se týká zejména prefixu IT{podmínka} a taktéž instrukcí určených pro načtení či uložení většího množství registrů LDM a STM. Význam některých méně obvyklých instrukcí bude vysvětlen v poznámkách:
Prováděná operace | Instrukce patřící do skupiny |
---|---|
Přesuny dat | MOV, MNV, MOVW, MOVT, MRS, BSR |
Konverze dat | SXTB, SXTH, UXTB, UXTH |
Součet (celočíselný) | ADD, ADC, ADR |
Rozdíl (celočíselný) | SUB, SBC, RSB |
Součin (celočíselný) | MUL, MLA, MLS, SMULL, UMULL, SMLAL, UMLAL |
Podíl (celočíselný) | SDIV, UDIV |
Porovnání a testy | CMP, CMN, TST, TEQ, CLZ |
Logické operace | AND, ORR, ORN, EOR |
Bitové operace | BIC |
Logické a aritmetické posuny | LSL, LSR, ASR |
Bitové rotace | ROR, RRX |
Posuny se saturací | SSAT, USAT |
Otočení bitů | REV, REV16, REVSH, RBIT |
Bitová pole | UBFX, SBFX, BFC, BFI |
Load (jeden registr) | LDR, LDRH, LDRB, LDRSH, LDRSB, LDRT, LDRHT, LDRBT, LDRSHT, LDRSBT, LDRD |
Load (více registrů) | LDM |
Store (jeden registr) | STR, STRH, STRB, STRSH, STRSB, STRT, STRHT, STRBT, STRSHT, STRSBT, STRD |
Store (více registrů) | STM |
Práce se zásobníkem | PUSH, POP |
Skoky | B, BL, BX, BLX, TBB, TBH |
Větvení | B{podmínka}, CBZ, CBNZ |
Události a přerušení | SEV, WFE, WFI, CPSID, CPSIE |
Práce s bariérami | ISB, DMB, DSB |
Práce se semafory | LDREX, LDREXH, LDREXB, STREX, STREXH, STREXB, CLREX |
Ostatní instrukce | NOP, SVC, IT{podmínka}, BKPT |
Poznámky:
- Instrukce SVC se mj. používá pro volání služeb kernelu.
- Instrukce SSAT a USAT se používají pro posun operandu s následnou saturací na zvolený počet bitů. SSAT provádí znaménkovou operaci, zatímco USAT provádí operaci bezznaménkovou.
- Instrukce TBB (Table Branch Byte) a TBH (Table Branch Halfword) mohou být použity například při překladu aplikací napsaných ve vyšších programovacích jazycích, typicky céčka s jazykovou konstrukcí typu switch. Tyto instrukce jsme si již popsali v rámci článku o jádrech Cortex-M7.
- Instrukce CBZ a CBNZ slouží k provedení skoku (rozvětvení), v případě, že je vybraný pracovní registr nulový či naopak nenulový (compare and branch if [not] zero).
- Instrukční prefix IT{podmínka} 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 při práci v assembleru 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.
- Instrukce REV a REV16 otáčí pořadí bajtů ve 32bitovém či 16bitovém slovu (lze použít pro konverzi little-big endian atd.), zatímco instrukce RBIT otočí pořadí všech bitů ve 32bitovém slovu. To je docela užitečná operace, zejména v oblasti zpracování signálů.
- U instrukcí LDM a STM je součástí instrukčního slova i bitové pole určující, které pracovní registry mají být načteny či naopak uloženy do operační paměti.
7. Instrukce orientované na zpracování signálu
Jak jsme si již řekli v předchozích kapitolách, jsou mikrořadičová jádra navržena takovým způsobem, aby je bylo možné efektivně použít při zpracování digitálních signálů. S tím samozřejmě souvisí i podpora pro některé specializované instrukce, o nichž se ve stručnosti zmíníme v následujících odstavcích. Mezi instrukce určené pro zpracování signálu patří především:
- Sčítání a odčítání se saturací.
- Instrukce MLA (Multiply and Accumulate) a MLS (Multiply and Subtract), kde především první instrukce je používaná například v číslicových filtrech.
- Varianty MLA s 64bitovým výsledkem, rozlišuje se znaménkové a bezznaménkové násobení atd. (viz násobička).
- Již výše zmíněné instrukce SSAT a USAT.
- Instrukce RBIT pro algoritmus výpočtu FFT apod.
- Instrukce pro konverze dat (protože mnoho vstupních číslicových dat používá osmibitové či šestnáctibitové vzorky).
8. Sčítání a odečítání se saturací
Kromě běžných aritmetických operací je možné u čipů s jádry Cortex-M4 použít i operace se saturací. Při využití těchto operací nedojde k přetečení přes maximální či minimální 8bitovou, 16bitovou či 32bitovou hodnotu (se znaménkem či bez znaménka), ale výpočet se „zasekne“ na minimální či maximální hodnotě.
# | Instrukce | Typ | Šířka operandů | Poznámka |
---|---|---|---|---|
1 | SSAT | Signed | 32 bitů | posun operandu před výpočtem |
2 | SSAT16 | Signed | 2×16 bitů | posun operandu před výpočtem |
3 | USAT | Unsigned | 32 bitů | posun operandu před výpočtem |
4 | USAT16 | Unsigned | 2×16 bitů | posun operandu před výpočtem |
5 | QADD | Signed | 32 bitů | součet se saturací |
6 | QADD8 | Signed | 4×8 bitů | součet se saturací |
7 | QADD16 | Signed | 2×16 bitů | součet se saturací |
8 | QSUB | Signed | 32 bitů | rozdíl se saturací |
9 | QSUB8 | Signed | 4×8 bitů | rozdíl se saturací |
10 | QSUB16 | Signed | 2×16 bitů | rozdíl se saturací |
11 | QASX | Signed | 32 bitů | add + exchange |
12 | QSAX | Signed | 32 bitů | sub + exchange |
13 | QDADD | Signed | 32 bitů | druhý operand je před výpočtem vynásoben dvěma |
14 | QDSUB | Signed | 32 bitů | druhý operand je před výpočtem vynásoben dvěma |
15 | UQADD8 | Unsigned | 4×8 bitů | součet se saturací |
16 | UQADD16 | Unsigned | 2×16 bitů | součet se saturací |
17 | UQSUB8 | Unsigned | 4×8 bitů | rozdíl se saturací |
18 | UQSUB16 | Unsigned | 2×16 bitů | rozdíl se saturací |
19 | UQASX | Unsigned | 32 bitů | add + exchange |
20 | UQSAX | Unsigned | 32 bitů | add + exchange |
9. Bitový příznak Q
Proč se vlastně ve jménech většiny instrukcí, které byly vypsány v předchozí tabulce, objevuje znak Q? Souvisí to s bitovým příznakem označeným (překvapivě) Q, který je taktéž nazýván sticky flag či sticky overflow bit (což není zcela přesné). Slovo „sticky“ se používá z toho důvodu, že pokud jednou dojde k jeho nastavení (na jedničku), musí se o jeho vynulování explicitně postarat programátor, na rozdíl od ostatních příznaků (Z, V, C apod.), které se mění s každou relevantní instrukcí. Příznak Q je nastaven ve chvíli, kdy při nějaké aritmetické operaci dojde k saturaci. To lze použít například k detekci špatně nastavených parametrů při zpracování signálu (příliš velké zesílení apod.). Díky tomu, že příznak Q není běžnými instrukcemi nulován, není nutné jeho nastavení testovat po každé aritmetické operaci, ale například až po zpracování celého bloku dat či po aplikaci celého filtru na jeden vzorek, což je rychlejší a většinou i dostačující.
10. Násobička
Násobička všech mikrořadičových jader Cortex-M4 podporuje takřka nepřeberné množství instrukcí pro násobení celočíselných operandů typu signed či unsigned (se znaménkem, bez znaménka) s tím, že výsledek je buď 32bitová hodnota či hodnota 64bitová. Navíc je možné určit, zda se má výsledek násobení přičíst k mezivýsledku a provést tak v oblasti digitálního zpracování signálů velmi užitečnou operaci nazývanou „Multiply&Accumulate“ (přičemž akumulátor má většinou šířku 32 bitů či 64 bitů, zatímco vstupní operand může být v některých instrukcích pouze šestnáctibitový). Následuje tabulka se základními operacemi násobičky:
# | Instrukce | Operandy | Výsledek | Počet cyklů | Operace |
---|---|---|---|---|---|
1 | MUL | 32bit×32bit | 32bit | 1 | násobení |
2 | MAL | 32bit×32bit | 32bit | 2 | násobení a přičtení výsledku (Multiply and Accumulate) |
3 | MLS | 32bit×32bit | 32bit | 2 | násobení a odečtení výsledku (Multiply and Subtract) |
4 | SMULL | 32bit×32bit | 64bit | 1 | násobení hodnot se znaménkem |
5 | SMLAL | 32bit×32bit | 64bit | 1 | Multiply and Accumulate (se znaménkem) |
6 | UMULL | 32bit×32bit | 64bit | 1 | násobení hodnot bez znaménka |
7 | UMLAL | 32bit×32bit | 64bit | 1 | Multiply and Accumulate (bez znaménka) |
8 | UMAAL | 32bit×32bit+32+32 | 64bit | 1 | Multiply and Accumulate long (bez znaménka) |
9 | SMLAD | 16bit×16bit | 32bit | 1 | násobení dvouprvkových vektorů |
10 | SMLADX | 16bit×16bit | 32bit | 1 | násobení dvouprvkových vektorů |
DSP operace (povšimněte si zejména konstantního počtu cyklů pro zahájení či dokončení operace):
# | Instrukce | Počet cyklů | Operace |
---|---|---|---|
1 | SMLALD | 1 | Signed Multiply Accumulate Long Dual (16bit×64bit) |
2 | SMLAWB | 1 | Signed Multiply Accumulate (word by halfword) |
3 | SMLAWT | 1 | Signed Multiply Accumulate (word by halfword) |
4 | SMLSD | 1 | Signed Multiply Subtract Dual |
5 | SMLSLD | 1 | Signed Multiply Subtract Long Dual |
6 | SMMLA | 1 | Signed Most Significant Word Multiply Accumulate |
7 | SMMLS | 1 | Signed Most Significant Word Multiply Subtract |
8 | SMUAD | 1 | Signed Dual Multiply Add |
9 | SMMUL | 1 | Signed Most Significant Word Multiply |
10 | SMULWB | 1 | Signed Multiply (word by halfword) |
11 | SMMLAR | 1 | 32-bit multiply with rounded 32-most-significant-bit accumulate |
12 | SMMLSR | 1 | 32-bit multiply with rounded 32-most-significant-bit subtract |
13 | SMMULR | 1 | 32-bit multiply returning rounded 32-most-significant-bits |
14 | SMLABB | 1 | Q setting 16-bit signed multiply with 32-bit accumulate, bottom by bottom |
15 | SMLABT | 1 | Q setting 16-bit signed multiply with 32-bit accumulate, bottom by top |
16 | SMLALBB | 1 | 16-bit signed multiply with 64-bit accumulate, bottom by bottom |
17 | SMLALBT | 1 | 16-bit signed multiply with 64-bit accumulate, bottom by top |
18 | SMLALTB | 1 | 16-bit signed multiply with 64-bit accumulate, top by bottom |
19 | SMLALTT | 1 | 16-bit signed multiply with 64-bit accumulate, top by top |
20 | SMULBB | 1 | 16-bit signed multiply yielding 32-bit result, bottom by bottom |
21 | SMULBT | 1 | 16-bit signed multiply yielding 32-bit result, bottom by top |
22 | SMULTB | 1 | 16-bit signed multiply yielding 32-bit result, top by bottom |
23 | SMULTT | 1 | 16-bit signed multiply yielding 32-bit result, top by bottom |
24 | SMULWT | 1 | 16-bit by 32-bit signed multiply returning 32-most-significant-bits, top |
25 | SMUSD | 1 | Dual 16-bit signed multiply returning difference |
26 | SMLATB | 1 | Q setting 16-bit signed multiply with 32-bit accumulate, top by bottom |
27 | SMLATT | 1 | Q setting 16-bit signed multiply with 32-bit accumulate, top by top |
Neříkal někdo, že zkratka RISC je odvozena od „Reduced Instruction Set“? :-)
11. Jádra Cortex-M4F
Základní mikrořadičová jádra označovaná pouze jménem Cortex-M4 (tj. bez znaku „F“ na konci) neobsahují žádný matematický koprocesor, který by dokázal nativně pracovat s numerickými hodnotami s plovoucí řádovou čárkou. To je pochopitelné, protože existuje poměrně mnoho aplikací, v nichž si vystačíme pouze s operacemi nad celými čísly popř. s vlastní implementací výpočtů s fixní řádovou čárkou (FX, fixed point). Pokud je však v nějaké aplikaci většina výpočtů prováděna s numerickými hodnotami typu single/float, může být výhodnější namísto jádra Cortex-M4 použít jádro Cortex-M4F, které již matematický koprocesor obsahuje – ovšem s několika omezeními, na která je zapotřebí si dávat pozor, a to zejména při portaci aplikací. Jedno z největších omezení spočívá v tom, že matematický koprocesor skutečně podporuje pouze typ single/float a nikoli double (což v některých případech nemusí vadit, ostatně své použití mají i šestnáctibitové formáty s plovoucí řádovou čárkou).
Poznámka: ve skutečnosti je několik operací pro práci s dvojitou přesností přece jen implementováno, což uvidíme v tabulce v další kapitole.
Matematický koprocesor implementovaný v jádrech Cortex-M4F se v mnoha ohledech odlišuje například od „klasických“ koprocesorů řady 80×87 (v nichž výpočty interně probíhají s hodnotami rozšířenými na plných 80 bitů, což mj. dovoluje bezeztrátovou konverzi mezi celočíselnými hodnotami long a interně používaným formátem koprocesoru). Především se v RISCovém matematickém koprocesoru operandy ukládají do sady registrů označených jmény S0 až S31, na které existují aliasy D0 až D15 (vždy dva registry, které původně nesly informace o numerické hodnotě typu float/single jsou použity pro uložení hodnoty typu double). Dále je možné zvolit tři režimy činnosti koprocesoru, které mají vliv na prováděné výpočty: režim odpovídající normě IEEE 754 (Full-compliance mode), režim při kterém jsou denormalizované hodnoty považovány za nulu (Flush to zero mode) a konečně režim, při kterém všechny operace, u nichž je jeden či oba vstupní operandy roven NaN (Not a Number), taktéž vrací NaN (naopak v režimu kompatibility s normou IEEE 754 se hodnoty NaN zpracovávají podle specifikace).
12. Operace podporované matematickým koprocesorem
Operace, které jsou podporovány matematickým koprocesorem, jsou vypsány v následující tabulce:
# | Skupina | Instrukce | Počet cyklů | Popis | Prováděný výpočet |
---|---|---|---|---|---|
1 | Aritmetické operace | VADD.F32 Fd, Fn, Fm | 1 | součet | Fd := Fn + Fm |
2 | Aritmetické operace | VSUB.F32 Fd, Fn, Fm | 1 | rozdíl | Fd := Fn – Fm |
3 | Aritmetické operace | VNEG.F32 Fd, Fm | 1 | změna znaménka | Fd := – Fm |
4 | Aritmetické operace | VABS.F32 Fd, Fm | 1 | absolutní hodnota | Fd := abs(Fm) |
5 | Aritmetické operace | VSQRT.F32 Fd, Fm | 14 | druhá odmocnina | Fd := sqrt(Fm) |
6 | Aritmetické operace | VDIV.F32 Fd, Fn, Fm | 14 | dělení | Fd := Fn / Fm |
7 | Aritmetické operace | VMUL.F32 Fd, Fn, Fm | 1 | násobení | Fd := Fn * Fm |
8 | Aritmetické operace | VMLA.F32 Fd, Fn, Fm | 3 | násobení + akumulace | Fd := Fd + (Fn * Fm) |
9 | Aritmetické operace | VMLS.F32 Fd, Fn, Fm | 3 | odečtení součinu | Fd := Fd – (Fn * Fm) |
10 | Aritmetické operace | VNMUL.F32 Fd, Fn, Fm | 1 | násobení + změna znaménka | Fn := – (Fn * Fm) |
11 | Aritmetické operace | VNMLA.F32 Fd, Fn, Fm | 3 | kombinace VNMUL a VMLA | Fd := – Fd – (Fn * Fm) |
12 | Aritmetické operace | VNMLS.F32 Fd, Fn, Fm | 3 | kombinace VNMUL a VMLS | Fd := – Fd + (Fn * Fm) |
13 | Aritmetické operace | VFMA.F32 Fd, Fn, Fm | 3 | fused multiply and accumulate (jedno zaokrouhlení) | Fd := Fd + (Fn * Fm) |
14 | Aritmetické operace | VFMS.F32 Fd, Fn, Fm | 3 | dtto + odečtení součinu | Fd := Fd – (Fn * Fm |
15 | Aritmetické operace | VFNMA.F32 Fd, Fn, Fm | 3 | fused VNMLA | Fd := – Fd – (Fn * Fm) |
16 | Aritmetické operace | VFNMS.F32 Fd, Fn, Fm | 3 | fused VNMLS | Fd := – Fd + (Fn * Fm) |
17 | Porovnání | VCMP.F32 Fd, Fm | 1 | porovnání obsahu dvou registrů | Fd – Fm |
18 | Porovnání | VCMP Fd, #0.0 | 1 | porovnání jednoho registru s nulou | Fd – 0.0 |
19 | Konverze | VCVT.F32 | 1 | konverze integer → single | |
20 | Přesuny dat | VMOV Sn, Rd | 1 | přesun dat do registru koprocesoru | Sn := Rd (Rd = registr ARM procesoru) |
21 | Přesuny dat | VMOV Rd, Sn | 1 | přesun dat do registru CPU | Rd := Sn (Rd = registr ARM procesoru) |
22 | Přesuny dat | VMOV Sn, # | 1 | načtení konstanty | Sd := # |
23 | Přesuny dat | VMOV Dn, Rd | 2 | přesun double | (jsou zapotřebí dva CPU registry) |
24 | Přesuny dat | VMOV Rd, Dn | 2 | přesun double | (jsou zapotřebí dva CPU registry) |
25 | Přesuny dat | VMRS APSR_nzcv, FPSCR | 1 | APSR flags := FPSCR flags (přenos příznaků) | |
26 | Přesuny dat | VSMR FPSCR, APSR_nzcv | 1 | opak předchozí instrukce | |
27 | Přesuny dat | VLDR.32 | 2 | načtení jednoho registru typu single | |
28 | Přesuny dat | VLDR.64 | 3 | načtení jednoho registru typu double | |
29 | Přesuny dat | VLDM.32 | 1+N | načtení jednoho až N registrů typu single | |
30 | Přesuny dat | VLDM.64 | 1+2×N | načtení jednoho až N registrů typu double | |
31 | Přesuny dat | VSTR.32 | 2 | uložení jednoho registru typu single | |
32 | Přesuny dat | VSTR.64 | 3 | uložení jednoho registru typu double | |
33 | Přesuny dat | VSTM.32 | 1+N | uložení jednoho až N registrů typu single | |
34 | Přesuny dat | VSTM.64 | 1+2×N | uložení jednoho až N registrů typu double | |
35 | Operace se zásobníkem | VPUSH.32 | 1+N | uložení N registrů na zásobník | |
36 | Operace se zásobníkem | VPUSH.64 | 1+2×N | uložení registrů na zásobník | |
37 | Operace se zásobníkem | VPOP.32 | 1+N | přečtení N registrů ze zásobníku | |
38 | Operace se zásobníkem | VPOP.64 | 1+2×N | přečtení N registrů ze zásobníku |
13. Operace ze standardu IEEE 754, které nejsou implementovány
Některé operace, které jsou (velmi přesně) definovány v normě IEEE 754 resp. v její novější úpravě IEEE 754–2008, ve skutečnosti nejsou na jádrech Cortex-M4F implementovány, což znamená, že pokud se dané operace objeví ve zdrojových kódech překládaných programů, musí překladač namísto vygenerování pouhých několika instrukcí koprocesoru volat knihovní funkce, což je samozřejmě pomalejší (a taktéž je nutné pro tyto funkce vyhradit dostatečnou kapacitu paměti ROM). Mezi nepodporované operace či instrukce patří především:
- Výpočet zbytku po dělení.
- Zaokrouhlení hodnoty s plovoucí řádovou čárkou na celočíselnou hodnotu uloženou zpět do registru koprocesoru.
- Porovnání hodnoty typu single s hodnotou typu double a naopak.
- Konverze mezi desítkovým a binárním formátem. Desítkový formát používá jako základ exponentu konstantu 10 a nikoli 2, norma IEEE 754 definuje tři takového formáty: decimal32, decimal64 a decimal128.
- Zpětná konverze mezi binárním a desítkovým formátem.
14. 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 - Instrukce typu SIMD na mikroprocesorech RISC
http://www.root.cz/clanky/instrukce-typu-simd-na-mikroprocesorech-risc/ - Instrukce typu SIMD na mikroprocesorech RISC (2. část)
http://www.root.cz/clanky/instrukce-typu-simd-na-mikroprocesorech-risc-2-cast/ - Instrukce typu SIMD na mikroprocesorech RISC (3.část – MIPS-3D a VIS)
http://www.root.cz/clanky/instrukce-typu-simd-na-mikroprocesorech-risc-3-cast-mips-3d-a-vis/