Rechnerstrukturen Bericht zu dem Vortrag über Java-Prozessoren Name: Matthias Pohl Semester: E7EI Mat.Nr.: 11382 Seite 1 von 15 Inhalt 1. Einleitung ................................. 1.2 Javaspezifikationen ....................... 1.3 Beispiele für Javaprozessoren ............. 3 3 5 2. Details zum aj-100 ......................... 6 2.1 Prinzipielle Funktionsweise der JVM ....... 6 2.2 Aufbau des aj-100 ......................... 7 2.3 Echtzeiterweiterungen des aj-100 .......... 12 3. Anwendungsbeispiele / Fazit ............... 13 3.1 Quellen ................................... 15 Seite 2 von 15 1. Einleitung Java ist zu einer bedeutenden Programmiersprache herangewachsen und hat sich weitgehend etabliert. Doch neben vielen Vorteilen gibt es auch einige Nachteile, die bei der Verwendung von Java vorhanden sind. Einer der gewichtigsten dürfte sicher die Performance sein. Da die Java-Virtual-Machine (JVM)[1] auf jedem Rechner emuliert werden muss, entstehen durch diese Interpretierung des Bytecodes enorme Leistungsverluste. Mittlerweile ist dies in dem Desktop PCBereich nicht mehr ein großes Problem, da die heute erhältlichen Rechner Leistung im Überfluss mitbringen. Doch im Embedded-Bereich und dort besonders im mobilen Sektor ist notwendig, aufgrund der eingeschränkten Möglichkeiten, die durch notwendige Stromsparmaßnahmen auftreten, andere Wege zu gehen. Statt einer software-seitigen Übersetzung des Bytecodes werden CPU's entwickelt, die diesen direkt verstehen können. 1.2 Javaspezifikationen Bild 1.2.1: Java-Spezifikationen im Überblick[8] Sun erkannte die Notwendigkeit von zusätzlichen Java-Spezifikationen für Eingebettete Systeme und schuf zusätzlich zur Java2-StandardEdition die Untermengen CDC (Connected Device Configuration)und CLDC (Connected Limited Device Configuration). Die CDC sowie CLDC werden auch unter dem Begriff Java-Microedition (J2ME)[2] zusammengefasst. Die Anforderungen der beiden Untermengen CDC und CLDC unterscheiden sich im Wesentlichen in ihrem Speicherbedarf: CDC: min. 256kB RAM und 512kB ROM CLDC: 128kB-512kB Speicher (RAM und ROM) CDC ist hauptsächlich für Settop-Boxen und stationäre Geräte gedacht. Für CLDC ist zusätzlich der Batteriebetrieb für den mobilen Einsatz spezifiziert. Wie man aus Bild 2.1 erkennen kann ragen die Spezifikationen CDC und CLDC etwas aus der J2SE heraus. Dieser Teil sieht zusätzliche Möglichkeiten wie direkte Hardwarezugriffe und spezielle GrafikFunktionen für kleine LCD-Displays vor. Seite 3 von 15 Bild 1.2.2: Einsparungen bei der J2ME am Beispiel der CLDC Einsparungen bei der J2ME sind z.B. : - Wegfall der JNI keine Mechanismen zur Klassenverifizierung keine Objektfinalisierung durch den Garbage-collector teilweise Wegfall von einigen Grunddatentypen aufgrund fehlender FPU's in mobilen Prozessoren weitere Einsparungen in java.net, java.io und java.util Geändert wurden: - die AWT-Klassen Klassen für Netzwerkanbindungen (Generic Connection Framework) sowie Klassen für Datenbankzugriffe (Record Management System) Diese neuen Funktionen werden unter einem neuen Namespace (java.microediton) zusammengefasst. Seite 4 von 15 1.3 Beispiele für Javaprozessoren Tabelle 1.3.1 Zeigt eine kleine Auswahl der derzeitig erhältlichen Javaprozessoren. Produkt Hersteller Sprache(n) aj-100 Jazelle MB86799 JSTAR Lightfoot picojava-2 aJile ARM Fujitsu Nazomi DCTL Sun native Java Multi Language Native Java(Picojava2)[3] native Java Multi Language native Java Tabelle 1.3.1: Javaprozessoren am Markt Die letzten drei Produkte sind dabei nur CPU-Core-Spezifikationen, die CPU-Hersteller einkaufen können, um ihren eigenen CPU's JavaFunktionalität hinzuzufügen, so wie offensichtlich Fujitsu dies getan hat. Die Begriffe in der Spalte Sprache(n) sind so zu verstehen: Native Java: kann ausschließlich nativen Bytecode verstehen Multi Language: kann Bytecode und zusätzlich eigene Mnemonics verstehen, Beispiel ARM Jazelle (dieser versteht neben seinem nativen Risc-Befehlssatz zusätzlich Java-bytecode). Multi-language-Prozessoren sollen die Akzeptanz bei den Entwicklern im Embedded-Bereich fördern, da von diesen die Programmiersprache 'C' immer noch weitgehend bevorzugt wird. Zum Leistungsvergleich der erhältlichen Prozessoren wird gebräuchlicherweise ein Benchmark der Firma 'Pendragon Software Corporation' namens "Embedded CaffeineMark 3.0"[14] herangezogen. Name Mhz CaffeineMarks/Mhz mW/Mhz aJile aj-100 100 2,75 <1 Fujitsu MB86799 66 9,4 5,4 ARM Jazelle 200 5 0,45 Tabelle 1.3.2: Ergebnisse des Embedded CaffeineMark 3.0 Bei diesem Benchmark werden fünf Tests durchgeführt: - Sieb des Eratosthenes (Algorithmus zum finden von Primzahlen) - Logiktest (prüft Geschwindigkeit von bedingten Sprüngen) - Schleifendurchlauftest (Sortieraufgaben und Sequenzgenerierung) - Methodenaufrufe (rekursive Methodenaufrufe) - Float (simuliert 3d-rotation eines Objektes um einen Punkt) Je öfter die Tests in einer vorgegebenen Zeit durchlaufen werden können, desto höher die Zahl der CaffeineMarks. Zum Schluss werden alle Einzelergebnisse zu einem Gesamtwert zusammengefasst. Die, in der Tabelle aufgeführten, Ergebnisse (entnommen aus dem Artikel "Silicon variety vanquishes embedded-Java taboos"[6]) sind also somit mit Vorsicht zu genießen. Seite 5 von 15 Um eine Standardisierung der Benchmarks in diesem Bereich zu erreichen hat sich das "Embedded Microprocessor Benchmark Consortium" oder kurz: "EEMBC" zusammengefunden. Die, mehr als 40 Mitglieder aus der Chip-Industrie und Compiler-Hersteller, die dieser Organisation angehören, haben sich das Ziel gesetzt, bestehende Benchmarks zu prüfen und zu zertifizieren. In Zukunft sollen selber Standard-Benchmarks entwickelt werden, die nicht so leicht durch bestimmte Compileroptimierungen oder ähnliches ausgetrickst werden können und mehr Typische Alltagsszenarien beinhalten. 2. Details zum aj-100 In diesem Bericht wird nun exemplarisch der aj-100 von aJile[4] näher erläutert. 2.1 Prinzipielle Funktionsweise der JVM Vorweg eine Bemerkung zur prinzipiellen Funktionsweise der JVM. Diese ist ein Stackbasierter Prozessor. Den Unterschied zum bekannten registerbasierten Prozessor soll folgendes Beispiel klären: Registerbasierte Addition Stackbasierte Addition (JVM) ADD R3, R2, R1 ILOAD_1 ILOAD_2 IADD ISTORE_3 Bei der registerbasierten Addition werden die Register R1 und R2 direkt addiert und in R3 gespeichert. Im Gegensatz dazu werden die beiden Operanden bei der stackbasierten Addition erst von den lokalen Variablen aus auf den Stack geschoben (iload_1 , iload_2) und dann mit iadd addiert. Bei jedem Methodenaufruf wird ein Array für die lokalen Variablen der Methode auf den Stack gelegt. Die lokalen Variablen können dann mit den entsprechenden Anweisungen geladen (ILOAD_n) bzw. gespeichert (ISTORE_n) werden. 'n' gibt hierbei den Offset in dem Array der lokalen Variablen an. Die parameterlose Additionsoperation kann die Operanden in den lokalen Variablen also nicht direkt benutzten, da immer nur die obersten beiden Operanden vom Stack genommen, addiert und das Ergebnis wieder oben auf den Stack gespeichert wird. Von dort verfrachtet der letzte Befehl, istore_3, das Ergebnis in die lokale Variable Nummer 3. Seite 6 von 15 2.2 Aufbau des aj-100 Der aj-100 ist eigentlich mehr ein Mikrocontroller als nur eine CPU. Er bietet diverse zusätzliche Hardwareeinheiten wie UARTschnittstellen, Timer, einige General-purpose-Schnittstellen sowie zahlreiche Funktionen für Echtzeitfunktionalitäten. Gerade diese Echtzeitunterstützung ist im Embedded-Bereich ein willkommenes Feature, da kein Echtzeitbetriebsystem mehr benötigt wird. Diese Erweiterung des Befehlssatzes ist problemlos möglich, da für den Opcode 8Bit vorgesehen aber, laut Spezifikation, nur ca. 230 Befehle vorhanden sind. Der aj-100 sieht auch vor, eigene Befehle als Micro-code in das eingebaute RAM laden zu können. Somit kann z.B. eine häufig benutzte Java-Methode wie java.lang.Math.sqrt() als Opcode integriert werden. Der Compiler versucht in der Regel, zeitaufwendige Anweisungen automatisch durch Micro-code zu ersetzen. Neben dem aj-100 existiert noch der aj-80[5] aus derselben Reihe. Dies ist im Prinzip nur eine abgespeckte Version des aj-100, der mit einem 8Bit-breiten statt einem 32Bit-Datenbus an externen Speicher angeschlossen ist, sowie nur bis 80Mhz getaktet werden kann. Der aj-100 kann im Gegensatz dazu bis 100Mhz getaktet werden. Der aj-100 basiert, wie auch der aj-80, auf dem JEM2-Core, der von Rockwell-Collins entwickelt wurde. Bereits Mitte der 90er-Jahre hatte Rockwell-Collins den JEM1 fertig entwickelt aber nie veröffentlicht, da die Funktionalität nicht so gut für EchtzeitApplikationen geeignet war. Der JEM2-core wurde exklusiv von der Firma aJile lizenziert. Da die JVM stackbasiert ist, wählte man bei der Entwicklung ebenfalls einen stabasierten Ansatz. Der aj-100 beherrscht bis auf zwei, alle Bytecodes. Die fehlenden beiden sind aThrow (Exception werfen) und multianewarray (multidimensionales Array anlegen). Diese beiden Befehle wurden aufgrund ihrer nicht deterministischen Natur (bezogen auf die Ausführungszeit) nicht integriert, da dies die Echtzeitfunktionalität nicht mehr voll gewährleisten würde. Stattdessen werden diese Befehle, falls sie dennoch benötigt werden, über Traps an Software weitergeleitet. Bei den ARM Jazelle-CPU's hingegen, werden nur ca. 140 Opcodes in Hardware realisiert und der Rest (ca. 94 Opcodes) müssen in Software nachgebildet werden. Seite 7 von 15 Bild 2.2.1: Blockschaltbild des aj-100 In dem Blockschaltbild des aj-100 kann man im unteren Bereich links einige Serielle Schnittstellen erkennen. Neben den Standard UARTSchnittstellen gibt es noch ein Serial Peripheral Interface, welches zum Anschluss von beispielsweise A/D-Wandlern dient. Auf der rechten unteren Seite sind einige Timer für generellen Einsatz zu erkennen, die nicht von den eingebauten Echtzeitfunktionen belegt sind. Alle diese Komponenten sind über einen Peripherial Bus mittels einer Bridge an den Prozessorbus angeschlossen. Oben rechts sieht man die JTAG-Schnittstelle, welche zum programmieren und testen des Systems dient. Darauf folgt der JEM2Core, der weiter unten erläutert wird. Die 16kByte RAM sind für die bereits erwähnten eigenen Opcodes vorgesehen, die als Micro-Code dort abgelegt werden. Außerdem befindet sich dort noch der Kernel für die Verwaltung der Echzeitfunktionen sowie Einstellungen für die Kontrolle mehrerer JVM's. Die folgenden 32kByte RAM sind für den Stack vorgesehen, da die JEM2, wie erwähnt, ein Stackbasiertes Design hat. Rechts daneben ist der Schaltkreis für die Kontrolle von mehreren JVM's zu sehen. Dieser ermöglicht die Existenz von zwei JVM's gleichzeitig. Seite 8 von 15 Bild 2.2.2: Multiple JVM Controller (MJM) Dabei wird Zeitscheibenbasiert (timesliced) zwischen beiden JVM's umgeschaltet. Dabei hat jede JVM ihren eigenen Thread Manager, ihre eigenen Timer sowie eigens zugewiesene Interrupts (im ganzen System sind über 30 vorhanden). Somit verliert keine der Beiden JVM's ihre EchtzeitFähigkeiten. Ebenso kann eine Memory-Protection vorgesehen und konfiguriert werden. Dabei wird in der MJM festgelegt auf welche Speicherbereiche des linearen Speichers, welche JVM exklusiv zugreifen darf. Der restliche Speicher kann global alloziert werden und ermöglicht somit eine Kommunikation zwischen beiden JVM's über Semaphoren. Eine Kommunikation ist zusätzlich über die Standard Java-NetworkingAPI möglich. Seite 9 von 15 Bild 2.2.2: Blockschaltbild des JEM2-Cores (Quelle: [4]) Bild 2.2.2 zeigt ein Blockschaltbild des JEM2-Cores. Deutlich kann man die typischen Merkmale eines einfachen Prozessors erkennen. Der Prozessorbus transportiert die zu dekodierenden Anweisungen. Dabei wird der Opcode im Instruction-Register abgelegt. Wenn die aktuelle Anweisung im Parser abgearbeitet worden ist, gelangt die neue Anweisung in den Parser, der nun mit Hilfe des Micro-codeControl-Stores und dem MicroPC (Micro-Instruction-Programmcounter) die Microinstructions erzeugt, im Microinstruction-Register ablegt, ausführt und somit den Aktuellen Befehl im Parser Schritt für Schritt abarbeitet. Eventuelle Daten (z.B. aus lokalen Variablen) werden in das DataRegister geladen und stehen somit für Berechnungen zur Verfügung. Dafür ist eine 32bit-ALU mit einem Schieberegister vorhanden. Der Micro-code-Control-Store ist in 2 Bereiche unterteilt. Der eine ist als ROM realisiert und beinhaltet alle Standard Bytecodes, die Floating Point Funktionalität sowie die Debugger-Control, also die Steuerung für die JTAG-Schnittstelle. Der andere Bereich ist vorgesehen für den Echzeit-Kernel, die Steuerung des MJM (Multiple JVM Controller) sowie der Speicherung des Microcodes, der Selbstdefinierten Opcodes. Auffällig ist das Registerfile, welches aus 24 32Bit-Registern besteht. Dies mag bei einer stackbasierten CPU seltsam erscheinen und leider werden über die art der Verwendung keinerlei Angaben gemacht. Vermutlich werden diese Register aber dazu genutzt, den oberen Teil des Stacks, ähnlich einem Cache-Speicher, zu halten. Seite 10 von 15 Dies ermöglicht erhebliche Performancevorteile, sowie zusätzliche Techniken, wie Instruction-Folding. Bild 2.2.3: Funktionsweise des Instruction-Folding Im Bild 2.2.3 ist das Ablaufschema des sogenannten InstructionFolding zu sehen, so wie es auch fester Bestandteil des PicojavaCore ist. Wie bereits in Kapitel 2.1 erwähnt wird bei jedem Methodenaufruf ein Array für die lokalen Variablen der Methode auf dem Stack abgelegt. Dieser Bereich liegt in dem Bild unterhalb der etwas dickeren schwarzen Linie. Oberhalb beginnt der Stack für die Methode, welcher nach oben wächst. Normalerweise läuft eine Addition in der stackbasierten Java-Welt wie im oberen Teil des Bildes ab. Die beiden zu addierenden Variablen werden nacheinander auf den Stack geschoben, die Anweisung iadd nimmt die obersten beiden Operanden vom Stack, addiert diese und legt das Ergebnis wiederum oben auf den Stack. Danach nimmt die Anweisung istore_3 das Ergebnis vom Stack und speichert es in einer lokalen Variablen. Diese Vorgehensweise benötigt ganze 4 Takte. Mittels Instruction-Folding, wie im unteren Teil des Bildes zu erkennen, ist es möglich, diese Operation in einem 'Rutsch' (1 Takt) durchzuführen. Dazu muss die CPU allerdings eine solche Abfolge von Befehlen erkennen, um sie anschließend zu einem Befehl zusammenfassen zu können. Dabei werden wie bei einer registerbasierten CPU die Lokalen Variablen direkt geladen, verarbeitet und gespeichert. Seite 11 von 15 2.3 Echtzeiterweiterungen des aj-100 Der aj-100 bietet einige zusätzliche Befehle für Echtzeitfunktionalität, die ein Echtzeitbetriebssystem weitgehend überflüssig machen, welches nur zusätzlich Speicher belegen würde. So sind z.B. einige Befehle für Threads in Micro-Code gefasst. Als Beispiele sind zu nennen: - yield() gibt laufwilligen Threads eine Chance, zu starten. (Falls keine Threads an den Startlöchern stehen, fährt der Thread, der yield() erteilt hat, einfach fort.) Diese Funktion ist in der aj-100 besonders schnell gelöst und benötigt nur ca. 300 ns. - join() Wird sie an einen Thread geschickt, bedeutet das: Der aktuelle Thread ist bereit, ewig zu warten, bis der benachrichtigte Thread mit seiner run()-Methode fertig ist. - wait() (und ihre zwei Varianten mit einem Timeout) veranlassen den aktiven Thread, so lange zu warten, bis eine Bedingung erfüllt ist. Die Methode notify() (bzw. notifyAll()), die innerhalb einer synchronized-Methode aufgerufen werden muß, weckt den aktiven bzw. alle Threads auf, - synchronized Das Schlüsselwort synchronized fordert Java auf, den Codeblock atomar durchzuführen. D.h. das dieser Codeblock von keinem anderen Thread unterbrochen werden darf. Somit lässt sich voraussagen, wie viel Zeit einzelne Threads in Java für die Ausführung benötigen. Dies ist eine wichtige Voraussetzung für die Entwicklung von Echtzeit-Schedulern. Eine weitere problematische Sache für Echtzeitsysteme ist der Garbage-Collector. Bei aJile hat man sich für einen einfachen Standard mark-and-sweep Garbage-Collector als Softwarelösung entschieden. Bei diesem Verfahren (mark-and-sweep) wird der Speicher periodisch nach Objekten durchsucht, die von laufenden Programmen aus noch erreicht werden können. Die so gefundenen Objekte werden markiert. Wenn alle erreichbaren Objekte markiert wurden, kann vom restlichen Speicher – in dem wahrscheinlich noch einige nicht erreichbare Objekte sind – angenommen werden, dass dieser frei ist. Der Garbage Collector geht dann den Speicher durch, merkt sich sämtlichen freien Speicher und fügt ihn wieder zum "freien Speicherpool" hinzu. Das 'mark-and-sweep'-Verfahren ist normalerweise nicht das Optimum für Echtzeitanwendungen. Verfahren wie 'Generational Garbage Collection' (GGC), die einen speziellen Speicherbereich für kurzlebige Objekte vorsehen, welcher öfter gescannt wird, sind Seite 12 von 15 besser geeignet. Bei dem aj-100 wird aber ein anderer Trick angewandt. Der Garbage-collector im aj-100 ist als synchronized Thread implementiert, um sicher zu stellen, dass der Heap, der gerade durchforstet wird, nicht in einen inkonsistenten Zustand gerät. Weiterhin kann ein Bereich des Heap's von einem Thread alloziert werden der nicht vom Garbage-Collector durchforstet wird. Dadurch kann der Garbage-Collector sehr schnell von einem solchen Thread unterbrochen (preempted) werden um diesen möglichen Echtzeit-Thread ausführen zu können, der natürlich nur auf seinen eigenen Speicher, der nicht vom Garbage-Collector bearbeitet wird, zugreifen darf. 3. Anwendungsbeispiele / Fazit Der Einsatz von Javaprozessoren wird auf dem Mobilen Markt in Zukunft sicher zunehmen. Gerade auch in Mobilfunktelefonen neuerer Generationen finden bereits jetzt Java-Anwendungen. Zusätzliche Echtzeitfunktionen werden viele Anwendungen im Embedded-Bereich besonders bei Regelung- und Steuerungsaufgaben gut unterstützen. Systronix Jstamp [7] Der JStamp ist eine kleine Mikro-Controllerplatine, welche neben dem zentralen aj-80-Microcontroller noch einen Spannungsregler sowie 512kByte SRAM und 512kByte Flash-Speicher beinhaltet. Dieser Controller ist besonders für Regelungs- und Steuertechnik gut geeignet. Dort kann er aufgrund seiner sehr kompakten Maße z.B. in Robotern eingesetzt werden. Seite 13 von 15 aJile aj-WRP100 Der aj-WRP100 ähnelt in seiner Funktionalität dem Handspring-PDA. Neben normalen Funktionen eines PDA's kann das Gerät ebenso als GSMMobilfunktelefon genutzt werden, hat einen mp3-Decoder onboard, beherbergt Email-Client, Webbrowser, hat diverse Schnittstellen wie USB, ein Grosses Farbdisplay (240*320), 8MB Flash-ROM und 8MB SRAM. Seite 14 von 15 3.1 Quellen/Referenzen - [1]"The JavaTM Virtual Machine Specification, Second Edition", Sun Microsystems, Inc., http://java.sun.com/docs/books/vmspec/ - [2]"JavaTM 2 Platform, Micro Edition (J2ME TM) Documentation", Sun Microsystems, Inc., http://java.sun.com/j2me/docs/ - [3]"PicoJava II Datasheet", Sun Microsystems, http://solutions.sun.com/embedded/databook/pdf/datasheets/8054634-02.pdf - [4]"aJ-100 ReferenceManual v2.1", aJile, 06.12.2002 www.ajile.com/downloads/aJ-100ReferenceManual.pdf - [5]"aJ-80 Datasheet, aJile", 04.09.2001, www.ajile.com/downloads/aJ-80Datasheet.pdf - [6]"Silicon variety vanquishes embedded-Java taboos", EDN Access, 01.02.2001, www.einsite.net/esec/Article_61880.htm - [7]JStamp, Systronix, www.jstamp.com - [8]"Low-Power Direct-Execution JavaTM Microprocessors for RealTime and Networked Embedded Applications", David S. Hardin, http://java.isavvix.com/whitepapers/1014166430514.pdf - [9]"Java™ 2 Platform, Micro Edition: Connected Device Configuration and Foundation Profile", Hinkmond Wong, David Hardin, Kimmo Loytana, JavaOne 2001, http://java.sun.com/javaone/javaone2001/pdfs/1602.pdf - [10]"Secure Reconfigurable Computing", Dr. David W. Jensen, 10.10.1999, http://klabs.org/richcontent/MAPLDCon99/Presentations/F3_Jensen _S.ppt - [11]"Hardware Accelerated Java™ Technology", Takashi Aoki, Takeshi Eto, JavaOne 2001, http://java.sun.com/javaone/jp2001/pdfs/549.pdf - [12]"ARM (Advance RISC Machine)", Pitipund Lorchirachoonkul, Uchot Jitpaisarnsook, http://www.cpe.ku.ac.th/~pom/courses/204521/report/2001/Jazelle .ppt - [13]"Jazelle Whitepaper", ARM (Advance RISC Machine), http://www.arm.com/arm/documentation?OpenDocument - [14] Embedded CaffeineMark 3.0, Pendragon Software, 1997, http://www-sor.inria.fr/~java/tools/cmkit/info.html Seite 15 von 15