Adressierungsmodus - Addressing mode

Adressierungsmodi sind ein Aspekt der Befehlssatzarchitektur in den meisten Designs von Zentraleinheiten (CPUs). Die verschiedenen Adressierungsmodi , die in einer gegebenen Befehlssatzarchitektur definiert sind , definiert , wie die Maschinensprache - Anweisungen in dieser Architektur den identifizieren Operanden (n) jeden Befehl. Ein Adressierungsmodus spezifiziert, wie die effektive Speicheradresse eines Operanden zu berechnen ist, indem Informationen verwendet werden, die in Registern und/oder Konstanten gehalten werden, die in einem Maschinenbefehl oder anderswo enthalten sind.

In der Computerprogrammierung sind Adressierungsmodi in erster Linie für diejenigen interessant, die in Assemblersprachen schreiben, und für Compiler- Autoren. Für ein verwandtes Konzept siehe orthogonaler Befehlssatz, der sich mit der Fähigkeit eines Befehls befasst, jeden Adressierungsmodus zu verwenden.

Vorbehalte

Beachten Sie, dass es keine allgemein akzeptierte Möglichkeit gibt, die verschiedenen Adressierungsmodi zu benennen. Insbesondere können verschiedene Autoren und Computerhersteller dem gleichen Adressierungsmodus unterschiedliche Namen oder verschiedenen Adressierungsmodi die gleichen Namen geben. Darüber hinaus kann ein Adressierungsmodus, der in einer gegebenen Architektur als ein einzelner Adressierungsmodus behandelt wird, eine Funktionalität darstellen, die in einer anderen Architektur durch zwei oder mehr Adressierungsmodi abgedeckt wird. Beispielsweise behandeln einige Computerarchitekturen mit komplexem Befehlssatz (CISC) wie beispielsweise die Digital Equipment Corporation (DEC) VAX Register und wörtliche oder unmittelbare Konstanten als nur einen anderen Adressierungsmodus. Andere, wie das IBM System/360 und seine Nachfolger, und die meisten Computer mit reduziertem Befehlssatz (RISC) codieren diese Informationen innerhalb des Befehls. Somit haben letztere Maschinen drei verschiedene Befehlscodes zum Kopieren eines Registers in ein anderes, zum Kopieren einer Literalkonstante in ein Register und zum Kopieren des Inhalts einer Speicherstelle in ein Register, während der VAX nur einen einzigen "MOV"-Befehl hat.

Der Begriff "Adressierungsmodus" selbst unterliegt unterschiedlichen Interpretationen: entweder "Speicheradressen-Berechnungsmodus" oder "Operandenzugriffsmodus". Gemäß der ersten Interpretation werden Anweisungen, die nicht aus dem Speicher lesen oder in den Speicher schreiben (wie "Add Literal to register"), als nicht "Adressierungsmodus" angesehen. Die zweite Interpretation ermöglicht Maschinen wie VAX, die Operandenmodusbits verwenden, um ein Register oder einen Literaloperanden zu ermöglichen. Für Anweisungen wie "Effektive Adresse laden" gilt nur die erste Interpretation.

Die unten aufgeführten Adressierungsmodi sind in Codeadressierung und Datenadressierung unterteilt. Die meisten Computerarchitekturen behalten diese Unterscheidung bei, aber es gibt (oder gab) einige Architekturen, die es ermöglichen, (fast) alle Adressierungsmodi in jedem Kontext zu verwenden.

Die unten gezeigten Anweisungen sind rein repräsentativ, um die Adressierungsmodi zu veranschaulichen, und spiegeln nicht notwendigerweise die von einem bestimmten Computer verwendeten Mnemoniken wider.

Anzahl der Adressierungsmodi

Unterschiedliche Computerarchitekturen variieren stark hinsichtlich der Anzahl von Adressierungsmodi, die sie in der Hardware bereitstellen. Es gibt einige Vorteile, komplexe Adressierungsmodi zu eliminieren und nur einen oder wenige einfachere Adressierungsmodi zu verwenden, obwohl dies einige zusätzliche Befehle und möglicherweise ein zusätzliches Register erfordert. Es hat sich als viel einfacher erwiesen, CPUs mit Pipeline zu entwerfen, wenn die einzigen verfügbaren Adressierungsmodi einfache sind.

Die meisten RISC-Architekturen haben nur etwa fünf einfache Adressierungsmodi, während CISC-Architekturen wie der DEC VAX über ein Dutzend Adressierungsmodi haben, von denen einige ziemlich kompliziert sind. Die IBM System/360- Architektur hatte nur drei Adressierungsmodi; einige weitere sind für das System/390 hinzugekommen .

Wenn nur wenige Adressierungsmodi vorhanden sind, wird der jeweils erforderliche Adressierungsmodus normalerweise im Befehlscode codiert (zB IBM System/360 und Nachfolger, die meisten RISC). Wenn es jedoch viele Adressierungsmodi gibt, wird in der Anweisung oft ein spezielles Feld zur Angabe des Adressierungsmodus beiseite gelegt. Der DEC VAX erlaubte mehrere Speicheroperanden für fast alle Befehle und reservierte so die ersten paar Bits jedes Operandenspezifizierers, um den Adressierungsmodus für diesen bestimmten Operanden anzuzeigen. Das getrennte Halten der Adressierungsmodusspezifiziererbits von den Operationscode-Operationsbits erzeugt einen orthogonalen Befehlssatz .

