23
Pipelining i RISC-processorn Joakim Lindström Institutionen för informationsbehandling Åbo Akademi E-post: [email protected]

Pipelining i RISC-processorn - Åbo Akademi

  • Upload
    others

  • View
    8

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Pipelining i RISC-processorn - Åbo Akademi

Pipelining i RISC-processorn

Joakim Lindström Institutionen för informationsbehandling

Åbo Akademi E-post: [email protected]

Page 2: Pipelining i RISC-processorn - Åbo Akademi

1

Innehållsförteckning

1. Inledning

2. Historia: Intel 8086 (1978) till Pentium 4 (2000)

3. Principer för RISC-arkitektur

4. Effektiviseringsmetoder .

4.1 Pipelining

4.2 Pipelining av funktionella enheter

4.3 Dynamisk exekvering (Dynamic execution)

4.4 Branch prediction

5. IA-32 arkitekturen

5.1 Instruktionsuppsättning och assemblerprogrammering

5.2 Mikroarkitekturen

5.3 Pipelinen i Pentium 4

6. Avslutning

Abstrakt Den explosiva utvecklingen av integrerade kretsar har lett till dagens effektiva processorer. Enligt Moores lag kommer antalet transistorer som ryms på en krets att fördubblas var 18:e månad. Detta möjliggör att man kan konstruera mer avancerade processorer. Orsaken till dagens snabba processorer är inte endast högre klockfrekvenser utan även mer utvecklade och optimerade processorarkitekturer och effektiviseringsmetoder. Sådana metoder är: Pipelining; flera instruktioner utförs parallellt och ökar genomloppet av instruktioner i processorn, branch prediction; löser datakonflikter i pipelinen, out-of-order execution eller dynamisk exekvering; omorganisera instruktioner för att lösa datakonflikter. De flesta moderna processorer är RISC-processorer för ökad prestanda, vilket betyder att det finns ett relativt litet antal (enkla)instruktioner. Trots detta kan det för assembler-programmeraren se ut som om det skulle finnas ett stort antal instruktioner. Detta beror på att mikroarkitekturen översätter dessa instruktioner till RISC-instruktioner, så kallad mikrokod (microcode).

Page 3: Pipelining i RISC-processorn - Åbo Akademi

2

1. Inledning

Inom de närmaste 20 åren har det gått mycket framåt inom processorutvecklingen.

Processorerna har blivit mycket snabbare vilket här märkts i det allt bredare

användningsområdet för persondatorer. Datorerna har blivit bättre på att hantera bild,

ljud och datorgrafik. Men ”megahertz racet” har en aning avstannat verkar det som.

Klockfrekvenserna har inte ökat i samma rasande takt som de gjorde för några år sedan.

Istället har processortillverkarna satsat på att utveckla processorer som kan göra fler

saker parallellt. Att göra två saker samtidigt men på halva hastigheten ger ju samma

resultat. I vissa fall har t.o.m. klockfrekvenserna sjunkit.

Denna uppsats handlar om dessa metoder för parallellitet. Hur man kan göra fler

saker samtidigt på en uppsättning hårdvara. Dessa metoder leder även till en hel del

problem av olika slag som måste beaktas. Jag kommer att ta upp en hel del historik.

Hur det har varit tidigare och hur datorerna har förändrats.

2. Historia: Intel 8086 (1978) till Pentium 4 (2004)

Intels processorer är bakåtkompatibla. Objektkod från 1978 kan fortfarande köras på de

senaste processorerna i IA-32 arkitekturen.

IA-32 arkitekturens föregångare är 16-bits processorer. Sådana processorer är

8086 och 8088 som båda kom 1978. 8086 hade 16-bits register, 16 bits extern databuss

och en 20 bits adressering vilket gav 1 MB RAM. 8088 var liknande som 8086 förutom

att den hade en 8 bits databuss istället för 16 bitars.

Intel 80286 som kom 1982 var även den en 16 bits processor. Det nya med

80286 var minneshanteringen. Den hade protected mode för minnet. En funktion som

använder en basaddress (base address) och en gränsadress (limit adress) för att

förhindra programmet att gå utanför sitt eget minnesområde. 80286 använde en 24 bits

basadress, vilket gav 16 Mbyte minnesrymd.

Intel 80386 processorn, som kom 1985 var den första 32 bits processorn i

familjen. Den hade 32 bits register för både operander och adresser precis som många

Page 4: Pipelining i RISC-processorn - Åbo Akademi

3

av dagens processorer har. Den första halvan av de 32 bitarna motsvarar de 16 bitarna i

de tidigare arkitekturerna. På så vis är processorerna bakåtkompatibla. 32 bitar ger en

minnerymd på 4 GB vilket fortfarande gäller för dagens 32 bits processorer. 80386 gav

även virtuellt minne och sidbyten (paging) på 4 KB stora sidor. 386 gav även en del

parallellitet i exekveringen av instruktionerna.

80486 processorn som kom 1989 gav stöd för utökad parallellitet. Den hade en

