-
Die
vorliegende Erfindung bezieht sich auf das Gebiet der Datenverarbeitungssysteme.
Genauer gesagt, bezieht sich die vorliegende Erfindung auf Datenverarbeitungssysteme,
die einen Prozessorkern mit einer Registerbank haben, welche Befehle
eines ersten Befehlssatzes ausführt,
die in Verbindung mit einem Befehlsübersetzer verwendet werden,
welcher in der Weise betreibbar ist, dass er Befehle eines zweiten
Befehlssatzes in Befehle des ersten Befehlssatzes übersetzt.
-
Es
ist bekannt, Datenverarbeitungssysteme bereitzustellen, welche mehrere
Befehlssätze
unterstützen.
Ein Beispiel derartiger Systeme sind die von ARM Limited in Cambridge,
England hergestellten Thumb enable-Prozessoren, die sowohl 16-Bit
Thumb-Befehle als auch 32-Bit ARM-Befehle ausführen können. Sowohl die Thumb-Befehle
als auch die ARM-Befehle führen
Operationen (wie zum Beispiel mathematische Manipulationen, Laden,
Speichern, etc.) mit Operanden durch, die in Registern des Prozessorkerns
gespeichert sind, welche durch Registerfelder innerhalb der Befehle
angegeben werden. Es wird eine beträchtliche Mühe für die Entwicklung von Compilern
aufgewendet, die in der Lage sind, Registerressourcen des Prozessorkerns in
effizienter Weise zu verwenden, um Befehlsströme zu erzeugen, die schnell
ablaufen.
-
Eine
weitere Klasse von Befehlssätzen
sind diejenigen, die einen Stapelansatz verwenden, um die Operanden,
auf welche sie einwirken, zu speichern und zu handhaben. Der Stapel
(stack) innerhalb eines solchen Systems kann eine Folge von Operandenwerten
speichern, die in dem Stapel in einer bestimmten Reihenfolge angeordnet
werden und dann aus dem Stapel in der umgekehrten Reihenfolge entnommen
werden. Der als letzter in dem Stapel anzuordnende Operand wird
also typischerweise der erste Operand sein, der aus dem Stapel entfernt
wird. Prozessoren auf Stapelbasis können einen Block von Speicherelementen
bereitstellen, in welche Stapeloperanden geschrieben werden können und
aus welchen Stapeloperanden in Verbindung mit einem Stapelzeiger
gelesen werden können,
welcher die aktuelle „oberste" Position innerhalb
des Stapels anzeigt. Der Stapelzeiger gibt einen Bezugspunkt innerhalb
des Stapelspeichers an, welches der letzte Stapeloperand ist, der
in dem Stapel gespeichert werden muss und von welchem aus weitere
Zugriffe auf den Stapel aufgerufen werden bzw. ausgehen können. Beträchtliche
Mühe ist
auch verwendet worden auf die Herstellung von Compilern, die in
der Lage sind, in effizienter Weise die Stapel-Hardwareressourcen
innerhalb solcher Prozessorsysteme auf Stapelbasis auszunutzen.
-
Ein
spezielles Beispiel eines Befehlssatzes auf Stapelbasis ist der
Befehlssatz der virtuellen Java-Maschine, wie er durch Sun Microsystems,
Inc. angegeben wird. Die Java-Programmiersprache
versucht, eine Umgebung bereitzustellen, in welcher Computersoftware,
die in Java geschrieben ist, auf vielen verschiedenen Hardware-Verarbeitungsplattformen
ausgeführt
werden kann, ohne dass man die Java-Software ändern muss.
-
Es
ist ein dauerhaftes Ziel für
Datenverarbeitungssysteme, dass sie in der Lage sein sollten, die
Computersoftware, die sie steuert, so schnell wie möglich auszuführen. Maßnahmen,
welche die Geschwindigkeit erhöhen
können,
mit welcher Computersoftware ausgeführt werden kann, sind in hohem
Maß wünschenswert.
-
Beispiele
bekannter Systeme für
die Übersetzung
zwischen Befehlssätzen
und andere Hintergrundinformation findet man in den folgenden Druckschriften:
US-A-5,805,895 ;
US-A-3,955,180 ;
US-A-5,970,242 ;
US-A-5,619,665 ;
US.A.-5,826,089 ;
US-A-5,925,123 ,
UA-A-5,875, 336 ,
US-A-5,937,193 ,
US-A-5,953,520 ,
US-A-6,021,469 ,
US-A-5,568,646 ,
US-A-5,758,115 ,
US-A-5,367,685 , IBM Technical
Disclosure Bulletin, März 1988,
S. 308–309; „System/370
Emulator Assist Processor For a Reduced Instruction Set Computer" IBM Technical Disclosure
Bulletin, Juli 1986, S. 546–549; „Full Function
Series/I Instruction Set Emulator", IBM Technical Disclosure Bulletin,
März 1994,
S. 605–606; "Real-Time CISC Architecture
HW Emulator On a RISC Processor",
IBM Technical Disclosure Bulletin, März 1998, S. 272; "Performance Improvement
Using An EMULATION Control Block",
IBM Technical Disclosure Bulletin, Januar 1995, S. 537–540; "Fast Instruction
Decode For Code Emulation an Reduces Instruction Set Computer/Cycles
Systems", IBM Technical
Disclosure Bulletin, Februar 1993, S. 231–234; "High Performance Dual Architecture Processor", IBM Technical Disclosure
Bulletin, August 1989, S. 40–43; "System/370 I/O Channel
Program Channel Command Word Perfetch", IBM Technical Disclosure Bulletin,
Juni 1985, S. 305–306; "Fully Microcode-Controlled
Emulation Architecture", IBM
Technical Disclosure Bulletin, März
1992, S. 3074–3076; "Op Code and Status
handling For Emulation", IBM
Technical Disclosure Bulletin, August 1982, S. 954–956; "On-Chip Microcoding
of a Microprocessor With Most Frequently Used Instructions of Large
System and Primitives Suitable for Coding Remaining Instructions", IBM Technical Disclosure
Bulletin, April 1983, S. 5576–5577; "Emulation Instruction", das Buch ARM System
Architecture von S. Furber; das Buch Computer Architecture: A Quantitative
Approach by Hennessy and Patterson; und das Buch The Java Virtual
Machine Specification von Tim Lindholm und Frank Yellin 1. und 2.
Edition.
-
Die
WO 0034844 offenbart einen
Java-Beschleuniger in Hardware, welcher Teile der virtuellen Java-Maschine
in Hardware implementiert. Der Hardware-Beschleuniger übersetzt
Java-Bytecodes auf
Stapelbasis in aktive bzw. ursprüngliche
CPU-Befehle auf Registerbasis und speichert Java-Stapeloperanden
in einer Registerdatei, die mit der CPU verbunden ist, indem eine
Abbildung bzw. Zuordnung zwischen Positionen in dem Stapel und den
Registern verwendet wird.
-
Unter
einem Aspekt gesehen, stellt die vorliegende Erfindung eine Vorrichtung
zum Verarbeiten von Daten bereit, wobei die Vorrichtung aufweist:
Einen
Prozessorkern mit einer Registerbank, welche eine Mehrzahl von Registern
enthält
und in der Weise betreibbar ist, dass sie Operationen mit Registeroperanden
durchführt,
welche in den Registern gehalten werden, wie es in Befehlen eines
ersten Befehlssatzes angegeben ist, und
einen Befehlsübersetzer,
der in der Weise betreibbar ist, dass er Befehle eines zweiten Befehlssatzes
in Übersetzerausgangssignale übersetzt,
welche Befehlen des ersten Befehlssatzes entsprechen, wobei Befehle
des zweiten Befehlssatzes Operationen spezifizieren, die mit Stapeloperanden
ausgeführt
werden sollen, welche in einem Stapel gehalten werden, wobei
der
Befehlsübersetzer
in der Weise betreibbar ist, dass er einen Satz von Registern in
der Registerbank zuweist, damit diese Operanden von einem Teil des
Stapels halten,
der Befehlsübersetzer
eine Mehrzahl von Zuordnungszuständen
hat, in welchen unterschiedliche Register innerhalb des Satzes von
Registern entsprechende Stapeloperanden von unterschiedlichen Positionen
innerhalb des Bereiches des Stapels halten, und dadurch gekennzeichnet,
dass der Befehlsübersetzer
in der Weise betreibbar ist, dass er zwischen den Zuordnungszuständen in
Abhängigkeit
von Operationen wechselt, die Stapeloperanden, welche in dem Satz
von Registern gehalten werden, hinzufügen oder entfernen, und
wobei
der Befehlsübersetzer
eine Mehrzahl von Befehlsschablonen zum Übersetzen von Befehlen aus
dem zweiten Befehlssatz in Befehle aus dem ersten Befehlssatz verwendet,
und
wobei ein Befehl aus dem zweiten Befehlssatz, welcher einen
oder mehrere Stapeloperanden enthält, eine Befehlsschablone hat,
die einen oder mehrere Befehle aus dem ersten Befehlssatz aufweist
und in welcher Registeroperanden den Stapeloperanden in Abhängigkeit
von einem aktuell angenommenen Zuordnungszustand des Befehlsübersetzers
zugeordnet werden.
-
Die
Erfindung stellt für
die Ausführung
von Befehlen einen zweiten, stapelbasierten Befehlssatz bereit, indem
dieser in Befehle eines ersten, registerbasierten Befehlssatzes
für die
Ausführung
auf einem Prozessorkern übersetzt
wird. Die Erfindung stellt einen Satz von Registern in der Registerbank
bereit, um Stapeloperanden von einem Teil des Stapels zu halten.
Dies ist effektiv eine Cache-Speicherung von Stapeloperanden innerhalb
des Prozessorkerns, um die Ausführung
zu beschleunigen. Weiterhin hat der Befehlsübersetzer, um die den Stapeloperanden
zugewiesenen Register effizienter zu nutzen, eine Mehrzahl unterschiedlicher
Zuordnungszustände,
in welchen unterschiedliche Register entsprechende Stapeloperationen
aus unterschiedlichen Positionen innerhalb des cache-gespeicherten
Abschnittes des Stapels halten. Der Abbildungs- bzw. Zuordnungszustand
wird in Abhängigkeit
von Operationen verändert,
die Stapeloperationen, welche in dem Satz Registern gehalten werden,
der für
den Stapel verwendet wird, hinzufügen, und entfernen, und zwar
in einer Weise, die eine Funktion ähnlich der eines Stapelzeigers
innerhalb eines Stapels gewährleistet.
Dieser Ansatz vermindert die Zusatzlast an Verarbeitung, die erforderlich
ist, um eine stapelartige Speicherung innerhalb der Register eines
registerbasierten Prozessors bereitzustellen.
-
Der
Befehlsübersetzer
ist zweckmäßigerweise
so ausgelegt, dass er Befehlsschablonen zum Übersetzen zwischen dem zweiten
Befehlssatz und dem ersten Befehlssatz verwendet. Derartige Befehlsschablonen
stellen ein vorteilhaftes Maß an
Flexibilität
in der Art und Weise der Zuordnung bereit, die zwischen den Befehlen
des zweiten Befehlssatzes und typischerweise mehreren Befehlen des
ersten Befehlssatzes erreicht werden kann.
-
In
bevorzugten Ausführungsformen
der Erfindung stellt der Befehlsübersetzer
Zuordnungszustände bereit,
welche Operanden stapeln, die dem ersten Satz von Registern hinzugefügt oder
von diesem entfernt werden, ohne Stapeloperationen zwischen Registern
innerhalb des Satzes von Registern zu verschieben.
-
Dieses
bevorzugte Merkmal hat zur Folge, dass die Zuordnungszustände so verwendet
werden, dass sie das Erfordernis vermeidet, irgendwelche Stapeloperationen
zwischen Registern zu verschieben, wenn sie in diesen Registern
gespeichert wurden, und dadurch eine beträchtliche Zusatzlast an Verarbeitung
vermeidet, die anderenfalls auftreten würde, wenn man versuchen würde, ein
System bereitzustellen, in welchem Stapeloperanden, die eine bestimmte
Position innerhalb des Stapels haben, immer in vorbestimmten Registern
zu finden wären
bzw. zu finden sein müssten.
-
Während es
sich versteht, dass der Satz von Registern Stapeloperanden aus irgendeiner
Position innerhalb des Stapels halten könnte, ist es in hohem Maß wünschenswert,
dass der Satz von Registern einen oberen Abschnitt des Stapels einschließlich des
obersten Stapeloperanden speichert. Stapelbasierte Verarbeitungssysteme
müssen
oft auf Stapeloperanden zugreifen, die gerade erst in dem Stapel
gespeichert wurden und demzufolge ist das Halten dieser Stapeloperanden
innerhalb von Registern, auf welche schnell zugegriffen werden kann,
sehr vorteilhaft. Weiterhin macht die Tatsache, dass die obersten
Stapeloperanden in den Registern gehalten werden, die Fähigkeit
des Befehlsübersetzers,
sich zwischen verschiedenen Zuordnungszuständen zu bewegen, in hohem Maß vorteilhaft,
da die oberen Stapeloperanden sich oftmals verändern, wenn Stapeloperanden
auf den Stapel geschoben oder von dem Stapel abgestoßen werden.
-
Während es
möglich
ist, dass der Bereich des Stapels, der nicht in den Registern gehalten
wird, mit verschiedenen Hardware-Anordnungen bereitgestellt werden
könnte,
umfasst in bevorzugten Ausführungsformen
der Erfindung der Stapel eine Mehrzahl von adressierbaren Speicherpositionen,
welche Stapeloperanden halten.
-
Einen
adressierbaren Speicher findet man häufig in Verarbeitungssystemen
zusammen mit Mechanismen, wie zum Beispiel ausgeklügelten Cache-Speichern,
um einen Hochgeschwindigkeitszugriff auf die Daten innerhalb eines
solchen adressierbaren Speichers zu ermöglichen.
-
Es
versteht sich, dass die Register des Prozessorkerns, welche der
Speicherung von Stapeloperanden gewidmet sein können, begrenzt sind, aufgrund
des Erfordernisses, andere Register für Funktionen bereitzustellen,
wie zum Beispiel für
die Verwaltung der Übersetzung
von Befehlen aus dem zweiten Befehlssatz in den ersten Befehlssatz
und die Emulierung anderer Steuerwerte, wie zum Beispiel eines variablen
Zeigers oder eines Zeigers auf einen Konstantenvorrat, die man in
einem stapelbasierten Verarbeitungssystem vorfinden kann. In diesem
Kontext können
Stapeloperationen, welche aus dem Satz von Registern überlaufen,
welcher für
die Sta peloperandenspeicherung vorgesehen ist, innerhalb des adressierbaren
Speichers gehalten werden.
-
In
komplementärer
Weise sind viele Verarbeitungssysteme auf der Basis von Hochgeschwindigkeitsregistern
dafür ausgelegt,
Vorgänge
bzw. Handhabungen der Datenverarbeitung nur mit Datenwerten durchzuführen, die
in Registern gehalten werden, um Probleme zu vermeiden, die aufgrund
der relativ langen Speicherzugriffslatenzzeit und dergleichen auftreten
können.
In diesem Kontext sieht die Erfindung vor, dass Stapeloperationen
vor der Verwendung immer in den Satz von Registern geladen werden.
-
Es
versteht sich, dass der Befehlsübersetzer
eine breite Vielfalt von Formen annehmen könnte. Insbesondere könnte der
Befehlsübersetzer
als speziell angepasste Hardware zum Übersetzen oder Kompilieren des
zweiten Befehlssatzes oder als Software, welche den Prozessorkern
steuert, um ähnliche Übersetzungs- oder
Kompilierungsfunktionen auszuführen,
bereitgestellt werden. Eine Mischung verschiedener Ansätze könnte ebenfalls
in zweckmäßiger Weise
verwendet werden. Im Fall eines Softwareübersetzers können die Ausgangssignale
des Übersetzers übersetzte
Befehle des ersten Befehlssatzes sein, die durch den Softwareübersetzer
erzeugt wurden.
-
Insbesondere
kann ein Hardwareübersetzer
bereitgestellt werden, um eine Hochgeschwindigkeitsübersetzung
einfacher, häufig
auftretender Befehle innerhalb des zweiten Befehlssatzes zu erreichen,
während eine
Softwareübersetzung
verwendet werden könnte
für komplexe
oder weniger häufig
auftretende Befehle aus dem zweiten Befehlssatz, die von der Art
sind, dass die Hardware-Zusatzlast der Bereitstellung einer solchen Übersetzung
nicht praktisch oder effizient wäre.
-
Eine
besonders bevorzugte Art, auf welche die Zuordnungszustände des
Befehlsübersetzers
gesteuert werden können,
ist die Bereitstellung einer Mehrzahl von Zustandsbits, welche die
Anzahl von Stapeloperanden anzeigen, die in dem Satz von Registern
gehalten werden, sowie eine Mehrzahl von Zustandsbits, welche anzeigen,
welche Register den obersten Stapeloperanden bzw. den obersten Teil
der Stapeloperanden halten.
-
Während es
sich versteht, dass der zweite Befehlssatz viele verschiedene Formen
annehmen könnte, ist
die Erfindung insbesondere zweckmäßig bei Ausführungsformen,
bei welchen der zweite Befehlssatz der Befehlssatz einer virtuellen
Java-Maschine ist.
-
Unter
einem anderen Aspekt betrachtet stellt die vorliegende Erfindung
ein Verfahren zum Verarbeiten von Daten unter Verwendung eines Prozessorkerns
bereit, der eine Registerbank hat, die eine Mehrzahl von Registern
enthält,
und der in der Weise betreibbar ist, dass er Operationen mit Registeroperanden
ausführt, die
in den Registern gehalten werden, wie es in Befehlen eines ersten
Befehlssatzes angegeben ist, wobei das Verfahren die Schritte aufweist:
Übersetzen
von Befehlen eines zweiten Befehlssatzes in Übersetzerausgangssignale, welche
Befehlen aus dem ersten Befehlssatz entsprechen, und zwar unter
Verwendung einer Mehrzahl von Befehlsschablonen, wobei Befehle aus
dem zweiten Befehlssatz Operationen beschreiben, die mit in einem
Stapel gehaltenen Operanden ausgeführt werden sollen,
Zuweisen
eines Satzes von Registern in der Registerbank, um Stapeloperanden
aus einem Abschnitt des Stapels zu halten,
Übernehmen einer Mehrzahl von
Zuordnungszuständen,
in denen unterschiedliche Register innerhalb des Satzes von Registern
entsprechende Stapeloperanden aus unterschiedlichen Positionen innerhalb
des Bereichs des Stapels halten, wobei ein Befehl aus dem zweiten
Befehlssatz, welcher einen oder mehrere Stapeloperanden enthält, eine
Befehlsschablone hat, die einen oder mehrere Befehle aus dem ersten
Befehlssatz aufweist, in welcher Registeroperanden den Stapeloperationen
in Abhängigkeit
von einem aktuell übernommenen
Zuordnungszustand des Befehlsübersetzers
zugeordnet werden, und
Wechseln zwischen Zuordnungszuständen in
Abhängigkeit
von Operanden, die Stapeloperationen, welche in dem Satz von Registern
gehalten werden, hinzufügen
oder entfernen.
-
Die
vorliegende Erfindung stellt auch ein Computerprogrammprodukt bereit,
welches durch ein Computerprogramm zum Steuern eines allgemeinen
Vielzweckcomputers gemäß den oben
beschriebenen Techniken speichert. Das Computerprogrammprodukt könnte eine
Vielfalt von Formen, wie zum Beispiel die einer Diskette, einer
Kompaktdisk (CD) oder einer aus einem Computernetzwerk heruntergeladenen
Computerdatei annehmen.
-
Es
werden nun lediglich beispielhaft Ausführungsformen der Erfindung
unter Bezug auf die zugehörigen
Zeichnungen beschrieben, von denen:
-
1 und 2 schematisch
beispielhaft Befehlspipeline-Anordnungen wiedergeben,
-
3 eine
Anordnung eines Heranholzustandes in Einzelheiten veranschaulicht,
-
4 schematisch
das Lesen von nicht nativen (nicht ursprünglichen) Befehlen variabler
Länge aus gepufferten
Befehlsworten innerhalb des Heranholzustandes veranschaulicht,
-
5 schematisch
ein Datenverarbeitungssystem für
die Ausführung
sowohl von nativen Prozessorkernbefehlen als auch von Befehlen zeigt,
welche eine Übersetzung
erfordern,
-
6 für eine Sequenz
von beispielhaften Befehlen und Zuständen die Inhalte der Register,
die für die
Speicherung von Stapeloperanden verwendet werden, die Zuordnungszustände und
die Beziehung zwischen Befehlen, welche Übersetzung erfordern und nativen
bzw. ursprünglichen
Befehlen veranschaulicht,
-
7 schematisch
die Ausführung
eines nicht nativen Befehls als eine Folge nativer Befehle veranschaulicht,
-
8 eine
Flussdiagramm ist, welches die Art und Weise zeigt, auf welche der
Befehlsübersetzer
in einer Weise arbeitet, welche die Interrupt-Latenzzeit für übersetzte
Befehle erhält,
-
9 schematisch
die Übersetzung
von Java-Bytecodes in ARM-Opcodes unter Verwendung von Hardware-
und Softwaretechniken veranschaulicht,
-
10 schematisch
den Steuerstrom zwischen einem Übersetzer
auf Hardwarebasis, einem Übersetzer
auf Softwarebasis und einer Planung auf Softwarebasis zeigt,
-
11 und 12 eine
andere Art und Weise der Steuerung von Planungsvorgängen unter
Verwendung eines Ansatzes auf Zeitgeberbasis zeigen, und
-
13 ein
Signaldiagramm ist, welches die Signale veranschaulicht, welche
die Operation des Schaltkreises nach 12 steuert.
-
1 zeigt
eine erste, beispielhafte Befehlspipeline 30 eines Typs,
wie er für
die Verwendung in einem System auf ARM-Prozessorbasis geeignet ist.
Die Befehlspipeline weist eine Heranholungsstufe 32, eine
Decodierstufe 34 für
native Befehle (ARM/Thumb-Befehle), eine Ausführungsstufe 36, eine
Speicherzugriffsstufe 38 und eine Rückschreibestufe 40 auf.
Die Ausführungsstufe 36,
die Speicherzugriffstufe 38 und die Schreibsteuerstufe 40 sind
im wesentlichen konventioneller Natur. Stromabwärts von der Heranholstufe 32 und
stromaufwärts
von der Decodierstufe 34 für native Befehle ist eine Befehlsübersetzerstufe 42 vorgesehen.
Die Befehlsübersetzerstufe 42 ist
eine endliche Zustandsmaschine bzw. endlicher Automat, welcher Java-Bytecodebefehle einer
variablen Länge
in native ARM-Befehle übersetzt.
Die Befehlsübersetzerstufe 32 ist
in der Lage, mehrstufige Operationen auszuführen, wodurch ein einzelner
Java-Bytecodebefehl
eine Folge von ARM-Befehlen erzeugen kann, die entlang des verbleibenden
Teils der Befehlspipeline 30 zugeführt werden, um die durch den
Java-Bytecodebefehl angegebene Operation auszuführen. Einfache Java-Bytecodebefehle
erfordern möglicherweise
nur einen einzelnen ARM-Befehl, um ihre Operation durchzuführen, wohingegen
kompliziertere Java-Bytecodebefehle
oder Bedingungen, in welchen der Zustand des umgebenden Systems
dieses verlangt, mehrere ARM-Befehle erforderlich machen können, um
die durch den Java-Bytecodebefehl
angegebene Operation bereitzustellen. Diese mehrstufige Operation
findet stromabwärts
von der Heranholstufe 32 statt und dementsprechend wird
beim Heranholen mehrerer übersetzter
ARM-Befehle oder Java-Bytecodes aus einem Speichersystem keine Energie
aufgewendet. Die Java-Bytecodebefehle werden in dem Speichersystem
in konventioneller Weise gespeichert, so dass im Speichersystem
keine zusätzlichen
Einschränkungen auferlegt
werden, um den Vorgang der Java-Bytecodeübersetzung zu unterstützen.
-
Wie
dargestellt, ist die Befehlsübersetzerstufe 42 mit
einem Umgehungspfad versehen. Wenn die Befehlspipeline 30 nicht
in einem Befehlsübersetzungsbetrieb
arbeitet, so kann sie die Befehlsübersetzerstufe umgehen und
in einer im wesentlichen unveränderten
Weise arbeiten, um eine Decodierung der ursprünglichen bzw. nativen Befehle
bereitzustellen.
-
In
der Befehlspipeline 30 ist die Befehlsübersetzerstufe 42 so
dargestellt, dass sie Übersetzerausgangssignale
erzeugt, die entsprechende ARM-Befehle vollständig repräsentieren und die über einen
Multiplexer an den Decoder 34 für den nativen Befehl weitergeleitet
werden. Der Befehlsübersetzer 42 erzeugt
außerdem
einige zusätzliche
Steuersignale, die an den nativen Befehlsdecoder 34 weitergeleitet
werden können. Einschränkungen
des Bitraumes innerhalb der nativen Befehlscodierung können dem
Bereich von Operanden, die durch die nativen Befehle spezifiziert
werden können,
Beschränkungen
auferlegen. Diese Beschränkungen gelten
aber nicht notwendigerweise für
die nicht nativen Befehle. Zusätzliche
Steuersignale werden bereitge stellt, um einen zusätzlichen
Befehl weiterzuleiten, der Signale spezifiziert, die aus den nicht
nativen Befehlen abgeleitet wurden, welche man nicht innerhalb der
nativen Befehle, die in dem Speicher gespeichert sind, spezifizieren
konnte. Beispielsweise stellt ein nativer Befehl möglicherweise
nur eine relativ kleine Anzahl von Bits für die Verwendung als unmittelbares
Operandenfeld in einem nativen Befehl bereit, wohingegen der nicht
native Befehl einen erweiterten Bereich zulassen könnte und
dies kann verwendet werden, indem die zusätzlichen Steuersignale benutzt
werden, um den erweiterten Bereich des unmittelbaren Operanden für den nativen Befehlsdecoder 34 außerhalb
des übersetzten
nativen Befehls, der ebenfalls an den Decoder 34 für den nativen
Befehl weitergeleitet wird, weiterzuleiten.
-
2 veranschaulicht
eine weitere Befehlspipeline 44. In diesem Beispiel ist
das System mit zwei Decodern 46, 48 für native
Befehle versehen, ebenso wie mit einem Decoder 50 für nicht
native Befehle. Der Decoder 50 für nicht native Befehle ist
hinsichtlich der Operationen, die er spezifizieren kann, durch die
Ausführungsstufe 52,
die Speicherstufe 54 und die Rückschreibestufe 56 eingeschränkt, die
vorgesehen sind, um die nativen Befehle zu unterstützen. Dementsprechend
muss der Decoder 50 für
nicht native Befehle in effektiver Weise die nicht nativen Befehle
in native Operationen übersetzen
(die eine einzelne native Operation oder eine Folge von nativen
Operationen sein können),
und dann geeignete Steuersignale für die Ausführungsstufe 52 zuführen, um
diesen einen oder die mehreren nativen Operationen auszuführen. Es
versteht sich, dass in diesem Beispiel der Decoder für nicht
native Befehle keine Signale erzeugt, die einen nativen Befehl bilden,
sondern stattdessen Steuersignale bereitstellt, welche Operationen
eines nativen Befehls (oder erweiterten nativen Befehls) spezifizieren.
Die Steuersignale, die erzeugt werden, passen möglicherweise nicht zu den Steuersignalen,
die durch die Decoder 46, 48 für native Befehle erzeugt werden.
-
Im
Betrieb wird ein Befehl, der durch die Heranholstufe 58 herangeholt
wurde, wahlweise einem der Befehlsdecoder 46, 48 oder 50 zugeführt, abhängig von
dem speziellen Verarbeitungsbetrieb, welcher den dargestellten Demultiplexer
verwendet.
-
3 veranschaulicht
schematisch und genauer die Heranholstufe einer Befehlspipeline.
Die Heranhollogik 60 holt Befehlsworte fester Länge aus
einem Speichersystem heran und führt
diese einem Befehlswortpuffer 62 zu. Der Befehlswortpuffer 62 ist
ein Schwingpuffer, welcher zwei Seiten hat, so dass er sowohl ein
aktuelles Befehlswort als auch ein nächstfolgendes Befehlswort speichern
kann. Wann immer das aktuelle Befehlswort vollständig decodiert ist und die
Decodierung zum nächsten
Befehlswort fortgeschritten ist, dient die Heranhollogik 60 dazu,
das vorherige aktuelle Befehlswort durch das nächste Befehlswort zu ersetzen,
das aus dem Speicher herangeholt werden muss, d. h. jede Seite des
Schwingpuffers erhöht
die Befehlsworte, welche sie aufeinanderfolgend speichern, in ineinander
verschachtelte Weise jeweils um zwei.
-
In
dem dargestellten Beispiel beträgt
die maximale Befehlslänge
eines Java-Bytecodebefehls
drei Bytes. Dementsprechend sind drei Multiplexer vorgesehen, die
es ermöglichen,
dass irgendwelche drei benachbarten Byte auf irgendeine der Seiten
des Wortpuffers 62 ausgewählt und dem Befehlsübersetzer 64 zugeführt wird.
Der Wortpuffer 62 und der Befehlsübersetzer 64 sind
auch mit einem Bypass bzw. einem Umgehungspfad 66 versehen,
der verwendet wird, wenn native Befehle herangeholt und decodiert
werden.
-
Man
erkennt, dass jedes Befehlswort einmal aus dem Speicher herangeholt
und in dem Wortpuffer 62 gespeichert wird. Ein einzelnes
Befehlswort kann mehrere Java-Bytcodes haben, die aus ihm gelesen
wurden, während
der Befehlsübersetzer 64 die Übersetzung
von Java-Bytecodes
in ARM-Befehle durchführt. Übersetzte
Sequenzen nativer Befehle in variabler Länge können erzeugt werden, ohne dass
mehrere Speichersystemablesungen erforderlich sind, noch Speicherressourcen
verbraucht werden oder sonstige Beschränkungen dem Speichersystem
auferlegt werden, wenn die Befehlsübersetzungsvorgänge auf
die Befehlspipeline eingeschränkt
werden.
-
Jedem
Java-Bytecode, welcher aktuell übersetzt
wird, ist ein Programmzählerwert
zugeordnet. Dieser Programmzählerwert
wird entlang der Stufen der Pipeline weitergeleitet, so dass jede
Stufe erforderlichenfalls in der Lage ist, die Information, welche
den speziellen Java-Bytecode
betrifft, den sie ausführt,
zu verwenden. Der Programmzählerwert
für einen
Java-Bytecode, der
in eine Folge einer Mehrzahl von ARM-Befehlsoperationen übersetzt
wird, wird nicht weitergesetzt, bevor nicht die letzte ARM-Befehlsoperation
innerhalb dieser Sequenz mit der Ausführung beginnt. Das Halten des
Programmzählerwertes
in einer Weise, die weiterhin direkt auf den Befehl in dem Speicher
zeigt, der ausgeführt
wird, vereinfacht in vorteilhafter Weise andere Aspekte des Systems,
wie z. B. ein Debugging (Fehlersuche) und die Berechnung von Verzweigungszielen.
-
4 veranschaulicht
schematisch das Lesen von Java-Bytecodebefehlen variabler Länge aus
dem Befehlspuffer 62. In der ersten Stufe wird ein Java-Bytecodebefehl,
der eine Länge
eins hat, gelesen und decodiert. Die nächste Stufe ist ein Java-Bytecodebefehl,
der eine Länge
von drei Bytes hat und sich zwischen zwei benachbarten Befehlsworten
erstreckt, die aus dem Speicher herangeholt worden sind. Diese beiden
Befehlsworte liegen in dem Befehlspuffer 62 vor und dadurch
wird die Befehlsdecodierung und Verarbeitung durch dieses Überbrücken eines
Befehls variabler Länge
zwischen herangeholten Befehlsworten nicht verzögert. Wenn die drei Java-Bytecodes
aus dem Befehlspuffer 62 gelesen worden sind, kann das
Auffüllen
der früher
herangeholten Befehlsworte beginnen, während die nachfolgende Verarbeitung
mit der Decodierung von Java-Bytecodes aus dem folgenden Befehlswort,
welches bereits vorliegt, fortgesetzt wird.
-
Die
in 4 dargestellte Endstufe veranschaulicht einen
zweiten Befehl mit drei Bytecodes, der gelesen wird. Dieser erstreckt
sich erneut zwischen Befehlsworten bzw. überbrückt diesen Raum. Wenn das vorgehende
Befehlswort noch nicht vollständig
wieder aufgefüllt
worden ist, so kann das Lesen des Befehls durch eine Pipeline-Anhalteeinheit
verzögert
werden, bis das passende Befehlswort in dem Befehlspuffer 62 gespeichert
worden ist. In einigen Ausführungsformen
kann die Zeitsteuerung derart sein, dass die Pipeline aufgrund dieser
Art von Verhalten niemals anhält.
Es versteht sich, dass das spezielle Beispiel etwas ist, welches
relativ selten auftritt, da die meisten Java-Bytecodes kürzer als
die dargestellten Beispiele sind und dementsprechend zwei aufeinanderfolgende
Decodierungen, die beide den Raum zwischen Befehlsworten überbrücken, relativ ungewöhnlich sind.
Ein gültiges
Signal kann jedem der Befehlsworte innerhalb des Befehlspuffers 62 in
einer Art und Weise zugeordnet werden, die in der Lage ist, anzuzeigen,
ob das Befehlswort ordnungsgemäß aufgefüllt worden
ist, bevor ein Java-Bytecode von ihm gelesen wurde.
-
5 zeigt
ein Datenverarbeitungssystem 102 einschließlich eines
Prozessorkerns 104 und einer Registerbank 106.
Ein Befehlsübersetzer 108 ist
mit dem Befehlspfad versehen, um Befehle einer virtuellen Java-Maschine
in native ARM-Signale zu übersetzen
(oder in Steuersignale, die diesen entsprechen), welche dann dem
Prozessorkern 104 zugeführt
werden können.
Der Befehlsübersetzer 108 kann
umgangen werden, wenn native ARM-Befehle aus dem adressierbaren
Speicher herangeholt werden. Der adressierbare Speicher kann ein
Speichersystem, wie z. B. ein Cache-Speicher mit weiterem RAM-Speicher
außerhalb
des Chips sein. Das Bereitstellen des Befehlsübersetzers 108 stromabwärts von
dem Speichersystem und insbesondere des Cache-Speichers ermöglicht es,
dass eine effiziente Ausnutzung der Speicherkapazität des Speichersystems erfolgt,
da dichte Befehle, die eine Übersetzung
erfordern, in dem Speichersystem gespeichert werden können und
unmittelbar bevor sie an den Prozessorkern 104 geleitet
werden, nur in native Befehle erweitert werden.
-
Die
Registerbank 106 in diesem Beispiel enthält 16 Vielzweckregister
für 32
Bit, von welchen vier für die
Verwendung bei der Speicherung von Stapeloperanden zugewiesen sind,
d. h. der Satz von Registern zu Speichern von Stapeloperanden besteht
aus den Registern R0, R1, R2 und R3.
-
Der
Satz von Registern kann leer, teilweise mit Stapeloperanden gefüllt oder
vollständig
mit Stapeloperanden gefüllt
sein. Das spezielle Register, welches aktuell den obersten Stapeloperanden
hält, kann
irgendeines der Register in dem Satz von Registern sein. Man erkennt
demnach, dass der Befehlsübersetzer in
irgendeinem von 17 verschiedenen Zuordnungszuständen sein kann, welche einem
Zustand entsprechen, zu dem alle Register leer sind und vier Gruppen
von vier Zuständen
jeweils einer entsprechend anderen Zahl von Stapeloperanden entsprechen,
in dem Satz von Registern gehalten wird, wobei ein anderes Register
den obersten Stapeloperanden hält.
Tabelle 1 veranschaulicht die 17 verschiedenen Zustände der
Zustandszuordnung für
den Befehlsübersetzer
108.
Es versteht sich, dass bei einer anderen Anzahl von Registern, die
der Stapeloperandenspeicherung zugewiesen werden, oder als Folge
von Beschränkungen,
die ein bestimmter Prozessorkern hinsichtlich der Art und Weise
haben kann, mit welcher er Datenwerte in den Registern manipulieren
kann, die Zuordndungszustände
beträchtlich
von der speziellen Implementierung abhängen können und Tabelle 1 nur als
ein Beispiel einer bestimmten Implementierung gegeben wird.
Zustand
00000 | | | |
R0
= leer | | | |
R1
= leer | | | |
R2
= leer | | | |
R3
= leer | | | |
| | | |
Zustand
00100 | Zustand
01000 | Zustand
01100 | Zustand
10000 |
R0
= TOS | R0
= TOS | R0
= TOS | R0
= TOS |
R1
= leer | R1
= leer | R1
= leer | R1
= TOS – 3 |
R2
= leer | R2
= leer | R2
= TOS – 2 | R2
= TOS – 2 |
R3
= leer | R3
= TOS – 1 | R3
= TOS – 1 | R3
= TOS – 3 |
| | | |
Zustand
00101 | Zustand
01001 | Zustand
01101 | Zustand
10001 |
R0
= leer | R0
= TOS – 1 | R0
= TOS – 1 | R0
= TOS – 1 |
R1
= TOS | R1
= TOS | R1
= TOS | R1
= TOS |
R2
= leer | R2
= leer | R2
= leer | R2
= TOS – 3 |
R3
= leer | R3
= leer | R3
= TOS – 2 | R3
= TOS – 2 |
| | | |
Zustand
00110 | Zustand
01010 | Zustand
01110 | Zustand
10010 |
R0
= leer | R0
= leer | R0
= TOS – 2 | R0
= TOS – 2 |
R1
= leer | R1
= TOS – 1 | R1
= TOS – 1 | R1
= TOS – 1 |
R2
= TOS | R2
= TOS | R2
= TOS | R2
= TOS |
R3
= leer | R3
= leer | R3
= leer | R3
= TOS – 3 |
| | | |
Zustand
00111 | Zustand
01011 | Zustand
01111 | Zustand
10011 |
R0
= leer | R0
= leer | R0
= leer | R0
= TOS – 3 |
R1
= leer | R1
= leer | R1
= TOS – 2 | R1
= TOS – 2 |
R2
= leer | R2
= TOS – 1 | R2
= TOS – 1 | R2
= TOS – 1 |
R3
= TOS | R3
= TOS | R3
= TOS | R3
= TOS |
Tabelle
1
-
In
Tabelle 1 kann man feststellen, dass die ersten drei Bits des Zustandswertes
die Anzahl nicht leerer Register in dem Satz von Registern anzeigen.
Die beiden letzten Bits des Zustandswertes zeigen die Registernummer
des Registers an, welches den obersten Stapelope randen hält. Auf
diese Weise kann der Zustandswert in einfacher Weise verwendet werden,
um den Betrieb eines Hardwareübersetzers
oder Softwareübersetzers
zu steuern bzw. zu kontrollieren, um die aktuelle Besetzung des
Satzes von Registern und die aktuelle Position des obersten Stapeloperanden
berücksichtigen.
-
Wie
in 5 dargestellt, wird dem Befehlsübersetzer 108 aus
dem adressierbaren Speichersystem ein Strom von Java-Bytecodes J1,
J2, J3 zugeführt.
Der Befehlsübersetzer 108 gibt
dann einen Strom von ARM-Befehlen oder äquivalenten Steuersignalen,
die möglicherweise
erweitert sind, aus, abhängig
von den eingegebenen Java-Bytecodes und dem momentanen Zuordnungszustand
des Befehlsübersetzers 8,
ebenso wie von anderen Variablen. Das dargestellte Beispiel zeigt,
dass Java-Bytecode J1 den ARM-Befehlen A11
und A12 zugeordnet ist. Der Java-Bytecode J2 entspricht
den ARM-Befehlen A21, A22
und A23. Schließlich ordnet der Java-Bytecode J3 den ARM-Befehl
A31 zu. Jeder der Java-Bytecodes kann einen
oder mehreren Stapeloperanden als Eingangsgröße erfordern und kann einen
oder mehrere Stapeloperanden als eine Ausgabe erzeugen. Wenn man
davon ausgeht, dass der Prozessorkern 104 in diesem Beispiel
ein ARM-Prozessor ist, der eine Lade/Speicher-Architektur hat, wobei
nur Datenwerte, die in den Registern gehalten werden, manipuliert
werden können,
ist der Befehlsübersetzer 108 dafür ausgelegt,
ARM-Befehle zu erzeugen, die, falls erforderlich, jegliche erforderliche
Stapeloperanden in den Registersatz vorab heranholen, bevor sie
gehandhabt bzw. manipuliert werden, oder um jegliche aktuell gehaltenen
Stapeloperanden in dem Satz von Registern in adressierbaren Speichern
zu speichern, um für
als Ergebnis möglicherweise
erzeugte Stapeloperanden Platz zu schaffen. Es versteht sich, dass
jeder Java-Bytecode als einer betrachtet werden kann, der einen
zugeordneten Wert „Benötige Füllung" haben muss, welcher
die Anzahl von Stapeloperanden angibt, die in dem Satz von Registern
vor ihrer Ausführung
vorliegen müssen,
zusammen mit einem Wert „Benötige Leerung", welcher die Anzahl
von leeren Registern in dem Satz von Registern angibt, die verfügbar sein
müssen,
bevor die ARM-Befehle ausgeführt
werden, welche den Java-Operationscode darstellen.
-
Tabelle
2 veranschaulicht die Beziehung zwischen anfänglichen Werten des Zuordnungszustandes, der
Werte für
das Benötigen
einer Füllung,
der Endzustandswerte und der zugehörigen ARM-Befehle. Die anfänglichen
Zustandswerte und die Endzustandswerte entsprechen den Zuordnungszuständen, die
in Tabelle 1 dargestellt sind. Der Befehlsübersetzer
108 legt
einen Wert für
die benötigte
Füllung
fest, welcher dem betreffenden Java-Bytecode (Operationscode) zugeordnet
ist, den er übersetzt.
Der Befehlsübersetzer
(
108) bestimmt in Abhängigkeit
von dem anfänglichen
Zuordnungszustand, welchen er hat, ob mehr Stapeloperanden in den
Satz von Registern vor der Ausführung
des Java-Bytecodes geladen werden müssen oder nicht. Tabelle 1
zeigt die Anfangszustände
zusammen mit den Tests, die mit dem Wert für das Füllerfordernis des Java-Bytecodes
angewandt werden, die gemeinsam angewendet werden, um festzustellen,
ob ein Stapeloperand unter Verwendung eines zugehörigen ARM-Befehls
(ein LDR-Befehl) in den Satz von Registern geladen werden muss,
ebenso wie in den endgültigen
Zuordndungszustand, der nach einem solchen Cache-Ladevorgang eines
Stapels angenommen wird. In der Praxis erfolgen, wenn mehr als ein
Stapeloperand vor der Ausführung des
Java-Bytecodes in den Satz von Registern geladen werden muss, mehrere Übergänge von
Zuordnungszuständen,
jeweils mit einem zugehörigen
ARM-Befehl, der einen Stapeloperanden in eines der Register aus dem
Satz von Registern lädt.
In anderen Ausführungsformen
kann es erforderlich sein, mehrere Stapeloperanden in einem einzigen
Zustandsübergang
zu laden und dementsprechend Veränderungen
des Zuordnungszustandes über
die in der Tabelle dargestellten hinaus durchzuführen.
Anfangszustand | Füllerfordernis | Endzustand | Aktionen |
00000 | > 0 | 00100 | LDR
R0, [Rstack, #-4]! |
00100 | > 1 | 01000 | LDR
R3, [Rstack, #-4]! |
01001 | > 2 | 01101 | LDR
R3, [Rstack, #-4]! |
01110 | > 3 | 10010 | LDR
R3, [Rstack, #-4]! |
01111 | > 3 | 10011 | LDR
R0, [Rstack, #-4]! |
01100 | > 3 | 10000 | LDR
R1, [Rstack, #-4]! |
01101 | > 3 | 10001 | LDR
R2, [Rstack, #-4]! |
01010 | > 2 | 01110 | LDR
R0, [Rstack, #-4]! |
01011 | > 2 | 01111 | LDR
R1, [Rstack, #-4]! |
01000 | > 2 | 01100 | LDR
R2, [Rstack, #-4]! |
00110 | > 1 | 01010 | LDR
R1, [Rstack, #-4]! |
00111 | > 1 | 01011 | LDR
R2, [Rstack, #-4]! |
00101 | > 1 | 01001 | LDR
R0, [Rstack, #-4]! |
Tabelle
2
-
Wie
man anhand von Tabelle 2 erkennt, bildet ein neuer Stapeloperand,
der in den Satz von Registern geladen wird, welche Stapeloperanden
speichern, einen neuen obersten Stapeloperanden und dieser wird
in ein bestimmtes Register aus dem Satz von Registern geladen, je
nach dem Anfangszustand.
-
In ähnlicher
Weise veranschaulicht Tabelle 3 die Beziehung zwischen dem Anfangszustand,
dem Wert für
die erforderliche Leerung, dem Endzustand und einem zugehörigen ARM-Befehl zum Leeren
eines Registers innerhalb des Satzes von Registern, um einen Übergang
zwischen dem Anfangszustand und dem Endzustand durchzuführen, wenn
der Wert der erforderlichen Leerung eines bestimmten Java-Bytecodes
anzeigt, dass er in Anbetracht des Anfangszustands erforderlich
ist, bevor der Java-Bytecode ausgeführt wird. Die betreffenden
Registerwerte, die mit einem STR-Befehl in den adressierbaren Speicher
ausgelagert werden, variieren in Abhängigkeit davon, welches der
Register den aktuell obersten Stapeloperanden hält.
Anfangszustand | Leerungserfordernis | Endzustand | Aktionen |
00100 | > 3 | 00000 | STR
R0, [Rstack], #4 |
01001 | > 2 | 00101 | STR
R0, [Rstack], #4 |
01110 | > 1 | 01010 | STR
R0, [Rstack], #4 |
10011 | > 0 | 01111 | STR
R0, [Rstack], #4 |
10000 | > 0 | 01100 | STR
R1, [Rstack], #4 |
10001 | > 0 | 01101 | STR
R2, [Rstack], #4 |
10010 | > 0 | 01110 | STR
R3, [Rstack], #4 |
01111 | > 1 | 01011 | STR
R1, [Rstack], #4 |
01100 | > 1 | 01000 | STR
R2, [Rstack], #4 |
01101 | > 1 | 01001 | STR
R3, [Rstack], #4 |
01010 | > 2 | 00110 | STR
R1, [Rstack], #4 |
01011 | > 2 | 00111 | STR
R2, [Rstack], #4 |
01000 | > 2 | 00100 | STR
R3, [Rstack], #4 |
00110 | > 3 | 00000 | STR
R2, [Rstack], #4 |
00111 | > 3 | 00000 | STR
R3, [Rstack], #4 |
00101 | > 3 | 00000 | STR
R1, [Rstack], #4 |
Tabelle
3
-
Es
versteht sich, dass in dem oben beschriebenen Beispielsystem die
Bedingungen des Füllerfordernisses
und des Leerungserfordernisses sich wechselseitig ausschließen, d.
h. nur eine der Bedingungen bzw. Zustände Füllerfordernis oder Leerungserfordernis
kann zu einem gegebenen Zeitpunkt für einen bestimmten Java-Bytecode
wahr sein, welchen der Befehlsübersetzer
zu übersetzen
versucht. Die durch den Befehlsübersetzer 108 verwendeten
Befehlsschablonen zusammen mit den Befehlen, für deren Unterstützung er
ausgewählt
wurde, werden bei dem Hardware-Befehlsübersetzer 108 derart
ausgewählt,
dass dieses Erfordernis der wechselseitigen Ausschließung erfüllt werden
kann. Wenn diese Anforderung nicht bestehen würde, könnte eins Situation auftreten,
in welcher ein bestimmter Java-Bytecode eine Anzahl von einzugebenden
Stapeloperanden erfordern würde,
die innerhalb des Satzes von Registern vorhanden seien müssen, die
keine ausreichende Anzahl leerer Register erlauben würden, die
nach der Ausführung
des Befehls verfügbar
sein müssten, welcher
den Java-Bytecode repräsentiert,
um zu ermöglichen,
dass die Ergebnisse der Ausführung
entsprechend dem Erfordernis in den Registern gehalten werden.
-
Es
versteh sich, dass ein gegebener Java-Bytecode eine Nettostapelaktion
hat, welche das Gleichgewicht zwischen der Anzahl von Stapeloperanden,
die gebraucht werden, und der Anzahl von Stapeloperanden, die bei
der Ausführung
des Java-Bytecodes erzeugt werden, wie dergibt. Da die Anzahl der
verbrauchten Stapeloperanden ein Erfordernis ist, das vor der Ausführung erfüllt sein
muss, und die Anzahl der Stapeloperanden, die erzeugt werden, ein
Erfordernis nach der Ausführung
ist, müssen
die Werte für
das Füllerfordernis
und für
das Leerungserfordernis, welche zu jedem Java-Bytecode gehören, vor
der Ausführung
dieses Bytecodes erfüllt
sein, selbst wenn die Gesamtnettoaktion an sich erfüllt wäre. Tabelle
4 veranschaulicht die Beziehung zwischen einem Anfangszustand, der
Gesamtstapelaktion, einem Endzustand, und einer Änderung in der Registerverwendung
und der relativen Position des obersten Stapeloperanden (TOS). Es
kann sein, dass einer oder mehrere der Zustandsübergänge, die in Tabelle 2 oder
Tabelle 3 dargestellt sind, ausgeführt werden müssen, bevor
die in Tabelle 4 dargestellten Zustandsübergänge ausgeführt werden, um die Voraussetzungen
für einen
gegebenen Java-Bytecode zu erfüllen,
je nach den Werten für
das Füllerfordernis
oder das Leerungserfordernis des Java-Bytecodes.
Anfangszustand | Stapelaktion | Endzustand | Aktionen |
00000 | +1 | 00101 | R1 <- TOS |
00000 | +2 | 01010 | R1 <- TOS – 1, R2 <- TOS |
00000 | +3 | 01111 | R1 <- TOS – 2, R2 <- TOS – 1, R3 <- TOS |
00000 | +4 | 10000 | R0 <- TOS, R1 <- TOS – 3, R2 <- TOS – 2, R3 <- TOS – 1 |
| | | |
00100 | +1 | 01001 | R1 <- TOS |
00100 | +2 | 01110 | R1 <- TOS – 1, R2 <- TOS |
00100 | +3 | 10011 | R1 <- TOS – 2, R2 <- TOS – 1, R3 <- TOS |
00100 | –1 | 00000 | R0 <- EMPTY |
| | | |
01001 | +1 | 01110 | R2 <- TOS |
01001 | +2 | 10011 | R2 <- TOS – 1, R3 <- TOS |
01001 | –1 | 00100 | R1 <- EMPTY |
01001 | –2 | 00000 | R0 <- EMPTY, R1 <- EMPTY |
| | | |
01110 | +1 | 10011 | R3 <- TOS |
01110 | –1 | 01001 | R2 <- EMPTY |
01110 | –2 | 00100 | R1 <- EMPTY, R2 <- EMPTY |
01110 | –3 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY |
| | | |
10011 | –1 | 01110 | R3 <- EMPTY |
10011 | –2 | 01001 | R2 <- EMPTY, R3 <- EMPTY |
10011 | –3 | 00100 | R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
10011 | –4 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
10000 | –1 | 01111 | R0 <- EMPTY |
10000 | –2 | 01010 | R0 <- EMPTY, R3 <- EMPTY |
10000 | –3 | 00101 | R0 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
10000 | –4 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
10001 | –1 | 01100 | R1 <- EMPTY |
10001 | –2 | 01011 | R0 <- EMPTY, R1 <- EMPTY |
10001 | –3 | 00110 | R0 <- EMPTY, R1 <- EMPTY, R3 <- EMPTY |
10001 | –4 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
10010 | –1 | 01101 | R2 <- EMPTY |
10010 | –2 | 01000 | R1 <- EMPTY,R2 <- EMPTY |
10010 | –3 | 00111 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY |
10010 | –4 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
01111 | +1 | 10000 | R0 <- TOS |
01111 | –1 | 01010 | R3 <- EMPTY |
01111 | –2 | 00101 | R2 <- EMPTY, R3 <- EMPTY |
01111 | –3 | 00000 | R1 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
01100 | +1 | 10001 | R1 <- TOS |
01100 | –1 | 01011 | R0 <- EMPTY |
01100 | –2 | 00110 | R0 <- EMPTY, R3 <- EMPTY |
01100 | –3 | 00000 | R0 <- EMPTY, R2 <- EMPTY, R3 <- EMPTY |
| | | |
01101 | +1 | 10010 | R2 <- TOS |
01101 | –1 | 01000 | R1 <- EMPTY |
01101 | –2 | 00111 | R0 <- EMPTY, R1 <- EMPTY |
01101 | –3 | 00000 | R0 <- EMPTY, R1 <- EMPTY, R3 <- EMPTY |
| | | |
01010 | +1 | 01111 | R3 <- TOS |
01010 | +2 | 10000 | R3 <- TOS – 1, R0 <- TOS |
01010 | –1 | 00101 | R2 <- EMPTY |
01010 | –2 | 00000 | R1 <- EMPTY, R2 <- EMPTY |
| | | |
01011 | +1 | 01100 | R0 <- TOS |
01011 | +2 | 10001 | R0 <- TOS – 1, R1 <- TOS |
01011 | –1 | 00110 | R3 <- EMPTY |
01011 | –2 | 00000 | R2 <- EMPTY, R3 <- EMPTY |
| | | |
01000 | +1 | 01101 | R1 <- TOS |
01000 | +2 | 10010 | R1 <- TOS – 1, R2 <- TOS |
01000 | –1 | 00111 | R0 <- EMPTY |
01000 | –2 | 00000 | R0 <- EMPTY, R3 <- EMPTY |
| | | |
00110 | +1 | 01011 | R3 <- TOS |
00110 | +2 | 01100 | R0 <- TOS, R3 <- TOS – 1 |
00110 | +3 | 10001 | R1 <- TOS, R0 <- TOS – 1, R3 <- TOS – 2 |
00110 | –1 | 00000 | R2 <- EMPTY |
| | | |
00111 | +1 | 01000 | R0 <- TOS |
00111 | +2 | 01101 | R0 <- TOS – 1, R1 <- TOS |
00111 | +3 | 10010 | R0 <- TOS – 2, R1 <- TOS – 1, R2 <- TOS |
00111 | –1 | 00000 | R3 <- EMPTY |
| | | |
00101 | +1 | 01010 | R2 <- TOS |
00101 | +2 | 01111 | R2 <- TOS – 1, R3 <- TOS |
00101 | +3 | 10000 | R2 <- TOS – 2, R3 <- TOS – 1, R1 <- TOS |
00101 | –1 | 00000 | R1 <- EMPTY |
|
(A. d. Ü.: EMPTY
= leer) |
Tabelle
4
-
Es
versteht sich, dass die Beziehungen zwischen Zuständen und
Bedingungen, die in Tabelle 2, Tabelle 3 und Tabelle 4 veranschaulicht
sind, auch zu einer einzigen Zustandsübergangstabelle oder zu einem einzigen
Zustandsdiagramm kombiniert werden könnten, sie sind jedoch der
Klarheit wegen getrennt dargestellt worden.
-
Die
Beziehungen zwischen den unterschiedlichen Zuständen, Bedingungen und Nettoaktionen
können
verwendet werden, um eine Hardware-Zustandsmaschine (in der Form
einer endlichen Zustandsmaschine bzw. eines endlichen Automaten)
zur Kontrolle bzw. Steuerung dieses Aspektes der Operation des Befehlsübersetzers 108 zu
definieren. Alternativ könnten
diese Beziehungen durch Software oder eine Kombination von Hardware
und Software modelliert werden.
-
Nachstehend
folgt ein Beispiel eines Teilsatzes der möglichen Java-Bytecodes, das
für jeden
Java-Bytecode des Teilsatzes die zugehörigen Werte für das Füllerfordernis,
das Leerungserfordernis und die Stapelaktion für diesen Bytecode anzeigt,
die in Verbindung mit den Tabellen 2, 3 und 4 verwendet werden können.
---
iconst_0 | |
Operation: | Push
int constant |
Stack: | ...
=> |
(Stapel:) | ...,
0 |
| Require-Full
= 0 (Füllmengenerfordernis
= 0) |
| Require-Empty
= 1 (Leerungserfordernis = 1) |
| Stack-Action
= +1 (Stapelaktion = +1) |
---
iadd | |
Operation: | Add
int |
Stack: | ...,
value1, value2 => |
| ...,
result |
| Require-Full
= 2 |
| Require-Empty
= 0 |
| Stack-Action
= –1 |
---
lload_0 | |
Operation: | Load
long from local variable |
| (langes
Laden von lokaler Variabler) |
Stack: | ...
=> |
| ...,
value.word1, value.word2 |
| Require-Full
= 0 |
| Require-Empty
= 2 |
| Stack-Action
= +2 |
---
lastore | |
Operation: | Store
into long array (Speichere in long array) |
Stack: | ...,
arrayref, index, value.word1, value.word2 => |
| ... |
| Require-Full
= 4 |
| Require-Empty
= 0 |
| Stack-Action
= –4 |
---
land | |
Operation | Boolean
AND long |
Stack: | ...,
value1.word1, value1.word2, value2.word1, |
value2.word2
=> | |
| ...,
result.word1, result.word2 |
| Require-Full
= 4 |
| Require-Empty
= 0 |
| Stack-Action
= –2 |
---
iastore | |
Operation: | Store
into int array |
Stack: | ...,
arrayref, index, value => |
| ... |
| Require-Full
= 3 |
| Require-Empty
= 0 |
| Stack-Action
= –3 |
---
ineg | |
Operation: | Negate
int |
Stack: | ...,
value => |
| ...,
result |
| Require-Full
= 1 |
| Require-Empty
= 0 |
| Stack-Action
= 0 |
-
Es
folgen außerdem
beispielhafte Befehlsschablonen für jeden der oben wiedergegebenen
Java-Bytecodebefehle. Die dargestellten Befehle sind die ARM-Befehle,
die das geforderte Verhalten jedes der Java-Bytecodes implementieren.
Die Registerfelder „TOS – 3", „TOS – 2", „TOS – 1", „TOS", „TOS +
1" und „TOS +
2" können durch
die passenden Registerangaben ersetzt werden, die man aus Tabelle
1 in Abhängigkeit
von dem aktuell angenommenen Zuordnungszustand ablesen kann. Die
Bezeichnung „TOS
+ n" zeigt das n-te
Register oberhalb des aktuell den obersten Stapeloperanden speichernden
Registers an, beginnend von dem Register, das den obersten Stapeloperanden
speichert, und aufwärts
zählend
in dem Registerwert, bis das Ende des Satzes von Registern erreicht
ist, wobei an diesem Punkt ein Umbruch zu dem ersten Register innerhalb des
Satzes von Registern erfolgt.
iconst_0 | MOV | tos
+ 1, #0 |
| | |
lload_0 | LDR | tos
+ 2, [vars, #4] |
| LDR | tos
+ 1, [vars, #0] |
| | |
iastore | LDR | Rtmp2,
[tos – 2,
#4] |
| LDR | Rtmp1,
[tos – 2,
#0] |
| CMP | tos – 1, Rtmp2,
LSR #5 |
| BLXCS | Rexc |
| STR | tos,
[Rtmp1], tos – 1,
LSL #2] |
| | |
lastore | LDR | Rtmp2,
[tos – 3,
#4] |
| LDR | Rtmp1,
[tos – 3,
#0] |
| CMP | tos – 2, Rtmp2,
LSR #5 |
| BLXCS | Rexc |
| STR | tos – 1, [Rtmp1,
tos – 2,
LSL #3]! |
| STR | tos,
[Rtmp1, #4] |
| | |
iadd | ADD | tos – 1, tos – 1, tos |
| | |
ineg | RSB | tos,
tos, #0 |
| | |
land | AND | tos – 2, tos – 2, tos |
| AND | tos – 3, tos – 3, tos – 1 |
-
Eine
beispielhafte Ausführungssequenz
ist nachstehend für
einen einzelnen Java-Bytecode
dargestellt, der durch eine Hardware-Übersetzungseinheit
108 gemäß den oben
beschriebenen Techniken ausgeführt
wird. Die Ausführungssequenz
ist auf Basis eines Anfangszustandes dargestellt, der durch eine
Folge von Zuständen
hindurchläuft,
abhängig
von den ausgeführten
Befehlen, wobei eine durch eine Folge von ARM-Befehlen als Ergebnis
der bei jedem Zustandsübergang
durchgeführten
Aktionen erzeugt wird und das Ganze den Effekt hat, dass ein Java-Bytecode
in eine Sequenz von ARM-Befehlen übersetzt wird.
Anfangszustand: | 00000 |
Befehl: | iadd
(Require-Full = 2, Require-Empty = 0, Stack-Action = –1) |
Bedingung: | Require-Full > 0 |
Zustandsübergang: | 00000 > 0 00100 |
ARM-Befehl(e): | LDR
R0, [Rstack, #-4]! |
Nächster Zustand: | 00100 |
Befehl: | iadd
(Require-Full = 2, Require-Empty = 0, Stack-Action = –1) |
Bedingung: | Require-Full>1 |
Zustandsübergang: | 00100 > 1 01000 |
ARM-Befehl(e): | LDR
R3, [Rstack, #-4]! |
Nächster Zustand: | 01000 |
Befehl: | iadd
(Require-Full = 2, Require-Empty = 0, Stack-Action = –1) |
Bedingung: | Stack-Action
= –1 |
Zustandsübergang: | 01000 –1 00111 |
Befehlsschablone: | ADD
tos – 1,
tos – 1,
tos |
ARM-Befehl(e)
(nach Ersetzung): | ADD
R3, R3, R0 |
Nächster Zustand: | 00111 |
-
6 veranschaulicht
auf andere Weise die Ausführung
einer Anzahl weiterer Java-Bytecodebefehle. Der
obere Teil von 6 veranschaulicht die Sequenz
von ARM-Befehlen und Veränderungen
von Zuordnungszuständen
und Registerinhalten, die bei Ausführung eines Java-Bytecodebefehls
iadd auftreten. Der anfängliche
Zuordnungszustand ist 00000, was der Tatsache entspricht, dass alle
Register innerhalb des Satzes von Registern leer sind. Die ersten
beiden ARM-Befehle, die erzeugt werden, dienen dazu, zwei Stapeloperanden
in das Register zu platzieren (POP), die Stapeloperanden speichern,
wobei das oberste Register des Stapels „TOS" R0 ist. Der dritte ARM-Befehl führt im eigentlichen
Sinne die add-Operation aus und schreibt das Ergebnis in das Register
R3 (welches nunmehr der oberste Stapeloperand wird), während der
Stapeloperand verbraucht wird, der zuvor in dem Register R1 gehalten
wurde, wodurch eine Gesamtstapelaktion von –1 erzeugt wird.
-
Die
Verarbeitung geht dann weiter zur Ausführung von zwei Java-Bytecodes,
die jeweils ein langes Laden (long load) von zwei Stapeloperanden
repräsentieren.
Die Bedingung des Leerungserfordernisses von 2 für den ersten Java-Bytecode
ist unmittelbar erfüllt
und dementsprechend können
zwei ARM-LDR-Befehle ausgegebenen und ausgeführt werden. Der Zuordnungszustand
nach der Ausführung
des ersten Java-Bytecodes (long load) ist 01101. In diesem Zustand
enthält
der Satz von Registern nur ein einzelnes leeres Register. Der nächste Java-Bytecode-Befehl (long
load) hat einen Wert des Leerungserfordernisses von 2, der nicht erfüllt wird,
und dementsprechend ist die erste erforderliche Aktion ein Verschieben
eines Stapeloperanden in den adressierbaren Speicher unter Verwendung
eines ARM-STR-Befehles. Dies macht ein Register in dem Satz von
Registern für
die Verwendung durch einen neuen Stapeloperanden frei, der dann
als Teil der beiden folgenden LDR-Befehle geladen werden kann. Wie
zuvor erwähnt,
kann die Befehlsübersetzung
durch Hardware, Software oder eine Kombination von beidem erreicht
werden. Nachstehend ist ein Teilabschnitt eines beispielhaften Softwareübersetzers
wiedergegeben, der entsprechend den oben beschriebenen Techniken
erzeugt wurde.
-
-
-
-
-
7 veranschaulicht
einen Java-Bytecodebefehl „laload", der die Funktion
des Ladens zweier Datenworte aus einem Datenarray hat, spezifiziert
durch zwei Datenworte beginnend an der obersten Stapelposition.
Die aus dem Datenarray gelesenen zwei Worte ersetzen dann die beiden
Worte, welche ihre Position angegeben hatten und bilden die am weitesten
oben liegenden Stapeleinträge.
-
Damit
der „laload"-Befehl ausreichenden
Registerraum für
die zwischenzeitliche Speicherung der Stapeloperanden hat, die aus
dem Array herangeholt werden, ohne dass die eingegebenen Stapeloperanden überschrieben
werden, die das Array und die Position innerhalb des Datenarrays
spezifizieren, wird der Java-Bytecodebefehl als einer spezifiziert,
der einen Wert des Leerungserfordernisses von 2 hat, d. h. zwei
der Register innerhalb der Registerbank, die für die Speicherung der Stapeloperanden
bestimmt sind, müssen
vor der Ausführung
der ARM-Befehle, die den „laload"-Befehl emulieren,
gelehrt werden. Wenn es keine zwei leeren Register gibt, wenn dieser
Bytecode auftritt, so können
die Speicheroperationen (STRs) ausgeführt werden, um Stapeloperanden,
die aktuell in den Registern gehalten werden, in den Speicherraum
auszulagern (PUSH), um Platz für
die erforderliche Zwischenspeicherung zu schaffen und um den geforderten
Leerungswert für
den Befehl zu erfüllen.
-
Der
Befehl hat außerdem
einen Wert des Füllerfordernisses
von 2, da die Position der Daten durch eine Array-Position und einen
Index innerhalb des Arrays in Form zweier getrennter Stapeloperanden
spezifiziert wird. Die Zeichnung veranschaulicht den ersten Zustand,
der bereits die Bedingungen des Füllerfordernisses und des Leerungserfordernisses
erfüllt
und einen Zuordnungszustand von „01001" hat. Der „laload"-Befehl wird in drei ARM-Befehle aufgebrochen.
Der erste der Ladevorgänge
ist ein Arrayaufruf in ein Reservearbeitsregister außerhalb
des Satzes von Registern, das als ein Register-Cache für Stapeloperanden
wirkt. Der zweite Befehl verwendet dann diesen Array-Aufruf in Verbindung
mit einem Indexwert in dem Array, um auf ein erstes Array-Wort zuzugreifen,
dass in eines der leeren Register beschrieben wird, die für die Speicherung
von Stapeloperanden bestimmt sind.
-
Es
ist wichtig, darauf hinzuweisen, dass nach der Ausführung der
ersten zwei ARM-Befehle
der Zuordnungszustand des Systems nicht verändert ist und der Zeiger auf
das obere Ende des Stapels dort verbleibt, wo er begann, wobei die
Register, die als leer spezifiziert wurden, nach wie vor so spezifiziert
bleiben.
-
Der
endgültige
Befehl innerhalb der Folge von ARM-Befehlen lädt das zweite Array-Wort in
den Satz von Registern zum Speichern von Stapeloperanden. Da dies
der letzte Befehl ist, wird ein Interrupt, falls er währenddessen
Auftritt, nicht bedient, bis der Befehl abgeschlossen ist, so dass
er sicher ist, dass der Eingangszustand mit diesem Befehl verändert wird
durch eine Veränderung
in dem Zuordnungszustand in den Registern, welche die Stapeloperanden
speichern. In dem Beispiel verändert
sich der Zuordnungszustand auf „01011", was den neuen Zeiger auf das obere
Ende des Stapels auf das zweite Array-Wort setzt und anzeigt, dass
die Eingangsvariablen des Array-Aufrufs und der Indexwert nunmehr
leere Register sind, d. h. das Markieren der Register als leer ist
dem Entfernen der Werte, die sie aus dem Stapel gehalten hatten, äquivalent.
-
Es
versteht sich, dass, während
die Gesamtstapelaktion des „laload"-Befehls die Anzahl
von in den Registern gehaltenen Stapeloperanden nicht verändert hat,
ein Wechsel des Zuordnungszustands dennoch aufgetreten ist. Die
Veränderung
des Zuordnungszustands, die bei der Ausführung des letzten Befehls durchgeführt wurde,
ist in dem Befehlsübersetzer
als eine Funktion des übersetzten
Java-Bytecodes hart verdrahtet und wird durch den „Wechsel"(„Swap")-Parameter
angezeigt, der als eine Eigenschaft des „laload"-Befehls dargestellt ist.
-
Während das
Beispiel dieser Zeichnung nur ein spezifischer Befehl ist, versteht
es sich, dass die dargelegten Prinzipien auf viele andere Java-Bytecodebefehle
erweitert werden können,
die als ARM-Befehle oder andere Typen von Befehlen emuliert werden.
-
8 ist
ein Flussdiagramm, welches schematisch die obige Technik veranschaulicht.
In Schritt 10 wird ein Java-Bytecode aus dem Speicher herangeholt.
In Schritt 12 werden die Werte für das Füllerfordernis und das Leerungserfordernis
dieses Java-Bytecodes untersucht. Wenn eine oder beide der Bedingungen
für das
Leerungserfordernis oder das Füllerfordernis
nicht erfüllt
sind, so können
die entsprechenden PUSH- und POP-Operationen von Stapelope randen
(möglicherweise
mehreren Stapeloperanden) in den Schritten 14 und 16 ausgeführt werden.
Dabei ist anzumerken, dass dieses spezielle System es nicht erlaubt,
dass die Bedingungen für
das Leerungserfordernis und das Füllerfordernis gleichzeitig
nicht erfüllt
sind. Mehrere Durchlaufe der Schritte 14 und 16 können erforderlich
sein, bis die Bedingung für
Schritt 12 erfüllt
ist.
-
In
Schritt 18 wird der erste ARM-Befehl, der in der Besetzungsschablone
für den
betreffenden Java-Bytecode beschrieben ist, ausgewählt. In
Schritt 20 wird eine Prüfung
vorgenommen, ob der ausgewählte ARM-Befehl
der letzte in der Emulation des in Schritt 10 herangeholten
Java-Bytecodes auszuführende
Befehl ist oder nicht. Wenn der ARM-Befehl, welcher ausgeführt ist,
der letzte Befehl ist, so dient Schritt 21 dazu, den Programmzählerwert
zu aktualisieren, so dass er auf den nächsten Java-Bytecode in der
Folge von auszuführenden
Befehlen hinweist. Es versteht sich, dass dann, wenn der ARM-Befehl
der letzte Befehl ist, er seine Ausführung unabhängig davon abschließt, ob nun
ein Interrupt auftritt, und dementsprechend ist es sicher, den Programmzählerwert
auf den nächsten
Java-Bytecode zu aktualisieren und die Ausführung von diesem Punkt aus
zu beginnen, da der Zustand des Systems dann die passende normale,
nicht unterbrochene vollständige Ausführung des
Java-Bytecodes erreicht hat. Wenn der Test in Schritt 20 anzeigt,
dass der letzte Bytecode noch nicht erreicht worden ist, so wird
die Aktualisierung des Programmzählerwertes
umgangen.
-
Schritt 22 führt den
aktuellen ARM-Befehl aus. In Schritt 24 wird ein Test vorgenommen,
ob es irgendwelche weiteren ARM-Befehle gibt, die als Teil der Schablone
eine Ausführung
erfordern oder nicht. Wenn es noch mehr ARM-Befehle gibt, dann wird
der nächste
hiervon in Schritt 26 ausgewählt und die Verarbeitung kehrt
zurück
zu Schritt 20. Wenn es keine weiteren Befehle gibt, so
geht die Verarbeitung weiter zu Schritt 28, wo irgendeine
Zuordnungsveränderung/Zuordnungswechsel,
der für
den betreffenden Java-Bytecode angegeben ist, durchgeführt wird,
um die gewünschte
oberste Position des Stapels und den Voll-/Leerzustand der verschiedenen
Register, welche Stapeloperanden halten, wiederzugeben.
-
8 veranschaulicht
weiterhin schematisch die Punkte, an welchen ein Interrupt, falls
er vorgebracht wird, bedient wird und dann die Verarbeitung nach
einem Interrupt wieder aufgenommen wird. Mit der Bedienung eines
Interrupt wird begonnen nach der Ausführung eines ARM-Befehls, der
aktuell in Schritt 22 in Verarbeitung ist, wie auch immer
der aktuelle Programmzählerwert
sein mag, der an einem Umkehrpunkt in der Bytecode-Sequenz gespeichert
ist. Wenn der aktuelle ARM-Befehl, der ausgeführt wird, der letzte Befehl
innerhalb der Schablonenfolge ist, so ist in Schritt 21 der
Programmzählerwert
gerade aktualisiert worden und dementsprechend weist dieser auf
den nächsten
Java-Bytecode (oder ARM-Befehl, falls eine Befehlssatzumschaltung
gerade ausgelöst
worden sein sollte) hin. Wenn der aktuell ablaufende ARM-Befehl
irgendein anderer als der letzte Befehl in der Folge ist, so bleibt
der Programmzählerwert
nach wie vor derselbe wie derjenige, der zu Beginn der Ausführung des
betreffenden Java-Bytecodes vorhanden war und dementsprechend wird, wenn
eine Umkehr vorgenommen wird, der gesamte Java-Bytecode erneut ausgeführt.
-
9 veranschaulicht
eine Bytecode-Übersetzungseinheit 68,
die einen Strom von Java-Bytecodes empfängt und einen übersetzten
Strom von ARM-Befehlen (oder entsprechende Steuersignale) ausgibt,
um die Arbeit eines Prozessorkerns zu steuern. Wie zuvor beschrieben übersetzt
der Java-Bytecode-Übersetzer 68 unter
Verwendung von Befehlsschablonen einfache Java-Bytecodes in ARM-Befehle
oder Sequenzen von ARM-Befehlen. Wenn jeweils ein Java-Bytecode ausgeführt worden
ist, so wird ein Zählerwert
innerhalb einer Plan- und Steuerlogik 70 herabgesetzt.
Wenn dieser Zählerwert
0 erreicht, so gibt die Java-Bytecode-Übersetzungseinheit 68 einen
ARM-Befehl aus, der in einen Planungscode verzweigt, welcher die
Planung zwischen Threads oder Aufgaben angemessen verwaltet.
-
Während einfache
Java-Bytecodes durch die Java-Bytecode-Übersetzungseinheit 68 selbst
gehandhabt werden, die auf der Basis der Ausführung dieser beiden Codes eine
Hochgeschwindigkeitshardware bereitstellt, werden Bytecodes, die
kompliziertere Verarbeitungsvorgänge
erfordern, an einen Softwareübersetzer
gesendet, der in Form einer Sammlung von Übersetzungsroutinen (Beispiele
einer Auswahl derartiger Routinen wurden schon oben in dieser Beschreibung
geliefert) bereitgestellt ist. Genauer gesagt kann für die Java-Bytecode-Übersetzungseinheit 68 festgelegt
werden, dass der Bytecode, den sie empfangen hat, nicht ein solcher
ist, der durch Hardwareübersetzung
unterstützt
wird, und dementsprechend kann eine Verzweigung zu einer anderen
von diesem Java-Bytecode abhängigen
Adresse vorgenommen werden, wo eine Softwareroutine bzw. ein Unterprogramm
zum Übersetzen
dieses Bytecodes vorgefunden oder aufgerufen wird. Dieser Mechanismus
kann auch verwendet werden, wenn die Planungslogik 70 anzeigt,
dass ein Planungsvorgang erforderlich ist, um eine Verzweigung zu
dem Planungscode hervorzubringen.
-
10 veranschaulicht
die Betriebsweise der Ausführungsform
nach 9 noch etwas genauer und auch die Aufspaltung
von Aufgaben zwischen Hardware und Software. Alle Java-Bytecodes werden
durch die Java-Bytecode-Übersetzungseinheit 68 empfangen
und bewirken, dass in Schritt 72 der Zähler herabgesetzt wird. In
Schritt 74 wird eine Überprüfung vorgenommen,
ob der Zählerwert
0 erreicht hat oder nicht. Wenn der Zählerwert 0 erreicht hat (Herunterzählen entweder
von einem vorbestimmten Wert, der in dem System hart verdrahtet
ist, oder von einem Wert, der durch den Benutzer gesteuert/programmiert
werden kann), so wird in Schritt 76 eine Verzweigung zu
dem Planungscode vorgenommen. Wenn der Planungscode in Schritt 76 abgeschlossen
ist, geht die Kontrolle zurück
an die Hardware und die Verarbeitung geht weiter zu Schritt 72,
wo der nächste
Java-Bytecode herangeholt und der Zähler erneut herabgesetzt wird.
Wenn der Zähler
eine 0 erreicht hat, wird er nunmehr zurückgeführt zu einem neuen Wert, der
nicht 0 ist. Alternativ kann ein neuer Wert in dem Zähler als
Teil des Anregens eines Planungsvorgangs in Schritt 76 erzwungen
werden.
-
Wenn
der Test in Schritt 74 angezeigt hat, dass der Zähler nicht
gleich 0 war, so holt der Schritt 78 den Java-Bytecode
heran. In Schritt 80 wird eine Feststellung getroffen,
ob der herangeholte Bytecode ein einfacher Bytecode ist, der durch
die Hardwareübersetzung
in Schritt 82 ausgeführt
werden kann, oder ob er eine kompliziertere Verarbeitung erfordert
und dementsprechend in Schritt 84 für eine Softwareübersetzung
nach außen
weitergeleitet werden sollte. Wenn die Verarbeitung zu der Softwareübersetzung
nach außen
weitergeleitet wird, so wird die Steuerung, nachdem dies abgeschlossen
ist, an die Hardware zurückgegeben,
wo Schritt 72 den Zähler
wieder herabsetzt, um das Heranholen des nächsten Java-Bytecodes zu berücksichtigen.
-
11 veranschaulicht
eine alternative Steuerungs- bzw. Kontrollanordnung. Zu Beginn der
Verarbeitung in Schritt 86 wird ein Anweisungssignal (Planungssignal)
zurückgenommen.
In Schritt 88 wird ein herangeholter Java-Bytecode untersucht,
um festzustellen, ob es ein einfacher Bytecode ist, für welchen
eine Hardwareübersetzung
unterstützt
wird. Wenn die Hardwareübersetzung
nicht unterstützt
wird, so wird die Steuerung in Schritt 90 an die Übersetzungssoftware
herausgegeben, welche dann eine ARM-Befehlsroutine ausführt, um
den Java-Bytecode zu übersetzen.
Wenn der Bytecode ein einfacher ist, für welchen eine Hardwareübersetzung
unterstützt
wird, so geht die Verarbeitung zu Schritt 92 weiter, wo
eine oder mehrere ARM-Befehle in Folge durch die Java-Bytecode-Übersetzungseinheit 68 ausgegeben
werden, die als eine Art von mehrheitlicher Zustandsmaschine bzw.
endlichem Automaten mit mehreren Zyklen arbeitet. Wenn der Java-Bytecode entweder
in Schritt 90 oder in Schritt 92 ordnungsgemäß ausgeführt wurde,
so geht die Verarbeitung weiter zu Schritt 94, wo das Befehlssignal
für eine
kurze Zeitdauer ansteht, bevor es in Schritt 86 zurückgenommen
wird. Das Vorbringen bzw. Anstehen des Befehlssignals zeigt einer
externen Schaltung an, dass ein geeigneter sicherer Punkt erreicht
worden ist, zu welchem eine auf einem Zeitgeber beruhende Planungsunterbrechung bzw.
Interrupt stattfinden könnte,
ohne dass man aufgrund einer nur teilweisen Ausführung eines umgesetzten oder übersetzten
Befehls das Risiko eines Verlustes der Datenintegrität hätte.
-
12 veranschaulicht
eine beispielhafte Schaltung, die verwendet werden kann, um auf
das in 11 erzeugte Befehlssignal zu
reagieren. Ein Zeitgeber 96 erzeugt periodisch ein Zeitgebersignal
nach dem Ablauf einer gegebenen Zeitdauer. Dieses Zeitgebersignal
wird in einem Zwischenspeicher 98 gespeichert, bis dieser
durch ein Interrupt-Signal zum Löschen
des Zeitgebers gelöscht
wird. Der Ausgang des Zwischenspeichers ist logisch über ein
UND-Gatter 100 mit dem in Schritt 94 anstehenden
Befehlssignal kombiniert. Wenn der Zwischenspeicher gesetzt und
das Befehlssignal vorgebracht ist, so wird ein Interrupt-Signal
als Ausgang des UND-Gatters 100 erzeugt
und verwendet, um einen Interrupt auszulösen, der Planungsvorgänge unter Verwendung
der Interrupt-Verarbeitungsmechanismen, die in dem System für eine standardmäßige Interrupt-Verarbeitung
bereitgestellt sind, durchführt.
Wenn das Interrupt-Signal erzeugt worden ist, löst dies wiederum die Erzeugung
eines Interrupt-Signals zum Löschen
des Zeitgebers aus, welches den Zwischenspeicher 98 löscht, bis
der nächste
Impuls eines Zeitgeberausgangs erfolgt.
-
13 ist
ein Signaldiagramm, welches die Betriebsweise des Schaltkreises
nach 12 veranschaulicht. Die Taktsignale des Prozessorkernes
erfolgen mit einer regelmäßigen Frequenz.
Der Zeitgeber 96 erzeugt Zeitgebersignale zu vorbestimmten
Perioden, um anzuzeigen, dass bei Sicherheit ein Planungsvorgang
ausgelöst
werden sollte. Die Zeitgebersignale werden zwischengespeichert.
Befehlssignale werden zu Zeitpunkten erzeugt, die durch Intervalle
voneinander getrennt sind, welche davon abhängen, wie schnell ein bestimmter
Java-Bytecode ausgeführt
wurde. Ein einfacher Java-Bytecode kann in einem einzigen Taktzyklus des
Prozessorkerns ausgeführt
werden, oder typischer eher in zwei oder drei Taktzyklen, wohingegen
ein komplexer Java-Bytecode, der eine verwaltungsartige Funktion
auf hohem Niveau bereitstellt, mehrere 100 Taktzyklen des Prozessors
benötigen
kann, bevor seine Ausführung
durch den Softwareübersetzer
abgeschlossen ist. In jedem Fall wird auf ein anstehendes, vorgeberachtes,
zwischengespeichertes Zeitgebersignal nicht so eingewirkt, dass
es einen Planungsvorgang auslöst,
bevor nicht das Befehlssignal ausgegeben wird, was anzeigt, dass
der Planungsvorgang sicher beginnen kann. Das gleichzeitige Auftreten
eines zwischengespeicherten Zeitgebersignals und des Befehlssignals
löst die
Erzeugung eines Interrupt-Signals aus, worauf unmittelbar ein Löschsignal
folgt, das den Zwischenspeicher 98 löscht.