Sogar auf einem Computer mit vielen Adressierungsmodi zeigen Messungen von tatsächlichen Programmen, dass die unten aufgeführten einfachen Adressierungsmodi etwa 90% oder mehr aller verwendeten Adressierungsmodi ausmachen. Da die meisten dieser Messungen auf Code basieren, der von Compilern aus höheren Sprachen generiert wurde, spiegelt dies in gewissem Maße die Einschränkungen der verwendeten Compiler wider.

Nützliche Nebenwirkung

Einige Befehlssatzarchitekturen, wie beispielsweise Intel x86 und IBM/360 und deren Nachfolger, haben einen effektiven Adressladebefehl . Dies führt eine Berechnung der effektiven Operandenadresse durch, aber anstatt auf diesen Speicherplatz einzuwirken, lädt es die Adresse, auf die zugegriffen worden wäre, in ein Register. Dies kann nützlich sein, wenn Sie die Adresse eines Array-Elements an eine Unterroutine übergeben. Es kann auch eine etwas hinterhältige Methode sein, mehr Berechnungen als normal in einer Anweisung durchzuführen; die Verwendung eines solchen Befehls mit dem Adressierungsmodus "Basis+Index+Offset" (siehe unten) ermöglicht es beispielsweise, zwei Register und eine Konstante in einem Befehl zu addieren.

Einfache Adressierungsmodi für Code

Absolut oder direkt

   +----+------------------------------+
   |jump|           address            |
   +----+------------------------------+

   (Effective PC address = address)

Die effektive Adresse für eine absolute Befehlsadresse ist der Adressparameter selbst ohne Änderungen.

PC-bezogen

   +----+------------------------------+
   |jump|           offset             |    jump relative
   +----+------------------------------+

   (Effective PC address = next instruction address + offset, offset may be negative)

Die effektive Adresse für eine PC- relative Befehlsadresse ist der Offset-Parameter, der zur Adresse des nächsten Befehls hinzugefügt wird. Dieser Offset ist normalerweise mit einem Vorzeichen versehen, um sowohl vor als auch nach dem Befehl einen Verweis auf den Code zu ermöglichen.

Dies ist besonders in Verbindung mit Sprüngen nützlich, da typische Sprünge zu nahegelegenen Anweisungen erfolgen (in einer Hochsprache sind die meisten if- oder while- Anweisungen relativ kurz). Messungen an aktuellen Programmen legen nahe, dass ein 8- oder 10-Bit-Offset für etwa 90% der bedingten Sprünge (ungefähr ±128 oder ±512 Byte) groß genug ist.

Ein weiterer Vorteil der PC-relativen Adressierung besteht darin, dass der Code positionsunabhängig sein kann, dh er kann überall in den Speicher geladen werden, ohne dass irgendwelche Adressen angepasst werden müssen.

Einige Versionen dieses Adressierungsmodus beziehen sich möglicherweise auf zwei Register ("jump if reg1=reg2"), ein Register ("jump without reg1=0") oder keine Register, die sich implizit auf ein zuvor gesetztes Bit im Statusregister beziehen . Siehe auch bedingte Ausführung unten.

Indirekt registrieren

   +-------+-----+
   |jumpVia| reg |
   +-------+-----+

   (Effective PC address = contents of register 'reg')

Die effektive Adresse für einen indirekten Registerbefehl ist die Adresse im angegebenen Register. Zum Beispiel (A7), um auf den Inhalt des Adressregisters A7 zuzugreifen.

Der Effekt besteht darin, die Steuerung an den Befehl zu übertragen, dessen Adresse sich im angegebenen Register befindet.

Viele RISC-Maschinen sowie das CISC IBM System/360 und Nachfolger verfügen über Subroutinenaufrufbefehle, die die Rückkehradresse in ein Adreßregister stellen – der registerindirekte Adressierungsmodus wird verwendet, um von diesem Subroutinenaufruf zurückzukehren.

Sequentielle Adressierungsmodi

Sequentielle Ausführung

   +------+
   | nop  |              execute the following instruction
   +------+

   (Effective PC address = next instruction address)

Die CPU führt nach der Ausführung eines sequentiellen Befehls sofort den folgenden Befehl aus.

Auf einigen Computern wird die sequentielle Ausführung nicht als Adressierungsmodus angesehen.

Die meisten Befehle auf den meisten CPU-Architekturen sind sequentielle Befehle. Da es sich bei den meisten Befehlen um sequentielle Befehle handelt, fügen CPU-Designer häufig Funktionen hinzu, die den anderen Befehlen – Verzweigungsbefehlen – absichtlich die Leistung opfern, damit diese sequentiellen Befehle schneller ausgeführt werden.

Bedingte Verzweigungen laden den PC mit einem von 2 möglichen Ergebnissen, abhängig von der Bedingung – die meisten CPU-Architekturen verwenden einen anderen Adressierungsmodus für den "genommenen" Zweig und die sequentielle Ausführung für den "nicht genommenen" Zweig.

Viele Funktionen moderner CPUs – Befehlsvorabruf und komplexeres Pipelineing , Ausführung in falscher Reihenfolge usw. – bewahren die Illusion, dass jeder Befehl beendet ist, bevor der nächste beginnt, was zu den gleichen Endergebnissen führt, auch wenn dies intern nicht genau der Fall ist .