5 stegs pipeline som kunde ha maximalt 5 instruktioner i exekvering samtidigt. Utöver

detta hade den ett 8 KB cacheminne integrerat i processorn.

1993 kom den första Pentium processorn. Parallelliteten utökades ytterligare

genom att en extra pipeline. Den hade 2 pipelines som kallades för u och v och gjorde

att 2 instruktioner kunde exekveras för varje klockcykel. Det integrerade cacheminnet

utökades från till det dubbla jämfört 80846. Pentium hade två 4 Kbyte cacheminnen, en

för programkod och en för data. Dessutom kom branch prediction med en hopptabell

(branch table) som var integrerad på kretsen [IA32IntMan].

1997 var det dags att utöka Pentium processorerna med MMX multimedia

extensioner. Där tillkom 57 nya instruktioner som använde flyttalsstacken för att

accelerera multimedia och kommunikations applikationer. MMX arbetar på många

korta dataelement. Metoden kallas single instruktion, multiple data (SIMD). Alltså

multipla dataelement i en enda instruktion [HenPat2005].

Pentium II och Pentium III processorn tillhör P6 mikroarkitekturfamiljen (1995-

1999). Pentium II ökade storleken av cacheminnet till 16 KB för nivå 1 cache och 265

för nivå 2 [IA32IntMan].

Pentium III introducerade nya multimediaextensioner: dataström SIMD (data

stream SIMD). Skillnaden var 8 nya register dubbelt så breda (128 bit), så att fyra 32

bits flyttalsinstruktioner kunde utföras parallellt. För förbättrad minnesprestanda SSE

inkluderade streaming store (dataström sparning) som kunde förbikoppla cache

minnena och skriva direkt till RAM [HenPat2005].

År 2000 kom den senaste och nuvarande Pentium 4 processor familjen som

bygger på NetBurst arkitekturen. Pentium 4 introducerade SSE2 som är en förbättrad

variant av SSE, och introducerade även Hyper Threading teknologin, som är en

funktion som ger en illusion av två logiska processorer. Detta för att kunna utnyttja alla

Page 5: Pipelining i RISC-processorn - Åbo Akademi

4

funktionella enheter bättre.[IA32IntMan] Det nya med SSE2 var att den kunde hantera

en ny datatyp: dubbel precision flyttal, alltså 64 bit. Med SSE2 kan man göra par av

dubbel precision flyttalsoperationer parallellt. Nästan alla av de 144 instruktionerna är

varianter ar av gamla SSE instruktioner som opererar på 64 bits flyttal [HenPat2005].

3. Principer för RISC-arkitektur

RISC (reduced instruction set) processorer är vad som används i dagens desktop

datorer. Tidigare användes CISC (complex instruction set computer). CISC

karakteriseras av ett stort antal instruktioner som processorn kan exekvera. Dessa

syns om man tittar på assemblerspråket för processorn. Instruktionerna består av

kraftfulla konstruktioner som liknar satser i ett högnivå språk som t.ex. C eller

FORTRAN. Principen med CISC är att: ”Gör inte i mjukvara vad du kan göra direkt i

hårdvaran”. RISC arkitekturerna däremot består av enkla instruktioner som är

betydligt enklare är instruktionerna i ett högnivåspråk. Det kommer att ta flera RISC-

instruktioner att göra samma sak än det tar CISC-instruktioner. Men det går snabbare

att utföra RISC-instruktionerna.

RISC konceptet är egentligen inte något nytt. Det fans maskiner redan på 60-

och 70-talet som hade RISC, men det var först på 80-talet som tekniken hade gått så

mycket framåt att RISC utgjorde något ordentligt alternativ till CISC. PÅ den tiden

fanns en debatt huruvida det var RISC eller CISC som gällde. Idag är det dock klart

att RISC- arkitekturer är den som ger mest fördelar.

Man kan ju undra: om RISC är så mycket snabbare varför använde man

överhuvudtaget CISC maskiner? Svaret till det är att med den tidens teknik så var

CISC en bättre väg att gå.

För det första så var inte kompilatorerna lika väl utvecklade som de är idag.

Det fanns kompilatorer men de gav inte någon speciellt optimal kod och slösade med

minne. Därför var det viktigt för programmerare att känna till assemblerspråket. Ett

kraftfullt assemblerspråk var användbart och gjorde programmerarens arbete enklare,

Page 6: Pipelining i RISC-processorn - Åbo Akademi

5

men det fanns också andra fördelar. Kraftfulla instruktioner sparade minne och tid vid

exekveringen.

En annan sak var att datorer på den tiden hade mycket begränsat

minnesutrymme. Därför var det bra att ha instruktioner som gjorde så mycket som

möjligt med en enda instruktion. Vissa av gamla tidens datorer kunde ha en

instruktion som gjorde en slinga (loop) i bara en enda maskininstruktion. Desto

mindre utrymme själva programkoden tog upp desto mer fanns det tillgängligt för

data.

En annan sak var att minnen dessutom var väldigt långsamma. De var mycket

