Cursus: Digitale Elektronica & Processoren H01L1A versie 2.7
Willem M. A. Van Onsem, BSc. KOMMUSOFT
Katholieke Universiteit Leuven Academiejaar 2010-2011
ii
Inhoudsopgave I
Digitaal Ontwerp en Fysische Limieten
1
1 De Basis van een Digitaal Ontwerp 1.1 Logische schakelingen . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 Logische schakelingen in huis . . . . . . . . . . . . . . . . . 1.1.2 Waarheidstabellen . . . . . . . . . . . . . . . . . . . . . . . 1.1.3 Logische poorten . . . . . . . . . . . . . . . . . . . . . . . . 1.1.4 Logische schakelingen . . . . . . . . . . . . . . . . . . . . . 1.2 Booleaanse algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 Theorema’s en eigenschappen . . . . . . . . . . . . . . . . . 1.3 Synthese met logische poorten . . . . . . . . . . . . . . . . . . . . . 1.3.1 SOP & POS . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.2 Canonieke versus standaard realisatie . . . . . . . . . . . . 1.3.3 Realisaties met NAND en NOR . . . . . . . . . . . . . . . . 1.4 Digitaal ontwerp in grote lijnen . . . . . . . . . . . . . . . . . . . . 1.4.1 Specificatie . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.2 Synthese . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.3 Bibliotheek . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.4 Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.5 Documentatie . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.6 Ontwerpen met CAD . . . . . . . . . . . . . . . . . . . . . 1.5 Taalgebaseerd hardware ontwerp: VHDL . . . . . . . . . . . . . . . 1.5.1 Alternatieven en uitbreidingen . . . . . . . . . . . . . . . . 1.5.2 Voordelen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5.3 Nadelen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5.4 Beperkingen . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5.5 Basisconcepten (entiteiten en architectuur) . . . . . . . . . 1.5.6 Gelijkenissen en verschillen met klassieke programmeertalen
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
3 4 4 6 7 8 9 9 11 11 12 13 14 14 15 15 16 16 16 17 17 18 18 19 19 22
2 Technologische Randvoorwaarden 2.1 Logische waarden voorstellen . . . . . 2.2 Implementatie van poorten . . . . . . 2.2.1 Schakelaars . . . . . . . . . . . 2.2.2 Basispoorten . . . . . . . . . . 2.2.3 Complexe poorten . . . . . . . 2.3 Negatieve logica . . . . . . . . . . . . . 2.4 Technologie¨en . . . . . . . . . . . . . . 2.4.1 Specifieke chips . . . . . . . . . 2.4.2 Programmeerbare chips . . . . 2.5 Praktische aspecten . . . . . . . . . . 2.5.1 Spanningsniveaus en ruismarge 2.5.2 Dynamisch gedrag . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
23 24 25 25 26 29 32 32 33 34 37 37 39
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
iii
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
iv
INHOUDSOPGAVE 2.5.3 2.5.4 2.5.5 2.5.6
II
Vermogenverbruik . . “0” en “1” doorgeven Fan-in en fan-out . . . Tri-state buffer . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Combinatorische en Sequenti¨ ele Schakelingen
3 Combinatorische Schakelingen (Schakelingen zonder 3.1 Minimaliseren van logische functies . . . . . . . . . . . 3.1.1 Waarom minimaliseren . . . . . . . . . . . . . . 3.1.2 Hoe minimaliseren? . . . . . . . . . . . . . . . 3.1.3 Karnaugh-kaarten . . . . . . . . . . . . . . . . 3.1.4 Quine-McCluskey . . . . . . . . . . . . . . . . . 3.1.5 Realisatie in meer dan 2 lagen . . . . . . . . . 3.1.6 Welke methode kiezen? . . . . . . . . . . . . . 3.2 Rekenkundige basisschakelingen . . . . . . . . . . . . . 3.2.1 Getallen voorstellen . . . . . . . . . . . . . . . 3.2.2 Radix-conversie . . . . . . . . . . . . . . . . . . 3.2.3 Optellen . . . . . . . . . . . . . . . . . . . . . . 3.2.4 Negatieve getallen . . . . . . . . . . . . . . . . 3.2.5 Optellen en aftrekken van negatieve getallen . . 3.2.6 Arithmetic-Logic Unit (ALU) . . . . . . . . . . 3.2.7 Vermenigvuldigen . . . . . . . . . . . . . . . . 3.2.8 Andere courante bewerkingen . . . . . . . . . . 3.2.9 Vaste komma getallen . . . . . . . . . . . . . . 3.2.10 Vlottende komma getallen . . . . . . . . . . . . 3.2.11 Andere voorstellingen van gegevens . . . . . . . 3.3 Andere basisschakelingen . . . . . . . . . . . . . . . . 3.3.1 Multiplexer . . . . . . . . . . . . . . . . . . . . 3.3.2 Decoder . . . . . . . . . . . . . . . . . . . . . . 3.3.3 Demultiplexer . . . . . . . . . . . . . . . . . . . 3.3.4 Encoder en prioriteitsencoder . . . . . . . . . . 3.3.5 Vergelijker . . . . . . . . . . . . . . . . . . . . . 3.3.6 Schuifoperator . . . . . . . . . . . . . . . . . .
45
geheugen) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Sequenti¨ ele Schakelingen (Schakelingen met geheugen) 4.1 Terminologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Classificatie van sequenti¨ele schakelingen . . . . . . . . . . 4.1.2 Terminologie van het kloksignaal . . . . . . . . . . . . . . 4.2 Bouwblokken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 De flipflop . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.2 Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.3 Tellers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Synchrone schakelingen . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Leidende voorbeelden . . . . . . . . . . . . . . . . . . . . 4.3.2 Stap 1: opstellen van het toestandsdiagram . . . . . . . . 4.3.3 Stap 2: Minimaliseren van de toestanden . . . . . . . . . 4.3.4 Stap 3: Implementeren van de toestanden in het geheugen 4.3.5 Stap 4: Implementeren van de combinatorische logica . . 4.3.6 Tijdsgedrag . . . . . . . . . . . . . . . . . . . . . . . . . . 4.4 Asynchrone schakelingen . . . . . . . . . . . . . . . . . . . . . . . 4.4.1 Leidend voorbeeld . . . . . . . . . . . . . . . . . . . . . . 4.4.2 Stap 1: Opstellen van een toestandstabel . . . . . . . . .
41 42 43 43
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
47 49 49 50 50 56 57 57 58 59 60 62 68 69 72 73 76 77 77 80 81 82 82 84 85 86 88
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
93 94 95 95 95 96 103 104 108 108 108 110 113 116 121 123 124 124
INHOUDSOPGAVE 4.4.3 4.4.4 4.4.5 4.4.6
III
Stap 2: Minimaliseren van de toestanden Stap 3: Codering van de toestanden . . . Stap 4: Realisatie met digitale logica . . . Besluit . . . . . . . . . . . . . . . . . . . .
v . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Processoren
125 130 138 143
145
5 Niet-Programmeerbare Processoren 5.1 De Niet-Programmeerbare Processor . . . . . . . . 5.1.1 Algemene Structuur . . . . . . . . . . . . . 5.1.2 Het Datapad . . . . . . . . . . . . . . . . . 5.2 Formeel Beschrijven van een Algoritme . . . . . . . 5.2.1 Leidend Voorbeeld: Deler . . . . . . . . . . 5.2.2 Toestandsbeschrijving . . . . . . . . . . . . 5.2.3 Toestand-Actie Tabel . . . . . . . . . . . . 5.2.4 ASM-Schema . . . . . . . . . . . . . . . . . 5.3 Geheugencomponenten . . . . . . . . . . . . . . . . 5.3.1 Register File Cell (RFC) . . . . . . . . . . . 5.3.2 Registerbank . . . . . . . . . . . . . . . . . 5.3.3 Random Access Memory (RAM) . . . . . . 5.3.4 Geheugens met Impliciete Adressering . . . 5.4 Synthese van een Niet-Programmeerbare Processor 5.4.1 Basisprincipes . . . . . . . . . . . . . . . . . 5.4.2 Ontwerp Controller . . . . . . . . . . . . . . 5.4.3 Minimaliseren Datapad . . . . . . . . . . . 5.4.4 Andere optimalisaties . . . . . . . . . . . . 5.4.5 Besluit . . . . . . . . . . . . . . . . . . . . . 5.5 Tijdsgedrag . . . . . . . . . . . . . . . . . . . . . . 5.5.1 Kritisch pad . . . . . . . . . . . . . . . . . . 5.5.2 Verschoven kloksignalen (“clock skew”) . . 5.5.3 Synchroniseren van asynchrone ingangen . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
147 148 149 150 150 151 151 152 154 158 158 159 161 162 167 167 172 176 206 212 212 212 213 214
6 Programmeerbare Processoren 6.1 De Programmeerbare Processor . . . . . . . . . . . 6.2 Instructies en Velden . . . . . . . . . . . . . . . . . 6.2.1 Programma . . . . . . . . . . . . . . . . . . 6.2.2 Instructie . . . . . . . . . . . . . . . . . . . 6.2.3 Instructieformaat . . . . . . . . . . . . . . . 6.2.4 Generische Instructiecyclus . . . . . . . . . 6.2.5 Uitvoeringssnelheid . . . . . . . . . . . . . . 6.2.6 Adresvelden . . . . . . . . . . . . . . . . . . 6.2.7 Adresseermodi . . . . . . . . . . . . . . . . 6.3 Processorontwerp . . . . . . . . . . . . . . . . . . . 6.3.1 RISC en CISC . . . . . . . . . . . . . . . . 6.3.2 Ontwerpcyclus . . . . . . . . . . . . . . . . 6.3.3 Complex Instruction Set Computer (CISC) 6.3.4 Reduced Instruction Set Computer (RISC)
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
217 218 219 219 219 220 221 221 221 224 228 228 229 229 246
vi
IV
INHOUDSOPGAVE
Very High Speed Integrated Circuit Hardware Description Language
7 VHDL 7.1 Elementen van de VHDL-taal . . . . . . . 7.1.1 Lexicale elementen (woordenschat) 7.1.2 Literals . . . . . . . . . . . . . . . 7.1.3 Identifiers . . . . . . . . . . . . . . 7.1.4 scheidingstekens . . . . . . . . . . 7.1.5 Commentaar . . . . . . . . . . . . 7.2 Typesysteem . . . . . . . . . . . . . . . . 7.2.1 Voorgedefinieerde types . . . . . . 7.2.2 Zelf types defini¨eren . . . . . . . . 7.3 Objecten . . . . . . . . . . . . . . . . . . . 7.3.1 Constante . . . . . . . . . . . . . . 7.3.2 Variabele . . . . . . . . . . . . . . 7.3.3 Signaal . . . . . . . . . . . . . . . 7.4 Bewerkingen . . . . . . . . . . . . . . . . 7.4.1 Logische bewerkingen . . . . . . . 7.4.2 Rekenkundige bewerkingen . . . . 7.4.3 Schuifoperaties . . . . . . . . . . . 7.4.4 Vergelijkingen . . . . . . . . . . . . 7.4.5 “Array aggregaat” bewerkingen . . 7.5 Bibliotheken . . . . . . . . . . . . . . . . . 7.6 Combinatorische schakelingen in VHDL . 7.6.1 Hardwarebeschrijving met VHDL . 7.7 Sequenti¨ele schakelingen in VHDL . . . . 7.8 Processoren in VHDL . . . . . . . . . . . 7.8.1 Leidend voorbeeld: sha1 checksum 7.9 VHDL grammatica . . . . . . . . . . . . . 7.10 Programmeerjargon . . . . . . . . . . . .
V
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
261 . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
Digitale Elektronica in de Praktijk
8 Circuits Schakelen 8.1 Anatomie van een Ge¨ıntegreerd circuit . . 8.1.1 DIP packing . . . . . . . . . . . . 8.1.2 Populaire ge¨ıntegreerde circuits . . 8.2 Analoge componenten . . . . . . . . . . . 8.2.1 Weerstanden . . . . . . . . . . . . 8.2.2 Condensatoren . . . . . . . . . . . 8.2.3 Spoelen . . . . . . . . . . . . . . . 8.2.4 Transistoren . . . . . . . . . . . . . 8.2.5 Diodes en Operationele versterkers 8.3 Bouw van een elektronische schakeling . . 8.3.1 Matrixbord . . . . . . . . . . . . . 8.3.2 Europrintplaat . . . . . . . . . . . 8.3.3 Printed Circuit Board (PCB) . . . 8.3.4 Plaatsen van componenten . . . . 8.3.5 Tips bij het solderen . . . . . . . . 8.4 Implementatie van een kloksignaal . . . . 8.4.1 555-timer . . . . . . . . . . . . . . 8.4.2 Astabiele multivibrator . . . . . . 8.4.3 Kristal-oscillator . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
263 264 264 264 265 265 266 266 266 266 270 271 271 272 275 275 276 276 276 276 277 277 278 278 278 278 280 281
283 . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
285 285 285 286 286 287 288 289 289 289 289 290 291 291 293 293 293 293 295 295
INHOUDSOPGAVE 8.5 8.6
vii
Printed Circuit Board (PCB) Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 Oproep aan de lezers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
9 Experimenten 9.1 Oneindig vermenigvuldigen . . . . 9.1.1 Benodigdheden . . . . . . . 9.1.2 Model . . . . . . . . . . . . 9.1.3 Realisatie . . . . . . . . . . 9.2 Fietslicht . . . . . . . . . . . . . . 9.2.1 Benodigdheden . . . . . . . 9.2.2 Implementatie-specificaties 9.2.3 Realisatie . . . . . . . . . . 9.3 Tic tac toe-machine . . . . . . . . 9.3.1 Benodigdheden . . . . . . . 9.3.2 Implementatie-specificaties
VI
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
Appendices
299 300 300 300 301 304 304 305 306 307 307 308
311
A Conventies en Schemas A.1 Waarheidstabellen van basisschakelingen A.1.1 Eenvoudige poorten . . . . . . . A.1.2 Complexe poorten . . . . . . . . A.2 Lijst van component interfaces . . . . . A.3 Conventies . . . . . . . . . . . . . . . . . A.4 Poorten . . . . . . . . . . . . . . . . . . A.4.1 Basispoorten . . . . . . . . . . . A.4.2 Complexe Poorten . . . . . . . . A.5 Componenten . . . . . . . . . . . . . . . A.5.1 Rekenkundige schakelingen . . . A.5.2 Geheugen schakelingen . . . . . . A.5.3 Andere schakelingen . . . . . . . A.6 Kostprijs van de Componenten . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
313 314 314 314 314 315 315 315 315 315 315 315 315 315
B Softwarepakketten B.1 Geschreven software . . . . . B.1.1 De software installeren B.1.2 Invoer en Uitvoer . . . B.1.3 Uitvoer . . . . . . . . B.1.4 Ondersteunde functies B.1.5 Functiecompositie . . B.2 Andere software . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
319 320 320 320 322 322 323 323
C Oplossingen van de Oefeningen C.1 Hoofdstuk 1 . . . . . . . . . . . C.2 Hoofdstuk 2 . . . . . . . . . . . C.3 Hoofdstuk 3 . . . . . . . . . . . C.3.1 Karnaugh-kaarten . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
325 325 325 325 325
Woordenlijst
337
viii
INHOUDSOPGAVE
Notities vooraf Deze cursus omvat de volledige inhoud van het onderwerp “Digitale Elektronica & Processoren” gegeven tijdens het academiejaar 2010-2011 door prof. Van Eycken. De cursus is dan ook hoofdzakelijk gebaseerd op de presentaties voor dit opleidingsonderdeel. Andere bronnen worden vermeld in de referentielijst op pagina 336. Aanbevolen literatuur is [?], [?], [?] en [?]. De cursus wordt uitgegeven onder de CopyLeft licentie, dit betekent dat iedereen de cursus vrij kan aanpassen en herverdelen. De auteur garandeert de juistheid van deze cursus niet. Hoewel deze cursus met de nodige zorg is samengesteld, is het niet ondenkbaar dat er fouten in staan. Errata/opmerkingen/suggesties kunnen altijd doorgestuurd worden naar
[email protected], deze worden dan in de volgende versie verbeterd. Over de auteur
valt eigenlijk niet veel te zeggen, behalve dat hij geen exemplaren signeert.
Speciale dank gaat naar (in alfabetische volgorde) “Amy Winehouse”, “Harold Budd”, “Hooverphonic”, “Moby”, “Paul Simon”, “Piknik”, “Russkij Razmer” en “The Beatles” voor de muziek tijdens de nachten waarin deze cursus tot stand kwam.
Betreft het examen Het examen bestond tijdens het academiejaar 2010-2011 traditioneel uit drie delen: 1. Theorie: bestaat uit twee vragen, dit zijn meestal termen. Deze termen kunnen achteraan in de index op pagina 351 worden teruggevonden. De meeste ook in de woordenlijst op pagina 336. 2. Synthese van een datapad en controller: De student krijgt een VHDL-code, en wordt gevraagd naar een equivalent ASM-schema. Vervolgens dient hierbij het datapad en de controller gesynthetiseerd te worden. Soms volstaat het echter om bij de controller een toestandsdiagram weer te geven. 3. Synthese van een toestandsdiagram: Er wordt een toestandsdiagram gegeven (meestal in tabelvorm). De student dient dit diagram te vertalen in hardware. Meestal worden er extra beperkingen opgelegd, zoals het gebruik van een bepaald type flip-flop, en/of poorten. Ook dient men vaak de Karnaugh-kaarten weer te geven. Het examen is volledig gesloten boek. De eerste twee vragen worden mondeling besproken, wat op papier staat vormt echter de basis. De laatste vraag is volledig schriftelijk. Enkel het examenmoment geldt als evaluatie. De student mag een referentieblad meebrengen over VHDL. Dit is te koop bij de VTK CuDi.
Layout en Stijl Alle pagina’s zijn afdrukbaar met een zwart-wit printer. Dit drukt eventuele kosten bij een afdruk van deze cursus. Bovendien verhoogt het de leesbaarheid bij kleurenblinden. ix
x
INHOUDSOPGAVE
Deze cursus is gecompileerd met LATEXen wordt ge¨ıllustreerd met talloze afbeeldingen. Deze afbeeldingen zijn allemaal tot stand gekomen met het grafisch pakket TikZ1 samen met zelfgeschreven bibliotheken. Alle afbeeldingen zijn bijgevolg vectorieel. En kunnen dus eindeloos uitvergroot worden met een geschikte .pdf viewer. Terminologie wordt in het vetjes en zonder schreven2 gezet. Deze terminologie wordt ook herhaald op het einde van de cursus in de index op pagina 351.
Kudos Kudos gaan uit naar volgende personen/groepen (in alfabetische volgorde): Conrad.be Leverancier van elektronische onderdelen om de circuits zelf te testen. Prof. Christian Maes Voor onvergetelijke lessen Statistische Thermodynamica over het grootcanonisch ensemble Ξ (T, V, µ) = eβP V . Ingmar Dasseville Voor enkele Haskell scripts in het kader van geautomatiseerde LATEX-code generatie. Wina studentenkring Om overduidelijke redenen... In tegenstelling tot VTK... Het revisoren-team bestaande uit: Ingmar Dasseville, Jonas Vanthornhout, Katie Pauwelyn en Steven Roose. Personen die errata indienden Alex Witteveen, Christophe Van Ginneken, Davy Vanclee, Dennis Degryse, Giel Dops, Ingmar Dasseville, Jonas Devlieghere, Jonas Vanthornhout, Katie Pauwelyn, Lynn Houthuys, Neline van Ginkel, Philippe De Croock, Pieter Van Riet, Sander Van Loock.
Link naar deze cursus De meest recente versie van deze cursus is op onderstaande link te vinden: Indien er fouten gerapporteerd http://www.4shared.com/documents/?? Figuur 1: Link naar de meest recente versie van deze cursus. worden, of toevoegingen gedaan worden zullen na verloop van tijd de aanpassingen daar te vinden zijn. Deze cursus is opgedragen aan leden van mijn familie: • Louis Van Onsem (1931-1993): voor drie jaar peterschap en m’n derde voornaam: Agnes. • Gabri¨ ella Simons (1923-2012): voor haar humor, fijne herinneringen en 17 jaar plaatsvervangend peterschap. • Constant Soetewey (1907-1945): voor hoogstaande absurdistische literatuur, die dit jaar opnieuw uitgegeven werd[?] onder het pseudoniem Kurt K¨ ohler.
1 TikZ: 2 De
TikZ ist kein Zeichenprogramm. zogenoemde “pootjes” die sommige letters krijgen. (Engels: serifs)
INHOUDSOPGAVE
xi
bad
poor
average
good
excellent
QualityReference: 1 KommuSoft Quality Standards at http://www.4shared.com/??
xii
INHOUDSOPGAVE
Voorbeschouwing
xiii
xiv
INHOUDSOPGAVE
Deel I
Digitaal Ontwerp en Fysische Limieten
1
Hoofdstuk 1
De Basis van een Digitaal Ontwerp werd niet als een soort accessoire van Adam geschapen, “ Eva maar Adam was het eerste ontwerp voor Eva. - Jeanne Moreau, Frans actrice (1928-)
”
Zoals de naam van deze cursus reeds doet vermoeden werken we met digitale schakelingen, digitale schakelingen onderscheiden zich van de traditionele analoge schakelingen omdat ze slechts een beperkt aantal waarden kunnen aannemen. In de praktijk werken we bijna uitsluitend met binaire signalen. Deze waarden hoeven niet noodzakelijk een verschil in spanning aan te duiden. Sterker nog, het gebruik van elektronica is zelfs niet verplicht. Zo zouden we ook een verschil in stroomsterkte, druk, reflectie,... als parameter kunnen nemen. Het komt er enkel op aan om twee waarden te defini¨eren die we symbolisch zullen voorstellen als 0 en 1 en een reeks operaties te kunnen realiseren voor deze natuurfenomenen. Indien we echter meer dan twee verschillende waarden nodig hebben, kunnen we dit probleem oplossen door een aantal binaire waarden te groeperen. In dit eerste hoofdstuk zullen we een beperkte set aan basisoperaties op deze binaire signalen introduceren: de NOT, AND en OR. We formaliseren deze operaties in de booleaanse algebra. Ook bespreken we een methode om een booleaanse functie te synthetiseren. Tot slot bespreken we het verloop van een digitaal ontwerp en introduceren we een taal om hardware mee te beschrijven: VHDL. 1.1
Logische schakelingen . . . . . . . . . . . . . . 1.1.1 Logische schakelingen in huis . . . . . . . . . 1.1.2 Waarheidstabellen . . . . . . . . . . . . . . . 1.1.3 Logische poorten . . . . . . . . . . . . . . . . 1.1.4 Logische schakelingen . . . . . . . . . . . . . 1.2 Booleaanse algebra . . . . . . . . . . . . . . . 1.2.1 Theorema’s en eigenschappen . . . . . . . . .
3
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
4 4 6 7 8 9 9
4
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP 1.3
1.4
1.5
Synthese met logische poorten
11 11
SOP & POS
1.3.2
Canonieke versus standaard realisatie . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.3.3
Realisaties met NAND en NOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
Digitaal ontwerp in grote lijnen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.1
Specificatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.2
Synthese . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.4.3
Bibliotheek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.4.4
Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.4.5
Documentatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.4.6
Ontwerpen met CAD
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
Taalgebaseerd hardware ontwerp: VHDL . . . . . . . . . . . . . . . . . . . . . .
17
1.5.1
Alternatieven en uitbreidingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
1.5.2
Voordelen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
1.5.3
Nadelen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
1.5.4
Beperkingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
1.5.5
Basisconcepten (entiteiten en architectuur) . . . . . . . . . . . . . . . . . . . . . .
19
1.5.6
1.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.1
Entity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
Architecture
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
Gelijkenissen en verschillen met klassieke programmeertalen . . . . . . . . . . . . .
22
Logische schakelingen
Het definieren van binaire waarden op zich heeft niet veel nut: we willen met deze binaire waarden bepaalde operaties uitvoeren. Om berekeningen te kunnen uitvoeren maken we gebruik van logische schakelingen. Logische schakelingen zijn een reeks operaties op ´e´en of meer binaire parameters die resulteren in een uitgang. De waarde die op de uitgang staat is hierbij afhankelijk van de ingangen. De set van basisoperaties dient klein, simpel en tegelijk universi¨eel te zijn: elke complexe schakeling moet uit een combinatie van deze basisschakelingen kunnen worden opgebouwd. Als basisschakelingen definieert men meestal de NOT, AND en OR operaties. Deze operaties zijn eenvoudig en gemakkelijk te begrijpen en onthouden. Hoewel booleaanse algebra in heel wat andere cursussen reeds aan bod komt, zullen we er ook in deze cursus enkele secties aan besteden. We zullen de booleaanse algebra behandelen aan de hand van een model met lichtschakelaars.
1.1.1
Logische schakelingen in huis
We beschouwen een schakeling zoals op Figuur 1.1. Zoals we zien zal indien we de schakelaar x indrukken, x
x
Figuur 1.1: Basis van het lamp-model.
1.1. LOGISCHE SCHAKELINGEN
5
het lichtje branden. Indien we vervolgens de schakelaar loslaten zien we dat het lampje opnieuw dooft. We formaliseren dit door te schrijven: L=x (1.1) Waarbij we L beschouwen als het al dan niet branden van het lampje, en x aanduidt of de schakelaar al dan niet ingedrukt is. Indien we nu als ingang beschouwen of de schakelaar al dan niet ingedrukt is, en als uitgang of het lichtje al dan niet brandt, kunnen we hiermee functies gaan defini¨eren. Not Indien we de implementatie van de schakelaar aanpassen zijn we in staat om een NOT poort te bouwen. Zoals op Figuur 1.2(a). Deze schakelaar laat stroom door indien deze niet ingedrukt is. Bijgevolg kunnen we stellen dat het al dan niet branden van het lampje equivalent is met niet de schakelaar indrukken. We formaliseren dit als: (1.2) L = x0 = ¬x =!x = x = NOT x Zoals we zien zijn er in de loop der tijd nogal wat notaties ingevoerd; wat bovendien eigen is aan de volledige booleaanse algebra. In deze cursus zullen we enkel het accent (x0 ) als negatie gebruiken. Literatuur buiten deze cursus kan echter andere standaarden gebruiken. Een NOT poort wordt vaak ook een inverter genoemd. And Soms willen we dat het lampje pas gaat branden indien twee of meer schakelaars allemaal ingedrukt zijn. In dat geval spreken we van een AND. Een AND kunnen we implementeren volgens het lamp-model zoals in Figuur 1.2(b). We noteren: L = x · y = x AND y (1.3) Or Een andere basisbewerking is de OR. Hierbij willen we dat het lampje brandt bij minstens ´e´en ingedrukte schakelaar. Of we noteren: L = x + y = x OR y (1.4) Een implementatie in het lamp-model is te vinden op Figuur 1.2(c). x
x
(a) Not
x
y
x
y
x
y
x
(b) And
x
x
x
x
y
y
y
y
(c) Or
Figuur 1.2: Implementatie van de basispoorten volgens het lamp-model.
y
6
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP
Door deze drie basisbewerkingen met elkaar te combineren kunnen we eindeloos veel nieuwe bewerkingen bouwen. Zoals bijvoorbeeld de exclusieve OR, ook wel de XOR genoemd. De XOR is een bewerking waarbij het lampje gaat branden indien juist ´e´en van de twee schakelaars ingedrukt is. Deze bewerking kunnen we realiseren door NOT, AND en OR bewerkingen te combineren als volgt: L = x ⊕ y = x XOR y = (x · y 0 ) + (x0 · y)
(1.5)
Deze schakelingen kunnen we dan vervolgens in ons lamp-model omzetten zoals op Figuur 1.3. x
y y
x
Figuur 1.3: XOR-poort in het lamp-model.
1.1.2
Waarheidstabellen
We kunnen alle schakelingen voorstellen met het lamp-model. Toch is het niet echt praktisch, we gaan dus op zoek naar andere manieren om de logische formules te berekenen, en ook eenvoudig voor te stellen. Een makkelijke manier om logische schakelingen te berekenen is met behulp van waarheidstabellen. Een waarheidstabel is een tabel waarbij we alle variabelen voorstellen, en vervolgens met eventuele tussenstappen de uiteindelijke bewerking berekenen. Hierbij maken we gebruik van waarheidstabellen die we reeds kennen: de waarheidstabellen van de basisfuncties. Indien we n variabelen beschouwen betekent dit dat onze waarheidstabel 2n rijen telt. Immers kan elke n variabele ofwel 0 ofwel 1 zijn. Bovendien is het aantal functies met n variabelen beperkt tot 22 . Dit zegt echter niet over het aantal mogelijke implementaties: deze is onbegrensd. In Tabel 1.1 geven we de waarheidstabellen van de basisoperaties weer. (a) Not
x 0 1
0
x 1 0
(b) And
x 0 0 1 1
y 0 1 0 1
x·y 0 0 0 1
(c) Or
x 0 0 1 1
y 0 1 0 1
x+y 0 1 1 1
Tabel 1.1: Waarheidstabellen van de basisoperaties.
We kunnen vervolgens aan de hand van deze waarheidstabellen de werking van een XOR-bewerking bestuderen. We dienen eenvoudigweg basisoperaties toe te passen op deelresultaten om zo uiteindelijk het finale gedrag van de bewerking te kennen zoals in Tabel 1.2. Indien twee implementaties voor iedere rij dezelfde uitvoer genereren, zijn de implementaties equivalent, en beschrijven ze dezelfde functie. Equivalente implementaties zijn nuttig om een schakeling effici¨enter te maken. We gaan immers altijd op zoek naar equivalente implementaties die minder kosten of sneller werken.
1.1. LOGISCHE SCHAKELINGEN x 0 0 1 1
y 0 1 0 1
x0 1 1 0 0
7 y0 1 0 1 0
x0 · y 0 1 0 0
x · y0 0 0 1 0
x0 · y + x · y 0 0 1 1 0
x⊕y 0 1 1 0
Tabel 1.2: Waarheidstabel voor de implementatie van een XOR.
1.1.3
Logische poorten
Naast het uitrekenen van operaties heeft ons lamp-model nog een nadeel. Het is erg onpraktisch om grote en complexe schakelingen voor te stellen. Een algemeen geaccepteerde notatie is deze met behulp van logische poorten. Poorten zijn kleine componenten die enkele ingangen bevatten, en ´e´en uitgang. Op figuren 1.4(a) tot en met 1.4(c) geven we de poorten van de basisbewerkingen weer. We kunnen alle mogelijke schakelingen bouwen met deze poorten. Toch worden vaak ook alternatieve poorten gedefinieerd om veelgebruikte bewerkingen mee toe te passen. Bovendien kunnen we de werking van de basis poorten ook veralgemenen naar meer ingangen. Zo defini¨eren we een n-and als een poort waar enkel een 1 op de uitgang verschijnt indien op alle n ingangen een 1 staat. Figuur 1.4(d) toont een 3-and. Een n-or is een poort waar enkel een 0 op de uitgang verschijnt indien op alle n ingangen een 0 staat. Zo staat op Figuur 1.4(e) een 5-or.
x
L
x y
L
(a) Not
(b) And
x y
L (c) Or
(d) 3-and
(e) 5-or
Figuur 1.4: Basispoorten en uitbreidingen.
Complexe poorten Complexe poorten die in de loop der tijd een eigen symbool kregen zijn onder meer de NOR, NAND en XOR, deze staan afgebeeld op Figuur 1.5, samen met een equivalent schema dat uitsluitend uit NOT, AND en OR poorten. De waarheidstabellen van deze complexe poorten staan in x L x y
L
x y
L (a) NAND
x y
L
x y
L
y x y
(b) NOR
L (c) XOR
Figuur 1.5: Complexe poorten. subsectie Subsectie A.4.2. Universi¨ ele poorten De reden dat NAND en NOR poorten populair zijn komt hoofdzakelijk omdat het universi¨ ele poorten zijn. Dat betekent dat iedere basispoort kan ge¨ımplementeerd worden met behulp van NAND of NOR poorten. In Tabel 1.3 staan deze implementaties. Bovendien is het realiseren van NAND en NOR poorten in de meeste technologie¨en goedkoper dan het bouwen van AND en OR poorten.
8
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP NOT
AND
OR x L
met NAND
x
L
x y
L
y
x L met NOR
x
L
y
x y
L
Tabel 1.3: Implementatie van de basispoorten met behulp van NAND en NOR poorten. Ge¨ınverteerde ingangen Tot slot introduceren we nog een andere conventie die vaak gebruikt wordt: ge¨ınverteerde ingangen. NOT poorten worden heel vaak gebruikt, ook bij ingangen van andere poorten. Het symbool van de NOT poort neemt nogal wat plaats in op een schema. Daardoor is het de gewoonte om soms cirkels te tekenen aan de ingangen van een bepaalde poort: ge¨ınverteerde ingangen. Deze cirkels stellen een NOT poort voor. Concrete voorbeelden staan op Figuur 1.6. In het algemeen kunnen we dus zeggen dat een cirkel duidt op het inverteren. Inverteren in het schema betekent echter niet noodzakelijk dat we bij de fysische implementatie gebruik moeten maken van een inverter of NOT poort (meestal is het zelfs omgekeerd): men kan vaak de implementatie van de poort - bijvoorbeeld AND of OR - zo aanpassen dat er geen extra transistoren nodig zijn om ingangen te inverteren.
Figuur 1.6: Poorten met ge¨ınverteerde ingangen.
1.1.4
Logische schakelingen
De vorige subsectie toonde al dat we met deze poorten netwerken kunnen bouwen. Deze netwerken worden logische schakelingen genoemd. Deze schakelingen implementeren dan uiteindelijk de functionaliteiten waarvoor we een digitaal circuit ontwerpen. We kunnen logische schakelingen beschrijven door middel van een schema zoals we dat tot nu toe altijd gedaan hebben. Een andere techniek is echter op basis van een taal: VHDL1 . Deze taal komt onder meer aan bod in sectie Sectie 1.5, en verder in de verdere hoofdstukken van deze cursus. Optimaliseren Een belangrijk probleem met schakelingen is het vinden van een optimale implementatie voor een bepaalde functie. Sommige schakelingen beschrijven dezelfde functie. Sterker nog, voor elke functie zijn er oneindig veel schakelingen die deze functie kunnen implementeren. Bijgevolg zoeken we voor een probleem uit de set van equivalente schakelingen naar de schakeling die ons het meeste voordeel oplevert. Hiervoor zijn twee parameters vaak belangrijk: kostprijs en verwerkingskracht. Om deze parameters te optimaliseren is het belangrijk eerst een (grove schatting) te kunnen maken van deze parameters voor een geggeven logische schakeling. De kostprijs van een logische schakeling is eenvoudig te berekenen met volgende formule: Kostprijs = #poortingangen + #poortuitgangen − #inverters (1.6) Merk op dat deze formule geen eenheid heeft. Het is dan ook niet de bedoeling de kostprijs in bijvoorbeeld euro te berekenen: het is eerder bedoeld als een ruwe metriek om verschillende schakelingen met elkaar te kunnen vergelijken. 1 VHDL:
VHSIC Hardware Design Language; VHSIC: Very High Speed Integrated Circuit.
1.2. BOOLEAANSE ALGEBRA
9
De verwerkingskracht wordt dan weer bepaald door het concept van het langste pad. Ketens van poorten waarbij de uitgangen van sommige poorten weer ingangen van andere poorten aansturen zijn immers nefast. We streven dus naar schakelingen waarbij een signaal slechts door een beperkt aantal poorten heen moet. De lengte van het langste pad is echter niet makkelijk te berekenen. Immers hangt de vertraging van een poort af van onder meer het type en het aantal ingangen. Het totaal aantal ingangen waar een signaal door moet daarentegen geeft in de meeste gevallen een goede ruwe schatting. We formaliseren tot: Minimale vertraging ∝ #poortingangen langste keten
(1.7)
Tijdsgedrag In de vorige paragraaf hadden we het reeds over performantie. Snelle systemen worden vaak beperkt door het tijdsgedrag van logische schakelingen. Wanneer we in de wiskunde een functie beschrijven die afhangt van een reeks variabelen, bestaat het concept tijd niet wanneer we plots een variable zouden aanpassen. Maar zoals we reeds gesteld hebben, heeft een poort een zekere tijd nodig om de verandering aan de ingang door te rekenen. Dit lijkt slechts een detail. Een nadelig effect hiervan is echter dat er overgangsverschijnselen kunnen ontstaan. Zo kan het gebeuren dat bij een verandering van een ingang, waarbij de uitgang niet hoort te veranderen, de uitgang toch tijdelijk een andere waarde aanneemt. Zo zien we bijvoorbeeld op Figuur 1.7 dat een verandering aan een ingang gepropgaeerd wordt langs twee wegen. Het veranderde ingangssignaal propageert zich sneller door de ene dan door de andere weg. Bovendien hangt de vertraging niet enkel af van het type poort: tijdens de fabricage van poorten zullen er kleine verschillen optreden, deze poorten zullen dan ook een licht verschillend tijdsgedrag ontwikkelen. Tussen twee (dezelfde) poorten zullen dus kleine tijdsverschillen optreden. In het geval een verschil in tijdsgedrag er toe leidt dat er tijdelijk een foute waarde aan de uitgang (of ergens in het midden van het circuit optreedt), spreken we van een glitch. Figuur 1.7 toont een scenario van veranderende signalen in een logische schakeling met een glitch.
x
a f
y
b
x 1 0 y 1 0 a 1 0 1 b 0 f 1 0
“glitch”
t
Figuur 1.7: Voorbeeld van het tijdsgedrag van een logische schakeling met een “glitch”.
1.2
Booleaanse algebra
De tak van de wiskunde die zich bezighoudt met logische bewerkingen is de booleaanse algebra. Deze algebra rekent uitsluitend met de twee logische waarden {0, 1} en drie logische operatoren die ons reeds bekend zijn: NOT (0 ), AND (·) en OR (+). Deze operaties hebben elk een specifieke prioriteit zodat men met een minimum aan haakjes toch een complexe expressie kan beschrijven. Zo heeft de NOT prioriteit over de AND die prioriteit heeft over de OR.2
1.2.1
Theorema’s en eigenschappen
De booleaanse algebra maakt gebruik van theorema’s om de operatoren te evalueren. Zo worden de resultaten van logische operatoren zonder variabelen gedefinieerd zoals we dat ook met een waarheidstabel kunnen doen. Deze definities staan in Tabel 1.4. 2 Een
ezelsbruggetje om dit te onthouden is het woord NANO: Not, ANd en Or.
10
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP 0·0=0 1·1=1 0·1=1·0=0 00 = 1
1+1=1 0+0=0 1+0=0+1=1 10 = 0
Tabel 1.4: Booleaanse algebra zonder variabelen. In de booleaanse algebra wordt ook met variabelen gerekend. Op die manier kan men vaak expressies manipuleren en optimaliseren. Indien we slechts ´e´en variabele beschouwen gelden regels weergegeven in Tabel 1.5. x·0=0 x·1=x x·x=x x · x0 = 0 (x0 )0 = x
x+1=1 x+0=x x+x=x x + x0 = 1
Tabel 1.5: Booleaanse algebra met ´e´en variabele.
Tot slot werden ook regels gedefinieerd voor meerdere variabelen. Deze regels kunnen onder meer het aantal variabelen reduceren evenals het aantal operatoren, of tot alternatieve implementaties leiden die mogelijk sneller werken. Een opsomming van deze wetten staan in Tabel 1.6. Commutativiteit x+y =y+x Associativiteit x · (y · z) = (x · y) · z x + (y + z) = (x + y) + z Distributiviteit x · (y + z) = x · y + x · z x + (y · z) = (x + y) · (x + z) Absorptie x+x·y =x x · (x + y) = x Wet van De Morgan (x · y)0 = x0 + y 0 (x + y)0 = x0 · y 0 x·y =y·x
Tabel 1.6: Booleaanse algebra met meerdere variabelen.
Dualiteit Een opmerkelijke eigenschap bij booleaanse algebra is de dualiteit. Indien we bij een van de wetten uit Tabel 1.4, Tabel 1.5 of Tabel 1.6 de OR operaties door AND operaties vervangen en vice-versa, en de 1 door 0 vervangen en vice-versa, bekomen we eenvoudigweg een andere wet uit deze tabellen (meestal dezelfde rij, maar de andere kolom). Deze eigenschap noemen we de dualiteit van de booleaanse algebra. Bovendien geldt dus ook dat slechts de helft van de gestelde wetten vereist is. Het andere deel kan met de wetten van De Morgan afgeleid worden. Verschil met de gewone algebra Omdat ook de booleaanse algebra een optelling en vermenigvuldiging lijkt te defini¨eren en er bovendien ook analogie¨en te trekken zijn, lijkt het soms dat booleaanse algebra niet verschilt van de standaard algebra. Toch zijn er enkele opmerkelijke verschillen. Zo bestaat er geen verschil of deling in de booleaanse algebra. Verder voldoet in de booleaanse algebra volgend stelsel voor iedere y:
y + y0 = 1 y·y =y
(1.8)
1.3. SYNTHESE MET LOGISCHE POORTEN
11
Terwijl in de standaard algebra er slechts ´e´en y is waarvoor dit geldt: y = 1. Tot slot is bij standaard algebra de optelling ook niet distributief tegenover de vermenigvuldiging, zo is 5 + 2 · 4 6= (5 + 2) · (5 + 4) terwijl in booleaanse algebra x + (y · z) = (x + y) · (x + z) dit wel geldt.
1.3
Synthese met logische poorten
Nu we weten hoe logische schakelingen werken, en hoe we deze door middel van de booleaanse algebra kunnen uitwerken, wordt het tijd om zelf schakelingen te beginnen bouwen. Dit doen we vertrekkend vanuit een waarheidstabel. Soms is het makkelijk om een implementatie af te leiden uit deze waarheidstabellen. Maar indien het aantal variabelen groot wordt of de functie complex is, wordt het vinden van een implementatie moeilijk. In deze cursus stellen we dan ook enkele algemene technieken voor om uit een waarheidstabel machinaal een logische functie te genereren. In Sectie 3.1 zullen we bovendien enkele methodes beschrijven om deze logische implementaties te optimaliseren. Doorheen deze sectie zullen we een logische functie genereren voor de waarheidstabel in Tabel 1.7. In de waarheidstabel zien we uitsluitend 0 en 1 staan. In x 0 0 0 0 1 1 1 1
y 0 0 1 1 0 0 1 1
z 0 1 0 1 0 1 0 1
f 0 1 0 0 1 1 1 0
Tabel 1.7: Waarheidstabel voor het synthese-voorbeeld. Subsubsectie 3.1.3 zullen we echter kennismaken met een derde ”waarde”3 : de don’t care.
1.3.1
SOP & POS
Sum-of-Products (SOP) en Product-of-Sums (POS) zijn twee technieken die op een machinale manier uit een waarheidstabel een logische functie genereren. Ze maken respectievelijk gebruik van mintermen en maxtermen. Sum-of-Products De Sum-of-Products methode maakt gebruik van mintermen. Een minterm is een logische functie die slechts waar is voor ´e´en gegeven rij in een waarheidstabel. Dit bekomen we door het booleaans product te nemen van alle ingangen. Indien een ingang in die rij 0 is wordt de bijbehorende variabele in het product ge¨ınverteerd. De minterm van rij i noteren we als mi . De Sum-of-Products methode neemt de booleaanse som van 1-mintermen. Een 1-minterm is een minterm die waar is bij een rij waarbij f ook waar is. Tabel 1.8 toont voor iedere rij de minterm. Wanneer f waar is, wordt ook de 1-minterm ingevuld. Vervolgens bepalen we de som van alle 1-mintermen. Product-of-Sums Analoog maakt de Product-of-Sums gebruik van maxtermen. Zoals de naam reeds doet vermoeden is een maxterm een logische functie die altijd waar is behalve voor ´e´en rij in de waarheidstabel. Indien we de maxterm voor een bepaalde term willen genereren dienen we de booleaanse optelling van de negatie van de variabelen te nemen. We noteren een maxterm voor rij i met Mi , niet te verwarren met mi voor de mintermen. De Product-of-Sums methode neemt analoog het booleaanse product van de 0maxtermen. Een 0-maxterm is analoog een maxterm wanneer f onwaar is. Tabel 1.9 toont voor iedere rij de maxterm. Wanneer f onwaar is, wordt ook de 0-maxterm ingevuld. Vervolgens bepalen we het product van alle 0-maxtermen. 3 De
don’t care is geen echte waarde, ze duidt eerder op ongespecificeerd.
12
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP
x 0 0 0 0 1 1 1 1
y 0 0 1 1 0 0 1 1
z 0 1 0 1 0 1 0 1
minterm m0 = x0 · y 0 · z 0 m1 = x0 · y 0 · z m2 = x0 · y · z 0 m3 = x0 · y · z m4 = x · y 0 · z 0 m5 = x · y 0 · z m6 = x · y · z 0 m7 = x · y · z
f 0 1 0 0 1 1 1 0
xy z
1-minterm
m1
m1 = x0 · y 0 · z
m4 f m4 = x · y 0 · z 0 m5 = x · y 0 · z m6 = x · y · z 0
m5 m6
SOP: f = m1 + m4 + m5 + m6 = x0 · y 0 · z + x · y 0 · z 0 + x · y 0 · z + x · y · z 0 Tabel 1.8: Sum-of-Products methode toegepast op het voorbeeld.
x 0 0 0 0 1 1 1 1
y 0 0 1 1 0 0 1 1
z 0 1 0 1 0 1 0 1
maxterm M0 = x + y + z M1 = x + y + z 0 M2 = x + y 0 + z M3 = x + y 0 + z 0 M4 = x 0 + y + z M5 = x 0 + y + z 0 M6 = x 0 + y 0 + z M7 = x 0 + y 0 + z 0
f 0 1 0 0 1 1 1 0
xy z
0-maxterm M0 = x + y + z
M0
M2 = x + y 0 + z M3 = x + y 0 + z 0
M2 f M3 M7
0
0
M7 = x + y + z
0
POS: f = M0 · M2 · M3 · M7 = (x + y + z) · (x + y 0 + z) · (x + y 0 + z 0 ) · (x0 + y 0 + z 0 ) Tabel 1.9: Product-of-Sums methode toegepast op het voorbeeld.
1.3.2
Canonieke versus standaard realisatie
Wanneer we de Sum-of-Products of Product-of-Sums methodes toepassen, zullen alle min- of maxtermen per definitie alle variabelen bevatten. Deze implementatie wordt de canonieke vorm genoemd. Dit is bijgevolg een relatief dure implementatie. Nochtans bestaat er een eenvoudige methode om een groot deel van de poorten te elimineren of te reduceren in aantal ingangen. Deze methode zet de canonieke vorm om in de standaard vorm. De methode komt er op neer verschillende min- of maxtermen samen te nemen door er de wetten van De Morgan (zie Tabel 1.6) op toe te passen. Op die manier kunnen we dan deelexpressies van de vorm x + x0 uitkomen. Omdat deze deelexpressies altijd waar zijn onafhankelijk van x kan bijgevolg x ge¨elimineerd worden uit de nieuwe min- of maxterm4 . Op Figuur 1.8 herleiden we de canonieke vormen van het voorbeeld naar hun standaard equivalent. Door alle mogelijkheden uit te putten bij de standaard vorm bekomen we gegarandeerd de meest minimale vorm voor schakelingen met twee lagen. Het is echter wel mogelijk goedkopere schakelingen te ontwerpen die uit meerdere lagen bestaat. In dat geval dient er echter een trade-off gemaakt te worden tussen kosten enerzijds en performantie anderzijds. Zo toont Figuur 1.9 een alternatieve implementatie van een standaardvorm. Deze is 8% goedkoper5 , maar zal slechts aan 66% van de snelheid werken. In dat geval zal de toepassing 4 Strikt 5 De
genomen is dit dan geen min- of maxterm meer. relatieve kost van een circuit kan berekend worden met Vergelijking (1.6).
1.3. SYNTHESE MET LOGISCHE POORTEN
13
Sum-of-Products 0 0
0 0
0
Product-of-Sums
x y z + xy z + xy z + xyz
(x + y + z) (x + y 0 + z) (x + y 0 + z 0 ) (x0 + y 0 + z 0 )
0
xy z
xy z
f
f
= (x + x0 ) y 0 z + (y + y 0 ) xz 0 = y 0 z + xz 0
= (y + y 0 ) (x + z) (x + x0 ) (y 0 + z 0 ) = (x + z) (y 0 + z 0 )
xy z
xy z f
f
Figuur 1.8: Herleiden naar standaard vorm van voorbeeld. vaak uitmaken wat het meest opportuun is. x
x f
y
y
f
z
z f = xy + yz + xz
f = x(y + z) + yz
Figuur 1.9: Standaard vorm en alternatief.
1.3.3
Realisaties met NAND en NOR
Zoals reeds kort vermeld in Subsectie 1.1.3 zijn NAND en NOR poorten erg populair bij heel wat implementaties. Dit komt omdat ze alle basispoorten kunnen emuleren zoals blijkt uit Tabel 1.3 op pagina 8. Bovendien is hun kostprijs lager dan een AND of OR poort6 . NAND en NOR poorten blijken bovendien ook makkelijk implementeerbaar als substituut voor AND en OR poorten in standaard vorm. Figuur 1.10 toont hoe we ons voorbeeld in standaardvorm verder kunnen optimaliseren. Eerst inverteren we de min- en max-termen door van een AND en OR respectievelijk een NAND en NOR te maken. We behouden echter de functie door inverters aan de ingangen van het tweede niveau toe te voegen. Immers is tweemaal inverteren niets anders dan dezelfde waarde behouden. Door vervolgens de wetten van De Morgan toe te passen in de tweede stap, resulteert dit in een circuit die alleen gebruik maakt van NAND en NOR poorten. Bovendien geldt dat een circuit ge¨ımplementeerd met NAND en NOR poorten altijd zowel goedkoper en sneller is dan zijn canonisch equivalent. Een laatste voordeel is dat we de schakelimg met ´e´en type poort implementeren. Dit kan nuttig zijn omdat we op een chip in massa poorten van eenzelfde type kunnen zetten, en dan later de bedrading ontwerpen. 6 Denk
aan de formule van de kostprijs: het aantal inverters wordt afgetrokken van de kostprijs.
14
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP Sum-of-Products
Product-of-Sums
xy z
xy z f
f
f
f
De Morgan
De Morgan
f
f
Figuur 1.10: Standaardvorm van het voorbeeld met NAND en NOR’s. Specificatie §specificatie Bibliotheek §bibliotheek Synthese §synthese Documentatie §documentatieAnalyse §analyse
Figuur 1.11: Typisch verloop van een digitaal ontwerp.
1.4
Digitaal ontwerp in grote lijnen
Nu we de concepten van een digitaal ontwerp in grote lijnen uitgetekend hebben, kunnen we het over de organisatorische kant van de zaak hebben. Immers komt bij een digitaal ontwerp veel meer kijken dan alleen het bouwen van de juiste schakeling. Een klant zal immers specificaties sturen waaraan de hardware moet voldoen, bovendien wil de klant naast de hardware vaak ook nog documentatie over hoe men het toestel dient te gebruiken. Bovendien willen we vermijden dat we bij het ontwerpen telkens opnieuw het wiel moeten uitvinden. Er bestaan immers al bibliotheken die allerhande schakelingen voor bijvoorbeeld optellingen, testen op gelijke waarde,... bevatten. Deze zijn meestal met de nodige zorg samengesteld zodat het vinden van een nog effici¨entere implementatie moeilijk wordt. We hebben er dus belang bij deze bibliotheken aan te spreken, en in het geval we een betere implementatie vinden, de bibliotheek aan te passen. Figuur 1.11 vat het hele verloop van het bouwen van een digitale schakeling goed samen. In de volgende subsecties zullen we de verschillende stappen meer in detail bekijken.
1.4.1
Specificatie
Een Specificatie is een beschrijving van de functionaliteiten die van de hardware in kwestie gevraagd worden. In tegenstelling tot specificaties in bijvoorbeeld de informatica, is de interface ook een onderdeel van de specificaties. De interface beschrijft hoe de hardware interageert met zijn omgeving. Deze omgeving is niet noodzakelijk de gebruiker die bijvoorbeeld toetsen indrukt en het scherm uitleest. Dit kan ook bijvoorbeeld een PCI7 bus zijn waarmee met bijvoorbeeld een computer gecommuniceerd wordt. 7 PCI:
Peripheral Component Interconnect.
1.4. DIGITAAL ONTWERP IN GROTE LIJNEN
15
Dikwijls zijn initieel de specificaties onvolledig. De gaten in de specificaties worden dan ook opgevuld wanneer er zich problemen stellen bij bijvoorbeeld de synthese. Specificaties zijn bijgevolg een iteratief proces. Dikwijls bevatten de specificaties ook reeds implementatiesbeslissingen die onnodige beperkingen opleggen aan het ontwerp. De beschrijving wordt ofwel in natuurlijke taal, wat soms dubbelzinnig is, of met behulp van een blokschema beschreven.
1.4.2
Synthese
De Synthese is niets anders dan de vertaling van de specificaties van een hoog en abstract naar een lager niveau. Hierbij dienen uiteraard concrete beslissingen genomen te worden over de implementatie. Zo kunnen de specificaties bijvoorbeeld vermelden dat x en y bij elkaar opgeteld moeten worden. De synthese moet dan een concrete implementatie voorstellen. Bijvoorbeeld een 16-bit ripple-carry adder met twee registers. Synthese gebeurt meestal op verschillende niveaus. Zo worden op het laagste niveau componenten gebouwd: dit zijn bijvoorbeeld de poorten maar ook flipflops of multiplexers8 . Deze worden op een niveau hoger gebruikt om Register-Transfer-Level (RTL) Componenten te bouwen. Deze RTL componenten zijn bijvoorbeeld optellers, schuifregisters en tellers. Schakelingen met deze componenten zijn dan Application Specific IC (ASIC) componentenEen laag van componenten voor synthese. Hieronder vallen de algemene bouwblokken van een systeem zoals processoren en geheugens.. Deze componenten vormen dan uiteindelijk de bouwblokken voor het systeem. Bij de systeemsynthese worden dan processoren, geheugens en de ASIC componenten gecombineerd. Figuur 1.12 toont de pyramide van synthese. Elk niveau combineert hierbij de componenten ge¨ıntroduceerd op een niveau lager.
Systeemsynthese (bouwblokken: processoren, geheugen, ASIC) Architectuursynthese (op RTL-niveau) (met RTL-componenten: optellers, tellers, schuifregisters) Ontwerp op componentniveau (met basiscomponenten: poorten, flipflops)
Ontwerp van componenten
Figuur 1.12: De verschillende lagen bij de synthese.
1.4.3
Bibliotheek
We dienen niet het volledige stuk hardware vanaf transistor of poortniveau te ontwerpen. Heel wat werk is dan ook al in het verleden door andere ontwerpers gedaan. Het hergebruiken van deze ontwerpen heeft dan ook heel wat voordelen: • De ontwerpen zijn meestal al door verschillende personen geoptimaliseerd. Het vinden van een nog optimalere implementatie is daardoor quasi onbestaand. 8 Zie
respectievelijk Subsectie 4.2.1 en Subsectie 3.3.1.
16
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP • Men streeft naar telkens hogere integratieniveaus waarbij soms volledige systemen op chip te verkrijgen zijn. Bovendien worden deze systemen telkens geavanceerder. Dit komt door de Wet van Moore. Deze stelt dat elke 24 maanden het aantal transistoren op een chip verdubbelt. • Vaak kan men componenten kopen die een bepaalde functie vervullen. Dit bespaart veel ontwerpwerk. Bovendien zijn deze componenten vaak veel goedkoper dan ze zelf te ontwerpen en te produceren. Bijvoorbeeld een 16 kB geheugen.
Er bestaan bibliotheken op elk syntheseniveau. Dus bijgevolg kan men tot op het niveau dat men zelf kiest putten uit de bibliotheken.
1.4.4
Analyse
Na elke synthesestap is het belangrijk om te testen of aan de vereiste specificaties voldaan is. Dit wordt gedaan in de Analyse. Niet alleen wordt hier getest of de implementatie de functionaliteit levert die gevraagd is, ook allerhande andere parameters worden in rekening gebracht: • Kostprijs: vaak wordt hier als metriek het aantal pinnen en de oppervlakte van de printplaat (PCB9 ) gebruikt. • Vermogengebruik : het vermogenverbruik wordt meestal berekend met de formule C · f · V 2 met als parameters: – C: De oppervlakte van de chip. De oppervlakte is in de tijd toegenomen. In 1983 was een gemiddelde chip immers 0.25 cm2 , in 2000 was dat ongeveer 4 cm2 . – f : De klokfrequentie. De klokfrequentie is in de loop der tijd exponentieel gestegen. Met 1 MHz in 1983, en 1 GHz in 2000. – V : De spanning die aan de chip geleverd wordt. De spanning is gedaald: van 5 V in 1983 tot 1.5 V ongeveer 17 jaar later. • Snelheid : de vertraging of doorvoer (“ throughput”), dit is het aantal resultaten per seconde. • Testbaarheid : kunnen we alle fouten ontdekken met behulp van testvectoren?
1.4.5
Documentatie
Naast de hardware verlangt de klant meestal ook documentatie. Afhankelijk van het soort klant zal er andere documentatie vereist zijn. Indien we een volledig afgewerkt consumentenproduct maken, dienen we een handleiding voor de consument en de hersteller samen te stellen. Hierin beschrijven we in natuurlijke taal hoe de component aangestuurd kan worden. Indien we echter een component leveren, bijvoorbeeld een geheugenmodule zal men een handleiding maken met daarin de specifieke ontwerpdetails. Meestal zal ook intern binnen het bedrijf documentatie een vereiste zijn. Dit om de eventueel verdere ontwikkelingen te ondersteunen.
1.4.6
Ontwerpen met CAD
Computer Aided Design (CAD) wordt vaak toegepast om een chip te ontwikkelen. Hierbij wordt met behulp van een computer een een speciaal softwarepakket meestal het volledige ontwerp begeleid. Een concreet voorbeeld hiervan is bijvoorbeeld KiCad voor Linux. Zoals andere CAD tools bevat KiCad een project manager die de gebruiker door de verschillende stappen begeleidt, en een set tools die de gebruiker bij iedere stap de nodige ondersteuning bieden. Uiteraard ziet het ontwerp met een CAD-tool er gelijkaardig uit aan het ontwikkelingsproces op Figuur 1.11. De CAD-tools bieden echter meer mogelijkheden om ontwerpen al in een vroeg stadium te testen en te simuleren. Figuur 1.13 toont het ontwikkelingsproces met behulp van een CAD-tool. 9 PCB:
Printed Circuit Board.
1.5. TAALGEBASEERD HARDWARE ONTWERP: VHDL
17
Specificatie
Ingave ontwerp Fysisch ontwerp
VHDL
Schema
Synthese
Functionele Simulatie
Simulatie tijdsgedrag
Nee
Tijdsgedrag OK?
Ja Nee
Ontwerp OK?
Chipconfiguratie
Ja
Figuur 1.13: Digitaal ontwerpen met CAD.
1.5
Taalgebaseerd hardware ontwerp: VHDL
Zoals reeds vermeld werd op Figuur 1.13, wordt VHDL veel gebruikt om schakelingen in te voeren in een computersysteem. VHDL is de afkorting van VHSIC Hardware Description Language. VHSIC staat voor Very High Speed Integrated Circuit. VHDL is een programmeertaal waarmee men het gedrag van digitale circuits probeert te beschrijven. De taal biedt mogelijkheden aan om op een eenduidige manier het gedrag van een circuit te specifi¨eren op RTL niveau. Daarnaast is de taal erg nuttig om simulaties te draaien, synthese uit te voeren (VHDL software is meestal in staat om zelf effici¨ente implementaties voor te stellen) en documentatie te genereren. VHDL is gestandaardiseerd bij de IEEE10 . De eerste versie van VHDL is VHDL-87, gestandaardiseerd onder IEEE 1076. In 1993 werd de tweede versie, VHDL-93 uitgebracht in IEEE 1164. Sinds 2002 bestaat er ook een derde versie die nog niet gestandaardiseerd is. Deze standaarden omvatten echter uitsluitend de syntax: de implementatie van de VHDL compiler is volledig vrij. Er is dan ook concurrentie tussen VHDL compilers in features om de meest effici¨ente implementatie te kunnen voorstellen.
1.5.1
Alternatieven en uitbreidingen
VHDL-AMS Een uitbreiding op VHDL is VHDL Analog and Mixed Signals (VHDL-AMS). Hierbij worden niet alleen digitale maar ook analoge signalen beschouwd. VHDL-AMS kan dus als een superset van de orginele VHDL beschouwd worden. Bovendien wordt met continue tijd gerekend in plaats van de door VHDL gebruikte discrete tijdstippen. Dit werd ge¨ımplementeerd door een set algebra¨ısche en differenti¨ele vergelijkingen. Hoewel deze uitbreiding in 1999 door de IEEE gestandaardiseerd werd, is VHDL-AMS sinds zijn oorsprong in 1993 nooit echt doorgebroken. 10 IEEE:
Institute for Electrical and Electronics Engineers.
18
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP
Verilog De de facto concurrent van VHDL is Verilog (IEEE 1364). Verilog is erg populair in de Verenigde Staten maar is nooit echt doorgebroken in Europa. Beide talen stammen ook uit andere taalfamilies met andere paradigma’s: terwijl VHDL eerder lijkt op Ada, is Verilog meer verwant met C. Ondanks de concurrentie lijkt geen van beide talen het pleit te kunnen beslechten. Of zoals D. Pellerin & D. Taylor het verwoorden in “VHDL Made Easy!”[?] stellen: Both languages are easy to learn and hard to master. And once you have learned one of these languages, you will have no trouble transitioning to the other. PLD talen Talen zoals Abel en Palasm zijn zogenaamde PLD talen11 . Deze talen specifi¨eren schakelingen op het niveau van de poorten en dit slechts voor een speciale technologie. Deze talen hebben bijgevolg ook een ander objectief. Waar VHDL net bedoeld is om zich met de details bezig te houden, en de gebruiker met de grote lijnen, zijn PDL talen bedoelt om te implementeren op deze lagere niveaus.
1.5.2
Voordelen
VHDL wordt hoofdzakelijk in de industrie gebruikt omwille van zijn overdraagbaarheid. VHDL is immers een standaard die door allerhande programma’s gehanteerd wordt. Elk van deze programma’s kunnen heel diverse toepassingen hebben. Op die manier kan een stuk VHDL eerst gesimuleerd worden met het ene programma, daarna gesynthetiseerd met een ander, om bijvoorbeeld geanalyseerd te worden met een derde programma. Deze programma’s kunnen bovendien afkomstig zijn van verschillende fabrikanten. Hierdoor kunnen fabrikanten zich ook toespitsen op ´e´en kant van het ontwerp zonder dat er compatibiliteitsproblemen ontstaan. VHDL is ook interessant om complexe schakelingen op een hogere abstractieniveau te beschrijven. Zo kan men een schakeling die vaak terugkomt groeperen in een bepaalde module. Repetitieve structuren dienen slechts ´e´enmaal beschreven te worden, maar kan men eindeloos blijven gebruiken. VHDL maakt het ook mogelijk om de gebruiker te laten ontwerpen los van de eigenlijke implementatie. Zo dient de gebruiker alleen te specificeren dat twee getallen opgeteld moeten worden. Het is dan aan het programma om de componenten te selecteren die dat op de beste manier doen (qua kosten, snelheid,...). Tot slot zorgt VHDL er ook voor dat een ontwerp makkelijk te parametriseren valt. Indien de ontwerper niet zeker is van de woordlengte van zijn processor kan hij deze in een parameter onderbrengen. Als later blijkt dat de woordlengte groter moet zijn, kan met een eenvoudige verandering van de parameterwaarde het volledige model aangepast worden, en dient men de componenten die de parameter gebruiken, niet opnieuw te ontwerpen.
1.5.3
Nadelen
Naast de reeks opgesomde voordelen heeft VHDL ook enkele belangrijke nadelen. Zo is het een eenvoudig te leren taal, maar de taal echt beheersen vraagt veel geduld. Dit komt door gedeeltelijk door de niet eenvoudige syntax. Een ander probleem is dat heel wat software afwijkt van de gestandaardiseerde versies. Er bestaan dan ook onnoemelijk veel VHDL “dialecten”: varianten op VHDL die ontwikkeld zijn door fabrikanten. De meeste van deze uitbreidingen werken slechts voor bepaalde softwarepakketten. Een ander nadeel is dat de taal nogal langdradig is. Bij complexe circuits zullen de groeperingen zeker hun effect hebben, maar om kleine schakelingen te realiseren is nogal veel code nodig. Dit is wat vergelijkbaar met Java. 11 PLD:
programmable Logic Device, zie Subsubsectie 2.4.2.
1.5. TAALGEBASEERD HARDWARE ONTWERP: VHDL
19
Een probleem met code in het algemeen is dat het erg onoverzichtelijk is. Een eenvoudig blokschema is nog altijd overzichtelijker omdat mensen nu eenmaal grafisch sterker zijn. Pas bij grote complexe schakelingen verliest het visuele zijn kracht en zal een stuk code als doeltreffender worden aanzien. Het feit dat VHDL redelijk uitgebreid is, brengt bovendien allerhande nadelen met zich mee. Alle extra features voor bijvoorbeeld tijdsgedrag simulaties dienen immers in de taal beschreven te kunnen worden. Bijgevolg worden sommige taalconcepten hierdoor hopeloos moeilijker gemaakt dan strikt nodig.
1.5.4
Beperkingen
Naast de voor- en nadelen heeft VHDL ook enkele beperkingen. Zo is VHDL slechts tot op zeker niveau automatisch synthetiseerbaar. Hierbij ondersteunt elke fabrikant van VHDL een verschillende subset. Een tweede beperking is dat slechts de syntax en de semantiek van VHDL gestandaardiseerd is. Niet hoe de code geschreven moet worden. Dit houdt in dat eenzelfde gedrag op tientallen verschillende manieren beschreven kan worden. Dit zorgt er ook voor dat elk programma dat VHDL leest de code op een andere manier kan implementeren. Het gevolg is dat de codestijl, die in grote mate bepaalt hoe de code ge¨ımplementeerd zal worden, variabel is. In het ene programma kan een codefragment tot de meest optimale implementatie leiden, terwijl een ander programma met dezelfde code slechts een standaardimplementatie kiest. Men moet dus eerst heel wat ervaring opdoen met een programma alvorens men weet hoe men de code moet schrijven zodat deze een effici¨ente implementatie kiest.
1.5.5
Basisconcepten (entiteiten en architectuur)
Na de voor- en nadelen besproken te hebben, is het tijd om een voorbeeld waarmee we de verschillende concepten zullen duidelijk maken. We ontwerpen een schakeling zoals op Figuur 1.14. We zullen een schakeling genaamd “test” ontwerpen. Deze schakeling krijgt drie 8-bit ingangen (In1, In2 en In3). Als uitgangen zijn er twee bits (Out1 en Out2). Out1 geeft 1 terug indien In1 en In2 aan elkaar gelijk zijn. Analoog geeft Out2 1 terug indien In2 en In3 gelijk zijn. Om deze vergelijker12 te bouwen werken we bijgevolg met een hi¨erarchisch schema. Waarbij we Comp op een andere plaats implementeren. Comp A[0] B[0]
Test A[1] B[1]
Comp In1
In2
A B
EQ
Out1
A
A[2] B[2] A[3] B[3]
Comp A[4] B[4]
In3
A B
EQ
Out2
B A[5] B[5] A[6] B[6] A[7] B[7]
Figuur 1.14: Voorbeeldcircuit voor VHDL code. 12 We
bespreken een algemenere vergelijker in Subsectie 3.3.5.
EQ
20
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP
We zullen eerst Comp implementeren in VHDL. De code hiervoor staat in VHDL-code 1.1. Als we de code goed bekijken onderscheiden we twee belangrijke delen entity en architecture. Entity Het entity gedeelte beschrijft de zogenaamde “ blackbox” ofwel de interface. Hierdoor is VHDL in staat een blokje te tonen met de juiste in en uitgangen. Zoals we zien bevat de beschrijving het port commando. Het port commando specificeert dan de in- en uitgangen. Dit doet men door eerst de namen van de in- of uitgangen te vermelden. Daarna plaatst men het token in of out om te specificeren of het om een in- of uitgang gaat. Merk dus op dat elke geleider naar de component een expliciete richting heeft. Tot slot duidt men het type van de in- of uitgang aan. Logischerwijs bevat dit het token bit. Een bit betekent zoveel als ´e´en enkele lijn (ofwel verbinding). Meestal willen we verschillende lijnen samennemen, in dat geval duiden we dit aan met een bit vector, een bitvector is dus een lijst van geleiders naar het blok die ook onder ´e´en naam opereren. Het is handig verschillende geleiders samen te nemen, dit maakt de code overzichtelijker. Indien bijvoorbeeld de lengte van A gewijzigd moet worden kost dit slechts een minimale ingreep. Architecture De concrete werking wordt beschreven in het architecture gedeelte. Dit beschrijft het gedrag van de component op RTL-niveau. VHDL is in staat met de gegeven beschrijving in de architecture omgeving een implementatie op poortniveau te bouwen. Verder dient ook opgemerkt te worden dat ´e´en entity verschillende architectures kan hebben.13 . Deze architectures moeten met dezelfde interface als de overeenkomstige entity werken. VHDL-code 1.1 8-bit comparator. 1 2 3 4 5 6 7 8 9 10 11
−− 8− b i t comparator −− entity Comp i s port ( A, B : in b i t v e c t o r ( 0 to 7 ) ; EQ: out b i t ) ; end entity Comp ; architecture Behav1 of Comp i s begin EQ <= ’ 1 ’ when (A=B) e l s e ’ 0 ’ ; end architecture Behav1 ;
Component Nu we een comparator component gebouwd hebben, zullen we deze component importeren in ons testcircuit. Hiervoor gebruiken we code beschreven in VHDL-code 1.2. Dit bestand deelt dezelfde structuur als de structuur in VHDL-code 1.1: een entity en architecture. Dit wijst er dus op dat we componenten hi¨erarchisch kunnen gebruiken. We bemerken echter een nieuw token: component. component is een virtuele verwijzing naar een andere entiteit. Wat die entiteit is laten we in de code nog in het midden. Het enige wat we moeten doen is de interface van deze component specificeren. Later zullen we dan in de configuratie (VHDL-code 1.3) een binding voorzien tussen ons virtuele component comparator en onze gedefinieerde entiteit comp. Verder merken we ook op dat in het architecture gedeelte eenmaal we de component interface gedefinieerd hebben, we er instanties van kunnen aanmaken. Zo maken we twee instanties aan: Comp1 en Comp2. Vervolgens dienen we nog de verbindingen tussen de entiteit test en deze instanties te leggen. Dit doen we met het token map. 13 Vandaar
dat we onze architectuur de naam Behav1 geven.
1.5. TAALGEBASEERD HARDWARE ONTWERP: VHDL
21
Hierbij mappen we de variabelen uit entity Test (In1, In2, In3, Out1 en Out2) op de in- en uitgangen van het component Comparator (X, Y en Z). Hierbij dient dus opgemerkt te worden dat we het gedrag van Test specificeren aan de hand van reeds gedefinieerde entiteiten. Tot slot dient ook opgemerkt te worden dat in tegenstelling tot klassieke programmeertalen alle componenten tegelijk werken. Het is dus niet zo dat bij het uitrekenen van Test eerst Comp1 en dan Comp2 uitgerekend zal worden. VHDL-code 1.2 Voorbeeldcode. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
−− Component Test met 2 comparatoren −− entity Test i s port ( In1 , In2 , I n 3 : in b i t v e c t o r ( 0 to 7 ) ; Out1 , Out2 : out b i t ) ; end entity Test ; architecture S t r u c t 1 of Test i s component Comparator i s port ( X,Y: in b i t v e c t o r ( 0 to 7 ) ; Z : out b i t ) ; end component Comparator ; begin Comp1 : component Comparator port map ( In1 , In2 , Out1 ) ; Comp2 : component Comparator port map ( In2 , In3 , Out2 ) ; end architecture S t r u c t 1 ;
Configuration We moeten nog de component Comparator met de entiteit Comp binden. Dit doen we in een configuration omgeving. Deze configuratie wordt beschreven in VHDL-code 1.3. Zoals we zien kunnen we opnieuw verschillende configurations aanmaken en deze een aparte naam geven. Op die manier kunnen we dus de feitelijke implementatie snel wijzigen. Verder dienen we ook te vermelden welke entiteit we zullen configureren (Test) en om welke architectuur het gaat (Struct1). Vervolgens kunnen we per instantie aangeven welke entiteit we gebruiken. Dit doen we door het token use entity. Ook specifi¨eren we de architecture die we zullen gebruiken van deze entity. Vervolgens mappen we opnieuw met behulp van map de in- en uitgangen van de entiteit op het virtuele component. VHDL-code 1.3 Configuratie van de voorbeeldcode. 1 2 3 4 5 6 7 8 9 10 11 12 13
−− C o n f i g u r a t i e : d e f i n i e e r k o p p e l i n g component met een −− b e p a a l d e a r c h i t e c t u u r van een e n t i t e i t −− configuration B u i l d 1 of Test i s for Struct1 f o r Comp1 : Comparator use entity Comp( Behav1 ) port map (A => X, B => Y, EQ => Z ) ; end f o r ; f o r Comp2 : Comparator use entity Comp( Behav1 ) port map (A => X, B => Y, EQ => Z ) ; end f o r ; end f o r ; end configuration B u i l d 1 ;
22
HOOFDSTUK 1. DE BASIS VAN EEN DIGITAAL ONTWERP
1.5.6
Gelijkenissen en verschillen met klassieke programmeertalen
VHDL lijkt in sommige opzichten een beetje op programmeren in klassieke programmeertalen zoals Java en C++. Immers kunnen we de ingangen als parameters bij een methode zien. De methode zelf fungeert ook als een interface die duidelijk maakt welke types er ingevoerd moeten worden, en welke uitvoer verwacht mag worden, zonder de feitelijke implementatie te tonen. We zouden bovendien elk component die we in een circuit gebruiken kunnen zien als een functie-oproep naar de functie van het bijbehorende component. Deze vergelijking heeft echter enkele anomalie¨en. • Gelijktijdigheid (“ Concurrency”): Alle hardwarecomponenten werken in parallel dit in tegenstelling tot klassieke talen waarin alles sequentieel wordt uitgevoerd. • Tijdsconcept: Alle hardware werkt continu en houdt nooit op met werken. Bovendien zal bij een simulatie de tijd uiteraard niet de re¨ele tijd zijn. • Datatypes: VHDL heeft nood aan typische hardware-types zoals bitvectoren, getallen met geparametriseerde grootte,... Dit terwijl klassieke talen meestal proberen abstractie te maken van dit hardwareniveau.
Hoofdstuk 2
Technologische Randvoorwaarden enige limiet aan de realisatie van de toekomst is ons twijfelen “ De van vandaag. - Franklin D. Roosevelt, Amerikaans staatsman en president (26e) (1882-1945)
”
Tot nu toe hebben we altijd abstractie gemaakt van de werkelijkheid. We hebben in Hoofdstuk 1 poorten ge¨ıntroduceerd, maar hebben altijd abstractie gemaakt van de concrete werking van deze poorten. Aan de hand van het lichtmodel konden we ´e´en en ander verklaren, maar deze schakelaars moesten manueel geschakeld worden. In dit hoofdstuk zullen we een manier zien hoe we poorten kunnen implementeren, en een 0 en 1 kunnen voorstellen die gebruik maakt van elektronica. Dit is uiteraard slechts ´e´en manier. Naast het implementeren van poorten stuiten we vaak op allerhande fysische problemen. Dit hoofdstuk geeft een overzicht van de verschillende aspecten die we in de gaten moeten houden bij het ontwerpen van een elektronische schakeling. Verder biedt het een overzicht van manieren om een digitale schakeling te realiseren. Tot slot bekijken we de ontwikkeling van digitale schakeling met een CAD tool. 2.1 2.2
Logische waarden voorstellen . . . . . . . . . Implementatie van poorten . . . . . . . . . . 2.2.1 Schakelaars . . . . . . . . . . . . . . . . . . . Werking van NMOS en PMOS . . . . . . . . 2.2.2 Basispoorten . . . . . . . . . . . . . . . . . . Implementatie in NMOS . . . . . . . . . . . . Implementatie in CMOS . . . . . . . . . . . . 2.2.3 Complexe poorten . . . . . . . . . . . . . . . AND-OR-Invert (AOI) . . . . . . . . . . . . . OR-AND-Invert (OAI) . . . . . . . . . . . . . Andere veelgebruikte poorten . . . . . . . . . 2.3 Negatieve logica . . . . . . . . . . . . . . . . .
23
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
24 25 25 25 26 26 28 29 29 30 30 32
24
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN 2.4
Technologie¨ en . . . . . . . . . . . . . . . . . . . . 2.4.1 Specifieke chips . . . . . . . . . . . . . . . . . . Maatwerk . . . . . . . . . . . . . . . . . . . . . Standaard cellen . . . . . . . . . . . . . . . . . Gate-array . . . . . . . . . . . . . . . . . . . . 2.4.2 Programmeerbare chips . . . . . . . . . . . . . Programmable Logic Array (PLA) . . . . . . . Programmable Logic Device (PLD) . . . . . . . Complex Programmable Logic Device (CPLD) Field Programmable Gate Array (FPGA) . . . 2.5 Praktische aspecten . . . . . . . . . . . . . . . . 2.5.1 Spanningsniveaus en ruismarge . . . . . . . . . Ruismarge . . . . . . . . . . . . . . . . . . . . . Onlogische Spanningen . . . . . . . . . . . . . . 2.5.2 Dynamisch gedrag . . . . . . . . . . . . . . . . 2.5.3 Vermogenverbruik . . . . . . . . . . . . . . . . 2.5.4 “0” en “1” doorgeven . . . . . . . . . . . . . . 2.5.5 Fan-in en fan-out . . . . . . . . . . . . . . . . . 2.5.6 Tri-state buffer . . . . . . . . . . . . . . . . . .
2.1
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
32 33 33 33 33 34 34 34 35 36 37 37 37 38 39 41 42 43 43
Logische waarden voorstellen
Alvorens we enige schakeling kunnen implementeren moeten we een conventie afspreken hoe we een 0 en 1 voorstellen. Deze logische waarden moeten we voorstellen door twee fysische waarden. Deze fysische waarden noemen we “ High” en “ Low”. In de elektronica kiezen we meestal als fysische grootheid de spanning. De referentie-spanningen noteren we dan respectievelijk als VH en VL . Omdat het moeilijk is om een constante spanning aan de uitgangen aan te leggen, kiezen we niet voor ´e´en spanning, maar defini¨eren we een bereik rond VH en VL . Immers is het systeem niet volledig deterministisch, en er kunnen bijgevolg kleine variaties in de spanningen optreden. Daarnaast hebben we ook nog allerhande omgevingsparameters zoals de temperatuur, waardoor deze spanning sowieso enigszins zal afwijken. Tussen het bereik van VH en VL defini¨eren we ook nog een zone waar het niet duidelijk is of er een 1 of 0 op staat. Dit laat ons toe om fouten te detecteren. Indien de spanning immers dicht bij het midden ligt, is de kans op een foute interpretatie groot. Met een detectiesysteem zouden we dan bijvoorbeeld kunnen vragen om de bit opnieuw uit te sturen. We defini¨eren het bereik van VH als [VIH , VDD ], dat van VL als [VSS , VIL ]. Figuur 2.1 toont schematisch het bereik van deze waarden. Overigens hebben VDD en VSS nog een andere betekenis bij een circuit: het zijn de spanningen die op de voeding van het elektronische apparaat geplaatst worden. Hierbij staat de S voor “ Source” en D voor “ Drain”. VDD
Fysisch
Positieve Logica
Negatieve Logica
High
1
0
Ongedefinieerd
-
-
Low
0
1
VIH
VIL
VSS
Figuur 2.1: Schematisch bereik van “High” en “Low” spanning.
2.2. IMPLEMENTATIE VAN POORTEN
25
Negatieve logica Het is niet per definitie zo dat VH geassocieerd wordt met 1, en VL met 0. Dit hangt af van het type logica dat gehanteerd wordt. We onderscheiden twee soorten logica: positieve logica en negatieve logica. In geval van positieve logica is dit inderdaad het geval. Soms komt het echter voordeliger uit om deze orde om te draaien, in dat geval spreekt men van negatieve logica. Merk op dat bij negatieve logica de poorten fysisch anders ge¨ımplementeerd moeten worden. Immers kent de fysische poort alleen maar spanningen, en geen 0 of 1. De belangrijkste reden om negatieve logica te gebruiken, is dan ook dat de implementatie van een logische functie goedkoper kan zijn in bijvoorbeeld negatieve logica. Bovendien kan men in een circuit op verschillende plaatsen een andere logica gebruiken. Een concreet voorbeeld is de reset-module in veel elektronicasystemen die men vaak in negatieve logica realiseert. We behandelen negatieve logica nog verderop in Sectie 2.3.
2.2
Implementatie van poorten
2.2.1
Schakelaars
In Hoofdstuk 1 maakten we gebruik van het lichtmodel om poorten te implementeren. Daarbij werd gebruik gemaakt van schakelaars. Ook in de echte implementatie van poorten maakt men gebruik van schakelaars. Deze schakelaars kunnen door een derde ingang automatisch open en dicht geschakeld worden, deze ingang wordt ook het “ stuursignaal” genoemd. Net als de schakelaars in het lichtmodel hebben deze schakelaars twee toestanden: open en gesloten. We kunnen dit interpreteren als een elektronische weerstand die respectievelijk een weerstand van ∞ Ω en 0 Ω heeft. Figuur 2.2(a) toont hoe dergelijke schakelaars genoteerd worden. Afhankelijk van hun toestand worden ze bovendien anders genoteerd1 . Zoals eerder gezegd dienen deze automatische schakelaars een stuursignaal te hebben. Op Figuur 2.2(b) en switchNotationControlledPmos staan de schakelaars met stuursignaal. We merken op dat er twee varianten van schakelaars zijn. De ene variant, NMOS, is gesloten wanneer het stuursignaal een hoog fysische waarde heeft, en open bij een lage waarde. De tweede soort, PMOS, inverteert dit principe en is gesloten bij een laag fysische waarde, en open bij een hoge waarde.
L Open
H
L
H
Gesloten
(a) Schakelaars
(b) NMOS Schakelaars met stuursignaal
(c) PMOS Schakelaars met stuursignaal
Figuur 2.2: Notatie van een schakelaar (met stuursignaal).
Werking van NMOS en PMOS In de vorige subsectie werden twee types automatische schakelaars ge¨ıntroduceerd: NMOS en PMOS. Dit zijn transistoren die in bijna elk elektronisch apparaat gebruikt worden. In deze subsectie zullen we de terminologie van een transistor bespreken, en de werking van deze componenten verklaren. Zoals de meeste transistoren hebben een NMOS en PMOS drie aansluitingen: de Source, Gate en Drain, in het Nederlands worden deze aansluitingen ook respectievelijk Collector, Basis en Emitter genoemd. Een transistor is eigenlijk niets anders dan een schakelaar tussen de source en drain. De weerstand tussen de source en de drain wordt geregeld volgens de spanning die op de gate staat. 1 In
algemene schemas maken we abstractie van de toestand en is deze niet zichtbaar.
26
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN
Figuur 2.3 toont de concrete werking van NMOS en PMOS transistoren. Voor beide typen transistoren beschouwen we een substraat van siliciumdioxide (SiO2 ). We kunnen dit substraat zowel positief als negatief doperen2 . Bij NMOS doperen we het substraat hoofdzakelijk positief (p). Bij de ingangen van de source en de drain doperen we negatief (n). Er kan nauwelijks stroom vloeien tussen het negatief en positief gedopeerde substraat. Bijgevolg fungeert de p-laag als een barri`ere tussen de source en de drain. Indien we echter een positieve spanning aanbrengen op de gate, zullen de negatieve deeltjes in de p-laag zich aangetrokken voelen tot de gate. Er ontstaat een reorganisatie van de p-laag waardoor er een n-laagje gevormd wordt ter hoogte van de gate. Hierdoor ontstaat er een kanaal tussen de source en de drain, waardoor de schakelaar zich sluit. De spanning die tussen de gate en de source moet staan om dit te bereiken wordt de threshold spanning VT genoemd. Indien de spanning tussen de gate en de source VGS dus kleiner is dan VT is de NMOS schakelaar open, anders is de schakelaar gesloten. Een PMOS transistor werkt op analoge manier, maar dan omgekeerd. Gate
Source
metaal isolator
n+
Gate
Drain n+
Source
Gate
metaal isolator
n+
Drain
Drain
n+
metaal isolator
p+
Gate
Source p+
Drain
metaal isolator
p+
Source p+
p
p
n
n
(a) NMOS bij VGS < VT .
(b) NMOS bij VGS ≥ VT .
(c) PMOS bij VGD < VT .
(d) PMOS bij VGD ≥ VT .
Figuur 2.3: Werking van NMOS en PMOS.
2.2.2
Basispoorten
Met de eerder beschreven NMOS en PMOS transistoren kunnen we de basispoorten implementeren. Eerst zullen we de basispoorten met behulp van NMOS implementeren. Het zal blijken dat deze implementaties enkele nadelen hebben. Hierdoor zullen we opteren voor implementatie met CMOS. CMOS is in feite een combinatie van NMOS en PMOS. We zullen alle schakelingen implementeren in positieve logica. In Sectie 2.3 bespreken we kort poorten in negatieve logica. Implementatie in NMOS NOT Figuur 2.4 toont de implementatie van een NOT-poort in NMOS. Als ingang beschouwen we x, als uitgang f de VDD en VSS zijn lijnen voor de voeding van de poort. Indien we een laag voltage aanbrengen op x is de NMOS transistor open. Hierdoor staat er een hoge spanning op f . Indien we een hoge spanning op x aanbrengen, zal de transistor zich sluiten. Hierdoor vloeit er stroom tussen VDD en VSS . Omdat de stroom door f nog andere componenten zal aansturen, zal de stroom bijgevolg verkiezen om door de transistor te stromen, en krijgt f dus een laag potentiaal. Het principe van het verlagen van de spanning door stroom door te laten wordt Pull-Down Network (PDN) genoemd. In werkelijkheid zal een poort in NMOS niet de volledige hoogspanning of laagspanning op de uitgang aanleggen: wanneer de NMOS transistor gesloten is, zal er nog steeds een kleine weerstand over staan. Deze weerstand noteren we als Ron . Dit betekent dat f niet volledig gelijk zal zijn aan L. We berekenen de spanning op f dan ook met volgende formule: Vout (x = 1) =
Ron VDD R + Ron
(2.1)
Een tweede groot nadeel is dat we bij x = H statisch vermogen verbruiken: P (x = 1) = 2 Het
introduceren van alternatieve atomen.
2 VDD R + Ron
(2.2)
2.2. IMPLEMENTATIE VAN POORTEN
27
Dit is op gebied van energie duur, vooral omdat er in een gemiddelde processor makkelijk miljoenen transistoren zitten. Bovendien zal dit hoge temperaturen genereren. Dit is dan ook de hoofdreden waarom er nauwelijks elektronica ge¨ımplementeerd wordt met NMOS. VDD (H)
VDD (H)
R
R f =H
x=L
f =L x=H
VSS (L)
VSS (L)
(a) x=L, f=H
(b) x=H, f=L
Figuur 2.4: NOT poort ge¨ımplementeerd in NMOS.
“Open-drain poort” Indien we de weerstand als een extern component beschouwen, en meerdere NMOS transistoren in parallel aan de draad hangen, kunnen we het gedrag van een AND poort nabootsen. Figuur 2.5 toont een dergelijke realisatie. Vanaf het moment dat ´e´en van de transistoren gesloten wordt, lekt de stroom door die transistor, en krijgt f dus een laag niveau. Alle ingangen moeten dus een lage spanning hebben, om een hoge spanning aan de uitgang te verkrijgen. We kunnen dit principe dus zien als een AND waarbij aan alle ingangen een inverter staat. Dit systeem wordt “ Open-Drain Poort” genoemd. En heeft het voordeel dat we een AND kunnen bouwen aan de hand van draden. Deze implementatie is goedkoop indien we een AND-poort willen maken met een zeer groot aantal ingangen. Standaard wordt dit soort implementatie dan ook gebruikt in de reset-functionaliteit van elektronica. Meestal wordt er immers een reset procedure aangeroepen indien ´e´en van de detectoren een fout registreert. In dat geval zal de detector een hoge spanning aan zijn ingang genereren. Dit resulteert een lage uitgang, bij een lage uitgang treed de reset-procedure dan in werking. VDD (H)
R
x f
y
Figuur 2.5: Open-Drain Poort in NMOS.
NAND en NOR De vorige paragraaf gaf reeds een opzet hoe we een NOR en NAND poort kunnen bouwen. We moeten er voor zorgen dat er stroom kan vloeien tussen VDD en VSS indien respectievelijk minstens ´e´en of alle transistoren gesloten worden. Figuur 2.6 toont de implementaties voor een NAND en NOR poort volgens dit concept. Een AND en OR poort kunnen we dan vervolgens synthetiseren door een inverter achter de poort te plaatsen. Deze implementaties maken ook meteen duidelijk waarom een NAND goedkoper is dan een AND3 . 3 Dit is geen rigoreus bewijs dat een NAND inderdaad goedkoper is dan een AND, vermits we enkel vanuit een concept werken, en er misschien andere manieren bestaan om een AND en NAND te realiseren.
28
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN VDD (H)
VDD (H)
R
R f
f
x y
x y
(a) NAND poort.
(b) NOR poort.
Figuur 2.6: NAND en NOR poort ge¨ımplementeerd met NMOS. Implementatie in CMOS Een belangrijk argument tegen het gebruik van NMOS is dat het veel vermogen nutteloos verbruikt: wanneer een transistor gesloten is lekt er onophoudelijk stroom van de bron naar de grond. CMOS biedt hiervoor een oplossing. CMOS is een techniek waarbij we zowel een NMOS als een PMOS transistor gebruiken. Analoog aan het “Pull-Down Network” fenomeen van de NMOS, spreken we dan over het “ Pull-Up Network (PUN)” fenomeen bij PMOS. NOT Indien we de uitgang f plaatsen tussen een NMOS en PMOS transistor, en beide transistoren aansturen met dezelfde ingang x zoals op Figuur 2.7, kunnen we een NOT poort implementeren. Op het moment dat we een hoge spanning aanleggen op de ingang sluit de NMOS transistor zich, en opent de PMOS transistor zich, hierdoor krijgt de uitgang dezelfde spanning als de ground. Indien we een lage spanning aan de ingang aanleggen is de configuratie van de transistoren omgekeerd, en wordt komt aan de uitgang een spanning VDD te liggen. VDD (H)
x=L
VDD (H)
f =H
x=H
f =L
Figuur 2.7: NOT poort ge¨ımplementeerd met CMOS.
NAND en NOR Ook NAND en NOR poorten hebben hun equivalent in CMOS. Figuur 2.8 toont hiervoor een implementatie. Wat opvalt is dat we redelijk eenvoudig het CMOS equivalent kunnen halen uit een NMOS implementatie. Immers is het onderste gedeelte van de NMOS-schakelaars volledig equivalent met de NMOS-implementatie. We plaatsen eenvoudigweg een PMOS circuit boven de uitgang. Dit circuit werkt met duale logica: indien de NMOS verbindingen parallel zijn, zullen we de PMOS transistoren in serie plaatsen, indien de NMOS transistoren in serie stonden, zetten we de PMOS transistoren in parallel. Verder kunnen we de weerstand ook weglaten. Deze weerstand stond er immers alleen om verschillende poorten aan eenzelfde voeding te kunnen hangen. Nu er echter geen stroom vloeit in om het even welke configuratie van de transistoren, is de weerstand dus nagenoeg nutteloos geworden, en brengt deze hoge kosten met zich mee. Uitgangen verbinden Bij NMOS kunnen we uitgangen met elkaar verbinden, zonder dat dit problemen met zich meebracht, sterker nog, we kunnen sommige poorten implementeren aan de hand van verbindingen. Een groot nadeel van CMOS is dat dit niet langer mogelijk is. Figuur 2.9 toont de reden hiervoor. Op het moment dat de ene ingang een hoog potentiaal heeft, en de andere een laag potentiaal ontstaat er immers
2.2. IMPLEMENTATIE VAN POORTEN
29
VDD (H)
VDD (H)
x x f
f
y y
(a) NAND
(b) NOR
Figuur 2.8: NAND en NOR poorten ge¨ımplementeerd met CMOS. een kortsluiting. De stroom is in staat om vanaf de VDD rechtstreeks de aarding te bereiken. Hoewel de transistoren een minimale weerstand hebben, volstaat deze meestal niet. Het gevolg zijn zeer hoge stromen die het elektronische circuit zouden kunnen beschadigen. VDD (H)
VDD (H)
Figuur 2.9: Kortsluiting bij wired poort implementaties met CMOS.
2.2.3
Complexe poorten
In Hoofdstuk 1 hadden we het reeds over de XOR-poort. Een poort die 1 teruggeeft als de twee ingangen niet gelijk zijn aan elkaar. Deze poort hadden we toen ge¨ımplementeerd met een ingewikkeld schema van basispoorten. Omdat we echter op transistor niveau werken, kunnen we verschillende complexe poorten toch relatief simpel implementeren. In de volgende subsecties zullen we eerst de AND-OR-Invert (AOI) en OR-AND-Invert (OAI) implementeren. Deze schakelingen worden relatief vaak gebruikt, om bijvoorbeeld XOR en XNOR poorten te implementeren. AND-OR-Invert (AOI) Een veelgebruikt component is een AND-OR-Inverter. Dit is een component die we op poort-niveau kunnen beschrijven als een tweelagige structuur waarbij de ingangen eerst door een reeks AND-poorten gaan. De uitgangen van de AND-poorten vormen op hun beurt de ingangen van een NOR-poort. Een concreet voorbeeld hiervan staat op Figuur 2.10(a). Indien we echter de schakeling zouden bouwen zoals we dit voorstellen op poortniveau4 , hebben we 18 transistoren nodig. Een effici¨entere manier is het implementeren van een nieuw component de AOI zoals op Figuur 2.10(b). Hierbij hebben we slechts 10 transistoren nodig. Bovendien hebben we de implementatie gereduceerd tot ´e´en laag. Hierdoor wordt de vertraging van de component ook teruggedrongen. 4 We
substitueren dus iedere poort door zijn equivalent in CMOS.
30
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN VDD (H)
VDD (H)
f
f
a
z
b b y
x
y
z a f
x x f a y
y
x
z
b
a b
z
x y z
(a) AOI op poortniveau.
a b
(b) AOI op CMOS-niveau.
x y z
(c) OAI op poortniveau.
a
b
(d) OAI op CMOS-niveau.
Figuur 2.10: AND-OR-Inverter (AOI) en OR-AND-Inverter (OAI) in CMOS. OR-AND-Invert (OAI) De tegenhanger van de AND-OR-Inverter is de OR-AND-Inverter. Figuur 2.10(c) toont een voorbeeld van dit type component. Naar analogie met de AOI bestaat deze component op poortniveau opnieuw uit twee lagen, ditmaal gaan de ingangen door een reeks OR poorten waarbij hun uitgangen dan weer de invoer van een NAND poort vormen. Opnieuw kunnen we door een implementatie in CMOS het aantal transistoren van 18 naar 10 reduceren. Andere veelgebruikte poorten Naast de NOT, NAND, NOR, AOI en OAI poorten, worden er nog enkele andere poorten frequent gebruikt. De implementatie van deze poorten wordt weergegeven in Figuur 2.11. In de volgende paragrafen wordt hun nut en werking kort toegelicht. Buffer Een buffer of driver is een speciaal type poort met ´e´en ingang waarbij de uitgang dezelfde waarde heeft als de ingang. Men zou dus een buffer kunnen vervangen door een geleider. Een buffer wordt echter frequent gebruikt indien een bepaalde draad verbonden moet worden met een groot aantal ingangen van poorten. Wanneer we dit aan de hand van een draad zouden doen, zou dit betekenen dat spanning op deze draad verlaagd wordt door lekstromen. Men kan dit oplossen aan de hand van een vertakking van de draad naar verschillende buffers die op hun beurt weer verschillende poorten aansturen. Een buffer dient dus om bij complexe circuits - een signaal over een groot aantal componenten te kunnen verspreiden, waar een eenvoudige vertakking zou falen. Figuur 2.11(a) toont de notatie en de implementatie van een buffer. We implementeren een buffer meestal aan de hand van twee opeenvolgende inverters. AND-poort We hebben een AND-poort reeds voldoende ge¨ıntroduceerd om te weten wat deze component doet. Als we naar Figuur 2.11(b) kijken, zien we dat we deze poort implementeren door een NOT-poort aan
2.2. IMPLEMENTATIE VAN POORTEN
31
≡
≡
≡
VDD
VDD
VDD
y
VDD
y
x
VDD
VDD
x x x
f
f
f
y
x
(a) Buffer
y
(b) AND-poort
≡
≡ VDD
(c) OR-poort
VDD
VDD
y
VDD
y
f
VDD
VDD
f
x
x
(d) XOR-poort
(e) XNOR-poort
Figuur 2.11: Implementatie van populaire alternatieve poorten in CMOS. de uitgang van een NAND-poort te plaatsen. Dit verklaart ook meteen waarom we de voorkeur zullen geven aan inverterende poorten: een NAND werkt sneller5 en is bovendien twee transistoren goedkoper. OR-poort Analoog aan een AND-poort implementeren we een OR-poort ook met een inverter na een NOR-poort. Figuur 2.11(c) toont hierbij de implementatie. De conclusies de we trokken voor AND-poorten gelden uiteraard ook voor een OR-poort. XOR-poort De XOR-poort werd reeds ge¨ımplementeerd aan de hand van NOT, OR en AND poorten, en dit aan de hand van een complex netwerk. We kunnen deze schakeling echter ook realiseren met een AND-OR-Inverter6 . Dit houdt in dat we een XOR poort ook relatief goedkoop kunnen implementeren. Figuur 2.11(d) toont dat we deze schakeling kunnen realiseren met een OR-AND-Inverter en twee invertoren. In totaal hebben we dus 12 transistoren nodig. Indien we deze schakeling zouden implementeren zoals op Figuur 1.5(c) op pagina 7 zouden we 22 transistoren nodig hebben. 5 Omdat 6 Een
het signaal niet nog eens door de inverter moet propageren. AOI deelt dezelfde conceptuele structure als deze die we voorstelden bij de poorten.
32
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN
XNOR-poort Een laatste populaire poort is de XNOR-poort. Deze poort is niets anders dan de ge¨ınverteerde van de XOR-poort. Door eenvoudigweg de AND-OR inverter te vervangen door een OR-AND-Inverter kunnen we deze poort implementeren zoals op Figuur 2.11(e). De XNOR poort is dan ook de enige hierboven beschouwde poort die even goedkoop is als zijn inverse.
2.3
Negatieve logica
We hebben reeds kort negatieve logica behandeld in Sectie 2.1. Nu we de poorten op transistor-niveau ge¨ımplementeerd hebben, zijn we beter in staat om te vatten wat negatieve logica precies doet. Indien we de NAND-poort beschouwen zoals op Figuur 2.8(a), kunnen we rekenen met high en low. Tabel 2.0(a) (a) High en Low
x L L H H
y L H L H
f H H H L
(b) Positief
(c) Negatief
x 0 0 1 1
x 1 1 0 0
y 0 1 0 1
f 1 1 1 0
y 1 0 1 0
f 0 0 0 1
Tabel 2.1: Verschil tussen positieve en negatieve logica. toont de functie met high en low signalen. Indien we deze signalen interpreteren met positieve logica zoals in Tabel 2.0(b) bekomen we inderdaad zoals verwacht de NAND-poort. Indien we echter negatieve logica toepassen zoals in Tabel 2.0(c) bekomen we een NOR-poort. Bijgevolg kunnen we dus stellen dat positieve en negatieve logica elkaars duale vorm zijn (zie Subsectie 1.2.1).
2.4
Technologie¨ en
Niet elk toestel wordt volledig ontworpen en specifiek geproduceerd: net zoals bij software maken we vaak gebruik van modules waar we onze specifieke applicatie dan inpluggen. Deze sectie geeft een overzicht van de verschillende technologie¨en om een schakeling daadwerkelijk te realiseren. Voor goedkope toestellen in beperkte oplages zal men vaak geen nieuwe specifieke chips ontwikkelen. Meestal maakt men gebruik van reeds bestaande componenten, die men vervolgens op een printplaat combineert. Nog een alternatief zijn programmeerbare chips. Hierbij wordt de logica in de chip geprogrammeerd, bijvoorbeeld in een geheugen. Het gedrag van de chip hangt dan ondermeer af van de waardes in dat geheugen. Dit laat toe programmeerbare chips in grote oplages te produceren die dan vervolgens voor allerhande verschillende toepassingen gebruikt worden. Tot slot worden sommige chips ook volledig zelf geassembleerd. We overlopen eerst kort de drie vormen, waarna we ze in detail bespreken in de volgende subsecties. • Specifieke Chips (ASIC) (Subsectie 2.4.1): Hierbij maken we de chips volledig zelf. Deze techniek is echter duur, omdat er bijvoorbeeld een masker moet aangemaakt worden. Bijgevolg is deze techniek enkel winstgevend bij grote volumes. • Programmeerbare Chips (Subsectie 2.4.2): Dit zijn chips waarbij de logica geprogrammeerd kan worden. Meestal is dit echter volgens het “ Write Once Read Many (WORM)” principe. Deze chips kunnen een redelijke complexiteit aan en bevatten anno 2010 2 miljoen logische cellen. Meestal worden deze chips dan ook gebruikt voor prototypes en voor apparaten met kleine tot middelgrote oplages7 . • Standaard Chips: Hierbij worden simpele chips gekocht zoals poorten (SSI) en chips die eenvoudige functies vervullen (MSI/LSI). Het enige wat men nog moet doen is deze componenten met elkaar verbinden. De zogenaamde “ Glue Logic”. Met deze techniek kunnen we echter enkel circuits bouwen 7 minder
dan 100 000 stukken per jaar.
¨ 2.4. TECHNOLOGIEEN
33
met een beperkte complexiteit. Een typevoorbeeld van zo’n chips is bijvoorbeeld de 744 chip. Deze bevat 6 NOT poorten.
2.4.1
Specifieke chips
Bij specifieke chips ontwerpen we zelf het volledige ge¨ıntegreerde circuit. Deze techniek is dan ook zeer arbeidsintensief. Er bestaan drie verschillende technieken om specifieke chips te maken: maatwerk, standaard cellen en gate-arrays. Deze technieken worden in de volgende subsubsecties besproken. Maatwerk Bij maatwerk zullen we elke transistor en verbinding zelf ontwerpen. Deze componenten stellen we dan voor als een set rechthoeken, die we op de chipoppervlakte plaatsen. Deze techniek zal in het algemeen tot het meest optimale ontwerp leiden qua snelheid, vermogenverbruik en afmetingen. Toch is deze techniek niet haalbaar voor complexe systemen. Men past maatwerk wel vaak toegepast bij het ontwerpen van componenten voor een bibliotheek. In dat geval zal men bijvoorbeeld een opteller zo effici¨ent mogelijk implementeren, zodat complexere systemen die een opteller nodig hebben, een zeer effici¨ente implementatie kunnen gebruiken. Een ander nadeel van deze techniek is, dat de bouw van transistoren verder evolueert. Deze transistoren worden telkens kleiner, en om de 18 maanden is een volledige herimplementatie nodig. Deze manier van werken wordt ook wel “ Custom Design” genoemd. Standaard cellen Een effici¨entere manier van werken is met de zogenoemde “ standaard cellen”. Deze techniek is min of meer analoog met het maatwerk. Alleen gebruiken we hier componenten uit een bibliotheek als cellen, in plaats van transistoren. Elk van deze cellen heeft een vaste hoogte, en een variabele breedte. Bovendien wordt er in de hoogte ruimte voorzien voor bedrading. Elke logische cel heeft enkele ingangen aan de bovenkant, en enkele uitgangen aan de onderkant van de cel. Het komt er dus alleen nog op aan de cellen op een interessante manier te plaatsen, de zogenoemde “ placement”. En het leggen van bedrading, wat “ routing” genoemd wordt. Deze taken dienen met de nodige zorg te gebeuren. Componenten die veel met elkaar interageren worden beter dicht bij elkaar gezet, om de snelheid op te drijven, en bovendien is het aantal lagen voor bekabeling heel beperkt. Deze techniek laat echter wel toe om snel complexe bouwblokken te ontwerpen, en bovendien laat deze methode toe dat fabrikanten cellen kunnen optimaliseren. Figuur 2.12 toont hoe het ontwerp van deze standaard cellen er ongeveer uitziet.
Figuur 2.12: Ontwerp met standaard cellen.
Gate-array Een techniek die nog minder ontwerp-kosten met zich meebrengt is de Gate Array. Hierbij beschouwen we een tweedimensionaal rooster met identieke poorten8 , de zogenoemde “ Sea of Gates”. In dit rooster heeft elke poort identieke afmetingen, en wordt er ruimte gelaten voor bedrading. Opnieuw bevinden zich alle ingangen bovenaan en de uitgangen onderaan. Enkel de bedrading is vervolgens nog uniek aan het product. 8 Meestal
worden hiervoor NAND-poorten gebruikt. Bijvoorbeeld een 3-NAND-poort.
34
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN
Dit heeft niet alleen het voordeel van goedkoop ontwerp, de rooster kunnen in massa geproduceerd worden, om daarna elk tot een specifieke circuit uit te groeien. Enkel de metallisatielaag9 is dus uniek.
2.4.2
Programmeerbare chips
Prototypes waar nog fouten uitgehaald moeten worden, of elektronica in bijvoorbeeld computers waar de firmware kan veranderen, worden meestal ge¨ımplementeerd met programmeerbare chips. Maar ook onder de programmeerbare chips bestaan nog verschillende technologie¨en. Vooral de programmeertechnieken zijn zeer divers. Hieronder worden de meest courante technieken opgesomd. Vervolgens worden deze technieken verder toegelicht in de subsubsecties. • Zekeringen: Hierbij bevat de chip een groot aantal zekeringen. We kunnen dan vervolgens een deel van deze zekeringen doorbranden, om de logica te implementeren. Deze techniek is irreversibel: een doorgebrande zekeringen kan niet hersteld worden. Weliswaar blijft bijprogrammeren10 wel mogelijk. • Flash-programmeerbaar: Hierbij kunnen we verbindingen openen en sluiten met transistoren waarbij de gate opgeladen kan worden. Hierdoor wordt herprogrammeren mogelijk, dit is echter traag, en bovendien zal na enige tijd het flash geheugen niet meer herprogrammeerbaar zijn. • Geheugen-programmeerbaar: Hierbij bevat de chip een geheugen component, meestal in SRAM. De transistoren die de verbindingen bepalen worden dan gekoppeld aan dit geheugen. Het voordeel hierbij is dat we makkelijk en snel de chip kunnen programmeren, en dit kan zelfs dynamisch11 . Het nadeel is dat dit geheugen telkens bij het aanleggen van voedingsspanning weer opnieuw ingeladen moet worden. Het typevoorbeeld van deze techniek is een Field Programmable Gate Array (FPGA). Programmable Logic Array (PLA) In Sectie 1.3 zagen we reeds dat we alle logische functies kunnen maken met een Sum-of-Products (SOP). Een Programmable Logic Array (PLA) is gebaseerd op dit idee. Deze chip bevat twee rasters van poorten: een AND-matrix en een OR-matrix. Als ingangen kunnen we vervolgens zowel een variable als zijn inverse aanleggen. Figuur 2.13 toont een schematische voorstelling van zo’n PLA. De punten tussen twee verbindingen stellen een zekering door. Door zekeringen door te branden kunnen we dus het model aanpassen. Punten waar een kruisje bij staat zijn in dit voorbeeld doorgebrand. Bij een doorgebrande zekering in de AND-matrix, komt er een 1 op de lijn, bij een doorgebrande zekering op de OR-matrix een 0. Er bestaan ook varianten op een PLA: • een Programmable Array Logic (PAL) heeft een vaste OR-matrix; en • een Programmable Read Only Memory (PROM) heeft een vaste AND-matrix. Hierbij fungeert deze matrix als een adresdecoder (zie Subsectie 3.3.2). Programmable Logic Device (PLD) Een PLA is niet in staat complexe functies te beschrijven zonder dat de AND- en OR-matrix zeer groot te maken. Omdat immers voor iedere verbinding ook nog lijnen moeten voorzien worden, zou de component al snel te groot worden. Een Programmable Logic Device (PLD) probeert hierop een antwoord te bieden. Hierbij wordt meer lagen logica gehanteerd. Figuur 2.14 toont het idee achter deze techniek. We beschouwen nog steeds een AND-matrix, alleen is een groot deel van de invoer eigenlijk de uitvoer van geprogrammeerde functies op de chip, er ontstaat dus een feedbackmechanism. Zo zijn x1 en x2 de enig invoerlijnen, de andere lijnen zijn het resultaat van de geprogrammeerde logica. Op de figuur bemerken we verder nog dat er componenten onder de uitgangen staan. Deze componenten komen later in de cursus aan bod. Het vierkant stelt een 1-bit geheugen voor (zie Sectie 4.2), meestal een D-flipflop. De trapezium een multiplexer (zie Subsectie 3.3.1). Dit component laat ons dus 9 De
laag waar de verbindingen gelegd worden. een tweede iteratie andere zekeringen doorbranden. 11 De chip kan tijdens uitvoering zijn gedrag aanpassen. 10 In
¨ 2.4. TECHNOLOGIEEN x0
x1
35 x2
x3
N3
N2
N1
N0
OR-matrix A7
A6
A5
A4
A3
A2
A1
A0
AND-matrix O0
O1
O2
O3
O4
O5
O6
O7
f0
f1
f2
f3
f4
f5
f6
f7
Figuur 2.13: Schematische voorstelling van een Programmable Logic Array (PLA). toe complexere schakelingen te maken, en tegelijk het aantal zekeringen onder controle te houden. Het zal meestal echter een grotere inspanning vragen om een logische functie te realiseren met een programmable logic device. Complex Programmable Logic Device (CPLD)
I/O
O
I/O
PLD
O PLD
Schakelmatrix
PLD O
PLD I/O
I/O
O
Figuur 2.15: Schematische voorstelling van een Complex Programmable Logic Device (CPLD). Een aantal PLD componenten samen op ´e´en chip samen met de zogenaamde Glue Logic om ze samen te laten werken, noemen we een Complex Programmable Logic Device (CPLD). Figuur 2.15 toont dat deze glue eigenlijk neerkomt op een schakelmatrix om PLDs te laten samenwerken en in- en uitvoer modules om te intrageren met de buitenwereld. Naast de PLDs zelf dient dus ook de schakelmatrix geprogrammeerd te
36
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN x2 N4
x1 N3
N2
N1
N0
D
D f3
f1
f2
Figuur 2.14: Schematische voorstelling van een Programmable Logic Device (PLD). worden. Een ander belangrijk verschil is dat CPLDs niet geprogrammeerd worden met behup van zekeringen. De chip wordt geprogrammeerd door ladingen op transistoren te plaatsen, bijgevolg kunnen de we deze chip enkele keren volledig herprogrammeren. Field Programmable Gate Array (FPGA) Een nog meer geavanceerde programmeerbare chip is de Field Programmable Gate Array (FPGA). Net zoals bij een CPLD bevat deze chip enkele logische blokken met daartussen “glue”. Deze “glue” uit zich opnieuw in een schakelmatrix, maar ook in korte en lange verbindingen. Deze laatsten worden vaak ook lange lijnen genoemd. Daarnaast bevat de chip uiteraard ook opnieuw en- en uitvoer modulen. Figuur 2.16(a) schematiseert dit concept. In tegenstelling tot een CPLD heeft een FPGA andere logische bouwblokken, namelijk Logical Blocks (LB). Dit logische blok staat weergegeven op Figuur 2.16(b). Het bestaat typisch uit 4 ingangen (x1 , x2 , x3 en x4 ) en twee uitgangen (y en yQ ). Inwendig bestaat het uit een 16 bit Look-Up Table (LUT) en een Data Flip-Flop (D-FF). Deze Look-Up Table is in feite niets anders dan een klein geheugen. Met de 4 ingangen zijn we in staat om 24 = 16 verschillende invoer-waarden te genereren. Voor elk van deze waarden programmeren we een bit als uitvoer. Deze wordt uitgevoerd langs de y. De Data Flip-Flop houdt deze bit een klokcyclus bij, en zal hem de volgende klokcyclus op yQ zetten. Het gevolg is dus dat yQ een klokflank na-ijlt op y. Tot slot beschouwen we op Figuur 2.16(c) de implementatie van een schakelmatrix. Hierbij verbinden we 4 lijnen met elkaar. Dit levert dus 6 mogelijke verbindingen. Door het programmeren van de chip, kunnen we de transistoren openen of sluiten, wat resulteert in het al dan niet verbinden van twee lijnen. De transistoren die men hierbij gebruikt zijn de zogenaamde “Pass-transistoren”. Spartan-3 Een beroemde FPGA-chip is de Spartan-3 van Xilinx. Deze FPGA maakt gebruik van Configurable Logic Blocks (CLB) in plaats van LBs. Een CLB wordt onderverdeeld in vier “ slices”. Twee van deze slices kunnen geconfigureerd worden als schuifregisters (zie Subsectie 3.3.6), geheugencellen, of logische
2.5. PRAKTISCHE ASPECTEN
37
I/O
I/O
I/O
I/O
I/O
SM
SMc
SM
SMc
SM
SMc
LB
SMc
LB
SMc
SM
SMc
SM
SMc
SM
SMc
LB
SMc
LB
SMc
(a) Volledige FPGA
x1 x2 x3 x4
16 × 1 LUT: logische functie van 4 variabelen
y D-FF
(b) Logical Block (LB)
yQ
(c) Schakelmatrix
Figuur 2.16: Schematische voorstelling van een Field Programmable Gate Array (FPGA). blokken, de overige twee alleen als logische blokken. Deze complexere slices bevatten twee verschillende componenten voor logica: twee functies met 4 variabelen, en ´e´en functie met 5 variabelen, meestal aangevuld met flipflops. Verder bevatten deze vaak een multiplexer en een schuifregister. De specificaties van deze slices zijn verder ook terug te vinden in [?, p. 22-23]. Op Figuur 2.16(a) zien we dat naast logische en in- en uitvoer blokken ook nog andere componenten op een FPGA zitten. Meestal gaat het dan om RAM-geheugen en een multiplexer. Bovendien bevat de chip ook enkele klokken die het systeem aansturen. Deze zijn als een zwart blokje weergegeven. Typische frequenties bevinden zich rond de 50 MHz. Modernere FPGA’s uiten zich in grotere geheugens, soms zelfs met een stack (LIFO, zie Subsectie 5.3.4), specifieke in- en uitvoer blokken zoals Ethernet, PCIe,... tot zelfs microprocessoren.
2.5
Praktische aspecten
In de vorige sectie werd beschreven hoe we chips kunnen bouwen. We hebben echter van enkele technische aspecten abstractie gemaakt die een invloed hebben op de werking die niet altijd van het circuit kunnen afgelezen worden. Bijvoorbeeld de geometrie van de chip. De volgende subsecties beschrijven met welke praktische aspecten rekening gehouden moeten worden bij het ontwerpen van een chipoppervlakte.
2.5.1
Spanningsniveaus en ruismarge
Ruismarge In Sectie 2.1 hebben we reeds kort beschreven dat we een bereik specificeren voor een High en Low signaal. We definieerden ook een ongedefinieerde zone. Deze zone omvat signalen waar het onduidelijk is welk waarde
38
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN
er precies aan de ingang staat. We willen natuurlijk vermijden dat een signaal ooit in deze ruismarge terecht komt. Daarom introduceren we een ruismargeEen marge die we inbouwen tussen de minimaal acceptabele spanning aan de invoer, en de spanning vanaf wanneer we over de ongedefinieerde zone spreken. Dit doen we om te voorkomen dat het signaal ooit in de ongedefinieerde zone zou kunnen terugkomen.. Een ruismarge is een spanningsmarge die we beschikbaar stellen door een kleiner gebied van uitgangsspanningen te gebruiken dan toegelaten. We zullen dus de poorten spanningen laten genereren die zich in het hoogste gedeelte van High bevinden, of in het laagste gedeelte van Low. De ruis zal het signaal uiteraard kunnen afzwakken, maar we bijven in de acceptabele zone van High en Low. Het resultaat is dus dat bij de marges van de ingangen ruimer is dan de marges van de uitgangen. Figuur 2.17 geeft dit concept schematisch weer. Ook vermeldt de figuur de typische spanningsniveaus bij CMOS en TTL12 implementatie. Ingang TTL 5.0 V
Uitgang
CMOS 5.0 V
VDD
CMOS 5.0 V
TTL 5.0 V
4.4 V
2.4 V
3.5 V
2.0 V
1.5 V
0.8 V
0.5 V
0.4 V
0.0 V
0.0 V
High (H) High (H)
VOH ruismarge (NML )
2.0 V
3.5 V
0.8 V
1.5 V
VIH
ongedefinieerd
ongedefinieerd
VIL ruismarge (NML ) Low (L)
VOL Low (L)
0.0 V
VSS
0.0 V
Figuur 2.17: Werking van ruismarge bij CMOS en TTL.
Onlogische Spanningen Wanneer een transistor omschakelt, betekent dit niet dat van het ene moment op het andere er een andere spanning op de uitgang komt te staan, Deze overgang is een continue proces. Dit betekent dus dat op een zeker moment aan de uitgang de spanning in het ongedefinieerde gebied komt te liggen. Ideaal zou uiteraard zijn dat bij een continue verandering aan de ingang er toch een discrete verandering aan de uitgang plaatsvindt. Dit is echter fysisch onmogelijk. De ontwerper dient dus rekening te houden met dit overgangsverschijnsel. Dit fenomeen een groot probleem omdat op een dergelijk omschakelmoment beide transistoren13 halfopen zijn, en er dus stroom door de componenten vloeit. Verder weet men ook niet altijd welke spanning er aan de uitgang zal staan. De Transferfunctie is immers afhankelijk van zowel het productieproces als omgevingsfactoren zoals warmte,... Figuur 2.18(a) toont verschillende realistische transferfuncties samen met de ideale transferfunctie. VDD
Ideaal Realistisch
VDD
VIH
VIH
VIL
VIL
VSS
VIL VT VIH
VDD
(a) Transferfuncties bij een inverter
VSS
VIL
VIH
VDD
(b) Schmitt-Trigger transferfunctie
Figuur 2.18: Transferfuncties en Schmitt-Trigger ingangen. 12 TTL:
Transistor-Transistor Logic. en NMOS.
13 PMOS
2.5. PRAKTISCHE ASPECTEN
39
Schmitt-trigger ingangen Dit effect is vooral nadelig voor bijvoorbeeld in- en uitvoer: communicatie van onze chip met de buitenwereld. Deze signalen veranderen doorgaans traag, en zijn bovendien niet strikt stijgend of dalend. Dit heeft tot gevolg dat indien het ingangssignaal van een 0 naar een 1 moet gaan, het gemeten digitale signaal meestal verschillende malen van waarde zal veranderen. We kunnen dit probleem (gedeeltelijk) oplossen door gebruik te maken van de zoegenoemde Schmitt-trigger ingangen, dit zijn componenten met een hysteresis. Dit betekent dat de overgangsspanning bij een overgang van laag naar hoog, hoger is dan de overgangsspanning van hoog naar laag. Deze transferfunctie staat op Figuur 2.18(b), samen met het symbool voor een Schmitt-Trigger ingang: een NOT poort, met een miniatuur van de inverse transferfunctie.
2.5.2
Dynamisch gedrag Schakeling VDD V
ROH
Laag⇒Hoog C
RIH t V
Hoog⇒Laag ROL
C
RIL t
Figuur 2.19: Dynamisch gedrag bij twee sequenti¨ele NOT poorten. Op simulaties zullen we meestal uitgaan van dynamisch gedrag. Dit betekent dus dat we veronderstellen dat indien we bijvoorbeeld de spanning aan de ingang van een poort naar een andere spanning brengen, de uitgang na enige vertraging van de oude naar de nieuwe spanning omschakelt. Dit zullen we illustreren met een voorbeeld zoals op Figuur 2.19 waar we twee NOT-poorten na elkaar plaatsen. We kunnen het gedrag van dit circuit nabootsen bij overgangen, door een lijn als een capaciteit te zien, verder zien we een gesloten transistor als een weerstand, open transistoren zijn open lijnen en worden dus niet beschouwd. We zullen eerst uit de beschreven modellen de spanning in functie van de tijd plaatsen. Hoog naar laag Bij een overgang van hoog naar laag aan de ingang, zal de spanning op de kabel tussen de twee poorten stijgen. Zoals we op de grafiek zien, zal dit exponentieel gebeuren. We zullen eerst de doelspanning V∞ bepalen, en vervolgens de tijdsconstante τ . De doelspanning kunnen we eenvoudig afleiden uit de stroom, indien de condensator volledig opgeladen is, stroomt alle stroom uitsluitend door de twee weerstanden. Hierdoor kunnen we de stroomsterkte afleiden. De spanning over de condensator kunnen we dan berekenen, omdat deze gelijk is aan de spanning op de tweede weerstand RIH : I∞ =
VDD RIH · VDD ⇒ V∞ = RIH · I∞ = RIH + ROH RIH + ROH
(2.3)
We leiden vervolgens de tijdsconstante af door de het systeem als een RC-keten te modelleren. In dat geval moeten we de twee weerstanden als parallel beschouwen. De tijdsconstante is dan de vervangweerstand voor deze twee weerstanden, vermenigvuldigd met de capaciteit van de condensator: Rsubs. =
RIH · ROH RIH · ROH · C ⇒ τ = Rsubs. · C = RIH + ROH RIH + ROH
(2.4)
40
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN Voor het opladen van een condensator geldt volgende exponenti¨ele functie: V (t) = V∞ · 1 − e−t/τ
(2.5)
Laag naar hoog We het dynamische gedrag voor laag naar hoog volledig analoog berekenen. Omdat er geen bron meer op de schakeling staat, is de schakeling een zuivere RC-keten. De condensator zal dus ontladen, met als eindspanning V∞ = 0 V. We berekenen de tijdsconstante dan ook opnieuw met behulp van de vervangweerstand: RIL · ROL RIL · ROL · C Rsubs. = ⇒ τ = Rsubs. · C = (2.6) RIL + ROL RIL + ROL Bij een RC-keten geldt voor het ontladen van een condensator vervolgens deze exponenti¨ele functie: V (t) = V0 · e−t/τ
(2.7)
Tijdsconstante minimaliseren We zien dus dat we - bij overgangen van laag naar hoog en hoog naar laag - te maken hebben met exponentieel tijdsgedrag. Deze constante wordt bepaald door de capaciteit, en door de in- en uitgangsimpedanties. We proberen deze parameters zo aan te passen dat ze aan volgende vier doelen voldoen: τ% P stat. ?? % P dyn. ?? % V∞ ≈ VDD
τ = Rsubs. · C Pstat. = V 2 / (RI + RO ) = V 2 /Rtot. Pdyn. = V 2 /RO V∞ = RI · VDD / (RI + RO )
lage tijdsconstante minimaal statisch vermogenverbruik minimaal dynamisch vermogenverbruik uitgangsspanning dicht bij de voedingsspanning (2.8) Hiervoor streven we naar bepaalde waardes voor de verschillende parameters: • Ingangsimpedantie RI : we streven naar een zo hoog mogelijke ingangsimpedantie, immers stelt Vergelijking (2.3) dat indien RI RO , V∞ ≈ VDD . Bovendien is het statisch vermogenverbruik lager (zie Vergelijking (2.8)).
• Uitgangsimpedantie RO : We proberen de uitgangsimpedantie zo laag mogelijk te houden. Dit haalt de tijdsconstante naar beneden, waardoor de chip sneller schakelt (zie Vergelijking (2.4) en Vergelijking (2.6)). Een nadelig bijeffect is een hoger dynamisch vermogenverbruik (zie Vergelijking (2.8)). • Capaciteit C: De capaciteit probeert men zo laag mogelijk te houden. Immers verhoogt een hoge capaciteit rechtstreeks de vertraging (zie Vergelijking (2.8)). Hoge capaciteiten zijn kenmerkend voor lange verbindingen, vandaar dat men deze meestal op chips tot een minimum beperkt. Al deze effecten zorgen ervoor dat een CMOS-implementatie betere karakteristieken heeft dan een NMOSpoort: NMOS heeft een groter statisch vermogenverbruik. Om dit tegen te gaan, kunnen we een sterke weerstand R in de schakeling plaatsen. Dit leidt echter tot een grote uitgangsimpedantie vermits geldt dat R ≈ RO , wordt de stijgtijd van de schakeling bijgevolg groter, en dus ook de algemene vertraging van de chip. Stijg- en daaltijd We hebben het reeds uitvoerig gehad over het dynamisch karakter van een elektronische schakeling. Naast het feit dat het enige tijd duurt alvorens een spanning die op een draad wordt aangelegd daadwerkelijk dit spanningsniveau bereikt, heeft ook een poort een dynamisch karakter. Een interessante eigenschap is dat de stijg- en daaltijd invloed hebben op de vertraging van de poort. We formaliseren dit in drie grootheden: • Stijgtijd tr ofwel rise time: de tijd die de geleider nodig heeft om van een lage spanning naar een hoge spanning te stijgen. Men neemt hiervoor de 10% en 90% grenzen tussen de basisspanning en de topspanning14 . 14 In
sommige publicaties wordt 80% en 20% gebruikt.
2.5. PRAKTISCHE ASPECTEN Stijgtijd tr
41 Daaltijd tf
90%
VIH
50%
VT
10%
VIL
90%
VOH
50%
VT
10%
VOL tpHL
tpLH
Figuur 2.20: Het dynamisch gedrag van een NOT-poort. • Daaltijd tf ofwel fall time: de tijd die de geleider nodig heeft om van een hoge spanning naar een lage spanning te dalen. Men neemt hiervoor de 90% en 10% grenzen tussen de basisspanning en de topspanning. • Vertragingstijd tp ofwel propagation delay: De tijd die de poort nodig heeft tussen het moment dat de ingangspanning die het midden bereikt tussen de basisspanning en de topspanning, en het moment dat de uitgang deze 50% grens bereikt. Vermits de stijg- en daaltijd ook bepalen hoe snel een signaal naar 50% stijgt of daalt, hebben deze parameters ook invloed op de vertragingstijd. We berekenen de vertraging door het gemiddelde te nemen tussen de vertraging tijdens het dalen tpHL en het stijgen tpLH : tpHL + tpLH Vertragingstijd tp = (2.9) 2 Dit principe wordt ge¨ıllustreerd op Figuur 2.20. We zien hier twee situaties: in de eerste situatie is de stijgtijd van de ingang gelijk aan de daaltijd van de uitgang. De poort heeft weliswaar een vertraging, maar deze is vrij beperkt. In het tweede geval is de stijgtijd van de uitgang dubbel zolang als de daaltijd van de ingang. Hoewel de poort sneller reageert op het veranderende signaal, is de vertraging groter. Vermits de stijg- en daaltijden be¨ınvloed worden door de parasitaire capaciteit15 , wordt dus ook de vertraging be¨ınvloed door de aard van de draden. De vertraging bij korte draden is aanzienlijk kleiner dan deze van lange draden.
2.5.3
Vermogenverbruik
Een van de belangrijkste ontwerpbeperkingen bij grote schakelingen is het vermogenverbruik. Een hoog vermogenverbruik uit zich in twee verschillende nadelen: • Levering: De verbruikte energie heeft een kostprijs: het bedrag op de elektriciteitsfactuur van een gebruiker. Bovendien uit het vermogenverbruik zich ook in een kortere levensduur van eventuele batterijen. • Gedissipeerd: het geleverde vermogen wordt omgezet in een andere vorm van energie: warmte. Deze warmte moet afgevoerd worden, bijvoorbeeld via een koelingssysteem, wat ook weer vermogenverbruik met zich meebrengt. We beschouwen ook twee vormen van vermogenverbruik die we hierboven al enkele keren hebben aangeraakt: 15 De
capaciteit die wordt veroorzaakt door de draad zelf.
42
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN • Statisch vermogenverbruik: Dit is het vermogen die continu verbruikt wordt, ook indien de schakeling niets doet. We zagen reeds dat dit bij NMOS implementaties het geval is, omdat we bij het sluiten van een NMOS-transistor, een lekstroom genereren van de source naar de drain. Bij NMOS-poorten mogen we dan ook uitgaan van een vermogenverbruik van 1 mW. Dit betekent dus voor een gemiddelde chip dat dit makkelijk oploopt in tot 1 kW wat totaal onaanvaardbaar is. Bij CMOS hebben we eenvoudigweg geen lekstroom en dus ook geen statisch vermogenverbruik. • Dynamisch vermogenverbruik: Dit is het vermogen die verbruikt wordt op het moment dat een poort omschakelt. Hierdoor wordt de parasitaire capaciteit C op- of ontladen. In [?, 3.12] wordt hiervoor volgende formule gegeven: Pdyn. = C × f × V 2
(2.10)
Met chipoppervlakte C, een klokfrequentie f en voedingsspanning V . We kunnen deze formule als volgt verklaren: vermits het chipoppervlakte hoofdzakelijk draden bevat is dit een goede schatting voor de totale lengte van de draden en dus de parasitaire capaciteit. De klokfrequentie bepaalt hoeveel maal we per seconde deze draden moeten op- en ontladen. Het vermogen ten slotte om een capaciteit C op te laden is evenredig met het kwadraat van de spanning. In de praktijk werken de meeste schakelingen met een klokfrequentie in de grootorde van 100 MHz. We schakelen schakelen natuurlijk niet alle draden telkens om, maar een realistische schatting ligt bij de 20% van de draden per klokflank. Indien we ook de oppervlakte van een poort in rekening brengen komen we uit op een ordegrootte van 35 nW per inverter. We kunnen dus in de grootorde van 300 000 000 invertoren plaatsen voor een vermogenverbruik van 1 W. In de praktijk is vermogenverbruik dan ook een van de belangrijkste beperkingen om rekening mee te houden bij het ontwerpen van digitale schakelingen, vandaar dat er in deze cursus ook een grote nadruk ligt op het minimaliseren van digitale schakelingen.
2.5.4
“0” en “1” doorgeven
Een oplettend lezer zal zich misschien de vraag gesteld hebben waarom we een buffer zoals op Figuur 2.11(a) op pagina 31 niet implementeren door de NMOS en PMOS transistor om te wisselen. Dit zou ons immers twee transistoren besparen, en bovendien zou de poort effici¨enter werken, zoals op Figuur 2.21(b). Deze methode kunnen we echter niet consistent hanteren. Voor de verklaring moeten we terug naar een belangrijk detail bij de werking van transistoren in Subsectie ??. Een NMOS transistor geleidt immers alleen maar indien de spanning tussen de basis en de collector VGS , groter is dan de transferspanning VT . Indien de NMOS transistor dus gesloten is, zal de uitgangsspanning VT lager zijn dan de ingangsspanning. Dit geeft misschien bij ´e´en transistor geen noemenswaardige problemen, maar bij een opeenvolging van transistoren, zal de spanning uiteindelijk onder het grensniveau vallen. Samenvattend kunnen we zeggen dat NMOS transistoren hoge spanningen niet goed doorgeven, en dus een slechte pull-up zijn. Analoog voor PMOS geldt dezelfde redenering, maar dan toegepast op lage spanningen. Een PMOS transistor is dus een slechte pull-down. Deze spanningsverschillen zijn ook gevisualiseerd op Figuur 2.21(b). VDD
VDD
x
VDD
f
(a) Buffer met inverterende poorten
x
VT
f
(b) Fout buffer
Figuur 2.21: Buffer ge¨ımplementeerd met omgekeerde transistoren: NMOS is een slechte pull-up.
2.5. PRAKTISCHE ASPECTEN
2.5.5
43
Fan-in en fan-out
Enkele belangrijke eigenschappen van een poort zijn de fan-in en fan-out. De fan-in is het aantal ingangen die de poort in kwestie heeft. Deze eigenschap is eigen aan het type poort: een 3-nand poort heeft bijvoorbeeld een fan-in van 3. De fan-out is het aantal ingangen van andere poorten die de poort kan aansturen, het aantal draden die uit de poort in kwestie komen zeg maar. De fan-in en fan-out bepalen in grote mate de vertraging van een circuit. Indien we een groot aantal ingangen hebben, en een van deze ingangen schakelt om, kan dit betekenen dat er ineens stroom door de bijbehorende transistoren gaat stromen. De stroom diet dan ook door een sequenti¨ele keten van de transistoren van de andere ingangen te stromen. Als het aantal ingangen groot is, is deze keten lang, en bijgevolg duur het langer alvorens deze verandering merkbaar wordt aan de uitgang van de poort. Bij een groot aantal transistoren zullen we ook de spanning moeten opdrijven. Elke transistor heeft - indien gesloten - nog steeds een kleine weerstand. Indien de stroom door een serie transistoren moet vloeien, verliezen we bij elke transistor een deel van de spanning. Bijgevolg wordt de spanning aan de uitgang gereduceerd. Een hogere spanning aan de voeding leidt op zijn beurt weer tot hogere vermogens wat we juist willen vermijden. Het is bijgevolg wenselijk de fan-in zo laag mogelijk houden. Daarom komen in de realiteit poorten met een groot16 aantal ingangen nooit voor. Indien men een poort met een groot aantal ingangen wil realiseren zal men deze meestal met een opeenvolging van eenvoudigere poorten realiseren. Een hoge fan-out is ook een voorbode van problemen em moeten we onder controle houden. Elke poort heeft immers maar ´e´en uitgang. Door deze uitgang moet alle stroom naar de ingangen van andere poorten stromen. Vermits de stroom over een draad beperkt is, kunnen we spreken over een maximale stroomsterkte IOmax . Deze stroomsterkte bepaalt dan weer hoe snel we de parasitaire capaciteit kunnen op- en ontladen: ∂V (2.11) ∂t Vermits de snelheid waarmee deze capaciteit op- en ontlaadt op zijn beurt weer invloed heeft op de vertraging, heeft de fan-out ook invloed op de maximale frequentie fmax van de elektronische schakeling: IOmax = C ·
fmax =
1 ∂V I · = Omax ∆V ∂t C · ∆V
(2.12)
Bij het verhogen van de fan-out zal ook de parasitaire capaciteit zelf toenemen: een verbinding van de uitgang naar de ingangen, vormt ´e´en draad17 . Vermits de grootte van deze draad zal afhangen van de fan-out zal de parasitaire capaciteit hiermee schalen. We kunnen de fan-out beperken door gebruik te maken van buffers: we verdelen de uitgang van de poort onder een paar buffers die op hun beurt de ingangen van de andere poorten bevoorraden. We laten get signaal aan de uitgang van de poort zich dus getrapt verdelen over alle ingangen van poorten die het hoort aan te sturen. Het nadeel van het gebruik van een buffer is dat dit buffer ook moet omschakelen, wat extra vermogenverbruik en vertragingen teweeg brengt.
2.5.6
Tri-state buffer
Een uitbreiding van een buffer is een Tri-state buffer ofwel 3-state buffer. Figuur 2.22(a) toont het symbool die men voor deze component gebruikt: een buffer met een derde ingang aan de zijkant van de driehoek. Een tri-state buffer heeft drie mogelijke uitgangswaardes: 0, 1 en de zogenaamde zwevende modus Z. Deze laatste toestand wordt ook wel hoog impedant genoemd. Het betekent dat de lijn losgekoppeld is van enige bron. Er staat dus zogezegd niets op de lijn. Hiertoe wordt een buffer uitgebreid met een tweede ingang: Enable E. Het resultaat is dat de component in drie toestanden kan worden gebracht: wanneer enable op 0 staat, staat de tri-state buffer in de Z stand. In het geval er een 1 op de enable-ingang wordt aangelegd, laat het de ingang x door. De ingang kan zelf in twee standen staan: 0 en 1. Op Figuur 2.22(b) 16 Met
groot bedoelen we meer dan 5 ingangen. mogelijk met vertakking, maar dat is niet relevant.
17 Weliswaar
44
HOOFDSTUK 2. TECHNOLOGISCHE RANDVOORWAARDEN
wordt dit concept met behulp van een waarheidstabel weergegeven. Er bestaan verschillende manieren om deze component te implementeren. Een goedkope manier wordt voorgesteld op Figuur 2.22(c) en maakt gebruik van een transmission gate, een component die functioneert als een schakelaar.
input x
output f enable e (a) Symbool
e 0 0 1 1
x 0 1 0 1
f Z Z 0 1
e x
(b) Tabel
f
(c) Implementatie
s¯ s¯ f1 x
f
≡
x
f
s s
x1 e1 x2 e2
(d) Transmission Gate
f2 f3 (e) Bus
Figuur 2.22: Tri-state buffer. De transmission gate zelf bestaat zoals te zien op Figuur 2.22(d) uit twee transistoren. Indien s = 0 en s¯ = 1 zijn beide schakelaars open, en staat er dus geen signaal op uitgang f , in dat geval is de uitgang dus hoog impedant. In aalle overige gevallen is minstens ´e´en transistor gesloten, en wordt het signaal die aangelegd wordt op x verder gepropageerd. De schakeling op Figuur 2.22(c) bevat extra componenten om opniew voldoende spanning op te bouwen18 , dezelfde argumenten als met fan-in en fan-out gelden hier immers. Bus Tri-state buffers worden vaak gebruikt om bijvoorbeeld over ´e´en lijn gegevens van verschillende bronnen over te brengen. We hebben reeds in Subsubsectie 2.2.2 op pagina 28 gezien dat het verbinden van uitgangen van poorten tot een kortsluiting leidt, en we dit bijgevolg niet kunnen realiseren. We zouden hierdoor echter genoodzaakt zijn om voor elke uitgang een aparte draad te voorzien. Verbindingen kunnen een groot gedeelte van het chipoppervlak beslaan, vandaar dat we het aantal draden ook tot een minimum proberen te beperken. We kunnen dit probleem oplossen met een zogenaamde bus. Bij een bus wordt een draad gedeeld tussen verschillende bronnen xi . Elke bron stuurt ook een tri-state buffer aan waardoor dat - indien de bron op dat moment niets te zeggen heeft - de toestand hoog impedant is. Men dient er voor te zorgen dat er op elk moment hoogstens ´e´en tri-state buffer actief is. Omdat de andere tri-state buffers op dat moment hoog-impedant zijn, is er geen gevaar voor kortsluiting. Figuur 2.22(e) geeft een implementatie van dit principe. In Subsectie 3.3.1 zullen we een component tegenkomen die dit principe met een algemenere techniek realiseert: de multiplexer.
18 Bemerk
de buffer tussen x en de tranmission gate.
Deel II
Combinatorische en Sequenti¨ ele Schakelingen
45
Hoofdstuk 3
Combinatorische Schakelingen (Schakelingen zonder geheugen) al zou er niets nieuws geschapen worden, dan is er nog al“ Zelfs tijd een nieuwe combinatie. - Henry Ford, Amerikaans automobielfabrikant (1863-1947)
”
Nu we de basis van het bouwen van digitale circuits onder de knie hebben, en de fysische beperkingen hiervan kennen, kunnen we nuttige schakeling zoals optellers en vergelijkers ontwikkelen. Combinatorische Schakelingen zijn schakelingen waarbij een bitvector aan uitgangen uitsluitend bepaald wordt aan de hand van een bitvector aan ingangen. We kunnen dus stellen dat het circuit een functie f~(~x) berekent. In Sectie 1.3 werd reeds een manier voorgesteld om voor een gegeven functie tot een schakeling van canonieke vorm te komen. In Sectie 3.1 zullen we kennismaken met technieken zien om deze implementaties verder te minimaliseren. In Sectie 3.2 en Sectie 3.3 bespreken we de implementatie van enkele populaire combinatorische schakelingen. 3.1
Minimaliseren van logische functies . . . . . . . 3.1.1 Waarom minimaliseren . . . . . . . . . . . . . . . 3.1.2 Hoe minimaliseren? . . . . . . . . . . . . . . . . 3.1.3 Karnaugh-kaarten . . . . . . . . . . . . . . . . . Optimaliseren met behulp van Karnaugh-kaarten 3.1.4 Quine-McCluskey . . . . . . . . . . . . . . . . . . 3.1.5 Realisatie in meer dan 2 lagen . . . . . . . . . . 3.1.6 Welke methode kiezen? . . . . . . . . . . . . . . 3.2 Rekenkundige basisschakelingen . . . . . . . . . 3.2.1 Getallen voorstellen . . . . . . . . . . . . . . . . 3.2.2 Radix-conversie . . . . . . . . . . . . . . . . . . . r1 → r2 omzetting met r1 = r2p . . . . . . . . . .
47
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
49 49 50 50 51 56 57 57 58 59 60 60
48HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) r1 → r2 omzetting met r1q = r2 . . . . . . . . . . . . . . . . . . . . . . . . . . . r1 → r2 omzetting met r1q = r2p . . . . . . . . . . . . . . . . . . . . . . . . . . . Algemene omzetting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.3 Optellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Half adder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Full adder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ripple-carry opteller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Carry-lookahead opteller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CLA-generator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.4 Negatieve getallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ‘Sign-Magnitude’-voorstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . Excess formaat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Complement-voorstellingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Twee-complement voorstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . Betekenis van binaire getallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.5 Optellen en aftrekken van negatieve getallen . . . . . . . . . . . . . . . . . . . . Signed-magnitude voorstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-complement voorstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-complement voorstelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.6 Arithmetic-Logic Unit (ALU) . . . . . . . . . . . . . . . . . . . . . . . . . . . . Instructieset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Synthese van de ALE en CIG . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.7 Vermenigvuldigen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-complement vermenigvuldiger . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.8 Andere courante bewerkingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . Delen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modulo rekenen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.9 Vaste komma getallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Aantal bits voor fouteloze voorstelling . . . . . . . . . . . . . . . . . . . . . . . 3.2.10 Vlottende komma getallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Underflow en overflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IEEE-formaat voor vlottende komma getallen . . . . . . . . . . . . . . . . . . . Rekenen met vlottende komma . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.11 Andere voorstellingen van gegevens . . . . . . . . . . . . . . . . . . . . . . . . . Binary Coded Decimal (BCD) . . . . . . . . . . . . . . . . . . . . . . . . . . . American Standard Code for Information Interchange (ASCII) . . . . . . . . . 3.3 Andere basisschakelingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Multiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.2 Decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Alternatieve implementatie voor multiplexers . . . . . . . . . . . . . . . . . . . 3.3.3 Demultiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.4 Encoder en prioriteitsencoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prioriteitsencoders cascaderen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.5 Vergelijker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergelijkers cascaderen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Speciale gevallen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.6 Schuifoperator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementatie van schuifoperaties . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60 61 61 62 62 63 63 64 65 68 68 68 68 69 69 69 69 70 71 72 73 73 73 75 76 76 76 77 77 77 78 78 79 80 80 81 81 82 82 82 83 83 84 85 86 86 87 88 88 89
3.1. MINIMALISEREN VAN LOGISCHE FUNCTIES
3.1
49
Minimaliseren van logische functies
In deze sectie geven we eerst een motivatie waarom het minimaliseren van implementaties een belangrijke taak is. Daarna tonen we een methode om op effici¨ente wijze een minimale implementatie te realiseren. We zullen ook een aantal uitbreidingen op deze methode beschouwen.
3.1.1
Waarom minimaliseren
In deze sectie zullen we als leidend voorbeeld schakelingen ontwerpen voor de worteltrekking en 7-segment display in een minimale implementatie. Streven naar een minimalisatie is een algemeen probleem en is vergelijkbaar met optimalisatie in de informatica. Minimalisatie levert niet enkel snellere doorvoer op. Hieronder sommen we de meest courante voordelen op, samen met hun metriek: • Minimaliseren van de kostprijs. Afhankelijk van de realisatie hanteren we hiervoor twee metrieken: Voor CMOS verfijnen we hiervoor de oorspronkelijke formule van de kostprijs uit Vergelijking (1.6). En bekomen: kostprijs =
X
kostprijs (poort)
(3.1)
alle poorten
De kostprijs van een poort wordt dan bepaald met volgende formule: kostprijs (poort) =
fan-in fan-in + 1
if poort ∈ {INV, NAND, NOR, AOI, OAI} if poort ∈ {AND, OR}
(3.2)
We zien dus dat alle inverterende poorten relatief 1 goedkoper zijn dat de niet-inverterende poorten. Bij een FPGA bepalen we de kostprijs aan de hand van het aantal logische cellen: kostprijs = #LB’s
(3.3)
Uiteraard dient hierbij de kanttekening gemaakt te worden, dat niet voor elk gegeven aantal logische cellen, er een FPGA bestaat. Indien er voldoende logische cellen op de FPGA aanwezig zijn, is de kostprijs dan ook van minder belang. We zullen immers toch dezelfde FPGA gebruiken. • Snelheid: We maximaliseren de snelheid door de maximale vertraging te minimaliseren. Deze vertraging is afhankelijk van de poorten in het kritische pad. Het kritische pad is een pad van de ingang naar de uitgang met de grootste vertraging. Deze vertraging is afhankelijk van twee parameters: – Vertraging van de poorten: een poort heeft tijd nodig om bij verandering van de ingang ook de uitgang te veranderen. Deze vertraging is afhankelijk van de technologie en evenredig met de fan-in. We zullen deze benaderen met de volgende formule: vertraging (poort) =
0.6 + 0.4 · fan-in if poort ∈ {INV, NAND, NOR, AOI, OAI} 1.6 + 0.4 · fan-in if poort ∈ {AND, OR}
(3.4)
Deze formule toont dus dat opnieuw de fan-in een belangrijke factor is, en dat niet-inverterende poorten opnieuw een nadeel hebben tegenover inverterende poorten. – (capacitieve) belasting: dit hangt hoofdzakelijk af van de geometrische implementatie van de printplaat. Deze vertraging is dan ook zeer moeilijk te berekenen en wordt niet beschouwd. We berekenen dan de formule met volgende formule: vertraging =
X kritisch pad
vertraging (poort)
(3.5)
50HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
3.1.2
Hoe minimaliseren?
Om te minimaliseren hebben we een methode nodig. Deze methode manipuleert de logische uitdrukking van f~ (~x) tot een uitdrukking die equivalent maar voordeliger is, rekening houdend met de metrieken van Vergelijking (3.1) en Vergelijking (3.5). Een probleem is echter dat er geen methodes bestaan die ons een reeks manipulaties voorstellen, waardoor we altijd tot de meest optimale implementatie komen. We moeten dus bijgevolg methodes bedenken waarmee we in staat zijn een redelijk optimale oplossingen te bekomen. Hiervoor zullen we methodes gebruiken zoals Karnaugh-kaarten. Computers bieden bovendien de mogelijkheid een groot aantal implementaties te simuleren. Bij een groot probleem volstaat ook deze rekenkracht niet meer om tot de beste implementatie te komen1 .
3.1.3
Karnaugh-kaarten
Karnaugh-kaarten of K-kaarten proberen het aantal nutteloze ingangen tot een minimum te beperken. Het is een visueel hulpmiddel dat gebruik maakt van een vermogen waar mensen goed in zijn: het herkennen en begrijpen van patronen. De basis van een Karnaugh-kaart is dan ook de waarheidstabel. In een waarheidstabel kunnen we vaak door bepaalde rijen te beschouwen verbanden zien. N-kubus Karnaugh-kaarten zijn niets anders dan de projectie van waarheidstabellen naar een tweedimensionele figuur. Wanneer we een waarheidstabel met N variabelen beschouwen, kunnen we dit in N dimensies projecteren op een zogenoemde N -kubus. Een N -kubus construeren we door booleaanse punten te beschoun wen in N dimensies: {0, 1} ; en vervolgens bogen te trekken tussen elke twee punten waar er hoogstens ´e´en variabele verschilt. De buren van een knoop K is de verzameling knopen waarvoor er een boog bestaat van of naar K. Figuur 3.1 toont N -kubussen voor 1 tot 4 dimensies. 1100 1101 1000 1001
0
1
(a) 1D
00
01
100 101 000 001
0100 0101 0000 0001
10
11
110 111 010 011
0110 0111 0010 0011
(b) 2D
(c) 3D
1110 1111 1010 1011
(d) 4D
Figuur 3.1: N-kubus voor dimensies 1 tot 4. Elke knoop van de N -kubus beschrijft bitvector van waarden aan de ingang. We kunnen dan vervolgens op deze knooppunten de waarde die we aan de uitgang verwachten plaatsen. Buren zijn cruciaal, indien de uitgang niet verandert tussen twee buren, kunnen we zeggen dat de veranderde ingangsbit irrelevant is voor de uitgang. Karnaugh-Kaarten Zoals eerder gesteld zijn Karnaugh-kaarten zijn in feite niets anders dan 2D projecties van de hierboven beschreven N -kubus. De projectie van een N -kubus naar twee dimensies is eenvoudig voor N ≤ 2: het is gewoon de N -kubus zelf. Vanaf dimensies hoger dan 2 wordt het moeilijker. Figuur 3.2 toont de overgang van een 3-kubus naar de respectievelijke Karnaugh-kaart. Bij een N -kubus heeft elke toestand N buren. Nochtans zien we op de figuur dat de linkse en rechtse toestanden slechts 2 buren hebben in plaats van 3. We moeten dan ook op een Karnaugh-kaart modulo rekenen: de linkse buur van het meest linkse veld is het rechtse veld. Hetzelfde geldt in de andere richtingen. Elke cel in de Karnaugh-kaart beschrijft een bepaalde configuratie aan de ingangen. Aan de rand van de Karnaugh-kaart 1 Wat
is u ¨berhaupt de beste oplossing, in veel gevallen zal de ene metriek verbeteren ten koste gaan van de tweede.
3.1. MINIMALISEREN VAN LOGISCHE FUNCTIES
51 z
100 101 000 001
000
001
101
100
⇒
001
101
100
011
111
010
011
111
110
110
y
010
110 111 010 011
000
⇒ x
Figuur 3.2: Van N -kubus naar Karnaugh-kaart. noteren we de naam van deze ingangen, en duiden we met een lijn bij welke cellen deze ingang 1 is. Voor cellen die niet omvat worden door deze lijn, zal de bijbehorende ingang op dat moment 0 zijn. Zo komt de cel linksboven op de figuur overeen met de configuratie hx, y, zi = h0, 0, 0i: alle ingangen zijn 0. De cel rechtsonder komt dan weer overeen met de configuratie hx, y, zi = h1, 1, 0i: alleen ingang z legt in dat geval een 0 aan.
y
yz z xy
1 5 13 9
wx
0 4 12 8
z
(c) 3D
3 7 15 11
1 5 13 9
wx
17 21 29 25
19 23 31 27
18 22 30 26
16 20 28 24
z
(e) 5D gespiegeld
v y
y 3 7 15 11
1 5 13 9
16 20 28 24
18 22 30 26
19 23 31 27
z
17 21 29 25
x
w
2 6 14 10
2 6 14 10
v y
yz
z
(d) 4D
0 4 12 8
y
x
3 7 15 11
w
(b) 2D
y
0 1 2 3
2 6 14 10
x
y x
(a) 1D
x
x
0 1
x
1 3 7 5
0 4 12 8
w
y x
0 2 6 4
wx
z
yz
z
(f) 5D gekopieerd
Figuur 3.3: Karnaugh-kaarten voor verschillende dimensies met binaire waarden. Figuur 3.3 toont Karnaugh-kaarten voor een verschillend aantal variabelen. In de cellen staat de decimale waarde van de ingang die deze cel vertegenwoordigt. Daarvoor gebruiken we de variabelen in de volgende volgorde: hv, w, x, y, zi. We kunnen in principe blijven uitbreiden. Vanaf zes dimensies wordt het echter moeilijk om nog patronen te herkennen. Karnaugh-kaarten hebben bijgevolg maar een beperkt vermogen. Spiegelen of kopi¨ eren Vanaf vijf dimensies groepeert men meestal cellen in rasters van 4 × 4. Men gebruikt hierbij twee varianten: ofwel spiegelt men ´e´en van de twee tabellen zoals op Figuur 3.3(e), ofwel zijn de tabellen exacte kopies (op de waarde van ´e´en enkele variabelen na) zoals op Figuur 3.3(f). Het spiegelen van variabelen is intu¨ıtiever omdat dit consistent is met lagere dimensies. Optimaliseren met behulp van Karnaugh-kaarten Nu we weten wat een Karnaugh-kaart is, bespreken we een methode om een optimale implementatie uit deze Karnaugh-kaarten af te leiden. We introduceren eerst terminologie, daarna bespreken we het stappenplan van de methode in detail met een voorbeeld. Tot slot beschouwen we enkele uitbreidingen op dit stappenplan.
52HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) Terminologie Alvorens we aan het optimalisatiewerk kunnen beginnen, hebben we nood aan enige terminologie. Een implicant is een productterm zodat de functie die ontstaat uit deze productterm 1 is voor minstens ´e´en cel op de Karnaugh kaart, die zelf ook 1 is. De priemimplicant dient ook 0 te zijn voor de cellen op de Karnaugh-kaart die zelf ook 0 zijn. Voor alle overige cellen op de Karnaugh-kaart maakt het niet uit of de functie 0 of 1. Deze definitie heeft nauwe banden met de 1-minterm, het verschil is dat bij een implicant niet alle variabelen aanwezig moeten zijn. Zo zien we op Figuur 3.4(a) verschillende implicanten met een verschillend aantal variabelen. Bij 1-minterm - zoals we bespraken in Subsectie 1.3.1 - zijn altijd alle variabelen aanwezig in het product. Een priemimplicant is een implicant die geen onderdeel is van een andere implicant met strikt minder variabelen. De priemimplicanten van Figuur 3.4(a) worden weergegeven op Figuur 3.4(b). Zo zien we op de figuur dat de implicant x1 ·x2 ·x3 ·x04 geen priemimplicant is: de implicant x1 · x3 · x04 is immers altijd waar wanneer x1 · x2 · x3 · x04 waar is, en bestaat uit minder variabelen. Een verdere uitbreiding is de essenti¨ ele priemimplicant, dit is een priemimplicant die minstens ´e´en 1-minterm omvat die niet in een andere priemimplicant verweven zit. Visueel is dit een priemimplicant die minstens ´e´en cel omvat met 1; en er bestaat geen enkele priemimplicant die deze cel omvat. Tenslotte defini¨eren we nog de dekking of cover als een verzameling van implicanten zodat voor elke cel waar functie 1 is, deze cel door minstens ´e´en implicant in de verzameling wordt omvat. Daarnaast mag geen enkele implicant een cel omvatten waar de functie 0 is.
f
f
x3
1 0 1 1
0 1 0 0
x4
0 0 0 1
x4
(a) Implicanten
(b) Priemimplicanten
0 0 0 1
1 0 1 1
0 1 0 0
0 0 0 1
x2
0 0 0 1
x1
0 0 0 1
x3
x2
0 1 0 0
x1
1 0 1 1
x2
x1
0 0 0 1
f
x3
x4 (c) Essenti¨ ele priemimplicanten
Figuur 3.4: Terminologie van een Karnaugh-kaart.
Stappenplan We minimaliseren een functie met behulp van een Karnaugh-kaart in vier stappen, deze stappen zullen we in de volgende paragrafen bespreken: 1. Maak de Karnaugh-kaart. 2. Bepaal alle priemimplicanten. 3. Bepaal alle essenti¨ele priemimplicanten. 4. Zoek de minimale dekking. Daarna zullen we nog drie speciale gevallen bestuderen. We bestuderen deze methode aan de hand van een voorbeeld. We zullen een schakeling synthetiseren die de functies f en g berekent. Functie f geeft 1 terug bij de getallen 0, 1, 3, 5, 7, 8, 10, 11, 14 en 15, en 0 in de andere gevallen, g is waar als de afgeronde vierkantswortel van het getal even is. De waarheidstabellen van deze functies staan in Tabel 3.1.
3.1. MINIMALISEREN VAN LOGISCHE FUNCTIES
53
(a) f
(b) g
x1
x2
x3
x4
f
x1
x2
x3
x4
g
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 0 1 0 1 0 1 1 0 1 1 0 0 1 1
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1
Tabel 3.1: Waarheidstabellen voor de leidende voorbeelden. Stap 1: maak de Karnaugh-kaart In de eerste stap bouwen we een Karnaugh-kaart op die de logische functie visueel weergeeft. We tekenen een Karnaugh-kaart met het juiste aantal ingangsvariabelen (zie Figuur 3.3) en vullen vervolgens de uitgangswaarden voor ´e´en bepaalde uitgang in op de respectievelijke plaatsen. per uitgang dienen we een afzonderlijke kaart op te maken: in elke cel dienen we net ´e´en bit te plaatsen. f
g
x3
x4
1 1 0 0
1 1 0 0
0 1 1 0
1 0 1 0
0 1 1 0
x2
1 1 1 1
x1
0 0 1 1
x2
x1
1 0 0 1
x3
x4
Figuur 3.5: Ingevulde Karnaugh-kaarten voor de uitgangen van het leidend voorbeeld. Op Figuur 3.5 staan de Karnaugh-kaarten voor de functies f en g. De variabelen hx1 , x2 , x3 , x4 i vormen de binaire voorstelling van het invoergetal2 . Stap 2: bepaal alle priemimplicanten De volgende stap is het bepalen van alle priemimplicanten van de Karnaugh-kaart. Visueel is een implicant niets anders dan een rechthoek zodat zowel de lengte en de breedte een lengte hebben van - mogelijk verschillende - machten van twee3 . Deze rechthoeken vallen ook onder de modulo-regel op een Karnaugh-kaart: een rechthoek kan dus beginnen op de meest rechtse kolom, en doorlopen tot de meest linkse, zodat de kolommen in het midden worden overgeslagen. Een priemimplicant is een rechthoek zoals hierboven beschreven, maar waarbij een verdubbeling van de lengte of de breedte in welke richting dan ook - niet langer mogelijk is. We kunnen priemimplicanten opsporen door eerst een cel met waarde 1 te beschouwen, en dan telkens ofwel de lengte ofwel de breedte te verdubbelen tot dit niet 2 Volgens 3 Niet
de little-endian conventie. te verwarren met veelvouden van twee.
54HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) langer mogelijk is. Dit is dus het geval wanneer er nullen bij een dergelijke verdubbeling in de rechthoek dreigen te komen liggen. doen. Indien er verschillende uitbreidingen mogelijk zijn, dienen al de uitbreidingen gevolgd te worden. Figuur 3.6 toont de priemimplicanten voor de twee uitgangen van het leidend voorbeeld. f
g
x3 1 1 0 0
1 1 0 0
0 1 1 0
x4
1 0 1 0
0 1 1 0
x2
1 1 1 1
x1
0 0 1 1
x2
x1
1 0 0 1
x3
x4
Figuur 3.6: Karnaugh-kaarten met priemimplicanten van het leidend voorbeeld.
Stap 3: Bepaal alle essenti¨ ele priemimplicanten Nadat we de priemimplicanten bepaald hebben, zullen we uit deze verzameling de essenti¨ele priemimplicanten halen. Deze stap is eenvoudig: als een priemimplicant ´e´en of meer cellen omvat die door geen enkele andere priemimplicant omvat worden, is dit een essenti¨ele priemimplicant. Deze implicanten zullen sowieso al tot de resulterende functie behoren. Op Figuur 3.7 staan de essenti¨ele priemimplicanten voor f en g. We zien duidelijk dat in beide gevallen de priemimplicanten onvoldoende zijn om de volledige functie te beschrijven daar er nog enen niet niet gedekt worden: dit komt omdat voor al deze cellen, er minstens twee priemimplicanten de cel bedekten. f
g
x3
x4
1 1 0 0
1 1 0 0
0 1 1 0
1 0 1 0
0 1 1 0
x2
1 1 1 1
x1
0 0 1 1
x2
x1
1 0 0 1
x3
x4
Figuur 3.7: Karnaugh-kaarten met essenti¨ele priemimplicanten van het leidend voorbeeld.
Stap 4: Zoek de minimale dekking De essenti¨ele priemimplicanten zijn de goedkoopste manier om de cellen die ze dekken te implementeren, we zien echter dat dit in de meeste gevallen onvoldoende is om de volledige functie te beschrijven: er blijven cellen met waarde 1 ongedekt. We dienen nog extra priemimplicanten toe te voegen om tot volledige dekking te komen. In het ideale geval doen we dit door alle mogelijke toevoegingen van priemimplicanten na te gaan. Dit is echter een erg arbeidsintensief proces. Men lost dit probleem dan ook meestal op met een “ gulzige strategie” ofwel “ greedy algorithm”. We beschouwen initieel de verzameling van essenti¨ele priemimplicanten, iedere iteratie voegen we de priemimplicant toe die het meeste aantal cellen dekt die tot dan toe ongedekt bleven. We stoppen op het moment dat de set van implicanten de volledige functie dekt. We illustreren dit proces op Figuur 3.8 waarbij we elke iteratiestap tonen. Synthese Elk van de priemimplicanten die we geselecteerd hebben stelt het product voor van enkele variabelen. We implementeren de functie door de som te nemen van deze priemimplicanten. Voor het voorbeeld wordt dit dus: f = x02 x03 x04 + x01 x4 + x1 x3 (3.6) g = x01 x03 x04 + x01 x02 x3 x4 + x2 x3 x04 + x2 x03 x4 + x1 x2 x3
3.1. MINIMALISEREN VAN LOGISCHE FUNCTIES f
f
x3
1 0 1 0
g 0 1 1 0
g
x3 1 1 0 0
⇒
0 1 1 0
x4
1 0 1 0
0 1 1 0
x3 1 1 0 0
⇒
0 1 1 0
1 0 1 0
x4
0 1 1 0
x2
0 1 1 0
x4
x1
x4
1 1 0 0
1 1 0 0
x2
⇒
x3
1 1 1 1
x1
0 1 1 0
0 0 1 1
x2
1 0 1 0
1 0 0 1
g
x1
0 1 1 0
⇒
x4
x2
x1
1 1 0 0
1 1 0 0
x3
x2
x3
1 1 1 1
x1
g
0 0 1 1
x2
x1
1 0 0 1
55
x4
Figuur 3.8: Werking van het greedy algoritme bij het leidend voorbeeld. Uitbreiding: Dambordpatroon Een patroon dat men vaak tegenkomt in Karnaugh-kaarten is het dambordpatroon. Dit dambordpatroon hoeft niet noodzakelijk uit vierkanten te bestaan, rechthoeken zijn ook mogelijk. Indien we dit patroon met de klassieke Karnaugh-methode implementeren bekomen we een groot aantal priemimplicanten wat leidt tot dure implementaties, we kunnen in dat geval gebruik maken van XORoperaties die we achter elkaar schakelen. Een aaneenschakeling van XOR-operaties impliceert een grotere vertraging maar heeft een grote invloed op de kostprijs. Figuur 3.9 toont enkele dambordpatronen en hun implementatie met XOR-logica. f1
f2
x3
1 1 0 0
0 0 1 1
1 1 0 0
x3 0 0 1 1
0 0 1 1
1 1 0 0
x4 f2 = (x3 ⊕ x4 ) ⊕ x1
1 1 0 0
x2
x4 f1 = (x1 ⊕ x2 ) ⊕ (x3 ⊕ x4 )
0 0 1 1
x1
1 0 1 0
x2
0 1 0 1
x1
1 0 1 0
x2
x1
0 1 0 1
f3
x3
x4 f3 = x1 ⊕ x4
Figuur 3.9: Voorbeelden van dambordpatronen in Karnaugh-kaarten.
Uitbreiding: Don’t cares In sommige gevallen dienen we slechts een beperkte set van invoer-configuraties te beschouwen. Stel bijvoorbeeld dat we een seven segment digitale display4 implementeren die getallen van 0 tot en met 9 voorstelt. In dat geval hebben we vier ingangen nodig. Maar we zullen bijvoorbeeld nooit de configuratie 10112 = 1110 aan de ingang tegenkomen. Er is echter wel een plaats gereserveerd op de Karnaugh-kaart voor deze configuratie. In dat geval maken we gebruik van de zogenaamde don’t care. Dit wordt genoteerd met een horizontale streep5 , een “X” of “d” zijn alternatieve voorstellingswijzen, maar zullen we in deze cursus niet verder gebruiken. Een don’t care is geen speciale vorm van uitvoer: we kunnen enkel nullen of enen op de uitvoer plaatsen. Een don’t care wordt enkel gebruikt om aan te geven dat we vrij mogen kiezen of de uitvoer een 0 of 1 wordt, iets wat dus het geval is bij een configuratie aan de invoer die nooit zal voorkomen. We proberen dan natuurlijk een keuze te maken tussen 0 of 1 zodat de implementatie van de schakeling goedkoper wordt. We kunnen tot betere implementaties komen door een don’t care als een 1 te zien indien dit de priemimplicanten kan vergroten. Op die manier bereiken deze priemgetallen immers 4 Dit
is een verzameling leds die zo georganiseerd is dat we met zeven leds, alle cijfers van 0 to 9 kunnen weergeven. dash.
5 Engels:
56HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) een groter gebied waardoor ze minder variabelen bevatten. Op Figuur 3.10 geven we de Karnaugh-kaart van led A en B bij een seven-segment display, samen met de priemimplicanten die we bekomen na het toewijzen van de don’t cares. In Appendix C staan de Karnaugh-kaarten van de andere leds. Deze kaarten zijn een goede oefening om het volledige proces te leren beheersen. A
x3
B
x1
1 1 1 1 1 0 1 0 - - - 1 - - 1
x4
x2
x2
x1
1 1 1 0 0 1 1 1 - - - 1 - - 1
x3
x4
Figuur 3.10: Karnaugh-kaart met don’t cares van led A en B van een seven-segment display.
Uitbreiding: Meerdere uitgangen Tot dusver hebben we steeds aangenomen dat we de functie voor ´e´en uitgang optimaliseren, uit het voorbeeld van de seven-segment display blijkt echter dat een component verschillende uitgangen kan hebben. Een na¨ıve manier kan erin bestaan al deze uitgangen los van elkaar te zien, en dus voor elke uitgang het proces van de Karnaugh-kaart doorlopen. Het is echter mogelijk dat een (priem)implicant in een dekking voor ´e´en van de uitgangen, ook nuttig kan zijn voor een andere uitgang. Men kan eerst een synthese apart maken, en dan kijken of er gemeenschappelijke implicanten in de bekomen dekkingen zitten, maar dit is weinig waarschijnlijk. Het is immers mogelijk dat een minder goedkope dekking voor de uitgangen apart, wel tot de globaal goedkoopste oplossing leidt. Hieronder een procedure bespreken die gebruik maakt van de priemimplicanten, er is echter geen garantie dat deze tot de globaal goedkoopste schakeling komt. Met trial-and-error kunnen we dus soms tot nog goedkopere implementaties komen. De volgende procedure bekomt echter meestal een goed resultaat: 1. Realiseer eerst bij elke uitgang de essenti¨ele priemimplicanten; 2. selecteer vervolgens priemimplicanten die essenti¨ele priemimplicanten zijn bij een andere uitgang. Bij deze keuze is het ook belangrijk om de priemimplicant te selecteren die in het kleinste aantal functies voorkomt, dit doen we om de fan-out laag te houden waardoor we minder vertraging induceren. Merk op dat deze operatie ons niets kost: we hebben immers deze implicanten al gerealiseerd; en 3. de overige priemimplicaten realiseren we per uitvoer zoals op de klassieke manier. Indien een priemimplicant in verschillende uitgangen voorkomt, kunnen we deze eventueel bevoordelen. Duale vorm Tot dusver hebben we telkens met behulp van Karnaugh-kaarten een AND-OR implementatie gerealiseerd: analoog aan de eerder gerealiseerd sum-of-products (SOP). De conclusie dat bijna alle logische methodes en duale vorm hebben, geldt hier opniew: ook de Karnaugh-kaarten kunnen we gebruiken om een minimale OR-AND implementatie te realiseren. In tegenstelling tot de AND-OR vorm draait alles hier rond nullen en niet rond enen. De priemimplicaten zijn hierbij gerelateerd aan 0-maxtermen: functies die overal 1 teruggeven behalve voor een bepaalde rechthoek, opnieuw met machten van twee voor de lengte en de breedte. Verder werkt deze methode volledig analoog: we bepalen eerst de essenti¨ele priemimplicanten en voegen vervolgens andere priemimplicanten toe. We synthetiseren vervolgens de schakeling door een AND tussen alle gekozen priemimplicanten te plaatsen. Op Figuur 3.11 voeren we deze methode uit op de f -functie van het leidend voorbeeld.
3.1.4
Quine-McCluskey
Een alternatieve methode voor het synthetiseren van minimale logische functies is het Quine-McCluskey algoritme. Dit algoritme wordt gebruikt in CAD-pakketten voor booleaanse optimalisatie en werkt op basis
3.1. MINIMALISEREN VAN LOGISCHE FUNCTIES f
f
x3
1 1 0 0
x4
Ingevulde Karnaugh-kaart
Priemimplicanten
⇒
1 0 0 1
0 0 1 1
1 1 1 1
1 1 0 0
⇒
x4 Essenti¨ele Priemimplicanten
x3 1 0 0 1
0 0 1 1
1 1 1 1
1 1 0 0
x2
x4
1 1 1 1
x1
0 0 1 1
f
x3
x2
⇒
1 0 0 1
x1
1 1 0 0
x2
1 1 1 1
f
x3
x1
0 0 1 1
x2
x1
1 0 0 1
57
x4 Resultaat
f = (x1 + x03 + x4 ) (x02 + x3 + x4 ) (x01 + x3 + x04 )
Figuur 3.11: Duale methode met Karnaugh-kaarten. van tabellen. Het algoritme zoekt ook naar priemimplicanten en essenti¨ele priemimplicanten om een functie te optimaliseren en is dus het tabel-equivalent van de methode met de Karnaugh-kaarten. Het algoritme werkt in exponenti¨ele tijd: O (3n ) met n het aantal variabelen. In de meeste gevallen is het aantal variabelen te groot om een gegeven functie te optimaliseren, in dat geval wordt er gewerkt met de Espresso heuristic logic minimizer.
3.1.5
Realisatie in meer dan 2 lagen
Een Karnaugh-kaart laat toe tot een sterke implementatie te komen wanneer we met twee lagen werken: bijvoorbeeld een AND- en OR-laag. Zoals we echter in de volgende secties zullen zien, zullen complexe schakelingen bij twee lagen toch vrij duur uitpakken. Daarom is het soms aangewezen om de logica in meer lagen te implementeren. Dit veroorzaakt tragere schakelingen maar aan een goedkopere kostprijs. Hieronder geven we enkele technieken: • Specificatie: in heel wat gevallen gaat de specificatie van de component reeds gepaard met een expliciete implementatie. Bijvoorbeeld “1 indien x en ofwel y ofwel z en t” kunnen we dan rechtstreeks implementeren als: f = x ∧ (y ⊕ (z ∧ t)). • Factoranalyse: We kunnen een expressie ook algebra¨ısch manipuleren met de wetten uit Sectie 1.2. Factoranalyse wordt ook gebruikt wanneer we een schakeling dienen te implementeren met beperkte fan-in: stel dat we enkel NAND-poorten met twee ingangen ter beschikking hebben. Bij realisaties met beperkte fan-in moet men altijd proberen deze te implementeren in een boomstructuur. Indien we dus f = x + y + z + t moeten implementeren, converteren we dit naar f = (x + y) + (z + t), en niet naar f = x + (y + (z + t)). De boomstructuur laat toe schakelingen te realiseren die een vertraging van O (log n) hebben tegenover de lineare implementatie met een vertraging van O (n), dit met dezelfde kostprijs. • Functionele ontbinding: Soms zijn we ook in staat om een functie op te delen in verschillende deelfuncties. In Subsubsectie 3.2.3 zullen we bijvoorbeeld een volledige opteller beschouwen. In plaats van een optelling van drie bits rechtstreeks te implementeren kunnen we twee optellingen van twee bits realiseren. In het algemeen betekent dit dat we de functie f~ (~x) soms kunnen herschrijven als ~h (~g (~x) , ~x) waarbij ~g en ~h meestal eenvoudigere en dus goedkopere functies zijn. Geen enkele van deze methodes levert altijd een beter resultaat op. Het probleem moet dan ook opgelost worden in “ trial-and-error” stijl.
3.1.6
Welke methode kiezen?
Samen met de methodes uit Subsectie 1.3.2 hebben we nu volgende methodes om een schakeling te synthetiseren: • Canonieke Sum-of-Products
58HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) • Canonieke Product-of-Sums • Minimale Sum-of-Products (Karnaugh-kaarten) • Minimale Product-of-Sums (Karnaugh-kaarten) • Meerlagenlogica We kunnen ook vrij kiezen tussen AND-OR en NAND-NAND in het geval van Sum-of-Products, en voor OR-AND en NOR-NOR bij Product-of-Sums. Het is altijd voordeliger om respectievelijk voor NAND-NAND en NOR-NOR te kiezen: deze schakelingen zijn altijd goedkoper en sneller. Immers blijft bij een omzetten het aantal poorten en de structuur dezelfde, en uit Vergelijking (3.2)) en Vergelijking (3.4) blijkt duidelijk dat dit een betere keuze is. Men kan ook beslissen om de bekomen minimale AND-OR implementatie om te zetten naar een AND-OR-Invert en een OR-AND implementatie naar zijn OR-AND-Invert equivalent. Ook kunnen we in het algemeen bewijzen dat de implementatie met Karnaugh-kaarten altijd goedkoper en sneller is dan de implementatie van hun canonieke tegenhangers. Immers komt in het slechtste geval een implementatie met behulp van karnaugh-kaarten neer op dezelfde implementatie als de canonieke sumof-products. In de meeste gevallen zal meerlagenlogica verder een grotere vertraging induceren dan de implementatie met Karnaugh-kaarten, dit is echter niet algemeen en bovendien kan meerlagenlogica gepaard gaan met grote kostenbesparingen. Veel rekenkundige schakelingen die we in de volgende sectie zullen tegenkomen maken dan ook gebruik van meerdere functionele lagen. Het is niet altijd belangrijk om tot de meest optimale implementatie te komen. Indien we bijvoorbeeld de logica op een FPGA programmeren hebben we per functie een logic block ter beschikking. Het aantal poorten in een logisch blok staat al op voorhand vast. Indien we dus onder dat aantal blijven levert het ons niks op om de functie verder te minimaliseren. We hebben immers toch reeds voor deze poorten betaald. Deze realisatie van de schakeling naar de beschikbare elementen (poorten, logic blocks,...) wordt dan ook de “ technology mapping” genoemd. Om de verschillende implementaties te illustreren zullen we tot slot een schakeling implementeren in de verschillende vormen van logica. De Karnaugh-kaart en de implementaties voor de hierboven beschreven methodes staan op Figuur 3.12. Een samenvatting van deze implementaties in termen van kosten en vertraging staan in Tabel 3.2. Modus Canonieke SOP Canonieke POS Minimale SOP Minimale POS
Implementatie AND-OR NAND-NAND OR-AND NOR-NOR AND-OR NAND-NAND OR-AND NOR-NOR
Kosten 47 39 59 49 16 12 17 13
Relatief 100% 83% 126% 104% 34% 26% 36% 28%
Vertraging 8.6 6.6 9.4 7.4 6.6 4.6 6.2 4.2
Relatief 100% 77% 109% 86% 77% 53% 72% 49%
Tabel 3.2: Samenvatting van de verschillende implementaties.
3.2
Rekenkundige basisschakelingen
In deze sectie defini¨eren we enkele belangrijke schakelingen voor rekenkundige bewerkingen. We hebben het dan over optellen, aftrekken vermenigvuldigen, delen, modulo rekenen en logische berekeningen. Alvorens we echter met getallen kunnen rekenen, moeten we een manier bedenken om getallen voor te stellen met behulp
3.2. REKENKUNDIGE BASISSCHAKELINGEN x1 x2 x3 x4
x3
A
0 1 1 1
0 1 1 0
0 1 0 0
x1 x2 x3 x4
x2
x1
0 1 0 0
59
x4
A
(a) Karnaugh-kaart
A
(b) Canonieke SOP (AND-OR)
x1 x2 x3 x4
(c) Minimale SOP
x1 x2 x3 x4
A
A (e) Minimale POS
(d) Canonieke POS (OR-AND)
Figuur 3.12: Verschillende implementaties van dezelfde logische functie. van binaire signalen. Doorheen deze sectie zullen we de voorstelling van getallen regelmatig veranderen om extra functionaliteit toe te voegen.
3.2.1
Getallen voorstellen
Bij het voorstellen van getallen gebruiken de meeste mensen het Arabisch getalsysteem. Hierbij stellen we een getal voor door een reeks cijfers. Een cijfer op een bepaalde plaats heeft een gewicht dat r keer groter is, dan het volgende cijfer, met de radix r van het getalstelsel. Om tot een eenduidige voorstelling van elk getal te komen wordt de verzameling mogelijke cijfers beperkt tot r elementen: meestal zijn dat de cijfers 0 tot 9, en daarna volgen de letters a, b, ... Een getal Dr wordt dus voorgesteld als: Dr = dm−1 dm−2 . . . d0 , d−1 . . . d−n =
m−1 X
r i × di
(3.7)
i=−n
Hierbij zijn di de cijfers van het getal. Wereldwijd gebruikt men het decimale stelsel met radix r = 10. Andere populaire stelsel zijn het binair stelsel (r = 2), het octaal stelsel (r = 8) en het hexadecimaal stelsel (r = 16). Het binaire getalstelsel heeft logischerwijs twee mogelijke cijfers, bij conventie meestal 0 en 1. We kunnen deze cijfers voorstellen door 0 of 1 op een lijn te zetten. Indien we meer cijfers nodig hebben, kunnen we meerdere lijnen voorzien, die elk een cijfer van het getal voorstellen. In de informatica en elektronica zal men getallen vaak niet binair uitschrijven: men gebruik van andere getalstelsel. Dit komt omdat binaire getallen nogal langdradig zijn6 . Immers is het omzetten van binaire getallen naar hexadecimale getallen niets anders 6 Een
binair getal bestaat gemiddeld uit 3.3 keer het aantal cijfers van zijn decimale tegenhanger.
60HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) dan het groeperen van vier cijfers. Indien men getallen noteert met een andere radix dan de decimale, wordt de radix in decimale notatie als subscript toegevoegd. Zo zijn 2A16 en 1010102 het equivalent van 42.
3.2.2
Radix-conversie
Omdat de meeste mensen met decimale cijfers werken, zullen we regelmatig decimale cijfers moeten kunnen omzetten naar hun binair (en soms ook ander) equivalent. We spreken hier van een bronradix en een doelradix. We maken hier een onderscheid tussen vier gevallen: 1. De bronradix is een macht is van de doelradix; 2. de doelradix is een macht van de bronmatrix; 3. de bron en doelradix delen een macht met elkaar; en 4. een algemene methode voor omzettingen. Een algemene methode is natuurlijk nuttig, maar het is belangrijk ook de andere methodes te beschouwen, omdat deze vaak veel sneller uit te rekenen vallen. r1 → r2 omzetting met r1 = r2p Een speciaal geval van omzetting treedt op indien de bronradix een macht is van de doelradix. In dat geval kunnen we de omzetting doen aan de hand van alfabetomzetting. Immers betekent dit dat we elk broncijfer kunnen omzetten naar p doelcijfers. De sequentie van doelcijfers dienen wiskundig equivalent te zijn aan het broncijfer. Een concreet voorbeeld is het omzetten van een hexadecimaal getal in het binair stelsel (r1 = 16 = 24 = r24 ). (b) Octaal ↔ Binair
(a) Hex ↔ Binair
Hex
Bin
Hex
Bin
Hex
Bin
Hex
Bin
Oct
Bin
Oct
Bin
0 1 2 3
0000 0001 0010 0011
4 5 6 7
0100 0101 0110 0111
8 9 A B
1000 1001 1010 1011
C D E F
1100 1101 1110 1111
0 1 2 3
000 001 010 011
4 5 6 7
100 101 110 111
Tabel 3.3: Radix-conversie van hexadecimaal en octaal naar binair. Tabel 3.3 toont de omzetting van hexadecimale en octale cijfers naar sequenties van binaire cijfers. Bij wijze van voorbeeld zetten we B4F16 om naar het binaire stelsel7 : B4F16 = 1011|0100|1111 = 1011010011112
(3.8)
Elk cijfer in B4F16 vervangen we dus door het binair equivalent, vervolgens nemen we al deze cijfers samen. r1 → r2 omzetting met r1q = r2 In de omgekeerde situatie willen we een getal met een bronradix r1 omzetten naar een getal met een radix die een macht is van de bronradix. De oplossing bestaat erin dat we groepjes van q broncijfers naar ´e´en doelcijfer omzetten. De vraag is hoe we de voorstelling met de bronradix onderverdelen in groepen? Dit doen we vanaf de komma van het originele getal: voor het gehele gedeelte maken we groepjes van q cijfers naar links; na de komma maken we groepjes van cijfers naar rechts. Aan de uiteinden van de voorstelling kunnen er soms onvoldoende cijfers aanwezig zijn deze groepjes te maken. In dat geval dienen nullen toegevoegd te 7 De
verticale strepen (|) dienen uitsluitend om educatieve doeleinden, en zijn niet verplicht.
3.2. REKENKUNDIGE BASISSCHAKELINGEN
61
worden. Eenmaal we deze groepjes hebben geconstrueerd, vertalen we elk van deze sequenties van cijfers naar hun equivalent cijfer in het nieuwe getalstelsel (dit is dus de omgekeerde richting voor Tabel 3.3). Bij wijze van voorbeeld zetten we 1011011111.100012 om naar zijn octale equivalent: 1011011111.100012 = 1|011|011|111.100|012 = 001|011|011|111.100|0102 = 1337.428
(3.9)
Nullen die we bijvoegen om groepjes te kunnen maken hebben we onderlijnd. r1 → r2 omzetting met r1q = r2p Een logisch gevolg van de voorgaande omzettingen, is dat we ook de mogelijkheid hebben om getallen makkelijk tussen twee radixen om te zetten indien ze een macht met elkaar delen. In dat geval bestaat er immers een getal r0 zodat r1 = sp en r2 = sq . We kunnen in dat geval de conversie laten verlopen langs een getalstelsel met radix s. Een concreet voorbeeld is het binaire stelsel die als een tolk kan functioneren tussen het hexadecimale en octale stelsel. Dit illustreren we door 1572558 om te zetten naar het hexadecimaal stelsel: Oct→Bin 1572558 = 001|101|111|010|101|1012 = 11011110101011012 Bin→Hex 11011110101011012 = 1101|1110|1010|11012 = DEAD16
(3.10)
We maken dus gebruik van de twee hierboven beschreven conversie-methodes om een derde conversie te introduceren. Algemene omzetting De vorige methoden werken enkel onder een aanname: de ene radix moest een macht van een andere zijn, of er moet een gemeenschappelijk macht zijn. In de praktijk is dit meestal niet zo, zo willen we vaak decimale getallen omzetten naar hun binair equivalent, of omgekeerd. In deze subsubsectie behandelen we kort een methode om in het algemeen een radixomzetting uit te voeren. Deze omzettingen zijn relatief arbeidintensief, en vereisen bovendien een getalstel waarin we simpele rekenkundige operaties kunnen uitvoeren. Voor mensen is dit over het algemeen het decimaal stelsel, computers werken doorgaans met het binair stelsel8 . We dienen dus eerst het getal dat we willen omzetten, omzetten naar een stelsel waarin we makkelijk kunnen rekenen, bijvoorbeeld het decimale getalstelsel. Indien we bijvoorbeeld 8C98916 willen omzetten naar een getalstelsel een radix 36, zullen we dit getal eerst omzetten naar het decimale stelsel, dit doen we door de waarde van de cijfers te vermenigvuldigen met het gewicht van hun positie en deze vervolgens op te tellen: 8C98916 = 8 · 164 + 12 · 163 + 9 · 162 + 8 · 161 + 9 · 160 = 575881 (3.11) Een mogelijk eenvoudigere methode, is het getal van links naar rechts te lezen en ondertussen een getal in ons geheugen aan te passen. Aanvankelijk is dat getal 0. Telkens wanneer we een nieuw cijfer tegenkomen, vermenigvuldigen we het getal in ons geheugen met de radix, en tellen er vervolgens de waarde van het cijfer bij op. Dit doen we tot het laatste cijfer. Het getal die dan in ons geheugen zit, is het uiteindelijke getal. Dit komt dus neer op: 8C98916 = ((((0 · 16 + 8) · 16 + 12) · 16 + 9) · 16 + 8) · 16 + 9 = 575881
(3.12)
Eenmaal we het getal in een voorstelling hebben gezet waarmee we kunnen rekenen, bepalen we iteratief elk cijfer van het getal in de nieuwe voorstelling en dit van rechts naar links. Dit cijfer rekenen we uit door het getal modulo de radix r te bepalen. Wanneer we dus 575881 modulo 36 uitrekenen, bekomen we 575881 mod 36 = 25 = P36 . Hiermee weten we al het laatste cijfers. We trekken vervolgens de bekomen waarde af van het getal (575881 − 25 = 575856), en delen het door de radix r (575856/36 = 15996). Dit resultaat manipuleren we iteratief verder, om de andere cijfers van rechts naar links te berekenen. Wanneer we 0 8 Dit is niet altijd zo, in de Sovjet-Unie waren in de jaren ’50 ternaire computers populair: computers die met drie soorten signalen kunnen werken.
62HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) uitkomen, stopt het algoritme en hebben we de equivalente representatie gevonden. Tabel 3.4 illustreert dit principe. Stap 1 2 3 4 5
Getal 575881 15996 444 12 0
Modulo 575881 mod 36 = 25 15996 mod 36 = 12 444 mod 36 = 12 12 mod 36 = 12 −
Volgende getal (575881 − 25) /36 = 15996 (15996 − 12) /36 = 44 (444 − 12) /36 = 12 (12 − 12) /36 = 0 −
Cijfer 25 = P36 12 = C36 12 = C36 12 = C36 −
Tabel 3.4: Voorbeeld van algemene radix-omzetting. We kunnen dus concluderen dat: 8C98916 = CCCP36 .
3.2.3
Optellen
Hoe tellen we nu twee getallen op? In het decimaal stelsel kunnen we twee (grote) getallen optellen door middel van cijferen. Hieronder geven we een illustrerend voorbeeld waarbij we 1425 + 1917 uitrekenen: overdracht c x y som s
+
1 0 1 1 4 2 5 1 9 1 7 3 3 4 2
(3.13)
Om getallen in het decimaal stelsel te kunnen optellen gebruiken we een repetitieve structuur, waarbij we 200 basisregels moeten onthouden. Een dergelijke basisregel f (ci , xi , yi ) = hsi , ci+1 i is een functie die de eventuele overdracht of carry, en de cijfers van de twee getallen x en y in een bepaalde kolom omzet naar de overdracht van de volgende kolom en de som van deze kolom. Een voorbeeld van zo’n basisregel is f (0, 4, 9) = h3, 1i. Deze regel wordt in ons voorbeeld gebruikt in de derde kolom vanaf rechts9 . De overdracht is hierbij een restproduct van de optelling van twee cijfers (eventueel ook met de overdracht van de vorige optelling). Het is immers mogelijk dat het resultaat van de optelling groter of gelijk is aan de radix r. In dat geval is het cijfer die we onderaan schrijven, gelijk aan si = ci + xi + yi − r, de overdracht is dan gelijk aan ci+1 = 1. In het geval ci + xi + yi < r, is het resultaat si = ci + xi + yi en ci+1 = 0. Binair optellen gebeurt volledig analoog, we hebben opnieuw met een repetitieve structuur te maken, alleen dienen we nu slechts 8 verschillende regels te onthouden: immers zijn alle variabelen ci , xi en yi binair. Nu we weten hoe we twee getallen kunnen optellen, zullen we digitale circuits voorzien om de binaire signalen van twee getallen daadwerkelijk om te zetten in binaire signalen die de som voorstellen. Hiervoor zullen we eerst twee nieuwe componenten voorstellen waarmee we een opteller kunnen realiseren. We zullen later deze implementatie verder verfijnen om sneller te kunnen optellen. Half adder In deze paragraaf synthetiseren we een half adder (HA), die de laatste bit van de twee getallen optelt. Bij het laatste cijfer is de overdracht c0 sowieso 010 , dus daarmee hoeven we geen rekening te houden. We dienen een functie te ontwikkelen die de overdracht van de volgende kolom berekent, en de bit die het laatste cijfer van de som bepaalt. We stellen hiervoor een waarheidstabel en de bijbehorende Karnaugh-kaarten op in Figuur 3.13. We zien dat we de som-bit si kunnen berekenen aan de hand van een XOR operatie tussen xi en yi , de carry ci+1 is enkel 1 wanneer beide cijfers xi en yi op 1 staan, dit gedrag kunnen we dus realiseren aan de hand van een AND-poort. Deze implementatie staat in Figuur 3.13(d) 9 We 10 Dit
nummeren de kolommen vanaf rechts, analoog aan de getalvoorstelling van Vergelijking (3.7). geldt enkel bij een optelling, later zullen we optellers ook gebruiken om het verschil tussen twee getallen uit te rekenen.
3.2. REKENKUNDIGE BASISSCHAKELINGEN
63 yi
xi
si 0 1 1 0
ci+1 0 0 0 1
(a) Waarheidstabel
yi xi ci+1
yi 0 0 0 1
si xi
yi 0 1 0 1
xi
xi 0 0 1 1
yi 0 1 1 0
(b) Karnaugh-kaarten
ci+1
ci+1
HA si
(c) Interface
si (d) Mogelijke implementatie
Figuur 3.13: Half adder (HA).
Full adder Met een half adder kunnen we geen optellingen uitrekenen: immers houdt de half adder geen rekening met de carry die eventueel wordt gegenereerd uit de cijfers rechts van de plaats waar de half adder staat. We ontwikkelen dus een component die deze functionaliteit wel aanbiedt: de full adder (FA). Een full adder bevat ´e´en ingang extra tegenover een half adder: de overdracht van de vorige opteller ci . Een full adder telt op door XOR-operaties toe te passen op de drie ingangen: xi , yi en ci . Er is sprake van overdracht naar de volgende bit indien twee of meer ingangen op dat moment op 1 staan. Dit kunnen we implementeren met tweelagen-logica. De waarheidstabellen en Karnaugh-kaarten voor deze schakelingen staan samen met een mogelijke implementatie op Figuur 3.14. We kunnen ook een implementatie synthetiseren met behulp van functionele ontbinding. Bij een full adder voeren we immers twee optellingen uit, de volgorde speelt hierbij geen rol. Indien minstens ´e´en van de twee optellingen van de half adders overdracht genereert, is er sprake van overdracht bij de full adder. Daarom plaatsen we een OR-poort tussen de twee carries. We kunnen een full adder dus ook implementeren zoals op Figuur 3.14(e). Tegenover de implementatie op Figuur 3.13(d), zien we dat we ´e´en poort uitsparen. Dit betalen we echter met grotere vertragingen, iets wat bij optellingen met grote getallen niet gewenst is. Ripple-carry opteller Met behulp van een half adder en n full adders kunnen we vervolgens een opteller realiseren die twee n + 1 bit getallen optelt. Dit doen we met behulp van een Ripple-carry opteller. Figuur 3.15 toont hoe dit in z’n werk gaat: we tellen de laatste twee bits op met een half adder11 , de overige bits tellen we op met full adders. De carry uitgang van elke adder gaat naar de de ingang van de volgende adder. De allerlaatste carry uitgang cn , kan men gebruiken als een overflow uitgang. Indien we immers twee n-bit getallen met elkaar optellen, kan dit resulteren in getallen waarvoor die we enkel met n + 1 bits kunnen voorstellen. In een ander geval wordt deze uitgang gebruikt om de waarde van de n + 1-ste bit te bepalen. We kunnen ook - zoals op de figuur - de half adder vervangen door een full adder met als carry ingang c0 = 0. Omdat we meestal getallen met een groot aantal bits optellen12 is het interessant om het tijdsgedrag van een ripple-carry adder te bekijken. Het kritisch pad gaat logischerwijs van een ingang van de half adder tot de laatste full adder. Indien we de implementaties van de full adder met functionele ontbinding beschouwen blijkt het kritische pad x0 → cn te zijn. In dit geval moet het signaal doorheen ´e´en XOR, n AND en n OR poorten. Elk van deze poorten heeft twee ingangen, de vertraging is dus bijgevolg: vertraging = 2.4n + 2.4n + 3.2 = 4.8n + 3.2
(3.14)
11 Op de figuur gebruiken we hiervoor een full adder FA , maar met carry ingang c = 0, wat op hetzelfde neerkomt. Later 0 0 zullen we zien dat door een full adder te gebruiken, we meer kunnen doen met een ripple-carry opteller. 12 Op de meeste processoren spreken we over 32 of 64 bits.
64HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) ci+1 0 0 0 1 0 1 1 1
si
(a) Waarheidstabel
ci 0 1 0 1
1 0 1 0
ci+1
ci 0 0 1 0
0 1 1 1
yi xi
(b) Karnaugh-kaarten
ci
yi
HA
ci+1
ci
(c) Interface
xi
ci+1
FA si
yi
xi
ci+1
yi
si 0 1 1 0 1 0 0 1
xi
ci 0 1 0 1 0 1 0 1
yi
yi 0 0 1 1 0 0 1 1
xi
xi 0 0 0 0 1 1 1 1
HA
si
ci
si
(d) Mogelijke implementatie
(e) Functionele ontbinding
Figuur 3.14: Full adder (FA). xn−1yn−1
cn
FAn
yi
xi
...
sn−1
FAi si
y2
x2
...
y1
x1
y0
x0
FA2
FA1
FA0
s2
s1
s0
c0 = 0
Figuur 3.15: Schematische voorstelling van een n-bit Ripple-carry opteller. Het is mogelijk dat we deze vertraging verder kunnen reduceren, een probleem is echter dat de vertraging van een orde O (n) blijft. Voor berekeningen met grote getallen zijn ripple-carry adders dan ook onaanvaardbaar. Om dit euvel te verhelpen introduceren we de carry-lookahead opteller. Carry-lookahead opteller Een Carry-lookahead opteller (CLA) is een component ter vervanging van een full adder. Het is de bedoeling om met behulp van deze component rechtstreeks ci te berekenen als een functie ci (c0 , x0 , x1 , . . . , xi−1 , y0 , y1 , . . . , yi−1 ). De Carry-lookahead opteller heeft dezelfde ingangen als een full adder: hxi , yi , ci i, maar meer en andere uitgangen hci+1 , gi , pi , si i. Deze uitgangssignalen hebben volgende functie: • carry-generate gi : 1 indien er bij het optellen van xi en yi overdracht gegenereerd wordt; 0 in het andere geval. Bijgevolg is gi = xi · yi . • carry-propagate pi : 1 indien bij de optelling de overdracht van de vorige bit verder gepropageerd zal worden, en deze overdracht niet gegenereerd wordt; 0 in het andere geval. Bijgevolg pi = xi ·yi0 +x0i ·yi = xi ⊕ yi .
3.2. REKENKUNDIGE BASISSCHAKELINGEN
65
• som si : het resultaat van de optelling si = ci ⊕(xi ⊕ yi ), wat equivalent is met si = ci p0i +c0i pi = ci ⊕pi . De opsomming van de uitgangen geeft dan ook al meteen een mogelijke implementatie; de waarheidstabellen, interface en een mogelijke implementatie staan op Figuur 3.16. si
(a) Waarheidstabel
gi
pi
ci 0 0 1 0
0 0 1 0
ci 0 1 0 1
0 1 0 1
xi yi
yi
pi 0 0 1 1 1 1 0 0
yi
gi 0 0 0 0 0 0 1 1
1 0 1 0
xi
si 0 1 1 0 1 0 0 1
0 1 0 1
yi
ci 0 1 0 1 0 1 0 1
xi
yi 0 0 1 1 0 0 1 1
xi
xi 0 0 0 0 1 1 1 1
ci
si
(b) Karnaugh-kaarten
xi
x
y
g
p
s
c
ci
gi pi (c) Interface
yi
si
ci
gi
pi
(d) Mogelijke implementatie
Figuur 3.16: Carry-Lookahead Opteller (CLA). We kunnen de overdracht van de carry-lookahead opteller ci+1 vervolgens berekenen met de formule ci+1 = gi + ci pi : er is overdracht wanneer deze ofwel gegenereerd wordt, ofwel wanneer er al overdracht is en deze gepropageerd wordt. De overdacht hangt dus niet langer rechtstreeks af van xi of yi . Deze eigenschap zal belangrijk blijken voor de synthese van het volgende component: de CLA-generator. CLA-generator Om een opteller te realiseren moeten we, net zoals bij de ripple-carry opteller, nog de glue logic voorzien tussen de verschillende carry-lookahead optellers. Bij deze optellers is het verhaal echter gecompliceerder: we hebben een extra component nodig om de CLA elementen met elkaar te verbinden: de CLA-generator. Een n-bit CLA-generator is een component met ingangen hc0 , g0 , . . . gn−1 , p0 , . . . , pn−1 i. De component heeft tot doel om de overdracht voor een reeks carry-lookahead optellers te berekenen met een zo klein mogelijk kritisch pad, logischerwijs heeft de component dan ook de uitgangen: hc1 , . . . cn , g0,n−1 , p0,n−1 i. De laatste twee uitgangen zullen we later bespreken. Op figuur 3.17(a) zien we hoe we een CLA-generator aansluiten op de Carry-lookahead optellers. Eerst zullen we een methode ontwikkelen om een overdracht ci te berekenen. Een overdracht kan maar op twee manieren tot stand komen: ofwel wordt deze gegenereerd, ofwel wordt deze gepropageerd. Dit formaliseren we als:
66HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) sn−1
xn−1yn−1 x s
s2
y
CLAn−1
g
...
c
s
p
gn-1 pn-1 g0,n-1
g0,n−1 p0,n−1
x2
y2
x
y
CLA2
s1
c
s
x1
y1
x
y
s0
c
CLA1
s
x0
y0
x
y
CLA0
g
p
g
p
g
p
g2
p2
g1
p1
g0
p0
CLA-generator
p0,n-1 cn
c
c0
c0
c3
c2
c1
c3
c2
c1
... cn
(a) Structuur van de CLA-generator. s8 x8 y8 x s
s7 x7 y7
y
CLA8 g
p
g2 g0,2 p0,2
p2
x c
s
y
CLA7
x c
s
p
g
p
g1
p1
g0
p0
CLA-Generator1,2 c2
g2
s5 x5 y5
y
CLA6
g
c3
g0,2 p0,2
s6 x6 y6
x c
c0
s
y
CLA5 g
p
g2 g0,2 p0,2
p2
c1
s4 x4 y4 x c
s
s3 x3 y3
y
CLA4
x c
s
y
g
p
g
p
g1
p1
g0
p0 c0
c2
p2
g1
x c
CLA3
CLA-Generator1,1 c3
s2 x2 y2
s
y
CLA2 g
p
g2 g0,2 p0,2
p2
c1
s1 x1 y1 x c
s
y
CLA1
x c
s
y
CLA0
g
p
g
p
g1
p1
g0
p0
CLA-Generator1,0 c3
c2
p1
c
c0
c0
c1
g0
p0
CLA-Generator2,0 c3
s0 x0 y0
c0
c2
c1
(b) Cascade van CLA-generators met n = 9, k = 3.
Figuur 3.17: CLA-generator.
ci = g0,i−1 + p0,i−1 · c0
(3.15)
Een oplettende lezer zal gemerkt hebben dat we hierbij g en p twee indices geven. De indices wijzen dan ook op een bereik: alle getallen tussen 0 en (inclusief) i − 1. g0,i−1 betekent dus zoveel als: “er wordt ergens tussen 0 en i − 1 een overdracht gegenereerd, en deze wordt dan verder gepropageerd tot i. p0,i−1 betekent dat er een propagatie-pad is tussen index 0 en i. Een dergelijk propagatie-pad bestaat uitsluitend tot de i-de bit indien voor alle posities tot i er geprogageerd wordt. Bijgevolg stellen we dat:
pi,j =
j Y
pk
(3.16)
k=i
Merk op dat we hier een booleaans product bedoelen, er staat dus tussen elk element van de deelexpressie een AND. Er wordt soms ook overdacht gegenereerd. Dit is bijvoorbeeld het geval indien de vorige bit een overdacht genereerde, of een willekeurige bit ervoor, die deze dan tot de i-de bit weet te propageren. Of meer formeel:
gi,j = gj +
j−1 X k=i
gk pk+1,j = gj +
j−1 X k=i
gk ·
j Y
! pl
(3.17)
l=k+1
Merk op dat we hier met het sommatie-teken de booleaanse som bedoelen, wat dus neerkomt op ORpoorten. Wanneer we Vergelijking (3.16) en Vergelijking (3.17) in Vergelijking (3.15) schuiven, dan bekomen we een formule waarmee we de overdacht ci kunnen berekenen, enkel op basis van de invoer van de CLAgenerator:
3.2. REKENKUNDIGE BASISSCHAKELINGEN
ci = gi−1 +
i−2 X
gk ·
k=0
67
i−1 Y
! pl
+ c0 ·
l=k+1
i−1 Y
pk
(3.18)
k=0
De berekening voor ci kost dus een i + 1-OR poort, en i + 1 AND poorten, elk van deze poorten heeft een ander aantal ingangen vari¨erend van twee tot i + 1. We kunnen nu opnieuw het kritische pad analyseren. Dit pad is x0 → cn . Hierbij gaat het signaal doorheen ´e´en XOR poort, ´e´en n + 1-input AND poort en ´e´en n + 1-OR poort. De totale vertraging is dus: vertraging = 3.2 + 2 · (2 + 0.4 · n) = 0.8 · n + 7.2
(3.19)
Toegegeven dat de orde van de vertraging nog steeds lineair is, maar de factor voor O (n) is met de CLA-generator sterk gereduceerd. De CLA-generator laat ons echter ook toe om toch logaritmisch gedrag te bereiken, en dit met een cascade van CLA-generatoren. Indien we twee n-bit getallen willen optellen, en we groeperen elke k carry-lookahead optellers met een CLA-generator, en vervolgens groeperen we elke k CLA-generatoren tot een niveau hoger, dan hebben we dlogk ne niveaus nodig. We kunnen in dat geval Vergelijking (3.19) gebruiken om de vertraging te berekenen: vertraging = 3.2 + (2 · dlogk ne − 1) · (4 + 0.8 · k)
(3.20)
Hiermee kunnen we de vertraging reduceren tot een logaritmische orde. Figuur 3.17(b) toont hoe we een dergelijke cascade kunnen bouwen. Met deze cascade wordt ook meteen de reden van de twee extra ingangen duidelijk: het zijn de propagate en generate ingangen voor de CLA-generator een niveau hoger, die dus enkel kijkt of een blok van bits overdracht zullen genereren en propageren. De bijbehorende formule voor g0,k−1 en p0,k−1 kunnen we respectievelijk afleiden uit Vergelijking (3.17) en Vergelijking (3.16). Bij wijze van afsluiter stellen we op Figuur 3.18 een mogelijke implementatie van een CLA-generator voor. Deze implementatie is ver van optimaal, en bovendien met een kleine n. g2
p2
g1
p1
g0
p0
g0,2 c0 p0,2
c3
c2
c1
Figuur 3.18: Een mogelijke implementatie voor een CLA-generator met n = 3. We zien rechtsboven een reeks AND-poorten. De meest rechtse AND-poorten berekenen de telkens het product van een reeks propagatoren pi en c0 . Ze bereken dus of de carry c0 kan worden doorgegeven tot een zekere bit. Links van elke generator-ingang gi staan ook een reeks AND-poorten. Deze poorten berekenen of we deze gegenereerde overdracht tot een zekere bit kunnen verder propageren. Helemaal links staat ook een AND-poort die het product van alle propagatoren pi berekent, en aanlegt op de p0,2 uitgang. Onderaan bevinden zich een aantal OR-poorten die carry ci berekenen. De poorten nemen telkens de som van hun overeenkomstige generator gi−1 alsook de poorten die erin slagen overdracht ver genoeg te propageren. Tot slot staat er nog links een OR-poort. Deze poort komt grotendeels overeen met de OR-poort die voor c3 staat, er ontbreekt echter een ingang van een AND-poort met c0 . Immers indien c0 = 1, wordt de overdracht niet binnen dit bereik gegenereerd.
68HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
3.2.4
Negatieve getallen
Om getallen te kunnen aftrekken, zullen we eerst ons getalbegrip uitbreiden, zodat we ook negatieve getallen kunnen voorstellen. Negatieve getallen voorstellen kan op verschillende manieren. In onderstaande subsubsecties zullen we de meest populaire bespreken. We moeten hierbij in gedachten houden dat we eventueel de bovenstaande opteller zullen moeten uitbreiden om ook negatieve getallen te kunnen optellen. Het is dus aan te raden niet eender welke voorstelling te kiezen, maar een voorstelling waarvan we verwachten dat we hiermee effici¨ent berekeningen kunnen uitvoeren. ‘Sign-Magnitude’-voorstelling Het arabische getalstelsel lost het probleem van het voorstellen van negatieve getallen op aan de hand van een teken. Een getal bestaat dan uit twee delen: een teken (+ of −) en een grootte. Bij positieve getallen wordt dit teken zelfs meestal niet geplaatst. Deze voorstelling is gekend als de ‘ sign-magnitude’ voorstelling. Aangezien een getal ofwel positief of negatief is, kunnen we bij een binaire voorstelling een extra bit bij het getal plaatsen, bijvoorbeeld ervoor. Deze bit is 0 bij een positief getal, en 1 bij een negatief getal. In dat geval wordt dus 011002 = +1210 en 111002 = −1210 . Een getal met n bits kan dus alle gehele waarden aannemen tussen −2n−1 + 1 en 2n−1 − 1. Er zijn echter enkele problemen met deze voorstelling. Zo zijn er bijvoorbeeld twee voorstellingen van 0: −0 en +0. Dit leidt tot extra complexiteit bij bijvoorbeeld het vergelijken van twee getallen. Optellen en aftrekken van twee getallen wordt bovendien gecompliceerder: er zijn verschillende testen nodig alvorens we de waardes van de getallen kunnen optellen of aftrekken, wat tot grote vertragingen leidt. De sign-magnitude voorstelling is dan ook niet populair bij het voorstellen van gehele getallen. Wel is het een populaire manier om positieve en negatieve getallen met vlottende komma voor te stellen zoals we zullen zien in Subsectie 3.2.10. Excess formaat Een tweede mogelijkheid om getallen voor te stellen is het zogenoemde excess formaat. Hierbij beschouwd men een parameter, de excess-bias B. Men stelt ieder getal voor alsof het een positief getal is, maar men trekt er virtueel de excess-bias vanaf. Indien de excess-bias dus bijvoorbeeld 12 is, dan slaat 00002 op −12; 01002 op −8 en 11102 op +2. Een probleem met het excess formaat is dat men bij het implementeren van optellers en andere componenten de boekhouding op orde moet houden. Men kan dus geen twee getallen in excess formaat zomaar optellen: men dient er de bias terug van af te trekken. Wanneer we dus bij excessbias 12 de getallen 10002 = −4 en 11102 = 2 willen optellen, kunnen we deze optellen alsof het natuurlijke getallen zijn, en bekomen we 101102 = 14, maar daarna dienen we nog 12 van af te trekken 11002 = −2. Het excess formaat wordt wel gebruikt bij de exponent bij getallen met vlottende komma (zie Subsectie 3.2.10). Complement-voorstellingen De meeste voorstellingen van negatieve getallen zijn gebaseerd op complement voorstellingen. Bij deze twee voorstellingen zal men negatieve getallen voorstellen door het complement van de cijfers te nemen. Wanneer het eerste cijfer van het getal dus groter is dan de helft van de radix spreken we over een negatief getal. Er bestaan twee soorten complement voorstellingen voor een getal D met m cijfers en radix r: • cijfer-complement of diminished-radix complement D0 : hierbij wordt elk cijfer i vervangen door zijn complement r − i − 1. Bijvoorbeeld: – Het 9-complement van 133710 is 866210 . – Het 1-complement van 01001011 010100112 is 10110100 101011002 . Het 1-complement wordt soms gebruikt voor het voorstellen van negatieve getallen in het binaire stelsel. Een belangrijk nadeel is echter dat er opnieuw twee voorstellingen van 0 bestaan. Om dit probleem op te lossen, bestaat er een andere complement voorstelling. • radix-complement D∗ = rm − D. Bijvoorbeeld:
3.2. REKENKUNDIGE BASISSCHAKELINGEN
69
– Het radix-complement van 133710 is 866310 . – Het radix-complement van 01001011 010100112 is 10110100 101011012 . Voor binaire getallen is dit het 2-complement. Dit is veruit de meest populaire voorstellingswijze. Een eigenschap waar we later nog op zullen terugkomen is dat D∗ = D0 + 1. De voorstelling van het radix-complement is dus altijd ´e´en groter dan de voorstelling van dat getal in cijfer-complement. Immers zal blijken dat - omdat het 1-complement snel uit te rekenen valt - het 2 complement ook snel uit te rekenen zijn. Immers is het 1-complement niets anders dan het toepassen van een NOT operatie op alle bits. Twee-complement voorstelling Omdat de 2-complement voorstelling vrij populair is, gaan we er nog wat dieper op in. Bij een getalstelsl met radix r en een getal met n cijfers, kunnen we rn getallen voorstellen. Een logisch gevolg is dat we getallen groter of gelijk aan rn niet voorstellen: 0 wordt immers ook voorgesteld. Daarom stellen we dat rn ≡ 0. We kunnen rn immer voorstellen door ´e´en 1 gevolgd door n cijfers met 0. Omdat we maar n bits beschikbaar hebben, weerhouden we de laatste n bits: de 1 valt er dus zogezegd af. Omdat D∗ = rn − D geldt, kunnen we stellen dat D∗ ≡ 0 − D = −D. Wanneer we dus de 2-complement voorstelling voor negatieve getallen gebruiken, kunnen we onze opteller van de vorige subsectie gebruiken, zonder enige aanpassing. Of een getal positief is of negatief, is natuurlijk een kwestie van interpretatie. De opteller weet niet of het met een geheel getal voorstelling of een 2-complement voorstelling te maken heeft, maar dat maakt niets uit. We dienen zelf bij te houden welk soort getallen onze voorstelling kan bevatten. We kunnen we relatief eenvoudig de negatie van een getal berekenen: we passen op elke bit een NOT operatie toe, en tellen daar vervolgens 1 bij op. Later zullen we zien dat we door een eenvoudige ingreep op onze eerder ontwikkelde opteller, deze optelling kunnen realiseren met een minimum aan extra hardware. Een ander voordeel van de 2-complement voorstelling, is dat er slechts ´e´en voorstelling van het getal 0 is. Indien we immers het negatief van 0 berekenen bekomen we: D = 00002 ⇒ −D ≡ D∗ = 11112 + 00012 = 100002 = 00002
(3.21)
Dit resulteert in het feit een getal met n bits een bereik van −2n−1 tot 2n−1 − 1, wat exact ´e´en element groter is dan de 1-complement tegenhanger13 . Betekenis van binaire getallen Om het verschil tussen de verschillende voorstellingen duidelijk te maken, zetten we de betekenis van de verschillende voorstellingen voor elke 4-bit getal naast elkaar in Tabel 3.5.
3.2.5
Optellen en aftrekken van negatieve getallen
Nu we de belangrijkste voorstellingen van negatieve getallen besproken hebben, werken we voor iedere voorstellingen een schema uit hoe we getallen kunnen optellen en aftrekken. Deze schema’s worden weergegeven in Figuur 3.19. We bespreken in de volgende subsubsecties deze voorstellingen. Signed-magnitude voorstelling Bij een sign-magnitude voorstelling moeten we eerst een reeks testen uitgevoeren alvorens we getallen kunnen optellen of aftrekken. In eerste instantie moeten we bij het aftrekken van twee getallen het teken van de tweede operand veranderen: we maken het getal dus negatief. Daarna kunnen we een optelling uitvoeren die rekening houdt met het aangepaste teken. Bij deze optelling moeten we eerst testen of beide getallen hetzelfde teken hebben. Indien dit het geval is, tellen we de magnitudes van de twee getallen op, en dit wordt 13 Dit
is de plaats die vrijkomt omdat de 2-complement voorstelling slechts ´ e´ en voorstelling van 0 heeft.
70HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) Binair
Unsigned
Sign-Magnitude
1-Complement
2-Complement
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15
+0 +1 +2 +3 +4 +5 +6 +7 −0 −1 −2 −3 −4 −5 −6 −7
+0 +1 +2 +3 +4 +5 +6 +7 −7 −6 −5 −4 −3 −2 −1 −0
+0 +1 +2 +3 +4 +5 +6 +7 −8 −7 −6 −5 −4 −3 −2 −1
Tabel 3.5: Betekenis van de binaire getallen.
de magnitude van het uiteindelijke getal. Het teken blijft dan gelijk aan dat van de twee oorspronkelijke getallen. Indien het teken niet gelijk is, zal het getal met de grootste magnitude m het teken van het getal bepalen, en moeten de magnitudes van elkaar afgetrokken worden. We vergelijken dus de magnitudes. In het geval dat beide gelijk zijn, is het resultaat 0, en is de teken-bit is vrij te kiezen14 . Zijn de magnitudes verschillende dan trekken we de kleinste magnitude af van de grootste, en bepaalt de grootste ook de tekenbit. Deze reeks testen - drie in totaal - zorgen voor complexe hardware die bovendien ook nog traag werkt, dit maakt sign-magnitude tot een weinig populaire voorstelling. Figuur 3.19(a) geeft de werkwijze schematisch weer. 1-complement voorstelling Optellen en aftrekken met de 1-complement voorstelling is eenvoudiger. Bij een aftrekking berekenen we ook eerst de negatie van de tweede operand. Dit komt neer op een bitgewijze15 NOT operatie. Vervolgens kunnen we de twee getallen optellen met onze eerder ge¨ımplementeerde opteller. Deze optelling volstaat niet altijd: met het volgende voorbeelden kunnen we illustreren wat er kan fout lopen: 0101 + 1010 0 1111
+5 + −5 −0
0110 + 1101 1 0011
+
+6 −2 +3
1011 + 0011 0 1110
+
−4 +3 −1
(3.22)
Indien we twee getallen optellen met een tegengesteld teken, zodat de uitkomst positief is, zien we dat het resultaat altijd 1 lager uitvalt dan het correcte resultaat. Dit komt omdat de 1-complement voorstelling twee representaties voor 0 heeft. Zoals we zien in het eerste voorbeeld, komen we −0 uit bij het optellen van twee tegengestelde getallen. Omdat het ophogen van −0, +0 oplevert betekent dit dus dat het “twee stappen kost” om een waarde boven de 0 uit te komen. Wanneer we dus een resltaat 1 zouden moeten uitkomen, zal de opteller de voorstelling die bereken die 1 hoger is dan −0: +0. We kunnen dit probleem oplossen aan de hand van de carry cn . Indien deze carry gelijk is aan 1, moeten we nog 1 optellen bij het resultaat. Wanneer we dit toepassen op de voorbeelden in Vergelijking (3.22) bekomen we wel correcte resultaten: 14 Op
de figuur hebben we voor 0 gekozen. bitgewijs bedoelen we dat we de beschreven operatie op elke bit toepassen. In dit geval betekent dit dus dat we op iedere bit afzonderlijk de NOT operatie toepassen. 15 Met
3.2. REKENKUNDIGE BASISSCHAKELINGEN Begin aftrekking
71
Begin optelling
s2 = s02
nee
nee
nee
m1 > m2
mr = m2 − m1 sr = s2
m1 = m2
s1 = s2
ja
Begin aftrekking
ja
B2 = B20
ja
mr = m1 − m2 sr = s1
Begin optelling
mr = 0 sr = 0
mr = m1 + m2 sr = s1
Br = B1 + B2
Begin aftrekking
Begin optelling
Carry aanpassen
Br = B1 +B20 +1
Br = B1 + B2
Einde
Einde
Einde
(a) Sign-magnitude
(b) 1-complement
(c) 2-complement
Figuur 3.19: Optelling en aftrekking van gehele getallen.
0101 + 1010 0 1111 + 0000 1111
+5 + −5 −0 + +0 −0
+ 1 +
0110 1101 0011 0001 00100
+ +
+6 −2 +3 +1 +4
1011 + 0011 0 1110 + 0000 1110
−4 +3 −1 + +0 −1 +
(3.23)
Deze aanpassing resulteert in een belangrijk nadeel: we de optelling-aftrekking dus in twee tijden moeten uitvoeren: eerst tellen we ze op en bepalen we de hoogste carry cn , vervolgens tellen we deze carry nog eens bij het resultaat op. Dit veroorzaakt dus een verdubbeling van de vertraging. Figuur 3.19(b) geeft het hele proces schematisch weer. 2-complement voorstelling De 2-complement voorstelling is de beste voor de implementatie van een opteller-aftrekker. Immers kunnen we een optelling eenvoudigweg uitvoeren zoals we die reeds hebben beschreven in Subsectie 3.2.3. Bij een optelling dienen we dus enkel de twee operatoren optellen: Br = B1 +B2 . Bij een aftrekking moeten we eerst de negatie van de tweede operand berekenen. Wanneer we deze negatie: −B2 = B20 + 1 in de berekening bij optelling inschuiven, wordt de volledige berekening dus Br = B1 + B20 + 1. Deze optelling lijkt tot hetzelfde probleem te leiden als bij de 1-complement voorstelling: we dienen tweemaal een optelling uit te voeren. In Subsectie 3.2.3 hebben we echter een opteller ge¨ıntroduceerd met een carry-ingang c0 die we altijd op 0 hebben gezet. Door deze carry bit c0 op 1 zetten, tellen we automatisch 1 extra op bij het resultaat, en dit zonder extra hardware te gebruiken, of vertragingen te introduceren. Uit de formule blijkt ook dat we bitgewijze een NOT operatie moeten uitvoeren op B20 , maar enkel in het geval van een aftrekking. Dit kunnen we bewerkstelligen met een XOR poort: Een XOR poort is dan ook een geparametriseerde NOT poort. Indien ´e´en van de ingangen van de XOR poorten op 1 staat, fungeert de XOR poort als een NOT poort voor de andere uitgang. Indien de eerste ingang op 0 staat, laat de XOR poort de andere ingang eenvoudigweg door. We kunnen dus een opteller-aftrekker realiseren zoals op Figuur 3.20(b). Deze component bevat een extra ingang s waarmee men kan aangeven of we een optelling of aftrekking willen uitvoeren. Indien s = 0 tellen we de twee getallen met elkaar op, anders trekken we de twee getallen van elkaar af. Door een XOR poort op de laatste twee carry-uitgangen cn−1 en cn te plaatsen, kunnen we een controle op overflow inbouwen. Deze component wordt meestal samengevat tot een interface zoals op Figuur 3.20(a)16 . Een schematische werkwijze van optellen en aftrekken met 2-complement voorstelling 16 Bemerk
op de figuur dat variabelen met hoofdletters een rij van in- of uitgangen voorstellen.
72HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) xn−1 yn−1
xn−2 yn−2
xn−3 yn−3
y2
x2
y1
x1
y0
x0
s
... X
Y cn
addersubtractor
cout
FAn−1
FAn−2
FAn−3
fn−1
fn−2
fn−3
...
FA2
FA1
FA0
f2
f1
f0
s
F
overflow
(a) Interface
(b) Mogelijke implementatie
Figuur 3.20: Opteller-aftrekker voor 2-complement getallen.
staat op Figuur 3.19(c). De 2-complement voorstelling is dan ook populair omdat deze weinig bewerkingen en testen vergt om sommen en verschillen te berekenen. Bovendien is er weinig extra hardware - een XOR poort per bit en mogelijk een full adder in plaats van een half adder - nodig om een opteller om te bouwen tot een opteller-aftrekker.
3.2.6
Arithmetic-Logic Unit (ALU) an−1bn−1
an−2bn−2
a1
b1
a0
b0 m i0 i1
ALEn−1
ALEn−2
...
ALE1
ALE0
FAn−1
FAn−2
...
FA1
FA0
fn−1
fn−2
f1
f0
cn
CIG
overflow
Figuur 3.21: Schematisch implementatie van een arithmetic-logic unit (ALU). Hoewel veel processoren in staat zijn om sommen en verschillen te berekenen zal men meestal geen directe opteller of opteller-aftrekker vinden. Meestal gebruikt men hiervoor een Arithmetic-Logic Unit (ALU). Een ALU is een component die, gebaseerd op een opteller, allerlei instructies17 kan uitvoeren. In ons geval beschouwen we vier rekenkundige (optellen, aftrekken, increment en decrement) en vier logische bewerkingen (AND, OR, NOT en identiteit). We bouwen een ALU op ongeveer dezelfde manier zoals we een opteller-aftrekker bouwden uit een opteller. In plaats van XOR poorten gebruiken we een nieuw component: een Arithmetic-Logic Extender (ALE). Een ander component – de Carry Input Generator (CIG) – berekent welke ingang aan de carry c0 moet worden gegeven. In het algemeen heeft een ALU dus een structuur zoals op Figuur 3.21 waarbij de ALE en CIG vrij ge¨ımplementeerd kunnen worden op basis van een instructieset. 17 Welke
instructies is niet echt gespecificeerd. Er bestaan dan ook boeken over het ontwerpen van een goede ALU.
3.2. REKENKUNDIGE BASISSCHAKELINGEN
73
Instructieset Alvorens we in staat zijn een ALU te maken moeten we een instructieset defini¨eren. Onze instructieset heeft drie18 ingangssignalen die bepalen welke opdracht er moet worden uitgevoerd. We delen de acht opdrachten in in twee groepen van vier: aritmetisch en logisch. Daarom noemen we de eerste bit van het instructiewoord m voor mode19 . Verder wijzen we dan elke opdracht toe aan een bepaald instructiewoord zoals in Tabel 3.6. m 0 0 0 0 1 1 1 1
i1 0 0 1 1 0 0 1 1
i0 0 1 0 1 0 1 0 1
F 0
A A AND B A A OR B A−1 A+B A−B A+1
X 0
A A AND B A A OR B A A A A
Y
c0
Instructie
0 0 0 0 -1 B B0 0
0 0 0 0 0 0 1 1
NOT AND Identiteit OR Decrement Optelling Aftrekking Increment
Tabel 3.6: Instructieset van een typische arithmetic-logic unit (ALU). Gebaseerd op deze instructieset moeten we een ALE en CIG implementeren. De ALE implementeert een functie die hA, Bi-waardes afbeeldt op hX, Y i-waardes. Deze laatste waardes dienen als invoer voor de opteller. De CIG ten slotte geeft – gebaseerd op het instructiewoord – een waarde voor c0 . Deze functies staan ook in het derde deel van instructietabel (Tabel 3.6). Synthese van de ALE en CIG Eenmaal we de instructieset hebben bepaald, dienen we enkel nog de ALE en CIG te implementeren. Een ALE is een component met als ingangen het instructiewoord en van elke operand een bit. In ons geval wordt dit dus hm, i1 , i0 , aj , bj i. Als uitgangen hebben we de ingangen van ´e´en van de full adders hxj , yj i. We zijn dus in staat om een waarheidstabel en Karnaugh-kaart op te stellen van de ALE. Zoals op Figuur 3.22(a). Op basis van de Karnaugh-kaart kunnen we dan een logisch circuit bouwen zoals is te zien op Figuur 3.22(b). Op de figuur hebben we dat gedaan met AND-OR lagen, maar zoals reeds gezegd zijn equivalente NAND-NAND lagen goedkoper en sneller. De CIG is enkel afhankelijk van het instructiewoord. Met de instructieset op Tabel 3.6 is dit hm, i1 , i0 i. Een CIG heeft slechts ´e´en uitgang: de carry c0 . Op basis van deze instructieset staat op Figuur 3.22(a) de bijbehorende Karnaugh-kaart. Deze blijkt een eenvoudige AND-operatie te zijn zoals op Figuur 3.22(c). De waarde van i0 blijkt zelfs geen effect te hebben op de carry.
3.2.7
Vermenigvuldigen
In deze subsectie bouwen we een vermenigvuldiger gebaseerd op de manier hoe men met behulp van cijferen twee getallen vermenigvuldigt. We zullen hierbij enkel natuurlijke getallen beschouwen, later breiden we dit uit naar gehele getallen. Vergelijking (3.24) toont hoe we met behulp van cijferen twee getallen in het decimale getalstelsel vermenigvuldigen: 1
4 3 7 1 8 5 5 + 4 2 7 5 5 2 0 1 ×
18 Omdat
2 5 6 5 2 5 0 2
5
we acht opdrachten gedefinieerd hebben, hebben we een log2 8 = 3 bit instructiewoord nodig. 1=aritmetisch.
19 0=logisch,
(3.24)
74HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
xj
m aj
aj
1 1 1 1
1 1 1 1
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
bj
0 0 0 0
1 1 0 0
bj
1 1 0 0
1 0 0 1
1 0 0 1
i0 0 0 1 0
0 0 1 0
i1
bj
0 0 0 0
c0
m
1 0 1 0
m aj
aj
i0
0 1 1 1
i1
0 0 1 1
i0
i1
1 0 0 0
yj
bj
(a) Karnaugh-kaarten m i1 i0 aj bj
m
i0
i1
c0
xj
yj
(b) Implementatie ALE
(c) Implementatie CIG
Figuur 3.22: Synthese van de ALE en CIG.
We kunnen dus twee getallen vermenigvuldigen door het eerste getal telkens te vermenigvuldigen met ´e´en van de cijfers van het onderste getal en deze – nadat we ze op de juiste manier hebben uitgelijnd – optellen. Deze methode werkt ook op binaire getallen zoals blijkt uit Vergelijking (3.25): 1
0 1 1 0 0 0 0 + 1 0 1 1 1 1 0 1 ×
1 1 0 1 1 1 0 1
(3.25)
1
Een groot voordeel van vermenigvuldigingen met binaire getallen is dat een cijfer slechts 1 of 0 kan zijn. Indien het 0 is tellen we niets op bij het resultaat; anders dienen we het bovenste getal op te tellen, in dit voldoende naar links opgeschoven. Deze realisatie noemt men een parallelle vermenigvuldiger. Figuur 3.23 toont enkele voorbeelden van parallelle vermenigvuldigers. Zo zien we het speciale geval van een 1 × 1bit, wat neerkomt op een AND-poort. De 3 × 2-bit vermenigvuldiger toont een speciale realisatie van het cascaderende effect: vermits er maar twee bits zijn, hebben we slechts ´e´en opteller nodig. Met behulp van AND-poorten kunnen we ofwel 0 op de opteller plaatsen, of het getal zelf. Tot slot implementeren we ook het algemeen geval van een m × n-vermenigvuldiger.
Naast parallelle vermenigvuldigers bestaan er ook andere implementaties die sneller werken en goedkoper te realiseren zijn. De kostprijs om een getal met m bits te vermenigvuldigen met een getal van n bits is immers O (n · m). Met een sequenti¨ele schakeling kunnen we de kosten sterk reduceren en vaak zelfs de vermenigvuldiging versnellen. Tot slot is het vermenigvuldigen met een macht van twee een speciaal geval wat we kunnen bewerkstelligen met een schuifoperator. Deze schuifoperator komt aan bod in Subsectie 3.3.6.
3.2. REKENKUNDIGE BASISSCHAKELINGEN
75 a2
a1
HA2
FA1
HA0
c3
c2
c1
a0
b0
a2
a1 b1 a1 b0 a0 b1 c1
× +
b0a0 ×
c4
a2 b1 c3
a2 b0 a1 b1 c2
a0 b0 a0 b0
b1
c0
a0 b0 a0 b0 a0 × b0
c4
(a) 1 × 1-bit
c0
(b) 3 × 2-bit an−1
b0 b1
a1
a0 0
... c
xn−1 . . .
x1
x0
an−1 b2
a1
a0
x1
x0
s1
a1
y1
y0
...
yn−1 . . .
n-opteller1
sn−1 . . .
a2
s0
... c
xn−1 . . .
c
xn−1 . . .
x1
x0
an−1 bm−2
a1
a0
x1
x0
yn−1 . . .
. . . m−3 n-opteller
sn−1 . . .
s1
yn−1 . . .
n-opteller2
sn−1 . . .
y1
s1
y1
y0
s0
y0
s0
... c
xn−1 . . .
sm+n−1
yn−1 . . .
n-optellerm−1
sn−1 . . .
sm+n−2
s1
y1
y0
s0
sm sm−1
s2
s1
(c) n × m-bit
Figuur 3.23: Parallelle vermenigvuldigers.
2-complement vermenigvuldiger Het uitbreiden van deze vermenigvuldiger naar gehele getallen met 2-complement voorstelling is geen sinecure. In de praktijk zal men dan ook eerst de getallen omzetten naar sign-magnitude voorstelling alvorens we de twee getallen vermenigvuldigen. In dat geval kunnen we de magnitude van de twee getallen vermenigvuldigen – zoals we hierboven hebben gedemonstreerd – en passen we een XOR operatie toe op de tekenbit van de getallen. Het resultaat zetten we vervolgens weer om naar 2-complement voorstelling. Er bestaat uiteraard wel een vermenigvuldiger voor een 2-complement voorstelling. Deze zullen we enkel op hoog niveau beschrijven door middel van een voorbeeld. We rekenen hierbij −2 × −3 uit op 4-bit voorstelling en het resultaat stellen we voor op een 8-bit voorstellingen zoals in onderstaande vergelijking:
×
−2 −3 +6
×
1110 1101 00000110
(3.26)
76HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) De oplossing bestaat eruit om −2 ≡ 11102 te zien in zijn binaire vorm als −8 + 4 + 2 = −2, bemerk het minteken bij de 8. Elk van de bits dient afzonderlijk vermenigvuldigd te worden, en vervolgens opgeteld te worden zoals in onderstaande vermenigvuldiging: 2 + 4 + −8 −2
3.2.8
× −3 × −3 × −3 × −3
⇒ ⇒ ⇒ ⇒
+ +
1111 1111 0001 0000
1010 0100 1000 0110
(3.27)
Andere courante bewerkingen
Om het gedeelte van de gehele getallen af te sluiten beschouwen we nog enkele populaire bewerkingen op de gehele getallen. We geven voor deze bewerkingen geen concrete implementatie, al kan de beschrijving op hoog niveau misschien volstaan om zelf een component hiervoor te ontwikkelen. Delen Analoog aan vermenigvuldigen kunnen we ook een deling in een binaire voorstelling gebaseerd op cijferen. We geven een voorbeeld van een binaire deling maar vermelden geen details over het realiseren van een schakeling: 1011 − 111 100 − 11 1 −0 1 −
1010 0000 1010 1000 0010 0000 0010 1110 100
1110 1101
(3.28)
Door herhaaldelijk het resterende deeltal te vergelijken met een verschuifde deler en indien deze groter is, deze af te trekken, kunnen we de rest en de het quoti¨ent berekenen. Het aantal cycli is dus ook tevens het aantal bits van het quoti¨ent. Deze manier van implementatie is dan ook de meest populaire, meestal zal men echter geen parallelle deler gebruiken. Indien we delen door een macht van twee, kunnen we het getal berekenen met een schuifoperatie (zie Subsectie 3.3.6). Modulo rekenen Een andere populaire berekening is modulo (ook wel bekend als mod ). Modulo-rekening is sterk gerelateerd aan, maar niet equivalent aan remainder-rekenen (ofwel rem). We defini¨eren de remainder als: a rem b ≡ a − ba/bc · b
(3.29)
De modulo-operatie daarentegen houdt rekening met het teken van zowel a als b: a mod b ≡
a rem b if a · b > 0 (a rem b) + b if a · b < 0
(3.30)
Het gevolg is dat het resultaat van een modulo altijd positief is: tussen 0 en abs b − 1. Net als bij andere operaties, is een modulo operatie met een macht van twee een speciaal geval: in dat geval kunnen we een AND operatie uitvoeren op het getal en de macht gedecrementeerd. Bijvoorbeeld: 1653
mod 16 = 1653 AND 15 = 5
(3.31)
3.2. REKENKUNDIGE BASISSCHAKELINGEN
3.2.9
77
Vaste komma getallen
We zullen het getal verder uitbreiden naar getallen met vaste komma en later met getallen vlottende komma. In Subsectie 3.2.11 zullen we ten slotte nog andere voorstellingen van gegevens bespreken. Vaste komma voorstelling (ofwel fixed point) lost het probleem van het zetten van een komma op, door gewoon een bit af te spreken waarna men een komma plaatst, deze positie staat vast. Er is dan ook geen voorstelling van de komma zelf nodig. Indien we dus bijvoorbeeld een 8-bit getal beschouwen, kunnen we de eerste vier bit voorstellen als het geheel deel, de overige vier bit behoren dan tot het fractionele gedeelte. Dit formaliseren we met de notatie fix hi, f i waarbij i het aantal bits voorstellen die tot het gehele deel behoren, en f het aantal bits die men aan het fractionele gedeelte toekent. Zo stelt 11100102 in fix h4, 3i, 14.25 voor. De eerste vier bits stellen immers binair het getal 14 voor, de laatste drie stellen 2 voor, deze delen we vervolgens door 2f wat hier 23 is, bijgevolg heeft het komma-gedeelte de waarde: 2/2f = 2/23 = 2/8 = 1/4 = 0.25. Aantal bits voor fouteloze voorstelling In de vorige secties hebben we al aandacht besteed aan het aantal bits die we moeten reserveren om de resultaten van bewerkingen zonder verlies te kunnen blijven voorstellen. Bij een optelling van vaste vaste komma getallen moet het resultaat voorgesteld worden op een vaste komma voorstelling waarbij we het geheel en fractioneelgedeelte voorstellen met het maximum aantal bits van de operanden. Bovendien dienen we ´e´en bit toe te voegen aan het geheel gedeelte, ofwel formeler: fix hi1 , f1 i + fix hi2 , f2 i = fix hmax (i1 , i2 ) + 1, max (f1 , f2 )i
(3.32)
Wat we verder kunnen veralgemenen tot: n X
n n fix hik , fk i = fix dlog2 ne + max ik , max fk k=1
k=1
k=1
(3.33)
Bij vermenigvuldigingen moeten we het aantal bits optellen van zowel het gehele als fractionele gedeelte: fix hi1 , f1 i · fix hi2 , f2 i = fix hi1 + i2 , f1 + f2 i
(3.34)
Of algemener: n Y
* fix hik , fk i = fix
k=1
3.2.10
n X k=1
ik ,
n X
+ fk
(3.35)
k=1
Vlottende komma getallen
Het kan voorkomen dat we niet weten tot welke grootorde een getal in kwestie zal behoren: het kan bijvoorbeeld tussen 0.000 000 001 en 1 000 000 000 liggen. In dat geval zouden we vaste kommagetallen met een groot aantal bits kunnen gebruiken. Maar in de meeste gevallen zullen slechts een beperkt aantal bits nuttig blijken. In dit soort gevallen kan men beter een getal met vlottende komma voorstelling gebruiken, ook wel zwevendekommagetal, drijvendekommagetal of floating-point number genoemd. Vlottende komma getallen worden voorgesteld door een sequentie van bits die in drie groepen worden onderverdeeld: • sign-bit s ofwel tekenbit s: ´e´en bit die het teken van het getal bepaalt. De vlottende kommavoorstelling werkt dus met de sign-magnitude voorstelling. • exponent E: een getal die bepaalt met hoeveel plaatsen het getal moet worden opgeschoven. Dit deel wordt voorgesteld in het excess-formaat. • mantisse M : het getal onafhankelijk van het schuiven van plaatsen. De voorstelling van een mantisse M met m bits is een fix h1, m − 1i vast komma getal.
78HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) Het getal dat we hierbij willen voorstellen is gelijk aan: s
N = (−1) · mantisse · rexponent
(3.36)
met radix r. Net als bij een vaste komma getal noteren we een familie van vlottende komma getallen met float hm, ei met m het aantal bits van de mantisse en e het aantal bits van de exponent. We maken ook een onderscheid tussen twee families van vlottende komma voorstellingen: • Genormaliseerde vlottende komma voorstelling: hierbij leggen we een extra voorwaarde op betreffende de mantisse: 1 ≤ mantisse < r. In het geval van binaire notatie (r = 2) impliceert dit dus dat de eerste bit altijd 1 is. Daarom wordt in dat geval de eerste bit van de mantisse weggelaten: deze staat er impliciet. In dat geval wordt de mantisse dus voorgesteld als fix h0, mi, maar dient men altijd de virtuele bit 1 tot het gehele gedeelte te rekenen. Deze aanpassing maakt de voorstelling efficienter: de extra bit bij de mantisse bij het fractionele gedeelte drijft de precisie van het formaat op. • Niet-genormaliseerde vlottende komma voorstelling: hierbij is de bovengenoemde beperking dus niet van toepassing. Niet-genormaliseerde vlottende komma getallen kunnen meer getallen voorstellen dan hun tegenhanger, omdat het geheel gedeelte op 0 kan worden gezet. Men betaalt hiervoor echter omdat voor veel getallen er verschillende voorstellingen bestaan. Het gevolg is dat het implementeren van bijvoorbeeld een vergelijker complexer wordt. Underflow en overflow Naast het eerder ge¨ıntroduceerde overflow – het niet voor te stellen van grote getallen – introduceert de vlottende kommavoorstelling nog een bijkomend fenomeen: “ underflow”. Underflow treedt op op het moment dat een getal niet meer voorgesteld kan worden omdat de absolute waarde te klein geworden is. Figuur 3.24 geeft dit fenomeen schematisch weer van een single (zie volgende paragraaf). ≈ −2128
−2−149
2−149
≈ 2128
≈ −2128
−2−126 2−126
≈ 2128
underflow
underflow
Genormaliseerde vlottende komma
Niet-genormaliseerde vlottende komma
Figuur 3.24: Underflow van een vlottende komma voorstelling. Op de figuur worden de getallen die we kunnen voorstellen gemarkeerd met de grijze zone. Bij genormaliseerde vlottende komma getallen, kunnen we enkel getallen tussen −2128 en 2128 voorstellen. Tussen −2−149 en 2−149 kunnen we slechts ´e´en getal voorstellen: 0. Merk op dat de gemarkeerde zone niet continu is: we kunnen bijvoorbeeld constanten zoals π en e niet exact voorstellen, de nauwkeurigheid hangt af van het aantal bits in de mantisse. IEEE-formaat voor vlottende komma getallen Nu we de vlottende komma voorstelling algemeen beschreven hebben, introduceren we enkele concrete getalvoorstellingen met vlottende komma zoals voorgesteld door IEEE20 . IEEE beschrijft hun floating point getallen in IEEE 754-198521 [?]. Men maakt er een onderscheid tussen vlottende komma getallen met enkele precisie (32-bit en beter bekend onder de term float of single) en dubbele precisie (64-bit en beter bekend als double). Tabel 3.6(a) toont de verdeling van de beschikbare bits onder de mantisse en exponent. Elk van deze formaten werkt natuurlijk met radix r = 2. IEEE 754-1985 vermeldt ook hoe een vlottende komma moet worden uitgelezen. Tabel 3.6(b) geeft hierbij weer hoe we het getal moeten interpreteren afhankelijk van de waarde van de exponent E en mantisse M . Bovendien wordt bij de IEEE 754 een extra variabele ingevoerd: de excess-bias B. Tot op heden is B altijd B = 2e−1 − 1, en is de range van de exponent dus van −2e−1 + 2 tot 2e−1 − 1. Eventueel zou men later kunnen afwijken en bijvoorbeeld meer 20 IEEE: 21 De
eerd.
Institute for Electrical and Electronics Engineers. opvolger van deze standaard is IEEE 754-2008[?]. In deze standaard worden ook halve en viervoudige precisie gedefini-
3.2. REKENKUNDIGE BASISSCHAKELINGEN
79
(a) Bit-indeling
Precisie
grootte
e
m
B
float double
32-bit 64-bit
8 11
23 52
127 1023
(b) Getalvoorstelling
M =0 M 6= 0
E=0
0 < E < 2e − 1
0 (−1) × 0.M × 21−B
(−1) × 1.M × 2E−B s (−1) × 1.M × 2E−B
s
s
E = 2e − 1 s
(−1) × ∞ NaN
Tabel 3.7: IEEE 754-1985 Floating Point.
positieve exponenten dan negatieve kunnen toelaten. Men gebruikt de excess voorstelling omdat dit toelaat twee getallen met vlottende komma te vergelijken zoals we een geheel getal vergelijken. We dienen dus geen aparte vergelijker te bouwen voor een vlottend kommagetal. Het formaat definieert ook enkele speciale variabelen: • Nul (0): dit getal kan eigenlijk niet weergegeven worden met ons eerdere definitie van een genormaliseerde vlottende komma. Nul is echter een nuttig getal bij het programmeren: om bijvoorbeeld een neutrale optelling uit te voeren. De getalexperts bij Intel bedachten daarom de regel dat indien E = 0, we het getal in niet genormaliseerde getalvoorstelling zien. Op die manier wordt 0 dus wel mogelijk. • Negatief oneindig −∞/ Positief oneindig +∞: Indien een operatie tot een overflow leidt, zal het resultaat worden voorgesteld als oneindig. Indien de bewerking een teken heeft,kan men dit teken ook worden overge¨erfd in het oneindig resultaat. Oneindig gedraagt zich ongeveer hetzelfde als zijn wiskundig equivalent: bijvoorbeeld het optellen van eender welk getal - behalve oneindig en NaN - met positief oneindig, levert positief oneindig op. • Not a Number (NaN): In tegenstelling tot gehele getallen die bij bijvoorbeeld een deling door nul een fout22 veroorzaken, zullen ongeldige bewerkingen bij de vlottende kommavoorstelling van IEEE 754 resulteren in NaN. We denken dan aan delen door nul, en het verschil van oneindig en oneindig en de vierkantswortel van een negatief getal trekken. In Tabel 3.6(b) zien we ten slotte ook dat enkele bits onderlijnd worden. Dit zijn de zogenaamde verborgen bits. Deze bits zijn geen onderdeel van de mantisse, maar dienen we er wel denkbeeldig aan toe te voegen om het getal te kunnen interpreteren. Rekenen met vlottende komma Het hierboven ge¨ıntroduceerde formaat is relatief complex. Het bouwen van optellers en andere bewerkingen voor deze vlottende-komma voorstellingen is geen sinecure en valt buiten het bereik van deze cursus. We bespreken enkel op hoog niveau hoe we met deze getallen kunnen rekenen. De details kan men vinden in [?, §4]. Het is belangrijk te weten dat IEEE 754 enkel het formaat van vlottende getallen beschrijft. Wiskundige operaties behoren niet tot de standaard: het resultaat van bijvoorbeeld het optellen van twee vlottende komma getallen staat niet vast. Het is dus mogelijk dat op de ene processor een sinus uitrekenen een licht afwijkend resultaat zal opleveren tegenover het resultaat bij een andere processor. Intel heeft bijvoorbeeld gepatenteerde technologie waarbij men de operatoren eerst omzet naar een equivalent met grotere mantisse om meer precisie te garanderen. In de praktijk komt het er dus op neer dat IEEE 754 niet specificeert wat het resultaat moet zijn na een wiskundige bewerking. 22 En
een interrupt bij de meeste processoren.
80HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) Optelling
Het optellen van twee vlottende komma getallen verloopt in drie stappen:
1. Eerst denormaliseren we de twee getallen door de exponenten gelijk te maken. Deze stap is geen sinecure omdat we bij dit proces zoveel mogelijk informatie willen blijven behouden: indien we dus enkel bij ´e´en van de twee getallen de exponent aanpassen, lopen we kans dat zijn mantisse alle informatie verliest. 2. Vervolgens tellen we de twee mantisses met elkaar op. 3. Het resultaat dienen we vervolgens weer te normaliseren: het is immers mogelijk dat het resultaat groter is dan voorstellbaar op de mantisse (of kleiner) in dat geval passen we de exponent aan en schuiven we met de bits op de mantisse. Vermenigvuldiging
Vermenigvuldigen is bij vlottende komma simpeler dan optellen:
1. We vermenigvuldigen de mantisse zoals we dit hebben gedaan bij vermenigvuldigen van natuurlijke getallen. We passen een XOR-operatie toe op de tekenbit van de twee getallen, en we tellen de exponenten met elkaar op23 . 2. We normaliseren het resultaat. Dit betekent dat ofwel de exponent hetzelfde blijft, ofwel met ´e´en moet worden opgehoogd.
3.2.11
Andere voorstellingen van gegevens
Naast de hierboven beschreven voorstellingen voor natuurlijke-, gehele- en kommagetallen bestaan er nog een groot aantal andere voorstellingen. We stellen niet noodzakelijk getallen voor, maar tekst, beelden, geluid, enzovoort. We stellen er in deze subsectie twee voor: Binary Coded Decimal (BCD) is een alternatief formaat om natuurlijke getallen voor te stellen. Dit kan eventueel uitgebreid worden tot geheleen kommagetallen. De American Standard Code for Information Interchange (ASCII) is een formaat dat hoofdzakelijk bedoeld is om tekst op te slaan. Binary Coded Decimal (BCD) In de vorige subsecties hebben we geen aandacht besteed aan het omzetten van een getal naar tekst. Deze omzetting is vrij arbeidsintensief en kost dus ook veel hardware. Bovendien stuiten we op nog een probleem: heel wat decimale kommagetallen kunnen niet voorgesteld worden in het binair getalstelsel. Zo bestaat er geen enkel binaire voorstelling voor 0.3. In dat geval moeten we het getal zo goed mogelijk benaderen24 . Een oplossing voor deze twee problemen is het Binary Coded Decimal (BCD) systeem. We kunnen immers elk decimaal cijfer voorstellen met 4-bit. Bijgevolg kunnen we een decimaal getal voorstellen, door voor ieder cijfer van de decimale voorstelling zijn binair equivalent om te zetten. Dit betekent dus dat we een decimaal getal met n cijfers voorstellen met 4 · n bit. Elk van deze groepen bits kan dus alleen waardes van 0 tot 9 aannemen. Bijvoorbeeld: 142510 = 0101 1001 00012 = 0001 0100 0010 0101BCD . Een nadeel van BCD voorstelling is dat de meeste bewerkingen complexer worden. Tabel 3.8 toont de omzetting van een decimaal cijfer naar het BCD equivalent. Bewerkingen met BCD Ter illustratie zullen we tonen hoe we een opteller kunnen realiseren voor het BCD formaat. Hierbij streven we niet zozeer naar een minimale implementatie, maar tonen we dat een optelling complexer is tegenover zijn binair equivalent. Bij een optelling dienen we immers elke decimaal afzonderlijk op te tellen. Net zoals een half- en full adder bit per bit optelden, dienen we nu per decimaal een 4-bit opteller te realiseren. Indien het resultaat van deze optelling bovendien groter is dan 9, dienen we dit resultaat verder aan te passen: we trekken er 10 vanaf en we geven overdacht (carry) door. Bij de aftrekking hebben we dus nogmaals een 4-bit opteller nodig. We dienen ook een component te realiseren dat controleert of het eerste resultaat groter is dan 9. Deze component heeft niet alleen een carry als uitgang, 23 Optellen
bij het excess-formaat verloopt anders, we dienen immers ´ e´ enmaal de excess-bias van de som af te trekken. is echter niet omdat het binair stelsel er niet in slaagt om alle decimale getallen voor te stellen dat het minder accuraat is, integendeel: het binair stelsel is accurater. 24 Het
3.3. ANDERE BASISSCHAKELINGEN
81
Dec.
BCD
Dec.
BCD
0 1 2 3 4
0000 0001 0010 0011 0100
5 6 7 8 9
0101 0110 0111 1000 1000
Tabel 3.8: Decimale cijfers en hun BCD equivalent. x3 x2 x1 x0 y3 x3
x2
c
y2
y1
y0
x1
x0
y3
y2
y1
y0
s3
s2
s1
s0
4-bit opteller z3
z2
>9
0
z0
0 x2
x1
x0
y3
y2
s3
s2
s1
s0
s3
s2
s1
s0
4-bit opteller
y1
y0
(a) Schematische voorstelling
z3
x3
co
c z1
z1 0 0 1 0
0 0 1 1
0 0 1 1
0 0 1 0 z0
-
1 -
c
1 1 - - - -
z3 z2
z2
co
z1
ci
z0
(b) Karnaugh-kaart
z1 z0
co
(c) Implementatie vergelijker
Figuur 3.25: Mogelijke implementatie van een BCD opteller. maar moet ook invoer genereren voor de tweede opteller. Indien het eerste resultaat immers groter is dan 9, tellen we er nog eens 6 bij op. Dit betekent dat bij een tussenresultaat van 10, de tweede opteller tot 16 komt wat dus gebaseerd op de laatste 4 bits in 0 resulteert. Figuur 3.25(a) toont schematisch hoe we twee decimale cijfers kunnen optellen. Indien we deze structuur voor ieder cijfer herhalen, realiseren we een BCD opteller. De vergelijker synthetiseren we met behulp van Karnaugh-kaarten zoals op Figuur 3.25(b). Merk op dat het resultaat van de eerste opteller hoogstens 18 is, en we dus voor de andere waarden don’t cares kunnen gebruiken. Een mogelijke synthese van deze vergelijker staat op Figuur 3.25(c). Tot slot merken we op dat we bij het bepalen van het negatieve getal van een BCD niet het 2-complement moeten berekenen, maar het 10-complement. Ook deze stap vereist extra hardware. American Standard Code for Information Interchange (ASCII) Een standaard om tekst voor te stellen is de American Standard Code for Information Interchange (ASCII). ASCII reserveert 7 bit per karakter in de tekst. Deze zeven bit zorgen dus voor 128 mogelijke karakters. De karakterset bestaat uit de Romaanse letters, Arabische cijfers, diverse leestekens en enkele functiesymbolen. De toewijzing van deze symbolen vertoont enige logica. Zo is het bijvoorbeeld eenvoudig om kleine letters om te zetten naar de equivalente hoofdletter, of bijvoorbeeld binaire getallen in hun ASCII equivalent. Tabel 3.9 toont de ASCII-karakters met hun bijbehorende binaire code. ASCII bevat geen ondersteuning voor karakters in het Cyrillische en Arabische geschrift. Unicode is een standaard die 8, 16 of 32 bit per karakter reserveert om dit probleem op te lossen. Anno 2011 is 11% van de binaire waarden toegewezen.
3.3
Andere basisschakelingen
Naast de rekenkundige schakelingen in Sectie 3.2 zullen we in schema’s ook geregeld enkele andere bouwstenen terugvinden. In deze sectie zullen we de meest voornaamste bespreken: In Subsectie 3.3.1 bespreken we de multiplexer. Daarna bespreken we in Subsectie 3.3.2 en Subsectie 3.3.3 twee verwante bouwstenen: de decoder en demultiplexer. Het omgekeerde van de decoder, de encoder behandelen we in Subsectie 3.3.4. We eindigen met de vergelijker in Subsectie 3.3.5 en de reeds aangehaalde schuifoperatie in subsectie Sub-
82HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
000 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
001 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
010 SP ! " # $ % & ’ ( ) * + , . /
011 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
100 @ A B C D E F G H I J K L M N O
101 P Q R S T U V W X Y Z [ \ ] ^ _
110 ‘ a b c d e f g h i j k l m n o
111 p q r s t u v w x y z { | } ~ DEL
Tabel 3.9: ASCII standaard. sectie 3.3.6.
3.3.1
Multiplexer
Een multiplexer, selector of MUX is een component die bij n selectie-ingangen si en 2n data-ingangen di heeft en een uitgang f . Een multiplexer zet de waarde van de data-ingang dS met index S op de uitgang. Hierbij is S de binaire waarde die wordt voorgesteld door de selectie-ingangen si . In een blokschema wordt deze component voorgesteld door een trapezium waarbij de data-ingangen aan de lange zijde staan, de uitgangen aan de korte zijde, en de selectie-ingangen aan ´e´en van de schuine zijden zoals op Figuur 3.26(a). Deze figuur toont een 4-naar-1 MUX. Eventueel worden aan de andere kant ook uitgangen toegevoegd, deze zijn identiek aan de selectie-ingangen aan de ene kant en dienen enkel om het blokschema overzichtelijker te maken. Figuur 3.26(b) en Figuur 3.26(c) tonen respectievelijk de eerder informeel besproken waarheidstabel en een mogelijke implementatie van deze component. Multiplexers worden gebruikt wanneer we de keuze hebben tussen twee bronnen en we - afhankelijk van een bepaald criterium - een van de twee bronnen moeten doorgeven aan een ander component. Cascade Voor elke willekeurige n kunnen we dus een 2n -naar-1 multiplexer bouwen. Een fabrikant zal meestal echter voor een beperkt aantal waarden voor n een multiplexer bouwen, immers wenst men dit te doen in massaproductie. Daarom zal men veelal met een cascade werken. Figuur 3.26(d) toont een 16-naar-1 MUX gebouwd met behulp van vijf 4-naar-1 multiplexers. We kunnen dit uiteraard veralgemenen: Indien we een 2n×m -naar-1 multiplexer willen bouwen, kunnen we dit met n niveaus van 2m -naar-1 multiplexers. Het aantal multiplexers die we in dat geval nodig hebben is: aantal multiplexers =
3.3.2
2n·m − 1 2m − 1
(3.37)
Decoder
Een andere schakeling die sterk gerelateerd is aan een multiplexer is een decoder. Een decoder beschikt over een enable-ingang e, en n adres-ingangen ai . De uitvoer bestaat uit 2n selectie-uitgangen si . Een decoder zal, indien er een 1 aangelegd wordt op de enable-ingang e, een 1 op de selectie-uitgang sA zetten met index A. Hierbij staat A voor de binaire waarde die voorgesteld wordt door de adres-ingangen ai , alle overige
3.3. ANDERE BASISSCHAKELINGEN
83 d3
d3 d2 d1 d0 s1 s0
s1 s0 f
(a) Interface
s0 0 0 1 1
s1 0 1 0 1
f d0 d1 d2 d3
d1
d0
s1
s1
s0
s0
f
(b) Waarheidstabel d15 d14 d13 d12
d2
(c) Mogelijke Implementatie d11 d10 d9 d8
d7 d6 d5 d4
d3 d2 d1 d0
s1 s0
s3 s2 f
(d) Cascade
Figuur 3.26: Multiplexer. selectie-uitgangen si zijn dan 0. Wanneer bovendien op de enable-ingang e een 0 wordt gezet, zullen alle selectie-uitgangen si op 0 staan. In een blokschema wordt een decoder voorgesteld zoals op Figuur 3.27(a) door een rechthoek. In dit geval een 2-naar-4 decoder. Bovenaan staan de adres-ingangen ai , aan de zijkant de enable-ingang e, en onderaan de uitgangen si . Op Figuur 3.27(b) staat de waarheidstabel voor deze component. Figuur 3.27(c) toont een mogelijke implementatie. Decoders worden hoofdzakelijk gebruikt voor het decoderen van adressen. Dit is nuttig bij geheugens zoals register-banken en RAM-geheugens. Cascade Net als bij multiplexer kunnen we, in plaats van een heel arsenaal aan decoders aan te bieden, door middel van een cascade een nieuwe decoder bouwen, zoals op Figuur 3.27(d). Hier bouwen we een 4-naar-16 decoder met vijf 2-naar-4 decoders. In het algemeen kunnen we een n · m-naar-2n·m decoder bouwen met n niveaus van m-naar-2m decoders. In totaal hebben we dus volgend aantal decoders nodig: aantal decoders =
2n·m − 1 2m − 1
(3.38)
Alternatieve implementatie voor multiplexers Decoders worden soms gebruikt bij de synthese van bijvoorbeeld multiplexers. Figuur 3.28(a) toont een manier om op basis van AND-poorten en een decoder een multiplexer te bouwen. Een alternatief waarbij we de OR-poort weglaten en de AND-poorten vervangen door 3-state buffers zoals is te realiseren zoals op Figuur 3.28(b). In dat geval hebben we een schakeling gerealiseerd die we een bus noemen. Bussen zijn multiplexers waarbij we toelaten dat de ingangen gedistribueerd zijn over de verschillende delen van de schakeling. Elk van deze ingangen dienen we eenvoudigweg een uitgang van de decoder toe toe te wijzen, en de uitgang met een 3-state buffer verbinden met de bus. Bussen hebben verschillende voordelen: • We kunnen makkelijk het aantal ingangen uitbreiden. We dienen enkel over een decoder met voldoende grote n te beschikken en een tri-state buffer per ingang;
84HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) a1
a1 e
e 0 1 1 1 1
a0
Decoder s3 s2 s1 s0
a0 0 0 1 1
(a) Interface
a1 0 1 0 1
s0 0 1 0 0 0
s1 0 0 1 0 0
s2 0 0 0 1 0
s3 0 0 0 0 1
Decoder
e
s3
(b) Waarheidstabel
a1
a0
a1
s2
s1
s0
(c) Mogelijke implementatie a3
e
a0
a2
Decoder a0
a1
a0
a1
a0
Decoder
Decoder
Decoder
Decoder
s15s14s13s12
s11s10 s9 s8
s7 s6 s5 s4
s3 s2 s1 s0
(d) Cascade
Figuur 3.27: Decoder. • indien we de traditionele multiplexer gebruiken zal bij een groot aantal ingangen de fan-in van de OR-poort toenemen. Bovendien moeten alle ingangen van de multiplexer dicht bij elkaar staan; en • tri-state buffers zijn meestal gratis op een FPGA. Elke logisch blok (LB) heeft immers minstens ´e´en uitgang langs een tri-state buffer die verbonden is met een lange lijn.
s0
d1
d0
d3
s1
Decoder
s1
d2
s0
1
d2
d1
1 f
(a) Muliplexer
d0
Decoder
d3
bus f
(b) Bus
Figuur 3.28: Multiplexer en bus gesynthetiseerd met decoders.
3.3.3
Demultiplexer
Het inverse van een 2n -naar-1 multiplexer is een 1-naar-2n demultiplexer (ook wel demux genoemd). Deze component bestaat dan ook logischerwijs uit ´e´en data-ingang d en n selectie-ingangen ai . De component beschikt verder over 2n uitgangen si . Logischerwijs zetten we de waarde van de data-ingang d op de uitgang sA met de index A die binair wordt voorgesteld door de selectie-ingangen ai . Een aandachtige lezer zal misschien al opgemerkt hebben dat dit probleem in wezen niet veel verschilt van de constructie van een decoder. Sterker nog, we hoeven geen nieuw component te ontwerpen. Een demultiplexer is een decoder, maar met een andere interface. Figuur 3.29 toont de interface van een demultiplexer en de equivalentie met een decoder. In tegenstelling tot de decoder zetten we de selectie-ingangen aan de zijkant en de data-ingang
3.3. ANDERE BASISSCHAKELINGEN
85
aan de bovenkant. Meestal zullen we ook specifiek andere “taken” toekennen aan een demultiplexer tegenover een decoder, maar achter de schermen werken we met dezelfde logica. a1
d a1 a0
≡
Demux
a0
Decoder
d
s3 s2 s1 s0
s3 s2 s1 s0
Figuur 3.29: Demultiplexer
Demultiplexers worden maar zeer zelden gebruikt, kun doel is immers om data op een bepaalde lijn te plaatsen, terwijl men op de andere lijnen een 0 aanlegt. In de praktijk is het aanleggen van de data op alle lijnen meestal geen probleem. In dat geval kunnen we dus de demultiplexer eenvoudigweg vervangen door een draad die de data-ingang met alle uitgangen verbindt.
3.3.4
Encoder en prioriteitsencoder
Ook de decoder heeft een inverse: een 2n -naar-n encoder. Een encoder bevat 2n data-ingangen di , een anyuitgang a en n selectie-uitgangen si . Het is de bedoeling dat de encoder, afhankelijk van de data-ingang waarop een 1 staat, de index van deze data-ingangg weergeeft op de selectie-uitgangen fi . De any-uitgang is 1 op het moment dat er ´e´en data-ingang de waarde 1 heeft, en 0 indien er op geen enkele data-ingang een 1 staat. We kunnen dit gedrag samenvatten in een waarheidstabel zoals in Tabel 3.9(a) voor een 4-naar-2 encoder. (b) Prioriteitsencoder
(a) Encoder
d3
d2
d1
d0
a
f1
f0
d3
d2
d1
d0
a
f1
f0
0 0 0 0 1 -
0 0 0 1 0 -
0 0 1 0 0 -
0 1 0 0 0 -
0 1 1 1 1 -
0 0 1 1 -
0 1 0 1 -
0 0 0 0 1
0 0 0 1 -
0 0 1 -
0 1 -
0 1 1 1 1
0 0 1 1
0 1 0 1
Tabel 3.10: Waarheidtabellen van een encoder en prioriteitsencoder. Merk op dat de tabel niet alle strikt mogelijke ingangen toont. We nemen aan dat aan de ingangen enkel geldige configuraties verschijnen. Indien dit niet zo is, staat het in principe vrij om te kiezen wat er op de uitgangen verschijnt. De ontbrekende rijen bevatten dus don’t cares op alle uitgangen. Op basis van deze tabel kunnen we eventueel Karnaugh-kaarten maken en een implementatie voorstellen: a = d3 + d2 + d1 + d0 f1 = d3 + d1 f0 = d3 + d2
(3.39)
We kunnen deze schakeling dus eenvoudig realiseren met ´e´en OR-poort per uitgang. Prioriteitsencoder Een variant van de encoder is de prioriteitsencoder. Een prioriteitsencoder biedt een antwoord op de ongeldige ingangen van de encoder. Hierbij telt niet d´e index van de data-ingang waarop een 1 wordt aangelegd, maar de hoogste index van alle data-ingangen met 1. Tabel 3.9(b) formaliseert dit. Deze schakeling kunnen we dan als volgt implementeren:
86HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
a = d3 + d2 + d1 + d0 f1 = d3 + d02 d1 f0 = d3 + d2
(3.40)
Dit komt overeen met ´e´en extra AND- en NOT-poort. De interface voor beide schakelingen staat beschreven op Figuur 3.30(a). d3 d2 d1 d0
a
Encoder f1
d3 d2 d1 d0
a
f0
Prioriteitsencoder f1
f0
(a) Interfaces
a
d15 d14 d13 d12
d11 d10 d9 d8
d7 d6 d5 d4
d3 d2 d1 d0
Prioriteitsencoder
Prioriteitsencoder
Prioriteitsencoder
Prioriteitsencoder
f1
f0
Prioriteitsencoder
f3
f2
(b) Cascade
Figuur 3.30: Encoder en Prioriteitsencoder. De interface is opnieuw een rechthoek. De data-ingangen staan bovenaan, de selectie-uitgangen onderaan, en de any-uitgang aan de linkerkant. Prioriteitsencoders cascaderen Ook bij prioriteitsencoders gaan we even in het op het cascaderend karakter. Ook encoders laten zich eenvoudig cascaderen, mits we ook extra multiplexers gebruiken. In Figuur 3.30(b) bouwen we een 16-naar-4 prioriteitsencoder met vier 4-naar-2 prioriteitsencoders en twee 4-naar-1 multiplexers.
3.3.5
Vergelijker
Een vergelijker of comparator is een component die in staat is om uitspraken te doen over hoe twee getallen zich tot elkaar verhouden. Meestal is een vergelijker in staat om een uitspraak te doen over vier mogelijke verhoudingen van de getallen X en Y : X X X X
Y =Y 6= Y
(3.41)
3.3. ANDERE BASISSCHAKELINGEN
87
Op basis van de eerste twee relaties, kunnen we uitspraken doen over de laatste twee25 . We kunnen dus een component bouwen die enkel de eerste twee uitspraken naagaat. Een comparator bevat 4 ingangen (x0 ofwel gin , y0 ofwel lin , x1 en y1 ). De twee uitgangen (g en l) geven respectievelijk weer of het getal X > Y en X < Y . Figuur 3.31(a) toont de interface van een vergelijker. g
x0 /gin y0 /lin
0 0 0 1
0 1 0 0
0 1 0 0
0 1 0 0
y0
(a) Interface
g l
0 0 0 1
1 1 1 0
y1
Comp
1 0 1 1
x1
l
x1
g
0 0 0 1
x0
l
y1
x1 y1
x0
y0
(b) Karnaugh-kaarten
x7 y7
x6 y6
x5 y5
x4 y4
x3 y3
x2 y2
x1 y1
Comp
Comp
Comp
Comp
Comp
Comp
Comp
x2 y2
x1 y1
x0 y0
(c) Lineare cascade x7 y7 Comp
Comp
g l
x6 y6
x5 y5 Comp
x4 y4
x3 y3 Comp
x0 y0
Comp
Comp
Comp
(d) Hi¨ erarchische cascade
Figuur 3.31: Vergelijker Op basis van de gedragsbeschrijving kunnen we een waarheidstabel en Karnaugh-kaarten opstellen zoals op Figuur 3.31(b). Op basis van deze kaarten synthetiseren we volgende formules26 : g = x1 y10 + x0 x1 y00 + x0 y00 y10 (3.42) l = x01 y1 + x00 x01 y0 + x00 y0 y1 Vergelijkers cascaderen Deze vergelijker vergelijkt enkel getallen die uit twee bits bestaan. In de praktijk is dit niet nuttig. Net als bij een opteller zullen we echter een methode uitwerken om met deze bouwstenen grotere getallen te vergelijken. Net als bij een ripple-carry opteller, kunnen we door verschillende vergelijkers aan elkaar te schakelen, een vergelijker met een groter aantal bits bouwen. In dat geval bekomen we een structuur zoals op Figuur 3.31(c). Zonder deze schakeling in detail te bestuderen komen we echter tot hetzelfde probleem als bij een ripple-carry opteller: de vertraging schaalt linear met het aantal bits, wat voor getallen met een groot aantal bits onaanvaardbaar is. We kunnen de vergelijkers echter ook in een hi¨erarchische structuur organiseren, waardoor we de vertraging beperken tot een logaritmische orde zoals op Figuur 3.31(d). Merk 25 Een
getal X is niet gelijk aan een getal Y indien X < Y of X > Y . de dualiteit op: beide formules hebben dezelfde variabelen, alleen zijn alle atomen ge¨ınverteerd.
26 Merk
88HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) op dat we eenzelfde hoeveelheid hardware gebruiken. Deze schakeling laat echter toe om verschillende delen van het getal tegelijk te vergelijken. Speciale gevallen Testen op gelijkheid We kunnen twee getallen altijd vergelijken met een vergelijker zoals eerder beschreven. Soms willen we echter ´e´en of twee getallen testen op specifieke eigenschappen, bijvoorbeeld of twee getallen gelijk zijn. Dit kunnen we natuurlijk realiseren met een vergelijker, maar dit introduceert extra hardware en vertraging. In het geval van gelijkheid kunnen we dan ook gebruik maken van een rij van XNOR-poorten waarbij elke poort ´e´en bit van het ene en ´e´en bit van het andere getal als invoer krijgt. De uitgangen van al deze XNOR-poorten vormen vervolgens de invoer voor een AND-poort gaan. De uitvoer van deze AND poort toont ons dan of X gelijk is aan Y . Figuur 3.32(a) toont een realisatie van dit concept voor twee n-bit getallen. xn−1yn−1
x4 y4 x3 y3 x2 y2 x1 y1 x0 y0
xn−1 ... x x2 x01
X=0
xn−1 ... xk+2 xk+1 xk
X ≥ 2k
xn−1 ... xk+2 xk+1 xk
X < 2n − 2k
... xn−1 ... x2 x1 x0
X = 2n − 1
x0
X=Y
(a) Gelijkheid
even (X)
x0
oneven (X)
(b) Testen met constanten
Figuur 3.32: Speciale gevallen van vergelijkers
Vergelijken met constanten We willen een getal niet altijd vergelijken met andere getal, maar soms met een constante. In dat geval zouden we natuurlijk ook van de vergelijker kunnen gebruikmaken, en de Y zelf samenstellen. Aangezien Y echter op voorhand gekend is spreekt het voor zichzelf dat we de implementatie echter grondig kunnen verbeteren. Bovendien kunnen we ook testen ontwerpen die we niet kunnen uitvoeren met een vergelijker27 . Dergelijke componenten kunnen bouwen getuigt ook van enig inzicht. Alle speciale gevallen beschouwen is moeilijk. Op Figuur 3.32(b) geven we enkele voorbeelden. Deze opsommig is verre van exhaustief en het verklaren van deze schakelingen wordt aan de lezer overgelaten.
3.3.6
Schuifoperator
Een laatste set van operaties die vaak gebruikt wordt zijn schuifoperaties. Vele processoren implementeren schuifoperaties. Een ARM processor laat bijvoorbeeld toe om tijdens elke operatie de operand over enkele plaatsen te schuiven. Er bestaan verschillende vormen van schuifoperaties, Daarom zullen we in deze paragraaf eerst de verschillende varianten bespreken. In het algemeen houdt een schuifoperatie in dat de waarde van de bit die eerst op plaats i stond, nu op een plaats i + m staat. Of formeler: Y is het resultaat van een schuifoperatie van X over m plaatsen naar links indien ∀i ∈ N : i ∈ [0, n] ∧ i + m ∈ [0, n] ⇒ yi+m = xi
(3.43)
De definitie toont al dat i en i + m beide binnen het bereik moeten liggen. Wat we doen met de bits die buiten de grenzen vallen, en met wat we de nieuwe plaatsen opvullen, wordt niet door Vergelijking (3.43) 27 Bijvoorbeeld
deelbaarheid door 2.
3.3. ANDERE BASISSCHAKELINGEN
89
gespecificeerd. Een tweede opmerking is dat m ook negatief kan zijn, in dat geval voeren we een schuifoperatie naar rechts uit. Voor dit probleem bestaan er drie populaire oplossingen, de varianten van de schuifoperaties. • Bij het schuiven negeren we de bits die buiten de grenzen vallen. Er bestaan twee vormen van schuiven die vari¨eren in wat we op de vrijgekomen plaatsen zetten: – Logisch schuiven: indien we logisch schuiven hebben we een extra parameter nodig, namelijk welke waarde we op de nieuwe plaatsen zetten. Soms is dit zelfs een rij van bits. We maken dus de invoer groot genoeg om geen vrije plaatsen meer over te houden. Logisch schuiven wordt in de C/C++/Java taalfamilies vaak voorgesteld met de operatoren <<< en >>>. – Aritmetisch schuiven: hierbij willen we eigenlijk een wiskundige functie realiseren namelijk vermenigvuldigen of delen met een macht van 2. Hoe we dus aritmetisch schuiven hangt vooral af van de getalvoorstelling. Indien we naar links schuiven betekent dit meestal dat we de nieuwe plaatsen vullen met nullen. Indien we naar rechts schuiven zal bij een 2-complement voorstelling de hoogste bit (MSB) van het originele getal ingevoegd worden. Bij een “unsigned” voorstelling vullen we de vrije plaatsen ook met nullen op. Aritmetisch schuiven is vrij populair in programmeertalen. Programmeertalen die tot de C/C++/Java taalfamilie behoren, introduceren daarom 2 functies: voor links (<<) en rechts (>>) aritmetisch schuiven deze worden gedefinieerd als:
X<>M ≡ X ÷ 2M
(3.44)
Men kan meestal niet schuiven met een negatieve M . De richting van schuiven dient men dus op voorhand te kennen. • Bij het roteren vangen we de bits op die er langs ´e´en kant afvallen en plaatsen we deze op de vrijgekomen plaatsen aan de andere kant. Implementatie van schuifoperaties In deze subsubsectie zullen we twee schakelingen realiseren. De eerste is een component die alle schuifoperaties kan realiseren op 4-bit getallen, maar slechts over ´e´en plaats naar links of rechts. Het tweede component is 8-bit barrel left rotator. Dit component roteert 8-bit getallen naar links over een variabel aantal plaatsen. Merk op dat het bij een rotatie het eigenlijk niet uitmaakt in welke richting we roteren: een n-bit getal m plaatsen naar links roteren is net hetzelfde als het getal n − m plaatsen naar rechts roteren. Deze tweede component illustreert verder hoe we schuifoperaties effici¨ent over meerdere posities kunnen uitvoeren. Schuifoperaties over 1 bit Indien we een component maken die meerdere operaties kan uitvoeren moeten we altijd eerst een instructieset defini¨eren, net zoals we dat ook deden in in Subsubsectie 3.2.6. De instructieset dient zowel een onderscheid te maken tussen schuiven of roteren, aritmetisch of logisch28 en links of rechts. Verder willen we ook een bit voorzien die aangeeft of er u ¨berhaupt een schuifoperatie moet worden uitgevoerd: een soort enable-ingang. We zullen dus een 4-bit instructieset gebruiken. Tabel 3.11 toont de betekenis van elke bit. Op basis van deze instructieset kunnen we nu een component bouwen. Voor de Signaal
0
1
s3 s2 s1 s0
geen schuifoperatie links schuiven aritmetisch
schuifoperatie rechts roteren logisch
Tabel 3.11: Instructieset voor de schuifoperaties over 1 bit. berekening van de uitgangsbits gebruiken we multiplexers. Immers kan elke uitgang yi maar drie mogelijke 28 Enkel
in geval van schuiven is dit relevant.
90HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN) uitgangen hebben: xi−1 , xi en xi+1 . Bij de uitgangen aan de rand dienen we alleen een andere interpretatie voor sommige xj te vinden. Welke van deze drie ingangen we kiezen hangt verder alleen af van twee bits uit het instructiewoord: s3 en s2 . In het geval dat s3 = 0 geldt yi = xi . Bijgevolg zetten we xi zowel op de d0 en d1 ingang van de multiplexer voor yi . Indien s3 = 1 en s2 = 0 schuiven we naar links. We zetten dus xi+1 en xi−1 respectievelijk op de d2 en d3 ingangen. Tot slot dienen we nog de randgevallen op te lossen. Deze randgevallen beslaan enkel xi+1 voor y3 en xi−1 voor y0 . Deze waarden zullen we respectievelijk noteren als x4 en x−1 en vallen dus buiten de grenzen van de ingangen. In geval van rotatie geldt: x−1 = x3 (rotatie) (3.45) x4 = x0 Dit dwingen we af met twee 2-naar-1 multiplexers. Deze multiplexers hebben als schakelelement instructiebit s1 . We dienen nu enkel nog het geval te behandelen waarin we schuiven. Indien we logisch schuiven, schuiven we de bits Lin en Rin in. Bij arithmetisch zullen we aan de rechterzijde een 0 inschuiven. Aan de linkerkant is dit ook het geval tenzij we schuiven met een 2-complement voorstelling. In dat laatste geval bepaalt de hoogste bit immers ook het teken van het getal. In dat geval moeten we de waarde van de hoogste bit dus nogmaals inschuiven. We kunnen bovenstaande beschrijvingen formaliseren tot volgende formules: x−1 = Rin (schuiven, aritmetisch) x4 = Lin
x−1 = 0 x4 = 0
(schuiven, logisch, unsigned)
x−1 = 0 x4 = x3
(schuiven, logisch, 2-complement)
(3.46)
Lin
2-comp
Deze logica kunnen we vervolgens implementeren met OR-AND-poorten. Het resultaat van deze volledige implementatie staat op Figuur 3.33.
x3
x2
x1
x0
Rin
s0
s1
s3 s2 y3
y2
y1
y0
Figuur 3.33: Implementatie van een schuifoperator over 1 bit.
8-bit barrel left rotator In de vorige paragraaf hebben we een schuifoperator gebouwd die over 1 bit kan schuiven. Door verschillende van deze schuifoperatoren na elkaar te plaatsen kunnen we schuiven over meerdere plaatsen. Toch is dit niet erg praktisch: om m plaatsen te schuiven zouden we m van deze schuifoperatoren na elkaar moeten plaatsen, wat grote vertragingen zou impliceren. In deze paragraaf zullen we een rotator bouwen die de vertraging beperkt tot log2 m, met m het maximaal aantal plaatsen dat kan opgeschoven worden. Het concept is toepasbaar op algemene schuifoperaties, dus ook bijvoorbeeld logisch schuiven. Figuur 3.34 geeft het concept weer.
3.3. ANDERE BASISSCHAKELINGEN x7
x6
91 x5
x4
x3
x2
x1
x0
s2
s1
s0 y7
y6
y5
y4
y3
y2
y1
y0
Figuur 3.34: Implementatie van een 8-bit barrel left rotator. Deze barrel left rotator is gebaseerd op het additief principe. Het additief principe stelt dat indien we een getal willen schuiven of roteren over m bits, we dit ook kunnen verwezenlijken door eerst te schuiven/roteren over m1 bits en vervolgens over m2 bits met m = m1 + m2 . Indien we onze rotator bouwen volgens een structuur waarbij elke niveau i een rotatie uitvoert over 2i plaatsen kunnen we elke rotatie-operatie uitvoeren. Gedurende dit hoofdstuk hebben we immers alle getallen binair kunnen voorstellen. Op Figuur 3.34 zien we dat het niveau s2 , vier plaatsen naar links roteert. Het volgende niveau twee en het laatste ´e´en. Elk van deze niveaus heeft dezelfde vertraging. Indien we dus een n-bit barrel left rotator willen bouwen die maximaal m plaatsen kan opschuiven moeten we dus dlog2 me niveaus synthetiseren. Een niveau i roteert 2i plaatsen voor ∀i = 0, 1, . . . , dlog2 me − 1. Dit concept is eenvoudig te veralgemenen naar een volledige schuifoperator. Merk op dat het aantal niveaus dus theoretisch niet afhangt van het aantal bit in het getal. Op de meeste processoren neemt men echter m = n. Een andere mooie eigenschap is dat de volgorde van de niveaus niet relevant is.
92HOOFDSTUK 3. COMBINATORISCHE SCHAKELINGEN (SCHAKELINGEN ZONDER GEHEUGEN)
Hoofdstuk 4
Sequenti¨ ele Schakelingen (Schakelingen met geheugen) denken dat sommige mensen intelligent zijn, terwijl ze al“ We leen maar een goed geheugen hebben. - Fr´ed´eric Dard, Frans humoristisch schrijver (1921-2000)
”
In het vorige hoofdstuk hebben we combinatorische schakelingen gebouwd: schakelingen waarbij de waardes op de uitgangen enkel afhangen van de waardes die op de ingangen staan. Bij de meeste schakelingen is er echter sprake van geheugen: een component die een toestand kan bijhouden. Afhankelijk van de invoer verandert de toestand en de uitvoer hangt af van de toestand van het component en de waardes die op de ingangen staan. In dit hoofstuk introduceren we hier eerst de nodige terminologie voor waarna we een reeks componenten ontwikkelen om gegevens op te slaan. Daarna bespreken we hoe we componenten met geheugen kunnen ontwerpen. We maken hierbij een onderscheid tussen synchrone sequenti¨ele schakelingen: schakelingen met een klok, en asynchrone sequenti¨ele schakelingen: schakelingen waarbij een verandering aan de invoer de oorzaak is van de verandering van toestand. 4.1
Terminologie . . . . . . . . . . . . . . . . . . . 4.1.1 Classificatie van sequenti¨ele schakelingen . . . 4.1.2 Terminologie van het kloksignaal . . . . . . . 4.2 Bouwblokken . . . . . . . . . . . . . . . . . . . 4.2.1 De flipflop . . . . . . . . . . . . . . . . . . . . De latch . . . . . . . . . . . . . . . . . . . . . De flipflop . . . . . . . . . . . . . . . . . . . . Types flipflops . . . . . . . . . . . . . . . . . 4.2.2 Registers . . . . . . . . . . . . . . . . . . . . 4.2.3 Tellers . . . . . . . . . . . . . . . . . . . . . .
93
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . .
. 94 . 95 . 95 . 95 . 96 . 96 . 99 . 101 . 103 . 104
94
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) 4.3
Synchrone schakelingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 4.3.1
Leidende voorbeelden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.3.2
Stap 1: opstellen van het toestandsdiagram . . . . . . . . . . . . . . . . . . . . . . 108
4.3.3
Stap 2: Minimaliseren van de toestanden . . . . . . . . . . . . . . . . . . . . . . . 110 Het minimalisatiealoritme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Omzetting naar een toestandsdiagram en -tabel . . . . . . . . . . . . . . . . . . . . 112
4.3.4
Stap 3: Implementeren van de toestanden in het geheugen . . . . . . . . . . . . . . 113 Stap 3A: Coderen van de toestanden . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Stap 3B: De keuze van het type flipflop . . . . . . . . . . . . . . . . . . . . . . . . 115
4.3.5
Stap 4: Implementeren van de combinatorische logica . . . . . . . . . . . . . . . . 116 Stap 4A: Logica die de volgende toestand berekent . . . . . . . . . . . . . . . . . . 117 Stap 4B: Logica die de uitgang toestand berekent . . . . . . . . . . . . . . . . . . . 120
4.3.6
Tijdsgedrag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Leidend voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
4.4
Asynchrone schakelingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.4.1
Leidend voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4.4.2
Stap 1: Opstellen van een toestandstabel . . . . . . . . . . . . . . . . . . . . . . . 124
4.4.3
Stap 2: Minimaliseren van de toestanden . . . . . . . . . . . . . . . . . . . . . . . 125
4.4.4
Stap 3: Codering van de toestanden . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Terminologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Elimineren van critical races . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 Methode 1: Zoeken naar een goede codering . . . . . . . . . . . . . . . . . . . . . . 132 Methode 2: Gebruik maken van een tussentoestand . . . . . . . . . . . . . . . . . . 134 Methode 3: Invoeren van extra overgangstoestand . . . . . . . . . . . . . . . . . . 136 Initi¨ele toestand (bis) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.4.5
Stap 4: Realisatie met digitale logica . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Hazards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Hazards en Karnaugh-kaarten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Realisatie leidend voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Problemen ten gevolge van skew op ingangen . . . . . . . . . . . . . . . . . . . . . 141
4.4.6
4.1
Besluit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Terminologie
Een sequenti¨ ele schakeling is een schakeling waarbij niet alleen de ingangen X van belang zijn, maar ook de toestand van deze schakeling. De toestand S wordt bepaald door de ingang, en door de vorige toestand Sprev. . In de wiskunde wordt een dergelijke constructie beschreven als een eindige-toestanden machine of finite state machine (FSM). Om dit te verwezenlijken hebben we een geheugencomponent nodig, een component die de toestand bijhoudt. Dit kunnen we bijvoorbeeld verwezenlijken met een condensator. In DRAM geheugens wordt dergelijke implementatie gebruikt. Het probleem met een condensator is dat de lading na verloop van tijd verloren gaat, wat tot dynamische logica leidt. In DRAM wordt dit opgelost door de condensatoren in kwestie terug op te laden. Een alternatief zijn componenten met positieve terugkoppeling, doorgaans zijn deze bekend als flipflop of register. In Sectie 4.2 zullen we verschillende van deze bouwblokken bespreken.
4.2. BOUWBLOKKEN
4.1.1
95
Classificatie van sequenti¨ ele schakelingen
classificationSequential Doorgaans kunnen we sequenti¨ele schakelingen onderverdelen volgens twee classificatiesystemen: gebaseerd op de uitgangsfunctie F , en de synchroniciteit van de schakeling. Wat betreft de uitgangsfunctie beschouwen we twee types: • Toestandsgebonden sequenti¨ ele schakelingen: In dit geval hangt de uitgangsfunctie enkel af van de toestand op dat moment. In dat geval is de uitgangsfunctie F (S). Dit concept is ook bekend als de Moore machine ofwel Moore-FSM. Bij een Moore machine is de invloed van de ingang dus met vertraging te zien, vermits de schakeling eerst van toestand moet veranderen. • Inputgebonden sequenti¨ ele schakelingen: Hierbij wordt de signatuur van de uitgangsfunctie uitgebreid. De uitgang is zowel afhankelijk van de toestand S als van de ingang X. Dit betekent dat indien de ingang verandert, maar de toestand niet de uitvoer F (S, X) ook verandert. Dit concept wordt ook wel de Mealy machine ofwel Mealy-FSM genoemd. Elke Moore machine is dus ook een Mealy machine waar de invoer geen onderdeel uitmaakt van de logica die de uitgang berekent. Verder maken we ook een onderscheid in schakelingen inzake synchroniciteit, ook hier beschouwen we twee soorten: • Asynchrone sequenti¨ ele schakelingen: Hierbij verandert uitgang F en toestand S wanneer de ingang X verandert. We zullen asynchrone schakelingen kort bespreken in sectie 4.4, bovendien zullen we veronderstellen dat slechts ´e´en bit tegelijk verandert aan de ingang. • Synchrone sequenti¨ ele schakelingen: Hierbij veranderen de uitgang F en toestand S enkel op het moment de zogenoemde klokingang verandert. Veruit de meeste sequenti¨ele schakelingen worden gebouwd op basis van een klok. In sectie 4.3 zullen we synchrone schakelingen en hun synthese uitgebreid bespreken.
4.1.2
Terminologie van het kloksignaal
Bij synchrone schakelingen maken we gebruik van een klokingang. Op deze klokingang staat periodiek een 0 gevolgd door een 1. Om dit kloksignaal te beschrijven maken we gebruik van de volgende terminologie: • Klokperiode: de tijd tussen twee opeenvolgende klokovergangen van 0 naar 1. • Klokfrequentie: het aantal klokperiodes per seconden of formeler: klokfrequentie =
1 klokperiode
(4.1)
• “Duty cycle”: fragment van de klokcyclus dat de klok op 1 staat. duty cycle =
tijd klok is 1 klokperiode
(4.2)
De klok staat dus niet per definitie even lang op 0 als op 1. • Stijgende flank (ook wel rising edge genoemd): de klokovergang waarbij de klok van 0 naar 1 gaat. • Dalende flank (ook wel falling edge genoemd): de klokovergang waarbij de klok van 1 naar 0 gaat.
4.2
Bouwblokken
In deze sectie zullen we de bouwblokken van geheugen ontwikkelen. Hierbij zullen we in Subsectie 4.2.1 eerst het basisblok ontwikkelen om ´e´en bit te onthouden: de flipflop. Door flipflops te groeperen kunnen we een groter geheugen ontwikkelen. Dergelijke geheugens worden registers genoemd. Registers kunnen meestal maar een beperkt aantal flipflops tegelijk aanspreken. Registers bespreken we in subsectie 4.2.2. Een andere populaire toepassing van geheugens is een teller. We ontwikkelen een tellerschakeling in subsectie 4.2.3.
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
96
4.2.1
De flipflop
Bij de synthese van een flipflop zullen we een eerste positief feedback component introduceren: de setreset latch. Vervolgens zullen we deze latch uitbreiden en verschillende varianten bespreken. Een probleem met latches is het zogenaamde transparantie-probleem. Dit probleem zullen we oplossen door extra logica met deze latch te verbinden wat resulteert in een flipflop. Er zijn verschillende varianten van flipflops om verschillende toepassingen te ondersteunen, we eindigen met een beknopt overzicht van de verschillende flipflops. De latch Set S
Reset R
Qn
Q
S 0 0 1 1
R 0 1 0 1
Qnext Q 0 1 N/A
1 0 1 R 0 Q 10 Qn 10
S
t
(a) Implementatie met NOR-poorten. Set S ∗
Reset R∗
Q
Qn
S∗ 1 1 0 0
R∗ 1 0 1 0
Qnext Q 0 1 N/A
1 0 1 R∗ 0 Q 10 Qn 10
S∗
t
(b) Implementatie met NAND-poorten.
Figuur 4.1: Set-reset latch. Figuur 4.1 toont de NOR- en NAND-implementatie van de zogenaamde set-reset latch (ofwel SR-latch). Dit component werkt met positieve terugkoppeling waarbij de uitgangen dus ook een deel van de ingangen vormen. We onthouden de uitvoer door bepaalde waarden aan de ingang aan te leggen, die resulteren in het opnieuw bekomen van dezelfde uitvoer. Bij de NOR-implementatie is dit (S, R) = (0, 0). De NANDimplementatie is in feite de volledig duale vorm en werkt volledig equivalent, alleen zijn S en R hier actief lage signalen (zie Sectie 2.3). We zouden ook negatieve logica aan Q en Qn moeten toekennen maar omdat altijd geldt Qn = Q0 kunnen we ook eenvoudigweg de twee uitgangen omdraaien en bekomen we positieve logica aan de uitgang. De stabiele invoer van de NAND-implementatie is dan ook (S ∗ , R∗ ) = (1, 1). Indien we ´e´en van de ingangen laten afwijken van de stabiele toestand, komen we in een onstabiele toestand. Deze stabiele toestand kan maar op ´e´en manier terug stabiel worden. Op deze manier kunnen we een nieuwe waarde toekennen aan de latch. Deze waarde zal ook verder gelden nadat de ingangen weer stabiel zijn. Hierdoor kent men ook de termen set (1 in het geheugen) en reset (0 in het geheugen) toe aan de ingangen. Indien beide ingangen afwijken van de stabiele ingangen is het gedrag niet meer bepaald. In dat geval zal de uiteindelijke waarde afhangen van de implementatie van de latch en de vertraging van de poorten. Bij identieke vertragingen leidt dit tot een oscillerend effect wat ook te zien is op de tijdsgrafieken op figuur 4.1. In een minder ideaal systeem zal de snelste poort1 de uiteindelijke vertraging bepalen. Dit gedrag noemt men een “race” (zie 4.4.4). Geklokte SR-latch Bij de SR-latch is er geen sprake van een klokingang. We kunnen immers ook geheugens zonder klok gebruiken in bijvoorbeeld asynchrone schakelingen. Door extra hardware voor de SR-latch te plaatsen, kunnen we een geklokte SR-latch bouwen. Figuur 4.2 toont hoe we dit kunnen realiseren. Zolang het kloksignaal op 0 staat zal het geheugen zijn waarde behouden, indien het kloksignaal op 1 staat gelden dezelfde regels als bij een SR-latch. 1 Uiteraard
zijn de twee poorten in theorie even traag, in de praktijk zullen er altijd kleine verschillen zijn.
4.2. BOUWBLOKKEN
97
Set S
Qn
Klok Clk
Set S
Q
Klok Clk Q
Reset R
(a) Met AND- en NOR-poorten.
Qn
Reset R
(b) Met NAND-poorten.
Clk 0 1 1 1 1
S − 0 0 1 1
R − 0 1 0 1
Qnext Q Q 0 1 N/A
(c) Overgangstabel.
Figuur 4.2: Geklokte SR-latch. Geklokte D-latch Indien we elke klokflank een nieuwe waarde in de latch willen opslaan loont het meestal de moeite om de geklokte SR-latch om te vormen tot een geklokte D-latch. Een geklokte D-latch zoals op figuur 4.3 bouwt meestal extra logica rond een geklokte SR-latch die met de data-ingang D de S en R ingang aanstuurt. D-latches zijn populair bij schakelingen waarbij bij iedere klokflank een nieuwe waarde wordt ingelezen. Soms wordt dan echter ook een SR-latch gebruikt omdat dit de logica rond deze geheugenmodules soms kan vereenvoudigen. Data D
Q
Klok Clk Qn
(a) Implementatie.
Clk D 0 − 1 0 1 1 (b) bel.
Qnext Q 0 1
Overgangsta-
Figuur 4.3: Geklokte D-latch.
Set-up- en houdtijd Aan de hand van de implementatie van de geklokte D-latch op figuur 4.3 zullen we de vertragingen van verschillende signalen berekenen: tHL = 1.4 + 1.4 = 2.8 if D = 0 ∧ Clk = 1 D→Q : tLH = 1 + 1.4 + 1.4 + 1.4 = 5.2 if D = 1 ∧ Clk = 1 D → Qn
tHL = 1 + 1.4 + 1.4 = 3.8 tLH = 1.4 + 1.4 + 1.4 = 4.2
if if
D = 0 ∧ Clk = 1 D = 1 ∧ Clk = 1
tHL = 1.4 + 1.4 + 1.4 = 4.2 tLH = 1.4 + 1.4 = 2.8
if if
D = 0 ∧ Clk = 1 D = 1 ∧ Clk = 1
tHL = 1.4 + 1.4 + 1.4 = 4.2 tLH = 1.4 + 1.4 = 2.8
if if
D = 0 ∧ Clk = 1 D = 1 ∧ Clk = 1
:
(4.3) Clk → Q
Clk → Qn
:
:
We kunnen dergelijke vertragingen grafisch weergeven zoals op de tijdsgrafieken op figuur 4.4. Deze grafische voorstelling toont twee bekende problemen die veroorzaakt worden door het niet respecteren van twee parameters: • Set-up-tijd: De tijd alvorens de het actieve kloksignaal wordt verlaten waarin de waarde op de dataingang niet meer mag wijzigen. Bij een geklokte D-latch zoals op figuur 4.3 is dit: tset-up = tpHL (inverter)
(vertraging van een hoog-naar-laag signaal door een inverter)
(4.4)
Figuur 4.4(a) toont twee senarios. Bij het eerste wordt de set-up tijd gerespecteerd, bij het tweede faalt de toekenning. Dit komt omdat bij dit scenario S ∗ weer hoog wordt alvorens R∗ een hoog signaal
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
98 1 0 1 Clk 0 1 Dn 0 1 S∗ 0 1 R∗ 0 Q 10 Qn 10
1 0 1 Clk 0 1 Dn 0 1 S∗ 0 1 R∗ 0 Q 10 Qn 10
D
D
t
t
(a) Set-up-tijd?? 1 0 1 Clk 0 1 Dn 0 1 S∗ 0 1 R∗ 0 Q 10 Qn 10
1 0 1 Clk 0 1 Dn 0 1 S∗ 0 1 R∗ 0 Q 10 Qn 10
D
D
t
t
(b) Houdtijd??
Figuur 4.4: Tijdsgrafieken van een D-latch. aanlegt. Indien we de vertragingen van de poorten doorrekenen komen we uit dat de vertraging van aan de inverter een cruciale rol speelt. Dit is ook enigszins logisch: indien we een 0 aan de data-ingang D aanleggen zal gedurende deze periode 1 op zowel de S als R van de geklokte SR-latch worden aangelegd, wat eigenlijk een ongeldige invoer is. • Houdtijd: We moeten niet alleen het signaal op tijd aanleggen voor de klok een laag signaal aanlegt. Meestal moeten we het signaal daarna nog een tijdje laten staan om te vermijden dat de latch alsnog een foute waarde aanneemt. Figuur 4.4(b) toont opnieuw twee scenarios.?? Metastabiliteit Een ander probleem dat komt kijken bij latches is de metastabiliteit. Dit probleem treedt op bij de twee poorten2 van de SR-latch en dus bijgevolg alle afgeleide latches. Als we bij de NORimplementatie (S, R) = (0, 0) aanleggen, of bij een NAND-implementatie (S ∗ , R∗ ) = (1, 1), kunnen we deze poorten modelleren als NOT-poorten zoals op figuur 4.5(a). Indien we deze schakeling logisch analyseren zien y y
x x
(a) Implementatie. (b) Transfer-functies.
(c) Bal-en-heuvel-analogie.
Figuur 4.5: Metastabiliteit. we twee mogelijke stabiele oplossingen: waarbij ofwel x ofwel y 1 is, en de andere 0. Deze waarden zijn ook de enige die we beschouwen indien we de NOT-poort louter als logisch component zien. We implementeren 2 NAND-
of NOR-implementatie maakt niet uit.
4.2. BOUWBLOKKEN
99
deze poorten echter met behulp van transistoren, bijgevolg behoudt de poort een zeker analoog karakter. Op de grafiek op figuur 4.5(b) geven we de transfer-functie van de twee NOT-poorten weer. De stippelijn geeft de transfer-functie van de bovenste NOT-poort weer, de volle lijn de onderste. We zien zoals verwacht de twee stabiele toestanden. We bemerken echter ook een metastabiele toestand. Op het moment dat op x of y een kleine hoeveelheid ruis wordt aangebracht zullen de poorten dit effect versterken en zal de schakeling in een stabiele toestand terechtkomen. Het probleem is echter dat we uiteraard niet weten hoelang dit zal duren. We gaan er echter vanuit dat de kans dat na een bepaald tijdstip er nog onvoldoende ruis is opgetreden Poisson-verdeeld is3 . We formaliseren dus tot: p (nog in metastabiele toestand na t) = e−t/τ
(4.5)
De tijdsconstante τ is hierbij afhangen van twee factoren: • De hoeveelheid ruis: hoe meer ruis hoe lager de tijdsconstante. • De stijlheid van de curves rond de metastabiele toestand: hoe stijler hoe lager de tijdsconstante. Een latch kan in een metastabiele toestand komen door een zogenaamde marginale triggering: een schending van de set-up- of houdtijd of van de minimale pulsbreedte4 . In deze gevallen kan een overgang tussen twee stabiele toestanden worden onderbroken. Indien dit gebeurt op het moment dat men net voorbij de metastabiele toestand passeert treedt dit probleem op. Een latch komt dan ook bij elke overgang kortstondig in een metastabiele toestand. Ook een tijdje in een metastabiele toestand blijven is geen probleem. Zolang deze toestand niet meer actief is wanneer we het signaal gaan gebruiken zullen er geen problemen optreden. Een populaire voorstelling van metastabiliteit is de zogenaamde bal-en-heuvel-analogie. In deze analogie beschrijven we een heuvel zoals op figuur 4.5(c). Een bal kan op deze heuvel in drie toestanden een evenwicht bereiken: twee toestanden in een dal (passief evenwicht) en een metastabiele toestand op de heuvel (actief evenwicht). Bij asynchrone circuits is metastabiliteit een veel voorkomend fenomeen. Zeker wanneer de klokfrequentie geen veelvoud is van de frequentie waarmee de ingang omwisselt. In dat geval bestaat de oplossing van het probleem eerder uit “hoe ga ik om met metastabiliteit?”, in plaats van “hoe los ik de metastabiliteit op?”. De flipflop Latches kunnen we gebruiken bij het opslaan van ´e´en bit. Indien we een geklokte latch aan een kloksignaal hangen zijn er twee toestanden afhankelijk van het niveau van het kloksignaal: • Indien het kloksignaal hoog is Clk = 1 is de latch transparant. De latch neemt de waarde over die aan de ingang staat. • Indien het kloksignaal laag is Clk = 0 onthoudt de latch de laatste waarde die aan de ingang stond toen de latch transparant was. Latches geven echter problemen op het moment we verschillende latches na elkaar willen hangen. In dat geval zullen immers alle latches transparant zijn op hetzelfde moment. Hierdoor zal de laatste latch de waarde aannemen die op de eerste latch wordt aangelegd5 . Dit probleem wordt ook wel het transparantie-probleem genoemd. Meestal willen we echter bij een sequentie van een aantal geheugencomponenten afdwingen dat de informatie door ´e´en geheugencomponent per klokflank propageert. De flipflop is een geheugencomponent die in tegenstelling tot de latch flankgevoelig is. Dit betekent dat de flipflop enkel transparant is op het moment dat de klok van 0 naar 1 gaat, in tegenstelling tot een latch die transparant is gedurdende de volledige periode dat de klok hoog is. Om dit te realiseren zijn er doorgaans twee methodes: • De master-slave flipflop. • De edge-triggered flipflop. We zullen deze twee verschillende technieken in de volgende paragrafen toelichten. 3 De
meeste kansverdelingen op het voorkomen van een gebeurtenis zijn Poisson-verdeeld. tijd dat een signaal wordt aangelegd. 5 Bij een groot aantal latches zal het signaal door vertragingen en set-up- en houdtijd uiteraard maar door een beperkt aantal latches in ´ e´ en klokflank propageren. 4 De
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
100
Master-slave flipflop Een master-slave flipflop maakt gebruik van twee latches die beurtelings transparant zijn. De master (eerste latch) is transparant wanneer het kloksignaal laag is, de tweede latch is transparant bij een hoog kloksignaal. Gegroepeerd vormen we dus een geheugen die de laatste waarde opslaat die aan de ingang stond op het moment dat het kloksignaal laag was, en deze verder propageert op het moment dat het kloksignaal hoog is. Figuur 4.6 toont dit concept samen met een tijdsgrafiek.?? Master D
Slave
Master
Slave
Q1
Master
Slave
Q2
D
Q
D
Q
D
Q
D
Q
D
Q
D
Q
Clk
Q
Clk
Q
Clk
Q
Clk
Q
Clk
Q
Clk
Q
Q3
D
Q
Clk
Q
Clk
(a) Implementatie.
(b) Interface
Figuur 4.6: Master-slave flipflop.
Edge-triggered flipflop Een edge-triggered flipflop maakt gebruik van een structuur die we kunnen groeperen als drie latches. Deze schakeling stelt ons in staat om het signaal op te slaan die aan de ingang staat op het moment dat de klok van 0 naar 1 gaat. Figuur 4.7 toont een basis en meer uitgebreide implementatie samen met een tijdsgrafiek. In de meer uitgebreide versie zijn er naast de data- en klokingang ook nog twee Preset PR∗ A
Qn
S∗ Qn Klok Clk Klok Clk
Q Q R∗ D B
D
Clear CLR∗
(a) Basisimplementatie.
(b) Uitgebreide implementatie.
1
Clk 0 1 0 1 B 0 1 A 0 1 R∗ 0 1 S∗ 0 Q 10 Qn 10
D
t
(c) Tijdsgrafiek
Figuur 4.7: Edge-triggered flipflop. andere ingangen beschreven:
4.2. BOUWBLOKKEN
101
• Preset PR∗ : Indien dit signaal laag wordt, slaan we asynchroon een 1 op in de flipflop. • Clear CLR∗ : Indien dit signaal laag wordt, slaan we asynchroon een 0 op in de flipflop. Deze twee signalen worden ook wel de asynchrone set en reset genoemd. Ze zijn asynchroon omdat ze onafhankelijk van de toestand van de klok een waarde in het geheugen kunnen inbrengen, deze eigenschap wordt bijvoorbeeld gebruikt om bij het opkomen van de stroom in de elektronica de flipflop in een gekende toestand te brengen6 . Types flipflops Er bestaan analoog aan de latches ook verschillende types flipflops. Hierbij is niet de klokaansturing variabel, maar de manier hoe data ingelezen wordt. Denk bijvoorbeeld aan het verschil tussen een SR-latch en D-latch. Elk type flipflop kunnen we karakteriseren aan de hand van twee tabellen: • De karakteristieke tabel: deze tabel gebruikt men bij de implementatie van de flipflops. Het toont aan de linkerkant de ingangen, en aan de rechterkant geeft het weer hoe er op deze ingangen wordt ingespeeld. • De excitatietabel: deze tabel beschrijft de verschillende vormen van gedrag van de component aan de linkerkant, en aan de rechterkant hoe we dit gedrag kunnen verwezenlijken met de ingangen. Deze twee tabellen zijn niet strikt het omgekeerde omdat de excitatietabel een kolom voorziet voor Q en Qnext , terwijl de karakteristieke tabel uitsluitend ´e´en kolom aan de rechterkant voorziet. In de volgende paragrafen zullen we de verschillende types flipflops bespreken met hun karakteristieke- en excitatietabel. SR-flipflop De SR-flipflop ofwel set-reset flipflop werkt volledig analoog aan een SR-latch, alleen verandert de waarde uitsluitend op het moment dat de klok van een laag signaal naar een hoog signaal gaat. De karakteristieke tabel is dan ook volledig equivalent met deze van de SR-latch op figuur 4.1. Figuur 4.8 toont de interface en de karakteristieke- en excitatietabel van de SR-flipflop.
S
Q Clk
R
Q
Symbool
S R Qnext 0 0 Q 0 1 0 1 0 1 1 1 N/A Karakteristieke tabel
Q Qnext S R 0 0 0 − 0 1 1 0 1 0 0 1 1 1 − 0 Excitatietabel
Figuur 4.8: Set-reset flipflop.
D-flipflop Ook de data-flipflop of D-flipflop is conceptueel equivalent aan zijn latch tegenhanger. Op het moment dat de klok van laag naar hoog gaat, zal het signaal dat aan de data-ingang D staat in het geheugen worden geladen. Hierdoor is het bouwen van schakelingen met D-flipflops meestal zeer eenvoudig. Merk dus op dat elk signaal slechts ´e´en klokperiode bewaard wordt. Figuur 4.9 toont het symbool samen met de karakteristieke- en excitatietabel. T-flipflop Een nieuwe variant is de zogenaamde toggle-flipflop ofwel T-flipflop. De toggle-flipflop heeft een ‘toggle’-ingang T . Indien deze ingang bij een stijgende klokflank hoog is, zal de flipflop het omgekeerde van zijn huidige waarde opslaan, de zogenaamde ‘toggle’-operatie. Indien T = 0, blijft de opgeslagen toestand dezelfde. We kunnen een toggle-flipflop bouwen met behulp van een data-flipflop en een XORpoort. Figuur 4.10 toont het symbool, een mogelijke implementatie en de karakteristieke- en excitatietabel van de T-flipflop. 6 Bij het opkomen van de stroom zal de flipflop of latch immers een waarde aannemen afhankelijk van de ruis en minimale verschillen in poortvertragingen.
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
102
D
Q
Clk
D 0 1
Q
Symbool
Qnext 0 1
Karakteristieke tabel
Q Qnext D 0 0 0 1 0 1 1 0 0 1 1 1 Excitatietabel
Figuur 4.9: Data-flipflop.
T
Q
T Clk
Q
D
Clk
Symbool
Clk
Q
Q
Q
Qn
Implementatie
T 0 1
Qnext Q Q0
Karakteristieke tabel
Q Qnext T 0 0 0 1 0 1 1 0 1 1 1 0 Excitatietabel
Figuur 4.10: Toggle-flipflop. JK-flipflop De JK-flipflop of voluit Jack Kilby-flipflop7 is een combinatie van de set-reset flipflop en de toggle-flipflop. Bij een SR-flipflop komen we immers in een ongeldige toestand indien we aan de ingangen (S, R) = (1, 1). De JK-flipflop lost dit probleem op door in dat geval een toggle-operatie uit te voeren op het geheugenelement, zoals te zien op de karakteristieke tabel op figuur 4.11. We kunnen een JK-flipflop realiseren met behulp van een SR-flipflop waarbij:
S = J · Q0 R=K ·Q
(4.6)
JK-flipflops worden vooral gebruikt om goedkopere schakelingen te synthetiseren. Deze eigenschap kunnen we afleiden uit de vele don’t cares in de excitatietabel.
J
Q
S
Clk
Clk K
J
Q
Symbool
K
Q
Q
Q
Qn
Clk R
Implementatie
J K Qnext 0 0 Q 0 1 0 1 0 1 1 1 Q0 Karakteristieke tabel
Q Qnext J K 0 0 0 − 0 1 1 − 1 0 − 1 1 1 − 0 Excitatietabel
Figuur 4.11: Jack-Kilby flipflop.
Overzicht We bundelen vervolgens al de latches en flipflops in figuur 4.12. Indien een cel leeg is bij dit overzicht is er geen realisatie mogelijk. Zo kunnen we onmogelijk een toggle-latch bouwen: deze zou immers bij een actief kloksignaal continue inverteren, waardoor het uiteindelijke resultaat onvoorspelbaar is. We kunnen elke flipflop verrijken met de asynchrone preset en clear ingangen. Verder bestaan er ook nog varianten van deze componenten waarbij we eerst een negatie toepassen op de ingang. In dat geval plaatsen we een cirkel bij deze ingang. Indien we een negatie toepassen op de klokingang bij een flipflop zal de flipflop dus de waarde memoriseren bij een falling edge, in plaats van een rising edge. 7 Genoemd
naar Jack Kilby (1923-2005), Amerikaans natuurkundige en nobelprijswinnaar.
4.2. BOUWBLOKKEN
103
S
Q
S
Q
R
Q
R
Q
Toggle (T)
Jack Kilby (JK)
NAND
S
Q
D
Q
Q
Clk
Q
Clk R
PR S
Q
S
Clk
PR Q
D
Q
D
PR Q
T
Q
T
PR Q
J
Clk
R
Q
R
J
Clk Q
Clk
CLR
Basis
Q
Uitgebreid
Basis
Q
Clk Q CLR
Uitgebreid
Clk
Basis
Q
Clk Q CLR
Uitgebreid
K
Q Clk
Q
K
Q CLR
Basis
Flipflop
Flankgeklokt
Geklokt
NOR
Data (D)
Latch
Ongeklokt
Set-Reset (SR)
Uitgebreid
Figuur 4.12: Overzicht van de interfaces van geheugencomponenten.
4.2.2
Registers
Register Een flipflop kan ´e´en bit opslaan voor ´e´en of meerdere klokflanken. Meestal willen we echter meerdere bits opslaan om bijvoorbeeld een getal voor te stellen. Dit kunnen we doen door middel van verschillende flipflops die elk een individuele bit opslaan. Een register is in dat opzicht eigenlijk ook een n-flipflop. Omdat we vaak meerdere bits opslaan defini¨eren we dus het registercomponent. Een register neemt enige functionaliteit weg van de flipflops: zo kunnen we niet beslissen dat een individuele flipflop een bit aan de ingang opslaat, en de andere flipflops niet. Desalniettemin maken ze schema’s eenvoudiger en worden registers op chipniveau verkocht. Verder biedt een dergelijk chip naast geheugenopslag ook extra functies aan: bijvoorbeeld schuifregisters en tellers. Een register heeft tradioneel ingangen voor de klok Clk, data D1 , D2 , . . . , Dn , load LD en asynchrone preset Pr∗ en clear Clr∗ . Als uitgangen heeft het minstens de data-uitgangen Q1 , Q2 , . . . , Qn . Enkel indien de load hoog is bij een rising edge zal de waarde die aan de data-ingangen staat opgeslagen worden. Indien dit niet zo is, wordt de vorige waarde behouden. Figuur 4.13 toont de interface van een register, samen met een mogelijke implementatie. We werken hier met D-flipflops en multiplexers om te kiezen tussen het laden van een nieuwe waarde en een vorige waarde. Meestal wordt de clear en preset in negatieve logica ge¨ımplementeerd8 . Schuifregister We hebben reeds vermeld dat men de meeste registers uitrust met extra functionaliteit. Een concreet voorbeeld hiervan is het schuifregister. Indien we met normale registers werken kunnen we per klokflank tussen twee acties kiezen: een nieuwe waarde inladen (“load”), of de oude waarde behouden. Een schuifregister voegt daar een functionaliteit aan toe: de oude waarde ´e´en plaats naar rechts schuiven, en deze waarde bij de rising edge inladen. Hiervoor bevat een schuifregister een extra ingang Shft die indien actief, de waarde van het register opschuift. Sommige schuifregisters bevatten bovendien extra ingangen om te bepalen of er naar links of rechts geschoven moet worden. SerIn is een andere ingang, deze bepaalt welke bit er op de vrijgekomen plaats komt te staan. Figuur 4.14 toont de implementatie van een schuifregister die de data naar rechts opschuift. Schuifregisters worden vooral gebruikt om data serieel te maken: er wordt een getal ingeladen in het register, en vervolgens kunnen we per klokflank de laatste bit doorsturen. Aangezien het getal telkens verder opschuift sturen we zo na n-klokcycli een n-bit getal door. Dit kan handig zijn indien de kostprijs van meerdere draden te hoog is. 8 Vandaar
de asterisk (*) bij Clr∗ en Pr∗ .
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
104
D3
D2
D1
D0
LD Pr∗ D3 D2 D1 D0 LD
LD
Clk
PR D
Clk
Clr
Clr
Q
D
Clk Q CLR
Pr∗
Pr
PR
PR Q
D
Clk Q CLR
PR Q
D
Clk Q CLR
Q
Clk Q CLR
Clr∗
∗
Clk
Q3 Q2 Q1 Q0
Q3
Q2
Q1
Q0
(b) Implementatie
(a) Interface
Figuur 4.13: Interface en implementatie van een 4-bit register. D3
D2
D1
D0
SerIn Shft LD Pr∗ PR D
PR Q
D
Clk Q CLR
PR Q
D
Clk Q CLR
PR Q
D
Clk Q CLR
Q
Clk Q CLR
Clr∗
Clk Q3
Q2
Q1
Q0
(a) Implementatie
Figuur 4.14: Implementatie van een 4-bit schuifregister.
4.2.3
Tellers
Een andere functionaliteit die men vaak combineert met registers is tellen. Een teller maakt het mogelijk om de waarde tijdens een klokflank met ´e´en op te hogen: increment. De meeste tellers laten echter ook toe om naar beneden te tellen: decrement. De meeste tellers laten ook toe om een waarde in te laden en deze dan vervolgens in de volgende klokcycli te verhogen of verlagen. Indien de teller op de maximale of minimale voor te stellen waarde komt, treedt na de volgende cyclus een “wrap-around” op: het getal voor het kleinste getal is het grootste en vice versa. Modulo-tellers wachten niet op de maximaal voor te stellen waarde alvorens deze wrap-around toe te passen. Zo telt een BCD-teller enkel tussen 0 en 9. We zouden een teller kunnen implementeren aan de hand van een register en een opteller9 . Er bestaan echter goedkopere manieren om tellers te implementeren. Een teller die enkel naar boven telt wordt een up-counter genoemd. Analoog wordt een teller die enkel naar beneden telt een down-counter genoemd. Een teller die in beide richtingen kan tellen is een bidirectionial counter ofwel bidirectionele teller. Tellers introduceren ook een aantal nieuwe ingangen: • Counter Enabled CEin : enkel indien dit signaal hoog is, wordt het tellen uitgevoerd. In het andere geval blijft de waarde uit de vorige klokcyclus behouden. • Down-Up D/U ∗ : deze ingang bepaalt de richting waarin er geteld wordt. Uit het symbool kunnen we 9 Analoog
aan het schuifregister die uit een schuifoperatie en register bestaat.
4.2. BOUWBLOKKEN
105
afleiden dat indien het signaal laag is we naar boven tellen, indien het signaal hoog is tellen we naar beneden. Een uitgang die we regelmatig in een teller zien terugkomen in Counter Enabled CEout . Deze uitgang is hoog op de klokflank waarbij de teller een wrap-around uitvoert. Indien we dan een cascade van tellers bouwen zal de teller die erna geschakeld is bij een wrap-around opgehoogd worden. Op die manier kunnen we bijvoorbeeld met 3 4-bit tellers een 12-bit teller bouwen. Deze uitgang wordt soms ook de “Ripple Carry Output (RCO)” genoemd. CEin
CEout PR T
PR Q
T
Clk Q CLR
PR Q
T
Clk Q CLR
PR Q
T
Clk Q CLR
Q
Clk Q CLR
Clk Clr∗ Q0
Q1
Q2
Q3
Figuur 4.15: Asynchrone 4-bit teller
Asynchrone teller Bij een asynchrone teller, asynchronous counter ofwel ripple counter wordt de verandering van de bittoestand van ´e´en van de bits gebruikt als klokingang voor de volgende bit. Dit leidt tot minimaal hardwaregebruik, maar heeft hetzelfde probleem als een ripple adder: het signaal dient te propageren door de bits10 , wat leidt tot grote vertragingen als het om veel bits gaat. Vooral indien we logica koppelen aan hoge bits kunnen deze vertragingen nefast zijn en leiden tot een lage performantie. We kunnen een down-counter realiseren door de Qn -uitgang aan de toggle-ingang van de volgende flipflop te koppelen (en niet de Q-uitgang). Eventueel kunnen we deze schakeling dus zelfs uitbreiden door een multiplexer te plaatsen tussen de flipflops die selecteert tussen Q en Qn en zo de gebruiker laat kiezen in welke richting de teller werkt. Het nadeel is dat ook deze multiplexer een vertraging induceert. Een eenvoudige implementatie van een asynchrone teller staat op figuur 4.15. CEin
CEout PR T
PR Q
T
Clk Q CLR
PR Q
T
Clk Q CLR
PR Q
T
Clk Q CLR
Q
Clk Q CLR
Clk Clr∗ Q0
Q1
Q2
Q3
Figuur 4.16: Synchrone 4-bit teller
Synchrone teller Een synchrone teller laat alle bits wel tegelijk van waarde veranderen. Dit doen we door de volgende toestand reeds vooraf uit te rekenen en bij het kloksignaal deze toestand op te slaan in de flipflops. Hoe we deze toestand berekenen staat ons in principe vrij net als de keuze van het type flipflop. Figuur 4.16 toont een implementatie met T-flipflops. Merk op dat ondanks het feit dat de nieuwe toestand berekend wordt voor de klokflank de teller daarom geen vertraging kan teweeg brengen: het berekenen van de volgende toestand van een teller met een grote woordlengte vraagt immers ook veel tijd (en kan dus het kritieke pad worden). Het voordeel van een synchrone teller is dat we deze berekening parallel doen met 10 Hiervan
komt overigens de notie van asynchroniciteit: niet alle bits veranderen op hetzelfde moment van waarde.
106
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
andere berekeningen die van de teller afhangen. Doordat de volgende toestand ook meteen beschikbaar is zullen berekeningen die afhangen van de teller ook onmiddellijk kunnen worden uitgerekend. D0 D/U
D1
D2
D3
∗
CEin
Ei Di
Dir Ei+1
Ei Di
Qi
Dir Ei+1
Ei Di
Qi
Dir Ei+1
Ei Di
Qi
Dir Ei+1
CEout
Qi
LD PR D
PR Q
D
Clk Q CLR
PR Q
D
Clk Q CLR
PR Q
D
Clk Q CLR
Q
Clk Q CLR
Clk Clr∗ Q0
Q1
Q2
Q3
(a) Algemene implementatie D3 D2 D1 D0
Dir ∗
D/U CEin Clk LD Clr∗
∗
D/U CEin Clk LD CLR
CEout
CEout
Ei
Ei+1
Di
Q3 Q2 Q1 Q0
(b) Interface
Qi
(c) Hulpcomponent
Figuur 4.17: Parallel-laadbare bidirectionele 4-bit teller.
Parallel-laadbare bidirectionele teller Een speciaal geval van een synchrone teller is een parallellaadbare bidirectionele teller. Een implementatie van zo’n teller staat op figuur 4.17(a). Deze teller is parallel laadbaar wanneer we de waarde van de teller kunnen zetten op een ingegeven waarde in ´e´en klokflank11 . Bij het laden wordt de LD ingang hoog gezet. In het andere geval dienen we elke bit te berekenen. Hiervoor wordt op figuur 4.17(a) een naamloze component ingevoerd. De nieuwe waarde van een bit wordt ge¨ınverteerd indien er geteld wordt op deze bit. In het andere geval blijft de bit onveranderd. Een bit wordt opgeteld indien de vorige bit geteld wordt en de bit ´e´en is bij een telling naar boven (analoog aan een overdracht (“carry”) dus), of nul en een telling naar beneden (een lening (“borrow”) dus). Bij het berekenen van de eerste bit Q0 gebruiken we logischerwijs de counter enabled CE ingang. Figuur 4.17(c) toont een implementatie voor een dergelijk component. De teller die we hiermee ontwikkelen verenigt de meeste functionaliteiten die we in tellers kunnen terugvinden. Figuur 4.17(b) toont een interface die vaak gebruik wordt voor tellers. Indien een functionaliteit niet wordt aangeboden wordt de vermelding eenvoudigweg weggelaten. Modulo-teller Tot nu toe hebben we enkel teller geconstrueerd die tellen van 0 tot het maximaal voor te stellen getal. Bij een n-bit teller is dit dus 2n − 1. In de praktijk komt het geregeld voor dat we tellen tot een bepaalde waarde om daarna terug bij 0 te beginnen. Stel bijvoorbeeld dat we een teller maken die het aantal minuten bijhoudt. Indien dit getal boven de 60 gaat komt het aantal minuten terug op 0, en dient het aantal uren verhoogd te worden. Ook controllers die elektronica aansturen dienen soms een beperkt aantal 11 Het schuifregister of figuur 4.14 kan bijvoorbeeld ook sequentieel geladen worden, waarbij we per klokflank een bit van het getal inschuiven.
4.2. BOUWBLOKKEN
107
toestanden met de regelmaat van de klok te herhalen, zelden zijn dit aantal toestanden een macht van twee. Voor dergelijke problemen kunnen we een Modulo-teller gebruiken. Een modulo-teller bestaat traditioneel uit een teller met daarrond extra logica die indien de maximale waarde wordt vastgesteld, in de volgende klokflank een 0 in de teller laadt. We kunnen deze teller veralgemenen door ook het tellen naar beneden toe te laten, in dat geval dient de maximale waarde in de klokcyclus na 0 ingeladen te worden. Figuur 4.18(a) toont een algemeen geval van een 4-bit teller. We tellen hierbij van 0 tot en met MAX. Uiteraard moet MAX in dit MAX
D/U∗ CEin Clk
0
0
D/U∗ CEin Clk LD CLR
Clr∗
0
CEout
0
1
CEout
D/U∗ CEin Clk Clr∗
0
0
1
0
D/U∗ CEin Clk LD CLR
0
0
CEout
0
CEout
= MAX Q3 Q2 Q1 Q0
(a) Algemeen geval
Q3 Q2 Q1 Q0
(b) BCD-teller
Figuur 4.18: 4-bit modulo-tellers. geval wel voor te stellen zijn met 4-bit. Voor een n-bit modulo-counter geldt dus steeds: MAX≤ 2n . Verder dienen we ´e´en component afhankelijk van MAX te synthetiseren. Deze component vergelijkt de waarde die ∗ op de Qi -uitgangen staat met MAX, indien deze aan elkaar gelijk zijn en D/U en CEin hoog zijn, dient een 1 aan de uitgang van deze component te verschijnen, in alle andere gevallen een 0. Voor eender welke MAX is dit te realiseren met een AND-poort12 . Verder zien we op de figuur ook een variant van een multiplexer. Deze multiplexer stelt eigenlijk 4 multiplexers voor die elk een bit uit het linkse en een bit uit het rechtse vak ∗ als invoer hebben, en die selecteren met dezelfde ingang, namelijk: D/U . Vanaf de volgende sectie zullen we vaak met registers met een groot aantal bits werken. In dat geval besparen ontwerpers zich het tekenen van de verschillende parallelle lijnen door ´e´en lijn te tekenen. Verder wordt er dus gebruik gemaakt van de notatie van de multiplexers om aan te duiden dat elke bit van deze lijnen door een dergelijk component gaat.
BCD-teller Een speciaal geval van een modulo teller is een BCD-teller. Deze teller telt van 0 tot en met 9. BCD ofwel Binary Coded Decimal werd reeds eerder besproken in subsectie ??. BCD-tellers zijn populair bij het voorstellen van getallen die ook snel naar de gebruiker moeten worden gecommuniceerd. Dit komt omdat bij de omzetting van een getal naar het equivalent op bijvoorbeeld seven-segment displays, we cijfer per cijfer kunnen werken. Indien we het getal binair opslaan wordt deze omzetting veel complexer. Op figuur 4.18(b) implementeren we dan ook een BCD-teller. Vermits 9 binair voorgesteld wordt door 10012 kunnen we een AND-poort realiseren die in dat geval een 1 op de uitgang plaatst. Verder dienen we dus ook deze waarde in de multiplexer in te brengen. Een oplettende lezer zal misschien merken dat sommige van de multiplexers in dat geval zinloos worden, omdat we bijvoorbeeld moeten kiezen tussen een 0 en een 0. 12 Waarom?
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
108
4.3
Synchrone schakelingen
Nu we de bouwstenen hebben beschreven om een sequenti¨ele schakeling te bouwen zullen we een stappenplan ontwikkelen uit een set van specificaties een sequenti¨ele schakeling te ontwikkelen. In deze sectie gaan we ervan uit dat deze schakeling synchroon is. Dit betekent dat er sprake is van een klok die de schakeling aanstuurt. Het stappenplan kan opgedeeld worden in volgende stappen: 1. Het opstellen van een toestandsdiagram uit de specificaties. 2. Het minimaliseren van het aantal toestanden door F-gelijke toestanden te bepalen. 3. Het implementeren van de toestanden in een geheugen (a) Het coderen van deze toestanden in geheugenelementen. (b) Het kiezen van het type flipflop die de toestanden bijhoudt. 4. Het implementeren van de combinatorische logica (a) Implementeren van logica die de volgende toestand berekent. (b) Implementeren van logica die de uitgangen (uitvoer) berekent.
4.3.1
Leidende voorbeelden
We zullen dit stappenplan doorlopen met behulp van twee voorbeelden. Het eerste is een Moore-FSM. Uit subsectie ?? weten we nog dat de uitgang dus volledig bepaald wordt door de toestand. In het tweede voorbeeld behandelen we een Mealy-FSM waarbij ook de invoer een rol speelt. Het stappenplan zelf verschilt meestal op enkele punten tussen het proces voor een Moore-machine en een Mealy-machine. In dat geval zullen op de afbeeldingen aan de linkerkant de Moore-machine staan, en aan de rechterkant de Mealy-machine. Indien dit niet relevant is voor het concept zullen we telkens gebruik maken van de Mealy-machine. Deze keuze is uiteraard louter arbitrair. We implementeren een Moore-machine die 1 op de uitvoer aanlegt als de laatste drie klokcycli afwisselend een 0, 1 en 0 zijn. We implementeren een min of meer equivalente constructie voor een Mealy-machine, hier dienen echter op de twee laatste klokcycli een 0 en 1 op de ingang aangelegd te worden, en dient er op het moment zelf een 0 op de ingang te staan. De Mealy-machine is dus de Moore-machine maar met ´e´en klokcyclus verschoven.
4.3.2
Stap 1: opstellen van het toestandsdiagram
Het opstellen van het toestandsdiagram is meestal de moeilijkste stap. Dit komt omdat men niet formeel kan uitdrukken hoe men uit de specificaties een toestandsdiagram opstelt. Het opstellen van een dergelijk diagram omvat echter meestal dezelfde vaardigheden als deze die bij bijvoorbeeld programmeren aan bod komen. Door middel van oefening kan men dan ook bekwaamheid verwerven. Het toestandsdiagram Alvorens we een toestandsdiagram kunnen opstellen zullen we eerst een toestandsdiagram formeel defini¨eren. Een toestandsdiagram bestaat uit een set van toestanden. Een toestand duiden we aan met een ellips. Meestal benoemen we toestanden met een hoofdletter. Dit is niet verplicht maar maakt het makkelijk om naar een toestand te verwijzen. Verder zijn er ook transities: overgangen van de ene toestand naar de andere13 toestand onder een bepaalde ingangscombinatie. Een transitie duiden we dan ook aan met behulp van een gerichte pijl tussen de twee toestanden. Voor elke mogelijke ingangscombinatie dienen we in elke toestand een transitie te voorzien. De ingangscombinatie waarbij de transitie van toepassing is noteren we bij de gerichte pijl. Het kloksignaal is in een synchrone sequenti¨ele schakeling geen onderdeel van de ingangscombinatie. Tot slot bevat een toestandsdiagram ook de initalisatie, een gerichte 13 Een
transitie kan ook naar dezelfde toestand gaan.
4.3. SYNCHRONE SCHAKELINGEN A 0
109
RST 0 1
B 0
0
0
E 0
0 1
L 0
0
1
0
1/0
0/0
0/0 D
E
N 0
F 0
1
(a) Moore-machine
0
1
0
1
J 1
0
K 0
1/0
1 0
0 C 0
1
M 0
0
0
B
0/0
I 0
1
0
1 1
1
H 0
1
D 0
O 0
0 G 0
1
1/0 0/1
0/0
1/0
A
RST
0/0 1
F
G
1/0 0/0
1/0
1/0
C
(b) Mealy-machine
Figuur 4.19: Toestandsdiagrammen van de leidende voorbeelden. pijl die naar een bepaalde toestand wijst maar niet uit een toestand komt. Het is de eerste toestand waarin de schakeling zich bevindt. Verder keert de schakeling ook naar deze toestand terug als de gebruiker een reset-operatie op de schakeling uitvoert. De uitgangscombinatie wordt ook weergegeven op het toestandsdiagram. Deze verschilt uiteraard tussen een Moore-machine en een Mealy-machine: bij een Moore-machine worden de uitgangen bij de toestanden genoteerd, dus in de ellips. Vermits de uitgangen bij een Mealymachine afhangen van de ingangscombinatie wordt de uitgang bij de transitiepijlen gezet. We maken hierbij een onderscheid tussen de ingangscombinatie en de uitgang door hier een slash (“/”) tussen te plaatsen. Op figuur 4.19 geven we de toestandsdiagrammen van de Moore- en Mealy-machine weer. Toestandstabel Een toestandsdiagram is een grafische voorstelling. Bij een groot aantal toestanden of bij bijvoorbeeld invoer van een toestandsdiagram in een computer, maken we meestal gebruik van een alternatieve voorstelling: de toestandstabel. De rijen in de toestandstabel stellen de verschillende toestanden voor, de kolommen stellen de invoercombinatie voor. In een cel i, j voor toestand Ai en invoer Ij plaatsen we de volgende toestand. In het geval van een Moore-machine voorzien we een extra kolom die per rij de uitgangscombinatie van deze toestand weergeeft. Bij een Mealy-machine plaatsen we in elke cel naast de volgende toestand de uitgangscombinatie voor toestand Ai en invoer Ij . Ook hier plaatsen we een slash om de volgende toestand van de uitvoer te onderscheiden. De toestandstabellen van de leidende voorbeelden staan in tabel 4.1. Opstellen van een toestandsdiagram en -tabel Zoals reeds gezegd is het opstellen van een toestandsdiagram of -tabel een kunst. Een algemene techniek die gehanteerd kan worden is het aantal klokflanken te bepalen dat we geheugen moeten voorzien. In het geval van de voorbeelden is dit drie klokflanken voor de Moore-machine en twee klokflanken voor de Mealy-machine. Vervolgens kunnen we een toestandstabel of -diagram opstellen die de overgang naar verschillende toestanden van het geheugen voorstelt. Zo komt A in beide voorbeelden overeen met de toestand waarin we starten, er is bijgevolg nog geen sprake over inhoud in het geheugen. B en C betekent dat er na de eerste klokflank respectievelijk een 0 en een 1 in het geheugen
110
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) (a) Moore-machine
Toestand A B C D E F G H I J K L M N O
0 B D F H J L N H J L N H J L N
1 C E G I K M O I K M O I K M O
Uitgang 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
(b) Mealy-machine
Toestand A B C D E F G
0 B/0 D/0 F/0 D/0 F/1 D/0 F/0
1 C/0 E/0 G/0 E/0 G/0 E/0 G/0
Tabel 4.1: Toestandstabellen van de leidende voorbeelden. opgeslagen is. D, E, F en G spreken over de respectievelijke geheugentoestanden 00, 01, 10 en 11. Voor de Mealy-machine is dit reeds voldoende. Bij de Moore-machine introduceren we nog een extra niveau. De overgangen op dit laatste niveau houden in dat we de oudste bit vergeten en de nieuwe bit memoriseren. Hierdoor gaan alle overgangen van een toestand op het laatste niveau enkel naar toestanden op hetzelfde niveau. We kunnen machinaal eenvoudig een tabel opstellen voor een arbitraire diepte. Een groot nadeel is dat indien we n klokflanken willen memoriseren, we 2n+1 − 1 toestanden bekomen. Na het opstellen van deze tabel dienen we enkel de specificaties nog te vertalen in de uitgangen van de toestanden in het geval van een Moore-machine, en de overgangen bij een Mealy-machine. Meestal kan men echter door logisch te redeneren voorkomen dat we dergelijke grote toestandstabellen moeten opstellen. In de volgende subsectie reduceren we het aantal toestanden tot de theoretische ondergrens. Of we de initi¨ele tabel opstellen met de hier beschreven methode of door logisch te redeneren verandert niets aan het resultaat van de volgende stap.
4.3.3
Stap 2: Minimaliseren van de toestanden
Nu we een toestandsdiagram opgesteld hebben kunnen we dit diagram implementeren met behulp van logica. Het loont echter meestal de moeite om eerst het toestandsdiagram te minimaliseren. Minder toestanden impliceren minder geheugencomponenten om de toestand bij te houden. Bovendien kunnen we meestal ook de achterliggende logica die de volgende toestand en de uitgangen berekent minimaliseren. Hiertoe geven we een methode die gegarandeerd het kleinste toestandsdiagram vindt die de specificaties kan implementeren. Met minimaal bedoelen we hier het aantal toestanden. Dit betekent dus niet noodzakelijk dat de schakeling die we hiermee verwezenlijken ook minimaal is. Het minimalisatiealoritme Het algemeen idee De methode die we implementeren gaat uit van een positief idee: alle toestanden zijn vertegenwoordigers van dezelfde toestand. Uiteraard is dit niet altijd het geval. Er zijn twee omstandigheden waarin twee toestanden niet gelijk aan elkaar zijn: 1. De uitgang van de toestanden of overgangen uit een toestand zijn verschillend. In dat geval kunnen we immers onmogelijk de uitgangsfunctie implementeren. Een uitgang kan immers niet tegelijk 0 of 1 zijn. 2. De uitgang na een willekeurig aantal willekeurige invoer (configuraties bij een klokflank) is verschillend. In dat geval betekent dit dat we dus in de toekomst op het vorige probleem zullen botsen.
4.3. SYNCHRONE SCHAKELINGEN
111
De eerste voorwaarde We kunnen deze twee condities eenvoudig in een algoritme implementeren. Het algoritme werkt op basis van een partitionering van de aanvankelijke toestandsruimte. Als twee toestanden tot dezelfde partitite behoren. betekent dit dat ze eigenlijk hetzelfde zijn. Zoals eerder vermeld begint de methode met een positieve ingesteldheid: alle toestanden zijn gelijk. De initi¨ele configuratie bevat dus ´e´en partitie waar alle toestanden in zitten. Vervolgens kunnen de eerste voorwaarde toepassen. Toestanden die een verschillende uitgang opleveren kunnen onmogelijk hetzelfde zijn. Voor een Moore-machine betekent dit dus de uitgang van de toestand. In het leidend voorbeeld is de uitgang 0 of 1. We partitioneren de configuratie dus in een partitie die 0 als uitgang geeft en een partitie met 1 als uitgang. De configuratie is dan: partitieMoore,0 = {{A, B, C, D, E, F, G, H, I, K, L, M, N, O} , {J}} (Leidend voorbeeld)
(4.7)
Merk echter op dat een schakeling ook meerdere lijnen als uitgang kan hebben. Indien de uitgang n bits telt levert dit ons een configuratie op van hoogstens 2n partities. In het geval een Mealy-machine leidt een toestand niet rechtstreeks tot een uitgang. Twee toestanden zijn dan gelijk indien voor elke invoerconfiguratie bij deze toestand, we dezelfde uitvoerconfiguratie bekomen. In het leidend voorbeeld beschouwen we een 1-bit ingang en een 1-bit uitgang. Dit leidt dus tot hoogstens 4 partities. In ons geval zijn er maar 2 partities: partitieMealy,0 = {{A, B, C, D, F, G} , {E}} (Leidend voorbeeld) (4.8) In het algemene geval met een m-bit ingang en een n-bit uitgang bekomen we hoogstens 2n+m partities. De tweede voorwaarde De tweede voorwaarde kunnen we ook afdwingen door middel van iteratie. Hierbij itereren we over de lengte van de invoer. Het specifieke geval is uiteraard het geval waarbij de uitvoer na ´e´en klokcyclus reeds verschilt. Dit kunnen we herformuleren tot het volgende: Indien twee toestanden x0 en y0 onder een willekeurige invoer i0 naar twee toestanden x1 en y1 gaan, en deze twee toestanden behoren niet tot dezelfde partities, dan behoren x0 en y0 ook niet tot dezelfde partitie. Deze uitspraak is logisch, stel dat x0 en y0 tot dezelfde partitie zouden behoren, dan kan het gebeuren dat we in de toestand geraken die door de partitie waar x0 en y0 toe behoort. Indien we daarna de invoer i0 dienen te verwerken komen we in toestand die zowel x1 en x2 dient te vertegenwoordigen. Vermits x1 en y1 echter tot een andere partitie behoren is dit onmogelijk. We gebruiken deze regel om partities vervolgens verder op te delen. We gebruiken de eerste configuratie van de minimale Moore-machine als voorbeeld. Hierbij gaan van de eerste partitie de toestanden A, B, C, D, F , G, H, K, L, N en O onder invoer van 0 en 1 naar de eerste partitie. De toestanden E, I en M gaan onder invoer van 0 naar de tweede partitie (J) en onder invoer van 1 naar de eerste partitie. Bijgevolg splitsen we de eerste partitie op in {{A, B, C, D, F, G, H, K, L, N, O} , {E, I, M }}. Vermits de tweede partitie reeds uit ´e´en element bestaat, valt deze niet verder op te delen. De totale partitie na ´e´en iteratie is dan gelijk aan: partitieMoore,1 = {{A, B, C, D, F, G, H, K, L, N, O} , {E, I, M } , {J}} (Leidend voorbeeld)
(4.9)
Het enige wat we nu moeten doen is deze stap herhalen op de nieuwe partitie partitieMoore,1 . Op die manier passen we de regel toe bij een invoerlengte van 2. De enige vraag die open blijft is wanneer we mogen stoppen. Deze vraag is eenvoudig te beantwoorden: zolang er partities bijkomen kan een volgende stap de partities verder verdelen. Indien de uitvoering van een stap geen wijzigingen aan de partities aanbrengt, zal de volgende stap dit uiteraard ook niet meer doen, en alle stappen hierna ook niet meer. In dat geval is het veilig om te stoppen. Bij de minimalisatie van de Moore-machine zullen we dan volgende partities bekomen: partitieMoore,0 partitie Moore,1 partitieMoore,2 partitie Moore,3
= {{A, B, C, D, E, F, G, H, I, K, L, M, N, O} , {J}} = {{A, B, C, D, F, G, H, K, L, N, O} , {E, I, M } , {J}} = {{A, C, G, K, O} , {B, D, F, H, L, N } , {E, I, M } , {J}} = {{A, C, G, K, O} , {B, D, F, H, L, N } , {E, I, M } , {J}}
(Leidend voorbeeld)
(4.10)
Het geval van de Mealy-machine is volledig analoog: we bekomen dan: partitieMealy,0 = {{A, B, C, D, F, G} , {E}} partitieMealy,1 = {{A, C, G} , {B, D, F } , {E}} partitie Mealy,2 = {{A, C, G} , {B, D, F } , {E}}
(Leidend voorbeeld)
(4.11)
112
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Omzetting naar een toestandsdiagram en -tabel Nadat we het aantal toestanden geminimaliseerd hebben, dienen we alleen nog een nieuwe Moore- of Mealymachine te bouwen op basis van de partitie van de toestanden van de originele machine. Zoals we al enkele keren vermeld hebben staat een partitie voor de toestand van de minimale machine. We dienen dus voor elke partitie een nieuwe toestand te voorzien. Dit doet men meestal door de nieuwe toestand dezelfde naam te geven als de toestand in de partitie die alfabetisch het eerst voorkomt. Maar we kunnen uiteraard ook een arbitraire naam kiezen, of een naam die de letters van alle inwendige toestanden omvat. Verder dienen we in het geval van een Moore machine aan elke toestand een uitvoerconfiguratie toe te kennen. Omdat we de eerste voorwaarde hebben afgedwongen hebben alle toestanden in een partitie dezelfde uitvoerconfiguratie, bijgevolg nemen we de configuratie van ´e´en van de toestanden in de partitie over. Hetzelfde geldt voor de Mealymachine. De uitgang verbonden aan de transitie uit een bepaalde nieuwe toestand is dezelfde als de uitgang van dezelfde transitie uit ´e´en van de toestanden in de partitie. De transitiefunctie kunnen we opstellen op basis van de tweede voorwaarde: alle toestanden in partitie zullen voor eenzelfde ingangscombinatie naar eenzelfde partitie lopen. Op die manier kunnen we dus een transitie-functie opstellen over de nieuwe toestanden. De initi¨ele toestand ten slotte is de toestand verbonden aan de partitie die de oorspronkelijke initi¨ele toestand bevat. Op figuur 4.20 en tabel 4.2 staan de nieuwe machines na minimalisatie van de leidende voorbeelden. We kunnen eenvoudig vaststellen dat minimalisatie soms tot spectaculaire reducties van het aantal toestanden kan leiden. 0
1 RST
0
A 0
1/0 0/0
B 0
01
0/0
RST
A
B
1 1/0
0 1
J 1
1/0
E 0
(a) Moore-machine
0/1 E
(b) Mealy-machine
Figuur 4.20: Geminimaliseerde toestandsdiagrammen van de leidende voorbeelden.
(a) Moore-machine
Toestand A B E J
0 B B J B
1 A E A E
Uitgang 0 0 0 1
(b) Mealy-machine
Toestand A B E
0 B/0 B/0 B/1
1 A/0 E/0 A/0
Tabel 4.2: Geminimaliseerde toestandstabellen van de leidende voorbeelden.
Een formeel algoritme De cursus “Automaten en Berekenbaarheid” van prof. Demoen[?] bevat een formeel algoritme voor de minimalisatie van een deterministische eindige toestandsautomaat (DFA). Met minimale veranderingen kan dit algoritme omgevormd worden tot een algoritme die Moore- en Mealy-machines minimaliseert. We beschouwen dit in Algoritme 1. Het algoritme bevat de algemene Minimize-procedure. Deze procedure maakt gebruik van twee functies: Minimize1 en Minimize2. De eerste functie wijkt af tussen een Moore- en Mealy-machine. Daarom wordt deze functie opgesplitst: voor de Moore-machine gebruiken we dus Minimize1Moore, de Mealy-machine maakt gebruik van Minimize1Mealy. We dienen ook een formele beschrijving te geven van de variabelen in het algoritme. Het algoritme heeft als invoer 3 verzamelingen:
4.3. SYNCHRONE SCHAKELINGEN
113
Algorithm 1 Minimaliseren van een toestandsdiagram. 1: procedure Minimize(S, I, O, δ, f ) . Minimaliseer de machine 2: Q ← Minimize1(S, I, O, f ) . Initi¨ele partitionering gebaseerd op uitvoer. 3: repeat 4: P←Q 5: Q ← Minimize2(S, I, δ, P) . Bereken de nieuwe partitionering op basis van de oude. 6: until P = Q . Indien geen verandering is het algoritme ten einde. 7: return Q . De uiteindelijke partitie. 8: end procedure 9: function Minimize1Moore(S, I, O, f ) 10: return {{s|s ∈ S : f (s) = o} |o ∈ O} . I wordt genegeerd. 11: end function 12: function Minimize1Mealy(S, I, O, f ) 13: return {{s|s ∈ S, ∀i ∈ I ∧ ∀f (s, i) = oi } |o ∈ O, ∀i ∈ I : ∃oi ∈ O} 14: end function 15: function Minimize2(S, I, δ, P) 16: return {{s|s ∈ P ∧ ∀i ∈ I : δ (s, i) = Pi } |P ∈ P, ∀i ∈ I : ∃Pi ∈ P} 17: end function • S is de verzameling van alle toestanden. • I is de verzameling van alle invoerconfiguraties. • O is de verzameling van alle uitvoerconfiguraties. Daarnaast heeft het algoritme ook nood aan twee functies: • Een transitiefunctie δ : S × I → S die de volgende toestand beschouwt na een bepaalde invoer op de ingangen te hebben waargenomen bij de klokflank. • Een uitvoerfunctie f . Bij de Moore-machine is deze functie van de signatuur f : S → O, bij een Mealy-machine is dit f : S × I → O. Het algoritme is ge¨ımplementeerd in het softwarepakket die wordt meegeleverd met deze cursus. De interface en de implementatie wordt besproken in Appendix B op pagina 319.
4.3.4
Stap 3: Implementeren van de toestanden in het geheugen
Stap 3A: Coderen van de toestanden Tot nu toe hebben we toestanden altijd voorgesteld met letters. Uiteraard dienen we deze toestanden op de een of andere manier voor te stellen in de geheugencomponenten in onze schakeling. Vermits letters niet opgeslagen kunnen worden in een flipflop of een register14 zullen we de toestanden moeten omzetten naar een binaire voorstelling. Dit wordt het coderen van de toestanden genoemd. Doorgaans lijkt dit geen ingewikkeld probleem, we kunnen eenvoudigweg elke toestand een opeenvolgend nummer geven en deze toestanden dan binair coderen. Merk echter op dat de toestand geen impliciete ordening hebben, alleen al door opeenvolgende nummers te gebruiken zijn er n! mogelijke coderingen mogelijk. Er bestaan echter technieken die ervoor zorgen dat we door een intelligente codering minder hardware zullen gebruiken. Dit leidt meestal tot goedkopere en snellere schakelingen. Algemeen zijn er drie technieken die we kunnen gebruiken: • “Straightforward codering”: soms is de codering triviaal. • De “one-hot codering”: hierbij stellen we n toestanden voor door n bits, elke toestand krijgt z’n eigen bit. Indien de toestand actief is, is deze bit hoog, de andere bits zijn dan laag. 14 Uiteraard
kunnen we bijvoorbeeld wel het ASCII equivalent opslaan.
114
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) • De “minimal-bit-change”: we zoeken een codering die telkens een minimum aan bits verandert. Hierbij gebruiken we dlog2 ne bits om de n toestanden voor te stellen.
Uiteraard dienen we ons niet te beperken tot ´e´en van deze implementaties. Indien het aantal uitgangen bijvoorbeeld niet voldoet om een straightforward codering toe te passen kunnen we dit bijvoorbeeld aanvullen met extra bits die een minimal-bit change gebruiken. We bespreken nu de verschillende coderingstechnieken in detail. Straightforward codering Een codering kan triviaal zijn als de toestand een duidelijke betekenis heeft. Dit is doorgaans het geval bij bijvoorbeeld tellers. Ook indien we over een Moore-machine beschikken waarbij elke toestand een andere uitgang heeft en de uitgang minstens dlog2 ne bits bevat, kunnen we een straightforward codering toepassen. In dat geval gebruiken we de uitgang van een toestand ook als zijn codering. Merk op dat in dat geval we geen logica nodig hebben die de toestand naar de uitgang codeert. Deze codering is echter niet altijd ideaal. We reduceren dan de logica aan de uitgang, maar meestal resulteert dit in complexere logica om de transities te implementeren. Verder veranderen er meestal heel wat bits per overgang. We herinneren ons dat een CMOS-implementatie enkel energie verbruikt wanneer deze omschakelt. Indien we dus veel flipflops van waarde moeten laten veranderen betekent dit dus een groter vermogenverbruik. Een tweede aspect is dat niet elke bit tegelijk verandert. Vermits er meerdere bits zijn kan dit problemen opleveren: er bestaat een gevaar voor glitches, een tijdelijk foute waarde op een lijn ten gevolge van asynchroon gedrag aan de ingang. Indien het resultaat van een teller dus nog in een andere schakeling gebruikt wordt leidt dit mogelijk tot problemen. One-hotcodering We voorzien een flipflop voor elke toestand, hierdoor is het aantal flipflops O (n) in tegenstelling tot de O (log2 n). Bij elke toestand is er ´e´en flipflop hoog, alle andere flipflops zijn laag. Het spreekt dus voor zich dat we deze configuratie enkel kunnen gebruiken bij een klein aantal toestanden. Onehotcoderingen hebben enkele voordelen: het ontwerp van een dergelijke schakeling is vrij eenvoudig en is dus snel te realiseren. Verder is het ideaal voor een implementatie bij een FPGA. Een one-hotcodering verbruikt doorgaans weinig vermogen aangezien bij elke overgang tussen twee verschillende toestanden er twee flipflops omschakelen. Tot slot zijn ook de combinatorische schakelingen voor de uitgangen en de transities doorgaans vrij goedkoop. Het grootste nadeel van een one-hot codering is dan ook de kostprijs voor de flipflops. Minimal-bit-change Indien de kostprijs en vermogenverbruik een belangrijke factor zijn maken we meestal gebruik van de minimal-bit-change. Hierbij proberen we ervoor te zorgen dat de som van het aantal bits die veranderen van alle overgangen minimaal is. Dit probleem is echter niet triviaal en is NP-compleet. Bij een klein aantal toestanden kunnen we alle mogelijkheden uitproberen, bij een groter aantal maakt men gebruik van programma’s zoals bijvoorbeeld MUSE, JEDI, MUSTANG,... Deze programma’s werken op basis van heuristieken en geven meestal een benaderende oplossing. Soms worden er ook kansen bij de overgangen betrokken om het de kosten en het vermogenverbruik verder te minimaliseren. Een typisch voorbeeld is de Gray-code teller15 . Gray ontwikkelde een teller die bij elke overgang slechts ´e´en bit veranderde. Figuur 4.21 toont het toestandsdiagram van een 2-bit en 3-bit teller. Op de bogen plaatsen we hier het aantal bits die veranderen. Het feit dat we niet voor een straightforward implementatie voor een teller kiezen kan vreemd lijken. Deze teller dient dan ook meestal niet om de binaire waarde onmiddellijk uit te lezen, maar kan bijvoorbeeld gebruikt worden als een controller die een lus vormt over een vast aantal toestanden. Over het concreet oplossen van dit probleem gaan we niet verder in. Leidende voorbeelden Voor de Moore-machine kiezen we voor een minimal-bit-change benadering en voor de Mealy-machine een one-hot codering. Deze keuzes zijn louter didactief. De toegewezen bitvoorstellingen worden in een toestandstabel geschreven. Voor een one-hot codering is dit vrij triviaal. We wijzen elke toestand ´e´en bit toe. Welke bit heeft geen invloed op de schakeling. Tabel 4.3 stelt de Mealy-machine uit de leidende voorbeelden voor met de one-hot codering. Bij het zoeken naar een minimal-bit-change voor de Moore-machine maken we gebruik van een greedy algoritme. We stellen eerst een tabel op die het aantal bindingen tussen twee toestanden bevat. Vervolgens wijzen we coderingen aan toestanden toe volgens het 15 Vernoemd
naar Frank Gray (1887-1969), fysicus bij Bell Labs.
4.3. SYNCHRONE SCHAKELINGEN
RST
1
000
1 RST
00
115 1
001
1
1
1
10
101
1
111
111
010
110
1
1
2
010
01
2
2
11
110
(a) Gray-code (minimal-bit-change)
001
00
1
1
11
1
1
000
3 RST
1
01
1
100
RST
011
1 101
2
10
1
1 011
3 100
(b) Straightforward
Figuur 4.21: Een 2-bit en 3-bit Gray-code teller en zijn straightforward equivalent. Toestand 001 010 100
0 010/0 010/0 010/1
1 001/0 100/0 001/0
Tabel 4.3: Codering van de Mealy-machine van het leidend voorbeeld. aantal bindingen tussen de toestanden. De bindingstabel staat beschreven in tabel 4.3(a). We zien dat E en J een dubbele binding bevat. We kennen hier de waarde 01 toe aan E en 11 bij J. Verder is B gelinkt aan E en daarom geven we dit de waarde 00. A krijgt ten slotte de waarde 10. (a) Bindingstabel
A B E J
A 1 -
B 1 1 -
E 1 1 0 -
(b) Coderingstabel
J 0 1 2 0
Toestand 10 00 01 11
0 00 00 11 00
1 10 01 10 01
Uitgang 0 0 0 1
Tabel 4.4: Codering van de Moore-machine van het leidend voorbeeld.
Stap 3B: De keuze van het type flipflop Nadat we elke toestand kunnen voorstellen met een sequentie aan bits, dienen we flipflops te voorzien om deze toestand bij te houden. Hierbij hebben we de keuze tussen de verschillende flipflops die we in 4.2.1 besproken hebben. Elk van deze types zal een specifieke combinatorische logica vereisen met specifieke kosten en vertraging. Om de meest optimale schakeling te realiseren zullen we altijd alle types moeten uitproberen. Verder kunnen we ook voor verschillende bits een verschillend type flipflop voorzien. Hierop gaan we echter niet in. De ervaring leert ons wel dat voor verschillende toepassingen verschillende soorten flipflops een zekere voorkeur genieten. De typische toepassingen zeg maar. Een cruciale factor is ook het aantal don’t cares. In het algemeen is het zo dat hoe meer don’t cares de combinatorische schakeling bevat, hoe eenvoudiger te implementeren. Sommige flipflops introduceren makkelijker don’t cares dan andere flipflops. De kosten van een flipflop Als we de kostprijs van de verschillende types flipflops met elkaar vergelijken merken we dat de JK-flipflop opmerkelijk duurder16 is. Dit betekent daarom niet dat de totale kostprijs 16 Ter
illustratie een JK-flipflop ge¨ıntegreerd circuit kost $0.116, een gelijkaardige D-flipflop kost ongeveer $0.049.
116
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
van de schakeling groter is. Immers dienen we ook een combinatorisch gedeelte te voorzien; de optelling van beide leidt tot de totale kostprijs. Don’t cares Een JK-flipflop is dan duurder, maar door de typische realisatie leidt dit tot veel don’t cares. Dit leidt tot een eenvoudige schakeling. Het is logisch dat een JK-flipflop nogal wat don’t cares impliceert: er zijn immers enkele manieren om dezelfde waarde in een JK-flipflop te klokken. Ook een SR-flipflop laat ruimte voor don’t cares in het combinatorische gedeelte. Een D-flipflop laat doorgaans weinig plaats voor don’t cares. Dit komt omdat in elke klokflank een nieuwe waarde uit de ingang wordt gelezen. We dienen er dus telkens voor te zorgen dat op dit moment de juiste waarde aan de ingang staat. Een T-flipflop ten slotte heeft net hetzelfde probleem, meestal is het effect hier zelfs nog erger. Eenvoud van het ontwerp Indien we de schakeling zelf moeten realiseren moeten we ook rekening houden met het tijdsaspect en dus de eenvoud van het ontwerp. Doorgaans leidt een D-flipflop tot de eenvoudigste implementatie. Dit komt omdat we meestal geneigd zijn absoluut te denken. Verder heeft een D-flipflop ook slechts ´e´en ingang, en is de component makkelijk te specifi¨eren: ”wat we aan de ingang aanleggen staat de volgende klokflank in de flipflop”. Het opstellen van een excitatietabel is dan ook eenvoudig. Een T-flipflop is ook conceptueel eenvoudig: ¨ındien de waarde moet omslaan, leg dan 1 aan op de ingang”. Moeilijker zijn de SR- en JK-flipflop. Dit komt in de eerste plaats omdat beide componenten twee ingangen hebben. Merk dus op dat we een excitatietabel met twee ingangen moeten opstellen. Toepassingen Door jaren ervaring heeft men kennis opgebouwd welke toepassing welke flipflop vereist. In subsectie 4.2.3 hebben we reeds tellers gebruikt en hebben we vaak gebruik gemaakt van T- en Dflipflops. Tellers en frequentiedelers17 worden typisch ge¨ımplementeerd met T-flipflops. Meestal zal dit tot ijle excitatietabellen leiden. Een D-flipflop wordt typisch gebruikt om een waarde zeer tijdelijk te onthouden, meestal slechts enkele klokflanken. Voor complexe toepassingen waarbij de waarde van de flipflop frequent een 0 of 1 wordt zijn SR- en JK-flipflops het meest geschikt. Welke flipflop kiezen? De vorige paragrafen proberen hints te geven welke flipflops het meest geschikt zijn, deze hints zijn echter niet absoluut. Om tot de goedkoopste schakeling te komen, moeten we alle mogelijkheden uitproberen. Meestal hebben we de tijd niet alle configuraties te proberen. In dat geval zijn D-flipflops meestal de beste keuze. Ook een FPGA volgt deze redenering en bevat enkel D-flipflops. Samevatting
We vatten de vorige paragrafen samen in tabel 4.5. Flipflop
JK
SR
D
T
Kostprijs Don’t cares Ontwerp
-++ --
++ + -
++ ++ tijdelijke geheugens
++ -+ tellers, frequentiedelers
Toepassingen
veel veranderingen
Tabel 4.5: Keuze van het type flipflop.
4.3.5
Stap 4: Implementeren van de combinatorische logica
Met alle vorige stappen hebben we beslist hoe we de specificaties van de sequenti¨ele schakeling zullen implementeren. Het enige wat we nu nog moeten doen is de schakeling zelf implementeren. Deze implementatie is op te delen in het implementeren van de logica die de volgende toestand berekent, en de logica die de uitgang bepaalt. We bespreken elk van deze onderdelen apart. 17 Een frequentiedeler is een moduloteller die de frequentie waarmee er geteld wordt deelt door het modulo-getal. Enkel wanneer zich een overflow voordoet geven we het signaal door. Hierdoor kunnen we delen van de schakeling aan een lagere klokfrequentie laten werken.
4.3. SYNCHRONE SCHAKELINGEN
117
Stap 4A: Logica die de volgende toestand berekent Excitatietabellen van flipflops Het deel van de logica die de volgende toestand van het circuit berekent is bij zowel een Moore- als een Mealy-machine identiek. Het is een combinatorische schakeling die als ingangen de invoer van de component en de toestand heeft, als uitvoer heeft het de ingangen van de flipflops die de toestand bijhouden. Het aantal uitgangen en de uitgangen zelf hangen dus af van het type flipflop die we gekozen hebben. We dienen dus een tabel op te stellen die op basis van de invoer van de schakeling en de toestand aangeeft welke ingangen van welke flipflops hoog of laag moeten zijn. Deze functies noemen we de excitatiefuncties; deze komen voort uit de excitatietabellen van de verschillende flipflops. Deze tabellen werden reeds ge¨ıntroduceerd in 4.2.1. In tabel 4.6 geven we eerst opnieuw een kort overzicht van de excitatietabellen van de verschillende flipflops. Op basis van deze tabellen kunnen we nu de excitatiefuncties (b) SR
(a) JK
Q 0 0 1 1
Qnext. 0 1 0 1
J 0 1 -
K 1 0
Q 0 0 1 1
Qnext. 0 1 0 1
(c) D
S 0 1 0 -
R 0 1 0
Q 0 0 1 1
Qnext. 0 1 0 1
(d) T
D 0 1 0 1
Q 0 0 1 1
Qnext. 0 1 0 1
T 0 1 1 0
Tabel 4.6: Excitatietabellen van de verschillende flipflops berekenen. Deze functies bevatten traditioneel veel don’t cares. Deze don’t cares hebben drie oorzaken: • De don’t cares die we terug vinden bij de excitatietabellen. Dit zijn don’t cares in de uitgang van de functie en komen enkel voor bij implementaties met JK- en SR-flipflops. • Binaire coderingen van toestanden die niet bestaan. Een concreet geval is bijvoorbeeld 011 bij een one-hot codering. Dergelijke invoer codeert nooit naar een uitvoer. • Binaire coderingen van ingangscombinaties die niet mogelijk zijn. Stel bijvoorbeeld dat we een 2-bit ingang beschouwen en enkel configuraties 00, 01 en 11 kunnen voorkomen. Deze laatste twee zijn een vorm van invoer die niet kan voorkomen. In een tabel kunnen we de rijen weglaten, of we kunnen de rij opvullen met dont cares aan het uitganggedeelte. De transitiefunctie We stellen de transitiefunctie op door voor elke bit die de toestand voorstelt de ingangen van deze flipflop als uitgangen van onze schakeling te zien. Hiervoor kunnen we eerst het coderingstabel wijzigen. We lineariseren het diagram en laten de uitvoer voorlopig vallen. We illustreren dit concept met de Moore-machine uit het leidende voorbeeld. In tabel 4.6(a) staat de toestandstabel van deze Moore-machine beschreven. Elke bit van de toestand Fi is een ingang samen met de in dit geval 1-bit ingang Ii van de schakeling. Als uitgang nemen we voorlopig de bits Di die de volgende toestand voorstellen. Deze linearisatie staat in tabel 4.6(b). Merk op dat deze reeds de implementatie zijn als we werken met D-flipflops. In het geval we niet met D-flipflops werken dienen we nog een extra stap te beschouwen: in dat geval beschouwen we voor elke flipflop het tuple (Fi , Di ). Hierbij geldt Fi = Q en Di = Qnext. . We dienen dan nog enkel op te zoeken welke invoer het specifieke type flipflop nodig heeft in de excitatietabellen (zie tabel 4.6). In het geval van een SR- en JK-flipflop leidt dit dus tot een verdubbeling van het aantal uitgangen. Voorbeelden hiervan voor respectievelijk de T-, JK- en SR-flipflop staan in tabellen 4.6(c), 4.6(d) en 4.6(e). In principe hebben we nu alle elementen om de combinatorische schakeling te realiseren. We minimaliseren eerst de functies met behulp van Karnaugh-kaarten en implementeren dan vervolgens de logica. Merk op dat deze schakelingen meervoudige uitgangen hebben (1 per D- en T-flipflop en 2 per JK- en SR-flipflop). We kunnen dus ook de logica verder optimaliseren door implicanten over de verschillende Karnaugh-kaarten samen te nemen. Op figuur 4.22 geven we voor elk type flipflop de Karnaugh-kaarten en een implementatie. Naast de logica voor de volgende toestand, verbinden we ook de klokingangen van de flipflops met het globale kloksignaal, en implementeren we de clear logica. De clear zorgt ervoor dat op het moment dat we de schakeling herzetten en dus het Clr∗ signaal van de schakeling 0 wordt, de schakeling in de eerste toestand terechtkomt. In ons
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
118
(a) Coderingstabel
Toestand 10 00 01 11
0 00 00 11 00
1 10 01 10 01
(b) D-flipflop
Uitgang 0 0 0 1
F0 0 0 0 0 1 1 1 1
F1 0 0 1 1 0 0 1 1
I0 0 1 0 1 0 1 0 1
D0 0 0 1 1 0 1 0 0
(d) JK-flipflop
F0 0 0 0 0 1 1 1 1
F1 0 0 1 1 0 0 1 1
I0 0 1 0 1 0 1 0 1
J0 0 0 1 1 -
K0 1 0 1 1
(c) T-flipflop
D1 0 1 1 0 0 0 0 1
F0 0 0 0 0 1 1 1 1
F1 0 0 1 1 0 0 1 1
I0 0 1 0 1 0 1 0 1
T0 0 0 1 1 1 0 1 1
T1 0 1 0 1 0 0 1 0
(e) SR-flipflop
J1 0 1 0 0 -
K1 0 1 0 1
F0 0 0 0 0 1 1 1 1
F1 0 0 1 1 0 0 1 1
I0 0 1 0 1 0 1 0 1
S0 0 0 1 1 0 0 0
R0 0 0 1 0 1 1
S1 0 1 0 0 0 0
R1 0 0 1 0 1
Tabel 4.7: Voorstelling van de transitiefunctie van de Moore-machine. geval is dat 10. Daarom verbinden we de clear-ingang met de preset ingang van de eerste flipflop en de clear-ingang van de tweede flipflop. Op de clear-ingang van de eerste flipflop en de preset-ingang van de tweede wordt steeds een hoog signaal aangelegd. Merk verder ook op we in principe geen negatieve ingangen voor toestandssignalen moeten gebruiken. In plaats van een negatie aan de ingang van de AND-poort te plaatsen, kunnen we eenvoudig gebruik maken van de Q-uitgang van de flipflop. Omdat we echter hiermee het aantal lijnen voor de flipflops bijna verdubbelen, maken we er in de figuur abstractie van. Dit principe kunnen we enkel toepassen voor signalen die uit de flipflops komen. De signalen die de ingangsconfiguratie bepalen hebben wel een expliciete NOT-poort nodig. Het one-hot-codering geval Naast het geval van de Moore-machine zullen we ook de transitiefunctie van de Mealy-machine implementeren. Over deze realisatie is het ook eenvoudiger om enkele eigenschappen te formaliseren. Deze eigenschappen gaan over de kosten van de transitiefunctie v´o´or dat we minimalisatie van de Karnaugh-kaarten toepassen. Verder hangen de eigenschappen af van het type flipflop die we gebruiken: • Bij een D-flipflop is het aantal AND-poorten voor een flipflop equivalent met het aantal transities naar de toestand die de flipflop voorstelt. Bij een transitie18 naar toestand x dient immer de overeenkomstige flipflop op 1 gezet te worden, in de andere gevallen is de waarde van de flipflop altijd 0. We kunnen dit verder formaliseren tot: “Het aantal enen in de Di kolom is gelijk aan het aantal transities naar toestand i”. • Bij een T-flipflop is het aantal T-poorten gelijk met het aantal transities die naar een de bijbehorende toestand gaan, of vanuit de toestand vertrekken, die geen lussen zijn. Of eenvoudiger: “Het aantal enen in de Ti -kolom is gelijk aan het aantal transitites van of naar toestand i die geen lussen zijn”. • Bij een SR-flipflop is het aantal AND-poorten die naar de S-ingang gaan gelijk aan het aantal transities naar de toestand, die niet uit de toestand komen. Het aantal AND-poorten die voor de R-ingang staan zijn het aantal transities die uit de toestand vertrekken, en die geen lussen zijn. Deze logica kunnen we ook omzetten naar het aantal enen in de kolommen Si en Ri . 18 Inclusief
lussen.
4.3. SYNCHRONE SCHAKELINGEN D0
119 T0
I0 PR D
I0 Clk Clr∗
T1 PR D
Q
F1
F0
Clk Q CLR
0 1 1 0
PR T
Clk Q CLR
I0 Clk Clr∗
I0 0 0 1 0
1 1 0 0
I0
K0
S0
I0 PR J
Q
K
Q
I0 0 0 1 1 0 0 0 -
Clk Q CLR
R0
I0 -
F0
Clk
F0
F0
1 1 1 0
-
0 0 1 1 1 0
PR S
J1
I0
R
Q
S1
Clk
K
I0
1 PR S
I0 - 0 1 0 0 1 - -
Q Clk
R
F1
F0
0 1 0 - 0 0 0
R1
F1
(c) JK-flipflops
Q CLR
F0
1 0 0 1 - -
F1
F0
0 0
I0 Clk Clr∗
PR J
Q CLR
1
I0 -
F1
F0
0 1 - - -
K1
Q Clk
CLR
I0 Clk Clr∗
Q
F1
F1
-
F1
-
PR
(b) T-flipflops
F1
F1
F0
0 0 1 1 - - -
1
T
(a) D-flipflops J0
Q
F0
F1
F1
F0
1 0 1 0
1
0 1 1 1
F1
F0 Clk Q CLR
I0 0 1 0 0
Q
F0
D1
0 1 0 1
F1
F0
0 1 0 0
I0
Q CLR
(d) SR-flipflops
Figuur 4.22: Implementatie van de Moore-schakeling met verschillende soorten flipflops. • Bij JK-flipflops gelden dezelfde regels als bij de SR-flipflops, we dienen hier S door J en R door K te vervangen. We kunnen deze theorie testen met de praktijk in tabel 4.8. Hierbij hebben we de tabellen voor de verschillende types flipflops naast elkaar gezet, dit is louter om de voorstelling eenvoudig te houden. Merk op dat verschillende rijen uitsluitend don’t cares bevatten. Dit is het gevolg van het feit dat heel wat binaire voorstellingen van toestanden bij de invoer geen overeenkomstige toestand hebben. Meestal worden deze rijen in een tabel weggelaten, wat de tweede tabel een stuk korter en leesbaarder maakt. Uiteraard dienen we dan wel op deze plaatsen in de Karnaugh-kaarten don’t cares te plaatsen. We zien dat D0 ´e´en 1 bevat, wat overeenkomt met ´e´en transitie naar toestand E op figuur 4.20(b), verder bevatten de kolommen voor toestand A en B respectievelijk 2 en 3 enen. Bij de JK-flipflop heeft toestand A 1 transitie naar A en 1 transitie uit A. We zien dat dit ook overeenkomt met het aantal enen bij J2 en K2 . We kunnen dus besluiten dat dergelijke eigenschappen handig kunnen zijn bij het controleren van onze tabel. Een andere eigenschap is dat bij een T-flipflop er altijd twee bits veranderen. Bij elke rij zijn er dus ofwel 0 enen ofwel 2. Op figuur 4.23 implementeren we de D- en JK-flipflop variant van de Mealy-machine. Het implementeren van de T- en SR-flipflop variant wordt als een oefening voor de lezer overgelaten. Merk op dat we hier de verbindingen naar de Clr∗ en Pr∗ ingangen anders geconfigureerd zijn dan bij de Moore-machine. Dit komt omdat de begintoestand van de Mealy-machine 001 is, terwijl dit 10 is bij de Moore-machine.
120
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) (a) D- en JK-flipflops
F0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
F1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
F2 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
I0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
D0 0 0 0 1 0 0 -
D1 1 0 1 0 1 0 -
D2 0 1 0 0 0 1 -
J0 0 0 0 1 -
K0 1 1 -
J1 1 0 1 0 -
K1 0 1 -
J2 0 0 0 1 -
K2 1 0 -
(b) T- en SR-flipflops
F0 0 0 0 0 1 1
F1 0 0 1 1 0 0
F2 1 1 0 0 0 0
I0 0 1 0 1 0 1
T0 0 0 0 1 1 1
T1 1 0 0 1 1 0
T2 1 0 0 0 0 1
S0 0 0 0 1 0 0
R0 0 1 1
S1 1 0 0 1 0
R1 0 0 1 0 -
S2 0 0 0 0 1
R2 1 0 0
Tabel 4.8: Implementatie van de Mealy-schakeling met verschillende soorten flipflops.
Stap 4B: Logica die de uitgang toestand berekent Naast de logica die de volgende toestand berekent, dienen we ook de de logica te synthetiseren die de uitgangen bepaalt. Dit is eigenlijk niets anders dan het synthetiseren van een combinatorische schakeling. Hiervoor dienen een tabel op te stellen die vanuit de coderingstabel een tabel opstelt die de functie bepaalt. Vermits de uitgang bij een Moore-machine anders bepaald wordt dan bij een Mealy-machine, zal ook de techniek om deze tabel op te stellen licht verschillen. Bij een Moore-machine wordt de uitgang enkel bepaald door de toestand. Hierdoor kunnen we de tabel opstellen door de transitiekolommen weg te laten. Bij een Mealy-machine dienen we een linearisering toe te passen. Hierbij beschouwen we niet meer de codering van de volgende toestand zoals in de vorige stap, maar uiteraard de uitgang. Vanuit die tabel stellen we dan opnieuw een combinatorische schakeling op. Merk op dat deze schakeling niet afhangt van het type flipflop. Immers hebben alle types flipflop een Q-uitgang. De schakeling hangt wel af van de toestandscodering. Op tabel 4.9 toont de tabellen die we opstellen voor de Moore- en Mealy-machine naast hun coderingstabellen. (a) Moore coderingstabel
Toestand 10 00 01 11
0 00 00 11 00
1 10 01 10 01
Uitgang 0 0 0 1
(b) Moore
F0 0 0 1 1
F1 0 1 0 1
O0 0 0 0 1
(c) Mealy coderingstabel
Toestand 001 010 100
0 010/0 010/0 010/1
1 001/0 100/0 001/0
(d) Mealy
F0 0 0 0 0 1 1
F1 0 0 1 1 0 0
F2 1 1 0 0 0 0
Tabel 4.9: Uitgangslogica van de Moore- en Mealy-machine naast hun coderingstabellen.
I0 0 1 0 1 0 1
O0 0 0 0 0 1 0
4.3. SYNCHRONE SCHAKELINGEN
D0
1
I0
F2
J0 PR
-
D
-
Q
I0 D1
F2
1
J1 PR
-
D
Q
-
1 0 - - - - 1 - - 0
PR D
0 -
(a) D-flipflop
0 1 I0
K
Q CLR
-
-
PR
1 -
F2 -
1 Q Clk K
Q CLR
Clr∗ -
1 0 - - - -
J
PR J
F1
1
0
-
F0
I0
F0
Clk Q CLR
-
F1
F1
F F2
0 -
Q Clk
1
1
I0 K2
F2 -
Q
PR J
Clk
I0 J2
-
F2 -
F0
F0
Clk Q CLR
-
F0
0 1 - - 0 - - 0 - - 1
-
F1
F F1
Clr∗
0 -
-
I0
F1
F1
F0
F2
1
K1
F2
I0 D2
-
I0
Clk
1 0 1 - - 0 - - - 1 - - 0
F0
F0
0 0 0 - - 1 - - - - - - -
1
I0
F2
F1
F F0 Clk Q CLR
K0
F2
F1
F1
F0
0 0 0 - - 1 - - - 0 - - 0
121
I0
Q Clk
K
Q CLR
1
(b) JK-flipflop
Figuur 4.23: Implementatie van de Mealy-schakeling met verschillende soorten flipflops. Daarna is het alleen nog een kwestie van de schakeling te implementeren, dit wordt meestal opnieuw gedaan met behulp van Karnaugh-kaarten. We implementeren vervolgens op figuur 4.24 een volledige sequenti¨ele schakeling gebaseerd op de Mealy-machine met een D-flipflop. Merk op dat we in deze figuur gebruik maken van de Q-uitgangen. Hoewel we in de figuur de logica implementeren met AND-OR logica zal men in de praktijk altijd opteren voor NAND- en NOR-poorten bij de implementatie. Een andere interessante vaststelling dat het geheugen van de tweede flipflop niet gebruikt wordt. We kunnen bijgevolg deze flipflop en de logica er rond weglaten. Deze extra flipflop is het gevolg van een slecht gekozen toestandscodering. Dit drukt niet alleen de kosten, maar zorgt ook voor een kleinere vertraging waardoor we de klokfrequentie kunnen opdrijven. We gaan kort in op het tijdsgedrag in subsectie 4.3.6.
4.3.6
Tijdsgedrag
Tot slot bepalen we de maximale klokfrequentie die we bij een implementatie van een sequenti¨ele schakeling kunnen hanteren. We herinneren ons uit het hoofdstuk over combinatorische schakelingen dat de vertraging in een systeem bepaald wordt door het kritische pad, de maximale tijd die een signaal nodig heeft om zich doorheen de schakeling voort te planten. In een sequenti¨ele schakeling betekent dit dat het signaal zich doorheen de combinatorische schakeling dient te propageren die de volgende toestand bepaalt. Verder dient ook de set-tup-tijd van de geheugenmodules en de tijd die het kloksignaal nodig heeft om zich tot aan de Q- of Q-uitgang te propageren in rekening te worden gebracht. Bij het bepalen van het kritische pad van de transitiefunctie moeten we alle paden vanuit alle ingangen (dus ook de flipflops die toestand bijhouden) beschouwen, naar alle flipflops. Of formeler: vertraging pad = logica transitie + set-up flipflop + Clk naar Q of Q
(4.12)
De vertragingen van de klok naar Q en Q kunnen we berekenen vanuit de implementatie van de flipflop. De fabrikant van een flipflop zal bovendien steeds deze vertragingen in het datasheet19 van de component zetten. Indien de implementatie gegeven is, kunnen we de vertraging berekenen. Indien we een master-slave D-flipflop gebruiken dienen we enkel rekening te houden met de propagatietijd van de klok naar Q of Q van 19 Elk ge¨ ıntegreerd circuit heeft een datasheet, een document opgesteld door de producent die de karakteristieken van de component formeel beschrijft.
122
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) 1 PR D
O0
Q
F F0 Clk Q CLR
Clr∗ 1
O0 -
PR
I0
D
F2
Q
F1
F F1
F0
Clk Q CLR
0 0 - - 0 - - 1 - - 0 0 -
I0 PR D
Q
F F2
Clk
Clk Q CLR
1 Figuur 4.24: Volledige implementatie van de Mealy-machine met D-flipflops.
een D-latch. We hebben deze vertragingen reeds uitgerekend in vergelijking (4.3) op pagina 97. Eenmaal we de vertraging van het kritisch pad hebben berekend kunnen we de maximale klokfrequentie bepalen. Dit doen we door het inverse te berekenen van deze vertraging:
fmax. =
1 vertraging kritisch pad
(4.13)
Merk wel op dat we bij het berekenen van de vertraging geen eenheid gegeven hebben. Deze vertragingen die we tot hier toe hebben berekend dienen uitsluitend om verschillende implementaties met elkaar te vergelijken. In de praktijk zal de technologie waarmee we de schakeling realiseren een tijds´e´enheid impliceren waarmee we die vertraging kunnen vermenigvuldigen.
Leidend voorbeeld
Moore-machine We berekenen de vertraging van de implementatie van de Moore-machine die beschreven staat op figuur 4.22(a). In totaal kunnen we 10 verschillende paden onderscheiden: in de schakeling staan twee flipflops. Het signaal van deze flipflops vormt een ingang bij alle 5 de AND-poorten. Merk op dat we de inverter aan de AND-poort niet moeten meetellen in onze berekening. We dienen in dat geval de Q-uitgang te beschouwen. In de onderstaande vergelijking berekenen we de vertraging van alle paden. Het subscript van de vertraging wijst op de bron- en doel-flipflop, en de AND-poort. Deze poorten nummeren we van 0
4.4. ASYNCHRONE SCHAKELINGEN tot 4 van boven naar beneden: tF F0 →F F0 ,0 = Clk → Q + set-up t F F0 →F F0 ,1 = Clk → Q + set-up t F F0 →F F1 ,2 = Clk → Q + set-up tF F0 →F F1 ,3 = Clk → Q + set-up tF F0 →F F1 ,4 = Clk → Q + set-up tF F1 →F F0 ,0 = Clk → Q + set-up tF F1 →F F0 ,1 = Clk → Q + set-up tF F1 →F F1 ,2 = Clk → Q + set-up tF F1 →F F1 ,3 = Clk → Q + set-up tF F1 →F F1 ,4 = Clk → Q + set-up
D + 2-AND + 2-OR = 4.2 + 1 + 2.4 + 2.4 = 10.0 D + 3-AND + 2-OR = 4.2 + 1 + 2.8 + 2.4 = 10.4 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8 D + 2-AND + 2-OR = 4.2 + 1 + 2.4 + 2.4 = 10.0 D + 3-AND + 2-OR = 4.2 + 1 + 2.8 + 2.4 = 10.4 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8 D + 3-AND + 3-OR = 4.2 + 1 + 2.8 + 2.8 = 10.8
123
(Voorbeeld)
(4.14) Het maximale pad heeft dus een vertraging van 10.8. Indien we een referentievertraging van 1 ns nemen, is de maximale frequentie fmax. = 1/10.8 ns ≈ 93 MHz. Indien we dezelfde schakeling met NAND-NAND logica zouden hebben gebouwd, zou de vertraging van elk pad gereduceerd worden met 2. In dat geval zou de maximale klokfrequentie fmax. = 1/8.8 ns ≈ 114 MHz. Mealy-machine Voor de Mealy-machine gebruiken we de implementatie op figuur 4.24. In deze schakeling dienen we twee paden te beschouwen: het eerste loopt van F F1 naar F F0 , vertrekt vanuit Q en gaat door ´e´en 2-AND-poort. Het andere pad ligt tussen F F1 en F F2 . Ook hierbij passeren we een 2-AND-poort, merk echter op dat het signaal vertrekt vanuit Q. De vertraging van dit pad is dus gelijk aan: tF F1 →F F0 = Clk → Q + set-up D + 2-AND = 4.2 + 1 + 2.4 = 7.6 (Voorbeeld) (4.15) tF F1 →F F2 = Clk → Q + set-up D + 2-AND = 4.2 + 1 + 2.4 = 7.6 Beide paden hebben hier dus dezelfde vertraging. Als we een referentievertraging van 1 ns nemen, is de maximale frequentie fmax. = 1/7.6 ns ≈ 131 MHz.
4.4
Asynchrone schakelingen
Naast schakelingen waar het ritme bepaald wordt door een klok, bestaan er ook schakelingen die een vorm van geheugen bezitten, maar van toestand veranderen doordat het ingangssignaal verandert. We hebben in dit hoofdstuk reeds dergelijke schakelingen ge¨ımplementeerd. In Subsectie 4.2.1 hebben we een latch geconstrueerd. Een latch heeft in principe geen klokingang, maar houdt wel een toestand bij. Op het moment dat we een ingang aan een SR-latch aanpasen, zal de latch soms in een andere toestand terechtkomen. Verder bezit de component ook duidelijk een geheugen vermits als de ingang (S, R) = (0, 0), de vorige toestand behouden blijft. De situatie van de latch illustreert hoe asynchrone schakelingen worden gerealiseerd: We hebben een aantal ingangssignalen, die door logica worden verwerkt in een soort geheugen. Dit geheugen vertraagt een terugkoppeling, en houdt de toestand bij. Het terugkoppelen betekent dat de uitgangen van een logische schakeling als een deel van de invoer fungeren die door die logica verwerkt wordt. In deze cursus zullen we uitsluitend asynchrone sequenti¨ele schakelingen beschouwen die voldoen aan een belangrijke voorwaarde: de fundamentele modus, ofwel de “fundamental mode restriction”. Deze beperking bestaat uit twee delen: • Er mag hooguit ´e´en ingangssignaal tegelijk veranderen. Een voorbeeld die dit concept duidelijk illustreert is de SR-latch: indien we S en R ingang tegelijk van 1 naar 0 omschakelen, komt de component in een oscillerend toestand komt. • Een ingangsverandering mag slechts optreden als alle effecten van de vorige verandering uitgestorven zijn. Ook dit principe kennen we al impliciet. Zo dienen we de set-up tijd van een flipflop te respecteren om te voorkomen dat de flipflop in een onvoorspelbare toestand komt. We zijn in principe niet verplicht om ons aan deze voorwaarden te houden, het ontwerpen van schakelingen die deze restricties niet volgen is echter zeer moeilijk.
124
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Ook bij het ontwerpen van een asynchrone schakeling zullen we een stappenplan volgen. In grote lijnen lijkt deze procedure op het ontwikkelen van synchrone schakelingen. De stappen zelf wijken echter sterk af van hun synchrone variant. In de meeste stappen zullen we ook met de complexe problemen die eigen zijn aan een asynchrone schakeling moeten rekening houden. Het plan bestaat uit 4 stappen: 1. Opstellen van een toestandstabel. 2. Minimaliseren van het aantal toestanden. 3. Coderen van de toestanden. 4. Realisatie van de schakeling met digitale logica. Terminologie Bij synchrone schakelingen werkten we met een klokflank. Vaak gebruikt men bij een kloksignaal de termen “stijgende klokflank” en “dalende klokflank”. Dit zijn immers de tijdstippen waarop gebeurtenissen plaatsvinden in de schakeling die relevant zijn. Een asynchrone schakeling heeft geen kloksignaal. Toch worden de termen “stijgende flank” en “dalende flank” ook in deze context gebruikt. De gebeurtenissen in een asynchrone schakeling zijn immers de omschakeling van ´e´en van de ingangssignalen.
4.4.1
Leidend voorbeeld
Een oplettende lezer heeft misschien al opgemerkt dat de geheugencomponenten die we gebruiken in synchrone schakelingen – latches en flipflops – op hun beurt weer asynchrone schakelingen zijn. Daarom zullen we een nieuw type latch ontwerpen, die uiteraard louter fictief is. De latch wordt gebruikt als een interrupt-register. In de meeste computers voert een programma niet constant controles uit of een gebruiker bijvoorbeeld een toets aanslaat. De CPU bevat een component die bijhoudt of er een bepaalde gebeurtenis plaatsvindt. Hardwarematig controleert de CPU frequent of zo’n gebeurtenis is opgetreden. In dat geval voert de processor een procedure uit gedefinieerd door het besturingssysteem. Op dat moment dient de component uiteraard gereset te worden. Verder kan een besturingssysteem ook een masker plaatsen op een interrupt. In dat geval zal de CPU niet reageren op deze gebeurtenis. Deze component heeft twee ingangen I en E. I zal een stijgende flank vertonen wanneer de gebruiker een toets aanslaat, maar zal na enige tijd weer dalen. E bepaalt of de CPU luistert naar deze interrupt. Indien E = 0 heeft het besturingssysteem een masker gezet. Indien we een laag signaal op E aanleggen wordt een reset op de module uitgevoerd. Dit is het geval wanneer de processor de procedure van het besturingssysteem zal uitvoeren. Op het moment dat de procedure uitgevoerd is, zetten we E dan terug hoog om te luisteren naar een mogelijke gebeurtenis. De uitgang Q vertelt ons of er een gebeurtenis is opgetreden op het moment dat er geen masker op de interrupt. Formele beschrijving De vorige paragraaf is relatief informeel beschreven. We zetten deze beschrijving om in een formeler equivalent. Dit doen we aan de hand van tabel 4.10. In de eerste kolom plaatsen we de gebeurtenis. Dit is dus een ingang die van waarde verandert. De tweede kolom bevat de voorwaarden die relevant zijn voor deze regel. Dit zijn testen in verband met ingangen en uitgangen. De derde kolom ten slotte bevat het effect. Een effect houdt in dat de uitgang verandert. Merk verder op dat het onmogelijk is Gebeurtenis I:0→1 E:1→0
Voorwaarde(n) E=1
Effect(en) Q→1 Q→0
Tabel 4.10: Formele beschrijving van het leidend voorbeeld. dat Q een 1 bevat en E een 0.
4.4.2
Stap 1: Opstellen van een toestandstabel
Net zoals bij de synchrone schakelingen stellen we eerst een toestandstabel op. Een eerste vraag die zich stelt is wat een toestand is. Een toestand is elke combinatie van in- en uitgangen waarin de schakeling
4.4. ASYNCHRONE SCHAKELINGEN
125
kan terechtkomen. De schakeling die we zullen implementeren telt 3 verschillende signalen. Dit betekent dus dat we hooguit 8 toestanden kunnen bekomen. Aangezien configuraties met (Q, E) = (1, 0) onmogelijk kunnen voorkomen houden we 6 toestanden over. We stellen een configuratietabel op die voor elke mogelijke configuratie een toestand voorziet in tabel 4.10(a). Op basis van deze configuratietabel kunnen we nu een (a) Configuratietabel
Toestand a b c d (onmogelijk) e (onmogelijk) f
Q 0 0 0 0 1 1 1 1
I 0 0 1 1 0 0 1 1
(b) Toestandstabel
E 0 1 0 1 0 1 0 1
Toestand a b c d e f
00 a a a − a −
I E 01 11 b − b f − d b d e f e f
10 c − c c − c
Q 0 0 0 0 1 1
Tabel 4.11: Configuratie- en toestandstabel van het leidend voorbeeld. toestandstabel maken. Deze toestandtabel loopt erg gelijk met een toestandstabel van een Moore-machine. De tabel bestaat uit drie delen: toestand, invoer en uitvoer. Een verschil met de toestandtabel van de Moore-machine is dat we niet alle kolommen invullen bij elke toestand. Een toestand is immers gekoppeld aan een bepaalde invoerconfiguratie20 , de fundamentele modus zorgt ervoor dat er slechts ´e´en bit tegelijk kan omslaan, bijgevolg kunnen we kolommen die op meerdere bits afwijken niet invullen. Concreet betekent dit dat we voor een invoer van n-bits, n + 1 van de 2n kolommen kunnen invullen. In de overige kolommen schrijven we een liggende streepje (“-”). Veelal zal men ook de kolommen van de toestandtabel anders schikken. Men probeert configuraties die slechts ´e´en bit verschillen naast elkaar te plaatsen. Dit is echter niet vereist. We stellen de toestandstabel op met behulp van de configuratietabel en de tabel met mogelijke gebeurtenissen. Toestand a betekent in dit geval bijvoorbeeld dat we (I, E) = (0, 0) aan de ingangen aanleggen. Het spreekt dus voor zich dat we bij de kolom met dezelfde configuratie ook een a schrijven. In dat geval is de toestand stabiel. Bij de tweede kolom geldt (I, E) = (0, 1), dit betekent dus dat we een stijgende flank van E beschouwen. Uit de gebeurtenissentabel leiden we af dat in dat geval Q op 0 komt te staan. Dit is reeds het geval. We migreren dus naar de toestand met (Q, I, E) = (0, 0, 1). Op de configuratietabel zien we dat dit toestand b is. Bij de laatste kolom beschouwen we een stijgende flank van I, opnieuw gebeurt er niets vermits er niet aan de voorwaarden wordt voldaan in de gebeurtenissentabel. Op deze manier kunnen we de volledige toestandstabel opstellen zoals in tabel 4.10(b). We kunnen ook met behulp van een toestandsdiagram een grafische voorstelling van deze tabel geven. Het toestandsdiagram staat op figuur 4.25. Een toestandtabel bij asynchrone schakelingen wordt ook een “flow table” genoemd. Indien de tabel nog niet geminimaliseerd is, spreekt met van een “primitive flow table”.
4.4.3
Stap 2: Minimaliseren van de toestanden
Net als bij synchrone schakelingen loont het meestal de moeite om de toestandsruimte te minimaliseren. Dit leidt immers in de meeste gevallen tot een goedkopere schakeling. Vermits het probleem anders is, vertoont de minimalisatie van asynchrone schakelingen ook verschillen tegenover synchrone schakelingen. Een belangrijk verschil is dat we in de flow toestandstabel ook rekening moeten houden met don’t cares. Elke toestand heeft er immers 2n − n − 1 bij n-bit invoer. Daarnaast kunnen er uiteraard nog bijkomende don’t cares optreden die probleemafhankelijk zijn. Meestal laten deze don’t cares toe om op een flexibele manier de toestandsruimte te minimaliseren. 20 Beschreven
in de configuratietabel.
126
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN) 11 f
e 1
01
1
11
01 00
11 01
a 0
00
00 10 11
00 10
b 0
01
d 0
11
00
c 0
10 10
Figuur 4.25: Toestandsdiagram van het leidend voorbeeld. Er bestaan verschillende methodes om de toestandsruimte te minimaliseren. We opteren voor een methode die werkt met twee stappen. Allereerst is er de partitionering. Deze partitionering is volledig analoog aan de sequenti¨ele schakelingen (zie 4.3.3 op pagina 110). We dienen echter de voorwaarden van deze partitionering minimaal aan te passen. De nieuwe voorwaarde wordt dan: 1. De toestanden hebben dezelfde uitgangscombinatie. 2. De don’t cares bevinden zich in dezelfde kolommen. Vervolgens passen we opnieuw de iteratiestap toe zoals bij synchrone schakelingen. De voorwaarden veranderen hierbij niet. Nadat we de partitionering berekend hebben, kunnen we een eerste toestandsreductie toepassen. Bij de synchrone schakelingen betekent de toestandreductie dan ook meteen het einde van de minimalisatie. Bij synchrone schakelingen kunnen we verder reduceren. Hiertoe berekenen we compatibele toestanden21 . Twee toestanden Si en Sj zijn equivalent indien: 1. Dezelfde uitvoerconfiguratie hebben 2. Voor elke ingangscombinatie geldt ofwel: (a) Si en Sj zijn beide stabiel (b) De volgende toestand van minstens ´e´en van de twee toestanden Si of Sj is niet gespecificeerd, er staat dus een don’t care in de kolom van minstens ´e´en van de toestanden. (c) Beide toestanden gaan naar dezelfde toestand Sk . Merk op dat de toestanden Si , Sj en Sk niet de toestanden zijn uit de initi¨ele toestandstabel, maar uit de door partitionering reeds gereduceerde toestandstabel. Een andere mogelijke valkuil is dat beide toestanden naar dezelfde toestand moeten gaan, niet naar twee compatibele of equivalente toestanden. De reden hiervoor is dat de compatibiliteitsrelatie niet transitief is: Als toestand A compatibel is met toestand B en B is compatibel met toestand C, is A niet noodzakelijk compatibel met toestand C. De relatie is echter wel symmetrisch22 en uiteraard reflexief. 21 Bemerkt 22 Dit
het verschil met “equivalente toestanden” bij de partitionering. kunnen we eenvoudig aantonen door Si en Sj om te wisselen. In dat geval zien we dat de voorwaarden niet veranderen.
4.4. ASYNCHRONE SCHAKELINGEN
127
Het feit dat er de compatibiliteitsrelatie niet transitief is introduceert ook een nieuw probleem: we willen verschillende compatibele toestanden samennemen in ´e´en nieuwe toestand, een zogenaamde kliek Kn . Vermits hiervoor elke twee toestanden compatibel met elkaar moeten zijn, is dit proces niet deterministisch. Men kan dit probleem op verschillende methodes oplossen. In de praktijk lost men dit vaak op met behulp van programma’s die zoeken naar een zo goed mogelijke groepering. Nadat we een groepering hebben bepaald, minimaliseren we opnieuw de toestandentabel. Dit betekent echter nog niet dat het minimalisatiealgoritme ten einde is: door het groeperen van toestanden in een nieuwe toestand, kunnen deze nieuwe toestanden weer compatibiliteit vertonen. We dienen dus opnieuw een compatibiliteitsrelatie op te bouwen en eventueel te minimaliseren. De minimalisatie stopt op het moment dat geen enkele nieuwe toestand meer compatibel is met een andere. Schematisch geven we het hele proces weer in een flowchart op figuur 4.26. Partitioneren van de toestanden
Start
Bepaal compatibele toestanden Groepeer compatibele toestanden Samenvoegen van de toestanden in een groep
yes
Toestandstabel veranderd?
no
Stop
Figuur 4.26: Flowchart van het minimalisatieproces van asynchrone schakelingen.
Samenvoegen van toestanden in een nieuwe toestand Hoe bouwen we vanuit een groep toestanden een nieuwe toestand op? Dit kunnen we in principe al afleiden uit de definitie van compatibele toestanden. Uit de toestanden {s1 , s2 , . . . , sn } construeren we een toestand t indien alle toestanden met elkaar compatibel zijn. We dienen bij t ook de overgangen te defini¨eren: s gaat onder een invoer I over naar δ (s, I). Deze functie noemen we ook de transitie-functie. Verder voeren we ook een functie G (s) in, deze functie geeft de nieuwe toestand weer van de groep waar s toe behoort. We kunnen dan volgende regels op t defini¨eren23 : 1. δ (t, I) = − indien ∀i : δ (si , I) = −. We plaatsen een don’t care bij een transitie van t met invoer I als elke toestanden si onder deze invoer ook een don’t care bevat. 2. δ (t, I) = t indien ∀i : δ (si , I) = − ∨ δ (si , I) ∈ {s1 , s2 , . . . , sn }. Indien alle toestanden onder invoer I binnen de groep blijven of een don’t care bevatten, vormt t onder invoer I een stabiele toestand. 3. δ (t, I) = u indien ∀i : δ (si , I) = −∨G (δ (si , I)) = u. Indien alle toestanden onder invoer I naar dezelfde groep transformeren, transformeert t onder deze invoer naar de toestand die deze groep voorstelt. 23 We voeren de regels in de volgorde van verschijnen uit. Het kan zijn dat een situatie aan twee criteria voldoet, in dat geval voeren we de eerste regel uit.
128
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Voorbeeld Om alle speciale gevallen in te sluiten gebruiken we een andere toestandstabel beschreven in tabel 4.11(a). Allereerst passen we de initialisatiestap van het partitiealgoritme toe. We dienen hierbij buiten een verschil(a) Initi¨ ele tabel
Toestand a b c d e f g h i j k l m
00 a − − − g − l − i b − − m
I E 01 11 f − b h c g f d − d f k g j l h e − − − b k l k l −
(b) Tabel na partitionering
10 c − j − e − − e f j e − e
Q
Toestand
0 1 0 1 1 0 0 1 1 0 1 1 1
a b c d e f g h i j m
00 a − − − g − b − i b m
I E 01 11 f − b h c g f d − d f h g j b h e − − − b −
10 c − j − e − − e f j e
Q 0 1 0 1 1 0 0 1 1 0 1
Tabel 4.12: Evolutie van de toestandstabel bij het minimaliseren voor en na partitioneren. lende uitvoerconfiguratie ook rekening te houden met verschillende don’t care configuraties. Dit leidt tot de volgende partitie: P0 = {{a} , {b, d, l} , {c} , {e} , {f } , {g} , {h, k} , {i, m} , {j}} (voorbeeld)
(4.16)
Na het iteratieproces bij de partitionering die wel volledig behouden blijft bekomen we volgende partitie: P1 = {{a} , {b, l} , {c} , {d} , {e} , {f } , {g} , {h, k} , {i} , {j} , {m}} (voorbeeld)
(4.17)
Op basis van deze partitionering kunnen we een nieuwe toestandstabel opstellen: tabel 4.11(b). We gebruiken hier telkens de alfabetisch eerste letter van de toestanden die in een bepaalde partitie zitten. Dit is echter een arbitraire keuze. Vervolgens minimaliseren we verder door een compatibiliteitsrelatie op te stellen. Zo is a duidelijk niet compatibel met b net als a en d, ze hebben immers een verschillende uitvoer. Ook (a, c) en (a, e) zijn duidelijk geen elementen van de relatie: a en c gaan onder invoer (0, 1) naar een verschillende toestand, hetzelfde geldt voor a en e onder invoer (1, 0). (a, f ) behoort dan weer wel tot de relatie. Het zijn beide toestanden met dezelfde uitvoer, en in alle mogelijke invoercombinaties heeft ofwel minstens ´e´en van de toestanden een don’t care, of wijzen ze naar dezelfde toestand. Alle andere toestanden zijn niet compatibel met a omwille van hiervoor opgesomde redenen. We kunnen zo verder alle toestanden tegen elkaar uitspelen, en defini¨eren zo de equivalentierelatie ≡0 als volgt24 : a ≡0 f b ≡0 h b ≡0 m c ≡0 j (4.18) d ≡0 e f ≡0 j g ≡0 j h ≡0 m We kunnen deze relatie ook grafisch voorstellen, dit doen we met behulp van een Merger diagram. Hierbij stellen we de toestanden voor als knopen, en indien twee toestanden compatibel zijn, tekenen we een ongerichte boog tussen de knopen die deze toestanden voorstellen. Een dergelijk Merger diagram staat op figuur 4.27(a). We kunnen vervolgens een keuze maken welke compatibele toestanden we samennemen. Merk op 24 Bij de definitie hebben we de symmetrische redundantie weggelaten. Het spreekt echter voor zich dat als x ≡ y, dat ook 0 geldt y ≡0 x
4.4. ASYNCHRONE SCHAKELINGEN
a
g
b
f
j
m
i
c
d
129
h
e
a
b
c
d
i
g
(a) Iteratie 1
a
b
d
i
(b) Iteratie 2
c
(c) Iteratie 3
Figuur 4.27: Merger-diagrammen van het leidend voorbeeld. dat we enkel toestanden kunnen samennemen als elke twee toestanden compatibel met elkaar zijn. Zo kunnen we {a, f } samennemen, maar {a, f, j} is niet mogelijk omdat a en j niet compatibel met elkaar zijn. Op figuur 4.27(a) duiden we met behulp van de stippelijnen aan welke toestanden we hebben samengenomen. Of formeler: P2 = {{a, f } , {b, h, m} , {c, j} , {d, e} , {g} , {i}} (voorbeeld) (4.19) We hadden echter in plaats van {c, j} ook voor {g, j} kunnen opteren. Of {a, f } en {c, j} kunnen inwisselen voor {f, j}. Men kan argumenteren dat we met de laatste configuratie minder toestanden wegwerken. Merk echter op dat we eventueel na deze iteratie nog iteraties kunnen uitvoeren en toestanden wegwerken. Een strategie waarin we in elke iteratie het aantal toestanden maximaal reduceren zal niet altijd tot het beste resultaat leiden. We genereren vervolgens voor elke voorgestelde groep een nieuwe toestand. Deze toestand stellen we met de alfabetisch laagste letter voor van de toestanden die de groep omvat. De toestandstabel die hieruit voortkomt staat in tabel 4.12(a). Hierbij voegen we dus de toestanden samen. We zullen in deze tekst de (b) Iteratie 2 en 3
(a) Iteratie 1
Toestand a b c d g i
00 a b b g b i
I E 01 11 a b b b c g a d g c d −
10 c d c d − a
Q
Toestand
0 1 0 1 0 1
a b c d i
00 a b b c i
I E 01 11 a b b b c c a d d −
10 c d c d a
Q 0 1 0 1 1
Tabel 4.13: Evolutie van de toestandstabel bij het minimaliseren voor en na twee iteraties. groep {b, h, m} volledig uitwerken. Deze groep hebben we voorgesteld door b. Bij de invoer (0, 0) zien we dat zowel b als h een don’t care bevatten. Voor m is dit echter een stabiele toestand, bijgevolg is deze ingang ook een stabiele toestand. Bij de configuratie (0, 1) wijzen alle toestanden naar b, vermits b in de groep zit die later b zal worden, plaatsen we b in de tabel. Indien (1, 1) op de ingang wordt aangelegd gaan b en h naar h, m bevat een don’t care. We kunnen dus zonder problemen ook h invullen bij die don’t care. h is een onderdeel van de groep die later toestand b zal worden. Bijgevolg kunnen we ook voor deze kolom b invullen. In de laatste configuratie ten slotte – (1, 0) – gaan h en m naar e. We zien dat e een onderdeel is van de groep {d, e}. Deze groep zal dus later voorgesteld worden door de toestand d. Bijgevolg vullen we d in. Indien we deze procedure ook toepassen op de andere groepen resulteert dit in tabel 4.12(a). Hiermee zijn we aan het einde gekomen van de eerste iteratie. Vermist we echter een andere toestandstabel hebben tegenover het begin van de iteratie, dienen we een nieuwe iteratie aan te vatten. Hierbij berekenen we opnieuw een compatibiliteitsrelatie: ≡1 . We zullen de berekening van deze relatie achterwege laten, vermits we reeds de
130
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
vorige relatie uitgebreid hebben beschreven. We defini¨eren ≡1 op symmetrie na als volgt: c ≡1 g
(4.20)
Het Merger-diagram van deze relatie staat op figuur 4.27(b). Hier is de keuze van de groep wel deterministisch. De nieuwe partitie is dus: P3 = {{a} , {b} , {c, g} , {d} , {i}} (voorbeeld)
(4.21)
Op basis van deze partitie ruilen we dus {c, g} in voor een nieuwe toestand c. De vernieuwde toestandstabel is dan tabel 4.12(b). Merk op dat we niet enkel de rij van toestand c moeten aanpassen. Ook toestanden die naar g kunnen springen, springen nu naar c, bijvoorbeeld toestand d. Opnieuw hebben we dus de toestandstabel aangepast. Dit impliceert dat we nogmaals een iteratie uitvoeren. De compatibiliteitsrelatie ≡2 blijkt echter leeg te zijn, geen enkele toestand is dus compatibel met een andere. Dit leidt tot een Merger-diagram zoals op figuur 4.27(c). We kunnen bijgevolg geen toestanden groeperen waardoor de tabel onveranderd blijft. We hebben dus het aantal toestanden geminimaliseerd tot 5 zoals in tabel 4.12(b). Alternatieve groepering Bij de eerste iteratie bij het samenvoegen van de toestanden, konden we kiezen tussen twee vormen van groeperingen. Ofwel groeperen we c en j ofwel g en j. Anderzijds hadden we ook f en j kunnen samenvoegen, maar deze configuratie is minder voordelig. We zullen bij wijze van extra voorbeeld ook het alternatieve scenario bespreken. Wanneer we dit alternatieve scenario uitwerken bekomen we na ´e´en iteratie de waarden op Tabel 4.13(a). Op basis van deze tabel kunnen we verder bepalen welke (b) Iteratie 2 en 3
(a) Iteratie 1
Toestand a b c d g i
00 a b − g b i
I E 01 11 a b b b c g a d g g d −
10 c d g d g a
Q
Toestand
0 1 0 1 0 1
a b c d i
00 a b b c i
I E 01 11 a b b b c c a d d −
10 c d c d a
Q 0 1 0 1 1
Tabel 4.14: Evolutie van de toestandstabel bij een alternatieve minimalisering voor en na twee iteraties. toestanden compatibel zijn. Door de definitie van compatibele toestanden toe te passen zien we dat enkel c en g compatibel met elkaar zijn. Vermits er geen alternatieven zijn, voegen we beide toestanden samen en bekomen we Tabel 4.13(b). We kunnen opmerken dat deze tabel volledig identiek is aan de Tabel 4.12(b). Bijgevolg kunnen we deze tabel ook niet verder minimaliseren. We kunnen ook besluiten dat zelfs wanneer we een keuze kunnen maken tussen verschillende alternatieven, dit niet noodzakelijk betekent dat we een andere ofwel minder minimale configuratie zullen uitkomen. Soms kan men via verschillende keuzes toch hetzelfde of een even goedkope configuratie bekomen. Anderzijds is dit geen algemeen geldend principe: de keuze welke toestanden zullen worden samengevoegd kan wel degelijk verschillende eindconfiguraties opleveren. Leidend voorbeeld Bij wijzen van oefening kan de lezer de toestandstabel van het leidend voorbeeld minimaliseren. De oplossing staat in Subsectie ??.
4.4.4
Stap 3: Codering van de toestanden
Net als bij synchrone schakelingen moeten we elk van deze toestanden op een manier coderen in het geheugen. Het probleem is dat we bij het coderen van toestanden bij asynchrone schakelingen op nieuwe problemen stuiten.
4.4. ASYNCHRONE SCHAKELINGEN
131
Terminologie Deze problemen brengen nieuwe terminologie met zich mee die we eerst zullen introduceren: • Race: Een fenomeen dat optreedt wanneer door ´e´en ingangsbit te veranderen er minstens twee toestandsvariabelen moeten veranderen. • Critical race: Indien een race tot een tijdelijk verkeerde toestand leidt (de codering van een andere toestand dus) spreken we van een critical race. • Cycle: Een sequentieel circuit werkt met terugkoppeling. Door deze terugkoppeling kunnen er oscillerende effecten optreden. Een race die in een oscillerend effect uitmondt heet een cycle. Het optreden van deze een critical race of cycle hangt af van de vertragingskarakteristieken van de poorten. Het spreekt voor zich dat we trachten om deze fenomenen te voorkomen. Daarom zullen we ook technieken ontwikkelen die ons toelaten een goede toestandscodering te ontwikkelen waarbij we deze problemen reeds kunnen voorkomen. Figuur 4.28 illustreert het principe van een critical race en cycle. Op Figuur 4.28(b) en e i S s1 s0
00
hi, ei 01 11
10
Q q
00 01 10
00 00 00
01 01 10
00 −− 00
0 0 1
00 10 10
(a) Toestandstabel.
e i s0
s0
a
a0 s1 q
s1 b0
b (b) Implementatie 1.
(c) Implementatie 2.
i
i
i
a
a0
a
b
b0
b
s1
s1
s0
s0
s0
s1
(d) Verwacht gedrag.
q
(e) Cycle.
(f) Critical race.
Figuur 4.28: Voorbeelden van een cycle en critical race. Figuur 4.28(c) stellen we twee equivalente asynchrone schakelingen voor. Het enige wat we hebben aangepast is de twee NAND-poorten omzetten naar AND-poorten alsook een NAND-poort naar een OR-poort. In een combinatorische schakeling is dit een perfect geldige transformatie die tot equivalente resultaten leidt. In de implementatie bepalen de signalen s0 en s1 samen de toestand, q bepaald de uitvoer en i en e de invoer. Bij wijze van voorbeeld beschouwen we het systeem in een toestand hs0 , s1 i = h1, 0i met aan de ingang een signaal hi, ei = h0, 1i. We veranderen vervolgens het signaal van i waardoor we volgens de toestandstabel op Figuur 4.28(a) in toestand hs0 , s1 i = h1, 0i zullen terechtkomen. Wanneer we dit doen volgens de eerste schakeling bekomen we het tijdsgedrag zoals op Figuur 4.28(d). We zien dat beide toestandsignalen tegelijk veranderen. Zelfs wanneer er een klein tijdsverschil op de verandering zit zal dit echter niet tot grote problemen leiden. Wanneer we echter werken met de tweede oplossing is het tijdsverschil veel groter. Hierdoor ontstaat er een terugkoppeling tussen het signaal b0 en s1 . Beide reageren telkens op de verandering van de ander waardoor we in een cycle terechtkomen. De toestandsverandering wordt dus hs0 , s1 i = h0, 1i → h0, 0i → h0, 1i → . . ..
132
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Het aantal bits dat verandert tussen twee toestanden is een belangrijke eigenschap, deze wordt vaak ook de “Hamming distance” ofwel “Hammingafstand” genoemd, en is enkel gedefinieerd tussen twee bitreeksen van dezelfde lengte. Elimineren van critical races Men kan critical races elimineren door ervoor te zorgen dat er nooit twee of meer toestandssignalen tegelijk moeten veranderen. Overgangen zoals van 00 naar 11 zijn dus uit den boze. Er zijn grofweg drie methodes waarmee we dit kunnen realiseren. We zullen deze methodes ordenen volgens het vermogen om problemen op te lossen. Zo is de laatste methode in staat om alle problemen op te lossen, maar zal deze meestal een hoge kostprijs met zich meebrengen. We proberen dus de problemen op te lossen in de volgorde waarin de methodes worden voorgesteld. Verder zullen de methodes meestal in staat zijn een gedeelte van het probleem op te lossen, waarna de andere methodes de overige problemen kunnen oplossen. De methodes zijn: 1. Het kiezen van een toestandscodering die elke overgang realiseert door hooguit ´e´en bit te veranderen. 2. Werken met zogezegde “tussentoestanden”: via een reeds bestaande toestand toch de finale toestand bereiken, bij de verschillende overgangen verandert dan telkens slechts ´e´en bit. 3. Het introduceren van “overgangstoestanden”: nieuw toestanden toevoegen die geen functionaliteit hebben buiten deze van het doorverwijzen naar een andere toestand. We zullen elk van deze methodes in de volgende subsubsecties bespreken en toepassen op twee voorbeelden. De toestandstabellen van beide voorbeelden zijn gegeven in Tabel 4.14(a) en Tabel 4.14(b). In de tabellen (b) Voorbeeld 2.
(a) Voorbeeld 1.
Toestand
00
01
11
10
Uitgang
Toestand
00
01
11
10
Uitgang
a b c d
a1 b3 a b
b b4 c5 −
a2 c c6 a
c d d d7
00 01 10 11
a b c
a1 a a
b b4 c5
a2 − a
a3 c c6
0 0 1
Tabel 4.15: Toestandstabellen van de leidende voorbeelden bij de asynchrone toestandscodering. werden sommige overgangen geannoteerd met een subscript. Deze overgangen zijn stabiele configuraties: een set van toestand- en ingangbits die tot dezelfde toestand zullen leiden. In het eerste geval zijn er zeven van deze stabiele configuraties, in het tweede voorbeeld zes. Deze configuraties zijn: ha, h0, 0ii1 ha, h0, 0ii1 ha, h1, 1ii2 ha, h1, 1ii2 hb, h0, 0ii3 ha, h1, 0ii3 hb, h0, 1ii4 T2 = (4.22) T1 = hb, h0, 1ii4 hc, h0, 1ii 5 hc, h0, 1ii5 hc, h1, 1ii6 hc, h1, 0ii6 hd, h1, 0ii7 Deze stabiele configuraties spelen een belangrijke rol in de verschillende methodes en het transitiediagram. Methode 1: Zoeken naar een goede codering Hierbij kunnen we terugdenken aan de “minimal-bit-change” en de “Gray-code teller” uit 4.3.4. Deze methode lost in de meeste gevallen reeds heel wat problemen op. Een methode die het beste resultaat oplevert is
4.4. ASYNCHRONE SCHAKELINGEN
133
alle mogelijk toestandscoderingen afgaan en vervolgens het aantal overgangen met 1 veranderende bit tellen. Deze methode is niet effici¨ent vermits we O (n!) verschillende configuraties moeten analyseren. We kunnen uiteraard met behulp van heuristische methodes reeds tot een acceptabele configuratie komen. Bovendien is de kans groot dat niet elke overgang tot 1 veranderende bit is te herleiden, in dat geval moeten we de andere methodes gebruiken. Een optimale configuratie in methode 1 leidt niet noodzakelijk tot het beste eindresultaat. Voorbeeld Bij wijze van voorbeeld zullen we een goede codering zoeken voor beide voorbeelden. Het eerste geval (Tabel 4.14(a)) kunnen we oplossen met behulp van een heuristiek. Zo kennen we de toestand d de codering 10 toe. Omdat er slechts ´e´en overgang is tussen c en d, zullen we c de encodering 01 geven. a krijgt de encodering 00 omdat er zowel overgangen tussen a en c, als tussen a en d zijn. b krijgt ten slotte de overblijvende codering 11. Het resultaat van deze codering staat in de coderingstabel in Tabel 4.15(a). We voeren ook wat nieuwe syntax in die het ons in de volgende stappen makkelijker zal maken: stabiele configuraties zullen we noteren tussen twee vertical bars (“|”) in de tabel. Cellen waarbij de toestand naar een andere toestand gaat waarbij de encodering minstens twee bits verandert worden onderlijnd. Deze configuraties zullen we nog trachten aan te passen met de volgende methodes. (b) Voorbeeld 1, alternatief 2.
(a) Voorbeeld 1, alternatief 1.
Toestand s0 s1
00
01
I E 11
10
00 11 01 10
|00| |11| 00 11
11 |11| |01| −
|00| 01 |01| 00
01 10 10 |10|
Q
Toestand s0 s1
00
01
I E 11
10
00 01 10 11
00 01 11 10
|00| |01| 00 01
01 |01| |11| −
|00| 11 |11| 00
11 10 10 |10|
Q 00 01 10 11
(c) Voorbeeld 2.
Toestand s0 s1
00
01
I E 11
10
00 01 10
|00| 00 00
01 |01| |10|
|00| −− 00
|00| 10 |10|
Q 0 0 1
Tabel 4.16: Coderingstabellen van het voorbeeld na het toepassen van de eerste methode.
In het geval van een klein aantal toestanden kunnen we exhaustief zoeken. Dit wordt vergemakkelijkt omdat we symmetrie¨en kunnen uitbuiten. De concrete codering maakt immers niet zoveel uit, zolang de Hammingafstand maar dezelfde blijft. We introduceren hiervoor een transitiediagram. Een transitiediagram is een grafe waarbij de knopen toestanden voorstellen. We plaatsen bogen tussen twee toestanden wanneer er transities tussen twee toestanden kunnen plaatsvinden. Deze bogen bevatten de annotaties naar welke stabiele configuratie deze transitie uiteindelijk zal migreren. Deze annotaties worden opgedeeld in twee types. Wanneer we na de overgang meteen in een stabiele configuratie terecht komen zetten we de bijbehorende annotatie op de boog zonder deze te onderlijnen. Wanneer we echter na deze toestand niet in een stabiele configuratie terechtkomen, noteren we de annotatie van de stabiele toestand waar we uiteindelijk in zullen terecht komen en wordt deze onderlijnd. Het eerste leidende voorbeeld telt vier toestanden. We kunnen bijgevolg een grafe beschouwen met vier toestanden. Rotaties en spiegelingen bij deze grafes dienen we niet te beschouwen. De Hammingafstand blijft immers onder deze transformaties gelijk. Bijgevolg zijn er slechts twee mogelijke configuraties voorgesteld op Figuur 4.29(a) en Figuur 4.29(b). Zoals we kunnen vaststellen komt Figuur 4.29(a). We kunnen door twee horizontale of verticale buren om te wisselen de andere versie bekomen. Indien we dit doen – bijvoorbeeld met B en C – bekomen we het alternatief op Figuur 4.29(b). We hebben dit alternatief ook in tabelvorm
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
3;
A
01
(a) Voorbeeld 1, alternatief 1.
00
4;7
C
7 B
6
C
10
C
1;3
1;7
2;7
7
11
7
D
6;7
2;7
7 4; A
00
10
B
6;7
11
3;7 D
7
10
1;
134
A
01
(b) Voorbeeld 1, alternatief 2.
00
1;4
B
01
(c) Voorbeeld 2.
Figuur 4.29: Transitiediagramma van het voorbeeld na het toepassen van de eerste methode. geformaliseerd in Tabel 4.15(b). Een belangrijk aspect bij deze diagrammen is dat we het aantal overgangen waarbij twee of meer toestand-bits willen minimaliseren. Dit komt dus neer op de diagonale transities. We kunnen opmerken dat het eerste alternatief bijgevolg beter is dan het tweede. Ook het tweede voorbeeld minimaliseren we met behulp van een transitiediagram zoals op Figuur 4.29(c). Men kan opnieuw stellen dat dit systeem equivalent is onder spiegeling. Onder rotatie is dit echter niet het geval. Hoe we immers de toestanden ook alloceren, er zal steeds een boog zijn met twee te veranderen bits. We kunnen echter kiezen welke twee toestanden er verbonden zijn met deze boog. In het geval van b en c is er slechts sprake van ´e´en transitie. Bijgevolg alloceren we de toestanden zoals weergegeven op Figuur 4.29(c) en op Tabel 4.15(c). Methode 2: Gebruik maken van een tussentoestand Vermits er geen kloksignaal is en we dus te maken hebben met een schakeling die blijft zoeken naar een stabiele toestand, hoeven we niet noodzakelijk meteen de uiteindelijke toestand in een cel in te vullen. We kunnen ook een tijdelijke transitie naar een andere toestand ondernemen - waarbij slechts ´e´en toestandsbit verandert - waarna we met een reeks tussentoestanden in de uiteindelijke toestand belanden. Dit principe is dus niet beperkt tot ´e´en tussentoestand. Een extra hulpmiddel dat we hierbij kunnen hanteren zijn de don’t cares die nog in de tabel staan. Vermits deze configuraties toch niet kunnen voorkomen, kunnen we een transitie invullen bij de bijbehorende don’t cares. In het andere geval moeten we op zoek gaan naar een toestand die slechts ´e´en bit verschilt van de huidige toestand en die dezelfde stabiele eindtoestand voor de invoer-bits stelt. In het eerste voorbeeld is er sprake van twee transities die we moeten aanpassen: wanneer we ons bevinden in toestand h0, 0ia met invoer h0, 1i en in toestand h0, 1ic met invoer h1, 0i. Om deze problemen op te lossen dien we de relevante kolommen van de invoer te inspecteren. In het eerste geval zoeken we naar een toestand met een Hammingafstand van 1 bit die ons onder invoer h0, 1i naar de toestand h1, 1ib zal brengen. In het eerste geval lijkt zo’n toestand niet te bestaan. We kunnen echter toestand h1, 0id opmerken. Deze toestand verschilt slechts ´e´en bit en bevat in de relevante kolom een don’t care. Vermits de ingang toch niet kan voorkomen in deze toestand kunnen we deze gebruiken om de overgang te bewerkstelligen. We vullen dus h1, 1ib in in de rij van toestand h1, 0id met invoer h0, 1i. Verder passen we de rij van de originele toestand aan: de cel van toestand h0, 0ia met invoer h0, 1i overschrijven we met de waarde h1, 0id . Concreet betekent dit dus wanneer we ons in toestand b bevinden en we leggen de relevante invoer aan, we eerst naar toestand d zullen springen. Toestand d is echter niet stabiel onder deze invoer waardoor we meteen naar toestand b migreren: de oorspronkelijk bedoelde toestand. We proberen ook de tweede problematische transitie van het eerste voorbeeld op te lossen: invoer h1, 0i in toestand h0, 1ic . We gaan opnieuw op zoek naar een toestand die in dezelfde kolom ook tot toestand h1, 0id leidt. Er bestaat hiervoor ´e´en toestand: h1, 1ib heeft een Hamming-afstand van 1 en we zien dat in de kolom
4.4. ASYNCHRONE SCHAKELINGEN
135
voor invoer h1, 0i deze ook een transitie naar h1, 0id leidt. Bijgevolg modificeren we de eerste cel zodat deze naar h1, 1ib leidt. Na deze stappen bekomen we de coderingstabel in Tabel 4.16(a) en het transitiediagram in Figuur 4.30(a). De schuingedrukte cellen zijn cellen die we hebben aangepast. Zoals we kunnen zien zijn er geen transities meer die meer dan ´e´en bit aanpassen. De toestandscodering is dus volledig aangepast. (b) Voorbeeld 1 met compressie.
(a) Voorbeeld 1.
Toestand s0 s1
00
01
I E 11
10
00 11 01 10
|00| |11| 00 11
10 |11| |01| 11
|00| 01 |01| 00
01 10 11 |10|
Q
Toestand s0 s1
00
01
I E 11
10
00 01 10 11
00 11 01 10
|00| |11| 00 11
10 |11| |01| 11
|00| 01 |01| 00
10 10 11 |10|
Q 00 01 10 11
(c) Voorbeeld 2.
Toestand s0 s1
00
01
I E 11
10
00 01 10
|00| 00 00
01 |01| |10|
|00| −− 00
|00| 10 |10|
Q 0 0 1
Tabel 4.17: Coderingstabellen van het voorbeeld na het toepassen van de tweede methode.
10
11
3;4;7 D
6;7 1;7
C
(a) Voorbeeld 1.
6
00
C
1;3
2;4;7 A
10
B
A
01
00
1;4
B
01
(b) Voorbeeld 2.
Figuur 4.30: Transitiediagramma van het voorbeeld na het toepassen van de tweede methode.
We kunnen in deze methode ook een ander aspect bewerkstelligen: compressie. Compressie probeert de sequentie van toestanden in te korten die de schakeling zal overlopen wanneer de ingang verandert. Stel dat de schakeling zich in toestand h0, 0ia bevinden en de ingang vanuit een stabiele configuratie naar de invoerbits h1, 0i verandert. In dat geval doorloopt de schakeling de volgende toestanden: h0, 0ia → h0, 1ic → h1, 1ib → h1, 0id . We doorlopen dus vier toestanden alvorens we in de uiteindelijke stabiele configuratie terecht komen. Dit terwijl de Hammingafstand tussen a en d slechts ´e´en bit bedraagt. Dit betekent dus dat we rechtstreeks naar d kunnen migreren. Hiervoor dienen we dus enkel de transitie van toestand h0, 0ia met invoer h1, 0i aan te passen naar h1, 0id . We bekomen dus de coderingstabel in Tabel 4.16(b). We zullen ook proberen deze methode toe te passen op voorbeeld 2. Meer bepaald wanneer we ons in toestand h0, 1ib bevinden en we veranderen de ingang-bits naar h1, 1i beschouwen we momenteel een transitie waarbij twee bits veranderen. De enige toestand met een Hammingafstand van 1 is echter h0, 0ia . Vermits we in deze toestand met ingang-bits h1, 1i in een stabiele configuratie zitten, kunnen we geen transitie bewerkstelligen naar h1, 0ic . Het probleem kan dus niet opgelost worden met deze methode. We zullen dus methode 3 hiervoor moeten aanwenden.
136
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Methode 3: Invoeren van extra overgangstoestand In de laatste methode introduceren we om de problematische transities op te lossen een nieuwe toestand. Deze toestand mag – net als in de vorige methode – slechts een Hammingafstand van 1 optekenen met de toestand waartussen de problematisch codering zich bevindt. Dit is niet altijd mogelijk. Daarom zal men soms zelfs een pad van verschillende extra overgangstoestanden moeten ontwerpen die telkens ´e´en bit van elkaar verschillen. Omdat alle coderingen soms al in gebruik zijn of om aan de voorwaarde van de Hamming-afstand te voldoen is het daarom niet altijd eenvoudig of zelfs mogelijk om een codering met hetzelfde aantal bits te voorzien. In dat geval moeten we soms de toestandcodering uitbreiden naar meerdere bits. Wanneer we extra bits toevoegen betekent dit traditioneel dat we de volledige codering herbekijken wat veel werk met zich meebrengt. Door echter bits vooraan toe te voegen kunnen we de oude codering behouden (met leidende 0-bits bijvoorbeeld) en maken we tegelijk ruimte om meer toestanden voor te stellen. Eenmaal we een nieuwe codering hebben beschouwd is de realisatie eenvoudig: in de kolom van de relevante invoer-configuratie plaatsen we het pad door elke extra overgangstoestand te laten wijzen naar de volgende overgangstoestand in het pad. Ook passen we de rij van de oorspronkelijke toestand aan zodat deze wijst naar de eerste overgangstoestand in het pad. De overige kolommen vullen we op met don’t cares alsook de uitvoer in de overgangstoestanden. We hoeven niet voor elke problematische transitie meteen extra overgangstoestanden te voorzien. Soms kan men bijvoorbeeld eerst ´e´en overgang oplossen en vervolgens met methode 2 bijvoorbeeld proberen de nieuwe toestand als tussentoestand te beschouwen bij het oplossen van een andere problematische transitie. Met deze methode zullen we ten slotte de laatste problematische transitie oplossen van het tweede voorbeeld. De twee toestanden waartussen deze transitie zich afspeelt zijn h0, 1ib en h1, 0ic . Zonder de toestandscodering uit te breiden met extra bits zijn er twee coderingen die een Hammingafstand van 1 hebben met beide toestanden: h0, 0i en h1, 1i. We kunnen h0, 0i niet gebruiken omdat deze codering reeds gebruikt wordt door toestand a. De andere codering is echter nog vrij. We introduceren dus een toestand h1, 1id . Bij deze toestand vullen we de transitie-kolommen en de uitvoer-kolom met don’t cares behalve de relevante ingang: h1, 1i. Deze kolom laten we verwijzen naar de doeltoestand h1, 0ic . Tot slot passen we de rij van toestand h0, 1ib aan: we laten de relevante invoer-kolom verwijzen naar de ingevoerde overgangstoestand. Wanneer we deze wijzigingen doorvoeren bekomen we de coderingstabel op Tabel 4.18 en het transitiediagram op Figuur 4.31. We zien in de coderingstabel dat er geen problematische transities meer zijn. Alle problemen zijn bijgevolg opgelost. Toestand s0 s1
00
01
I E 11
10
00 01 10 11
|00| 00 00 --
01 |01| |10| --
|00| −− 00 --
|00| 11 |10| 10
Q 0 0 1 -
Tabel 4.18: Coderingstabel van het voorbeeld na het toepassen van de derde methode.
Initi¨ ele toestand Een laatste aspect die we moeten behandelen wanneer we methode 3 toepassen is de initi¨ele toestand: de schakeling van waaruit de schakeling vertrekt wanneer de spanning opkomt. Net als bij flipflops en latches is dit niet te voorspellen. De originele toestand hangt dan ook af van verschillende factoren: inductieve spanning ten gevolge van eerder gebruik, kleine verschillen in de vertragingen op poorten, de temperatuur van de poorten op dat moment, thermische ruis op de verbindingen. Het kan echter gebeuren dat we dus in een codering terechtkomen van een overgangstoestand. Het probleem is dat in het voorbeeld
4.4. ASYNCHRONE SCHAKELINGEN
137 10 C
11
6
D
6
1;3 A
00
B
1;4
01
Figuur 4.31: Transitiediagram van het voorbeeld na het toepassen van de derde methode. de codering h1, 1i niet overeenkomt met een werkelijke toestand. Wanneer de schakeling dus met dergelijke toestand wordt ge¨ınitialiseerd moet de schakeling dus meteen een transfer maken naar een andere – wel geldige – toestand. Een probleem is echter dat in Tabel 4.18 er don’t cares in de kolommen staan. Het is dus mogelijk dat dit later wordt ge¨ımplementeerd zodat er stabiele configuraties ontstaan voor een codering die niet overeenkomt met een toestand. Het is duidelijk dat dit niet de bedoeling is van een overgangstoestand. Om dit te vermijden kunnen we in de kolommen opgevuld met don’t cares concrete waarden invullen. Welke waarden we precies invullen maakt niet zoveel uit. Zolang het stabiele configuraties met de relevante invoer-bit en voor een geldige toestand: dit betekent geen overgangstoestand. We zoeken dus in dezelfde kolom naar een stabiele configuratie en verwijzen in de tabel naar de overeenkomstige toestand. In het leidend voorbeeld hebben we een overgangstoestand ge¨ıntroduceerd. Wanneer we h0, 0i aanleggen aan de invoer zien we ´e´en stabiele configuratie bij toestand h0, 0ia . In de tweede kolom zijn er twee stabiele configuraties we kunnen dus kiezen om ofwel h0, 1ib ofwel h1, 0ic in te vullen. We kiezen hier voor het eerste. De volgende kolom is er slechts ´e´en stabiele configuratie: een configuratie met toestand h0, 0ia . Men kan argumenteren dat we deze toestand niet kunnen gebruiken: er veranderen immers twee bits in vergelijking met de eerste bit. Anderzijds staat er nog een don’t care in de kolom. We kunnen deze don’t care ook laten verwijzen naar h0, 0ia . Hierdoor is de volledig kolom nu gevuld met verwijzingen naar h0, 0ia . Vermits de volledige kolom uniform met dezelfde waardes gevuld is, is de Hamming-afstand tussen de toestanden niet meer van belang: Stel dat we ons in toestand h1, 1i bevinden en we een transitie naar h0, 0ia maken, dan kan het gebeuren dat door een verschil in vertraging we in de toestand h0, 1ib ofwel h0, 0ic terechtkomen. Beide toestanden vormen echter geen probleem omdat ze zelf ook instabiele configuraties zijn die uiteindelijk toch naar dezelfde toestand zullen transformeren. Er is dus sprake van een race, maar deze is niet critical. De laatste kolom ten slotte is reeds ingevuld en bijgevolg bekomen we de uiteindelijke coderingstabel in Tabel 4.19. Toestand s0 s1
00
01
I E 11
10
00 01 10 11
|00| 00 00 00
01 |01| |10| 01
|00| 00 00 00
|00| 11 |10| 10
Q 0 0 1 -
Tabel 4.19: Coderingstabel van het voorbeeld met initi¨ele toestand voor de overgangstoestand.
Initi¨ ele toestand (bis) Naast eventuele overgangstoestanden kan het gebeuren dat niet alle coderingen zijn toegewezen aan werkelijke of overgangstoestanden. Stel bijvoorbeeld dat we een coderingstabel beschouwen met 6 rijen. Hoewel er slechts zes toestanden zijn, zullen er in werkelijkheid meer toestandscoderingen mogelijk zijn. Zoals we al hebben aangehaald kan men niet voorspellen in welke toestandscodering de schakeling zich initieel zal
138
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
bevinden wanneer de stroom opkomt. Daarom dienen we de overige coderingen dus ook te beschouwen en transities te voorzien naar eerder ge¨ıntroduceerde stabiele configuraties. De werkwijze is dan ook volledig identiek aan deze bij het aanpassen van de don’t cares van de overgangstoestanden. We gaan er dan ook niet verder op in.
4.4.5
Stap 4: Realisatie met digitale logica
Wie denkt dat met een geldige toestandscodering alle problemen van de baan zijn moeten we teleurstellen. We hebben dan wel kritische races ge¨elimineerd, maar bij het realiseren van de schakeling dienen we het volgende problemen op te lossen: hazards. Een hazard vormt een ander probleem dan een race. Een race betekent dat door het tijdsverschil waartussen twee of meer signalen van waarde veranderen we in een foute toestand kunnen terechtkomen. Combinatorische logica kan echter ook andere problemen met zich meebrengen: namelijk dat de signalen alvorens de definitieve waarde aan te namen eerst enkele malen veranderen. Hazards De vorige definitie is nogal abstract. We zullen deze dan ook verder toelichten aan de hand van een voorbeeld. Alvorens dit te doen introduceren we extra terminologie. Zo worden hazards opgedeeld in twee soorten: een statische hazard en een dynamische hazard. In het geval van een statische hazard zou het signaal eigenlijk niet moeten veranderen. Stel bijvoorbeeld dat we volgende expressie beschouwen: f (x, y, z) = x · y + y 0 · z
(4.23)
Wanneer we hx, y, zi = h1, 1, 1i aanleggen is het duidelijk dat dit resulteert in een uitgang f (1, 1, 1) = 1. Stel nu dat we het signaal van y aanpassen naar laag, dan geldt nog steeds dat f (1, 0, 1) = 1. We kunnen dus stellen dat het aanpassen van y in deze context geen verschil zal maken. Een gevaar voor een race is er dus bijgevolg zeker niet. Wanneer we deze formule implementeren met behulp van logica kunnen we een schakeling ontwerpen zoals op Figuur 4.32(a). Wanneer we de verandering van y echter simuleren zien we op de bijbehorende tijdsgrafiek (Figuur 4.32(b)) dat het signaal even naar 0 gaat. We hebben dit fenomeen al eerder omschreven als glitch. Men deelt statische hazards verder onder in een statische 0-hazard en een
y y0
x y
p
p
f z
q f
q (a) Voorbeeldimplementatie.
(b) Tijdsgedrag van het voorbeeld.
Figuur 4.32: Statische hazards. statische 1-hazard. De waarde verwijst naar de waarde die de uitgang oorspronkelijk had (en de waarde die dus ook moet worden aangehouden). Wanneer men schakelingen implementeert volgens het sum-of-products principe kan men enkel statische 1-hazards bekomen. Wanneer men werkt volgens de product-of-sums methodologie treden enkel statische 0-hazards op. We zullen dit principe verderop uitleggen.
4.4. ASYNCHRONE SCHAKELINGEN
139
We beschrijven dynamische hazards aan de hand van een andere formule: f (x, y, z, t) =
0 0
x ∧ (x ∧ y)
∧
0
(x ∧ y) ∧ z
0
0 0 ∧t
(4.24)
Deze formule kunnen we implementeren met een schakeling zoals op Figuur 4.33(a). Wanneer we deze formule uitrekenen met de invoer hx, y, z, ti = h0, 1, 1, 1i zal het uitgang-signaal laag zijn: f (0, 1, 1, 1) = 0. Wanneer we echter x aanpassen naar een hoog signaal bekomen we f (1, 1, 1, 1) = 1. Het signaal zal dus sowieso omkeren. Wanneer we dit echter simuleren in de tijd bekomen we de grafiek op Figuur 4.33(b). We zien dat uiteindelijk het signaal naar hoog gaat, maar dat er eerst storingen op de uitgang verschijnen. Een dynamische hazard is dan ook een storing waarbij de uitgang niet eenmaal verandert van signaal, maar een oneven aantal keer (groter dan 1). Een voordeel van een sum-of-products of product-of-sums implementatie te gebruiken is echter dat dynamische hazards niet kunnen voorkomen.
x a b c
b x y z t
a
f c d
(a) Voorbeeldimplementatie.
d f
(b) Tijdsgedrag van het voorbeeld.
Figuur 4.33: Dynamische hazards.
Oorzaak Bij het defini¨eren van de terminologie rond hazards hebben we niet stilgestaan hoe deze fenomenen tot stand komen. Hazards worden veroorzaakt door een tijdsverschil waarin een verandering doorheen de verschillende poorten wordt gepropageerd. Als voorbeeld nemen we opnieuw de schakeling bij statische hazards op Figuur 4.32(a). We zien dat het resultaat berekend wordt door een OR-poort die het resultaat van twee AND-poorten binair optelt. Wanneer we y aanpassen zal de bovenste AND-poort deze verandering meteen waarnemen. De onderste AND-poort zal dit echter nog niet waarnemen: het signaal moet eerst nog door de NOT-poort propageren. Daardoor zal de bovenste AND-poort een 0 op de OR-poort kunnen aanleggen alvorens de onderste AND-poort dit kan goedmaken door terug een 1 op een ingang van de OR-poort aan te leggen. Wanneer we dus y van 1 naar 0 zouden aanpassen treden er geen problemen op: de bovenste AND-poort zal een 1 aanleggen op ´e´en van de ingangen van de OR-poort alvorens de onderste dit doet waardoor dit niet aan de uitgang merkbaar zal zijn. Samenvattend kunnen we dus stellen dat de oorzaak van een hazard een verschil in vertraging is van eenzelfde ingang naar eenzelfde uitgang langs verschillende paden. Gestroomlijnd tijdsgedrag Omdat hazards veroorzaakt wordt door tijdsverschillen doorheen de schakeling zouden we ervoor kunnen opteren om een schakeling te ontwerpen waar alle signalen gestroomlijnd door de schakeling propageren. Dit is echter onmogelijk te realiseren. Allereerst zou men allerhande poorten moeten tussenvoegen om bepaalde signalen voldoende te vertragen waardoor de schakeling duurder wordt. Daarnaast is het theoretische vertragingsmodel slechts een benadering. De werkelijke vertraging van een poort is ook afhankelijk van bijvoorbeeld de lengte van de verbindingen, de temperatuur van de poort, enzovoort. Sommige parameters zoals de temperatuur zijn bovendien op voorhand niet gekend.
140
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Toestandssignalen In combinatorische en synchrone sequenti¨ele schakelingen komen hazards natuurlijk ook voor. Nochtans vormen hazards in deze schakelingen geen probleem. Dit komt omdat een combinatorische schakeling maar na een bepaalde tijd het correcte resultaat op de uitgangen moet kunnen aanleggen. Bij een synchrone schakeling bepaalt het kloksignaal dan weer wanneer de signalen aan de uitgang zullen worden ingelezen. Zolang het signaal dus correct berekend is voor de rising-edge die het resultaat in de flipflops zal opslaan, is er geen enkel probleem. In het geval van asynchrone sequenti¨ele schakelingen is dit niet geval. Dit komt door de toestandssignalen, de signalen die het terugkoppelingsmechanisme vormen. De signalen worden berekend door de logica van de schakeling, maar vormen ook een deel van de invoer van de schakeling. Wanneer de signalen dus tijdelijk een foutieve waarde aannemen kan dit tot problemen leiden: er kunnen oscillaties ontstaan of de schakeling kan in een foute toestand terechtkomen. Het detecteren van hazards is een niet triviaal probleem en vereist doorgaans het simuleren van overgangen. Vooral in het geval van dynamische hazards is dit problematisch. Hazards en Karnaugh-kaarten Combinatorische schakelingen komen meestal tot stand met behulp van een Karnaugh-kaart volgens het sumof-products concept. We hebben reeds aangehaald dat wanneer de logica het sum-of-products principe volgt, uitsluitend statische 1-hazards kunnen optreden. In deze subsubsectie gaan we hier dieper op in. Bovendien kunnen we op basis van Karnaugh-kaarten een methode voorstellen om combinatorische schakelingen te ontwikkelen waar geen hazards kunnen optreden. Op Figuur 4.34 tonen we de bijbehorende Karnaugh-kaart voor de schakeling op Figuur 4.32(a). Op de figuur tonen we ook voor elke AND-poort welke gevallen worden bedekt. In het voorbeeld veranderden we de invoer van hx, y, zi = h1, 1, 1i naar hx, y, zi = h1, 0, 1i. Zoals we op de figuur zien behoort dit tot een ander gebied. Men zou kunnen stellen dat de AND-poorten controleren of de invoer zich in hun overeenkomstige rechthoek bevindt en zo ja, komt er een ´e´en op de uitgang. Een statische 1-hazard wordt veroorzaakt wanneer de rechthoek die we verlaten dit eerder “opmerkt” en dus de uitvoer op 0 brengt alvorens de rechthoek waarin we toekomen dit merkt en de uitvoer terug hoog maakt. Door deze analogie kunnen we ook verklaren waarom we bij een schakeling volgens het sum-of-product-principe nooit een statisch 0-hazard zullen realiseren: we verplaatsen ons van cel naar cel. Wanneer beide cellen 0 zijn, zal geen enkel rechthoek ooit actief worden. Bijgevolg zal op geen enkel moment er een 1 aan de ingang van de OR-poort verschijnen. f
z 0 1 1 1
y
x
0 0 0 1
Figuur 4.34: Karnaugh-kaart bij het leidende voorbeeld.
Hazards voorkomen We kunnen een hazard voorkomen door ervoor te zorgen dat als we tussen twee cellen een transitie uitvoeren, er een rechthoek bestaat die beide cellen omvat. Een concrete oplossing wordt hiervoor voorgesteld in Figuur 4.35(a). Wanneer we in dit voorbeeld een transitie uitvoeren, zullen de ANDpoorten van de oorspronkelijke schakeling nog steeds een tijdsverschil optekenen. We introduceren echter een AND-poort die onder de transitie telkens een 1 zal blijven aanleggen op de OR-poort. Bijgevolg zal de uitvoer altijd 1 blijven. Om dus hazards te vermijden introduceren we redundante termen: AND-poorten die niet strikt gezien nodig zijn om de correcte combinatorische logica voor te stellen, maar poorten die bij een wijziging aan de invoer ervoor zorgen dat er nooit een statische 1-hazard kan optreden.
4.4. ASYNCHRONE SCHAKELINGEN
f
141
f
z 0 1 1 1
y
x
0 0 0 1
x y
(a) Kaart.
z (b) Implementatie.
Figuur 4.35: Het invoeren van redundante termen elimineert statische 1-hazards. Is het altijd mogelijk om zo’n AND-poort te realiseren? Wat indien we bijvoorbeeld een dambord patroon beschouwen zoals op Figuur 4.36? In dat geval zouden we geen redundante termen kunnen introduceren: we f
z 1 1 0 1
y
x
1 1 1 0
Figuur 4.36: Dambord patroon. kunnen dus bijvoorbeeld geen overgang van hx, y, zi = h1, 0, 1i naar hx, y, zi = h1, 1, 0i nemen en voorkomen dat we in een 0 terecht komen. Merk echter op dat we hier twee ingangen hebben aangepast, iets wat volgens de specificaties niet mag. Indien we dus een dergelijke overgang nemen, zullen we altijd eerst ´e´en van de ingangen eerst aanpassen en wachten tot de effecten zijn uitgewerkt. Dan pas passen we de andere ingang aan. Bijgevolg vormt dit geen probleem. Product of sums In het geval van sum-of-product voegen we mintermen toe voor disjuncte 1-gebieden. Soms is het echter goedkoper om een product-of-sum te implementeren. In dat geval voorzien we maxtermen voor disjuncte 0-gebieden. We gaan hier niet verder op in. Realisatie leidend voorbeeld We zullen voor het leidend voorbeeld doorheen deze sectie (coderingstabel in Tabel 4.18 op pagina 136) een schakeling realiseren. Hiervoor zullen we eerst de Karnaugh-kaarten opstellen zoals op Figuur 4.37(a). We doen dit voor zowel s0 , s1 en Q. De volgende toestand hangt af van de originele toestand en van de ingangen. De variabelen zijn dus s0 , s1 , I en E. Bij de uitgang Q is enkel de toestand van belang. Bijgevolg vermelden we enkel s0 en s1 op de Karnaugh-kaart. Vervolgens dienen we de logica zelf te implementeren. Hiervoor realiseren we de combinatorische schakelingen die we hebben gespecificeerd met behulp van de Karnaugh-kaarten. In dit geval doen we dit met een 3-OR poort voor s0 en een 2-OR poort voor s1 . In het geval van Q hebben we bovendien geen poorten nodig: de uitgang komt immers overeen met ´e´en van de toestand-bits s0 . Daarna verbinden we de uitgang van de combinatorische schakelingen met de ingangen die de respectievelijke toestand-bits voorstellen. We bekomen dus een implementatie zoals op Figuur 4.37(b). Problemen ten gevolge van skew op ingangen Met het voorkomen van hazards zijn de theoretische problemen opgelost bij het realiseren van een asynchrone schakeling: wanneer we een digitale schakeling simuleren zal de schakeling correct werken. Maar zoals reeds verschillende malen werd aangehaald is het theoretische model niet helemaal correct.
142
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
s0
s1
I
0 0 − 0
0 1 0 0
E
0 − − 0
1 1 − 0
Q s0
0 0 − 1
s1
0 − − 0
s0
0 0 1 1
s1
s0
0 0 − 0
I s1 0 0 1 −
Q I E s0 s1
E (a) Karnaugh-kaarten.
(b) Implementatie.
Figuur 4.37: Realisatie van het leidend voorbeeld. skew is een fenomeen waarbij een extra vertraging wordt ge¨ıntroduceerd op een lokale plaats in de schakeling. Of anders gesteld, een verandering op een lijn wordt niet overal op hetzelfde moment opgemerkt. Verder in deze cursus zullen we een speciale vorm van skew beschouwen: clock skew25 . Een mogelijk gevolg is een essenti¨ ele hazard: de verandering van slechts ´e´en ingangssignaal brengt de schakeling in een foute toestand. Algemeen verloopt een essenti¨ele hazard altijd als volgt: 1. Het ingangssignaal wordt aangepast (door ´e´en bit te veranderen, dus conform de regels). 2. Enkele poorten merken de verandering op en een bit van de toestand wordt aangepast. 3. Een poort merkt de verandering van de toestand op, maar heeft de aanpassing van de invoer nog niet opgemerkt. 4. Deze poort verandert op zijn beurt een toestand-bit. 5. Pas later wordt de verandering van de invoer opgemerkt. Empirisch zijn essenti¨ele hazards moeilijk op te sporen: het gebeurt niet zelden dat tijdelijk in de verkeerde toestand terechtkomen geen probleem vormt, de foute toestand kan immers dienst doen als een via-toestand waardoor de schakeling alsnog in de correcte toestand terecht komt. Er bestaat wel een algoritmische manier om essenti¨ele hazards te ontdekken. Voorbeeld Bij wijze van voorbeeld beschouwen we de schakeling op Figuur 4.37(b). We stellen op basis van de Karnaugh-kaarten een coderingstabel op in Tabel 4.20. We zullen eerst het scenario in abstracto Toestand s0 s1
00
01
I E 11
10
00 01 10 11
|00| 00 00 00
01 |01| |10| 11
|00| |01| 00 01
|00| 11 |10| 10
Q 0 0 1 1
Tabel 4.20: Coderingstabel van de schakeling uit Figuur 4.38. beschouwen: 1. We bevinden ons in toestand hs0 , s1 i = h1, 0i met invoer hI, Ei = h0, 1i. 2. De invoer van I verandert naar hI, Ei = h1, 1i. 25 Zie
Subsectie 5.5.2.
4.4. ASYNCHRONE SCHAKELINGEN
143
3. De toestand wordt omgeschakeld naar hs0 , s1 i = h0, 0i maar de eerste AND poort heeft de omschakeling van de ingang nog niet opgemerkt. 4. De AND-poort wordt hierdoor actief, bijgevolg schakelt de schakeling nu om naar toestand hs0 , s1 i = h0, 1i. 5. Deze toestand is stabiel met zowel de oude en de nieuwe invoer. Bijgevolg blijft de schakeling in toestand hs0 , s1 i = h0, 1i stabiel. Dit scenario treedt op wanneer op de verbinding tussen I en de eerste AND-poort een significante vertraging plaatsgrijpt. Dit kan bijvoorbeeld het gevolg zijn van een lange lijn. Figuur 4.38(a) toont de schakeling met de skew en Figuur 4.38(b) het tijdsgedrag van de schakeling. a3
a0
a2
a1
a1 a0
a2
Ia0
a3
I s1
a4 Q I E s0 s1
s0
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
t
(a) Implementatie.
(b) Tijdsgedrag.
Figuur 4.38: Essenti¨ele hazard van het leidend voorbeeld.
Detectie Een eenvoudige manier om essenti¨ele hazards op te sporen is de ingang niet ´e´en maar drie keer aanpassen. Toegepast op het voorbeeld betekent dit dat we opnieuw beginnen vanuit hs0 , s1 , I, Ei = h1, 0, 0, 1i. Wanneer we I eenmaal aanpassen bekomen we volgens de coderingstabel: hs0 , s1 , I, Ei = h1, 0, 0, 1i → h1, 0, 1, 1i → h0, 0, 1, 1i. We passen vervolgens nog tweemaal de invoer aan en bekomen: h0, 0, 1, 1i → h0, 0, 0, 1i → h0, 1, 0, 1i → h0, 1, 1, 1i → h0, 1, 1, 1i. Zoals we zien is de eindtoestand niet dezelfde. We hoeven het signaal nooit meer dan drie keer aan te passen. Oplossing Een elegante oplossing voor het probleem bestaat er niet. Men moet proberen te voorkomen dat toestandsvariabelen veranderen alvorens het ingangssignaal op alle poorten is aangekomen. Door de coderingstabel aan te passen kan men het probleem meestal reduceren, bijvoorbeeld door het aantal wijzigingen van toestandsvariabelen beperkt te houden. Maar bij sommige specificaties kan men dit effect niet wegnemen. In dat geval moet men op elektronisch niveau het plan aanpassen: men kan bijvoorbeeld vertragingen introduceren bij de andere poorten om het verschil weg te nemen. Meestal vereist dit zorgvuldige en complexe bewerkingen, deze liggen buiten het bereik van deze cursus.
4.4.6
Besluit
Als algemene conclusie kunnen we stellen: Vermijd asynchrone sequenti¨ele schakelingen. Asynchrone schakelingen zijn immers complexer te ontwerpen: twee ingangen mogen niet tegelijk aangepast worden dus dient men in sommige gevallen dit op te lossen aan de hand van extra (synchrone) logica voor de ingangen. Verder dient men verschillende problemen indachtig te zijn: de coderingstabel moet worden aangepast aan races en hazards. Tot slot wordt de meeste elektronica gebouwd aan de hand van CAD software. In deze software zijn asynchrone sequenti¨ele schakelingen meestal beperkt ondersteund.
144
¨ HOOFDSTUK 4. SEQUENTIELE SCHAKELINGEN (SCHAKELINGEN MET GEHEUGEN)
Asynchrone schakelingen worden dan ook enkel gebruikt in twee gevallen: wanneer snelheid van cruciaal belang is en een synchrone sequenti¨ele schakeling op geen enkele manier de gewenste doorvoer kan bereiken. Verder is het niet altijd mogelijk om een sequentieel systeem te implementeren. We kunnen bijvoorbeeld denken aan een computernetwerk: elke machine heeft een eigen klok. Het synchroniseren van klokken is een onmogelijk opdracht. In dat geval zal men met behulp van een kleine en eenvoudige asynchrone schakeling data tussen de twee synchrone “eilanden” uit wisselen.
Deel III
Processoren
145
Hoofdstuk 5
Niet-Programmeerbare Processoren accepteren nu het feit dat leren een levenslang proces is om “ We op de hoogte te blijven van veranderingen. En de meest urgente taak is mensen te leren hoe te leren. - Peter F. Drucker, Amerikaans management consultant en auteur (1909-)
”
In de twee vorige hoofdstukken hebben we componenten gebouwd met een beperkte functionaliteit. De combinatorische schakelingen laten ons toe om schakelingen te ontwerpen die een rekenkundige operatie uitvoeren, maar we hebben geen geheugen beschikbaar om tussenresultaten in op te slaan. Het hoofdstuk over sequenti¨ele schakelingen maakt het mogelijk om schakelingen te ontwerpen met een geheugen. De meeste problemen hebben echter zeer grote toestandsruimtes (een 32-bit getal heeft meer dan vier miljard toestanden). Daarom volstaan de methodes uit dit hoofdstuk niet om een component te ontwikkelen die iets functioneel doet. Daarvoor zullen we methodes op een hoger niveau introduceren, dat van een niet-programmeerbare processor. Een niet programmeerbare processor voert een algoritme uit dat op voorhand gekend is. Hierdoor kunnen we optimaal gebruik maken van de hardware en zoveel mogelijk instructies tegelijk uitvoeren. Het nadeel is dat eenmaal de processor geproduceerd is, we geen andere problemen met het component kunnen uitvoeren. 5.1
De Niet-Programmeerbare Processor . . . . 5.1.1 Algemene Structuur . . . . . . . . . . . . . . 5.1.2 Het Datapad . . . . . . . . . . . . . . . . . . 5.2 Formeel Beschrijven van een Algoritme . . . 5.2.1 Leidend Voorbeeld: Deler . . . . . . . . . . . 5.2.2 Toestandsbeschrijving . . . . . . . . . . . . . 5.2.3 Toestand-Actie Tabel . . . . . . . . . . . . . 5.2.4 ASM-Schema . . . . . . . . . . . . . . . . . . ASM-Elementen . . . . . . . . . . . . . . . .
147
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
148 149 150 150 151 151 152 154 154
148
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN Het ASM-Blok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Traditionele Valkuilen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inputgebaseerde en Toestandsgebaseerde ASM-schema’s . . . . . . . . . . . . . 5.3 Geheugencomponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Register File Cell (RFC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.2 Registerbank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.3 Random Access Memory (RAM) . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.4 Geheugens met Impliciete Adressering . . . . . . . . . . . . . . . . . . . . . . . Stack (LIFO: Last-In-First-Out) . . . . . . . . . . . . . . . . . . . . . . . . . . Queue (FIFO: First-In-First-Out) . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Synthese van een Niet-Programmeerbare Processor . . . . . . . . . . . . . 5.4.1 Basisprincipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Principes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Leidend voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Betere implementatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.2 Ontwerp Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Patronen in een algoritme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Algemene vorm van een controller . . . . . . . . . . . . . . . . . . . . . . . . . Natuurlijke volgorde van toestanden . . . . . . . . . . . . . . . . . . . . . . . . Ondersteunen van subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . Werken met “One-Hot” coderingen . . . . . . . . . . . . . . . . . . . . . . . . . Programmeerbare controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.3 Minimaliseren Datapad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Leidend voorbeeld: vierkantswortel benadering . . . . . . . . . . . . . . . . . . Kostprijsberekening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variabelen samenvoegen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bewerkingen samenvoegen (“functional-unit sharing”) . . . . . . . . . . . . . . Verbindingen samenvoegen (“bus sharing”) . . . . . . . . . . . . . . . . . . . . Registers samenvoegen in registerbank (“register port sharing”) . . . . . . . . . Vergelijking van de verschillende optimalisaties . . . . . . . . . . . . . . . . . . 5.4.4 Andere optimalisaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Minimaal instructiewoord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . “Chaining”: meerdere bewerkingen per klokcyclus . . . . . . . . . . . . . . . . “Multicycling” en “Pipelining”: meerdere klokcycli per bewerking . . . . . . . 5.4.5 Besluit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5 Tijdsgedrag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1 Kritisch pad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.2 Verschoven kloksignalen (“clock skew”) . . . . . . . . . . . . . . . . . . . . . . 5.5.3 Synchroniseren van asynchrone ingangen . . . . . . . . . . . . . . . . . . . . . .
5.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
155 155 158 158 158 159 161 162 163 165 167 167 167 168 171 172 172 172 173 174 175 176 176 177 178 178 188 200 203 205 206 206 207 207 212 212 212 213 214
De Niet-Programmeerbare Processor
Alvorens we de bouw van zo’n processor verder uitwerken, dienen we eerst enkele concepten te formaliseren. Allereerst ontleden we in deze sectie uit welke delen zo’n processor is opgebouwd. Vervolgens zullen we in sectie 5.2 een methode ontwikkelen om een algoritme formeel weer te geven. Deze beschrijving zal toelaten het algoritme later om te zetten naar een processor. In sectie 5.3 ten slotte zullen we extra geheugencomponenten introduceren die we nodig zullen hebben bij de bouw van een processor.
5.1. DE NIET-PROGRAMMEERBARE PROCESSOR
5.1.1
149
Algemene Structuur
Een Niet-programmeerbare processor, ofwel Finite State Machine with Data path (FSMD) bestaat grofweg uit twee delen: • Een datapad: een component die bewerkingen (rekenkundig, aritmetisch,...) uitvoert en de resultaten opslaat in tijdelijk geheugen. • Een controller: een component die het datapad aanstuurt. Het zegt welke actie op welk moment moet ondernomen worden. In dit hoofdstuk is de controller niet programmeerbaar. Dat wil zeggen dat de controller telkens hetzelfde programma uitvoert. Dit betekent echter niet dat er een vaste cyclus in de controller zit. De controller kan afhankelijk van de waarden die in de geheugens van het datapad zitten, of van ingangen van de processor beslissen om andere acties te ondernemen. Een controller is dus een sequenti¨ele schakeling ofwel finite state machine. De synthese van een finite state machine werd in het Hoofdstuk 4 reeds besproken. Uiteraard zullen we de karakteristieken die eigen zijn aan controllers in dit hoofdstuk bespreken. Het spreekt voor zich dat de controller en het datapad continu data met elkaar uitwisselen. Enerzijds geeft de controller instructies aan het datapad. De groep signalen waarmee een controller een datapad aanstuurt noemen we het “instructiewoord” ofwel “controle-signalen”. Anderzijds zullen de instructies vaak afhangen van de toestand van variabelen opgeslagen in het datapad. De verzameling van signalen die het datapad over zijn variabelen doorstuurt naar de controller noemen we “statussignalen”. Een processor voert operaties uit op data. Deze data moet op de een of andere manier ingelezen worden in de processor. De verzameling ingangen waarmee we data vanuit de omgeving in het datapad injecteren noemen we de “data-ingangen”. Verder zullen we vaak ook informatie aan de controller moeten meedelen: we denken bijvoorbeeld aan een signaal dat actief wordt wanneer alle data ingelezen is, en het algoritme kan uitgevoerd worden. Deze signalen noemen we “controle-ingangen”. Daarnaast willen we ook de resultaten kunnen uitlezen. Hiervoor voorzien we een reeks signalen vanuit het datapad, deze signalen noemen we “data-uitgangen”. Tot slot zijn we soms ook ge¨ınteresseerd in de toestand van het algoritme. We zullen bijvoorbeeld enkel data uitlezen indien het algoritme afgelopen is. De controller kan informatie over het algoritme naar buiten brengen via “controle-uitgangen”. De verschillende informatiestromen tussen het datapad en de controller en de processor en zijn omgeving beschrijven we op figuur 5.1(a). externe-ingangen
instructiewoord
Controller
Datapad
data-uitgangen
status-signalen
Processor Omgeving controle-ingangen
Datapad
Omgeving
data-ingangen
instructiewoord
Resultaatverbindingen Tijdelijk geheugen Operatorverbindingen Functionele eenheden
instructiewoord controle-uitgangen
Resultaatverbindingen externe-uitgangen
(a) Processor
(b) Datapad
Figuur 5.1: Opbouw van een processor en datapad.
150
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Door de controle-ingangen wordt de definitie van “niet-programmeerbaar” natuurlijk vaag. We zouden immers het toestandswoord van de controller in grote mate laten afhangen van de invoer die de controleingangen. Hierdoor kunnen we de processor toch programmeren. Het onderscheid is dan ook eerder een common-sense.
5.1.2
Het Datapad
Zoals we reeds hebben vermeld, kunnen we een controller modelleren als een eindige toestandsautomaat ofwel finite state machine. Een datapad daarentegen bestaat uit verschillende componenten: • Functionele Eenheden ofwel Functional Units (FU): dit zijn schakelingen die berekeningen en aritmetische operaties uitvoeren. Dit zijn dus de componenten die we in Hoofdstuk 3 hebben besproken: optellers, ALU, schuifoperator,... Uiteraard kunnen we ook zelf functionele eenheden bouwen op de manier die we gezien hebben. • Tijdelijke geheugens: dit zijn componenten die de waarden waarop we bewerkingen uitvoeren voor enkele klokcycli kunnen vasthouden. Dit zijn bijvoorbeeld de registerbanken en RAM die we in sectie 5.3 zullen invoeren. Het zijn groepen van flipflops die ons toelaten om op een hoger niveau te redeneren. • Verbindingen: de tijdelijke geheugens en de functionele eenheden wisselen informatie uit. Daarom hebben we twee types verbindingen nodig: – Operandverbindingen: dit zijn verbindingen die de waardes van de tijdelijke geheugens overbrengen als operanden van de functionele eenheden. De waarde van een register kan op die manier bijvoorbeeld gebruikt worden bij een optelling. – Resultaatverbindingen: het is de bedoeling dat de resultaten vervolgens in een tijdelijk geheugen opgeslagen worden. Resultaatverbindingen transporteren de resultaten van de functionele eenheden terug naar de tijdelijke geheugens. Sommige uitvoer kan ook weggeschreven worden naar de data-uitgangen. Ook de invoer van de data-ingangen wordt door deze verbindingen verwerkt. Het spreekt voor zich dat de verbindingen beslissen welke geheugens als operanden en resultaatgeheugens dienen. Daarom zullen we ze implementeren als bussen met multiplexers en 3-state buffers. Deze bussen zullen dan worden aangestuurd door de controller. Dit concept beschrijven we op figuur 5.1(b). In het datapad doen we dan ook niets anders dan waardes uit het tijdelijke geheugen inlezen, er een operatie van een functionele eenheid op uitvoeren en vervolgens in een tijdelijk geheugen plaatsen. Dit proces noemen we ook wel de “registertransfer” en formaliseren we als: (5.1) registera ← FUa registera1 , registera2 , . . . , registeran In het eerste hoofdstuk hebben we reeds vermeld dat we schakelingen bij het bouwen van een processor beschrijven op registertransfer-niveau. Dit betekent dat we bijvoorbeeld abstractie zullen maken van flipflops en zullen werken met registers. Ook zullen we details als het aantal bits die een opteller nodig heeft verwaarlozen. Deze nieuwe notatiestijl zullen we geleidelijk invoeren.
5.2
Formeel Beschrijven van een Algoritme
Alvorens we een processor kunnen bouwen die een algoritme uitvoert, moeten we eerst een formeel algoritme kunnen opstellen. Dit algoritme vertrekt altijd vanuit een probleemstelling. Hoe we een probleemstelling omzetten naar een algoritme behoort niet tot de inhoud van deze cursus1 . We zullen altijd stellen dat het algoritme vooraf gekend moet zijn. 1 Het omzetten van een probleem in een algoritme is geen exacte wetenschap. Het is een vaardigheid die wel geoefend kan worden. Hiervoor bestaan er andere cursussen.
5.2. FORMEEL BESCHRIJVEN VAN EEN ALGORITME
5.2.1
151
Leidend Voorbeeld: Deler
Als leidend voorbeeld doorheen dit hoofdstuk zullen we een processor bouwen die natuurlijke getallen kan delen. Uiteraard zouden we hiervoor een combinatorische schakeling kunnen bouwen. We zullen echter een algoritme beschouwen om de berekening te maken. De processor heeft 2 4-bit ingangen die het deeltal en de deler inlezen. Verder bevat het ook een controle-ingang. Zolang we een laag signaal op de controleingang aanleggen betekent dit dat er geen correcte invoer op de data-ingangen staat. Pas wanneer we een hoog signaal aanleggen zal het algoritme dus een deling uitvoeren. Verder bevat de processor ook 2 4-bit uitgangen om het quoti¨ent en de rest naar buiten te brengen, en een controle uitgang die hoog wordt op het moment dat het algoritme het quoti¨ent en de rest heeft berekend. Zolang de controle-uitgang dus laag is, is het algoritme nog bezig met de berekening. Verder zal de processor ook wachten totdat de controle-ingang eerst laag is geweest alvorens opnieuw te beginnen. We maken de assumptie dat de deler nooit gelijk is aan 0. Het algoritme dat dan vervolgens het deeltal en de deler omzet in het quoti¨ent en rest staat op Algoritme 2. We gaan niet in op de precieze werking van het algoritme. Indien we een index opvragen of Algorithm 2 Delen van twee n-bit getallen. 1: function Division(N, D) 2: Q←0 3: R←0 4: for I = n − 1 to 0 do 5: R ← R shl 1 6: R [0] ← N [n − 1] 7: N ← N shl 1 8: Q ← Q shl 1 9: if R ≥ D then 10: R←R−D 11: Q [0] ← 1 12: end if 13: end for 14: return (Q, R) 15: end function
. Logische shift R naar links over 1 positie . Logische shift N naar links over 1 positie . Logische shift Q naar links over 1 positie
zetten bij een variabele zoals V [i] betekent dit dat we een operatie op de i-de bit uitvoeren. We tellen we van rechts naar links, V [0] is dus de minst beduidende bit van V die rechts staat in de encodering. Verder zullen we ook de subscript-notatie gebruiken wanneer we bits samen nemen. Zo betekent v2 v1 w2 w2 v2 w1 dat we een getal samenstellen uit de eerste twee bits van V , gevolgd door de eerste en de derde bit van W , daarna volgen nog de derde bit van V en de tweede bit van W . Dit algoritme is echter niet geschikt voor een processor. Een processor voert immers continu het programma uit. Bovendien wordt hier niet gewacht tot er invoer op de data-ingangen staat. Een laatste opmerking is dat we geen berekeningen op invoer kunnen uitvoeren. Anders zouden we immers de uitgangen van functionele eenheden met de ingangen van de processor verbinden. Daarom dienen we variabelen te introduceren die we X, Y en Z noemen. Daarom zullen we het algoritme herschrijven2 . We beschouwen hierbij de controle-ingang ci en de controle-uitgang co. De herschreven procedure staat in Algoritme 3.
5.2.2
Toestandsbeschrijving
Een eerste probleem dient zich aan hoe we de procedure omzetten in een reeks toestanden. De vraag is immers wat we in ´e´en zo’n toestand zullen realiseren. Zo kunnen we Algoritme 3 uitvoeren en per instructie een nieuwe toestand bouwen. Als we echter het programma onder de loep nemen, zien we dat dit algoritme zich uitstekend leent om verschillende instructies samen uit te voeren. Allereerst voeren we in de for-lus hoofdzakelijke shift operaties uit. Deze shiftoperaties vinden plaats over een vast aantal posities. We dienen 2 Strikt genomen is dit geen algoritme meer, vermits het nooit eindigt en er geen echt resultaat is. Een betere bewoording is waarschijnlijk procedure.
152
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Algorithm 3 Procedure voor het delen van twee 4-bit getallen. 1: procedure Division 2: while true do 3: repeat 4: co ← 0 5: X←N 6: Y ←0 7: Z←0 8: until ci 9: for I = 3 to 0 do 10: Z ← Z shl 1 . Logische shift Z naar links over 1 positie 11: Z [0] ← X [3] 12: X ← X shl 1 . Logische shift X naar links over 1 positie 13: Y ← Y shl 1 . Logische shift Y naar links over 1 positie 14: if Z ≥ D then 15: Z ←Z −D 16: Y [0] ← 1 17: end if 18: end for 19: repeat 20: co ← 1 21: Q←Y 22: R←Z 23: until ¬ci 24: end while 25: end procedure
dus helemaal geen schuifoperator te implementeren, en kunnen eenvoudigweg schuiven met verbindingen. Vervolgens doen we ook aan bitmanipulaties. Omdat deze bitmanipulaties opnieuw op vaste plaatsen plaatsvinden kunnen we dit realiseren met behulp van verbindingen. De enige twee aspecten die enige logica vereisen is de test of Z ≥ D is (lijn 14), en het eventueel aftrekken van D uit Z (lijn 15). Daarnaast moeten we tijdens de uitvoer van de for lus ook controleren of I ≥ 0. In dat geval dienen we immers nogmaals de for-lus uit te voeren. We kunnen dit echter controleren met een simpele OR-poort die alle bits van I samenneemt. Indien minstens ´e´en van de bits een 1 is, zal de OR-lus een 1 teruggeven, en dienen we dus nog een cyclus uit te voeren. Dit leidt ertoe dat we ons algoritme in drie toestanden opdelen: 1. S0 : inlezen van invoer, initialiseren van variabelen en wachten totdat ci hoog wordt (lijnen 3-8). 2. S1 : uitvoeren van een cyclus van de for lus en I met 1 verlagen (lijnen 9-18). 3. S2 : resultaten op de uitgang plaatsen en wachten tot ci laag wordt (lijnen 19-23).
5.2.3
Toestand-Actie Tabel
Nu we de toestanden hebben vastgesteld kunnen we het algoritme verder formaliseren. Dit zouden we kunnen doen met een grafische voorstelling zoals we gedaan hebben met een eindige toestandsautomaat. Het probleem is dat een rij in het toestandsdiagram niet enkel de voorwaarden en eventuele uitgangen bevat, daarnaast dient het ook nog de acties die door het datapad moeten worden uitgevoerd weer te geven. Dit zou leiden tot een complex en chaotisch diagram. Daarom verkiezen we een tabel: de “Toestand-Actie Tabel”. De tabel bestaat grofweg uit drie gedeeltes: • de huidige toestand: de huidige toestand waarin de controller zich bevindt. • Een toestandsgedeelte: die we kunnen vergelijken met de toestandstabel van een eindige toestandsautomaat. De tabel bevat volgende kolommen:
5.2. FORMEEL BESCHRIJVEN VAN EEN ALGORITME
153
– condities (afhankelijk van controle- en status-signalen) – de volgende toestand – de uitvoer (van eventuele controle-uitgangen). • een controle-actie gedeelte. Dit gedeelte bevat twee kolommen: – conditie: een set voorwaarden wanneer een bepaalde set acties (gespecificeerd in de volgende kolom) moet worden uitgevoerd. – actie: afhankelijk van de conditie welke opdrachten uitgevoerd worden op de variabelen in een klokcyclus. Tabel 5.1 toont de toestand-actie tabel van Algoritme 3. Een belangrijke opmerking is dat het onderverdelen van toestanden in condities bij het toestandsgedeelte niet verder loopt bij het onderverdelen van diezelfde toestand in het controle-actie gedeelte. Dit betekent dus dat de conditie bij de volgende toestand niet de conditie bij de controle- en datapad-acties impliceert en omgekeerd. Concreet betekent dit dus dat indien I > 0, dit niet betekent dat z2 z1 z0 x3 < D of dat we de bijbehorende datapad-acties moeten uitvoeren. Het toestandsgedeelte en het controle-actie gedeelte zijn dus onafhankelijk en zijn enkel afhankelijk van de huidige toestand. Huidige Toestand
Volgende toestand Conditie Toestand
Uitgang
ci = 0
S0
co = 0
ci = 1
S1
co = 0
I>0
S1
co = 0
I=0
S2
co = 0
ci = 0
S0
ci = 1
S2
S0
S1
S2
Controle- & datapad-acties Conditie Acties X←N Y ←0 Z←0 I←3 Z ← z2 z1 z0 x3 X ← X shl 1 z2 z1 z0 x3 < D Y ← Y shl 1 I ←I −1 Z ← z2 z1 z0 x3 − D X ← X shl 1 z2 z1 z0 x3 ≥ D Y ← y2 y1 y0 1 I ←I −1
co = 1 Q=Y R=Z co = 1 Q=Y R=Z
Tabel 5.1: Toestand-actie tabel van het leidend voorbeeld.
Simulatie Om ons meer vertrouwd te maken met het concept van een toestand-actie tabel zullen we een deling simuleren met behulp van de tabel. We zullen N = 12 delen door D = 7 op de processor en stap per stap kijken wat er verandert. Dit doen we met behulp van tabel 5.2. Omdat we met bitoperaties werken zullen we alle variabelen in de tabel in binaire notatie zetten. We stellen dat vanaf dat we de simulatie beginnen, reeds de data op de ingangen van de processor aangelegd staat. Bijgevolg is ci = 1, N = 1100 en D = 0101. We maken verder ook een assumptie dat X, Y en Z 4-bit geheugens zijn, dit is redelijk vermits we uitsluitend bits in dit bereik gebruiken, en we geen schuifoperaties naar rechts uitvoeren waardoor hogere bits in het bereik zouden komen te liggen. I is een 2-bit geheugen vermits het uitsluitend waardes tussen 0 en 3 moet aannemen. Initieel vertrekt de processor vanuit toestand S0 we zien op die toestand-actie tabel dat in toestand S0 de ingangen in de geheugens worden ingelezen. Vermits er data op de ingangen staat, krijgt X de waarde van de teller N = 1100. De overige variabelen worden ge¨ınitialiseerd zoals beschreven staat in
154
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN Toestand
Voldane Condities
S0
ci = 1
I = 11 > 00 S1 z2 z1 z0 x3 = 0001 < D = 0101 I = 10 > 00 S1 z2 z1 z0 x3 = 0011 < D = 0101 I = 01 > 00 S1 z2 z1 z0 x3 = 0110 ≥ D = 0101 I = 00 S1 z2 z1 z0 x3 = 0010 < D = 0101 S2
ci = 0
Acties X ← N = 1100 Y ← 0000 Z ← 0000 I ← 11 Z ← z2 z1 z0 x3 = 0001 X ← X shl 1 = 1000 Y ← Y shl 1 = 0000 I ← I − 1 = 10 Z ← z2 z1 z0 x3 = 0011 X ← X shl 1 = 0000 Y ← Y shl 1 = 0000 I ← I − 1 = 01 Z ← z2 z1 z0 x3 − D = 0001 X ← X shl 1 = 0000 Y ← y2 y1 y0 1 = 0001 I ← I − 1 = 00 Z ← z2 z1 z0 x3 = 0010 X ← X shl 1 = 0000 Y ← Y shl 1 = 0010 I ← I − 1 = 11
Uitvoer co = 0
co = 0
co = 0
co = 0
co = 0 co = 1 Q = Y = 0010 R = Z = 0010
Tabel 5.2: Simulatie van het algoritme met behulp van de toestand-actie tabel (tabel 5.1). de toestand-actie tabel. Omdat ci = 1 kunnen we afleiden dat de volgende toestand S1 is. Verder specificeert de tabel ook dat we een laag signaal op de controle-uitgang moeten aanleggen (momenteel staat er immers geen uitkomst op de uitgangen). In de volgende stap bevinden we ons in toestand S1 . We evalueren eerst de verschillende condities ??.
5.2.4
ASM-Schema
Zoals reeds gezegd is de visualisatie van een eindige toestandsautomaat niet toereikend om een algoritme weer te geven. Een grafisch voorstelling die we wel kunnen gebruiken is een “Algorithmic-State-Machine Chart” ofwel “ASM-schema”. ASM-Elementen Een ASM-schema lijkt op een flow-chart en bestaat drie verschillende soorten “ASM-elementen”: • Toestandskader ofwel state box: dit is een set niet-conditionele toekenning. We stellen een toestandskader voor door middel van een rechthoek waarin we de toekenningen schrijven. De toekenningen in ´e´en toestandskader worden parallel uitgevoerd. Daarnaast bevat een toestandskader ook de status- en data-uitgangen van de processor. Men maakt een onderscheid doordat toekenningen met een pijl (←) weergegeven worden en uitgangen met een gelijkheidsteken (=). Figuur 5.2(a) toont een voorbeeld van een toestandskader. • Beslissingskader ofwel decision box: dit is de voorstelling van een bepaalde conditie. Een conditie wordt voorgesteld met behulp van een ruit, waarin de conditie wordt geschreven. Vanuit een beslissingskader vertrekken er twee pijlen: voor het geval waarin de voorwaarde waar of vals is. We noteren de pijlen dan ook respectievelijk met “[True]” en “[False]”, soms wordt ook 1 en 0 gebruikt. Figuur 5.2(b) toont een voorbeeld van een beslissingskader.
5.2. FORMEEL BESCHRIJVEN VAN EEN ALGORITME
155
• Conditioneel kader ofwel conditional box: Dit is een toestandskader die enkel onder voorwaarden gespecificeerd door een beslissingskader worden uitgevoerd. Ook deze toekenningen worden in parallel uitgevoerd. Verder bevat een conditioneel kader ook de conditionele uitvoer op de processoruitgangen. We noteren toekenningen en uitgangen op dezelfde manier als bij toestandskaders. Men stelt een conditioneel kader voor als een rechthoek met afgeronde hoeken. Figuur 5.2(c) toont een voorbeeld van een conditioneel kader.
in variabele1 ← expressie1 ··· variabelem ← expressiem uitgang1 = expressiem+1 ··· uitgangn = expressiem+n
uit (a) Toestandskader
[True]
in
in
test
variabele1 ← expressie1 ··· variabelem ← expressiem uitgang1 = expressiem+1 ··· uitgangn = expressiem+n
[False]
uit 1
uit 2 (b) Beslissingskader
uit (c) Conditioneel kader
Figuur 5.2: Voorstelling van de verschillende ASM-elementen
Het ASM-Blok Deze ASM-elementen worden gegroepeerd in een “ASM-blok”. Alle ASM-elementen die in eenzelfde ASMblok zitten, worden dan in ´e´en klokcyclus uitgevoerd. Hierdoor voorzien we per toestand in de Toestand-Actie tabel een ASM-blok. Het blok zelf moet dan specificeren wat er in de toestand gebeurt. We zullen deze component voorstellen met behulp van een vierkant met streepjeslijnen. Vermits alle acties in ´e´en klokflank uitgevoerd worden, bevat elk ASM-blok exact ´e´en toestandskader. Dit toestandskader bevat dan alle toekenningen en uitgangen die onafhankelijk van condities in die toestand worden uitgevoerd. Indien er geen onafhankelijke operaties zijn, is het vierkant leeg. Indien er naast onafhankelijke acties ook conditionele acties gebeuren (zowel in het toestand- als het actie-gedeelte), zullen we vervolgens enkele beslissingskaders plaatsen. We voeren testen uit op variabelen in het datapad door middel van status-signalen en eventuele signalen aan de controle-ingangen. Vermits we al deze testen reeds in de toestand-actie-tabel hebben gedefinieerd kunnen we eenvoudig de toestand-actie-tabel omvormen tot een ASM-schema. Zo staat op figuur 5.3 het ASM-schema voor het leidend voorbeeld. Traditionele Valkuilen Traditioneel maakt men een aantal fouten tegen ASM-schemas. In deze subsubsectie zullen we een overzicht geven van de meest gemaakte fouten. Meerdere volgende toestanden Men kan in een ASM-schema een flow chart tekenen waarbij onder bepaalde condities, men twee verschillende pijlen kan volgen. Een voorbeeld van zo’n flow chart staat op figuur 5.4(a). Indien bijvoorbeeld test t1 slaagt en t2 faalt, dienen we de stromen naar A1 ´en A3 te volgen. Dit is niet zo problematisch wanneer dit in hetzelfde ASM-blok gebeurt (we kunnen argumenteren dat we dan alle toewijzingen uit A1 en A3 uitvoeren). Indien we echter later naar verschillende toestanden gaan krijgen we problemen. We kunnen dit probleem makkelijk verhelpen door geen vertakkingen met pijlen toe te staan. Enkel uit het beslissingskader vertrekken twee pijlen. Uit een toestands- en conditioneel kader vertrekt altijd slechts ´e´en pijl. Het samenbrengen van pijlen is wel toegelaten. Geen volgende toestand Ook het omgekeerde kan voorkomen: een ASM-blok waarbij we geen volgende toestand bekomen bij een bepaalde situatie. Figuur 5.4(b) toont een minimaal voorbeeld: indien aan t1
156
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
X←N Y ←0 Z←0 I←3 co = 0
[True]
ci = 0
X ← X shl 1 I ←I −1 co = 0
[False]
[True]
z2 z1 z0 x3 < D
co = 1
[False]
S1
[True]
ci = 1
[False]
S3
Z ← z2 z1 z0 x3 Y ← Y shl 1
[True]
Z ← z2 z1 z0 x3 − D Y ← y2 y1 y0 1
I>0
Q=Y R=Z
[False]
S2 Figuur 5.3: ASM-schema van het leidend voorbeeld.
wordt voldaan zullen we nooit naar een volgende toestand overgaan. Dit komt omdat de pijl nooit een toestandskader bereikt (en we dus in een volgende toestand komen. Ook dit probleem kunnen we eenvoudig voorkomen: in elk ASM-blok gaan alle mogelijke lussen doorheen het toestandskader. Verschillende toekenningen aan dezelfde variabele Tijdens ´e´en klokflank kan een variabele slechts ´e´enmaal van waarde veranderen. We kunnen in een ASM-blok echter meerdere kaders plaatsen die elk een waarde aan dezelfde variabele toekennen. Figuur 5.4(c) toont zo’n situatie: indien t1 niet waar is, kennen we zowel 0 als 1 toe aan X. Men kan argumenteren dat X dan de waarde 1 krijgt, omdat dit de laatste toekenning is aan X in het diagram. De componenten die in een ASM-blok staan kunnen dus vrij veranderd worden in volgorde. Bovendien zullen we in sectie 5.4 een mechanisme ontwikkelen om deze ASM-schema’s om te zetten in hardware. Incorrecte ASM-schema’s zullen leiden tot implementatiefouten. We kunnen dit voorkomen door bij elk ASM-blok alle mogelijke paden te analyseren en te controleren dat geen variabele twee toewijzingen krijgt. Testen van nieuwe waarde Omdat alles in een ASM-blok tegelijk gebeurt, zijn de waardes van variabelen ook nog niet aangepast wanneer we een toestandsblok verlaten. Zolang we ons echter nog in hetzelfde ASMblok bevinden, zijn die aanpassingen nog niet doorgevoerd. Stel dat we bijvoorbeeld volgende C programma beschouwen: a--; if(a > 3) { b = 2; } Dan kunnen we dit vertalen naar ´e´en toestand in het ASM-schema. Figuur 5.4(d) is echter niet de juiste vertaling. Stel immers dat a = 4 dan zal in het C-programma de if-lus niet uitgevoerd worden, a heeft immers voor het if-statement de waarde 3. In het ASM-schema krijgt a ook de waarde 3, maar alleen nadat we het ASM-blok verlaten hebben. Bijgevolg zal bij de voorwaarde a nog steeds de waarde 4 hebben en zal de if-lus uitgevoerd worden. Een oplossing is om in dit geval gewoon te testen op a − 1 > 3 of dus a > 4.
5.2. FORMEEL BESCHRIJVEN VAN EEN ALGORITME
157
A0 [True]
S1 S2
[False] [True]
t1
A1
A0
S3
[False]
t2
A2
S1 S4
A3
(a) Meerdere volgende toestanden
t1
[False]
t1
S2
A1
(b) Geen volgende toestanden
a←a−1
X←0 [True]
[True]
[False]
[True]
X←1
b←2
a>3
[False]
y ←x+1
S1
S1
6=
y ←x+1 z ←y+2
z ←y+2
S2
A0
(c) Meerdere toekenningen
S2
A0
(d) Testen op nieuwe waarden
(e) Gebruik nieuwe waarde
A0 uitgang ← expressie A1
(f) Conditioneel toestandskader
na (g) Toewijzen uitgang
Figuur 5.4: Traditionele valkuilen bij het maken van ASM-schema’s.
Gebruiken van een nieuwe waarde Een verwante traditionele fout is het gebruiken van de nieuwe waarde in de volgende berekening. Een voorbeeld van dit concept staat op figuur 5.4(e). Hier zien we twee ASM-schema’s die niet equivalent zijn. Indien bijvoorbeeld x = 2 en y = 1 zal in de eerste flow z = 5. In het tweede geval is z = 3. Indien beide kaders in een verschillend ASM-blok of -element staan, is dit uiteraard toegelaten. Indien de toekenningen in hetzelfde ASM-element of ASM-blok staan, worden de opdrachten parallel uitgevoerd, en zullen we dus de oude waarde gebruiken. Men kan dit fenomeen testen door de volgorde van toekenningen in een ASM-element te wijzigen of de beslissingskaders en hun bijbehorende conditionele kaders anders te schikken. Nadat deze volgorde dan wijzigt, zou het programma nog steeds op dezelfde manier moeten werken.
Aanduiden van controller-uitgangen We zijn reeds kort ingegaan op de notatie van uitgangen in de toestand- en conditionele kaders. We noteren de waarde van een uitgang met behulp van een gelijkheidsteken (=). Indien we de uitgang niet vermelden, staat er een 0 op die uitgang (in het geval van meerdere bits, zijn alle bits dus 0). Soms komt het ook voor dat een uitgang in elke toestand een combinatorische schakeling van enkele variabelen is. In dat geval moeten we deze uitgang niet in elk toestandskader vermelden, maar volstaat het om een nota te maken, zoals we ook op figuur 5.3. Deze nota is geen onderdeel van het ASM-schema, en wordt makkelijk vergeten.
158
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Conditioneel kader na toestandskader Een laatste fout die regelmatig terugkomt is het plaatsen van een conditioneel kader na een toestandskader zoals op figuur 5.4(f). Vermits er geen beslissingskader aan vooraf gaat, is dit conditioneel kader helemaal niet gebonden aan een voorwaarde. Dit probleem lossen we op door het conditioneel kader om te vormen tot een toestandskader. Indien beide kaders bovendien in eenzelfde ASM-blok staan, kunnen we de inhoud van beide kaders samennemen in ´e´en toestandskader. Inputgebaseerde en Toestandsgebaseerde ASM-schema’s We hebben het reeds kort gehad over het toekennen van toestanden aan delen van een programma besproken. Een belangrijk aspect daarbij is dat we ASM-schema’s kunnen onderverdelen in twee categorie¨en: • Inputgebaseerd ASM-schema: In dit schema kunnen we de waarde van testen (status-signale) en controle-ingangen onmiddellijk gebruiken. Een inputgebaseerd ASM-schema van het leidend voorbeeld stond op figuur 5.3. • Toestandsgebaseerd ASM-schema: Hierbij kunnen we de waardes van testen (status-signalen) en controle-ingangen pas in de volgende klokflank gebruiken. Het betekent dus dat elke voorwaardelijke uitvoering van een opdracht gepaard gaat met de overgang naar een nieuwe toestand. Bijgevolg bevat dit diagram ook geen conditionele kaders. Inputgebaseerde ASM-schema’s kunnen meer opdrachten uitvoeren in een klokflank, omdat we niet moeten wachten op het kloksignaal om conditionele operaties uit te voeren. Anderzijds zal dit ASM-schema tot een langere klokcyclus leiden. Dit komt omdat de testen eerst moeten berekend worden alvorens we sommige opdrachten kunnen uitvoeren. Een nadeel van toestandsgebaseerde ASM-schema’s is dat we meer toestanden nodig hebben, wat zal leiden tot een groter geheugen en mogelijk ook logica. De termen inputgebaseerd en toestandsgebaseerd komen van de controller. We hebben reeds besproken dat een controller een eindige toestandsautomaat is. Ook bij deze eindige toestandsautomaten hebben we deze indeling gemaakt. Een toestandsgebaseerd ASM-schema zal aanleiding geven tot een toestandsgebaseerde controller en vice versa. Bij wijze van voorbeeld zullen we het leidend voorbeeld ook met een toestandsgebaseerd ASM-schema visualiseren op figuur 5.5.
5.3
Geheugencomponenten
Alvorens we processoren kunnen implementeren zullen we eerst nieuwe componenten moeten introduceren. We zullen we deze componenten introduceren in een logische volgorde waarbij componenten gebruik maken van eerder ge¨ıntroduceerde componenten.
5.3.1
Register File Cell (RFC)
Een register file cell is een uitbreiding op een geklokte D-flipflop. Het component bevat een klok-ingang Clk, data-ingangen Din1 , . . . , Dinm , data-uitgangen Dout1 , . . . , Doutn , leespoorten RE1 , REn (ook wel “ReadEnabled” genoemd) en schrijfpoorten WE1 , . . . , WEdlog2 m+1e (ook wel “Write-Enabled” genoemd). Deze ingangen laten ons toe om te kiezen uit welke data-ingang we data willen inlezen en deze bij de klokflank willen opslaan. We zullen data geklokt wegschrijven, net zoals bij een D-flipflop. Indien alle schrijfpoorten WEi = 0 lezen we geen nieuwe waarde in, en blijft de oude waarde behouden. In de andere gevallen dienen de schrijfpoorten een binair getal a te bepalen vanuit welke data-ingang dina we data inlezen. Indien er voor het aantal data-ingangen m geen natuurlijk getal l bestaat zodat l = log2 m + 1, zal er bij alle overige write-enable configuraties, data ingelezen worden uit de laatste data-ingang. Daarnaast kunnen we op eender welke uitgang de inhoud van het geheugen plaatsen. Vandaar dat er per uitgang ook een read-enable ingang is voorzien. Indien we een laag signaal aanleggen op een read-enable ingang REi , zal de overeenkomstige uitgang Douti hoog impedant zijn. De toestand van de uitgangen is niet geklokt: indien we tijdens twee klokflanken in een read-enable ingang aanpassen zullen we mits enige vertraging het resultaat op de datauitgang zien, we hoeven dus niet op een klokflank te wachten. Op figuur 5.6 tonen we een implementatie van een Register File Cell met m = n = 2.
5.3. GEHEUGENCOMPONENTEN
159
X←N Y ←0 Z←0 I←3 co = 0
[True]
ci = 0
X ← X shl 1 co = 0
[False]
[True]
z2 z1 z0 x3 < D
co = 1
[False]
[True]
S1
ci = 1
[False]
S3 S2 Z ← z2 z1 z0 x3 I ←I −1 Y ← Y shl 1
[True]
I>0
Z ← z2 z1 z0 x3 − D I ←I −1 Y ← y2 y1 y0 1
[False] [True]
S5
I>0
Q=Y R=Z
[False]
S4
Figuur 5.5: Toestandsgebaseerd ASM-schema van het leidend voorbeeld.
5.3.2
Registerbank
Een belangrijke toepassing van een Register File Cell is een registerbank. Een registerbank bevat verschillende register file cellen, die geordend worden in matrixstructuur. We spreken dan ook over een m × n registerbank met k schrijfpoorten en l leespoorten. Dit betekent dat de component m sequenties van n bits opslaat. We kunnen hierbij data op k verschillende sequenties tegelijk schrijven, en de inhoud van l verschillende sequenties uitlezen. Hiervoor dienen we volgende in- en uitgangen te voorzien: • invoer-ingangen Iij : een set van k × n ingangen om k sequenties van n bits te kunnen inlezen in de registerbank. • write-enable-ingangen WEi : k verschillende signalen waarmee we aangeven of de invoer op Iij ingangen moet worden ingelezen. • write-address-ingangen WAia : k groepen van dlog2 me bits waarmee we aangeven op welk adres we WE2 WE1
Din1 Din2
00 01 10 11
D
Dout1
Q
Dout2 Clk
Clk
Q
RE1 RE2
Figuur 5.6: Implementatie van een Register File Cell (RFC) met 2 lees- en 2 schrijfpoorten
160
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN de n bits die op Iij staan zullen wegschrijven. • uitvoer-uitgangen Oij : een reeks van l × n signalen die we gebruiken om data in de registerbank uit te lezen. • read-enable-ingangen REi : l signalen die bepalen of we op de uitgangen Oij iets zullen uitlezen. Analoog aan de write-enable-ingangen. • read-address-ingangen RAia : l groepen van dlog2 me bits bepalen welke sequentie – binair voorgesteld op de adres-ingangen – wordt uitgelezen. Dit is analoog aan de write-address-ingangen.
Een registerbank omvat twee scenarios: het inlezen van data en het uitlezen van data. Indien we een hoog signaal aanleggen op WEi , zullen we de data die op de ingangen Iij staan wegschrijven naar het adres dat binair ge¨encodeerd is met de write-access ingangen WAia voor j = 0 . . . n − 1 en a = 0 . . . dlog2 me − 1. Dit doen we op de klokflank. Indien we een laag signaal aan de write-enable ingang plaatsen, wordt de inhoud die op de bijbehorende invoer-ingangen staat genegeerd. Bij het uitlezen van data is het signaal van de read-enable-ingang van belang. Indien we een hoog signaal aanleggen op REi zullen de uitvoer-uitgangen Oij de waardes van de data opgeslagen in een adres, binair gevormd door de read-address-ingangen WAia , aannemen voor j = 0 . . . n − 1 en a = 0 . . . dlog2 me − 1. Indien we een laag signaal aanleggen, zijn deze uitvoer-uitgangen hoog impedant. Uitlezen van data gebeurt ongeklokt: indien we bijvoorbeeld de readadress signalen aanpassen, zullen de uitvoer-uitgangen zich aanpassen ongeacht de toestand van de kok op dat moment. Tot slot beschouwen we vaak een speciaal geval van een registerbank: de dual port registerbank is een registerbank met ´e´en lees- en ´e´en schrijfpoort. Bijgevolg is in dat geval k = l = 1. I00
I10
I01
I11
I12
RFC
RFC
RE0
WA00 WA01 WE0
decoder
decoder
RFC
I02
RFC
RFC
RFC
RA01 RA00 RE1
decoder
RFC
RFC
WA11 WE1
decoder
WA10
RA10 RE2
decoder
RFC
RA11
RFC
O20
RFC
O10
O00
O21
RA21 RA20
RFC
O11
O01
O22
O12
O02
Figuur 5.7: Implementatie van een 4 × 3 registerbank met 2 schrijf- en 3 leespoorten.??
Op figuur 5.7 beschouwen we een 4 × 3 registerbank met 2 schrijf- en 3 leespoorten. Bij de constructie van een registerbank met k schrijf- en l leespoorten, gebruiken we logischerwijs file register cellen met k
5.3. GEHEUGENCOMPONENTEN
161
schrijf- en l leespoorten. We zullen hier het kloksignaal negeren vermits de klokingang van de registerbank het kloksignaal enkel verder propageert naar de klokingangen van alle register file cellen. We construeren vervolgens k + l m-bit decoders te introduceren. Bij elk van de decoders verbinden we een read-enable REi of write-enable WEi met de enable-ingang van de decoder. De read-address RAij en write-address WAij ingangen leggen vervolgens signalen aan op de adres-ingangen van de bijbehorende decoders.?? Verder zullen we ook een nieuwe notatie invoeren die we vanaf hier frequent zullen gebruiken: vaak zullen een groot aantal signalen parallel verschillende bits van de ene component naar de andere overbrengen. Vermits door de ori¨entatie van de de component meestal duidelijk is om welke signalen het gaat, zullen we niet elk signaal individueel tekenen. In dat geval stellen we de groep signalen voor met een brede lijn, en schrijven naast een dwarse streep het aantal signalen op die deze lijn voorstelt.
5.3.3
Random Access Memory (RAM)
Een variant van een registerbank is “Random Access Memory (RAM)”. De term “Random Access” slaat op het feit dat we het geheugen niet sequentieel moeten uitlezen. We kunnen dus een adres meegeven dat bepaalt welke cellen we uitlezen. Verder wijkt een RAM ook af van “Read-Only Memory (ROM)” omdat we data naar het geheugen kunnen schrijven. Bij ROM branden we de data via een ingewikkelde procedure op de chip, waarna we enkel data kunnen uitlezen. Beide eigenschappen zijn ook eigen aan een registerbank. Indien we echter naar de implementatie van een registerbank kijken, is deze niet goedkoop. RAM geheugens bieden een gelijkaardige functionaliteit met minder hardware. Hiervoor bestaan er twee soorten implementaties: • Statisch RAM: hier realiseren we een bit geheugen met een flipflop (wat dus neerkomt op 4 tot 6 transistoren per bit). • Dynamisch RAM: een implementatie met behulp van een condensator. Indien er stroom op de condensator staat bevat de cel een 1, in het ander geval een 0. Dynamisch RAM heeft de eigenschap dat door de data van een bit op te vragen, we de stroom uit de condensator halen, en deze dus opnieuw moeten opladen. Daarnaast kent een condensator ook lekstroom, waardoor we aan een zekere frequentie de cellen die een 1 voorstellen terug moeten opladen. Vermits we minder hardware per bit nodig hebben, zal RAM bepaalde functionaliteit van een registerbank niet aanbieden. Allereerst werkt RAM geheugen trager. Dit kan alleen al verklaard worden door een grotere adres-decoder - RAM geheugens zijn immers groter - en het is dus niet geschikt voor het opslaan van tussenresultaten in processoren. Daarnaast heeft RAM-geheugen een gecombineerde lees-schrijfpoort R/W ∗ . Om aan te geven dat we iets willen schrijven of uitlezen bevat RAM-geheugen daarnaast ook een Chip Select-ingang CS. Deze ingang functioneert ook als een vorm van klok-ingang. RAM geheugen is bijgevolg niet geklokt3 . RAM-geheugens hebben complex tijdsgedrag. Daarom zullen we twee scenario’s bespreken: het uitlezen en wegschrijven van data bespreken samen met de verschillende vormen van vertraging. Verder zullen we ook enkele typische grenzen van vertragingstijden voor vergelijkbare RAM-geheugen geven in tabel 5.3. Uitlezen van data Hiervoor dienen we het adres op de adres-ingang aan te leggen en een hoog signaal ∗ op de Chip Select-ingang CS en de lees-schrijfpoort R/W . Op het moment dat we dit doen, zal de datauitgang4 Dout hoog impedant zijn. Na enige tijd zal er op deze uitgang een ongeldig signaal komen te staan dit wordt meestal veroorzaakt door de interne logica van de component. Vervolgens komt de werkelijke data op de data-uitgangen te staan. Kenmerkend zijn hier de toegangstijd tAA en de CS toegangstijd tACS . Het zijn de maximale tijdsverschillen tussen het aanleggen van het signaal en het verschijnen van de geldige data op de data-uitgangen. Stel dat de lees-schrijfpoort en de chip-select ingang al hoog aangestuurd worden, en we zetten een adres op de adres-ingang zal het hoogstens de tijd gespecificeerd door de toegangstijd 3 Of
tenminste niet op de globale klok van de schakeling. heeft RAM-geheugen geen enkele data-uitgang maar een reeks uitgangen waardoor we bijvoorbeeld 8 bit tegelijk kunnen uitlezen. 4 Meestal
162
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
duren alvorens er geldige data op data-uitgang komt te staan. Omgekeerd kan er ook een geldig adres op ∗ de adres-ingang staan en dienen we nog een hoog signaal op de CS- en R/W aan te leggen. In dat geval duurt het hoogstens de CS toegangstijd alvorens geldige data op de data-uitgang verschijnt. Eenmaal er geldige data op de data-uitgang verschijnt kunnen we deze uitlezen en ergens in de schakeling gebruiken. Om nieuwe data uit te lezen of weg te schrijven zullen we ofwel het adres moeten veranderen, ofwel een laag ∗ signaal op de CS- of R/W -ingang aanleggen. Er treed enige vertraging op alvorens het signaal van de datauitgang dan terugvalt op de hoog impedante toestand. Deze vertraging noemen we de CE Off to Output High Impedance State tHZ . Een laatste tijdseenheid is de leescyclustijd tRC . Deze vertraging bepaalt de minimale duur van het volledige leesproces. Het specificeert de minimale tijd die tussen twee leesopdrachten ligt. Vaak is deze bij DRAM langer dan de som van alle vertragingen die we hierboven beschouwd hebben. Dit komt omdat we na het uitlezen van de data, de condensatoren terug moeten opladen. Een schematische voorstelling van deze tijden staat op figuur 5.8(a). tRC
tWC
Adres
Adres
Adres
Adres
tAA ∗ 0
∗
CS · R/W
CS · R/W tACS
tHZ
geldig
Dout (a) Uitlezen
tDW Din
-
geldig
tDH
-
(b) Wegschrijven
Figuur 5.8: Tijdsgedrag van RAM-geheugens.
Wegschrijven van data Een gelijkaardig scenario treedt op bij het wegschrijven van data, alleen beschouwen we hier de data-ingang5 Din . Opnieuw dienen we eerst het adres aan te leggen op de adres ingang. Verder zetten we een 0 op de lees-schrijfpoort om aan te geven dat we een schrijf-operatie uitvoeren, en zetten we een 1 op de Chip Select-ingang om aan te geven dat we een operatie zullen uitvoeren. Vervolgens kunnen we data op de data-ingang aanleggen. Wanneer we de correcte data wegschrijven is in principe irrelevant. Vanaf het moment dat we de operatie starten, zal het geheugencomponenten beginnen met data weg te schrijven. Als we data aan de data-ingang veranderen zal met enige vertraging de nieuwe data weggeschreven worden. We dienen alleen de tijdkarakteristieken van geheugencomponenten in het algemeen in de gaten te houden: de set-up-tijd tDW en de data houdtijd tDH . Kort voor het afronden van de operatie dient immers de data niet meer te veranderen aan de ingang van de data-ingang. Dit is de set-up tijd. Anderzijds dient de data bovendien nog een zekere periode na het afronden van de operatie te blijven staan: de houdtijd. Tot slot spreken we ook over een schrijf cyclustijd tWC . Dit is de minimale tijd dat het adres op de adres-ingang moet blijven staan en de chip select-ingang en lees-schrijfpoort dezelfde configuratie blijven behouden. Een schematische voorstelling van een schrijfoperatie staat op figuur 5.8(b). Typische vertragingen voor een 4k × 1-RAM6 geheugen voor SRAM en DRAM staan in tabel 5.3.
5.3.4
Geheugens met Impliciete Adressering
RAM geheugens vereisen dat we een absoluut adres meegeven. In heel wat programmeertalen hebben we echter datastructuren beschikbaar die zonder expliciete adressen werken. We spreken dan over een stapelgeheugen ofwel stack en een buffergeheugen ofwel queue. Omdat deze datastructuren bijzonder nuttig zijn in sommige algoritmen, werden hiervoor ook hardware-equivalenten ontwikkeld. We zullen in de volgende subsubsecties eerst deze datastructuren bespreken en vervolgens een hardwarecomponent bouwen 5 Vermits er bij het inlezen op data-uitgang een hoog-impedant signaal wordt aangelegd, combineren sommige RAM-geheugens de data-ingang en de data-uitgang. In dat geval kunnen de signalen dus in beide richtingen stromen. We gaan hier niet verder op in. 6 Dit betekent dat het geheugencomponent 4096 adressen bevat en elk adres 1 bit bijhoudt.
5.3. GEHEUGENCOMPONENTEN ∆t tRC tAA tACS tHZ tW C tDW tDH
163
Vertraging cyclustijd lezen toegangstijd CS toegangstijd CS 0 → Z cyclustijd schrijven data set-up-tijd data houdtijd
2147H SRAM min max 35 ns 35 ns 35 ns 0 ns 30 ns 35 ns 20 ns 0 ns
MM5280 DRAM min max 400 ns 200 ns 180 ns 0 ns 0 ns 150 ns 0 ns
Tabel 5.3: Typische vertragingstijden voor RAM-geheugens. die deze structuren implementeert. Studenten met een uitgebreide kennis over deze datastructuren kunnen de definitie overslaan. Stack (LIFO: Last-In-First-Out) Definitie Een stack ofwel stapelgeheugen is een datastructuur die een lineare lijst voorstelt. Alle methodes van de stapel kunnen enkel bewerkingen uitvoeren op ´e´en uiteinde van deze lijst: de top. De lijst van aangeboden functionaliteiten verschilt nogal. Toch dient een stapel minstens volgende functionaliteiten aan te bieden: • push: het toevoegen van een element aan de stapel. Dit element wordt dan de nieuwe top. • pop: het weghalen van het element die zich bij de top bevindt. Het element net onder de top wordt dan de nieuwe top. • reset: ook wel clear genoemd. Een operatie die de volledige stapel verwijdert. We kunnen dit opvatten als het herhalen van een pop-operatie totdat de stapel leeg is, in de meeste gevallen kunnen we deze operatie echter sneller uitvoeren. • leeg/empty: controleren of een stapel leeg is en dus geen enkel element bevat. Indien dit het geval is, kan men geen pop-operaties meer uitvoeren. • vol/full: controleren of het volledige geheugen van de stapel gebruikt wordt. Indien dit het geval is, kan men geen push-operaties meer uitvoeren. Deze functionaliteit wordt meestal niet in softwareimplementaties van stapels aangeboden vermits men het geheugen dynamisch kan uitbreiden tot het volledige RAM geheugen in gebruik genomen is. Een fenomeen dat men doorgaans niet beschouwt in software. In hardware is een element een hoeveelheid data met een vast aantal bits. Men spreekt over het “LastIn-First-Out (LIFO)”-principe omdat de elementen die het laatst aan een stapel toegevoegd worden (door middel van een push-operatie), de eerste elementen zijn die terug uit de stapel gehaald worden (door middel van een pop-operatie).
2
1 2
6
(a) Push 6
1
6
6
6
6
6
(b) Push 2
(c) Pop
(d) Push 1
(e) Pop
(f) Pop
Figuur 5.9: Conceptueel voorbeeld van een stapelgeheugen.
164
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Conceptueel voorbeeld We introduceren ook een conceptueel voorbeeld van een stapelgeheugen dat staat op figuur 5.10. Initieel is de stapel leeg en bevat deze dus geen elementen. Vervolgens voeren we een push-operatie uit met als argument 6. Het gevolg is een stapel met als enig element 6. Daarna voeren we een push operatie uit met 2. We voegen dus 2 toe aan de top van de stapel. Hierna voeren we een pop-operatie uit. Vermits het laatste toegevoegde element – dat nog niet van de stapel is gehaald – 2 is, zullen we 2 terugkrijgen. Bij de push-operatie van 1 voegen we 1 toe aan de stapel. De stapel heeft dan als top 1 en subtop 6. Tot slot voeren we twee pop-operaties uit. Omdat 1 het laatste toegevoegde element is, is dit het resultaat van de eerste pop-operatie. Tot slot zullen we ook 6 van de stapel halen. Implementatie met een schuifregister We kunnen een stapel implementeren met behulp van een schuifregister. Voorwaarde is wel dat het geheugen dan niet bijzonder groot kan worden. Bij een push operatie zullen we in dat geval de bits van het element inschuiven en dit aantal bits naar links opschuiven. Bij een pop-operatie schuiven we dit aantal bits terug naar rechts, en stellen de meest rechtse bits dit element voor. Deze implementatie is vrij kostelijk: in 4.2.2 hebben we reeds registers ge¨ımplementeerd. Per bit geheugen hebben we een flipflop en enkele multiplexers nodig. Bij grote stapelgeheugens is deze kost onacceptabel. Daarom zullen we bij grote stapels meestal gebruik maken van RAM-geheugens. 0 1 2 3
3 lees schrijf 0
0 1 2 3
6
(a) Push 6
0 lees schrijf 1
0 1 2 3
6 2
(b) Push 2
0 1 2 3
6 1
1 lees schrijf 2 (e) Pop
1 lees schrijf 2
0 1 2 3
(c) Pop
0 1 2 3
6
6
0 lees schrijf 1 (d) Push 1
0 lees schrijf 1 (f) Pop
Figuur 5.10: Demonstratie van een stapelgeheugen met tellers.
Implementatie met RAM-geheugens Een goedkopere manier is gebruik maken van RAM-geheugens. Hierbij is de kost beperkt tot een 4 ` a 6 transistoren per bit. We realiseren dan een stapelgeheugen met behulp van een RAM-geheugen – die tevens ook de grootte van het stapelgeheugen bepaalt – en twee tellers: het leesadres en het schrijfadres. Indien het RAM-geheugen 2n adressen kent, beschouwen we een n-bit leesteller en n + 1-bit schrijftellers7 . De schrijfteller staat initieel op 0, de leesteller staat initeel op 2n − 1. Wanneer we een push operatie uitvoeren schrijven we de data weg naar het adres voorgesteld door de schrijfteller, en verhogen we beide tellers. Bij een pop-operatie lezen we de data uit het RAM-geheugen op het adres voorgesteld door de leesteller. Vervolgens verlagen we beide tellers. Merk op dat we bij een push- en popoperatie dus niet alle data in het RAM-geheugen moeten opschuiven. We verhogen en verlagen enkel de tellers. Indien we het volledige geheugen volgeschreven hebben, zal de schrijfteller op 2n komen te staan8 . Dit betekent dus dat de n + 1-de bit van die teller een hoog signaal bevat. We kunnen dit hoog signaal naar buiten brengen als een full-signaal. Op figuur 5.11 implementeren we dit stapelgeheugen. Indien het reset-signaal actief wordt, wordt de schrijfteller gereset en komt deze op 0 te staan, de leesteller voert een loadoperatie uit en laadt de waarde 2n − 1 in. Bij een push-operatie wordt het push/pop∗ signaal hoog, hierdoor wordt het increment-signaal bij beide tellers geactiveerd en worden deze opgehoogd in de volgende klokflank. De multiplexer zal intussen de huidige waarde van de schrijfteller doorsturen naar het RAM-geheugen, die de waarde die op de data-ingangen staat zal inlezen en wegschrijven. Bij een pop-operatie ontvangen beide 7 Op
die manier kunnen ze elk adres voorstellen. We voegen aan de schrijfteller een extra bit toe voor overflow. de schrijfteller een n + 1-bit teller is.
8 Vermits
5.3. GEHEUGENCOMPONENTEN
165
Full Empty
n n
n
n
2n − 1
n n
Reset∗
U/D∗ CEin n + 1-bit CEout Clk LD schrijfteller CLR
A
∗
Push/Pop Enable
∗
U/D CEin Clk LD CLR
R/W
n-bit leesteller
D
n
2n × w-bit RAM
CS
Data In/Out
∗
CEout
n
Figuur 5.11: Implementatie van een stapelgeheugen met behulp van RAM-geheugen. tellers een decrement-signaal, de multiplexer stuurt het leesadres door naar het RAM-geheugen die de waarde die op dit adres staat op de data-uitgang zal zetten. Ons component bevat daarnaast nog een enable-ingang: indien deze op 0 staat, worden de tellers en het RAM-geheugen niet aangepast en gebeurt er dus niets. De full-uitgang brengt zoals eerder vermeld de hoogste bit van de schrijfteller naar buiten, en is hoog indien alle geheugenplaatsen opgebruikt zijn. Daarnaast bevat ons component ook een empty-uitgang. Deze voert een NOR-operatie uit op alle bits van de schrijfteller. Indien alle bits 0 zijn (en de teller dus op 0 staat) is de stapel leeg, en geeft empty dus een laag signaal. Tot slot kunnen we opmerken dat we voor de implementatie strikt genomen geen twee tellers nodig hebben. Vermits de leesteller telkens gelijk is aan de gedecrementeerde waarde schrijfteller (en modulo 2n ), zouden we ook een combinatorische moduler kunnen voorzien die de waarde van de leesteller uit de schrijfteller afleidt. In dit geval zal de vertraging van de pop- operaties wel groter worden. Queue (FIFO: First-In-First-Out) Definitie Een queue of buffergeheugen is een datastructuur die een lineare lijst voorstelt. Deze lijst heeft twee uiteindes. Aan het ene uiteinde voegen we elementen toe bij een schrijfoperatie, aan het andere uiteinde zullen we bij een leesoperatie elementen weghalen. Zoals de naam al doet vermoeden heeft een queue hoofdzakelijk de taak om data te bufferen in de tijd9 . Dit kan bijvoorbeeld nuttig zijn indien we een component soms aan hoge snelheid invoer data krijgt (zogenaamde bursts) en men deze data niet aan dezelfde snelheid kan verwerken. Een queue dient minstens volgende functionaliteiten aan te bieden: • Write (ofwel enqueue): het inlezen van data en dit aan ´e´en uiteinde van het buffergeheugen plaatsen. • Read (ofwel dequeue): het uitlezen van data aan het andere uiteinde van het buffergeheugen. • Reset: het buffergeheugen in de initi¨ele toestand plaatsen (waarbij het dus geen elementen bevat). Dit kan opgevat worden als het herhalen van read operaties tot alle elementen uit de queue verdwenen zijn. • Full: een indicator of alle beschikbare geheugenlocaties bezet zijn. • Empty: een indicator dat het buffergeheugen leeg is. 9 Men dient een buffergeheugen niet te verwarren met een buffer-component. Een buffercomponent staat in voor het gelijkmatig verdelen van de spanning over verschillende uitgangen (en buffert dus het elektrisch potentiaal).
166
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
In hardware is een element een hoeveelheid data met een vast aantal bits. Men spreekt over het “FirstIn-First-Out (LIFO)”-principe omdat de elementen die het eerst aan een queue toegevoegd worden (door middel van een write-operatie), de eerste elementen zijn die terug uit de queue gehaald worden (door middel van een read-operatie). 6
2
1
2
(a) Write 6
1
6
6
2
2
1
(b) Write 2
(c) Read
(d) Write 1
(e) Read
(f) Read
Figuur 5.12: Conceptueel voorbeeld van een buffergeheugen.
Conceptueel voorbeeld Analoog aan het stapelgeheugen introduceren we een conceptueel voorbeeld voor een buffergeheugen op figuur 5.13. We voeren dezelfde operaties uit als bij het stapelgeheugen (push is write en pop is read). Toch zien we dat de elementen op een andere manier uit de datastructuur verdwijnen. Aanvankelijk is de queue leeg. Vervolgens plaatsen we met write operaties een 6 en een 2 in de queue. Bij de read operatie zullen we in tegenstelling tot bij een stapel, de 6 uit het geheugen halen. lees 0 0 schrijf
0 1
0 1
lees 0 1 schrijf
6
(a) Push 6
0 1
6 2
(b) Push 2
0 1
lees 1 3 schrijf
1 6 (e) Pop
lees 0 2 schrijf
0 1
(c) Pop
0 1
6
lees 1 2 schrijf (d) Push 1
lees 2 3 schrijf
6
(f) Pop
Figuur 5.13: Demonstratie van een buffergeheugen met tellers.
Implementatie met RAM-geheugens Analoog kunnen we ook een buffergeheugen implementeren met behulp van een RAM-geheugen en een lees- en schrijfteller. De schrijfteller houdt de positie bij van het uiteinde van de rij, waar we elementen zullen bijschrijven. De leesteller houdt de positie van het andere uiteinde bij, waar we elementen zullen uitlezen. We gebruiken het RAM-geheugen op een manier waarbij we de elementen niet dienen te verplaatsen. Dit kunnen we doen door zowel de lees als de schrijfteller aanvankelijk op 0 te zetten. Indien we een schrijf-operatie dienen uit te voeren, schrijven we het elementen op het adres gespecificeerd door de schrijfteller, en incrementeren we deze teller. Bij een lees-operatie lezen we de locatie van het geheugen uit en incrementeren we de leesteller. Indien ´e´en van de tellers aan het einde van het geheugen komt, voeren we eenvoudigweg een wrap-around uit, en schrijven we dus opnieuw op het begin van het geheugen. Een probleem stelt zich op het moment dat de lees- en schrijftellers beide dezelfde waarde hebben. In dat geval zijn er immers twee situaties mogelijk: ofwel zijn op dat moment
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
167
alle geheugencellen bezet, ofwel is op dat moment het buffergeheugen leeg (zoals bijvoorbeeld bij de initi¨ele toestand van de tellers). We verhelpen dit probleem opnieuw door bij een 2n × w-bit RAM geheugen, de tellers uit te breiden naar n + 1-bit tellers. De hoogste bit wordt niet gebruikt om het adres voor het RAM-geheugen aan te wijzen, we beschouwen voor adressering dus enkel de laagste n bits. Indien deze n laagste bits van de lees- en schrijfteller aan elkaar gelijk zijn, speelt zich opnieuw het scenario van vol of leeg af. Indien daarenboven de hoogste bits aan elkaar gelijk zijn, is de queue leeg, indien ze niet gelijk zijn is het buffergeheugen vol. Het conceptueel principe van deze tellers staat op figuur 5.13. Op figuur 5.14 implementeren we een schakeling die een buffergeheugen realiseert. Vermits de tellers in ´e´en richting tellen, makken we gebruik van uptellers. Indien de enable-inang hoog is, zal afhankelijk van het signaal aan de read/write∗ -ingang ´e´en van de tellers een increment uitvoeren. Verder bepaalt deze ingang ook, welke teller de multiplexer naar het RAM-geheugen doorstuurt. De multiplexer stuurt wel enkel de laagste n bits door. De enable ingang zal verder ook het RAM-geheugen activeren. Indien de reset-ingang geactiveerd is, zullen beide tellers terug de initi¨ele waarde 0 krijgen. Tot slot implementeren we de indicators zoals eerder besproken: een buffergeheugen is leeg indien alle n + 1 bits van de twee tellers gelijk zijn. Een buffergeheugen is vol indien op de hoogste bits na de tellers gelijk zijn.
Read/Write∗
CEin
Full n + 1-bit schrijfteller
Comp
CLR
n
Reset∗
n
Clk
n n
n
n0 n
1
A
CLR
Enable
n + 1-bit leesteller
R/W
D
n
2n × w-bit RAM
CS
CEin
Empty
Data In/Out
∗
n
Clk
Figuur 5.14: Implementatie van een buffergeheugen met behulp van RAM-geheugen.
5.4
Synthese van een Niet-Programmeerbare Processor
Nu we een ASM-schema gedefinieerd hebben en nieuwe geheugencomponenten ter beschikkingen hebben kunnen we eindelijk een processor implementeren. We vertrekken vanuit het ASM-schema, en zullen in subsectie 5.4.1 eerst een methode bespreken om op een mechanische manier een ASM-schema om te zetten in een processor. Deze methode leidt tot een straightforward resultaat, maar dit is verre van optimaal. In subsecties 5.4.2, 5.4.3 en 5.4.4 zullen we dan ook optimalisaties bespreken om de processor goedkoper en effici¨enter te maken.
5.4.1
Basisprincipes
Principes We kunnen door volgende principes toe te passen op het ASM-schema een processor bouwen: 1. Elke variabele is een register.
168
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
2. Voor elk register maakt de set-ingang deel uit van het instructiewoord. 3. Elke operatie komt overeen met een functionele eenheid (FU) die logischerwijs dezelfde opdracht uitvoert (indien er dus een optelling in het ASM-schema voorkomt, zullen we een opteller in het datapad plaatsen). 4. Indien een operatie de waarde van een variabele nodig heeft, maken we een verbinding van de uitgang van het bijbehorende register naar de bijbehorende ingang van de functionele eenheid. 5. Indien het resultaat van een operatie wordt weggeschreven naar een variabele, bouwen we een verbinding van de uitgang van de bijbehorende functionele eenheid naar de data-ingang van het register. 6. Indien data-ingangen of constanten ingelezen kunnen worden bij een variabele, bouwen we een verbinding tussen de data-ingang/constante en het bijbehorende register, tenzij de constante 0 is. 7. Indien een variabele op 0 gezet kan worden, bevat het instructiewoord de reset-ingang van het bijbehorende register. 8. Indien verschillende functionele eenheden waardes wegschrijven naar eenzelfde register, voorzien we een multiplexer om de waarde te kiezen. De selectie-ingangen van deze multiplexers behoren tot het instructiewoord. 9. Elk ASM-blok komt overeen met een toestand van de controller. 10. Voor elke test waarbij een variabele betrokken is, dienen we een combinatorische module te bouwen die op basis van de waarde van de registers de test kan uitvoeren. De uitgang van deze test module is ´e´en van het status-signalen, en bijgevolg een deel van de controller-ingangen. 11. De reset- en load-ingangen van de registers vormen samen met de selectie-ingangen de het instructiewoord: een deel van de uitgangen van de controller. 12. Data-uitgangen worden berekend aan de hand van een combinatorische schakeling met als invoer de waarde van de relevante registers, en eventuele instructiewoord-bits. Leidend voorbeeld Datapad Op basis van het ASM-schema op figuur 5.3 op pagina 156 kunnen we een processor bouwen. Het resultaat van van deze omzetting staat op figuur 5.15. In het ASM-schema is er sprake van vier variabelen: X, Y , Z en I. Daarom introduceren we vier registers. Uit het ASM-schema kunnen we afleiden dan zowel Y als Z op 0 gezet kunnen worden. Daarom voorzien we op basis van de register reeds 6 instructiebits: de set-ingangen van de X en I-registers en de set- en reset-ingangen van de Y en Z registers. Voor elk van de registers voorzien we vervolgens een lijn (deze tekenen we onder de registers). We kunnen nu de functionele eenheden introduceren. Alle operaties uit het ASM-schema gebeuren in toestand S2 . In totaal zijn er 6 functionele eenheden: een shift voor zowel X als Y samen met de speciale recombinaties en decrement. We maken geen verschil of de instructies al dan niet voorwaardelijk zijn. Elk van deze functionele eenheden plaatsen we onder de lijnen van de registers. Vervolgens tekenen we verbindingen vanuit de registers en eventuele data-ingangen naar de functionele eenheden. Zo tekenen we een signaal vanuit I naar de decrementor, X en Y naar een shift-operator, en andere registers naar hun specifieke recombinaties. Verder tekenen we ook de testen: I > 0 en z2 z1 z0 x3 < D. Ook deze testen verbinden we met de respectievelijk registers en data-ingangen. Elk van deze testen vormen een deel van het statussignaal. We duiden deze bits aan met onderlijnde grote letters. Vervolgens dienen we de uitgang van de functionele eenheden samen met data-ingangen te verbinden met de ingang van de registers. Zo zien we in het ASM-schema dat de variable X vanuit twee bronnen waardes kan krijgen: vanuit de data-ingang N en vanuit een schuifregister X shl 1. Bijgevolg voorzien we een multiplexer die zowel de data-ingang N als de uitgang van een schuifoperator combineert. De selectie- ingang van deze multiplexer maakt deel uit van het instructiewoord. Bits van het instructiewoord duiden we aan met onderlijnde kleine letters10 . Y kan worden 10 De
voorstelling van bits van het toestand- en instructiewoord zijn louter arbitrair, andere notaties zijn eveneens toegelaten.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
169
gezet op drie soorten waardes: de waarde 0, het resultaat van een andere schuifoperator en de waarde na de recombinatiestap. Vermits we 0 kunnen activeren door een hoog signaal op de reset-ingang van het register aan te leggen, zullen we 0 niet toevoegen aan de multiplexer, en combineert de multiplexer alleen de uitvoer van de schuifoperator met deze van recombinatie-functionele eenheid. Op een gelijkaardige manier realiseren we de rest van de multiplexers. Tot slot dienen we nog combinatorische logica voor de data-uitgangen te bouwen. In dit geval is het simpel: de notitie bij het ASM-schema stelt dat de data-uitgangen Q en R louter de waardes van Y en Z naar buiten brengen. We specificeren dus deze uitgangen en verbinden de bussen van de registers met deze data-uitgangen. We hebben nu het volledige datapad gerealiseerd zoals op figuur 5.15.
N b
d c
X
I>0
z2 z1 z0 x3
B
A Q
e
1 0 R
a
D
shl 1
h
1 0 R
shl 1
y2 y1 y0 1
j
1 0
g f
Y
3
R
R
Z
z2 z1 z0 x3
1 0
i
z2 z1 z0 x3 −D
I
−1
R
Figuur 5.15: Implementatie van het datapad van het leidend voorbeeld via de basisprincipes.
Controller Naast het datapad moeten we ook de controller realiseren. De controller bouwen we op basis van het ASM-schema. Elke toestand van het ASM-schema komt overeen met een toestand van de controller. De invoer van de controller bestaat enerzijds uit controle-ingangen en anderzijds status-signalen. Voor het voorbeeld van de deler betekent dit dus: ci het signaal van de controle-ingang dat aangeeft dat de data-ingangen gereed zijn voor verwerking. A het resultaat van de test z2 z1 z0 x3 < D B het resultaat van de test I > 0 Daarnaast dient de controller zowel een instructiewoord naar co het signaal van de controle-uitgang dat aangeeft dat het algoritme was uitgevoerd en de resultaten op de data-uitgangen staat. a indien hoog wordt de waarde van de variabele X gezet op de waarde van de multiplexer. b indien hoog wordt de waarde N doorgegeven aan het register X, anders wordt X shl 1 doorgegeven. c indien hoog wordt de waarde van de variabele Y gezet op de waarde van de multiplexer. d indien hoog wordt de waarde van de variabele Y gezet op 0.
170
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN e indien hoog wordt de waarde Y shl 1 doorgegeven aan het register Y , anders wordt y2 y1 y0 1 doorgegeven. f indien hoog wordt de waarde van de variabele Z gezet op de waarde van de multiplexer. g indien hoog wordt de waarde van de variabele Z gezet op 0.
h indien hoog wordt de waarde z2 z1 z0 x3 doorgegeven aan het register Z, anders wordt z2 z1 z0 x3 − D. i indien hoog wordt de waarde van de variabele I gezet op de waarde van de multiplexer. j indien hoog wordt de waarde 3 doorgegeven aan het register I, anders wordt I − 1 doorgegeven. Op basis van deze beschrijving kunnen we een toestandstabel bouwen die de volledige controller beschrijft zoals in tabel 5.4 of figuur 5.16. Deze tabel genereren we opnieuw op basis van het ASM-schema. Het Toestand S1
S2
S3
ci 0 1 0 1
Ingang A B 0 0 0 1 1 0 1 1 -
co 0 0 0 0 0 0 1 1
a 1 1 1 1 1 1 0 0
b 1 1 0 0 0 0 -
c 0 0 1 1 1 1 0 0
Uitgang d e f 1 - 0 1 - 0 0 0 1 0 0 1 0 1 1 0 1 1 0 - 0 0 - 0
g 1 1 0 0 0 0 0 0
h 0 0 1 1 -
i 1 1 1 1 1 1 0 0
j 1 1 0 0 0 0 -
Volgende toestand S1 S2 S3 S2 S3 S2 S1 S3
Tabel 5.4: Toestandstabel van de controller van het leidend voorbeeld via de basisprincipes.
0--/10-00-00-0S1
S2
S3
-00/01010010010 -10/01010110110 -01/01010010010 1--/10-00-00-0-11/01010110110
1--/01101-01-11 0--/01101-01-11
Figuur 5.16: Toestandsdiagram van de controller van het leidend voorbeeld via de basisprincipes. instructiewoord – een sequentie aan bits die bepaalt welke instructies op het datapad worden uitgevoerd – is afhankelijk van zowel de toestand als de controller-ingang en statussignalen. Bij wijze van voorbeeld zullen we de controller-tabel van het leidend voorbeeld opbouwen. Bij toestand S1 zijn alle opdrachten onafhankelijk van testen. Bijgevolg zal het instructiewoord ook onafhankelijk zijn van de invoer. Dit instructiewoord kunnen we bouwen aan de hand van de instructies bij toestand 1. Zo is de controller-uitgang co = 0, logischerwijs is dit ook het geval de uitvoer. Daarnaast bevat de toestand de instructie X ← N . Bijgevolg zetten we het set-signaal van het X-register hoog, samen met het selectie-signaal van de multiplexer, waardoor deze N doorgeeft. Dit resulteert in (a, b) = (1, 1). Daarnaast worden Y en Z op 0 gezet. Dit betekent dat we het set-signaal op laag zetten van beide registers en het reset-signaal op hoog. Vermits de waarde van de multiplexers niet wordt ingelezen, maakt het niet uit welke waarde de multiplexer doorgeeft. Daarom is het volgende deel van het instructiewoord (c, d, e, f, g, h) = (0, 1, −, 0, 1, −). De instructie I ← N bepaalt tot slot de rest van het instructiewoord. Het complete instructiewoord wordt dan: S1 : (co, a, b, c, d, e, f, g, h, i, j) = (0, 1, 1, 0, 1, −, 0, 1, −, 1, 1)
(5.2)
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
171
Ondanks het feit dat alle instructies onafhankelijk van testen worden uitgevoerd, is de volgende toestand wel afhankelijk van de ci-controller-ingang. Bijgevolg plaatsen we twee regels in de toestandstabel: indien ci = 0 is de volgende toestand opnieuw S1 , in het andere geval is de volgende toestand S2 . In het geval van toestand S2 zijn sommige instructies wel afhankelijk van de resultaten van enkele testen. Er zijn echter wel enkele instructies die onafhankelijk van testen worden uitgevoerd. Op analoge wijze bekomen we voor deze instructiebits: (co, a, b, i, j) = (0, 1, 0, 1, 0). De andere instructies zijn afhankelijk van de test die we gespecificeerd hebben als de status-bit A ofwel z2 z1 z0 x3 < D. In het geval deze test slaagt zijn de rest van de instructie-bits (c, d, e, f, g, h) = (1, 0, 0, 1, 0, 0). In het andere geval is (c, d, e, f, g, h) = (1, 0, 1, 1, 0, 1). Dit kunnen we formaliseren als: (0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0) if A (5.3) S2 : (co, a, b, c, d, e, f, g, h, i, j) = (0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0) otherwise Opnieuw wordt de volgende toestand gedifferentieerd op basis van een test: B. Indien B waar is, is I > 0 bijgevolg is de volgende toestand S2 , in het geval de test faalt, is de volgende toestand S3 . Tot slot beschouwen we de laatste toestand S3 : hierbij worden er geen instructies uitgevoerd. Bijgevolg staan alle set- en resetsignalen van de registers op 0. Opnieuw is ook de selectie-ingang van de multiplexers irrelevant: de inhoud wordt immers niet opgeslagen in de registers. Tot slot is de controller-uitgang co = 1. Bijgevolg is de volledige uitvoer: S3 : (co, a, b, c, d, e, f, g, h, i, j) = (1, 0, −, 0, 0, −, 0, 0, −, 0, −) (5.4) Ook hier bepaalt de controller-ingang ci de volgende toestand. Bijgevolg differenti¨eren we de volgende toestand opnieuw op basis van deze test. Op basis van deze paragraaf kunnen we dus de controller toestandstabel op tabel 5.4 opstellen. Voor de concrete implementatie van de controller met behulp van flipflops verwijzen we naar het vorige hoofdstuk. Eenmaal de controller en het datapad gebouwd zijn, dienen we beide componenten alleen nog met elkaar te verbinden: de instructie-uitgangen van de controller worden gelinkt met de set- en reset-signalen van de registers en de selectie-ingangen van de multiplexers. De testen die op het datapad worden uitgevoerd vormen dan weer de invoer van de controller. Merk verder ook op dat we hier een input-gebaseerd ASM-schema hebben verwezenlijkt. Een toestandsgebaseerd ASM-schema wordt op compleet analoge wijze gesynthetiseerd, alleen zal het instructiewoord niet afhangen van eventuele testen. Opdelingen zoals bij toestand S2 komen dus niet voor. Betere implementatie Zoals reeds eerder vermeld leidt de procedure die we in deze subsectie hebben ontwikkeld hebben niet tot een optimale oplossing. Er zijn verschillende problemen die afhankelijk van het algoritme tot een ineffici¨ente implementatie leiden: • In deze implementatie zullen we voor elke operatie een aparte functionele eenheid voorzien. Merk echter op dat indien we in eender welke toestand slechts ´e´en optelling uitvoeren we dezelfde opteller zouden kunnen gebruiken. • Nogal wat functionele eenheden hebben gelijkaardige kenmerken. Zo valt Y shl 1 te combineren met y2 y1 y0 1. Functionele eenheden te combineren leidt tot een complexere schakeling maar minder redundante delen. • In sommige algoritmen wordt slechts een subset van de register tegelijk gebruikt. In dat geval kunnen we een registerbank gebruiken en enkel de adressen uitlezen die bij een bepaalde toestand relevant zijn. • We dienen niet steeds per register een bus te voorzien. Indien bij elke toestand een deel van de register belangrijk zijn, kunnen we op een beperkt aantal bussen de waardes van de relevante registers plaatsen. • Soms kunnen we het ASM-schema verder optimaliseren. Dit sluit enigzinds aan bij de discussie over het aantal toestanden die we gebruikten voor de vertaling van het algoritme naar een ASM-schema. • Logischerwijs kunnen we de toestandstabel van de controller eerst minimaliseren alvorens deze te implementeren. In de volgende subsecties zullen we een groot deel van deze problemen bespreken en toepassen op het leidend voorbeeld.
172
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
5.4.2
Ontwerp Controller
Patronen in een algoritme Het ontwerp van een controller is in wezen equivalent met de implementatie van een Finite State Machine (FSM). De controller in het leidende voorbeeld is dan ook vrij eenvoudig te implementeren met behulp van de methodes uit Hoofdstuk 4. Bij complexe programma’s is een implementatie van een controller echter niet meer zo triviaal: deze kennen een groot aantal toestanden en tests, en doorgaans een groot instructiewoord. Daarom werd al snel naar een methode gezocht om snel complexe controllers te bouwen. Dit doen we door volgende patronen in een ontwerp (ASM-schema) te zoeken: • Natuurlijke volgorde van toestanden. • Terugkerende sets van toestanden veroorzaakt door een subroutine. • Eenvoud van het implementeren van logica met behulp van one-hot coderingen. Elk van deze elementen wordt in de volgende subsubsecties verder uitgewerkt. Op basis van deze drie elementen zullen we een component bouwen die een algemene controller vertegenwoordigt: de microprogrammeerbare controller. Een component die we in een schakeling inpluggen en die we gegeven een ASM-schema vervolgens kunnen programmeren en daardoor omvormen tot een concrete controller. Algemene vorm van een controller StatusSignalen (SS)
ControleSignalen (CS)
Next State Logic ControleIngangen (CI)
ControleUitgangen (CO)
SReg Output Logic
Figuur 5.17: Algemene vorm van een controller. Allereerst grijpen we terug naar de definitie van een controller en combineren we deze met de defintie van een sequenti¨ele schakeling. In subsectie 5.1.1 hebben we reeds de invoer en uitvoer van een controller besproken. We zien dezelfde structuur op figuur 5.17. Daarnaast weten we uit Hoofdstuk 4 hoe de algemene sequenti¨ele structuur eruit ziet: • State Register ofwel toestandsregister: een register die de huidige toestand bijhoudt. • Next State Logic: combinatorische logica die de volgende toestand berekent.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
173
• Output Logic ofwel uitvoer logica: een component die het instructiewoord ofwel de controle-signalen berekend, samen met de controle-uitgangen. Beide combinatorische componenten zijn afhankelijk van zowel de controle-ingangen en de huidige toestand bijgehouden door het toestandregister. Daarnaast zullen de statussignalen (de resultaten van de testen in het datapad) de volgende toestand mee helpen bepalen. In het geval van een inputgebaseerd ASM-schema is dit zelfs het geval voor de uitvoer logica. We kunnen dus stellen dat figuur 5.17 de algemene structuur van de controller weergeeft. We zullen dit ontwerp in de volgende subsubsecties aanpassen tot een structuur die gericht is op specifieke eigenschappen van een controller.
Natuurlijke volgorde van toestanden
StatusSignalen (SS)
ControleSignalen (CS)
Next State Logic ControleIngangen (CI)
+1
ControleUitgangen (CO)
SReg Output Logic
Figuur 5.18: Controller met natuurlijke volgorde van toestanden. Men kan de toestand van een controller enigzinds vergelijken met een programmateller. In de meeste gevallen zal een programma dan ook bestaan uit een reeks toestanden waarbij de volgende toestand vaststaat. Omdat het zoeken van een minimale encodering voor grote toestandstabellen tijdrovend is, zullen we deze optie niet beschouwen. Een logisch gevolg hiervan is dat we de opeenvolgende toestanden opeenvolgende toestandscoderingen geven, in plaats van deze volgende toestandscoderingen voor elke toestand uit te rekenen. We kunnen dit probleem eenvoudig oplossen door een incrementor en een multiplexer te voorzien. Een deel van de volgende toestandlogica bestaat er dan uit om te bepalen of we de toestandcodering incrementeren, in het ander geval dient de volgende toestand logica zelf een adres te berekenen. In veel gevallen leidt dit tot een vereenvoudiging van de uitvoer logica: er zijn immers heel wat toestanden die deze increment functie kunnen gebruiken, indien dit het geval is kunnen we bovendien don’t cares invoeren bij de logica die de volgende encodering berekent. De volgende toestandlogica dient dan ook enkel conditionele volgende toestanden genereren. Figuur 5.18. Een oplettende lezer zal misschien reeds opgemerkt hebben dat een register gecombineerd met increment neerkomt op een teller. Vermits we met behulp van de multiplexer kunnen kiezen om het register met 1 op te hogen, ofwel een nieuwe waarde in te laden, hebben we hier een laadbare teller gerealiseerd. Op figuur 5.18 hebben we de componten die leiden tot deze laadbare teller gemarkeerd met behulp van een lichtgrijze rechthoek.
174
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN ControleSignalen (CS)
Push/Pop∗
StatusSignalen (SS)
ControleIngangen (CI)
Next State Logic ControleUitgangen (CO)
LIFO SReg +1
Output Logic
Figuur 5.19: Controller met natuurlijke volgorde van toestanden en subroutines.
Ondersteunen van subroutines Bij het bouwen van een programma wordt vaak gebruik gemaakt van een subroutine: een klein programma dat we oproepen om een bepaalde opdracht uit te voeren en nadien terugkeert naar de toestand die volgt op de toestand waar we de subroutine hebben opgeroepen. Een probleem bestaat erin dat we niet eenvoudigweg de subroutine kunnen omzetten naar een reeks toestanden en vervolgens naar de eerste toestand van deze subroutine kunnen springen. In dat geval weet de subroutine immers niet meer naar welke toestand men dient terug te springen (deze toestand wordt de terugkeertoestand genoemd) nadat de subroutine is uitgevoerd. Een oplossing zou erin kunnen bestaan om in dat geval per oproep van een subroutine de subroutine te kopi¨eren in de structuur. Deze oplossing heeft echter enkele nadelen: • Iedere keer wanneer we een subroutine oproepen dienen we een kopie te maken van alle toestanden. Indien de subroutine Ts verschillende toestanden heeft en we roepen de routine n keer op, resulteert dit in een controller waarvan n · Ts toestanden door de subroutine zijn gegenereerd. Dit leidt dus tot een groot aantal toestanden en complexe logica voor het berekenen van de volgende toestand en de uitvoer. • In sommige programma’s roept een subroutine zichzelf op. Dit fenomeen wordt recursie genoemd. We kunnen dit fenomeen niet rechtstreeks omzetten in de aangereikte oplossing, omdat we niet altijd vooraf weten hoe diep deze recursie gaat. In dat geval zullen we de subroutine eerst moeten herschrijven in een subroutine zonder recursie. De oplossing bestaat dan ook uit een datastructuur genaamd de call stack die – zoals de naam reeds doet vermoeden – een vorm van stapelgeheugen is. De oplossing bestaat eruit bij elke oproep naar het stapelgeheugen de terugkeertoestand op de call stack te zetten. Op het moment dat de subroutine is afgelopen, wordt de terugkeertoestand terug uit het stapelgeheugen uitgelezen en in het toestandsregister geplaatst. De callstack ondersteunt ook recursie omdat indien een subroutine zichzelf oproept, ook de terugkeertoestand van deze subroutine op de stapel wordt gezet. Indien we deze wijziging combineren met wat we al hebben bekomen we een structuur met een incrementor, een stapelgeheugen en een multiplexer zoals op figuur 5.19. De volgende toestand logica heeft dan vier verschillende types instructies:
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
175
• Natuurlijke volgende toestand: het toestandregister wordt met 1 opgehoogd. Dit gebeurt bij toestanden waarbij de volgende toestand vast staat (onafhankelijk van testen). • Specifieke volgende toestand: indien de volgende toestand wel afhankelijk is van testen, of we springen naar een bepaalde toestand in een programma kan de volgende toestand logica zelf een toestand berekenen. • Uitvoeren van een subroutine: in dat geval wordt de natuurlijke volgende toestand van de huidige toestand op de call stack geplaatst, en lezen we de begintoestand van de subroutine in het toestandsregister in. • Terugkeren uit een subroutine: dit is de laatste instructie bij een subroutine. We voeren een popoperatie uit op de call stack en de terugkeertoestand wordt in het toestandsregister ingelezen. We maken dus de veronderstelling dat we terugspringen naar de volgende natuurlijke toestand van de procedure die we hebben opgeroepen11 . We realiseren deze schakeling door naast de incrementor, ook een een stapelgeheugen te plaatsen. De volgende toestandslogica heeft controle over de multiplexer (die kan kiezen uit het stapelgeheugen, de incrementor of een toestandencodering die hij zelf heeft gegenereerd) samen met de push/pop∗ -ingang van het stapelgeheugen. Verder kan de volgende toestand logica ook zelf een toestandcodering genereren door deze aan ´e´en van de data-ingangen van de multiplexer aan te leggen. Werken met “One-Hot” coderingen In het vorige hoofdstuk hebben we het reeds uitgebreid gehad over de one-hot codering. Een one-hotcodering kan de volgende toestand logica drastisch vereenvoudigen. Een probleem is echter dat we bij een one-hot codering het aantal flipflops opdrijven. Een tussenoplossing zou er echter uit kunnen bestaan om een decoder tussen het toestandsregister en de volgende toestand logica te zetten. Merk op dat we verder ook de uitvoerlogica op een gelijkaardige manier kunnen vereenvoudigen. Figuur 5.20 toont een algemene controller waarbij ControleSignalen (CS)
Push/Pop∗
StatusSignalen (SS)
ControleIngangen (CI)
Next State Logic ControleUitgangen (CO)
LIFO SReg +1
Decoder Output Logic
Figuur 5.20: Controller met one-hotcodering. 11 We kunnen echter de component aanpassen dat we ook zelf een terugkeertoestand kunnen invoeren. Anderzijds kunnen we, indien dit nodig is, van de terugkeertoestand ook een lege toestand maken en de volgende toestandlogica dan naar het juiste adres laten springen.
176
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
we een decoder tussen het toestandsregister en de volgende toestand- en uitvoer-logica’s plaatsen. Programmeerbare controller In plaats van specifieke logica te voorzien voor de volgende toestand logica en de uitvoer logica, kunnen we deze componenten ook vervangen door een meer algemene structuur: een vorm van look-up tables. Indien we deze look-up table vervolgens combineren met de decoder bekomen we een geheugen (deze componenten staan gemarkeerd op figuur 5.20). Welk geheugen we gebruiken is in principe arbitrair. Indien we een ROM-geheugen gebruiken kunnen we de controller eenmaal programmeren naar een specifieke controller. Een andere mogelijkheid is om een RAM-geheugen te gebruiken waarbij we de specifieke controller telkens inladen bij het opstarten van het elektronisch circuit. Een voordeel van het gebruik van een RAM-geheugen is dat we bijgevolg het algoritme kunnen wijzigen, op voorwaarde dat alle benodigde hardware op het datapad aanwezig is. Daarentegen betalen we een prijs dat bij het opstarten van de component we eerst de controller moeten inladen wat tijd vergt. Op figuur 5.21 tonen we een realisatie de microprogrammeerbare controller. StatusSignalen (SS)
ControleIngangen (CI)
ControleSignalen (CS)
LIFO SReg
ROMgeheugen
ControleUitgangen (CO)
+1
Figuur 5.21: Microprogrammeerbare controller. Merk op dat we geen aparte geheugens voor de volgende toestand en de uitvoer voorzien. We kunnen beide componenten immers combineren tot ´e´en geheugen component. Het ROM-geheugen dient dan ook verschillende rijen van bits op te slaan: • Push/Pop bits: wordt gebruikt bij het oproepen of verlaten van een subroutine, ofwel blijft het stapelgeheugen ongewijzigd. • Multiplexer bits: bepalen welke van de drie bronnen van toestandscoderingen we gebruiken: natuurlijke opvolging, eigen adressering of stapelgeheugen. • Toestandsencodering: in het geval men naar een speciale toestand wil gaan (geen natuurlijke opvolging). • Controle-uitgang: bits die de toestand van een algoritme buiten de processor brengen. • Controle-signalen ofwel het instructiewoord: bepaalt welke opdrachten het datapad zal uitvoeren.
5.4.3
Minimaliseren Datapad
Naast het introduceren van een algemene controller zullen we enkele verbeteringen bij een datapad bespreken. Hiervoor zullen we vier technieken bespreken: • Het samenvoegen van variabelen.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
177
• Het samenvoegen van bewerkingen. • Het samenvoegen van verbindingen ofwel “bus sharing”. • Het samenvoegen van registers in een registerbank. Alvorens we al deze optimalisaties bespreken zullen we eerst een ander leidend voorbeeld introduceren. We zullen telkens ´e´en van de leidende voorbeelden gebruiken op de plaatsen waar dit relevant is. Leidend voorbeeld: vierkantswortel benadering Een tweede leidende voorbeeld is het benaderen van een vierkantswortel. Veel programma’s berekenen vaak de vierkantswortel van de som van twee kwadraten (bijvoorbeeld bij het berekenen van een afstand tussen twee punten). Voor de meeste programma’s is het echter niet belangrijk dat deze vierkantswortel met een hoge nauwkeurigheid berekend wordt. Daarom maakt men meestal gebruik van een volgende benadering: p x2 + y 2 ≈ max (max (|x| , |y|) , 0.875 · max (|x| , |y|) + 0.5 · min (|x| , |y|)) (5.5) Figuur 5.22 toont een ASM-schema die deze vierkantswortel kan uitrekenen. Bemerk dat we ook een controleingang start voorzien, die op hoog dient gezet te worden alvorens het algoritme wordt uitgevoerd, en een controle-uitgang ready die aangeeft dat het resultaat berekend is. Daarnaast zijn er twee data-ingangen A en B. Daarnaast voorzien we ook een data-uitgang R die het berekende resultaat naar buiten brengt. Indien
S0
ready=1
t1 ← A t2 ← B
t11 ← max (t5 , t10 )
[True]
[False]
S6
t10 ← t8 + t9
S5
t3 ← |t1 | t4 ← |t2 |
t9 ← t5 − t7
S4
t5 ← max (t3 , t4 ) t6 ← min (t3 , t4 )
t7 ← t5 shr 3 t8 ← t6 shr 1
S1
S2
S7
R = t11
start
S3
Figuur 5.22: ASM-schema van het vierkantswortel-benaderingsalgoritme. we dit ASM-schema op de eerder genoemde wijze zouden implementeren zouden we volgende componenten nodig hebben: • 11 registers (van een arbitrair aantal bits). • 2 absolute waarde functionele eenheden. • 2 maximum functionele eenheden. • 1 minimum functionele eenheid. • 1 opteller functionele eenheden. • 1 aftrekker functionele eenheid.
178
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN • 1 shift 3 posities naar rechts functionele eenheid. • 1 shift 1 positie naar rechts functionele eenheid.
Het is duidelijk dat dit ASM-schema een grote kost met zich teweeg brengt. We zullen in de volgende subsubsecties dan ook de implementatie significant verbeteren.
R
a
t1
R
b
t2
abs
R
c
t3
R
d
abs
t4
max
R
e
t5
min
R
f
t6
g
shr 3
R
t7
R
h
shr 1
t8
R
i
−
t9
R
j
+
t10
R
k
t11
max
Figuur 5.23: Implementatie van het datapad van de benaderende vierkantswortel volgens de basisprincipes.
Kostprijsberekening Alvorens we een goedkopere realisatie van de processor in kwestie kunnen bekomen, dienen we eerst te weten hoeveel elk component precies kost. Hiervoor kunnen we de implementatie van bijvoorbeeld een multiplexer in ´e´en van de vorige hoofdstukken herbekijken, en de prijs uitrekenen. We zullen in deze subsubsectie echter een bondig overzicht geven die de kostprijs van de belangrijkste componenten die we zullen tegenkomen samenvat. Per component zullen we de kostprijs zowel in transistoren als in het aantal logische cellen in een FPGA weergeven. Verder zullen we ook telkens de componenten in functie van 1 bit uitdrukken, bijvoorbeeld een 1 bit register. Het vermenigvuldigen met het aantal bits geeft een ruwe schatting maar ervaring uit vorige hoofdstukken zou moeten leren dat we soms ook heel wat transistoren kunnen uitsparen omdat we sommige deelcircuits kunnen hergebruiken. Variabelen samenvoegen Een belangrijke verbetering is het reduceren van het aantal variabelen en dus het aantal registers. We merken immers op in figuur 5.22 dat de meeste variabelen slechts ´e´enmaal op een waarde gezet worden, en daarna – meestal in de volgende toestand – uitgelezen worden. Vanaf dat moment worden deze variabelen niet meer gebruikt, bijgevolg levert het niets op om hun waarde effectief bij te houden. We kunnen de registers die eerst
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR 3-state buffer # Transistoren # Logische cellen
179
multiplexer
register
10 0
12 1
18 2
24 2
Half Adder
Full Adder
Aftrekker
Opteller/Aftrekker
18 2
36 2
38 2
48 2
# Transistoren # Logische cellen
30 3
44 1
Tabel 5.5: Samenvatting van de kostprijs van de belangrijkste componenten de waarde van de ene variabele bijhielden echter hergebruiken om de waarde van een andere variabele bij te houden. Hiervoor maken we gebruik van een levensduurtabel. Een levensduurtabel is een tabel waarin de variabelen horizontaal worden voorgesteld, en de toestanden verticaal. We markeren een gegeven cel indien we in de gegeven of een latere toestand de waarde van de variabele uitlezen nadat de waarde is toegewezen. Zo zien we bijvoorbeeld op het ASM-schema (figuur 5.22), dat de variabele t5 toegewezen wordt in toestand S2 en we de waarde uitlezen in toestanden S3 , S4 en S6 . Dit betekent dus dat de levensduur van t5 zich uitstrekt van S3 tot en met S6 . Men kan zich misschien afvragen waarom de toestand waarin we de waarde toewijzen niet ook deel uitmaakt van de levensduur. De reden is omdat op dat moment we nog geen register hebben waarin we de variabele opslaan. Let wel: er dient een register te bestaan waarin we plannen de waarde te zullen opslaan. In toestand S2 wordt echter enkel de waarde van t5 berekent en aangelegd op ´e´en van de registers. Het register heeft echter de waarde nog niet opgeslagen. Dit doet het bij de klokflank tussen S2 en S3 . We stellen de levensduur tabel op door voor elke variabele uit te rekenen wanneer welke variabelen actief zijn. De levensduurtabel van het leidend voorbeeld staat in tabel 5.6. Onder de rij van variabelen vermelden we telkens het totaal aantal variabelen die in de gegeven toestand actief zijn. S0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 #
S1 • •
S2
S3
S4
S5
S6
• •
•
•
•
S7
• •
• •
• • •
· 1
2
2
2
3
3
2
• 0
Tabel 5.6: Levensduurtabel van het vierkantswortel voorbeeld.
Formeel algoritme We hebben tabel 5.6 opgesteld door te redeneren over de levensduurte van een bepaalde variabele. We kunnen de levensduur echter ook berekenen met een formeel algoritme. Dit algoritme is geen leerstof die behoort tot het opleidingsonderdeel “Digitale Elektronica en Processoren”, maar is desalniettemin ook nuttig voor andere opleidingsonderdelen zoals bijvoorbeeld “compilerconstructies”, In compilerconstructies wordt het genereren van een dergelijke tabel ook wel de “liveness analyse genoemd”. In [?] wordt zo’n algoritme aangereikt. In het algoritme zal men eerst code opdelen in toestanden. Dit hoeven we hier niet meer te doen: dit zijn immers de toestanden van het ASM-schema. Verder dient elke toestand ook drie verzamelingen bij te houden: • succ [n]: dit is een verzameling toestanden die op toestand n kan volgen. Voor een ASM-blok zonder beslissingskader bestaat de toestand uit juist ´e´en toestand. Voor ASM blokken met beslissingskaders
180
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN uit ´e´en of meerdere toestanden. • use [n]: dit is een verzameling van variabelen die in toestand n gebruikt worden om berekeningen uit te voeren. Voor toestand S5 is dit dus: use [S5 ] = {t8 , t9 } • def [n]: dit is de verzameling van alle variabelen die in een toestand n gedefinieerd worden. Indien we niet weten of een variabele in een bepaalde toestand zal gedefinieerd worden
We dienen vervolgens de volgende twee sets te berekenen per toestand: • in [n]: een variabele zit in in [n] voor een toestand n wanneer er een uitvoer-pad bestaat waarbij de variabele levend is bij het binnenkomen van die toestand. • out [n]: een variabele zit in out [n] voor een toestand n wanneer er een uitvoer-pad bestaat waarbij de variabele levend is bij het verlaten van die toestand. Het algoritme die deze sets kan berekenen staat in Algoritme 4. Het algoritme werkt op basis van leastAlgorithm 4 Berekenen van liveness. 1: function Liveness(succ [n],use [n],def [n]) 2: for all n do 3: in [n] ← ∅ 4: out [n] ← ∅ 5: end for 6: repeat 7: for all n do 8: in’ [n] ← in [n] 9: out’ [n] ← out [n] 10: in [n] ← use [n] ∪ (out [n] \ def [n]) 11: out [n] ← ∪s∈succ[n] in [s] 12: end for 13: until ∀n : in’ [n] = in [n] ∧ out’ [n] = out [n] 14: return (in [n] , out [n]) 15: end function fixed-point theorie. Hierbij berekenen we de sets door ze te initialiseren als lege sets. En vervolgens deze telkens te updaten. Wanneer we een iteratie bereiken waarbij geen enkele set aangepast wordt, weten we dat dit in de volgende iteratie ook niet zal gebeuren. Bijgevolg kunnen we stoppen. In tabel 5.7 staan de succ [n], use [n] en def [n] tabellen samen met de nodige iteraties om de in [n] en out [n] set uit te rekenen. We kunnen opmerken dat de in [n] set dus overeenkomt met de levensduurtabel (zie tabel 5.6). n S0 S1 S2 S3 S4 S5 S6 S7
succ [n] {S0 , S1 } {S2 } {S3 } {S4 } {S5 } {S6 } {S7 } {S0 }
use [n] ∅ {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 } {t8 , t9 } {t5 , t10 } {t11 }
def [n] {t1 , t2 } {t3 , t4 } {t5 , t6 } {t7 , t8 } {t9 } {t10 } {t11 } ∅
in0 [n] ∅ {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 } {t8 , t9 } {t5 , t10 } {t11 }
out0 [n] {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 } {t8 , t9 } {t5 , t10 } {t11 } ∅
in1 [n] ∅ {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 , t8 } {t5 , t8 , t9 } {t5 , t10 } {t11 }
out1 [n] {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 , t8 } {t5 , t8 , t9 } {t5 , t10 } {t11 } ∅
in2 [n] ∅ {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 , t8 } {t5 , t8 , t9 } {t5 , t10 } {t11 }
out2 [n] {t1 , t2 } {t3 , t4 } {t5 , t6 } {t5 , t7 , t8 } {t5 , t8 , t9 } {t5 , t10 } {t11 } ∅
Tabel 5.7: De evolutie van de in [n]- en out [n]-set op basis van het leidend voorbeeld (zie figuur 5.22)
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
181
Nut Men kan zich terecht afvragen wat het nut is van het opstellen van zo’n tabel. Wanneer welke variabele actief is, is niet zo nuttig. Het interessante aspect zit hem eerder in de onderste rij: het aantal actieve variabelen per toestand. Dit getal specificeert immers hoeveel registers we in die toestand eigenlijk nodig hebben om de variabelen te bewaren. De overige variabelen dienen we immers niet meer op te slaan, ze worden verder nergens meer gebruikt. Vermits we in elke toestand slechts een aantal registers nodig hebben, is het totaal aantal benodigde registers niets anders dan het maximum van de onderste rij over alle toestanden. In het geval van het leidend voorbeeld is dit dus: Nreg. = max (1, 2, 2, 2, 3, 3, 2, 0) = 3
(leidend voorbeeld)
(5.6)
We kunnen dus onze schakeling implementeren met drie registers op voorwaarde dat een register de waarde van verschillende variabelen op verschillende tijdstippen bijhoudt. Een eenvoudige methode is aan elk van deze drie registers een lijst met variabelen associ¨eren die dit register zal bijhouden. De enige voorwaarde is dat de variabelen in geen enkele toestand allebei actief zijn. Deze methode zal sowieso tot het minimaal aantal registers leiden, maar introduceert een nieuw probleem: we zullen multiplexers voor de ingang van deze registers moeten plaatsen en bovendien lopen we een gelegenheid mis om multiplexers te elimineren die de waarde van een register doorgeven aan een functionele eenheid. Daarom zullen we extra tabellen opstellen. Functionele-eenhedentabel Een tweede tabel die we zullen opstellen is de functionele-eenhedentabel. Deze tabel bevat horizontaal de toestanden en verticaal de types functionele eenheden. In elke cel schrijven we in, hoeveel functionele eenheden van het specifieke type we in de specifieke toestand nodig hebben. Zo zien we bijvoorbeeld op figuur 5.22 dat we in toestand S2 zowel een component nodig hebben die het minimum berekent als een component die het maximum berekent. In toestand S1 hebben we twee functionele eenheden nodig die elk de absolute waarde berekenen. Indien we dit voor alle toestanden doen, bekomen we tabel 5.8. De enige potenti¨ele moeilijkheid aan het opstellen van deze tabel is de definitie van “type functionele S0 abs max min shr − + #
S1 2
S2
S3
S4
S5
1 1
S6
S7
1 2 1
0
2
2
2
1
1 1
1
0
# 2 1 2 2 1 1 9
Tabel 5.8: Functionele-eenhedentabel van het leidend voorbeeld (zie figuur 5.22) eenheid”. Men kan zich afvragen of bijvoorbeeld een shift over 3 bits bijvoorbeeld tot hetzelfde type behoort als een shift over 1 bit. In geval van twijfel kan het geen kwaad om een onderscheid te maken (en dus een rij in de tabel te voorzien voor shr1 en shr3). Als algemene definitie kunnen we stellen dat twee functionele eenheden tot hetzelfde type behoren wanneer we hardware kunnen voorzien die beide operaties op dezelfde component uitvoert. Indien we dus beslissen om de shift te implementeren met behulp van de verbindingen, is een shift over drie bits een ander operatie dan een shift over 1 bit. Wanneer we echter met een schuifregister werken, kunnen beide operaties op hetzelfde schuifregister worden uitgevoerd. Verbindingentabel, Invoer- en uitvoertabellen Een andere tabel is de zogenaamde verbindingentabel. Deze tabel bevat horizontaal de variabelen, en verticaal de functionele eenheden (niet verwarren met “type functionele eenheid”). In een cel plaatsen we een “I” wanneer de variabele als invoer dient voor de functionele eenheid, en “O” wanneer het resultaat van deze functionele eenheid wordt weggeschreven in de variabele. We gaan er hier altijd van uit dat we in de verschillende toestanden verschillende functionele eenheden gebruiken. Hierdoor ligt het aantal functionele eenheden in deze tabel meestal hoger dan het uiteindelijke aantal functionele eenheden in de implementatie. In deze cursus zullen we de functionele eenheden dan ook nummeren. Zo maken we in toestand S1 gebruik van twee functionele eenheden die de absolute
182
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
waarde berekenen: abs1 en abs2. Hierbij zorgen t1 en t2 respectievelijk voor de invoer bij abs1 en abs2. De resultaten worden weggeschreven naar respectievelijk t3 en t4 . Daarom noteren we in de tabel bij cellen (t1 , abs1) en (t2 , abs2) een “I” en in cellen (t3 , abs1) en (t4 , abs2) een “O”. Indien we dit voor alle toestanden doen, bekomen we tabel 5.9. Als laatste stellen we ook een set invoer- en uitvoertabellen op. Deze tabellen abs1 abs2 max1 min shr 3 shr 1 − + max2
t1 I
t2
t3 O
I I I
t4
t5
O I I
O
t6
t7
t8
t9
t10
t11
O I
O
O I
O I
O
I
I I
O I
I
Tabel 5.9: Verbindingentabel van het leidend voorbeeld (zie figuur 5.22) worden gedeeltelijk afgeleid uit de verbindingentabel (in dit voorbeeld tabel 5.9). In deze tabel hebben we enkel een onderscheid gemaakt tussen invoer en uitvoer. Sommige functionele elementen hebben echter verschillende ingangen. Door variabelen toe te wijzen aan een specifieke ingang maken we de tabel dus concreter. In sommige gevallen staat deze ingang vast. In toestand S4 trekken we bijvoorbeeld t7 van t5 af. Het spreekt voor zich dat we dus t5 verbinden met de eerste ingang en t7 met de tweede ingang. Bij sommige functionele eenheden kunnen we echter kiezen. In dat geval is de operatie die door de functionele eenheid wordt uitgevoerd “commutatief”. Formeler kunnen we stellen dat een functie f commutatief is indien: f (~x) = f (σ~x) voor elke permutatie σ
(5.7)
Concrete voorbeelden van zulke operaties zijn optellen, minimum en maximum. Sommige functionele eenheden hebben meer dan twee ingangen. Ook hier kan er commutativiteit spelen. Soms is de operatie volledig commutatief en is dus elke permutatie geldig. In andere gevallen is er sprake van gedeeltelijke commutativiteit en wordt slechts een subset van permutaties ondersteund. Het toewijzen van ingangen kunnen we natuurlijk willekeurig doen. Toch loont het de moeite om dit op een intelligentere manier te doen. In het leidend voorbeeld (zie figuur 5.22) zien we bijvoorbeeld dat we zowel in toestand S2 en S6 een maximum berekenen. De kans is relatief groot, dat we in de toekomst deze twee bewerkingen op dezelfde functionele eenheid zullen uitvoeren. In toestand S2 berekenen we max (t3 , t4 ), in toestand S6 max (t5 , t10 ). Indien we echter in toestand S6 , max (t5 , t3 ) hadden willen uitrekenen, was het zinvol geweest om deze operatie aan te passen naar max (t3 , t5 ). Indien we dan later de twee functionele eenheden zouden samenvoegen, dienen we geen multiplexer voor de eerste ingang te plaatsen. In het algemeen geldt meestal volgende regel: Wijs dezelfde variabele zoveel mogelijk aan dezelfde ingangen en uitgangen toe. Bij wijze van voorbeeld zullen we deze regel toepassen op het leidend voorbeeld. Hierbij zijn variabelen t1 ,t2 , t6 triviaal: ze worden uitsluitend in functionele eenheden met maar ´e´en ingang gebruikt. Daarom kennen we dus deze ingangen toe aan: (ht1 , abs1i , ht2 , abs2i , ht6 , shr 1i) 7→ (I1 , I1 , I1 )
(leidend voorbeeld)
(5.8)
Vervolgens kunnen we t5 en t7 toewijzen: beide variabelen zijn immers betrokken in een aftrekking. In deze bewerking is t5 verplicht gebonden aan ingang I1 , t7 is gebonden aan ingang t7 : (ht5 , −i , ht7 , −i) 7→ (I1 , I2 )
(leidend voorbeeld)
(5.9)
We kijken eerst of we de toewijzingen van t5 en t7 kunnen uitbreiden. t5 is verder nog betrokken in shr 3 en max2, dit zijn beide commutatieve functionele eenheden. We zullen dus ook voor deze operaties t5 toekennen aan ingang I1 . t7 is in geen enkele andere operatie betrokken. We vatten samen: (ht5 , shr 3i , ht5 , max2i) 7→ (I1 , I1 )
(leidend voorbeeld)
(5.10)
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
183
Nu we t7 aan deze functionele eenheden hebben toegewezen, kunnen we de andere variabelen die in deze operaties betrokken zijn toewijzen: max2 heeft een twee ingangen en aan de andere ingang dient t10 te staan: (ht10 , max2i) 7→ (I2 )
(leidend voorbeeld)
(5.11)
Voor de overige variabelen hebben we niet meteen een aanwijzing. Daarom zullen we deze eenvoudigweg aan een ingang toewijzen. Zo is t3 betrokken in max1 en min. Bij beide operaties kennen we t3 toe aan I1 . Een logisch gevolg is dat t4 toegewezen wordt aan ingang I2 . t8 wijzen we ook arbitrair toe aan I1 voor de + operatie, bijgevolg wijzen we t9 toe aan I2 . (ht3 , max1i , ht3 , mini , ht4 , max1i , ht4 , mini , ht8 , +i , ht9 , +i) 7→ (I1 , I1 , I2 , I2 , I1 , I2 )
(leidend voorbeeld) (5.12) Vermits elke eenheid maar ´e´en uitgang heeft kunnen we ook deze aspecten triviaal oplossen: O1 ht3 , abs1i O1 ht4 , abs2i O1 ht5 , max1i O1 ht6 , mini ht7 , shr 3i 7→ O1 (leidend voorbeeld) (5.13) O1 ht8 , shr 1i O1 ht9 , −i O1 ht10 , +i O1 ht11 , max2i Indien we nu alle voorgaande informatie samenvatten in een tabel, bekomen we de invoer- en uitvoertabellen zoals in tabel 5.10. We zetten hier de variabelen op de horizontale as, en de functionele eenheden op de
abs1 abs2 max1 min shr 3 shr 1 − + max2
t1 •
t2
In I1 t3 t5
t6
t8
t4
In I2 t7 t8
t9
•
t3 •
t4
t5
t6
Out O1 t7 t8
t9
t10
t11
• • •
• •
• •
•
• •
•
•
• •
•
• •
• •
•
Tabel 5.10: Invoer- en uitvoertabellen van het leidend voorbeeld (zie figuur 5.22) verticale as. Variabelen die aan geen enkele functionele eenheid bijdragen hebben we weggelaten uit de kolommen: bijvoorbeeld variabele t1 is nergens verbonden met een ingang I2 , bijgevolg staat deze ook niet in dat deel van de tabel. Het weglaten van deze kolommen is vanzelfsprekend optioneel. Onsamenvoegbaarheid en Prioriteit Nu we deze tabellen hebben opgesteld, kunnen we met het echte werk beginnen: het samenvoegen van registers. Een eerste probleem die we moeten oplossen is bepalen wanneer twee variabelen eenzelfde register kunnen delen. Allereerst kunnen we opmerken dat een variabele eigenlijk niet gebonden is aan een register: we zouden bijvoorbeeld dezelfde variabele in de ene toestand in register 1 kunnen bewaren en de andere toestand in register 2. Dit kan er toe leiden dat we inderdaad tot zeer compacte configuraties komen, maar in de meeste gevallen, maakt het het optimaliseren hopeloos ingewikkeld. Daarom gebruiken we doorgaans de vuistregel: We kennen een variabele toe aan strikt ´e´en register. De vraag blijft in welke omstandigheden we twee variabelen niet in hetzelfde register kunnen opslaan. Een algemene regel is:
184
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN Twee variabelen kunnen niet in hetzelfde register worden opgeslagen indien de twee variabelen leven in ´e´en of meer toestanden.
We kunnen dit formaliseren met behulp van de sets die we berekend hebben in het deel over de lifeness analyse: ∀ti , tj ∈ Variabelen, ti 6= tj : NietSamenvoegen (ti , tj ) ⇔ (∃s ∈ S : ti ∈ in [s] ∧ tj ∈ in [s])
(5.14)
Op basis van deze definitie kunnen we de volledige relatie berekenen van variabelen die we kunnen niet kunnen samenvoegen: (t1 , t2 ) (t3 , t4 ) (t5 , t6 ) (t5 , t7 ) (t5 , t8 ) (t5 , t9 ) (5.15) (t5 , t10 ) (t7 , t8 ) (t8 , t9 ) Toegegeven dat er negen paren van variabelen botsen, maar dit geeft ruimte voor een groot aantal manieren om variabelen samen te voegen. De schaduwzijde van het feit dat veel configuraties mogelijk zijn, is dat er een serieuze kans bestaat dat we een foute configuratie uitkiezen. Om meer gericht op zoek te gaan naar welke variabelen we kunnen samennemen, zullen we een heuristiek ontwikkelen: een functie die aangeeft in welke mate het de moeite loont om twee variabelen samen te nemen. Deze functie heeft de signatuur h : V × V → N, waarbij V de set van variabelen voorstelt, en N de set van natuurlijke getallen (met 0). Een interessante metriek kunnen we opstellen op basis van de invoer- en uitvoertabellen (zie tabel 5.10). De heuristiek defini¨eren we dan als: Het aantal in- en uitgangen die de twee variabelen gemeenschappelijk hebben met elkaar bij functionele eenheden die het potentieel hebben om samengenomen te worden. De argumentatie is de volgende: indien we effectief functionele eenheden samennemen, zal dit er meestal toe leiden dat verschillende registers naar eenzelfde ingang van deze samengestelde functionele eenheid worden geleid. Indien alle variabelen die deze ingang gemeenschappelijk hebben, echter in hetzelfde register opgeslagen zitten, zijn deze multiplexers overbodig. Formeel kunnen we deze functie dus defini¨eren als: ∀ (ti , fa , c) , (tj , fb , c) ∈ Verbindingen, a < b, (fa , fb , c) ∃F ∈ SamenvoegbareFunctioneleEenheden, (5.16) ∀ti , tj , ti 6= tj : prioriteit (ti , tj ) = # fa , fb ∈ F Ook deze definitie zullen we toepassen op leidend voorbeeld. We verwachten dat we max1 en max 2 kunnen samennemen alsook + en −. Daarom wordt de set SamenvoegbareFunctioneleEenheden gelijk aan: SamenvoegbareFunctioneleEenheden = {{max1, max2} , {+, −}} (leidend voorbeeld)
(5.17)
De Verbindingen-set hebben we eigenlijk al opgesteld en kunnen we bekijken in de in- en uitvoertabellen (zie tabel 5.10). De set bestaat uit tuples met als volgorde: (variable, functionele eenheid, verbinding). De Verbindingen bevat dus onder andere de volgende elementen: Verbindingen = {(t1 , abs1, I1 ) , (t3 , abs1, O1 ) , (t2 , abs2, I1 ) , (t4 , abs1, O1 ) , . . .}
(leidend voorbeeld) (5.18)
?? prioriteit (t3 , t5 ) = 1 prioriteit (t4 , t10 ) = 1 prioriteit (t5 , t8 ) = 1 prioriteit (t5 , t11 ) = 1 prioriteit (t7 , t9 ) = 1 prioriteit (t9 , t10 ) = 1
(5.19)
Opstellen van een compatibiliteitsgraaf Met de informatie uit de vorige paragraaf kunnen we een compatibiliteitsgraaf opstellen. Een compatibiliteitsgraaf is een graaf waarbij de knopen (ofwel nodes) entiteiten voorstellen die al dan niet compatibel met elkaar zijn (in dit geval dus de variabelen). Verder bevat de graaf twee soorten bogen: 1. Incompatibiliteitsranden: dit zijn bogen tussen twee knopen die onverenigbaar met elkaar zijn. In het geval van de compatibiliteitsgraaf die we hier aan het opstellen zijn, zijn dit dus de paren uit vergelijking (5.15). We stellen de bogen voor met stippellijnen.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
185
2. Prioriteitsranden: dit zijn bogen tussen twee knopen die net goed verenigbaar zijn, en die dus waarschijnlijk een belangrijk voordeel opleveren wanneer ze samengevoegd worden. We hebben deze bogen berekend met de prioriteitsfunctie uit vergelijking (5.16). In dit geval komt dit dus neer op de bogen in vergelijking (5.19). We stellen de bogen voor met volle lijnen. Bovendien hebben de bogen natuurlijk een label: de waarde van de prioriteit. Een uitgewerkte compatibiliteitsgraaf voor het leidend voorbeeld staat op figuur 5.24 (de gevulde gebieden laten we voorlopig nog buiten beschouwing). De bedoeling van een compatibiliteitsgraaf is om een grafisch hulpmiddel te bieden om de variabelen optimaal samen te voegen. Op basis van de graaf moeten we op zoek gaan naar een max-cut graph partitioning: het opdelen van de graaf in een minimaal aantal groepen zodat het totale gewicht van alle groepen samen maximaal is. Hierbij is het totale gewicht van een groep de som van alle prioriteitsranden waarbij beide knopen in de groep zitten. De partitionering van de graaf dient verder volledig te zijn: elke knoop dient tot juist ´e´en groep te behoren. Het bekomen van een max-cut graph partitioning is een niet-triviaal probleem en valt niet onder deze cursus. We zullen in de volgende paragraaf een methode ontwikkelen waarmee we grafisch tot een redelijke partitionering zullen komen. 1 t1
t3
t2
t4
t11
1
t10
1
1
t5
t9
t6
1
t7
t8
Figuur 5.24: De evolutie van de compatibiliteitsgraaf voor de variabelen.
Partitioneren van de compatibiliteitsgraaf drie stappen bewerkstelligen:
Het bekomen van een optimale partitionering zullen we in
1. Zoek een kliek: een kliek is een groep knopen waarbij er tussen elke twee knopen een incompatibiliteitsrand zit. In het leidend voorbeeld kunnen we dus een kliek beschouwen met de knopen {{t5 } , {t7 } , {t8 }}. Deze variabelen vormen de oorsprong van de partities. 2. Voeg knopen toe op basis van de prioriteitsranden: we gaan de prioriteitsranden van groot naar klein af. Telkens wanneer er juist ´e´en van de knopen al toegevoegd is aan een partitie zullen we proberen de andere knoop ook aan de partitie toe te voegen. Dit kan enkel wanneer er geen incompatibiliteitsrand tussen de knoop van de partitie en de knoop die we willen toevoegen zit. Telkens wanneer we erin slagen om zo’n knoop toe te voegen, overlopen we alle bogen opnieuw. We stoppen wanneer we bij geen enkele boog meer een knoop kunnen toevoegen. Indien twee bogen hetzelfde gewicht hebben, is de volgorde arbitrair. Toegepast op het voorbeeld kunnen we dus de volgorde volledig zelf kiezen. We kiezen de volgorde op basis van de knoop met de laagste index. In het geval beide bogen dezelfde kleinste knoop gemeenschappelijk hebben, dient de andere knoop als “tiebreak”. We behandelen de knopen dus in volgende volgorde: (t3 , t5 , 1) < (t4 , t10 , 1) < (t5 , t11 , 1) < (t7 , t9 , 1) < (t9 , t10 , 1)
(leidend voorbeeld)
(5.20)
Vervolgens beginnen we met toevoegen. De eerste boog die aan de voorwaarden voldoet is (t3 , t5 , 1), we voegen dus t3 toe aan de partitie van t5 . Daarna volgt t11 die eveneens aan t5 wordt toegevoegd. De volgende bogen zijn (t7 , t9 , 1), (t9 , t10 , 1) en (t4 , t10 , 1). We voegen dus t9 , t10 en t4 toe aan de partitie van t7 . Hiermee hebben we alle prioriteitsranden met succes kunnen oplossen. De partitie achter deze stap is dan ook: {{t3 , t5 , t11 } , {t4 , t7 , t9 , t10 } , {t8 }}.
186
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
3. Wijs de overige knopen toe: de laatste stap bestaat er uit om de knopen toe te wijzen die nog vrij zijn. Dit kunnen we arbitrair doen: we voegen een knoop toe aan een partitie naar keuze. Dit kan zolang er geen incompatibiliteitsrand tussen een knoop in de partitie en de knoop die we willen toevoegen zit. Indien dit wel zo is, zullen we een andere partitie moeten kiezen. In het geval voor iedere partitie er een incompatibiliteitsrand bestaat, richt de knoop zijn eigen partitie op. Vervolgens kunnen we weer naar stap 2 terugkeren om eventuele prioriteitranden op te lossen met de nieuwe partitie, om vervolgens weer stap 3 uit te voeren. Zo zullen we in het leidend voorbeeld t1 aan de partitie van t5 toevoegen. t2 kunnen we niet aan diezelfde partitie toevoegen, want tussen t1 en t2 ligt immers een incompatibiliteitsrand. Daarom voegen we t2 toe aan de partitie van t7 . Tot slot dienen we nog t6 toe te voegen. Hiervoor hebben we de keuze tussen de partities van t7 en t8 . We kiezen hier voor de partitie van t8 , maar het alternatief is ook correct. Na deze stap hebben we alle knopen toegewezen en is de partitie de volgende: {{t1 , t3 , t5 , t11 } , {t2 , t4 , t7 , t9 , t10 } , {t6 , t8 }} (leidend voorbeeld)
000 001 010 011 100 101 110 111
g c b
f 11 10 01 00
R a
abs
abs
e
i
R
t1
d
max
min
(5.21)
shr 3
R
t2
shr 1
1 0
h
−
+
t6
max
Figuur 5.25: Implementatie van het datapad van het leidend voorbeeld na het minimaliseren van de variabelen. Minimalisering Figuur 5.25 toont de implementatie van het datapad nadat we de variabelen hebben gereduceerd. De figuur toont drie registers. Elke registers krijgt de naam van een van de element van de partitie12 . Vermits het aantal registers op drie staat, zal ook het aantal verbindingen van de registers naar de functionele eenheden gereduceerd worden. Een register vertegenwoordigt een groep variabelen, bijgevolg trekken we een lijn van een register naar alle functionele eenheden die invoer uitlezen uit minstens ´e´en van de vertegenwoordigde variabelen. De verbinding gebeurt uiteraard met de relevante invoerlijnen. Bijvoorbeeld de min component berekent het minimum tussen t3 en t4 respectievelijk op ingang 1 en 2. Omdat t3 vertegenwoordigd wordt door het register t1 , verbinden we dit register met de eerste ingang. t4 wordt dan weer vertegenwoordigd door register t2 . Bijgevolg verbinden we dit register met de tweede ingang. 12 In werkelijkheid vertegenwoordigt het register alle variabelen in de partitie. We hadden het register t dus ook bijvoorbeeld 1 t3 kunnen noemen.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
187
Het samenvoegen van registers levert ook nog een ander probleem op: wat doet men met de uitvoer van de functionele eenheden. In Figuur 5.23 komt de uitvoer van een functionele eenheid altijd in ´e´en register terecht. Omdat we hier de registers samenvoegen in drie algemene registers lukt dit niet. We kunnen de uitvoer van de functionele eenheden verbinden met het register die de relevante variabele vertegenwoordigt. We kunnen echter geen uitgangen combineren. Dit kan tot kortsluiting leiden en bovendien is het onduidelijk welke uitvoer er in dat geval in het register zou worden ingelezen. We kunnen dit probleem oplossen met behulp van multiplexers. Bij iedere register waar meerdere uitgangen van functionele eenheden toekomen plaatsen we een multiplexer met voldoende data-ingangen. De uitgang van de multiplexer verbinden we vervolgens met het register. Ten slotte zijn de selectie-ingangen van de multiplexer de verantwoordelijkheid van de controller. De controller dient bijgevolg te bepalen uit welke functionele eenheid de data moet worden ingelezen die in het register zal worden geplaatst. Wanneer we een multiplexer introduceren, zal de controller extra logica moeten voorzien om de selectieingangen te besturen. Anderzijds verdwijnt de logica voor de set- en reset-ingangen van de registers die wegvallen. Ook moet de we logica voorzien voor de set- en reset-ingangen van de gegroepeerde registers. In deze paragraaf beschrijven we kort hoe we de logica bepalen voor de selectie-ingangen van de multiplexers. Als voorbeeld nemen we register t1 . Een eerste aspect is het voorzien van de set- en reset-ingangen, indien ´e´en van de oorspronkelijke registers zo’n ingang voorzag. Dus voor het uiteindelijke register t1 moeten we enkel een set-ingang voorzien (verbonden met de controller). Dit komt omdat de originele registers voor t1 , t3 , t5 en t11 uitsluitend een set-ingang voorzien. Een tweede aspect is wanneer set- en reset-ingangen actief moeten worden. Omdat een samengevoegd register alle oorspronkelijke registers vertegenwoordigt, moeten de set- en reset-ingangen actief zijn, wanneer dit bij minstens ´e´en van de originele registers het geval was. Concreet laadt het originele register t1 een waarde in, in toestand 0, t3 doet dit in toestand 1, t5 in toestand 2 en t11 ten slotte in toestand 6. Bijgevolg moet de set-ingang van het samengevoegde register t1 dus actief zijn in toestanden 0, 1, 2 en 6. In alle andere toestand moet het signaal laag zijn. Hetzelfde geldt voor (hier niet aanwezige) reset-ingangen. Indien we de controller dus minimaal willen aanpassen kunnen we een OR-poort plaatsen die als invoer de uitvoer naar de register neemt en zelf het signaal op de set- en reset-ingangen van de samengevoegde registers bepaalt. In de praktijk zal het opnieuw synthetiseren van de logica goedkoper zijn. Een tweede type logica die we moeten synthetiseren is het signaal op de selectie-ingangen. We weten dat het originele register t1 in toestand 0 data moest inladen die op dat moment op data-ingang A van de processor staat. Deze data staat op 11 bij de multiplexer. Bijgevolg moet op dat moment ook deze waarde aan de selectie-ingangen van multiplexer staan. Analoog staat in toestand 1, 10 op de selectie-ingangen. In toestand 2 is het signaal 01, en in toestand 6 is dit 00. In de andere toestanden moeten we natuurlijk ook een signaal op de selectie-ingangen zetten. Omdat de waarde die de multiplexer doorgeeft toch niks uitmaakt, kunnen we hiervoor gebruik maken van don’t cares. Meestal maakt men multiplexers waarbij het aantal data-ingangen machten van twee is. Wanneer we er echter minder data-ingangen gebruikt worden, kunnen we op verschillende ingangen dezelfde data aanleggen. In zo’n situatie kunnen we dan kiezen tussen ´e´en van de data-ingangen die het signaal aanlegt. Dit leidt dus tot meer don’t cares en bijgevolg een mogelijk nog compactere implementatie. Zo zien we dat bij de multiplexer van t2 we meermaals data-ingang B aanleggen. Dit zorgt ervoor dat behalve de hoogste bit, we vrije keuze hebben welke waarde wordt aangelegd. Tabel 5.11 geeft de stuursignalen van alle componenten weer. Toestand 0 1 2 3 4 5 6 7
a 1 1 1 0 0 0 1 0
b 1 0 1 0 -
c 1 1 0 0 -
d 1 1 0 1 1 1 0 0
e 1 0 1 0 -
f 1 1 0 0 -
g 1 0 0 0 0 -
h 0 0 1 1 0 0 0 0
i 1 0 -
Tabel 5.11: Stuursignalen voor de verschillende toestanden na samenvoegen van registers.
188
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Het samenvoegen van registers gaat dus gepaard met de introductie van multiplexers en extra combinatorische logica in de controller. Dit is een van de redenen waarom het moeilijk is om te voorspellen of een optimalisatie effectief tot goedkopere implementaties zal leiden. Bewerkingen samenvoegen (“functional-unit sharing”) In het leidend voorbeeld zien we verschillende functionele eenheden. Sommige van deze functionele eenheden voeren echter dezelfde bewerking in een andere toestand uit. Het is mogelijk goedkoper deze bewerkingen met dezelfde functionele eenheid uit te voeren. Anderzijds zijn sommige functionele eenheden zeer gelijkaardig. In Subsectie ?? hebben we de implementatie van een schakeling besproken die getallen kan optellen en aftrekken. Functionele eenheden die gelijkaardige bewerkingen uitvoeren kunnen meestal worden samengevoegd in schakelingen die beide bewerkingen kunnen uitvoeren, en waarbij de resulterende schakeling goedkoper is dan de som van de twee aparte functionele eenheden. Het samenvoegen van functionele eenheden wordt functional-unit sharing genoemd omdat een functionele eenheid tussen verschillende toestanden wordt gedeeld. Gelijkaardige bewerkingen samenvoegen Een probleem in dit proces is dat het samenvoegen van twee functionele eenheden in een nieuwe functionele eenheid geen sinecure is, en meestal enige ervaring vereist. We zullen in doorheen deze subsectie verschillende functionele eenheden combineren om de lezer een notie te geven over de principes hierachter. Meestal zoekt men naar logica die beide functionele eenheden gemeenschappelijk hebben. Daarna moeten extra ingangen bepalen welke bewerking wordt uitgevoerd door de overige logica aan te sturen. Compatibiliteitsgrafe Eenmaal we de kostprijs berekend hebben van het samenvoegen van verschillende functionele eenheden, dienen we een keuze te maken welke bewerkingen we effectief zullen samenvoegen. Hiervoor zullen we dezelfde werkwijze met de compatibiliteitsgrafe hanteren. In de compatibiliteitsgrafe hebben de componenten de volgende betekenis: 1. Knopen: de knopen stellen bewerkingen voor, dus de originele functionele eenheden. 2. Incompatibiliteitsranden: twee bewerkingen zijn niet verenigbaar, wanneer ze een toestand gemeenschappelijk hebben waarin ze beiden actief zijn. 3. Prioriteitsranden: twee of meer13 bewerkingen die men kan samenvoegen delen een prioriteitsrand. Het gewicht is de winst in kostprijs (transistors of logische blokken) bij het samenvoegen. Figuur 5.26 toont de initi¨ele compatibiliteitsgraaf met de incompatibiliteitsranden. abs1
min
abs2
max1
max2
-
shr 3
+
shr 1
Figuur 5.26: Oorspronkelijke compatibiliteitsgrafe bij het samenvoegen van bewerkingen.
Multiplexers Wanneer twee functionele eenheden worden samengevoegd, delen ze een deel van de ingangen. Het is mogelijk dat de ingangen van beide functionele eenheden verbonden zijn met andere registers. In dat geval moeten extra multiplexers bepalen welk register de invoer levert voor de functionele eenheid. Multiplexers brengen echter een extra kost met zich mee. Zelfs wanneer de samengestelde functionele eenheid 13 Soms
kan men drie of meer bewerkingen samenvoegen in ´ e´ en nieuwe functionele eenheid.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
189
goedkoper is, zal de resulterende schakeling daarom niet noodzakelijk goedkoper zijn. De extra kosten die met het invoeren of aanpassen van multiplexers gepaard gaan, moeten dus ook in rekening worden gebracht. Figuur 5.27 illustreert dit concept. Aanvankelijk zijn er twee functionele eenheden FU1 en FU2, elk met eigen in- en uitgangen. Wanneer we de functionele eenheden in een nieuwe functionele eenheid FU1&2 onderbrengen, introduceren we twee multiplexers. Ook de controller zal extra stuursignalen moeten implementeren: het bedienen van de multiplexers vereist extra logica. Soms zal de samengestelde functionele eenheid ook extra stuursignalen vereisen. Dit is het geval wanneer de twee functionele eenheden niet dezelfde bewerking uitvoeren, en de controller dus moet bepalen welke opdracht zal worden uitgevoerd. Indien sommige registers dezelfde zijn (bijvoorbeeld A en C op de figuur), kunnen we multiplexers weglaten. AB
CD
AC
a
FU1
FU2
F
G
BD
b
c
F
FU1&2
G
Figuur 5.27: Minimaliseren van bewerkingen introduceert multiplexers.
Minimum en Maximum bewerking In het leidend voorbeeld berekenen we het minimum en maximum. Deze schakelingen hebben we niet gedefinieerd in Hoofdstuk 3. De schakeling is echter vrij eenvoudig: we berekenen eerst het verschil tussen de twee getallen. Indien het verschil positief is, zullen we met behulp van multiplexers het tweede getal teruggeven, in het andere geval geven we de waarde terug op de eerste invoer. In het geval van het maximum draaien we de multiplexer om. Een schematische voorstelling staat op Figuur 5.28(a) geeft dit proces schematisch weer. Vermits we bij het verschil enkel ge¨ınteresseerd zijn
AB
ai b cii
AB
−
−
teken
teken 1 0
min(A, B) (a) Minimum
a
ci+1 (b) Carry-logica
1 0
min(A, B)/ max(A, B) (c) Minimax
Figuur 5.28: Implementatie van een minimum-component. in het teken, hoeven we de overige bits niet uit te rekenen. Bijgevolg moeten we ook enkel de carry-logica implementeren. Figuur 5.28(b) toont een mogelijke implementatie van deze carry-logica. De schakeling is bijgevolg een gereduceerde versie van Figuur 3.14(d). Wanneer we de kostprijs van de carry-logic uitrekenen komen we uit op 20 transistors per bit14 . Een multiplexer kost 12 transistors per bit. Bijgevolg kost een minimum- of maximum-component 32 transistors per bit. 14 Op een constante kostprijs na, die we hier niet beschouwen. Als het aantal bits vrij groot is, maakt de constante kostprijs meestal niet veel uit.
190
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
De compatibiliteitsgrafe op Figuur 5.26 toont dat het samenvoegen van de min en max1 bewerking niet mogelijk is. Beide bewerkingen worden immers in dezelfde toestand gebruikt. We kunnen echter wel max1 en max2 samenvoegen. Door het samenvoegen sparen we 32 transistors per bit uit. We dienen echter rekening te houden met de mogelijke introductie van multiplexers. In dit geval hebben we geluk: max1 neemt als invoer variabelen t3 en t4 voorgesteld door registers t1 en t2 . max2 neemt als invoer variabelen t5 en t10 die ook worden opgeslagen in registers t1 en t2 . In dit geval dienen we dus geen extra multiplexers te introduceren, de totale winst is dan ook 32 transistors per bit zoals aangeduid op Figuur 5.37. We kunnen er ook voor opteren om min en max2 samen te voegen. Figuur 5.28(c) toont een functionele eenheid die zowel het minimum als maximum kan uitrekenen. De schakeling verschilt slechts op ´e´en punt van Figuur 5.28(a): er staat een XNOR15 -poort tussen het tekenen van het verschil een de multiplexer. Met behulp van het stuursignaal kan men dus beslissen om het signaal uit het verschil om te draaien of te behouden. Door het signaal om te draaien, kan men dus de andere data-ingang bij de multiplexer selecteren. Omdat de XNOR-poort maar eenmalig in de schakeling moet worden verwerkt, stijgt de kostprijs per bit niet. Ook hier hebben we geluk met de registers: beide functionele eenheden halen hun invoer uit dezelfde registers. De totale winst is dus opnieuw 32 transistors per bit. Abs&max Een volgende combinatie die we uitproberen is het berekenen van een absolute waarde en het maximum. Omdat we in de vorige paragraaf besproken hebben dat het minimum en maximum zeer gelijkaardig zijn, gelden alle uitspraken ook voor een component abs&min. Allereerst dienen we een component te introduceren die de absolute waarde kan uitrekenen. Een mogelijke implementatie staat op Figuur 5.29(a). De meest significante bit bepaalt in complementvoorstelling het teken van het getal. Het teken stuurt vervolai
ai
bi
Max/Abs*
di
A teken an−1
ci+1 ci+1
HA
−
an−1
1 0
1 0
abs a (a) Abs
ci
ci
si m1 m0
11 10 01 00
fi
abs ai (b) Abs per bit
FA
(c) Abs&max per bit
Figuur 5.29: Implementatie van abs en abs&max. gens de selectie-ingang van een multiplexer aan. Indien het getal negatief is, wordt het tegengestelde van het oorspronkelijke getal doorgelaten. In het andere geval wordt het getal zelf doorgelaten. We moeten per bit het tegengestelde uitrekenen en voor elke bit dienen we ook een multiplexer te voorzien. Deze implementatie per bit wordt voorgesteld op Figuur 5.29(b). Op basis van deze schakeling zetten we de kostprijs van een abs bewerking op 32 transistors per bit. We kunnen beide componenten samenvoegen, door per bit een schakeling te implementeren zoals op Figuur 5.29(c). De component berekent ofwel het maximum van de twee data-ingangen, of de absolute waarde van de tweede data-ingang. De schakeling werkt als volgt: de full adders berekenen samen met de NOT-poort het verschil tussen D (voorgesteld door de di -bits) en B (voorgesteld door de bi -bits), het resultaat is een getal S (voorgesteld door de si -bits). Indien we de absolute waarde berekenen (dit betekent dat het signaal Max/Abs* laag staat), is D gelijk aan 0, bijgevolg is S = −B. 15 Een
XOR-poort is ook correct indien het stuursignaal wordt ge¨ınverteerd, alleen kost een XOR-poort meer.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
191
In het geval we het maximum berekenen is S = A − B. Indien we de absolute waarde berekenen, zullen we op basis van het teken van B de multiplexer aansturen, en beslissen of we ofwel B doorlaten (in het geval B positief is), ofwel S = −B. Dit hangt louter af van de hoogste bit van B zoals voorgesteld in Tabel 5.12. In het geval we het maximum berekenen zal het teken van S de multiplexer aansturen. Indien de teken-bit sn−1 laag is (S is positief), laten we A door. S is immers positief wanneer A ≥ B. In het andere geval laten we B door. Op basis van de tekens van B, S en de operatie die we willen uitvoeren (absolute waarde of maximum), moeten we dus de stuursignalen m0 en m1 voor de multiplexer bepalen. Deze stuursignalen zijn voor de multiplexers van alle bits gelijk. Omdat we de logica dus maar eenmalig moeten implementeren zullen we de kostprijs hiervan verwaarlozen. De kost per bit omvat echter de multiplexer (18 transistors per bit), de full adder (36 transistors per bit), de AND-poort (6 transistors per bit) en de NOT-poort (2 transistors per bit). In totaal maakt dit dus 62 transistors per bit. Max/Abs*
bn−1
sn−1
fi
m1
m0
0 0 1 1
0 1 − −
− − 0 1
bi si ai bi
1 0 0 1
− 1 0 −
Tabel 5.12: Multiplexer selectie-ingangen bij abs&max.
Nu we een samengesteld component hebben ge¨ımplementeerd, kunnen we de mogelijke winst berekenen. Er zijn verschillende manieren hoe we een dergelijk component kunnen gebruiken. Hieronder beschouwen we alle mogelijkheden: {abs1, min} , {abs1, max1} , {abs1, max2} {abs2, min} , {abs2, max1} , {abs2, max2} (5.22) {abs1, max1, max2} , {abs2, max1, max2} We zullen niet alle combinaties bespreken. De mogelijke winsten staan op Figuur 5.37. Enkel de scenario’s die interessant zijn worden besproken. Als eerste voorbeeld nemen we abs1 en max1. De twee functionele eenheden apart kosten 64 transistors per bit. Wanneer we de twee functionele eenheden samenvoegen, dan verwachten we slechts 62 transistors per bit te betalen. Een probleem vormt echter de registers: abs1 haalt de gegevens uit register t1 , terwijl max1 deze uit de registers t1 en t2 haalt. Vermits de samengestelde component voor de absolute waarde de tweede ingang neemt, betekent dit dat we een multiplexer moeten plaatsen die kiest tussen register t1 en t2 . Dit concept is ge¨ıllustreerd in Figuur 5.30. We kunnen echter t1
t1 t2
t1
t1 t2
t2 t1
a
⇒ abs1
max1
t1
t6
≡ b
t1
a
abs1&max1
t6
abs1&max1
t1
t6
Figuur 5.30: Het combineren van abs1 en max1 introduceert een multiplexer. een eigenschap van het maximum uitbuiten: deze operator is commutatief. Het maakt dus niet uit of deze component het maximum van t1 en t2 berekent, of van t2 en t1 . Door de bedrading van het maximum om te draaien, vervalt de noodzaak om een multiplexer in te voeren. De totale winst bij het combineren is dus 2 transistors per bit. Ditzelfde principe kan men toepassen bij het samenvoegen van alle combinaties in Vergelijking (5.22) met twee bewerkingen.
192
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
We kunnen ook drie functionele eenheden in een nieuwe functionele eenheid combineren. Vermits we twee functionele eenheden hebben die de absolute waarde uitrekenen en twee die het maximum uitrekenen kunnen we verschillende combinaties uitproberen. Dit kan zolang niet beide absolute waardes door dezelfde component worden uitgerekend. De twee bewerkingen zijn immers incompatibel. Als voorbeeld nemen we abs1, max1 en max2. Vermits max1 en max2 commutatieve operaties zijn maakt de volgorde van de data-ingangen niet uit. Omdat de bewerkingen die we combineren allemaal op dezelfde registers werken, zullen we dus geen extra multiplexers moeten introduceren. De oorspronkelijke kostprijs per bit was 32 transistors voor abs1, 32 transistors voor max1 en 32 voor max2, wat dus samen 96 transistors per bit betekent. De totale winst is dus 34 transistors per bit. Een probleem is hoe we de winsten met drie of meer functionele eenheden in een compatibiliteitsgrafe voorstellen. We kunnen immers geen boog tussen drie knopen trekken. Twee bogen die de drie knopen verbinden kan dan weer tot verwarring leiden: de twee bogen kunnen als twee afzonderlijke prioriteitsranden beschouwd worden. Daarom voert men meestal een gevulde knoop die de prioriteitsrand voorstelt. Vanuit de knoop vertrekken bogen naar de bewerkingen op dewelke de prioriteitsrand betrekking heeft. Op de knoop zelf noteren we de winst. Deze notatie staat ook op Figuur 5.37. Add&Sub In Figuur 3.20(b) op pagina 72 bespraken we reeds hoe we een component kunnen realiseren die zowel een optelling als een aftrekking kan uitvoeren. Op basis van een stuur-signaal kan men beslissen welke operatie uiteindelijk zal worden uitgevoerd. In deze paragraaf bespreken we de mogelijke winst die dit oplevert. Allereerst berekenen we de kostprijs per bit van een aparte opteller en aftrekker. Een opteller kost per bit een full adder, dit komt dus neer op een kostprijs van 36 transistors per bit. Een aftrekker voorziet per bit een full adder en een NOT-poort. De kostprijs is bijgevolg 38 transistors per bit. De totale kostprijs van de twee afzonderlijke componenten is dus 74 transistors per bit. Bij een component die beide bewerkingen uitvoert vervangen we de NOT-poort door een XOR-poort zodat we kunnen kiezen of we de bits inverteren. De kostprijs per bit wordt dus opgedreven naar 48 transistors per bit. Dit betekent dus een winst van 26 transistors per bit. Wanneer we echter naar de bedrading kijken, zien we dat de optelling data uitleest uit registers t1 en t2 . De aftrekking werkt met de registers t6 en t2 . Bijgevolg moeten we een multiplexer introduceren die 12 transistors per bit kost. De totale winst wordt dus 14 transistors per bit. ai bi
ai bi
ai bi
di ai
S/A*
ci
FA
ci−1
fi
ci
FA
ci−1
fi
(a) Opteller per bit
(b) Aftrekker per bit
ci
S/A*
FA
fi
ci−1
ci
bi
1 0
FA
ci−1
fi
(c) Opteller/aftrekker per bit (d) Opteller/aftrekker per bit met multiplexer
Figuur 5.31: Implementatie van een opteller, aftrekker en opteller/aftrekker.
Add&Max We kunnen ook proberen om een optelling een het maximum in ´e´en bewerking samen te voegen. Rekenkundig zijn beide bewerkingen niet direct met elkaar verwant. We kunnen echter op Figuur 5.29(c) vaststellen dat we om het teken van het verschil te berekenen, full adders kunnen gebruiken. Vermits deze componenten de basis vormen van de optelling, is er een vermoeden dat in termen van poorten beide operaties een deel van de logica delen. Figuur 5.32 toont de implementatie per bit voor een zo’n component. Indien we een optelling willen uitrekenen, zal de XOR-poort voor elke bit eenvoudigweg de waarde van bi doorlaten.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR ai
193
bi
Max/Add*
ci+1
ci
FA
si m1 m0
11 10 01 00
fi Figuur 5.32: De implementatie van add&max per bit. Bijgevolg zullen de full adders de optelling van A (voorgesteld door de ai ’s) en B (voorgesteld door de bi ’s) uitrekenen. Het komt er op neer in dat stadion de waarde S (voorgesteld door de si ’s) bij alle multiplexers door te laten. In het geval we het maximum berekenen is het signaal Max/Add* hoog. Bijgevolg doet de XOR-poort dienst als een NOT-poort voor bi . Het gevolg is dat S = A−B. Het teken van S wordt mee in de logica van de selectie-ingangen voor de multiplexer genomen en bepaalt dus of we ofwel A zullen doorlaten (indien S ≥ 0) ofwel B (indien S < 0). Het bepalen van de selectie-ingangen van de multiplexer vereist natuurlijk ook logica. Tabel 5.13 beschrijft in welke omstandigheden welke selectie-ingangen vereist zijn. Max/Add*
sn−1
fi
m1
m0
0 1 1
− 0 1
si ai bi
0 1 1
− 0 1
Tabel 5.13: Multiplexer selectie-ingangen bij add&max. Een eenvoudige implementatie die geen extra kosten met zich meebrengt is m1 = Max/Add* en m1 = sn−1 . De kosten van een add&max-component bestaan uit drie delen: de multiplexer kost 18 transistoren per bit, de XOR-poort 12 transistoren per bit en de full adder 36 transistoren per bit. Samen maakt dit dus 66 transistoren per bit. Nu we de kostprijs berekend hebben, kunnen we bepalen wat een dergelijk component kan opleveren. We kunnen de component op drie verschillende manieren gebruiken: {{+, max1} , {+, max2} , {+, max1, max2}}
(5.23)
Bij alle combinaties komen we hetzelfde probleem tegen: de opteller haalt data uit registers t6 en t2 terwijl de beide componenten die het maximum berekenen dit halen uit de registers t1 en t2 . Doordat beide bewerkingen commutatief zijn kunnen we de ingangen schikken zoals we wensen. Het resultaat blijft echter dat we minimum 1 multiplexer moeten introduceren aan 12 transistors per bit. De kostprijs van een opteller is 36 transistors per bit en het maximum kost 32 transistors per bit. Indien we dus een opteller samenvoegen met ´e´en maximum-component bekomen we dus een verlies van 10 transistors per bit. Dit duidt ook meteen aan dat het samenvoegen van bewerkingen niet altijd goedkoper is. Het rendeert echter wel wanneer we de opteller combineren met twee maximum componenten. In dat geval maken we 22 transistoren per bit winst. Deze winst staat ook op Figuur 5.37. Verliezen worden niet op een compatibiliteitsgrafe gezet. Men zal immers dergelijke prioriteitsranden altijd vermijden omdat het de kostprijs alleen maar verder verhoogt.
194
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Abs&Add&Max Tot dusver hebben we telkens twee types bewerken samengevoegd, eventueel is er wel sprake van meerdere functionele eenheden. Het is echter ook mogelijk meer dan twee types bewerkingen samen te voegen in een nieuwe functionele eenheid. Componenten die drie of meer bewerkingen werden al kort besproken onder de naam “Arithmetic Logic Unit (ALU)” in Subsectie 3.2.6 op pagina 72. Het valt op dat combinaties met de absolute waarde, de opteller en het maximum op Figuren 5.29(c) en 5.32 een soortgelijk patroon vertonen: een full adder met daaronder een multiplexer die ofwel het resultaat van de full adder ofwel dit van de originele ingangen doorlaat. Meestal zijn de ingangen van de full adder ook voorzien van poorten. Het samenvoegen van bewerkingen kan dus mogelijk de transistoren uitsparen die betrokken zijn in de full adder en de multiplexer. Figuur 5.33 toont de implementatie per bit van een component die zowel een optelling, absolute waarde en maximum kan uitrekenen. Hiervoor werkt de component met twee ai
bi
Add’ Abs’
ci+1
ci
FA
si m1 m0
11 10 01 00
fi Figuur 5.33: De implementatie van abs&add&max per bit. stuursignalen: Abs en Add. Indien Abs hoog staat en Add laag, wordt de absolute waarde uitgerekend. Bij Abs laag en Add hoog berekent de component de optelling. Wanneer beide laag staan wordt het maximum uitgerekend. Dit systeem werkt als volgt: wanneer Abs hoog staat, zal het resultaat van de AND-poort 0 zijn16 . Verder zal in alle gevallen waarbij Add laag staat, wordt het signaal ge¨ınverteerd (dit zijn dus alle toestanden behalve de optelling). Hieruit kunnen we drie situaties afleiden: bij een optelling is S = A + B, bij het berekenen van een absolute waarde is S = −B en bij het berekenen van het maximum stellen we S = A − B. Het komt er dus op neer dat de selectie-ingangen van de multiplexer op basis van enerzijds het soort bewerking, en anderzijds het teken van S en B, de juiste data moeten doorlaten. De relevante selectieingangen voor de verschillende situaties staan op Tabel 5.14. De kostprijs per bit voor deze component Abs
Add
bn−1
sn−1
fi
m1
m0
0 0 0 1 1 1
0 0 1 0 0 1
− − − 0 1 −
0 1 − − − −
ai bi si bi si −
0 0 1 0 1 −
0 1 − 1 − −
Tabel 5.14: Multiplexer selectie-ingangen bij abs&add&max. bedraagt 72 transistors per bit: 18 voor de multiplexer, 36 voor de full adder, 12 voor de XOR-poort en 6 voor de AND-poort. We kunnen verder opnieuw heel wat mogelijkheden beschouwen bij het combineren van 16 Bemerk
dat we de negatie nemen van Abs als tweede invoer op de AND-poort.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
195
functionele eenheden:
{abs1, max1, +} , {abs1, max2, +} , {abs1, max1, max2, +} {abs2, max1, +} , {abs2, max2, +} , {abs2, max1, max2, +}
(5.24)
Een eigenschap die we zeker kunnen uitbuiten is dat alle beschouwde bewerkingen commutatief zijn. abs1 haalt bijvoorbeeld data uit register t1 . Dit betekent dus dat we dit register op de tweede ingang moeten aanleggen. Door de operanden van de maximum-bewerkingen om te draaien vermijden we echter dat we hiervoor een multiplexer moeten invoeren. De optelling leest de gegevens echter uit registers t6 en t2 . We zullen dus sowieso een multiplexer moeten introduceren die kiest tussen het register t6 en een ander register (t1 of t2 afhankelijk van de gekozen combinatie). Een dergelijke multiplexer komt met een kost van 12 transistors per bit. Indien we bijvoorbeeld abs2 combineren met de twee maximum-bewerkingen en de opteller, kunnen we de schakeling implementeren zoals op Figuur 5.34(a). In deze schakeling wordt de data van B (voorgesteld door de bi ’s) opgehaald uit register t2 . Het getal A (voorgesteld door de ai ’s) halen we uit register t1 en D (voorgesteld door de di ’s) uit register t6 . De 2-naar-1 multiplexer kiest bijgevolg uit een van de twee registers (register t6 wordt enkel gekozen bij een optelling). Een aspect die we echter kunnen di ai a
bi
0 ai
Add’ Abs
ci
FA
ci+1
si m1 m0
bi
1 0
Add’ Abs’
ci+1
di
11 10 01 00
fi (a) Generische multiplexer.
11 10 01 00
ci
FA
si m1 m0
11 10 01 00
fi (b) Samenstelling met poort.
Figuur 5.34: Methodes bij het introduceren van een multiplexer bij een samengestelde functionele eenheid. uitbuiten is de AND-poort die vlak onder deze multiplexer staat. Het resultaat van de AND-poort bestaat immers uit drie gevallen: ai , di of 0. We kunnen dus de AND-poort en de 2-naar-1 multiplexer samenvoegen in een 3-naar-1 multiplexer. Figuur 5.34(b) toont de implementatie door de AND-poort en de multiplexer samen te drukken. De kostprijs blijft in dit geval constant (al is dat niet altijd zo). Al kan er nog een reden zijn om dit te doen: de tijdsduur van het kritische pad. Wanneer het signaal door een 3-naar-1 multiplexer gaat, is dit sneller dan door een 2-naar-1 multiplexer gevolgd door een AND-poort. Vermits het kritische pad de te realiseren kloksnelheid bepaalt, is dit een niet onbelangrijke factor. Concreet realiseren we de volgende winsten: wanneer we een combinatie maken met ´e´en maximumbewerking is de originele kostprijs 100 transistors per bit. De samengestelde component kost 72 transistors per bit: 18 transistors voor de multiplexer, 36 voor de full adder, 12 voor de XOR-poort en 6 voor de ANDpoort. Verder dienen we ook een multiplexer van 12 transistors per bit te implementeren. De winst is dus 16 transistors per bit. Wanneer we een samenstelling maken met de twee maximum-bewerkingen, besparen we alle transistoren betrokken in de tweede maximum bewerking: 32 transistors per bit. De totale winst is dus 48 transistors per bit.
196
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Abs&Add&Max&Sub In de component die de absolute waarde, de optelling en het maximum samenvoegt in ´e´en functionele eenheid valt op dat in sommige omstandigheden de full adder het verschil van de twee operanden uitrekent. Dit effect is afkomstig van het maximum: we berekenen immers het verschil om te bepalen welk register we zullen doorlaten. Door minimale veranderingen kunnen we een component implementeren die in het geval we een verschil willen uitrekenen, de onderste multiplexer het resultaat van het verschil doorlaat. Hiervoor zullen we teruggrijpen naar Figuur 5.33. We beschouwen ook een extra stuursignaal: Sub. We dienen de schakeling per bit niet aan te passen, deze is dus volledig identiek aan Figuur 5.33. We dienen alleen de logica die de selectie-ingangen van de multiplexer berekent aan te passen. De nieuwe logica staat in Tabel 5.15. Abs
Add
Sub
bn−1
sn−1
fi
m1
m0
0 0 0 0 0 1 1 1 1
0 0 0 1 1 0 0 0 1
0 0 1 0 1 0 0 1 −
− − − − − 0 1 − −
0 1 − − − − − − −
ai bi si si − bi si − −
0 0 1 1 − 0 1 − −
0 1 − − − 1 − − −
Tabel 5.15: Multiplexer selectie-ingangen bij abs&add&max&sub.
De kostprijs verschilt niet van deze van Abs&Add&Max: 72 transistors per bit. {abs1, max1, +, −} , {abs1, max2, +, −} , {abs1, max1, max2, +, −} {abs2, max1, +, −} , {abs2, max2, +, −} , {abs2, max1, max2, +, −}
(5.25)
Min&Sub We onderzoeken ook het samenvoegen van minimum- en verschil-bewerkingen. Uit de implementatie van minumum en maximum weten we al dat we daarvoor het teken van het verschil moeten berekenen. Daarom verwachten we dat het samenvoegen van de componenten winst kan opleveren. Figuur 5.35 toont de implementatie per bit van zo’n component. De full adder rekent altijd het verschil uit: ai
ci+1
bi
ci
FA
si m1 m0
11 10 01 00
fi Figuur 5.35: De implementatie van min&sub per bit. S = A − B. Ofwel wordt vervolgens op basis van het teken van S een getal doorgelaten (in het geval van
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR Sub/Min*
sn−1
m1
m0
0 0 1
0 1 -
0 0 1
0 1 -
197
Tabel 5.16: Multiplexer selectie-ingangen bij min&sub. een minimum-bewerking), ofwel wordt S zelf doorgelaten (wanneer we het verschil uitrekenen). Tabel 5.16 toont hoe we de stuur-signalen van de multiplexer moeten implementeren. De kostprijs per bit bestaat uit de multiplexer (18 transistors), de full adder (36 transistors) en de NOTpoort (2 transistors). Dit maakt dus samen 56 transistors per bit. In de schakeling komt maar ´e´en minimumbewerking en ´e´en verschil bewerking voor. Dit is ook de enige combinatie die we kunnen uitproberen voor deze samengestelde functionele eenheid. Beide originele functionele eenheden halen bovendien gegevens uit dezelfde registers, bijgevolg worden geen extra multiplexers ge¨ıntroduceert. De kostprijs van de twee afzonderlijke functionele eenheden is 70 transistors per bit. We maken dus 14 transistors winst per bit. Abs&Min&Sub Bij het berekenen van de absolute waarde maken we een keuze tussen het ingevoerde getal en de negatie van dat getal. Vermits we in de schakeling van Min&Sub de negatie van een ingevoerd getal berekenen, hopen we deze hardware te kunnen hergebruiken. We proberen dus een Abs&Min&Sub component te implementeren. We moeten echter wel extra logica voorzien: het is immers de bedoeling dat de full adders de negatie zullen leveren, maar dan moet de eerste operand wel op 0 worden gezet. Dit kan men doen door over een AND-poort te voorzien die wanneer het stuur-signaal op de AND-poort 0 is, zal de AND-poort ook 0 op de linkse ingang van de full adder aanleggen. We bekomen dus de schakeling op Figuur 5.36(a). Tabel 5.17 ten slotte, toont de logica bij de selectie-ingangen van de multiplexer. We ai
bi
ai
Abs’
ci+1
Abs’
ci
FA
ci+1
si m1 m0
bi
11 10 01 00
fi (a) Algemene implementatie.
1 0
ci
FA
si m1 m0
11 10 01 00
fi (b) Met multiplexer.
Figuur 5.36: De implementatie van abs&min&sub per bit. beschouwen een verschil-bewerking wanneer zowel Abs en Min allebei op 0 staan. De kostprijs per bit van deze samengestelde component is 62 transistoren: 36 van de full adder, 6 van de AND-poort, 2 voor de NOT-poort en 18 voor de multiplexer. Er zijn twee verschillende combinaties van
198
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN Abs
Min
bn−1
sn−1
fi
m1
m0
0 0 0 1 1 1
0 1 1 0 0 1
− − − 0 1 −
− 0 1 − − −
si bi ai bi si −
1 0 0 0 1 −
− 1 0 1 − −
Tabel 5.17: Multiplexer selectie-ingangen bij abs&min&sub. functionele eenheden die we kunnen samenstellen met deze samengestelde functionele eenheid: {{abs1, min, −} , {abs2, min, −}}
(5.26)
Indien we abs1 betrekken in de combinatie, ontstaat er echter een probleem met de ingangen. De aftrekker berekent immers het verschil tussen de waarde in registers t1 en t2 . Omdat een verschil operator niet commutatief is, mogen we dus de volgorde van de ingangen niet kiezen. abs1 berekent echter de absolute waarde van t1 . Hierdoor moet t1 op de tweede ingang worden aangelegd. Het gevolg is dus dat we een multiplexer moeten introduceren zoals op Figuur 5.36(b). Dit drijft de kostprijs op naar 74 transistors per bit. De originele kostprijs van de afzonderlijke functionele eenheden is 102 transistoren: 32 voor de absolute waarde, 32 voor de minimum en 38 voor het verschil. De winst is dus 40 transistoren per bit voor een combinatie met abs1 en 28 transistoren per bit voor een combinatie met abs2. Combinaties met schuif-operaties over een vast aantal bits In de processor komen ook twee schuifbewerkingen voor: shr 1 en shr 3. Kunnen we deze operaties niet combineren met andere functionele eenheden? Vermits een schuif-bewerking over een vast aantal bits17 wordt ge¨ımplementeerd met behulp van bekabeling, worden er geen transistoren gebruikt. Het combineren met enig ander component zal bijgevolg nooit winst opleveren (het combineren zal immers altijd nieuwe logica introduceren, tenzij de originele bewerkingen niet optimaal werden ge¨ımplementeerd). Uiteindelijk compatibiliteitsgrafe Nu we een groot aantal combinaties hebben uitgeprobeerd bekomen we de compatibiliteitsgrafe of Figuur 5.37. Op de prioriteitsranden staat de winst in transistors per bit. Optimaliseren van een meervoudige compatibiliteitsgraaf Bij de compatibiliteitsgraaf hebben we de max-cut methode gebruikt om tot een goed resultaat te komen. Dit algoritme is echter minder geschikt voor compatibiliteitsgrafes met prioriteitsranden met drie of meer knopen. Het algoritme werkt minder goed vanaf het moment dat de winst op een prioriteitsrand voor drie of meer knopen verschilt van de som van de winsten van prioriteitsranden tussen twee van de knopen. Daarom zullen we gebruik maken van een gretig18 algoritme. We zoeken de prioriteitrand met de meeste winst. Alle betrokken knopen worden vervolgens in een aparte partitie ondergebracht. De knopen samen met prioriteitsranden die betrokken zijn in minstens ´e´en van de knopen worden vervolgens uit de grafe verwijderd waarna we het proces herhalen. Algoritme 5 formaliseert het principe. In het algoritme beschouwen we V , de verzameling van oorspronkelijke bewerkingen. In het geval van het leidend voorbeeld is V dus: V0 = {abs1, abs2, min, max1, max2, −, +, shr1, shr3}
(5.27)
E is de verzameling van prioriteitsranden. We stellen een element e ∈ E voor als een verzameling knopen e ⊆ V . Bijgevolg is E ⊆ P (V ). l : E → N ten slotte is een functie die de prioriteitsranden afbeeldt op een 17 Merk op dat dit niet geldt voor een schuif-operatie over een variabel aantal bits, hiervoor wordt een schuifoperator gebruikt (zie Subsectie 3.3.6 op pagina 88). 18 Engels: greedy.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
199
28 abs1
2
14
min
32
max1
34
shr 3
14
92
abs2
-
max2
+
shr 1
22 54
Figuur 5.37: De uiteindelijke compatibiliteitsgrafe bij het samenvoegen van bewerkingen. Algorithm 5 Het bepalen van sterke samengestelde functionele eenheden. 1: procedure CalculatePartition(V, E,l) . Berekenen van een sterke partitie 2: P←∅ . Initi¨ele partitionering gebaseerd op uitvoer. 3: while V 6= ∅ ∧ E 6= ∅ do . Er zijn nog knopen en bogen over over 4: e? ← argmaxe∈E l (e) . Bereken de prioriteitsrand met de grootste winst. 5: V ← V \ e? . Verwijder de knopen die betrokken zijn met e? . 6: E ← E \ {e|e ∈ E ∧ e ∩ V 6= e} . Verwijder de prioriteitsranden met knopen buiten V . 7: P ← P ∪ e? . Voeg de knopen toe als partities. 8: end while 9: for v ∈ V do . Er zijn nog knopen over, maar geen bogen 10: P ← P ∪ {v} . Voeg de knoop toe als enkelvoudige partitie. 11: end for 12: return P . De uiteindelijke partitie. 13: end procedure
geheel getal die de winst19 voorstelt. In het leidend voorbeeld zijn E en de functie l dus: {abs1, min} : 2, {abs1, min, −} : 28, {abs2, max1, max2, −, +} : 92 {abs2, max1, max2} : 34, {abs2, max1, max2, +} : 54, {min, −} : 14 E0 : l = {max1, max2} : 32, {max1, max2, +} : 22, {−, +} : 14
(5.28)
Met X : f de set X 0 waarbij elk element x ∈ X verreikt is met de waarde f (x). Het element met de hoogste waarde in E0 is {abs2, max1, max2, −, +} met 92 transistoren winst per bit. We nemen bijgevolg deze prioriteitsrand en voegen deze toe aan de partitie-verzameling: P1 = {{abs2, max1, max2, −, +}}
(5.29)
We verwijderen vervolgens de knopen uit V en de interfererende prioriteitsranden uit E: V1 E1 : l
=
{abs1, min, shr1, shr3}
= {{abs1, min} : 2}
(5.30) (5.31)
19 De winst drukt men niet noodzakelijk uit in transistoren per bit: in het geval van een ontwerp op een FPGA zal men bijvoorbeeld het aantal logische blokken nemen.
200
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Er blijft nog ´e´en prioriteitsrand over die we bijgevolg selecteren. We voegen deze toe aan de partitie en verwijderen de relevante knopen en bogen: P2
= {{abs2, max1, max2, −, +} , {abs1, min}}
(5.32)
V2
= {shr1, shr3}
(5.33)
= ∅
(5.34)
E2 : l
We merken dat de verzameling met prioriteitsranden E2 leeg is. We voegen de resterende knopen bijgevolg als enkelvoudige partities toe: P3 = {{abs2, max1, max2, −, +} , {abs1, min} , {shr1} , {shr3}}
(5.35)
Nu we deze partitionering hebben gerealiseerd, kunnen we een nieuwe processor implementeren. Figuur 5.38 toont de realisatie na het minimaliseren van de functionele eenheden.
c b
11 10 01 00
R
a
abs&min
t1
abs&max&+&-
f e
11 10 01 00
R
d
shr 3
t2
h
1 0 R
g
t6
shr 1
Figuur 5.38: Implementatie van het datapad na optimalisatie van de bewerkingen.
Verbindingen samenvoegen (“bus sharing”) Niet alleen transistoren bepalen de kostprijs in een processor. Ook de bedrading vormt een niet te onderschatten kost. Doorgaans bevatten registers echter een groot aantal bits: 16, 32 of 64 bits vormen geen uitzondering. Wanneer we dus een groot aantal verbindingen moeten leggen tussen de registers en de functionele eenheden loopt de kostprijs dus wel op. Daarom tracht men meestal dezelfde verbinding te gebruiken om data van de registers naar de functionele eenheden te brengen. Dit concept wordt dan ook bus sharing genoemd: het delen van verbindingen. Om het aantal verbindingen te verminderen, moeten we echter multiplexers of tri-state buffers introduceren. Het verminderen van de verbindingen komt dus met een kostprijs. Anderzijds bevatten sommige functionele eenheden zelf al multiplexers. Wanneer we twee of meer verbindingen kunnen samenvoegen die op de data-ingangen staan van een multiplexer van een functionele eenheid, kan deze multiplexer worden gereduceerd of zelfs worden ge¨elimineerd. Figuur 5.39 illustreert het principe van bus sharing. In plaats van de originele twee verbindingen bekomen we na de transformatie ´e´en verbinding die gedeeld wordt door de twee registers. Om te voorkomen dat beide registers tegelijk data op de bus plaatsen voorzien we multiplexers. Indien een functionele eenheid aanvankelijk met behulp van een multiplexer kiest vanuit welk register data kan worden uitgelezen, kan deze bij het samenvoegen van de verschillende registers worden ge¨elimineerd. In dit opzicht is het soms zelfs mogelijk om van deze operatie een neutrale operatie te maken. Merk echter op dat een 2-naar-1 multiplexer 12 transistoren per bit kost, terwijl een tri-state buffer 10 transistoren per bit kost. In het voorbeeld maken we dus 8 transistoren per bit verlies. Dit impliceert echter niet dat we altijd verlies maken: stel dat verschillende functionele eenheden met behulp van een multiplexer het uit te lezen register bepaalden, kan het samenvoegen van verbindingen zelfs winst opleveren.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR R
R
R1
R
R2 ⇒
R
R1
a
201
R2
b
a
FU
FU
Figuur 5.39: Het samenvoegen van verbindingen kan multiplexers elimineren.
Compatibiliteitsgrafe Net als de twee vorige optimalisaties zullen we opnieuw gebruik maken van een compatibiliteitsgrafe. In deze compatibiliteitsgrafe zijn de knopen logischerwijs de verbindingen. Een eerste probleem is dat er twee soorten verbindingen zijn: operanden (van registers naar functionele eenheden) en resultaten (van functionele eenheden naar registers). Omdat de twee soorten verbindingen geen effect op elkaar hebben, worden ze apart geoptimaliseerd. We zullen dus twee compatibiliteitsgrafes aanmaken. Twee verbindingen zijn incompatibel wanneer ze in dezelfde toestand actief20 gebruikt worden en gegevens van een verschillende aansturing dragen. Met aansturing bedoelen we een register bij een operand en een functionele eenheid bij een resultaat. Tot slot dienen we ook de prioriteitsranden te introduceren. Er is een voorkeur om twee verbindingen te gebruiken wanneer ze de aansturing delen (en dus tri-state buffers besparen) of eenzelfde gebruiker21 hebben (en dus multiplexers besparen).
Om een compatibiliteitsgrafe op te stellen, zullen we twee nieuwe tabellen introduceren: een operandtabel en een resultaten-tabel. Deze tabellen bevatten in de verticale dimensie de verbindingen van het specifieke type (operanden of resultaten) en in de horizontale dimensie de verschillende toestanden die het algoritme doorloopt. Een cel wordt gemarkeerd wanneer in de gegeven toestand de verbinding actief gebruikt wordt. We zullen dit doen op basis van het algoritme op Figuur 5.22 op pagina 177 en de verbindingen op Figuur 5.38.
In toestand S0 wordt de data ingelezen in de registers t1 en t2 . Bijgevolg gebruiken we 2 verbindingen: r1 : In1 → t1 en r4 : In2 → t2 . We markeren dan ook deze cellen in Tabel 5.17(b). In toestand S2 wordt de absolute waarde van beide registers berekend en wordt het resultaat opnieuw in de registers opgeslagen. Hiervoor wordt de data van registers t1 en t2 respectievelijk naar FU1 en FU2 geleid. Bijgevolg zijn de verbindingen o2 : t1 → FU1.1 en o6 : t2 → FU2.2 actief. Omdat het resultaat ook terug in de registers moet worden geladen, zijn ook resultaten-verbindingen actief: r2 : FU1 → t1 en r5 : FU2 → t2 . Analoog berekenen we de actieve verbindingen van de andere verbindingen en bekomen de waarden in Tabellen 5.17(a) en 5.17(b).
Op basis van de opgestelde tabellen kunnen we de compatibiliteitsgrafes opstellen. Twee verbindingen zijn immers incompatibel wanneer er een kolom bestaat waar beide verbindingen tegelijk actief zijn en de aansturing verschilt. Zo kunnen we uit Tabel 5.17(a) dat o1 compatibel is met alle andere verbindingen: de verbinding is actief in toestand S7 , een toestand waarin geen enkele andere verbinding actief is. o2 is echter wel incompatibel met andere verbindingen. o2 is immers actief in toestanden S1 en S2 . In die toestanden zijn volgende verbindingen actief: o3 , o4 , o6 . Van deze verbindingen wordt o4 ook aangestuurd door register t1 . De verbindingen o3 en o6 worden echter aangestuurd door register t2 . Bijgevolg is o2 incompatibel met 20 Een verbinding wordt uiteraard altijd gebruikt en zal altijd een signaal overbrengen. Met actief bedoelen we dat het resultaat ook effectief zal gebruikt worden. Bij bijvoorbeeld de resultaten betekent dit dat de data in de registers zal worden geladen. 21 Een gebruiker is een functionele eenheid in het geval van een operand en een register in het geval van een resultaat.
202
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN (a) Operand-tabel.
#
Verbinding
o1 o2 o3 o4 o5 o6 o7 o8
t1 t1 t2 t1 t6 t2 t1 t6
S0
→ Out → FU1.1 → FU1.2 → FU2.1 → FU2.1 → FU2.2 → FU3 → FU4
S1
S2
•
• • •
S3
S4
S5
S6
S7 •
•
•
•
•
•
• •
•
S4
S5
S6
• • (b) Resultaten-tabel.
#
Verbinding
S0
r1 r2 r3 r4 r5 r6 r7 r8
In1 → t1 FU1 → t1 FU2 → t1 In2 → t2 FU2 → t2 FU3 → t2 FU1 → t6 FU4 → t6
•
S1
S2
S3
S7
• •
•
• •
•
•
• • •
Tabel 5.18: Operand- en resultaten-tabel van het leidend voorbeeld. o3 en o6 . Analoog berekenen we alle incompatibiliteitsranden van de operanden en de resultaten: Io
= {ho2 , o3 i , ho2 , o6 i , ho3 , o4 i , ho4 , o6 i , ho5 , o6 i , ho7 , o8 i}
(5.36)
Ir
= {hr1 , r4 i , hr2 , r5 i , hr3 , r7 i , hr6 , r8 i}
(5.37)
Vervolgens berekenen we de prioriteitsranden. o1 wordt aangestuurd door register t1 . Andere operanden die door dit register worden aangestuurd zijn o2 , o4 en o7 . We hoeven bij eenzelfde aansturing niet te controleren op het bestaan van een incompatibiliteitsrand. Eenzelfde aansturing is immers een voldoende voorwaarde om te stellen dat deze niet zal bestaan. o1 wordt verder gebruikt door Out. Vermits dit de enige verbinding is die hiervan gebruik maakt, levert het delen van de gebruiker geen extra prioriteitsranden op. We tekenen bijgevolg prioriteitsranden tussen o1 en o2 , o4 en o7 . Vervolgens beschouwen we verbinding o4 op basis van de aansturing vinden we prioriteitsranden met o1 , o2 en o7 . Daarnaast is er een andere verbinding die dezelfde gebruiker deelt: o5 . Omdat beide verbindingen niet tegelijk actief zijn, is er geen sprake van een incompatibiliteitsrand. Daarom tekenen we ook een prioriteitsrand tussen o4 en o5 . Indien we dit proces verder zetten bekomen we de volgende prioriteitsranden: Po
= {ho1 , o2 i , ho1 , o4 i , ho1 , o7 i , ho2 , o4 i , ho2 , o7 i , ho3 , o6 i , ho4 , o5 i , ho4 , o7 i , ho5 , o8 i}
(5.38)
Pr
= {hr1 , r2 i , hr1 , r3 i , hr2 , r3 i , hr2 , r7 i , hr3 , r5 i , hr4 , r5 i , hr4 , r6 i , hr5 , r6 i , hr7 , r8 i}
(5.39)
De compatibiliteitsgrafen van de twee types verbindingen worden voorgesteld in Figuren 5.40(a) en 5.40(b). Nadat we de max-cut methode op de grafen toepassen bekomen we de volgende partities:
Uiteindelijke implementatie
Po
= {{o1 , o2 , o4 , o5 , o7 } , {o3 , o6 , o8 }}
(5.40)
Pr
= {{r1 , r2 , r7 , r8 } , {r3 , r4 , r5 , r6 }}
(5.41)
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
203
o8
o5
r7
r8
o6
o3
r2
r3
o2
o4
r1
r5
o7
o1
r4
r6
(a) Operanden (registers naar functionele eenheden).
(b) Resultaten (functionele eenheden naar registers).
Figuur 5.40: De compatibiliteitsgrafes bij het samenvoegen van verbindingen. Registers samenvoegen in registerbank (“register port sharing”) Registers voorzien niet enkel logica om gegevens op te slaan. Er is ook logica vereist om nieuwe data op te slaan of om de data uit te lezen. We kunnen echter opmerken dat niet steeds alle registers hun data in elke toestand beschikbaar moeten stellen of nieuwe gegevens moeten opslaan. Door registers te groeperen in een registerbank kunnen we besparen op de implementatie van deze functies. Verder kunnen we het aantal multiplexers en tri-state buffers mogelijk reduceren omdat het aantal ingangen en uitgangen van een registerbank beperkter zijn. Dit proces, ook wel register port sharing genoemd, zullen we in deze subsectie bespreken. Alvorens we het aantal registers kunnen reduceren dienen we eerst te onderzoeken hoeveel lees- en schrijfpoorten22 we dienen te introduceren voor de registerbank(en). Hiervoor stellen we eerst een registertoegangstabel ofwel “Register Access Table” op. Op basis van deze tabel kunnen we dan opnieuw minimaliseren met bijvoorbeeld de max-cut methode of in eenvoudige gevallen zelfs exhaustief zoeken. Registertoegangstabel Een registertoegangstabel is een tabel met in de verticale dimensie de verschillende registers en de horizontale dimensie de verschillende toestanden. Een cel wordt gemarkeerd als leeg, lees (R), schrijf (W) of lees/schrijf (RW). De cel specificeert of we in de gegeven toestand uit het gegeven register gegevens uitlezen en/of wegschrijven. We kunnen een registertoegangstabel opstellen met behulp van het ASM-schema op Figuur 5.22 of bijvoorbeeld de operand- en resultaten-tabellen op Tabel 5.18. Wanneer 22 Met poort wordt geen logische (AND, OR, NOT,...) poort bedoelt, maar een toegangspunt waar men data kan uitlezen of wegschrijven.
204
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
1 0
R
FU1
R
t1
FU2
t2
FU3
R
t6
FU4
Figuur 5.41: De implementatie van het datapad na het minimaliseren van de verbindingen. een operand-verbinding aangestuurd door een register ti actief is in toestand Sj , dan zetten we een R in de overeenkomstige cel van de registertoegangstabel. Wanneer er een resultaten-verbinding actief is in deze toestand, plaatsen we een W in de cel. Zo zien we in Tabel 5.17(a) dat in toestand S0 dat geen enkele verbinding actief is. Bijgevolg plaatsen we in de kolom van toestand S0 geen R. In toestand S1 zijn de operand-verbindingen o2 en o6 actief. De overeenkomstige register die aansturen zijn t1 en t2 . We plaatsen dus in de rijen t1 en t2 in kolom S1 een R. Analoog berekenen we de leestoegang van de andere cellen: ht1 , S1 i , ht1 , S2 i , ht1 , S3 i , ht1 , S4 i ht1 , S6 i , ht1 , S7 i , ht2 , S1 i , ht2 , S2 i , ht2 , S4 i R= (5.42) ht2 , S5 i , ht2 , S6 i , ht6 , S3 i , ht6 , S5 i We berekenen op een gelijkaardige manier de schrijftoegang van de verschillende registers. Met behulp van Tabel 5.17(b) kunnen we vaststellen dat in toestand S0 de resultaten-verbindingen r1 en r4 actief zijn. Vermits r1 en r4 data laten inlezen in register t1 en t2 , schrijven we W in de cellen ht1 , S0 i en ht2 , S0 i. In toestand S1 zien we opnieuw activiteit op de verbindingen naar t1 en t2 bijgevolg schrijven we opnieuw W in de volgende kolom. Wanneer we dit proces verder toepassen, bekomen we de volgende lijst van schrijftoegangen: ht1 , S0 i , ht1 , S1 i , ht1 , S2 i , ht1 , S6 i ht2 , S0 i , ht2 , S1 i , ht2 , S3 i W = (5.43) ht2 , S4 i , ht2 , S5 i , ht6 , S2 i , ht6 , S3 i De uiteindelijke registertoegangstabel staat in Tabel 5.19. Een registerbank bevat een set van registers. Een belangrijke vraag is hoeveel lees en schrijfpoorten we moeten voorzien in een registerbank vermits dit in grote mate de kostprijs zal bepalen. De aantallen worden bepaald door de registers die de registerbank vertegenwoordigt. In elke toestand wordt er immers data ingelezen en weggeschreven in deze registers. Het aantal leespoorten is dan ook gelijk aan het maximale aantal
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR Register t1 t2 t6
S0 -
W W -
S1 R R -
W W -
S2 R R -
W W
S3 R R
S4
W W
R R -
W -
205
S5 R R
W -
S6 R R -
W -
S7 R -
-
Tabel 5.19: Registertoegangstabel van het leidend voorbeeld. leesoperaties van de betrokken registers in een bepaalde toestand. Analoog stelt men het aan schrijfpoorten gelijk aan het maximale aantal schrijfoperaties van deze registers in een toestand. We zullen dit concept illustreren met twee voorbeelden. Stel dat we een registerbank opstellen die de registers t1 en t6 groepeert. Vermits in toestand S2 naar beide registers wordt geschreven, moeten we twee schrijfpoorten voorzien. Vermits de registerbank slechts twee registers vertegenwoordigt kan dit aantal onmogelijk groter worden. Verder kunnen we ook vaststellen dat in toestand S3 uit de twee registers data wordt uitgelezen. Bijgevolg is het aantal leespoorten ook gelijk aan twee. Indien we een registerbank met de drie registers t1 , t2 en t6 beschouwen is de situatie echter anders. Er bestaat immers geen enkele toestand waar uit alle registers tegelijk data wordt uitgelezen. Evenmin bestaat er een toestand waarin data in alle betrokken registers wordt weggeschreven. In elke toestand zijn er maximum twee leesbewerkingen en twee schrijfbewerkingen. We dienen dus 2 leespoorten en 2 schrijfpoorten te voorzien, terwijl we drie registers beschouwen. Alvorens de registers samen te voegen in een registerbank, zullen we eerst onderzoeken of het wel interessant is om alle registers in eenzelfde registerbank onder te brengen. Misschien is het interessanter om bijvoorbeeld twee of drie registerbanken te voorzien. Het feit dat we slechts drie registers beschouwen, laat ons toe alle mogelijkheden te onderzoeken. Er zijn in totaal 5 partities: {{t1 } , {t2 } , {t6 }} {{t1 } , {t2 , t6 }} {{t1 , t2 } , {t6 }} (5.44) Pregisterbank = {{t1 , t6 } , {t2 }} {{t1 , t2 , t6 }} Het aantal lees- en schrijfpoorten per partitionering in registerbanken staan in Tabel 5.20. We kunnen vaststellen dat het groeperen van alle registers in ´e´en registerbank de meeste voordelige implementatie is. Registerbanken
# Leespoorten
# Schrijfpoorten
{{t1 } , {t2 } , {t6 }} {{t1 } , {t2 , t6 }} {{t1 , t2 } , {t6 }} {{t1 , t6 } , {t2 }} {{t1 , t2 , t6 }}
1+1+1 1+2 2+1 2+1 2
1+1+1 1+2 2+1 2+1 2
=3 =3 =3 =3 =2
# Poorten
=3 =3 =3 =3 =2
6 6 6 6 4
Tabel 5.20: Registerbank-configuraties voor het leidend voorbeeld.
Vergelijking van de verschillende optimalisaties Om de verschillende optimalisaties samen te vatten, presenteren we Tabel 5.21 die de implementaties na de verschillende optimalisaties samenvat. We drukken de kostprijs uit volgens twee systemen: het aantal transistoren bij een ASIC implementatie en het aantal logische blokken wanneer we de processor implementeren op een FPGA. Verder bepalen we ook het aantal verbindingen. We delen het aantal transistoren verder
206
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN Minimalisatie Reg Origineel Registers Functionele Eenheden Verbindingen Registerbank
484 132 132 132 132
Transistoren FU R→F F→R 234 234 140 140 140
0
Logische cellen Reg FU Tot.
Tot.
0 66
718 432 320 378 326
11 6 5 3 3
14 14 9 9 9
Verbindingen
25 20 14 12 12
20 12 7 4 4
Tabel 5.21: Vergelijking van de kostprijs na de verschillende optimalisaties. op in vier categorie¨en: registers, functionele eenheden, registers naar functionele eenheden en functionele eenheden naar register. De laatst twee bepalen het aantal transistoren die betrokken zijn in de tri-state buffers aan de uitgangen van de aansturing en de multiplexers aan de ingangen van de ontvangers. In het geval van een FPGA kunnen we enkel een onderscheid maken tussen registers en functionele eenheden. De reden is dat een FPGA altijd multiplexers voorziet aan de in en uitgangen en we bijgevolg er de logica tussen registers en functionele eenheden geen extra logische blokken vereist. Merk op dat de kostprijs telkens is uitgedrukt per bit. Indien de registers bijvoorbeeld 32 bit getallen voorstellen moet men de kostprijs ongeveer vermenigvuldigen met 32 om een benaderende kostprijs uit te rekenen.
5.4.4
Andere optimalisaties
Minimaal instructiewoord De verzameling van stuursignalen noemt men doorgaans het instructiewoord. Het is immers een verzameling van bits die voor het datapad de operatie die moet worden uitgevoerd verder specificeert. Een typisch datapad bestaat uit ´e´en of meer registerbanken, een paar tellers, een paar afzonderlijke registers, ´e´en of meer aritmetische logische eenheden (ALU), een schuifoperator en een vergelijker. Al deze componenten introduceren stuursignalen. Figuur 5.42 toont een voorbeeld van hoe zo’n instructiewoord er kan uitzien. Per bit bevat de figuur een korte beschrijving van de betekenis van de bit. 31 R
30 L
29 C
28 COE
27 S
Teller
17
16
15
26
25
24
23
22
13
RF RA2 RA1 RA0 RE2 OE2 Registerbank lees 2
20
19
18
RF WA2 WA1 WA0 WE RA2 RA1 RA0 RE1 OE1 Registerbank schrijf
14
21
Registerbank lees 1
12
11
10
9
8
7
R
L
ROE
F2
F1
F0
Register
ALU
6
5
AOE SH2
4
3
2
SH1
SH0
D
1
0
SOE OOE
Barrel shifter
Figuur 5.42: Een voorbeeld van een instructiewoord.
In de meeste gevallen kan men echter het instructiewoord verkleinen met behulp van verschillende assumpties. Een eerste assumptie is bijvoorbeeld dat niet alle functionele eenheden (ALU, schuifregister,...) tegelijk actief zullen zijn. In plaats van voor elke functionele eenheid een reeks bits in het instructiewoord te voorzien, kunnen we enkele bits reserveren die bepalen of een sequentie aan stuursignalen bedoeld zijn voor de ene functionele eenheid of de andere. Een andere reductie omvat het gebruik van tri-state buffers. Tri-state buffers verhinderen dat uitvoer van registers of functionele eenheden tegelijk op dezelfde verbindingen worden gezet. Bijgevolg zijn de stuursignalen van de tri-state buffers exclusief: slechts ´e´en van de stuursignalen van de tri-state buffers is
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
207
tegelijk actief. In plaats van voor iedere tri-state buffer een bit in het instructiewoord te voorzien, kunnen we in bits een getal uitdrukken die bepaalt welke tri-state buffer nu de data op de verbinding moet zetten. Voor n tri-state buffers wordt het instructiewoord dus gereduceerd van n bits naar dlog2 ne bits. Bij wijze van voorbeeld zullen we nog enkele voorbeelden geven gebaseerd op het instructiewoord van Figuur 5.42. 1. De eerste operandbus bevat ofwel gegevens afkomstig van de de registerbank (leespoort 1) ofwel het register.We kunnen dus ofwel RFOE1 ofwel ROE elimineren. We besparen 1 bit. 2. De tweede operandbus bevat ofwel gegevens afkomstig van de de registerbank (leespoort 2) ofwel de teller.We kunnen dus ofwel RFOE2 ofwel COE elimineren. We besparen 1 bit. 3. In een registerbank is het signaal “read-enabled (RE)” altijd gelijk aan het stuursignaal op het tristate buffer (RFOE). We kunnen dus voor beide leespoorten ofwel REi ofwel RFOEi elimineren. We besparen 2 bits (we beschouwen immers twee leespoorten). 4. De resultaatbus bevat het resultaat van ofwel de ALU ofwel de schuifoperator. We kunnen dus opnieuw het stuursignaal van ´e´en van de tri-state buffers wegwerken: ofwel AOE ofwel SOE. We besparen 1 bit. 5. De ALU en barrelshifter worden nooit tegelijk gebruik (de resultaten kunnen immers niet tegelijk op de bus worden geplaatst). Op basis van de tri-state buffer die de output op de bus plaatst, weten we welke component actief is. De overige bits die voor de instructie instaan (F0, F1, F0, SH2, SH1, SH0 en D), kunnen worden gedeeld. We besparen bijgevolg 3 bits. 6. Bij de teller zijn de increment (C) en het inladen van de nieuwe waarde (L) exclusief. We besparen 1 bit. Op basis van deze maatregelen hebben 9 bits op het instructiewoord bespaard. “Chaining”: meerdere bewerkingen per klokcyclus Naast de eerder beschreven optimalisaties, kunnen we ook het ASM-schema zelf aanpassen. De argumentatie om dit te doen is een analyse van het tijdsgedrag. Elke klokcyclus wordt de data van de registers uitgelezen en voeren de functionele eenheden hierop bewerkingen uit. Niet alle functionele bewerkingen vereisten echter dezelfde hoeveelheid tijd om het resultaat te berekenen. We kunnen bijvoorbeeld denken aan de schuifoperaties met een vast aantal bits. Vermits hierbij geen logica moet worden ge¨ımplementeerd, wordt zo’n operatie in theorie onmiddellijk uitgevoerd. We kunnen echter analyseren wat er vervolgens met de gegevens van de functionele eenheid zal worden gedaan. Indien het mogelijk is om de volgende operatie in dezelfde klokcyclus uit te voeren kan dit tot besparingen leiden. Het groeperen van operaties die na elkaar moeten worden uitgevoerd noemen we chaining. Figuur 5.43(b) illustreert dit principe. Wanneer we het ASM-schema en het datapad aanpassen zoals op Figuur 5.43, voeren we een chaining transformatie uit. In het ASM-schema worden twee operaties f1 en f2 uitgevoerd. We kunnen de twee operaties samenvoegen in een operatie f met f (x, y) = f2 (f1 (x) , y). Alvorens we een chaining-transformatie kunnen uitvoeren, moeten we echter ´e´en voorwaarde controleren: alle operanden moeten beschikbaar zijn alvorens we de gegroepeerde functie uitvoeren. Indien z bijvoorbeeld nog niet beschikbaar is in de eerste toestand, kunnen we f nog niet berekenen. “Multicycling” en “Pipelining”: meerdere klokcycli per bewerking Multicycling Ook in omgekeerde richting kunnen we mogelijk winst boeken. Door een instructie “uit te smeren” over verschillende toestanden kunnen we mogelijk de schakeling goedkoper maken, of de kloksnelheid verhogen. Dit concept noemen we multicycling. In het leidend voorbeeld dienen we bijvoorbeeld het verschil te berekenen tussen twee getallen. Het verschil wordt doorgaans gerealiseerd met een functionele eenheid die
208
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
R
R
x
R
y
R
z
R
t
y ← f1 (x)
R
x
R
z
t
⇒ ⇒
t ← f2 (f1 (x) , z)
f1
f2
f1
f2
t ← f2 (y, z)
f
(a) ASM-schema.
(b) Datapad.
Figuur 5.43: De chaining-transformatie. dit in twee “stappen” zal uitrekenen: eerst nemen we de negatie van het tweede getal, waarna we vervolgens met behulp van een keten van full adders het eerste getal en de negatie van het tweede getal optellen. Omdat de twee stappen een sequentieel karakter vertonen23 , zouden we ervoor kunnen opteren om twee toestanden te voorzien. We voorzien dus geen aftrekker, maar voorzien twee functionele eenheden: een opteller en een componenten die de negatie van het getal kan berekenen.
y ← f1 (x) R
t ← f (x, z)
⇒
R
x
z
R
R
t
x
R
R
y
z
R
t
⇒ t ← f2 (y, z)
f
(a) ASM-schema.
f1
f2
(b) Datapad.
Figuur 5.44: De multicycling-transformatie. Figuur 5.44 beschrijft de transformatie die gepaard gaat met de introductie van multicycling. In het ASM-schema wordt een complexe functie f uitgerekend die we kunnen opsplitsen in twee functies f1 en f2 zodat f (x, y) = f1 (f2 (x) , y). In het ASM-schema wordt de functie uitgesmeerd over twee toestanden. Dit hoeft niet te betekenen dat we de tweede toestand moeten introduceren: we kunnen bijvoorbeeld ook de f2 -bewerking naar de volgende (al bestaande) toestand schuiven. In het datapad wordt in het algemeen een register ge¨ıntroduceerd. Dit hoeft echter niet de betekenen dat we ook effectief een nieuw register zullen nodig hebben. Door de minimalisatie van de variabelen, kunnen we eventueel het ge¨ıntroduceerde register elimineren. Als voorwaarde om deze transformatie uit te voeren stellen we ´e´en voorwaarde: de bewerking moet zijn uitgevoerd alvorens andere bewerkingen het resultaat zullen gebruiken als operand. De voordelen van multicycling zijn tweeledig. Allereerst kunnen we mogelijk hardware besparen in de functionele eenheden. Een opteller is immers goedkoper dan een aftrekker. Wanneer elders in het algoritme bijvoorbeeld nog een negatie moet worden berekend, kunnen we mogelijk de ge¨ıntroduceerde functionele eenheid delen waardoor dit geen extra kosten met zich meebrengt. Verder valt op te merken dat wanneer we operaties kunnen herleiden naar kleinere basis-instructies, de kans groter is dat complexe operaties een deel van die basis-instructies zullen delen. Een eerste winst is dus mogelijk de kostprijs van de functionele eenheden. 23 Men
kan de twee stappen niet tegelijk uitvoeren of ze laten overlappen
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
209
Daarnaast kunnen we mogelijk de kloksnelheid opdrijven. Stel bijvoorbeeld dat de aftrekker de traagste operatie is in heel het proces, zal deze functionele eenheid de kloksnelheid bepalen. Het is echter mogelijk dat alle overige functionele eenheden significant sneller resultaten berekenen. Door een verschil-operatie op te splitsen in twee operaties die apart sneller presteren kunnen we mogelijk de kloksnelheid opdrijven. Indien de verschil-operatie vrij zeldzaam is, kan dit dus de doorvoer van het algoritme significant verhogen. Multicycling komt in de meeste gevallen echter met een kostprijs. Allereerst valt in de praktijk de snelheidswinst meestal tegen. Stel bijvoorbeeld dat in het algoritme alleen verschil-bewerkingen worden uitgevoerd. De periode van het kloksignaal is in de realisatie van dit algoritme 1 v24 . We kunnen deze periode vervolgens opdelen in 3 delen25 : 0.35 v om de negatie te berekenen, 0.35 v voor de optelling en 0.3 v om de waarde in het register in te klokken. Merk op dat de tijd in dit fictieve voorbeeld mooi verdeeld is over de twee deeloperaties en dus ideaal is voor multicycling. Toch zullen we de kloksnelheid niet kunnen verdubbelen: de tussenresultaten (de negatie van het tweede getal) moeten immers ook in een register worden opgeslagen. De periode van een deelbewerking wordt bijgevolg 0.65 v. We besparen bijgevolg 35% op de klokfrequentie. Een tweede kost heeft betrekking op de kostprijs. De kostprijs van de functionele eenheden kan in principe afnemen, maar introduceert extra logica ter hoogte van de controller. We introduceren immers een nieuwe “deel-toestand”: een toestand waarin we de negatie van de tweede operand hebben berekend. Verder dienen we mogelijk nieuwe registers te introduceren om tussenresultaten in weg te schrijven26 . Bovendien introduceren we mogelijk nieuwe verbindingen, multiplexers en tri-state buffers om de resultaten van de extra functionele eenheden in de correcte registers weg te schrijven. Multicycling is echter wel een populaire techniek voor operaties die buitenproportioneel veel tijd vragen. Dit is meestal het geval bij bijvoorbeeld RAM-geheugen. Men merkt op dat sinds de jaren ’80 de processorsnelheid significant werd opgedreven terwijl de RAM-geheugens deze evolutie niet hebben gevolgd. Indien we dus een toestand zouden voorzien om een cel uit het RAM-geheugen uit te lezen, zou de processorsnelheid hoogstens gelijk zijn aan deze van het RAM-geheugen. Een processor en geheugen werken dan ook eerder onafhankelijk van elkaar. Op geregelde tijdstippen geeft de processor een opdracht aan het RAM-geheugen om een cel uit te lezen en vervolgens enkele toestanden later te controleren of de gegevens reeds in de registers of cache zitten. De 80x86 instructieset kent zelfs “prefetching”-instructies: instructies waarmee men de opdracht kan geven om data in de cache in te laden zodat op het moment dat de data effectief nodig is, deze meteen kan worden uitgelezen. Pipelining Het uitsmeren van instructies over verschillende toestanden maakt ook een ander effect mogelijk: pipelining. Pipelining is een uitvoeringsstrategie naast sequenti¨ ele uitvoering en parallelle uitvoering.
... ... ... t (a) Sequentieel.
t
t (b) Parallel.
(c) Pipelining.
Figuur 5.45: De verschillende uitvoeringsstrategie¨en: sequentieel, parallel en pipelining. . 24 We
introduceren hier een tijdseenheid v: de tijd die het proces nodig heeft om een verschil uit te rekenen en in te klokken. verhoudingen van de delen is louter fictief en dient enkel ter illustratie. 26 In het geval van een verschil-bewerking is dit niet het geval omdat we na de negatie van de tweede operand, de originele operand niet meer nodig hebben. In het algemeen is dit echter niet het geval. 25 De
210
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
Figuur 5.45 toont de verschilende uitvoeringsstrategie¨en naast elkaar. Als voorbeeld gebruiken we het wassen van kledij. In het geval van sequenti¨ele uitvoer beschikken we over ´e´en wasmachine, ´e´en droogkast en ´e´en strijkijzer. Kledij wordt eerst in de wasmachine gestopt, vervolgens gedroogd en daarna gestreken. Wanneer we een grote hoeveelheid kledij moeten wassen, herhalen we dit mechanisme. Indien elke opdracht ∆t in beslag neemt, betekent dit dus dat we O (3 · k · ∆t) tijd nodig hebben om alles te verwerken met k de hoeveelheid kledij. Dit proces staat beschreven in Figuur 5.45(a). Men kan de doorvoer echter opdrijven door meer infrastructuur te voorzien. Indien we elke machine in het n-voud aankopen en over n arbeiders beschikken, kunnen we de doorvoer opdrijven met ongeveer O (n). De gemiddelde tijd die het wassen van alle kledij in beslag neemt wordt dus gereduceerd tot O (3 · k · ∆t/n). Het probleem is echter dat de kosten ook stijgen met een factor O (n). Bovendien wordt de versnelling niet altijd gerealiseerd. Meestal is er een vorm van boekhouding nodig die bepaalt wie welke taak precies zal uitvoeren27 . Dit proces staat beschreven in Figuur 5.45(b). Tot slot is er pipelining. In het geval van pipelining beschikken we opnieuw over ´e´en wasmachine, droogkast en strijkijzer. In plaats van echter alles na elkaar uit te voeren, werken de machines continu. Op het moment dat de wasmachine immers klaar is, verhuist de gewassen kledij naar de droogkast, maar stopt men nieuwe kledij in de wasmachine. Het gevolg is dat wanneer er s stappen in het proces zijn, we de doorvoer kunnen opdrijven met O (s) ten opzichte van het sequentieel proces, zonder de kosten voor de infrastructuur op te drijven. Dit proces staat beschreven in Figuur 5.45(c). Men kan pipelining ook vergelijken met het principe van de lopende band: we voorzien telkens ´e´en machine voor elke bewerking en het resultaat schuift van machine naar machine.
y ← f1 (x) z2 ← z1
t ← f (x, z)
R
⇒
R
z
R
z1
z2
y ← f1 (x) z2 ← z1 t ← f2 (y, z2 )
f
R
t
⇒
f2
R
t
t ← f (x, z)
t ← f2 (y, z2 )
(a) ASM-schema.
R
x
R
x
f1
R
y
(b) Datapad.
Figuur 5.46: De pipelining-transformatie. Figuur 5.46 beschrijft het transformatieproces bij pipelining. Wanneer twee identieke operaties dicht op elkaar volgen, kunnen we beide bewerkingen uitsmeren in de tijd en tegelijk parallelle uitvoer introduceren. De transformatie van het datapad is erg gelijkaardig aan dat van multicycling. Merk echter op dat we ook een nieuw register introduceren voor z. De reden is dat terwijl we de f2 voor de eerste keer uitvoeren, we ook de operanden van de tweede instructie moeten uitvoeren. We kunnen een pipelining-transformatie uitvoeren op voorwaarde dat alle resultaten zijn uitgerekend alvorens ze door andere bewerkingen worden uitgevoerd en de instructies betrokken in het pipelining proces onafhankelijk van elkaar kunnen worden uitgevoerd. 27 De
maximaal te realiseren versnelling wordt geformaliseerd met de “Wet van Amadahl”.
5.4. SYNTHESE VAN EEN NIET-PROGRAMMEERBARE PROCESSOR
211
We kunnen pipelining op vier niveaus toepassen: 1. Functionele eenheden: in dit niveau splitsen we de bewerkingen op in deelbewerkingen en bewaren we de tussenresultaten in registers. 2. Datapad: indien we werken met een trage registerbank (bijvoorbeeld RAM-geheugen) gebruiken we meestal ook pipelining. 3. Controller. 4. Het ASM-schema: we kunnen het ASM-schema herschrijven, bijvoorbeeld door de verschil-instructie op te splitsen in een negatie-instructie en een optelling-instructie. Dit hoeft niet te betekenen dat we meer toestanden introduceren: sommige omstandigheden laten toe dat we een onderdeel van de instructie gewoon doorschuiven naar de volgende toestand. Op basis van het aangepaste schema zullen we mogelijk meer hardware introduceren, maar door het minimaliseren van het datapad kunnen we dit mogelijk terug ontdubbelen. In moderne processoren implementeert men pipelining op nagenoeg alle niveaus in de zogenaamde generische instructiecyclus. De generische instructiecyclus is een beschrijving in welke onderdelen een gegeven instructie wordt uitgevoerd: 1. Lees een instructie. 2. Bereken de adressen (indien de instructie operanden uit bepaalde geheugenadressen haalt). 3. Lees de operand(en) uit. 4. Voer de bewerking uit. 5. Schrijf het resultaat weg. Pipelining komt echter ook met enkele problemen. Om de snelheid effectief met O (s) op te drijven, dienen de deelstappen precies evenveel tijd te vragen. In de praktijk is het niet eenvoudig een proces zo op te delen. Wanneer dit niet te realiseren valt geldt de “Wet van de zwakste schakel”: het traagste deelproces bepaalt hoelang het duurt alvorens data zal worden uitgelezen. Verder is pipelining ook enkel interessant wanneer we kort na elkaar een groot aantal maal de operatie moeten uitvoeren. Indien we slechts ´e´enmaal de operatie uitvoeren blijft de rekentijd ongeveer dezelfde. We kunnen dus stellen dat de doorvoer (“throughput”) wordt verhoogd, maar de vertraging (“latency time”) ongeveer dezelfde blijft. Net als bij multicycling dienen we ook opnieuw extra registers te voorzien om de tussenresultaten in op te slaan. Deze register verhogen de kostprijs en zullen bovendien een deel van de tijdswinst tenietdoen omdat het wegschrijven van tussenresultaten in de registers ook tijd vergt.
Ins1
Ins2
Ins1
Ins3
Ins2
Ins1
Ins2
Ins4
...
Ins3
Ins4
...
Ins3
Ins4
... t
Figuur 5.47: Terugkoppeling verhindert pipelining.
212
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
We kunnen ook niet zomaar elk proces uitvoeren volgens de pipelining uitvoeringsstrategie. Pipelining vereist dat de opeenvolgende stappen eerder onafhankelijk van elkaar kunnen werken. Stel bijvoorbeeld dat de tweede operatie echter een operand nodig heeft die in de vorige instructie wordt berekend, treedt er een probleem op. Bij deze vorm van terugkoppeling verliezen we de performantie-winst. De pipeline wordt gestopt tot het resultaat van de eerste operatie beschikbaar is om vervolgens de tweede operatie uit te voeren. Figuur 5.47 illustreert dit principe. Stel dat instructie 2 bijvoorbeeld t4 ← t1 − t3 berekent en instructie 3 vervolgens t5 ← t2 − t4 . We kunnen opmerken dat instructie 3 als operand een resultaat gebruikt dat wordt berekend door instructie 2. Bijgevolg worden er geen nieuwe instructies in de pipeline ge¨ınjecteerd, tot instructie 2 volledig is uitgevoerd.
5.4.5
Besluit
Als algemene conclusie kunnen we stellen dat het zeer moeilijk is om de optimale implementatie te vinden. Dit aspect wordt bovendien bemoeilijkt omdat de optimalisaties op verschillende niveaus elkaar be¨ınvloeden: de minimalisatie van het aantal registers kan ertoe leiden dat we de functionele eenheden op een andere manier zullen optimaliseren. Daarom zullen we ons meestal tevreden stellen met heuristieken: benaderende methodes zoals bijvoorbeeld het max-cut algoritme. Sommige methodes zijn echter meer geschikt voor optimalisatie bij het ene niveau tegenover het andere. Bovendien is de beste keuze afhankelijk van de gekozen technologie: als we een schakeling implementeren op een FPGA zullen we logische blokken optimaliseren in plaats van transistoren. Het algoritme herschrijven biedt ook veel mogelijkheden. Soms kunnen we hierdoor pipelining mogelijk maken of een functionele eenheid alsnog hergebruiken. Wanneer we echter het algoritme aanpassen, moeten we ook opnieuw het datapad minimaliseren. Minimaliseren van het datapad is bijgevolg een complex proces waarbij het nagenoeg onmogelijk is om een globaal optimale implementatie te bekomen.
5.5
Tijdsgedrag
Hoewel een niet-programmeerbare processor in wezen een sequenti¨ele schakeling is, en we het tijdsgedrag omtrent sequenti¨ele schakelingen al hebben besproken, zullen we in deze sectie tijdsaspecten bespreken die enkel relevant zijn voor niet-programmeerbare processoren.
5.5.1
Kritisch pad
Een belangrijk aspect is deze van het kritisch pad. We hebben al besproken dat het kritisch pad bepaalt hoe snel een verandering aan de ingang effect heeft op de uitgang. In een processor is er niet altijd een in- of uitgang. Wel moet op het moment van een klokflank de correcte data op de ingang van de registers staan. Bovendien dienen we ook de controller in rekening te brengen die waar nodig de functionele eenheden configureert, en ook bepaalt welke data er bijvoorbeeld uit de registers wordt uitgelezen. Concreet komt het kritische pad nog altijd neer op het langste combinatorische pad. De verleiding is groot om hierbij enkel het datapad in rekening te brengen: namelijk vanuit een register door een functionele eenheid naar een register. Om te beantwoorden aan de formele definitie dient men dus de controller mee in rekening te brengen. Bovendien is het nagenoeg altijd zo dat het kritische pad zowel door de controller en het datapad loopt. Een typisch kritisch pad vertrekt dan ook vanuit bijvoorbeeld de ingang van een register die de toestand van de controller bijhoudt. Hierdoor wordt een nieuwe toestand in de registers van de controller geklokt. Vervolgens loopt het kritische pad doorheen de uitvoer-logica van de controller naar bijvoorbeeld een register van waaruit data dan door een functionele eenheid loopt om vervolgens ofwel terug te keren als status-signaal naar de controller of als resultaat-signaal naar de flipflop.
5.5. TIJDSGEDRAG
213
Het concreet bepalen van het kritisch pad is geen sinecure. Meestal stelt men tabellen op per functionele eenheid/register om te bepalen hoelang het signaal onderweg is, en wordt op basis van de tabellen dan het kritische pad bepaald. Meestal kan men het kritisch pad ook niet meteen vertalen naar de klokfrequentie: men dient meestal enige buffer te nemen die te wijten is aan meta-stabiliteit, lange lijnen, enzovoort.
5.5.2
Verschoven kloksignalen (“clock skew”)
In het vorige hoofdstuk hebben we het reeds gehad over “skew”. Een speciaal geval van skew die in de context van processoren belangrijk wordt is clock skew, dit is de verschuiving van het kloksignaal. Processoren zijn immers grote en complexe schakelingen. Een constante doorheen de schakeling is echter dat de controller, de registers en eventuele RAM-geheugens allemaal afhankelijk zijn van ´e´en en hetzelfde kloksignaal. Het gevolg is dat een verandering die aanvangt bij de klok zelf niet altijd op alle plaatsen in de schakeling op hetzelfde moment wordt waargenomen. Oorzaken van de vertraging zijn: 1. Vertraging op de verbinding (a) Een verbinding die over de volledige schakeling loopt is relatief lang. Hoewel de snelheid van een elektrisch signaal twee derde van de lichtsnelheid bedraagt, is de frequentie zeer hoog en kan een relatief kleine afstand toch een significant tijdsverschil betekenen in verhouding tot de periode van de klok. (b) Wanneer we werken met een FPGA doorloopt een kloksignaal meestal ´e´en of meerdere schakelmatrices. Deze matrices zijn opgebouwd uit poorten die een significante vertraging teweeg brengen. 2. Combinatorische logica op het klokpad (a) Sommige schakelingen werken met een clock-enabled. Een clock-enabled werkt door het kloksigaal door een AND-poort te sturen. Deze AND-poort levert een extra vertraging op. (b) Een Klokbuffer: een poort mag slechts een beperkte fan-out hebben. Het kloksignaal wordt echter gepropageerd naar een zeer groot aantal componenten. Men propageert het signaal dan ook door een hi¨erarchische structuur van klokbuffers. Wanneer componenten echter niet aangesloten zijn op dezelfde diepte van deze hi¨erarchie, ontstaat er een tijdsverschil. 3. Verschillende daal- en stijgtijden: door verschillende capacitieve belasting (tussen bijvoorbeeld twee klokbuffers) zijn de vertragingen op lange lijnen – zelfs al zijn ze identiek in lengte – niet altijd gelijk. Wanneer een bepaalde lijn bijvoorbeeld een grote oppervlakte aan metaal vertegenwoordigt, stijgt de capaciteit van de virtuele condensator. Clock enabled bij laadbare registers In registers werken we vaak met een clock enabled. Dit is een belangrijke oorzaak van clock skew en kan zelfs leiden tot het inklokken van foute waarden: wanneer de data aan de ingang zelf afhankelijk is van de klok en sneller wordt aangepast dan de het signaal door de AND-poort propageert, wordt soms de nieuwe waarde opgeslagen. Er zijn dan ook grofweg twee technieken
D Clk CE
D
Clk
(a) Met multiplexer.
Q
D
Q
CE Clk
D
Q
Clk
(b) Met clock enabled.
Figuur 5.48: Laadbaar registers om een selectief op bepaalde klokflanken nieuwe waarden op te slaan: 1. Met behulp van een multiplexer (zoals bij Figuur 5.48(a));
Q
214
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
2. Met behulp van een AND-poort (zoals bij Figuur 5.48(b)). Zoals zo vaak is geen van de twee technieken altijd te verkiezen: beide implementaties hebben hun voor- en nadelen. Zo kost register met multiplexer 6 transistoren per bit meer dan een AND-poort. Ook het energieverbruik ligt hoger: het kloksignaal komt immers in de flipflop terecht waar een groot aantal transistoren zullen schakelen. Dit verbruik is nutteloos wanneer we geen nieuwe gegevens willen inklokken en we dus opnieuw dezelfde waarde op de data-ingang aanbieden. Anderzijds is een multiplexer een vrij veilige optie. De nadelen van een AND-poort zijn dat dit typisch clock-skew introduceert omdat het kloksignaal duidelijk vertraging oploopt wanneer het door de AND-poort propageert. Wanneer het kloksignaal hoog is, mag de “clock enabled” bovendien niet zomaar worden veranderd: de flipflop zou dit immers interpreteren als een veranderend kloksignaal. Het vereist dus wat ontwerpervaring om implementatie met een AND-poort veilig te stellen.
5.5.3
Synchroniseren van asynchrone ingangen
Ondanks voorzichtig ontwerp van een niet-programmeerbare processor, komt invoer doorgaans van buiten de schakeling. Deze data wordt misschien ook door een synchrone schakeling – bijvoorbeeld een processor – aangeboden, maar het synchroniseren van verschillende klokken is onmogelijk. Zelfs in eenzelfde synchrone schakeling kunnen bovendien synchronisatieproblemen ontstaan, bijvoorbeeld wanneer bepaalde delen van de schakeling sneller resultaten berekenen. Dergelijke effecten maken het echter niet evident om logica te ontwikkelen: meestal gaan we ervan uit dat tijdens berekeningen van de processor de ingang niet zomaar een andere waarde aanneemt. Stel dat de processor afwisselend de twee getallen aan de ingang optelt en aftrekt maken we meestal de assumptie dat halverwege de optelling de operanden niet veranderen. Om asynchrone veranderingen op te vangen gebruikt men doorgaans flipflops die de waarden aan de ingangen op vaste momenten inlezen. De data-uitgangen van deze flipflops zijn gedurende een klokflank stabiel. Dit is echter de theorie en ook hier kunnen dingen foutlopen. Een signaal moet immers een tijdje op de ingang van een flipflop worden aangelegd voor de klokflank om het correct in te klokken. Indien de gegevens op tijd worden aangelegd is er dus geen probleem. Wanneer de gegevens echter kort voor de klokflank worden aangeleverd kunnen er verschillende problemen ontstaan: • De gegevens komen te laat waardoor de oude gegevens na de klokflank op de uitgang van de flipflops worden aangelegd. De gegevens komen dan meestal met vertraging van ´e´en klokflank wel beschikbaar. Dit wordt ge¨ıllustreerd in periode a op Figuur 5.49(b). • Een deel van de gegevens wordt correct ingeklokt, een ander deel wordt foutief ingelokt, dit kan ertoe leiden dat de flipflops invoer aanleggen die zelfs niet mogelijk werd geacht. Dit wordt ge¨ıllustreerd in periode b op Figuur 5.49(b). ´ en of meer flipflops komen in een metastabiele toestand terecht: er wordt noch 0 noch 1 op de ingang • E´ aangelegd. Het duurt een zekere tijd voor een flipflop uit dergelijke toestand gaat. Dit effect kan ook optreden wanneer de nieuwe data al lang op de flipflop wordt aangelegd. Dit wordt ge¨ıllustreerd in periode c op Figuur 5.49(b). Aan de eerste twee problemen is weinig te verhelpen. In de praktijk zal men dit meestal oplossen met een synchronisatiesignaal: men stuurt bijvoorbeeld het kloksignaal mee op ´e´en van de verbindingen tussen de twee circuits, of in het geval er maar af en toe data op de ingang komt te staan kondigt men dit aan door de ingangen met de regelmaat van de klok te laten veranderen van signaal28 . Metastabiliteit is echter een probleem waar men wel iets aan kan doen. Uit Subsectie 4.2.1 weten we immers dat de kans dat een schakeling zich na een zekere tijd nog steeds in een metastabiele toestand bevindt, exponentieel daalt met de tijd. Als we dus een redelijk termijn wachten, kunnen we vrij zeker stellen dat de de binnenkomende signalen niet metastabiel zijn. Deze tijd noemt men de metastability 28 Dit
is het geval bij Ethernet (IEEE 802.3).
5.5. TIJDSGEDRAG
215
a1
s1 D
Q
F1
Externe signalen
Clk
a2
D
Q
F2 Clk
1
Synchroon sequentieel signaal
Q
Clk 0 a0 1 0 1 0 s0 1 0 s1 1 0
a1
s2
Q
t
a (a) Schakeling.
b
c
(b) Problemen met synchronisatie.
Figuur 5.49: Synchronisatie. resolution time tr . Logischerwijs wensen we dat tr ≥ tmeta met tmeta de tijd om uit een metastabiele toestand te geraken. tr hangt echter van drie andere parameters af: tr = tclock − tcomb − tset-up
(5.45)
Met tclock de periode van de klok, tcomb de tijd die het signaal nodig heeft om door de combinatorische schakeling te propageren van het circuit en tset-up de set-up tijd om de resultaten op te slaan in de flipflops van het circuit29 . asynchroon
D
Q
Clk
Q
comb.
D
Q
Clk
Q
clock Figuur 5.50: De verschillende componenten van de “metastability resolution time”.
De klokperiode tclock staat in principe niet vast: we kunnen zelf de kloksnelheid bepalen, maar wensen meestal een hoge kloksnelheid. Bovendien wordt de kloksnelheid ook beperkt in de mate dat invoer beschikbaar komt: wanneer we bijvoorbeeld geluid verwerken moet we 40 kHz aan metingen kunnen aanbieden. In het geval we echter een niet-programmeerbare processor beschouwen, staat de toepassing meestal vast en dus ook de invoersnelheid van die toepassing. De kloksnelheid verder opdrijven heeft dan geen zin. We kunnen dus de klokperiode altijd proberen te maximaliseren. Men kan ook inzetten op technologie. Snelle flipflops hebben een kortere set-up tijd en bovendien verkleint ook de halfwaardetijd: hierdoor zullen we dus ook sneller de metastabiele toestand verlaten. Bijgevolg wordt tmeta kleiner. Een nadeel van deze flipflops is dat ze meer vermogen verbruiken. Extra hardware kan ook een bijdrage leveren. Wanneer de processor de data moet verwerken met een bepaalde doorvoersnelheid, maar de vertraging niet zo belangrijk is30 kan men in plaats van ´e´en flipflop, een opeenvolging aan flipflops plaatsen. Men geeft hierdoor meer tijd aan het signaal om uit de metastabiele toestand te komen maar behoudt tegelijk een sterke (interne) klokfrequentie. Indien de ingangssignalen zelf met hoge frequentie worden aangeleverd kunnen we n flipflops plaatsen die de synchronisatie uitvoeren. Een signaal propageert dus eerst door n flipflops en heeft dus meer tijd om uit 29 Bijvoorbeeld 30 De
om op basis van de invoer een nieuwe toestand aan te nemen. vertraging is bijvoorbeeld wel van belang bij real-time applicaties zoals live televisie-uitzendingen en Skype.
216
HOOFDSTUK 5. NIET-PROGRAMMEERBARE PROCESSOREN
async.
D
Q
Clk
D
...
FF1 Q
Q
comb.
D
Q
async.
Clk
D
Q
FF1
FFn Q
Clk
Clk
Q
D
Q
Q
Clk
Q
clk/n
clk (a) Zelfde kloksignaal.
comb.
D
Q
FF2 Clk
Q
clk (b) Trager kloksignaal.
Figuur 5.51: Metastabiliteit oplossen door een opeenvolging van flipflops. de metastabiele toestand te geraken. In dat geval is de resolutie-tijd: tr = n · tclock − tset-up − tcomb (Figuur 5.51(a))
(5.46)
Meestal volstaan 2 of 3 flipflops. Een abstracte implementatie staat beschreven in Figuur 5.51(a). Soms verandert het signaal niet zo snel. Denk bijvoorbeeld aan een processor die een deling moet uitrekenen. Meestal zal de interne klok significant sneller klokken omdat er veel operaties moeten worden uitgevoerd om het quoti¨ent uit te rekenen, terwijl de invoer trager wordt aangepast, bijvoorbeeld maar om 1 van de 10 klokflanken. In dat geval kunnen we werken met twee flipflops die aan een lagere (in dit geval 10 de originele klokfrequentie nieuwe waardes opslaan. De resolutie-tijd wordt dan: tr = n · tclock + tclock − tcomb − 2 · tset-up Een abstracte implementatie staat beschreven in Figuur 5.51(b).
(Figuur 5.51(b))
(5.47)
Hoofdstuk 6
Programmeerbare Processoren hebben met computers gemeen dat ze ook niets bereiken “ Mensen zonder goede programmeurs. - Toon Verhoeven, Nederlands aforist (??-??)
”
In dit hoofdstuk bespreken we programmeerbare processoren. Deze processoren verschillen van de niet-programmeren processoren omdat een gebruiker een programma – een reeks van instructies – kan uitvoeren op de processor en bijgevolg in grote mate het algoritme die de processor uitvoert zelf kan bepalen. Centrale processoreenheden (CPU’s) zijn hiervan slechts een subset van de programmeerbare processoren. We bespreken eerst de hoe een instructie eruitziet en hoe we een schakeling kunnen ontwerpen om deze instructies uit toe voeren. Cruciaal hierbij zijn de verschillende adresseermodi. Vervolgens beschouwen we de twee grote instructie-families: RISC en CISC. We zullen voor beide een instructieset ontwerpen en de verschillende aspecten die hierbij komen kijken bespreken. 6.1 6.2
De Programmeerbare Processor . . . . . . . . . . . . . . . Instructies en Velden . . . . . . . . . . . . . . . . . . . . . . 6.2.1 Programma . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.2 Instructie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.3 Instructieformaat . . . . . . . . . . . . . . . . . . . . . . . . 6.2.4 Generische Instructiecyclus . . . . . . . . . . . . . . . . . . 6.2.5 Uitvoeringssnelheid . . . . . . . . . . . . . . . . . . . . . . . 6.2.6 Adresvelden . . . . . . . . . . . . . . . . . . . . . . . . . . . Instructies met 3 adresvelden . . . . . . . . . . . . . . . . . Instructies met 2 adresvelden . . . . . . . . . . . . . . . . . Instructies met 1 adresvelden . . . . . . . . . . . . . . . . . Instructies zonder adresvelden . . . . . . . . . . . . . . . . . Instructies met registerbank-adressen: dubbele adressering . Besluit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2.7 Adresseermodi . . . . . . . . . . . . . . . . . . . . . . . . .
217
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
218 219 219 219 220 221 221 221 222 222 223 223 224 224 224
218
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN Impliciete adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Onmiddellijke adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Directe adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Indirecte adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Relatieve adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 Ge¨ındexeerde adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Ge¨ındexeerde adressering met autoincrement/autodecrement . . . . . . . . . . . . 227 6.3
Processorontwerp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 6.3.1
RISC en CISC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 CISC
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
RISC
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Evolutie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 6.3.2
Ontwerpcyclus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
6.3.3
Complex Instruction Set Computer (CISC) . . . . . . . . . . . . . . . . . . . . . . 229 Ontwerp Instructieset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 Instructieset-stroomschema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Allocatie datapadcomponenten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 ASM-schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Ontwerp Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Ontwerp Datapad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 De 8086 Microprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 De 8051 Microcontroller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
6.3.4
Reduced Instruction Set Computer (RISC) . . . . . . . . . . . . . . . . . . . . . . 246 Ontwerp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 De ARM7 Microprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 De ARM11 Microprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
6.1
De Programmeerbare Processor
We zullen in deze sectie het verschil bespreken tussen een niet-programmeerbare processor (zie Hoofdstuk 5) en een programmeerbare processor. Algemeen is deze grens eerder vaag. Ook bij een niet programmeerbare processor zullen de controller en het datapad meestal be¨ınvloed worden door signalen van buiten de schakeling. Sommige technici kunnen door deze invoer te manipuleren de processor een algoritme laten uitvoeren waarvoor de schakeling niet ontworpen was. Een duidelijke grens kunnen we trekken bij de controller. Bij conventie stellen we dat een processor nietprogrammeerbaar is wanneer de schakeling wordt aangestuurd met een vaste controller. In het geval we dus een ander algoritme willen uitvoeren zullen we een ander controller moeten implementeren om het uit te voeren. Bij een programmeerbare processor dient men de controller niet aan te passen. De controller beschikt immers over een geheugen waarin het programma geladen kan worden. Door het geheugen aan te passen zal de controller het datapad anders aansturen waardoor een ander algoritme kan worden uitgevoerd. We kunnen dus stellen dat de eindige toestandsautomaat die in de controller werd ge¨ımplementeerd vast staat, onafhankelijk van het ingeladen programma. Het geheugen waaruit zo’n controller leest noemen we het programmageheugen. De gegevens die van de controller naar dit geheugen stuurt worden het adres, de programmateller of de program counter (PC) genoemd. De data van het programmageheugen naar de controller noemen we de instructie.
6.2. INSTRUCTIES EN VELDEN
219
Merk op dat de definitie hierbij geen concrete uitspraak doet over hoe een programma of instructie er precies dient uit te zien. De definitie impliceert bijvoorbeeld niet dat de processor elk te beschrijven algoritme moet kunnen uitvoeren. Hierbij kunnen we bijvoorbeeld denken aan een “Graphical Processing Unit (GPU)”. Een GPU is een programmeerbare processor die gespecialiseerd is in grafische taken. De instructieset is dan ook eerder beperkt tot grafische operaties. Hoewel men dergelijk processoren meestal niet kan programmeren om bijvoorbeeld Dijkstra’s algoritme uit te voeren, is de processor wel programmeerbaar.
Controller
controle-uitgangen
adres
instructie
data-uitgangen
status-signalen
Processor Omgeving controle-ingangen
Datapad instructiewoord
data-ingangen
Programmageheugen
Figuur 6.1: De structuur van een programmeerbare processor. Figuur 6.1 toont hoe een programmeerbare processor er in grote lijnen uitziet. Merk op dat het enige verschil tussen deze figuur en Figuur 5.1(a) op pagina 149 de introductie van een programmageheugen is.
6.2
Instructies en Velden
Nu we de structuur van een programmeerbare processor hebben voorgesteld, zullen we in deze sectie de verschillende aspecten en terminologie van een programma bespreken.
6.2.1
Programma
Een algemeen aanvaarde definitie voor een programma is een sequentie van instructies. De instructies zijn op zo’n manier bepaald en geordend dat ze samen een complexe (en nuttige) taak uitvoeren. In dit opzicht bevat een sequentie van instructies dus dezelfde informatie als de eindige toestandsmachine van de controller bij een niet-programmeerbare processor.
6.2.2
Instructie
Een instructie is een reeks van bits die de informatie van ´e´en toestand in het ASM-schema of ´e´en toestand in de eindige toestandsautomaat van de controller voorstellen. Door pipelining kan een instructie of multicycling kan een instructie echter meerdere klokcycli duren. Dit kan men implementeren door bijvoorbeeld een andere volgende instructie te kiezen. Om een toestand voor te stellen zijn drie types informatie vereist: • De aansturing van het datapad: het bepalen van de stuursignalen naar de verschillende functionele eenheden, registers, tri-state buffers en multiplexers betrokken in het datapad.
220
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN • Data-uitwisseling: sommige instructies bepalen welke informatie er ingeladen of weggeschreven wordt naar (externe) geheugens. • De volgende instructie: de meeste algoritmes bevatten lussen en voorwaardelijke gedeeltes. Deze controle wordt ge¨ımplementeerd doordat de instructies (impliciet) bepalen wat de volgende instructie zal zijn.
Een instructie moet niet elk type informatie expliciet specificeren. We kunnen bijvoorbeeld denken aan het bepalen van de volgende toestand: meestal wordt een programma zo gestructureerd dat de volgende instructie bijna altijd op het volgende adres staat. In dat geval zullen enkel instructies die afwijken van deze regel dit moeten specificeren. Notatie van een instructie Om instructies uit te drukken bestaan er twee typische notaties: de mnemonische notatie en de actie-notatie. In de mnemonische notatie specificeert men eerst de operatie gevolgd door het doel1 en de operanden. Verder worden zowel het doel en de operanden gespecificeerd aan de hand van adressen. Een typische instructie is bijgevolg add A B C. Dit voorbeeld is een instructie uit de 80x86 instructieset. Mnemonische notatie wordt dan ook vaak gebruikt in assembleertalen (80x86, ). Actie-notatie specificeert daarentegen eerst het doel, meestal gevolgd door bijvoorbeeld een pijl met daarna de functie en de operand. Een concreet voorbeeld van een instructie volgens deze notatie is Mem[A] <- Mem[B]+Mem[C]. Actie-notatie is populair bij hardwarespecificatietalen.
6.2.3
Instructieformaat
De mnemonische notatie en de actie-notatie zijn manieren om instructies voor te stellen zodat ze leesbaar zijn voor mensen. In digitale logica wordt een instructie enkel voorgesteld door een sequentie aan bits. De ontwerper van een processor dient dan ook een instructieformaat te specificeren: een beschrijving hoe een sequentie bits een instructie bepaalt. Men kan dit formaat natuurlijk vrij bepalen, maar meestal beoogt men een structurele opbouw: de instructie wordt onderverdeeld in velden: groepen van bits waar een betekenis of een subtaak aan wordt toegekend. In de meeste instructieformaten komen volgende velden voor: • Instructietype: een groep bits die de klasse van de instructie aangeeft (bijvoorbeeld een sprongbevel, een bewerking, een geprivilegieerde instructie,...) • Opcode ofwel operation code: een groep bits die de bewerking voorstellen (bijvoorbeeld een optelling, vermenigvuldiging,...) • Adres: een groep bits die de locatie van een operand of een resultaat specificeert. Een adres hoeft echter niet beperkt te zijn tot de locatie in een (extern) geheugen: ook registers en registerbanken kunnen soms worden geadresseerd. • Adresseermode: een adresseermode bepaalt hoe het adres gespecificeerd in bits wordt omgezet in een fysisch adres. Zo kan de adresseermode bijvoorbeeld bepalen dat het adres een register uit de registerbank specificeert of dat de adressen indirect2 moeten worden berekend. • Constante: bewerkingen zoals een optelling tellen soms een constante op bij een register. In dat geval moet de constante in de instructie worden ingebed. Men dient op te merken dat een veld niet noodzakelijk een vaste lengte heeft of slechts ´e´enmaal voorkomt. Stel bijvoorbeeld dat de adresseermode bepaalt dat de gegevens uit een registerbank moeten uitgelezen worden, verwachten we dat het adres korter zal zijn dan wanneer we het adres uit een RAM-geheugen halen. Verder zal men bij sommige operaties twee of meer operanden moeten selecteren. In dat geval is het dus mogelijk dat het adresveld meerdere keren voorkomt. Sommige processoren voorzien ook een instructieformaat waarbij men twee of meer bewerkingen kan specificeren die dan parallel worden uitgevoerd. In dat geval komt de opcode dus twee of meer keer voor. 1 De
plaats waar het resultaat zal worden opgeslagen. indirecte adressering leest men de waarde van het geheugen uit op de gegeven locatie. Die waarde bepaalt dan de locatie van de effectieve waarde. 2 Bij
6.2. INSTRUCTIES EN VELDEN
6.2.4
221
Generische Instructiecyclus
Een processor voert een instructie doorgaans uit in vijf stappen. Deze stappen noemt men de generische instructiecyclus. De stappen zijn: 1. Lees de instructie in: het programmageheugen wordt uitgelezen en de instructie wordt in het instructieregister (IR) opgeslagen. De programmateller wordt verhoogd. 2. Bereken de adressen: Op basis van de adresseermodi en de adressen in de instructie worden de echte adressen bepaald. Een adres uit een registerbank zal er dus anders uitzien dan een adres uit het RAM-geheugen. 3. Lees de operanden: de adressen van de operanden worden uitgelezen en weggeschreven in tijdelijke registers. 4. Voer de bewerking uit: op basis van de data in de operand-registers en de opcode kan men de relevante bewerking op de relevante data uitvoeren. Het resultaat wordt in een tijdelijk register geplaatst. 5. Schrijf het resultaat weg: het resultaat wordt weggeschreven in een registerbank of RAM-geheugen (indien dit relevant is voor de bewerking). Deze cyclus wordt eindeloos herhaald en leent zich meestal erg goed tot pipelining: enkel wanneer de volgende instructie een operand moet inlezen die bepaald wordt door een instructie die kort ervoor is uitgevoerd moet de pipeline worden onderbroken. Men kan een sprongbevel uitvoeren door in de instructie de programmateller aan te passen.
6.2.5
Uitvoeringssnelheid
De uitvoeringssnelheid van een instructie hangt in grote mate af van twee factoren: • De snelheid van het datapad • Het aantal toegangen tot extern geheugen. We kunnen de snelheid van het datapad doorgaans opdrijven door meer hardware te voorzien die bijvoorbeeld bewerkingen in parallel uitvoeren. Het aantal toegangen tot extern geheugen kunnen we dan weer verlagen door kleine en simpele instructies te voorzien waardoor elke instructie maar een beperkt aantal operaties op het geheugen uitvoert. De grootte van een instructie is echter een trade-off. Wanneer we grote instructies voorzien met een groot aantal bits laten we de programmeur toe om een complexe taak in zo’n instructie te specificeren. Bijgevolg verwachten we dat een programma uit een klein aantal van dergelijke instructies zal bestaan. Omdat de instructies echter complex zijn, verwachten we een traag datapad en veel geheugentoegangen. Wanneer de processor enkel simpele instructies aanbiedt kan het datapad deze snel uitvoeren, maar een programma zal een groot aantal instructies bevatten. De complexiteit van een instructieset wordt dan ook soms uitgedrukt in het aantal adresvelden.
6.2.6
Adresvelden
In deze subsectie zullen we enkele instructiesets bespreken volgens het aantal adresvelden. Bij de verschillende instructiesets zullen we aantal geheugentoegangen berekenen die nodig zijn om de functie (a + b) × (a − b) uit te rekenen. Deze operatie wordt doorgaans niet als ´e´en instructie aangeboden (tenzij bij processoren die taken uitvoeren waarbij deze bewerking zeer regelmatig zou voorkomen). We zullen dan ook uitgaan van een algemene instructieset die de optelling (Add-instructie), aftrekking (Sub-instructie) en vermenigvuldiging (Mul-instructie) voorziet.
222
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Alvorens we de instructiesets met elkaar kunnen vergelijken, zullen we eerst enkele aannames moeten maken over hoe gegevens en instructies kunnen worden ingelezen. We zullen uitgaan van een woordlengte3 w. We maken de assumptie dat een instructie zonder geheugenadressen in ´e´en woord4 kan worden opgeslagen. Het geheugen omvat 2w adressen, bijgevolg telt het geheugen w ·2w bits en is elk adres voor te stellen met een woord. Een instructie met k geheugenadressen kan dus worden opgeslagen in k + 1 woorden. We vergelijken de instructiesets op basis van geheugentoegangen. Dit zijn dus het aantal toegangen om de instructie uit te lezen samen met het uitlezen en wegschrijven van gegevens die in de instructie worden gespecificeerd. Instructies met 3 adresvelden Een instructieset met drie adresvelden bepaalt meestal ´e´en adres voor het resultaat en twee adressen voor de operanden. Bijvoorbeeld de Add a b c instructie berekent de optelling van de gegevens die op de geheugenplaatsen b en c staan en plaatst het resultaat dus in adres a. Om (a + b) × (a − b) dus uit te rekenen zullen we volgend programma uitvoeren: Add c a b Sub x a b Mul c c x Per instructie voorzien we dus 4 + 3 geheugentoegangen. 4 instructietoegangen per instructie, 2 leesoperaties voor de operanden en 1 schrijfoperatie. Omdat we 3 instructies uitvoeren vereist het programma dus 21 geheugentoegangen. We kunnen echter opmerken dat in de laatste instructies we tweemaal hetzelfde adres vermelden. Dit soort instructies vormen dan ook de argumentatie om soms instructies met twee adresvelden te gebruiken. Instructies met 2 adresvelden Instructiesets met twee adresvelden zijn vrij populair. 80x86 is een voorbeeld van zo’n instructieset. In zo’n instructieset vertegenwoordigen het eerste en tweede adresveld de adressen van de operanden en het eerste veld ook het adres van het resultaat. Het eerste adres wordt bijgevolg overschreven. Een probleem bij dit mechanisme is dat we soms na de bewerking de operanden willen kunnen hergebruiken om andere operaties uit te voeren. Zo willen we na het berekenen van a+b nog over a en b kunnen beschikken om a−b uit te rekenen. We kunnen de waarde kopi¨eren om dit probleem te vermijden. We kunnen de waarde van x kopi¨eren naar adres y met behulp van twee instructies: Sub y y en Add y x. De meeste processoren voorzien echter een kopieer instructie: de Mov-instructie. Het voordeel van deze instructie is dat naast het ophalen van de instructie slechts twee geheugentoegangen vereist zijn. We kunnen het algoritme dan ook als volgt implementeren: Mov Add Mov Sub Mul
c c x x c
a b a b x
De Mov-instructie vereist in totaal 5 geheugentoegangen, de overige instructies vereisen 6 geheugentoegangen. In totaal vereist het uitvoeren van het algoritme dus 28 geheugentoegangen. We dienen echter wel op te merken dat de instructies sneller zullen worden uitgevoerd. 3 De
woordlengte is het aantal bits die in een geheugen onder ´ e´ en adres worden opgeslagen. woord is een sequentie van w bits met w de woordlengte.
4 Een
6.2. INSTRUCTIES EN VELDEN
223
Instructies met 1 adresvelden We kunnen de instructieset verder reduceren tot ´e´en adresveld per instructie. Dit doen we met behulp van een accumulator (ACC). Een accumulator is een speciaal register die dienst doet als zowel de eerste operand en het register waar het resultaat in wordt geplaatst. Men kan deze instructieset dus vergelijken met de eerste instructieset, maar waarbij de eerste operator altijd een vast adres voorstelt. Het voordeel van een accumulator is de implementatie door middel van een register: de accumulator inlezen of resultaten wegschrijven vereist bijgevolg geen geheugentoegang. Ook wanneer we een accumulator gebruiken zullen we soms tussenresultaten tijdelijk in een andere variabele willen opslaan om de waarde later in te lezen. We kunnen hier geen gebruik maken van de Movinstructie omdat het resultaat altijd vast staat: de accumulator. Daarom worden twee nieuwe instructies ge¨ıntroduceerd: de Load-instructie leest het adres uit en plaatst de waarde in de accumulator, de Storeinstructie schrijft de waarde van de accumulator weg in het opgegeven adres. De Store-instructie is bijgevolg een instructie waar de accumulator geen dienst doet als de ontvanger van het resultaat. We kunnen het algoritme realiseren met volgende code: Load a Add b Store x Load a Sub b Mul x Store c Elke instructie vereist telkens 3 geheugentoegangen: 2 om de instructie uit te lezen en 1 geheugentoegang om het adres uit te lezen of de resultaten weg te schrijven. Omdat het algoritme in 7 instructies kan worden ge¨ımplementeerd, zijn er in totaal 21 geheugentoegangen vereist. Instructies zonder adresvelden Sommige instructiesets bevatten geen adressen als operanden. In een dergelijk systeem moeten we echter wel een systeem implementeren die zelf de adressen voorstelt. Een populaire methode werkt met een stapelgeheugen. In zo’n systeem beschouwen we een stapel die groeit bij een een Load-instructie. Wanneer een instructie een berekening uitvoert worden de operanden uit de bovenste elementen van de stapel gehaald. Deze elementen worden van de stapel gehaald en het resultaat wordt vervolgens op de stapel gezet. Ook in een dergelijk systeem is er soms nood aan het opslaan van tussenresultaten om deze later te hergebruiken. Ook hiervoor gebruiken we de store operatie. De operatie neemt als argument een adres van de stapel: het aantal elementen onder de top. Ook dit kan men als een adres zien. Men maakt echter meestal de assumptie dat deze waarde niet buitengewoon groot is en de waarde dus in de instructie kan worden meegenomen. Bijgevolg bevat de instructie dus geen adres. Omdat het bovenste gedeelte van de stapel meestal met een registerbank wordt ge¨ımplementeerd, vereisen de bewerkingen bijgevolg geen geheugentoegangen. We kunnen het algoritme implementeren met volgende instructies: Load Load Add Load Load Sub Mul
a b a b
224
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Store c Om de impact te berekenen moeten we opnieuw een onderscheid maken tussen twee soorten instructies: Load- en Store instructies vereisen twee geheugentoegangen (1 geheugentoegang om de instructie op te halen en 1 instructie om het resultaat op te halen of weg te schrijven) de overige instructies vereisen slechts ´e´en geheugentoegang. In totaal vereist dit programma dus 13 toegangen tot het geheugen. Instructies met registerbank-adressen: dubbele adressering Tot slot dienen we nog te vermelden dat een adresveld niet noodzakelijk altijd een geheugenadres moet omvatten. Men kan bijvoorbeeld een bit in dit veld voorzien die bepaalt of het adres een geheugenadres specificeert of het adres van een registerbank. Daarnaast kan de interpretatie van een dergelijk adres ook afhangen van de instructie. Moderne processoren interpreteren bijvoorbeeld vaak de adressen bij bewerkingen als registerbank-adressen en de tweede operand bij een Load- of Store-instructie als een geheugenadres. Vermits een algoritme vooral met tussenresultaten zal rekenen verwachten we een tijdswinst omdat we niet telkens de operanden uit het geheugen moeten uitlezen. Een dergelijke instructieset kan ook instructies met variabele lengte beschouwen. Sommige instructies omvatten immers geen geheugenadressen, andere wel. In dat geval kan de eerste instructie bijvoorbeeld aanleiding geven om het volgende woord in een instructieregister in te lezen, of de instructie meteen uit te voeren. Registeradressen worden meestal voorgesteld met een prefix R. In het geval van een dergelijke instructieset ziet het programma er als volgt uit: Load R1 a Load R2 b Add R3 R1 R2 Sub R4 R1 R2 Mul R5 R3 R4 Store c R5 Bewerking instructies worden voorgesteld in ´e´en woord en vereisten geen extra geheugentoegang. Bijgevolg vereisen ze ´e´en geheugentoegang. Load- en Store-bewerkingen vereisen 3 geheugentoegangen: 2 bij het inlezen van de instructie en 1 bij het inlezen of wegschrijven van de data. In totaal vereist het programma dan ook 12 keer toegang tot het geheugen. Besluit Er zijn verschillende instructiesets mogelijk met een verschillend aantal adresvelden. Instructies met een groot aantal adresvelden laten compacte programma’s toe maar vereisen soms onnodig toegang tot het geheugen. Deze extra belasting komt in twee vormen: het inlezen van de adresvelden van de instructie en het uitlezen of wegschrijven van data in de vermelde geheugenadressen. Een instructieset met minder adresvelden zal minder vaak onnodig toegang tot het geheugen aanvragen. Anderzijds wordt het programma langer waardoor de processor meer instructies uit het geheugen met uitlezen.
6.2.7
Adresseermodi
In de loop der jaren zijn er verschillende manieren ontwikkeld om een geheugenadres te bepalen op basis van een adresveld. Deze methodes noemen we adresseermodi. Adresseermodi hebben als primair doel het aantal bits te reduceren die het adresveld in beslag neemt. Anderzijds laten verschillende adresseermodi soms toe om meer te realiseren per instructie en dus tot compactere programma’s te schrijven.
6.2. INSTRUCTIES EN VELDEN
225
Ook in hogere programmeertalen maakt men impliciet gebruik van adresseermodi. We kunnen bijvoorbeeld denken aan arrays. Wanneer men in Java het tiende element van een array a wil uitlezen schrijft men a[10]. Impliciet stelt men echter het adres dat tien plaatsen verder dan het begin van het record voor a ligt. Adresseermodi kunnen programma’s dus ook leesbaarder maken. Impliciete adressering Impliciete adressering is een adresseermode waarbij een adresveld niet vermeld wordt in de instructie maar door de processor zelf kan worden berekend. Dit is bijvoorbeeld het geval bij processoren met een stapelgeheugen. In een dergelijke instructieset worden de adressen afgeleid uit de toestand van de stapel: de bovenste elementen bevatten de data van de operanden. De processor rekent deze aspecten dus zelf uit. Ook bij processoren die werken met een accumulator is dit het geval: men vermeldt immers de bestemming van de data niet. Dergelijke processoren bieden meestal een instructie aan om de gegevens uit de accumulator te verwijderen: de CLRA-instructie. Onmiddellijke adressering Behalve in het adresveld de plaats in het geheugen te specificeren waar de data moet worden opgehaald, kunnen we ook de data zelf opslaan in een adresveld. Deze vorm van adressering noemen we onmiddellijke adressering. Dit is bijvoorbeeld het geval wanneer we werken met constanten. Directe adressering Meestal lezen we operanden uit met behulp van een adres. Dit adres verwijst ofwel naar een geheugenadres ofwel naar een index van een registerbank. In beide gevallen spreken we over directe adressering. Het is meestal voordelig om een registerbank te gebruiken. Dit omwille van twee redenen: een registerbank bevat minder adressen en de toegang is sneller. Omdat een registerbank typisch 8 tot 256 registers bevat, is bijgevolg de lengte van een registeradres tussen de 3 en 8 bits, terwijl een geheugenadres typisch tussen de 32 en 64 bits lang is. We besparen dus ook tijd bij het inladen van de instructie. Indirecte adressering Soms kennen we de plaats waar de data in het geheugen staat niet expliciet. Stel bijvoorbeeld dat we werken met een heap5 , hangt de plaats waar de data staat meestal af van de manier hoe het programma eerder werd doorlopen. Het adres wordt dan ook ergens anders bewaard in het geheugen of een registerbank. Indirecte adressering is een belangrijke vorm in programma’s. Naast werken met een onbekend adres laat het ook toe het adres mee te geven wanneer we bijvoorbeeld een subroutine uitvoeren die een “pointer” vereist. Indirecte adressering maakt het mogelijk om in ´e´en instructie de operand in te lezen waarvan het adres ergens in het geheugen staat. In dat geval dienen we dus het adres te specificeren waar het adres staat. Tweemaal het geheugen uitlezen in ´e´en instructie is echter een dure operatie. Daarom zal men de adressen doorgaans in een registerbank opslaan. In dat geval spreken we dan ook van register-indirecte adressering. 5 Een
heap is een geheugenruimte waar men dynamisch records kan toevoegen en terug verwijderen.
226
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
opcode adres
opcode adres Geheugen
Registerbank
Geheugen
Adres Adres
Operand (a) Indirecte adressering
Operand (b) Register-indirecte adressering
Figuur 6.2: Indirecte adressering Relatieve adressering Hedendaagse besturingssystemen ondersteunen doorgaans multiprogramming: het tegelijk uitvoeren van verschillende programma’s. Bijgevolg worden verschillende programma’s tegelijk in het register geladen. De compiler van een programma weet doorgaans op voorhand niet waar het programma in het geheugen zal worden ingeladen. Wanneer een programma echter een sprongbevel uitvoert, moet het adres van het sprongbevel wijzen naar het correcte adres. Het aangehaalde voorbeeld is ´e´en van de redenen om relatieve adressering toe te passen. Bij relatieve adressering houdt de processor een basisadres bij in een impliciet register. Dit basisadres wordt bij het gegeven adres opgeteld om het werkelijke adres te bepalen. Het adresveld wordt in dat geval de offset genoemd. opcode offset
opcode adres offset Geheugen
Register Basis
Registerbank
Geheugen
Basis
+
Operand
(a) Relatieve adressering
+
Operand
(b) Register-relatieve adressering
Figuur 6.3: Relatieve adressering
Naast het verzekeren van correcte spronginstructies kan relatieve adressering ook tot kortere instructiewoorden leiden. We kunnen bijvoorbeeld een registerbank voorzien die verschillende basisadressen voorziet. De basisadressen kunnen bijvoorbeeld wijzen naar datastructuren die vaak gebruikt worden. Naast een veld die het register in de registerbank specificeert, dient men een veld te voorzien die de offset vanaf het basisadres voorstelt. Een dergelijke vorm van adressering noemen we register-relatieve adressering.
6.2. INSTRUCTIES EN VELDEN
227
Ge¨ındexeerde adressering We kunnen ook de twee velden omdraaien door het basisadres in de instructie onder te brengen en de offset in een impliciet register of een registerbank op te slaan. Deze vormen van adressering noemen we ge¨ındexeerde adressering. Ge¨ındexeerde adressering is vooral interessant voor gegevensstructuren met eigen indexsystemen. We denken hierbij bijvoorbeeld aan arrays, matrices, stapels, wachtrijen,... In het register staat immers de index van de datastructuur zelf. Bij een array is dit bijvoorbeeld i indien we het i-de element willen uitlezen.
opcode basis
opcode adres basis Geheugen
Register Offset
Registerbank
Geheugen
Offset
+
Operand
(a) Ge¨ındexeerde adressering
+
Operand
(b) Register-ge¨ındexeerde adressering
Figuur 6.4: Ge¨ındexeerde adressering De structuur van ge¨ındexeerde adressen op Figuur 6.4 lijkt sterk op de structuur van relatieve adressen op Figuur 6.3. Het verschil is echter dat een basisadres een volwaardig adres is en dus makkelijk 32 bits telt. De offset daarentegen telt doorgaans slechts 3 tot 8 bits. Bij ge¨ındexeerde adressering zijn de instructies dus groter. Ook bij deze vorm van adressering kunnen we gebruik maken van een register bank. In dat geval wordt het adres van de registerbank bepaald door een veld in de instructie. Uit dit adres wordt dan de offset opgeslagen in registerbank berekend. Deze vorm van adressering noemen we naar analogie register-ge¨ındexeerde adressering. Ge¨ındexeerde adressering met autoincrement/autodecrement Meestal leest men een bepaald element uit een array, matrix,... uit binnen een lus in het programma. De meeste programma’s zullen dan ook de volledige array of een significant deel overlopen. Dit gebeurt doorgaans in een logische volgorde van links naar rechts of omgekeerd. Men kan het mechanisme achter ge¨ındexeerde adressering uitbreiden met autoincrement en/of autodecrement. Wanneer we deze adresseringmode toepassen wordt het impliciete register die de offset bijhoudt na het uitvoeren van de opdracht automatisch opgehoogd of verlaagd. Hierdoor kan men bij een volgende instructie meteen het volgende of vorige element in de array uitlezen zonder eerst zelf manueel het register op te hogen. Dit kan voordelig zijn omdat het uitrekenen van de nieuwe waarde voor het offset-register parallel kan gebeuren met het uitvoeren van de instructie zelf. Figuur 6.5 illustreert het principe. Op basis van de een de instructie kiest men welke waarde door de multiplexer stroomt, deze waarde wordt bij de originele offset opgeteld en vervolgens in het register ingeladen. Door dezelfde instructie vervolgens daarna uit te voeren, zullen we een ander geheugenadres uitlezen bij het bepalen van de operand.
228
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN opcode basis Geheugen Offset
−1 1
+
+
Operand
Figuur 6.5: Ge¨ındexeerde adressering met autoincrement/autodecrement.
Soms bestaat een array niet uit bytes maar uit bijvoorbeeld long integers (8 bytes). Bij sommige processoren kan men dan ook de staplengte bepalen door deze in een veld in de instructie te specificeren, of weg te schrijven in een speciaal hiervoor bestemd register.
6.3
Processorontwerp
Nu we de belangrijkste aspecten van een instructieset hebben besproken, zullen we het ontwerp van de processor zelf in detail bespreken. We zullen eerst de algemene ontwerpcyclus waarna we het ontwerp bespreken voor de twee grote families van instructiesets: CISC en RISC.
6.3.1
RISC en CISC
In de vorige sectie werden instructiesets vergeleken volgens het aantal adresvelden per instructie. Het aantal adresvelden vormt dan ook de belangrijkste basis om instructiesets in te delen in ´e´en van de twee families: de Complex Instruction Set Computer (CISC) of Reduced Instruction Set Computer (RISC). CISC In het geval van CISC beschouwt men een grote instructieset met complexe en trage instructies. De instructieset omvat meestal een groot aantal verschillende operaties waarbij men ook een groot aantal adresseermodi voorziet. Dit leidt meestal tot een complex datapad met veel functionele eenheden registers en complexe verbindingen die de datastroom controleren. Het gevolg is dat dergelijke processoren aan een lage klokfrequentie werken. De programma’s zijn echter vrij kort en men hoopt meestal snelheidswinst te boeken door de operaties die worden uitgevoerd bij een operatie in parallel op het datapad uit te voeren. Typische CISC instructiesets zijn System/360, PDP-11, VAX, Motorola 68k en 80x86. RISC Een RISC processor omvat een kleine instructieset die uit een klein aantal eenvoudige instructies bestaat. Een instructie omvat hoogstens ´e´en adresveld en meestal zijn slechts enkele adresmodi beschikbaar. Een eenvoudige instructieset leidt echter tot een eenvoudig datapad waardoor men een hoge kloksnelheid kan aanbieden. De programma’s zijn vrij lang maar men hoopt meestal om hierdoor neven-operaties die soms ongewild worden uitgevoerd op een CISC processor te vermijden. Typische RISC instructiesets zijn DEC Alpha, ARM, SPARC, en MIPS.
6.3. PROCESSORONTWERP
229
Evolutie Men merkt dat er een evolutie is van CISC processoren naar RISC processoren. Deze evolutie werd vooral gepromoot door onderzoek bij IBM dat aantoonde dat meestal een beperkte subset van de aangeboden instructies effectief door programma’s werd gebruikt. Dit effect werd ook versterkt door de komst van compilers die er meestal niet in slagen alle aspecten van een CISC instructieset automatisch uit te buiten. Andere aspecten die voor het gebruik van RISC processoren pleiten zijn de grootte van de chip, de energieconsumptie en de kostprijs.
6.3.2
Ontwerpcyclus
Ontwerp instructieset
Instructiesetstroomschema
Allocatie van datapadcomponenten
Bepaal het ASM-schema
Ontwerp van de controller en het datapad
Figuur 6.6: De processorontwerp-cyclus. Figuur 6.6 beschrijft de vijf fases bij het ontwerpen van een processor: 1. Ontwerp van de instructiecyclus: in deze fase stelt men een set van mogelijke instructies op, meestal gaan de instructies gepaard met een informele beschrijving van het effect van de instructie. 2. Instructieset-stroomschema: in deze fases worden per instructie alle betrokken operaties beschreven. De meeste instructies zullen immers verschillende effecten teweegbrengen. Bij de 80x86-instructieset zal bijvoorbeeld naast de bewerking ook de programmateller worden opgehoogd en zullen bepaalde registers op basis van het resultaat worden aangepast. 3. Allocatie van het datapad: op basis van de vereiste bewerkingen kunnen we bepalen welke componenten we in het datapad zullen moeten voorzien. Dit omvat een beschrijving van de vereiste registers en functionele eenheden. Indien dit tot een duur datapad leidt kan men beslissen om de instructieset opnieuw te herbekijken en begint men dus terug met fase 1. 4. Op basis van de beschikbare datapad componenten kan men een ASM-schema opstellen. Doorgaans wordt een instructie niet in ´e´en klokcyclus uitgevoerd. De verschillenden vereiste operaties worden dus uitgevoerd in verschillende toestanden in het ASM-schema. Dit schema beschrijft dan ook de verschillende registertransfers per klokcyclus. 5. Ontwerp van de controller en het datapad: op basis van het ASM-schema kunnen we vervolgens een datapad en controller synthetiseren. De methodologie van deze synthese staat beschreven in Hoofdstuk 5.
6.3.3
Complex Instruction Set Computer (CISC)
In deze subsectie zullen we het proces doorlopen bij het ontwerpen van een CISC processor.
230
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Ontwerp Instructieset In de eerste stap zullen we een CISC instructieset bepalen. We bepalen eerst de specificaties van het geheugen waarmee de processor werkt. Bij wijze van voorbeeld zullen we een 216 × 16-bit geheugen beschouwen. De woordlengte is dus 16 bit en elk adres kan voorgesteld worden met behulp van 16 bits. We beschouwen ook een registerbank met 8 registers. Elk registeradres kan dus voorgesteld worden met 3 bits. Uit de specificaties van het geheugen kunnen we afleiden dat een adresveld bij voorkeur ook 16 bit groot is. De rest van de instructie zullen we ook voorstellen met behulp van 16 bit. We beschouwen vier verschillende types van instructies: 1. Registerinstructies: instructies die bewerkingen uitvoeren met 1 of 2 operanden en 1 doelregister. 2. Verplaatsinstructies: instructies die de gegevens van een register of geheugenadres kopi¨eren naar een register of geheugenadres. 3. Spronginstructies: instructies die de programmateller aanpassen. Deze instructies bepalen bijgevolg het verloop van het programma. 4. Overige instructies: dit zijn instructies zoals No Operation (NOP)6 . We voorzien in een instructie dan ook twee bits om het type voor te stellen. De instructies vereisen hoogstens drie registers. In elke registers zullen we daarom drie velden van telkens 3 bits voorzien om het doelregister – Bestemming – en de twee operandregisters Operand 1 en Operand 2 voor te stellen. Vermits een instructie 16 bits telt en we in totaal reeds 11 bits hebben toegewezen, blijven er 5 bits over voor de opcode. We hebben bijgevolg een instructieformaat gedefinieerd zoals weergegeven op Figuur 6.7. 0
1 Type
2
3
4
5
Operatie/mode
6
7
8
9
Bestemming
10
11 Operand 1
12
13
14
15
Operand 2
16-bit adres/constante
Figuur 6.7: De bitstructuur van de CISC instructieset.
Het type en de opcode bepalen samen welke instructie zal worden uitgevoerd. We dienen echter nog bewerkingen toe te kennen aan de verschillende waardes. Hiervoor voorzien we Tabellen 6.1 6.2, 6.3 en 6.4 die de instructies per type beschrijven. Registerinstructies De registerinstructies worden allemaal uitgevoerd op registeradressen en worden opgedeeld in drie categorie¨en: aritmetische, logische en schuifoperaties. De categorie¨en worden bepaald door de eerste twee bits: wanneer o4 laag is beschouwen we een schuifoperatie, in het andere geval beschouwen we ofwel een aritmetische of logische operatie. Bij een schuifoperatie bepaalt o3 of we naar links of naar rechts schuiven. De overige drie bits bepalen vervolgens het aantal bits waarover we schuiven. In het andere geval bepaalt o3 of we aritmetische (laag) of logische operatie (hoog beschouwen). We delen de aritmetische operaties verder op in optelling/aftrekking-bewerkingen en vermenigvuldiging/deling operaties. o2 deelt de operaties verder in zodat bij bewerkingen met twee operanden o1 laag is en we in het andere geval bewerkingen met ´e´en operand beschouwen. We beschouwen volgende operaties: optelling, aftrekking, increment, decrement, vermenigvuldiging, deling, vierkantswortel en negatie. In het geval van logische bewerkingen bepalen de overige drie bits welke operatie we uitvoeren: AND, NAND, OR, NOR, XOR, XNOR, mask en invert. De verschillende instructies worden voorgesteld in Tabel 6.1 samen met een formele beschrijving van de bewerking. 6 De “No Operation” is een instructie die geen effect heeft. Deze instructie wordt gebruikt bij pipelining om ruimte op te vullen in de pipeline zodat instructies kunnen wachten tot andere instructies zijn uitgevoerd.
6.3. PROCESSORONTWERP
o4
Operatie/mode o3 o2 o1 o0
0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
n2 n2 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
n1 n1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
n0 n0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
231 Bewerking
Formeel
Assembleertaal
Schuif rechts Schuif links Optelling Aftrekking Increment Decrement Vermenigvuldiging Deling Vierkantswortel Negatie AND NAND OR NOR XOR XNOR MASK INV
RF[d]←RF[s1]>>N RF[d]←RF[s1]<
ASR Rd Rs1 #N ASL Rd Rs1 #N ADD Rd Rs1 Rs2 SUB Rd Rs1 Rs2 INC Rd Rs1 DEC Rd Rs1 MUL Rd Rs1 Rs2 DIV Rd Rs1 Rs2 ROOT Rd Rs1 NEG Rd Rs1 AND Rd Rs1 Rs2 NAND Rd Rs1 Rs2 OR Rd Rs1 Rs2 NOR Rd Rs1 Rs2 XOR Rd Rs1 Rs2 XNOR Rd Rs1 Rs2 MASK Rd Rs1 INV Rd Rs1
Tabel 6.1: De registerinstructies van de CISC-processor (type 00).
o0 0 0 0 0 0 0 − 1 1 1 1 1
Operatie/mode m3 m2 m1 m0 0 0 0 0 1 1 − 0 0 0 1 1
0 0 0 1 0 0 1 0 0 1 0 0
0 0 1 0 1 1 0 0 1 0 1 1
0 1 0 0 0 1 1 1 0 0 0 1
Bewerking
Formeel
Assembleertaal
Onmiddellijk Direct Indirect Register-ge¨ındexeerd Register-indirect Register-relatief Kopieer register Direct Indirect Register-ge¨ındexeerd Register-indirect Register-relatief
RF[d]←Constante RF[d]←Mem[adres] RF[d]←Mem[Mem[adres]] RF[d]←Mem[adres+RF[s1]] RF[d]←Mem[RF[s1]] RF[d]←Mem[RF[s1]+s2] RF[d]←RF[s1] Mem[adres]←RF[s1] Mem[Mem[adres]]←RF[s1] Mem[adres+RF[d]]←RF[s1] Mem[RF[d]]←RF[s1] Mem[RF[d]+s2]←RF[s1]
LOAD LOAD LOAD LOAD LOAD LOAD COPY STOR STOR STOR STOR STOR
Rd #waarde Rd adres Rd (adres) Rd adres+(Rs1) Rd (Rs1) Rd (Rs1)+Rs2 Rd Rs1 adres Rs1 (adres) Rs1 adres+(Rd) Rs1 (Rd) Rs1 (Rd)+Rs2 Rs1
Tabel 6.2: De verplaatsinstructies van de CISC-processor (type 01). Verplaatsinstructies Verplaatsinstructies zijn instructies die gegevens tussen het geheugen en de registerbank kopi¨eren. Er zijn in dit geval slechts twee basisinstructies mogelijk: kopi¨eren naar het geheugen (store) of kopi¨eren naar de registerbank (load). We bepalen dit met behulp van de eerste bit o0 . Met de overige vier bits kunnen we vervolgens de adresseermode bepalen. De eerste bit van de adresmodus bepaalt of de instructie een adresveld voorziet. Dit is nuttig omdat de hardware snel moet kunnen beslissen of dit adresveld ook moet worden uitgelezen. Indien m3 dus laag is maken we gebruik van een adresveld, in het andere geval kan men het adres afleiden uit de gegevens in de registervelden. De overige bits bepalen vervolgens de soort adressering: onmiddellijk (000), direct (001), indirect (010), relatief (011), ge¨ındexeerd (100) en registerkopie (101). Afhankelijk van het feit of we een adresveld beschouwen is de adressering dan bijvoorbeeld relatief of register-relatief. Verder zijn sommige combinaties niet mogelijk: we kunnen bijvoorbeeld onmogelijk de waarde van een register naar een constante kopi¨eren wanneer we onmiddellijke adressering zouden gebruiken. Wanneer we de verschillende mogelijkheden uitproberen bekomen we de instructieset in Tabel 6.2. Spronginstructies
Doorgaans beschouwt men vier verschillende soorten sprongbevelen:
232
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
o4
Operatie/mode o3 o2 o1 o0
Bewerking
Formeel
Assembleertaal
PC←adres PC←adres of PC←PC+1 Mem[RF[s1]]←PC+1; RF[s1]←RF[s1]+1; PC←adres RF[s1]←RF[s1]-1; PC←Mem[RF[s1]]
JMP adres CJMP adres
0 0
0 1
− −
− −
− −
Onconditionele sprong Conditionele sprong
1
0
−
−
−
Subroutine sprong
1
1
−
−
−
Terugkeer subroutine
JSR adres (Rs1)
RTS (Rs1)
Tabel 6.3: De spronginstructies van de CISC-processor (type 10).
• Ongeconditioneerde sprong (JMP): in dit geval wordt de programmateller gezet op het opgegeven adres. • Geconditioneerde sprong (CJMP): dit is een spronginstructie die enkel wordt uitgevoerd als aan een bepaalde voorwaarde wordt voldaan. Hiervoor houdt de processor een statusregister bij. Een bit in het statusregister noemt men meestal een statusvlag7 . Sommige instructies die we verder zullen beschouwen kunnen op basis van een bepaalde voorwaarde een 0 of een 1 naar dat register schrijven. Enkel wanneer het statusregister op 1 staat wordt de programmateller op het opgegeven adres gezet. In het andere geval wordt de programmateller opgehoogd. • Subroutine sprong (JSR): Wanneer het programma een subroutine wil uitvoeren, wordt het terugkeeradres eerst op een stapel gezet. Dit terugkeeradres is de opgehoogde programmateller. Nadat de stapel is verhoogd wordt de programmateller vervolgens aangepast zodat de processor aan het begin van de subroutine staat. • Subroutine terugkeer (RTS): Eenmaal we de subroutine hebben uitgevoerd is het de bedoeling dat het processor terugkeert naar het stuk code net achter de plaats waar de subroutine werd opgeroepen. Omdat verschillende stukken code een subroutine kunnen oproepen werd daarom dit adres op de stapel geplaatst. Door het adres uit te lezen van de stapel en de stapel met ´e´en element te reduceren bereikt de processor de correcte toestand. Vermits we slechts vier instructies beschouwen kunnen we de instructies voorstellen met behulp van twee bits. De overige bits zijn dan ook niet relevant. Tabel 6.3 beschrijft het formaat van verschillende spronginstructies samen met een formele beschrijving. Overige instructies De voorwaardelijke sprong leest het statusregister uit. Tot nu toe hebben we echter nog geen instructies ge¨ıntroduceerd die de waarde van het statusregister aanpast. Hiervoor voorzien we zes vergelijking-operaties: groter dan (GT), groter dan of gelijk aan (GE), kleiner dan (LT), kleiner dan of gelijk aan (LE), gelijk aan (EQ) en niet gelijk aan (NE). Indien aan de voorwaarde wordt voldaan wordt het statusregister op 1 gezet, in het andere geval op 0. Soms wenst men ook complexere condities te berekenen. Daarom voorzien we ook twee overige instructies die het statusregister aanpassen: zet status (SetS) en reset status (ClrS). Tot slot introduceren we ook twee andere operaties: de no operation (NOP) en reset register (ClrR). No-operation kan worden gebruikt als we werken met pipelining om de pipeline op te vullen met instructies waardoor de instructies na de no operation-instructie wachten tot de instructie ervoor is afgelopen. Het op 0 zetten van een register is soms nuttig alvorens we bijvoorbeeld de som van een array willen berekenen en vormt een alternatief voor de het inladen van een constante vermits de laatste instructie twee woorden vereist. Het instructieformaat van de overige instructies staat in Tabel 6.4. 7 Met
het concept vlag introduceert men meestal een terminologie: de vlag is gehesen wanneer de bit op 1 staat.
6.3. PROCESSORONTWERP
o4 0 0 0 1 1 1 1 1 1 1
Operatie/mode o3 o2 o1 o0 0 1 1 0 0 0 0 0 0 1
− 0 1 0 0 0 0 1 1 −
− − − 0 0 1 1 0 0 −
− − − 0 1 0 1 0 1 −
233 Bewerking
Formeel
Assembleertaal
No-operation Reset register Reset status Groter dan Groter dan of gelijk Kleiner dan Kleiner dan of gelijk Gelijk Niet gelijk Zet status
RF[d]←0 Status←0 Status←RF[s1] Status←RF[s1] Status←RF[s1] Status←RF[s1] Status←RF[s1] Status←RF[s1] Status←1
NOP CLR Rd ClrS GT Rs1 GE Rs1 LT Rs1 LE Rs1 EQ Rs1 NE Rs1 SetS
> RF[s2] >= RF[s2] < RF[s2] <= RF[s2] == RF[s2] != RF[s2]
Rs2 Rs2 Rs2 Rs2 Rs2 Rs2
Tabel 6.4: De overige instructies van de CISC-processor (type 11). Machinetaal Het binaire patroon van de instructies wordt ook wel de machinetaal genoemd. Het is immers een formele beschrijving hoe communicatie met de processor verloopt. Een programmeur kan een programma schrijven in machinetaal door elementen van deze taal in het geheugen in te laden. Zo zal bijvoorbeeld de de instructie 00100001111100002 een optelling realiseren die de som van registers R6 en R0 berekend en opslaat in register R7. We kunnen dit signaal als volgt decoderen:
00 |{z} registerbewerking
aritmetisch z}|{ 10
D=R7 s2=R0 z}|{ z}|{ 000 111 110 |{z} |{z} 000 s1=R6 optelling
(6.1)
Deze interpretatie van de machinecode wordt op hardware niveau uitgevoerd met behulp van logische poorten in de controller. Om schrijffouten te vermijden zullen programmeurs doorgaans de broncode in hexadecimale cijfers schrijven. Dit maakt de instructies compacter en vermijdt schrijffouten door bijvoorbeeld een 1 of 0 te vergeten. De instructie kunnen we dus ook voorstellen als 21F016 . Assembleertaal Hoewel de hexadecimale voorstelling de meeste schrijffouten voorkomt, vormt dit geen gemakkelijke basis om programma’s te schrijven. De hexadecimale code is immers niet makkelijk leesbaar omdat de bits niet altijd in groepen van vier zijn gestructureerd en we bijgevolg niet snel kunnen bepalen of een bepaald binair getal overeenkomt met een optelling. Daarom maakt men meestal gebruik van een assembleertaal. Een assembleertaal is een mnemonische voorstelling van de instructie en vormt een ´e´en-op´e´en relatie met de binaire instructies. Tabellen 6.1 6.2, 6.3 en 6.4 bevatten daarom ook een kolom die het equivalent in een zelf ontwikkelde assembleertaal voorstelt. Assembleerprogramma Een programma geschreven in de assembleertaal naar een equivalent programma in machinetaal gebeurt door een assembleerprogramma. Dergelijke programma’s werken met een eenvoudige opzoektabel die per mnemonische instructie het binaire equivalent bevat. De meeste assembleerprogramma’s bieden bovendien extra gebruiksgemak aan: symbolische adressen en labels. Wanneer we gegevens uit het geheugen lezen of wegschrijven dienen we een adres op te geven. De programmeur moet daarom bijhouden op welke plaats welke data precies staat. De meeste assembleerprogramma’s nemen deze taak echter gedeeltelijk over met symbolische adressen. Een programmeur gebruikt hierbij een symbolische naam en het programma kent zelf een adres toe. Dit leidt niet alleen tot gebruiksgemak maar voorkomt ook dat programmeurs per ongeluk een fout adres opgeven. Ook wanneer we sprongbevelen uitvoeren dienen we een adres op te geven. Het probleem met expliciete adressen is dat wanneer we een instructie invoegen alle adressen erna opschuiven. Om dit probleem te verhelpen werken assembleerprogramma’s met een label. Een label is een symbolische markering bij een bepaalde
234
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
instructie. Wanneer men vervolgens een sprong-instructie invoegt zet de programmeur de symbolische markering op de plaats waar het adres moet staan. Het assembleerprogramma houdt vervolgens zelf bij met welk adres dit label overeenkomt en vervangt de symbolische markering bij sprongbevel door een expliciet adres. Voorbeeld Bij wijze van voorbeeld zullen we een programma beschrijven in zowel een hoog-niveau programmeertaal, de assembleertaal en de machinetaal. Het programma berekent tegelijk het minimum, maximum en de som van 1024 getallen in een array A. Wanneer we dit in bijvoorbeeld Pascal implementeren schrijven we volgende code: In het codefragment in 6.1 maken we de assumptie dat een ander deel van Listing 6.1 Hoog niveau beschrijving van het min-max-sum algoritme. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
program minmaxsum ; var min : integer ; max : integer ; sum : integer ; A : array [ 0 . . 1 0 2 3 ] of integer ; begin min = maxint ; max = 0 ; sum = 0 ; f o r i := 0 to 1023 do begin sum = sum + A[ i ] ; i f A[ i ] > max then max = A[ i ] ; i f A[ i ] < min then min = A[ i ] ; end ; end .
het programma waardes in A zal laden. We houden verder drie integers bij: min, max en sum. Vervolgens overlopen we in een for-lus alle items. Ieder item wordt bij sum opgeteld en ondergaat vervolgens twee testen: indien het getal groter is dan max passen we max aan. Analoog berekenen we min. Bijgevolg bevatten op het einde van de lus min en max respectievelijk het minimum en maximum. Het omzetten van dit codefragment naar assembleertaal valt buiten het bereik van deze cursus maar wordt besproken in cursussen over compilerconstructie. We presenteren echter een equivalent programma in assembleertaal in 6.2. Het codefragment bestaat grofweg uit twee delen: data en programma. ORG DATA en ORG PROGRAM zijn dan ook directieven voor het assembleerprogramma. Het zijn geen instructies die omgezet worden in machinecode maar aanwijzingen om de assembleercode correct om te zetten in machinecode. Onder ORG DATA plaatst men een lijst met variabelen samen met hun datatype. Het is de bedoeling dat het assembleerprogramma ruimte voorziet voor de variabelen en de symbolische adressen in de code vervangt door hun fysieke waarde. Het type van de variabele bepaalt hoeveel adressen er gereserveerd moeten worden in het geheugen. In de micro-assembleertaal beschouwen we twee types: Word en Array. Een Word omvat ´e´en woord en is dus een hoeveelheid data die kan worden binnengehaald met ´e´en adres. Het assembleerprogramma zal bijgevolg adres 016 toekennen aan min, 116 aan max en 216 aan sum. In het geval van de processor die we hier ontwikkelen is dat 16 bit. Een Array duidt op een aantal woorden met het aantal gespecificeerd tussen vierkante haken. Dit betekent dus dat de variabele A zal worden opgeslagen in adressen 316 tot 40216 . Na ORG PROGRAM begint het eigenlijke program. De instructies staan dus vanaf adres 40316 vermits de vorige adressen worden ingenomen door de variabelen. Indien we een nieuwe variabele toevoegen, zal het assembleerprogramma alle adressen automatisch aanpassen. Het programma begint met het zetten van de drie registers waarin we min (R0), max (R1) en sum (R2). Zo laden we de maxint constante in in R0 en 0 in de overige registers. Daarna begint de initialisatie van de for-lus. We gebruiken hiervoor register R3 als
6.3. PROCESSORONTWERP
235
Listing 6.2 Het min-max-sum algoritme in assembleertaal. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
ORG DATA min Word max Word sum Word A Array [ 1 0 2 4 ] ORG PROGRAM LOAD R0 #0xFFFF CLR R1 CLR R2 CLR R3 LOAD R4 #0x03FF LOAD R5 #A body : LOAD R6 ( R5 ) ADD R2 R2 R6 LE R6 R1 CJMP n e x t COPY R1 R6 n e x t : GE R6 R0 CJMP l a s t COPY R0 R6 l a s t : INC R3 R3 INC R5 R5 LE R3 R4 CJMP body STOR min R0 STOR max R1 STOR sum R2
−−R0 b e w a a r t h e t minimum −−R1 b e w a a r t h e t maximum −−R2 b e w a a r t de som −−R3 b e w a a r t de l u s − t e l l e r ( i ) −−MaxCount ( 1 0 2 3 ) −−b e g i n a d r e s A −−b e g i n f o r l u s , R6 b e w a a r t A[ i ] −−sum=sum+A[ i ] −−i n d i e n A[ i ] <= max −−s p r i n g naar n e x t −−a n d e r s : max = A[ i ] −−i n d i e n A[ i ] >= min −−s p r i n g naar l a s t −−a n d e r s : min = A[ i ] −−hoog l u s t e l l e r op −−hoog a d r e s van de a r r a y op −−i n d i e n i <= 1023 −−s p r i n g t e r u g naar h e t b e g i n van de l u s −−p l a a t s R0 i n min −−p l a a t s R1 i n max −−p l a a t s R2 i n sum
lus-variabele (i). R4 gebruiken we als register die de constante bijhoudt om de for-lus te be¨eindigen. Tot slot gebruiken we register R5 die het adres bijhoudt van het element die we op dat moment moeten uitlezen. Vanaf het body-label beginnen de instructies in de for-lus. Zo laden we eerst de data op de specifieke plaats in de array in register R6. De data wordt bij het som-register opgeteld waarna we een eerste test uitvoeren. Indien de waarde kleiner of gelijk is dan het op dat moment geldende maximum, slaan we het aanpassen van de max variabele over. In het andere geval kopi¨eren we het getal naar het max-register. In de tweede test vergelijken we de waarde met het minimum. Indien de waarde groter is dan het minimum slaan we het aanpassen van het min-register over. Na de twee testen bereiken we het last-label: de laatste instructies binnen de for-lus. In dit gedeelte hogen we de lus-teller op samen met adres binnen de array. Vervolgens vergelijken we de for-teller en de eindconditie. Wanneer de teller kleiner is of gelijk aan het einde van de array voeren we de lus opnieuw uit: we springen dus terug naar het body-label. In het andere geval is de for-lus afgelopen. Tot slot dienen we nog de waardes binnen het register te kopi¨eren naar de variabelen. Dit doen we met behulp van drie store-instructies. Merk op dat het voorgestelde algoritme niet volledig equivalent is: we slaan immers eerst de waarde van A[i] in een register op in plaats van deze telkens uit te lezen. Het voordeel van deze werkwijze is echter dat we load-instructies en toegang tot het geheugen uitsparen en bijgevolg de snelheid van het programma opdrijven. We kunnen de code in assembleertaal handmatig omzetten in binaire machinetaal. Het resultaat na deze omzetting staat in 6.3. In de listing beschouwen we twee formaten: -- ----- --- --- --- beschrijft instructies en ---- ---- ---- ---- beschrijft adresvelden. In werkelijkheid is er natuurlijk geen verschil bij de instructies. Verder beschouwen we in het bestand don’t care bits. Men kan deze bits uiteraard niet voorstellen in een geheugen. In dat geval dienen we gewoon een waarde – 0 of 1 – in te vullen. Doorgaans kiest een assembleerprogramma 0. We zien dat een assembleerprogramma zowel de labels als de variabelen vervangt door hun fysische equivalent. Verder worden de verschillende instructies omgezet en de opgegeven registers ingevuld. Samen met deze cursus komt het programma assembler-cisc.hs die in staat is om programma’s geschreven in de gegeven assembleertaal om te zetten in de gegeven machinetaal. Men schrijft het programma in de assembleertaal en slaat het op in een bestand. Vervolgens roept men het programma
236
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Listing 6.3 Het min-max-sum algoritme in machinetaal. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
01 00000 000 −−− −−− 1111 1111 1111 1111 11 010−− 001 −−− −−− 11 010−− 010 −−− −−− 11 010−− 011 −−− −−− 01 00000 100 −−− −−− 0000 0011 1111 1111 01 00000 101 −−− −−− 0000 0000 0000 0011 01 01010 110 101 −−− 00 10000 010 010 110 11 10011 −−− 110 001 10 01−−− −−− −−− −−− 0000 0100 0001 0010 01 −−101 001 110 −−− 11 10001 110 000 −−− 10 01−−− −−− −−− −−− 0000 0100 0001 0110 01 −−101 000 110 −−− 00 10010 011 011 −−− 00 10010 101 101 −−− 11 10011 −−− 011 100 10 01−−− −−− −−− −−− 0000 0100 0000 1100 01 10000 −−− 000 −−− 0000 0000 0000 0000 01 10000 −−− 001 −−− 0000 0000 0000 0001 01 10000 −−− 010 −−− 0000 0000 0000 0010
#LOAD R0 #0xFFFF #CLR R1 #CLR R2 #CLR R3 #LOAD R4 #0x03FF #LOAD R5 ##A=3 #LOAD R6 (R5) #ADD R2 R2 R6 #LE R6 R1 #CJMP #n e x t=0x412 #COPY R1 R6 #GE R6 R0 #CJMP #l a s t = 0 x416 #COPY R0 R6 #INC R3 R3 #INC R5 R5 #LE R3 R4 #CJMP #body=0x40C #STOR R0 #min = 0 x0 #STOR R1 #min = 0 x1 #STOR R2 #min = 0 x2
aan met assembleer-cisc bestand program. De uitvoer is een binair bestand genaamd program die de equivalente machinecode voorstelt. In Hoofdstuk 9 ten slotte vindt men terug hoe men de CISC-processor zelf kan realiseren. Op die manier kan men dus zelfgeschreven programma’s uitvoeren.
We zullen tot slot op basis van het programma cijfermateriaal berekenen over het aantal uitgevoerde instructies. Dit is nuttig wanneer we bijvoorbeeld een sneller datapad willen ontwikkelen en statistische gegevens nodig hebben in verband met het voorkomen van instructies. Bij het verzamelen van statistische gegevens kunnen we een onderscheid maken tussen enerzijds het programma en de uitvoer. Bij de uitvoer van een programma kunnen sommige instructies immers meermaals worden uitgevoerd. Tabel 6.4(a) toont dan ook het gebruik van instructies in een programma. Wat opvalt is het hoge aantal verplaatsinstructies. Wanneer we de frequentie van de instructies willen berekenen zullen de meeste instructies 1024 keer in de lus worden uitgevoerd: we denken bijvoorbeeld aan de increment instructies. Een probleem vormen echter de register-kopieer instructies (COPY). De uitvoer van deze instructies hangt immers af van de gegevens in de array. We kunnen echter stellen dat wanneer we reeds k elementen hebben onderzocht, de kans om nog een minimum of maximum te bekomen gelijk is aan: 1 Pnieuw min/max (k) = 1+k
(6.2)
In dat geval verwachten we dat we 15.018 keer deze instructie zullen moeten uitvoeren. Tabel 6.4(b) beschrijft de frequentietabel bij de uitvoer. Wat opvalt is dat het aandeel aan verplaatsinstructies significant lager is. Dit is typisch: buiten de lussen voert men vooral instructies uit die gegevens inladen en wegschrijven. Binnen de lussen voert men meestal rekenwerk uit.
6.3. PROCESSORONTWERP
237 (a) Programma.
Register Op # % INC ADD
2 1
10 5
Tot.
3
14
Op
Verplaats # %
LOAD1 STOR1 COPY LOAD5 Tot.
3 3 14 1 9
14 14 10 5 43
Op
Sprong #
Overige Op # %
%
CJMP
3
14
CLR LE GE
3 2 1
14 10 5
Tot.
3
14
Tot.
6
29
(b) Uitvoer.
Op
Register #
Verplaats #
%
Op
LOAD5 COPY STOR1 LOAD1 Tot.
INC ADD
2048 1024
20 10
Tot.
3072
30
1024 15 3 3 1045
Sprong #
%
Op
10 0 0 0 10
CJMP
Tot.
Overige #
%
Op
%
3072
30
LE GE CLR
2048 1024 3
20 10 0
3072
30
Tot.
3075
30
Tabel 6.5: Frequentietabel bij het uitvoeren van het voorbeeldprogramma. Instructieset-stroomschema Na het opstellen van een instructieset volgt de volgende stap: het opstellen van een instructieset-stroomschema ofwel Instruction Set Flowchart. Een dergelijk stroomschema is een visuele voorstelling van alle instructies samen met de bijbehorende registertransfers. Meestal wordt dit schema dan ook gebruikt om later de instructiedecoder te ontwikkelen: een onderdeel van de controller die de instructie omzet in de juiste stuursignalen voor het datapad. Bij het defini¨eren van de instructieset hebben we verondersteld dat we beschikken over: • een geheugen (Mem) • een registerbank (RF) • een programmateller (PC) • een instructieregister (IR) • een statusvlag (Status) Het stroomschema kent twee concepten: instructieblokken en beslissingsblokken. Een instructieblok wordt voorgesteld door een rechthoek terwijl een beslissingsblok wordt voorgesteld door een driehoek. Op het bovenste hoekpunt wordt de variabele gezet die betrokken is in de beslissing of een booleaanse expressie. Op de basis van de driehoek worden vervolgens de verschillende resultaten van de variabele of booleaanse expressie geplaatst en vertrekt vanuit elk resultaat een pijl. Men leest een stroomschema dan ook door de relevante pijl te volgen. De beschrijving van een stroomschema lijkt op dat van een ASM-schema maar verschilt op enkele punten. Zo omvat een stroomschema geen concrete toestanden: we doen geen uitspraak over wat precies in welke klokcyclus moet worden afgehandeld, soms zullen bewerkingen in het stroomschema dus verder onderverdeeld worden. Verder kent een stroomschema wel een sequenti¨ele volgorde toe aan instructies. Instructies die vermeld staan in eenzelfde blok worden conceptueel na elkaar uitgevoerd8 . In een ASM-schema worden 8 Dit hoeft echter niet te betekenen dat de opdrachten ook effectief na elkaar moeten worden uitgevoerd. Indien beide instructies niet interfereren bijvoorbeeld kan men de instructies omdraaien of tegelijk uitvoeren.
238
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
alle instructies in een blok tegelijk uitgevoerd. Stel bijvoorbeeld dat men in een blok volgende instructies tegenkomt: a←a+1 (6.3) b ← Mem[a] In het geval deze instructies in een ASM-schema staat zal b de waarde van het geheugen inlezen dat op het adres van de oude waarde van a staat. In het geval van een stroomschema wordt de waarde op het adres ernaast uitgelezen. Een stroomschema voor een instructieset omvat alle mogelijke instructies die kunnen worden uitgevoerd. Centraal staat doorgaans een instructieblok die beschrijft hoe de instructie wordt opgehaald en de programmateller wordt opgehoogd. Vanuit dit blok worden de stroom vervolgens opgedeeld op basis van mogelijke instructies. Elke vertakking voert vervolgens de instructie uit en keert terug naar het centrale blok zodat de volgende instructie kan worden opgehaald. Figuur 6.8 toont het stroomschema van alle 44 instructies in ´e´en afbeelding. De verschillende types instructies zijn in verschillende richtingen opgebouwd. Centraal zien we een instructieblok met twee instructies: IR ← Mem[PC] laadt de instructie op het adres van de programmateller in het instructieregister en PC ← PC hoogt de instructieteller op. Na het inladen van de instructie vertakt de stroom zich aan de hand van de data in het instructieregister. Allereerst maken we op basis van IR15 9 en IR14 een onderscheid tussen de verschillende types. Eenmaal voldoende vertakt beschrijft een instructieblok de concrete uitvoer van de bewerking. Het stroomdiagram toont ook details die niet in de tabellen met de instructies vermeld staan. We denken hierbij bijvoorbeeld aan het inlezen van het adresveld. In het geval de instructie gepaard gaat met een adresveld wordt wordt dit ook uitgelezen met Mem[PC]10 waarna de programmateller nogmaals wordt opgehoogd. Na het uitvoeren van de instructies komen de verschillende stromen terug samen bij het instructieblok die de volgende instructie inleest. Allocatie datapadcomponenten Nadat per instructie een formele beschrijving werd opgesteld met betrekking tot de verschillende operaties, bestudeert men in een volgende fases het datapad. Op basis van de uitgevoerde bewerkingen, kunnen we immers de vereiste hardware vastleggen. Zo vereist het stroomdiagram vijf soorten geheugen: • Een extern geheugen Mem: 216 × 16 ofwel 128 kiB met 1 lees/schrijfpoort. • Een registerbank RF: 23 × 16 met 2 leespoorten en 1 schrijfpoort. • Een statusvlag Status • Een instructieregister IR • Een programmateller PC De laatste twee registers behoren echter tot de controller en zullen we in deze stap niet beschouwen. We kunnen verder voor elke operatie een functionele eenheid voorzien. Anderzijds zal elke klokcyclus er hoogstens ´e´en instructie actief zijn. Alle bewerkingen die moeten worden uitgevoerd kunnen we uitvoeren met drie algemene functionele eenheden: • Aritmetische Logische Eenheid (ALU) • Vergelijker • 16-bit bidirectionele schuifoperator. 9 Met
deze notatie bedoelen we de 15-de bit van het instructieregister. op dat alvorens we deze instructie bereiken, de programmateller al is opgehoogd. Bijgevolg staat de programmateller op dat moment op het adresveld. 10 Merk
6.3. PROCESSORONTWERP
239
We maken de assumptie dat de ALU alle basisbewerkingen (ADD, SUB, MUL, DIV, ROOT, NEG, AND, NAND, OR, NOR, XOR, XNOR, MASK en INV) kan uitvoeren, dat de vergelijker iedere conditie (GT, GE, LT, LE, EQ en NE) met betrekking tot twee registers kan uitrekenen en dat het schuifregister de twee schuifinstructies (ASR, ASL) kan uitvoeren. Instructies die niet onder het type registerinstructies vallen voeren doorgaans geen bewerkingen uit behalve de optelling. In dat geval is de ALU echter vrij waardoor dit geen probleem vormt. In deze fase is het echter de bedoeling te onderzoeken of we de snelheid niet kunnen opdrijven door extra hardware te voorzien. Wanneer men echter aanpassingen aanbrengen aan het datapad zal men ook de instructieset moeten herzien. Wanneer we de snelheid willen opdrijven zullen we dit altijd doen ter hoogte van het kritisch pad. Het heeft immers weinig zin andere instructies sneller uit te voeren wanneer de kloksnelheid onder druk staat van een andere instructie. We hebben reeds vermeld dat geheugen doorgaans een bottleneck vormt dus is het meestal interessant vooral naar instructies te kijken met een groot aantal geheugentoegangen. Op basis van het stroomdiagram kunnen we opmerken dat impliciete adressering het meeste geheugenoproepen kent. De instructie vereist immers volgende bewerking: RF[d] ← Mem[Mem[Mem[PC]]]
(6.4)
Dit komt bijgevolg neer op 4 geheugentoegangen (inclusief het inlezen van de instructie). Stel dat het RAMgeheugen een toegangstijd heeft van 50 ns, dan vereist de instructie dus minstens 200 ns. Indien we dus de volledige instructie in ´e´en klokcyclus uitvoeren, dan is de maximale klokfrequentie bijgevolg: 1 = 5 MHz (6.5) 4 · 50 ns We kunnen de impliciete adressering onmogelijk versnellen met de gegeven toegangstijd. Anderzijds impliceert het uitvoeren van de instructie in ´e´en klokcyclus dat alle instructies in 200 ns worden uitgevoerd, ook registeroperaties die geen geheugenoperaties vereisen. Dit betekent dat het uitvoeren van het voorbeeldprogramma 2 052 800 ns vereist. fmax =
We kunnen een multicycling transformatie uitvoeren waarin instructies worden uitgesmeerd zodat per klokcyclus er ´e´en geheugentoegang wordt uitgevoerd. In dat geval is een klokcyclus ongeveer 50 ns lang. Wanneer we dus een LOAD instructie uitvoeren met behulp van impliciete adressering zal dit nog steeds 200 ns vereisen. Anderzijds zullen bijvoorbeeld registeroperaties in 1 klokcyclus worden uitgevoerd. Uit Tabel 6.4(b) kunnen we echter afleiden dan het grootste deel van de instructies enkel toegang tot het geheugen vereisen om de instructie in te laden. De uitvoertijd van het programma zal dus ongeveer verviervoudigen. Met de multicycling transformatie dienen we echter een nieuw register te introduceren: het adresregister (AR). Dit register houdt het adres bij tijdens de uitvoeren van verplaatsinstructies. We hebben slechts nood aan ´e´en register omdat bij bijvoorbeeld impliciete adressering we dit register enkele malen kunnen overschrijven tot de instructie is uitgevoerd. ASM-schema Na het alloceren van componenten bij het datapad zullen we een ASM-schema opstellen. We stellen dit proces op op basis van enerzijds het stroomdiagram op Figuur 6.8 en anderzijds de allocatie van de componenten op het datapad. Met deze stap dienen we echter te beslissen welke bewerkingen we in welke toestand uitvoeren. Concreet betekent dit dat we de instructieblokken van het stroomdiagram opsplitsen in zo weinig mogelijk ASM-blokken. In principe kan men alle instructies altijd tegelijk uitvoeren. Anderzijds hebben we de componenten op het datapad reeds vastgelegd. Concreet betekent dit dat we in dit geval over slechts ´e´en ALU beschikken, dat we slechts ´e´en adres van het geheugen tegelijk kunnen uitlezen, we ´e´en woord per toestand naar de registerbank kunnen wegschrijven, enzovoort. Bij wijze van voorbeeld zullen we enkele gevallen bespreken.
240
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Aritmetisch schuiven naar rechts (ASR) Om de voorbeelden te bespreken zullen we telkens eerst de relevante delen van het stroomschema voorstellen. In het geval van aritmetisch schuiven naar rechts (ASR) is dit Figuur 6.9(a). De cyclus omvat slechts twee instructieblokken: het ophalen van een instructie en het uitvoeren. Dit is het geval bij alle registerinstructies. Hardwarematig is er geen probleem om de twee bewerkingen in ´e´en klokcyclus uit te lezen: we kunnen de instructie uit het geheugen inlezen en deze tegelijk uitvoeren en in het instructieregister plaatsen. Er zijn echter drie redenen om dit niet te doen: in dat geval heeft het plaatsen van de instructie in het register geen nut: de volgende instructie zal de waarde immers overschrijven zonder dat deze ooit werd uitgelezen. Verder beschouwen we ook een Moore-machine als controller. Dat betekent dat de stuursignalen afhankelijk zijn van de data die in een vorige klokcyclus werd uitgevoerd. Tot slot is het ophalen van de instructie een bewerking die met alle overige instructies wordt gedeeld. De logica wordt meestal eenvoudiger als men bij het ophalen van de instructie niet voor sommige instructies meteen de relevante bewerkingen uitvoert. We stellen dus twee verschillende toestanden: een toestand waarin we de instructie ophalen en een toestand waarin we de schuifoperatie naar rechts uitvoeren. In het ASM-schema moeten we dus een leeg toestandskader introduceren na het toestandskader die de instructie ophaalt. Onder dit toestandskader plaatsen we vervolgens beslissingskaders die naar een conditioneel kader leiden waar de instructie wordt uitgevoerd. Een ASM-schema dat enkel relevant is voor de ASR-instructie is getekend in Figuur 6.9(b). Merk op dat in een ASM-schema zaken die in hetzelfde toestandskader gebeuren tegelijk worden uitgevoerd, dit in tegenstelling tot een stroomschema. Laden van een constante (LOAD) We beschouwen vervolgens de LOAD-instructie met onmiddellijke adressering die een constante uit het programma in een register inladen. Een compact deel van het stroomschema staat op Figuur 6.10(a). In het geval van deze instructie zijn we verplicht om twee toestanden te voorzien. Dit komt omdat het geheugen slechts ´e´en leespoort heeft en we bijgevolg geen twee woorden tegelijk uit het geheugen kunnen laden. Verder wordt ook de programmateller tweemaal opgehoogd terwijl de controller slechts ´e´en increment-operator omvat. We introduceren dus opnieuw twee toestanden: ´e´en toestand waarbij we de instructie inlezen en ´e´en toestand waarin we het adresveld inlezen en wegschrijven naar de registerbank. Dit leidt tot het ASM-schema in Figuur 6.10(b). Laad direct uit het geheugen (LOAD) Naast het inladen van een constante bevat de instructieset ook een instructie om gegevens in te laden waarbij het adres gespecificeerd is. Opnieuw kunnen we omwille van het feit dat het geheugen slechts ´e´en leespoort telt deze operatie enkel met minstens drie toestanden uitvoeren. Bij een multicycling-transformatie dienen we echter de tussenresultaten op te slaan. Hiervoor werd echter het adresregister ge¨ıntroduceerd. Dit adresregister zal na toestand twee het adres bevatten dat moet worden uitgelezen. In de derde toestand wordt de waarde meteen terug uitgelezen om het correcte adres uit het geheugen uit te lezen. Laad indirect uit het geheugen (LOAD) De laatste LOAD-instructie die we beschouwen is de impliciete adressering. Deze instructie vereist in totaal viermaal toegang tot het geheugen. Bijgevolg vereist deze operatie minimum vier toestanden. Ook hier beschouwen we dus een multicycling-transformatie waarbij we ´e´en instructieblok van het stroomschema op in drie toestandsblokken in het ASM-schema. We zullen bijgevolg de tussenresultaten opnieuw moeten wegschrijven. In een algemeen geval betekent dit dat we twee registers moeten voorzien11 . In dit geval hebben we slechts ´e´en extra register nodig. We dienen immers enkel de resultaten van de vorige toestand te onthouden. Dit betekent dat we in de vierde toestand de resultaten van de tweede toestand niet meer nodig hebben. Sprong naar een subroutine (JSR) Ook in het geval van een sprong naar een subroutine moeten we het uitvoeren van de eigenlijke instructie opsplitsen in twee delen. De volledige set instructies staat op Figuur 6.13(a). Dit komt opnieuw door de toegang tot het geheugen: we moeten zowel het adresveld uitlezen 11 In een algemeen geval kan het immers voorkomen dat het finale resultaat afhangt van alle tussenresultaten berekend in de vorige toestanden.
6.3. PROCESSORONTWERP
241
en de programmateller na uitlezen in het geheugen plaatsen. Het geheugen omvat echter ´e´en lees/schrijfpoort. We kunnen dus niet tegelijk lezen en schrijven. Om de toestand te overbruggen zullen we bovendien opnieuw gebruik moeten maken van de adresregister. In de eerste toestand lezen we dus eenvoudigweg het adresveld uit en hogen we de programmateller op. In de tweede toestand schrijven we de programmateller weg naar het geheugen, hogen we de stapel op en stellen we tot slot de programmateller gelijk aan het adresregister. Men kan opmerken dat er nog een tweede reden is om de instructies in twee blokken op te splitsen: we dienen tweemaal een increment uit te voeren. In het geval van de programmateller valt deze verantwoordelijkheid echter onder de controller. De controller beschikt over een eigen increment-operator waardoor men in principe tegelijk een optelling met de ALU en een increment van de programmateller kan realiseren. Het ASM-schema die de twee blokken voorstelt staat in Figuur 6.13(b). Terugkeer uit een subroutine (RTS) Tot slot beschouwen we ook nog de terugkeer instructie waarvan het stroomschema is afgebeeld op Figuur 6.14(a). Deze instructie voeren we uit in ´e´en toestand. Men kan opmerken dat we eerst de waarde van een register in de registerbank moeten aftellen om vervolgens de relevante geheugenplaats in te lezen. We kunnen echter zonder gebruik te maken van extra hardware een chaining-transformatie uitvoeren en dus niet alleen het resultaat na de decrement-operatie opslaan in de registerbank maar deze ook gebruiken om het adres te bepalen in het geheugen. We kunnen bijgevolg alle instructies in ´e´en klokcyclus uitvoeren. Dit leidt dan ook tot het ASM-schema op Figuur 6.14(b). Ontwerp Controller Na het ontwerpen van een (gedeeltelijk) ASM-schema, kunnen we een specifieke controller ontwikkelen voor onze processor. In de eerste plaats beschouwen we altijd de controller uit Figuur 5.19 op pagina 174. In deze controller beschouwen we echter enkele algemene componenten zoals een toestandsregister, next-state logica en output logica. In deze subsubsectie ondernemen we een poging deze componenten in te vullen. De eerste component die we zullen bespreken is het toestandsregister. Dit register omvat normaal de toestand waarin de controller zich bevindt. In het geval van een processor is de toestand echter de plaats in het programma waarin we ons bevinden. Deze plaats wordt gemarkeerd door de programmateller: deze teller bevat immers het geheugenadres van waaruit we de instructie zullen uitlezen. Het stroomschema en het ASM-schem specificeren verder ook dat we op basis van de waarde van de programmateller de relevante instructie uit het geheugen inlezen en deze vervolgens in het instructieregister plaatsen. We voegen bijgevolg het geheugen en register tussen de programmateller enerzijds en de next-state- en output-logica anderzijds. De implementatie van de controller na deze stap is ge¨ıllustreerd in Figuur 6.15. Door het toestandsregister te vervangen met de programmateller introduceren we echter een belangrijk probleem: de waarde van het toestandsregister in een controller beschrijft immers volledig de toestand. Dit zou dus betekenen dat we op basis van de programmateller of de overeenkomstige instructie alle bewerkingen kunnen afleiden. Dit is echter niet het geval: bij sommige bewerkingen werd een multicycling transformatie uitgevoerd. Bij bijvoorbeeld een indirecte laad-instructie doorlopen we vier verschillende toestanden. Alleen in de eerste twee toestanden wordt de programmateller opgehoogd. Dit betekent dus dat we geen onderscheid kunnen maken tussen bijvoorbeeld toestand S3 en S4 in Figuur 6.12(b) op pagina 251. We kunnen dit probleem echter oplossen met behulp van de componenten die de volgende toestand en de uitvoer-logica berekenen. Klassiek zijn dit twee combinatorische schakelingen. We kunnen echter ook een eindige toestandsautomaat implementeren om deze componenten voor te stellen. Deze automaat omvat dan een intern toestandsregister die de verschillende deeltoestanden van een instructie bijhoudt. In sommige processoren is er zelfs sprake van een volledige eindige toestandsautomaat-controller met een micro-programmateller en micro-programmageheugen. De controller laat toe om naast de programmateller op te hogen ook op twee andere manieren een nieuwe waarde in te laden: de logica die de volgende toestand uitrekent kan zelf een waarde voorstellen of de waarde kan worden afgeleid uit een LIFO-stack (ook wel de execution stack of uitvoerstapel genoemd) in het geval van subroutines. Op basis van het stroomschema kunnen we echter opmerken dat in het geval van een
242
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
spronginstructie het adres expliciet in het programma wordt vermeld. We hebben bijgevolg geen extra logica nodig om het adres verder te decoderen. Daarom vervangen we de verbinding vanuit de next-state logica naar de multiplexer door een verbinding vanuit het geheugen naar de multiplexer. Wanneer we een subroutine uitvoeren doet een deel van het geheugen zelf dienst als stapel. Dit zien we bijvoorbeeld in het stroomschema waar de instructies Mem[RF[s1]] ← PC en RF[s1] ← RF[s1] + 1 respectievelijk eerst de waarde van de programmateller op de juiste plaats in de stapel plaatst en vervolgens een register in de registerbank die dienst doet als stapelteller ophoogt. In het geval we terugkeren uit een subroutine geldt een omgekeerde procedure. De controller die we op dit moment beschouwen voorziet hiervoor op dit moment zelf een LIFO-stapel. We kunnen vervolgens deze stapel elimineren en de verbindingen afleiden naar het geheugen. Dit betekent dat de uitgang van de increment die oorspronkelijk het adres van de LIFO bepaalde nu in bepaalde omstandigheden het geheugenadres bepaalt. Verder werd al een verbinding vanuit het geheugen naar de multiplexer voorzien. We elimineren dus een verbinding en reduceren ook de multiplexer tot een 2-naar-1 MUX. De controller na het doorvoeren van deze twee wijzigingen staat op Figuur 6.17. Tot slot dienen we op te merken dat het geheugen van de ontwikkelde processor geen onderdeel is van de controller zelf: ook het datapad heeft toegang tot hetzelfde geheugen om bijvoorbeeld programmaconstanten uit te lezen. Een architectuur waar men een centraal geheugen beschouwt die zowel gegevens als programma’s beschouwt noemen we Von Neumann-architectuur, in het geval beide geheugens gescheiden zijn spreken we over Harvard-architectuur. We verplaatsen dus het geheugen uit de controller. Dit doen we door twee bussen te beschouwen: een adresbus is een reeks verbindingen waarmee men de adresingangen van het geheugen kan aansturen en met behulp van de databus leest men gegevens in of schrijft men deze weg in het geheugen. De databus is bijgevolg een bus die in twee richtingen werkt. We dienen bijgevolg tri-state buffers te voorzien voor zowel lees- als schrijfoperaties. Ook op de adresbus brengen we tri-state buffers aan: het datapad moet immers ook adressen kunnen aanleggen. De uiteindelijke controller beschrijven we in Figuur 6.18. Ontwerp Datapad De laatste stap is het ontwerpen van een datapad. We hebben reeds enkele stappen geleden de vereiste componenten voor het datapad vastgelegd. We dienen echter nog verbindingen te introduceren om de verschillende instructies te kunnen uitvoeren. Deze verbindingen omvatten ook tri-state buffers aan de ingangen van een bus en multiplexers aan de uitgangen. De vereiste verbindingen kunnen we uiteraard afleiden uit het ASM-schema. Het is mogelijk dat er conflicten ontstaan tussen enerzijds het ASM-schema en anderzijds de componenten en verbindingen op het datapad. Dit kunnen we oplossen door terug te keren op ´e´en van de volgende stappen: • De allocatie van de componenten: in dat geval voorzien we extra componenten zoals een extra ALU of registerbank. We dienen vervolgens wel opnieuw een ASM-schema op te stellen en mogelijk ook een nieuwe controller ontwerpen. • Het ASM-schema: we kunnen extra toestanden introduceren zodat we de componenten op het datapad meermaals kunnen gebruiken. Hiervoor dienen we het ASM-schema en mogelijkerwijs de controller aan te passen. Dit leidt uiteraard tot meer klokcycli voor (sommige) instructies. Bij het omzetten van het ASM-schema naar de verbindingen van het datapad is het belangrijk een onderscheid te maken tussen bewerkingen die onder de verantwoordelijkheid van de controller vallen en deze van het datapad. Zo beschrijft toestand S0 het ophalen van een instructie en deze vervolgens in het instructieregister plaatsen. Zowel de programmateller en het instructieregister vallen echter onder de verantwoordelijkheid van de controller. Bijgevolg dienen we voor deze bewerkingen geen verbindingen te introduceren. Ook het interpreteren van de instructie is de verantwoordelijkheid van het datapad.
6.3. PROCESSORONTWERP
243
Bij het ontwerp beginnen we met een datapad waar we enkel de componenten tekenen. Verder worden ook externe componenten (behalve de controller) die interageren met het datapad getekend. In dit concrete geval is dit het centrale geheugen samen met de adres- en databus. We beschrijven ook de tri-state buffers van de databus van en naar het geheugen. Deze aspecten werden ook al beschreven bij het ontwerp van de controller. Dit resulteert in de afbeelding op Figuur 6.19. We realiseren een controller door de verschillende instructies toe te voegen en waar nodig extra bussen in het datapad aan te brengen. Het is daarom nuttig om onmiddellijk bij het introduceren van een bus met tri-state buffers bij de aansturing en eventueel ontvangers aan de kant van de gebruikers te plaatsen. Indien later blijkt dat de bus enkel door ´e´en register wordt aangestuurd of de multiplexer slechts data ontvangt van ´e´en bus, kan men deze componenten gewoon verwijderen. We zullen in de rest van deze subsubsectie enkele instructies vertalen naar het datapad. Natuurlijk dienen we in realiteit alle instructies te beschouwen. Het resulterende datapad staat in Figuur 6.21 op pagina 256 en de uiteindelijke controller in Figuur 6.20 op pagina 255. We zullen vanaf hier de synthese van deze figuren beschouwen. Schuifoperatie (SHR) We beschouwen opnieuw de schuifoperatie naar rechts. Zoals reeds aangehaald is het inlezen en interpreteren van de instructie de verantwoordelijkheid van de controller. Bijgevolg rest alleen nog verbindingen te voorzien voor de laatste bewerking in de instructie: RF[d] ← RF[s1]>>N. Het bepalen van de juiste adressen in de registerbank (d en s1) valt hierbij ook onder de verantwoordelijkheid van de controller. Dit doen we door verbindingen te plaatsen tussen de output logica eindige toestandsautomaat en de adres-ingangen van de registerbank en de schuiflengte-ingangen van het schuifregister. We dienen dus enkel bussen te realiseren die gegevens vanuit de registerbank naar het schuifregister transporteert en terug. De eerste bus wordt via een tri-state buffer aangestuurd vanuit de eerste lees-poort van de registerbank12 . Verder loopt vanuit het schuifregister een bus terug naar de registerbank. Optelling (ADD) In het geval van een optelling dienen we opnieuw slechts de verbindingen verantwoordelijk voor de optelling zelf te realiseren. Dit betekent dat we de twee leespoorten moeten aanleggen op de twee ingangen van de ALU. We hebben echter al ´e´en operandbus voorzien: deze bus wordt aangestuurd door het register bepaald door het s1 veld van de instructie. We verwachten dat de implementatie van de controller vereenvoudigt wanneer we dit principe consistent toepassen. Bijgevolg zullen we ook bij de optelling deze bus aansturen met de inhoud van RF[s1]. We dienen echter nog een andere operand-bus te voorzien: een bus om RF[s2] te verplaatsen. Deze bus wordt dus aangestuurd door de tweede leespoort van de registerbank. We dienen tot slot ook de twee ingangen van de ALU aan de operandbussen te koppelen. Het datapad voorziet ook reeds een resultaatbus. Deze resultaatbus wordt aangestuurd door de schuifoperator en gebruikt door de registerbank. Omdat we het schuifregister niet tegelijk met de ALU gebruiken, kunnen we bijgevolg de resultaatbus hergebruiken. We voorzien dus een tri-state buffer tussen de uitgang van de ALU en de resultaatbus. De overige registerinstructies worden allemaal ofwel door het schuifregister ofwel door de ALU uitgevoerd. Zonder verder in detail te gaan kunnen we dus stellen dat de twee operandbussen en de resultaatbussen dus volstaan om al deze instructies te ondersteunen. Onmiddellijk laden (LOAD) Naast register-instructies beschouwen we ook instructies die data in en uit het geheugen halen. Dit geheugen bevindt zich buiten het datapad, maar het datapad kan wel communiceren met dit geheugen via de adres- en databus. Wanneer we een constante inladen betekent dit dat we volgende bewerking uitvoeren: RF[d] ← Mem[PC]. We beschikken evenmin over de inhoud van de programmateller, maar de controller kan wel de inhoud op de adres-bus plaatsen. In dat geval staat de inhoud die moet worden ingeladen dus op de data-bus. Wanneer we dus een tri-state buffer plaatsen tussen de data-bus en de resultaat-bus, kunnen we de data in de registerbank inladen. Direct laden (LOAD) Het ASM-schema op Figuur 6.11(b) op pagina 250 beschrijft hoe gegevens direct uit het geheugen worden ingeladen. Het proces komt neer op twee bewerkingen waar het datapad een rol in 12 We kunnen ook opteren voor de tweede leespoort. Vermits momenteel nog geen enkele leespoort in gebruik is, is de keuze arbitrair.
244
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
speelt: AR ← Mem[PC] en RF[d] ← Mem[AR]. De eerste bewerking heeft veel gemeen met het onmiddellijk inladen van een constante: we laden immers opnieuw Mem[PC] in, alleen is de gebruiker nu het adresregister AR. We kunnen opnieuw gebruik maken van de resultaatbus vermits deze bus opnieuw door geen enkel ander component gebruikt wordt in dezelfde toestand. We dienen hierbij wel het adresregister aan te sluiten op de resultaatbus. Hiervoor hoeven we op dit moment uitsluitend een eenvoudige verbinding te gebruiken: het adresregister dient immers niet te kiezen tussen data van verschillende bussen waardoor een multiplexer overbodig is. Vervolgens beschouwen we de tweede bewerking. In deze bewerking dient de inhoud van het adres-register op de adres-bus te verschijnen. Hiervoor voorzien we dus een verbinding tussen de lees-poort van het adresregister enerzijds en de adresbus anderzijds. In dit geval dienen we wel gebruik te maken van een tri-state buffer: er zijn immers nog registers en componenten die hun inhoud op de adres-bus kunnen plaatsen. Ge¨ındexeerd laden (LOAD) Als laatste laad commando beschouwen we ge¨ındexeerd laden. Bij ge¨ındexeerd laden voorzien we opnieuw twee relevante bewerkingen: de eerste bewerking stelt: AR ← Mem[PC]+RF[s1], en in een volgende toestand RF[d] ← Mem[AR]. De tweede bewerking is identiek aan een bewerking bij het direct laden van een waarde. Bijgevolg dienen we geen extra verbindingen te voorzien. De eerste operatie omvat echter een nieuw aspect: we laden niet enkel de waarde van de programmateller in, maar tellen er ook nog de registerwaarde RF[s1] bij. Bijgevolg dienen we de waarde die op de databus verschijnt eerst aan te leggen op een ALU die vervolgens de som berekent. Het resultaat van de ALU wordt dan aangelegd op de resultaat-bus en wordt op die manier in de registerbank ingeklokt. Om de data aan te leggen kunnen we gebruik maken van een operand-bus: slechts ´e´en van de twee wordt immers gebruikt om de data van het register RF[s1] te verplaatsen. Omdat in alle voorgaande bewerkingen de eerste operandbus deze waarde transporteerde, zullen we de waarde van de data-bus dan ook aanleggen op de tweede operand-bus. De optelling is immers commutatief dus maakt de concrete toewijzing niks uit. Concreet introduceren we dus ´e´en nieuw tri-statebuffer tussen de databus en de tweede operand-bus. Vermits alle overige laad-instructies enkel gebruik maken van bewerkingen die reeds werden beschouwd, zullen deze geen nieuwe verbindingen introduceren. Kopi¨ eren van een register (COPY) Verplaatsinstructies verplaatsen niet enkel gegevens tussen registers en het geheugen, maar ook tussen de registers onderling. Dit is de zogenaamde COPY-instruction. We kunnen in de eerste plaats denken om in het geval van een copy-instruction een operandbus te verbinden met de resultaat-bus met behulp van een tri-state buffer. Anderzijds kan deze instructie worden ondersteund zonder extra verbindingen te voorzien. Wanneer we immers schuiven over 0 bits naar links of rechts, zal dezelfde waarde op de resultaat-bus worden aangelegd die op de eerste operand bus stond. De meeste ALU’s laten bovendien toe dat met behulp van een bepaalde functiecode de waarde aan ´e´en van de ingangen eenvoudigweg wordt aangelegd op de resultatenbus. We kunnen kiezen welke methode moet worden ge¨ımplementeerd in de logica van de controller, maar de operatie introduceert geen nieuwe verbindingen op het datapad. Direct stockeren (STOR) De verplaats-instructies die data uit het geheugen inladen hebben op het inladen van een constante na een tegenhanger die data wegschrijft naar het geheugen. Vermits het berekenen van het adres gelijkaardig is, zullen we hiervoor geen nieuwe instructies moeten voorzien. De bewerking die het uiteindelijke resultaat wegschrijft – Mem[AR] ← RF[s1] dienen we echter wel te beschouwen. In deze bewerking leggen we de inhoud van het adresregister aan op de adresbus. De verbindingen hiervoor zijn reeds voorzien omdat we dit ook moeten doen om bijvoorbeeld gegevens direct in te laden. Anderzijds dienen we de inhoud van het gespecificeerde register aan te leggen op de registerbank. Tot nu werd altijd de eerste leespoort gebruikt om RF[s1] uit te lezen. Om de implementatie van de controller eenvoudig te houden zullen we deze conventie verder toepassen. We dienen echter de leespoort te verbinden met de data-bus. We voorzien dus een tri-state buffer tussen de eerste leespoort en de databus. Met deze STOR-instructie beschouwen we alle overige verplaats-instructies ook als ge¨ımplementeerd. Sprong naar subroutine (JSR) We zullen ook enkele sprong-instructies beschouwen. De eerste instructie is de sprong naar een subroutine. We beschouwen deze instructie omdat we hierdoor ook tegelijk de bewerkingen van de onvoorwaardelijke (JMP) en voorwaardelijke (CJMP) sprong beschouwen. Het ASM-schema
6.3. PROCESSORONTWERP
245
van deze instructie staat op Figuur 6.13(b) op pagina 252. We zien op het ASM-schema twee toestanden die van belang zijn. In de eerste toestand wordt het geheugen op het adres van de programmateller ingelezen in het adresregister. Deze bewerking hebben we echter ook beschouwd bij het inladen van geheugendata met directe adressering. In de volgende toestand beschouwen we drie bewerkingen: Mem[RF[s1]] ← PC, RF[s1] ← RF[s1]+1 en PC ← AR. De increment van het register RF[s1] is eenvoudig te implementeren. Dit is immers een register-instructie en bijgevolg dienen we geen extra verbindingen te voorzien. We dienen verder ook de waarde van de programmateller weg te schrijven in het geheugen op het adres aangegeven door een register. Hiervoor dienen we verbindingen te voorzien die de programmateller verbindt met de databus en de eerste leespoort met de adresbus. Merk op dat we bijgevolg zowel de controller als het datapad moeten aanpassen. Tot slot dienen we de waarde van het adresregister naar de programmateller kopi¨eren. Een probleem is echter dat alle beschikbare bussen reeds bezet zijn. We kunnen weliswaar de tweede operandbus gebruiken, maar deze heeft op dit moment geen verbinding met de programmateller. We kunnen dit oplossen door een verbinding te voorzien vanuit het adresregister naar de programmateller, al da niet via de tweede operandbus, ofwel door het ASM-schema aan te passen. We kunnen bijvoorbeeld een nieuwe toestand voorzien waarin – bijvoorbeeld via de vrijgekomen databus – de waarde van het adresregister aanlegt op de multiplexer van de programmateller. In dit geval kiezen we voor het tweede. Dit leidt tot de finale controller in Figuur 6.20. Terugkeer uit subroutine (RTS) De laatste spronginstructie die we beschouwen is de terugkeer uit een subroutine ofwel de RTS-instructie. Het relevante ASM-schema bij deze instructie staat in Figuur 6.14(b). Hiervoor dienen twee bewerkingen tegelijk worden uitgevoerd: RF[s1] ← RF[s1]-1 en PC ← Mem[RF[s1]-1]. Een terugkeer-instructie heeft veel gemeen met een sprong naar een subroutine. Toch is er een fundamenteel verschil: het geheugenadres wordt bepaald door een verschil berekend in dezelfde klokcyclus. Dit verschil wordt berekend door de ALU. Het resultaat van de ALU dient niet enkel teruggeschreven worden naar de registerbank, maar moet ook op de adresbus worden aangelegd (om de waarde op te vragen die in de programmateller moet worden weggeschreven). Daarom voorzien we een tri-state buffer tussen de resultaat-bus en de adresbus. Het wegschrijven van de waarde van de programmateller is vervolgens de verantwoordelijkheid van de controller. De vereiste verbindingen in de controller werden reeds gerealiseerd. Groter dan (GT) en andere vergelijkingen Tot slot beschouwen we ´e´en van de overige instructies: de groter dan operatie (hoewel iedere operatie kan worden beschouwd). De vergelijker in het datapad is een algemene vergelijker die op basis van stuursignalen ´e´en van de voorwaarden bepaalt. De vergelijker vergelijkt de waarde in de registers RF[s1] en RF[s2]. Vermits hiervoor reeds operandbussen werden voorzien dienen we enkel verbindingen tussen de bussen en de ingangen van de vergelijker te voorzien. Verder dienen we vervolgens het resultaat in het statusregister weg te schrijven. We kunnen hiervoor een bit van de resultaatbus gebruiken. In dat geval dienen we echter een tri-state buffer te voorzien. Vermits het statusregister slechts ´e´en bit bijhoudt, is de vereiste verbinding slechts ´e´en bit breed. Daarom voorzien we een aparte verbinding vanuit de vergelijker naar het statusregister. De toestand van het statusregister vormt ook een signaal voor de controller (bijvoorbeeld bij een voorwaardelijk sprong). We kunnen andere condities testen door de stuursignalen van de vergelijker aan te passen. We beschouwen geen verdere overige instructies omdat deze geen nieuwe verbindingen introduceren. Deze instructies zetten of resetten immers registers, iets wat we kunnen realiseren met behulp van een multiplexer aan de ingang van het statusregister en met behulp van de reset-ingang bij verschillende registers. We bekomen dan ook het uiteindelijke datapad op Figuur 6.21. De 8086 Microprocessor Tot slot kijken we naar enkele populaire CISC-processoren: de 8086 microporocessor en de 8051 microcontroller. De structuur van deze processoren staat respectievelijk in Figuur 6.22 en Figuur 6.23. Vooral de 8086 is een populaire processor in computers en vormt de basis voor alle Intel CPU’s13 . Op de figuur staat een component waarvan de vorm nog niet werd ge¨ıntroduceerd: een trapezium met in het 13 Hoewel de verdere processoren bijvoorbeeld de bitlengte van de registers verder hebben opgedreven is de algemene structuur nog steeds dezelfde.
246
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
midden een inkeping wordt meestal gebruikt om een ALU aan te duiden. In het blokdiagram van Intel 8086 zien we twee ALU’s staan. De bovenste ALU rekent enkel het adres uit bij impliciete adressering en staat dan ook bekend als de adress adder. De onderste ALU voert verschillende bewerkingen uit zoals optellen, aftrekken, vermenigvuldigen,... Verer zien we onderaan links ook een registerbank. Deze registerbank houdt de acht registers van elk 16 bit. Vier van de registers: AX, BX, CX en DX kunnen verder worden opgedeeld als registers van 8-bit. De overige vier registers zijn registers met een speciaal doel: bijvoorbeeld SP houdt de stack pointer bij. Deze registers kan men dan ook niet aanwenden om eender welke instructie op toe te passen en de waarde wordt meestal impliciet aangepast. Onder de ALU zien we nog een register die de Operand Flags bijhoudt. Het is een 16 bit registers waarvan 9 bits dienstdoen om een voorwaarde met betrekking tot het resultaat berekend in de ALU bij te houden. Bijvoorbeeld als het resultaat van de ALU gelijk is aan 0 wordt de Zero Flag op 1 gezet. Het voordeel van dit register is dat men niet altijd eerst een expliciete vergelijk-instructie moet uitvoeren. Boven de central bus zijn we een andere registerbank. Deze registerbank houdt registers bij met betrekking tot de adressering zoals Instruction Pointer (IP) Code Segment (CS), Data Segment (DS), Extra Segment (ES) en Stack Segment (ES). Behalve de instructionpointer (het equivalent van de programmateller) valt de betekenis van de overige registers buiten het bereik van deze cursus. Men kan echter stellen dat ze nuttig zijn om het adres in een instructie uit te rekenen. Tot slot vinden we bovenaan centraal ook nog een registerbank. Deze registerbank noemen we de Instruction Queue. Het is een geheugen dat enkele instructies bevat die waarschijnlijk binnenkort zullen worden uitgevoerd. Door deze in een register te bewaren hoopt men geen wachttijden te introduceren om instructies uit het geheugen op te halen. Onder deze wachtrij bevindt zich ten slotte de controle-eenheid ofwel de controller die op basis van de instructie de gegevens op de juiste manier door de bussen laat stromen. De 8051 Microcontroller De 8051-microcontroller is in tegenstelling tot de Intel 8086 een Harvard-machine met een onderscheid tussen datageheugen en instructiegeheugen. In tegenstelling tot de 8086 waar enkel een rekeneenheid met registers wordt voorzien, voorziet de 8051 een rekeneenheid, geheugen, ROM-geheugen, Input-Output (I/O), interrupt logica en een timer. De processor werkt hoofdzakelijk met een woordlengte van 8-bit. Zo voorziet men een 8-bit ALU en 8-bit registers. De adresbus is echter 16-bit waardoor een groter geheugen kan worden uitgelezen. Wat opvalt is dat de processor zowel een klein RAM-geheugen voorziet van 128 bytes waar de programmagegevens in worden ondergebracht terwijl de chip ook over een grote hoeveelheid EPROM of ROM geheugen beschikt waar het programma in wordt ingelezen. EPROM kan slechts eenmalig worden beschreven. Het is dan ook de bedoeling om deze chip in een specifieke applicatie te gebruiken door er een programma in onder te brengen zonder hier later wijzigingen in aan te brengen. Verder kan men ook opmerken dat de chip voor verschillende speciale registers extra functionaliteit voorziet. Zo zien we een increment-operator die enkel dienst doet om de programmateller op te hogen.
6.3.4
Reduced Instruction Set Computer (RISC)
Ontwerp Het ontwerp van een RISC processor verloopt ongeveer gelijkaardig aan dat van een CISC processor. Een programma zal echter uit meer instructies bestaan dan bij een CISC processor, daarom is de klokfrequentie een zeer belangrijke factor. Pipelining vormt dan ook een zeer belangrijk aspect in de implementatie van een
6.3. PROCESSORONTWERP
247
RISC processor. Zo worden de instructies zelf in nagenoeg alle processoren uitgevoerd volgens het pipelining principe14 . Pipelining zal er meestal toe leiden dat men extra beperkingen op de instructieset plaatst. We denken bijvoorbeeld aan het feite dat de meeste instructies even lang zijn. Op de ARM7 processor worden bijvoorbeeld alle instructies voorgesteld met 32 bit (inclusief verplaats instructies). Door geen optioneel adresvelden te voorzien kan een instructie in ´e´en toestand worden opgehaald. Dit is belangrijk wanneer we bijvoorbeeld een instructie willen inlezen in ´e´en toestand. Met optionele velden toe te laten moeten we op basis van de instructie beslissen of we de programmateller verder ophogen. Dit verhindert echter dat we in de volgende toestand dus een nieuwe instructie kunnen ophalen. Ook de controller en het datapad zelf werken volgens het pipelining-principe. Dit is belangrijk omdat de pipeline in het geval van sprongbevelen bijvoorbeeld moet worden onderbroken. Andere instructiesets voorzien geen hardware om de pipeline te onderbreken maar een No-Operation instruction die tussen twee instructies kunnen worden geplaatst waardoor de tweede instructie wacht tot de eerste instructie volledig is uitgevoerd. De ARM7 Microprocessor Bij wijze van voorbeeld zullen we twee microprocessoren bespreken: de ARM7 en ARM11 microprocessor. Voor beide processoren zullen we de structuur bespreken samen met de instructieset en de vormen van pipelining die werden ge¨ımplementeerd. Figuur 6.24 beschrijft de structuur van een ARM7 processor. Op de figuur staan opnieuw enkele vormen die nog niet werden ge¨ıntroduceerd. Zo wordt een barrel shifter typisch voorgesteld aan de hand van een parallellogram en een vermenigvuldiger aan de hand van een zeshoek waarbij de linkse en rechtse knoop inwendige hoeken zijn. Net als in het geval van de Intel 8086 omvat de processor zelf geen RAM geheugen behalve enkele registers. Instructies en data worden dan ook uit een geheugen gelezen naast de ARM processor die verbonden is via een adresbus A[31:0] en een databus D[31:0]. De ARM7 processor omvat grofweg drie delen: een geheugeninterface: dit omvat het adresregister, de adres incrementer, en het write data register ; een rekenkundige eenheid met een registerbank, vermenigvuldiger, ALU en barrel shifter en de controle eenheid die de instruction pipeline en de instruction decoder omvat. De ARM11 Microprocessor
14 Zie
voorbeelden van de ARM7 en ARM11 microprocessor verder in deze subsectie.
248
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
111 110
RF[d] ← RF[s1]
100 011 010 001 000
Mem[RF[s1]] ← RF[s1]
IR11 IR10 IR9
101
Mem[RF[s1]+s2] ← RF[s1]
1 0
110 100 011 010 000 11 00
001 000 1 0
IR12
111 110 100 011 010
IR11 IR10 IR9
101 001 000
RF[d] ← Mem[Mem[PC]] PC ← PC+1
01
010
RF[d] ← Mem[Mem[Mem[PC]]] PC ← PC+1
10
011
RF[d] ← Mem[Mem[PC]+RF[s1]] PC ← PC+1
IR15 IR14
0
100
IR11 IR10 IR9
101
RF[d] ← Mem[RF[s1]]
1
110
RF[d] ← Mem[RF[s1]+s2]
IR13
111
RF[d] ← RF[s1]
IR ← Mem[PC] PC ← PC+1
001
Mem[Mem[PC]] ← RF[s1] PC ← PC+1
IR11 IR10 IR9
101
Mem[Mem[Mem[PC]]] ← RF[s1] PC ← PC+1
IR12
111
Mem[Mem[PC]+RF[s1]] ← RF[s1] PC ← PC+1
RF[d] ← Mem[PC] PC ← PC+1
Figuur 6.8: Het instructieset-stroomschema van de CISC processor.
6.3. PROCESSORONTWERP
249
S0
PC ← PC + 1 IR ← Mem [PC]
IR ← Mem[PC] PC ← PC + 1
S1 IR15
IR15 IR14 11
10
01
00
IR14 IR13
IR13 IR12 11
10
01
00
IR12 RF [d] ← RF [s1] n
RF[d] ← RF[s1]>>N
(a) Stroomschema.
(b) Tussentoestand.
Figuur 6.9: Stroomschema naar ASM-schema voor de ASR-instructie.
IR ← Mem[PC] PC ← PC + 1
S0
IR15 IR14 11
10
01
PC ← PC + 1 IR ← Mem [PC]
S1
00
IR15 IR13 1
IR14
0
IR13 IR12 1
IR11
0
IR12 IR10
IR11 IR10 IR9 111
110
101
100
011
010
001
000
RF[d] ← Mem[PC] PC ← PC + 1
(a) Stroomschema.
IR9
PC [d] ← Mem [P C] PC ← PC + 1 (b) ASM-schema.
Figuur 6.10: Stroomschema naar ASM-schema voor de LOAD constante-instructie.
250
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
S0
IR ← Mem[PC] PC ← PC + 1
PC ← PC + 1 IR ← Mem [PC]
S1 IR15
IR15 IR14 11
10
01
IR14
00
IR13 IR13 1
IR11
0
IR12 IR10
IR12 1
IR9
0
AR ← Mem [P C] PC ← PC + 1
IR11 IR10 IR9 111
110
101
100
011
010
001
000
RF[d] ← Mem[Mem[PC]] PC ← PC + 1
(a) Stroomschema.
S2
RF [d] ← Mem [AR]
(b) Tussentoestand.
Figuur 6.11: Stroomschema naar ASM-schema voor de LOAD direct-instructie.
6.3. PROCESSORONTWERP
251
S0
IR ← Mem[PC] PC ← PC + 1
PC ← PC + 1 IR ← Mem [PC]
S1 IR15
IR15 IR14 11
10
01
IR14
00
IR13 IR13 1
IR11
0
IR12 IR10
IR12 1
IR9
0
AR ← Mem [P C] PC ← PC + 1
IR11 IR10 IR9 111
110
101
100
011
010
001
000
RF[d] ← Mem[Mem[Mem[PC]]] PC ← PC + 1
(a) Stroomschema.
S3
AR ← Mem [AR]
S4
RF [d] ← Mem [AR]
(b) Tussentoestand.
Figuur 6.12: Stroomschema naar ASM-schema voor de LOAD indirect-instructie.
252
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
S0
PC ← PC + 1 IR ← Mem [PC]
S1 IR15 IR14
IR ← Mem[PC] PC ← PC + 1
IR13 IR12
IR15 IR14 11
10
01
00
AR ← Mem [PC] PC ← PC + 1 IR13 IR12 11
10
01
00
S5
Mem[RF[s1]] ← PC + 1 RF[s1] ← RF[s1] + 1 PC ← Mem[PC]
(a) Stroomschema.
Mem [RF [s1]] ← PC RF [s1] ← RF [s1] + 1 PC ← AR (b) Tussentoestand.
Figuur 6.13: Stroomschema naar ASM-schema voor de JSR-instructie.
S0
IR ← Mem[PC] PC ← PC + 1
PC ← PC + 1 IR ← Mem [PC]
S1 IR15 IR14
IR15 IR14 11
10
01
00
IR13 IR12
IR13 IR12 11
10
01
00
RF[s1] ← RF[s1] − 1 PC ← Mem[RF[s1]]
(a) Stroomschema.
RF [s1] ← RF [s1] − 1 PC ← Mem [RF [s1] − 1] (b) Tussentoestand.
Figuur 6.14: Stroomschema naar ASM-schema voor de RTS-instructie.
6.3. PROCESSORONTWERP
253
SS
CS
Next State Logic LIFO CI
PC
Mem
IR
+1
CO Output Logic
Figuur 6.15: Het ontwerp van een CISC-controller met programmateller, geheugen en instructieregister.
SS
CS
LIFO CI
PC +1
Mem
IR
Next State & Output Logic FSM
CO
Figuur 6.16: Het ontwerp van een CISC-controller met interne eindige toestandsautomaat.
254
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
SS
CI
+1
CS
PC
Mem
IR
Next State & Output Logic FSM
CO
Figuur 6.17: Controller met samengevoegd geheugen en stapelgeheugen.
SS
+1
CI
CS
PC
IR
Next State & Output Logic FSM
Adresbus Databus
Mem Data & Prog. Figuur 6.18: Controller met extern geheugen (Von Neumann-architectuur).
CO
6.3. PROCESSORONTWERP
255
RF 8 × 16
AR
Status
Shift
ALU
Comp
Adresbus Databus
Mem Data & Prog. Figuur 6.19: De basis datapad-ontwerp van de CISC-processor.
SS
CI
+1
CS
PC
IR
Next State & Output Logic FSM
Adresbus Databus
Mem Data & Prog. Figuur 6.20: De uiteindelijke controller van de CISC-processor.
CO
256
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
RF 8 × 16
AR
Status
Shift
ALU
Comp
Adresbus Databus
Mem Data & Prog. Figuur 6.21: Het datapad-ontwerp na het aanbrengen van verbindingen van de CISC-processor.
6.3. PROCESSORONTWERP
257
Memory Interface
Vcc Vss
CS DS SS ES IP
AH AL BH BL CH CL DH DL SP BP SI DI
I6 I5 I4 I3 I2 I1
Control Unit
Operands Flags
Figuur 6.22: De structuur van de 8086 microprocessor.
258
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
P0.0-P0.7
Vcc Vss
RAM Address Register
RAM
Port 0 Drivers
Port 2 Drivers
Port 0 Latch
Port 2 Latch
EPROM/ ROM
Program Address Register
Stack Pointer
ACC
B Register
P2.0-P2.7
TMP2
TMP1
Buffer Interrupt, Serial Port, and Timer Blocks
PC Increment
Program Counter
PSW
ALE/PROG* EA*/PP
Time and Control
RST
Instruction Register
PSEN*
Oscillator
1 2 AL TAL XT X
DPTR
Port 1 Latch
Port 3 Latch
Port 1 Drivers
Port 3 Drivers
P1.0-P1.7
P3.0-P3.7
Figuur 6.23: De structuur van de 8051 microcontroller.
6.3. PROCESSORONTWERP
259
A[31:0] ALE
ABE
Vcc Vss
Scan Control
Adress Register
Address Incrementer
Register bank (31 × 32-bit registers) (6 status registers)
Instruction Decoder & Control Logic
Multiplier
Barrel shifter
Instruction Pipeline & Read Data Register & Thumb Instruction Decoder
Write Data Register
ENOUT*
ENIN*
DBGRQI BREAKPT DBGACK ECLK EXEC* ISYNC BL[3:0] APE MCLK WAIT* RW* MAS[1:0] IRQ* FIQ* RESET* ABORT TRANS* MREQ* OPC* SEQ LOCK CPI* CPA CPB M*[4:0] TBE TBIT HIGHZ
D[31:0]
DBE
Figuur 6.24: De structuur van de ARM7 microprocessor.
Figuur 6.25: De pipelining-structuur van de ARM11 microprocessor.
260
HOOFDSTUK 6. PROGRAMMEERBARE PROCESSOREN
Deel IV
Very High Speed Integrated Circuit Hardware Description Language
261
Hoofdstuk 7
VHDL “ In redelijke taal weerklinkt wat in werkelijkheid gebeurt.
- Gerard Bolland, Nederlands taalkundige en filosoof (1854-1922)
”
VHDL is een taal waarmee hardware kan worden beschreven. Het wordt gebruikt om elektronische schakelingen te genereren, simuleren, analyseren, enzovoort. 7.1
7.2
7.3
7.4
7.5 7.6
Elementen van de VHDL-taal . . . . . . . . . . . . . . . 7.1.1 Lexicale elementen (woordenschat) . . . . . . . . . . . . 7.1.2 Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1.3 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1.4 scheidingstekens . . . . . . . . . . . . . . . . . . . . . . 7.1.5 Commentaar . . . . . . . . . . . . . . . . . . . . . . . . Typesysteem . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.1 Voorgedefinieerde types . . . . . . . . . . . . . . . . . . 7.2.2 Zelf types defini¨eren . . . . . . . . . . . . . . . . . . . . Defini¨eren met opsomming . . . . . . . . . . . . . . . . Defini¨eren met subtypering . . . . . . . . . . . . . . . . Defini¨eren van fysische types . . . . . . . . . . . . . . . Defini¨eren van matrices en vectoren (“array aggregate”) Objecten . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.1 Constante . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.2 Variabele . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3.3 Signaal . . . . . . . . . . . . . . . . . . . . . . . . . . . Logische signalen . . . . . . . . . . . . . . . . . . . . . . Bewerkingen . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.1 Logische bewerkingen . . . . . . . . . . . . . . . . . . . 7.4.2 Rekenkundige bewerkingen . . . . . . . . . . . . . . . . 7.4.3 Schuifoperaties . . . . . . . . . . . . . . . . . . . . . . . 7.4.4 Vergelijkingen . . . . . . . . . . . . . . . . . . . . . . . . 7.4.5 “Array aggregaat” bewerkingen . . . . . . . . . . . . . . Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . Combinatorische schakelingen in VHDL . . . . . . . . .
263
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
264 264 264 265 265 266 266 266 266 267 268 269 269 270 271 271 272 273 275 275 276 276 276 276 277 277
264
HOOFDSTUK 7. VHDL 7.6.1
Hardwarebeschrijving met VHDL . . . . . . . Structurele beschrijving . . . . . . . . . . . . Gedragsbeschrijving . . . . . . . . . . . . . . Repetitieve structuren . . . . . . . . . . . . . 7.7 Sequenti¨ ele schakelingen in VHDL . . . . . . 7.8 Processoren in VHDL . . . . . . . . . . . . . . 7.8.1 Leidend voorbeeld: sha1 checksum . . . . . . Algoritme . . . . . . . . . . . . . . . . . . . . VHDL-proces . . . . . . . . . . . . . . . . . . 7.9 VHDL grammatica . . . . . . . . . . . . . . . 7.10 Programmeerjargon . . . . . . . . . . . . . . .
7.1
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
278 278 278 278 278 278 278 279 279 280 281
Elementen van de VHDL-taal
In deze sectie bespreken we de verschillende elementen van de VHDL-taal. Een opsomming van de mogelijke sleutelwoorden en andere karaktersequenties met hun betekenis wordt doorgaans de “syntax” van de taal genoemd. In deze sectie lichten we de verschillende sleutelwoorden toe. In de rest van dit hoofdstuk zullen we dan de betekenis (ofwel “semantiek”) bespreken.
7.1.1
Lexicale elementen (woordenschat)
Elk code-bestand1 bestaat uit een sequentie van lexicale elementen die men tokens noemt. We zullen eerst de verschillende lexicale elementen die in VHDL-code kunnen voorkomen beschrijven. Deze kunnen we dan als terminologie gebruiken. De tokens kunnen verder worden onderverdeeld in: literals (deze vertegenwoordigen bepaalde waardes zoals getallen, tekst,...), identifiers (dit zijn namen van variabelen, functies, componenten,... gebruikt om naar te refereren en defini¨eren), scheidingstekens2 (haakjes en andere symbolen die waardes en identifiers combineren) en commentaar. We beschrijven de verschillende soorten tokens verder in de volgende subsecties.
7.1.2
Literals
We onderscheiden vier soorten literals: getallen, karakters, karakterreeksen en bitreeksen. We overlopen de verschillende types. In VHDL is er ook nog sprake van enumeration literals en van de NULL literal, deze literals worden niet beschouwd. Getal Een getal (ook wel “abstract literal” genoemd) is een numerieke waarde. Net als bij programmeertalen onderscheid men verschillende soorten numerieke waarden: • universal integer: dit zijn numerieke literals die geen decimale komma (.) bevatten, bijvoorbeeld 1425. Deze getallen zijn vergelijkbaar met het int-type in Java3 . • universal real: dit zijn numerieke getallen die wel een decimale komma bevatten. Bijvoorbeeld 1425.1917. Merk op dat indien er enkel nullen achter de komma staan dat het getal dezelfde waarde heeft als een universal integer: 1425.0, maar daarom niet dezelfde representatie. In Java zouden we dit type voorstellen met bijvoorbeeld een float of double. • physical types: dit zijn fysische waarden. Fysische waarden bestaan uit een getal gevolgd door een fysische eenheid. Er wordt een spatie tussen het getal en de eenheid gezet. Bijvoorbeeld: 1818 ns. Dit type heeft geen echt equivalent in de meeste programmeertalen. Immers redeneren programmeertalen meestal niet over grootheden. 1 Onafhankelijk
van de taal. delimiters. 3 De vergelijking gaat echter niet geheel op: een int is immers beperkt tot 32 bit en heeft een specifieke representatie. 2 Engels:
7.1. ELEMENTEN VAN DE VHDL-TAAL
265
Getallen worden standaard in decimale notatie uitgedrukt. Men kan ze ook in exponenti¨ele vorm schrijven door het toevoegen van een ’E’ of ‘e’ op het einde van het getal gevolgd door de exponent, bijvoorbeeld: 14e2. Om een andere basis te gebruiken, wordt volgend formaat gebruikt: base#literal#exp, met de basis tussen 2 en 16. Zo kunnen we 1425 schrijven als 16#591#, of 4864 als 16#13#E2. Tot slot mag men ook vrij underscores ( ) toevoegen in een getal om de code leesbaar te houden. Bijvoorbeeld: 19_171_425. Karakter Een karakter (ofwel “character literal”) slaat een karakter (ofwel character) op: de eenheid van tekst. Deze literals worden tussen enkele aanhalingstekens (’) geplaatst, bijvoorbeeld ’K’. In Java zou het equivalent van dit type een char zijn. Karakterreeks Een karakterreeks (ofwel “string literal”) slaat een sequentie karakters op, dus een tekstfragment. In Java noemt men een dergelijk type een String. Deze reeks wordt tussen dubbele aanhalingstekens (") geplaatst, bijvoorbeeld "Hello World!". Een probleem doet zich voor wanneer we de dubbele aanhalingstekens (") zelf in het tekstfragment willen gebruiken. In dat geval dienen we de aanhalingstekens dubbel te plaatsen, bijvoorbeeld: """The answer?"" said Deep Thought. ""The answer to what?"""[?, §25] Bitreeksen Een bitreeks (ofwel “bit string literal”) is een sequentie aan bits (dit is een eenheid van informatie die ofwel 0 ofwel 1 is). Een bitreeks wordt geschreven als een sequentie van enen en nullen tussen dubbele aanhalingstekens ("). Zoals we al vroeger in deze cursus hebben opgemerkt is zo’n sequentie niet effici¨ent, leesbaar en praktisch. Daarom laat men ook octale en hexadecimale notatie toe. Hiertoe wordt er een B (binair), O (octaal) of X (hexadecimaal) voor de dubbele aanhalingstekens geplaatst om de bitreeks in een bepaald formaat te lezen. Bij hexadecimale getallen gebruikt men a, b, c, d, e en f om respectievelijk 10 tot 15 voor te stellen. Net als bij getallen kan de gebruiker underscores ( ) toevoegen om tot meer leesbare code te komen.
7.1.3
Identifiers
Een identifier is een referentie naar een variabele, functie, component,... Dit is vergelijkbaar met de naam van een variabele, methode, klasse,... in Java. Identifiers beginnen met een letter en mogen letters en cijfers bevatten. Ook de underscore ( ) teken is toegelaten, indien dit niet het eerste of laatste karakter van de identifier vormt. Identifiers zijn niet hoofdletter gevoelig. In VHDL’93 wordt het begrip van een identifier verder uitgebreid. Deze uitbreiding wordt hier niet beschouwd. Voor meer details [?, p. 4]. Gereserveerde woorden Niet alle namen die aan de hierboven beschreven regels mag men zelf gebruiken. Sommige identifiers zijn immers sleutelwoorden die een reeds ingebouwde functie vevullen in VHDL: ze verwijzen naar functies die in de VHDL compiler zijn ingebakken. De woorden in Tabel 7.1 mogen niet gebruikt worden als identifiers. We onderscheiden verschillende soorten sleutelwoorden: enerzijds zijn er compiler-directieven zoals bijvoorbeeld case en downto, daarnaast zijn er basis-operaties zoals nand en sla, tot slot zijn er ook typedirectieven zoals array en signal. Sommige gereserveerde worden werden pas ge¨ıntroduceerd in VHDL’93, we gaan hier niet verder op in.
7.1.4
scheidingstekens
Een scheidingsteken (ofwel “delimiter”) tenslotte wordt gebruikt om operaties op gegevens uit te voeren, bijvoorbeeld een optelling maar ook een index. De scheidingstekens van VHDL worden weergegeven in Tabel 7.2. We onderscheiden opnieuw verschillende soorten scheidingstekens: tekens die operaties voorstellen (zoals + en *), tekens die voorwaarden voorstellen (zoals <>), tekens die tekst afbakenen (zoals ( en [) en tekens die aangeven dat twee fragmenten los van elkaar staan (zoals ,).
266
HOOFDSTUK 7. VHDL
abs array bus else function in literal nor others pure return sla transport wait
access assert case elsif generate inertial loop not out range rol sll type when
after attribute component end generic inout map null package record ror sra unaffected while
alias begin configuration entity group is mod of port register select srl units with
all block constant exit guarded label nand on postponed reject severity subtype until xnor
and body disconnect file if library new open procedure rem shared then use xor
architecture buffer downto for impure linkage next or process report signal to variable
Tabel 7.1: Gereserveerde woorden in VHDL. & + : | :=
’ , ; [ /=
( < ] >=
) . = => <=
* / > ** <>
Tabel 7.2: Scheidingstekens in VHDL.
7.1.5
Commentaar
Commentaar zijn delen van de code die genegeerd worden door de VHDL-compiler, maar die nuttig zijn voor programmeurs: ze bevatten gegevens over het project en richtlijnen die een belangrijke rol kunnen hebben tijdens het project. Commentaar plaatst men na twee horizontale strepen -- en reikt tot het einde van de lijn. Dit is vergelijkbaar met de dubbele slash (//) in Java.
7.2
Typesysteem
VHDL is getypeerd: een variabele slaat data op volgens een bepaald type, dit type geeft een interpretatie aan zowel de data en de operatoren die erop gedefinieerd zijn. De types kunnen bovendien door de programmeur uitgebreid worden. Men vertrekt echter steeds van basistypes.
7.2.1
Voorgedefinieerde types
Ook in de VHDL-secties werden sommige van deze types reeds gebruikt. Tabel 7.2(a) geeft een overzicht van de meest populaire basistypes. Naast deze reeks van basistypes bevat VHDL ook standaard enkele afgeleide types. Het zijn types die een gereduceerd bereik uit de basistypes vertegenwoordigen. Deze subtypes staan in Tabel 7.2(b) samen met hun gereduceerd bereik.
7.2.2
Zelf types defini¨ eren
Hoe defini¨eren we nu zelf types? Afhankelijk van het soort type dat we willen bouwen zijn er verschillende mogelijkheden: • opsomming;
7.2. TYPESYSTEEM
267 (a) Overzicht van belangrijke types in VHDL.
Type
Bereik
Operatoren (prioriteit)
INTEGER
−2 147 483 647 tot 2 147 483 647
REAL
−1.0E38 tot 1.0E38
TIME
−2 147 483 647 tot 2 147 483 647 fs, ps, ns, us ms, sec, min, hr
BIT
‘0‘ of ‘1‘
BIT VECTOR
onbegrensde rij BIT
CHARACTER STRING
256 karakters (ASCII) onbegrensde rij van CHARACTERs
ABS, ** *, /, MOD, REM + (unair), - (unair) + (binair), - (binair) =, /=, <, <=, >, >= ABS, ** *, / + (unair), - (unair) + (binair), - (binair) =, /=, <, <=, >, >= ABS *, / + (unair), - (unair) + (binair), - (binair) =, /=, <, <=, >, >= NOT =, /=, <, <=, >, >= AND, NAND, OR, NOR, XOR, XNOR NOT & SLL, SRL, SLA, SRA, ROL, ROR =, /=, <, <=, >, >= AND, NAND, OR, NOR, XOR, XNOR
(b) Overzicht van belangrijke afgeleide types in VHDL.
Type
Bereik
NATURAL POSITIVE DELAY LENGTH
0 tot INTEGER’HIGH 1 tot INTEGER’HIGH 0 fs tot TIME’HIGH
Operatoren (prioriteit) equivalent aan INTEGER equivalent aan INTEGER equivalent aan TIME
Tabel 7.3: Overzicht van belangrijke types en afgeleide types in VHDL. • subtypering (beperk het bereik); • fysische types; en • Afgeleide types met matrices en vectoren. De lijst is niet exhaustief: VHDL bevat ook constructies om bijvoorbeeld records aan te maken, deze constructies vallen buiten het bereik van deze cursus. We bespreken de verschillende methodes nu in meer detail. Defini¨ eren met opsomming We kunnen een type specificeren door alle mogelijke toestanden op te sommen. Deze methode wordt toegepast voor bijvoorbeeld de types bit en byte. De namen of karakters die de toestand bepalen worden tussen haakjes opgesomd na het sleutelwoord is. Dit doen we na het sleutelwoord type en de identifier voor het type. VHDL-code 7.1 toont mogelijke definities van bit en byte. We defini¨eren ook het type StateMachine, dit type bevat drie elementen: start, processing en wait die de “toestanden” weergeven van een schakeling die we bijvoorbeeld zouden kunnen willen bouwen.
268
HOOFDSTUK 7. VHDL
VHDL-code 7.1 Defini¨eren van types door opsomming. 1 type b i t i s ( ’ 0 ’ , ’ 1 ’ ) ; 2 type b o o l e a n i s ( f a l s e , t r u e ) ; 3 type S t a t e M a c h i n e i s ( s t a r t i n g , p r o c e s s i n g , w a i t i n g ) ;
In Java is de enum de dichtste imitator van het defini¨eren van types aan de hand van opsomming. Immers is het aantal waarden die een enum kan aannemen beperkt. VHDL is echter wel niet (sterk) objectgericht, dus deze analogie gaat slechts gedeeltelijk op. Defini¨ eren met subtypering Soms wensen we een type te specificeren die een deelverzameling omvat van een reeds eerder gespecificeerd type. Zo zal een integer alle waarden omvatten die met 32 bit voor te stellen zijn, het is echter mogelijk dat we bijvoorbeeld een type byte willen specificeren die uitsluitend numerieke waarden bevat die we op 8 bit kunnen voorstellen. In dat geval gebruiken we het sleutelwoord subtype gevolgd door een identifier die de naam van het type aanduidt, daarna volgt opnieuw het sleutelwoord is en het “supertype”. VHDL kent twee soorten beperkingen die hierop kunnen volgen: de “range beperking” en de “index beperking”. Een “range beperking” omvat twee literals die het begin en het einde markeren van een bereik van waarden. Vermits alle basistypes in VHDL een inherente orde-relatie hebben4 is dit voldoende om altijd alle waarden tussen de twee gegeven waarden mee in het bereik te nemen. Syntactisch definieert men een range beperking met het sleutelwoord range gevolgd door de laagste waarde gevolgd door het sleutelwoord to gevolgd door de hoogste waarde. Voor vectoren kan men gebruik maken van de “index constraint”. Deze beperking zet voorwaarden op het bereik van de index van de vector. Syntactisch schrijven we tussen haakjes respectievelijk de laagste of hoogste waarde gevolgd door respectievelijk het sleutelwoord to of downto en daarna respectievelijk de hoogste of laagste waarde. In VHDL hoeft men geen getal als index te gebruiken: ook karakters kunnen bijvoorbeeld voor dit doel worden aangewend. Bovendien is het mogelijk dat een lijst multidimensionaal is en er dus verschillende indices moeten beperkt. In dat geval worden de indices gescheiden door komma’s. Omdat deze cursus slechts een inleiding tot VHDL wil geven zullen we deze uitzonderlijke situaties niet verder beschouwen. We verwijzen dan ook naar [?]. VHDL-code 7.2 lijkt enkele definities van types op aan de hand van subtypering. Zo defini¨eren we de byte aan de hand van een integer en het type lowercase is een deelverzameling van de character. Tot slot defini¨eren we ook een type InputVector die een sequentie bits voorstelt waarvan de index loopt van 7 tot 3. VHDL-code 7.2 Defini¨eren van types door subtypering. 1 subtype b y t e i s i n t e g e r range 0 to 2 5 5 ; 2 subtype l o w e r c a s e i s c h a r a c t e r range ’ a ’ to ’ z ’ ; 3 subtype I n p u t V e c t o r i s b i t v e c t o r ( 7 downto 3 ) ;
Er bestaan in Java geen duidelijk equivalent van definities aan de hand van subtypering. Natuurlijk kan men wel subklassen defini¨eren met behulp van het sleutelwoord extends, maar in Java heeft men de mogelijkheid extra velden toe te voegen. De beste analogie is misschien een speciale constructor die bij aanmaak van een object na zal gaan of de gewenste waarde wel degelijk mogelijk is. 4 Voor
karakters maakt men gebruik van de ASCII-code.
7.2. TYPESYSTEEM
269
Defini¨ eren van fysische types Soms dienen we ook te werken met fysische types: types met een zekere eenheid. Zo is de periode van het kloksignaal een tijdsverschil die we dienen uit te drukken in een zekere tijdseenheid. VHDL ziet fysische eenheden eerder als getallen, maar met bijgevoegde constanten die de “eenheden” vormen. Zo kan men bijvoorbeeld gewicht defini¨eren als een getal tussen 0 en 10 0000 000 met drie eenheden: de gram, de kilogram en de ton. VHDL-code 7.3 toont aan de hand van voorbeelden hoe we een fysische eenheid defini¨eren. We vermelden opnieuw het sleutelwoord type gevolgd door de identifier van het type. Daarna bakenen we het type af aan de hand van een “range beperking”, in een units blok defini¨eren we vervolgens de eenheden als “virtuele constanten”. Het eenheden-blok bestaat altijd uit minstens ´e´en eenheid-identifier: de “primaire eenheid”. De primaire eenheid heeft altijd een waarde gelijk aan 1 en specificeert bijgevolg ook meteen de nauwkeurigheid. Zo kunnen we in het voorbeeld geen gewichten voorstellen met een nauwkeurigheid van een microgram: immers drukken we elk gewicht uit in gram. Daarna volgen optioneel andere eenheden, deze eenheden gaan altijd gepaard met een toekenning van een reeds gekende eenheid. Zo is bijvoorbeeld een kilogram het equivalent van 10 000 gram. VHDL zal al deze eenheden doorrekenen als constanten. Een ton krijgt dus de waarde 10 0000 000. Een code-blok wordt be¨eindigd met het end sleutelwoord waarna het soort blok wordt herhaald. VHDL-code 7.3 Defini¨eren van fysische types. 1 type Weight i s range 0 to 1 0 0 0 0 0 0 0 2 units 3 gr ; 4 kg = 1000 g r ; 5 ton = 1000 kg ; 6 end units ; 7 8 type D i s t a n c e i s range 0 to 10 0 0 0 0 0 0 0 0 0 9 units 10 pm ; 11 nm = 1000 pm ; 12 um = 1000 nm ; 13 mm = 1000 um ; 14 end units ;
Er is opnieuw geen echt equivalent in Java. Men kan natuurlijk ook constanten defini¨eren en deze bijvoorbeeld gr en kg noemen. Fysische types zijn echter meer getallen waar men een soort afspraak maakt hoe deze getallen een fysische grootheid zullen voorstellen. Defini¨ eren van matrices en vectoren (“array aggregate”) Tot slot kunnen we ook types ook verder gebruiken bij de constructie van vector- en matrix-types. Dit hebben we bovendien al eerder gedaan: de bit vector is een array aggregate van het basistype bit. VHDL kent twee soorten vector-types: begrensde (“constrained”) en ongebonden (“unconstrained”). In het geval van een begrensde vector wordt het aantal elementen gespecificeerd samen met het type5 , terwijl in het geval van een ongebonden vector er geen beperking op de index wordt gezet. 5 Dus
niet bij de declaratie van een object van dat type.
270
HOOFDSTUK 7. VHDL
In het geval van begrensde vectoren specificeren we het type met het sleutelwoord type gevolgd door de identifier van het type. Daarna schrijven we is array daarna volgt de “index beperking” (zie eerder) en het sleutelwoord of tot slot dienen we ook het basistype te specificeren. Zoals reeds eerder gezegd hoeft een “index beperking” niet altijd te slaan op een bereik van een numerieke index. In VHDL-code 7.4 geven we twee voorbeelden. In het eerste geval gebruiken we een numerieke index. In het tweede geval maken we gebruik van het eerder ge¨ıntroduceerde type StateMachine (zie VHDL-code 7.1), vermits een opsomming beperkt is in lengte de vector dit bijgevolg ook. Wanneer we meerdimensionale vectoren willen specificeren scheiden we de verschillende indices aan de hand van een komma (,). In het geval van een onbegrensde vector schrijven we als “index beperking” de identifier van een (eerder gedefinieerd) type gevolgd door het range sleutelwoord en daarna het <> scheidingsteken. Een voor de hand liggend type om te gebruiken als index is het natural type: de natuurlijke getallen zoals dit ook als index in Java wordt gebruikt. Onbegrensde vectoren worden meestal als associatieve lijsten opgeslagen: enkel wanneer een index wordt toegekend wordt deze opgeslagen6 . Men kan natuurlijk ook combinaties maken van begrensde en onbegrensde indices: bijvoorbeeld een matrix waar de eerste index begrensd is maar de tweede niet. Op VHDL-code 7.4 tonen we een voor de hand liggende declaratie van een onbegrensde vector van real objecten. VHDL-code 7.4 Defini¨eren van matrix types. 1 2 3 4 5 6
−− Begrensd type word i s array ( 1 5 downto 0 ) of b i t ; type AConstrainedArray i s array ( StateMachine , 1 to 3 ) of b i t ; −− Onbegrensd type AnUnconstrainedArray i s array ( n a t u r a l range <>) of r e a l ;
Er bestaat geen equivalentie in Java. Men kan argumenteren dat het declareren van een array een vaste lengte heeft en dus zou kunnen overeenkomen met een begrensde array. Deze begrenzing manifesteert zich echter op instantie-niveau en niet op type-niveau. Wanneer we deze analogie wel zouden gebruiken kan een onbegrensde vector worden gezien als een HashMap.
7.3
Objecten
Types beschrijven enkel het soort waarden die een object (ofwel instantie) kunnen voorstellen. Types zijn daarom nuttig omdat de VHDL-compiler consistentie kan controleren. Een programma werkt echter in de eerste plaats met objecten. Een object is een benoemd item (aan de hand van een identifier) met een specifieke waarde. We onderscheiden 3 soorten objecten: 1. constante: een object met een vaste waarde. Deze waarde wordt ´e´enmaal ergens in het programma bepaald en kan in de rest van de code gebruikt worden; 2. variabele: een object met een waarde die kan veranderen doorheen het programma. Een variabele verandert meteen van waarde en heeft dus geen echte band met de “werkelijkheid”; en 3. signaal: een object die de toestand van een draad, in- of uitgang of een andere fysische toestand voorstelt. De waarde verandert enkel nadat er een zekere tijd is verstreken. We bespreken de verschillende soorten objecten hieronder in meer detail samen met de bijbehorende syntax en semantiek. 6 Indien
de index immers niet begrensd is zou men anders oneindig veel geheugen nodig hebben om zo’n lijst op te slaan.
7.3. OBJECTEN
7.3.1
271
Constante
Constanten worden gebruikt om aan een ontwerp parameters toe te kennen. Stel dat we bijvoorbeeld een processor wensen te ontwerpen, maar nog niet bepaald hebben hoe groot het operand gedeelte van de operand in een instructie moet worden, kunnen we hiervoor een constante toekennen. Wanneer we dan later van operandgrootte willen veranderen, dienen we enkel de constante aan te passen. Constanten zijn dus benoemde waarden die door de VHDL-compiler op alle plaatsen waar de constante wordt aangeroepen zullen worden vervangen door de werkelijke waarde. We specificeren een constante aan de hand van het constant sleutelwoord, vervolgens specificeren we de naam en het type. We plaatsen het : tussen de naam en het type. Na het := scheidingsteken plaatsen we een waarde of een expressie. Het algemene formaat is dus: constant identifier : type := expressie;
(7.1)
In plaats van een waarde kunnen we ook een expressie specificeren. In zo’n expressie mogen we waarden en constanten schrijven en operaties hiertussen. Het gebruik van variabelen is natuurlijk niet toegelaten vermits de waarde van deze variabelen niet op voorhand gekend is en kan veranderen. VHDL-code 7.5 Defini¨eren van constanten. 1 constant p i : r e a l := 3 . 1 4 1 5 9 2 6 5 ; 2 constant b y t e l e n g t h : n a t u r a l := 8 ; 3 constant w o r d l e n g t h : n a t u r a l := 4∗ b y t e l e n g t h ;
VHDL-code 7.5 toont enkele voorbeelden van constante-declaraties. Zo defini¨eren we pi en byte length aan de hand van waarden, word length wordt gedefini¨eerd aan de hand van een expressie waarin zowel een waarde en een constante betrokken zijn.
7.3.2
Variabele
Een variabele is een VHDL-object die wel van waarde kan veranderen. Ze worden tijdens de uitvoer gebruikt door de VHDL-compiler, bijvoorbeeld om te bepalen hoeveel klokflanken een component moet wachten alvorens weer van waarde te veranderen, of wanneer de compiler bijvoorbeeld een tweede maal door de een lus gaat ander gedrag te bewerkstelligen. Omdat een variabele van waarde kan veranderen zijn er twee soorten toekenningen: de “declaratie” en de “assignatie”. Bij de declaratie stelt men de variabele voor samen met een type en optioneel een initi¨ele waarde, bij de assignatie geeft met de variabele een nieuwe waarde. Bij de declaratie gebruikt men het sleutelwoord variable gevolgd door de naam van de variabele, het : scheidingsteken en het type van de variabele. Optioneel voegt men hierna nog het := scheidingsteken toe met een expressie de de eerste waarde voor de variabele oplevert. Een algemeen formaat7 is dus: variable identifier : type [:= expressie];
(7.2)
Bij de assignatie kent men een nieuwe waarde toe. Dit doet men door de identifier van de variabele te vernoemen gevolgd door het := scheidingsteken en een expressie voor de nieuwe waarde, of formeler: identifier := expressie; 7 Delen
van de formaat-declaratie die tussen vierkante haken staan zijn optioneel.
(7.3)
272
HOOFDSTUK 7. VHDL
Voorbeelden van werken met variabelen staan in VHDL-code 7.6. In de code wordt de declaratie van index getoond zonder directe assignatie. Later kennen we achtereenvolgens 0 en 1 toe aan index. We declareren ook twaalf en geven deze variabele de waarde 12. We declareren ook viertwee die de waarde 42 krijgt8 . tenslotte hogen we index voor de laatste keer op. VHDL-code 7.6 Werken met variabelen. 1 2 3 4 5 6
variable i n d e x := i n d e x := variable variable i n d e x :=
7.3.3
index : i n t e g e r ; 0; index + 1 ; t w a a l f : n a t u r a l := 1 2 ; v i e r t w e e : n a t u r a l := 4∗ t w a a l f −6∗ i n d e x ; index + 1 ;
−−d e c l a r a t i e −−a s s i g n a t i e −−a s s i g n a t i e −−d e c l a r a t i e met a s s i g n a t i e −−d e c l a r a t i e met a s s i g n a t i e −−a s s i g n a t i e
Signaal
Een signaal ten slotte is het VHDL-equivalent van een fysische verbinding of een groep van verbindingen in de hardware. Een toekenning bij een signaal is niet direct: de expressie wordt niet louter ge¨evalueerd. Wanneer de betrokken signalen waarop de toekenning steunt later veranderen, zal het signaal zelf ook veranderen. Een signaal wordt gedeclareerd door het sleutelwoord signal gevolgd door de identifier van het signaal en na een dubbele punt (:) het type van het signaal. Optioneel volgt ook een assignatie gedeelte, of formeler: signal identifier : type [<= expressie];
(7.4)
Bij een “assignatie” plaatsen we eerst de identifier van het object gevolgd door de <= operator en de expressie, of formeler: identifier <= expressie;
(7.5)
Zoals reeds eerder vermeld werkt de toekenning bij een signaal anders dan bij de toekenning van een variabele en constante. VHDL laat bovendien slechts ´e´en toekenning toe per signaal (die mogelijk uitgesteld kan worden en beslist op de waarde van variabelen). In het andere geval betekent dit immers dat een draad wordt aangestuurd door twee verschillende expressies en dus kortsluiting kan veroorzaken. Hoe we dit probleem kunnen oplossen bespreken we in deze sectie.
VHDL-code 7.7 Werken met signalen. 1 2 3 4 5
s i g n a l a : b i t <= ’ 1 ’ ; signal b : b i t ; signal y : b i t ; y <= a and b ; b <= ’ 0 ’ , ’ 1 ’ a f t e r 100 ns ;
−−D e c l a r a t i e met a s s i g n a t i e −−D e c l a r a t i e −−D e c l a r a t i e −−A s s i g n a t i e met e x p r e s s i e −−A s s i g n a t i e met t i j d b e p e r k i n g
In VHDL-code 7.7 beschouwen we drie signalen van het type bit: a, b en y. De signalen hebben dus ofwel de waarde ’0’ of ’1’. a kennen we de constante ’1’ toe. Het signaal blijft dus constant. Bij b kennen we de waarde ’0’ toe, maar na 100 nanoseconden wordt het signaal ’1’. Wanneer we y gelijk stellen aan een AND-operatie tussen a en b. Het signaal van y zal dus gelijk zijn aan ’0’, maar na 100 nanoseconden (en een zekere vertraging) wordt de waarde gelijk aan ’1’. 8 Op
dat moment heeft index nog de waarde 1.
7.3. OBJECTEN
273
Logische signalen We hebben reeds het type bit gedefinieerd. Dit type neemt twee waarden aan: ’0’ en ’1’, dit lijkt een ideaal type bij het werken met signalen. In de praktijk zijn deze waarden echter ontoereikend om hardware te beschrijven. In de cursus hebben we bijvoorbeeld al vaak de toestand “hoog impedant” aangehaald: een toestand waarbij de draad aan geen enkel deel van het circuit aangelegd wordt. Deze toestand wordt bijvoorbeeld gebruikt bij de realisatie van een bus. Om meer toestanden te kunnen voorstellen, werd IEEE 1164 opgesteld. Dit zijn de verschillende toestanden waarin een draad zich kan bevinden, een verrijkt bit-type dus. IEEE 1164 introduceert onder meer twee nieuwe types: std logic en std ulogic. Beide types bevatten volgende elementen: 1. ’U’: een niet-ge¨ıntialiseerd signaal (bijvoorbeeld bij het opstarten van hardware); 2. ’X’: een sterk aangestuurd maar onbekend signaal; 3. ’0’: een sterk aangestuurde logische 0; 4. ’1’: een sterk aangestuurde logische 1; 5. ’Z’: hoog-impedant (niet aangestuurd); 6. ’W’: een zwak aangestuurde maar ongekend signaal; 7. ’L’: een zwak aangestuurde logische 0; 8. ’H’: een zwak aangestuurde logische 1; en 9. ’-’: don’t care (’0’ of ’1’). VHDL-code 7.8 De definitie van std logic en std ulogic (IEEE 1164). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
type s t d u l o g i c i s ( ’U’ , −−n i e t g e i n i t i a l i s e e r d ( o p s t a r t e n ) ’X’ , −−s t e r k a a n g e s t u u r d , maar ongekend ’ 0 ’ , −−s t e r k a a n g e s t u u r d e l o g i s c h e 0 ’ 1 ’ , −−s t e r k a a n g e s t u u r d e l o g i s c h e 1 ’ Z ’ , −−hoog impedant ( n i e t a a n g e s t u u r d ) ’W’ , −−zwak a a n g e s t u u r d , maar ongekend ’ L ’ , −−zwak a a n g e s t u u r d e l o g i s c h e 0 ’H’ , −−zwak a a n g e s t u u r d e l o g i s c h e 1 ’−’ −−don ’ t c a r e ( ’ 0 ’ o f ’ 1 ’ ) ); type s t d u l o g i c v e c t o r i s array ( n a t u r a l range <>) of s t d u l o g i c ; function r e s o l v e d ( s : s t d u l o g i c v e c t o r ) return s t d u l o g i c ; type s t d l o g i c i s r e s o l v e d s t d u l o g i c ; type s t d l o g i c v e c t o r i s array ( n a t u r a l range <>) of s t d l o g i c ;
VHDL-code 7.8 toont hoe we de types zouden kunnen defini¨eren. Bij deze code zien we dat std logic wordt gedefinieerd met behulp van std ulogic, maar dat er ook nog een extra identifier bij deze declaratie staat: resolved. Deze identifier wijst naar een functie waarvan de signatuur eerder in de code werd gedefinieerd. Deze functie wordt gebruikt om meervoudige toekenning mogelijk te maken: stel dat we een bus zouden schrijven in VHDL, dan zullen we de poorten van verschillende componenten toewijzen aan eenzelfde signaal.
274
HOOFDSTUK 7. VHDL
Zoals echter al opgemerkt laat VHDL dit niet toe, tenzij we een resolutie-functie resolved9 defini¨eren die regels specificeert hoe een verzameling aan signalen – de std ulogic vector – worden omgezet in ´e´en type. VHDL zal dus bij meervoudige toekenning een soort virtueel “bus”-component bijvoegen met invoer alle mogelijke signalen die op de bus worden aangebracht en als uitvoer het signaal die op de “werkelijke” bus staat. De resolved functie doet dus dienst als een operator die gegeven verschillende signalen, een consensussignaal moet berekenen. IEEE berekent zo’n signaal aan de hand van een tweedimensionale tabel res table die twee signalen omzet in ´e´en signaal. Deze tabel staat beschreven in Tabel 7.4. ⊕
’U’
’X’
’0’
’1’
’Z’
’W’
’L’
’H’
’-’
’U’ ’X’ ’0’ ’1’ ’Z’ ’W’ ’L’ ’H’ ’-’
’U’ ’U’ ’U’ ’U’ ’U’ ’U’ ’U’ ’U’ ’U’
’U’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’
’U’ ’X’ ’0’ ’X’ ’0’ ’0’ ’0’ ’0’ ’X’
’U’ ’X’ ’X’ ’1’ ’1’ ’1’ ’1’ ’1’ ’X’
’U’ ’X’ ’0’ ’1’ ’Z’ ’W’ ’L’ ’H’ ’X’
’U’ ’X’ ’0’ ’1’ ’W’ ’W’ ’W’ ’W’ ’X’
’U’ ’X’ ’0’ ’1’ ’L’ ’W’ ’L’ ’W’ ’X’
’U’ ’X’ ’0’ ’1’ ’H’ ’W’ ’W’ ’H’ ’X’
’U’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’ ’X’
Tabel 7.4: Resolutie-tabel voor std logic.
De tabel is reflexief: wanneer de twee signalen gelijk zijn, is de het resultaat ook gelijk aan de invoer. De tabel is ook commutatief: onafhankelijk van welke dimensie we voor welk signaal kiezen levert dit eenzelfde waarde op. Dit is vanzelfsprekend: anders zouden we immers een signaal in de bus bevoordelen tegenover een ander signaal. Verder is de tabel ook associatief: wanneer we resolutie ⊕ toepassen op drie verschillende signalen a, b en c, maakt het niet uit welke twee signalen we eerst uitrekenen: a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c, ongeacht de waardes van de signalen. Er is tot slot ook sprake van enige prioriteit: wanneer een signaal de waarde ’U’ heeft aangenomen, is het resultaat sowieso ’U’. Op basis van de tabel kunnen we volgende “prioriteitsregels” opstellen: ’U’ ’X’, ’-’ ’0’, ’1’ ’W’ ’L’, ’H’ ’Z’
(7.6)
Dit betekent dat wanneer we resolutie ⊕ toepassen op twee signalen van een verschillende prioriteitsklasse, het resultaat steeds de waarde van de hoogste prioriteitsklasse wordt gebruikt. Een uitzondering vormt de don’t care (’-’) die zich als sterk signaal (’X’) gedraagt. Wanneer twee waarden uit dezelfde prioriteitsklasse komen en gelijk zijn is het resultaat evident gelijk aan de invoer-signalen. Wanneer de twee invoer-signalen niet gelijk zijn, is het resultaat het signaal van een prioriteitsklasse hoger, Vergelijking (7.6) zorgt ervoor dat telkens wanneer dit mogelijk is, de prioriteitsklasse erboven slechts ´e´en element bevat, de don’t care (’-’) doet zich immers voor als een sterk signaal (’X’). VHDL-code 7.9 toont hoe we deze resolutie-functie kunnen schrijven in VHDL. Dit code-fragment is bovendien interessant omdat het inzicht heeft in het ontwikkelen van functies en de verschillende attributen die bij een vector horen. In de eerste lijnen van de code defini¨eren we de res table: een tabel die de hierboven beschreven functie opslaat. De functie resolved wordt dan gebruikt om voor een vector van signalen met willekeurige grootte een nieuw signaal uit te rekenen. Na de signatuur van de functie volgt een lijst van lokale variabelen, deze komen voor het function-blok. We declareren de resultaat-variabele result en geven deze de standaard waarde ’Z’. We controleren vervolgens of de vector een lengte heeft die gelijk is aan 1. Dit doen we door het length attribuut op te vragen van de vector10 . Indien de vector een lengte heeft van 1 is de resolutie triviaal: we geven dit element terug. Wanneer er sprake is van meer (of minder) elementen. 9 We 10 We
kunnen ook een andere identifier gebruiken. krijgen toegang tot een attribuut met de ’-operator, dit is vergelijkbaar met het punt (.) in Java.
7.4. BEWERKINGEN
275
VHDL-code 7.9 Implementatie van de std logic resolutie-functie in VHDL. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
constant r e s t a b l e : array ( s t d u l o g i c , s t d u l o g i c ) of s t d u l o g i c := −− ’U’ , ’ X’ , ’ 0 ’ , ’ 1 ’ , ’ Z ’ , ’W’ , ’ L ’ , ’ H’ , ’ − ’ ( t w e e d e i n v o e r ) ( ( ’ U’ , ’ U’ , ’ U’ , ’ U’ , ’ U’ , ’ U’ , ’ U’ , ’ U’ , ’ U’ ) , −− ’U’ ( ’U’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ ) , −− ’X’ , ( ’U’ , ’ X’ , ’ 0 ’ , ’ X’ , ’ 0 ’ , ’ 0 ’ , ’ 0 ’ , ’ 0 ’ , ’ X’ ) , −− ’ 0 ’ , ( ’U’ , ’ X’ , ’ X’ , ’ 1 ’ , ’ 1 ’ , ’ 1 ’ , ’ 1 ’ , ’ 1 ’ , ’ X’ ) , −− ’ 1 ’ , ( ’U’ , ’ X’ , ’ 0 ’ , ’ 1 ’ , ’ Z ’ , ’W’ , ’ L ’ , ’ H’ , ’ X’ ) , −− ’Z ’ , ( ’U’ , ’ X’ , ’ 0 ’ , ’ 1 ’ , ’W’ , ’W’ , ’W’ , ’W’ , ’ X’ ) , −− ’W’ , ( ’U’ , ’ X’ , ’ 0 ’ , ’ 1 ’ , ’ L ’ , ’W’ , ’ L ’ , ’W’ , ’ X’ ) , −− ’L ’ , ( ’U’ , ’ X’ , ’ 0 ’ , ’ 1 ’ , ’ H’ , ’W’ , ’W’ , ’ H’ , ’ X’ ) , −− ’H’ , ( ’U’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ , ’ X’ ) −− ’ − ’ ); function r e s o l v e d ( s : s t d u l o g i c v e c t o r ) return s t d u l o g i c i s variable r e s u l t : s t d u l o g i c := ’ Z ’ ; begin i f s ’ l e n g t h = 1 then return s ( s ’ low ) ; else f o r i in s ’ range loop r e s u l t := r e s t a b l e ( r e s u l t , s ( i ) ) ; end loop ; return r e s u l t ; end i f ; end function r e s o l v e d ;
We doen dit door het low attribuut op te vragen: de laagste (en enige) index. In het andere geval vouwen we de vector aan de hand van de accumulator result en de tabel res table. Dit doen we door het range op te vragen: dit is een verzameling van indices die gedefinieerd zijn voor de vector. Indien er dus sprake is van een lege vector is het resultaat ’Z’. Zoals men al uit de code kan afleiden bevat het pakket tot slot ook nog vector-types zoals std logic vector en std ulogic vector.
7.4
Bewerkingen
We kunnen zoals in VHDL-code 7.9 telkens een tabel aanleggen voor de uitvoer van een functie, maar dit is niet echt praktisch. Bovendien is het mogelijk dat we het bereik van een variabele op voorhand niet kennen. VHDL kent dan ook een groot aantal bewerkingen van verschillende aard. Voor de meeste van deze bewerkingen hebben we in deze cursus al hardware gesynthetiseerd: bijvoorbeeld een opteller, vermenigvuldiger, schuifoperator. In deze sectie geven we een overzicht van de belangrijkste bewerkingen.
7.4.1
Logische bewerkingen
De logische bewerkingen komen grotendeels overeen met de beschouwden poorten in Hoofdstuk 1. Dit zijn dus de not, and, nand, or, nor, xor en xnor11 . Behalve de not-operator zijn alle operatoren gedefinieerd met twee operanden. Logische bewerkingen zijn gedefinieerd op logische types zoals bit, boolean, std logic en op afgeleide “array aggregaten” zoals de bit vector en std logic vector. Een voorwaarde bij deze vectoren is dat ze van dezelfde lengte zijn: wat zou men immers invullen op plaatsen die maar door ´e´en elementen bepaald zijn?
11 xnor
is niet beschikbaar is VHDL’87.
276
HOOFDSTUK 7. VHDL
7.4.2
Rekenkundige bewerkingen
7.4.3
Schuifoperaties
7.4.4
Vergelijkingen
7.4.5
“Array aggregaat” bewerkingen
Tot slot zijn er nog enkele operaties gedefinieerd op generische12 vectoren. Dit zijn de “concatenate” en de “slice”.
Bij een “concatenate”13 voegen we twee vectoren samen in ´e´en nieuwe vector. Fysisch komt dit dus neer op het bundelen van signalen. Een concatenate wordt aangeduid met de & operator: de identifiers van twee vectoren met hetzelfde type worden links en rechts van de operator geschreven, het resultaat is een vector van hetzelfde type met de lengte de som van de lengtes van de twee gegeven vectoren. Een typisch voorbeeld is een bus die data vanuit verschillende componenten groepeert en doorstuurt. Stel bijvoorbeeld dat twee componenten elk vier bit op de bus willen zetten, kunnen we dit beschrijven zoals in VHDL-code 7.10. VHDL-code 7.10 Vector aaneenschakeling. 1 2 3 4 5 6 7 8 9 10
s i g n a l bus : b i t v e c t o r ( 7 downto 0 ) ; s i g n a l p a r t a , parb : b i t v e c t o r ( 3 downto 0 ) ; bus <= p a r t a & p a r t b ; −− e q u i v a l e n t w i t h : −− b u s ( 7 ) <= p a r t a ( 3 ) −− . . . −− b u s ( 4 ) <= p a r t a ( 0 ) −− b u s ( 3 ) <= p a r t b ( 3 ) −− . . . −− b u s ( 0 ) <= p a r t b ( 0 )
Zoals ook in het codefragment staat is een aaneenschakeling equivalent met het overlopen van de indices en de eerste indices toekennen vanuit de eerste operand. Wanneer de eerste operand uitgeput is, wordt de tweede operand gebruikt. Het voordeel van de concatenate operator is echter dat men niet op voorhand hoeft te weten over welk bereik de operanden werken.
Bij een “slice”14 halen we een deel van de elementen uit een vector en wordt deze gezien als een op zichzelf staande vector. VHDL-code 7.11 Vector matrixdeling. 1 2 3 4 5 6
s i g n a l bus : b i t v e c t o r ( 7 downto 0 ) ; s i g n a l l a r g e r : b i t v e c t o r ( 0 to 3 ) ; bus ( 5 downto 4 ) <= l a r g e r ( 1 to 2 ) ; −− e q u i v a l e n t w i t h : −− b u s ( 5 ) <= l a r g e r ( 1 ) −− b u s ( 4 ) <= l a r g e r ( 2 )
12 Onder
generisch verstaan we dat het “element-type” er niet toe doet aaneenschakeling of concatinatie. 14 Nederlands: matrixdeel 13 Nederlands:
7.5. BIBLIOTHEKEN
7.5
277
Bibliotheken
Net zoals Java kent VHDL een mechanisme om eerder gedefinieerde deelprogramma’s te groeperen in een pakket dat dan in een volgend ontwerp kan worden gebruikt. Dit is belangrijk: net zoals men in Java grote delen van een programma kan hergebruiken voor andere programma’s kan men meestal componenten uit een vorig project hergebruiken om nieuwe hardware te beschrijven. VHDL maakt gebruik van twee concepten: “packages” en “libraries”. Een pakket (“package”) groepeert functies, programma’s, types, constanten, signalen, structuren, enzovoort die zullen worden gedeeld onder verschillende eenheden. VHDL kent verschillende standaard pakketten zoals IEEE 1164. Een pakket bestaat doorgaans uit twee delen: de “pakket declaratie” (ook wel “package declaration”) genoemd waarin men samen met de naam van het pakket de verschillende componenten die in het pakket zitten oplijst, en de “package body” waarin men de opgelijste delen specificeert en implementeert. Een bibliotheek (“library”) daarentegen is een plaats waar men code en analyses opslaat. Dit is dus een map of een databank.
VHDL-code 7.12 Voorbeeld van een “package declaration”. 1 package v a r i o u s i s 2 constant h o l d : time ; 3 procedure push ( s i g n a l bu tt on : inout s t d l o g i c ; h o l d : time ) ; 4 end package v a r i o u s ;
VHDL-code 7.13 Voorbeeld van een “package body”. 1 package body v a r i o u s i s 2 constant h o l d : time := 100 ns ; 3 procedure push ( s i g n a l bu tt on : inout s t d l o g i c ; h o l d : time ) i s 4 begin 5 bu tt on <= ‘ 0 ’ , ‘ 1 ’ a f t e r h o l d ; 6 end procedure push ; 7 end package body v a r i o u s ;
VHDL-code 7.12 en VHDL-code 7.13 tonen respectievelijk een voorbeeld van een “package declaration” en “package body”. Beide voorbeelden hebben betrekking op een pakket various die we willen defini¨eren. In de “package declaration” schrijven we dat het pakket twee items bevat: een constante hold van het type time en een procedure push (wat een procedure precies doet is hier niet relevant). In het “package body” dienen we deze abstracte items te binden met betekenis. Zo is de waarde van hold 100 ns en komt push er blijkbaar op neer dat de knop tijdelijk het signaal ‘0’ zal aanleggen. Om pakketten te defini¨eren en . De bibliotheken work en std zijn altijd beschikbaar. VHDL laat ook “overloading” toe. Bij overloading kan men eenzelfde functie meerdere malen defini¨eren wanneer het aantal of het type parameters verschilt. Zo kan men een optelling beschrijven op een bit vector en een integer, en is de uiteindelijke uitwerking transparant naar de gebruiker toe.
7.6
Combinatorische schakelingen in VHDL
In deze sectie zullen we verschillende combinatorische schakelingen die we doorheen de cursus hebben ontwikkeld beschrijven in VHDL. In deze sectie zullen we eerst een formeel overzicht geven van de VHDL-syntax.
278
HOOFDSTUK 7. VHDL
Vervolgens zullen we in subsectie Subsectie 7.6.1 een methode ontwikkelen om combinatorische elementen te beschrijven met deze syntax. In elk hoofdstuk zullen we de methodologie uitbreiden zodat we de nieuwe componenten ook kunnen beschrijven.
7.6.1
Hardwarebeschrijving met VHDL
Structurele beschrijving VHDL-code 7.14 2-naar-1-multiplexer. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
−− 2−naar−1 M u l t i p l e x e r −− architecture S t r u c t of MUX2 i s s i g n a l U, V,W : b i t ; component AND2 i s port (X,Y: in b i t ; Z : out b i t ) ; end component AND2; component OR2 i s port (X,Y: in b i t ; Z : out b i t ) ; end component OR2 ; component INV i s port (X: in b i t ; Z : out b i t ) ; end component INV ; begin Gate1 : component INV port map Gate2 : component AND2 port map Gate3 : component AND2 port map Gate4 : component OR2 port map end S t r u c t ;
(X=>S , Z=>U) ; (X=>A,Y=>S , Z=>W) ; (U, B,V) ; (X=>W,Y=>V, Z=>Y) ;
Gedragsbeschrijving Repetitieve structuren
7.7
Sequenti¨ ele schakelingen in VHDL
7.8
Processoren in VHDL
7.8.1
Leidend voorbeeld: sha1 checksum
Als leidend voorbeeld zullen we een specifieke processor bouwen die de sha1 hash van een boodschap kan berekenen. Een hash is een “samenvatting” van een sequentie data. In het geval van sha1 is deze samenvatting 160 bit lang (voor eender welke sequentie aan bits). Een dergelijke samenvatting kan bijvoorbeeld als handtekening gebruikt worden om te verifi¨eren dat een het bestand wel degelijk gemaakt is door de afzender en niet aangepast is door een “man-in-the-middle”. Zo kan men een samenvatting van het document genereren en deze bijvoorbeeld via een ander kanaal doorsturen. Wanneer de ontvanger dan ook het originele bestand ontvangt kan deze, door zelf ook de samenvatting uit te rekenen dat men over hetzelfde bestand spreekt. Het is natuurlijk niet uitgesloten dat twee bestanden tot dezelfde samenvatting worden herleid, maar het algoritme is zo opgesteld dat “reverse engineering”15 zeer moeilijk is. 15 Het
analyseren van het resultaat om dit vervolgens uit te buiten.
7.8. PROCESSOREN IN VHDL
279
VHDL-code 7.15 n-bit Opteller. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
−− O p t e l l e r −− library i e e e ; use i e e e . s t d l o g i c s i g n e d . a l l ; entity adder i s generic ( n : p o s i t i v e := 4 ) ; port ( Cin : in s t d l o g i c ; X,Y : in s t d l o g i c v e c t o r ( n−1 downto 0 ) ; S : in s t d l o g i c v e c t o r ( n−1 downto 0 ) ; Cout , O v e r f l o w : out s t d l o g i c ) ; end adder ; architecture behav of adder i s s i g n a l Sum : s t d l o g i c v e c t o r ( n downto 0 ) ; begin Sum <= (X( n−1) & X) + Y + Cin ; S <= Sum( n−1 downto 0 ) ; Cout <= Sum( n ) ; O v e r f l o w <= Sum( n ) xor X( n−1) xor Y( n−1) xor Sum( n−1) ; end behav ;
Algoritme Het algoritme in pseudo-code staat beschreven in Algoritme 6. Technisch gezien moet het bericht dus uit blokken van 512 bits bestaan en de lengte in bits moet congruent zijn met 448 mod 512. Dit is natuurlijk niet altijd het geval. In dat geval worden 0’en bijgevoegd op het einde van het bestand tot aan de voorwaarde is voldaan. De overige 64 bits in het laatste blok moeten dan worden opgevuld met de lengte van het bestand in bits modulo 264 . We gaan er vanuit dat deze stappen al uitgevoerd zijn door de logica die invoer op onze processor aanlegt, we krijgen dus 512-bit blokken aangeleverd met correcte inhoud. Een laatste opmerking over de invoer is dat indien het bestand bovendien tekst bevat is nog een extra stap nodig, we gaan er hier vanuit dat het bestand binair is, ook deze stappen worden dus niet beschouwd. Het algoritme leest eerst enkele constanten in h0 , h1 , . . . , h4 . Vervolgens leest het algoritme de verschillende blokken x in. In een eerste stap wordt het blok opgedeeld in items van 32-bit. Dit impliceert dus 16 items. Men vult de array w ~ echter op tot 80 items door een functie toe te passen op de vorige data-elementen. Daarna worden op basis van de items, a, b, c, d en e aangepast: grotendeels door de variabelen te permuteren en enkele variabelen op te tellen met constanten en het item. Op basis van a, b, c, d en e worden h0 , h1 , . . . , h4 aangepast. Wanneer alle blokken zijn behandeld, vormt de aaneenschakeling van h0 , h1 , h2 , h3 en h4 het resultaat. VHDL-proces Het algoritme die we voorstellen in Algoritme 6 is niet equivalent met een VHDL-beschrijving van een proces: er ontbreekt welke instructie we wanneer zullen uitvoeren, een duurder datapad kan immers meerdere instructies tegelijk uitvoeren. Het is bijvoorbeeld evident dat we a ← h0 en b ← h1 in parallel kunnen uitvoeren. We kunnen er ook voor opteren om de instructies van de if-lussen in ´e´en tijdstap uit te voeren: de controller beslist welke instructies moeten worden uitgevoerd en overloopt dus alles if’s tegelijk. We hebben op basis van het algoritme een procesbeschrijving opgesteld die een redelijke hoeveelheid instructies samenneemt zonder dat dit tot een duur datapad leidt. Het proces is niet gegarandeerd het meest effici¨ente, maar dit voorbeeld heeft dit ook niet tot doel. Zo kunnen we bijvoorbeeld de twee for-lussen in elkaar schuiven. Dit leidt niet enkel tot snellere implementatie, maar bovendien moet de volledige w-vector ~ niet worden uitgerekend: we dienen wel 16 × 32-bit
280
HOOFDSTUK 7. VHDL
Algorithm 6 Genereren van een sha1 checksum. 1: function Sha1(~ x) . ~x is een vector van 512-bit blokken. 2: h0 ← 6745230116 ; h1 ← EFCDAB8916 ; h2 ← 98BADCFE16 ; h3 ← 1032547616 ; h4 ← C3D2E1F016 3: for x ∈ ~x do 4: a ← h0 ; b ← h1 ; c ← h2 ; d ← h3 ; e ← h4 5: for i = 0 to 15 do . Elke wi telt 32-bit. 6: wi ← x shr 32 · i 7: end for 8: for i = 16 to 79 do . Blok wordt uitgebreid naar 80 × 32-bit. 9: wi ← (wi−3 xor wi−8 xor wi−14 xor wi−16 ) rol 1 10: end for 11: for i = 0 to 79 do 12: if 0 ≤ i ≤ 19 then 13: f ← (b and c) or ((not b) and d); k ← 5A82799916 14: else if 20 ≤ i ≤ 39 then 15: f ← b xor c xor d; k ← 6ED9EBA116 16: else if 40 ≤ i ≤ 59 then 17: f ← (b and c) or (b and d) or (c and d); k ← 8F1BBCDC16 18: else . 60 ≤ i ≤ 79 19: f ← b xor c xor d; k ← CA62C1D616 20: end if 21: t ← (a rol 5) + f + e + k + wi ; e ← d; d ← c; c ← b rol 30; b ← a; a ← t 22: end for 23: h0 ← h0 + a; h1 ← h1 + b; h2 ← h2 + c; h3 ← h3 + d; h4 ← h4 + e 24: end for 25: return (h0 shl 128) or (h1 shl 96) or (h2 shl 64) or (h3 shl 32) or h4 26: end function
bij te houden om de vorige waarden van w ~ op te slaan. Merk op dat dit dus een 512-bit geheugen vormt: precies evenveel als de invoergrootte. Dit is niet toevallig: het laat toe om een schuifregister te gebruiken en zo het sha1 algoritme effici¨ent in hardware te implementeren. Signalen versus variabelen
7.9
VHDL grammatica
Een programmeertaal beschrijft men meestal aan de hand van een (geannoteerde) context-vrije grammatica. Zo’n grammatica bestaat uit “productieregels”. Een productieregel bestaat aan de linkerkant uit een een “non-terminal” en aan de rechterkant uit een sequentie van “terminals” en non-terminals. Een non-terminal is een symbool waarop verdere productieregels kunnen worden toegepast. Een terminal is een elementen uit de taal zelf, bijvoorbeeld een sleutelwoord of karakter. Een programma is geldig wanneer men vanuit de start non-terminal een sequentie van terminals kan genereren die equivalent is met dat programma. Om een grammatica compacter voor te stellen maakt men doorgaans gebruik van extra componenten. Zo zijn elementen aan de rechterkant van een productie-regel tussen vierkante haken optioneel. Ze zijn niet verplicht bij een productieregel. Wel is het zo dat alles wat tussen vierkante haakjes staat samengenomen moet worden: wanneer twee elementen binnen dezelfde vierkante haken staan, worden beide elementen genegeerd, of allebei toegevoegd. Een tweede vorm van syntactische suiker zijn accolades. Deze worden gebruikt bij herhaling van een groep elementen: de elementen binnen acculades worden nul, ´e´en of meerdere keren herhaald. Doorgaans zal het laatste element binnen de accolades een terminal zijn: het scheidingsteken tussen twee groepen elementen.
7.10. PROGRAMMEERJARGON
281
VHDL-code 7.16 Beschrijving van de procedure om de sha1 uit te rekenen. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
library i e e e ; use i e e e . s t d l o g i c 1 1 6 4 . a l l ; entity s h a c a l c i s port ( c l k : in s t d l o g i c ; data : in s t d l o g i c v e c t o r ( 5 1 1 downto 0 ) ; e n a b l e : in s t d l o g i c ; s i g n a t u r e : out s t d l o g i c v e c t o r ( 1 5 9 downto 0 ) ; done : out s t d l o g i c ; ); end entity s h a c a l c ; architecture p r o t o t y p e of s h a c a l c begin process ( c l k , data , e n a b l e ) variable wvec : s t d l o g i c v e c t o r ( 5 1 1 downto 0 ) ; variable h0 , h1 , h2 , h3 , h4 , h5 , a , b , c , d , e , f , t : s t d l o g i c v e c t o r ( 3 1 downto 0 ) ; variable i : begin while e n a b l e = ’0 ’ loop wait u n t i l c l k = ’ 1 ’ ; end loop ; s i g n a t u r e <= h0 & h1 & h2 & h3 & h4 & h5 ; end process end architecture p r o t o t y p e ;
In een grammatica komen traditioneel veel identifiers voor: namen van allerhande items die op de ´e´en of andere manier gerelateerd zijn met het type. Een probleem is echter dat een productie-regel verschillende identifiers kunnen bevatten en daarom de betekenis niet altijd duidelijk is. Daarom zullen we non-terminals die eigenlijk identifiers zijn extra annoteren: de non-terminal eindigt op “-ident” en bevat ervoor informatie over het soort identifier. In werkelijkheid staat er dus een identifier. Grammatica 1 beschrijft de belangrijkste delen van de VHDL taal. Deze grammatica wordt louter ter illustratie gegeven: het is niet de bedoeling deze grammatica te kennen, het kan echter helpen bij het begrijpen van de VHDL syntax.
7.10
Programmeerjargon
Tijdens het beschrijven van de VHDL taal zijn we verschillende termen tegengekomen die vaak aan bod komen bij programmeertalen in het algemeen. Voor lezers die minder vertrouwd zijn met programmeren volgt hier een beschrijving van deze concepten. De lijst is niet exhaustief, voor een uitgebreidere Engelstalige lijst, zie [?]. Overloading Overloading betekent dat men verschillende betekenissen kan koppelen aan ´e´en en dezelfde identifier. Door extra informatie kan de compiler echter zelf bepalen welke betekenis aan een oproep moet worden gekoppeld. Zo is het bijvoorbeeld in Java toegestaan om verschillende methodes te defini¨eren met eenzelfde naam, wanneer het aantal parameters of de types van deze parameters anders zijn. Op basis van het aantal parameters en het type van deze parameters weet de Java compiler welke methode moet worden opgeroepen.
282
HOOFDSTUK 7. VHDL
Grammatica 1 De belangrijkste delen van de VHDL-grammatica. htype-decli→type hidenti is htype-indi ; hsubtype-decli→subtype hidenti is hsubtype-indi ; harraytype-decli→type hidenti is array ( htype-namei range <> {, htype-namei range <>} ) of helem-subtype-indi ; harraytype-decli→type hidenti is array hindex-constrainti of helem-subtype-indi ; hconst-decli→constant hidenti {, hidenti} hsubtype-indi [:= hexpressioni] ; hvar-decli→[shared] variable hidenti {, hidenti} hsubtype-indi [:= hexpressioni] ; hsignl-decli→signal hidenti {, hidenti} hsubtype-indi [register|bus] [:= hexpressioni] ; hpackage-decli→package hidenti is {htype-decli|hsubtype-decli|harraytype-decli|hconstdecli|hvar-decli|hsignl-decli|hcomponent-declarationi|huse-clausei} end [package] [hpackagename-identi] ; hlib-clausei→library hlogical-name-identi {, hlogical-name-identi} ; huse-clausei→use hselected-namei hpackage-bodyi→package body hpackage-name-identi is {} end [package body] [hpackagename-identi] ; hsubtype-indi→[hresolution-function-namei] htype-namei [hrange-constrainti|hindex-constrainti] htype-indi→[hresolution-function-namei] htype-namei [hrange-constrainti|hindex-constrainti] helem-subtype-indi→[hresolution-function-namei] htype-namei [hrange-constrainti|hindexconstrainti] hselected-namei→hprefixi . hsuffixi
Deel V
Digitale Elektronica in de Praktijk
283
Hoofdstuk 8
Circuits Schakelen Tot slot bieden we een laatste gedeelte over het bouwen van digitale schakelingen in de praktijk. Dit gedeelte is optioneel. Het is geen leerstof, staat niet in de presentaties en vorm zeker geen onderdeel tijdens het examen. Het is dan ook eerder tot stand gekomen voor “enthousiastelingen” die de opgedane kennis in de praktijk willen omzetten. In dit hoofdstuk beschrijven we welke ge¨ıntegreerde circuits men zich dient aan te schaffen om de schakelingen te implementeren. In de rest van het deel worden enkele projecten besproken die men kan realiseren.
8.1
Anatomie van een Ge¨ıntegreerd circuit
We beginnen het hoofdstuk met de terminologie die men hanteert bij ge¨ıntegreerde circuits.
8.1.1
DIP packing
Vermits het de bedoeling is dat men de circuits zelf implementeert, zullen we ook enkel werken met ge¨ıntegreerde circuits die men zelf kan ineenzetten. Meestal kiest men daarvoor voor “DIP packing”. DIP packing beschouwt rechthoekige chips met verbindingen in de lengte. Figuur 8.1(a) geeft dit concept grafisch weer. Een verbinding noemt men een “pin” of “pootje”. Omdat chips correct geori¨enteerd moeten 6
5
2
3
4
1
7
8
(a) Structuur
(b) Vooraanzicht
(c) Zijaanzicht
Figuur 8.1: DIP packing worden maakt men gebruik van twee systemen. De “notch” is een cirkelvormige inkeping aan ´e´en kant van de chip. Daarnaast zet men op de meeste chips ook een “index marker”. Een index marker is een cirkel in de buurt van pin 1. Wanneer we de notch aan de linkerkant plaatsen (zoals op de figuur), worden de pootjes onderaan van links naar rechts genummerd. De nummering van de bovenste pootjes verloopt van rechts naar links. Elke digitale chip beschikt telkens over minstens twee pootjes: de power pin (ofwel Vcc) 285
286
HOOFDSTUK 8. CIRCUITS SCHAKELEN
en de ground pin (ofwel GND). Bij de meeste chips stelt pin 1 de ground pin door. Meestal stelt de laatste pin (pin 8 op Figuur 8.1(a)) de power pin voor. Soms gebruikt men ook de eerste pin van de bovenste rij (pin 5 op Figuur 8.1(a)). De powerpin moet worden verbonden met de positieve pool van de voeding, de ground pin met de negatieve pool. In een schematische voorstelling van een ge¨ıntegreerd circuit geeft men vaak de nummers van de verschillende pinnen weer. Een diagram die de functie van de verschillende pinnen beschrijft noemt men een “pinout”. Figuur 8.1(b) en Figuur 8.1(c) tonen het voor- en zijaanzicht van een DIP ge¨ıntegreerd circuit. Doorgaans zijn de pootjes dikker rond het midden van de chip dan het einde. De structuur van DIP vereist bijna dat het aantal pootjes altijd even is. Indien dit niet het geval is zal men meestal een veelvoud van de componenten in een chip implementeren. Zo bestaan er bijvoorbeeld chips die 4 NAND-poorten aanbieden.
8.1.2
Populaire ge¨ıntegreerde circuits
Nu we de structuur van een ge¨ıntegreerd circuit hebben voorgesteld, zullen we een bondige samenvatting geven over de belangrijkste ge¨ıntegreerde circuits. Belangrijke ge¨ıntegreerde circuits werden gestandaardiseerd met een nummer. Op gebied van digitale elektronica spreekt men over twee “ge¨ıntegreerde circuit-families”: de 74000 serie en de 4000 serie. De 74000 serie omvat digitale componenten ge¨ımplementeerd met transistortransistor logic. De 4000 serie implementeert dezelfde schakelingen in CMOS-logica. Indien we dus Zo stelt ge¨ıntegreerd circuit 4068 een 8-NAND poort voor in CMOS logica. 47068 biedt dezelfde poort aan, maar volgens een andere technologie. Voor een volledige lijst van de ge¨ıntegreerde circuits in de 74000 en 4000 families: zie [?, ?].
# 555 556 4017 4269 4701 4703 4705 4706 4707 4708 4710 4702
Naam
#
Naam
555-timer 2× 555-timer Decade counter 8-bit counter 4× 2-NAND 4× 2-NOR 6× NOT 6× Buffer 4× 2-NOR 4× 2-AND 4× 3-NAND 3× 2-NOR
Tabel 8.1: Lijst met populaire ge¨ıntegreerde circuits. In Tabel 8.1 staat een lijst met populaire ge¨ıntegreerde circuits. Naast de digitale circuits omvat de tabel ook enkele analoge schakelingen. De werking van deze circuits wordt verder in dit hoofdstuk verduidelijkt.
8.2
Analoge componenten
Naast ge¨ıntegreerde circuits zal men in de praktijk in een digitale schakeling ook analoge componenten aantreffen: weerstanden, condensatoren, transistoren en in mindere mate spoelen. Deze componenten zijn meestal nodig om effectief iets aan te sturen (bijvoorbeeld een led) of bij de captatie van invoer (bijvoorbeeld radiogolven). In deze sectie geven we een kort overzicht.
8.2. ANALOGE COMPONENTEN
8.2.1
287
Weerstanden
Een weerstand is een component die de stroomsterkte in een circuit verlagen en bovendien lokaal de spanningsniveaus verminderen. Een circuit gedraagt zich dan ook volgens de “Wet van Ohm”. Deze wet stelt dat tussen elke twee punten in een elektronische schakeling, het verschil in potentiaal ∆V lineair schaalt met zowel de stroomsterkte I als de weerstand R: ∆V = I · R
(8.1)
De meeste weerstanden in een schakeling hebben een vaste weerstand R, er bestaan echter ook weerstanden zoals lichtgevoelige weerstanden, waar de weerstand afhangt van de lichtintensiteit, temperatuur, ... In deze cursus zullen we enkel weerstanden met een vaste weerstand beschouwen. Kleurcode De weerstand wordt traditioneel niet numeriek op de component genoteerd, maar aan de hand van vier tot zes banden die elk een specifieke kleur hebben. Deze sequentie beschrijft de weerstand, de toleratie 1 en optioneel de temperatuursco¨effici¨ent 2 . Afhankelijk van het aantal banden, heeft elke band ook een verschillende betekenis: getal, multiplicatie, toleratie en temperatuursco¨effici¨ent. Tabel 8.2 toont hoe de verschillende kleuren overeenstemmen met hun betekenis. Kleur Zwart Bruin Rood Oranje Geel Groen Blauw Paars Grijs Wit Zilver Goud
Cijfer c
Multiplicatie m
Toleratie t
Temperatuursco¨ effici¨ ent T
0 1 2 3 4 5 6 7 8 9 n.v.t. n.v.t.
0
n.v.t. 01.00% 02.00% n.v.t. n.v.t. 00.50% 00.25% 00.10% n.v.t. n.v.t. 10.00% 05.00%
n.v.t. 100 ppm 50 ppm 15 ppm 25 ppm n.v.t. n.v.t. n.v.t. n.v.t. n.v.t. n.v.t. n.v.t.
10 101 102 103 104 105 106 107 n.v.t. n.v.t. 10−2 10−1
Tabel 8.2: De verschillende kleurcodes bij een weerstand.
De eerste band is altijd aangebracht op een plaats waar de straal van de weerstand groter is. In het geval de weerstand uit zes banden bestaat, is de zesde band aangebracht aan de andere kant van de weerstand waar de straal ook groter is. Om toch het onderscheid te kunnen maken tussen de eerste en de laatste band zijn de tweede en de derde band altijd aan dezelfde kant van de weerstand. Vermits er hoogstens zes banden aangebracht zijn op een weerstand kan men dus door te rekenen vanuit het midden van de weerstand, altijd de eerste band lokaliseren door de kant te nemen die de meeste banden bevat. De posities samen met de betekenis van de banden staat schematisch voorgesteld op Figuur 8.2. In het algemeen beschrijven de eerste twee (in het geval van vier banden) of drie banden de cijfers die samen een getal vormen. Dit getal moet dan vermenigvuldigt worden met de multiplicator. De toleratie drukt aan de hand van een percentage uit wat het betrouwbaarheidsinterval is. Indien de weerstand bijvoorbeeld 10 kΩ is met een toleratie van 5%, dan is het betrouwbaarheidsinterval: [9.5 kΩ; 10.5 kΩ]. 1 Dit 2 De
is een betrouwbaarheidsinterval waarin de werkelijke weerstandswaarde zit. werkelijke waarde van de weerstand is altijd enigszins afhankelijk van de temperatuur van de weerstand op dat moment.
288
HOOFDSTUK 8. CIRCUITS SCHAKELEN
Figuur 8.2: De uitlijning en betekenis van de verschillende kleurbanden. In het geval de weerstand vier banden bevat zijn de eerste twee banden cijfers c1 en c2 , de derde de multiplicatie m en de laatste de toleratie t, in dat geval is de weerstandswaarde dus: R = (10 · c1 + c2 ) · m Ω
(4 banden)
(8.2)
In het geval van vijf en zes banden zijn de eerste drie banden cijfers c1 , c2 en c3 , de vierde de multiplicatie m, de vijfde de tolerantie t en optioneel de zesde de temperatuurco¨effici¨ent. In dat geval is de weerstandswaarde dus: R = (100 · c1 + 10 · c2 + c3 ) · m Ω (5 en 6 banden) (8.3)
8.2.2
Condensatoren
Condensatoren en spoelen zijn componenten die streven naar een behoudt van respectievelijk spanning en stroomsterkte. In het geval van wisselstroom of een periodiek veranderende spanning, kan men ze bovendien zien als weerstanden waarbij de weerstand afhangt van de fase op dat moment. Een condensator heeft tot doel spanning te stabiliseren, dit doet een condensator door elektronische spanning om te zetten in een elektrisch veld, wanneer de spanning vervolgens oploopt of afneemt, zal het elektrische veld een tegenbeweging uitvoeren. Het garanderen van de spanning is van cruciaal belang in een groot digitaal circuit. Zo hebben computers meestal enkele condensatoren die dicht bij de voeding het spanningsverschil moeten waarborgen. Immers is het mogelijk dat door het aan- en uitschakelen van andere apparaten, de spanning licht fluctueert. In analoge circuits is dit meestal niet problematisch. In een digitaal circuit kan dit echter het verschil maken tussen een 0 of een 1. Omdat in sequenti¨ele circuits een fout ge¨ınterpreteerd signaal tot een opeenvolging van foute invoer en foute toestanden kan leiden is een foute interpretatie dus zeer gevaarlijk. Een condensator wordt ook vaak gebruikt in een RC-keten: een keten waarbij een weerstand een condensator in serie worden geplaatst. Wanneer er dan spanning wordt aangelegd op het circuit, zal de spanning op de condensator traag evolueren. Dit kan men dus gebruiken om signalen met enige vertraging te laten propageren. Dit is belangrijk in analoge circuits alsook in digitale, bijvoorbeeld om een kloksignaal te generen (zie Sectie 8.4). Een condensator wordt als volgt gerealiseerd. Men voorziet doorgaans twee of meer platen die dicht bij elkaar liggen, maar niet verbonden zijn zoals weergegeven op Figuur 8.3.
~ E
Figuur 8.3: De realisatie van een condensator.
8.3. BOUW VAN EEN ELEKTRONISCHE SCHAKELING
289
Wanneer er spanning wordt aangelegd op de condensator, worden de platen elektrisch geladen. Als gevolg ontstaat er een elektrisch veld dat gelijk is aan: E=
V d
(8.4)
De meeste condensatoren worden niet gerealiseerd aan de hand van twee parallelle platen, maar aan de hand van bijvoorbeeld een opgerold structuur waarbij de twee platen gescheiden worden door een di¨elektrische stof.
8.2.3
Spoelen
Een spoel tracht de stroomsterkte te behouden, dit doet men door stroomsterkte om te zetten in magnetisch veld. Een spoel wordt doorgaans weinig gebruikt bij een digitaal circuit. Men kan een spoel in een RL-keten gebruiken om een vertraging te realiseren op de stroomsterkte, bovendien kan men een LC-keten realiseren om een oscillerende keten te bouwen. In de analoge elektronica wordt een spoel typische gebruikt bij het filteren van bepaalde frequenties uit een signaal, bijvoorbeeld uit een gecapteerd radiosignaal zodat enkel de signalen van een bepaald radiostation de luidspreker aanleggen. Men realiseert een spoel door door de stroomsterkte die doorheen een geleider vloeit om te zetten in een magnetisch veld. Men bereikt een maximaal effect wanneer men deze geleider op een spiraal-vormige manier buigt zoals weergegeven op Figuur 8.4.
Figuur 8.4: De realisatie van een spoel.
8.2.4
Transistoren
We hebben transistoren al in Hoofdstuk 2 besproken, maar dan vooral in een digitale context. Transistoren worden echter ook in een analoge context gebruikt: bijvoorbeeld als versterker waarbij de weerstand tussen de collector en de emittor wordt bepaald door de spanning die op de basis wordt aangelegd. Soms ook als basis om een feedback-circuit te bouwen: als men bijvoorbeeld een RC-keten laat op- en ontladen op basis van een transistor, en deze transistor vervolgens ook aangestuurd wordt door deze RC-keten, kan men wisselstroom realiseren of bijvoorbeeld een kloksignaal.
8.2.5
Diodes en Operationele versterkers
Diodes en operationele versterkers zijn componenten die toelaten om bij een bepaalde drempelwaarden, stroom door te laten. In het ideale geval betekent dit dat een diode wanneer de spanning correct gepolariseerd is, een weerstand van 0 Ω voorstelt. In het andere geval is de weerstand ∞ Ω.
8.3
Bouw van een elektronische schakeling
Om de verschillende componenten die we hier besproken hebben samen te schakelen, dienen we geleiders te voorzien. We kunnen dit natuurlijk realiseren door geleiders zoals koperdraad te voorzien en dit te solderen aan de connectoren van de verschillende componenten. Dit zou echter tot een chaotische realisatie leiden die
290
HOOFDSTUK 8. CIRCUITS SCHAKELEN
weinig compact is. Men maakt dan ook meestal gebruik van bijvoorbeeld een matrixbord, europrintplaat of printplaat die de geleiders structureren: meestal wordt ´e´en zijde van een plaat voorzien voor de componenten en de andere zijde voor de geleiders. In het geval van een printplaat wordt soms de zijde van de componenten ook gebruikt om geleiders op te zetten. Indien geleiders enkel aan ´e´en kan van de plaat automatisch worden aangebracht, zal men soms ook manueel nog extra geleiders moeten aanbrengen, meestal met behulp van koperdraad. Wanneer men aan de twee kanten van de plaat geleiders toelaat, kan men in feite elke schakeling realiseren zonder extra geleiders te moeten aanbrengen.
8.3.1
Matrixbord
Een matrixbord ook wel breadboard genoemd is een paneel waar de geleiders reeds op voorhand op een gestructureerde wijze zijn aangebracht. De componentenkant van een matrixbord bestaat uit vooraf gefabriceerde gaten, waar componenten eenvoudigweg ingeplugd kunnen worden. Figuur 8.5 beschrijft een typisch matrixbord.
A B C D E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
F G H I J 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
Figuur 8.5: Een voorbeeld van een matrixbord.
Op de figuur zien we centraal twee matrices van 57 × 5 pinnen. Deze pinnen zijn horizontaal verbonden. Aan beide kanten zijn ook lange lijnen. Dit zijn 25 × 2 matrices die verticaal verbonden zijn. Bij grote breadboards zijn er (zoals ook de figuur) meerdere onderbroken lange lijnen. Ook bestaan er breadboards met meer centrale matrices. Bovenaan ten slotte voorziet men verbindingen voor bijvoorbeeld stroombronnen. De meeste lange lijnen worden verbonden met de polen van de spanningsbron. Tussen twee centrale matrices
8.3. BOUW VAN EEN ELEKTRONISCHE SCHAKELING
291
loopt een opening van 0.2 inch. Dit laat toe om typische chips in DIP verpakking op het breadboard te plaatsen. Immers kan men dit niet op een centrale matrix plaatsen: anders zouden de pootjes met elkaar verbonden worden. Een matrixbord is erg geschikt om snel een prototype mee uit te testen. Na gebruik kan men immers de componenten terug uitpluggen. Een matrixbord is echter niet geschikt om compacte en blijvende realisaties mee te bouwen. Immers men de componenten zo ori¨enteren dat de juiste connectoren met elkaar verbonden worden. Dit leidt er toe dat bijvoorbeeld DIP-componenten altijd onder elkaar moeten worden geplaatst en bovendien in het midden van een kolom. Doorgaans kan men door eerst de componenten te plaatsen en dan de geleiders te minimaliseren tot een compacter ontwerp komen dan omgekeerd. Een matrixbord biedt echter comfort aan bij het schakelen van elementen en is daarom nuttig voor een eerste realisatie.
8.3.2
Europrintplaat
Een europrintplaat is een stap tussen een matrixbord en speciaal ontwikkelde printplaat. In een europrintplaat beschouwen we een rechthoekige bord van kunststof. Op deze plaat brengt men in een rasterstructuur rechthoekige plaatjes van koper aan die men eilanden noemt. Zo’n plaatje bevat drie gaten waarop men de verbindingen van de componenten kan solderen. Hierdoor zijn de connectoren die worden gesoldeerd aan eenzelfde eiland automatisch verbonden. Deze structuur is ge¨ıllustreerd op Figuur 8.6.
Figuur 8.6: Structuur van een europrintplaat.
Doordat de eilanden relatief klein zijn, levert dit vrij compacte schakelingen op. Immers verliest men bij een matrixbord meteen een volledige rij wanneer men op een bepaalde plaats een component inplugt. Bij een europrintplaat zijn dit slechts drie verbindingen. De componenten dienen op het bord gesoldeerd te worden, wat dus tot een permanente realisatie leidt. Het realiseren van een schakeling is echter arbeidsintensief en bovendien is het moeilijk om een component terug te verwijderen. In Subsectie ?? bespreken we hoe men componenten op een (euro)printplaat solderen.
8.3.3
Printed Circuit Board (PCB)
Wanneer men een schakeling heeft ontwikkeld die men wil realiseren in een klein formaat gebruikt men meestal een “Printed Circuit Board (PCB)” of “printplaat”. Een printplaat is een op maat gemaakte plaat waarbij de verbindingen gerealiseerd worden door een koperen laag aan de ene kant van deze plaat. De componenten worden op deze plaat bevestigt door openingen in de plaat. De componenten worden aan de andere kant bevestigd waarbij de verbindingen door middel van kleine openingen en de connectoren worden op de koperen kant gesoldeerd. Moderne printplaten laten ook toe om verbindingen aan de twee kanten van de plaat te plaatsen.
292
HOOFDSTUK 8. CIRCUITS SCHAKELEN
100 kΩ
2SA
1 kΩ
2SC
Figuur 8.7: Een voorbeeld van een printed circuit board (pcb).
Figuur 8.7 toont een voorbeeld van een printplaat die een knipperlicht implementeert aan de hand van twee transistoren. In het grijs staan de verbindingen die aan de achterkant van de plaat zijn aangebracht. De zwarte lijnen tonen de contouren van de componenten die aan de voorkant van de plaat worden aangebracht. De grijze cirkels wijzen op verbindingen en gaten in de printplaat.
Men kan printplaten op twee manieren bekomen: ze bestellen bij een bedrijf die hierin gespecialiseerd is of ze zelf maken. Bij beide dient men eerst de printplaat te ontwerpen. Op maat gemaakte printplaten zijn relatief goedkoop: ongeveer e 10.00 voor een prototype en e 00.25 per stuk bij massaproductie. We zullen nu het productieproces bespreken.
Ontwerp Het ontwerp van een printplaat is een proces waarin men bepaald hoe de koper-laag er zal uitzien samen met de locaties van de openingen. Er bestaan computerprogramma’s die voor een geven elektronische schakeling een compacte printplaat ontwerpen en verder bestaan er ook computerprogramma’s zoals PCB Designer die mensen helpen bij het ontwerpen van zo’n printplaat. Het ontwerpen van een compacte printplaat is geen sinecure. Het is echter meestal wel mogelijk om snel een eenvoudig ontwerp te bouwen. We gaan hier niet verder op in. Meer informatie over het plaatsen van componenten en verbindingen is te vinden in [?].
Productieproces Eenmaal de printplaat ontworpen is, kan men beslissen deze ook zelf te produceren. In deze subsubsectie zullen we het productieproces om zelf printplaten te maken bondig beschrijven. Meer informatie over dit proces is te vinden in [?].
Het proces bestaat grofweg uit vier fases: “blootstelling”, “etsen”, “tin betegeling” en “boren”[?, p. 69]. In de volgende paragrafen zullen we de fases bespreken. De productie van printplaten is op zich niet gevaarlijk, maar er komen corrosieve chemicali¨en bij kijken. Het is dus aangewezen handschoenen en een veiligheidsbril te dragen.
Blootstelling
Etsen
Tin betegeling
Boren
Als primaire grondstof hebben we een koperplaat nodig. Deze
8.4. IMPLEMENTATIE VAN EEN KLOKSIGNAAL
8.3.4
Plaatsen van componenten
8.3.5
Tips bij het solderen
8.4
293
Implementatie van een kloksignaal
In de cursus hebben we telkens abstractie gemaakt van de implementatie van een kloksignaal: een signaal die met een bepaalde frequentie afwisselend 0 en 1 aanlegt. Hoe kunnen we een dergelijk signaal implementeren? Een eerste antwoord zou kunnen zijn dat men een sequenti¨ele schakeling bouwt die dit signaal zal aanleggen. Het probleem is dat een dergelijke schakeling zelf een kloksignaal nodig heeft. We zullen dus een ander component nodig hebben. Twee populaire keuzes zijn het gebruik van een 555-timer en een kristal-oscillator. We zullen beide technieken kort bespreken.
8.4.1
555-timer
De 555-timer3 is een ge¨ıntegreerd circuit die gebruikt wordt om allerhande periodieke functies te implementeren. Het component kost los rond de $2.50. Een 555-timer kan kloksignalen produceren tot ongeveer 300 kHz. Pinout en interface Een 555-timer is een component met 8 verbindingen. Figuur 8.8(a) geeft de pinout van de chip met DIP packing weer. In een blokdiagram tekent men een 555-timer meestal met vaste posities voor de verschillende
Output 2
Trigger 2
Trigger 1
GND
5
(b) 555-interface
Reset 1
1
Control 1
2
Threshold 1
(a) 555-timer pinout
3
555
Discharge 1
Reset
Output
Trigger
Output 1
556
4
7 6
GND
Reset 2
Control 2
Threshold 2
555
Discharge 2
Vcc
Control Voltage
Threshold
Discharge
Vcc
8
(c) 556-timer pinout
Figuur 8.8: De pinout van de 555-timer en 556-timer. in- en uitgangen. Figuur 8.8(b) toont deze posities samen met de nummers van de pinout. Werking De werking van de 555-timer is niet eenvoudig te verklaren. Dit komt omdat men een dergelijk timer implementeert met complexe analoge elektronica zoals operationele versterkers. Zonder in detail te treden zullen we verklaren hoe we een 555-timer als kloksignaal kunnen gebruiken. De ground pin en de power pin leggen een spanning aan op de component zodat het kan functioneren. Daarnaast bevat de 555-timer een interne flipflop. De toestand van deze flipflop (0 of 1) wordt aangelegd op de output pin. Twee ingangen 3 Soms
uitgesproken als “triple five” of “triple five timer”.
294
HOOFDSTUK 8. CIRCUITS SCHAKELEN
dienen vervolgens om het signaal om te wisselen: de trigger en de threshold. De trigger is een ingang die de flipflop op 1 zet op het moment dat de spanning hoger wordt dan 1/3 van de spanning die op de Vcc staat. De threshold werkt omgekeerd: de ingang is gevoelig voor spanning boven 2/3 van de spanning op de Vcc. Indien op dat moment de trigger een spanning heeft groter dan 1/3, wordt de flipflop terug op 0 gezet. De overige pinnen zijn van minder belang. De controle pin kan de waarde van de threshold aanpassen. Wanneer we dus een vaste kloksignaal willen genereren is het belangrijk dat de control pin ten alle tijde op een vaste spanning staat. Daarom wordt de controle pin meestal via een condensator verbonden met de negatieve pool van de stroombron. Vermits een condensator behoudt van spanning nastreeft, is dit dus de beste garantie op een constante spanning op de controle-ingang. De discharge ingang is een verbinding die stroom naar de ground laat vloeien op het moment dat de output hoog is. Wanneer de output laag is, is de discharge hoog impedant. De reset pin ten slotte zal de output terug op 0 zetten wanneer men een lage spanning4 aanlegt. Meestal is de reset-ingang aangesloten op de positieve pool van de stroombron om dit te vermijden.
U (C1 )
U (output)
V
1V
2/3 V
8
R1
1/3 V
4
7 6
0V
3
555
0V
2
t C1
t 1
5
100n
Figuur 8.9: Schakeling voor de implementatie van een kloksignaal met een 555-timer Op basis van de beschrijving kunnen we een eenvoudige schakeling met een RC-keten ontwerpen die een kloksignaal zal genereren. Deze schakeling staat beschreven in Figuur 8.9. Op het moment dat men een spanning op de schakeling aanlegt, is de condensator C1 niet opgeladen en het output-signaal van de 555timer is hoog. Bijgevolg wordt de condensator opgeladen door de RC-keten. Op het moment dat de spanning van de condensator (de spanning tussen pin 1 en pin 6) 2/3 van de totale spanning bereikt, wordt de output op laag gezet. Vanaf dat moment begint de condensator te ontladen. De spanning over de condensator neemt bijgevolg af en op het moment dat spanning onder 1/3 van de totale spanning gaat, detecteert de trigger dit. Op dat moment wordt de output terug hoog en begint de cyclus opnieuw. Omdat het opladen en ontladen van tussen 1/3 en 2/3 van de spanning in de RC-keten even lang duurt, is de duty cycle bijgevolg 50%. Figuur 8.9 toont ook de spanning van de output en de condensator op verschillende momenten in de tijd. De stippellijnen op de grafiek van de condensator tonen het verdere verloop van de functie indien de output-niet zou worden omgedraaid. De frequentie van het kloksignaal hangt duidelijk af van de parameters van de RC-keten. Een condensator wordt op- en ontladen volgens volgende functies: Uop (t) Uont (t)
= Uf − (Uf − U0 ) · e−t/R1 ·C1 = U0 · e
−t/R1 ·C1
(8.5) (8.6)
Met U0 de beginspanning en Uf de spanning die op de keten wordt aangelegd. In een halve klokcyclus wordt de spanning dus opgeladen van 1/3 V naar 2/3 V of ontladen van 2/3 V naar 1/3 V . De tijd die hierbij verstrijkt is dus gelijk aan: ∆t = −R1 · C1 · ln (1/2) = ln (2) · R1 · C1 ≈ 0.693147181R1 · C1 4 Beneden
een spanning van 0.8 V tegenover de ground.
(8.7)
8.4. IMPLEMENTATIE VAN EEN KLOKSIGNAAL
295
De frequentie van het kloksignaal is bijgevolg gelijk aan: f=
1 1 1 0.72134752 = = ≈ 2∆t 2 · ln (2) · R1 · C1 ln (4) · R1 · C1 R1 · C 1
(8.8)
Meer informatie over de implementatie, de werking en concrete oscillator-schakelingen is te vinden in [?]. 556-timer Tot slot introduceren we ook nog een andere populaire ge¨ıntegreerde schakeling: de 556-timer. Deze ge¨ıntegreerde schakeling is eigenlijk niets anders dan twee 555-timers in ´e´en chip. Het voordeel van dergelijke chips is dat bepaalde in- en uitgangen gedeeld kunnen worden. In het geval van de 556-timer is dat het geval voor de power pin en ground pin.
8.4.2
Astabiele multivibrator
Een andere manier om een kloksignaal te implementeren is door een oscillator te implementeren. De meeste oscillatoren werken op basis van het volgende principe: een we beschouwen een transistor die een zekere weerstand tussen de collector en emitor aanbrengt. De weerstand wordt bepaald door de spanning tussen de basis en de emitor. Door een schakeling te implementeren die de weerstand negatief terugkoppelt naar de basis en hierover een zekere tijd laat verstrijken kunnen we een oscillator bouwen. Een dergelijke feedback schakeling moet dus in het geval van een PNP-transistor bij een lage weerstand de spanning op de basis verlagen en bij een hoge weerstand de spanning aan de basis opdrijven.
+V R1
R2 C1
R3
R4 C2
0V Figuur 8.10: Astabiele multivibrator. Een typische manier om dit te realiseren is een symmetrische schakeling met twee PNP-transistoren en twee RC-ketens zoals ge¨ıllustreerd op Figuur 8.10. Deze schakeling werkt als volgt. We beschouwen een toestand waarbij de eerste transistor gesloten is5 en de andere transistor gesloten.
8.4.3
Kristal-oscillator
Een nadeel van de 555-timer is dat de periodieke functie meestal niet nauwkeurig wordt aangelegd. Componenten op basis van transistoren en weerstanden zijn bijvoorbeeld onderhevig aan de temperatuur. Indien men dus een kloksignaal met een zekere frequentie aanlegt kan men fluctuaties op die frequentie verwachten. Zolang de frequentie laag is, levert dit weinig problemen op: de componenten rekenen immers zo snel dat de data lang op de ingangen van de registers staat alvorens ze worden ingeladen. Wanneer men echter een processor implementeert, wil men een hoge kloksnelheid die zo weinig mogelijk tijd de data onbenut laat. Ook bij hoge frequenties blijft er echter sprake van ruis. In dat geval kan de ruis het verschil maken tussen de correcte data die aan de ingang van een register staat, of oude of tijdelijke data. 5 Een
transistor is gesloten wanneer er stroom vloeit van de collector naar de emitor. In het ander geval is de transistor open.
296
HOOFDSTUK 8. CIRCUITS SCHAKELEN
In dergelijke gevallen zal men opteren voor een kristal-oscillator. Een kristal-oscillator werk op basis van pi¨ezo-elektromagnetisme. De fysica achter dit proces valt buiten het bereik van deze cursus. Men kan echter stellen dat het een component is die op basis van een kwartskristal met een zeer vaste frequentie van weerstand varieert. De afwijkingen worden dan ook uitgedrukt in “parts per billion (ppb)”.
8.5
Printed Circuit Board (PCB) Layout
In vakbladen zal men meestal naast de schakeling ook een “printed circuit board (pcb) layout” weergeven. Dit is een schematische weergave hoe men de schakeling compact kan realiseren op een printplaat. Een dergelijke afbeelding dient niet om de schakeling te analyseren, maar enkel om de schakeling zelf op een effici¨ente manier te realiseren. Een probleem met dergelijke plannen is dat men andere symbolen gebruikt om de componenten voor te stellen: meestal wordt de basisvorm van het relevante component weergegeven, bovendien dient men ook twee lagen weer te geven: de boven- en onderkant van de printplaat. De meeste afbeeldingen lossen het probleem van de twee lagen op met behulp van kleur: in deze cursus zullen we de voorzijde afbeelden in het zwart en de achterzijde in het grijs. Het probleem met het toewijzen van componenten wordt meestal aangepakt door de componenten te labelen. Meestal wordt hierbij het type component (weerstand, condensator, ...) weergegeven, maar de meest relevante eenheid van de component. Zo zal bij een condensator de capaciteit in micro-Farad worden weergegeven. Bij wijze van introductie toont Figuur 8.11 een overzicht van de symbolische weergaven van enkele populaire componenten.
capacitor 1 nF
1N60P
(a) Condensator.
(b) Diode.
4017
diode
wire
(c) DIP-chip.
L01
(d) Draad.
transistor
X01
X01
U01 (e) Kristal-oscillator.
(f) LED.
(g) Schakelaar.
(h) Transistor.
resistor USB01
(i) USB-verbinding.
200k (j) Weerstand.
Figuur 8.11: PCB-weergave van populaire componenten.
8.6. OPROEP AAN DE LEZERS
297
Een PCB-layout kan ook digitaal worden ingevoerd. Bijvoorbeeld met gEDA of Gerber. Bovendien kan deze software op basis van de gegevens een lijst met specificaties maken waar gaten in de printplaat moeten worden geboord, waar de geleiders moeten worden aangebracht en welke componenten worden gebruikt en waar deze moeten worden aangebracht. Dit proces kan bovendien worden geautomatiseerd door relevante apparatuur aan te sturen. Dit ligt buiten het bereik van deze cursus.
8.6
Oproep aan de lezers
De auteur roept enthousiaste lezers op om projecten te delen zodat deze in deze cursus kunnen worden gepubliceerd als een hoofdstuk in dit deel. Men kan echter niet elk project als nuttig beschouwen. Ingediende projecten moeten aan enkele voorwaarden voldoen: 1. De componenten in het project dienen in de cursus vermeld te worden. Het is niet de bedoeling om “exotische componenten” te introduceren, in het bijzonder denken we dan aan componenten uit de analoge elektronica (operationele versterker, spoel, ...). Sommige projecten kunnen een klein aantal van dit soort componenten bevatten. In dat geval dient men een korte beschrijving van de werking bij te voegen. 2. Het project moet realiseerbaar zijn. Zowel op een op maat gemaakte printplaat als bijvoorbeeld een europrintplaat. Verder is het evenmin de bedoeling dat het project veel werk vereist en het resultaat weinig inzichten zal verwerken (hierbij denken we bijvoorbeeld aan een 1024-bit opteller). 3. De effecten die in het project beschreven worden moeten te verklaren zijn, en dit op basis van de cursus. Indien het project aan deze voorwaarden voldoet maakt het kans om opgenomen te worden. Een lezer kan een project indienen op volgend adres: http://goo.gl/rzIlr3. Een “aanvraag” bestaat uit ´e´en of meerdere schema’s samen met een verslag. Dit verslag bevat een lijst van benodigde componenten, aanwijzingen bij de bouw van de schakeling en een tekst die de werking verklaart. Het verslag mag figuren bevatten die de werking verder uitleggen. Omdat een dergelijke aanvraag veel werk vraagt, kan men ook een “voor-aanvraag” indienen (op hetzelfde webadres). In een voor-aanvraag specificeert men kort het project in een tekst van maximaal ´e´en pagina. Op basis van de reactie van de auteur kan men dan beslissen om al dan niet een aanvraag in te dienen.
298
HOOFDSTUK 8. CIRCUITS SCHAKELEN
Hoofdstuk 9
Experimenten leven is niets dan een experiment. Hoe meer je experimen“ Het teert, hoe beter. - Ralph Waldo Emerson, Amerikaans dichter en filosoof (1803-1882)
”
In dit hoofdstuk beschrijven we enkele experimenten die we kunnen uitvoeren om praktische en nuttige digitale schakelingen te realiseren voor dagelijks gebruik. 9.1
Oneindig vermenigvuldigen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 9.1.1
Benodigdheden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
9.1.2
Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
9.1.3
Realisatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
Implementatie-specificaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 Toestanden en soorten schakeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 Toestandscodering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Type flipflop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Implementatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 9.2
Fietslicht
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
9.2.1
Benodigdheden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
9.2.2
Implementatie-specificaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
9.2.3
Realisatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 Toestandstabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 Toestandscodering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 Type flipflop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 Implementatie in poortlogica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
9.3
Tic tac toe-machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 9.3.1
Benodigdheden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
9.3.2
Implementatie-specificaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
299
300
9.1
HOOFDSTUK 9. EXPERIMENTEN
Oneindig vermenigvuldigen
´ en van de voordeling van delen en vermenigvuldigen met constanten, is dat de overdracht of het lenen ook E´ beperkt is. Wanneer we een binair getal bijvoorbeeld vermenigvuldigen met 3, kan de carry nooit groter worden dan 4. Wanneer we dit veralgemenen naar een vermenigvuldiging in het binair stelsel met n, kan de overdracht nooit groter worden dan 2·n−1. We kunnen dit uitbuiten om een sequenti¨ele vermenigvuldiger te maken die over bit-stromen met oneindige lengte werkt. We realiseren dus een schakeling waar als invoer een stroom aan bits en het bijbehorende kloksignaal binnenkomt, en als uitvoer een andere stroom bits geklokt volgens hetzelfde kloksignaal maar waarbij de bits het k-voud voorstellen van de inkomende bitstroom. We werken volgen big-endian encodering: de eerste bit die in de schakeling binnenkomt is altijd de minst significante.
9.1.1
Benodigdheden
Dit hangt grotendeels af van de constante k waarmee we willen vermenigvuldigen. Voor een constante k = 5 zijn de benodigdheden de volgende: 1. 2 leds; 2. 3 npn-transistoren; 3. 1 pnp-transistoren; 4. 2 drukschakelaars. Samen kosten deze componenten (zonder gereedschap, printplaten en soldeersel) ongeveer e ??.??1 .
9.1.2
Model
In de inleiding hebben we de werking van de component niet gespecificeerd. Dit zullen we in deze sectie doen. Wanneer een getal bit-na-bit wordt ingelezen in het circuit, dient het circuit dit getal de vermenigvuldigen. We kunnen echter de eigenschap uitbuiten dat de overdracht die bij de vermenigvuldiging optreedt, altijd eindig zal zijn. Bij voorbeeld zullen we een vermenigvuldiging met k = 5 modelleren.
0/0
q0
1/1
0/0
q4
1 1/
0/0
1 0/ q2
q8
1/0
1/0
start
1/1
q6
0/1 Figuur 9.1: Een toestandsdiagram voor k = 5. De machine begint in een toestand waar er geen overdracht is, formeler c = 0. Dit is de toestand q0 op Figuur 9.1. Wanneer er nu een 0 binnenkomt, is het resultaat logischerwijs 0 en blijft de overdracht ook op 0 staan. We trekken dus een lus vanuit q0 met boog 0/0. Wanneer er echter een 1 op de invoer wordt aangelegd, dan weten we dat de uitvoer-bit ook 1 moet worden, en dat we vanaf dat moment met overdracht c = 4 moeten rekening houden. Nu hebben we alle invoer voor q0 gemodelleerd, maar q4 dienen we verder 1 Gebaseerd
op prijzen bij Conrad.
9.1. ONEINDIG VERMENIGVULDIGEN
301
in te vullen. In het algemeen geldt de regel voor een vermenigvuldiging van k dat we een boog van qi naar qj trekken met label bi /bo zodat: bi ∈ {0, 1} i r = + k · bi 2 bo = r mod 2
(9.3)
j = r − bo
(9.4)
(9.1) (9.2)
Voor q4 betekent dit dus dat we een boog 0/0 naar q2 trekken en een boog 1/1 naar q6 . We dienen vervolgens ook bogen uit deze toestanden te trekken en dit tot er geen nieuwe toestanden meer opduiken. We bekomen vervolgens een diagram zoals op Figuur 9.1. We kunnen dit voor iedere k doen. Implementatie-specificaties Reset Getallen hebben altijd een eindig aantal cijfers en bijgevolg ook een eindig aantal bits. We willen de schakeling dan ook niet noodzakelijk gebruiken om een product uit te rekenen over een oneindige sequentie bits. Maar wel op een snelle manier getallen van willekeurige lengte vermenigvuldigen. We dienen echter aan het circuit duidelijk te maken dat we een nieuw getal willen vermenigvuldigen. We kunnen dit op twee manieren doen: 1. We lezen de resterende bits uit door telkens 0 op de ingang aan te leggen tot het circuit zich terug in toestand q0 bevindt, dit duurt hoogstens log2 (n) + 1 stappen. Dit is ook in principe de correcte methode omdat het resultaat van een vermenigvuldiging nu eenmaal een getal met meer bits kan opleveren. Een nadeel is echter wanneer we dit circuit in een processor zouden gebruiken, waarbij de registers een beperkt aantal bits hebben, we meestal ge¨ınteresseerd zijn in de n minst significante bits2 , en we dus klokflanken “verspillen”. 2. We voorzien een reset-ingang die de schakeling terug in de grondtoestand brengt. De meest significante bits gaan verloren. In dit voorbeeld kiezen we voor de eerste variant. Dit houdt immers ook het circuit eenvoudig en goedkoop. In- en Uitvoer Normaal kunnen we een dergelijk circuit gebruiken in bijvoorbeeld een processor, of kunnen we het in een ethernet-kaart implementeren wanneer data moet worden aangepast. Wanneer we echter de schakeling op zichzelf willen implementeren, dienen we deze te kunnen testen. Bijgevolg zullen we ook invoer-uitvoer voorzien. Communicatie tussen mens en modules wordt meestal gerealiseerd met behulp van leds en schakelaars. Om duidelijk te maken welk signaal we zelf zullen aanleggen zullen we ook leds aan de ingang gebruiken. Een probleem die zich soms stelt is dat er een groot aantal bits aan de invoer kunnen worden aangelegd, en het dus niet eenvoudig is om met drukschakelaars een bepaalde configuratie aan te leggen. In dat geval kunnen we gebruik maken van een tuimelschakelaar. Een tuimelschakelaar kan worden aangekocht, maar ook ge¨ımplementeerd met behulp van een drukschakelaar, twee weerstanden, een pnp- en npn-transistor. Een dergelijke implementatie staat beschreven in Figuur 9.2.
9.1.3
Realisatie
Toestanden en soorten schakeling In de vorige subsectie hebben we besproken hoe we een diagram kunnen opstellen voor de overdracht. Dit diagram is precies het diagram voor de Mealy-machine om onze schakeling te realiseren. We kunnen het diagram dus rechtstreeks gebruiken om een toestandstabel op te stellen zoals in Tabel 9.1. 2 Analoog
met de overloop bij bijvoorbeeld een optelling.
302
HOOFDSTUK 9. EXPERIMENTEN VDD 20k output
100k
VSS
Figuur 9.2: Implementatie van een tuimelschakelaar. Toestand q0 q2 q4 q6 q8
I 0
1
q0 /0 q0 /1 q2 /0 q2 /1 q4 /0
q4 /1 q6 /0 q6 /1 q8 /0 q8 /1
Tabel 9.1: Toestandstabel van de oneindige vermenigvuldiger. Toestandscodering We dienen nu enkel nog een codering te bedenken om de verschillende toestanden op te slaan. Een logische manier kan zijn om qi op te slaan als het binaire equivalent van i/2. Dit biedt bovendien in dit geval vrij mooie overgangen: bij twee overgangen verandert er geen bit, bij vijf overgangen slechts ´e´en bit, ´e´en overgang brengt twee veranderingen teweeg en ´e´en overgang drie. We kunnen echter q8 ook encoderen als 111. Dit zorgt ervoor dat er geen overgangen met drie bits meer zijn. Dit is natuurlijk heuristisch: er is geen echte garantie dat dit effectief tot een goedkopere implementatie zal leiden, al wordt het wel verondersteld. De coderingstabel wordt dan zoals voorgesteld als in Tabel 9.2 Toestand 000 001 010 011 111
I 0
1
000/0 000/1 001/0 001/1 010/0
010/1 011/0 011/1 111/0 111/1
Tabel 9.2: Coderingstabel van de oneindige vermenigvuldiger.
Type flipflop Het is niet echt duidelijk welk type flipflop hier nodig is. We zullen de schakeling met een D-flipflop implementeren. Wanneer we D-flipflops gebruiken bekomen dienen we combinatorische schakelingen te implementeren zoals op Tabel ?? een grafische voorstelling met behulp van Karnaugh-kaarten staat op Figuur 9.3.
9.1. ONEINDIG VERMENIGVULDIGEN
303
q2
q1
q0
I
d2
d1
d0
O
0 0 0 0 0 0 0 0 1 1 −
0 0 0 0 1 1 1 1 1 1 −
0 0 1 1 0 0 1 1 1 1 −
0 1 0 1 0 1 0 1 0 1 −
0 0 0 0 0 0 0 1 0 1 −
0 1 0 1 0 1 0 1 1 1 −
0 0 0 1 1 1 1 1 0 1 −
0 1 1 0 0 1 1 0 0 1 −
Tabel 9.3: De oneindige vermenigvuldiger. d2
d1
q0
q0
O
I
q0 0 1 0 1 0 1 0 1 - 0 1 - - - -
q1
I
q2
0 0 1 0 1 1 1 1 - 0 1 - - - -
q1
q2
0 0 1 1 0 0 1 1 - 1 1 - - - -
q1
q2
I
q1
q2
0 0 0 0 0 0 1 0 - 0 1 - - - -
d0
q0
I
Figuur 9.3: Karnaugh-kaarten voor de oneindige vermenigvuldiger. Implementatie Tot slot dienen we enkel nog de schakeling te implementeren. Het logische circuit staat om dit te realiseren staat op Figuur 9.4. In de praktijk worden poorten meestal niet per eenheid verkocht: het is goedkoper om vier poorten op ´e´en chip te zetten dan vier afzonderlijke chips te produceren. Bijgevolg dienen we nog een keuze te maken hoe we deze schakeling realiseren. Wanneer we naar de schakeling op Figuur 9.4 kijken, kunnen we de verschillende types poorten tellen: 1. 3× NOT poort; 2. 2× 2-NOR poorten; 3. 1× 3-NOR poort; 4. 4× 2-NAND poorten; 5. 2× 3-NAND poorten; en 6. 3× D-flipflops. Op chipniveau zullen we daarom werken met volgende poorten: 1. 1× 7400 (4× 2-NAND poorten), DIP14, ongeveer e 00.14 per stuk; 2. 1× 7404 (6× NOT-poorten), DIP14, ongeveer e 00.17 per stuk; 3. 1× 7410 (3× 3-NAND poorten), DIP14, ongeveer e 00.32 per stuk; 4. 1× 7427 (3× 3-NOR poorten), DIP14, ongeveer e 00.32 per stuk; en 5. 2× 7474 (2× D-flipflops), DIP14, ongeveer e 00.14 per stuk; Hieruit kunnen we dan een printplaat samenstellen zoals op Figuur 9.5.
304
HOOFDSTUK 9. EXPERIMENTEN
D
Q
Clk
D
Q
Q
Clk
D
Q
Q
Clk
Q
O
I q0 q1 q2 Figuur 9.4: Mogelijke implementatie voor de oneindige vermenigvuldiger.
20k
20k 2N3906
2N3906
U0
U1 100k
100k
2N3904
USB
2N3904 7474
7474
7407
7410
7410
7410
Figuur 9.5: Printplaat-ontwerp voor de oneindige vermenigvuldiger.
9.2
Fietslicht
Men kan vandaag fietslichten kopen met verschillende knippermodes. Bij wijze van experiment zullen we een knipperlicht implementeren gebaseerd op een ledlamp van Hema. Het fietslicht bestaat uit drie leds en kent 4 standen: uit, links-rechts, knipperen en aan. Figuur 9.6 beschrijft de verschillende modi. Men verandert de modus door een drukschakelaar in te duwen. In het geval dat men in knipper-modus staat, is de frequentie waarmee men van toestand van led verandert, slechts de helft.
9.2.1
Benodigdheden
Volgende componenten heeft men nodig om deze schakeling te implementeren: • 3 leds
9.2. FIETSLICHT
305
uit
links-rechts
aan
knipperen
Figuur 9.6: De verschillende standen van een Hema-fietslicht • 3 NPN transistoren. Bij voorkeur BC547C • 3 weerstanden van 1 kΩ. • 1 drukschakelaar. • 1 europrintplaat. Alle componenten zijn verkrijgbaar bij Conrad. De richtprijs is ongeveer e ??.??.
9.2.2
Implementatie-specificaties
In deze subsectie bespreken we hoe we de schakeling zullen implementeren. Dit betekent dat we onder meer de in- en uitvoer vastleggen. In- en Uitvoer Naast de drie leds van het fietslicht is er geen uitvoer: we gaan er immers vanuit dat een gebruiker door op de drukschakelaar te duwen de werking van het licht zelf kan leren. Als invoer voorzien we ´e´en enkele drukschakelaar. We realiseren de in- en uitvoer aan de hand van de schakeling op Figuur 9.7. VDD l2 l1 l0
k0 1k
white
1k
white
1k
white
VSS Figuur 9.7: De IO-module van het fietslicht
306
HOOFDSTUK 9. EXPERIMENTEN
Toestanden en soort schakeling We dienen ook te beslissen wat soort schakeling we zullen implementeren. Vermits het aantal toestanden en de mogelijkheden nogal beperkt is, is het implementeren van een processor niet nodig: we kunnen deze schakeling met een eenvoudige sequenti¨ele schakeling realiseren. Verder dienen we te beslissen of we een synchrone of asynchrone schakeling zullen bouwen. Er speelt natuurlijk een tijdsaspect: we willen niet dat we meteen in de volgende toestand geraken wanneer een led aan of uitgaat. Anders is het verschil tussen knipperen en aan moeilijk te zien. We kunnen echter ook het kloksignaal als een ingangsignaal beschouwen. Dit laatste pleit voor een asynchrone schakeling: er is sprake van twee soorten ingangen: de schakelaar van het fietslicht die aangeeft dat we een volgende toestand willen kiezen, en het kloksignaal die wanneer het opkomt betekent dat we de bij links-rechts en knipperen leds aan of uit moeten zetten. Een asynchrone schakeling is echter moeilijker te implementeren. Wanneer we voor een synchrone schakeling opteren zal de gebruiker wanneer hij de schakelaar induwt moeten wachten tot het volgende kloksignaal voor de volgende stand van het fietslicht wordt geactiveerd. Het tijdverlies valt echter goed mee en is meestal niet levensbedreigend. In dit boek kiezen we daarom voor een synchrone schakeling. Verder rest ons nog het aangeven van de verschillende toestand en wat we doen wanneer een gebruiker de schakelaar indrukt. In principe zijn hier drie mogelijkheden. Iedere keer wanneer de gebruiker de schakelaar indrukt, dan komen we in de begintoestand van de stand. We kunnen ervoor opteren terecht te komen in een toestand die bijvoorbeeld globaal bepaald is: wanneer er k ticks geweest zijn komen we in de k mod n-de toestand terecht, met n het aantal toestanden van die stand. Een laatste optie is dat het niet uitmaakt, zolang we maar in een toestand terechtkomen die geldig is voor die stand. We opteren in deze cursus voor de eerste optie, dit is ook zo bij het echte fietslicht van Hema.
9.2.3
Realisatie
Toestandstabel Op basis van de specificaties zullen we een toestandstabel opstellen. De uitgangssignalen van de sequenti¨ele schakeling zijn drie bits: voor elke led betekent 1 dat de overeenkomstige led zal branden, in het geval van 0 brandt de led natuurlijk niet. Verder voorzien we ´e´en ingangssignaal: dit signaal is 1 wanneer de gebruiker de schakelaar indrukt. In het geval de schakelaar niet ingedrukt is, is het signaal 0. Dit levert ons de toestandstabel op zoals Tabel 9.4. In de tabel hebben we de toestanden geannoteerd met de stand in Toestand a0 b1 c1 d1 e1 f1 g1 h1 i1
k0
l0
0
1
a0 c1 d1 e1 f1 g1 h1 i1 j1
b1 n2 n2 n2 n2 n2 n2 n2 n2
0 0 0 0 0 0 1 0 1
l1 0 0 0 0 1 0 0 0 0
l2 0 0 1 0 0 0 0 0 0
Toestand j1 k1 l1 m1 n2 o2 p2 q2 r3
k0 0
1
k1 l1 m1 b1 o2 p2 q2 n2 r3
n2 n2 n2 n2 r3 r3 r3 r3 a0
l0
l1
l2
0 0 0 0 0 0 1 1 1
0 1 0 0 0 0 1 1 1
0 0 0 1 0 0 1 1 1
Tabel 9.4: Toestandstabel van het fietslicht. subscript (0 uit, 1 links-rechts, 2 knipperen, 3 aan). In stand 2 moest de frequentie gehalveerd worden. Dit hebben we opgelost door vier toestanden te voorzien: twee wanneer alle leds uit zijn, en twee wanneer alle leds branden. Op die manier kost het twee klokflanken vooraleer de leds veranderen. Toestandscodering In totaal hebben we 18 toestanden nodig om de schakeling te realiseren. Een toestand zal dus worden ge¨encodeerd op minstens 5 bits. We kunnen er ook voor opteren om de toestand van de leds rechtstreeks in
9.3. TIC TAC TOE-MACHINE
307
het geheugen te encoderen. In dat geval hebben we drie bits nodig om de toestand van de leds weer te geven en vier overige bits3 . Dit zou neerkomen op zeven bits wat vrij duur is. We zullen de toestand voorstellen aan de hand van 5 bits. Nadat we het aantal bits bepaald heb dienen we nog voor elke toestand een codering te voorzien. Hier proberen we de transitie- en uitvoerlogica mee te vereenvoudigen. We zien dat de links-rechts staat de meeste toestanden gebruikt. We zullen dit dan ook encoderen op zo’n manier dat de eerste bit 1 aanwijst en de overige bits werken volgens het principe van een 4-bit gray-teller. De overige standen zullen allemaal met een 0 beginnen. Ook hier proberen we enige logica in de codering te stoppen. Zo spreekt het voor zich dat we de uit-toestand code 00000a toewijzen: we kunnen logica voorzien die wanneer bepaalde bits passief zijn, alle leds meteen niet branden. De eerste en tweede toestand van de knipper-stand geven we dan weer de coderingen 01000n en 01001n . Alle leds moeten branden in de laatste twee toestanden van de knipper-stand en de enige toestand van de aan-stand. We coderen deze toestanden respectievelijk met 01101p , 01100q en 01110r . De volledige coderingstabel staat beschreven in Tabel 9.5. Toestand 00000a 10000b 10001c 10011d 10010e 10110f 10111g 10101h 10100i
k0
l0
0
1
00000a 10001c 10011d 10010e 10110f 10111g 10101h 10100i 11100j
10000b 01000n 01000n 01000n 01000n 01000n 01000n 01000n 01000n
0 0 0 0 0 0 1 0 1
l1 0 0 0 0 1 0 0 0 0
l2 0 0 1 0 0 0 0 0 0
Toestand 11100j 11101k 11111l 11110m 01000n 01001o 01101p 01100q 01110r
k0 0
1
11101k 11111l 11110m 10000b 01001o 01101p 01100q 01000n 01110r
01000n 01000n 01000n 01000n 01110r 01110r 01110r 01110r 00000a
l0
l1
l2
0 0 0 0 0 0 1 1 1
0 1 0 0 0 0 1 1 1
0 0 0 1 0 0 1 1 1
Tabel 9.5: Coderingstabel van het fietslicht.
Type flipflop Na het opstellen van de coderingstabel dienen we het type flipflop uit te kiezen. Implementatie in poortlogica
9.3
Tic tac toe-machine
Tic tac toe is een spel waarbij twee spelers beurtelings een zet spelen. Tijdens een zet schrijft een speler een cirkel of een kruis op het scorebord, een 3 × 3 raster. De eerste speler zet altijd een cirkel, de tweede een kruis. Elke speler probeert een situatie te bekomen waarbij drie van de eigen symbolen op een rij staan. Het spel is simpel en kan daarom goedkoop op zelf in electronica ge¨ımplementeerd worden. We zullen bij dit experiment twee schakelingen ontwerpen en realiseren: een schakeling zodat twee personen tegen elkaar spelen, en een schakeling waarbij het ook mogelijk is om te spelen tegen een artifici¨ele intelligentie4 .
9.3.1
Benodigdheden
Volgende componenten heeft men nodig om deze schakeling te implementeren. 1. 22 leds waaronder 11 rode en 11 groene. 2. 11 NPN transistoren. Bij voorkeur BC547C. 3 Het
komt immers 9 keer voor dat alle leds uit zijn. Om een onderscheid te maken tussen de verschillende toestanden hebben we dus minstens 4 extra bits nodig 4 Deze AI-bot zal perfect spelen: als eerste speler zal hij altijd winnen
308
HOOFDSTUK 9. EXPERIMENTEN
3. 11 weerstanden van 1 kΩ. 4. 6 drukschakelaars. 5. 1 normale schakelaar. 6. 1 europrintplaat. Alle componenten zijn verkrijgbaar bij Conrad. De richtprijs is ongeveer e ??.??
9.3.2
Implementatie-specificaties
Alvorens we dit spel kunnen implementeren, zullen we eerst moeten specificeren hoe we bijvoorbeeld met de gebruiker(s) gaan communiceren, hoe we de toestand van het bord gaan voorstellen, hoe het spel verloopt, enzovoort. Uitvoer De uitvoer is een 3×3 bord waar op elke tegel in principe een cirkel of kruis kan worden geplaatst. Dit geeft dus ongeveer5 39 toestanden. De uitvoeren realiseren we aan de hand van leds. Op elk vakje brengen we twee leds aan, bijvoorbeeld een rode en groene. We maken de afspraak dat indien de rode led brandt, er een cirkel op het respectievelijke vak staat. Wanneer de groene led brandt stelt dit een kruis voor. Wanneer geen van de twee leds brandt is het vakje leeg. In het vorige hoofdstuk hebben we reeds beargumenteerd dat men niet zomaar leds aan de uitgang van een poort kan schakelen. We voorzien dus een relay-mechanimsme met behulp van transistoren6 . We dienen dus een schakeling te realiseren zoals op Figuur 9.8. Om te communiceren met de spelers is meer hardware nodig. Zo is het nuttig dat de schakeling aangeeft wie aan zet is, of de gespeelde zet legaal is en wie er gewonnen heeft. Daarom voorzien we nog twee leds: een rode en een groene. Wanneer ´e´en rode let brandt, is de eerste speler aan zet, in het geval van de groene led speelt de tweede speler. Wanneer een speler gewonnen is knippert de overeenkomstige led. Wanneer een speler een onmogelijke zet speelt, branden beide leds voor een korte periode allebei. Invoer We kunnen ervoor opteren om per vak een schakelaar te voorzien. Wanneer een speler dan op de schakelaar drukt, zal de schakeling de overeenkomstige led laten branden. Dit betekent echter dat we 9 schakelaars moeten voorzien. We hebben daarom besloten om aan de rand van de twee dimensies elk 3 schakelaars te voorzien. 3 schakelaars laten dus toe om de rij te specificeren, met de overige 3 kan een gebruiker de kolom aangeven. Ook vanuit educatief standpunt is deze beslissing positief: men zal immers meer logica moeten voorzien om de invoer te interpreteren. Spelverloop
5 Niet alle toestanden zijn mogelijk: wanneer bijvoorbeeld de tweede speler wint, is er altijd ´ e´ en vakje niet toegekend. Een situatie waarbij alle vakjes zijn opgevuld en er drie kruiss op ´ e´ en rij staan is bijgevolg niet mogelijk. 6 We kunnen in principe ook echte relays gebruiken. Leds hebben echter een laag verbruik waardoor de taak ook door transistoren kan worden uitgevoerd.
9.3. TIC TAC TOE-MACHINE
309
VDD i0,0,0 i0,0,1
1k
i0,1,0 i0,1,1
1k red 1k green
i0,2,0
1k red
i0,2,1
1k green 1k
i1,0,0 i1,0,1
red green 1k
i1,1,0 i1,1,1
1k red 1k green
i1,2,0
1k red
i1,2,1
1k green 1k
i2,0,0 i2,0,1
red green 1k
i2,1,0 i2,1,1
1k red 1k green
i2,2,0 i2,2,1
1k red 1k green 1k red green
VSS Figuur 9.8: Een led-matrix en invoer-component voor het tic tac toe spel.
310
HOOFDSTUK 9. EXPERIMENTEN
Deel VI
Appendices
311
(a) Nand.
(b) Nor.
(c) Xor.
(d) Xnor.
x
y
f
x
y
f
x
y
f
x
y
f
0 0 1 1
0 1 0 1
1 1 1 0
0 0 1 1
0 1 0 1
1 0 0 0
0 0 1 1
0 1 0 1
0 1 1 0
0 0 1 1
0 1 0 1
1 0 0 1
Tabel A.1: Waarheidstabellen voor complexe poorten. 313
314
BIJLAGE A. CONVENTIES EN SCHEMAS
Bijlage A
Conventies en Schemas A.1
Waarheidstabellen van basisschakelingen
A.1.1
Eenvoudige poorten
A.1.2
Complexe poorten
A.2
Lijst van component interfaces Poorten
Rekenkundig
Andere basisschakelingen
AND-poort
Carry-Lookahead Opteller (CLA) x y
Vergelijker
y x
f
s
OR-poort y x
f
NOT-poort x
f
NAND-poort y x
f
x
y
g
p
s
c
c
g p Carry-Lookahead Opteller-Generator g2 p2 g1 p1 g0 p0 p0,2 g0,2
g2 g0,2 p0,2
p2
g1
p1
g0
p0 c0
c3
c2
c1
c3
c2
c1
c
Andere basisschakelingen Multiplexer
NOR-poort
d3 d2 d1 d0
y x
f
s1 s0
s1 s0
XOR-poort y x
f
XNOR-poort y x
f Decoder
Decoder f
Rekenkundig Demultiplexer
Halve Opteller x y co
Demux
HA
s Volledige Opteller x y co
FA
Encoder
Encoder
ci
s
Figuur A.1: Lijst van component interfaces.
A.3. CONVENTIES
315
Basispoorten NOT x
z
AND y x
z
OR y x
z
Complexe Poorten NAND y x
NOR y x
XOR y x
Figuur A.2: Samenvattend schema: poorten en componenten (deel 1)
A.3
Conventies
A.4
Poorten
A.4.1
Basispoorten
A.4.2
Complexe Poorten
A.5
Componenten
A.5.1
Rekenkundige schakelingen
A.5.2
Geheugen schakelingen
A.5.3
Andere schakelingen
Multiplexer
A.6
Kostprijs van de Componenten
316
BIJLAGE A. CONVENTIES EN SCHEMAS
d3
d2
d1
d0
a0
a1 enable
R
EXE
DECODER
MUL TIPL
s1 s0
f
s3
(a) Multiplexer
s2
s1
(b) Decoder
s3 f
s2
s1
s0
DEMUX
ENCODER
any
s1 s0
d3
d2
d1
(c) Demultiplexer
s0
d0
f1 (d) Encoder
Figuur A.3: Andere combinatorische schakelingen
f0
A.6. KOSTPRIJS VAN DE COMPONENTEN
Component Absolute waarde Absolute waarde&Maximum Aftrekker Aftrekker&Maximum Aftrekker&Opteller AND-poort Full adder Maximum Maximum&Aftrekker Maximum&Absolute waarde Maximum&Opteller Minimax Minimum NAND-poort NOT-poort Opteller Opteller&Aftrekker Opteller&Maximum Register Teken aftrekking Tri-state buffer Vaste schuifoperatie 2-naar-1 multiplexer 4-naar-1 multiplexer 4 n-naar-1 multiplexer
317
Transistors
Logische blokken
32/bit 62/bit 38/bit 48/bit 48/bit 6/bit 36/bit 32/bit 48/bit 62/bit 66/bit 32/bit 32/bit 4/bit 2/bit 36/bit 48/bit 66/bit 44/bit 20/bit 10/bit 0/bit 12/bit 18/bit 2 · n + 2 · dlog2 ne + 2 · dlog2 n + 1e · n
2/bit 4/bit
Tabel A.2: De kostprijs van de verschillende componenten.
2/bit 2/bit 1/bit 2/bit 2/bit 2/bit 4/bit 5/bit 2/bit 2/bit 1/bit 1/bit 2/bit 5/bit 1/bit 1/bit 1/bit 2/bit
318
BIJLAGE A. CONVENTIES EN SCHEMAS
Bijlage B
Softwarepakketten die bezig zijn met software, zouden hun eigen hardware “ Mensen moeten bouwen. - Alan Kay, Amerikaans informaticus (1940-)
”
Bij het schrijven van de cursus Digitale Elektronica en Processoren werden enkele softwarepakketten geschreven. Deze software laat toe aan de lezer om zelf oefeningen te maken, oplossingen te controleren en op een geautomatiseerde manier kleine combinatorische en sequenti¨ele te realiseren alsook een processor te bouwen. In dit hoofdstuk geven we een kort overzicht van deze software. Voor het Linux besturingssysteem bestaat ook software die helpt bij het concreet realiseren van een schakeling op bijvoorbeeld een printplaat of het simuleren van een schakeling. Deze software wordt kort besproken in enkele secties. B.1 Geschreven software . . . . . B.1.1 De software installeren . . B.1.2 Invoer en Uitvoer . . . . . Commentaar . . . . . . . Bit . . . . . . . . . . . . . Bit-sequenties (bitstring) Tuples . . . . . . . . . . . Tabel . . . . . . . . . . . Schakeling . . . . . . . . . Karnaugh-kaart . . . . . . Assembler code . . . . . . Binaire code . . . . . . . B.1.3 Uitvoer . . . . . . . . . . B.1.4 Ondersteunde functies . . B.1.5 Functiecompositie . . . . B.2 Andere software . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
320 320 320 320 320 320 320 320 321 322 322 322 322 322 323 323
320
BIJLAGE B. SOFTWAREPAKKETTEN
B.1
Geschreven software
B.1.1
De software installeren
De software is geschreven in Haskell en kan worden gedownload op volgend adres: http://goo.gl/tkyilf. De code staat onder git-subversiebeheer. Bijdragen aan de software wordt aangemoedigd. Men kan de software gebruiken door de Makefile te draaien. Dit doet men door in de desbetreffende map het commando make te typen. Standaard wordt de software niet ge¨ınstalleerd op het systeem: de commando’s kunnen alleen in de map zelf uitgevoerd worden. Indien men de programma’s in om het even welke map wenst uit te voeren, kan men make install draaien.
B.1.2
Invoer en Uitvoer
Het programma neemt tekst als invoer en geeft tekst of diagrammen als uitvoer. We overlopen in de volgende subsubsecties de verschillende vormen van invoer. Commentaar Om toe te laten de invoer te annoteren met commentaar, worden alle lijnen die beginnen met een hashsymbool (#) genegeerd. Dit is conform Linux Bourne Again Shell (bash). Het verschil is echter dat enkel lijn die beginnen met het hash-symbool daarvoor in aanmerking komen. Bit Een bit is een logische waarde waarmee doorheen het volledige programma wordt gerekend. Een bit kent drie toestanden: waar (1), onwaar (0) en don’t care (-). Het programma is echter in staat op verschillende manieren een bit te lezen. Zo stellen t, T en 1 alle drie waar voor; f, F en 0 duiden onwaar aan; en d, D, x, X, - betekenen allemaal don’t care. Bit-sequenties (bitstring) Meestal beperkt een toestand, invoer en uitvoer zich niet tot ´e´en bit. Een bitstring is een sequentie van nul of meer bits. Men schrijft een bitstring eenvoudigweg aan de hand van een sequentie van voorstellingen voor bits zonder spaties of andere tekens. Een voorbeeld is t-TX1xfDFd0 een geldige representatie van een bitstring. Tuples In het geval van een Mealy-toestandstabel schrijven we in een cel niet alleen de volgende toestand, maar ook de te genereren uitvoer. Met andere woorden een koppel van twee bitsstrings. Koppels stellen we voor aan de hand van de elementen, gescheiden door een slash (/). Tabel Een tabel is een twee dimensionale structuur. Een tabel is onderverdeeld in cellen. Een horizontale groep cellen noemt men een rij, een verticale groep een kolom. De bovenste rij noemt men doorgaans de hoofding en verklaart meestal de inhoud van de cellen eronder. Cellen worden verticaal opgedeeld aan de hand van een verticaal streepje (|), horizontaal worden ze van elkaar onderscheiden door een nieuwe lijn. Optioneel kan men tussen twee lijnen ook een reeks streepjes (-) zetten, optioneel aangevuld met plus (+) en asterisk (*), een dergelijke lijn wordt eenvoudigweg genegeerd. Lijnen die echter enkel horizontale en verticale streepjes bevatten worden niet genegeerd: immers kan met het streepje als een don’t care interpreteren en het verticale streepje als een nieuwe kolom. De verticale streepjes hoeven niet op elkaar uitgelijnd te zijn: men kan bijvoorbeeld in de ene rij het eerste verticale streepje op positie 2 zetten terwijl dit in de lijn erna op positie 20 staat, maar het wordt toch aangeraden consistent te zijn.
B.1. GESCHREVEN SOFTWARE Voorbeeld
321
Een voorbeeld van een tabel is de volgende code:
dit| is | een | 001001-DXXD ----------------------------------geldige| 01111 | Tabel | a/0010 | Ook al | is | de | tabel | 111 ---------+-----+-------+--------+---moeilijk| leesbaar | | | Soorten tabellen Een tabel bevat data die door het programma verwerkt kan worden. Om een tabel te kunnen verwerken dient deze niet alleen syntax-matig in orde te zijn. Het is ook belangrijk wat er waar in de tabellen staat. Hieronder geven we een kort overzicht van de verschillende types tabellen: 1. Combinatorische tabel : Een tabel die uit twee kolommen bestaat. Alle cellen bestaan uit bit-sequenties. De lengte van de bit-sequenties van alle linkse cellen moet gelijk zijn, alsook deze uit de rechtse cellen. Een combinatorische tabel wordt geparsed van boven naar onder. Alle resultaten worden eerst op don’t cares gezet. Telkens wanneer men een rij inleest, wordt de bijbehorende invoer1 aangepast aan de overeenkomstige uitvoer. Wanneer dus een invoer tweemaal gespecificeerd wordt - bijvoorbeeld eerst aan de hand van een don’t care en daarna voluit - telt de laatste rij. Zoals gezegd tellen horizontale lijnen niet. 2. Toestandstabel : In de eerste kolom staan vanaf de tweede rij toestanden (tekst die geen bitstring voorstelt). Toestandstabellen komen verder in twee gedaantes voor: de Moore-toestandstabel en de Mealy-toestandstabel. 3. Moore-toestandstabel : Dit is een toestandstabel waarbij vanaf de tweede rij, de tweede tot en met de voorlaatste kolommen uit toestanden (tekst bestaat). In deze tabel staan in de eerste rij vanaf de 2-de tot en met de voorlaatste kolom bitstrings die invoer weergeven. De toestanden moeten ook gedefinieerd zijn ergens in een rij in de eerste kolom. In de laatste kolom staan vanaf de tweede rij bitstrings. 4. Mealy-toestandstabel : Dit is een toestandstabel waarbij vanaf de tweede rij, de tweede tot en met de laatste kolommen uit toestanden (tekst bestaat) gepaard met bitstrings. De toestand en de bitstring worden van elkaar onderscheiden door middel van een slash (/). De toestanden moeten ook gedefinieerd zijn ergens in een rij in de eerste kolom. 5. Coderingstabel : In de eerste kolom staan vanaf de tweede rij bitstrings. Coderingstabellen komen verder in twee gedaantes voor: de Moore-coderingstabel en de Mealy-coderingstabel. 6. Moore-coderingstabel: Dit is een coderingstabel die volledig uit bitstrings bestaat. In deze tabel staan in de eerste rij vanaf de 2-de tot en met de voorlaatste kolom bitstrings die invoer weergeven. De tabel bevat buiten de behalve de eerste rij en buitenste kolommen bitstrings die verwijzen naar toestanden. Deze toestanden moeten ook gedefinieerd zijn. In de laatste kolom staan vanaf de tweede rij bitstrings. 7. Mealy-toestandstabel : Dit is een toestandstabel waarbij vanaf de tweede rij, de tweede tot en met de laatste kolommen uit 2-tuples van bitstrings bestaat. De twee bitstrings worden van elkaar onderscheiden door middel van een slash (/). De toestanden moeten ook gedefinieerd zijn ergens in een rij in de eerste kolom. Schakeling Een schakeling beschrijft op poort-niveau, en soms op hoger niveau hoe verschillende componenten gegevens uitwisselen. Om het programma eenvoudig te houden werd niet geopteerd voor een grafische schil, maar voor tekstuele invoer. Een schakeling bestaat daarom uit twee delen: 1. Een lijst met componenten; en 1 Dit
kunnen er meerdere zijn in het geval de invoer een don’t care bevat.
322
BIJLAGE B. SOFTWAREPAKKETTEN
2. een lijst met verbindingen tussen deze componenten. Karnaugh-kaart Een Karnaugh-kaart is een grafische voorstelling van een booleaanse-functie. Karnaugh-kaarten worden enkel geproduceerd als uitvoer. Assembler code Assembler-code is een datastructuur die is afgeleid uit het hoofdstuk rond programmeerbare processoren (zie Hoofdstuk 6). Binaire code In hetzelfde hoofdstuk hebben we ook een binair equivalent beschouwd: namelijk per instructie wordt de instructie vertaalt naar een hoeveelheid bits, alsook de argumenten. Binaire code is niets anders dan een lange binaire sequentie.
B.1.3
Uitvoer
Standaard wordt de uitvoer in tekstvorm op de standaard uitvoer (stdout) geschreven. Men kan natuurlijk de shell functionaliteiten gebruiken om de uitvoer naar een bestand of een ander programma te schrijven. Afhankelijk van de functie kan men soms ook een ander formaat specificeren met de --ascii en --svg vlaggen om de uitvoer respectievelijk als webpagina of LATEX-code weer te geven.
B.1.4
Ondersteunde functies
De naam van het programma is dep. Aan de hand van een Linux alias kan men het commando dep ook associ¨eren met dat programma. Men dient het programma op te roepen met een instructie, bijvoorbeeld dep showKarnaugh. Met dep --help schrijft men een pagina met een lijst van ondersteunde functies naar de terminal. Men kan elke instructie ook aanroepen met de --help parameter om een overzicht te krijgen van wat de functie precies doet en de ondersteunde uitvoerformaten. 1. expand: neemt als invoer een combinatorische tabel en breidt deze uit zodat de don’t cares in de linkse kolom verdwijnen. 2. reduce: neemt als invoer een combinatorische tabel en reduceert deze enigszins. De reductie is niet minimaal maar is computationeel goedkoop en levert redelijke resultaten op. 3. lookup: neemt als invoer een combinatorische tabel en als query een bitstring en geeft als uitvoer indien de don’t cares in de query geen problemen opleveren - een bitstring van uitvoer terug. 4. showKarnaugh: toont ´e´en of meerdere Karnaugh-kaarten aan de hand van een ingegeven tabel. De kaarten worden standaard op de stdout geschreven. Men kan ook gebruik maken van de --svg optie om een grafische uitvoer te genereren. 5. synthesize: neemt als invoer een combinatorische tabel en genereert een beschrijving een “sum-ofproducts” om deze combinatorische schakeling te bouwen. 6. reduceFSM: neemt als invoer een toestandstabel of coderingstabel (Moore of Mealy mode) en stelt de minimale variant van de gegeven toestandstabel op. De resulterende toestandstabel is gegarandeerd minimaal in aantal toestanden.
B.2. ANDERE SOFTWARE
B.1.5
323
Functiecompositie
Wanneer men een lijst van verschillende commando’s na elkaar beschrijft, worden de commando’s van rechts naar links uitgevoerd en wordt de uitvoer van de eerste (meest rechtse) functie doorgegeven als invoer naar de tweede functie, enzovoort. Een compositie van verschillende functies kan effici¨enter zijn dan de commando’s zelf afzonderlijk uit te voeren via “pipes” in de Linux shell: allereerst worden de interne structuren niet telkens omgezet naar tekstvorm en terug en bovendien kunnen composities ook sneller worden uitgevoerd omdat een Haskell omgeving enkel termen zal uitrekenen wanneer deze echt nodig zijn.
B.2
Andere software
Het hoeft niet te verbazen dat gebruikers van het Linux besturingssysteem soms ook amateur elektrotechnici zijn, en zelf een omgeving ontwikkelen waarin men elektronica kan ontwikkelen, simuleren tot en met het ontwerpen van een printplaat.
324
BIJLAGE B. SOFTWAREPAKKETTEN
Bijlage C
Oplossingen van de Oefeningen C.1
Hoofdstuk 1
C.2
Hoofdstuk 2
C.3
Hoofdstuk 3
C.3.1
Karnaugh-kaarten
Invullen van Karnaugh-kaarten a
b
y 0 1 1 1
d
0 0 1 0
1 0 1 1
1 0 1 1
1 0 1 1
w g
1 0 1 1 1 1 1 1 - - - 1 - - 1 h
w
1 1 0 0 0 1 0 0 - - - 1 - - 0
1 1 1 0 0 1 0 1 - - - 1 - - 1
0 1 1 0 1 1 0 1 - - - 1 - - 1
f
e 1 1 1 1 1 0 1 0 - - - 1 - - 1
1 1 1 0 0 1 1 1 - - - 1 - - 1
x
0 1 1 1
x
0 1 1 1
y
x
w
0 1 1 1
c
y
i 1 0 0 0 1 1 0 1 - - - 1 - - 1
z
z
z
Figuur C.1: Oplossingen van het invullen van de Karnaugh-kaarten.
325
326
BIJLAGE C. OPLOSSINGEN VAN DE OEFENINGEN
Lijst van tabellen 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9
Waarheidstabellen van de basisoperaties. . . . . . . . . . . . . Waarheidstabel voor de implementatie van een XOR. . . . . . Implementatie van de basispoorten met behulp van NAND en Booleaanse algebra zonder variabelen. . . . . . . . . . . . . . Booleaanse algebra met ´e´en variabele. . . . . . . . . . . . . . Booleaanse algebra met meerdere variabelen. . . . . . . . . . Waarheidstabel voor het synthese-voorbeeld. . . . . . . . . . Sum-of-Products methode toegepast op het voorbeeld. . . . . Product-of-Sums methode toegepast op het voorbeeld. . . . .
. . . . . . . . .
6 7 8 10 10 10 11 12 12
2.1
Verschil tussen positieve en negatieve logica. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11
Waarheidstabellen voor de leidende voorbeelden. . . . . . . Samenvatting van de verschillende implementaties. . . . . . Radix-conversie van hexadecimaal en octaal naar binair. . . Voorbeeld van algemene radix-omzetting. . . . . . . . . . . Betekenis van de binaire getallen. . . . . . . . . . . . . . . . Instructieset van een typische arithmetic-logic unit (ALU). . IEEE 754-1985 Floating Point. . . . . . . . . . . . . . . . . Decimale cijfers en hun BCD equivalent. . . . . . . . . . . . ASCII standaard. . . . . . . . . . . . . . . . . . . . . . . . . Waarheidtabellen van een encoder en prioriteitsencoder. . . Instructieset voor de schuifoperaties over 1 bit. . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
53 58 60 62 70 73 79 81 82 85 89
4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.12 4.13 4.14 4.15 4.16 4.17 4.18
Toestandstabellen van de leidende voorbeelden. . . . . . . . . . . . . . . . . . . . . . . . . . Geminimaliseerde toestandstabellen van de leidende voorbeelden. . . . . . . . . . . . . . . . Codering van de Mealy-machine van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . Codering van de Moore-machine van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . Keuze van het type flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Excitatietabellen van de verschillende flipflops . . . . . . . . . . . . . . . . . . . . . . . . . . Voorstelling van de transitiefunctie van de Moore-machine. . . . . . . . . . . . . . . . . . . Implementatie van de Mealy-schakeling met verschillende soorten flipflops. . . . . . . . . . . Uitgangslogica van de Moore- en Mealy-machine naast hun coderingstabellen. . . . . . . . . Formele beschrijving van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . . . . . . Configuratie- en toestandstabel van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . Evolutie van de toestandstabel bij het minimaliseren voor en na partitioneren. . . . . . . . Evolutie van de toestandstabel bij het minimaliseren voor en na twee iteraties. . . . . . . . Evolutie van de toestandstabel bij een alternatieve minimalisering voor en na twee iteraties. Toestandstabellen van de leidende voorbeelden bij de asynchrone toestandscodering. . . . . Coderingstabellen van het voorbeeld na het toepassen van de eerste methode. . . . . . . . . Coderingstabellen van het voorbeeld na het toepassen van de tweede methode. . . . . . . . Coderingstabel van het voorbeeld na het toepassen van de derde methode. . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
110 112 115 115 116 117 118 120 120 124 125 128 129 130 132 133 135 136
327
. . . . . . . . . . .
. . . . . . . . . . . . . . . . . . NOR poorten. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . .
328
LIJST VAN TABELLEN 4.19 Coderingstabel van het voorbeeld met initi¨ele toestand voor de overgangstoestand. . . . . . . 137 4.20 Coderingstabel van de schakeling uit Figuur 4.38. . . . . . . . . . . . . . . . . . . . . . . . . . 142 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11 5.12 5.13 5.14 5.15 5.16 5.17 5.18 5.19 5.20 5.21
Toestand-actie tabel van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . . Simulatie van het algoritme met behulp van de toestand-actie tabel (tabel 5.1). . . . Typische vertragingstijden voor RAM-geheugens. . . . . . . . . . . . . . . . . . . . . Toestandstabel van de controller van het leidend voorbeeld via de basisprincipes. . . Samenvatting van de kostprijs van de belangrijkste componenten . . . . . . . . . . . Levensduurtabel van het vierkantswortel voorbeeld. . . . . . . . . . . . . . . . . . . . De evolutie van de in [n]- en out [n]-set op basis van het leidend voorbeeld (zie figuur Functionele-eenhedentabel van het leidend voorbeeld (zie figuur 5.22) . . . . . . . . . Verbindingentabel van het leidend voorbeeld (zie figuur 5.22) . . . . . . . . . . . . . Invoer- en uitvoertabellen van het leidend voorbeeld (zie figuur 5.22) . . . . . . . . . Stuursignalen voor de verschillende toestanden na samenvoegen van registers. . . . . Multiplexer selectie-ingangen bij abs&max. . . . . . . . . . . . . . . . . . . . . . . . Multiplexer selectie-ingangen bij add&max. . . . . . . . . . . . . . . . . . . . . . . . Multiplexer selectie-ingangen bij abs&add&max. . . . . . . . . . . . . . . . . . . . . Multiplexer selectie-ingangen bij abs&add&max&sub. . . . . . . . . . . . . . . . . . Multiplexer selectie-ingangen bij min&sub. . . . . . . . . . . . . . . . . . . . . . . . Multiplexer selectie-ingangen bij abs&min&sub. . . . . . . . . . . . . . . . . . . . . . Operand- en resultaten-tabel van het leidend voorbeeld. . . . . . . . . . . . . . . . . Registertoegangstabel van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . Registerbank-configuraties voor het leidend voorbeeld. . . . . . . . . . . . . . . . . . Vergelijking van de kostprijs na de verschillende optimalisaties. . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . 5.22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
153 154 163 170 179 179 180 181 182 183 187 191 193 194 196 197 198 202 205 205 206
6.1 6.2 6.3 6.4 6.5
De registerinstructies van de CISC-processor (type 00). . . . . . De verplaatsinstructies van de CISC-processor (type 01). . . . . De spronginstructies van de CISC-processor (type 10). . . . . . De overige instructies van de CISC-processor (type 11). . . . . Frequentietabel bij het uitvoeren van het voorbeeldprogramma.
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
231 231 232 233 237
7.1 7.2 7.3 7.4
Gereserveerde woorden in VHDL. . . . . . . . . . . . . . . . . Scheidingstekens in VHDL. . . . . . . . . . . . . . . . . . . . Overzicht van belangrijke types en afgeleide types in VHDL. . Resolutie-tabel voor std logic. . . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
266 266 267 274
8.1 8.2
Lijst met populaire ge¨ıntegreerde circuits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 De verschillende kleurcodes bij een weerstand. . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
9.1 9.2 9.3 9.4 9.5
Toestandstabel van de oneindige vermenigvuldiger. Coderingstabel van de oneindige vermenigvuldiger. De oneindige vermenigvuldiger. . . . . . . . . . . . Toestandstabel van het fietslicht. . . . . . . . . . . Coderingstabel van het fietslicht. . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
302 302 303 306 307
A.1 Waarheidstabellen voor complexe poorten. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 A.2 De kostprijs van de verschillende componenten. . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Lijst van figuren 1
Link naar de meest recente versie van deze cursus. . . . . . . . . . . . . . . . . . . . . . . . .
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 1.14
Basis van het lamp-model. . . . . . . . . . . . . . . . . . . . . Implementatie van de basispoorten volgens het lamp-model. . XOR-poort in het lamp-model. . . . . . . . . . . . . . . . . . Basispoorten en uitbreidingen. . . . . . . . . . . . . . . . . . Complexe poorten. . . . . . . . . . . . . . . . . . . . . . . . . Poorten met ge¨ınverteerde ingangen. . . . . . . . . . . . . . . Voorbeeld van het tijdsgedrag van een logische schakeling met Herleiden naar standaard vorm van voorbeeld. . . . . . . . . Standaard vorm en alternatief. . . . . . . . . . . . . . . . . . Standaardvorm van het voorbeeld met NAND en NOR’s. . . Typisch verloop van een digitaal ontwerp. . . . . . . . . . . . De verschillende lagen bij de synthese. . . . . . . . . . . . . . Digitaal ontwerpen met CAD. . . . . . . . . . . . . . . . . . . Voorbeeldcircuit voor VHDL code. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
4 5 6 7 7 8 9 13 13 14 14 15 17 19
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.15 2.14 2.16 2.17 2.18 2.19 2.20 2.21 2.22
Schematisch bereik van “High” en “Low” spanning. . . . . . . . . . . . . . . . . . . . Notatie van een schakelaar (met stuursignaal). . . . . . . . . . . . . . . . . . . . . . Werking van NMOS en PMOS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NOT poort ge¨ımplementeerd in NMOS. . . . . . . . . . . . . . . . . . . . . . . . . . Open-Drain Poort in NMOS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NAND en NOR poort ge¨ımplementeerd met NMOS. . . . . . . . . . . . . . . . . . . NOT poort ge¨ımplementeerd met CMOS. . . . . . . . . . . . . . . . . . . . . . . . . NAND en NOR poorten ge¨ımplementeerd met CMOS. . . . . . . . . . . . . . . . . . Kortsluiting bij wired poort implementaties met CMOS. . . . . . . . . . . . . . . . . AND-OR-Inverter (AOI) en OR-AND-Inverter (OAI) in CMOS. . . . . . . . . . . . Implementatie van populaire alternatieve poorten in CMOS. . . . . . . . . . . . . . . Ontwerp met standaard cellen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Schematische voorstelling van een Programmable Logic Array (PLA). . . . . . . . . Schematische voorstelling van een Complex Programmable Logic Device (CPLD). . . Schematische voorstelling van een Programmable Logic Device (PLD). . . . . . . . . Schematische voorstelling van een Field Programmable Gate Array (FPGA). . . . . Werking van ruismarge bij CMOS en TTL. . . . . . . . . . . . . . . . . . . . . . . . Transferfuncties en Schmitt-Trigger ingangen. . . . . . . . . . . . . . . . . . . . . . . Dynamisch gedrag bij twee sequenti¨ele NOT poorten. . . . . . . . . . . . . . . . . . Het dynamisch gedrag van een NOT-poort. . . . . . . . . . . . . . . . . . . . . . . . Buffer ge¨ımplementeerd met omgekeerde transistoren: NMOS is een slechte pull-up. Tri-state buffer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
24 25 26 27 27 28 28 29 29 30 31 33 35 35 36 37 38 38 39 41 42 44
3.1 3.2 3.3
N-kubus voor dimensies 1 tot 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Van N -kubus naar Karnaugh-kaart. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Karnaugh-kaarten voor verschillende dimensies met binaire waarden. . . . . . . . . . . . . . .
50 51 51
329
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . een “glitch”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
x
330
LIJST VAN FIGUREN 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.20 3.21 3.22 3.23 3.24 3.25 3.26 3.27 3.28 3.29 3.30 3.31 3.32 3.33 3.34
Terminologie van een Karnaugh-kaart. . . . . . . . . . . . . . . . . . . . . . . . Ingevulde Karnaugh-kaarten voor de uitgangen van het leidend voorbeeld. . . . Karnaugh-kaarten met priemimplicanten van het leidend voorbeeld. . . . . . . Karnaugh-kaarten met essenti¨ele priemimplicanten van het leidend voorbeeld. . Werking van het greedy algoritme bij het leidend voorbeeld. . . . . . . . . . . . Voorbeelden van dambordpatronen in Karnaugh-kaarten. . . . . . . . . . . . . Karnaugh-kaart met don’t cares van led A en B van een seven-segment display. Duale methode met Karnaugh-kaarten. . . . . . . . . . . . . . . . . . . . . . . . Verschillende implementaties van dezelfde logische functie. . . . . . . . . . . . . Half adder (HA). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Full adder (FA). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Schematische voorstelling van een n-bit Ripple-carry opteller. . . . . . . . . . . Carry-Lookahead Opteller (CLA). . . . . . . . . . . . . . . . . . . . . . . . . . CLA-generator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Een mogelijke implementatie voor een CLA-generator met n = 3. . . . . . . . . Optelling en aftrekking van gehele getallen. . . . . . . . . . . . . . . . . . . . . Opteller-aftrekker voor 2-complement getallen. . . . . . . . . . . . . . . . . . . Schematisch implementatie van een arithmetic-logic unit (ALU). . . . . . . . . Synthese van de ALE en CIG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parallelle vermenigvuldigers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Underflow van een vlottende komma voorstelling. . . . . . . . . . . . . . . . . . Mogelijke implementatie van een BCD opteller. . . . . . . . . . . . . . . . . . . Multiplexer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Decoder. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Multiplexer en bus gesynthetiseerd met decoders. . . . . . . . . . . . . . . . . . Demultiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Encoder en Prioriteitsencoder. . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergelijker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Speciale gevallen van vergelijkers . . . . . . . . . . . . . . . . . . . . . . . . . . Implementatie van een schuifoperator over 1 bit. . . . . . . . . . . . . . . . . . Implementatie van een 8-bit barrel left rotator. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52 53 54 54 55 55 56 57 59 63 64 64 65 66 67 71 72 72 74 75 78 81 83 84 84 85 86 87 88 90 91
4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.12 4.13 4.14 4.15 4.16 4.17 4.18 4.19 4.20 4.21
Set-reset latch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Geklokte SR-latch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Geklokte D-latch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tijdsgrafieken van een D-latch. . . . . . . . . . . . . . . . . . . . . . . Metastabiliteit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Master-slave flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Edge-triggered flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . Set-reset flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data-flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Toggle-flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Jack-Kilby flipflop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overzicht van de interfaces van geheugencomponenten. . . . . . . . . . Interface en implementatie van een 4-bit register. . . . . . . . . . . . . Implementatie van een 4-bit schuifregister. . . . . . . . . . . . . . . . . Asynchrone 4-bit teller . . . . . . . . . . . . . . . . . . . . . . . . . . . Synchrone 4-bit teller . . . . . . . . . . . . . . . . . . . . . . . . . . . Parallel-laadbare bidirectionele 4-bit teller. . . . . . . . . . . . . . . . 4-bit modulo-tellers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Toestandsdiagrammen van de leidende voorbeelden. . . . . . . . . . . Geminimaliseerde toestandsdiagrammen van de leidende voorbeelden. Een 2-bit en 3-bit Gray-code teller en zijn straightforward equivalent.
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
96 97 97 98 98 100 100 101 102 102 102 103 104 104 105 105 106 107 109 112 115
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
LIJST VAN FIGUREN
331
4.22 4.23 4.24 4.25 4.26 4.27 4.28 4.29 4.30 4.31 4.32 4.33 4.34 4.35 4.36 4.37 4.38
Implementatie van de Moore-schakeling met verschillende soorten flipflops. . . . . Implementatie van de Mealy-schakeling met verschillende soorten flipflops. . . . . Volledige implementatie van de Mealy-machine met D-flipflops. . . . . . . . . . . Toestandsdiagram van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . Flowchart van het minimalisatieproces van asynchrone schakelingen. . . . . . . . Merger-diagrammen van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . Voorbeelden van een cycle en critical race. . . . . . . . . . . . . . . . . . . . . . . Transitiediagramma van het voorbeeld na het toepassen van de eerste methode. . Transitiediagramma van het voorbeeld na het toepassen van de tweede methode. Transitiediagram van het voorbeeld na het toepassen van de derde methode. . . . Statische hazards. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dynamische hazards. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Karnaugh-kaart bij het leidende voorbeeld. . . . . . . . . . . . . . . . . . . . . . Het invoeren van redundante termen elimineert statische 1-hazards. . . . . . . . . Dambord patroon. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Realisatie van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . . . . . . Essenti¨ele hazard van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
119 121 122 126 127 129 131 134 135 137 138 139 140 141 141 142 143
5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11 5.12 5.13 5.14 5.15 5.16 5.17 5.18 5.19 5.20 5.21 5.22 5.23 5.24 5.25
Opbouw van een processor en datapad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Voorstelling van de verschillende ASM-elementen . . . . . . . . . . . . . . . . . . . . . . . . . ASM-schema van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Traditionele valkuilen bij het maken van ASM-schema’s. . . . . . . . . . . . . . . . . . . . . . Toestandsgebaseerd ASM-schema van het leidend voorbeeld. . . . . . . . . . . . . . . . . . . . Implementatie van een Register File Cell (RFC) met 2 lees- en 2 schrijfpoorten . . . . . . . . Implementatie van een 4 × 3 registerbank met 2 schrijf- en 3 leespoorten.?? . . . . . . . . . . Tijdsgedrag van RAM-geheugens. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conceptueel voorbeeld van een stapelgeheugen. . . . . . . . . . . . . . . . . . . . . . . . . . . Demonstratie van een stapelgeheugen met tellers. . . . . . . . . . . . . . . . . . . . . . . . . . Implementatie van een stapelgeheugen met behulp van RAM-geheugen. . . . . . . . . . . . . Conceptueel voorbeeld van een buffergeheugen. . . . . . . . . . . . . . . . . . . . . . . . . . . Demonstratie van een buffergeheugen met tellers. . . . . . . . . . . . . . . . . . . . . . . . . . Implementatie van een buffergeheugen met behulp van RAM-geheugen. . . . . . . . . . . . . Implementatie van het datapad van het leidend voorbeeld via de basisprincipes. . . . . . . . . Toestandsdiagram van de controller van het leidend voorbeeld via de basisprincipes. . . . . . Algemene vorm van een controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Controller met natuurlijke volgorde van toestanden. . . . . . . . . . . . . . . . . . . . . . . . Controller met natuurlijke volgorde van toestanden en subroutines. . . . . . . . . . . . . . . . Controller met one-hotcodering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Microprogrammeerbare controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ASM-schema van het vierkantswortel-benaderingsalgoritme. . . . . . . . . . . . . . . . . . . . Implementatie van het datapad van de benaderende vierkantswortel volgens de basisprincipes. De evolutie van de compatibiliteitsgraaf voor de variabelen. . . . . . . . . . . . . . . . . . . . Implementatie van het datapad van het leidend voorbeeld na het minimaliseren van de variabelen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Oorspronkelijke compatibiliteitsgrafe bij het samenvoegen van bewerkingen. . . . . . . . . . . Minimaliseren van bewerkingen introduceert multiplexers. . . . . . . . . . . . . . . . . . . . . Implementatie van een minimum-component. . . . . . . . . . . . . . . . . . . . . . . . . . . . Implementatie van abs en abs&max. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Het combineren van abs1 en max1 introduceert een multiplexer. . . . . . . . . . . . . . . . . . Implementatie van een opteller, aftrekker en opteller/aftrekker. . . . . . . . . . . . . . . . . . De implementatie van add&max per bit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . De implementatie van abs&add&max per bit. . . . . . . . . . . . . . . . . . . . . . . . . . . . Methodes bij het introduceren van een multiplexer bij een samengestelde functionele eenheid.
149 155 156 157 159 159 160 162 163 164 165 166 166 167 169 170 172 173 174 175 176 177 178 185
5.26 5.27 5.28 5.29 5.30 5.31 5.32 5.33 5.34
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
186 188 189 189 190 191 192 193 194 195
332
LIJST VAN FIGUREN 5.35 5.36 5.37 5.38 5.39 5.40 5.41 5.42 5.43 5.44 5.45 5.46 5.47 5.48 5.49 5.50 5.51
De implementatie van min&sub per bit. . . . . . . . . . . . . . . . . . . . . . De implementatie van abs&min&sub per bit. . . . . . . . . . . . . . . . . . . De uiteindelijke compatibiliteitsgrafe bij het samenvoegen van bewerkingen. . Implementatie van het datapad na optimalisatie van de bewerkingen. . . . . . Het samenvoegen van verbindingen kan multiplexers elimineren. . . . . . . . . De compatibiliteitsgrafes bij het samenvoegen van verbindingen. . . . . . . . De implementatie van het datapad na het minimaliseren van de verbindingen. Een voorbeeld van een instructiewoord. . . . . . . . . . . . . . . . . . . . . . De chaining-transformatie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . De multicycling-transformatie. . . . . . . . . . . . . . . . . . . . . . . . . . . De verschillende uitvoeringsstrategie¨en: sequentieel, parallel en pipelining. . . De pipelining-transformatie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Terugkoppeling verhindert pipelining. . . . . . . . . . . . . . . . . . . . . . . Laadbaar registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Synchronisatie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . De verschillende componenten van de “metastability resolution time”. . . . . Metastabiliteit oplossen door een opeenvolging van flipflops. . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
196 197 199 200 201 203 204 206 208 208 209 210 211 213 215 215 216
6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 6.10 6.11 6.12 6.13 6.14 6.15 6.16 6.17 6.18 6.19 6.20 6.21 6.22 6.23 6.24 6.25
De structuur van een programmeerbare processor. . . . . . . . . . . . . . . . . . . . . . . Indirecte adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Relatieve adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ge¨ındexeerde adressering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ge¨ındexeerde adressering met autoincrement/autodecrement. . . . . . . . . . . . . . . . . De processorontwerp-cyclus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . De bitstructuur van de CISC instructieset. . . . . . . . . . . . . . . . . . . . . . . . . . . . Het instructieset-stroomschema van de CISC processor. . . . . . . . . . . . . . . . . . . . Stroomschema naar ASM-schema voor de ASR-instructie. . . . . . . . . . . . . . . . . . . Stroomschema naar ASM-schema voor de LOAD constante-instructie. . . . . . . . . . . . Stroomschema naar ASM-schema voor de LOAD direct-instructie. . . . . . . . . . . . . . Stroomschema naar ASM-schema voor de LOAD indirect-instructie. . . . . . . . . . . . . Stroomschema naar ASM-schema voor de JSR-instructie. . . . . . . . . . . . . . . . . . . Stroomschema naar ASM-schema voor de RTS-instructie. . . . . . . . . . . . . . . . . . . Het ontwerp van een CISC-controller met programmateller, geheugen en instructieregister. Het ontwerp van een CISC-controller met interne eindige toestandsautomaat. . . . . . . . Controller met samengevoegd geheugen en stapelgeheugen. . . . . . . . . . . . . . . . . . Controller met extern geheugen (Von Neumann-architectuur). . . . . . . . . . . . . . . . . De basis datapad-ontwerp van de CISC-processor. . . . . . . . . . . . . . . . . . . . . . . De uiteindelijke controller van de CISC-processor. . . . . . . . . . . . . . . . . . . . . . . Het datapad-ontwerp na het aanbrengen van verbindingen van de CISC-processor. . . . . De structuur van de 8086 microprocessor. . . . . . . . . . . . . . . . . . . . . . . . . . . . De structuur van de 8051 microcontroller. . . . . . . . . . . . . . . . . . . . . . . . . . . . De structuur van de ARM7 microprocessor. . . . . . . . . . . . . . . . . . . . . . . . . . . De pipelining-structuur van de ARM11 microprocessor. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
219 226 226 227 228 229 230 248 249 249 250 251 252 252 253 253 254 254 255 255 256 257 258 259 259
8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10
DIP packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . De uitlijning en betekenis van de verschillende kleurbanden. . . . . . . . De realisatie van een condensator. . . . . . . . . . . . . . . . . . . . . . De realisatie van een spoel. . . . . . . . . . . . . . . . . . . . . . . . . . Een voorbeeld van een matrixbord. . . . . . . . . . . . . . . . . . . . . . Structuur van een europrintplaat. . . . . . . . . . . . . . . . . . . . . . . Een voorbeeld van een printed circuit board (pcb). . . . . . . . . . . . . De pinout van de 555-timer en 556-timer. . . . . . . . . . . . . . . . . . Schakeling voor de implementatie van een kloksignaal met een 555-timer Astabiele multivibrator. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
285 288 288 289 290 291 292 293 294 295
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
LIJST VAN FIGUREN
333
8.11 PCB-weergave van populaire componenten. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8
Een toestandsdiagram voor k = 5. . . . . . . . . . . . . . . . Implementatie van een tuimelschakelaar. . . . . . . . . . . . . Karnaugh-kaarten voor de oneindige vermenigvuldiger. . . . . Mogelijke implementatie voor de oneindige vermenigvuldiger. Printplaat-ontwerp voor de oneindige vermenigvuldiger. . . . De verschillende standen van een Hema-fietslicht . . . . . . . De IO-module van het fietslicht . . . . . . . . . . . . . . . . . Een led-matrix en invoer-component voor het tic tac toe spel.
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
300 302 303 304 304 305 305 309
A.1 Lijst van component interfaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 A.2 Samenvattend schema: poorten en componenten (deel 1) . . . . . . . . . . . . . . . . . . . . . 315 A.3 Andere combinatorische schakelingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 C.1 Oplossingen van het invullen van de Karnaugh-kaarten. . . . . . . . . . . . . . . . . . . . . . 325
334
LIJST VAN FIGUREN
Lijst van VHDL-Codes 1.1 8-bit comparator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.2 Voorbeeldcode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1.3 Configuratie van de voorbeeldcode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 6.1 Hoog niveau beschrijving van het min-max-sum algoritme.234 6.2 Het min-max-sum algoritme in assembleertaal.235 6.3 Het min-max-sum algoritme in machinetaal.236 7.1 Defini¨eren van types door opsomming. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.2 Defini¨eren van types door subtypering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.3 Defini¨eren van fysische types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 7.4 Defini¨eren van matrix types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 7.5 Defini¨eren van constanten. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 7.6 Werken met variabelen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 7.7 Werken met signalen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 7.8 De definitie van std logic en std ulogic (IEEE 1164). . . . . . . . . . . . . . . . . . . . . . 273 7.9 Implementatie van de std logic resolutie-functie in VHDL. . . . . . . . . . . . . . . . . . . . . 275 7.10 Vector aaneenschakeling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 7.11 Vector matrixdeling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 7.12 Voorbeeld van een “package declaration”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 7.13 Voorbeeld van een “package body”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 7.14 2-naar-1-multiplexer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 7.15 n-bit Opteller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 7.16 Beschrijving van de procedure om de sha1 uit te rekenen. . . . . . . . . . . . . . . . . . . . . 281
335
336
LIJST VAN VHDL-CODES
Woordenlijst Symbols
A
fix hi, f i De notatie voor een vaste komma voorstel- adres-ingangen ai Een reeks ingangen waardoor men ling met i cijfers voor het gehele gedeelte, en f een component kan meegeven aan een compocijfers voor het fractionele gedeelte. Deze nonent. Componenten met adres-ingangen zijn tatie wordt gebruikt om te redeneren over het bijvoorbeeld de decoder en het RAM geheugen. aantal cijfers die men voor beide delen moet reDe adres-ingang bepaald welke cel wordt uitgeserveren om bijvoorbeeld een optelling volledig lezen/weggeschreven of welke data-uitgang wordt te kunnen berekenen.. 77 geactiveerd.. 82 float hm, ei De notatie voor een vlottende komma voor- algebra¨ısch manipuleren Het aanpassen van een stelling met m cijfers voor de mantisse, en e gegeven algebra¨ısche expressie zodat het resulcijfers voor de exponent. Deze notatie wordt taat equivalent is met het origineel. Aan de gebruikt om te redeneren over het aantal cijfers hand van algebra¨ısche manipulatie kan men een die men voor beide delen moet reserveren om expressie echter in een meer wenselijke vorm bijvoorbeeld een vermenigvuldiging foutloos te brengen. Algebra¨ısche manipulatie wordt soms kunnen berekenen.. 78 gebruikt in de zoektocht naar een goedkope implementatie voor een booleaanse functie.. 57 mod zie modulo. 76
American Standard Code for Information Interchange (A Een formaat om tekst voor te stellen. ASCII omvat 128 karakters. Tekst wordt dan karakter n-and Een basisschakeling met n ingangen. h1, 1, . . . , 1i per karakter voorgesteld.. 80 wordt afgebeeld op 1; en alle overige configuraties op 0.. 7 Analyse Een stap in het ontwerpproces waarbij men n-or Een basisschakeling met n ingangen. h0, 0, . . . , 0i test of een synthese voldoet aan alle vereiste wordt afgebeeld op 0; alle overige configuraties specificaties.. 16 op 1.. 7 AND Een populaire basisschakeling met twee ingandouble zie dubbele precisie. 78 gen. h0, 0i, h0, 1i en h1, 0i worden afgebeeld op 0; en h1, 1i wordt afgebeeld op 1.. 4 float zie enkele precisie. 78 rem zie remainder. 76
AND-matrix Een raster dat gebruikt wordt voor programmeerbare chips. Men beschouwt n ingangen en m n-AND-poorten, voor elke ingang 0-maxtermen 0-maxtermen is de verzameling van en elke AND poort is er een zekering waarmaxtermen voor de rijen waar de waarheidstadoor men kan beslissen welke ingangen er aan bel 0 is.. 11 welke AND-poort worden gehangen. Een AND1-complement zie cijfer-complement. 68 matrix wordt ondermeer gebruikt bij een programmable logic array (PLA).. 34 1-mintermen 1-mintermen is de verzameling van mintermen voor de rijen waar de waarheidsta- AND-OR-Invert (AOI) Een schakelin gemaakt uit bel 1 is.. 11 transistoren die een tweelagige structuur omsingle zie enkele precisie. 78
vat met op het eerste niveau een reeks ANDpoorten, de uitgangen van deze AND poorten passeren vervolgens door een NOR poort. Men
2-complement zie radix-complement. 69 3-state buffer zie . 43 337
338
Woordenlijst kan de schakelin echter zeer goedkoop realiseren.. 29
basisoperaties Set van operaties waaruit andere operaties zijn opgebouwd: in de booleaanse algebra zijn dit de NOT, AND en OR.. 4
any-uitgang a Een uitgang van een component die een 1 aanlegt in het geval ´e´en of meerdere data- binair stelsel Een Arabisch getalstelsel met radix r = 2.. 59 ingangen een 1 aanleggen. Voorbeelden van componenten met een any-uitgang zijn de enBinary Coded Decimal (BCD) Een formaat om coder en prioriteitsencoder.. 85 getallen mee voor te stellen. Bij een binary coded decimal wordt elk cijfer in het decimaal Arabisch getalsysteem Een manier om getallen voor stelsel voorgesteld door vier bits. Men zet dus te stellen. Met het Arabisch getalsysteem stelelk cijfer van de decimale voorstelling om in zijn len we getallen voor als een opeenvolging van binair equivalent. Rekenen met binary coded cijfers. Elk cijfer heeft een bepaald gewicht dat decimals is complexer. Het voordeel is dat men afhangt van de plaats van dat cijfer in de seelk getal dat decimaal kan worden voorgesteld, quentie: de waarde van het i-de getal van rechts ook in bcd notatie exact kan voorstellen. Het - inclusief 0 - is ri met r de radix.. 59 formaat is dan ook populair in de financi¨ele weArithmetic-Logic Extender (ALE) Een deelcomreld.. 80 ponent van een arithmetic logic unit (ALU). Een ALE mapt telkens twee bits van de operan- blackbox Een systeem waarvan de inwendige werking niet bekend is, men weet enkel hoe het den ai en bi en het instructiewoord naar twee systeem communiceert met zijn omgeving, en nieuwe bits xi en yi , vaak door logische bewersoms zijn ook enkele specificaties over het syskingen toe te passen. De resulterende getallen teem bekend.. 20 A en B gaan dan door een opteller om tot een finaal resultaat te komen.. 72 booleaanse algebra De tak van de wiskunde die zich bezighoudt met logische bewerkingen.. 9 Arithmetic-Logic Unit (ALU) Een component die op basis van een opteller en een arithmeticbronradix Bij omzetting van een getal tussen twee logic extender in staat is een reeks populaire Arabische getalstelsels de radix van het origiinstructies uit te voeren zoals optellen, aftreknele getalstelsel.. 60 ken, increment, decrement samen met bitgewijze logische operaties (NOT, AND, OR,...). buffer Een poort met ´e´en ingang waarbij 0 wordt Veel processoren beschikken over ´e´en of meerafgebeeld op 0; en 1 op 1. Een buffer is dus dere ALUs.. 72 equivalent aan een draad, maar wordt gebruikt om de fan-out onder controle te houden.. 30, Aritmetisch schuiven Een variant van schuiven waar341 bij we schuiven zien als een vermenigvuldiging of deling door een macht van twee. Bij bijvoor- buren De buren van een knoop k in een graaf is de beeld de 2-complement voorstelling leidt dit tot verzameling van knopen zodat er een boog beeen ander gedrag dan bij logisch schuiven. In staat tussen k en de knoop in kwestie.. 50 dat geval zullen we bij aritmetisch schuiven naar rechts de hoogste bit van het originele getal in bus Een bus is een coponent die het mogelijk maakt om over ´e´en geleider signalen van verschillende rekening brengen, en deze waarde op de vrijgebronnen naar andere componenten over te stukomen plaatsen invullen.. 89 ren. Een bus maakt gebruik van tri-state buffers. Op ieder moment is er hoogstens ´e´en bron B waarvoor de overeenkomstige tri-state buffer actief is.. 44, 83 barrel left rotator Een component die een rotatie kan uitvoeren over een willekeurig aantal bits. Dit doet men door voor een n bit getal, log2 n C lagen te beschouwen. Voor elke laag i maakt men aan de hand van multiplexers de keuze om canonieke vorm Een implementatie van een logische functie aan de hand van Sum-of-Products het getal door te laten of 2i posities naar links of Product-of-Sums waarbij men geen poging te rotereren,. 89 doet de min- of maxtermen verder te optimaliBasis zie Gate. 25 seren.. 12
Woordenlijst
339
Capaciteit C De capaciteit van een geleider ont- cijfer-complement Een complement voorstelling waarstaat door de geometrie van de chip: de gebij men negatieve getallen voorstelt door elk cijleider en zijn positie tegenover geleiders van de fer i te vervangen door het complement r − i − 1 grond en bron. Men probeert deze capaciteit zo met radix r.. 68, 337, 340 laag mogelijk te houden om de tijdsconstante te verlagen en bijgevolg de chip sneller te laten cijferen Een verzameling van technieken die in het lager onderwijs worden aangeleerd om bewerschakelen. Typisch zal een lange geleider ook kingen zoals optellen, aftrekken, vermenigvuleen hogere capaciteit hebben. Daarom probeert digen en delen uit te voren op grote getallen. met het aantal lange lijnen op een geleider tot In plaats van de bewerking in ´e´en keer op de een minimum te beperken.. 40 twee getallen uit te voeren, wordt een bepaalde methode cijfer per cijfer uitgevoerd. Cijferen carry zie overdracht. 62 komt ook terug in digitale logica wanneer men Carry Input Generator (CIG) Een deelcomponent rekenkundige circuits implementeert.. 62 van een arithmetic logic unit (ALU). Een CIG berekent welke overdracht c0 er voor de opteller CLA-generator Een component met ingangen hc0 , g0 , . . . , gn−1 , p die overdracht doorrekent en die de carry-lookahead moet worden gegenereerd, en doet dit op basis optellers van de waarde voor de overdracht-ingang van het instructiewoord.. 72 voorziet. De uitgangen zijn dan ook hc1 , . . . , cn , g0,n−1 , p0,n−1 Door een cascade van CLA-generatoren te becarry-generate gi Een uitgang van een carry-lookahead schouwen, kan men een optelling realiseren die opteller; 1 indien er carry gengereerd zal worin O (log n) werkt, in plaats van in O (n).. 65 den door xi en yi . Dit is het geval wanneer beide ingangen een 1 aanleggen. In het andere Collector zie Source. 25 geval staat er 0 op deze uitgang.. 64 Carry-lookahead opteller (CLA) Een uitbreiding Combinatorische Schakelingen Schakelingen waarbij een bitvector aan de uitgangen uitsluitend op de full adder. In plaats van een carry uitwordt bepaald aan de hand van een bitvector gang ci , heeft de carry-lookahead opteller een aan de ingangen. Er zijn met andere woorgenerate uitgang gi en een popagate uitgang pi . den geen geheugencomponenten en de schakeDeze uitgangen berekenen of er op deze bit een ling houdt bijgevolg geen toestand bij. Oncarry zal gegenereerd worden - wanneer zowel der combinatorische schakelingen vinden we bijxi als yi 1 zijn, of wanneer een carry van de voorbeeld optellers, vergelijkers en multiplexers.. vorige bit zal gepropageerd worden: wanneer 47 minstens ´e´en van de twee ingangen xi of yi 1 is.. 64 comparator zie vergelijker. 86 carry-propagate pi Een uitgang van een carry-lookahead complement voorstellingen Een reeks voorstellinopteller; 1 indien er carry gepropageerd zal worgen voor negatieve getallen. Bij elk van deze den door xi en yi en niet gegenereerd. Dit is complement voorstellingen neemt men de bithet geval wanneer ´e´en van de twee ingangen 1 gewijze negatie van het getal, eventueel wordt aanlegt. In het andere geval staat er 0 op de er nog een 1 opgeteld om te vermijden dat er uitgang.. 64 twee voorstellingen voor het getal 0 bestaan. Er zijn twee soort complement voorstelling: 1cascade Het organiseren van componenten op meercomplement en 2-complement.. 68 dere lagen. Een dergelijke organisatie leidt vaak tot effici¨entie, zowel in doorvoersnelheid als in Complex Programmable Logic Device (CPLD) kostprijs. Concrete voorbeelden van cascade orEen programmeerbare chip die bestaat uit een ganisatie vinden we terug bij een CLA-generator, aantal programmable logic devices (PLDs) samultiplexers en vergelijkers.. 82 men met een manier om glue logic uit te drukken, dit aan de hand van een schakelmatrix en chipoppervlakte C De totale oppervlakte die een in- en uitvoer modules.. 35 chip inneemt, en waarop transistoren en bedrading wordt gezet. Het dynamisch vermogenver- Computer Aided Design (CAD) Een techniek waarbruik schaalt lineair met de chipoppervlakte.. bij men een product ontwerpt en sommige ta42 ken automatiseert met behulp van een compu-
340
Woordenlijst ter. Bijvoorbeeld het simuleren of (gedeeltelijk) decimale stelsel Een Arabisch getalstelsel met rasynthetiseren van een logische schakeling.. 16 dix r = 10.. 59
decoder Een component met een enable-ingang enable ingang e, n adres-ingangen ai en 2n selectieConfigurable Logic Blocks (CLB) Een uitbreiding uitgangen si . Wanneer op de enable-ingang een op het Logical Block (LB) die men in field pro0 staat, staan op alle selectie-uitgangen een 0. grammable gate arrays (FPGAs) aantreft. Een Wanneer er 1 op de enable-ingang wordt gezet, CLB bestaat uit vier slices, twee van deze slien de binaire waarde van de adres-ingangen is ces kunnen worden geconfigureerd als schuifreA, dat staat er 1 op selectie-uitgang sA ; op de gisters, geheugencellen of logische blokken. De overige selectie-uitgangen staat een 0.. 82 overige slices ondersteunen enkel logische blokdecrement Het aftellen van een getal met 1.. 72 ken.. 36 Concurrency zie Gelijktijdigheid. 22
dekking Een verzameling van implicanten voor een gegeven functie (en bijbehorende Karnaugh-kaart) zodat voor elke cel waar de functie 1 is, deze cel Custom Design zie maatwerk. 33 minstens wordt omvat door een implicant in de verzameling. Bovendien is er geen enkele cel D waar de functie 0 is die omvat wordt door een implicant in de verzameling.. 52, 340 Daaltijd tf De tijd die een geleider nodig heeft om van een hoge spanning naar een lage spanning te deling Een rekenkundige bewerking op twee getallen dalen. Omdat de spanning van de bron of grond waarbij men zoekt hoeveel maal het eerste getal vaak niet bereikt wordtn, neemt men vaak waarin het tweede getal past.. 76 den van respectievelijk 90% en 10% tussen de basisspanning en de topspanning.. 41, 342 demultiplexer Een component met een data-ingang d, n selectie-ingangen ai en en 2n data-uitgangen dambordpatroon Een veel voorkomend patroon waarsi . Afhankelijk van de binaire waarde A die op bij wisselend in een ene rij men 0 en 1 tegende selectie-ingangen ai staat, wordt het signaal komt, na enkele rijen wisselt het patroon naar 1 dat op de data-ingang d staat doorgegeven aan en 0. Wanneer het dambordpatroon voorkomt de data-uitgang sA . Op de overige uitgangen op een Karnaugh-kaart kan dit vaak effectief wordt een 0 gezet. Een demultiplexer is functiworden gerealiseerd met behulp van XOR pooroneel equivalent aan een decoder.. 84, 340 ten. De grootte van de vlakken bepaalt welke ingangen aan deze XOR poorten moeten wor- demux zie demultiplexer. 84 den gezet.. 55 diminished-radix complement zie cijfer-complement. 68 data-ingang d Een ingang bij een component die cover zie dekking. 52
gegevens (een bit dus) bevat die verwerkt moet documentatie Documentatie beschrijft het gebouwde worden. Deze ingang komt bijvoorbeeld voor product. Dit is bijvoorbeeld een handleiding bij geheugens zoals een flipflop, maar ook bij hoe het product kan aanestuurd worden, of een bijvoorbeeld een demultiplexer. De gegevens document met ontwerpdetails indien we het proworden vaak ofwel opeslagen, ofwel - zonder duct als component aan een ander bedrijf verveel aanpassingen - doorgestuurd naar een ankopen. Documentatie wordt soms ook intern dere uitgang.. 84 bijgehouden in een bedrijf.. 16 data-ingangen di Een reeks ingangen bij een multi- doelradix Bij omzetting van een getal tussen twee plexer. Afhankelijk van de waarde op de selectieArabische getalstelsels de radix van het getalingangen wordt de waarde van ´e´en van de datastelsel naar waar we de omzetting willen doen.. ingangen doorgegeven naar de uitgang van de 60 multiplexer.. 82 don’t care Don’t care is een derde waarde in een Datatypes Een verzameling van soorten van signawaarheidstabel, die zoveel betekent als: ”het len: bijvoorbeeld vectoren, getallen met geparamaakt niet uit of hier een 0 of 1 staat.”. Wanmetriseerde grootte,... Deze datatypes worden neer de don’t care bij de ingangen staat, beteonder meer ondersteund in VHDL.. 22 kent dit dat het rechter lid van deze rij geldt
Woordenlijst voor zowel 0 als 1. Wanneer de don’t care aan de rechterkant van de waarheidstabel staat (bij de uitgangen) betekent dit dat we vrij mogen kiezen of we een 0 of een 1 gebruiken. De Don’t care is nuttig bij het optimaliseren van logische schakelingen.. 11, 55
341 beslist of het component in kwestie op dat moment een taak uitvoert (bijvoorbeeld de teller ophogen bij het volgende kloksignaal). De enable ingang wordt ook gebruikt bij een tri-state buffer om te bepalen of de waarde aan de ingang wordt doorgegeven aan de uitgang; of dat de uitgang in zwevende modus hoort te verkeren.. 43
doorvoer Een metriek van de snelheid van een logische schakeling: het aantal resultaten per seenable-ingang e Een ingang bij verschillende comconde.. 16, 349 ponenten. Wanneer men 0 op de enable-ingang doperen Het introduceren van alternatieve atomen zet, zal de component meestal geen logica uitin een substraat. In de context van een transisvoeren, en bijvoorbeeld een 0 op alle uitgangen tor worden substraten van siliciumdioxide nezetten. Indien er 1 op de anble-ingang staat, zal gatief of positief edopeerd.. 26 het component meestal een logische functie uitrekenen. Componenten met een enable-ingang Drain Een connectie van een FET transistor.. 24, zijn bijvoorbeeld het tri-state buffer, de deco25, 341 der, registerbanken, RAM-geheugens en tellers. Sommige componenten die verschillende taken drijvendekommagetal zie vlottende komma voorkunnen uitvoeren hebben verschillende enablestelling. 77 ingangen. De specifieke naam van de ingang verduidelijkt dan welke functie welke ingang heeft.. driver zie buffer. 30 82 dualiteit Een eigenschap van de Booleaanse algen bra dat elke wet in de booleaanse algebra, door encoder Een component met 2 data-ingangen, een any-uitgang a en n selectie-uitgangen fi . InAND met OR te verwisselen en 0 met 1, een dien er op ´ e ´ e n van de data-ingangen een 1 staat, andere geldige wet uitkomt.. 10 staat er ook een 1 op de any-uitgan en vice versa. Wanneer juist ´e´en data-ingang di een dubbele precisie Een voorstelling voor vlottende kom1 aanlegt, geven de selectie-uitgangen binair de magetallen met 64-bit beschreven in IEEE 754 waarde van deze index weer. Indien meer datamet 11 bit voor de exponent en 52 bit voor de ingangen op 1 staan, is het gedrag onbepaald.. mantisse. Enkele precisie wordt ook double ge85 noemd.. 78, 337 dynamisch gedrag Het gedrag die eigen is aan de enkele precisie Een voorstelling voor vlottende kommagetallen met 32-bit beschreven in IEEE 754 fysieke realisatie van een chip. Omdat geleiders met 8 bit voor de exponent en 23 bit voor de kunnen gemodelleerd worden als RC ketenen, mantisse. Enkele precisie wordt ook single of betekent dit dat zelfs bij een directe omschakefloat genoemd.. 78, 337 ling van de poort, het signaal traag en geleidelijk door de geleider zal propageren.. 39 Espresso heuristic logic minimizer Een algoritme die voor een gegeven logische functie - bijvoorDynamisch vermogenverbruik Het vermogen die beeld aan de hand van een waarheidstabel - een een chip verbruikt als gevolg van het veranderen implementatie zoekt die vrij effici¨ent is. Een van de waarde aan de ingang(en) of het klokheuristiek garandeert niet dat de oplossing opsignaal. Dit vermogen dient bijvoorbeeld om de timaal is, maar vaak wel dicht genoeg bij het poorten om te schakelen. Bij alle technologie¨en optimum voor praktische doeleinden.. 57 (NMOS, CMOS,...) is er sprake van dynamisch vermogenverbruik.. 42 E
essenti¨ ele priemimplicant Een priemimplicant die voor ´e´en cel in de Karnaugh-kaart 1 bevat, en waar er geen enkele andere priemimplicant voor deze cel 1 geeft.. 52
Emitter zie Drain. 25 Enable E Een ingang die bij veel componenten zoals tellers wordt gebruikt. De enable ingang
excess formaat Een manier om negatieve getallen voor te stellen. Men beschouwd een parameter: de excess-bias B, men encodeert het getal als
342
Woordenlijst
een natuurlijk getal, maar virtueel trekt men fractionele gedeelte Een deel van een getal bij vaste telkens de excess-bias van het getal af. Indien komma voorstell. Het fractioneel deel is de reeks de excess-bias bijvoorbeeld 12 is, dan betekent cijfers die na de komma staat. Het aantal cijfers 00002 dus 12, wanneer het getal 01002 mapt dan staat vooraf vast.. 77 op −8 en 11102 op 2. Men dient in dat geval optellers aan te passen zodat men de excess- full adder (FA) Een component die voor drie gegeven bits xi , yi en ci - twee echte bits en meestal bias ook optelt: wanneer we 01002 optellen met de overdracht van de vorige opteller - de bit 11102 dienen we dus 01102 uit te komen.. 68 si = xi ⊕ yi ⊕ ci uitrekent die onder de som excess-bias B Een parameter bij het excess formaat. moet komen te staan, samen met de overdracht Men dient het getal te interpreteren als een povoor de volgende bit ci+1 . Een full adder wordt sitief getal, maar men trekt er vervolgens de gebruikt bij het optellen en aftrekken van twee excess-bias virtueel vanaf.. 68 getallen.. 63 exponent E Een reeks bits bij de vlottende komma Functionele ontbinding Het zoeken van deelfuncvoorstelling. De exponent E geeft aan dat we ties in een functie en deze er vervolgens uit weghet getal van de mantisse M (vereikt met de substitueren. Gegeven een functie f~ (~x) zoeken sign-bit s) moeten vermenigvuldigen met rE we dus naar een equivalente functie ~h (~g (~x) , ~x). met r de radix van het getalstelsel.. 77 Functionele ontbinding wordt vaak toegepast in de zoektocht naar een goedkope en effici¨ente imF plementatie: men zoekt structuren die verschillende keren terugkomen in de originele functie Factoranalyse Het algebra¨ısche manipuleren van een en deze dienen we dan slechts ´e´enmaal te bere(booleaanse) expressie met bijvoorbeeld de wetkenen.. 57 ten van De Morgan. We gaan op zoek naar variabelen die verschillende keren voorkomen in de expressie en proberen deze af te zonderen. G Factoranalyse wordt soms gebruikt in een zoektocht naar een goedkope implementatie van een Gate Een van de aansluitingen van een transistor. booleaanse functie. Vaak bekoment men impleDe gate regelt of er een verbinding tussen de mentaties met een beperkte fan-in.. 57 source en de drain tot stand komt.. 25, 338 fall time zie Daaltijd tf . 41
Gate Array Een techniek om specifieke cellen te realiseren. Men beschouwt een tweedimensionaal fan-in Het aantal ingangen van een bepaalde poort rooster met identieke poorten, elke poort heeft in een digitale schakeling.. 43 bijgevolg ook identieke afmetingen. Er wordt fan-out Het aantal ingangen van poorten die de uitruimte tussen de poorten gelaten voor de bedragang van een bepaalde poort aanstuurt... 43 ding. De bedrading - uniek voor elke applicatie - wordt dan handmatig gelegd.. 33 Field Programmable Gate Array (FPGA) Een programmeerbare chip die bestaat uit program- ge¨ınverteerde ingangen Een conventie die wordt meerbare logische blokken, schakelmatrices; en gebruikt om het aantal getekende NOT poorten invoer- en uitvoer modules.. 36 in een schema drastisch te verminderen. Men zet hierbij cirkels bij de ingangen van een poort. fixed point zie Vaste komma voorstelling. 77 Deze cirkels duiden dan op een invertering (en dus eventueel een NOT poort) voor deze inFlash-programmeerbaar Een techniek voor progang.. 8 grammeerbare chips. Er worden hierbij ladingen aangebracht als een geheugen. Deze ladingen bepalen een stuursignaal voor transistoren. geheel deel Een deel van een getal bij vaste komma voorstelling. Het geheel deel is de reeks cijfers De toestand van deze transistoren - open of gedie voor de komma staan. Het aantal cijfers sloten - bepaalt dan verder het gedrag van de staat vooraf vast.. 77 chip.. 34 floating-point number zie vlottende komma voorstelling. 77
Geheugen-programmeerbaar Een techniek voor programmeerbare chips. Hierbij bevat de chip
Woordenlijst
343
een geheugen, bijvoorbeeld SRAM. Het stuur- half adder (HA) Een component die voor twee gesignaal van sommige transistoren wordt dan gegeven bits x en y het binaire cijfer van de som koppeld aan de toestand van eeen bepaalde bit s = x ⊕ y uitrekent, en de overdracht c = x · y. in dat geheugen. Men kan dit geheugen bijna Een half-adder wordt soms gebruikt om de laateindeloos herprogrammeren, en soms zelfs dyste bit bij een optelling van twee getallen te benamisch aanpasssen. Men dient wel voortdurekenen. De rest van de bits worden met een rend spanning op dit geheugen aan te leggen.. full adder berekend.. 62 34 hexadecimaal stelsel Een Aratisch getalstelsel met radix r = 16.. 59 Gelijktijdigheid Het feit dat alle hardwarecomponenten parallel werken: wanneer de ingang ver- High De fysische waarde die we associ¨eren met een andert, zullen alle poorten die door deze in1 of 0 (bij negatieve logica); bij een implemengang worden aangestuurd, tegelijk de verandetatie met elektronica is dat meestal een hoge ring doorrekenen. Gelijktijdigheid is een eigenspanning.. 24 schap in VHDL die niet overeen komt met klassieke programmeertalen.. 22, 340 hoog impedant zie zwevende modus Z. 43 Genormaliseerde vlottende komma voorstelling hysteresis Een hysteresis is een mogelijke eigenschap van een transferfunctie. Het gedrag van de transferEen familie van vlottende komma voorstellinfunctie hangt dan af of de spanning van hoog gen. Bij deze familie geldt een extra beperking naar laag gaat; of van laag naar hoog. Men gedat de waarde van de mantisse M ligt tussen bruikt een hysteresis soms om te voorkomen dat 1 ≤ M < r met radix r. Bij het binaire systeem bij een chaotische ingang, de uitgang eenveel (of impliceert dit dat de eerste bit van de mantisse zelfs versterkte) chaos toont.. 39 dus altijd op 1 zo staan. Daarom wordt deze bit weggelaten, maar bestaat ze wel nog virtueel. Deze bit wordt dan vervangen door een I extra bit in het fractionele gedeelte.. 78 implicant Een implicant is een productterm, zodat er minstens ´e´en cel op de Karnaugh-kaart is die gesloten Een toestand bij een schakelaar waarbij er zelf 1 is en waarvoor de functie - beschreven stroom vloeit door de schakelaar.. 25 door deze productterm - ook 1 is. De functiewaarde voor cellen die 0 zijn op de Karnaughglitch Een fenomeen waar bij de verandering van ´e´en kaart horen ook 0 te zijn. De cellen op de of meerdere ingangen van een logische circuit Karnaugh-kaart die 1 zijn, hoeven niet - op ´e´en door het verschil in tijdsgedrag van de poorten, cel na - een functie-waarde 1 te hebben.. 52 er tijdelijk een foute waarde op een van de uitgangen (of tussensignalen) komt te staan.. 9
in- en uitvoer modules Een module die erop gericht is een circuit te laten communiceren met Glue Logic Een schakeling die nodig is om twee chips zijn omgeving. Dit zijn bijvoorbeeld modules met elkaar te kunnen laten samenwerken en/of die signalen in een geheugen klokken, maar soms communiceren.. 32 ook Ethernet of USB interfaces.. 35 greedy algorithm zie gulzige strategie. 54
increment Het ophogen van een getal met 1.. 72
gulzige strategie Een methode om een probleem Ingangsimpedantie RI De ingangsimpedantie is de virtuele weerstand die bij een poort tussen een op te lossen door het op te delen in verschilingang van die poort en de grond staat. Er is lende beslissingen. Bij elke beslissing kiezen we een zeker streven naar een hoge ingangsimpede optie die ons onmiddellijk het meeste opledantie omdat dit ervoor zorgt dat een geleider vert. Het is echter niet gezegd dat dit tot de vaak zal opgeladen worden tot aan de spanning uiteindelijke beste oplossing zal leiden, omdat die op de drain staat, bovendien perkt dit het een eerste beslissing er voor kan zorgen dat een statisch vermogensverbruik van de poort in.. 40 tweede beslissing tot minder winst kan worden.. 54, 343 instructieset Een verzameling instructies die een arithmetic logic unit (ALU) of processor moet kunH nen uitvoeren. Een instructieset dient voor elke
344
Woordenlijst
instructie, de semantische betekenis van de in- lange lijnen Verbindingen die over een groot deel structie te beschrijven. Men dient ook deze invan het chipoppervlak lopen. Lange lijnen zijn structies te encoderen op een instructiewoord: vaak ongewenst in chipdesign omdat ze de proeen sequentie bits waarmee we aan de processor pagatie van het signaal afremmen, en hierdoor of ALU duidelijk maken welke instructie op dat de maximale klokfrequentie verminderen.. 36 moment moet worden uitgevoerd.. 73 lekstroom Stroom die wegvloeit in een schakeling, instructiewoord Een reeks bits die bepalen welke bijvoorbeeld omdat een transistor gesloten is bij instructie een processor of een arithmetic logic een poort ge¨ımplementeerd met NMOS technounit (ALU) uit moet voeren.. 73 logie.. 42 interface Een interface is een deel van een systeem Logical Blocks (LB) Een deelcomponent van een dat communiceert met de buitenwereld. Bijfield programmable gate array (FPGA). Een lovoorbeeld een USB poort van een computer, of gische blok bestaat typisch uit 4 ingangen en een API van een computerprogramma.. 14 bevat dan een 16-bit look-up table (LUT) en een geheugencomponent om het resultaat van inverterende poorten Poorten waar conceptueel op de vorige klokcyclus ook te kunnen aanleggen.. het einde een inverter staat. Inverterende poor36 ten zijn INV, NAND, NOR, AOI en OAI.. 49 Logisch schuiven Een variant van schuiven. Bij logisch schuiven worden de vrijgekomen plaatsen opgevuld door een constante, meestal 0. Soms K-kaarten zie Karnaugh-kaarten. 50 wordt zelfs in detail bepaald welke waarde men Karnaugh-kaarten De projectie van een N -kubus op welke vrijgekomen bit zet.. 89 in twee dimensies. Karnaugh-kaarten vormen een visueel hulpmiddel bij de synthese van een logische schakelingen Een netwerk van logische poorten.. 8 combinatorische schakeling voor een gegeven booleaanse functie met twee lagen.. 50, 344 Look-Up Table (LUT) Een programmeerbaar geklokfrequentie f De frequentie waarmee de klok heugen met n ingangen. Wanneer er op de ineen component die de schakeling aan de hand gangen binair k staat, wordt de k-de cel op de van het verlopen van de tijd aanstuurt - werkt. uitgang aangelegd.. 36 Het dynamisch vermogenverbruik schaalt lineLow De fysische waarde die we associ¨eren met een air met de klokfrequentie.. 42 0 of een 1 (bij negatieve logica); bij een implekopies Een manier om Karnaugh-kaarten voor te mentatie met elektronica is dat meestal een lage stellen indien het aantal dimensies stijgt bospanning.. 24 ven de vier. In dat geval worden er twee 4 × 4 rasters beschouwd. Beide rasters gebruiken deM zelfde positionering van de variabelen.. 51 K
kostprijs De kostprijs van een schakeling is een (ruwe) maatwerk Een technologie om specifieke chips te ontwerpen. Bij maatwerk ontwerpen we tot op schatting van het aantal transistoren (of logihet transistorniveau. We stellen transistoren sche blokken in het geval van een FPGA) die dan voor als rechthoeken die we op het chipopmen nodig heeft om deze schakeling te realisepervlak plaatsen. Met deze techniek kunnen we ren. Meestal schaalt deze kostprijs ook met de tot het beste ontwerp komen, zowel qua snelfinanci¨ele kostprijs om de schakeling fysiek te heid, vermogenverbruik en afmetingen. Deze realiseren.. 8 techniek is niet haalbaar voor complexe schakritische pad Een pad van ingang tot uitgang in kelingen.. 33, 340 een schakeling die de grootste vertraging heeft. Het is mogelijk dat een schakeling verschillende mantisse M Een reeks bits bij de vlottende komma kritische paden heeft, al deze paden hebben dan voorstelling. De mantisse zelf wordt voorgedezelfde (theoretische) vertraging.. 49 steld als een vlottend komma getal. Dit getal wordt vermenigvuldigt met het teken dat wordt L bepaald door de sign-bit en de exponent.. 77
Woordenlijst
345
maximale frequentie fmax De maximale snelheid Negatief oneindig −∞ Een element bij de vlottende waarop een elektronische schakeling een cyclus komma voorstelling van IEEE 754. Negatief onkan uitvoeren: van het veranderen van ´e´en of eindig wordt voorgesteld met de tekenbit op 1, meer ingang(en) of het kloksignaal, tot het aan0 voor de mantisse, en het hoogst mogelijk voor passen van geheugens en het aanleggen van ante stellen getal van de exponent. Berwerkingen dere waardes op de uitgangen. De maximale die tot overflow leiden in het negatieve, geven frequentie wordt bepaalt door het logische cirnegatief oneindig.. 79 cuit zelf, maar ook de organisatie van de chip en bijvoorbeeld de fan-out van de poorten.. 43 negatieve logica Een vorm van implementeren van logica waarbij we een hoge spanning associ¨eren met een 0 en een lage spanning met een 1.. 25 maximale stroomsterkte IOmax De maximale hoeveelheid stroom die door een uitgang van een poort kan stromen per tijdseenheid. Deze stroom- Niet-genormaliseerde vlottende komma voorstelling Een familie van vlottende komma voorstellinsterkte hangt grotendeels af van de parasitaire gen. Hierbij wordt de waarde van de mantisse capaciteit. De maximale stroomsterkte heeft M niet begrensd. De niet-genormaliseerde vlottot gevolg dat een poort maar met een beperkte tende komma voorstelling kan meer getallen voorfan-out kan werken.. 43 stellen, maar veel getallen kunnen ook op verschillende manieren worden voorgesteld. Dit lemaxtermen Een maxterm is een logische functie die vert complexere logica op bij bijvoorbeeld het waar is voor alle configuraties behalve ´e´en conimplementeren van een vergelijker.. 78 figuratie. Het is een booleaanse som van alle ingangen (waarbij een deel van de ingangen evenniet-inverterende poorten Poorten waar conceptueel ge¨ınverteerd zijn). Indien de maxterm tueel op het einde geen inverter staat. Nietbijvoorbeeld enkel onwaar hoort te zijn voor inverterende poorten zijn AND en OR.. 49 hx, y, z, ti = h1, 0, 1, 1i, is de maxterm x0 + y + z 0 + t0 .. 11 NMOS Een variant van een automatische schakelaar waarbij de schakelaar gesloten is indien het mintermen Een minterm is een logische functie die stuursignaal hoog is; en open indien het stuurslechts waar is voor juist ´e´en configuratie van signaal laag is.. 25 ingangen. Het is een booleaanse product van alle ingangen (waarbij een deel van de ingangen NOR Een basisschakeling met 2 ingangen. De coneventueel gge¨ınverteerd zijn). Indien de minfiguratie h0, 0i wordt afgebeeld op 1; de overige term bijvoorbeeld enkel waar hoort te zijn voor configuraties op 0. 7 hx, y, z, ti = h1, 0, 1, 1i, is de minterm x·y 0 ·z ·t.. NOT Een populaire bassischakeling die 0 afbeelt op 11 1; en 1 op 0.. 4 modulo Een rekekundige bewerking op twee getallen. Modulo berekent de rest. Indien de rest Not a Number (NaN) Een speciaal getal bij getallen met vlottende komma volgens IEEE 754. negatief is, is het resultaat een getal tussen 0 NaN stelt het resultaat voor van een bewerking en abs b − 1 (inclusief) die equivalent is met de die wiskundig niet correct is. Bijvoorbeeld het rest.. 76, 337 delen door nul, het verschil tussen twee oneinmultiplexer Een component dat bestaat uit n selectiedige getallen, de vierkantswortel van een negaingangen si , 2n data-ingangen di en een uitgang tief getal, enzovoort.. 79 f . Wanneer de binaire waarde van het getal S op de selectie-ingangen wordt aangelegd, wordt Nul (0) Het kleinste natuurlijke getal. Dit getal is niet voor te stellen bij een genormaliseerde vlotde waarde van data-ingang DS op de uitgang tende komma voorstelling. Men introduceerde gezet.. 82, 345, 348 hiervoor een regel dat indien zowel de exponent MUX zie multiplexer. 82 als de mantisse nul zijn, het getal ook nul is.. 79 N O NAND Een basisschakeling met 2 ingangen. De configuratie h1, 1i wordt afgebeeld op 0; de ove- octaal stelsel Een Arabisch getalstelsel met radix rige configuraties worden afgebeeld op 1.. 7 r = 8.. 59
346
Woordenlijst
open Een toestand bij een schakelaar waarbij er geen placement Een deelproces bij het bouwen van spestroom door de schakelaar vloeit.. 25 cifieke chips aan de hand van standaardcellen. Bij placement probeert men de componenten zo Open-Drain Poort Een poort die bestaat uit meerte plaatsen dat het ontwerp optimaal is.. 33 dere parallel geschakelde NMOS transistoren. Vanaf het moment dat een van de NMOS tran- PLD talen Een verzameling talen die een schakesistoren gesloten wordt, vloeit er stroom van de ling beschrijven op het niveau van poorten voor bron naar de grond. Enkel wanneer alle schakeeen specifieke technologie. PLD talen beschrijlaars open zijn, wordt er dus een hoge spanning ven dus details over de implementatie, dit in op de uitgang aangelegd.. 27 tegenstelling tot bijvoorbeeld VHDL die eerder het gedrag beschrijft. Voorbeelden van PLD OR Een populaire basisschakeling met twee ingantalen zijn Abel en Palasm.. 18 gen. h0, 0i wordt afgebeeld op 0; en h0, 1i, h1, 0i en h1, 1i worden afgebeeld op 1.. 4 PMOS Een variant van een automatische schakelaar waarbij de schakelaar gesloten is indien het OR-AND-Invert (OAI) Een schakeling gemaakt stuursignaal laag is; en open indien het stuuruit transistoren die een tweelaggie structuur omsignaal hoog is.. 25 vat met het eerste een reeks OR-poorten, de uitgan van dezeOR poorten passeren vervolens Positief oneindig +∞ Een element bij de vlottende door een NAND poort. Men kan deze schakelin komma voorstelling van IEEE 754. Positief onechter zeer goedkoop realiseren.. 29 eindig wordt voorgesteld met de tekenbit op 0, 0 voor de mantisse, en het hoogst mogelijk voor OR-matrix Een raster dat gebruikt wordt voor prote stellen getal van de exponent. Berwerkingen grammeerbare chips. Men beschouwt n ingandie tot overflow leiden in het positieve, geven gen en m n-OR-poorten, voor elke ingang en positief oneindig.. 79 elke AND poort is er een zekering waardoor men kan beslissen welke ingangen er aan welke positieve logica Een vorm van implementeren van OR-poort worden gehangen. Een OR-matrix logica waarbij we een hoge spanning associ¨eren wordt ondermeer gebruikt bij een programmamet een 1 en een lage spanning met een 0.. 25 ble logic array (PLA).. 34 priemimplicant Een implicant die geen onderdeel overdracht Een restproduct dat ontstaat wanneer is van een andere implicant met strikt minder we twee cijfers x en y optellen, en de het resulvariabelen.. 52 taat is groter dan de radix r. In dat geval is de overdracht b(x + y) /rc. De overdracht wordt prioriteitsencoder Een variant van een encoder. Een gebruikt als toevoeging bij de optelling van het component met 2n data-ingangen di , een anyvolgend cijfer.. 62, 339 uitgang a en n selectie-uitgangen fi . Indien er op minstens ´e´en van de data-ingangen een overflow Een signaal dat na een bewerking - bijvoor1 staat, staat er ook een 1 op de any-uitgan beeld een optelling - het resultaat niet meer volen vice versa. Wanneer er op ´e´en of meerdere ledig voor te stellen valt op de gegeven bits. Dit data-ingang di een 1 staat, geven de selectieis bijvoorbeeld het geval bij een 8-bit opteller, uitgangen binair de waarde van deze index van waarbij het resultaat groter is dan 255.. 63 de hoogste data-ingang met 1 weer.. 85 Product-of-Sums (POS) Een machinale manier om uit een waarheidstabel een logische functie te parallelle vermenigvuldiger Een component die voor genereren die gebruik maakt van 0-maxtermen. twee getallen het product berekent. Dit doet Men berekent eerst de 0-maxtermen van de waarhet op een manier die vergelijkbaar is met cijheidstabel, en neemt vervolgens het booleaanse feren. Voor elke bit van het tweede getal wordt product van deze 0-maxtermen.. 11 een opteller voorzien. Indien de overeenkomstige bit 1 is, wordt het eerste getal opgeteld, Programmable Array Logic (PAL) Een variant voldoende opgeschoven naar links. Een paralop een programmable logic array (PLA). Hierlelle vermenigvuldiger kost veel hardware en is bij staat de OR-matrix echter vast (deze kan bovendien meestal niet sneller dan andere vorniet geprogrammeerd worden door zekeringen men van vermenigvuldigers.. 74 door te branden).. 34 P
Woordenlijst
347
Programmable Logic Array (PLA) Een program- Quine-McCluskey algoritme Een algoritme die voor meerbare chip die werkt op basis van zekerineen gegeven logische functie - bijvoorbeeld aan gen. Deze chip bevat twee rasters van poorten: de hand van een waarheidstabel - een minimale een AND- en OR-matrix. Voor elk van item implementatie zoekt. Het algoritme is grotenin het raster is er een zekering die doorgebrand deels equivalent aan minimalisatie met behulp kan worden.. 34 van Karnaugh-kaarten, maar werkt aan de hand van patronen, in plaats van visuele hulpmiddeProgrammable Logic Device (PLD) Een programlen. Het algoritme is aanwezig in de meeste meerbare chip waarbij men een programmable CAD-paketten.. 56 array logic (PAL) gebruikt, maar aangevuld met flipflops bij de uitgangen en een gedeeltelijk feedbackR mechanisme: een deel van de uitvoer, wordt terug als invoer hergebruikt.. 34 radix r Een eigenschap van een Arabisch getalsysteem. De radix wijst op het gewicht die een Programmable Read Only Memory (PROM) cijfer in een getal heeft ten opzichte van het Een variant op een programmable logic array volgende cijfer. Het i-de cijfer van rechts - in(PLA). Hierbij staat de AND-matrix vast (deze clusief 0 - heeft een waarde van ri .. 59 kan dus niet geprogrammeerd worden). De ANDmatrix is gestructureerd als een adresdecoder: radix-complement Een complement voorstelling waarwanneer de invoer binair het getal n voorstelt, bij men negatieve getallen voorstelt door ze voor is de n-de uitgang actief.. 34 te stellen als het getal D∗ = rm − D met D de absolute waarde van het getal, r de radix van Programmeerbare Chips Een technologie waarbij de getalvoorstelling, en m het aantal cijfers van met een chip realiseert door naar het geheuhet getal.. 68, 337 gen van een programmeerbare chip te schrijven. Het gedrag van de chip hangt dan ondermeer RC-keten Een schakeling in de analoge elektronica af dat geheugen. Vaak deelt men een dergelijke die bestaat uit een condensator en een weerchip op in logische blokken met elk een kleine stand. Wanneer men spanning op deze schahoeveelheid geheugen. Sommige programmeerkeling aanbrengt, wordt de condensator opgebare chips bevatten 2 miljoen logische cellen.. laden. Wanneer men later de spanningsbron 32 ontkoppelt en de kring sluit, zal de condensator ook traag leeglopen. De snelheid waarmee programmeerbare chips Chips met een vorm van dit zal gebeuren, hangt af van de weerstand R geheugen. Het gedrag van deze chips hangt dan en de capaciteit van de condensator C.. 39 af van de waarden in dat geheugen. Dit geheugen hoeft geen RAM, ROM, of flash geheugen Register-Transfer-Level (RTL) Componenten te zijn; het al dan niet doorbranden van een Een laag van componenten voor synthese. Hierzekering is ook een vorm van geheugen.. 34 onder vallen ondermeer optellers, tellers en schuifregissters vallen.. 15 propagation delay zie Vertragingstijd tp . 41 remainder Een rekenkundig bewerking op twee gePull-Down Network (PDN) Het principe dat we tallen waarbij het resultaat de rest na deling een lage spanning aanleggen op een uitgang met voorstelt. Voor de getallen a en b betekent dit behulp van een transistor die zich sluit, waardus a rem b ≡ a − ba/bc · b.. 76, 337 door de stroom een alternatieve route naar de grond kan vinden, en dus niet langer een poten- Ripple-carry opteller Een component die aan de tiaal op de uitang zet.. 26 hand van full adders en optioneel een half adder, twee getallen in binaire notatie optelt. Dit doen Pull-Up Network (PUN) Het principe dat we een men door de full adders aan elkaar te schakelen hoge spanning aanleggen op een uitgang met zodat elke adder twee bits van de getallen op behulp van een transistor die zich sluit. Hierdezelfde positie verwerkt, en de carry van bits door wordt de uitgang verbonden met de hoge op positie i als carry ingang voor de volgende spanning.. 28 bit wordt gebruikt.. 63 Q
rise time zie Stijgtijd tr . 40
348 roteren Een variant van een schuifoperatie waarbij de bits die buiten het bereik van het nieuwe getal vallen, aan de andere kant op de vrijgekomen plaatsen worden gezet.. 89
Woordenlijst data. Wat er met de vrijgekomen plaatsen gebeurt is niet gespecificeerd, dit hangt af van de concrete variant. Er zijn twee soort schuiven: logisch schuiven en aritmetisch schuiven.. 89
routing Een deelproces bij het bouwen van speci- Sea of Gates Een tweedimensionaal rooster met idenfieke chips aan de hand van standaardcellen. tieke poorten en ruimte tussen de poorten. De Bij routing legt men de bedrading tussen de sea of gates wordt gebuikt bij het realiseren van verschillende componenten.. 33 schakelinen met de gate array techniek.. 33 S schakelaars Een component waar - afhankelijk van een stuursignaal of toestand - er al dan niet stroom door vloeit.. 25
selectie-ingangen si Ingangen bij een multiplexer de waarde die op de selectie-ingangen worden gezet bepalen welke data-ingang van de multiplexer wordt doorgegeven op de uitgang.. 82
selectie-uitgangen si Een reeks uitgangen bij bijvoorbeeld een decoder. Wanneer bij een decoschakelmatrix Een schakelmatrix is een programder de adres-ingangen ai het binaire getal A meerbare component waarin verbindingen savormen, en op de enable-ingang e staat 1, zal menkomen. Afhankelijk van de manier hoe men op de selectie-uitgang sA ook een 1 staan; en de matrix programmeert zijn sommige ingangen op de overige selectie-uitgangen 0. Wanneer er wel of niet met elkaar verbonden. Men gebruikt op de enable-ingang een 0 staat, staan op alle schakelmatrices vaak als een deel van programselectie-uitgangen nullen.. 82, 85 meerbare chips zoals een complex programmable logic device (CPLD) of een field programselector zie multiplexer. 82 mable gate array (FPGA).. 35 sequenti¨ ele schakeling Een schakeling waarbij de Schmitt-trigger ingangen Een component die men waardes die op de uitgangen worden gezet, niet bij de invoer van een chip plaatst. Schmittenkel afhangen van de waardes die aan de intrigger ingangen hebben een hysteresis. Deze gang staan, maar ook aan een interne toestand hysteresis probeert het probleem op te lossen van de schakeling. Deze toestand wordt bijgedat bij een chaotische overgang van 0 naar 1, er houden door een geheugencomponent. De toeverschillende binaire waarden doorheen de chip stand van een sequenti¨ele schakeling kan verzouden propageren.. 39 anderen door veranderingen aan de invoer, of door een klokflank.. 94 schuifoperaties Een reeks operaties waarbij men bits opschuift in een getal naar links of naar rechts. seven-segment display Een component die zeven Afhankelijk van het soort schuifoperaties zal men leds plaatst in de vorm van een acht. Men kan bepaalde bits op de vrijgekomen plaatsen inaan de hand van een seven-segment display elk vullen en bepaalde bewerkingen uitvoeren op cijfer van 0 tot 9 weergeven.. 56 de bits die uit de getalvoorstelling vallen. Onder schuifoperaties rekenen we logisch schuiven, sign-bit s Een bit bij de vlottende komma voorstelaritmetisch schuiven en roteren. Deze operaties ling. De tekenbit geeft - zoals bij een signkomen telkens voor in twee richtingen: links en magnitude voorstelling - aan of we de rest van rechts. Bij een schuifoperatie van m bits naar het getal als positief (0) of negatief (1) moeten links zullen de waardes van de bits xi worden interpreteren.. 77, 349 verplaatst naar yi+m = xi , maar enkel indien zowel i als i + m binnen het bereik liggen. Wat sign-magnitude Een manier om negatieve getallen voor te stellen. Men plaatst hierbij een bit voor er met de overige bits en de vrijgekomen plaathet getal - de tekenbit - en indien deze 1 is, diesen zal gebeuren, hangt af van de variant van nen we het getal als zijn negatie te interpretede schuifoperatie.. 88 ren. Wanneer de bit 0 is, is het getal positief.. schuiven Een variant van een schuifoperatie waarbij 68 de bits van het originele getal die na schuiven niet langger in het bereik van het resultaat lig- slices De delen van een configurable logic block (CLB).. gen, genegeerd worden. Er is dus verlies aan 36
Woordenlijst Source Een connectie van een FET transistor.. 24, 25, 339 Spartan-3 Een populaire field programmable gate array (FPGA) chip.. 36
349 te stijgen. Omdat de spanning van de bron of grond vaak niet bereikt worden, neemt men vaak waarden van respectievelijk 10% en 90% tussen de basisspanning en de topspanning.. 40, 347
Specificatie Een document die de functionaliteiten beschrijft van hardware.. 14
stuursignaal Een signaal bij een generische transistor. Het stuursignaal (vaak “basis” genoemd) beslist of er stroom tussen de collector en de Specifieke Chips (ASIC) Een technologie waarbij emitor stroomt.. 25 chips die volledig zelf fysiek gerealiseerd worden. Men maakt een masker aan en belazerde Sum-of-Products (SOP) Een machinale methode vervolgens de chip zodat er poorten ontstaan. om uit een waarheidstabel een logische functie Deze techniek is erg duur en wordt enkel toegete genereren die gebruik maakt van 1-mintermen. past bij chips met grote oplage.. 32 Men berekent eerst de 1-mintermen van de waarheidstabel, en neemt vervolgens de booleanse spiegelt Een manier om Karnaugh-kaarten voor te som van deze 1-mintermen.. 11 stellen indien het aantal dimensies stijgt boven de vier. In dat geval worden twee 4 × 4 ras- Synthese De vertaling van specificaties van een hoog ters beschouwd. Het tweede raster spiegelt de en abstract niveau naar een lager niveau. Er variabelen over de as tussen de twee rasters.. 51 zijn verschillende lagere niveaus. Het gekozen niveau hangt af van de beschikbare componenstandaard cellen Een technologie om specifieke chips ten in de bibliotheek. Zo is er het RTL niveau, te ontwerpen. Bij standaardcellen maken we gehet ASIC niveau, etc.. 15 bruik van componenten uit een bibliotheek die allemaal eenzelfde hoogte, maar een variabele systeemsynthese De hoogste laag van de synthese pyramide. Hier worden processoren, geheugens breedte hebben. Bovenaan deze componenten en ASIC componenten gecombineerd in een volbevinden zich de ingangen, onderaan de uitganledig systeem.. 15 gen. We leggen deze componenten in rijen (een proces dat placement wordt genoemd), waarna men de bedradingg tussen de componenten legt T (dit noemt men routing).. 33 technology mapping Het realiseren van een gegeStandaard Chips Een technologgie bij het realiseren van een elektronische schakeling. Hierbij koopt men eenvodige chips (bijvoorbeeld poorten en optellers) die specifieke functies vervullen. Men dient dan enkel nog deze chips met elkaar te verbinden.. 32
ven schakeling in een bepaalde technologie. Bijvoorbeeld met behulp van poorten, logische blokken,... Afhankelijk van de gekozen technologie verschilt de kostprijs en ook de doelen bij een implementatie. Bij een FPGA bijvoorbeeld staat het aantal poorten in een logisch blok vast, en proberen we enkel de implementatie te optimaliseren tot deze in de beschikbare logische blokken past.. 58
standaard vorm Een implementatie van een logische functie aan de hand van Sum-of-Products of Products-of-Sum, maar waarbij men aan de hand van de wetten van De Morgan het aantal tekenbit s zie sign-bit s. 77 poorten reduceert. De standaard vorm is altijd threshold spanning VT Het minimale verschil in spangoedkoper dan de canonieke vorm.. 12 ning die men tussen de gate en de source moet aanleggen bij een NMOS zodat er een verbinStatisch vermogenverbruik Het vermogen die een ding tussen de source en de gate ontstaat.. 26 chip continu verbruikt, en die niet afkomstig is van bijvoorbeeld veranderingen aan de ingang throughput zie doorvoer. 16 of het kloksignaal. Bij NMOS is dit de lekstroom bij gesloten transistoren. Bij CMOS is Tijdsconcept Een eigenschap van VHDL die niet van toepassing is bij klassieke programmeertahet statisch vermogenverbruik praktisch onbelen. De eigenschap stelt dat alle hardware constaand.. 42 tinue werkt, en dat er ook een specifieke verStijgtijd tr De tijd die een geleider nodig heeft om traging in de tijd is bij het doorrekenen van van een lage spanning naar een hoge spanning veranderende signalen.. 22
350
Woordenlijst
tijdsconstante τ Een parameter die beschrijft hoe Uitgangsimpedantie RO De virtuele weerstand die snel een systeem zich aanpast aan een nieuwe tussen de bron of de grond enerzijds en de uittoestand aan de invoer. Systemen zoals het gang van een poort staat. We streven ernaar de dynamische systeem van een geleider gedragen uitgangsimpedantie zo laag mogelijk te houden, zich typisch exponentieel. In dat geval zal het zodat de tijdsconstante van de geleider naar gedrag dus beschreven worden aan de hand van andere ingangen lager is en de chip bijgevolg V (t) = V∞ · 1 − et/τ ofwel V (t) = V0 · e−t/τ .. sneller zal schakelen. Een nadeel bij een lage 39 ingangsimpedantie is een hoger dynamisch vermogenverbruik.. 40 Transferfunctie Een transfer-functie van een logische poort of circuit mapt de spanning aan de underflow Het fenomeen dat kleine getallen – in de zin van te dicht bij 0 – niet voor te stellen zijn ingang(en) op de spanning die op dat moment door alle getalvoorstellingen, dit is bijvoorbeeld aan de uitgang(en). Deze functie hangt af van een belangrijk fenomeen bij vlottende kommaondermeer het productieproces om de poort te getallen.. 78 maken, maar ook van omgevingsfactoren zoals warmte. Idealiter beogen we discreet gedrag ele poorten Een poort waarmee men elke aan de uitgang. In werkelijkheid is dit gedrag universi¨ functie kan bouwen. In de booleaanse logica eerder continu.. 38 komt dit er op neer dat men een NOT en AND moet kunnen bouwen. Voorbeelden van unitransistoren Automatische schakelaars. Een tranversi¨ele poorten zijn de NAND en NOR.. 7 sistor heeft drie verbindingen, de collector en de emittter vormen een schakelaar, en de basis stuurt deze schakelaar aan. Afhankelijk van de soort transistor gelden er andere regels over wanneer de schakelaar gesloten wordt, en volgens welk patroon.. 25 transmission gate Een component die functioneert als een schakelaar. De component heeft drie ingangen: x, s en s¯. Indien s = 0 en s¯ = 1, is de ingang x niet verbonden met de uitgang f ; in alle overige gevallen, is x verbonden met f . Een transmission gate wordt ondermeer gebruikt om een tri-state buffer te realiseren.. 44
V Vaste komma voorstelling Een voorstellingswijze voor kommagetallen. De voorstelling van een getal bestaat in dat geval uit twee delen: een geheel deel een fractioneel deel. Tussen de twee delen wordt een punt (.) gezet. Beide delen krijgen een vast aantal cijfers, wat we noteren met fix hi, f i: i bits voor het geheel deel, f voor het fractioneel deel. Omdat het aantal bits vast staat kunnen getallen met vaste komma maar een beperkte hoeveelheid getallen voorstellen. Het voordeel is echter dat men optellers en andere componenten niet hoeft aan te passen.. 77, 342
Tri-state buffer Een uitbreiding op een buffer. Een tri-state buffer heeft een extra enable ingang E. Indien op deze ingang een 1 staat, wordt de waarde aan de ingang ook op de uitgang ge- verborgen bits Bits die alleen virtueel bestaan, bijzet. In het andere geval wordt er een zwevende voorbeeld bij de interpretatie van een getal. In toestand Z op de uitgang gezet.. 43 het geval van IEEE 754 is de eerste bit in de “semantisch” interpretatie van de mantisse vertrial-and-error Een strategie waarbij men een proboren: deze wordt niet expliciet voorgesteld.. bleem oplost door een reeks - al dan niet popu79 laire - methodes op het probleem toepast en vervolgens de resultaten van deze methodes verge- vergelijker Een component die als invoer twee getallen krijgt en een reeks testen uitvoert. Welke lijkt. Daarna kiest men de meest voordelige optesten men concreet bekijkt staat niet vast. Meestal lossing. Ervaring laat toe om vaak niet alle mezal men kijken of het ene getal groter is dan het thodes te moeten uitproberen, en dus op voortweede en/of omgekeerd.. 86, 339 hand te weten welke methodes zeker niet tot een betere oplossing zullen leiden.. 57 Verilog Een concurrent van VHDL. Verilog is vooral populair in de Verenigde Staten en gestandaarU diseerd in IEEE 1364.. 18
Woordenlijst
351
vermogenverbruik De hoeveelheid energie per tijds- Write Once Read Many (WORM) Een principe eenheid die een schakeling nodig heeft om te waarbij men slechts ´e´enmaal naar een geheugen kunnen functioneren. Het vermogenverbruik wordt kan schrijven, maar de gegevens in dat geheuopgedeeld in statisch vermogenverbruik en dygen dan meermaals kan lezen.. 32 namisch vermogenverbruik.. 41 X Vertragingstijd tp De tijd die een poort nodig heeft tussen het moment waarop de spanning aan de XNOR Een poort met twee ingangen die de ge¨ınverteerde ingang de 50% tussen de de basisspanning en is van de XOR poort. h0, 0i en h1, 1i worden aftopspanning bereikt, en de tijd dat de spanning gebeeld op 1 de overige configuraties op 0.. 29 aan de uitvoer dat punt bereikt.. 41, 347 XOR Een populaire basisschakeling met twee inganverwerkingskracht De verwerkingskracht van een gen. Hierbij worden h0, 0i en h1, 1i afgebeeld op schakeling duidt op hoe snel een veranderin aan 0; en h0, 1i en h1, 0i afgebeeld op 1.. 6 de ingang van de schakeling kan worden doorgerekend ofwel gepropageerd naar de uitgangen.. Z 8 Zekeringen Een geleider, maar die makkelijk door VHDL Afkortin voor VHSIC Hardware Description overbelasting kan worden doorgebrand. ZekeLanguage. Een programmeertaal die wordt geringen zijn een vorm van programmeerbaar gebruikt om het specificeren, ontwikkelen en anaheugen: door het doorbranden van bepaalde zelyseren van hardware.. 17 keringen kan het gedrag van een programmeerbare chip wijzigen.. 34 VHDL Analog and Mixed Signals (VHDL-AMS) Een uitbreiding van VHDL die het mogelijk maaktzwevende modus Z Een waarde die op een geleiniet alleen met digitale, maar ook met analoge der staat. Bij een zwevende modus staat er geen signalen te rekenen. Het is dus een superset van 0 of 1 op de geleider. Deze toestand is nuttig VHDL.. 17 wanneer verschillende poorten eenzelfde geleider willen aansturen. Wanneer er bijvoorbeeld vlottende komma voorstelling Een manier om een twee poorten een uitgang verbinden met een gekommagetal voor te stellen met een bereik tusleider, en de ene poort zit in zwevende modus, sen zeer kleine en zeer grote getallen. Men encoen de andere poort legt 1 aan, dan staat er 1 op deert het getal op een wetenschappelijke manier de geleider. De zwevende modus kan men bekoin bits met een tekenbit s, een mantisse M en men met een tri-state buffer en wordt gebruikt een exponent. Getallen met drijvende komma bij de implementatie van bussen.. 43, 343 zijn gestandaardiseerd in IEEE-754.. 77, 341, 342, 351 zwevendekommagetal zie vlottende komma voorstelling. 77 voedingsspanning V Het spanningsverschil van de voeding waarmee een chip haar werk uitvoert. Het dynamisch vermogenverbruik schaalt kwadratisch met de voedingsspanning.. 42 W Wet van Moore Een geobserveerde wet dat het aantal transistoren op een chip gemiddeld elke 24 maanden verdubbelt.. 16 wetten van De Morgan Twee wetten in de booleaanse algebra. De eerste wet stelt dat de negatie van een AND, een OR is met ge¨ınverteerde ingangen. De tweede wet is zijn duale: de negatie van een OR is een AND met ge¨ınverteerde ingangen. Formeel schrijven we de wetten als 0 0 (x · y) = x0 + y 0 en (x + y) = x0 · y 0 .. 10
Index N -kubus, 50 N fix N Ai, f B, 77 float Am, e B, 78 mod , 76 rem, 76 m × n registerbank, 159 n-and, 7 n-or, 7 double, 78 float, 78 single, 78 VHDL ’-’, 273, 274 ’0’, 273, 274 ’1’, 273, 274 ’H’, 273, 274 ’L’, 273, 274 ’U’, 273, 274 ’W’, 273, 274 ’X’, 273, 274 ’Z’, 273–275 ’, 265 **, 267 *, 267 +, 267 ,, 270 -, 267 ., 264 /=, 267 /, 267 :=, 271 :, 271, 272 ;, 271, 272 <=, 267, 272 <>, 270 <, 267 =, 267 >=, 267 >, 267 ABS, 267 AND, 267 BIT VECTOR, 267 BIT, 267 B, 265
CHARACTER, 267 DELAY LENGTH, 267 E, 265 INTEGER’HIGH, 267 INTEGER, 267 MOD, 267 NAND, 267 NATURAL, 267 NOR, 267 NOT, 267 NULL literal, 264 OR, 267 O, 265 POSITIVE, 267 REAL, 267 REM, 267 ROL, 267 ROR, 267 SLA, 267 SLL, 267 SRA, 267 SRL, 267 STRING, 267 TIME’HIGH, 267 TIME, 267 XNOR, 267 XOR, 267 X, 265 &, 267, 276 , 265 ‘0’, 277 abstract literal, 264 and, 275 architecture, 20 array, 265, 270 a, 265 base#literal#exp, 265 bit string literal, 265 bit vector, 20, 269, 275, 277 bitreeks, 265 bit, 20, 267, 269, 272, 273, 275 boolean, 275 byte, 267 b, 265 352
INDEX case, 265 character literal, 265 character, 268 component, 20 constant, 271 c, 265 delimiter, 265 downto, 265, 268 d, 265 end, 269 entity, 20 enumeration literals, 264 e, 265 fs, 267 function, 274 f, 265 hr, 267 identifier, 265 integer, 268, 277 in, 20 is, 267, 268, 270 length, 274 low, 275 map, 20 min, 267 ms, 267 nand, 265, 275 natural, 270 nor, 275 not, 275 ns, 267 of, 270 or, 275 out, 20 physical types, 264 port, 20 ps, 267 range, 268, 270, 275 real, 270 scheidingsteken, 265 sec, 267 signal, 265, 272 sla, 265 std logic vector, 275 std logic, 273–275 std ulogic vector, 274, 275 std ulogic, 273 string literal, 265 subtype, 268 to, 268 type, 267, 269, 270 units, 269 universal integer, 264
353 universal real, 264 use entity, 21 us, 267 variable, 271 xnor, 275 xor, 275 0-maxtermen, 11 1-complement, 68 1-mintermen, 11 2-complement, 69 3-state buffer, 43 Absorptie, 10 Accumulator (ACC), 223 Actie-notatie, 220 Add-instructie, 221 Adres, 218 Adres-ingangen ai , 82 Adresbus, 242 Adresdecoder, 34 Adresregister (AR), 239 Adresseermode, 220 Algebra¨ısch manipuleren, 57 Algorithmic-State-Machine Chart, 154 American Standard Code for Information Interchange (ASCII), 80 Analyse, 16 AND, 4 AND-matrix, 34 AND-OR-Invert (AOI), 29 Any-uitgang a, 85 Application Specific IC (ASIC) componenten, 15 Arabisch getalsysteem, 59 Arithmetic-Logic Extender (ALE), 72 Arithmetic-Logic Unit (ALU), 72 Aritmetisch schuiven, 89 Array aggregate, 269 ASM-blok, 155 ASM-elementen, 154 ASM-schema, 154 Assembleerprogramma, 233 Assembleertaal, 233 Assignatie, 271 Associativiteit, 10 Asynchrone sequenti¨ele schakelingen, 95 Asynchrone set en reset, 101 Asynchrone teller, 105 Asynchronous counter, 105 Autodecrement, 227 Autoincrement, 227 Bal-en-heuvel-analogie, 99 Barrel left rotator, 89 Basis, 25
354 Basisadres, 226 Basisoperaties, 4 BCD-teller, 107 Beslissingskader, 154 Bidirectionele teller, 104 Bidirectionial counter, 104 Binair stelsel, 59 Binaire signalen, 3 Binary Coded Decimal (BCD), 80 Blackbox, 20 Booleaanse algebra, 9 Bronradix, 60 Buffer, 30 Buffergeheugen, 162 Buren, 50 Bus, 44, 83 Bus sharing, 177, 200 Call stack, 174 Canonieke vorm, 12 Capaciteit C, 40 Carry, 62 Carry Input Generator (CIG), 72 Carry-generate gi , 64 Carry-lookahead opteller (CLA), 64 Carry-propagate pi , 64 Cascade, 82 Chaining, 207 Character, 265 Chip Select-ingang CS, 161 Chipoppervlakte C, 42 Cijfer-complement, 68 Cijferen, 62 CLA-generator, 65 x CLR∗ , 101 Clock skew, 213 CLRA-instructie, 225 CMOS, 26 Coderen, 113 Collector, 25 Combinatorische Schakelingen, 47 Commentaar, 264 Commutativiteit, 10 Comparator, 86 Compatibele toestanden, 126 Compatibiliteitsgraaf, 184 Complement voorstellingen, 68 Complex Instruction Set Computer (CISC), 228 Complex Programmable Logic Device (CPLD), 35 Computer Aided Design (CAD), 16 Concurrency, 22 Conditional box, 155 Conditioneel kader, 155 Configurable Logic Blocks (CLB), 36
INDEX Constante, 270 Controle-ingangen, 149 Controle-signalen, 149 Controle-uitgangen, 149 Controller, 149 Cover, 52 Critical race, 131 Custom Design, 33 Cycle, 131 D-flipflop, 101 Daaltijd tf , 41 Dalende flank, 95, 124 Dambordpatroon, 55 Data Flip-Flop (D-FF), 36 Data-flipflop, 101 Data-ingang D, 97 Data-ingang d, 84 Data-ingangen, 149 Data-ingangen di , 82 Data-uitgangen, 149 Data-uitwisseling, 220 Databus, 242 Datapad, 149 Datatypes, 22 Decimale stelsel, 59 Decision box, 154 Declaratie, 271 Decoder, 82 Decrement, 72, 104 Dekking, 52 Deling, 76 Demultiplexer, 84 Demux, 84 Diminished-radix complement, 68 Directe adressering, 225 Distributiviteit, 10 Documentatie, 16 Doelradix, 60 Don’t care, 11, 55 Doorvoer, 16 Doperen, 26 Down-counter, 104 Down-Up D/U ∗ , 104 Drain, 24, 25 Drijvendekommagetal, 77 Driver, 30 Dual port registerbank, 160 Dualiteit, 10 Dubbele precisie, 78 Duty cycle, 95 Dynamisch gedrag, 39 Dynamisch RAM, 161 Dynamisch vermogenverbruik, 42
INDEX Dynamische hazard, 138 Edge-triggered flipflop, 99 Eindige-toestanden machine, 94 Emitter, 25 Empty, 165 Enable E, 43 Enable-ingang e, 82 Encoder, 85 Enkele precisie, 78 Espresso heuristic logic minimizer, 57 Essenti¨ele hazard, 142 Essenti¨ele priemimplicant, 52 Excess formaat, 68 Excess-bias B, 68 Excitatiefuncties, 117 Excitatietabel, 101, 116 Excitatietabellen, 117 Execution stack, 241 Exponent E, 77 Factoranalyse, 57 Fall time, 41 Falling edge, 95 Fan-in, 43 Fan-out, 43 Field Programmable Gate Array (FPGA), 34, 36 Finite state machine (FSM), 94 Finite State Machine with Data path (FSMD), 149 First-In-First-Out (LIFO), 166 Fixed point, 77 Flankgevoelig, 99 Flash-programmeerbaar, 34 Flipflop, 94, 96 Floating-point number, 77 Flow table, 125 Fractionele gedeelte, 77 Full, 165 Full adder (FA), 63 Functional Units (FU), 150 Functional-unit sharing, 188 Functionele Eenheden, 150 Functionele ontbinding, 57 Functionele-eenhedentabel, 181 Fundamental mode restriction, 123 Fundamentele modus, 123 Gate, 25 Gate Array, 33 Ge¨ındexeerde adressering, 227 Ge¨ınverteerde ingangen, 8 Gecombineerde lees-schrijfpoort R/W ∗ , 161 Geconditioneerde sprong (CJMP), 232 Geheel deel, 77
355 Geheugen-programmeerbaar, 34 Geheugencomponent, 94 Geklokte D-latch, 97 Geklokte SR-latch, 96 Gelijk aan (EQ), 232 Gelijktijdigheid, 22 Generische instructiecyclus, 211 Genormaliseerde vlottende komma voorstelling, 78 Gesloten, 25 Glitch, 9 Glitches, 114 Glue Logic, 32, 35 Gray-code teller, 114 Greedy algorithm, 54 Groter dan (GT), 232 Groter dan of gelijk aan (GE), 232 Gulzige strategie, 54 Half adder (HA), 62 Hamming distance, 132 Hammingafstand, 132 Hazards, 138 Hexadecimaal stelsel, 59 High, 24, 37 Hoog impedant, 43 Houdtijd, 98 Hysteresis, 39 Identifiers, 264 IEEE 1164, 273 Implicant, 52 Impliciete adressering, 225 In- en uitvoer modules, 35 Incompatibiliteitsranden, 184 Increment, 72, 104 Indirecte adressering, 225 Ingangscombinatie, 108 Ingangsimpedantie RI , 40 Initalisatie, 108 Inputgebaseerd ASM-schema, 158 Inputgebonden sequenti¨ele schakelingen, 95 Instantie, 270 Instructie, 218 Instructiedecoder, 237 Instructieformaat, 220 Instructieregister (IR), 221 Instructieset, 73, 221 Instructieset-stroomschema, 237 Instructietype, 220 Instructiewoord, 73, 149, 206 Instruction Set Flowchart, 237 Interface, 14 Interpretatie, 233 Inverter, 5
356 Inverterende poorten, 49 Invoer- en uitvoertabellen, 182 Invoer-ingangen Iij , 159 Jack Kilby-flipflop, 102 JK-flipflop, 102 K-kaarten, 50 Karakter, 265 Karakteristieke tabel, 101 Karakterreeks, 265 Karnaugh-kaarten, 50 Kleiner dan (LT), 232 Kleiner dan of gelijk aan (LE), 232 Kliek, 185 Kliek Kn , 127 Klokbuffer, 213 Klokfrequentie, 16, 95 Klokfrequentie f , 42 Klokingang, 95 Klokperiode, 95 Knopen, 184 Kopies, 51 Kostprijs, 8, 49 Kritische pad, 49 Label, 233 Lange lijnen, 36 Last-In-First-Out (LIFO), 163 Latency time, 211 Leeg/empty, 163 Lees (R), 203 Lees/schrijf (RW), 203 Leesadres, 164 Leespoorten, 159 Lekstroom, 42 Levensduur, 179 Levensduurtabel, 179 Literals, 264 Load, 231 Load-instructie, 223 Logical Blocks (LB), 36 Logisch schuiven, 89 Logische poorten, 7 Logische schakelingen, 4, 8 Look-Up Table (LUT), 36 Low, 24, 37 Maatwerk, 33 Machinetaal, 233 Mantisse M , 77 Marginale triggering, 99 Mask, 230 Master-slave flipflop, 99
INDEX Max-cut graph partitioning, 185 Maxtermen, 11 Mealy machine, 95 Mealy-FSM, 95 Merger diagram, 128 Metastabiele toestand, 99 Metastabiliteit, 98 Metastability resolution time tr , 215 Microprogrammeerbare controller, 172 Minimal-bit-change, 114 Mintermen, 11 Mnemonische notatie, 220 Modulo, 76 Modulo-teller, 107 Moore machine, 95 Moore-FSM, 95 Mov-instructie, 222 Mul-instructie, 221 Multicycling, 207 Multiplexer, 82 MUX, 82 NAND, 7 Natuurlijke volgorde, 172 Negatief oneindig −∞, 79 Negatieve logica, 25 Next State Logic, 172 Niet gelijk aan (NE), 232 Niet-genormaliseerde vlottende komma voorstelling, 78 Niet-inverterende poorten, 49 Niet-programmeerbare processor, 149 NMOS, 25 No Operation (NOP), 230 Nodes, 184 NOR, 7 NOT, 4 Not a Number (NaN), 79 Nul (0), 79 Object, 270 Octaal stelsel, 59 Offset, 226 One-hot codering, 113 Ongeconditioneerde sprong (JMP), 232 Onmiddellijke adressering, 225 Opcode, 220 Open, 25 Open-Drain Poort, 27 Operand-tabel, 201 Operanden, 201 Operandverbindingen, 150 Operation code, 220 OR, 4
INDEX OR-AND-Invert (OAI), 29 OR-matrix, 34 Output Logic, 173 Overdracht, 62 Overflow, 63 Overgangstoestanden, 132 Overloading, 277 Parallel laadbaar, 106 Parallel-laadbare bidirectionele teller, 106 Parallelle uitvoering, 209 Parallelle vermenigvuldiger, 74 Pass-transistoren, 36 Pipelining, 209 Placement, 33 PLD talen, 18 PMOS, 25 Pop, 163 Positief oneindig +∞, 79 Positieve logica, 25 Positieve terugkoppeling, 94 x PR∗ , 101 Priemimplicant, 52 Primitive flow table, 125 Prioriteitsencoder, 85 Prioriteitsranden, 185 Product-of-Sums (POS), 11 Program counter (PC), 218 Programma, 219 Programmable Array Logic (PAL), 34 Programmable Logic Array (PLA), 34 Programmable Logic Device (PLD), 34 Programmable Read Only Memory (PROM), 34 Programmageheugen, 218 Programmateller, 218 Programmeerbare Chips, 32 Programmeerbare chips, 34 Propagation delay, 41 Pull-Down Network (PDN), 26 Pull-Up Network (PUN), 28 Push, 163 Queue, 162 Quine-McCluskey algoritme, 56 Race, 96, 131 Radix r, 59 Radix-complement, 68 Random Access, 161 Random Access Memory (RAM), 161 RC-keten, 39 Read, 165 x RAia , 160 x REi , 160
357 Read-Enabled, 158 Read/write∗ -ingang, 167 Recursie, 174 Reduced Instruction Set Computer (RISC), 228 Redundante termen, 140 Register, 94, 103 Register Access Table, 203 Register file cell, 158 Register port sharing, 203 Register-ge¨ındexeerde adressering, 227 Register-indirecte adressering, 225 Register-relatieve adressering, 226 Register-Transfer-Level (RTL) Componenten, 15 Registerbank, 159 Registerinstructies, 230 Registertoegangstabel, 203 Registertransfer, 150 Relatieve adressering, 226 Remainder, 76 Reset, 96, 163, 165 Reset register (ClrR), 232 Reset status (ClrS), 232 Resultaatverbindingen, 150 Resultaten, 201 Resultaten-tabel, 201 Ripple Carry Output (RCO), 105 Ripple counter, 105 Ripple-carry opteller, 63 Rise time, 40 Rising edge, 95 Roteren, 89 Routing, 33 Ruismarge, 38 Schakelaars, 25 Schakelmatrix, 35, 36 Scheidingstekens, 264 Schmitt-trigger ingangen, 39 Schrijf (W), 203 Schrijfadres, 164 Schrijfpoorten, 159 Schuifoperaties, 88 Schuifregister, 103 Schuiven, 89 Sea of Gates, 33 Selectie-ingangen si , 82 Selectie-uitgangen si , 82, 85 Selector, 82 Sequenti¨ele schakeling, 94 Sequenti¨ele uitvoering, 209 Set, 96 Set-reset flipflop, 101 Set-reset latch, 96 Set-up-tijd, 97
358 Seven-segment display, 56 Sign-bit s, 77 Sign-magnitude, 68 Signaal, 270 Skew, 142 Sleutelwoorden, 265 Slices, 36 Source, 24, 25 Spartan-3, 36 Specificatie, 14 Specifieke Chips (ASIC), 32 Spiegelt, 51 Spronginstructies, 230 SR-flipflop, 101 SR-latch, 96 SRAM, 34 Stabiel, 125 Stabiele toestanden, 99 Stack, 162 Standaard cellen, 33 Standaard Chips, 32 Standaard vorm, 12 Stapelgeheugen, 162 Stapelteller, 242 State box, 154 State Register, 172 Statisch RAM, 161 Statisch vermogenverbruik, 42 Statische 0-hazard, 138 Statische 1-hazard, 138 Statische hazard, 138 Statusregister, 232 Statussignalen, 149 Statusvlag, 232 Stijgende flank, 95, 124 Stijgtijd tr , 40 Store, 231 Store-instructie, 223 Straightforward codering, 113 Stuursignaal, 25 Sub-instructie, 221 Subroutine, 172 Subroutine sprong (JSR), 232 Subroutine terugkeer (RTS), 232 Sum-of-Products (SOP), 11, 34 Symbolische adressen, 233 Synchrone sequenti¨ele schakelingen, 95 Synchrone teller, 105 Synthese, 15 Systeemsynthese, 15 T-flipflop, 101 Technology mapping, 58 Tekenbit s, 77
INDEX Teller, 104 Terugkeertoestand, 174 x T, 26 Throughput, 16, 211 Tijdelijke geheugens, 150 Tijdsconcept, 22 Tijdsconstante τ , 39, 99 Toestand S, 94 Toestand-Actie Tabel, 152 Toestanden, 108 Toestandsdiagram, 108 Toestandsgebaseerd ASM-schema, 158 Toestandsgebonden sequenti¨ele schakelingen, 95 Toestandskader, 154 Toestandsregister, 172 Toestandstabel, 109 Toggle, 101 Toggle-flipflop, 101 Tokens, 264 Top, 163 Totale gewicht, 185 Transferfunctie, 38 Transistoren, 25 Transitie-functie, 127 Transitiediagram, 133 Transities, 108 Transmission gate, 44 Transparant, 99 Transparantie-probleem, 96, 99 Tri-state buffer, 43 Trial-and-error, 57 Tussentoestanden, 132 Uitgangscombinatie, 109 Uitgangsimpedantie RO , 40 Uitvoer logica, 173 Uitvoer-uitgangen Oij , 160 Uitvoerstapel, 241 Underflow, 78 Underscores, 265 Universi¨ele poorten, 7 Up-counter, 104 Variabele, 270 Vaste komma voorstelling, 77 Velden, 220 Verbindingen, 150 Verbindingentabel, 181 Verborgen bits, 79 Vergelijker, 86 Verilog, 18 Vermogenverbruik, 41 Verplaatsinstructies, 230 Vertragingstijd tp , 41
INDEX Verwerkingskracht, 8 Very High Speed Integrated Circuit, 17 VHDL, 17 VHDL Analog and Mixed Signals (VHDL-AMS), 17 VHSIC Hardware Description Language, 17 Vierkantswortel, 230 Vlottende komma voorstelling, 77 Voedingsspanning V , 42 Vol/full, 163 Waarheidstabellen, 6 Wet van De Morgan, 10 Wet van Moore, 16 Wetten van De Morgan, 10 Wrap-around, 104 Write, 165 Write Once Read Many (WORM), 32 x WAia , 159 x WEi , 159 Write-Enabled, 158 XNOR, 29 XOR, 6 Zekeringen, 34 Zet status (SetS), 232 Zwevende modus Z, 43 Zwevendekommagetal, 77
359
360
INDEX