Jeder „ Grundblock “ solcher sequentieller Befehle weist sowohl eine zeitliche als auch eine räumliche Referenzlokalität auf .

CPUs, die keine sequentielle Ausführung verwenden

CPUs, die keine sequentielle Ausführung mit einem Programmzähler verwenden, sind äußerst selten. In einigen CPUs gibt jeder Befehl immer die Adresse des nächsten Befehls an. Solche CPUs haben einen Befehlszeiger, der diese angegebene Adresse hält; es ist kein Programmzähler, weil es nicht vorgesehen ist, ihn zu inkrementieren. Solche CPUs umfassen einige Trommelspeichercomputer, wie den IBM 650 , den SECD-Rechner und den RTX 32P.

Andere Computerarchitekturen gehen viel weiter und versuchen, den von Neumann-Engpass mit einer Vielzahl von Alternativen zum Programmzähler zu umgehen .

Bedingte Ausführung

Einige Computerarchitekturen haben bedingte Befehle (wie ARM , aber nicht mehr für alle Befehle im 64-Bit-Modus) oder bedingte Ladebefehle (wie x86), die in einigen Fällen bedingte Verzweigungen unnötig machen und das Leeren der Befehlspipeline vermeiden können . Eine Anweisung wie "Vergleichen" wird verwendet, um einen Bedingungscode zu setzen , und nachfolgende Anweisungen enthalten einen Test auf diesen Bedingungscode, um zu sehen, ob sie befolgt oder ignoriert werden.

Überspringen

   +------+-----+-----+
   |skipEQ| reg1| reg2|      skip the next instruction if reg1=reg2
   +------+-----+-----+

   (Effective PC address = next instruction address + 1)

Die Sprungadressierung kann als eine spezielle Art des PC-relativen Adressierungsmodus mit einem festen "+1"-Offset angesehen werden. Wie bei der PC-relativen Adressierung haben einige CPUs Versionen dieses Adressierungsmodus, die sich nur auf ein Register ("skip if reg1=0") oder keine Register beziehen und sich implizit auf ein zuvor gesetztes Bit im Statusregister beziehen . Andere CPUs haben eine Version, die ein bestimmtes Bit in einem bestimmten Byte zum Testen auswählt ("skip if bit 7 of reg12 is 0").

Im Gegensatz zu allen anderen bedingten Verzweigungen muss ein "Überspringen"-Befehl niemals die Befehlspipeline spülen , obwohl er möglicherweise veranlassen muss, dass der nächste Befehl ignoriert wird.

Einfache Adressierungsmodi für Daten

Registrieren (oder direkt registrieren)

   +------+-----+-----+-----+
   | mul  | reg1| reg2| reg3|      reg1 := reg2 * reg3;
   +------+-----+-----+-----+

Dieser "Adressierungsmodus" hat keine effektive Adresse und wird auf einigen Computern nicht als Adressierungsmodus angesehen.

In diesem Beispiel befinden sich alle Operanden in Registern und das Ergebnis wird in einem Register abgelegt.

Basis plus Offset und Variationen

Dies wird manchmal als "Basis plus Verschiebung" bezeichnet.

   +------+-----+-----+----------------+
   | load | reg | base|     offset     |  reg := RAM[base + offset]
   +------+-----+-----+----------------+

   (Effective address = offset + contents of specified base register)

Der Offset ist normalerweise ein 16-Bit-Wert mit Vorzeichen (obwohl der 80386 ihn auf 32 Bit erweitert hat).

Wenn der Offset null ist, wird dies ein Beispiel für eine indirekte Registeradressierung ; die effektive Adresse ist nur der Wert im Basisregister.

Auf vielen RISC-Maschinen ist Register 0 auf den Wert Null festgelegt. Wenn Register 0 als Basisregister verwendet wird, wird dies zu einem Beispiel für absolute Adressierung . Es kann jedoch nur auf einen kleinen Teil des Speichers zugegriffen werden (64 Kilobyte , wenn der Offset 16 Bit beträgt).

Der 16-Bit-Offset mag im Verhältnis zur Größe aktueller Computerspeicher sehr klein erscheinen (weshalb der 80386 ihn auf 32-Bit erweitert hat). Es könnte noch schlimmer kommen: IBM System/360 Mainframes haben nur einen vorzeichenlosen 12-Bit-Offset. Es gilt jedoch das Prinzip der Referenzlokalität : Über einen kurzen Zeitraum liegen die meisten Datenelemente, auf die ein Programm zugreifen möchte, ziemlich nahe beieinander.

Dieser Adressierungsmodus ist eng mit dem indizierten absoluten Adressierungsmodus verwandt.

Beispiel 1 : Innerhalb eines Unterprogramms interessiert sich ein Programmierer hauptsächlich für die Parameter und die lokalen Variablen, die selten 64 KB überschreiten , wofür ein Basisregister (der Rahmenzeiger ) ausreicht. Wenn diese Routine eine Klassenmethode in einer objektorientierten Sprache ist, dann wird ein zweites Basisregister benötigt, das auf die Attribute für das aktuelle Objekt zeigt ( this oder self in einigen höheren Sprachen).

Beispiel 2 : Wenn das Basisregister die Adresse eines zusammengesetzten Typs enthält (ein Datensatz oder eine Struktur), kann der Offset verwendet werden, um ein Feld aus diesem Datensatz auszuwählen (die meisten Datensätze/Strukturen sind kleiner als 32 kB).

