Fördelar med 32 bits processorkärna

I SoC-konstruktioner ser vi en övergång från 8-bitskärnor till 32-bitskärnor. David Kerr-Munslow från det franska processorföretaget Cortus S.A.S. analyserar här skillnaderna mellan en populär 8-bitskärna och en 32-bitskärna.

I denna artikel kommer vi att se närmare på några faktorer som SoS-konstruktörer måste ta hänsyn till vid valet av processorarkitektur för embeddedsystem. 8-bitskärnor har tidigare använts i hög utsträckning, men många går nu över till 32-bitskärnor. För att analysera detta har vi valt två representativa processorer: 8051 som fortfarande är en populär processor, och Cortus APS3R som utvecklats speciellt för att exekvera embeddedprogram skrivna i C eller C++.
Vi utforskar vilken betydelse bussbredden har med avseende på
– enkelhet att programmera
– kodtäthet
– prestanda
– realtidsegenskaper
– kodstorlek
– effektförbrukning
– portering

Enkelhet att programmera
Den viktigaste utvecklingskostnaden i de flesta system är utvecklandet av mjukvaran [3], och detta är en viktig faktor vid valet mellan 8- och 32-bitskärnor. Idag sker det mesta programutvecklandet i högnivåspråk, och i embeddedvärlden betyder det C och ibland C++.

rogramspråket C togs ursprungligen fram för utveckling av systemmjukvara för minidatorer [4]. Språket ställer vissa krav på den underliggande hårdvaran:
– bitadresserbart minne
– heltal och pekare har samma storlek
– en enda adressrymd
– ”stack” och ”heap”

Kompilatorer för C/C++ finns till de flesta processorer, dock ibland inte utan eftergifter för vissa arkitektoniska egenskaper.

Arkitekturens inverkan
Dessa aspekter påverkar hur enkelt det är att implementera en specifik arkitektur.
De flesta kompilatorer bygger på att det finns en stack, och de använder denna stack inte bara för att skicka parametrar och lagra returadresser, utan också för automatiska variabler. Detta sätt att använda stacken ger ”lexical scope” till automatiska variabler, åtminstone implicit.

Processorer som har begränsat stackutrymme måste implementera någon annan mekanism för korttidslagring av lokala variabler. Den interna stacken i 8051 är t ex 128 byte stor och används för subrutiner och avbrottsreturer. Om stacken rinner över sker detta i tysthet, vilket kan resultera i svårreproducerbara kraschar om nästade avbrott överskrider stackdjupet. Detta är något som författaren har erfarenhet av!
SDCC, som är en populär C-kompilator för 8051, lagrar lokala variabler i vanligt RAM, och ”lexical scope”-kollisioner vållar problem. Detta gör det svårt att implementera "re-entrant"-funktioner och potentiellt osäkert att använda biblioteksfunktioner inuti en avbrottshanterare. Rekursion är naturligtvis omöjligt.

Pekararitmetik
Antagandet att minnet är en linjär array av minnesceller uppmuntrar till manipulation av datastrukturer med hjälp av explicit pekararitmetik. I embeddedsystem, där hastighet väger tyngre än elegans, gäller detta i ännu högre grad. Detta förvärras av att C använder arrayer och pekare som aspekter på samma språkfunktion.

I 8-bits CPUer är adresserna ofta 16 bitar stora, men den naturliga heltalsstorleken är 8 bitar. Detta problem mildras ofta av indexregister och adresseringsmoder i CPUn. Det är svårt för en kompilator att dra fullständig nytta av detta.

Adressrymd
Storleken på adressrymden har stor betydelse. De flesta 8-bits CPUer kan direkt adressera en adressrymd på 64 Kbyte. Moderna embeddedsystem har ofta mer än 64 Kbyte programkod, vilket kräver komplexa metoder för bankväxling. Detta gör avbrott och subrutinaccesser komplexa och med potentiella risker för fel. Man måste skapa komplexa metoder för att vara säker på att biblioteksrutiner alltid finns tillgängliga i adressrymden.


Fig 1. Adressrymden i 8051

Fig 1 visar de olika adressrymderna i en 8051. Vissa rymder kan bara anropas antingen med direkta adresseringsmoder, eller genom indirekta adresseringsmoder [2, 1-6]. Denna egenskap hos många 8-bits CPUer med multipla adressrymder, för program, för data, för I/O, kräver olika accessmetoder. Därför krävs ofta en extension av C-språket för manipulering av data.
Här ser vi en klar fördel hos 32-bits arkitekturer, som kan adressera 4 Gbyte.

Kodtäthet
Kodtätheten är måttet på hur mycket minne som krävs för att lagra ett program som skall utföra en uppgift. Kodtätheten påverkar följande faktorer:
– minnets förbrukning
– exekveringshastigheten

