Universität Rostock Fachbereich Elektrotechnik und Informationstechnik Institut für Angewandte Mikroelektronik und Datentechnik Großer Beleg Entwicklung und Implementierung einer Langzahl-Integer-Arithmetik-Bibliothek in VHDL Bearbeiter: cand. ing. Mathias Schmalisch Betreuer: Dipl.-Ing. Hagen Ploog Institut für Angewandte Mikroelektronik und Datentechnik Richard-Wagner-Str. 31 18119 Warnemünde U N I V E R S I T Ä T RO S T O C K FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK Institut für Angewandte Mikroelektronik und Datentechnik Studienarbeit für cand. ing. Mathias Schmalisch Entwicklung und Implementierung einer Langzahl-Integer-Arithmetik-Bibliothek in VHDL Zur funktionalen Verifikation unterschiedlicher Implementierungen von Architekturen werden diese in einer VHDL-Testumgebung mit Stimuli beaufschlagt. Üblicherweise werden diese Stimuli direkt in der Testumgebung erzeugt. Probleme treten dann auf, wenn das Erzeugen der Stimuli aus gegebenen Gründen nicht mit den Mitteln der Testumgebung erfolgen kann. Einen solchen Grund stellt die Verwendung von Langzahl-Integer-Arithmetik dar, da VHDL nur Wortbreiten bis 32 Bit unterstützt. Ziel der Studienarbeit ist es, eine Bibliothek in VHDL zu entwickeln, die Funktionen zum Bearbeiten von langen Zahlen bereitstellt. Neben der üblichen Arithmetik sind Funktionen zur Erzeugung von Schlüsselpaaren, wie sie beim RSA-Verfahren eingesetzt werden, zu realisieren. Die nach außen sichtbaren Funktionen der Bibliothek sollen für Zahlen im reinem Binärformat als auch für im Zweier-Komplement vorliegende Zahlen realisiert werden. Die Bibliothek ist auf Ausführungsgeschwindigkeit zu optimieren. Folgende Aufgaben sind dabei zu lösen: • • • • Einarbeitung in die Theorie der langen Zahlen Realisierungsvorschläge und Bewertung Nachweis der Funktionalität durch C-Cross-Simulation Simulation der VHDL-Quellen Betreuer: Dipl.-Ing. H. Ploog Tag der Ausgabe: Tag der Abgabe: 19.10.1998 29. 1.1999 Prof. Dr. D. Timmermann Betreuender Hochschullehrer Inst. für Angewandte Mikroelektronik und Datentechnik Seite 2 KURZREFERAT Aufgabe dieses Beleges ist die Entwicklung einer simulationsfähigen Langzahl-Integer-Arithmetik-Bibliothek in VHDL. Um der Komplexität dieser Aufgabe Rechnung zu tragen, reichen die aufgeführten Themen von der Einführung in die Zahlentheorie bis zum Aufzeigen möglicher Implementierungen einzelner Funktionen. Einen wichtigen Aspekt stellen dabei die kryptographischen Funktionen dar, die ebenfalls in der VHDL-Bibliothek zu realisieren sind. Da es mit ihnen dann möglich ist, in Hardware realisierte Funktionalitäten mit dieser Bibliothek zu simulieren. Dabei wird vor allem Wert darauf gelegt, Funktionen zur Erzeugung von Schlüsselpaare für den RSA-Algorithmus zu entwickeln. Vervollständigt wird die Arbeit durch die Beschreibung und Benutzung des C-Interfaces des Synopsys-Simulators, wodurch die Simulationszeit meßbar wird, und so die schnellste Implementierung ausgewählt werden kann. Zum Schluß soll noch gezeigt werden, wie die Bitbreite der Ziffern in der Zahlendarstellung mit der benötigten Rechenzeit für einige Funktionen zusammenhängt. Alle Quellen sowie die Dokumentationen zu den einzelnen Funktionen sind im Anhang enthalten. Seite 3 INHALTSVERZEICHNIS Abkürzungsverzeichnis ........................................................................................... 7 Abbildungsverzeichnis ............................................................................................ 8 Tabellenverzeichnis ................................................................................................. 9 Motivation................................................................................................................ 10 1 Theorie der Langzahlarithmetik................................................................. 11 1.1 1.2 1.2.1 1.2.2 1.2.3 Zahlendarstellung.................................................................................................................... 11 Darstellung vorzeichenbehafteter Zahlen ............................................................................... 12 Betrags-/Vorzeichendarstellung.................................................................................................... 12 Komplementdarstellung ................................................................................................................ 13 Wahl einer geeigneten Darstellung............................................................................................... 13 1.3 1.4 1.5 Einstellung des Basiswertes für die Ziffern............................................................................. 14 Darstellung von Zahlen in der VHDL-Bibliothek ..................................................................... 14 Hierarchischer Aufbau der Bibliothek...................................................................................... 14 2 Logische Funktionen.................................................................................. 15 3 Mathematische Grundfunktionen.............................................................. 16 3.1 3.2 3.3 3.4 Addition ................................................................................................................................... 16 Subtraktion .............................................................................................................................. 16 Multiplikation ........................................................................................................................... 17 Division.................................................................................................................................... 17 4 Vergleichsfunktionen ................................................................................. 19 4.1 4.2 4.3 4.4 4.5 4.6 Die "kleiner als" Funktion ........................................................................................................ 19 Die "kleiner gleich" Funktion ................................................................................................... 19 Die "größer als" Funktion ........................................................................................................ 20 Die "größer gleich" Funktion ................................................................................................... 20 Die "gleich" Funktion ............................................................................................................... 20 Die "ungleich" Funktion ........................................................................................................... 20 5 Zusätzliche Funktionen.............................................................................. 21 5.1 5.1.1 5.1.2 Schiebeoperationen ................................................................................................................ 21 Links Schieben............................................................................................................................... 21 Rechts Schieben............................................................................................................................. 21 5.2 Konvertierungsfunktionen ....................................................................................................... 21 6 Kryptographische Funktionen................................................................... 23 6.1 6.2 6.3 6.4 6.4.1 Potenzierung ........................................................................................................................... 23 Remainder............................................................................................................................... 24 Modulo .................................................................................................................................... 24 Erzeugung von Zufallszahlen.................................................................................................. 24 Eigenschaften eines guten Zufallszahlengenerators...................................................................... 25 Seite 4 6.4.2 6.4.3 6.4.4 6.4.5 Lineare-Kongruenz Generatoren .................................................................................................. 26 Tausworthe Generatoren............................................................................................................... 27 Erweiterte Fibonacci Generatoren ............................................................................................... 29 Kombinierte Generatoren ............................................................................................................. 30 6.5 6.6 6.6.1 6.6.2 6.6.3 Euler-Phi Funktion................................................................................................................... 31 Primzahltests........................................................................................................................... 31 Fermat Test ................................................................................................................................... 32 Solovay-Strassen Test.................................................................................................................... 32 Miller-Rabin Test .......................................................................................................................... 33 6.7 6.8 6.9 6.9.1 6.9.2 6.9.3 6.9.4 Größter gemeinsamer Teiler................................................................................................... 34 Erweiterter euklidischer Algorithmus....................................................................................... 34 Der RSA-Algorithmus.............................................................................................................. 35 Erzeugen von RSA-Schlüsselpaaren.............................................................................................. 35 RSA-Verschlüsselung .................................................................................................................... 36 RSA-Entschlüsslung ...................................................................................................................... 36 RSA Beispiel .................................................................................................................................. 37 7 Geschwindigkeitsmessung mit dem C-Interface ..................................... 38 7.1 7.1.1 7.1.2 7.1.3 7.1.4 Benutzung des C-Interfaces ................................................................................................... 38 Die Verbindung zum C-Code ........................................................................................................ 38 Der C-Code ................................................................................................................................... 39 Die Komponente............................................................................................................................ 41 Compilieren und Linken ................................................................................................................ 42 7.2 Beschreibung der Meßfunktion ............................................................................................... 42 8 Überprüfung der Bibliothek ....................................................................... 44 9 Testergebnisse ........................................................................................... 45 9.1 9.2 9.3 Testergebnisse bei konstanter Vektorbreite ........................................................................... 45 Testergebnisse bei konstanter Ziffernbreite ........................................................................... 47 Optimierung nach Ermittlung von Meßergebnissen................................................................ 48 10 Zusammenfassung ..................................................................................... 50 Literaturverzeichnis ............................................................................................... 51 Anhang .................................................................................................................... 52 A A1 A1.1 A1.2 A1.3 A1.4 A2 A1.1 A1.2 A1.3 A1.4 Die VHDL-Bibliothek ............................................................................................................... 52 Enthaltene Funktionen ...................................................................................................................... 52 Logische Funktionen ..................................................................................................................... 52 Mathematische und Vergleichsfunktionen .................................................................................... 52 Krytographische Funktionen ......................................................................................................... 55 Zusätzliche Funktionen ................................................................................................................. 55 VHDL-Quellen .................................................................................................................................. 57 Datei: mp_logic.vhd ...................................................................................................................... 57 Datei: mp_arith.vhd....................................................................................................................... 64 Datei: mp_std_logic.vhd ............................................................................................................... 79 Datei: mp_crypt.vhd...................................................................................................................... 82 Seite 5 B B1 B1.1 B1.2 B1.3 B1.4 B2 B2.1 B2.2 B2.3 B2.4 Die Quellen für das C-Interfaces............................................................................................. 90 Das Addiererbeispiel......................................................................................................................... 90 Datei: adder.vhd ............................................................................................................................ 90 Datei: adder_comp.vhd ................................................................................................................. 90 Datei: adder.h ................................................................................................................................ 90 Datei: adder.c ................................................................................................................................ 90 Die Meßfunktion................................................................................................................................ 92 Datei: benchmark.vhd ................................................................................................................... 92 Datei: benchmark_comp.vhd......................................................................................................... 92 Datei: Benchmark.h....................................................................................................................... 92 Datei: Benchmark.c....................................................................................................................... 92 Seite 6 ABKÜRZUNGSVERZEICHNIS CLI C-Language Interface DES Data Encryption Standard GCD Greatest Common Divisor IEEE Institute of Electrical and Electronics Engineers MPA Multiple-Precision Arithmetic RSA Rivest Shamir Adleman VHDL VHSIC Hardware Description Language VHSIC Very High Speed Integrated Circuit Seite 7 ABBILDUNGSVERZEICHNIS Abbildung 1.1: Fließkommadarstellung................................................................................... 11 Abbildung 1.2: Hierarchischer Aufbau am Beispiel einer Addiererfunktion .......................... 14 Abbildung 6.1: Die Periode eines Zufallszahlengenerators ..................................................... 26 Abbildung 6.2: Implementation eines Zufallszahlengenerators mit Schieberegistern............. 28 Abbildung 6.3: Schieberegisterimplementation eines Zufallszahlengenerators ...................... 29 Abbildung 6.4: Der RSA-Algorithmus .................................................................................... 35 Abbildung 9.1: Durchschnittszeiten für die Addition, Subtraktion und Multiplikation .......... 47 Abbildung 9.2: Rechenzeiten bei konstanter Ziffernbreite ...................................................... 48 Seite 8 TABELLENVERZEICHNIS Tabelle 1.1: Parameter für die Basisformate ............................................................................ 11 Tabelle 1.2: Bezeichnungen für einige Basiswerte .................................................................. 12 Tabelle 1.3: Vergleich zwischen Vorzeichen- und Zweierkomplementdarstellung ................ 13 Tabelle 5.1: Konvertierungsfunktionen.................................................................................... 22 Tabelle 5.2: Konvertierungsfunktionen mit Längenänderung ................................................. 22 Tabelle 6.1: Vergleich zwischen Remainder und Modulo....................................................... 24 Tabelle 7.1: Parameter für das Eingangssignal-Attribut .......................................................... 39 Tabelle 8.1: Programmparameter für "mpa" ............................................................................ 44 Tabelle 9.1: Testergebnisse bei konstanter Vektorbreite ......................................................... 46 Tabelle 9.2: Testergebnisse bei konstanter Ziffernbreite ......................................................... 47 Tabelle 9.3: Vergleich zweier verschiedener Addiererimplementationen ............................... 49 Seite 9 MOTIVATION Um Architekturen, die in VHDL entwickelt wurden, zu verifizieren, werden diese in dem VHDL-Simulator von Synopsys mit Stimuli beaufschlagt. Normalerweise werden diese Stimuli direkt im VHDL-Simulator mit Hilfe einer Testbench erzeugt. Es gibt allerdings Probleme, wenn die Stimuli mit Hilfe der standardmäßigen VHDL-Bibliotheken nicht erzeugt werden kann, weil diese Bibliotheken nicht ausreichend Funktionalitäten bereitstellen. So fehlt zum Beispiel in den IEEE-Bibliotheken eine Funktion zur Division von Bitvektoren. Daher ist es notwendig gewesen, eine Bibliothek in VHDL zu entwickeln, die alle nötigen Funktionalitäten aufweist und auch mit sehr großen Zahlen rechnen kann. Neben der üblichen Arithmetik sollten auch noch Funktionen zur Erzeugung von Schlüsselpaaren für den RSA-Algorithmus entwickelt werden. Besonderer Wert wurde dabei auf die Optimierung der Funktionen auf Ausführungsgeschwindigkeit gelegt. Daher war es notwendig das C-Interface des Synopsys VHDL-Simultors zur Messung der Rechenzeit zu benutzen, da in VHDL die Rechenzeit sonst nicht meßbar ist. Seite 10 1 THEORIE DER LANGZAHLARITHMETIK Die gebräuchlichste Form, zur Darstellung von großen Zahlen auf dem Computer und auch in Taschenrechnern, ist die der Fließkommadarstellung. Für die Darstellung von Fließkommazahlen gibt es verschiedene Formen [1]. Die heute üblichste, entspricht dem 1985 verabschiedeten IEEE-Standard (Institute of Electrical and Electronics Engineers). Charakteristik C Mantisse M Vorzeichen v der Fließkommazahl Abbildung 1.1: Fließkommadarstellung Wie in Abbildung 1.1 zu sehen ist, besteht die Fließkommazahl aus der Charakteristik C, der Mantisse M und dem Vorzeichen v. Dabei wird die Charakteristik C aus dem Exponenten E durch Addition einer geeigneten Konstante K gebildet, so daß für die Charakteristik nur positive Werte auftreten. So kann dann eine Zahl A mit der Basis B dargestellt werden. A = (− 1) ⋅ M ⋅ B E v mit E = C - K (1.1) Der IEEE-Standard gibt zwei Basisformate vor, läßt aber auch weitere zu. Die Tabelle 1.1 enthält die Parameter für das einfach- und doppeltgenaue Basisformat. Parameter einfachgenau doppeltgenau Wortlänge in Bits 32 64 maximaler Exponent Emax +127 +1023 minimaler Exponent Emin -127 -1022 Konstante K +127 +1023 Anzahl Bits des Exponenten 8 11 Anzahl Bits der Mantisse 24 53 Tabelle 1.1: Parameter für die Basisformate In einigen Fällen, wie z.B. in der Kryptographie, ist es allerdings notwendig mit sehr großen Zahlen zu rechnen, die bis auf die letzte Stelle vor dem Komma genau sein müssen. Dafür ist die Fließkommaarithmetik nicht mehr zu gebrauchen, da die Genauigkeit auf die Anzahl Stellen der Mantisse begrenzt ist. Deshalb wird eine anderer Art der Arithmetik benötigt, die sogenannte Langzahlarithmetik. Bei dieser werden alle Stellen vor dem Komma gespeichert, um so die nötige Genauigkeit zu gewährleisten. 1.1 Zahlendarstellung Eine beliebige positive natürliche Zahl A mit der Basis r, die aus n Ziffern besteht, kann folgendermaßen dargestellt werden: Seite 11 A = a n −1 a n −2 ⋅ ⋅ ⋅ a1 a 0 (1.2) Wobei ai eine Ziffer mit 0 ≤ ai < r ist. In Tabelle 1.2 werden einmal einige Bezeichnungen für häufig verwendete Basiswerte aufgezeigt. Basis r = Bezeichnung 2 binär 3 ternär 8 octal 10 dezimal 16 hexadezimal Tabelle 1.2: Bezeichnungen für einige Basiswerte Beim Stellenwertverfahren ergibt sich der Zahlenwert V(A) aus der Summe der Produkte des Ziffernwerts und des Stellenwerts: n −1 V ( A) = ∑ ai r i (1.3) i =0 So kann eine beliebige Zahl im Bereich von 0 ≤ V(A) < rn dargestellt werden. 1.2 Darstellung vorzeichenbehafteter Zahlen Negative Zahlen können auf verschiedene Weise dargestellt werden. Zwei der am häufigsten verwendeten Methoden sind: • Betrags-/Vorzeichendarstellung (sign magnitude) • Komplementdarstellung Diese werden im folgenden Abschnitt etwas genauer behandelt. 1.2.1 Betrags-/Vorzeichendarstellung Bei der Betrags-/Vorzeichendarstellung (sign magnitude) wird eine zusätzliche Ziffer eingefügt, die sogenannte Vorzeichenziffer, diese dient als Zeiger für positive bzw. negative Zahlen. Das Vorzeichen wird dabei folgendermaßen dargestellt: • 0 = positive • (r-1) = negativ Somit wird eine n-stellige positive bzw. negative Zahl wie folgt dargestellt: ASM = 0 a n − 2 a n −3 ⋅ ⋅ ⋅ a1 a 0 − ASM = (r − 1) an−2 an−3 ⋅ ⋅ ⋅ a1 a0 (für eine n-stellige positive Zahl) (1.4) (für eine n-stellige negative Zahl) (1.5) Mit dieser Darstellungsform können Zahlen im Bereich -rn-1 < V(A) < rn-1 dargestellt werden. Wobei sich der Zahlenwert folgendermaßen berechnen läßt: n −2 V ( ASM ) = (− 1) n −1 ⋅ ∑ ai r i a (1.6) i =0 Seite 12 Der Wertebereich ist bei der Betrags-/Vorzeichendarstellung vollkommen symmetrisch und somit die Null existiert doppelt, einmal positiv und einmal negativ. Der große Nachteil dieser Darstellung liegt darin, daß man positive und negative Zahlen gesondert behandeln muß. Die Tabelle 1.3 zeigt die binäre Betrags-/Vorzeichendarstellung von Zahlen im Bereich [-7,7]. 1.2.2 Komplementdarstellung Bei der Komplementdarstellung gibt es zwei unterschiedliche Arten, die Einer- bzw. Zweierkomplementdarstellung. Die Einerkomplementdarstellung (allg. (r-1)-Komplement) hat die gleichen Vor- und Nachteile wie die Betrags-/Vorzeichendarstellung, daher soll diese Methode hier nicht weiter behandelt werden. Bei der Zweierkomplementdarstellung (allg. r-Komplement) sieht das schon anders aus, sie hat den großen Vorteil, daß positive und negative Zahlen bei der Addition und Subtraktion nicht gesondert behandelt werden müssen. Die Darstellung positiver bzw. negativer Zahlen im Zweierkomplement sieht folgendermaßen aus: AZK = 0 an−2 an−3 ⋅ ⋅ ⋅ a1 a0 − AZK = ( ( r − 1) a n −2 a n −3 ⋅ ⋅ ⋅ a1 a 0 ) + 1 (für eine n-stellige positive Zahl) (1.7) (für eine n-stellige negative Zahl) (1.8) Wobei mit ai = r − 1 − ai gemeint ist. So können Zahlen im Bereich -rn-1 ≤ V(A) < rn-1 dargestellt werden, wobei sich der Zahlenwert wie folgt berechnet: n −2 V ( AZK ) = − a n −1 ⋅ r n −1 + ∑ ai r i (1.9) i =0 Ein weiterer Vorteil dieser Form der Zahlendarstellung ist der, daß die Null nur einmal existiert, da dies keine symmetrische Darstellung ist. Die Tabelle 1.3 zeigt die binäre Zweierkomplementdarstellung von Zahlen im Bereich [-8,7]. Sequenz Vorzeichendar- ZweierkomSequenz Vorzeichendar- Zweierkomstellung plement stellung plement 0111 7 7 1111 -7 -1 0110 6 6 1110 -6 -2 0101 5 5 1101 -5 -3 0100 4 4 1100 -4 -4 0011 3 3 1011 -3 -5 0010 2 2 1010 -2 -6 0001 1 1 1001 -1 -7 0000 0 0 1000 -0 -8 Tabelle 1.3: Vergleich zwischen Vorzeichen- und Zweierkomplementdarstellung 1.2.3 Wahl einer geeigneten Darstellung Nachdem nun die einzelnen Darstellungsmethoden für negative Zahlen, sowie ihre Vor- und Nachteile vorgestellt wurden, ist die Wahl einer geeigneten Darstellungsform leicht zu begründen. Da die VHDL-Bibliothek auf die Ausführungsgeschwindigkeit optimiert werden soll, fällt die Wahl auf die Zweierkomplementdarstellung. Denn damit kann die Addition oder Seite 13 Subtraktion positiver und negativer Zahlen mit ein- und derselben Funktion berechnet werden. 1.3 Einstellung des Basiswertes für die Ziffern Um die VHDL-Bibliothek möglichst variabel zu gestalten, ist es möglich, die Anzahl Bits für jede Ziffer mit Hilfe der Konstanten "digit_size" in er Bibliothek einzustellen. Allerdings ist diese Einstellung vor der Compilierung der Bibliothek vorzunehmen. Somit ergibt sich dann eine Basis von r = 2digit_size, die für die ganze Bibliothek gilt. 1.4 Darstellung von Zahlen in der VHDL-Bibliothek Um in VHDL mit Zahlen in Langzahlarithmetik Format arbeiten zu können, war es notwendig neue Zahlentypen zu erstellen. Dies sind die Typen: • udigit_vector • digit_vector Dabei ist der Typ "udigit_vector" für Berechnungen ausschließlich mit positiven Zahlen gedacht, daher auch das "u" am Anfang, welches hier für unsign (positiv) steht. Der Typ "digit_vector" ist für Berechnungen im positiven und negativen Bereich gedacht, wobei die negative Zahlen im Zweierkomplement dargestellt werden. 1.5 Hierarchischer Aufbau der Bibliothek Um den Aufbau der Bibliothek möglichst einfach zu gestalten, wurde eine Hierarchie, wie sie in Abbildung 1.2 am Beispiel einer Addiererfunktion zu sehen ist, eingeführt. Durch dieses Konzept, kann ein und die selbe Addiererfunktion mit verschiedenen Zahlentypen genutzt werden. Denn durch die vorgeschalteten Konvertierungsfunktionen werden aus zwei unterschiedlichen Zahlentypen zwei "digit_vector"-Zahlen gemacht. Da die Addition zwei Zahlen der selben Länge benötigt, wird durch die Konvertierungsfunktion gleichzeitig noch die Länge der beiden Zahlen angepaßt. Falls eine Verbesserung für die Addiererfunktion gefunden wurde, braucht nur eine Funktion ausgetauscht zu werden, da diese durch die vorhergehenden Konvertierungsfunktionen von den unterschiedlichen Zahlentypen entkoppelt ist. Damit ist eine leichte Wartung der VHDL-Bibliothek gewährleistet. Andere arithmetische Funktionen können nach dem selben Prinzip aufgebaut werden, dabei können dann auch die selben Konvertierungsfunktionen eingesetzt werden. Wenn dann bei einer Funktion noch eine neuer Zahlentyp benötigt werden sollte, ist nur eine neue Konvertierungsfunktion zu entwickeln. a b conv_digit_vector conv_digit_vector addition Ergebnis Abbildung 1.2: Hierarchischer Aufbau am Beispiel einer Addiererfunktion Seite 14 2 LOGISCHE FUNKTIONEN Da VHDL aus dem Bereich der Hardwareentwicklung kommt, wo häufig logische Verknüpfungen von zwei Werten vorgenommen werden, dürfen die logischen Funktionen in einer vollständigen VHDL-Bibliothek nicht fehlen. Diese Funktionen können allerdings nur angewendet werden, wenn die Zahlen binär darstellbar sind, deshalb muß die Basis r einen Potenz von 2 sein (r = 2x). Als Beispiel für die logischen Funktionen wird in Algorithmus 2.1 einmal die AND-Verknüpfung für Zahlen in Langzahlarithmetik vorgestellt. Dazu werden zwei Zahlen gleicher Länge ziffernweise AND-verknüpft. Algorithmus 2.1: AND EINGABE: Zwei natürliche Zahle x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die logische AND-Verknüpfung von x und y. 1. Für i in n bis 0 mache folgendes: 1.1. result = xi AND yi. 2. Gebe (result) zurück. Dieser Algorithmus kann auch für viele andere logische Verknüpfungen genutzt werden, dazu zählen die NAND-, OR-, NOR-, XOR- und XNOR-Verknüpfung. Es muß jeweils nur der Schritt 1.1. an die entsprechende logische Funktion angepaßt werden. Für die XNOR-Verknüpfung gibt es in den VHDL-Standardbibliotheken keine Funktion, daher wird ein abgewandelter Algorithmus verwendet, welcher in Algorithmus 2.2 dargestellt ist, um eine XNOR-Funktion auch in der Langzahlarithmetikbibliothek zu realisieren. Algorithmus 2.2: XNOR EINGABE: Zwei natürliche Zahle x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die logische AND-Verknüpfung von x und y. 1. Für i in n bis 0 mache folgendes: 1.1. result = NOT (xi XOR yi). 2. Gebe (result) zurück. Eine weiterr Besonderheit stellt die NOT-Verknüpfung oder auch Invertierung dar, da diese nur auf eine Zahl angewendet wird. Deshalb wird diese auch in Algorithmus 2.3 vorgestellt. Algorithmus 2.3: NOT EINGABE: Eine natürliche Zahle x, mit n+1 Ziffern der Basis r. AUSGABE: Die Invertierung von x. 1. Für i in n bis 0 mache folgendes: 1.1. result = NOT xi. 2. Gebe (result) zurück. Seite 15 3 MATHEMATISCHE GRUNDFUNKTIONEN In diesem Kapitel werden mögliche Implementierungen für die vier Grundrechenarten Addition, Subtraktion, Multiplikation und Division vorgestellt. 3.1 Addition Die Addition wird auf zwei natürliche Zahlen mit der selben Anzahl Ziffern der Basis r ausgeführt. Um zwei natürliche Zahlen mit verschiedener Länge zu addieren, muß die kürzere zuerst mit Nullen auf der linken Seite aufgefüllt werden. Algorithmus 3.1: Addition EINGABE: Zwei positive natürliche Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Summe x + y = (wn+1wn ⋅⋅⋅ w1w0)r. 1. c ← 0 (c ist die Überlaufziffer (carry digit)). 2. Für i von 0 bis n mache folgendes: 2.1. wi ← (xi + yi + c) mod r. 2.2. Wenn (xi + yi + c) < r dann c ← 0, ansonsten c ← 1. 3. wn+1 ← c. 4. Gebe (wnwn-1 ⋅⋅⋅ w1w0) zurück. Wenn man die Basis r günstig wählt, kann (xi + yi + c) mod r schneller berechnet werden. Die Wahl für die Basis wurde schon in Kapitel 1.3 beschreiben, dadurch lassen sich die Schritte 2.1. und 2.2. durch folgende ersetzen: 2.1. t ← (xi + yi + c). 2.2. wi ← t((digit_size -1) downto 0) und c ← t(digit_size). Dabei ist die Variable t (digit_size + 1) Bits lang, die unteren Bits werden dann der aktuellen Summenziffer wi zugewiesen und das oberste Bit wird an die Überlaufziffer c weitergegeben. Durch diese Konstruktion fällt die Modulo- und Vergleichsoperation weg, und das Ergebnis kann so in VHDL schneller berechnet werden. Mit diesem Algorithmus ist es auch möglich negative Zahlen zu addieren. Allerdings müssen diese, wenn sie kürzer als die zweite Zahl sind, mit (r-1) auf der linken Seite aufgefüllt werden. 3.2 Subtraktion Auch die Subtraktion wird auf zwei Zahlen gleicher Länge ausgeführt. Wenn die Zahlen unterschiedlich lang sind, müssen sie wie schon bei der Addition beschrieben, auf der linken Seite verlängert werden. Algorithmus 3.2: Subtraktion EINGABE: Zwei Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Differenz x - y = (wn+1wn ⋅⋅⋅ w1w0)r. 1. c ← 1. . 2. yv ← y 3. Für i von 0 bis n mache folgendes: 3.1. wi ← (xi + yvi + c) mod r. Seite 16 3.2. Wenn (xvi + yvi + c) < b dann c ← 0, ansonsten c ← 1. 4. wn+1 ← c. 5. Gebe (wn+1wn ⋅⋅⋅ w1w0) zurück. Auch hier können die Schritte 3.1. und 3.2., wie schon bei der Addition beschrieben ersetzt werden, wenn die Basis r eine Potenz von 2 ist. Dieser Algorithmus ist der Addition sehr ähnlich, allerdings wird hier durch die Schritte 1. und 2. die Zahl y negiert. Der Schritt 2. kann in VHDL durch einen einfache Invertierung ersetzt werden. Somit benötigt die Subtraktion nur einen minimalen Rechenaufwand mehr als die Addition. 3.3 Multiplikation Die Multiplikation kann auf zwei natürliche Zahlen x und y unterschiedlicher Länge mit der Basis r angewendet werden, mit x = (xnxn-1 ⋅⋅⋅ x1x0)r und y = (ytyt-1 ⋅⋅⋅ y1y0)r. Das Produkt von x ⋅ y hat dann (n + t + 2) Ziffern der Basis r. Algorithmus 3.3: Multiplikation EINGABE: Zwei positive Zahlen x und y, mit n + 1 und t + 1 Ziffern der Basis r. AUSGABE: Das Produkt x ⋅ y = (wn+t+1 ⋅⋅⋅ w1w0)r. 1. Für i von 0 bis (n + t + 1) mache: wi ← 0. 2. Für i von 0 bis t mache folgendes: 2.1. c ← 0. 2.2. Für j von 0 bis n mache folgendes: Berechne (uv)r = wi+j + xj ⋅ yi + c, und setze wi+j ← v, c ← u. 2.3. wi+n+1 ← u. 3. Gebe (wn+t+1 ⋅⋅⋅ w1w0) zurück. Der Algorithmus 3.3 ist eine abgewandelte Form der Papier und Bleistiftmethode (paper and pencil method), wie sie in der Schule gelehrt wird. Allerdings kann dieser Algorithmus nicht für negative Zahlen angewendet werden, dazu sind einige Veränderungen nötig. Zum Anfang sind die Absolutwerte von x und y zu ermitteln, dann kann der Algorithmus 3.3 angewendet werden. Und zu Schluß muß noch überprüft werden, ob einen Zahl positiv und die andere negativ war, denn dann ist das Ergebnis noch zu negieren, bevor es zurückgegeben werden kann. 3.4 Division Die Division ist die am schwierigsten zu realisierende Operation unter den vier Grundrechenarten. Algorithmus 3.4 berechnet den Quotienten q und den Rest z in der Basis r, wenn x durch y geteilt wird. Algorithmus 3.4: Division für Langzahlarithmetik EINGABE: Positive Zahlen x = (xn ⋅⋅⋅ x1x0)r und y = (yt ⋅⋅⋅ y1y0)r, mit n ≥ t ≥ 1, yt ≠ 0. AUSGABE: Der Quotient q = (qn-t ⋅⋅⋅ q1q0)r und der Rest z = (zt ⋅⋅⋅ z1z0)r, so daß x = qy + z, 0 ≤ z < y. 1. Für j von 0 bis (n - t) mache: qj ← 0. 2. Solange (x ≥ yrn-t) mache folgendes: qn-t ← qn-t + 1, x ← x - yrn-t. 3. Für i von n bis (t + 1) mache folgendes: Seite 17 3.1. Wenn xi = yt dann setze qi-t-1 ← r – 1, ansonsten qi-t-1 ← (xir + xi-1) / yt. 3.2. Solange (qi-t-1(ytr + yt-1) > xir2 + xi-1r + xi-2) mache: qi-t-1 ← qi-t-1 – 1. 3.3. x ← x – qi-t-1yri-t-1. 3.4. Wenn x < 0 dann setze x ← x + yr i-t-1 und qi-t-1 ← qi-t-1 – 1. 4. z ← x. 5. Gebe (q, z) zurück. Wie auf den ersten Blick zu sehen ist, benötigt dieser Algorithmus viele Rechenoperationen. Des weiteren wird im Schritt 3.1. eine Division für die Ziffern benötigt, welche in den VHDL-Standardbibliotheken nicht vorhanden ist. Daher wurde für die VHDL-Bibliothek eine andere Implementierung gewählt, welche in Algorithmus 3.5 beschreiben ist. Dabei ist noch zu erwähnen, daß x und y vorher in Bitvektoren umzuwandeln sind, bevor der folgende Algorithmus angewendet werden kann. Algorithmus 3.5: Division in VHDL EINGABE: Positive Zahlen x = (xn ⋅⋅⋅ x1x0) und y = (yt ⋅⋅⋅ y1y0) in Binärdarstellung, mit n ≥ t, y ≠ 0. AUSGABE: Der Quotient q = (qn ⋅⋅⋅ q1q0) und der Rest z = (zt ⋅⋅⋅ z1z0), so daß x = qy + z, 0 ≤ z < y. 1. q ← 0, qw ← n + 1, z ← x. 2. Für i in 1 bis qw mache folgendes: 2.1. Wenn (z((qw – 1) downto (qw – i)) ≥ b) dann mache folgendes: 2.1.1. q(qw - i) ← 1. 2.1.2. Wenn (i ≤ t) berechne folgendes: z((qw - 1) downto (qw - i)) = z((qw - 1) downto (qw - i)) – b((i - 1) downto 0), ansonsten mache folgendes: z((qw – i + t) downto (qw - i)) = z((qw – i + t) downto (qw - i)) – b((t - 1) downto 0). 3. Gebe (q, z) zurück. Nachdem der Quotient q als Bitvektor vorliegt, ist dieser dann wieder in eine Basis r Darstellung zurück zu wandeln, bevor er für weitere Berechnungen verwendet werden kann. Der Rest z der bei diesem Algorithmus ebenfalls anfällt, kann für andere Berechnungen genutzt werden, so zum Beispiel für Modulo- oder Remainderalgorithmen. Um diesen Algorithmus auch auf negative Zahlen anwenden zu können, müssen die selben Modifikationen wie sie schon bei der Multiplikation beschrieben wurden vorgenommen werden. Seite 18 4 VERGLEICHSFUNKTIONEN Um die VHDL-Bibliothek für Langzahlarithmetik wie jede andere Bibliothek weiter verwenden zu können ist es nötig auch Vergleichsoperationen zu implementieren. Daher werden in diesem Kapitel mögliche Implementierungen für die Vergleichsfunktionen vorgestellt. 4.1 Die "kleiner als" Funktion Diese Funktion wird auf zwei positive natürliche Zahlen angewendet, die die selbe Anzahl Ziffern mit der Basis r haben. Wenn die beiden Zahlen unterschiedlich lang sind, dann ist die kürzere auf der linken Seite mit Nullen aufzufüllen. Algorithmus 4.1: kleiner als ("<") EINGABE: Zwei positive natürliche Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Antwort wahr oder falsch auf die Frage: Ist x kleiner als y ? 1. result ← falsch. 2. Für i von n bis 0 mache folgendes: 2.1. Wenn (xi ≠ yi) dann mache folgendes: 2.1.1. Wenn (xi < yi) dann setze result ← wahr, ansonsten result ← falsch. 2.1.2. Gebe (result) zurück. 3. Gebe (result) zurück. Der Algorithmus 4.1 kann nicht ohne weiters auf positive und negative Zahlen angewendet werden. Zuerst einmal ist ein kürzere negative Zahl auf der linken Seite mit (r - 1) aufzufüllen, damit die beiden Zahlen die selbe Länge haben. Dann ist das Vorzeichen zu überprüfen. Wenn es unterschiedlich ist, kann dann schon festgelegt werden, welche Zahl die kleinere ist. Bei gleichem Vorzeichen wird der Algorithmus 4.1 verwendet, um die kleinere Zahl zu ermitteln. 4.2 Die "kleiner gleich" Funktion Dieser Algorithmus wird ebenfalls auf zwei natürliche Zahlen gleicher Länge angewendet. Algorithmus 4.2: kleiner gleich ("≤") EINGABE: Zwei positive natürliche Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Antwort wahr oder falsch auf die Frage: Ist x kleiner gleich y ? 1. result ← wahr. 2. Für i von n bis 0 mache folgendes: 2.1. Wenn (xi ≠ yi) dann mache folgendes: 2.1.1. Wenn (xi < yi) dann setze result ← wahr, ansonsten result ← falsch. 2.1.2. Gebe (result) zurück. 3. Gebe (result) zurück. Der Algorithmus 4.2 unterschiedet sich zum Algorithmus 4.1 nur in Schritt 1., dort wird die boolsche Variable result mit "wahr" vorgeladen. Wenn die Schleife in Schritt 2. dann ohne einen vorzeitigen Abbruch durchlaufen wird, steht fest, daß x gleich y ist und so der Vergleich "wahr" ist. Auch bei diesem Algorithmus müssen die Modifikationen, wie sie im Abschnitt 4.1 beschrieben wurden, vorgenommen werden um negative Zahlen darauf anwenden zu können. Seite 19 4.3 Die "größer als" Funktion Für diese Funktion wird kein neuer Algorithmus benötigt, es kann der Algorithmus 4.1 angewendet werden. Allerdings sind vorher die beiden Zahlen x und y zu vertauschen. 4.4 Die "größer gleich" Funktion Auch hier ist es nicht nötig einen neuen Algorithmus zu erstellen. Wenn die Zahlen x und y vertauscht an den Algorithmus 4.2 übergeben werden, erhält man das richtige Ergebnis. 4.5 Die "gleich" Funktion Diese Funktion wird auf zwei natürliche Zahlen gleicher Länge der Basis r angewendet. Algorithmus 4.3: gleich ("=") EINGABE: Zwei positive natürliche Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Antwort wahr oder falsch auf die Frage: Ist x gleich y ? 1. Für i von n bis 0 mache folgendes: 1.1. Wenn (xi ≠ yi) dann gebe (falsch) zurück. 2. Gebe (wahr) zurück. Der Algorithmus 4.3 kann ohne weitere Veränderungen auf negative Zahlen angewendet werden, da durch die Schleife in Schritt 1. auch die Vorzeichenziffer abgetestet wird. 4.6 Die "ungleich" Funktion Der Algorithmus 4.4 wird wieder auf zwei Zahlen gleicher Länge angewendet. Dabei ist es egal ob die Zahlen positiv oder negativ sind. Algorithmus 4.4: ungleich ("≠") EINGABE: Zwei positive natürliche Zahlen x und y, jede mit n+1 Ziffern der Basis r. AUSGABE: Die Antwort wahr oder falsch auf die Frage: Ist x ungleich y ? 1. Für i von n bis 0 mache folgendes: 1.1. Wenn (xi ≠ yi) dann gebe (wahr) zurück. 2. Gebe (falsch) zurück. Wie zu sehen ist, sieht der Algorithmus 4.4 dem Algorithmus 4.3 sehr ähnlich. Es wurden nur die Ergebnisse, welche zurückgegeben werden, vertauscht. Seite 20 5 ZUSÄTZLICHE FUNKTIONEN Um der Langzahlarithmetik-Bibliothek die volle Funktionalität einer Standart-Bibliothek, wie zum Beispiel der IEEE-Bibliothek, zu geben, sind noch einige zusätzliche Funktionen nötig. Diese sollen in diesem Kapitel behandelt werden. 5.1 Schiebeoperationen 5.1.1 Links Schieben Hierbei wird eine Zahl a mit n + 1 Ziffern um b Ziffern nach links geschoben, wobei b eine positive Zahl sein muß. Der Algorithmus dazu ist im folgenden dargestellt: Algorithmus 5.1: Links schieben EINGABE: a mit n + 1 Ziffern und b mit er Anzahl zu schiebender Ziffern. AUSGABE: a um b Ziffern nach links geschoben. 1. Wenn (b ≤ n) dann mache folgendes: 1.1. x(n downto b) = a((n – b) downto 0). 1.2. x((b – 1) downto 0) = 0. 2. ansonsten mache folgendes: 2.1. x = 0 3. Gebe (x) zurück. Wie in Algorithmus 5.1 zu sehen ist, wird als Ergebnis eine Null zurückgegeben, wenn b größer als n ist, da in diesem Fall alle Ziffern über das linke Ende hinausgeschoben wurden. 5.1.2 Rechts Schieben Die Zahl a mit n + 1 Ziffern wird um b Ziffern nach rechts verschoben, wobei b eine positive Zahl sein muß. Der Algorithmus dazu sieht folgendermaßen aus: Algorithmus 5.2: Rechts schieben EINGABE: a mit n + 1 Ziffern und b mit er Anzahl zu schiebender Ziffern. AUSGABE: a um b Ziffern nach rechts geschoben. 1. Wenn (b ≤ n) dann mache folgendes: 1.1. x((n – b) downto 0) = a(n downto b). 1.2. x(n downto (n – b + 1)) = 0 2. ansonsten mache folgendes: 2.1. x = 0 3. Gebe (x) zurück. Auch hier wird eine Null zurückgegeben, wenn alle Ziffern über das rechte Ende hinausgeschoben wurde. 5.2 Konvertierungsfunktionen In VHDL gibt es verschiedene Darstellungsmöglichkeiten für Zahlen, daher werden Konvertierungsfunktionen benötigt, um auch diese Zahlenformate in der Langzahlarithmetik-Bibliothek verwenden zu können. Es gibt dabei zwei verschiedenen Arten von Konvertierungsfunktionen. Eine davon dient zum Umwandeln eines beliebigen Zahlenformates in "udiSeite 21 git_vector" oder "digit_vector", und wieder zurück in "std_logic_vector". Diese Konvertierungsfunktionen sind in Tabelle 5.1 dargestellt. Kovertiertungsfunktion To_DigitVector To_UdigitVector Konvertierung von in std_logic_vector digit_vector std_ulogic_vector udigit_vector string std_logic_vector udigit_vector std_ulogic_vector digit_vector string Tabelle 5.1: Konvertierungsfunktionen Dabei ist zu beachten, daß die Länge von "std_logic_vector" und "std_ulogic_vector" ein vielfaches der Konstanten "digit_size" sind, da sonst die obersten Bits in der höchstwertigsten Zahl nicht definiert sind, und somit eine korrekte Arbeitsweise der darauffolgenden Funktionen nicht gewährleistet werden kann. Eine Besonderheit sind dabei die Funktionen zum konvertieren eines Strings. Dabei wird ein Zahl die hexadezimal in einem String dargestellt ist in einen "udigit_vector" oder "digit_vector" umgewandelt. Bei der zweiten Art von Konvertierungsfunktionen wird zusätzlich zur eigentlichen Konvertierung noch die Anzahl Ziffern verändert. Diese Art wird benötigt, um zwei Zahlen auf die selbe Länge zu bringen, bevor sie zum Beispiel mit der Addition verwendet werden können. Konvertierung von in digit_vector digit_vector udigit_vector integer CONV_UDIGIT_VECTOR udigit_vector udigit_vector digit_vector integer Tabelle 5.2: Konvertierungsfunktionen mit Längenänderung Kovertiertungsfunktion CONV_DIGIT_VECTOR Die Besonderheit bei den in Tabelle 5.2 dargestellten Konvertierungsfunktionen ist, daß es auch Funktionen zur Konvertierung von "digit_vector" in "digit_vector" und "udigit_vector" in "udigit_vector" gibt, diese dienen eigentlich nur zur Änderung der Anzahl Ziffern einer Zahl. Seite 22 6 KRYPTOGRAPHISCHE FUNKTIONEN Die zu entwickelnde VHDL-Bibliothek soll vor allem zur Simulation von kryptographischen Routinen eingesetzt werden. Daher ist es notwendig einige Funktionen in die Bibliothek mit aufzunehmen, die speziell für dieses Einsatzgebiet gedacht sind. In dem folgenden Kapitel werden die Funktionen und ihre Realisierungsvorschläge vorgestellt und bewertet. 6.1 Potenzierung Eine der wichtigsten Funktionen für die asymmetrische Kryptographie ist die Potenzierung, daher ist sie auch die erste, die in diesem Abschnitt behandelt wird. Als Beispiel für die asymmetrische Kryptographie soll hier der RSA-Algorithmus dienen. Dieser wird in Abschnitt 6.9 genauer behandelt und wie dort zu sehen ist, wird die Potenzierung zur Ver- und Entschlüsselung benötigt. Der naivste Weg um ge zu berechnen währe e – 1 Multiplikationen mit der Zahl g auszuführen. In der Kryptographie kann dieser Weg allerdings nicht angewendet werden, da dort mit Zahlen bis zu 1024 Bit Länge gearbeitet wird, was 21024 – 2 Multiplikationen im ungünstigsten Fall bedeuten würde. Selbst wenn e nicht immer so groß ausfällt, so ist es aber meist immer noch groß genug um diese Methode ineffizient zu machen. Daher ist es notwendig die Anzahl Multiplikationen deutlich zu reduzieren. Die beiden folgenden Algorithmen sind für Zahlen in Binärdarstellung gedacht. Algorithmus 6.1: Binäre Potenzierung von rechts nach links EINGABE: Zwei Zahlen in Binärdarstellung g und e, mit e ≥ 0. AUSGABE: Das Ergebnis von ge. 1. A ← 1, S ← g. 2. Solange (e ≠ 0) mache folgendes: 2.1. Wenn e ungerade ist dann A ← A ⋅ S. 2.2. e ← e / 2. 2.3. Wenn e ≠ 0 dann S ← S ⋅ S. 3. Gebe (A) zurück. Wie in Algorithmus 6.1 zu sehen ist, werden im schlechtesten Fall pro Schleifendurchlauf zwei Multiplikationen und ein Division, die allerdings durch die Binärdarstellung durch eine Schiebeoperation ersetzt werden kann, benötigt. Wenn e eine Bitlänge von t + 1 hat, und wt(e) die Anzahlen Einsen in der Binärdarstellung ist, dann werden bei diesem Algorithmus insgesamt t + wt(e) – 1 Multiplikationen gebraucht, um die Potenzierung auszuführen. Algorithmus 6.2: Binäre Potenzierung von links nach rechts EINGABE: Zwei Zahlen in Binärdarstellung g und e = (etet-1⋅⋅⋅e1e0)2, mit e ≥ 0. AUSGABE: Das Ergebnis von ge. 1. A ← 1. 2. Für i von t bis 0 mache folgendes: 2.1. A ← A ⋅ A. 2.2.Wenn ei = 1, dann setze A ← A ⋅ g. 3. Gebe (A) zurück. Auch in Algorithmus 6.2 werden in schlechtesten Fall zwei Multiplikationen pro Schleifendurchlauf benötigt. Für diesen Algorithmus werden insgesamt t + wt(e) Multiplikationen geSeite 23 braucht, das ist eine mehr als bei Algorithmus 6.1 allerdings fällt die Division bzw. Schiebeoperation weg. Daher ist dieser Algorithmus die bessere Wahl. Bei die Potenzierung zweier relativ kleiner Zahlen kann eine Ergebnis entstehen, welches sehr groß ist, das kann in manchen Fällen zu Problem führen. Da die Exponential-Funktion in der asymmetrischen Kryptographie häufig in Verbindung mit der Modulo-Funktion eingesetzt wird, währe an dieser Stelle ein Einsatz der modularen Expansion von Vorteil, da das Ergebnis dann nicht so groß ausfällt. 6.2 Remainder Da in der Langzahlarithmetik nur mit ganzen Zahlen gerechnet wird, entsteht bei der Division von einer Zahl a durch eine Zahl b außer dem Quotienten q auch noch ein Rest r, so daß: a = qb + r mit 0 ≤ r < b (6.1) Mit der Remainder-Funktion kann dieser Rest ermittelt werden. Er fällt als Nebenprodukt bei der Division, wie sie in Kapitel 3.4 beschrieben ist, ab. Daher kann der gleiche Algorithmus verwendet werden um den Rest zu ermitteln. a rem b = r (6.2) Das Vorzeichen des Restes ist das gleiche wie das von a, somit hat b keinen Einfluß darauf. 6.3 Modulo Die Modulo-Funktion arbeitet genau wie die Remainder-Funktion, solange a und b positiv sind. a mod b = r (6.3) Das Vorzeichen wird hier allerdings nicht von a, sondern von b bestimmt. Außerdem wird der Quotient nicht durch Abschneiden der Nachkommastellen ermittelt, wie es bei Remainder der Fall ist, sondern durch Abrunden zur nächsten ganzen Zahl, so daß bei negativem a oder b andere Werte für r entstehen, damit die Gleichung (6.1) erfüllt wird. In Tabelle 6.1 erfolgt einmal ein Vergleich zwischen Remainder und Modulo an einem Beispiel. a Rem 5 Mod 5 Rem -5 Mod -5 -9 -4 1 -4 -4 -8 -3 2 -3 -3 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 -2 -1 0 -4 -3 -2 -1 0 1 2 3 4 0 3 4 0 1 2 3 4 0 1 2 3 4 0 -2 -1 0 -4 -3 -2 -1 0 1 2 3 4 0 -2 -1 0 -4 -3 -2 -1 0 -4 -3 -2 -1 0 Tabelle 6.1: Vergleich zwischen Remainder und Modulo 6 7 8 9 1 2 3 4 1 2 3 4 1 2 3 4 -4 -3 -2 -1 6.4 Erzeugung von Zufallszahlen Eine der Schlüsselfunktionen für die Simulation ist eine Routine zur Erzeugung von zufälligen Werten für Variablen mit einer spezifischen zufälligen Verteilung, z.B. exponentiell und normal. Dies kann in zwei Schritten vollzogen werden. Zuerst wird eine Sequenz von zufälliSeite 24 gen Zahlen, gleichmäßig verteilt zwischen 0 und 1, benötigt. Dann wird diese Sequenz transformiert, um die zufälligen Werte mit der benötigten Verteilung zu erzeugen. 6.4.1 Eigenschaften eines guten Zufallszahlengenerators Um zu verstehen, warum ein Zufallszahlengenerator besser ist als ein anderer, ist es erst einmal wichtig zu verstehen, wie ein solcher Generator funktioniert. Bei den gebräuchlichsten Methoden wird eine rekursive Beziehung verwendet, in welcher die nächste Zahl der Sequenz eine Funktion der letzten oder der letzten zwei Zahlen ist. xn = f ( xn −1 , xn −2 , ...) (6.4) Eine solche Funktion ist: x n = 5 x n −1 + 1 mod 16 (6.5) Wenn mit x0 = 5 gestartet wird, erhält man x1 wie folgt: x1 = 5(5) + 1 mod 16 = 26 mod 16 = 10 (6.6) Die ersten 32 Zahlen die man mit dieser Prozedur erhält, sind 10, 3, 0, 1, 6, 15, 12, 13, 2, 11, 8, 9, 14, 7, 4, 5, 10, 3, 0, 1, 6, 15, 12, 13, 2, 11, 8, 9, 14, 7, 4, 5. Wie zu sehen ist, sind dies natürliche Zahlen zwischen 0 und 15. Wenn diese dann durch 16 dividiert werden, bekommt man eine Sequenz von zufälligen Zahlen zwischen 0 und 1. Für dieses Beispiel sind das die Zahlen 0,6250; 0,1875; 0,0000; 0,0625; 0,3750; 0,9375; 0,7500; 0,8125; 0,1250; 0,6875; 0,5000; 0,5625; 0,8750; 0,4375; 0,2500; 0,3125; 0,6250; 0,1875; 0,0000; 0,0625; 0,3750; 0,9375; 0,7500; 0,8125; 0,1250; 0,6875; 0,5000; 0,5625; 0,8750; 0,4375; 0,2500; 0,3125. Es ist offensichtlich, daß wenn die Funktion ƒ bekannt ist, die Sequenz jeder Zeit regeneriert werden kann, vorausgesetzt der Startwert x0 ist gegeben. Dieser Wert, der benutzt wird um die Sequenz zu beginnen, wird auch Saat genannt. Eine wichtige Beobachtung bei diesem Beispiel ist, daß die Funktion ƒ deterministisch ist. Denn mit einer vorgegebenen Saat kann mit einer Wahrscheinlichkeit von 1 gesagt werden, welche Zahlen in der Sequenz sind. Aber die Zahlen sind zufällig in dem Sinn, daß sie einem statistischen Test auf Zufälligkeit bestehen würden. Diese Zahlen sind deshalb nur teilweise zufällig, und werden daher auch pseudozufällig genannt. Solche Zahlen werden aber für Simulationen eher bevorzugt, als völlig zufällige Zahlen, denn es ist oftmals notwendig ein Simulationsexperiment mit genau denselben Werten zu wiederholen. Wenn natürlich verschiedene Ergebnisse benötigt werde, kann ja die Saat verändert werden, bevor die Simulation gestartet wird. So hat man zusätzlich Kontrolle über die Reproduzierbarkeit von Ergebnissen. Wie man sieht sind in dem durchgeführten Beispiel nur die ersten 16 Zahlen einzigartig. Die 17. Zahl ist die gleiche, wie die erste und die folgende Sequenz ist einfach eine zyklische Wiederholung der ersten 16 Zahlen. In anderen Worten, der Zufallszahlengenerator hat eine Zykluslänge von 16. Einige Generatoren wiederholen einen anfänglichen Teil der Sequenz nicht. Dieser Teil wird Schwanz genannt. In diesem Fall, besteht die Periode des Generators aus der Summe der Schwanzlänge und der Zykluslänge, wie es in Abbildung 6.1 gezeigt wird. Seite 25 Saat Schwanz Zykluslänge Periode Abbildung 6.1: Die Periode eines Zufallszahlengenerators Die nötigen Eigenschaften einer guten Generatorfunktion sind folgende: 1. Die Funktion sollte gut berechenbar sein. Für typische Simulationen werden einige tausend Zufallszahlen benötigt. Daher sollte die Prozessorzeit, die vergeht während diese Zahlen erzeugt werden, kurz sein. 2. Die Periode sollte lang sein. Eine kurze Periode würde bedeuten, daß sich die Zufallszahlen schnell wiederholen. Damit würde die nutzbare Länge für eine Simulation begrenzt sein. 3. Die aufeinanderfolgenden Werte sollten unabhängig voneinander und gleichmäßig verteilt sein. Die Korrelation zwischen aufeinanderfolgenden Zahlen sollte klein sein. Denn eine signifikante Korrelation gibt Hinweise auf Abhängigkeiten. Während die ersten beiden Eigenschaften leicht zu überprüfen sind, benötigt man für die Dritte entsprechende Tests. Im Folgenden sind einige Typen von Zufallszahlengeneratoren aufgezählt, welche in diesem Abschnitt behandelt werden: • • • Lineare-Kongruenz Generatoren • Tausworthe Generatoren Erweiterte Fibonacci Generatoren Kombinierte Generatoren Eine Beschreibung jedes Typen folgt. 6.4.2 Lineare-Kongruenz Generatoren 1951 entdeckte D. H. Lehmer, daß der Rest aufeinanderfolgender Potenzen einer Zahl gute zufällige Eigenschaften hat. Er bekam die n-te Zahl in einer Sequenz mittels dividieren der n-ten Potenz einer ganzen Zahl a durch eine andere ganze Zahl m und verwenden des Restes. x n = a n mod m (6.7) Um xn nach xn-1 zu berechnen, gibt es einen äquivalenten Ausdruck: x n = a x n −1 mod m (6.8) Seite 26 Die Parameter a und m werden jeweils Multiplikator und Modulus genannt. Lehmer wählte für diese Parameter a = 23 und m = 108 + 1. Damit wurde die Implementierung auf ENIAC, einer achtstelligen dezimalen Maschine, sehr einfach. Viele der heute gebräuchlichen Zufallszahlengeneratoren sind Verallgemeinerungen der Vorschläge von Lehmer und haben folgende Form: x n = a x n −1 + b mod m (6.9) Dabei ist xn eine ganze Zahl zwischen 0 und m – 1, und die Konstanten a und b sind positiv. Im allgemeinen hat die Wahl von a, b und m Einfluß auf die Periode und Autokorrelation der Sequenz. Viele Wissenschaftler haben diese Generatoren studiert und die Ergebnisse ihrer Untersuchungen können folgendermaßen zusammengefaßt werden: 1. Der Modulus m sollte groß sein. Denn alle Werte von x liegen zwischen 0 und m – 1, die Periode kann niemals größer als m sein. 2. Um die (mod m) Berechnung schnell ausführen zu können, sollte m eine Potenz von 2 sein (m = 2k). In diesem Fall erhält man das Ergebnis, indem man die niederen k Bits verwendet und die höherwertigen Bits abschneidet. 3. Wenn b nicht Null ist, dann erhält man die maximale Periode nur wenn: a) die natürlichen Zahlen m und b relativ prim zueinander sind. Das heißt, sie haben keine gemeinsamen Faktoren außer 1. b) jede Primzahl die ein Faktor von m ist, auch ein Faktor von a – 1 ist. c) a – 1 ein Vielfaches von 4 ist, dann ist m ebenfalls ein Vielfaches von 4. All diese Bedingungen werden erfüllt, wenn m = 2k, a = 4c + 1 und b ungerade ist. Wobei c, b und k natürliche Zahlen sind. Ein Generator, der die maximal mögliche Periode hat, wird auch Vollperiode Generator genannt. Alle Vollperiode Generatoren sind aber nicht gleich gut. Generatoren mit niedriger Autokorrelation zwischen aufeinanderfolgenden Zahlen sind vorzuziehen. Zum Beispiel haben die beiden folgenden Generatoren die gleiche volle Periode, aber der erste hat eine Korrelation von 0,25 zwischen xn-1 und xn, wobei der zweite eine viel geringere Korrelation von 2-18 hat: xn = (2 34 + 1) xn −1 + 1 mod 2 35 (6.10) x n = (218 + 1) x n −1 + 1 mod 2 35 (6.11) 6.4.3 Tausworthe Generatoren Das Interesse an Zufallszahlengeneratoren entstand vor kurzem infolge des Aufkommens der Kryptographie, denn dort werden Zufallszahlen mit großer Länge benötigt. Zum Beispiel wird eine 64-Byte (512-Βit) lange Zahl benötigt, um eine Nachricht zu Verschlüsseln. Solche langen Zahlen werden produziert unter Benutzung von zufälligen Sequenzen binärer Zahlen (0 oder 1), die in die benötigte Länge unterteilt werden. Solche Generatoren wurden zum ersten mal von Tausworthe (1965) vorgeschlagen und tragen deshalb seinen Namen. Im allgemeinen hat ein Tausworthe Generator folgenden Form: Seite 27 bn = c q −1bn −1 ⊗ c q −2 bn −2 ⊗ c q −3bn −3 ⊗ ⋅ ⋅ ⋅ ⊗ c0 bn −q (6.12) wobei ci und bi binäre Variablen mit Werten von 0 oder 1 sind und ⊗ ist die XOR Operation. Der Generator verwendet die letzten q Bits der Sequenz. Deshalb wird diese auch autoregresisve Sequenze der Ordnung q genannt oder auch AR(q). Ein AR(q) Generator kann eine maximale Periode von 2q – 1 haben. Wenn man mit D einen Verzögerungsoperator andeutete, so daß Db(n) = b(n + 1) ist, dann kann die Gleichung (6.12) folgendermaßen geschrieben werden: D q b(i − q ) = cq −1 D q −1b(i − q ) + cq − 2 D q − 2 b(i − q ) + ⋅ ⋅ ⋅ + c0 b(i − q ) mod 2 (6.13) D q − c q −1 D q −1 − c q −2 D q −2 − ⋅ ⋅ ⋅ − c0 = mod 2 (6.14) oder In der binären Architektur ist die Subtraktion äquivalent zur Addition, damit ist die vorhergehende Gleichung äquivalent zu: D q + c q −1 D q −1 + c q − 2 D q − 2 + ⋅ ⋅ ⋅ + c0 = mod 2 (6.15) Das Polynom auf der linken Seite dieser Gleichung wird auch charakteristisches Polynom genannt und wird normalerweise folgendermaßen geschrieben, wobei das D durch ein x ersetzt wird: x q + c q −1 x q −1 + c q − 2 x q −2 + ⋅ ⋅ ⋅ + c0 (6.16) Die Periode eines Tausworthe Generators ist von charakteristischen Polynom abhängig. In der Praxis ist die Periode, die kleinste positive natürliche Zahl n, für welche xn – 1 durch das charakteristische Polynom teilbar ist. Die maximal mögliche Periode mit einem Polynom der Ordnung q ist 2q – 1. Das Polynom, welches diese Periode ergibt wird auch einfaches Polynom genannt. bn bn-1 bn-2 bn-3 bn-4 bn-5 Ausgabe Abbildung 6.2: Implementation eines Zufallszahlengenerators mit Schieberegistern Eine Tausworthe Sequenz kann in Hardware einfach realisiert werden, im dem man Schieberegister verwendet. Als Beispiel wurde das Polynom: x5 + x3 + 1 (6.17) in Abbildung 6.2 realisiert. Wenn der D Operator für das x eingesetzt wir, erhält man folgende Formel zur Erzeugung einer Bitsequenz: Seite 28 D 5b(n ) + D 3b(n ) + b( n ) = 0 mod 2 (6.18) bn +5 + bn +3 + bn = 0 mod 2 (6.19) oder Wird der XOR Operator als Modulo 2 Addition verwendet, erhält man folgende Gleichung: bn +5 ⊗ bn + 3 ⊗ bn = 0 (6.20) bn +5 = bn +3 ⊗ bn (6.21) oder Jetzt wird n mit n – 5 Substituiert: bn = bn −2 ⊗ bn −5 (6.22) So erhält man aus dem Polynom in Gleichung (6.17) die Funktion, welche in Abbildung 6.2 realisiert wurde. Dort sind sechs Register, welche jeweils ein Bit enthalten. Bei jedem Takt werden die Register um eins weiter geschoben. In Abbildung 6.3 ist der Kreislauf eines allgemeinen Tausworthe Generators dargestellt, wie er in Gleichung (6.12) beschrieben wurde. ... cn-1 & cn-2 cn-q+1 & & AND bn bn-1 bn-2 ... bn-q+1 bn-q Ausgabe Abbildung 6.3: Schieberegisterimplementation eines Zufallszahlengenerators In der Praxis kann die AND Funktion weggelassen werden, wenn ci konstant ist. Wenn ci = 1 ist, dann fällt die AND Funktion weg. Bei ci = 0 fällt zusätzlich auch noch die entsprechende XOR Funktion weg. 6.4.4 Erweiterte Fibonacci Generatoren Eine Fibonacci Sequenz {xn} wird durch folgende Beziehung generiert: x n = x n −1 + x n − 2 (6.23) Ein Zufallszahlengenerator kann durch folgende Modifikationen der Fibonacci Sequenz erzeugt werden: Seite 29 x n = x n −1 + x n −2 mod m (6.24) Jedoch hat diese Sequenz keine guten zufälligen Eigenschaften. In der Praxis hat sie eine große serielle Korrelation. Eine Erweiterung dieser Methode währe zum Beispiel eine Kombination des fünften und siebzehnten Vorgängers: x n = x n −5 + x n −17 mod 2 k (6.25) Marsaglia (1983) zeigte, daß dieser Generator die meisten statistischen Test besteht und empfahl eine Implementierung wie folgt mit 17 Speicherstellen L[1], ... , L[17]. Während der Initialisierung werden diese Speicherstellen mit 17 natürlichen Zahlen gefüllt, wobei nicht alle gerade sein dürfen. Dann werden die beiden Zeiger i und j jeweils auf 5 und 17 gesetzt. Bei jedem Aufruf wird der folgende Algorithmus ausgeführt, welcher die nächste Zufallszahl zurückgibt und die Zeiger neu berechnet: Algorithmus 6.3: Erweiterter Fibonacci Generator AUSGABE: Die Zufallszahl x. 1. x = L[i] + L[j] mod 2k. 2. L[i] = x. 3. i = i – 1, wenn i = 0 dann setze i ← 17. 4. j = j – 1, wenn j = 0 dann setze j ← 17. 5. Gebe (x) zurück. Bei der Addition in der erste Zeile dieses Generators kann die Modulooperation weggelassen werden, wenn der Algorithmus in einer k-Bit begrenzten Zweierkomplement Berechnung eingesetzt wird. Die Periode dieses Generators ist 2k(217 – 1). Für k = 8, 16 und 32 ist diese Periode jeweils 1,6 ⋅ 107; 4,3 ⋅ 109 und 2,8 ⋅ 1014. Diese ist bedeutend länger, als die eines Linearen-Kongruenz Generators. 6.4.5 Kombinierte Generatoren Es ist möglich zwei oder mehr Zufallszahlengeneratoren zu kombinieren um einen besseren Generator zu erhalten. Dafür gibt es drei Techniken die im folgenden beschrieben werden: 1. Addition von Zufallszahlen, die aus zwei oder mehr Generatoren erhalten wurden. Wenn xn und yn zwei Zufallszahlsequenzen im Bereich von 0 bis m – 1 sind, dann können sie kombiniert werden, um wn = (xn + yn) mod m zu erhalten. Wenn die beiden Sequenzen unterschiedliche Perioden haben und auf verschiedenen Algorithmen beruhen, dann wird die Periode und die Zufälligkeit erheblich erhöht. Als Beispiel empfahl L'Ecuyer (1988) die Kombination der folgenden zwei Generatoren: x n = 40014 x n −1 mod 2 ⋅147 ⋅ 483⋅563 (6.26) y n = 40692 y n −1 mod 2 ⋅147⋅ 483⋅399 (6.27) Damit entsteht folgender Generator: Seite 30 wn = ( x n − y n ) mod 2 ⋅147 ⋅ 483⋅562 (6.28) Dieser Generator hat eine Periode von 2,3 ⋅ 1012. 2. XOR Verknüpfung von Zufallszahlen, die aus zwei oder mehr Generatoren erhalten wurden. Diese Technik ist mit der vorherigen ähnlich, hierbei wird die Addition durch eine bitweise XOR Verknüpfung ersetzt. Santha und Vazirani (1984) zeigten, daß die XOR Verknüpfung von einigen einfachen Zufallszahlengeneratoren, wobei jeder eine n-Bit Zahl erzeugt, benutzt werden kann, um eine zufälligere Sequenz zu produzieren. 3. Mischen. Bei dieser Technik wird eine Sequenz als Index benutzt, um zu entscheiden, welche Zahl einer zweiten Sequenz zurückgeben wird. Viele verschiedene Mischalgorithmen sind in der Literatur zu finden. Eine populäre Technik, welche man Marsaglia und Bray (1964) anrechnen muß, ist auch als Algorithmus M bekannt. Wobei eine Feld der Größe 100 zum Beispiel mit Zufallszahlen einer Sequenz xn gefüllt wird. Um Zufallszahlen zu erzeugen, wird eine neue Sequenz yn (zwischen 0 und m – 1) generiert und skaliert um einen Index i = 1 + 100yn / m zu erhalten. Der Wert im i-ten Element des Feldes wird als nächste Zufallszahl zurückgegeben. Dann wird ein neuer Wert xn generiert und an die i-te Stelle im Feld gespeichert. 6.5 Euler-Phi Funktion Die Euler-Phi Funktion ϕ(n) gibt die Anzahl der natürlichen Zahlen im Intervall von 1 bis n an, welche zu n relative prim sind. Wenn die Zahl n eine Primzahl ist, dann ist: ϕ ( n) = n − 1 (6.29) Die Euler-Phi Funktion ist multiplikativ. Wenn zwei Zahlen m und n relativ prim zueinander sind, daß heißt der größte gemeinsame Teiler ist 1, dann ist: ϕ ( mn ) = ϕ ( m ) ⋅ ϕ ( n ) (6.30) Um die Euler-Phi Funktion einer natürlichen Zahl n zu bestimmen, wobei n keine Primzahl ist, ist vorher eine Primfaktorzerlegung von n vorzunehmen. n = p1e1 p 2e2 ⋅ ⋅ ⋅ pkek ϕ ( n ) = n 1 − Primfaktoren von n 1 1 1 1 − ⋅ ⋅ ⋅ 1 − p1 p2 pk (6.31) (6.32) 6.6 Primzahltests Für einige kryptographische Algorithmen werden große Primzahlen benötigt, z.B. für das RSA-Verfahren. Die Bedeutung von Primzahlen für die Kryptographie liegt in der Tatsache begründet, daß es schwierig und zeitaufwendig ist, Zahlen, die aus großen Primzahlen bestehen, zu faktorisieren. Daher werden in diesem Abschnitt die bekanntesten Primzahlentests vorgestellt. Seite 31 6.6.1 Fermat Test Dieser Algorithmus beruht auf dem kleinen Fermatschen Satz (nach Pierre Fermat, 1601-1655) und ist auch in [4] und [5] nachzulesen. Der Satz besagt, daß für jede Primzahl n und jede natürliche Zahl a mit 1 ≤ a ≤ n-1 gilt: a n −1 ≡ 1 ( mod n ) (6.33) Somit erhält man dann folgenden Primzahltest für n: Algorithmus 6.4: Der Fermat Primzahltest FERMAT(n, t) EINGABE: Eine ungerade natürliche Zahl n ≥ 3 und einen Sicherheitsparameter t ≥ 1. AUSGABE: Die Antwort "prim" oder "zusammengesetzt" auf die Frage: "Ist n prim?" 1. Für i von 1 bis t mache folgendes: 1.1. Wähle eine zufällige Zahl a, mit 1 ≤ a ≤ n – 1. 1.2. Berechne r = an-1 mod n. 1.3. Wenn r ≠ 1, dann gebe ("zusammengesetzt") zurück. 2. Gebe ("prim") zurück. Allerdings kann man nach diesem Test nicht sicher sein, daß n eine Primzahl ist, denn es gibt zusammengesetzte Zahlen n, die die Gleichung (6.33) für alle zu n teilerfremden ganzen Zahlen a erfüllen. Diese heißen Carmichael-Zahlen. Diese Zahlen können mit Hilfe probabilistischer Tests, wie etwa des Solovay-Strassen oder Miller-Rabin Tests mit beliebiger Wahrscheinlichkeit ausgeschlossen werden. 6.6.2 Solovay-Strassen Test Dieser probabilistische Test geht auf die Entwickler Robert Solovay und Volker Strassen zurück, nachzulesen in [2]. Dieser Test war der erste Primzahltest, der mit dem Aufkommen der asymmetrischen Kryptographie bekannt wurde. Allerdings wird dieser Test normalerweise nicht mehr verwendet, denn es gibt inzwischen eine bessere Alternative, den Miller-Rabin Test. Trotzdem sollte dieser Primzahltest nicht unerwähnt bleiben, denn er fand einige Zeit lang Verwendung. Der Solovay-Strassen Test basiert auf dem Eulerschen Kriterium, das folgendes besagt. Wenn n eine Primzahl ist, dann gilt: a a (n −1) / 2 ≡ ( mod n ) n (6.34) für alle natürlichen Zahlen a mit 1 ≤ a ≤ n-1 und mit dem größten gemeinsamen Teiler von 1 für a und n. Dabei ist mit an das Jacobisymbol gemeint, das wie folgt berechnet wird: Algorithmus 6.5: Berechnung des Jacobisymbols JACOBI(a, n) EINGABE: Eine ungerade natürliche Zahl n ≥ 3, und eine natürliche Zahl a, mit 0 ≤ a < n. a AUSGABE: Das Jacobisymbol n . 1. Wenn a = 0 dann gebe (0) zurück. Seite 32 2. Wenn a = 1 dann gebe (1) zurück. 3. Berechne a1 und e so, daß a = 2ea1, wobei a1 ungerade ist. 4. Wenn e gerade ist, dann setze s ← 1. Andernfalls setze s ← 1, wenn n ≡ 1 oder 7 (mod 8), oder setze s ← –1, wenn n ≡ 3 oder 5 (mod 8). 5. Wenn n ≡ 3 (mod 4) und a1 ≡ 3 (mod 4), dann setze s ← -s. 6. Setze n1 ← n mod a1. 7. Gebe (s ⋅ JACOBI(n1, a1)) zurück. Mit dem Jacobisymbol ist dann der Solovay-Strassen Test durchführbar: Algorithmus 6.6: Der Solovay-Strassen Primzahltest SOLOVAY-STRASSEN(n, t) EINGABE: eine ungerade natürliche Zahl n ≥ 3 und einen Sicherheitsparameter t ≥ 1. AUSGABE: Die Antwort "prim" oder "zusammengesetzt" auf die Frage: "Ist n prim?" 1. Für i von 1 bis t mache folgendes: 1.1. Wähle eine zufällige Zahl a, mit 2 ≤ a ≤ n – 2. 1.2. Berechne r = a(n-1)/2 mod n. 1.3. Wenn r ≠ 1 und r ≠ n – 1, dann gebe ("zusammengesetzt") zurück. 1.4. Berechne das Jacobisymbol s = JACOBI(a, n) mit dem Algorithmus 6.5. 1.5.Wenn r ≡/ s (mod n) ist, dann gebe ("zusammengesetzt") zurück. 2. Gebe ("prim") zurück. Nach einem Schleifendurchlauf beträgt die Wahrscheinlichkeit, daß n keine Primzahl ist 50%. Dies potenziert sich aber mit jedem weiterem Durchlauf. Somit beträgt die Wahrscheinlichkeit nach t Durchläufen nur noch (½)t. 6.6.3 Miller-Rabin Test Dieser Test ist der heute gebräuchlichste Primzahltest. Er wurde von Gary Miller und Michael Rabin entwickelt, weshalb er auch ihre Namen trägt. Der Test basiert auf folgendem Kriterium, das besagt wenn n eine Primzahl ist und s und r die Gleichung n – 1 = 2sr erfüllen, wobei r ungerade ist, dann gilt: a r ≡ 1 ( mod n ) (6.35) oder a2 j r ≡ − 1 ( mod n ) (6.36) für alle natürlichen Zahlen a, die den größten gemeinsamen Teiler von 1 für a und n haben, wobei j im Bereich von 0 ≤ j ≤ s – 1 liegt. So erhält man dann folgenden Primzahltest: Algorithmus 6.7: Der Miller-Rabin Primzahltest MILLER-RABIN(n, t) EINGABE: Eine ungerade natürliche Zahl n ≥ 3 und einen Sicherheitsparameter t ≥ 1. AUSGABE: Die Antwort "prim" oder "zusammengesetzt" auf die Frage: "Ist n prim?" 1. Berechne s und r, so daß r ungerade ist und die Gleichung n – 1 = 2sr erfüllt ist. 2. Für i von 1 bis t mache folgendes: Seite 33 2.1. Wähle eine zufällige Zahl a, mit 2 ≤ a ≤ n – 2. 2.2. Berechne y = ar mod n. 2.3. Wenn y ≠ 1 und y ≠ n – 1 dann mache folgendes: 2.3.1. j ← 1. 2.3.2. Solange j ≤ s – 1 und y ≠ n – 1 mache folgendes: 2.3.2.1. Berechne y = y2 mod n. 2.3.2.2. Wenn y = 1 dann gebe ("zusammengesetzt") zurück. 2.3.2.3. j ← j + 1. 2.3.3. Wenn y ≠ n – 1 dann gebe ("zusammengesetzt") zurück. 3. Gebe ("prim") zurück. Die Wahrscheinlichkeit, daß eine Zahl, die keine Primzahl ist, diesen Test trotzdem besteht, beträgt 25%. Des weiteren nimmt diese Wahrscheinlichkeit aber schneller ab als bei den beiden vorhergehenden Tests. So beträgt diese nur noch (¼)t nach t Schleifendurchläufe. 6.7 Größter gemeinsamer Teiler Der größte gemeinsame Teiler, kurz gcd (greatest common divisor), zweier natürlicher Zahlen läßt sich mit Hilfe des euklidischen Algorithmus wie folgt berechnen: Algorithmus 6.8: Berechnung des größten gemeinsamen Teilers (gcd) GCD(a, b) EINGABE: zwei positive natürliche Zahle a und b mit a ≥ b. AUSGABE: der größte gemeinsame Teiler von a und b. 1. Solange b ≠ 0 ist, mache folgendes: 1.1. Setze r ← a mod b, a ← b, b ← r. 2. Gebe (a) zurück. 6.8 Erweiterter euklidischer Algorithmus Der euklidische Algorithmus kann so erweitert werden, daß damit nicht nur den größte gemeinsame Teiler berechenbar ist, sondern auch folgende Gleichung gelöst werden kann: e ⋅ d = k ⋅ϕ + 1 (6.37) Dabei sind e und ϕ bekannt und d ist zu berechnen. Die Auflösung dieser Gleichung ist zur Erzeugung von Schlüsselpaaren für den RSA-Algorithmus nötigt, welcher im Abschnitt 6.9 beschrieben wird. Der erweiterte euklidische Algorithmus ist folgendermaßen zu berechnen: Algorithmus 6.9: Der erweiterte euklidische Algorithmus EUCLID(e, ϕ) EINGABE: zwei positive natürliche Zahlen e und ϕ mit e ≤ ϕ. AUSGABE: d für die Lösung der Gleichung (6.37). 1. Setze a ← ϕ, b ← e, x ← 0 und y ← 1. 2. Berechne q = a/b und r = a – q ⋅ b. 3. Solange r > 0 ist, mache folgendes: 3.1. Berechne s = x – q ⋅ y. 3.2. Wenn s ≥ 0, dann setze s ← s mod ϕ, sonst setze s ← ϕ – (–s mod ϕ). Seite 34 3.3. Setze x ← y, y ← s, a ← b und b ← r. 3.4. Berechne q = a/b und r = a – q ⋅ b. 4. Wenn b ≠ 1, dann setze r ← 0, sonst setze r ← y mod ϕ. 5. Gebe (r) zurück. 6.9 Der RSA-Algorithmus Der RSA-Algorithmus ist einer der bekanntesten Vertreter aus der Familie der asymmetrischen Verschlüsselungsverfahren. Dabei steht RSA für die drei Erfinder Rivest, Shamir und Adleman. Der Algorithmus wurden 1978 entwickelt, als sie beweisen wollten, daß Public-Key Kryptographie unmöglich ist. Die Sicherheit des RSA-Verfahren beruht vor allem in dem Rechenaufwand, der zur Primfaktorzerlegung sehr großer Zahlen benötigt wird. Bevor auf Einzelheiten eingegangen wird, soll erst einmal ein allgemeiner Überblick über die Funktionsweise das RSA-Algorithmus aufgezeigt werden. Wie schon erwähnt, ist dies ein asymmetrisches Verfahre. Das bedeutet, daß es dabei nicht nur einen Schlüssel gibt, wie es bei symmetrische Algorithmen, z.B. dem DES-Algorithmus, der Fall ist, sonder hier wird ein privater und ein öffentlicher Schlüssel verwendet. Dabei wird der öffentliche Schlüssel des Empfängers zur Verschlüsselung einer Nachricht verwendet und dieser kann dann die Nachricht mit seinen privatem Schlüssel wieder entschlüsseln. Dieser Vorgang ist einmal in Abbildung 6.4 dargestellt. Entschlüsselung Verschlüsselung Klartext (message) E(m) =c = me mod n D(c) =m = cd mod n Chiffretext öffentlicher Schlüssel: e, n Klartext (message) privater Schlüssel: d Abbildung 6.4: Der RSA-Algorithmus 6.9.1 Erzeugen von RSA-Schlüsselpaaren Bevor der RSA-Algorithmus angewendet werde kann, muß für jeden Kommunikationsteilnehmer ein Schlüsselpaar, welches aus privaten und öffentlichen Schlüssel besteht, erzeugt werden. Dazu werden zwei große Primzahlen p und q sowie das Produkt beider n = p ⋅ q benötigt. Dann ist die Euler-Phi Funktion von n zu berechnen: ϕ (n ) = ϕ ( p ⋅ q ) = ϕ ( p ) ⋅ ϕ (q ) = ( p − 1) ⋅ (q − 1) (6.38) Anschließend wird eine natürliche Zahl e gewählt, die relative prim zu ϕ(n) ist, und deren größter gemeinsamer Teiler 1 ist. Dann ist d zu berechnen, so daß Seite 35 e ⋅ d mod ϕ (n ) = 1 (6.39) erfüllt ist. Die Gleichung (6.39) kann so umgerechnet werden, daß man die Gleichung (6.37) erhält. Somit ist es möglich den erweiterten euklidischen Algorithmus zu benutzen um d zu berechnen. Dann ist noch zu überprüfen, ob der größte gemeinsame Teiler von d und ϕ(n) auch 1 ist. Wenn diese Berechnungen abgeschlossen sind wird e und n als öffentlicher Schlüssel an alle anderen Kommunikationsteilnehmer weitergegeben, während d, p und q als privater Schlüssel geheim gehalten werden muß. 6.9.2 RSA-Verschlüsselung Um eine Nachricht m zu verschlüsseln ist folgenden Gleichung zu berechnen: c = m e mod n (6.40) Dabei ist zu beachten, daß m < n sein muß. Wenn die Nachricht m größer als n ist, dann ist sie in mehrere Teile aufzuteilen, so daß die Teilnachricht mi kleiner als n ist. Algorithmus 6.10: RSA Verschlüsselung RSAEncrypt(m, e, n) EINGABE: Die Nachricht m und der öffentliche Schlüssel e und n. AUSGABE: Den Chiffretext c. 1. Berechne c = me mod n. 2. Gebe (c) zurück. 6.9.3 RSA-Entschlüsslung Um eine Verschlüsselte Nachricht wieder lesbar zu mache, ist folgende Formel zu berechnen: m = c d mod n (6.41) Wenn die Nachricht aus mehreren Teile bestand, so können diese nach dem Entschlüsseln wieder zusammengesetzt werden. Im folgenden ist die Gleichung (6.41) als Algorithmus dargestellt: Algorithmus 6.11: RSA Entschlüsselung RSADecrypt(c, d, n) EINGABE: Der Chiffretext c und der private Schlüssel d und n. AUSGABE: Die Nachricht m. 1. Berechne m = cd mod n. 2. Gebe (m) zurück. Der Algorithmus 6.11 ist genau derselbe wie Algorithmus 6.10, es werden nur andere Werte übergeben, daher können diese Berechnungen auch in eine Algorithmus vorgenommen werden. Seite 36 6.9.4 RSA Beispiel An dieser Stelle soll einmal ein kleines Beispiel zum RSA-Algorithmus vorgestellt werden. 1. Auswahl zweier Primzahlen p und q: p = 47 q = 59 2. Berechnung des Produktes n: n=p⋅q n = 2773 3. Berechnung von ϕ(n): ϕ(n) = (p – 1) ⋅ (q – 1) ϕ(n) = (47 – 1) ⋅ (59 – 1) = 2668 4. Auswahl einer Zahl e, die relative prim zu ϕ(n) ist: e = 17 Test: gcd(e, ϕ(n)) = 1 5. Berechnung von d mit dem erweiterten Euklidischen Algorithmus: e ⋅ d mod ϕ(n) = 1 umrechnen in e ⋅ d = k ⋅ ϕ(n) + 1 d = euclid(e, ϕ(n)) d = 157 Test: gcd(d, ϕ(n)) = 1 gcd(e, d) = 1 öffentlicher Schlüssel (e, n): e = 17, n = 2773 privater Schlüssel (d, p, q): d = 157, p = 47, q = 59 6. Verschlüsselung der Nachricht "Test": E(m) = me mod n T e s t 7. Entschlüsseln der Nachricht: → → → → 84 101 115 116 → 8417 → 10117 → 11517 → 11617 mod mod mod mod 2773 2773 2773 2773 = 2063 = 758 = 1751 = 2504 D(c) = cd mod n 2063157 758157 1751157 2504157 Seite 37 mod mod mod mod 2773 2773 2773 2773 = 84 → T = 101 → e = 115 → s = 116 → t 7 GESCHWINDIGKEITSMESSUNG MIT DEM C-INTERFACE Um die Funktionen der VHDL-Bibliothek hinsichtlich ihrer Ausführungsgeschwindigkeit zu optimieren, ist es notwendig die Zeit, die für die Simulation benötigt wird, zu messen. So kann dann entschieden werden, welche Implementierung einer Funktion die schnellere ist. Die Simulationszeit ist allerdings in VHDL nicht meßbar, aber es gibt noch eine andere Möglichkeit, denn der Simulator von Synopsys verfügt über ein C-Language Interface (CLI). Mit einem drüber eingebundenen C-Programm ist es dann möglich Zeitmessungen vorzunehmen. 7.1 Benutzung des C-Interfaces Für die Benutzung von C-Code mit dem Simulator sind drei Dateien notwendig. In der ersten wird in VHDL beschrieben, wie die Verbindung zum C-Code aussieht. Als Zweites wird dann der eigentliche C-Code benötigt. Die dritte Datei enthält die Komponentenbeschreibung, um den C-Code in andere VHDL-Quellen einbinden zu können. Um dies alles zu verdeutlichen wird anschließend die Benutzung des CLI am Beispiel eines Integer-Addierers beschrieben. 7.1.1 Die Verbindung zum C-Code Im folgenden VHDL-Code wird die Verbindung zum C-Code beschrieben. Datei: adder.vhd LIBRARY synopsys; USE synopsys.attributes.all; LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY adder IS GENERIC ( delay ); PORT ( a : IN b : IN c : OUT ); END adder; : time := 5 ns -- Ausgangsverzögerung integer; integer; integer ARCHITECTURE CLI OF adder IS ATTRIBUTE FOREIGN OF CLI : ARCHITECTURE IS "SYNOPSYS:CLI"; ATTRIBUTE ATTRIBUTE ATTRIBUTE ATTRIBUTE CLI_ELABORATE CLI_EVALUATE CLI_CLOSE CLI_ERROR OF OF OF OF CLI CLI CLI CLI : : : : ARCHITECTURE ARCHITECTURE ARCHITECTURE ARCHITECTURE IS IS IS IS "adder_open"; "adder_eval"; "adder_close"; "adder_error"; ATTRIBUTE CLI_PIN OF a : SIGNAL IS CLI_EVENT; ATTRIBUTE CLI_PIN OF b : SIGNAL IS CLI_EVENT; BEGIN END CLI; Die ENTITY enthält alle Eingangs- und Ausgangssignale die zur Kommunikation mit dem C-Code notwendig sind. In der darauffolgenden ARCHITECTURE sind einige Attribute zu setzen, um das Interface genauer zu spezifizieren. Mit dem FOREIGN-Attribut wird festgelegt, um welches Interface es sich in diesem Fall handelt, denn der Synopsys-Simulator unterstützt auch noch andere außer dem CLI. In den vier folgenden Attributen sind die C-Funktionen, die bei den entsprechenden Ereignissen aufgerufen werden, einzutragen. Allerdings sind nur die CLI_ELABORATE und CLI_EVALUATE Attribute nötig, die beiden Seite 38 anderen können weggelassen werde. Es ist aber empfehlenswert alle vier zu verwenden. Zum Schluß ist noch ein Attribut für jedes Eingangssignal zu setzen. Damit wird dem Simulator mitgeteilt, wann die CLI-Komponente auszuwerten ist. Es gibt dafür 3 möglich Werte, die dem Attribut zugewiesen werden können, siehe dazu Tabelle 7.1. Parameter CLI_EVENT CLI_ACTIVE CLI_PASSIVE Zeitpunkt der Auswertung Sobald sich das Signal verändert, wird die Komponente ausgewertet. Wenn der Simulator diese Signal aktualisiert, erfolgt eine Auswertung. Diese Signal hat keine Effekt auf die Komponentenauswertung. Tabelle 7.1: Parameter für das Eingangssignal-Attribut 7.1.2 Der C-Code Der C-Code enthält die eigentliche Funktionalität der Komponente. Hier sind die vier C-Funktionen zu realisieren, welche vorher im VHDL-Code den Ereignis-Attributen zugewiesen wurden. Um Probleme beim Arbeiten mit dem C-Interface feststellen zu können wird eine Funktion zur Fehlerabfrage benötigt, diese kann auch als DEFINE realisiert werden, wie es in der folgenden Header-Datei zu sehen ist. Datei: adder.h #define CHECK_ERRNO if(cli_errno) { (void) printf("file %s, line %d\n",__FILE__,__LINE__); cliPrintError((char *)0); exit(1) ;} Zum Anfang der C-Codes sind erst einmal die Header-Dateien einzubinden. Eine Besonderheit spielt dabei die "cli.h", in dieser Datei sind sämtliche Funktionen und Definitionen die für das C-Interface benötigt werden enthalten. Als nächstes folgt eine Struktur, in welcher die ID's für die Signale zwischen C und VHDL, und einige zusätzliche Variablen enthalten sind. Datei: adder.c #include <stdio.h> #include "adder.h" #include "cli.h" typedef struct { cliPID pidA; cliPID pidB; cliPID pidC; cliGID gidDelay; cliAFTER gvCDelay; } ADDER_INSTANCE_DATA; /* CLI-Headerdatei enthält alle Typen für VHDL */ /* /* /* /* /* Pin ID für "a" */ Pin ID für "b" */ Pin ID für "c" */ ID für "delay" */ Ausgangsverzögerung für C */ Die folgenden Funktion wird beim Start des C-Interfaces aufgerufen. Dabei wird Speicher für die obige Struktur reserviert und die ID's für die Signal ermittelt. Wie zu sehen ist, wird nach jedem Aufruf einer Funktion des C-Interfaces das DEFINE aus der Header-Datei "adder.h" ausgeführt, um eventuelle Fehler beim Aufruf zu ermitteln. Nachdem alle Variablen der Struktur mit ihren Startwerten beschrieben wurden, wird die Struktur gespeichert. void adder_open(did, iid) cliDID did; cliIID iid; Seite 39 { ADDER_INSTANCE_DATA *adder_idata; cliVALUE gvDelay; /* Speicher für die Datenstruktur reservieren */ adder_idata = (ADDER_INSTANCE_DATA *) cliAllocMem(sizeof(ADDER_INSTANCE_DATA)); /* Pins und Generics auf die Datenstruktur abbilden */ adder_idata->pidA = cliPortName2PID(did, "A"); CHECK_ERRNO; adder_idata->pidB = cliPortName2PID(did, "B"); CHECK_ERRNO; adder_idata->pidC = cliPortName2PID(did, "C"); CHECK_ERRNO; adder_idata->gidDelay = cliGenericName2GID(did, "DELAY"); CHECK_ERRNO; /* Ausgansverzögerung setzen */ cliGetGenericValue(did, iid, adder_idata->gidDelay, &gvDelay); CHECK_ERRNO adder_idata->gvCDelay.delaytype = INERTIAL; adder_idata->gvCDelay.delay.low = gvDelay.value.time.low; adder_idata->gvCDelay.delay.high = 0; adder_idata->gvCDelay.delay.timebase = gvDelay.value.time.timebase; /* die Datenstruktur sichern */ cliSaveInstanceData(did, iid, (void *) adder_idata); CHECK_ERRNO; } Bei Beendigung des VHDL-Simulators ist auch der reservierte Speicher des C-Interfaces wieder freizugeben, dies erfolgt in der folgenden Funktion. void adder_close(did, iid) cliDID did; cliIID iid; { ADDER_INSTANCE_DATA *adder_idata; /* Datenstruktur wiederherstellen */ adder_idata = (ADDER_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); /* reservierten Speicher für die Datenstruktur freigeben */ if(adder_idata != (ADDER_INSTANCE_DATA *)0) { cliFreeMem((void *) adder_idata); } } Wenn sich im VHDL-Simulator ein Signal der C-Komponente ändert und der Simulator eine Auswertung dieses Signals vornimmt wird die folgende C-Funktion aufgerufen. Dies Funktion enthält die Funktionalität der C-Komponente. Zuerst einmal wird die Struktur wiederhergestellt, um überhaupt auf sie zugreifen zu können. Dann werden die aktuellen Werte von den Signalen des C-Interfaces eingelesen. Danach wird die Struktur für die Ergebnisvariable aufgebaut und das Ergebnis berechnet. Zum Schluß wird diese Ergebnis über ein Signal des C-Interfaces zurückgegeben. Die möglichen Signale und ihr Aufbau sind in der Dokumentation für den Simulator nachzulesen. void adder_eval(did, iid, ppid, np) cliDID did; cliIID iid; cliPID *ppid; /* Zeiger auf die Pin-IDs (Pinliste) */ int np; /* Anzahl Pins in der Pinliste */ { ADDER_INSTANCE_DATA *adder_idata; cliVALUE svA; cliVALUE svB; cliVALUE svC; Seite 40 /* Datenstruktur wiederherstellen */ adder_idata = (ADDER_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); cliGetPortValue(did, iid, adder_idata->pidA, &svA); CHECK_ERRNO; cliGetPortValue(did, iid, adder_idata->pidB, &svB); CHECK_ERRNO; svC.typemark = CLI_TYPE_INTEGER; svC.length = 0; svC.value.integer = svA.value.integer + svB.value.integer; cliScheduleOutput(did, iid, adder_idata->pidC, &svC, &adder_idata->gvCDelay); CHECK_ERRNO; } Die letze Funktion wird benötigt, um Fehler, die der VHDL-Simulator feststellt, anzuzeigen. void adder_error(did, iid, level) cliDID did; cliIID iid; int level; { char *s; if(level == 0) s = "WARNUNG"; else s = "FEHLER"; (void) printf("%s gefunden mit (%d,%d)\n",s,did,iid); cliPrintError("ADDER FEHLER"); } Damit ist der C-Teil des Interfaces abgeschlossen. Wie sehr gut ersichtlich wird, ist es nicht allzu schwierig das C-Interface des Synopsys VHDL-Simulators zu benutzen. Allerdings kann solch ein Interface bei anderen Simulatoren völlig anders aussehen, daher ist die beschriebene Komponente nur mit dem Synopsys-Simulator lauffähig. 7.1.3 Die Komponente Um den C-Code auch in anderen VHDL-Quellen einzusetzen, wird eine Komponentenbeschreibung benötigt. Diese kann wie im folgenden beschrieben, als Bibliothek realisiert werden. So daß dann nur noch diese Bibliothek eingebunden werden muß, um die C-Komponente in anderen VHDL-Beschreibungen benutzen zu können. Datei: adder_comp.vhd LIBRARY ieee; USE ieee.std_logic_1164.all; PACKAGE adder_comp IS COMPONENT adder GENERIC ( delay : time := 5 ns ); PORT ( a : IN integer; b : IN integer; c : OUT integer ); END COMPONENT; END; Seite 41 7.1.4 Compilieren und Linken Bevor die C-Komponente verwendet werden kann, sind die C-Datei zu compilieren und zu linken. Dabei sollte wie folgt vorgegangen werden: 1. Analysieren der VHDL-Dateien: vhdlan -nc adder_comp.vhd adder.vhd Dabei werden als Parameter die beiden VHDL-Datei übergeben. Der "-nc"-Parameter kann weggelassen werden, er unterdrückt nur die Startausgabe des VHDL-Analysers. 2. Compilieren der C-Dateien: cli -nc -add -cv adder adder Hierbei gibt der erste "adder"-Parameter den Namen der C-Datei an, und der zweite den ENTITY-Namen der Komponente. Beim ausführen dieser Kommandozeile wird eine Objektdatei erzeugt, die "adder.o" heißt. 3. Erzeugen einer C-Bibliothek: ar crl adder.a adder.o Mit diesem Programmaufruf wird aus der Objektdatei eine C-Bibliothek mit dem Namen "adder.a" erzeugt. 4. Linken der C-Bibliothek cli -nc -s -build -libs adder.a Hiermit wird die C-Bibliothek statisch mit dem VHDL-Simulator gelinkt. Dabei wird ein neues VHDL-Simulatorprogramm im aktuellen Verzeichnis erzeugt, dieses muß dann auch von dort aufgerufen werden, um die C-Komponente benutzen zu können. Es ist auch möglich die C-Bibliothek dynamisch zu linken, allerdings ist dies nur unter einigen wenigen Betriebssystemen (Sparc oder SparcOS5) möglich. Wenn diese Möglichkeit genutzt werden soll, dann hat der Kommandozeilenaufruf folgendermaßen auszusehen: cli -nc -build -libs adder.a 7.2 Beschreibung der Meßfunktion Um die Zeit zu messen, die vergeht während eine Berechnung statt findet, kann die folgende C-Funktion genutzt werden. Dabei wird der Funktion die Variable s übergeben, diese kann die Werte 0 und 1 annehmen. Wenn s = 1 ist, dann wird die Zeitmessung gestartet und mit s = 0 beendet. Bei Beendigung der Zeitmessung wird das Ergebnis ausgegeben und auch als Rückgabeparameter an die aufrufende Funktion zurückgegeben. Dort kann das Ergebnis dann auch über ein Signal an das C-Interface übergeben werden. double Time_F(s) int s; { static struct timeb tstart, tend; long i; double ret; switch(s) { case 0: printf("\n--------------------- ENDE -------------------------------\n\n"); ftime(&tend); i = (long)tend.millitm - (long)tstart.millitm; ret = ((double)(tend.time - tstart.time)) + ((double)i) / 1000.0; printf("Rechenzeit: %21.3f Sekunden\n", ret); printf("\n--------------------- ENDE -------------------------------\n\n"); Seite 42 break; case 1: printf("\n--------------------- START ------------------------------\n\n"); ret = (double)0; ftime(&tstart); break; default: break; } return (ret); } Diese Funktion wird in der EVALUATE-Teil des C-Codes aufgerufen. Seite 43 8 ÜBERPRÜFUNG DER BIBLIOTHEK Um die richtige Funktionsweise der VHDL-Bibliothek zu überprüfen, war es notwendig ein C-Programm zu entwickelt, welches Testvektoren für den VHDL-Simulator berechnete. Dazu wurde der C-Code von Arjen K. Lenstra verwendet, mit dem es möglich ist Langzahlarithmetikfunktionen auszuführen. Um diesen C-Code zur Generierung von Testvektoren einsetzen zu können, war es nötig einige Anpassungen und Erweiterungen vorzunehmen. So wurde eine Funktion entwickelt, mit der es möglich ist große Zufallszahlen zu erzeugen. Des weiteren wurde noch eine Funktion benötigt, um die langen Zahlen in hexadezimaler Form in eine Datei auszugeben. Das Programm hat folgende Kommandozeilenparameter, wobei "mpa" der Name der Programmes ist: mpa Funktion Vektoranzahl Vektorbreite Ausgabedatei [Saat] Dabei haben die Parameter folgende Bedeutung: Paramter Funktion Vektoranzahl Vektorbreite Ausgabedatei Saat Bedeutung 1 Addition 2 Subtraktion 3 Multiplikation 4 Division 5 Modulo Anzahl der zu erzeugenden Testvektoren Breite der Testvektoren in Bits Name der Datei, in der die Testvektoren gespeichert werden Die Saat für den Zufallszahlengenerator. Wenn dieser Parameter weggelassen wird, werden jedesmal andere Testvektoren erzeugt. Tabelle 8.1: Programmparameter für "mpa" Die Testvektoren, die so erzeugt wurden, können nun mit Hilfe des VHDL-Simulators eingelesen werden, und so zum Überprüfen der VHDL-Funktionen genutzt werden. Seite 44 9 TESTERGEBNISSE 9.1 Testergebnisse bei konstanter Vektorbreite In Tabelle 9.1 sind die Meßergebnisse, welche mit dem C-Interface des VHDL-Simulators und der Meßfunktion aus Kapitel 7.2 ermittelt wurden, abgebildet. Dabei ist zu beachten, daß diese Meßfunktion nur die Zeit mißt, die auf dem Computer vergeht während die Berechnung stattfindet. Da der Simulator auf einem UNIX Betriebssystem mit Multitaskingfunktion läuft, war es notwendig eine Rechner zu benutzen, auf dem keine weiteren Programme liefen, weil es sonst zu Verfälschungen der Meßergebnisse gekommen währe. Vektorbreite Ziffernbreite Durchläufe Addition 1024 4 10000 109,853 10000 109,886 10000 110,293 10000 109,660 10000 108,453 10000 108,492 109,440 ∅ 8 10000 60,540 10000 60,684 10000 60,698 10000 60,524 10000 60,909 10000 60,860 60,703 ∅ 16 10000 36,600 10000 37,845 10000 37,740 10000 36,698 10000 38,913 10000 36,623 37,403 ∅ 32 10000 24,748 10000 25,666 10000 24,604 10000 24,731 10000 24,733 10000 24,598 24,847 ∅ 64 10000 19,107 10000 19,631 10000 18,486 10000 18,679 10000 18,732 10000 18,688 18,887 ∅ Seite 45 in Sekunden Subtraktion Multiplikation 110,606 155,268 110,660 154,954 110,781 155,235 110,128 154,654 109,257 148,490 109,189 148,548 110,104 152,858 61,133 85,894 61,179 86,266 61,017 86,441 61,186 85,999 61,346 87,072 61,522 86,408 61,231 86,347 37,227 54,820 38,421 56,202 38,446 56,276 37,299 54,863 39,511 57,681 37,239 54,657 38,024 55,750 25,593 39,160 25,880 40,090 25,615 39,135 25,571 39,172 25,256 39,274 25,459 39,150 25,562 39,330 19,946 32,220 20,386 32,806 19,384 31,718 19,279 31,674 19,428 31,920 19,401 31,867 19,637 32,034 Division 2620,101 2619,379 2618,980 2620,231 3066,831 3059,711 2767,539 3001,722 3001,815 3001,861 3001,733 3027,597 3025,981 3010,118 2974,308 2980,363 2980,012 2974,872 3017,391 2974,030 2983,496 2955,730 2960,383 2956,750 2955,159 2955,379 2957,580 2956,830 2974,895 2973,338 2946,335 2947,299 2947,745 2948,637 2956,375 128 10000 15,673 16,616 29,711 10000 16,193 17,123 30,755 10000 17,251 17,988 31,617 10000 15,676 16,481 29,691 10000 15,663 16,532 29,704 10000 15,802 16,386 29,666 16,043 16,854 30,191 ∅ 256 10000 14,657 15,214 26,191 10000 14,527 15,416 25,937 10000 14,489 15,221 26,192 10000 14,621 15,314 26,100 10000 14,518 15,384 26,028 10000 14,490 15,248 26,236 14,550 15,300 26,114 ∅ 512 10000 13,679 14,562 25,945 10000 13,819 14,430 26,153 10000 13,653 14,422 26,364 10000 13,665 14,561 26,121 10000 13,641 14,428 26,025 10000 13,837 14,785 26,333 13,716 14,531 26,157 ∅ 1024 10000 13,448 14,362 21,369 10000 14,036 15,163 21,890 10000 14,148 14,699 22,086 10000 14,170 14,375 21,609 10000 14,319 14,553 21,828 10000 14,139 15,592 21,710 14,043 14,791 21,749 ∅ Tabelle 9.1: Testergebnisse bei konstanter Vektorbreite 2948,219 2948,303 2948,653 2946,506 2949,505 2946,708 2947,982 3011,864 3012,169 3012,264 3014,144 3012,465 3012,248 3012,526 2685,863 2602,149 2602,602 2601,580 2601,381 2602,023 2615,933 3209,273 3216,082 3219,504 3270,300 3372,407 3319,777 3267,891 Die Durchschnittszeiten der Addition, Subtraktion und Multiplikation, welche in Tabelle 9.1 ermittelt wurden, sind in Abbildung 9.1 als Diagramm dargestellt. Die Division wurde dabei weggelassen, da die Meßzeiten hier so groß sind, daß die Kurven der Addition, Subtraktion und Multiplikation sonst nicht mehr sichtbar währen. Die Kurve der Addition wird von der Subtraktion fast verdeckt, da die Meßwerte so dicht zusammen liegen, daß der Unterschied nur minimal ist. Wie in Abbildung 9.1 sehr gut zu sehen ist, nimmt die Rechenzeit um so mehr zu, je kleiner die Anzahl Bits pro Ziffer sind. Allerdings strebt die Rechenzeit nicht gegen Null, sonder pegelt sich bei einem bestimmten Wert ein. Seite 46 160,000 Rechenzeit [s] 140,000 120,000 100,000 Addition Subtraktion Mutliplikation 80,000 60,000 40,000 20,000 0,000 4 8 16 32 64 128 256 512 1024 Ziffernbreite [bit] Abbildung 9.1: Durchschnittszeiten für die Addition, Subtraktion und Multiplikation 9.2 Testergebnisse bei konstanter Ziffernbreite Als zweites wurden noch einige Meßergebnisse aufgenommen, wobei die Ziffernbreite konstant blieb und die Vektorbreite variiert wurden. Dabei war zu erwarten, daß die Rechenzeit linear ansteigt und sich bei doppelter Vektorbreite auch verdoppelt. Bei der Messung wurden folgende Werte ermittelt: Addition in Sekunden bei einer Vektorbreite von Ziffernbreite Durchläufe 256 512 1024 2048 4096 16 10000 11,120 19,049 38,773 76,260 165,706 10000 10,990 19,220 38,804 75,989 165,796 10000 10,975 19,202 38,802 75,981 166,089 10000 11,270 19,774 38,705 75,417 167,420 10000 10,937 19,308 38,921 76,087 166,154 10000 11,043 19,189 38,798 75,978 165,815 11,056 19,290 38,801 75,952 166,163 ∅ 32 10000 7,945 12,937 26,667 49,801 104,140 10000 7,555 13,075 25,509 49,683 104,678 10000 7,738 12,966 26,581 50,067 104,417 10000 7,762 12,996 26,874 50,063 104,715 10000 7,574 13,136 26,810 50,041 104,413 10000 7,830 12,986 25,815 50,058 104,559 7,734 13,016 26,376 49,952 104,487 ∅ Tabelle 9.2: Testergebnisse bei konstanter Ziffernbreite Die Tabelle 9.2 zeigt, daß sich die Erwartungen in etwa erfüllt haben. Noch besser wird dies gezeigt, wenn die Durchschnittswerte grafisch dargestellt werden, wie es in Abbildung 9.2 Seite 47 geschehen ist. Dabei ist ein linearer Anstieg der Rechenzeit unverkennbar. Um dies noch zu verdeutlichen, wurden die Meßergebnisse für zwei verschiedene Ziffernbreiten ermittelt. So ist sehr gut zu erkennen, daß sich die Geraden immer weiter voneinander entfernen, je größer die Vektorbreite wird. 180,000 160,000 Rechenzeit [s] 140,000 120,000 100,000 Ziffernbreite 16 80,000 Ziffernbreite 32 60,000 40,000 20,000 0,000 0 1024 2048 3072 4096 Vektorlänge [bit] Abbildung 9.2: Rechenzeiten bei konstanter Ziffernbreite 9.3 Optimierung nach Ermittlung von Meßergebnissen Außer der MPA-Adition (multiple-precision arithmetic) wie sie in Algorithmus 3.1 vorgestellt wurde, ist in VHDL auch noch eine andere Implementation möglich. Dabei werden die beiden Zahlen x und y zum Anfang von einer "digit_vector"-Darstellung in eine "std_logic_vector"-Darstellung umgewandelt. Auf diese "std_logic_vector"-Zahlen kann dann die Addition aus der IEEE-Bibliothek angewendet werden. Um das Ergebnis wieder weiter verwende zu können, ist diese dann in eine "digit_vector"-Zahl zurück zu wandeln. Ein solcher Algorithmus kann wie folgt realisiert werden: Algorithmus 9.1: Addition in VHDL EINGABE: Zwei positive natürliche Zahlen x und y, in "digit_vector"-Darstellung. AUSGABE: Die Summe x + y = w. 1. Umwandeln in "std_logic_vector": xv ← x, yv ← y. 2. Adition mit der IEEE-Funktion: wv = xv + yv. 3. Zurückwandeln in "digit_vector": w ← wv. 4. Gebe (w) zurück. Allerdings stellt sich jetzt die Frage welche Implementation ist die schnellere. Dazu kann dann wieder das C-Interface genutzt werden. Die damit ermittelten Meßwerte sind in Tabelle 9.3 dargestellt. Wie deutlich zu sehen ist, stellt sich die in Algorithmus 9.1 vorgestellte Lösung als die bessere Variante dar. Auf die gleiche Weise lassen sich die Algorithmen für die Subtraktion und Multiplikation auch noch verbessern. Seite 48 in Sekunden Vektorbreite Ziffernbreite Durchläufe MPA Addition VHDL Addition 1024 4 10000 142,135 109,853 10000 142,664 109,886 10000 141,792 110,293 10000 142,218 109,660 10000 141,748 108,453 10000 143,932 108,492 142,415 109,440 ∅ 32 10000 27,413 24,748 10000 28,037 25,666 10000 27,057 24,604 10000 28,203 24,731 10000 27,589 24,733 10000 27,414 24,598 27,619 24,847 ∅ Tabelle 9.3: Vergleich zweier verschiedener Addiererimplementationen Seite 49 10 ZUSAMMENFASSUNG Durch die Fertigstellung der Langzahl-Integer-Arithmetik-Bibliothek in VHDL sind Berechnungen für VHDL-Simulationen möglich geworden, die mit den Standard-Bibliotheken nur unter großen Umständen zu realisieren gewesen wären. Es wurden auch Funktionen zur Generierung von Schlüsselpaaren für den RSA-Algorithmus in der VHDL-Bibliothek realisiert, allerdings kann die Berechnung eines Schlüsselpaares mehrere Stunden oder sogar Tage in Anspruch nehmen. Daher währe hierfür eine Berechnung in einem C-Programm vorteilhafter, da diese wesentlich schneller fertig ist. Wie bei der Zeitmessung der einzelnen Funktionen zu sehen ist, war die Divisionsfunktion wesentlich langsamer als alle anderen mathematischen Grundfunktionen. Deswegen sollte an dieser Funktion nach Möglichkeit noch Optimierungen vorgenommen werden. Allerdings ist dies schwierig zu realisieren, da es keine Division für eine "std_logic_vector"-Typen in den Standard-Bibliotheken gibt. Seite 50 LITERATURVERZEICHNIS [1] Bronstein, Semendjajew, Musiol, Mühlig, Taschenbuch der Mathematik, Verlag Harri Deutsch, Frankfurt am Main, 1993 [2] Alfred J. Menezes, Paul C. van Oorschot, Scott A. Vanstone, Handbook of Applied Cryptography, CRC Press, Boca Raton, 1997 [3] Peter J. Ashenden, The Designer's Guide to VHDL, Morgan Kaufmann Publishers, Inc., San Francisco, 1996 [4] Beutelspacher, Schwenk, Wolfenstetter, Moderne Verfahren der Kryptographie, Vieweg Verlag, Braunschweig, 1995 [5] Neal Koblitz, A Course in Number Theory and Cryptography, Springer-Verlag, New York, 1994 Seite 51 ANHANG A Die VHDL-Bibliothek A1 Enthaltene Funktionen A1.1 LOGISCHE FUNKTIONEN Die logischen Funktionen sind in der Datei "mp_logic.vhd" enthalten. Dort sind die folgende Funktionen realisiert: FUNCTION "and" FUNCTION "and" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "nand" ( l, r : udigit_vector ) RETURN udigit_vector; FUNCTION "nand" ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "or" FUNCTION "or" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "nor" FUNCTION "nor" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "xor" FUNCTION "xor" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION xnor FUNCTION xnor ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "not" FUNCTION "not" ( l : udigit_vector ( l : digit_vector ) RETURN udigit_vector; ) RETURN digit_vector; Zusätzlich sind noch einige Konvertierungsfunktionen enthalten, um andere Datentype in einen "digit_vector" oder "udigit_vector" umzuwandel: FUNCTION To_StdLogicVector ( d : digit_vector ) RETURN std_logic_vector; FUNCTION To_StdLogicVector ( u : udigit_vector ) RETURN std_logic_vector; FUNCTION To_StdLogicVector ( u : digit ) RETURN std_logic_vector; FUNCTION FUNCTION FUNCTION FUNCTION To_DigitVector To_DigitVector To_DigitVector To_DigitVector FUNCTION FUNCTION FUNCTION FUNCTION To_UDigitVector To_UDigitVector To_UDigitVector To_UDigitVector ( ( ( ( s s u s ( ( ( ( : : : : s s d s std_logic_vector std_ulogic_vector udigit_vector string : : : : std_logic_vector std_ulogic_vector digit_vector string ) ) ) ) RETURN RETURN RETURN RETURN ) ) ) ) RETURN RETURN RETURN RETURN digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; udigit_vector; udigit_vector; Mit den folgenden beiden Funktionen können die "digit_vector" und "udigit_vector" in Strings umgewandelt werden, um sie zum Beispiele in eine Datei auszugeben: FUNCTION To_String ( u : udigit_vector ) RETURN string; FUNCTION To_String ( d : digit_vector ) RETURN string; A1.2 MATHEMATISCHE UND VERGLEICHSFUNKTIONEN In der Datei "mp_arith.vhd" sind die folgenden mathematischen Grundfunktionen enthalten: FUNCTION "+" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector; FUNCTION "+" ( l : digit; r : udigit_vector ) RETURN udigit_vector; FUNCTION "+" ( l : udigit_vector; r : digit ) RETURN udigit_vector; FUNCTION "+" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector; FUNCTION "+" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector; FUNCTION "+" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector; Seite 52 FUNCTION "+" ( l : digit_vector; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "+" "+" "+" "+" "+" "+" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "-" "-" "-" "-" "-" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "-" "-" "-" "-" "-" "-" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "+" ( "+" ( "-" ( "-" ( "-" ( "ABS" l l l l l ( : : : : : l udigit_vector ) RETURN udigit_vector; digit_vector ) RETURN digit_vector; udigit_vector ) RETURN udigit_vector; udigit_vector ) RETURN digit_vector; digit_vector ) RETURN digit_vector; : digit_vector ) RETURN digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "*" "*" "*" "*" "*" "*" ( ( ( ( ( ( l l l l l l : : : : : : udigit_vector; r digit; r : digit udigit_vector; r udigit_vector; r digit_vector; r digit_vector; r FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "*" "*" "*" "*" "*" "*" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "/" "/" "/" "/" "/" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "/" "/" "/" "/" "/" "/" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer r r r r r : : : : : RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector udigit_vector digit_vector udigit_vector digit_vector : ) : : : : r r r r r ) ) ) ) ) ) ) RETURN digit_vector; ) ) ) ) ) ) ) ) ) ) ) udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector ) RETURN RETURN udigit_vector; udigit_vector ) RETURN digit_vector ) RETURN udigit_vector ) RETURN digit_vector ) RETURN : : : : : ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) ) ) ) ) ) ) ) udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; Des weiteren sind in dieser Datei auch die folgenden Vergleichsfunktionen realisiert: FUNCTION FUNCTION FUNCTION FUNCTION "<" "<" "<" "<" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION "<" "<" "<" "<" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "<=" "<=" "<=" "<=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : r r r r udigit_vector digit_vector udigit_vector digit_vector : : : : ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; FUNCTION "<=" ( l : udigit_vector; r : integer ) RETURN boolean; FUNCTION "<=" ( l : integer; r : udigit_vector ) RETURN boolean; FUNCTION "<=" ( l : digit_vector; r : integer ) RETURN boolean; Seite 53 FUNCTION "<=" ( l : integer; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION ">" ">" ">" ">" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : FUNCTION FUNCTION FUNCTION FUNCTION ">" ">" ">" ">" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION ">=" ">=" ">=" ">=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION ">=" ">=" ">=" ">=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "=" "=" "=" "=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION "=" "=" "=" "=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "/=" "/=" "/=" "/=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION "/=" "/=" "/=" "/=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector r r r r r r r r udigit_vector digit_vector udigit_vector digit_vector : : : : : : : : r r r r ) RETURN boolean; ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector digit_vector udigit_vector digit_vector boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; RETURN RETURN RETURN RETURN udigit_vector digit_vector udigit_vector digit_vector : : : : ) ) ) ) boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; Zusätzlich sind auch noch die folgende Schiebefunktionen enthalte: FUNCTION FUNCTION FUNCTION FUNCTION SHL SHL SHL SHL ( ( ( ( ARG ARG ARG ARG : : : : udigit_vector; COUNT : udigit_vector digit_vector; COUNT : udigit_vector udigit_vector; COUNT : integer digit_vector; COUNT : integer ) ) ) ) RETURN RETURN RETURN RETURN udigit_vector; digit_vector; udigit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION SHR SHR SHR SHR ( ( ( ( ARG ARG ARG ARG : : : : udigit_vector; COUNT : udigit_vector digit_vector; COUNT : udigit_vector udigit_vector; COUNT : integer digit_vector; COUNT : integer ) ) ) ) RETURN RETURN RETURN RETURN udigit_vector; digit_vector; udigit_vector; digit_vector; Um die Hierarchie in den Funktionen zu realisieren, sind noch folgende Konvertierungsfunktionen nötig: FUNCTION CONV_INTEGER ( ARG : udigit_vector ) RETURN integer; FUNCTION CONV_INTEGER ( ARG : digit_vector ) RETURN integer; FUNCTION CONV_DIGIT_VECTOR FUNCTION CONV_DIGIT_VECTOR FUNCTION CONV_DIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN digit_vector; ( ARG : digit_vector; SIZE : integer ) RETURN digit_vector; ( ARG : integer; SIZE : integer ) RETURN digit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN udigit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : digit_vector; SIZE : integer ) RETURN udigit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : integer; SIZE : integer ) RETURN udigit_vector; Seite 54 A1.3 KRYTOGRAPHISCHE FUNKTIONEN In der Datei "mp_crypt.vhd" sind die erweiterten mathematischen und kryptographischen Funktionen enthalten: FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "mod" "mod" "mod" "mod" "mod" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "mod" "mod" "mod" "mod" "mod" "mod" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "rem" "rem" "rem" "rem" "rem" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "rem" "rem" "rem" "rem" "rem" "rem" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "**" "**" "**" "**" "**" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "**" "**" "**" "**" "**" "**" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer r r r r r r r r r r : : : : : : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector udigit_vector digit_vector udigit_vector digit_vector ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; FUNCTION modexp ( b, e, m : udigit_vector ) RETURN udigit_vector; FUNCTION modexp ( b, e, m : digit_vector ) RETURN digit_vector; Die folgenden Funktionen werden zur Erzeugung von RSA-Schlüsslepaaren benötigt: FUNCTION gcd ( a, b : udigit_vector ) RETURN udigit_vector; FUNCTION euclid ( e, phi : udigit_vector ) RETURN udigit_vector; PROCEDURE rnd ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE number : OUT udigit_vector ); FUNCTION prim ( p : udigit_vector; t : integer ) RETURN boolean; PROCEDURE RSA ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE p, q, e, d, n : OUT udigit_vector ); A1.4 ZUSÄTZLICHE FUNKTIONEN In der Datei "mp_std_logic.vhd" sind einige zusätzliche Funktionen enthalten, die die Funktionalität der IEEE-Bibliotheken erweitern: FUNCTION "/" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "/" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "/" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "mod" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "mod" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "mod" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "rem" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "rem" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; Seite 55 FUNCTION "rem" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "**" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "**" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "**" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION modexp ( b, e, m : std_logic_vector ) RETURN std_logic_vector; Seite 56 A2 VHDL-Quellen A1.1 DATEI: MP_LOGIC.VHD LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_arith.all; PACKAGE mp_logic IS -- pragma synthesis_off ----------------------------------------------------------------------------------- constants ----------------------------------------------------------------------------------- size of digits in bits CONSTANT digit_size : positive := 4; ----------------------------------------------------------------------------------- subtypes and types ----------------------------------------------------------------------------------- digit SUBTYPE digit IS std_logic_vector((digit_size - 1) DOWNTO 0); -- unsigned digit vector TYPE udigit_vector IS ARRAY ( NATURAL RANGE <> ) OF digit; -- two's coplement digit vector TYPE digit_vector IS ARRAY ( NATURAL RANGE <> ) OF digit; ----------------------------------------------------------------------------------- constants ---------------------------------------------------------------------------------CONSTANT zero_digit : digit := (OTHERS => '0'); CONSTANT max_digit : digit := (OTHERS => '1'); CONSTANT one_digit : digit := (0 => '1', OTHERS => '0'); ----------------------------------------------------------------------------------- overloaded logical operators ----------------------------------------------------------------------------------------- FUNCTION "and" ( l : digit; FUNCTION "nand" ( l : digit; FUNCTION "or" ( l : digit; FUNCTION "nor" ( l : digit; FUNCTION "xor" ( l : digit; FUNCTION xnor ( l : digit; FUNCTION "not" ( l : digit r r r r r r : : : : : : digit ) RETURN digit; digit ) RETURN digit; digit ) RETURN digit; digit ) RETURN digit; digit ) RETURN digit; digit ) RETURN digit; ) RETURN digit; ----------------------------------------------------------------------------------- vectorized overloaded logical operators ---------------------------------------------------------------------------------FUNCTION "and" FUNCTION "and" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "nand" ( l, r : udigit_vector ) RETURN udigit_vector; FUNCTION "nand" ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "or" FUNCTION "or" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "nor" FUNCTION "nor" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "xor" FUNCTION "xor" ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION xnor FUNCTION xnor ( l, r : udigit_vector ) RETURN udigit_vector; ( l, r : digit_vector ) RETURN digit_vector; FUNCTION "not" FUNCTION "not" ( l : udigit_vector ( l : digit_vector ) RETURN udigit_vector; ) RETURN digit_vector; ----------------------------------------------------------------------------------- conversion functions ---------------------------------------------------------------------------------FUNCTION To_StdLogicVector ( d : digit_vector ) RETURN std_logic_vector; FUNCTION To_StdLogicVector ( u : udigit_vector ) RETURN std_logic_vector; FUNCTION To_StdLogicVector ( u : digit ) RETURN std_logic_vector; FUNCTION FUNCTION FUNCTION FUNCTION To_DigitVector To_DigitVector To_DigitVector To_DigitVector ( ( ( ( FUNCTION FUNCTION FUNCTION FUNCTION To_UDigitVector To_UDigitVector To_UDigitVector To_UDigitVector s s u s ( ( ( ( : : : : s s d s std_logic_vector std_ulogic_vector udigit_vector string : : : : ) ) ) ) std_logic_vector std_ulogic_vector digit_vector string RETURN RETURN RETURN RETURN ) ) ) ) digit_vector; digit_vector; digit_vector; digit_vector; RETURN RETURN RETURN RETURN udigit_vector; udigit_vector; udigit_vector; udigit_vector; FUNCTION To_String ( u : udigit_vector ) RETURN string; FUNCTION To_String ( d : digit_vector ) RETURN string; -- pragma synthesis_on END mp_logic; ----------------------------------------------------------------------------------- Seite 57 PACKAGE BODY mp_logic IS -- pragma synthesis_off ----------------------------------------------------------------------------------- overloaded logical operators -------------------------------------------------------------------------------------- FUNCTION "and" ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( std_logic_vector(l) and std_logic_vector(r) ); END; ----- FUNCTION "nand" ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( std_logic_vector(l) nand std_logic_vector(r) ); END; ----- FUNCTION "or" ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( std_logic_vector(l) or std_logic_vector(r) ); END; ----- FUNCTION "nor" ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( std_logic_vector(l) nor std_logic_vector(r) ); END; ----- FUNCTION "xor" ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( std_logic_vector(l) xor std_logic_vector(r) ); END; ----- FUNCTION xnor ( l : digit; r : digit ) RETURN digit IS BEGIN RETURN digit( not(std_logic_vector(l) xor std_logic_vector(r)) ); END; ----- FUNCTION "not" ( l : digit ) RETURN digit IS BEGIN RETURN digit( not std_logic_vector(l) ); END; ----------------------------------------------------------------------------------- vectorized overloaded logical operators -------------------------------------------------------------------------------------------------------------------------------------------------------------------- and ---------------------------------------------------------------------------------FUNCTION "and" ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'and' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) and rv(i) ); END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "and" ( l, r : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'and' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) and rv(i) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- nand ---------------------------------------------------------------------------------FUNCTION "nand" ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'nand' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) nand rv(i) ); END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "nand" ( l, r : digit_vector ) RETURN digit_vector IS Seite 58 ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'nand' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) nand rv(i) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- or ---------------------------------------------------------------------------------FUNCTION "or" ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'or' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) or rv(i) ); END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "or" ( l, r : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'or' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) or rv(i) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- nor ---------------------------------------------------------------------------------FUNCTION "nor" ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'nor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) nor rv(i) ); END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "nor" ( l, r : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'nor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) nor rv(i) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- xor ---------------------------------------------------------------------------------FUNCTION "xor" ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'xor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) xor rv(i) ); Seite 59 END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "xor" ( l, r : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'xor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( lv(i) xor rv(i) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- xnor ---------------------------------------------------------------------------------FUNCTION xnor ( l, r : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : udigit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'xnor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( not( lv(i) xor rv(i) ) ); END LOOP; END IF; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION xnor ( l, r : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; ALIAS rv : digit_vector ( (r'LENGTH - 1) DOWNTO 0 ) IS r; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN IF ( l'LENGTH /= r'LENGTH ) THEN ASSERT FALSE REPORT "arguments of overloaded 'xnor' operator are not of the same length" SEVERITY FAILURE; ELSE FOR i IN result'RANGE LOOP result(i) := ( not( lv(i) xor rv(i) ) ); END LOOP; END IF; RETURN result; END; ----------------------------------------------------------------------------------- not ---------------------------------------------------------------------------------FUNCTION "not" ( l : udigit_vector ) RETURN udigit_vector IS ALIAS lv : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; VARIABLE result : udigit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN FOR i IN (l'LENGTH - 1) DOWNTO 0 LOOP result(i) := ( NOT lv(i) ); END LOOP; RETURN result; END; ---------------------------------------------------------------------------------FUNCTION "not" ( l : digit_vector ) RETURN digit_vector IS ALIAS lv : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ) IS l; VARIABLE result : digit_vector ( (l'LENGTH - 1) DOWNTO 0 ); BEGIN FOR i IN (l'LENGTH - 1) DOWNTO 0 LOOP result(i) := ( NOT lv(i) ); END LOOP; RETURN result; END; ----------------------------------------------------------------------------------- conversion functions ---------------------------------------------------------------------------------FUNCTION To_StdLogicVector ( d : digit_vector ) RETURN std_logic_vector IS ALIAS dv : digit_vector((d'LENGTH - 1) DOWNTO 0) IS d; VARIABLE result : std_logic_vector(((d'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN dv'RANGE LOOP prod := i * digit_size; result((prod + (digit_size - 1)) DOWNTO prod) := dv(i); END LOOP; RETURN result; END; FUNCTION To_StdLogicVector ( u : udigit_vector ) RETURN std_logic_vector IS ALIAS uv : udigit_vector((u'LENGTH - 1) DOWNTO 0) IS u; VARIABLE result : std_logic_vector(((u'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN uv'RANGE LOOP Seite 60 prod := i * digit_size; result((prod + (digit_size - 1)) DOWNTO prod) := uv(i); END LOOP; RETURN result; END; FUNCTION To_StdLogicVector ( u : digit) RETURN std_logic_vector IS VARIABLE result : std_logic_vector((digit_size-1) DOWNTO 0); BEGIN result((digit_size-1) DOWNTO 0) := u; RETURN result; END; FUNCTION To_DigitVector ( s : std_logic_vector ) RETURN digit_vector IS ALIAS sv : std_logic_vector((s'LENGTH - 1) DOWNTO 0) IS s; VARIABLE result : digit_vector(((s'LENGTH - 1) / digit_size) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN result'RANGE LOOP prod := i * digit_size; result(i) := sv((prod +(digit_size - 1)) DOWNTO prod); END LOOP; RETURN result; END; FUNCTION To_DigitVector ( s : std_ulogic_vector ) RETURN digit_vector IS VARIABLE sv : std_logic_vector((s'LENGTH - 1) DOWNTO 0) := To_StdLogicVector(s); VARIABLE result : digit_vector(((s'LENGTH - 1) / digit_size) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN result'RANGE LOOP prod := i * digit_size; result(i) := sv((prod + (digit_size - 1)) DOWNTO prod); END LOOP; RETURN result; END; FUNCTION To_DigitVector ( u : udigit_vector ) RETURN digit_vector IS ALIAS uv : udigit_vector((u'LENGTH - 1) DOWNTO 0) IS u; VARIABLE result : digit_vector((u'LENGTH - 1) DOWNTO 0); BEGIN FOR i IN result'RANGE LOOP result(i) := uv(i); END LOOP; RETURN result; END; FUNCTION To_DigitVector ( s : string ) RETURN digit_vector IS CONSTANT msb : integer := (s'LENGTH * 4); ALIAS sv : string(s'LENGTH DOWNTO 1) IS s; VARIABLE result : std_logic_vector((msb - 1) DOWNTO 0); BEGIN FOR i IN 0 TO (s'LENGTH - 1) LOOP CASE sv(i + 1) IS WHEN '0' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0000"; WHEN '1' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0001"; WHEN '2' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0010"; WHEN '3' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0011"; WHEN '4' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0100"; WHEN '5' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0101"; WHEN '6' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0110"; WHEN '7' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0111"; WHEN '8' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1000"; WHEN '9' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1001"; WHEN 'a' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1010"; WHEN 'b' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1011"; WHEN 'c' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1100"; WHEN 'd' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1101"; WHEN 'e' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1110"; WHEN 'f' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1111"; WHEN 'A' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1010"; WHEN 'B' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1011"; WHEN 'C' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1100"; WHEN 'D' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1101"; WHEN 'E' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1110"; WHEN 'F' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1111"; WHEN OTHERS => ASSERT FALSE REPORT "failure in 'to_digitvector' function, S is not a hex string" SEVERITY FAILURE; END CASE; END LOOP; RETURN To_DigitVector(result); END; FUNCTION To_UDigitVector ( s : std_logic_vector ) RETURN udigit_vector IS ALIAS sv : std_logic_vector((s'LENGTH - 1) DOWNTO 0) IS s; VARIABLE result : udigit_vector(((s'LENGTH - 1) / digit_size) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN result'RANGE LOOP prod := i * digit_size; result(i) := sv((prod + (digit_size - 1)) DOWNTO prod); END LOOP; RETURN result; END; FUNCTION To_UDigitVector ( s : std_ulogic_vector ) RETURN udigit_vector IS VARIABLE sv : std_logic_vector((s'LENGTH - 1) DOWNTO 0) := To_StdLogicVector(s); VARIABLE result : udigit_vector(((s'LENGTH - 1) / digit_size) DOWNTO 0); VARIABLE prod : integer; BEGIN FOR i IN result'RANGE LOOP prod := i * digit_size; result(i) := sv((prod + (digit_size - 1)) DOWNTO prod); Seite 61 END LOOP; RETURN result; END; FUNCTION To_UDigitVector ( d : digit_vector ) RETURN udigit_vector IS ALIAS dv : digit_vector((d'LENGTH - 1) DOWNTO 0) IS d; VARIABLE result : udigit_vector((d'LENGTH - 1) DOWNTO 0); BEGIN FOR i IN result'RANGE LOOP result(i) := dv(i); END LOOP; RETURN result; END; FUNCTION To_UDigitVector ( s : string ) RETURN udigit_vector IS CONSTANT msb : integer := (s'LENGTH * 4); ALIAS sv : string((s'LENGTH) DOWNTO 1) IS s; VARIABLE result : std_logic_vector((msb - 1) DOWNTO 0); BEGIN FOR i IN 0 TO (s'LENGTH - 1) LOOP CASE sv(i + 1) IS WHEN '0' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0000"; WHEN '1' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0001"; WHEN '2' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0010"; WHEN '3' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0011"; WHEN '4' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0100"; WHEN '5' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0101"; WHEN '6' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0110"; WHEN '7' => result(((i * 4) + 3) DOWNTO (i * 4)) := "0111"; WHEN '8' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1000"; WHEN '9' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1001"; WHEN 'a' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1010"; WHEN 'b' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1011"; WHEN 'c' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1100"; WHEN 'd' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1101"; WHEN 'e' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1110"; WHEN 'f' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1111"; WHEN 'A' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1010"; WHEN 'B' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1011"; WHEN 'C' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1100"; WHEN 'D' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1101"; WHEN 'E' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1110"; WHEN 'F' => result(((i * 4) + 3) DOWNTO (i * 4)) := "1111"; WHEN OTHERS => ASSERT FALSE REPORT "failure in 'to_udigitvector' function, S is not a hex string" SEVERITY FAILURE; END CASE; END LOOP; RETURN To_UDigitVector(result); END; FUNCTION To_String ( u : udigit_vector ) RETURN string IS CONSTANT string_length : integer := (u'LENGTH * digit_size)/4; CONSTANT std_length : integer := u'LENGTH * digit_size; ALIAS uv : udigit_vector((u'LENGTH - 1) DOWNTO 0) IS u; VARIABLE temp : std_logic_vector((std_length - 1) DOWNTO 0); VARIABLE temp2 : std_logic_vector(3 DOWNTO 0); VARIABLE result : string (string_length DOWNTO 1); BEGIN temp := To_StdLogicVector(uv); FOR i IN 0 TO (string_length - 1) LOOP temp2 := temp(((i * 4) + 3) DOWNTO (i * 4)); CASE temp2 IS WHEN "0000" => result(i + 1) := '0'; WHEN "0001" => result(i + 1) := '1'; WHEN "0010" => result(i + 1) := '2'; WHEN "0011" => result(i + 1) := '3'; WHEN "0100" => result(i + 1) := '4'; WHEN "0101" => result(i + 1) := '5'; WHEN "0110" => result(i + 1) := '6'; WHEN "0111" => result(i + 1) := '7'; WHEN "1000" => result(i + 1) := '8'; WHEN "1001" => result(i + 1) := '9'; WHEN "1010" => result(i + 1) := 'A'; WHEN "1011" => result(i + 1) := 'B'; WHEN "1100" => result(i + 1) := 'C'; WHEN "1101" => result(i + 1) := 'D'; WHEN "1110" => result(i + 1) := 'E'; WHEN "1111" => result(i + 1) := 'F'; WHEN OTHERS => result(i + 1) := 'X'; END CASE; END LOOP; RETURN result; END; FUNCTION To_String ( d : digit_vector ) RETURN string IS CONSTANT string_length : integer := (d'LENGTH * digit_size)/4; CONSTANT std_length : integer := d'LENGTH * digit_size; ALIAS dv : digit_vector((d'LENGTH - 1) DOWNTO 0) IS d; VARIABLE temp : std_logic_vector((std_length - 1) DOWNTO 0); VARIABLE temp2 : std_logic_vector(3 DOWNTO 0); VARIABLE result : string (string_length DOWNTO 1); BEGIN temp := To_StdLogicVector(dv); FOR i IN 0 TO (string_length - 1) LOOP temp2 := temp(((i * 4) + 3) DOWNTO (i * 4)); CASE temp2 IS WHEN "0000" => result(i + 1) := '0'; WHEN "0001" => result(i + 1) := '1'; WHEN "0010" => result(i + 1) := '2'; WHEN "0011" => result(i + 1) := '3'; WHEN "0100" => result(i + 1) := '4'; WHEN "0101" => result(i + 1) := '5'; WHEN "0110" => result(i + 1) := '6'; Seite 62 WHEN "0111" WHEN "1000" WHEN "1001" WHEN "1010" WHEN "1011" WHEN "1100" WHEN "1101" WHEN "1110" WHEN "1111" WHEN OTHERS END CASE; END LOOP; RETURN result; END ; => => => => => => => => => => result(i result(i result(i result(i result(i result(i result(i result(i result(i result(i + + + + + + + + + + 1) 1) 1) 1) 1) 1) 1) 1) 1) 1) := := := := := := := := := := '7'; '8'; '9'; 'A'; 'B'; 'C'; 'D'; 'E'; 'F'; 'X'; -- pragma synthesis_on END mp_logic; Seite 63 A1.2 DATEI: MP_ARITH.VHD LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; LIBRARY WORK; USE WORK.mp_logic.all; PACKAGE mp_arith IS -- pragma synthesis_off ------------------------------------------------------------------------------ overloaded "+" functions with two arguments ----------------------------------------------------------------------------FUNCTION "+" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector; FUNCTION "+" ( l : digit; r : udigit_vector ) RETURN udigit_vector; FUNCTION "+" ( l : udigit_vector; r : digit ) RETURN udigit_vector; FUNCTION FUNCTION FUNCTION FUNCTION "+" "+" "+" "+" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "+" "+" "+" "+" "+" "+" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded "-" functions with two arguments ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "-" "-" "-" "-" "-" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "-" "-" "-" "-" "-" "-" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded functions with one argument ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "+" ( "+" ( "-" ( "-" ( "-" ( "ABS" l l l l l ( : : : : : l udigit_vector ) RETURN udigit_vector; digit_vector ) RETURN digit_vector; udigit_vector ) RETURN udigit_vector; udigit_vector ) RETURN digit_vector; digit_vector ) RETURN digit_vector; : digit_vector ) RETURN digit_vector; ------------------------------------------------------------------------------ overloaded "*" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "*" "*" "*" "*" "*" "*" ( ( ( ( ( ( l l l l l l : : : : : : udigit_vector; r digit; r : digit udigit_vector; r udigit_vector; r digit_vector; r digit_vector; r : ) : : : : udigit_vector ) RETURN RETURN udigit_vector; udigit_vector ) RETURN digit_vector ) RETURN udigit_vector ) RETURN digit_vector ) RETURN FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "*" "*" "*" "*" "*" "*" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded "/" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "/" "/" "/" "/" "/" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "/" "/" "/" "/" "/" "/" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded "<" functions ----------------------------------------------------------------------------FUNCTION "<" ( l : udigit_vector; r : udigit_vector ) RETURN boolean; FUNCTION "<" ( l : udigit_vector; r : digit_vector ) RETURN boolean; FUNCTION "<" ( l : digit_vector; r : udigit_vector ) RETURN boolean; Seite 64 FUNCTION "<" ( l : digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION "<" "<" "<" "<" ( ( ( ( l l l l : : : : r : digit_vector udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) RETURN boolean; RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded "<=" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION "<=" "<=" "<=" "<=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "<=" "<=" "<=" "<=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded ">" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION ">" ">" ">" ">" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION ">" ">" ">" ">" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded ">=" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION ">=" ">=" ">=" ">=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION ">=" ">=" ">=" ">=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded "=" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION "=" "=" "=" "=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "=" "=" "=" "=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded "/=" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION "/=" "/=" "/=" "/=" ( ( ( ( l l l l : : : : udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r : : : : udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION "/=" "/=" "/=" "/=" ( ( ( ( l l l l : : : : udigit_vector; r : integer integer; r : udigit_vector digit_vector; r : integer integer; r : digit_vector ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN boolean; boolean; boolean; boolean; boolean; boolean; boolean; boolean; ------------------------------------------------------------------------------ overloaded shift functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION SHL SHL SHL SHL ( ( ( ( ARG ARG ARG ARG : : : : udigit_vector; COUNT : udigit_vector digit_vector; COUNT : udigit_vector udigit_vector; COUNT : integer digit_vector; COUNT : integer ) ) ) ) RETURN RETURN RETURN RETURN udigit_vector; digit_vector; udigit_vector; digit_vector; FUNCTION FUNCTION FUNCTION FUNCTION SHR SHR SHR SHR ( ( ( ( ARG ARG ARG ARG : : : : udigit_vector; COUNT : udigit_vector digit_vector; COUNT : udigit_vector udigit_vector; COUNT : integer digit_vector; COUNT : integer ) ) ) ) RETURN RETURN RETURN RETURN udigit_vector; digit_vector; udigit_vector; digit_vector; ------------------------------------------------------------------------------ conversion functions ----------------------------------------------------------------------------FUNCTION CONV_INTEGER ( ARG : udigit_vector ) RETURN integer; FUNCTION CONV_INTEGER ( ARG : digit_vector ) RETURN integer; FUNCTION CONV_DIGIT_VECTOR FUNCTION CONV_DIGIT_VECTOR FUNCTION CONV_DIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN digit_vector; ( ARG : digit_vector; SIZE : integer ) RETURN digit_vector; ( ARG : integer; SIZE : integer ) RETURN digit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN udigit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : digit_vector; SIZE : integer ) RETURN udigit_vector; FUNCTION CONV_UDIGIT_VECTOR ( ARG : integer; SIZE : integer ) RETURN udigit_vector; Seite 65 -- pragma synthesis_on END mp_arith; ----------------------------------------------------------------------------------PACKAGE BODY mp_arith IS -- pragma synthesis_off FUNCTION max ( L, R : integer ) RETURN integer IS BEGIN IF L > R THEN RETURN L; ELSE RETURN R; END IF; END; FUNCTION min ( L, R : integer ) RETURN integer IS BEGIN IF L < R THEN RETURN L; ELSE RETURN R; END IF; END; FUNCTION mult ( a, b : digit_vector ) RETURN digit_vector IS VARIABLE av : UNSIGNED(((a'LENGTH * digit_size) - 1) DOWNTO 0) ; VARIABLE bv : UNSIGNED(((b'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE result : UNSIGNED( (((a'LENGTH + b'LENGTH) * digit_size) - 1) DOWNTO 0); VARIABLE neg : std_logic; BEGIN neg := a(a'LEFT)(digit_size - 1) XOR b(b'LEFT)(digit_size - 1); av := UNSIGNED(To_StdLogicVector(ABS(a))); bv := UNSIGNED(To_StdLogicVector(ABS(b))); result := av * bv; IF (neg = '1') THEN RETURN -To_DigitVector(std_logic_vector(result)); ELSE RETURN To_DigitVector(std_logic_vector(result)); END IF; END; FUNCTION division ( a, b : digit_vector ) RETURN digit_vector IS CONSTANT q_width : positive := a'LENGTH * digit_size; VARIABLE bv : UNSIGNED(((b'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE quotient, z : UNSIGNED((q_width - 1) DOWNTO 0); VARIABLE neg : std_logic; BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE neg := a(a'LEFT)(digit_size - 1) XOR b(b'LEFT)(digit_size - 1); bv := UNSIGNED(To_StdLogicVector(ABS(b))); z := UNSIGNED(To_StdLogicVector(ABS(a))); quotient := (OTHERS => '0'); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN quotient(q_width-i) := '1'; IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; IF (neg = '1') THEN RETURN -To_DigitVector(std_logic_vector(quotient)); ELSE RETURN To_DigitVector(std_logic_vector(quotient)); END IF; END; FUNCTION minus ( a, b : digit_vector ) RETURN digit_vector IS VARIABLE av, bv, sum : unsigned((a'LENGTH * digit_size - 1) DOWNTO 0); BEGIN av := unsigned(To_StdLogicVector(a)); bv := unsigned(To_StdLogicVector(b)); sum := av - bv; RETURN To_DigitVector(std_logic_vector(sum)); END; FUNCTION plus ( a, b : digit_vector ) RETURN digit_vector IS VARIABLE av, bv, sum : unsigned((a'LENGTH * digit_size - 1) DOWNTO 0); BEGIN av := unsigned(To_StdLogicVector(a)); bv := unsigned(To_StdLogicVector(b)); sum := av + bv; RETURN To_DigitVector(std_logic_vector(sum)); END; Seite 66 FUNCTION is_less ( a, b : digit_vector ) RETURN boolean IS CONSTANT sign : integer := a'LEFT; VARIABLE result : boolean; BEGIN IF (a(sign)(digit_size - 1) /= b(sign)(digit_size - 1)) THEN result := a(sign)(digit_size - 1) = '1'; ELSE result := FALSE; FOR i IN sign DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (a(i)(j) /= b(i)(j)) THEN result := a(i)(j) = '0'; RETURN result; END IF; END LOOP; END LOOP; END IF; RETURN result; END; FUNCTION is_less_or_equal ( a, b : digit_vector ) RETURN boolean IS CONSTANT sign : integer := a'LEFT; VARIABLE result : boolean; BEGIN IF (a(sign)(digit_size - 1) /= b(sign)(digit_size - 1)) THEN result := a(sign)(digit_size - 1) = '1'; ELSE result := TRUE; FOR i IN sign DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (a(i)(j) /= b(i)(j)) THEN result := a(i)(j) = '0'; RETURN result; END IF; END LOOP; END LOOP; END IF; RETURN result; END; FUNCTION equal ( l, r : digit_vector ) RETURN boolean IS BEGIN FOR i IN l'RANGE LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (l(i)(j) /= r(i)(j)) THEN RETURN FALSE; END IF; END LOOP; END LOOP; RETURN TRUE; END; FUNCTION not_equal ( l, r : digit_vector ) RETURN boolean IS BEGIN FOR i IN l'RANGE LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (l(i)(j) /= r(i)(j)) THEN RETURN TRUE; END IF; END LOOP; END LOOP; RETURN FALSE; END; FUNCTION shift_left ( arg : digit_vector; count : integer ) RETURN digit_vector IS CONSTANT msb : integer := arg'LENGTH - 1; VARIABLE result : digit_vector( msb DOWNTO 0 ); VARIABLE count2 : integer; BEGIN IF (count < 0) THEN ASSERT FALSE REPORT "failure in 'shift_left' function, COUNT have to be a positive integer" SEVERITY FAILURE; ELSE IF (count <= msb) THEN result(msb DOWNTO count) := arg((msb - count) DOWNTO 0); IF (count /= 0) THEN result((count - 1) DOWNTO 0) := (OTHERS => zero_digit); END IF; ELSE result := (OTHERS => zero_digit); END IF; END IF; RETURN result; END; FUNCTION shift_right ( arg : digit_vector; count : integer ) RETURN digit_vector IS CONSTANT msb : integer := ARG'LENGTH - 1; VARIABLE result : digit_vector( msb DOWNTO 0 ); VARIABLE count2 : integer; BEGIN IF (count < 0) THEN ASSERT FALSE REPORT "failure in 'shift_right' function, COUNT have to be a positive integer" SEVERITY FAILURE; ELSE IF (count <= msb) THEN result((msb - count) DOWNTO 0) := arg(msb DOWNTO count); IF (count /= 0) THEN result(msb DOWNTO (msb - count + 1)) := (OTHERS => zero_digit); END IF; ELSE result := (OTHERS => zero_digit); END IF; END IF; Seite 67 RETURN result; END; FUNCTION unsigned_mult ( a, b : udigit_vector ) RETURN udigit_vector IS VARIABLE av : UNSIGNED(((a'LENGTH * digit_size) - 1) DOWNTO 0) ; VARIABLE bv : UNSIGNED(((b'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE result : UNSIGNED( (((a'LENGTH + b'LENGTH) * digit_size) - 1) DOWNTO 0); BEGIN av := UNSIGNED(To_StdLogicVector(a)); bv := UNSIGNED(To_StdLogicVector(b)); result := av * bv; RETURN To_UDigitVector(std_logic_vector(result)); END; FUNCTION unsigned_division ( a, b : udigit_vector ) RETURN udigit_vector IS CONSTANT q_width : positive := a'LENGTH * digit_size; VARIABLE bv : UNSIGNED(((b'LENGTH * digit_size) - 1) DOWNTO 0); VARIABLE quotient, z : UNSIGNED((q_width - 1) DOWNTO 0); BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(To_StdLogicVector(b)); z := UNSIGNED(To_StdLogicVector(a)); quotient := (OTHERS => '0'); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN quotient(q_width-i) := '1'; IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; RETURN To_UDigitVector(std_logic_vector(quotient)); END; FUNCTION unsigned_minus ( a, b : udigit_vector ) RETURN udigit_vector IS VARIABLE av, bv, sum : unsigned((a'LENGTH * digit_size - 1) DOWNTO 0); BEGIN av := unsigned(To_StdLogicVector(a)); bv := unsigned(To_StdLogicVector(b)); sum := av - bv; RETURN To_UDigitVector(std_logic_vector(sum)); END; FUNCTION unsigned_plus ( a, b : udigit_vector ) RETURN udigit_vector IS VARIABLE av, bv, sum : unsigned((a'LENGTH * digit_size - 1) DOWNTO 0); BEGIN av := unsigned(To_StdLogicVector(a)); bv := unsigned(To_StdLogicVector(b)); sum := av + bv; RETURN To_UDigitVector(std_logic_vector(sum)); END; FUNCTION unsigned_is_less ( a, b : udigit_vector ) RETURN boolean IS CONSTANT sign : integer := a'LEFT; VARIABLE result : boolean; BEGIN result := FALSE; FOR i IN sign DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (a(i)(j) /= b(i)(j)) THEN result := a(i)(j) = '0'; RETURN result; END IF; END LOOP; END LOOP; RETURN result; END; FUNCTION unsigned_is_less_or_equal ( a, b : udigit_vector ) RETURN boolean IS CONSTANT sign : integer := a'LEFT; VARIABLE result : boolean; BEGIN result := TRUE; FOR i IN sign DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (a(i)(j) /= b(i)(j)) THEN result := a(i)(j) = '0'; RETURN result; END IF; END LOOP; END LOOP; RETURN result; END; FUNCTION unsigned_equal ( l, r : udigit_vector ) RETURN boolean IS BEGIN Seite 68 FOR i IN l'RANGE LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (l(i)(j) /= r(i)(j)) THEN RETURN FALSE; END IF; END LOOP; END LOOP; RETURN TRUE; END; FUNCTION unsigned_not_equal ( l, r : udigit_vector ) RETURN boolean IS BEGIN FOR i IN l'RANGE LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF (l(i)(j) /= r(i)(j)) THEN RETURN TRUE; END IF; END LOOP; END LOOP; RETURN FALSE; END; FUNCTION unsigned_shift_left ( arg : udigit_vector; count : integer ) RETURN udigit_vector IS CONSTANT msb : integer := arg'LENGTH - 1; VARIABLE result : udigit_vector( msb DOWNTO 0 ); VARIABLE count2 : integer; BEGIN IF (count < 0) THEN ASSERT FALSE REPORT "failure in 'shift_left' function, COUNT have to be a positive integer" SEVERITY FAILURE; ELSE IF (count <= msb) THEN result(msb DOWNTO count) := arg((msb - count) DOWNTO 0); IF (count /= 0) THEN result((count - 1) DOWNTO 0) := (OTHERS => zero_digit); END IF; ELSE result := (OTHERS => zero_digit); END IF; END IF; RETURN result; END; FUNCTION unsigned_shift_right ( arg : udigit_vector; count : integer ) RETURN udigit_vector IS CONSTANT msb : integer := ARG'LENGTH - 1; VARIABLE result : udigit_vector( msb DOWNTO 0 ); VARIABLE count2 : integer; BEGIN IF (count < 0) THEN ASSERT FALSE REPORT "failure in 'shift_right' function, COUNT have to be a positive integer" SEVERITY FAILURE; ELSE IF (count <= msb) THEN result((msb - count) DOWNTO 0) := arg(msb DOWNTO count); IF (count /= 0) THEN result(msb DOWNTO (msb - count + 1)) := (OTHERS => zero_digit); END IF; ELSE result := (OTHERS => zero_digit); END IF; END IF; RETURN result; END; ------------------------------------------------------------------------------ overloaded "+" functions with two arguments ----------------------------------------------------------------------------FUNCTION "+" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_plus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : digit; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH; VARIABLE lv : UDIGIT_VECTOR(0 DOWNTO 0); BEGIN lv(0) := l; RETURN unsigned_plus( CONV_UDIGIT_VECTOR(lv, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : udigit_vector; r : digit ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; VARIABLE rv : UDIGIT_VECTOR(0 DOWNTO 0); BEGIN rv(0) := r; RETURN unsigned_plus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(rv, length) ); END; FUNCTION "+" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH + 1); BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN Seite 69 RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN unsigned_plus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN unsigned_plus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "+" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN plus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "-" functions with two arguments ----------------------------------------------------------------------------FUNCTION "-" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_minus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH + 1); BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN unsigned_minus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; Seite 70 FUNCTION "-" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN unsigned_minus( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "-" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN minus( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded functions with one argument ----------------------------------------------------------------------------FUNCTION "+" ( l : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN l; END; FUNCTION "+" ( l : digit_vector BEGIN RETURN l; END; ) RETURN digit_vector IS FUNCTION "-" ( l : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN 0 - l; END; FUNCTION "-" ( l : udigit_vector ) RETURN digit_vector IS BEGIN RETURN 0 - l; END; FUNCTION "-" ( l : digit_vector BEGIN RETURN 0 - l; END; ) RETURN digit_vector IS FUNCTION "ABS" ( l : digit_vector ) RETURN digit_vector IS BEGIN IF (l(l'LEFT)(digit_size - 1) = '0') THEN RETURN l; ELSE RETURN 0 - l; END IF; END; ------------------------------------------------------------------------------ overloaded "*" functions ----------------------------------------------------------------------------FUNCTION "*" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_mult( CONV_UDIGIT_VECTOR(l, l'LENGTH), CONV_UDIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "*" ( l : digit; r : digit ) RETURN udigit_vector IS VARIABLE lv : UDIGIT_VECTOR(0 DOWNTO 0); VARIABLE rv : UDIGIT_VECTOR(0 DOWNTO 0); BEGIN lv(0) := l; rv(0) := r; RETURN unsigned_mult( CONV_UDIGIT_VECTOR(lv, 1), CONV_UDIGIT_VECTOR(rv, 1) ); END; FUNCTION "*" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "*" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), Seite 71 END; CONV_DIGIT_VECTOR(r, r'LENGTH) ); FUNCTION "*" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "*" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "*" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN unsigned_mult( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "*" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN unsigned_mult( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "*" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "*" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "*" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "*" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN mult( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "/" functions ----------------------------------------------------------------------------FUNCTION "/" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_division( CONV_UDIGIT_VECTOR(l, l'LENGTH), CONV_UDIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "/" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN division( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "/" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN division( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "/" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN division( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "/" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN division( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "/" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH ; BEGIN RETURN unsigned_division( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "/" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN unsigned_division( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; Seite 72 FUNCTION "/" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN division( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN division( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN division( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN division( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "<" functions ----------------------------------------------------------------------------FUNCTION "<" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_is_less( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH+ 1); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : digit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "<=" functions ----------------------------------------------------------------------------FUNCTION "<=" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_is_less_or_equal( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; Seite 73 FUNCTION "<=" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : digit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "<=" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded ">" functions ----------------------------------------------------------------------------FUNCTION ">" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_is_less( CONV_UDIGIT_VECTOR(r, length), CONV_UDIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : digit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN is_less( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; ------------------------------------------------------------------------------ overloaded ">=" functions ----------------------------------------------------------------------------- Seite 74 FUNCTION ">=" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_is_less_or_equal( CONV_UDIGIT_VECTOR(r, length), CONV_UDIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : digit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; FUNCTION ">=" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN is_less_or_equal( CONV_DIGIT_VECTOR(r, length), CONV_DIGIT_VECTOR(l, length) ); END; ------------------------------------------------------------------------------ overloaded "=" functions ----------------------------------------------------------------------------FUNCTION "=" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_equal( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : digit_vector; r : integer CONSTANT length : integer := l'LENGTH; ) RETURN boolean IS Seite 75 BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "=" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "/=" functions ----------------------------------------------------------------------------FUNCTION "/=" ( l : udigit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN unsigned_not_equal( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : udigit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH + 1, r'LENGTH); BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : digit_vector; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH + 1); BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : digit_vector; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : udigit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : integer; r : udigit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : digit_vector; r : integer ) RETURN boolean IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "/=" ( l : integer; r : digit_vector ) RETURN boolean IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN not_equal( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded shift functions ----------------------------------------------------------------------------FUNCTION SHL ( ARG : udigit_vector; COUNT : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_shift_left( CONV_UDIGIT_VECTOR(ARG, ARG'LENGTH), CONV_INTEGER(COUNT) ); END; FUNCTION SHL ( ARG : digit_vector; COUNT : udigit_vector BEGIN RETURN shift_left( CONV_DIGIT_VECTOR(ARG, ARG'LENGTH), CONV_INTEGER(COUNT) ); END; ) RETURN digit_vector IS FUNCTION SHL ( ARG : udigit_vector; COUNT : integer ) RETURN udigit_vector IS BEGIN RETURN unsigned_shift_left( CONV_UDIGIT_VECTOR(ARG, ARG'LENGTH), COUNT ); END; FUNCTION SHL ( ARG : digit_vector; COUNT : integer BEGIN RETURN shift_left( CONV_DIGIT_VECTOR(ARG, ARG'LENGTH), COUNT ); END; ) RETURN digit_vector IS FUNCTION SHR ( ARG : udigit_vector; COUNT : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_shift_right( CONV_UDIGIT_VECTOR(ARG, ARG'LENGTH), CONV_INTEGER(COUNT) ); END; Seite 76 FUNCTION SHR ( ARG : digit_vector; COUNT : udigit_vector ) RETURN digit_vector IS BEGIN RETURN shift_right( CONV_DIGIT_VECTOR(ARG, ARG'LENGTH), CONV_INTEGER(COUNT) ); END; FUNCTION SHR ( ARG : udigit_vector; COUNT : integer ) RETURN udigit_vector IS BEGIN RETURN unsigned_shift_right( CONV_UDIGIT_VECTOR(ARG, ARG'LENGTH), COUNT ); END; FUNCTION SHR ( ARG : digit_vector; COUNT : integer ) RETURN digit_vector IS BEGIN RETURN shift_right( CONV_DIGIT_VECTOR(ARG, ARG'LENGTH), COUNT ); END; ------------------------------------------------------------------------------ conversion functions ----------------------------------------------------------------------------FUNCTION CONV_INTEGER ( ARG : udigit_vector ) RETURN integer IS VARIABLE msb : integer := ARG'LENGTH - 1; ALIAS argv : udigit_vector(msb DOWNTO 0) IS ARG; VARIABLE result : integer := 0; VARIABLE position : integer; BEGIN FOR i IN 0 TO msb LOOP FOR j IN 0 TO (digit_size - 1) LOOP IF (argv(i)(j) = '1') THEN position := (i * digit_size) + j; IF (position > 30) THEN ASSERT FALSE REPORT "ARG value is too large in 'conv_integer', it can not convert in a integer" SEVERITY FAILURE; ELSE result := result + (2**position); END IF; END IF; END LOOP; END LOOP; RETURN result; END; FUNCTION CONV_INTEGER ( ARG : digit_vector ) RETURN integer IS VARIABLE msb : integer := ARG'LENGTH - 1; VARIABLE argv : udigit_vector(msb DOWNTO 0) := To_UDigitVector(ABS(ARG)); VARIABLE result : integer := 0; VARIABLE position : integer; BEGIN FOR i IN 0 TO msb LOOP FOR j IN 0 TO (digit_size - 1) LOOP IF (argv(i)(j) = '1') THEN position := (i * digit_size) + j; IF (position > 30) THEN ASSERT FALSE REPORT "ARG value is too large in 'conv_integer', it can not convert in a integer" SEVERITY FAILURE; ELSE result := result + (2**position); END IF; END IF; END LOOP; END LOOP; IF (ARG(ARG'LEFT)(digit_size - 1) = '1') THEN RETURN -result; ELSE RETURN result; END IF; END; FUNCTION CONV_DIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN digit_vector IS CONSTANT msb : integer := min(ARG'LENGTH, SIZE) - 1; VARIABLE argv : digit_vector(msb DOWNTO 0) := To_DigitVector(ARG); VARIABLE result : digit_vector((SIZE - 1) DOWNTO 0); BEGIN IF ((argv(msb)(digit_size - 1) = '1') AND (msb = (SIZE - 1))) THEN ASSERT FALSE REPORT "failure in 'conv_digit_vector' function, use a larger SIZE" SEVERITY FAILURE; ELSE result := (OTHERS => zero_digit); result(msb DOWNTO 0) := argv; END IF; RETURN result; END; FUNCTION CONV_DIGIT_VECTOR ( ARG : digit_vector; SIZE : integer ) RETURN digit_vector IS CONSTANT msb : integer := min(ARG'LENGTH, SIZE) - 1; ALIAS argv : digit_vector(msb DOWNTO 0) IS ARG; VARIABLE result : digit_vector((SIZE - 1) DOWNTO 0); BEGIN IF (argv(msb)(digit_size - 1) = '1') THEN result := (OTHERS => max_digit); ELSE result := (OTHERS => zero_digit); END IF; result(msb DOWNTO 0) := argv; RETURN result; END; FUNCTION CONV_DIGIT_VECTOR ( ARG : integer; SIZE : integer VARIABLE result : digit_vector((SIZE - 1) DOWNTO 0); ) RETURN digit_vector IS Seite 77 VARIABLE temp : integer := ARG; BEGIN FOR i IN 0 TO (SIZE - 1) LOOP FOR j IN 0 TO (digit_size - 1) LOOP IF ((temp mod 2) = 1) THEN result(i)(j) := '1'; ELSE result(i)(j) := '0'; END IF; IF (temp > 0) THEN temp := temp / 2; ELSE IF (temp > integer'low) THEN temp := (temp - 1) / 2; ELSE temp := temp / 2; END IF; END IF; END LOOP; END LOOP; RETURN result; END; FUNCTION CONV_UDIGIT_VECTOR ( ARG : udigit_vector; SIZE : integer ) RETURN udigit_vector IS CONSTANT msb : integer := min(ARG'LENGTH, SIZE) - 1; ALIAS argv : udigit_vector(msb DOWNTO 0) IS ARG; VARIABLE result : udigit_vector((SIZE - 1) DOWNTO 0); BEGIN result := (OTHERS => zero_digit); result(msb DOWNTO 0) := argv; RETURN result; END; FUNCTION CONV_UDIGIT_VECTOR ( ARG : digit_vector; SIZE : integer ) RETURN udigit_vector IS CONSTANT msb : integer := min(ARG'LENGTH, SIZE) - 1; VARIABLE argv : udigit_vector(msb DOWNTO 0) := To_UDigitVector(ARG); VARIABLE result : udigit_vector((SIZE - 1) DOWNTO 0); BEGIN IF (argv(msb)(digit_size - 1) = '1') THEN ASSERT FALSE REPORT "failure in 'conv_udigit_vector' function, it is not possible to convert a negative digit_vector in a udigit_vector" SEVERITY FAILURE; ELSE result := (OTHERS => zero_digit); result(msb DOWNTO 0) := argv; END IF; RETURN result; END; FUNCTION CONV_UDIGIT_VECTOR ( ARG : integer; SIZE : integer ) RETURN udigit_vector IS VARIABLE result : udigit_vector((SIZE - 1) DOWNTO 0); VARIABLE temp : integer := ARG; BEGIN IF (ARG < 0) THEN ASSERT FALSE REPORT "failure in 'conv_udigit_vector' function, it is not possible to convert a negative integer in a udigit_vector" SEVERITY FAILURE; ELSE FOR i IN 0 TO (SIZE - 1) LOOP FOR j IN 0 TO (digit_size - 1) LOOP IF ((temp mod 2) = 1) THEN result(i)(j) := '1'; ELSE result(i)(j) := '0'; END IF; IF (temp > 0) THEN temp := temp / 2; ELSE IF (temp > integer'low) THEN temp := (temp - 1) / 2; ELSE temp := temp / 2; END IF; END IF; END LOOP; END LOOP; END IF; RETURN result; END; -- pragma synthesis_on END mp_arith; Seite 78 A1.3 DATEI: MP_STD_LOGIC.VHD LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; PACKAGE mp_std_logic IS -- pragma synthesis_off ------------------------------------------------------------------------------ overloaded "/" functions ----------------------------------------------------------------------------FUNCTION "/" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "/" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "/" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; ------------------------------------------------------------------------------ overloaded "mod" functions ----------------------------------------------------------------------------FUNCTION "mod" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "mod" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "mod" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; ------------------------------------------------------------------------------ overloaded "rem" functions ----------------------------------------------------------------------------FUNCTION "rem" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "rem" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "rem" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; ------------------------------------------------------------------------------ overloaded "**" functions ----------------------------------------------------------------------------FUNCTION "**" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector; FUNCTION "**" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector; FUNCTION "**" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector; ------------------------------------------------------------------------------ modular exponentation ----------------------------------------------------------------------------FUNCTION modexp ( b, e, m : std_logic_vector ) RETURN std_logic_vector; -- pragma synthesis_on END mp_std_logic; ----------------------------------------------------------------------------------PACKAGE BODY mp_std_logic IS -- pragma synthesis_off FUNCTION max ( L, R : integer ) RETURN integer IS BEGIN IF L > R THEN RETURN L; ELSE RETURN R; END IF; END; FUNCTION division ( a, b : std_logic_vector ) RETURN std_logic_vector IS CONSTANT q_width : positive := a'LENGTH; VARIABLE quotient, z, bv : UNSIGNED((q_width - 1) DOWNTO 0); BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(b); z := UNSIGNED(a); quotient := (OTHERS => '0'); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN quotient(q_width-i) := '1'; IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; RETURN std_logic_vector(quotient); END; FUNCTION modulo ( a, b : std_logic_vector ) RETURN std_logic_vector IS CONSTANT q_width : positive := a'LENGTH; CONSTANT r_width : positive := b'LENGTH; VARIABLE z : UNSIGNED((q_width - 1) DOWNTO 0); VARIABLE result, bv : UNSIGNED((r_width - 1) DOWNTO 0); BEGIN IF (b = 0) THEN Seite 79 ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(b); z := UNSIGNED(a); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; result := z((r_width - 1) DOWNTO 0); RETURN std_logic_vector(result); END; FUNCTION power ( a, b : std_logic_vector ) RETURN std_logic_vector IS VARIABLE av : unsigned((a'LENGTH - 1) DOWNTO 0); VARIABLE bv : unsigned((b'LENGTH - 1) DOWNTO 0); VARIABLE result : unsigned(((a'LENGTH * b'LENGTH) - 1) DOWNTO 0); BEGIN av := unsigned(a); bv := unsigned(b); result := (OTHERS => '0'); result(0) := '1'; FOR i IN (bv'LENGTH - 1) DOWNTO 0 LOOP result := result * result; IF (av(i) = '1') THEN result := result * av; END IF; END LOOP; RETURN std_logic_vector(result); END; ------------------------------------------------------------------------------ overloaded "/" functions ----------------------------------------------------------------------------FUNCTION "/" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector IS CONSTANT length : integer := max(l'LENGTH, r'LENGTH); BEGIN RETURN division( CONV_STD_LOGIC_VECTOR(unsigned(l), length), CONV_STD_LOGIC_VECTOR(unsigned(r), length) ); END; FUNCTION "/" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN division( CONV_STD_LOGIC_VECTOR(unsigned(l), length), CONV_STD_LOGIC_VECTOR(r, length) ); END; FUNCTION "/" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN division( CONV_STD_LOGIC_VECTOR(l, length), CONV_STD_LOGIC_VECTOR(unsigned(r), length) ); END; ------------------------------------------------------------------------------ overloaded "mod" functions ----------------------------------------------------------------------------FUNCTION "mod" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector IS BEGIN RETURN modulo( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; FUNCTION "mod" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector IS BEGIN RETURN modulo( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(r, l'LENGTH) ); END; FUNCTION "mod" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN modulo( CONV_STD_LOGIC_VECTOR(l, r'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; ------------------------------------------------------------------------------ overloaded "rem" functions ----------------------------------------------------------------------------FUNCTION "rem" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector IS BEGIN RETURN modulo( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; FUNCTION "rem" ( l : std_logic_vector; r : integer CONSTANT length : integer := l'LENGTH; BEGIN ) RETURN std_logic_vector IS Seite 80 RETURN modulo( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(r, l'LENGTH) ); END; FUNCTION "rem" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN modulo( CONV_STD_LOGIC_VECTOR(l, r'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; ------------------------------------------------------------------------------ overloaded "**" functions ----------------------------------------------------------------------------FUNCTION "**" ( l : std_logic_vector; r : std_logic_vector ) RETURN std_logic_vector IS BEGIN RETURN power( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; FUNCTION "**" ( l : std_logic_vector; r : integer ) RETURN std_logic_vector IS BEGIN RETURN power( CONV_STD_LOGIC_VECTOR(unsigned(l), l'LENGTH), CONV_STD_LOGIC_VECTOR(r, l'LENGTH) ); END; FUNCTION "**" ( l : integer; r : std_logic_vector ) RETURN std_logic_vector IS BEGIN RETURN power( CONV_STD_LOGIC_VECTOR(l, r'LENGTH), CONV_STD_LOGIC_VECTOR(unsigned(r), r'LENGTH) ); END; ------------------------------------------------------------------------------ modular exponentation ----------------------------------------------------------------------------FUNCTION modexp ( b, e, m : std_logic_vector ) RETURN std_logic_vector IS ALIAS bv : std_logic_vector((b'LENGTH - 1) DOWNTO 0) IS b; ALIAS ev : std_logic_vector((e'LENGTH - 1) DOWNTO 0) IS e; ALIAS mv : std_logic_vector((m'LENGTH - 1) DOWNTO 0) IS m; VARIABLE result : std_logic_vector((m'LENGTH - 1) DOWNTO 0); BEGIN result := (OTHERS => '0'); result(0) := '1'; FOR i IN (e'LENGTH - 1) DOWNTO 0 LOOP result := (result * result) mod mv; IF (ev(i) = '1') THEN result := (bv * result) mod mv; END IF; END LOOP; RETURN result; END; -- pragma synthesis_on END mp_std_logic; Seite 81 A1.4 DATEI: MP_CRYPT.VHD LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; LIBRARY work; USE work.mp_logic.all; USE work.mp_arith.all; USE work.mp_std_logic.all; PACKAGE mp_crypt IS -- pragma synthesis_off ------------------------------------------------------------------------------ overloaded "mod" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "mod" "mod" "mod" "mod" "mod" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "mod" "mod" "mod" "mod" "mod" "mod" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded "rem" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "rem" "rem" "rem" "rem" "rem" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "rem" "rem" "rem" "rem" "rem" "rem" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ overloaded "**" functions ----------------------------------------------------------------------------FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "**" "**" "**" "**" "**" ( ( ( ( ( l l l l l : : : : : udigit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; r r r r r : : : : : udigit_vector udigit_vector digit_vector udigit_vector digit_vector FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION FUNCTION "**" "**" "**" "**" "**" "**" ( ( ( ( ( ( l l l l l l : : : : : : integer; r : udigit_vector udigit_vector; r : integer integer; r : udigit_vector udigit_vector; r : integer integer; r : digit_vector digit_vector; r : integer ) ) ) ) ) ) ) ) ) ) ) RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN RETURN udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; udigit_vector; udigit_vector; digit_vector; digit_vector; digit_vector; digit_vector; ------------------------------------------------------------------------------ modular exponentation ----------------------------------------------------------------------------FUNCTION modexp ( b, e, m : udigit_vector ) RETURN udigit_vector; FUNCTION modexp ( b, e, m : digit_vector ) RETURN digit_vector; ------------------------------------------------------------------------------ extended functions ----------------------------------------------------------------------------FUNCTION gcd ( a, b : udigit_vector ) RETURN udigit_vector; FUNCTION euclid ( e, phi : udigit_vector ) RETURN udigit_vector; PROCEDURE rnd ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE number : OUT udigit_vector ); FUNCTION prim ( p : udigit_vector; t : integer ) RETURN boolean; PROCEDURE RSA ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE p, q, e, d, n : OUT udigit_vector ); -- pragma synthesis_on END mp_crypt; ----------------------------------------------------------------------------------PACKAGE BODY mp_crypt IS -- pragma synthesis_off FUNCTION max ( L, R : integer ) RETURN integer IS BEGIN IF L > R THEN RETURN L; ELSE RETURN R; END IF; END; FUNCTION remainder ( a, b : digit_vector ) RETURN digit_vector IS CONSTANT q_width : positive := a'LENGTH * digit_size; Seite 82 CONSTANT r_width : positive := b'LENGTH * digit_size; VARIABLE bv : UNSIGNED((r_width - 1) DOWNTO 0); VARIABLE z : UNSIGNED((q_width - 1) DOWNTO 0); VARIABLE result : UNSIGNED((r_width - 1) DOWNTO 0); BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(To_StdLogicVector(ABS(b))); z := UNSIGNED(To_StdLogicVector(ABS(a))); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; result := z((r_width - 1) DOWNTO 0); IF (a(a'LEFT)(digit_size - 1) = '1') THEN RETURN -To_DigitVector(std_logic_vector(result)); ELSE RETURN To_DigitVector(std_logic_vector(result)); END IF; END; FUNCTION modulo ( a, b : digit_vector ) RETURN digit_vector IS CONSTANT q_width : positive := a'LENGTH * digit_size; CONSTANT r_width : positive := b'LENGTH * digit_size; VARIABLE bv : UNSIGNED((r_width - 1) DOWNTO 0); VARIABLE z : UNSIGNED((q_width - 1) DOWNTO 0); VARIABLE abs_result, result : digit_vector((b'LENGTH - 1) DOWNTO 0); BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(To_StdLogicVector(ABS(b))); z := UNSIGNED(To_StdLogicVector(ABS(a))); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; abs_result := To_DigitVector(std_logic_vector(z((r_width - 1) DOWNTO 0))); IF ( (b(b'LEFT)(digit_size - 1) = '1') OR (a(a'LEFT)(digit_size - 1) = '1') ) THEN IF (abs_result = 0) THEN result := abs_result; ELSE IF ( (b(b'LEFT)(digit_size - 1) = '0') AND (a(a'LEFT)(digit_size - 1) = '1') ) THEN result := b - abs_result; ELSE IF ( (b(b'LEFT)(digit_size - 1) = '1') AND (a(a'LEFT)(digit_size - 1) = '1') ) THEN result := 0 - abs_result; ELSE result := b + abs_result; END IF; END IF; END IF; ELSE result := abs_result; END IF; RETURN result; END; FUNCTION power ( a, b : digit_vector ) RETURN digit_vector IS VARIABLE result : digit_vector(((a'LENGTH * b'LENGTH) - 1) DOWNTO 0); VARIABLE av : digit_vector(a'LEFT DOWNTO 0); VARIABLE tdigit, tbit : integer := 0; BEGIN IF (b < 0) THEN ASSERT FALSE REPORT "exponent have to be a positive digit_vector" SEVERITY FAILURE; ELSE result := (OTHERS => zero_digit); result := result + 1; IF (b > 0) THEN av := ABS(a); FOR i IN b'LEFT DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF ((b(i)(j) = '1') AND (tdigit = 0) AND (tbit = 0)) THEN tdigit := i; tbit := j; END IF; END LOOP; END LOOP; Seite 83 IF (tbit /= 0) THEN FOR i IN tbit DOWNTO 0 LOOP result := result * result; IF (b(tdigit)(i) = '1') THEN result := result * av; END IF; END LOOP; tdigit := tdigit - 1; END IF; IF (tdigit >= 0) THEN FOR i IN tdigit DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP result := result * result; IF (b(i)(j) = '1') THEN result := result * av; END IF; END LOOP; END LOOP; END IF; END IF; END IF; IF ((a(0)(0) = '1') AND (a(a'LEFT)(digit_size - 1) = '1')) THEN RETURN -result; ELSE RETURN result; END IF; END; FUNCTION unsigned_modulo ( a, b : udigit_vector ) RETURN udigit_vector IS CONSTANT q_width : positive := a'LENGTH * digit_size; CONSTANT r_width : positive := b'LENGTH * digit_size; VARIABLE bv : UNSIGNED((r_width - 1) DOWNTO 0); VARIABLE z : UNSIGNED((q_width - 1) DOWNTO 0); VARIABLE result : UNSIGNED((r_width - 1) DOWNTO 0); BEGIN IF (b = 0) THEN ASSERT FALSE REPORT "division by zero" SEVERITY FAILURE; ELSE bv := UNSIGNED(To_StdLogicVector(b)); z := UNSIGNED(To_StdLogicVector(a)); FOR i IN 1 TO q_width LOOP IF (z(q_width-1 DOWNTO q_width-i) >= bv) THEN IF (i <= bv'LENGTH) THEN z(q_width-1 DOWNTO q_width-i) := z(q_width-1 DOWNTO q_width-i) - bv(i-1 DOWNTO 0); ELSE z(q_width-i+bv'LENGTH DOWNTO q_width-i) := z(q_width-i+bv'LENGTH DOWNTO q_width-i) - bv(bv'LENGTH-1 DOWNTO 0); END IF; END IF; END LOOP; END IF; result := z((r_width - 1) DOWNTO 0); RETURN To_UDigitVector(std_logic_vector(result)); END; FUNCTION unsigned_power ( a, b : udigit_vector ) RETURN udigit_vector IS VARIABLE result : udigit_vector(((a'LENGTH * b'LENGTH) - 1) DOWNTO 0); VARIABLE tdigit, tbit : integer := 0; BEGIN result := (OTHERS => zero_digit); result := result + 1; IF (b > 0) THEN FOR i IN b'LEFT DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP IF ((b(i)(j) = '1') AND (tdigit = 0) AND (tbit = 0)) THEN tdigit := i; tbit := j; END IF; END LOOP; END LOOP; IF (tbit /= 0) THEN FOR i IN tbit DOWNTO 0 LOOP result := result * result; IF (b(tdigit)(i) = '1') THEN result := result * a; END IF; END LOOP; tdigit := tdigit - 1; END IF; IF (tdigit >= 0) THEN FOR i IN tdigit DOWNTO 0 LOOP FOR j IN (digit_size - 1) DOWNTO 0 LOOP result := result * result; IF (b(i)(j) = '1') THEN result := result * a; END IF; END LOOP; END LOOP; END IF; END IF; RETURN result; END; ------------------------------------------------------------------------------ overloaded "mod" functions ----------------------------------------------------------------------------FUNCTION "mod" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l, l'LENGTH), Seite 84 END; CONV_UDIGIT_VECTOR(r, r'LENGTH) ); FUNCTION "mod" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "mod" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "mod" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, (r'LENGTH) + 1) ); END; FUNCTION "mod" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "mod" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(l, length) ); END; FUNCTION "mod" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "mod" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH + 1; BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "mod" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH + 1; BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "mod" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : integer := r'LENGTH; BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "mod" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : integer := l'LENGTH; BEGIN RETURN modulo( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "rem" functions ----------------------------------------------------------------------------FUNCTION "rem" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l ,l'LENGTH), CONV_UDIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "rem" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "rem" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l, (l'LENGTH + 1)), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "rem" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, (r'LENGTH + 1)) ); END; FUNCTION "rem" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "rem" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : positive := r'LENGTH; Seite 85 BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "rem" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : positive := l'LENGTH; BEGIN RETURN unsigned_modulo( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "rem" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : positive := r'LENGTH + 1; BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l ,length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "rem" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : positive := l'LENGTH + 1; BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l ,length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "rem" ( l : integer; r : digit_vector ) RETURN digit_vector IS CONSTANT length : positive := r'LENGTH; BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l ,length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "rem" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : positive := l'LENGTH; BEGIN RETURN remainder( CONV_DIGIT_VECTOR(l ,length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ overloaded "**" functions ----------------------------------------------------------------------------FUNCTION "**" ( l : udigit_vector; r : udigit_vector ) RETURN udigit_vector IS BEGIN RETURN unsigned_power( CONV_UDIGIT_VECTOR(l, l'LENGTH), CONV_UDIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "**" ( l : udigit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN power( CONV_DIGIT_VECTOR(l, l'LENGTH + 1), CONV_DIGIT_VECTOR(r, r'LENGTH + 1) ); END; FUNCTION "**" ( l : udigit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN power( CONV_DIGIT_VECTOR(l, l'LENGTH + 1), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "**" ( l : digit_vector; r : udigit_vector ) RETURN digit_vector IS BEGIN RETURN power( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH + 1) ); END; FUNCTION "**" ( l : digit_vector; r : digit_vector ) RETURN digit_vector IS BEGIN RETURN power( CONV_DIGIT_VECTOR(l, l'LENGTH), CONV_DIGIT_VECTOR(r, r'LENGTH) ); END; FUNCTION "**" ( l : integer; r : udigit_vector ) RETURN udigit_vector IS CONSTANT length : positive := r'LENGTH; BEGIN RETURN unsigned_power( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "**" ( l : udigit_vector; r : integer ) RETURN udigit_vector IS CONSTANT length : positive := l'LENGTH; BEGIN RETURN unsigned_power( CONV_UDIGIT_VECTOR(l, length), CONV_UDIGIT_VECTOR(r, length) ); END; FUNCTION "**" ( l : integer; r : udigit_vector ) RETURN digit_vector IS CONSTANT length : positive := r'LENGTH + 1; BEGIN RETURN power( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "**" ( l : udigit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : positive := l'LENGTH + 1; BEGIN RETURN power( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "**" ( l : integer; r : digit_vector CONSTANT length : positive := r'LENGTH; BEGIN ) RETURN digit_vector IS Seite 86 RETURN power( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; FUNCTION "**" ( l : digit_vector; r : integer ) RETURN digit_vector IS CONSTANT length : positive := l'LENGTH; BEGIN RETURN power( CONV_DIGIT_VECTOR(l, length), CONV_DIGIT_VECTOR(r, length) ); END; ------------------------------------------------------------------------------ modular exponentation ----------------------------------------------------------------------------FUNCTION modexp ( b, e, m : udigit_vector ) RETURN udigit_vector IS VARIABLE result : std_logic_vector((m'LENGTH * digit_size - 1) DOWNTO 0); BEGIN result := modexp( To_StdLogicVector(b), To_StdLogicVector(e), To_StdLogicVector(m) ); RETURN To_UDigitVector(result); END; FUNCTION modexp ( b, e, m : digit_vector ) RETURN digit_vector IS VARIABLE result : std_logic_vector((m'LENGTH * digit_size - 1) DOWNTO 0); BEGIN result := modexp( To_StdLogicVector(b), To_StdLogicVector(e), To_StdLogicVector(m) ); RETURN To_DigitVector(result); END; ------------------------------------------------------------------------------ gcd function ----------------------------------------------------------------------------FUNCTION gcd ( a, b : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := max(a'LENGTH, b'LENGTH); VARIABLE av, bv, r : udigit_vector((length - 1) DOWNTO 0); BEGIN av := (OTHERS => zero_digit); bv := (OTHERS => zero_digit); IF (a >= b) THEN av((a'LENGTH - 1) DOWNTO 0) := a; bv((b'LENGTH - 1) DOWNTO 0) := b; ELSE av((b'LENGTH - 1) DOWNTO 0) := b; bv((a'LENGTH - 1) DOWNTO 0) := a; END IF; WHILE (bv /= 0) LOOP r := av mod bv; av := bv; bv := r; END LOOP; RETURN av; END; ------------------------------------------------------------------------------ extended euclidean function ----------------------------------------------------------------------------FUNCTION euclid ( e, phi : udigit_vector ) RETURN udigit_vector IS CONSTANT length : integer := max(e'LENGTH, phi'LENGTH); VARIABLE a, b, r, q, result : udigit_vector((length - 1) DOWNTO 0) := (OTHERS => zero_digit); VARIABLE x, y, s : digit_vector(length DOWNTO 0); VARIABLE st : digit_vector((2 * (length + 1) - 1) DOWNTO 0); BEGIN a((phi'LENGTH - 1) DOWNTO 0) := phi; b((e'LENGTH - 1) DOWNTO 0) := e; x := (OTHERS => zero_digit); y := (OTHERS => zero_digit); y(0) := one_digit; q := a / b; r := a mod b; WHILE (r > 0) LOOP st := x - (q * y); IF (st >= 0) THEN s := st mod phi; ELSE s := phi - (-st mod phi); END IF; x := y; y := s; a := b; b := r; q := a / b; r := a mod b; END LOOP; IF (b /= result ELSE s := y result END IF; 1) THEN := (OTHERS => zero_digit); mod phi; := To_UDigitVector(s(length - 1 DOWNTO 0)); RETURN result; END; ------------------------------------------------------------------------------ random nuber generation ----------------------------------------------------------------------------PROCEDURE rnd ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE number : OUT udigit_vector ) IS VARIABLE m : udigit_vector(length DOWNTO 0) := (OTHERS => zero_digit); VARIABLE a : udigit_vector((length) DOWNTO 0) := (OTHERS => zero_digit); Seite 87 VARIABLE temp : udigit_vector((length + seed'LENGTH) DOWNTO 0); VARIABLE result : udigit_vector((length) DOWNTO 0); BEGIN -- linear-congruence generator m(length)(0) := '1'; a(length/2)(0) := '1'; a(0)(0) := '1'; temp := (a * seed) + 1; -result := ((a * seed) + 1) mod m; result := (OTHERS => zero_digit); result((length - 1) DOWNTO 0) := temp((length - 1) DOWNTO 0); number(number'length-1 downto length) := (OTHERS => zero_digit); seed(seed'length-1 downto length) := (OTHERS => zero_digit); number((length - 1) DOWNTO 0) := (result((length - 1) DOWNTO 0)); seed((length - 1) DOWNTO 0) := result((length - 1) DOWNTO 0); END; ------------------------------------------------------------------------------ primaly test ----------------------------------------------------------------------------FUNCTION prim ( p : udigit_vector; t : integer ) RETURN boolean IS -- "n is prim !" (true or false) VARIABLE a, m, z, j, p1, p2 : udigit_vector((p'LENGTH - 1) DOWNTO 0); VARIABLE b : integer; VARIABLE seed : udigit_vector((p'LENGTH - 1) DOWNTO 0); VARIABLE plength, i : integer; BEGIN -- Miller-Rabin test -- error probability is (1/4)**t plength := p'LENGTH; WHILE ((p(plength - 1) = 0) AND (p /= 0)) LOOP plength := plength - 1; END LOOP; seed := p; IF (p(0)(0) = '0') THEN RETURN FALSE; END IF; p1 := p - 1; p2 := p - 2; b := 0; FOR i IN 0 TO (p'LENGTH - 1) LOOP FOR j IN 0 TO (digit_size - 1) LOOP IF ((p1(i)(j) = '1') AND (b = 0)) THEN b := ((i*digit_size) + j); END IF; END LOOP; END LOOP; m := p1 / (2**b); FOR i IN 1 TO t LOOP rnd(plength, seed, a); WHILE ((a > p2) OR (a < 2)) LOOP rnd(plength, seed, a); END LOOP; z := modexp(a, m, p); --(a**m) mod p; IF ((z /= 1) AND (z /= p1)) THEN j := (OTHERS => zero_digit); j := j + 1; WHILE ((j < b) AND (z /= p1)) LOOP z := modexp(z, CONV_UDIGIT_VECTOR(2, z'LENGTH), p); --(z**2) mod p; IF (z = 1) THEN RETURN FALSE; END IF; j := j + 1; END LOOP; IF (z /= p1) THEN RETURN FALSE; END IF; END IF; END LOOP; RETURN TRUE; END; ------------------------------------------------------------------------------ RSA-key generation ----------------------------------------------------------------------------PROCEDURE RSA ( CONSTANT length : IN integer; VARIABLE seed : INOUT udigit_vector; VARIABLE p, q, e, d, n : OUT udigit_vector ) IS VARIABLE pv, qv, ev, dv, nv : udigit_vector((length - 1) DOWNTO 0) := (OTHERS => zero_digit); VARIABLE phi : udigit_vector((length - 1) DOWNTO 0); VARIABLE pqlength : integer := (length /2); VARIABLE test, test2 : boolean; CONSTANT security : integer := 4; VARIABLE nv_temp, phi_temp : udigit_vector(((2 * length) - 1) DOWNTO 0); VARIABLE pv1, qv1 : udigit_vector((length - 1) DOWNTO 0); BEGIN -- p generation and prim test test := TRUE; WHILE (test) LOOP pv := (OTHERS => zero_digit); rnd(pqlength + 2, seed, pv); pv(0)(0) := '1'; pv(pqlength + 1)(digit_size - 1) := '1'; IF (prim(pv, security)) THEN test := FALSE; END IF; END LOOP; Seite 88 -- q generation and prim test test := TRUE; WHILE (test) LOOP rnd(pqlength - 2, seed, qv); qv(0)(0) := '1'; qv(pqlength - 3)(digit_size - 1) := '1'; IF (prim(qv, security) AND (qv /= pv)) THEN test := FALSE; END IF; END LOOP; nv_temp := pv * qv; nv := nv_temp((nv'LENGTH - 1) DOWNTO 0); pv1 := pv - 1; qv1 := qv - 1; phi_temp := pv1 * qv1; phi := phi_temp((phi'LENGTH - 1) DOWNTO 0); test := TRUE; WHILE (test) LOOP -- e generation test2 := TRUE; WHILE (test2) LOOP rnd(length/4, seed, ev); IF ((gcd(ev, phi) = 1) AND (ev < nv)) THEN test2 := FALSE; END IF; END LOOP; -- d generation with euclidean algorithm dv := euclid(ev, phi); IF ((gcd(dv, phi) = 1) AND (gcd(dv, ev) = 1) AND (dv < nv)) THEN test := FALSE; END IF; END LOOP; -- return p := pv; q := qv; e := ev; d := dv; n := nv; END; -- pragma synthesis_on END mp_crypt; Seite 89 B Die Quellen für das C-Interfaces B1 Das Addiererbeispiel B1.1 DATEI: ADDER.VHD LIBRARY synopsys; USE synopsys.attributes.all; LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY adder IS GENERIC ( delay : time := 5 ns ); PORT ( a : IN integer; b : IN integer; c : OUT integer ); END adder; -- Ausgangsverzögerung ARCHITECTURE CLI OF adder IS ATTRIBUTE FOREIGN OF CLI : ARCHITECTURE IS "SYNOPSYS:CLI"; ATTRIBUTE ATTRIBUTE ATTRIBUTE ATTRIBUTE CLI_ELABORATE CLI_EVALUATE CLI_CLOSE CLI_ERROR OF OF OF OF CLI CLI CLI CLI : : : : ARCHITECTURE ARCHITECTURE ARCHITECTURE ARCHITECTURE IS IS IS IS "adder_open"; "adder_eval"; "adder_close"; "adder_error"; ATTRIBUTE CLI_PIN OF a : SIGNAL IS CLI_EVENT; ATTRIBUTE CLI_PIN OF b : SIGNAL IS CLI_EVENT; BEGIN END CLI; B1.2 DATEI: ADDER_COMP.VHD LIBRARY ieee; USE ieee.std_logic_1164.all; PACKAGE adder_comp IS COMPONENT adder GENERIC ( delay : time := 5 ns ); PORT ( a : IN integer; b : IN integer; c : OUT integer ); END COMPONENT; END; B1.3 DATEI: ADDER.H #define CHECK_ERRNO exit(1) ;} if(cli_errno) { (void) printf("file %s, line %d\n",__FILE__,__LINE__); cliPrintError((char *)0); B1.4 DATEI: ADDER.C #include <stdio.h> #include "adder.h" #include "cli.h" typedef struct { cliPID pidA; cliPID pidB; cliPID pidC; cliGID gidDelay; cliAFTER gvCDelay; } ADDER_INSTANCE_DATA; /* /* /* /* /* Pin ID für "a" */ Pin ID für "b" */ Pin ID für "c" */ ID für "delay" */ Ausgangsverzögerung für C */ void adder_open(did, iid) cliDID did; cliIID iid; { ADDER_INSTANCE_DATA *adder_idata; cliVALUE gvDelay; /* Speicher für die Datenstruktur reservieren */ adder_idata = (ADDER_INSTANCE_DATA *) cliAllocMem(sizeof(ADDER_INSTANCE_DATA)); Seite 90 /* Pins und Generics auf die Datenstruktur abbilden */ adder_idata->pidA = cliPortName2PID(did, "A"); CHECK_ERRNO; adder_idata->pidB = cliPortName2PID(did, "B"); CHECK_ERRNO; adder_idata->pidC = cliPortName2PID(did, "C"); CHECK_ERRNO; adder_idata->gidDelay = cliGenericName2GID(did, "DELAY"); CHECK_ERRNO; /* Ausgansverzögerung setzen */ cliGetGenericValue(did, iid, adder_idata->gidDelay, &gvDelay); CHECK_ERRNO adder_idata->gvCDelay.delaytype = INERTIAL; adder_idata->gvCDelay.delay.low = gvDelay.value.time.low; adder_idata->gvCDelay.delay.high = 0; adder_idata->gvCDelay.delay.timebase = gvDelay.value.time.timebase; /* die Datenstruktur sichern */ cliSaveInstanceData(did, iid, (void *) adder_idata); CHECK_ERRNO; } void adder_close(did, iid) cliDID did; cliIID iid; { ADDER_INSTANCE_DATA *adder_idata; /* Datenstruktur wiederherstellen */ adder_idata = (ADDER_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); } /* reservierten Speicher für die Datenstruktur freigeben */ if(adder_idata != (ADDER_INSTANCE_DATA *)0) { cliFreeMem((void *) adder_idata); } void adder_eval(did, iid, ppid, np) cliDID did; cliIID iid; cliPID *ppid; /* Zeiger auf die Pin-IDs (Pinliste) */ int np; /* Anzahl Pins in der Pinliste */ { ADDER_INSTANCE_DATA *adder_idata; cliVALUE svA; cliVALUE svB; cliVALUE svC; /* Datenstruktur wiederherstellen */ adder_idata = (ADDER_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); cliGetPortValue(did, iid, adder_idata->pidA, &svA); CHECK_ERRNO; cliGetPortValue(did, iid, adder_idata->pidB, &svB); CHECK_ERRNO; svC.typemark = CLI_TYPE_INTEGER; svC.length = 0; svC.value.integer = svA.value.integer + svB.value.integer; } cliScheduleOutput(did, iid, adder_idata->pidC, &svC, &adder_idata->gvCDelay); CHECK_ERRNO; void adder_error(did, iid, level) cliDID did; cliIID iid; int level; { char *s; if(level == 0) s = "WARNUNG"; else s = "FEHLER"; } (void) printf("%s gefunden mit (%d,%d)\n",s,did,iid); cliPrintError("ADDER FEHLER"); Seite 91 B2 Die Meßfunktion B2.1 DATEI: BENCHMARK.VHD LIBRARY synopsys; USE synopsys.attributes.all; LIBRARY ieee; USE ieee.std_logic_1164.all; USE work.benchmark_comp.all; ENTITY benchmark IS PORT ( ready : IN std_logic; prtime : OUT string(1 TO 30) ); END; ARCHITECTURE CLI OF benchmark IS ATTRIBUTE FOREIGN OF CLI : ARCHITECTURE IS "Synopsys:CLI"; ATTRIBUTE ATTRIBUTE ATTRIBUTE ATTRIBUTE CLI_ELABORATE CLI_EVALUATE CLI_ERROR CLI_CLOSE OF OF OF OF CLI CLI CLI CLI : : : : ARCHITECTURE ARCHITECTURE ARCHITECTURE ARCHITECTURE IS IS IS IS "benchmark_open"; "benchmark_eval"; "benchmark_error"; "benchmark_close"; ATTRIBUTE CLI_PIN OF ready : SIGNAL IS CLI_ACTIVE; BEGIN END; CONFIGURATION cfg_benchmark OF benchmark IS FOR CLI END FOR; END cfg_benchmark; B2.2 DATEI: BENCHMARK_COMP.VHD LIBRARY ieee; USE ieee.std_logic_1164.all; PACKAGE benchmark_comp IS COMPONENT benchmark PORT ( ready : IN std_logic; prtime : OUT string(1 TO 30) ); END COMPONENT; END; B2.3 DATEI: BENCHMARK.H #define CHECK_ERRNO exit(1); } if(cli_errno) { (void) printf("file %s, line %d\n",__FILE__,__LINE__); cliPrintError((char *)0); B2.4 DATEI: BENCHMARK.C #include #include #include #include #include <stdio.h> <sys/types.h> <sys/timeb.h> "benchmark.h" "cli.h" typedef struct { cliPID pidReady; cliPID pidPrTime; cliAFTER afterPROP; } BENCHMARK_INSTANCE_DATA; double Time_F(s) int s; { static struct timeb tstart, tend; long i; double ret; switch(s) { case 2: printf("\n--------------------- ENDE -------------------------------\n\n"); ftime(&tend); i = (long)tend.millitm - (long)tstart.millitm; ret = ((double)(tend.time - tstart.time)) + ((double)i) / 1000.0; printf("Rechenzeit: %21.3f Sekunden\n\n--------------------- ENDE -------------------------------\n\n", ret); break; Seite 92 case 3: printf("\n--------------------- START ------------------------------\n\n"); ret = (double)0; ftime(&tstart); break; } default: break; return (ret); } void benchmark_open(did, iid) cliDID did; cliIID iid; { BENCHMARK_INSTANCE_DATA *benchmark_idata; benchmark_idata = (BENCHMARK_INSTANCE_DATA *) cliAllocMem(sizeof(BENCHMARK_INSTANCE_DATA)); benchmark_idata->pidReady = cliPortName2PID(did,"READY"); CHECK_ERRNO; benchmark_idata->pidPrTime = cliPortName2PID(did,"PRTIME"); CHECK_ERRNO; cliSaveInstanceData(did,iid,(void *) benchmark_idata); CHECK_ERRNO; } void benchmark_close(did, iid) cliDID did; cliIID iid; { BENCHMARK_INSTANCE_DATA *benchmark_idata; benchmark_idata = (BENCHMARK_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); if(benchmark_idata != (BENCHMARK_INSTANCE_DATA *)0) { cliFreeMem((void *) benchmark_idata); } } void benchmark_eval(did, iid, ppid, np) cliDID did; /* definition ID */ cliIID iid; /* instance ID */ cliPID *ppid; /* pointer to pin IDs (pin list) */ int np; /* number of pins in pin list */ { int ready_value = 0; int i; double prtime; unsigned char temp_string[31]; unsigned char temp; cliVALUE svReady; cliVALUE svPrTime; BENCHMARK_INSTANCE_DATA *benchmark_idata; benchmark_idata = (BENCHMARK_INSTANCE_DATA *) cliRestoreInstanceData(did,iid); cliAssert(np == 1); cliAssert(ppid[0] == benchmark_idata->pidReady); cliGetPortValue(did, iid, benchmark_idata->pidReady, &svReady); CHECK_ERRNO; cliAssert(svReady.typemark == CLI_TYPE_STD_LOGIC); ready_value = svReady.value.std_logic; prtime = Time_F(ready_value); sprintf(temp_string, "%21.3f Sekunden", prtime); /* string umdrehen für vhdl */ for(i = 0; i < 15; i++) { temp = temp_string[i]; temp_string[i] = temp_string[29-i]; temp_string[29-i] = temp; } /* neu */ svPrTime.typemark = CLI_TYPE_STRING; svPrTime.length = 30; svPrTime.direction = TO; svPrTime.value.string = temp_string; cliScheduleOutput(did, iid, benchmark_idata->pidPrTime, &svPrTime, &benchmark_idata->afterPROP); CHECK_ERRNO; } void benchmark_error(did, iid, level) cliDID did; cliIID iid; Seite 93 { int level; char *s; if(level == 0) s = "warning"; else s = "fatal error"; (void) printf("%s encountered with (%d,%d)\n",s,did,iid); cliPrintError("benchmark_error"); } Seite 94