långsammare än själva processorn. Så om en enda instruktion kan göra många

operationer samtidigt så kommer antalet hämtningar från minnet att bli färre.

Fram till 1980-talet satte man likhetstecken mellan en mer effektiv dator och

en större instruktionsuppsättning. På den tiden experimenterades det mycket med

detta att få mer avancerade instruktioner. Det visade sig dock att assembler-

programmerare kunde använda dessa instruktioner på ett bra sätt men inte

kompilatorerna.

Dat fanns olika orsaker till att man på 1980-talet började utveckla RISC-

processorer. En sak var att antalet transistorer på ett mikrochip ökade. Man ville då få

hela processorn att rymmas på ett enda mikrochip, och för att lycka med detta så

måste man skära ner på hårdvaran. Orsaken varför man ville ha processorn att

rymmas på ett anda chip var att det blev billigare. En annan sak var att man började

utveckla pipelining tekniker (parellell instruktions exekvering). CISC arkitekturen var

inte speciellt lämpad för pipelining eftersom den hade instruktioner av varierande

längd och med varierande exekveringstider.

De första RISC-processorerna var byggda på ett mycket begränsat utrymme

och hade därför en väldigt liten instruktionsuppsättning. Dessa processorer hade inget

stöd i hårdvaran för flyttalsberäkningar och vissa hade inte ens integer multiplikation.

Dessa sköttes med rutiner i mjukvaran som använde sig av flera enklare instruktioner,

en sorts mikrokod (microcode). Dessa tidiga RISC-processorer blev ingen större

framgång främst p.g.a. att de var nya och de använde för mycket minnesreferenser,

Page 7: Pipelining i RISC-processorn - Åbo Akademi

6

vilket ledde till att minnet blev en flaskhals. Detta problem löstes senare med cache-

minnen.

Det finns ett antal saker som anses vara karakteristiska för RISC-arkitekturer.

Dessa är:

• Pipelining

• Flyttalsberäkning i pipeline

• Alla instruktioner lika långa

• Delayed branching (fördröjt hopp, p.g.a. datakonflikter)

• Load/Store arkitekturer (endast speciella instruktioner får accessera minnet

direkt)

• Några enkla och väldefinierade addresseringstyper (addressing modes)

Det är dock inte sant att RISC processorer alltid är ”enklare” än CISC, utan snarare

tvärtom. Nya RISC processorer har avancerade tekniker så som: funktionell pipeline

och sofistikerade minnestekniker och kan även slutföra 2 eller flera instruktioner i

samma klockcykel (superscalar) [DowSev1998]. En del av Dessa tekniker behandlas i

nästa kapitel.

4. Effektiviseringsmetoder

I detta kapitel skall jag berätta om de metoder som finns för att effektivisera

instruktions-exekveringen i en modern RISC processor. Främst handlar det om

pipelining och metoder för att få själva pipeliningen att fungera som det är tänkt. En

annan benämning på pipelining är ILP (instruktion level parallellism), (parallellitet på

instruktionsnivå). När pipelinen blir mera komplicerad så kommer den att se väldigt

annorlunda ut från den enkla MIPS processor som jag har använt som exempel här. Ett

exempel på en sådan pipeline kommer i nästa kapitel som handlar om IA-32

arkitekturen.

Page 8: Pipelining i RISC-processorn - Åbo Akademi

7

4.1 Pipelining

Pipelining går ut på att instruktionerna överlappar varandra, man kan börja exekvera en

ny instruktion även om den första instruktionen inte ännu är slutförd. Detta ger nästan

samma prestanda som äkta parallell exekvering men med endast en uppsättning

hårdvara [DowSev1998]. Jämfört normal exekvering blir exekvering med pipelining i

allmänhet lika många gånger snabbare som det finns steg i pipelinen [HenPat1998]. I

pipeline exekvering så är varje instruktion uppdelad i ett antal delar. Dessa kunde vara

t.ex.

1. Instruktionshämtning (Instruction fetch IF) Processorn Hämtar en instruktion

från minnet

2. Instruktionsavkodning (Instruction decode ID) och Hämtande av operander.

Dessa kan vara register eller i minnet.

3. Exekvering (Execution EXE)

4. Minnes access (Memory access MEM)

5. Skrivning till register (Write back WB)

Jag skall förklara hur dessa steg fungerar. Det första är instruktionshämtningen. Ett

speciellt register Programräknaren (program counter) håller reda på var nästa

instruktion finns. En instruktion hämtas från minnet från adressen som specificeras av

programräknaren. Programräknaren måste sedan uppdateras. I en arkitektur med 32 bits

ord och om inget hopp sker så kommer programräknaren att ökas med 4 för att sedan

peka på nästa 32 bits instruktion. Därefter görs avkodning på instruktionen. Det går till

så att man plockar ut de enskilda bitarna i instruktionen. Det är färdigt bestämt vilka

bitar som specificerar vad. Vissa bitar kan t.ex. bestämma vad för sorts instruktion det

är frågan om. Om det är en hoppinstruktion en aritmetisk instruktion en minnesaccess-

