Samenvatting Processorarchitectuur - martenserver.com

advertisement
Processorarchitectuur
Samenvatting lesnota’s
en
Gestructureerde Computerarchitectuur.
Processorarchitectuur ............................................................................................................... 1
Samenvatting lesnota’s.............................................................................................................. 1
en ................................................................................................................................................ 1
Gestructureerde Computerarchitectuur. .................................................................................. 1
1
Inleiding ............................................................................................................................. 5
1.1
Gestructureerde computerarchitectuur ______________________________________ 5
1.1.1
1.1.2
1.1.3
2
Talen, niveaus en virtuele machines _______________________________________________ 5
Hedendaagse machines met meerdere niveaus _______________________________________ 5
De evolutie van machines met meerdere niveaus _____________________________________ 6
Organisatie van computersystemen .................................................................................. 7
2.1
Processor _______________________________________________________________ 7
2.1.1
2.1.2
2.1.3
2.1.4
2.1.5
2.1.6
2.2
De organisatie van de CPU ______________________________________________________
Het uitvoeren van een instructie __________________________________________________
RISC versus CISC _____________________________________________________________
Ontwerpprincipes voor tegenwoordige computers ____________________________________
Parallellisme op instructieniveau __________________________________________________
Parallellisme op processorniveau _________________________________________________
Primair geheugen _______________________________________________________ 10
2.2.1
2.2.2
2.2.3
2.2.4
2.2.5
Bits _______________________________________________________________________
Geheugenadressen ____________________________________________________________
De volgorde van bytes _________________________________________________________
10
Cachegeheugen ______________________________________________________________
10
10
10
10
2.3
11
2.4
Input/Output __________________________________________________________ 11
2.4.1
3
7
7
8
8
9
9
Bussen, interrupts ____________________________________________________________ 11
Het niveau van de digitale logica .................................................................................... 13
3.1
13
3.2
13
3.2.1
3.2.2
3.2.3
3.2.4
3.3
13
13
Rekenkundige circuits _________________________________________________________ 13
Klokken ____________________________________________________________________ 13
Geheugen _____________________________________________________________ 13
3.3.1
3.3.2
3.3.3
3.3.4
3.3.5
3.3.6
3.3.7
3.3.8
3.3.9
3.4
13
13
13
Geheugenorganisatie __________________________________________________________
Geheugenchips ______________________________________________________________
RAM en ROM _______________________________________________________________
Aansluiten van geheugenchips __________________________________________________
Koppeling tussen microprocessor en randapparaten __________________________________
Adressering van de IO _________________________________________________________
CPU-chips en BUSSEN __________________________________________________ 16
3.4.1
3.4.2
3.4.3
3.4.4
3.4.5
3.4.6
CPU chips __________________________________________________________________
Computerbussen _____________________________________________________________
Busbreedte __________________________________________________________________
Het klokken van een bus _______________________________________________________
Busarbitrage ________________________________________________________________
Busoperaties ________________________________________________________________
16
16
16
17
17
17
3.5
18
3.6
Voorbeelden van bussen _________________________________________________ 18
3.7
Interfaces _____________________________________________________________ 18
3.7.1
3.7.2
4
13
14
14
15
15
15
IO-chips ____________________________________________________________________ 18
Adresdecodering _____________________________________________________________ 18
Het niveau van de microarchitectuur ............................................................................. 19
4.1
4.1.1
4.1.2
4.1.3
4.2
4.2.1
4.2.2
4.2.3
4.2.4
4.3
4.3.1
4.3.2
Een voorbeeld van een microarchitectuur ___________________________________ 19
Het datapad _________________________________________________________________ 19
Micro-instructies _____________________________________________________________ 20
Micro-instructie besturing: de MIC-1 _____________________________________________ 21
Een voorbeeld ISA: IJVM ________________________________________________ 22
Stapels _____________________________________________________________________
Het IJVM-geheugenmodel _____________________________________________________
De IJVM instructieset _________________________________________________________
Compileren van Java naar IJVM _________________________________________________
22
22
23
23
Een voorbeeld van een implementatie ______________________________________ 23
Micro-instructies en hun notatie _________________________________________________ 23
Implementatie van IJVM met de MIC-1 ___________________________________________ 23
4.4
Ontwerp van het microarchitectuurniveau __________________________________ 24
4.4.1
4.4.2
4.4.3
4.4.4
4.4.5
4.5
Snelheid versus kosten ________________________________________________________
Reductie van de lengte van het executiepad ________________________________________
De MIC-2: een ontwerp met prefetching: de MIC-2 __________________________________
Een ontwerp met pipelining: de MIC-3 ____________________________________________
Pipelining in zeven stadia: de MIC-4 _____________________________________________
Verbetering van de prestaties _____________________________________________ 26
4.5.1
4.5.2
4.5.3
4.5.4
5
Cachegeheugen ______________________________________________________________
Sprongvoorspellingen _________________________________________________________
Out-of-order uitvoering en herbenoemen van registers ________________________________
Speculatieve uitvoering ________________________________________________________
26
29
30
30
Het niveau van de instructiesetarchitectuur................................................................... 31
5.1
31
5.2
31
5.3
Instructieformaten ______________________________________________________ 31
5.3.1
5.3.2
5.3.3
5.3.4
5.3.5
5.4
Ontwerpcriteria voor instructieformaten ___________________________________________ 31
Expanderende opcodes ________________________________________________________ 31
32
32
32
Adressering ____________________________________________________________ 32
5.4.1
5.4.2
5.4.3
5.4.4
5.4.5
5.4.6
5.4.7
5.4.8
5.4.9
5.4.10
6
24
24
25
25
25
Adresseringsmodi ____________________________________________________________
Onmiddellijke adressering ______________________________________________________
Absolute of directe adressering __________________________________________________
Registeradressering ___________________________________________________________
Registerindirecte adressering ___________________________________________________
Geïndexeerde adressering ______________________________________________________
Basisgeïndexeerde adressering __________________________________________________
Relatieve adressering__________________________________________________________
Adresseringsmodi voor sprongopdrachten _________________________________________
Orthogonaliteit van opcodes en adresseringsmodi ___________________________________
32
32
32
32
32
33
33
33
33
33
Het assembleertaalniveau ............................................................................................... 34
6.1
6.1.1
6.1.2
6.1.3
6.1.4
6.2
6.2.1
6.3
Inleiding tot assembleertalen _____________________________________________ 34
Wat is assembleertaal? ________________________________________________________
Waarom assembleertaal gebruiken _______________________________________________
Een statement in assembleertaal _________________________________________________
Pseudo-instructies ____________________________________________________________
34
34
34
34
Macro’s _______________________________________________________________ 35
Defenitie, aanroep en expansie van macro’s ________________________________________ 35
Het assembleerproces ___________________________________________________ 35
6.3.1
6.3.2
6.3.3
6.4
6.4.1
6.4.2
6.4.3
6.4.4
Two-pass-assemblers _________________________________________________________ 35
Pass 1______________________________________________________________________ 36
Pass 2______________________________________________________________________ 36
Linken en laden ________________________________________________________ 36
Door de linker uitgevoerde taken ________________________________________________
Structuur van een objectmodule _________________________________________________
Bindingstijdstip en dynamische relocatie __________________________________________
Dynamisch linken ____________________________________________________________
36
37
37
38
1 INLEIDING
1.1 Gestructureerde computerarchitectuur
1.1.1 Talen, niveaus en virtuele machines
Vertaling: Elke instructie in een taal T1 wordt vervangen door een equivalente instructie in
een taal T0
Interpretatie: Een programma in T0 leest de instructies in taal T1 en voert equivalente
instructies uit T1 uit.
Onderstel een virtuele machine die taal T1 als machinetaal heeft. Dit is een virtuele machine.
Elke taal definieert een machine, en elke machine definieert een taal. Hoe complexer de taal
van de machine, hoe moeilijker en duurder het is om ze te bouwen.
Een computer kan bestaan uit meerdere niveaus, waarbij elk niveau als een virtuele machine
kan worden beschouwd. Iemand die programma’s wil schrijven voor een bepaald niveau,
hoeft enkel dat niveau te kennen.
1.1.2 Hedendaagse machines met meerdere niveaus
Het microarchitectuur niveau is het niveau boven de digitale logica. Het bestaat uit een
collectie van registers en een ALU. De ALU staat in voor het uitvoeren van eenvoudige
arithmetische en logische berekeningen.
De registers en de ALU zijn met elkaar verbonden door middel van het datapad. De
voornaamste taak van het datapad bestaat er in registers te selecteren en de ALU ermee te
laten werken. Deze taken worden hetzij door een microprogramma gerealiseerd, hetzij
rechtstreeks door hardware.
Indien het datapad door software wordt gerealiseerd, is het programma een interpreter voor
instructies van het hogere niveau (het instructiesetarchitectuur niveau, ISA-niveau). Het
niveau is verbonden met de instructieset van de machine.
Het volgende niveau (3) is het besturingssysteem architectuur niveau. Dit is meestal een
gemengd niveau. Naast de instructies van het ISA niveau, zijn er ook een aantal nieuwe
instructies. Verder is er nog een andere geheugenorganisatie, en de mogelijkheid om
programma’s parallel uit te voeren. De faciliteiten van dit niveau worden uitgevoerd door een
interpreter die op niveau twee loopt. Deze interpreter is het operating system. Sommige
instructie worden rechtstreeks door het microprogramma van het hogere niveau uitgevoerd,
andere worden geïnterpreteerd door het besturingssysteem.
Samenvattend: computers zijn opgebouwd uit een reeks van niveaus, elk gebouwd op zijn
voorganger. Elk niveau stelt een andere abstractie voor. De verzameling datatypen, operaties
en faciliteiten op elk niveau wordt de architectuur genoemd.
1.1.3 De evolutie van machines met meerdere niveaus
Het microprogrammeren werd uitgevonden om de complexiteit van het ISA niveau en de
schakelingen op het niveau van de digitale logica te verlagen. Er werd een interpreter
toegevoegd bovenop de ISA laag. Door deze toevoeging kon de instructieset van de ISA laag
verkleind worden.
Het besturingssysteem werd gemaakt om het inlezen en compileren van programma’s te
automatiseren. Door de tijd heen werden besturingssystemen complexer, en worden ze zelfs
als geheel nieuw niveau aanzien.
Na verloop van tijd ontstonden time sharing systemen waarop meerdere programmeurs
tegelijk konden werken.
2 ORGANISATIE VAN COMPUTERSYSTEMEN
2.1 Processor
De functie van de CPU bestaat erin de instructies van programma’s uit het hoofdgeheugen
een voor een op te halen, te analyseren en uitvoeren. De verschillende componenten van de
digitale computer zijn intern verbonden door middel van een bus.
De CPU bevat een geheugen dat bestaat uit een aantal registers. Het belangrijkste van deze
registers is de programmateller. Deze bepaalt het adres van de volgende uit te voeren
instructie. Het instructieregister bevat de instructie in uitvoering.
2.1.1 De organisatie van de CPU
Het datapad bestaat uit registers, een ALU en bussen om beiden te verbinden. De ALU voert
eenvoudige bewerking uit met zijn invoerregisters, en plaatst het resultaat in het
uitvoerregister.
De meeste instructies kunnen worden ondergebracht in twee categorieën: register-register
instructies en register-geheugen instructies.
2.1.2 Het uitvoeren van een instructie
De CPU voert elke instructie uit in een reeks kleine stappen:







Plaats de volgende instructie uit het geheugen in het instructieregister
Incrementeer de progammateller
Bepaal het type van de opgehaalde instructie
Als de instructie een woord uit het geheugen gebruikt, bepaal dan de plaats van dit
woord
Haal het geheugenwoord op in CPU register indien nodig
Voer de instructie uit
Ga naar stap 1
Dit is de fetch-decode-execute cyclus.
Sommige instructies zijn complexer dan andere. Complexere instructies laten versnelde
uitvoering toe (vb. floating point instructies), maar zorgen ervoor dat de hardware duurder
wordt om te maken. Duurdere computers hadden een grotere instructieset dan goedkopere.
Om deze ongelijkheid te elimineren werd door IBM een architectuur ontworpen waaraan
zowel goedkopere als duurdere modellen voldeden. Dit werd gerealiseerd door de instructies
te interpreteren op goedkopere modellen. Op de duurdere computers met een grotere
instructieset werden deze instructies rechtstreeks door de hardware uitgevoerd. Hierdoor zijn
de verschillende modellen toch in staat om dezelfde programma’s uit te voeren, hetzij met een
verschil in snelheid.
Het gebruik van interpretatie heeft bijkomende voordelen:



Fouten in de implementatie van een instructie kunnen worden gecorrigeerd.
Instrcuties kunnen goedkoop worden toegevoegd
Complexe instructies kunnen efficiënt worden ontwikkeld.
Een van de problemen was het de baas blijven van de complexiteit die door geïntegreerde
schakelingen mogelijk was geworden. Door het gebruik van geïnterpreteerde instructies, kon
men van een complex hardware ontwerp een complex software ontwerp maken.
Een andere factor voor het succes van interpretatie is het bestaan van control stores. Dit zijn
snelle read only geheugens, waarin de interpreters konden worden geplaatst. De control stores
bevatten de micro instructies van de interpreter.
2.1.3 RISC versus CISC
Het ontwerpen van nieuwe processoren die niet compatibel hoefden te zijn met oudere
generaties, liet toe om de instructieset zo te kiezen, dat de totale prestaties van het systeem
werden gemaximaliseerd. Na verloop van tijd werd de nadruk gelegd op het aantal instructies
dat per tijdseenheid kon worden gestart. De uitvoeringstijd van een enkele instructie werd
minder belangrijk.
Het voornaamste idee achter CISC, is dat elke instructie efficiënt van het datapad kon worden
gehaald, en uitgevoerd. Instructies moesten in één cyclus van het datapad kunnen worden
gelezen en uitgevoerd.
Uiteindelijk zijn de CISC computers niet verdreven, omdat enerzijds vele bedrijven erin
hadden geïnvesteerd. Anderzijds is Intel in staat gebleken om bepaalde ideeën van de RISC
architectuur toe te passen. De Intel CPU’s bevatten een RISC kern die de eenvoudigste
instructies onmiddellijk in één datapad cyclus kon uitvoeren. De meer complexe CISC
instructies werden op de gebruikelijke CISC manier uitgevoerd.
2.1.4 Ontwerpprincipes voor tegenwoordige computers
RISC ontwerpprincipes
Alle instructies worden best door hardware uitgevoerd: Geen interpretatie door microinstructies leidt tot versnelde uitvoering. Complexe instructies kunnen in stukken worden
gesplitst die elk als een serie micro-instructies worden uitgevoerd.
Maximaliseer de frequentie waarmee instructies worden gestart: Maximaal aantal
instructies per seconde starten. Dit geeft aanleiding tot parallellisme, en bijhorden
problemen. Zie ook pipeling.
Instructies moeten eenvoudig te decoderen zijn: Zorgen voor een regelmatige vorm, een
vaste lengte en een klein aantal velden. Dit heeft als doel om snel te kunnen bepalen welke
resources er nodig zijn.
Geheugentoegang beperken tot de LOAD en STORE instructies: Geheugentoegang is
traag in vergelijking met de snelheid van de microprocessor. Het aantal registers in de
microprocessor moet zo groot mogelijk zijn. Data overdracht gebeurt het best simultaan met
andere instructies.
Zorg voor voldoende registers: Woorden kunnen tijdelijk worden opgeslagen in de registers,
zodat het hoofdgeheugen niet telkens hoeft worden gecontacteerd.
2.1.5 Parallellisme op instructieniveau
Parallellisme op instructieniveau behelst het simultaan uitvoeren van instructies Parallellisme
op processorniveau gebruikt meerdere processoren om de instructies uit te voeren.
Grondslag van pipelining is het gebruik van de prefetch-buffer. De instructies worden van te
voren uit het geheugen opgehaald, en in de prefetch-buffer opgeslagen. Het ophalen van
instructies uit het geheugen is een belangrijke bottleneck. De uitvoering werd dus gesplitst in
twee stadia: het ophalen en de eigenlijk invoering.
Bij echte pipelining wordt de uitvoering in nog meer stadia opgeslipst. Elk stadium wordt
afgehandeld door speciaal hiervoor ontworpen stuk hardware. Alle stadia kunnen parallel
worden afgehandeld. Zie ook analogie met transportband in een fabriek.
Pipelines maken een trade-off mogelijk tussen wachttijd (uitvoeringstijd van een instructie) en
processorbandbreedte (aantal instructies per seconde.). Bij een processor met n stadia en een
klokcyclus van T nanoseconden, is de wachttijd nT nanoseconden. Een instructie doorloop n
stadia die elk T nanoseconden duren.
Een superscalaire architectuur gebruikt meerdere Pipelines. Hierbij moet ervoor gezorgd
worden dat gelijktijdig verwerkte instructies geen conflicten veroorzaken inzake resources.
Ofwel moet de compiler dit garanderen, ofwel moeten de conflicten tijdens uitvoering worden
gedecteerd en geëlimineerd door speciale hardware.
2.1.6 Parallellisme op processorniveau
Organisatie van computers met meerdere processoren.
Array computers: voor het uitvoeren van berekeningen van natuurkundige problemen
gebaseerd op arrays. Twee soorten: arrayprocessors en vectorprocessors. Arrayprocessors
bestaan uit een groot aantal identieke processoren, die eenzelfde reeks instructies uitvoeren
op verschillende gegevens. Ze zijn opgebouwd als een rooster waarbij elke eenheid bestaat uit
geheugen en een processor. Een controle eenheid stuurt de instructies uit, die elke processor
dan op zijn eigen geheugen uitvoert. Vectorprocesors zijn gelijkaardig. Een vectorprocessor
voert alle optellingsoperaties uit in één opteller, die sterk van pipelining gebruik maakt. Een
vectorprocessor heeft bijkomend een vectorregister dat bestaat uit een aantal conventionele
registers, die in een instructie uit het geheugen kunnen worden opgehaald. De processoren
zijn in beide soorten niet onafhankelijk omdat er nog steeds een besturingseenheid is.
Multiprocessors hebben in tegenstelling tot arraycomputers zelfstandige processoren. Alle
CPU’s gebruiken hetzelfde gemeenschappelijk geheugen. Om te voorkomen dat de
processoren elkaar hinderen, worden ze door software gecoördineerd. Er bestaan
implementatievariaties waarbij elke processor is aangesloten op een bus, waar ook het
geheugen is op aangesloten. Om conflicten bij geheugentoegang te reduceren, kan bij elke
processor een lokaal geheugen worden geplaatst dat enkel door de desbetreffende processor
mag worden benaderd.
Multicomputers bestaan uit een groot aantal computers die onderling verbonden zijn, en
geen gemeenschappelijk geheugen meer hebben, enkel privé geheugen. De communicatie
verloopt door middel van berichten die vaak moeten worden gerouteerd. Dit systeem is
gemakkelijker
te
bouwen.
Men
probeert
ook
met
gemengde
system
(multicomputer/multiprocessor) om de illusie van gemeenschappelijk geheugen te creeëren,
zonder het daadwerkelijk te moeten bouwen.
2.2 Primair geheugen
2.2.1 Bits
Hoe meer waarden moeten kunnen worden voorgesteld door een bepaald spanningsbereik,
hoe minder scheiding er is tussen de waarden, hoe minder betrouwbaar het systeem
uiteindelijk is. Dus, zo weinig mogelijk waarden voorstellen: minimaal twee om als geheugen
te kunnen functioneren. Vandaar de oorsprong van de binaire voorstelling.
2.2.2 Geheugenadressen
Geheugen bestaat uit individuele cellen, die elk een eigen adres krijgen. Het aantal bits in het
adres van een geheugen houdt direct verband met het maximaal aantal cellen dat direct kan
worden aangesproken. Een individuele cel bevat een vast aantal bits
2.2.3 De volgorde van bytes
Big endian = MSB links. Little Endian = MSB rechts.
Bij overdrachten van gegevens tussen machines met verschillende bytevolgorde, ontstaan er
conflicten.
2.2.4
2.2.5 Cachegeheugen
Geheugens zijn meestal meerdere malen langzamer dan processoren. Het kan enkele cycli
duren vooraleer een CPU het gewenste woord uit het geheugen ontvangt. Mogelijks moet hij
een aantal cycli wachten vooraleer hij kan verder gaan met de uitvoering. Er zijn twee
mogelijke benaderingen. In de eerste benaderingen worden de READ instructie gewoon
uitgevoerd wanneer ze worden tegengekomen, maar de processor gaat gewoon door met de
uitvoering. Hij moet dan pas wachten wanneer een instructie een woord probeert te gebruiken
dat nog niet is aangekomen. Een andere benadering zegt dat de compiler ervoor moet zorgen
dat er geen code is die woorden probeert te gebruiken vooraleer ze zijn opgehaald. Vaak zit er
niets anders op dan NOP instructies te gebruiken.
Men is technisch in staat om snellere geheugens te bouwen, maar dit is te kostelijk doordat ze
op de CPU zelf zouden moeten aanwezig zijn. In de plaats daarvan maakt men een
compromis: er is een kleine hoeveelheid snel geheugen aanwezig op de CPU: de cache. Door
de gebruikte technieken benadert de performantie van dit systeem de performantie van het
ideale geval.
Het principe van de cache is eenvoudig: als de CPU een woord nodig heeft, kijkt hij eerst in
de cache. Is het daar niet aanwezig, dan wordt pas in het hoofdgeheugen gekeken. Dit
principe is verwant met het lokaliteitsbeginsel: geheugenreferenties die binnen eenzelfde
korte tijdsspanne nodig zijn, bestrijken slechts een fractie van het totale geheugen. Als een
woord uit het hoofdgeheugen in de cache wordt geladen, worden meteen ook een aantal buren
ingeladen.
Hoofdgeheugens en caches worden op grond van het lokaliteitsbeginsel in blokken van een
vaste grootte verdeeld. Blokken in de cache worden meestal cacheregels genoemd.
Het ontwerpen van caches behelst een aantal aspecten:




De grootte van de cache: hoe groter de cache, hoe groter de trefkans, maar hoe
duurder.
De grootte van de cacheregel
De organisatie van de cache: hoe wordt bijgehouden welke woorden aanwezig zijn in
de cache.
Worden data en instructies in dezelfde of aparte caches geplaatst? (verenigde caches
vs. Gesplitste caches). Gesplitste caches zijn voordeliger voor systemen met pipeling.
De eenheid die instructies ophaalt en de eenheid die de operanden bepaalt kunnen dan
parallel toegang hebben tot de cache.
2.3
2.4 Input/Output
2.4.1 Bussen, interrupts
De eenvoudige goedkope PC heeft een bus om CPU geheugen en randapparaten te verbinden.
Elk I/O-apparaat bestaat uit een controller, en het apparaat zelf. De controller bestuurt het IOapparaat en regelt de bustoegang ervoor. Een controller kan zelfstandig waarden naar het
geheugen schrijven. In dat geval wordt er van direct memory access gesproken. Na afloop
van een overdracht d.m.v. DMA treedt meestal een interrupt op die de processor onderbreekt
en in een interrupt-handler (ISR, interrupt service routine) verplicht om na te gaan of er
geen fouten opgetreden zijn, en het besturingssysteem te verwittigen dat de IO voltooid is. Na
afloop van de ISR, hervat de processor zijn programma.
Wanneer een interrupt optreedt gebeurt het volgende:








De huidige instructie wordt afgewerkt
Het statusregister en programmateller worden op de stapel geplaatst
Het beginadres van de ISR wordt in de programmateller geplaatst
In de ISR:
Extra register die worden gebruikt in de ISR worden op de stapel geplaatst
De service wordt uitgevoerd
De registers worden van de stapel gehaald
De instructie RETI zorgt ervoor dat de PC en het SR van de stapel worden gehaald en
worden hersteld.
Elke processor heeft twee interrupt ingangen:


De NMI: de non-maskable interrupt: deze interrupt kan niet door de processor worden
genegeerd.
De IRQ: de gewone interrupt request. Deze interrupts kunnen wel worden
gemaskeerd. Wanneer er interrupts gelijktijdig optreden, wordt deze met de hoogste
prioriteit afgehandeld. Hiervoor kan een PIC (programmable interrupt controller)
worden gebruikt. Alle interrupt lijnen worden op de PIC aangesloten, die dan beslist
welke interrupt er naar de processor wordt doorgegeven. De processor stuurt een
interrupt acknowledge (IACK), waarna de aanvrager zichzelf identificeert via de
adresbus.
De busarbitrage bepaalt wie er toegang krijgt tot de bus. Er zijn twee benaderingen:


Gecentraliseerde busarbitrage: een speciale eenheid, de busarbiter, bepaalt wie
toegang krijgt bij gelijktijdige aanvragen. IO devices krijgen hierbij doorgaans
voorrang. Als er geen IO plaatsvindt kan de processor alle cycli opeisen.
Gedecentraliseerde busarbitrage: Er zijn een aantal busaanvraaglijnen (met een
verschillende prioriteit). Elke aangesloten component moet dan die lijnen in de gaten
houden om te weten of hij aan de beurt is. (dit is goedkoper, maar er zijn meer lijnen
nodig.)
3 HET NIVEAU VAN DE DIGITALE LOGICA
3.1
3.2
3.2.1
3.2.2
3.2.3 Rekenkundige circuits
Schuivers: zie diagram pg. 156
Optellers: half-adders, full-adders, ripple carry adders en cary select adders.
ALU
3.2.4 Klokken
Om een nauwkeurig kloksignaal te verkrijgen, wordt meestal gebruik gemaakt van een
kristaloscilator. Omdat gedurende een cyclus dikwijls veel zaken moeten gebeuren, kan de
klok in subcycli worden verdeeld. Dit kan worden gerealiseerd door de kloklijn af te tappen,
en een vertraginsschakeling te plaatsen. Hierdoor wordt een kloksignaal gegenereerd dat in
fase verschoven is. Dit kan voor elke nodige subcyclus worden gedaan (vertragingen
verschillen dan)
3.3 Geheugen
3.3.1
3.3.2
3.3.3
3.3.4 Geheugenorganisatie
Geheugens kunnen worden opgebouwd als een matrix van d-latches. Er zijn invoerlijnen voor
adres, besturing en data. De adreslijnen selecteren het juiste woord, de data invoerlijnen
dienen om gegevens in het geheugen te plaatsen. De besturingslijnen bestaan uit chip-enable,
read/write select en output-enable. (zie tekening pg. 168). Deze types geheugens zijn
eenvoudig uit te bereiden naar grotere geheugens.
3.3.5 Geheugenchips
Voor een bepaalde grootte zijn er meerdere mogelijkheden om het geheugen te organiseren.
Adressering kan gebeuren door woorden te adresseren, of zelfs individuele cellen door
gebruik te maken van rijadressen en kolomadressen. Rij en kolomadressen worden soms in
aparte cycli doorgegeven, zodat dezelfde pinnen kunnen worden gebruikt. Dit is echter trager.
3.3.6 RAM en ROM
RAM: random access memory. Er zijn twee soorten: SRAM (statisch) en DRAM
(dynamisch). Statische geheugens maken gebruik van d-flipflops om de gegevens te bewaren.
Zolang deze worden gevoed,blijven ze hun toestand houden. Deze geheugens zijn snel, en
daarom geschikt voor caches van niveau 2. De densiteit van SRAM’s is typisch veel lager dan
die van de DRAM’s.
Dynamische geheugens bevatten cellen die elk bestaan uit een transistor en een condensator.
De condensator wordt opgeladen en ontladen naar gelang de waarde die de cel moet
voorstellen. Omdat een condensator na verloop van tijd zijn lading verliest, moeten de cellen
in dynamische geheugens om de zoveel miliseconden worden ververst. Deze geheugens zijn
veel geodkoper dan statische rams, omdat ze slechts één transistor per cel vereisen t.o.v. van
zes transistoren bij dynamische rams. Deze dynamische geheugens worden meestal gebruikt
voor het hoofdgeheugen. Dynamische geheugens zijn trager, omdat het opladen van een
condensator trager is dan het zetten van een flipflop. Ze laten echter wel een grotere densiteit
toe.
SDRAM (synchronous dynamic RAM) is een kruising tussen beide soorten. De processor laat
aan het geheugen weten hoeveel cycli het moet doorlopen en start het dan. In elke cyclus
levert het geheugen dan een aantal bits af aan de processor.
Indien een niet vluchtig geheugen nodig is, kan ROM (read only memory) worden gebruikt.
ROMS zijn typisch goedkoper als ze in voldoende grote aantallen worden geproduceerd.
Klassieke ROMS kunnen op geen enkele manier worden aangepast. Eens gefabriceerd is hun
inhoud vast.
Om de inhoud van het geheugen te kunnen vastleggen na fabricage, werd de PROM
(programmable ROM) ontwikkeld. Deze laat toe om de inhoud éénmaal te schrijven.
Vervolgens werd de EPROM ontwikkeld, die toelaat de het geheugen kan worden gewist en
opnieuw worden geschreven. Het wissen gebeurt door een kwartsvenster sterk te belichten
met ultraviolet licht. Ze zijn handig voor ontwikkeling, maar ongeschikt voor massaproductie
van apparaten.
Nog beter is de EEPROM. Deze laat toe om de chip door middel van elektrische signalen te
wissen.
De recentste ontwikkeling in niet vluchtige geheugens is het flash memory. Deze geheugens
kunnen per blok worden gewist en herschreven. Door de lage toeganstijden kunnen deze
worden gebruikt als vervanger voor magnetische schijven.
3.3.7 Aansluiten van geheugenchips
Om een geheugen aan te sluiten dat uit meerdere individuele geheugenchips bestaat, kunnen
een paar lijnen van de adresbus worden gebruikt om een decoder aan te sturen die de juiste
chip selecteert via de CS ingang van de chip. De adresruimte lijkt dan lineair te zijn, terwijl in
wezen de woorden op verschillende chips zijn gesitueerd.
Anderzijds is het ook mogelijk om meerdere chips te combineren om bredere woorden te
verkrijgen. Alle adresingangen van de chips worden dan recht op recht verbonden met de
adresbus, terwijl de data-uitgangen worden verbonden met een deel van de databus. Zo
kunnen bijvoorbeeld 4 chips met een 8 bit data-uitgang worden gecombineerd om woorden
van 32 bit te vormen, en deze aan te sluiten op de 8-bit databus van de microprocessor. Indien
de adresbus breed genoeg is, kunnen de laagste orde bytes eventueel worden gebruikt om
individuele bytes binnen het geheugenwoord te adresseren.
3.3.8 Koppeling tussen microprocessor en randapparaten
Gebeurt door middel van een interface chip. Deze chip bevat registers, toestand en data.
3.3.9 Adressering van de IO
Om de IO apparaten te adresseren zijn er twee mogelijke benaderingen. Beiden zijn snel en
goedkoop te implementeren.