Minnets effektförbrukning är naturligtvis proportionell mot minnesstorleken. På samma vis påverkar antalet använda adressbitar routing- och busskapacitansen och därmed hur mycket drivning som krävs.

Hur många hämtoperationer som krävs påverkar direkt exekveringshastigheten. Ju färre minnesaccesser som krävs för att läsa in programmet i CPUn, desto snabbare och effektivare exekveras programmet.

Ett praktiskt exempel: FreeRTOS
FreeRTOS-kärnan kompilerades för 8051 och Cortus APS3R. Samma optioner och demon användes. Assemblerkoden analyserades för att visa fördelningen av instruktionslängden.


Tab 1. Kodstorlek för FreeRTOS


Tab 2. Instruktionsmix för FreeRTOS

Tab 1 visar att 32-bits APS3R-arkitekturen är 2,35 gånger mer minneseffektiv jämfört med 8051. Det är intressant att notera att bara drygt en tredjedel av instruktionerna för 8-bitsprocessorn verkligen är 8 bitar långa.

Prestanda
Många faktorer påverkar en arkitekturs prestanda. Med hjälp av benchmark-tester går det att få en allmän indikation av hur höga prestanda är.
Dhrystone är ett populärt benchmark-test för embeddedsystem. Det är ett syntetiskt test som måste användas med varsamhet, men det kan ge mycket användbara indikationer. Det enda sättet att bestämma hur snabbt ett program kommer att köra är att verkligen köra det. Resultaten för 8051, en förbättrad 8051 och APS3R visar vilka avsevärda prestandafördelar 32-bitsarkitekturen ger.


Tab 3. Prestanda

Det viktigaste som visas i Tab 3 är att 32-bitsarkitekturen utför väsentligt mer användbart arbete per klockcykel än 8051 [5]. Det innebär att 26,5 gånger mer arbete kan utföras under en given tidsrymd (vid samma klockfrekvens), eller att samma mängd arbete kan spridas över en längre tidsperiod (med lägre klockfrekvens).

Registeruppsättning
Registeruppsättningen har en avsevärd inverkan på hur effektiv kod en kompilator kan generera, liksom hur lämplig processorn är för att hantera tidskritiska avbrott utan stora mängder overhead.

Registeruppsättningen kan karakteriseras av följande egenskaper:
– General Purpose
– ackumulator
– bredd (8, 16 eller 32 bitar)
– antal register


Fig 2. Registerspecifikation för adderingsinstruktion

8-bits arkitekturer har generellt 8-bits instruktioner, och om nödvändigt en eller flera extensionsbitar. Dessa korta instruktioner begränsar antalet register som kan specificeras, och de flesta instruktioner opererar på ett implicit register, en ackumulator. Processorer med bredare bussar har ofta större instruktionsstorlekar, 16 eller 32 bitar långa.

Fig 2 visar som jämförelse en typisk instruktion från APS3R resp 8051, en additionsinstruktion. Den större instruktionsbredden gör att fler bitar kan användas för att specificera registren. APS3R använder t ex två 4-bitsfält för att specificera vilket av de 16 registren som skall användas.
Möjligheten för ALUn att operera på ett större antal register minskar behovet att flytta data från minnet till specifika register.

Perifer access
Den stora adressrymden hos 32-bitsarkitekturer kan påverka uppbyggnaden av perifera register. Varje perifert register kan konstrueras för effektiv access, istället för att spara in på använt adressutrymme.

Den stora adressrymden gör att funktionalitet kan grupperas i operationella uppsättningar, istället för att garantera optimal paketering.


Fig 3. Jämförelse mellan perifera register

Fig 3 visar två perifera register: Serial Control (SCON) från 8051 och Receive Status från APS3R. SCON-registret styr flera viktiga aspekter hos 8051. Mottagningsstatus (avbrottsstatus) ligger begravt bland sändarstatus, styrbitar och databitar. En avsevärd mängd bearbetning krävs för att avläsa mottagarens status.

Registret APS Receive Status innehåller bara de bitar som anger mottagningsstatus. Tillståndet ”inget att rapportera” hos mottagaren indikeras med att alla bitar är nollor.

Med denna ansats blir det enklare att skriva avbrottshanteraren. Denna kan snabbt bestämma den exakta orsaken till ett avbrott och reagera på lämpligt sätt: att snabbt återlämna kontrollen till avbrutna rutiner eller att återgå till viloläge.