instruktion etc. Vissa av bitarna kan specificera minnesaddresser andra register.

Hårdvaran avkodar dess bitar och styr dem till rätta platser. Bitarna som anger vilken

sorts instruktion det är frågan om kopplas till styrenheten. Styrenheten innehåller logik

som på basen av vilken sorts instruktion det är frågan om kommer att koppla logiken i

Page 9: Pipelining i RISC-processorn - Åbo Akademi

8

processorn på olika sätt. T.ex. om det är frågan om en aritmetisk logisk instruktion med

2 register som operander ser styrenheten till att 2 register kan läsas från registerbanken.

I nästa fas hämtas data från minnet eller från register som är specificerade i

bitarna som avkodades i föregående fas. När operanderna har hämtats så utförs någon

slags exekvering på dessa i den aritmetisk logiska enheten (ALU). Det kan vara t.ex. en

aritmetisk operation på 2 integer tal eller att beräkna en effektiv adress med hjälp av

innehållet i ett register och en konstant. I nästa steg; minnes access steget görs

eventuellt en läsning av eller skrivning till minnet och det är en sådan instruktion. I det

sista steget skrivs eventuellt ett resultat tillbaka till ett register.

Hela iden med att dela upp en instruktions exekvering i olika faser är att man

skall kunna påbörja en ny instruktion varje klockpuls. Så att när den första

instruktionen har gått vidare till sitt andra skede (instruktions avkodning) så kan nästa

instruktion sättas in, vilket betyder att den instruktionen är i sitt

instruktionshämtningsskede. Förloppet har illustrerats i fig1 (från [HenPat2003]).

fig1. Bilden visar exekveringen av 5 instruktioner i pipelinen. I den första klockcykeln

börjar instruktion i, sitt första skede. I nästa klockcykel kommer instruktion i att ha

slutfört sitt första skede (IF-steget) och överfört resultatet till nästa steg (ID-steget),

vilket ger möjlighet för instruktion i+1 att påbörja sin exekvering.

För att man skall kunna göra allt detta i en pipeline så måste det finnas register som

lagrar data mellan en klockpuls till en annan. Dessa register lagrar allt som fanns i den

ursprungliga instruktionen, plus hämtad data som behövs senare, uträknade resultat och

styrsignaler. Dessa register sätts in mellan de olika stegen: IF, ID, EXE, MEM, WB.

fig2 (från [HenPat2003]) illustrerar detta. I bilden är de svarta balkarna pipeline

Page 10: Pipelining i RISC-processorn - Åbo Akademi

9

registren. Och mellan dem finns hårdvaran som sköter varje av de 5 stegen i

exekveringen [HenPat2003].

fig2. Denna figur visar hårdvaran som behövs för att genomföra enkel pipelining i en

MIPS-processor. De olika delarna: IM, REG, ALU etc. separeras av pipeline-register

och motsvarar de 5 olika instruktionsstegen i fig 1.

I en pipeline så är genomloppet (throughput) det antalet instruktioner som kan slutföras

på en tidsenhet. Desto oftare en instruktion blir färdig desto högre blir genomloppet.

Tiden det tar att föra en instruktion från ett steg i pipelinen till ett annat är definierat

Page 11: Pipelining i RISC-processorn - Åbo Akademi

10

som en processorcykel (processor cycle). Den undre gränsen på en processorcykel

bestäms av det längsta steget (det steg som tar längs tid att utföra) i pipelinen.

Det finns olika sätt att mäta prestanda i en pipeline. Man kan tänka sig att

pipelining sänker antalet klockcykler per instruktion. Ett annat sätt att se på saken är att

pipelining minskar tiden för en klockcykel. I en konstruktion utan pipelining kan det

hända att det tar 5 eller flera klockcykler att slutföra en instruktion, men med pipelining

kan man (i bästa fall) få en instruktion slutförd per klockcykel. En annan möjlighet är

att man har en icke pipeline processor som slutför varje instruktion i en mycket lång

klockcykel. I det fallet gäller det ju att pipelining förkortar klockcykeltiden.

Det finns situationer där nästa instruktion inte kan exekveras i påföljande

clockcykel som det är meningen. Dessa situationer kallas konflikter (hazards). Det finns

flera olika datakonflikter.

Den första är något som kallas en strukturell konflikt (structural hazard). Det

innebär att två instruktioner i olika faser av sin exekvering försöker komma åt samma

hårdvaruenhet t.ex. minnet. Detta kan lösas t.ex. genom att duplicera minnet eller ha

flera cacheminnen.

Den andra konflikten är en kontrollkonflikt (control hazard). Det har att göra

med att man måste göra ett beslut om hopp innan man har räknat ut de värden som

behövs för att avgöra om hoppet skall göras eller inte. Detta löses i praktiken med att

estimera hopp (branch prediction) som tas upp i kapitel 4.4.

Den tredje och sista typen av konflikt är datakonflikten (data hazard). Detta

innebär att data som ännu inte har beräknats behövs i en annan beräkning. Detta kan