Unmittelbar/wörtlich

   +------+-----+-----+----------------+
   | add  | reg1| reg2|    constant    |    reg1 := reg2 + constant;
   +------+-----+-----+----------------+

Dieser "Adressierungsmodus" hat keine effektive Adresse und wird auf einigen Computern nicht als Adressierungsmodus angesehen.

Die Konstante kann mit oder ohne Vorzeichen sein. Um beispielsweise move.l #$FEEDABBA, D0den unmittelbaren Hex-Wert von "FEEDABBA" in das Register D0 zu verschieben.

Anstatt einen Operanden aus dem Speicher zu verwenden, wird der Wert des Operanden in der Anweisung selbst gehalten. Auf der DEC-VAX-Maschine können die Literaloperandengrößen 6, 8, 16 oder 32 Bit lang sein.

Andrew Tanenbaum zeigte, dass 98% aller Konstanten in einem Programm in 13 Bit passen (siehe RISC-Designphilosophie ).

Implizit

   +-----------------+
   | clear carry bit |
   +-----------------+

   +-------------------+
   | clear Accumulator |
   +-------------------+

Der implizite Adressierungsmodus, auch impliziter Adressierungsmodus ( x86-Assemblersprache ) genannt, gibt weder für die Quelle noch für das Ziel (oder manchmal für beide) explizit eine effektive Adresse an.

Entweder die effektive Quelladresse (falls vorhanden) oder die effektive Zieladresse (oder manchmal beides) wird durch den Opcode impliziert.

Implizite Adressierung war auf älteren Computern (bis Mitte der 1970er Jahre) recht verbreitet. Solche Computer hatten typischerweise nur ein einziges Register, in dem arithmetisch ausgeführt werden konnte – den Akkumulator. Solche Akkumulatormaschinen verweisen implizit in fast jedem Befehl auf diesen Akkumulator. Zum Beispiel die Operation < a := b + c; > kann mit der Sequenz < load b; c hinzufügen; speichern a; > -- das Ziel (der Akkumulator) ist in jeder "load"- und "add"-Anweisung enthalten; die Quelle (der Akkumulator) ist in jedem "Speicher"-Befehl enthalten.

Spätere Computer hatten im Allgemeinen mehr als ein Allzweckregister oder einen RAM-Speicherort, der Quelle oder Ziel oder beides für die Arithmetik sein konnte – und daher benötigen spätere Computer einen anderen Adressierungsmodus, um die Quelle und das Ziel der Arithmetik anzugeben.

Unter den x86-Befehlen verwenden einige implizite Register für einen der Operanden oder Ergebnisse (Multiplikation, Division, bedingter Zählsprung).

Viele Computer (wie x86 und AVR) haben ein Spezialregister namens Stack-Zeiger, das beim Pushen oder Popup von Daten vom Stack implizit inkrementiert oder dekrementiert wird, und die effektive Quell- oder Zieladresse ist (implizit) die darin gespeicherte Adresse Stapelzeiger.

Viele 32-Bit-Computer (wie 68000, ARM oder PowerPC) haben mehr als ein Register, das als Stapelzeiger verwendet werden könnte – und verwenden Sie daher den Adressierungsmodus "Register Autoincrement indirekt", um anzugeben, welches dieser Register wann verwendet werden soll Pushen oder Popping von Daten von einem Stack.

Einige aktuelle Computerarchitekturen (zB IBM/390 und Intel Pentium) enthalten einige Befehle mit impliziten Operanden, um die Rückwärtskompatibilität mit früheren Designs aufrechtzuerhalten.

Auf vielen Computern geben Anweisungen, die das Benutzer-/Systemmodusbit, das Interrupt-Aktivierungsbit usw. umdrehen, implizit das spezielle Register an, das diese Bits enthält. Dies vereinfacht die Hardware, die zum Abfangen dieser Befehle erforderlich ist, um die Virtualisierungsanforderungen von Popek und Goldberg zu erfüllen – auf einem solchen System muss die Trap-Logik keinen Operanden (oder die endgültige effektive Adresse) betrachten, sondern nur den Opcode .

Es wurden einige CPUs entwickelt, bei denen jeder Operand immer implizit in jeder Anweisung angegeben ist – Null-Operanden- CPUs.

Andere Adressierungsmodi für Code oder Daten

Absolut/direkt

   +------+-----+--------------------------------------+
   | load | reg |         address                      |
   +------+-----+--------------------------------------+

   (Effective address = address as given in instruction)

Dies erfordert Platz in einem Befehl für eine ziemlich große Adresse. Es ist oft auf CISC-Computern verfügbar, die Befehle variabler Länge haben, wie z. B. x86 .

Einige RISC-Maschinen haben einen speziellen Load Upper Literal- Befehl, der eine 16- oder 20-Bit-Konstante in der oberen Hälfte eines Registers platziert. Dieses kann dann als Basisregister in einem Basis-plus-Offset-Adressierungsmodus verwendet werden, der die 16 oder 12 Bit niedriger Ordnung liefert. Die Kombination ermöglicht eine vollständige 32-Bit-Adresse.

Indiziert absolut

   +------+-----+-----+--------------------------------+
   | load | reg |index|         address                |
   +------+-----+-----+--------------------------------+

   (Effective address = address + contents of specified index register)