Realtidsegenskaper
Embeddedsystem är ofta också realtidssystem. Det viktigaste kravet på ett sådant är att det reagerar inom fastställd tid på en händelse – som vanligen är ett externt stimulus eller en timer som avslutats – och att den gör det på ett förutsägbart sätt. För detta används ofta avbrott. Den viktigaste egenskapen hos ett avbrott är att det kan stoppa en uppgift och exekvera avbrottskoden inom fastställd tid och på ett förutsägbart sätt, och sedan återgå till den avbrutna uppgiften eller gå ned i viloläge.

Ett antal faktorer påverkar ett systems möjligheter att reagera inom fastställd tid och förutsägbart.
– registeruppsättningens storlek
– instruktionernas latens
– avbrottens effektivitet

Registeruppsättningens storlek
Storleken på registeruppsättningen har en direkt inverkan på tiden för kontextväxling. Processens tillstånd måste lagras mellan dessa växlingar, och här ingår alla register som processen kan anropa.

Instruktionernas latens
Latensen hos instruktionerna påverkar förutsägbarheten hos avbrotten. Bara ett fåtal arkitekturer tillåter att instruktioner avbryts mitt under en exekvering. Därför måste ett avbrott vänta tills en instruktion avslutats innan det kan agera. Denna latens ökar med instruktionernas komplexitet, vilket ökar osäkerheten om när avbrottet kommer att uppmärksammas.

Avbrottens effektivitet
Effektiviteten hos avbrotten kan ha en avgörande betydelse. Implementeringen av avbrottsmekanismen kan göras på olika sätt:
– vektoriserade avbrott
– delade avbrott
– adresser med fasta rutiner

I en processor med vektoriserade avbrott finns en tabell över adresserna till avbrottshanterarna. Varje avbrytande enhet har tilldelats ett vektornummer, och när ett avbrott signaleras anropar processorn vektortabellen och hoppar direkt till avbrottsrutinen. Detta är i stort sett den mest effektiva metoden (och det är så som de allra flesta moderna 32-bits arkitekturer arbetar).

Med delade avbrott finns det bara ett eller två avbrott, och avbrottshanteraren måste polla alla tänkbara avbrytande enheter för att veta vem som är källan till avbrottet. Denna pollning är tämligen ineffektiv.

I en del processorer finns avbrottshanterarna på fasta adresser, och när ett avbrott uppstår hoppar processorn till den fasta adress som svarar mot avbrottet. Denna ansats är effektivare än att använda vektoriserade avbrott. Men metoden har nackdelen att om det finns flera avbrott måste det finnas ett fast avstånd mellan hanterarna. Detta avstånd kommer antingen att vara för stort, vilket slösar bort värdefullt adressutrymme. Eller också finns det inte tillräckligt med utrymme, och då måste man lägga in hopp. Detta skapar en invecklad kod som är svår att skriva i annat än assembler.
I 8051 används den sista metoden, och i APS3R den första.

Kärnstorlek
IP-kärnans storlek har stor betydelse vid SoC-konstruktion och påverkar direkt produktionskostnaden.


Tab 4. Grindantal för utvalda processorer

Tab 4 visar att det är en faktor större än 4 i storlek mellan processorer som kan användas i samma applikation. Värt att notera är likheten i storlek mellan vissa 32-bits processorer och 8051.

Läckström
Nyckelparametern för batterilivslängden hos en enhet som huvudsakligen befinner sig i tomgångs- eller viloläge är läckströmmen. Denna är direkt proportionell mot chipytan, som har samband med antalet grindar.

Effektförbrukning
Effektförbrukningen har avgörande betydelse i batteridrivna enheter, men den påverkar också hur man skall hantera förlusteffekter. Det finns två faktorer som påverkar effektförbrukningen hos en SoC, nämligen statiska läckströmmar och dynamiska switchningsförluster.
I båda dessa fall minskas effektförbrukningen om man minskar antalet grindar. Genom att minska klockfrekvensen går det att ytterligare minska den dynamiska förbrukningen.

I många system är minnet den största källan till läckströmmar. Den ökade kodtäthet som APS3R ger medför att denna läckström minimeras, jämfört med 8-bits processorer.


Tab 5. Effektförbrukning

Dessa effektförluster kan betraktas mot bakgrund av de värden som visas i Tab 3 och som säger att en 32-bits processor ger avsevärt mycket högre bearbetningskraft per cykel jämfört med 8051. APS3R presterar 37 gånger bättre, uttryckt i DMIPS per µW, vilket ökar batterilivslängden.

Detta värde tar bara hänsyn till processorernas råa beräkningskraft. Den ökade kodtätheten, som framgår av Tab 1, ger färre opcode-hämtningar, och register-till-register-arkitekturen klarar sig med färre minnesaccesser. Båda dessa faktorer minskar effektförbrukningen.