lösas med hjälp av återkoppling d.v.s. att man sätter in extra ledningar som förbinder de

olika enheterna direkt, alltså man kan t.ex. få ett värde direkt från ALU:s utgångar

istället för att vänta tills resultatet har skrivits tillbaka till register. För att detta skall

funka så behövs en del extra ledningar och logik i kontrollenheten [HenPat1998].

Datakonflikter kan även lösas mera effektivt med dynamisk exekvering, vilket innebär

att instruktionernas ordning kastas om för att undvika datakonflikter [HenPat2003].

Dynamisk exekvering tas upp i kapitel 4.3.

Page 12: Pipelining i RISC-processorn - Åbo Akademi

11

4.2 Pipelining av funktionella enheter Det är viktigt att man kan utöka pipelinen för att fungera även på enskilda funktionella

enheter som t.ex. enheter för flyttalsberäkning och multiplikation, vilka båda är

operationer som kan ta ett stort antal klockcykler att utföra.

Att utgå från att alla flyttalsoperationer skulle göras i en klockcykel blir väldigt

opraktiskt. Det skulle betyda att detta enda steg skulle bli mycket långt och därför kräva

en långsam klocka, eftersom hela systemets hastighet är bestämt av det långsammaste

steget i pipelinen.

Man kan tänka sig att man har en likadan pipeline för flyttal som för vanlig

integerberäkning. Man gör 2 förändringar från denna.

1. Exekveringssteget (EXE) kan repeteras så många gånger som det behövs för

att slutföra flyttalsberäkningen.

2. Det kan finnas flera flyttalsenheter.

När man funderar på dessa problem så är det speciellt 2 saker som man bör ta i

betraktande: bundenhet (latency) och repetitionsintervall (repeat interval). Latency

definieras som antalet överlappande instruktioner mellan en instruktion som ger ett

resultat och en instruktion som använder samma resultat. Repetitionsintervall är antalet

cykler som måste passera mellan två instruktioner av samma typ. Typiska exempel på

latency och repetitionsintervall ges i fig3 (från [HenPat2003]).

fig3. Tabellen visar bundenhet (latency) och repetitionsintervall för olika typer av

instruktioner.

Page 13: Pipelining i RISC-processorn - Åbo Akademi

12

I det här fallet har integer aritmetiska operationer en latency som är 0, vilket betyder att

resultatet kan användas redan i nästa klockcykel. Load instruktioner har en latency som

är 1 eftersom resultatet av dem kan användas först efter att en clockcykel har passerat

emellan. Det är i den clockcykeln som minnet accesseras med den effektiva adressen

som beräknades i Ex-steget, och det är därför logiskt att resultatet av en LOAD finns

tillgängligt först efter detta steg

Latency för en pipeline definieras som en clockcykel färre än djupet på

exekveringsdelen av pipelinen (antalet steg från EXE steget till steget som producerar

ett resultat). Fig4 ger ett exempel på en processor med 3 olika flyttals exekverings-

enheter och en vanlig integerenhet. Man kan se att det finns ett samband mellan latency

för de olika flyttalsoperationerna och djupet på motsvarande enhets pipeline. Djupet på

pipelinen är alltid 1 steg större än latency för motsvarande operation. För att få en högre

klockfrekvens så måste designern lägga färre logiska operationer i varje steg. Man byter

alltså en högre klockfrekvens mot högre latency för operationer. Processorn i fig4 (från

[HenPat2003]) kan ha 4 flyttalsadditioner och 7 multiplikationer i samtidig exekvering i

pipelinen. Divisionsenheten kan ha endast en division i exekvering åt gången. Det

betyder att när en divisions operation har startat så måste man vänta 25 clockcykler,

tills hela operationen är färdig innan nästa divisions operation kan matas in i enheten.

Detta beror på flyttalsdivisionens höga repetitionsintervall; 25, som syns i fig3.

Division är därför en mycket krävande operation som bör undvikas så långt som

möjligt. I en konstruktion som i fig4 så kan olika konflikter (hazarder) uppstå.

1. Olika strukturella konflikter kan uppstå. Eftersom operationerna är av

varierande längd.

2. När instruktionerna är av varierande längd så kommer de att slutföras i annan

ordning än vad de var i den ursprungliga koden

[HenPat2003].

Page 14: Pipelining i RISC-processorn - Åbo Akademi

13

fig4. Så har kan det se ut om man utökar MIPS-hårdvaran med flerstegs funktionella

enheter för flyttalsmultiplikation –addition och –division.

4.3 Dynamisk Exekvering

Det finns två olika sätt att optimera en dator med pipelining. En av dessa är att göra det

statiskt, d.v.s. i mjukvaran. En annan teknik är att göra det dynamiskt, alltså i

hårdvaran. Dynamisk exekvering hör till den senare kategorin.

Dynamisk exekvering är en viktig teknik som med hjälp av hårdvaran kastar om

ordningen på instruktionerna för att undvika datakonflikter. Tekniken har en rad