Dies erfordert auch Platz in einem Befehl für eine ziemlich große Adresse. Die Adresse könnte der Anfang eines Arrays oder Vektors sein, und der Index könnte das bestimmte erforderliche Arrayelement auswählen. Der Prozessor kann das Indexregister skalieren, um die Größe jedes Array-Elements zu berücksichtigen .

Beachten Sie, dass dies mehr oder weniger dem Adressierungsmodus Basis plus Offset entspricht, außer dass der Offset in diesem Fall groß genug ist, um jede beliebige Speicherstelle zu adressieren.

Beispiel 1 : Innerhalb eines Unterprogramms kann ein Programmierer einen String als lokale Konstante oder statische Variable definieren . Die Adresse des Strings wird in der Literaladresse in der Anweisung gespeichert. Der Offset – welches Zeichen des Strings bei dieser Iteration einer Schleife verwendet werden soll – wird im Indexregister gespeichert.

Beispiel 2 : Ein Programmierer kann mehrere große Arrays als Globals oder als Klassenvariablen definieren . Der Anfang des Arrays wird in der Literaladresse (möglicherweise zur Programmladezeit durch einen sich verlagernden Loader geändert ) der Anweisung gespeichert, die darauf verweist. Der Offset – welches Element aus dem Array für diese Iteration einer Schleife verwendet werden soll – wird im Indexregister gespeichert. Häufig verwenden die Befehle in einer Schleife dasselbe Register für den Schleifenzähler und die Offsets mehrerer Arrays.

Basis plus Index

   +------+-----+-----+-----+
   | load | reg | base|index|
   +------+-----+-----+-----+

   (Effective address = contents of specified base register + contents of specified index register)

Das Basisregister könnte die Startadresse eines Arrays oder Vektors enthalten, und der Index könnte das bestimmte erforderliche Arrayelement auswählen. Der Prozessor kann das Indexregister skalieren , um die Größe jedes Array-Elements zu berücksichtigen . Dies könnte für den Zugriff auf Elemente eines als Parameter übergebenen Arrays verwendet werden.

Basis plus Index plus Offset

   +------+-----+-----+-----+----------------+
   | load | reg | base|index|         offset |
   +------+-----+-----+-----+----------------+

   (Effective address = offset + contents of specified base register + contents of specified index register)

Das Basisregister könnte die Startadresse eines Arrays oder Vektors von Datensätzen enthalten, der Index könnte den speziellen erforderlichen Datensatz auswählen und der Offset könnte ein Feld innerhalb dieses Datensatzes auswählen. Der Prozessor kann das Indexregister skalieren, um die Größe jedes Array-Elements zu berücksichtigen .

Skaliert

   +------+-----+-----+-----+
   | load | reg | base|index|
   +------+-----+-----+-----+

   (Effective address = contents of specified base register + scaled contents of specified index register)

Das Basisregister könnte die Startadresse eines Arrays oder einer Vektordatenstruktur enthalten , und der Index könnte den Offset des einen bestimmten erforderlichen Arrayelements enthalten.

Dieser Adressierungsmodus skaliert den Wert im Indexregister dynamisch, um die Größe jedes Arrayelements zu berücksichtigen. Wenn die Arrayelemente z. B. Gleitkommazahlen mit doppelter Genauigkeit sind, die jeweils 8 Byte belegen, wird der Wert im Indexregister mit 8 multipliziert, bevor er bei der Berechnung der effektiven Adresse verwendet. Der Skalierungsfaktor ist normalerweise auf eine Zweierpotenz beschränkt , so dass eine Verschiebung statt einer Multiplikation verwendet werden kann.

Indirekt registrieren

   +------+------+-----+
   | load | reg1 | base|
   +------+------+-----+
 
   (Effective address = contents of base register)

Einige Computer haben dies als unterschiedlichen Adressierungsmodus. Viele Computer verwenden nur Basis plus Offset mit einem Offset-Wert von 0. Beispiel: (A7)

Autoinkrement indirekt registrieren

   +------+-----+-------+
   | load | reg | base  |
   +------+-----+-------+

   (Effective address = contents of base register)

Nach der Ermittlung der effektiven Adresse wird der Wert im Basisregister um die Größe des Datenelements, auf das zugegriffen werden soll, inkrementiert. Zum Beispiel würde (A7)+ auf den Inhalt des Adressregisters A7 zugreifen und dann den Adresszeiger von A7 um 1 (normalerweise 1 Wort) erhöhen. Innerhalb einer Schleife kann dieser Adressierungsmodus verwendet werden, um alle Elemente eines Arrays oder Vektors zu durchlaufen.

In Hochsprachen wird oft angenommen, dass Funktionen, die ein Ergebnis zurückgeben, keine Nebenwirkungen haben sollten (das Fehlen von Nebenwirkungen erleichtert das Verständnis und die Validierung des Programms erheblich). Dieser Adressierungsmodus hat den Nebeneffekt, dass das Basisregister geändert wird. Führt der anschließende Speicherzugriff zu einem Fehler (zB Seitenfehler, Busfehler, Adressfehler), der zu einem Interrupt führt, wird der Neustart der Anweisung wesentlich problematischer, da ggf die Anweisung begann ursprünglich.