Läckströmmen är direkt proportionell mot kiselytan. Tab 4 visar antalet grindar i olika processorer, och den relativa läskströmmen kan räknas fram ur dessa värden.

32-bits bussar
När en bussledning är i drift laddas och urladdas ledningens kapacitans hela tiden, så med ökande bussaktivitet ökar behovet av effekt. Att driva 32 ledningar kräver mer effekt än att driva 8, så här har en 8-bits CPU en fördel. Men om man behöver använda konstanter som är större än 8 bitar krävs flera accesser, och det är inte bara dataledningarna som måste drivas utan också adressledningarna.


Fig 4. 8-bits buss jämförd med 32-bits buss

Portering
I många fall finns en väletablerad uppsättning kod i form av bibliotek som inte ingår i projektet eller som mjukvara som redan utvecklats för tidigare produkter. Externa bibliotek kan finnas tillgängliga som högnivåkällkod eller assemblerkod. Befintlig källkod kan implementeras som dåligt dokumenterat assemblerspråk, och att återanvända detta i C är en omständlig uppgift.

Att ändra målarkitekturen till en ny IC-generation kan vara nödvändigt av flera olika skäl:
– kostnadsminskningar
– ersätta utgångna delar
– lägga till funktioner

Om det är nödvändigt att portera kod är det naturligtvis mycket enklare att göra detta till en arkitektur vars funktioner utgör en övermängd till funktionerna hos den ursprungliga processorn. Med de höga prestanda som en 32-bits arkitektur ger går det att emulera instruktionsuppsättningen och viktiga delar av arkitekturen i 8051. Detta kan göras genom ”run time emulation” (den enklaste ansatsen) eller genom at rekompilera 8051s assemblerspråk. Enkla strategier som arbetar med hopptabeller kan vara anmärkningsvärt effektiva.

Datajustering
Vid en övergång från 8-bits till 32-bits arkitekturer kan det uppstå problem med justering (alignment) och packning av data. Problem kan uppstå om arkitekturen inte kan hantera justerade accesser.


Fig 5. Justering av packad struktur

Fig 5 visar en tänkbar packning av en struktur i minnet. Detta har ingen betydelse för 8-bits CPUer, men det kan påverka hur en kompilator kan tänkas placera elementen i en struktur i minnet. Detta blir problematiskt om programmeraren försöker anropa innehållet i en struktur genom att gå runt strukturens accessyntax och anropa minnet direkt.

Språkextensioner
Som vi redan nämnt kan funktioner hos vissa MCUer kräva extensioner till språket. Det är avsevärt mycket enklare att flytta standard-C än att anpassa redan utvecklad kod till en specialversion av språket.

Framtidssäkring av konstruktioner
Målet för många projekt är att få fram en produkt som kan säljs i stora volymer och har en lång produktlivslängd. Därför är det klokt att se till att konstruktionen inte bara kan tillverkas i stora kvantiteter, utan också under lång tid. Möjligheten att utöka konstruktionen till nya versioner med förbättrade egenskaper kan också förbättra försäljningen, t ex genom att överträffa konkurrenterna eller att kunna erbjuda en ”uppgraderingsväg".

Att utveckla sådana system är en viktigt projektmål. En väg att garantera att framtida utveckling kan utföras med minimala besvär är att se till att all mjukvara som utvecklas är porterbar. Eller annorlunda uttryckt: utvecklad i ett ”oförbättrat” standardspråk för en enhetlig arkitektur.

Slutsats
32-bits processorkärnor konstruerade att köra program i C/C++ ger fördelar avseende enkel mjukvaruutveckling, kodtäthet och precessorprestanda. Ökad kodtäthet och ökade prestanda leder direkt till lägre dynamisk effektförbrukning. Högre kodtäthet ger också mindre chipytor och lägre läckströmmar. För den som använder 8-bits processorer är den viktigaste uppgiften att portera gammal mjukvara till standard-C.
David Kerr-Munslow, Cortus S.A.S

Referenser
[1]    Hennessy and Patterson: “Computer Architecture A Quantitative Approach”,
[2]    Intel: “MCS51 Microcontroller Family User’s Manual” Intel, 1994
[3]    http://www.softwaremetrics.com/
Articles/HardwareandSoftware.htm
[4]    Denis M. Ritchie: “The Development of the C Language”, Second History of Programming Languages conference (Cambridge, Mass) 1993
[5]    Dolphin Integration:
 http://www.dolphin.fr/flip/logic/8bit/logic_8bit.php accessed 4th April 2012
[6]    Tom R. Halfhill,: “Itty-Bitty 32-Bitters”, Microprocessor Report, 5/11/09-01
[7]    Cortus:
    “http://marketing.cortus.com/acton/formfd/9762/0001:d-0004”

Comments are closed.