fördelar. Den kan lösa konflikter som var okända vid kompileringen, och underlättar

kompilatorns arbete. Dessutom gör den möjligt att kod som var kompilerad för en viss

pipeline även kommer att fungera bra på någon annan pipeline. Nackdelen med

dynamisk exekvering är att hårdvaran blir mycket mera komplicerad.

Tänk dig följande exempel. Man vill addera ihop två operander från minnet och

spara tillbaka resultatet till en minnesplats. I vissa CISC arkitekturer skulle detta kunna

göras med en enda instruktion. I en typisk RISC arkitektur å andra sidan så krävs 4

instruktioner för att göra detta: 2 load, 1 add och en store. Dessa instruktioner kan inte

matas sekventiellt i de festa pipelines utan man blir tvungen att stanna pipelinen vid

Page 15: Pipelining i RISC-processorn - Åbo Akademi

14

konflikter. Man kan lösa detta antingen statiskt genom att påverka kompilatorn, eller

också kan det göras dynamiskt i hårdvaran. Men om den dynamiska scheduleringen

görs bra så får man god prestanda. Därför använder många nya processorer (t.ex.

Pentium III och 4) tekniken att ta in komplicerade instruktioner som mikroarkitekturen

sedan översätter till dynamiskt schedulerade RISC operationer.

Problemet med out-of-order execution (exekvering i oordning) är att den kan

leda till olika strukturella konflikter. Jag skall visa en enklare metod kallad

scoreboarding (scorekort) som håller reda på de olika instruktionerna för att undvika

strukturella konflikter. Iden med en scorekort är att hålla en frekvens om 1 instruktion

per klockpuls, genom att starta en operation så tidigt som möjligt. Så att när en

instruktion blir stannad (stalled) i pipelinen så kan ändå nästa instruktion starta,

förutsatt att den inte är beroende av någon annan instruktion i exekvering. För att hålla

reda på vilka instruktioner som kan starta har man ett scorekort. För att man skall ha

någon nytta av out-of-order execution så måste man ha flera instruktioner i sitt EXE

steg samtidigt, och flera funktionella enheter med hög latency.

Varje instruktion går genom scorekortet som konstruerar en tabell över

databeroenden. Detta steg kan sägas motsvara ID steget i en vanlig pipeline.

Scorekortet avgör sedan när en instruktion kan läsa sina operander och börja

exekveringen. Om scorekortet avgör att instruktionen inte kan börja sin exekvering så

observerar den alla förändringar i processen och bestämmer när en instruktion kan

starta. Scorekortet avgör också när instruktionen kan skriva sitt resultat till

destinationsregistret. Fig5 (från [HenPat2003]) visar hur en processor med scorekort

kunde se ut.

Page 16: Pipelining i RISC-processorn - Åbo Akademi

15

fig5. Bilder visar en implementering av score-kort (score card) för att åstadkomma en

enkel form av dynamisk exekvering.

De vertikala linjerna är kontrolllinjer. Som utgående från scorekortet kontrollerar hur

dataflödet sker över bussarna (de horisontala linjerna). Varje instruktion i scorekort-

systemet går genom 4 steg i exekveringen. Stegen är som följande.

1. Issue (utgång). Om en funktionell enhet för instruktionen är ledig och ingen

annan aktiv instruktion har samma destinationsregister styr scorekortet

instruktionen till rätt funktionella enhet, varefter scorekortet uppdaterar sina

interna tabeller.

2. Läsning av operanderna. Skorekortet håller reda på tillgängligheten av

källoperanderna. En källoperand är tillgänglig om ingen annan tidigare startad

operation kommer att skriva den. När källoperanderna är tillgängliga säger

scorekortet till den funktionella enheten att läsa operanderna och starta

exekveringen.

Page 17: Pipelining i RISC-processorn - Åbo Akademi

16

3. Exekvering. Enheten börjar sin exekvering. När den är färdig anmäler den det

till scorekortet.

4. Skriv resultatet. När scorekortet får reda på att operationen är färdig kontrollerar

den on det finns någon datakonflikt: den kontrollerar om någon tidigare

operation borde läsa registret innan det ändras.

Ett exempel på en sådan här konflikt kan illustreras med följande assemblerkod.

DIV f0, f2, f4

ADD f10, f0, f8

SUB f8, f8, f14

ADD instruktionen har en källoperand f8 som är samma som SUB-instruktioens

destinationsoperand. Men ADD operationen är fördröjd eftersom den är beroende av

den långa instruktionen DIV. Här kommer scoreboarden att fördröja SUB

instruktionens skriv skede tills ADD instruktionen har hunnit läsa (det gamla värdet på)

f8 [HenPat2003].

4.4 Branch prediction

Så kallade hopp (branches) kan även orsaka konflikter i en pipeline. Dessa hopp

uppstår alltid när man i källkoden har en loop eller if-sats. Hopp orsakar kontroll-

konflikter (control hazards). Antalet hopp som görs när man kör ett program är

vanligen ganska många, så det är nödvändigt att ha någon form av branch prediction