Es hat mindestens zwei Computerarchitekturen gegeben, bei denen Implementierungsprobleme in Bezug auf die Wiederherstellung von Interrupts aufgetreten sind, wenn dieser Adressierungsmodus verwendet wird:

  • Motorola 68000 (Adresse wird in 24 Bit dargestellt). Könnte einen oder zwei Autoinkrement-Registeroperanden haben. Der 68010+ löste das Problem, indem er den internen Zustand des Prozessors bei Bus- oder Adressfehlern speicherte .
  • DEZ VAX. Kann bis zu 6 Autoinkrement-Registeroperanden haben. Jeder Operandenzugriff könnte zwei Seitenfehler verursachen (wenn Operanden zufällig eine Seitengrenze überspannen). Natürlich kann die Anweisung selbst über 50 Byte lang sein und auch eine Seitengrenze überschreiten!

Autodekrement indirekt registrieren

   +------+-----+-----+
   | load | reg | base|
   +------+-----+-----+

   (Effective address = new contents of base register)

Vor der Bestimmung der effektiven Adresse wird der Wert im Basisregister um die Größe des Datenelements, auf das zugegriffen werden soll, dekrementiert.

Innerhalb einer Schleife kann dieser Adressierungsmodus verwendet werden, um rückwärts durch alle Elemente eines Arrays oder Vektors zu gehen. Ein Stack kann implementiert werden, indem dieser Modus in Verbindung mit dem vorherigen Adressierungsmodus (Autoinkrement) verwendet wird.

Siehe die Diskussion der Nebenwirkungen im Adressierungsmodus Autoinkrement .

Speicher indirekt

Jeder der in diesem Artikel erwähnten Adressierungsmodi könnte ein zusätzliches Bit haben, um die indirekte Adressierung anzuzeigen, dh die mit einem Modus berechnete Adresse ist tatsächlich die Adresse einer Stelle (typischerweise ein vollständiges Wort ), die die tatsächliche effektive Adresse enthält.

Für Code oder Daten kann eine indirekte Adressierung verwendet werden. Es kann die Implementierung von Zeigern , Referenzen oder Handles viel einfacher machen und kann auch das Aufrufen von Unterprogrammen erleichtern, die sonst nicht adressierbar sind. Die indirekte Adressierung bringt aufgrund des zusätzlichen Speicherzugriffs eine Leistungseinbuße mit sich.

Einige frühe Minicomputer (zB DEC PDP-8 , Data General Nova ) hatten nur wenige Register und nur einen begrenzten Adressierungsbereich (8 Bit). Daher war die Verwendung der indirekten Speicheradressierung fast die einzige Möglichkeit, sich auf eine signifikante Speichermenge zu beziehen.

PC-bezogen

   +------+------+---------+----------------+
   | load | reg1 | base=PC |     offset     |
   +------+------+---------+----------------+

   reg1 := RAM[PC + offset]
   (Effective address = PC + offset)

Der PC-relative Adressierungsmodus kann verwendet werden, um ein Register mit einem Wert zu laden, der im Programmspeicher in kurzer Entfernung vom aktuellen Befehl gespeichert ist. Er kann als Sonderfall des Adressierungsmodus "Basis plus Offset" angesehen werden, der den Programmzähler (PC) als "Basisregister" auswählt.

Es gibt einige CPUs, die PC-relative Datenreferenzen unterstützen. Zu diesen CPUs gehören:

Der MOS 6502 und seine Derivate verwendeten eine relative Adressierung für alle Verzweigungsbefehle . Nur diese Befehle verwenden diesen Modus, Sprünge verwenden eine Vielzahl anderer Adressierungsmodi.

Die x86-64- Architektur und die 64-Bit- ARMv8-A- Architektur verfügen über PC-relative Adressierungsmodi, die in x86-64 "RIP-relativ" und in ARMv8-A "literal" genannt werden. Das Motorola 6809 unterstützt auch einen PC-relativen Adressierungsmodus.

Die PDP-11- Architektur, die VAX- Architektur und die 32-Bit- ARM-Architekturen unterstützen die PC-relative Adressierung, indem sie den PC in der Registerdatei haben.

Die IBM z/Architecture enthält spezifische Anweisungen, zB Load Relative Long, mit PC-relativer Adressierung, wenn die General-Instructions-Extension-Facility aktiv ist.

Wenn dieser Adressierungsmodus verwendet wird, platziert der Compiler die Konstanten normalerweise in einem Literalpool unmittelbar vor oder unmittelbar nach der Unterroutine, die sie verwendet, um zu verhindern, dass diese Konstanten versehentlich als Anweisungen ausgeführt werden.

Dieser Adressierungsmodus, der immer Daten aus dem Speicher holt oder Daten im Speicher ablegt und dann sequentiell durchfällt, um den nächsten Befehl auszuführen (die effektive Adresse zeigt auf Daten), sollte nicht mit "PC-relativer Zweig" verwechselt werden, der keine Daten holt von oder speichert Daten in den Speicher, sondern verzweigt stattdessen zu einem anderen Befehl am gegebenen Offset (die effektive Adresse zeigt auf einen ausführbaren Befehl).

Veraltete Adressierungsmodi

Die hier aufgeführten Adressierungsmodi wurden in den Jahren 1950-1980 verwendet, sind jedoch auf den meisten aktuellen Computern nicht mehr verfügbar. Diese Liste ist keineswegs vollständig; es wurden von Zeit zu Zeit viele andere interessante und eigentümliche Adressierungsmodi verwendet, zB absolutes-minus-logisches-ODER von zwei oder drei Indexregistern.