Memory mapped IO zorgt ervoor dat IO chips op dezelfde manier als het
hoofdgeheugen kunnen worden aangesproken. De adressen van de IO chip maken deel
uit van dezelfde geheugenruimte als de andere geheugens. Externe decoder logica
bepaalt dan welke chip er daadwerkelijk wordt aangesproken. Nadelig is dan weer dat
een deel van de adresruimte moet worden opgeofferd voor de IO chips, dus er is
minder geheugen. De programmeur moet weten hoe er geadresseerd wordt, en hij
moet hierover de controle uitvoeren. De microprocessor voert domweg de instructies
uit.
Isolated IO brengt de IO onder in een eigen geheugenruimte. Er worden apparte
stuurlijnen voorzien om IO in te schakelen. De processor geeft hiermee aan of de
adressen op de adresbus bestemd zijn voor geheugen of IO. Hierdoor ontstaat meer IO
ruimte dan er in wezen nodig is. (De extra stuurlijn verdubbelt de aanwezig
geheugenruimte, en deelt ze op in twee gelijke stukken IO en MEMORY) De
instructieset van de microprocessor moet ook worden uitgebreid met instructies voor
IO bewerkingen. In moderne implementaties krijgt deze techniek de voorkeur.
3.4 CPU-chips en BUSSEN
3.4.1 CPU chips
De CPU communiceert met geheugen en randapparaten door signalen op zijn pinnen te zetten
en signalen van die pinnen te lezen. Er zijn datapinnen, adrespinnen en besturingspinnen. Hoe
groter het aantal adrespinnen, hoe groter de hoeveelheid geheugen de processor kan
adresseren. Hoe meer datapinnen, hoe meer bits de processor in een instructie uit het
geheugen kan lezen.
Verder nog pinnen voor busbesturing, interruptpinnen, pinnen voor busarbitrage, pinnen voor
communicatie met een coprocessor. Sommigen zijn aanwezig omwille van
compatibiliteitsredenen.
3.4.2 Computerbussen
Een bus is een elektrisch pad dat gemeenschappelijk is tussen alle erop aangesloten
randapparaten.
Oorspronkelijke computers hadden slechts een externe (buiten de CPU gelegen) bus: de
systeembus. Om toe te staan dat kaarten van andere fabrikanten konden gebruikt worden, was
er nood aan een busprotocol dat beschrijft hoe de communicatie op de bus verloopt.
Op een bus kunnen actieve apparaten (masters) en passieve apparaten (slaves) worden
aangesloten.
Bus communicatie verloopt dikwijls met three state apparaten die kunnen worden
uitgeschakeld indien nodig. Three state wil zeggen dat de logica naast de gebruikelijk hoog en
laag waarden, ook nog de toestand High-Z (hoogimpedant) kent. Door de hoge impedantie
die het apparaat dan krijgt, lijkt het alsof de pinnen van de chip niet zijn aangesloten, en wordt
de bus niet verder belast. Dit vermijdt problemen gerelateerd aan de maximale fan-out van de
chips.
Een bus heeft adreslijnen, besturingslijnen en datalijnen.
Aspecten van busontwerp zijn: busbreedte, klokken van de bus, arbitrage, busarbitrage en
busoperaties.
3.4.3 Busbreedte
Hoe meer adreslijnen in de bus, hoe meer geheugen er kan worden aangesproken. Achteraf
adreslijnen toevoegen is duur, omdat deze dan ook van besturingslijnen moeten worden
vergezeld.
De om de bandbreedte van de bus te verhogen, kan men hetzij het aantal datalijnen opvoeren,
of de buscyclus verkleinen. Dit heeft wel als gevolg dat de compatibiliteit met oudere
modellen verloren gaat. Het aantal datalijnen verhogen draagt dus de voorkeur.
Om de breedte van een bus te verlagen (en ze dus goedkoper te maken) maakt men soms
gebruik van een gemultiplexte bus waarbij data en adressen achtereenvolgens op de bus
worden geplaatst.
3.4.4 Het klokken van een bus
Er zijn twee soorten bussen: synchrone bussen, met een master kloksignaal, en asynchrone
bussen, zonder master kloksignaal.
Bij synchrone bussen treden alle gebeurtenissen op, op gehele veelvouden van de
systeemklok. Dit heeft als nadeel dat het traagste apparaat op de bus de snelheid van de gehele
bus bepaalt. Ook moeten er steeds volledige cycli worden doorlopen, ook al is er slechts een
klein deel van de laatste cyclus nodig om een volledige overdracht te voltooien.
De asynchrone bus maakt gebruik van synchronisatielijnen, waarbij masters en slaves elkaar
verwittigen van een voltooiing van een opdracht.
3.4.5 Busarbitrage
Naast de CPU moeten IO chips ook als master kunnen optreden om gegevens naar het
geheugen weg te schrijven. Soms moet ook een coprocessor master van de bus kunnen
worden. Om te voorkomen dat er chaos ontstaat wanneer twee apparaten tegelijk master van
de bus willen bworden is er busarbitrage nodig.
Busarbitrage kan gecentraliseerd of gedecentraliseerd gebeuren. In het gecentraliseerde geval
wordt er gebruik gemaakt van een vergunningslijn waarop apparaten in serie zijn aangesloten,
die vergunningen doorgeven als ze geen aanvraag hebben gedaan. (daisy chain)
In het geval van gedecentraliseerde arbitrage, worden er meerdere aanvraaglijnen (elk met een
prioriteit) door alle apparaten in de gaten gehouden. Op het einde van een aanvraagcyclus
weet een apparaat dan of het de hoogste prioriteit had of niet. Een andere mogelijkheid voor
gedecentraliseerde busarbitrage maakt gebruik van een wired-OR lijn voor de aanvragen, en
twee gewone lijnen: BUSY wordt aangezet door de actuele master, en een arbitragelijn.
3.4.6 Busoperaties
Datatransfers Bloktransfers kunnen efficiënter worden uitgevoerd dan afzonderlijke
transfers. Bij overdrachten naar caches is het wenselijk dat volledige regels in een keer
kunnen worden overgebracht.
Afhandelen van interrupts Een CPU verwacht meestal een interrupt van het IO apparaat als
een overdracht voltooid is. Als er meerdere interrupts tegelijk kunnen optreden is het
gebruikelijk om prioriteiten toe te kennen aan de interrupts.
3.5
3.6 Voorbeelden van bussen
3.7 Interfaces
3.7.1 IO-chips
UART (Universal asynchronous receiver transmitter) en USART (universal synchronous asynchronous receiver transmitter)
Een UART is een chip die een byte uit de databus kan lezen, en bit voor bit op een
transmissielijn plaatsen voor een terminal, of deze data van een terminal inlezen. Een USART
kan naast alle functionaliteit van UART ook synchrone transmissies op basis van diverse
protocollen afhandelen.
PIO-chips
Een parallel Input/Output chip zorgt ervoor dat de CPU de waarden van een willekeurige
statuslijn kan lezen of er naar schrijven.
3.7.2 Adresdecodering
Een deel van de lijnen van de adresbus wordt gebruikt voor de selectie van de juiste chip. De
lijnen die worden gebruikt, verdelen de geheugenruimte in stukken, die elk een subset van de
ruimte zijn. Elk van deze ruimten heeft dan een specifiek doel, de adressen van een bepaalde
chip vallen dan binnen een bepaalde ruimte.
4 HET NIVEAU VAN DE MICROARCHITECTUUR
4.1 Een voorbeeld van een microarchitectuur
4.1.1 Het datapad
Zie afbeelding pg. 236
Het datapad is het gedeelte van de CPU dat de ALU bevat met de bijbehorende registers,
input en output. De meeste registers kunnen hun inhoud op de B-bus plaatsen. Het resultaat
van de ALU stuurt de C bus aan. De ALU wordt aangestuurd door zes besturingslijnen. Het is
niet zo dat elke mogelijke toekenning van waarden aan de besturingslijnen iets zinvol doet.
De rechteroperand van de ALU wordt voorgesteld door de B-bus, de linkeroperand is de
inhoud van het H register. Dit register kan worden geladen door de ALU te schakelen zodat
hij de input in van de B-bus naar de uitgang doorgeeft.
Het is mogelijk om in één klokcyclus te lezen en te schrijven naar hetzelfde register. Dit
gebeurt tijdens verschillende fasen van dezelfde cyclus. Er zijn dus deelcyclussen nodig, en
een precieze timing van het datapad.
Timing van het datapad
Bij de start van elke klokcyclus wordt een korte pul gegenereerd. Tegen de tijd dat deze puls
is afgevallen, zijn alle signalen die de poorten aansturen opgezet. Dit neemt een tijdsinterval
∆w in beslag.
Vervolgens wordt het register geselecteerd dat op de B-bus nodig is, en wordt de inhoud
ervan op de B-bus geplaatst. Het duurt een tijd ∆x vooraleer de waarde stabiel is.
De ALU kan dan zijn bewerking uitvoeren, het duurt een tijd ∆y vooraleer de uitgang van de
ALU stabiel is.
Het duurt nog een tijd ∆z vooraleer de resultaten zich over de C-bus hebben voortgeplant.
Een andere benadering beschouwt deze gebeurtenissen als deelcycli met volgende
omschrijvingen:




Opzetten van de stuursignalen
Laden van de registers op de B-bus
Werking van de ALU en de shifter
Voortplanting van de resultaten langs de C-bus terug naar de register.
Tijdens de stijgende flank van de volgende klokcyclus, worden de resultaten in de registers
opgeslagen. Merk op dat deze deelcycli hoe dan ook impliciet zijn. Ze worden niet
gerealiseerd door klokpulsen, dan wel door de vertragingen op het datapad.
Geheugenmodel
Er kan op twee mogelijke manieren met het geheugen worden gecommuniceerd:


In eerste instantie via een 32 bit poort bestuurd via twee registers: het memory
address register (MAR) en via het memory data register (MDR). Deze poort is
adresseerbaar per woord.
In tweede instantie via een 8 bit poort adresseerbaar per byte. Deze poort wordt
aangestuurd via de PC. Waarden worden in de minst significante acht bits van het
memory buffer register (MBR) geplaatst.
Elk van de registers wordt aangestuurd door twee stuurlijnen die bepalen. Een eerste lijn
bepaalt of de inhoud van het register op de B-bus wordt geplaatst, een tweede lijn bepaald of
er van de C-bus naar het geheugen wordt gelezen.
De harvard architectuur wordt gevolgd. Programmageheugen en datageheugen zijn appart.
De data gebruikt de MAR/MDR combinatie. Het programmagehgeugen wordt benaderd via
de PC/MBR combinatie.
De B bus is 32 bit breed terwijl het MBR slechts 8 bit breed is. Om het MBR op de B bus te
plaatsen zijn er twee mogelijkheden. Enerzijds kunnen enkel de eerste 8 LSB van de B bus
worden gebruikt. Anderzijds kan de tekenbit van het MBR (de MSB) worden uitgebreid over
24 plaatsen. Dit heet sign extension.
Wanneer een gegeven wordt opgevraagd in cyclus k is het gegeven pas beschikbaar in cyclus
k+2
4.1.2 Micro-instructies
Een micro-instructie is een verzameling binaire waardes die wordt aangelegd aan de
controlelijnen van het datapad gedurende een cyclus.
Voor het besturen van het datapad zijn 27 signalen nodig:




9 signalen voor het regelen van het schrijven van de C bus naar de registers
9 signalen voor het regelen van de inschakeling van registers op de B-bus voor ALUinput. Dit wordt vereenvoudigd, we gebruiken er slechts 4.
8 signalen voor het regelen van ALU en schuifeenheid instructies.
1 signaal voor het ophalen van de geheugenwaarde via PC/MBR
Een enkele cyclus bestaat uit volgende impliciete deelcycli:



Opzetten van de stuursignalen voor het aandrijven van het datapad (delta-x)
Het lezen van de waarden uit registers en het plaatsen van deze waarden op de B-bus
(delta-y)
Het voortplanten van de signalen over de schuifeenheid naar de C bus (delta-z)

Het voortplanten van de resultaten naar een of meer registers. (enveneens onderdeel
delta-z)
Tijdens de stijgende flank van de volgende klokcyclus worden de waarden naar de registers
geschreven.
4.1.3 Micro-instructie besturing: de MIC-1
De volgordebepaling bepaalt welke stuursignalen tijden elke cyclus wordt ingeschakeld. De
sequencer is verantwoordelijk voor het in volgorde uitvoeren van de operaties die een enkele
ISA instructie realiseren. De sequencer moet tijdens iedere cyclus twee soorten informatie
produceren:


De status van ieder stuursignaal binnen het systeem
Het adres van de volgende uit te voeren micro instructie
De micro architectuur bestaat uit twee gedeelten. Enerzijds is er het datapad, anderzijds is er
het stuurgedeelte.
Het belangrijkste onderdeel van het stuurgedeelte is de control store. Dit is een geheugen dat
het volledige microprogramma bevat. In tegenstelling tot instructies in het hoofdgeheugen,
hoeven instructies in de control store niet in adresvolgorde worden uitgevoerd. Om dit
eenvoudig te realiseren geeft iedere microinstructie expliciet zijn opvolger aan. De control
store heeft zijn eigen geheugenadresregister (MPC, micro program counter) en
geheugendataregister (MIR, micro instruction register). De functie van het MIR is het
bewaren van de huidige micro instructie; waarvan de bits de stuursignalen aandrijven die het
datapad in werking zetten.
Bits van het instructieregister (MIR):




ADDR en J(JAM) zorgen voor de selectie van de volgende instructie
ALU (8 bit) sturen de ALU en shifter aan
De C bits zorgen ervoor dat de registers worden geladen vanaf de C bits
De M en B bits sturen de decoder aan die bepaalt wat er op de B-bus wordt geplaatst.
Werking van de microarchitectuur
Bij het begin van iedere cyclus (dalende flank van de klokpuls) wordt MIR geladen in de
controlstore vanuit het woord waarnaar MPC verwijst. De laadtijd van het MIR is ∆w. Dit is
de eerste deelcyclus.
Wanneer het MIR de micro-instructie bevat, planten de diverse signalen zich voort over het
datapad. Een registerinhoud wordt op de B-bus geplaatst, de ALU weet welke bewerkingen er
moeten worden uitgevoerd. Er worden dus meerdere handelingen uitgevoerd. Na een tijd ∆w
+ ∆x zijn de ALU inputs stabiel.
Na een tijd ∆y is de ALU output en shifter output stabiel, alsook de N en Z outputs. De N en Z
waarden worden opgeslagen in enkele flipflops. Deze bits worden samen met alle overige
register die vanaf de C-bus worden geladen en uit het geheugen worden geladen, opgeslagen
tijdens de stijgende flank van het kloksignaal, tegen het einde van de datapadcyclus.
Na een interval ∆z wordt heeft de output van de schuifeenheid de registers via de C-bus
bereikt. Nu kunnen de registers tijdens het einde van de cyclus worden geladen. Tezelfdertijd
zijn de resultaten van de vorige geheugenbewerking beschikbaar en is de MPC geladen.
De bepaling van de volgende instructie begint nadat het MIR geladen is, en stabiel
geworden is. Eerst wordt de 9 bit waarde van NEXT_ADDRESS gekopieerd naar de MPC.
Wanneer een van de JAM bits gezet is (JAMN of JAMZ), wordt de logische OR operatie
gedaan tussen de gezette bits, en respectievelijk het N of Z bit (latches) afkomstig van de
ALU. Het bekomen resultaat wordt geladen in de meest significante bit van de MPC.
Wanneer het JMPC bit gezet is, wordt er een logische OR gedaan tussen de 8 MBR bits, en de
8 minst significante bits van de MPC.
4.2 Een voorbeeld ISA: IJVM
Het ISA niveau waarvan de instructies moeten worden geïnterpreteerd door het
microarchitectuur niveau. Het ISA niveau wordt soms ook de macro architectuur genoemd.
4.2.1 Stapels
Procedures gebruiken lokale variabelen die traditioneel worden gerealiseerd met stapels.
Lokale variabelen worden bijgehouden in stack frames. Er worden twee pointers
bijgehouden: de stack pointer en de local variable pointer. De SP wijst steeds naar de
bovenkant van de stapel, terwijl LV naar de basis van het stack frame wijst.
Berekeningen worden via een operanden stack gerealiseerd. Hierbij worden alle operanden op
de stack gepushed, er wordt een intructie uitgevoerd die de operanden popt en het resultaat op
de stapel pusht. Daarna moet het programma het resultaat van de stapel poppen, en opslaan in
de juiste variabele in de stack.
4.2.2 Het IJVM-geheugenmodel
Het geheugengebied is in de volgende vier delen opgedeeld:






Constantenpool
Read-only
Bevat constanten, strings en pointers naar andere geheugengebieden
De inhoud wordt samen met het hoofdprogramma geladen, en blijft onveranderd tijden
de uitvoering.
CPP (constant pool pointer)
Lokale variabelenframe








Bij het aanroepen van een methode wordt een gebied gereserveerd voor opslag van de
lokale variabelen. De geldigheid van het gebied is beperkt tot de levensduur van de
aanroep.
LV pointer duidt basis aan
Operand stack
Tijdelijk opslaan van operanden. De omvang wordt vooraf door de compiler berekend.
SP duidt bovenzijde aan
Method gebied
Geheugengebied dat het programma zelf bevat.
PC duidt volgende instructie aan.
4.2.3 De IJVM instructieset
Instructies bestaan uit een opcode en eventuele operanden. (stapelgeoriënteerd)
4.2.4 Compileren van Java naar IJVM
De het Java programma wordt vertaald naar een equivalent programma dat de IJVM
instructies gebruikt.
4.3 Een voorbeeld van een implementatie
4.3.1 Micro-instructies en hun notatie
Een fictieve taal waarbij een regel een microinstructie voorstelt, die in een klokcyclus wordt
uitgevoerd. De taal is de micro assembly language (MAL)
4.3.2 Implementatie van IJVM met de MIC-1
Het microprogramma dat de instructies van de IJVM interpreteert bevat slechts 112 microinstructies.
Registers:






CPP pointer naar de constantenpool
LV pointer naar de lokale variabelen
SP bovenkant van de stapel
MBR register van één byte dat de bytes vanuit de instructiestroom na elkaar bewaart
als deze ter interpretatie vanuit het geheugen worden aangeboden.
TOS bevat steeds de waarde van de geheugenlocatie waarnaar de SP wijst.
OPC tijdelijk register zonder vast doel.
De volgende opcode wordt steeds klaargezet in het MBR. Vanuit de hoofdlus wordt
gespronden naar het label dat overeenkomt met de opcode die aanwezig is in de MBR. Aan
het einde van een instructie wordt teruggesprongen naar de hoofdlus.
4.4 Ontwerp van het microarchitectuurniveau
4.4.1 Snelheid versus kosten
Voor eenzelfde schakelsnelheid en ISA kan de verwerkingssnelheid op drie manieren worden
verhoogd:



Het aantal klokcycli nodig voor het uitvoeren van een instructie reduceren
Organisatie vereenvoudigen met kortere klokcycli als gevolg
De uitvoering van instructies te laten overlappen. (pipelining)
Het aantal nodige cycli om een instructie uit te voeren heet de padlengte.
Snelheid verhogen kan door horizontale microprogrammering: de micro-instructies worden
zo weinig mogelijk gecodeerd. Dit is echter wel duur en ingewikkeld. De verbetering komt er
dan omdat micro-instructies niet hoeven gedecodeerd te worden. De instructies zijn dan
breder, maar hun aantal is kleiner.
Kosten verlagen kan door verticale microprogrammering: de microinstructies worden
maximaal gecodeerd. Hierdoor kan plaats worden bespaard. Er zijn dan meer micro
instructies nodig, maar ze zijn korter.
Bij nanoprogrammering bevat het microprogramma pointers naar micro-instructies.
Bepaalde micro instructies komen in het microprogramma meerdere keren voor. Bij
nanoprogrammering zijn er dan geen dubbele instructies meer aanwezig. De micro instructies
zelf worden in de control store geplaatst, en de nano store bevat de verwijzingen naar de
micro instructies. Dit is relatief traag, maar goedkoop.
4.4.2 Reductie van de lengte van het executiepad
De volgende drie paragrafen beschrijven de verbetering die worden aangebracht om uit de
MIC-1 de MIC-2 te construeren.
Interpretatielus samenvoegen met het einde van iedere microcodereeks
De interpretatielus wordt samengevoegd met het einde iedere microcode reeks. Dit heeft als
nadeel dat het microprogramma langer wordt.
Architectuur met drie bussen
Een bus toevoegen voor de linkeroperand van de ALU zorgt ervoor dat er geen cyclus meer
nodig is om een waarde in het H register te laden.
Aparte unit voor het ophalen van instructies
Er wordt een apparte unit gemaakt voor het ophalen van de instructies, de instruction fetch
unit (IFU), om de ALU te ontlasten met zaken zoals de programmateller incrementeren. De
taken zijn:



PC onafhankelijk verhogen
Bytes uit de instructiestroom ophalen en bufferen. Dit gebeurt ongeacht het feit of ze
nu nodig zijn of niet.
8 en 16 bit operanden assembleren.
Zie figuur 4-27 p. 283 voor de instruction fetch unit.
Modelleren als een finite state machine met 7 staten.
4.4.3 De MIC-2: een ontwerp met prefetching: de MIC-2
Verbeteringen t.o.v. de MIC-1:
Het gebruik van de IFU zorgt ervoor dat de padlengte van de gemiddelde instructie
aanzienlijk wordt verkort:


De hoofdlus wordt volledig geëlemineerd, het einde van iedere instructie is
eenvoudigweg een sprong naar de volgende instructie
Telkens een 16 bits index of een offset moet worden berekend (16 bits waarde wordt
geassembleerd en direct aan de ALU als 32 bit waarde gepresenteerd.)
4.4.4 Een ontwerp met pipelining: de MIC-3
Door het toevoegen van latches (registers van) wordt het datapad in afzonderlijke delen
verdeeld, die onafhankelijk van elkaar kunnen opereren. Door deze toevoeging kan de klok
versneld worden, omdat de maximale vertraging korter wordt. Verder kunnen nu ook alle
delen van het datapad tegelijk opereren en tijdens iedere cyclus worden gebruikt. Het is
redelijk om te veronderstellen dat de kloksnelheid kan worden verdrievoudigd. (Padlengte
voor elk deel is een derde van het oorspronkelijke pad.)
Zie ook RAW dependencies en stalling. (p. 292)
4.4.5 Pipelining in zeven stadia: de MIC-4
De laatste verbeteringen lossen het probleem op dat voorwaardelijke spronden de pipelining
in de war sturen. Er wordt een decoderingseenheid toegevoegd, die eveneens wordt gevoed
door de IFU.
De decoderingseenheid bevat een ROM die wordt geïndexeerd met de opcode van de
instructie. De ROM bevat dan voor elke opcode de lengte van de instructie, en een index in
een ander ROM: het ROM voor de microbewerkingen. De IJVM instructielengte wordt
gebruikt om de decoderingseenheid in staat te stellen de inkomende bytestroom in instructies
te ontleden. De eenheid weet dan voortdurend welke bytes opcodes zijn, en welke operanden
voorstellen.
De decoderingseenheid transporteert de index naar het ROM voor micro-operaties, die in de
tabel wordt gevonden, naar de volgende component: de queuing unit. Deze unit bevat twee
interne tabellen: een in ROM en een in RAM. De tabel in de ROM bevat het
microprogramma, waarbij elke IJVM instructie een aantal opeenvolgende elementen bevat,
micro-operaties genaamd. Deze micro-operaties zijn gelijkaardig aan de micro-instructies, en
bevatten twee extra bitvelden: Final en Goto. Final duidt de laatste instructie in de reeks aan,
Goto duidt op een voorwaardelijke microsprong.
De queueing unit ontvangt een index in het micro-operatie ROM van de decoderingseenheid.
De micro-operatie wordt opgezocht, en gekopieerd naar de interne wachtrij, de volgende
micro-operatie wordt ook opgezocht en ook gekopieerd naar de wachtrij. Dit gaat door totdat
er een micro-operatie wordt gevonden waarvan de Final bit gezet is. Dit is de laatste microoperatie die wordt gekopieerd. De queueing unit geeft bij het laden van de laatste instructie
een bevestigingssignaal aan de decodeereenheid, die dan de volgende IJVM instructie
doorgeeft. De queueing unit voedt het MIR register.
Omdat het MIR register niet in elke deelcyclus beschikbaar is, wordt er voor elke deelcyclus
een eigen MIR voorzien, waarin de instructie voor elke opeenvolgende Het eerste MIR wordt
steeds geladen met een nieuwe micro-instructie.
Wanneer de queuing unit een instructie met het Goto bit ziet, wacht houdt hij de queing op,
totdat de spronginstructie verwerkt is.
Samengevat is de structuur van de pipeline de onderstaande:
IFU
Deco
der
Wach
trij
Opera
nden
Uitvo
ering
Terug
schrij
ven
Gehe
ugen
4.5 Verbetering van de prestaties
Verbeteringen aan de implementatie, zonder de architectuur te wijzigen. Oude programma’s
blijven dan compatibel. Op een gegeven moment zullen er geen verbeteringen mogelijk zijn
met de huidige architectuur, dan besluit men om de architectuur bij te werken.
4.5.1 Cachegeheugen
Moderne processoren stellen grote eisen aan het geheugen inzake de latentie en de
geheugenbrandbreedte. Daarom voegt men een klein en snel cachegeheugen tussen de
microprocessor en het grote trage hoofdgeheugen.
Het gebruik van meervoudige caches is een van de meest doeltreffende technieken om zowel
de latentie te verlagen als de geheugenbandbreedte te verhogen. Een elementaire doch
effectieve techniek gebruikt een aparte cache voor data en instructies. (split cache)
Verder kan ook een L2 cache worden toegevoegd, die zich niet in de CPU bevindt, maar
dikwijls wel via een hogesnelheidspad verbonden is met de CPU, en in dezelfde behuizing zit.
Dit is meestal een unified cache die een mengsel van data en instructies bevat.
Wanneer er toegang tot geheugen vereist is, laadt men het opgevraagde woord en een aantal
woorden uit zijn omgeving in de cache, zodat deze de volgende keer snel kunnen worden
benaderd. Dit principe is gebaseerd op het lokaliteitsprincipe, dat uiteenvalt in twee
aspecten:

Met Ruimtelijke lokaliteit wordt bedoeld dat het waarschijnlijk is dat
geheugenlocaties zullen worden benaderd met adressen die in numerieke zin lijken op
de adressen van zojuist benaderde geheugenlocaties.

Men spreekt van Tijdelijke lokaliteit als geheugenlocaties worden benaderd die even
terug ook werden benaderd. Sommige caches berusten in het feit dat regels die lang
niet meer werden geraadpleegd, uit het geheugen mogen verwijderd worden.
Het geheugen wordt verdeeld in blokken van vaste grootte, die cacheregels worden genoemd.
Wat betreft de opbouw van de caches zijn er drie benaderingen: associatieve caches, directmapped caches en set-associatieve caches.
Associatieve caches
Zijn een voorbeeld van content adressable memory (CAM). De cache is opgebouwd als een
tabel met een entry per bloknummer. Een entry bevat een valid bit dat aangeeft of de
verwijzing geldig is, het bloknummer en de inhoud van het blok.
Om te bepalen of een blok aanwezig is in de cache, moet elk slot in de tabel worden
gekoppeld met een hardware comparator die het bloknummer vergelijkt met het gevraagde
nummer. Elke entry in de cache wordt tegelijk gecontroleerd, daarom is de omvang van de
cache beperkt door de plaats die de comparatoren innemen. Dit is toepasbaar voor L1 caches.
Wanneer de cache vol is wordt een plaats gezocht om een nieuw gegeven op te zoeken. De
least recently used benadering is de beste, maar deze vergt te veel tijd. Een willekeurig blok
uit de cache verwijderen is dan weer te rudimentair. Daarom gebruikt men meestal de FIFO
strategie.
Direct mapped cache
Er wordt een relatie opgesteld tussen het bloknummer en het slotnummer. Dit heeft als gevolg
dat een blok slechts op een plaats in de cache kan worden gevonden. Er moet dus ook maar
een comparator worden voorzien.
Het adres wordt onderverdeeld in:




TAG: Zelfde als de TAG bits van het cache element
LINE: Geeft aan in welk cache element het blok wordt verwacht
WORD: Geeft aan welk woord binnen het blok wordt benaderd
BYTE: welke byte van het woord, indien slechts een byte.
Om een regel in de cache op te zoeken:




LINE bits worden gebruikt als index om het cache slot op te zoeken
Als het element geldig is, worden de TAG bits vergeleken.
Als de TAG bits gelijk zijn, werd er een cache hit gevonden. Het blok is beschikbaar
in de cache
Als de TAG bits verschillend zijn, is de regel afwezig en moet het hoofdgeheugen
worden gecontacteerd. Men spreekt van een cache miss.
Collisions waarbij een cache regel te vroeg werd overschreven zijn zeer zeldzaam. Daarom
presteren deze caches goed.
Set-associatieve caches
Deze benadering is een combinatie van de beide. Men staat nu toe dat een slot meerdere cache
elementen bevat. Elke van deze cache-elementen moet nu weer door parallelle comparatoren
worden onderzacht. De cache bestaat uit m slots met elke n elementen. Als m=1 is dit
equivalent aan het geval van de associatieve cache. Als n=1 krijgen we het geval van de direct
mapped cache. (merk ook de overeenkomst met seperate chaining op.)
Bedenkingen bij het gebruik van caches
Hoe moet de blokgrootte worden gekozen? Groot of klein? Elke benadering heeft zowel
voordelen als nadelen.
Problemen bij schrijfacties: er moet worden voor gezorgd dat de cache en het geheugen
dezelfde waarde bevat. Twee mogelijk benaderingen:


Write trough: bij een schrijfactie naar de cache wordt onmiddellijk het geheugen
bijgewerkt. Er onstaat een permanente gelijkheid tussen cache en hoofdgeheugen.
Deze benadering zorgt voor vertragingen bij schrijfacties.
Copy back: bij een schrijfactie wordt enkel de cache zelf bijgewerkt. Het geheugen
wordt pas aangepast op het moment dat de regel van de cache vervangen wordt. Dit is
sneller maar vereist extra geheugenadministratie. De cache moet ook worden geleegd
alvorens I/O transfers te doen.
Een andere vraag is het schrijfbeleid. Wat moet er gebeuren als er wordt geschreven naar een
woord dat niet aanwezig is in de cache? Moet deze in de cache worden gehaald, en daar
worden bijgewerkt, of wordt er rechtsreeks naar het geheugen geschreven?
Wat betreft adressen voor I/O: deze blokken mogen niet in de cache worden opgenomen. Als
deze aanwezig zouden zijn, zouden er gegevens kunnen worden gelezen die intussen al
vervangen zijn door de IO controller.
4.5.2 Sprongvoorspellingen
Spronginstructies vormen een probleem bij pipelining. Pipelining werkt het best bij lineaire
code. Zowel onvoorwaardelijke als voorwaardelijke sprongen zorgen voor problemen nij
pipelining.
Problemen ten gevolge van onvoorwaardelijke sprongen kunnen worden vermeden door het
inlassen van delay slots. De verantwoordelijkheid om deze in te lassen ligt bij de compiler.
De oorsprong van het probleem licht bij de feit dat het fetch stadium van de pipeline reeds de
volgende instructie moet ophalen, nog voor het weet wat voor instructie de vorige is. Veel
machines hebben de eigenschap dat bij een onvoorwaardelijke sprong de volgende instructie
altijd wordt uitgevoerd. De compiler kan dit dan oplossen, door de volgorde van de instructies
te wijzigen, en een nuttige instructie na de sprongopdracht te plaatsen. Dit is het delay slot.
Als er geen nuttige instructie beschikbaar is om het delay slot op te vullen, moet er een NOP
instructie worden gebruikt.
Voorwaardelijke sprongen zijn nog vervelender, omdat de fetch unit pas vele instructies
later in de pipeline weet wat de volgende instructie is die hij moet ophalen. De eenvoudigste
benadering bestaat erin om te wachten met de verwerking van de volgende instructies tot
bekend is naar waar moet gesprongen worden. Dit is echter nadelig voor de
verwerkingssnelheid. De meeste machines proberen daarom te voorspellen welke sprongen
moeten worden uitgevoerd:

Een eerste eenvoudige benadering zegt dat alle achterwaartse sprongen moeten
worden uitgevoerd, en voorwaartse sprongen niet moeten worden uitgevoerd. De
redenering hierachter is dat achterwaartse sprongen meestal op het einde van lussen
voorkomen, en deze in het merendeel van de gevallen moeten worden uitgevoerd.
Problemen ontstaan wanneer de sprongvoorspelling foutief was en een instructie ten onrechte
werd uitgevoerd, en deze ongedaan moet worden gemaakt. Om dit probleem op te lossen zijn
er twee mogelijke benaderingen:

De eerste benadering zegt dat de instructie na de voorspelling van de sprong mogen
worden uitgevoerd, totdat een instructie de toestand van de machine (een register)
probeert te wijzigen. In plaats van de schrijfopdracht uit te voeren naar het register,
wordt de berekende waarde bijgehouden in een kladregister en pas daadwerkelijk naar
het eigenlijke register geschreven als is vastgesteld dat de voorspelling correct was.

De tweede benadering bestaat erin de toestand van de machine te bewaren op het punt
dat er wijzigingen worden doorgevoerd. Indien een voorspelling foutief bleek te zijn,
kan de toestand worden hersteld door een roll back uit te voeren.
Naast de eenvoudige benadering, zijn er nog twee andere benadering om de voorspelling van
sprongopdrachten uit te voeren.
Dynamische sprongvoorspelling
Dynamische sprongvoorspelling houdt in dat de sprongvoorspelling tijdens de uitvoering van
het programma gebeurt. Dit laat toe dat de instructie op volle snelheid doorstromen. Het
maakt gebruik van een historietabel die aangeeft of een sprong in een verleden al dan niet
werd uitgevoerd. Op basis van deze waarde wordt er al dan niet gesprongen. De
implementatie van de historietabel kan met dezelfde mogelijkheden als caches.
Als de sprong foutief werd voorspeld, wordt hij in de historietabel als verkeerd gemerkt.
Sommige implementaties hebben twee foutbits, zodat de sprong pas als foutief wordt
aangemerkt wanneer de voorspelling twee maal achter elkaar fout bleek te zijn.
Statische sprongvoorspelling
Deze sprongvoorspelling vereist ook inspanningen van de compiler. Aan de instructieset van
de machine voegt men een tweede set spronginstructies toe, die elk een vlag bevatten die
aangeeft of de spronginstructie gewoonlijk wordt uitgevoerd of niet. De compiler kan
bijvoorbeeld spronginstructies ten gevolge van een for lus merken met dit bit.
Met behulp van profilering kan men het programma gesimuleerd laten uitvoeren, en het
sprongprofiel bepalen. Deze informatie wordt dan aan de compiler gegeven, die betreffende
sprong instructies merkt met het nodige bit.
4.5.3 Out-of-order uitvoering en herbenoemen van registers
Sommige processoren staan toe dat afhankelijke instructies worden overgeslagen, om verder
te gaan met onafhankelijke instructies. De instructies worden zo optimaal herordend om een
verbeterde prestatie te bereiken.
4.5.4 Speculatieve uitvoering
Het uitvoeren van code zonder dat bekend is of deze werkelijk moet worden uitgevoerd.
5 HET NIVEAU VAN DE INSTRUCTIESETARCHITECTUUR
Programma’s in hogere programmeertalen worden vertaald naar een tussenniveau. Dit niveau
is het ISA niveau. Doordat verschillende programmeertalen naar hetzelfde ISA niveau worden
vertaald, is een systeem potentieel in staat om heel veel hogere programmeertalen te
ondersteunen.
5.1
5.2
5.3 Instructieformaten
Een instructie bestaat doorgans uit een opcode, en eventuele extra informatie over de
oorsprong van de operanden, en de bestemming van de resultaten. Het algemene onderwerp
van specificeren van locaties noemt men adresseren.
De lengte van instructies kan variëren, zowel voor eenzelfde machine, als tussen de machines.
Instructies met vaste lengte zijn eenvoudig te decoderen, en snel op te halen. Instructies met
variabele lengte zorgt er dan weer voor dat er minder geheugen wordt verspild.
Een ander probleem, is het probleem van de beperkte geheugenbandbreedte. Geheugens
kunnen instructies niet aanleveren aan de snelheid waarmee de processor de instructies kan
verwerken. Hoe korter de instructies, hoe meer instructies er per tijdseenheid kunnen worden
aangeleverd.
5.3.1 Ontwerpcriteria voor instructieformaten



Minimaliseren van de afmetingen van de instructies. Instructies zijn daardoor
moeilijker te decoderen, maar dit laat toe om meer instructies per tijdseenheid aan de
CPU aan te leveren, en de beperkte geheugenbandbreedte op te vangen.
Binnen het instructieformaat moet voldoende ruimte aanwezig zijn om alle gewenste
operaties te kunnen formuleren. De opcode moet bijvoorbeeld voldoende groot zijn
om het gewenste aantal instructies te kunnen coderen. Een machine met 2 n instructies
moet minstens n bits voor de opcode voorzien.
Het aantal bits per adresveld. De lengte van het adresveld bepaalt de
geheugenresolutie.
5.3.2 Expanderende opcodes
De lengte van de instructies blijft vast, maar de ligging van de grens van de velden van de
instructie kan variëren. Gaan we bijvoorbeeld uit van een 16 bit instructie met 4 bit opcode en
3 x 4 bit adresvelden, dan kunnen de eerste 15 opcodes (waarden 0000b to 0111b) beschouwd
als instructies met 3 adresvelden. De volgende opcodes kunnen dan beschouwd worden als
instructies met 8 bit opcodes, en twee adresvelden, enzovoort.
5.3.3
5.3.4
5.3.5
5.4 Adressering
Adressering is de manier waarop wordt aangegeven waar de operanden van een instructie te
vinden zijn.
5.4.1 Adresseringsmodi
Het adresveld van de instructie kan op verschillende manieren worden geïnterpreteerd. Deze
verschillende interpretaties zijn de verschillende adresseermodi.
5.4.2 Onmiddellijke adressering
In plaats van de locatie van het operand op te geven, wordt het operand onmiddellijk
meegegeven in de instructie zelf. (immediate operand) Er is dus geen geheugentoegang
nodig om het operand op te halen. Nadelig is dan wel dat er enkel constanten kunnen worden
meegegeven.
5.4.3 Absolute of directe adressering
Het volledige adres wordt als operand gespecifieerd. Nu kan de waarde van het operand
veranderen, maar deze wordt altijd uit dezelfde plaats van het geheugen opgehaald. Directe
adressering kan bijgevolg enkel worden gebruikt om globale variabelen te benaderen,
waarvan de locatie tijdens compilatie bekend is. In het geval van memory mapped IO kunnen
ook
5.4.4 Registeradressering
Deze aanpak is analoog aan directe adressering, het operand specifieert echter een register in
plaats van een locatie in het hoofdgeheugen
5.4.5 Registerindirecte adressering
De bestemming of bron van de operand ligt in het hoofdgeheugen, maar in plaats van deze
expliciet mee te geven, wordt deze in een register geplaatst. Dit heeft als voordeel dat de
instructie geen volledig geheugenadres hoeft te bevatten, maar wel het hele hoofdgeheugen
kan bestrijken. Een bijkomend voordeel is dat het adres tijdens de loop van het programma
veranderd kan worden. Dit is bijvoorbeeld nuttig bij het overlopen van een tabel in het
geheugen. (Register incrementeren.)
Sommige platformen hebben instructies waarbij voor of na een dereferentie van een register,
de pointer die het register voorstelt kan worden verplaatst. (postincrement, predecrement)
5.4.6 Geïndexeerde adressering
De adressering gebeurt nu via een constante offset, vermeerderd met inhoud van een register.
Als constante offset kan bijvoorbeeld het beginadres van een tabel worden meegegeven. Om
de individuele tabelelementen te benaderen, kan dan de waarde van het register worden
veranderd.
Deze addresseringswijze heeft als voordeel dat er geen volledig geheugenadres in de
instructie hoeft worden opgenomen. Bijkomend kunnen de geheugenwoorden veranderen
telkens de instructie wordt uitgevoerd.
5.4.7 Basisgeïndexeerde adressering
In deze modus zijn wordt het effectieve adres bepaald door de som van twee registers
vermeerderd met een constante offset. Een van de register fungeert als basis, het andere
fungeert dan als offset.
5.4.8 Relatieve adressering
Het adres van de operanden wordt relatief t.o.v. de programmateller genoteerd. Dit kan
worden gebuikt als addresseringsmodus voor sprongopdrachten. Dit is evenwel niet altijd het
geval, sommige platformen implementeren ook absolute sprongen. Een relatieve sprong heet
een branch een absolute sprong is een jump. Alle voorwaardelijke sprongen zijn branches.
Deze zijn beperkt tot een klein bereik, en staan positieonafhankelijk programmeren toe.
Stack-adressering
Er moeten geen adressen worden meegegeven. Alle operanden worden op de stapel geplaatst,
de instructie haalt de nodige operanden van de stapel, en plaatst indien nodig het resultaat
terug.
Een eenvoudig voorbeeld van een taal die ook deze principes gebruikt is de reversed polish
notation voor rekensommen. HP rekenmachines kunnen in deze modus worden geschakeld.
In plaats van de operator tussen de operanden in te geven, worden eerst de operanden
ingegeven, en dan de operator. Het resultaat van de bewerking wordt terug op de stapel
geplaatst.
5.4.9 Adresseringsmodi voor sprongopdrachten
5.4.10 Orthogonaliteit van opcodes en adresseringsmodi
Orthogonaliteit van opcodes: alle opcodes ondersteunen alle adresseringsmodi waar zinvol.
Dit komt echter zelden voor.
6 HET ASSEMBLEERTAALNIVEAU
Het onderscheid tussen interpretatie en vertaling is belangrijk. Bij vertaling wordt een
programma eerst vertaald naar de doeltaal, waarbij er een uitvoerbaar programma wordt
gegenereerd. Dit vertaalde programma wordt dan uitgevoerd.
6.1 Inleiding tot assembleertalen
Als de brontaal een symbolische voorstelling is voor een machinetaal, en de doeltaal een
machinetaal wordt het vertaalproces assembleren genoemd. De brontaal heet dan een
assembleertaal, en de vertaler een assembler.
6.1.1 Wat is assembleertaal?
Elk statement komt overeen met precies één instructie van de machinetaal. Er is dus een één
op één correspondentie tussen de machinetaal en de assembleertaal.
De assembleertaal wordt gebruikt zodat de programmeur enkel symbolische instructies zou
moeten onthouden.
Eenzelfde assembleertaal kan enkel slechts op een bepaalde familie van machines lopen.
Hogere talen kunnen potentieel op verschillende families van machines lopen.
6.1.2 Waarom assembleertaal gebruiken
Programmeren in assembleertaal heeft twee voordelen: Enerzijds is het sneller en zijn de
programma’s kleiner dan die van in een hogere taal, anderzijds is er ook betere toegang tot de
hardware van het systeem.
Programmeren in assembleertaal is veel arbeidsintensiever in termen van opstellen van
programma’s, debuggen en onderhoud.
Bepaalde stukken van een programma in een hogere programmeertaal waarvan men merkt dat
ze voor een groot deel de tijd van de processor in beslag neemt, of kritisch zijn kan men
herschrijven in assembleertaal. Dit heet tuning. Als vuistregel geldt dat programma’s in
assembleertaal 3 maal sneller zijn dan programma’s in een hogere taal, maar 5 keer moeilijker
te ontwikkelen zijn.
6.1.3 Een statement in assembleertaal
6.1.4 Pseudo-instructies
Een pseudo-instructie of assembler directieve is een instructie voor de assembler zelf.
6.2 Macro’s
Als een bepaald stuk code veelvuldig voorkomt, kan men ofwel de instructies iedere keer
herschrijven (vervelend) of wel de code onderbrengen in een procedure (aanroep moet iedere
keer worden gecodeerd en is langzamer)
Macro’s vormen een eenvoudige oplossing voor het aanroepen van een reeks gelijke of
weinig verschillende instructies.
6.2.1 Defenitie, aanroep en expansie van macro’s
Een macrodefinitie is een manier om een stuk tekst een naam te geven. De macro kan dan
worden aangeroepen door de macronaam als instructie te gebruiken. Als de assembler deze
naam ziet, zal hij deze ter plaatse expanderen (vervangen) door de tekst die hij voorstelt.
Macro’s kunnen ook formele parameters hebben (in de definitie). Bij de aanroep van de
macro worden deze dan vervangen door de actuele parameters.
Bij de definitie van de macro worden er sleutelwoorden gebruikt die begin en einde
aanduiden. Deze zijn afhankelijk van het platform.
Macro’s kunnen genest worden. Ze mogen ook recursief worden aangeroepen.
Macroaanroepen mogen niet verward worden met procedureaanroepen. Procedure aanroepen
zijn machineinstructies, terwijl een macrodefinitie ene assembler directive is.
6.3 Het assembleerproces
6.3.1 Two-pass-assemblers
Om het probleem van de voorwaartse referentie waarbij een symbool wordt gebruikt alvorens
het gedefinieerd is op te lossen, wordt er twee keer door de code gegaan. In de eerste
doorgang worden de definities van de symbolen ontdekt en bijgehouden, in de tweede
doorgang wordt de broncode vertaald.
One-pass assemblers vertalen het programma met een doorgang. Het programma wordt dan
naar een soort tussenvorm vertaald, die gaandeweg wordt aangevuld wanneer er meer
symbolen bekend worden.
De kern van de assembler is de opcodetabel. De opcodetabel bevat de vertalingen tussen de
mnemonics en de hexadecimale opcodes, als ook de lengte van de instructie, de klasse van de
instructie en de types van de operanden.
De symbooltabel bevat een de vertaling tussen de labels en de instructie locaties plus
eventuele andere informatie.
6.3.2 Pass 1
De voornaamste functie van de eerste pass is het opbouwen van de symbooltabel, die de
waarden en namen van alle gedefinieerde symbolen bevat. Voor de adressen van labels bij te
houden gebruikt de assembler de instruction location counter (ILC) die bij iedere instructie
wordt verhoogd met de lengte van de instructie.
Elke mogelijke implementatie van een symbooltabel simuleert een associatief geheugen.
Mogelijke implementaties zijn:



Lineair zoeken in een ongeordende tabel
Binair zoeken in een geordende tabel
Hashing
6.3.3 Pass 2
Genereren van het objectprogramma, en produceren van de informatie die de linker eventueel
nodig kan hebben. Eventueel wordt ook een listing bestand gegenereerd.
6.4 Linken en laden
Procedures worden apart geassembleerd. Uit elke procedure bron ontstaat dan een
objectbestand (een objectmodule). Alle objectbestanden moeten worden samengevoegd tot
een uitvoerbaar binair programma. Dit proces heet linken, en wordt uitgevoerd door de
linker.
Deze werkwijze heeft het voordeel dat, wanneer een procedurebron wordt gewijzigd, het
volledige binaire programma niet moet worden opnieuw geassembleerd. Enkel de gewijzigde
procedure moet opnieuw worden geassembleerd, en de linkage moet opnieuw worden
uitgevoerd. Verder zijn kleinere modules beter beheersbaar, en gaat de vertaling van apparte
module sneller.
Wanneer een programma gelinkt is, moet het uitvoerbare programma in het hoofdgeheugen
worden geladen.
6.4.1 Door de linker uitgevoerde taken
Elke geassembleerde module start bij adres 0, en stelt dus zijn eigen virtuele adresruimte
voor. De linker moet dus deze adressen aanpassen. Daarbij zijn volgende problemen:


Relocatieprobleem: referenties naar geheugenadressen kloppen niet meer, omdat de
modules in het geheugen verschoven zijn. Op systemen met gesegmenteerde
adresruimten is dit eenvoudig op te lossen door elke module in zijn eigen segment de
plaatsen. De systemen waarop dit toepasbaar is, zijn echter zeldzaam.
Probleem van externe referenties: Bij linken is het adres van een andere module die
wordt aangeroepen met CALL nog niet bekend.
De linker voert de volgende taken uit om beide problemen op te lossen:




Constructie van een tabel met object modules en hun lengte
Op basis van de geconstrueerde tabel wordt aan iedere module een laad adres
toegekend.
Alle instructies die een adres bevatten worden verhoogd met een relocatieconstante.
Alle instructies met aanroepen van procedures worden van een correct adres voorzien.
6.4.2 Structuur van een objectmodule
Figuur 7-16, pg. 551.





Identificatie: naam, lengte, datum
Ingangentabel: symbolen die door andere modules worden gebruikt
Machines-instructies en constanten
Relocatie-dictionary: lijst van de te wijzigen adressen
Einde van de module
Merk op dat enkel de machine-instructies uiteindelijk in het geheugen zullen worden geladen.
6.4.3 Bindingstijdstip en dynamische relocatie
Bij het in- en uitswappen van programma’s is er geen garantie dat een programma twee keer
op dezelfde plaats terechtkomt. De adressen zijn dus na een swapin mogelijks verkeerd, en de
relocatie gegevens zijn dan niet meer beschikbaar.
Het bindinstijdstip is het tijdstip waarop aan de symbolische namen het werkelijke
geheugenadres wordt toegekend. Een programma verplaatsen na de binding levert fouten op.
Een aantal mogelijke bindinstijdstippen:






Bij het schrijven
Bij de vertaling
Bij het linken, voor het laden
Bij het laden
Bij het laden van een basisregister dat voor adressen wordt gebruikt
Bij het uitvoeren van de instructie
Bij het binden zijn er twee aspecten die van belang zijn:




Wanneer wordt aan een symbolische naam een virtueel adres toegekend? Dit gebeurt
door de linker.
Wanneer wordt aan een virtueel adres een fysiek adres toegekend? Hiervoor zijn drie
benaderingen gangbaar:
Het programma kan worden verplaatst, enkel de paginatabel wordt aangepast, niet het
programma. Dit is positie onafhankelijk programmeren.
Werken met een relocatieregister.

Geheugenreferenties relatief maken t.o.v. PC. Als het programma wordt verplaatst,
hoeft enkel de PC worden aangepast.
6.4.4 Dynamisch linken
Dynamisch linken houdt in dat een procedure pas wordt gelinkt op het moment dat ze wordt
aangeroepen, tijdens de uitvoering van het programma.
Dynamisch linken in MULTICS




Elk programma bevat een linksegment, dat een blok informatie bevat voor elke
procedure die kan worden aangeroepen. Dit blok bevat onder andere het virtuele adres
van de procedure, en de string naam van de procedure.
Procedure aanroepen van de brontaal worden vertaald naar instructies die indirect het
eerste woord van het corresponderende linkblok adresseren. De compiler vult dit blok
op zodanig dat er een trap wordt veroorzaakt.
De trap start dan de linker op, die de naam van de procedure opzoekt, de procedure
linkt, en het adres in het linkblok aanpast.
De instructie die de trap veroorzaakte wordt opnieuw uitgevoerd, het programma kan
dan verder lopen.
Dynamisch linken in OS/2


Het hoofdprogramma doet een systeemaanroep met de vraag een bepaalde file op te
zoeken op disk, deze in het geheugen te laden, en de locatie van de file in het
geheugen terug te geven.
Dit heeft als voordeel dat programma’s uit te bereiden zijn door files op disk te
plaatsen.
Dynamisch linken in windows









Er wordt gebruik gemaakt van speciale files zoals dll’s.
De dll bevat procedures en/of data.
Dit laat toe om een bibliotheek van procedures te sharen door meerdere processen,
zodat er geheugen wordt bespaard.
Elke dll bevat naast de gewone procedures en data ook minstens
Een procedure voor allocatie
Een procedure voor deallocatie
Allocatie kan gebeuren
Impliciet (of statisch): de dll’s worden vermeld in een import library, en worden bij
opstarten van proces allen ingeladen
Expliciet: er wordt at run-time gelinkt door een dll aan te roepen als die nodig is.
Dynamisch linken in UNIX

Gebeurt zoals in windows, met impliciete allocatie van een shared library.
Download