(uppskattning av hopp). Branch prediction metoder går ut på att i förtid kunna gissa

vart nästa hopp skall ske. På så sätt behöver man inte fördröja pipelinen om man har

gissat rätt. Jag skriver här om dynamisk branch prediction som är implementerad i

hårdvaran. I dynamisk branch prediction är uppskattningen beroende av hur

programmet beter sig under exekvering. Det finns även statiska branch prediction

metoder som görs av kompilatorn innan programmet startar.

Den enklaste formen av branch prediction är en branch prediction-buffer (hopp

uppskattnings buffert). Bufferten är en liten bit minne som är lagrar historik över ett

visst hopp. I det enklaste fallet har man bara en bit. Biten anger om det har gjorts ett

Page 18: Pipelining i RISC-processorn - Åbo Akademi

17

hopp eller inte inom den närmste tiden. Så om biten är satt utgår man från att hoppet

kommer att göras och man börjar ladda in nästa instruktion från hoppaddressen. Om

uppskattningen visade sig vara fel så inverterar man biten. Denna metod har visat sig

vara dålig, så därför använder man istället en 2 bitars buffert. I ett sådant system måste

uppskattningen missa 2 gånger förrän den ändras. Denna variant kommer att ge rätt

uppskattning oftare än varianten med 1-bits buffert [HenPat2003].

5. IA-32 arkitekturen

IA-32 arkitekturen är Intels processorfamilj, startande från 8086 år 1978. IA-32 är

världens populäraste arkitektur för desktop datorer. Senaste modellerna är Pentium 4

och Pentium M, speciellt utformad för bärbara datorer. Nyare Pentium datorer så som

Pentium II, III och 4 bygger på avancerade pipelining metoder [HenPat2005].

5.1 Instruktionsuppsättning och assemblerprogrammering

Instruktionerna i IA-32 kan indelas i: Generella instruktioner, flyttalsinstruktioner,

MMX-instruktioner, olika sorters SSE-instruktioner, 64-bits instruktioner och speciella

systeminstruktioner.

De generella instruktionerna är de vanliga instruktioner som kan användas för

att skriva enklare program utan desto mera optimering eller prestandakrav. De generella

intruktionerna är sådana som finns tillgängliga på alla Intels processorer. Uppsättningen

generella instruktioner innehåller: aritmetiska instruktioner (add sub etc.),

dataflyttnings instruktioner, logiska instruktioner, dataflöde- och stringoperationer.

Instruktionerna kan arbeta på data som finns i de generella registren EAX, EBX, ECX,

EDX, EDI, ESI, EBP, och ESP (se fig6 ) och data som finns i minnet. De kan också

operera på addresser som finns i minnet eller de generella registren. Även de kortare 16

bits segmentregistren: CS, DS, SS, ES, FS, och GS kan användas för att få fram

addresserna [IA32IntMan].

Page 19: Pipelining i RISC-processorn - Åbo Akademi

18

fig6. (från [HenPat2005]) Registren i IA-32 arkitekturen. 80386 processorn var den

första i IA-32 familjen som använde 32 bits instruktioner och register. I den gamla 16

bits arkitekturen, som återfanns i 8086, 8088, och 80286 så var de allmänna registren

namngivna som: AX, BX, CX, DX. Så när arkitekturen ändrades till 32 bit så behöll

man dessa namn, men man satte ett E framför dem för att ange att de var förlängda

(extended). Så registren kallas nu EAX, EBX, ECX etc. I 80386 arkitekturen finns 7

allmänna (general purpouse) register. Förutom de allmänna registren finns även 16

bits register som har hållits samma från den tidigare arkitekturen. Dessa är 16 bits

registren: CS, SS, DS, ES, FS och GS. Dessa är segmentregister. Till exempel så

innehåller CS registret en pekare till platsen i minnet där kodsegmentet börjar

[HenPat2005].

Page 20: Pipelining i RISC-processorn - Åbo Akademi

19

De aritmetiska, logiska, data flyttnings (data transfer) operationerna är alla två-

operands instruktioner. Operand 1 måste vara både destinationsoperand och första

källoperand. Detta register alternativt en minnesreferens som är destination kommer

alltså att skrivas över. Operand 1 ett kan vara antingen register eller en minnesreferens.

Operand 2 kan vara register, konstant eller minnesreferens. Det finns ingen instruktion i

vilken båda operanderna är minnesreferenser. Det finns 7 olika addresseringslägen

(addressing modes) i IA-32. En minnes operand kan använda vilka addresseringslägen

som helst, men det finns en begränsning på vilka register som får användas. T.ex. i

register indirekt läget där man har en adress i ett register så får man inte använda ESP

eller EBP registret [HenPat2005].

5.2 Mikroarkitekturen

”Mikoarkitektur är en metod för att designa komplicerade kontrollenheter. Den

använder en enkel hårdvarumotor som kan programmeras att implementera mer

komplicerade instruktionsuppsättningar. Mikroprogrammering används idag för att