Multi-Level-Speicher indirekt

Wenn die Wortgröße größer als die Adresse ist, könnte das Wort, auf das für die speicherindirekte Adressierung verwiesen wird, selbst ein indirektes Flag gesetzt haben, um einen anderen indirekten Speicherzyklus anzuzeigen. Dieses Flag wird als Indirektionsbit bezeichnet , und der resultierende Zeiger ist ein markierter Zeiger , wobei das Indirektionsbit markiert, ob es ein direkter oder ein indirekter Zeiger ist. Es ist darauf zu achten, dass eine Kette indirekter Adressen nicht auf sich selbst verweist; Wenn dies der Fall ist, kann man beim Versuch, eine Adresse aufzulösen, eine Endlosschleife erhalten .

Der IBM 1620 , der Data General Nova , die HP 2100- Serie und der NAR 2 haben jeweils einen solchen indirekten Speicher mit mehreren Ebenen und könnten in eine solche unendliche Adressberechnungsschleife eintreten. Der indirekte Speicheradressierungsmodus auf der Nova beeinflusste die Erfindung des indirekten Thread-Codes .

Der Computer DEC PDP-10 mit 18-Bit- Adressen und 36-Bit-Worten ermöglichte eine indirekte Mehrebenen-Adressierung mit der Möglichkeit, in jeder Stufe auch ein Indexregister zu verwenden. Das Prioritäts-Interrupt-System wurde vor der Dekodierung jedes Adresswortes abgefragt. Eine indirekte Adressschleife würde also die Ausführung von Gerätedienstroutinen, einschließlich des Zeitscheibenablauf-Handlers eines präemptiven Multitasking- Schedulers, nicht verhindern . Ein Schleifenbefehl würde wie jeder andere rechengebundene Job behandelt werden.

Speicherabgebildete Register

Auf einigen Computern wurde davon ausgegangen, dass die Register die ersten 8 oder 16 Wörter des Speichers belegen (zB ICL 1900 , DEC PDP-10). Dies bedeutete, dass kein separater Befehl „Register zum Register hinzufügen“ erforderlich war – man konnte einfach den Befehl „Speicher zum Register hinzufügen“ verwenden.

Bei den frühen Modellen des PDP-10, die keinen Cache-Speicher hatten, lief eine enge innere Schleife, die in die ersten paar Wörter des Speichers geladen wurde (wo die schnellen Register adressierbar waren, wenn sie installiert waren), viel schneller als zuvor Magnetkernspeicher.

Spätere Modelle der DEC- PDP-11- Serie bildeten die Register auf Adressen im Ein-/Ausgabebereich ab, dies sollte jedoch in erster Linie eine Ferndiagnose ermöglichen. Verwirrenderweise wurden die 16-Bit-Register auf aufeinanderfolgende 8-Bit-Byte-Adressen abgebildet.

Speicher indirekt und Autoinkrement

Der Minicomputer DEC PDP-8 hatte acht spezielle Standorte (an den Adressen 8 bis 15). Beim Zugriff über eine indirekte Speicheradressierung würden diese Stellen nach der Verwendung automatisch inkrementiert. Dies machte es einfach, in einer Schleife durch den Speicher zu gehen, ohne Register verwenden zu müssen, um die Schritte zu verarbeiten.

Der Data General Nova- Minicomputer hatte 16 spezielle Speicherplätze an den Adressen 16 bis 31. Beim Zugriff über die indirekte Speicheradressierung würden 16 bis 23 vor der Verwendung automatisch inkrementiert und 24 bis 31 würden vor der Verwendung automatisch verringert.

Nullseite

Die Prozessoren der Data General Nova- , Motorola 6800- und MOS Technology 6502- Familie hatten sehr wenige interne Register. Arithmetische und logische Befehle wurden im Gegensatz zu internen Registern meist gegen Werte im Speicher ausgeführt. Als Ergebnis erforderten viele Befehle eine Speicherstelle von zwei Byte (16 Bit). Da Opcodes auf diesen Prozessoren nur ein Byte (8 Bit) lang waren, konnten Speicheradressen einen erheblichen Teil der Codegröße ausmachen.

Die Entwickler dieser Prozessoren haben eine teilweise Abhilfe geschaffen, die als "Nullseiten"-Adressierung bekannt ist. Auf die anfänglichen 256 Bytes des Speichers ($0000 – $00FF; auch bekannt als Seite "0") könnte über eine absolute oder indizierte Ein-Byte-Speicheradresse zugegriffen werden. Dies reduzierte die Befehlsausführungszeit um einen Taktzyklus und die Befehlslänge um ein Byte. Durch das Speichern häufig verwendeter Daten in dieser Region könnten Programme kleiner und schneller gemacht werden.

Als Ergebnis wurde die Nullseite ähnlich einer Registerdatei verwendet. Auf vielen Systemen führte dies jedoch zu einer hohen Auslastung des Zero-Page-Speicherbereichs durch das Betriebssystem und Benutzerprogramme, was seine Nutzung einschränkte, da der freie Speicherplatz begrenzt war.

Direktseite

Der Nullseiten-Adressmodus wurde in mehreren 8-Bit-Prozessoren neueren Modells verbessert, einschließlich des WDC 65816 , des CSG 65CE02 und des Motorola 6809 . Der neue Modus, bekannt als "Direct Page"-Adressierung, fügte die Möglichkeit hinzu, das 256-Byte-Zero-Page-Speicherfenster vom Anfang des Speichers (Offsetadresse $0000) an eine neue Position innerhalb der ersten 64 KB des Speichers zu verschieben.

