WDC 65816

Aus C64-Wiki
(Weitergeleitet von 65C816)
Wechseln zu: Navigation, Suche
WDC 65816
WDC65816.jpg
Typ Chip
Hersteller Western Design Center
Erscheinungsjahr 1983
Sonstiges 8−Bit Datenbus
24−Bit Adressbus
24 Adressierungsarten


Der WDC 65816 ist ein Prozessor, der von der Firma Western Design Center entwickelt wurde. Er stellt eine 16-Bit-Weiterentwicklung der 6502-Familie dar. Er wurde in den Turbokarten für Commodore-Rechner TurboProcess, Flash8 und SuperCPU verbaut. Außerdem ist eine Variante von ihm, der 65C816 in einer der bekanntesten Spielkonsolen der Welt eingesetzt worden, dem Super Nintendo Entertainment System (SNES).

Der 65C802 wurde einst von WDC als 40-Pin-Variante kompatibel zum 65C02 angeboten. Aus Software-Sicht war diese CPU völlig identisch mit dem 65C816, allerdings war der Adressraum auf 64 KByte beschränkt.

Native-/Emulation-Modus[Bearbeiten]

Nach einem Reset befindet sich der 65816 im sogenannten Emulation Mode, der dem Verhalten einer 6502-CPU weitgehend entspricht. Wichtig dabei ist, dass weder das Verhalten der nicht implementierten Opcodes eines 6502 noch jene des 6510 vorhanden sind. Also auch im Emulation Mode läuft in einem C64 verbaut nicht jede Software fehlerfrei.
Die zuvor nicht implementierten bzw. illegalen Opcodes haben durchwegs eine Bedeutung für zusätzliche Befehle oder neue Adressierungsmodi bekannter Befehle. Diese werden auch in diesem Modus unterstützt, allerdings mit der Einschränkung auf 8 Bit breite Register, was nicht immer sonderlich nutzbringend ist.

Erst im Native Mode hat man Zugriff auf alle 16-Bit-Fähigkeiten, also alle zusätzlichen Register bzw. die volle Registerbreite, eine verschiebliche Direct Page und den 16-Bit-Stack und den umfassenden, bequemeren Zugang auf den vollen 16 MByte großen Adressbereich (bei 24 Adress-Bits). Bei manchen Befehlen ändert sich in diesem Modus auch das Timing, insbesondere dann, wenn diese in 16-Bit ausgeführt werden.

Das Statusregister des Prozessors besitzt neben den Bits, die auch ein 6502 hat, noch ein "E"-Bit mit dem sich der "Emulation-Mode" auswählen lässt. Mit diesem Bit wird zwischen Emulation- und Native-Mode-Betrieb der CPU umgeschaltet.

Aktivieren des Native Mode (16-Bit-Modus)
CLC ; CLear Carry bit
XCE ; eXchange Carry and Emulation bit
Aktivieren des Emulation Mode (8-Bit-Modus)
SEC ; SEt Carry bit
XCE ; eXchange Carry and Emulation bit

Diese Implementierung des Native Mode stellt eine hochinteressante Alternative zu anderen Herangehensweisen, z.B. bei Intel, bereit. Statt neben den "alten" 8 Bit Registern neue 16-Bit-Register mit eigenen Bezeichnungen und eigenen Opcodes einzuführen, behalten alle Register-Opcodes ihre bisherige Bedeutung. Dazu gibt es im Native Mode weitere 2 Bits im Statusregister, die angeben, ob

  • Register X, Y (X/Y-Flag, ehem. Break-Flag, Bit 4 des Statusregisters)
  • Akku und Memory-Zugriffe (A/M-Flag, ehem. frei, Bit 5 des Statusregisters)

8- oder 16-bittig sind, also im 8-Bit oder 16-Bit-Modus. D.h. im Native-Modus hängt es von diesen beiden Bits ab, was ein und derselbe Maschinencode tatsächlich tut. Mit den neuen Opcodes für SEP und REP lassen sich diese Bits gezielt setzen oder löschen, z.B.

SEP #%00010000  ; Indexregister 8-Bit

REP #%00010000  ; Indexregister 16-Bit

Ein LDA #$00 holt im 8-Bit-Modus die Zahl #$00 in den Akku. Im 16-Bit-Modus wird der Opcode für LDA - $A9 - anders interpretiert. Nicht nur ein Byte, sondern zwei Byte werden als Operand herangezogen. Damit können dann 16 Bit Werte in den Akku geladen werden: LDA #$1000. Zugriffe auf Speicher, z.B. LDA $C000, holten je nach Registerbreite dann das Byte von $C000 aus dem RAM, oder die zwei Bytes ab $C000, also $C000 ins Lowbyte des Akku und $C001 ins Highbyte des Akku.

Diese variable Registerbreite erfordert aber auch durch einen Assembler eine besondere Berücksichtigung, da der zur Laufzeit aktive Modus für das Erzeugen des korrekten Codes dem Assembler mitgeteilt werden muss. Z.B. könnte

LDA #1