implementera delar av en komplicerad instruktionsuppsättning som t.ex. i en Pentium

eller i en dator för specialanvändningsområden” [HenPat2005].

P6 är mikroarkitekturen som användes i Pentium Pro Pentium I, Pentium II och

Pentium III. Den är föregångare till NetBurst mikroarkitekturen som finns i Pentium 4.

P6 är en dynamiskt schedulerad processor. Som översätter varje IA-32 instruktion till

en serie mikrooperationer, liknande vanliga RISC operationer. En serie på upp till 3 IA-

32 instruktioner hämtas och översätts till mikrooperationer varje klockcykel. Om en IA-

32 instruktion kräver fler än 4 mikrooperarioner så är det implementerat med hjälp av

en mikrokodsekvens som genererar mikrooperationerna i flera klockcykler.

Mikrooperationerna är sedan exekverade med hjälp av en dynamisk schedulerad

pipeline.

Page 21: Pipelining i RISC-processorn - Åbo Akademi

20

5.3 Pipelinen i Pentium 4

Pipelinen i Pentium 4 är en sofistikerad dynamiskt schedulerad pipeline som kan utföra

i medeltal 3 mikrooperationer per klockcykel. När det gäller design av sofistikerade

processorer så är det svårt att skilja åt de olika delarna från varandra. De funktionella

enheterna, cache, register filen, instruktionsutgång (issue) och pipelienekontroll smälter

ihop till en enda enhet. Denna brukar allmänt kallas mikroarkitekturen. Fig7 (från

[HenPat2005]) visar en modell av mikroarkitekturen hos Pentium 4.

Fig7. Schematisk bild över mikroarkitekturen i Pentium4.

Pentium 4 har många förbättringar jämfört med sin föregångare III. Dessa är:

1. Pipelinen är dubbelt så djup (20 steg jämfört tidigare 10)

2. Mera funktionella enheter (7 tidigare 5)

Page 22: Pipelining i RISC-processorn - Åbo Akademi

21

3. Kan ha ett större antal operationer i samtidig exekvering (126 tidigare 40)

4. Bättre minneshantering

I modellen i fig7 kan man se många olika sorters köer. Där finns en Mikrooperationskö

(Microoperation que), Integerkö och en flyttals kö. De omfattande köerna tillåter 126

mikrooperationer att vara ”i flykt” samtidigt. I bilden ser det ut som om det skulle

finnas endast 6 funktionella enheter och inte 7, men flyttals enheten räknas som två

därför att den har en skild enhet för flyttning av flyttal . Load och store enheterna består

vardera av två olika delar. Första delen är ansvarig för addressberäkningen och den

andra för minnesaccess. Integer ALU enheterna kör på dubbel klockfrekvens jämfört

med vad den övriga processorn gör, vilket betyder att vardera integer enhet kan slutföra

två integer operationer per vanlig klockcykel. Multimiediaextensioner så som MMX

och SSE2 är även inbyggda i flyttalsenheten [HenPat2005].

5. Avslutning

Processorarkitektur är ett avancerat område i pågående utveckling. Det är många nya

begrepp att lära sig och även om man tror sig veta grunderna i datorarkitektur kan man

lätt känna sig borttappad. Också tillkommer ju det faktum att det finns många olika

sorters processorer och de flesta är väldigt olika, med olika instruktionsuppsättningar

etc. En sak som jag kom att tänka att tänka på är hur primitiva de gamla processorerna

verkar när man jämför med de avancerade konstruktioner som byggs i dag till desktop

datorer. Man är nästan förvånad att dessa datorer fungerade överhuvudtaget, men det

vet ju alla som har, eller har haft en gammal dator att den ofta fungerar till samma saker

bara lite långsammare.

I denna uppsats har skummat lätt på ytan av ämnet processordesign utan att gå

djupt in de avancerade sakerna som finns i den moderna processorn. Det finns mycket

annat som är viktigt när man designar och bygger processorer men som jag inte har

tagit upp. Sådana saker är beräkning av en processors prestanda på en teoretisk nivå

Page 23: Pipelining i RISC-processorn - Åbo Akademi

22

innan man bygger och mätning och testning av en redan färdig processor. Jag har heller

inte tagit upp något speciellt om de minnestekniker som finns.

Litteraturlista:

[DowSev1998] Kevin Dowd & Charles Severance: High Performance Computing,

O’ Reilly, 1998

[HenPat2003] John L. Hennessy & David A. Pattersson: Computer Architecture, A

Qantitative Approach, Morgan Kaufmann, 2003

[HenPat2005] John L. Hennessy & David A. Pattersson: Computer Organization &

Design, The Hardware/Software Interface, 3rd ed, Morgan Kauffmann, 2005

[HenPat1998] John L. Hennessy & David A. Pattersson: Computer Organization &

Design, The Hardware/Software Interface, 2nd ed, Morgan Kauffmann, 1998

[IA32IntMan] IA-32 Intel® Architecture Software Developer's Manual

<http://www.intel.com/design/pentium4/manuals/index_new.htm>