Das CSG 65CE02 ermöglichte es, die Direktseite an eine beliebige 256-Byte-Grenze innerhalb der ersten 64 KB des Speichers zu verschieben, indem ein 8-Bit-Offset-Wert im neuen Basisseiten-(B)-Register gespeichert wurde. Das Motorola 6809 könnte das gleiche mit seinem Direct Page (DP)-Register tun. Der WDC 65816 ging noch einen Schritt weiter und ermöglichte es, die Direktseite an eine beliebige Stelle innerhalb der ersten 64 KB des Speichers zu verschieben, indem ein 16-Bit-Offset-Wert im neuen Direkt-(D)-Register gespeichert wurde.

Als Ergebnis war eine größere Anzahl von Programmen in der Lage, den verbesserten direkten Seitenadressierungsmodus gegenüber herkömmlichen Prozessoren zu verwenden, die nur den Nullseitenadressierungsmodus enthielten.

Skalierter Index mit Grenzüberprüfung

Dies ähnelt der skalierten Indexadressierung, außer dass der Befehl zwei zusätzliche Operanden (typischerweise Konstanten) hat und die Hardware prüft, ob der Indexwert zwischen diesen Grenzen liegt.

Eine andere Variante verwendet Vektordeskriptoren, um die Grenzen zu halten; Dies macht es einfach, dynamisch zugewiesene Arrays zu implementieren und dennoch eine vollständige Überprüfung der Grenzen zu haben.

Indirekt zum Bitfeld innerhalb des Wortes

Einige Computer hatten spezielle indirekte Adressierungsmodi für Unterfelder innerhalb von Wörtern.

Das indirekte Wort der Zeichenadressierung der Serie 600 von GE/Honeywell spezifizierte entweder 6-Bit- oder 9-Bit-Zeichenfelder innerhalb seines 36-Bit- Wortes.

Der DEC PDP-10 , ebenfalls 36-Bit, hatte spezielle Befehle, die es ermöglichten, den Speicher als eine Folge von Bitfeldern fester Größe oder Bytes jeder Größe von 1 Bit bis 36 Bit zu behandeln. Ein Ein-Wort-Sequenzdeskriptor im Speicher, "Byte-Zeiger" genannt, hielt die aktuelle Wortadresse innerhalb der Sequenz, eine Bitposition innerhalb eines Wortes und die Größe jedes Bytes.

Es gab Befehle, um Bytes über diesen Deskriptor zu laden und zu speichern und den Deskriptor zu inkrementieren, um auf das nächste Byte zu zeigen (Bytes wurden nicht über Wortgrenzen hinweg aufgeteilt). Viele DEC-Software verwendet fünf 7-Bit-Bytes pro Wort (einfache ASCII-Zeichen), wobei ein Bit pro Wort ungenutzt ist. Implementierungen von C mussten vier 9-Bit-Bytes pro Wort verwenden, da die 'malloc'-Funktion in C davon ausgeht, dass die Größe eines int ein Vielfaches der Größe eines char beträgt ; das tatsächliche Vielfache wird durch den systemabhängigen Kompilierzeit-Operator sizeof bestimmt .

Nächste Anweisung indexieren

Der Elliott 503 , der Elliott 803 und der Apollo Guidance Computer verwendeten nur absolute Adressierung und hatten keine Indexregister. Somit wurden indirekte Sprünge oder Sprünge durch Register im Befehlssatz nicht unterstützt. Stattdessen könnte er angewiesen werden, den Inhalt des aktuellen Speicherworts zum nächsten Befehl hinzuzufügen . Das Hinzufügen eines kleinen Wertes zur nächsten auszuführenden Anweisung könnte beispielsweise a JUMP 0in a ändern JUMP 20, wodurch der Effekt eines indizierten Sprungs erzeugt wird. Beachten Sie, dass die Anweisung on-the-fly modifiziert wird und unverändert im Speicher verbleibt, dh es handelt sich nicht um selbstmodifizierenden Code . Wenn der Wert, der dem nächsten Befehl hinzugefügt wird, groß genug wäre, könnte er den Opcode dieses Befehls sowie oder anstelle der Adresse modifizieren.

Glossar

Indirekt
Daten, auf die durch einen Zeiger oder eine Adresse verwiesen wird .
Sofort
Daten direkt in einer eingebetteten Befehl oder Befehlsliste.
Index
Ein dynamischer Offset, der typischerweise in einem Indexregister gehalten wird und möglicherweise durch eine Objektgröße skaliert wird.
Versatz
Ein direkter Wert, der einer Adresse hinzugefügt wird; zB entsprechend dem Strukturfeldzugriff in der Programmiersprache C .
Relativ
Eine relativ zu einer anderen Adresse gebildete Adresse.
Beitragsinkrement
Das Steppen einer Adresse nach Daten verwendet, ähnlich wie *p++in der Programmiersprache C , die für Stack-Pop- Operationen verwendet wird.
Pre-Dekrement
Das Dekrementieren einer Adresse vor der Verwendung, ähnlich wie *--pin der Programmiersprache C , die für Stack-Push- Operationen verwendet wird.

Siehe auch

Verweise

Externe Links