im 8-Bit-Modus aus 2 Bytes (Opcode + 1 Byte Operand) oder im 16-Bit-Modus aus 3 Bytes (Opcode + 2 Bytes Operand) bestehen. Welcher Modus aktiv sein soll, muss für einen Codebereich dem Assembler mit Hilfe von Pseudobefehlen bekannt gemacht werden.

Neue Opcodes[Bearbeiten]

Der 65816 bietet ferner eine Reihe neuer Opcodes, die man als Programmierer früher manchmal schmerzhaft vermisste hatte.

Beispiele:

INC A      ; oder
INA        ; INcrease Akku

DEC A      ; oder
DEA        ; DEcrement Akku

TXY        ; Transfer X-Register to Y-Register
TYX        ; Transfer Y-Register to X-Register

PHX        ; Push X
PLX        ; Pull X
PHY        ; Push Y
PLY        ; Pull Y

STZ addr   ; Store Zero to Memory

BRA label  ; Branch (unconditionally)
BRL label  ; Branch long (unconditionally, with 16 bit offset)

TSB addr   ; Test and Set Bit (with mask in Akku)
TRB addr   ; Test and Reset Bit (with mask in Akku)

u.v.m.

Neue Adressierungsarten[Bearbeiten]

Schon die 6502-Adressierungsarten sind recht vielfältig, allerdings machen auch viele 8-bittigen Einschränkungen einem Programmierer das Leben schwer. Ergänzungen wie stack-relativen Adressierungsmodi und Befehle für weiter reichende, sogenannte long branches mit PC-relativem Bezug ermöglichen ein wesentlich einfacheres Programmieren von positionsunabhängigem Code (engl. position-independent code oder relocatable code), was etwa Mult-Tasking-Umgebungen und der Betriebssystem-Programmierung zu Gute kommt. Allerdings zeigt sich das Konzept nicht in voller Konsequenz umgesetzt, denn der fehlende relative Unterprogrammaufruf muss explizit mittels zweier Befehle realisiert werden.

Es gibt sogenannte Long-Addressing-Modi, die den vollen 24-Bit-Adressraum erreichen (sowohl für Datenzugriffe als auch für den Programmfluss), ohne erst die Bank-Register manipulieren zu müssen.

Die Zero-Page-Adressierung ist nicht mehr auf auf Page 0 beschränkt, sondern bezieht sich auf die sogenannte Direct Page, deren Lage mit Hilfe des 16-bittigen Direct Page Base Registers eine beliebige Position innerhalb der Bank 0 einnehmen kann. Allerdings sollte man darauf achten, dass die Direct-Page an einer Page-Grenze zu liegen kommt, da andernfalls die Ausführung aller Direct-Page-Zugriffe einen Taktzyklus länger braucht.
Alle Adressierungsarten, die sich auf Zugriffe der Direct-Page beziehen, bleiben stets auf die Bank 0 beschränkt (also mit address wrapping).

Der Stack ist nicht mehr an Page 1 gebunden, sondern auch das Stack-Pointer-Register weist 16 Bit auf, allerdings stets auf Bank 0 beschränkt (mit address wrapping).

Neue Adressierungsarten bezogen auf das Stack-Pointer-Register erleichtern den Zugriff über einen Offset zum Stack-Pointer direkt auf einen Wert am Stack oder indirekt über eine am Stack liegende Adresse. Das erleichtert besonders die Unterstützung für Compiler prozeduraler Hochsprachen, wo die Parameterübergabe üblicherweise stack-basierend ist.

Datenzugriffe sind üblicherweise 16-Bit-bezogen und der entsprechende 64 KByte große Block innerhalb des 24-bittigen Adressbereichs wird mit dem 8-Bit-breiten Data Bank Register festgelegt. Die Zugriffe sind dabei allerdings nicht strikt auf die jeweils gewählte Bank beschränkt, insbesondere im Native-Mode (im Emulation-Mode auch für 6502-abweichende Opcodes) kann durch komplexe Adressierungsarten und 16-Bit breite Zugriffe auch die nachfolgende Bank betroffen sein (non-wrapping).

Die Ausführung des Programmcodes beschränkt sich zwar primär auf 64 KByte (wrapped execution), aber dieser Bereich lässt sich auf eine bestimmte Bank (mit Hilfe des Program Bank Register wählbar) im 16 MByte großen Bereich verorten.

Block-Move-Befehle[Bearbeiten]

Ähnlich wie eine REU kann der 65816 ganze Speicherblöcke auf einmal transferieren. Dafür müssen der Akku mit der Länge des Bereichs minus 1, Register X mit Startadresse des Quellbereichs und Register Y mit Startadresse für den Zielbereich geladen und dann der Block-Move-Opcode mit der Quell- und und Zielbank aufgerufen werden. D.h. der Transfer kann auch dazu benutzt werden, Daten zwischen verschiedenen Bänken zu kopieren. Zwei verschiedene Varianten erlauben dabei auch das Kopieren überlappender Quell- und Zielbereiche je nachdem, wo sich der Quell- und Zielbereich befindet.
Der Transfer eines Bytes benötigt dann nur noch 7 Takte, was mindestens doppelt so schnell ist verglichen mit einer programmierten Schleife.

Literatur[Bearbeiten]

Weblinks[Bearbeiten]

WP-W11.png Wikipedia: Western Design Center 65816