Diese Referenzseite gibt genaue
Informationen über die Wirkung der Instruktionen
des HaDes XP-Prozessors.
Im
folgenden seien w,a,b Register
der HaDes XP (im Assembler mit r0..r15
bezeichnet)
und 0 das 0-Register. Konstanten werden durch #k
beschrieben.
Die Dauer der Befehle in Takten wird stets für den Gutfall,
d.h. alle Caches enthalten bereits die benötigten Daten,
angegeben. Bei einem Instruction Cache Miss kommen jeweils nocheinmal
18 Takte zur Ausführungsdauer hinzu. Dies gilt auch für Data
Cache Misses (nur bei den Load und Store-Befehlen).
Arithmetische und logische
Befehle
Interner Zustand
Der HaDes XP-Prozessor hat
neben den 32 Bit General-Purpose-Registern r1
bis r15
noch
einige weitere
interne Register, die ebenfalls wichtig für die Verarbeitung
arithmetischer Befehle sind. Diese werden in der folgenden Tabelle
erklärt.
Name |
Bezeichnung |
Beschreibung |
Overflow |
(ovMul, ovShift, ovUns, ovSgn) |
Speichert jeweils, ob
bei der letzten
- Multiplikation (ovMul)
- arithmetischen
Linksshift-Operation (ovShift)
- Addition
oder Subtraktion (ovUns, ovSgn)
ein Überlauf aufgetreten ist. Dabei werden die
Parameter einer Addition oder Subtraktion bei ovUns
als unsigned und bei ovSgn
als signed interpretiert.
Der Zugriff erfolgt über die Befehle lflags
und sflags,
die allerdings im Emulator nicht korrekt
implementiert
sind. |
Modulus |
rMod |
Speichert das Ergebnis
der Modulo-Operation der zuletzt
ausgeführten Division. Das Register kann durch den mod-Befehl
gelesen, aber nicht direkt beschrieben werden. |
Hochwertige Produktbits |
rMulHigh |
Speichert die oberen 32
Bits (Bits 63..32) der zuletzt
ausgeführten Multiplikation. Das Register kann mit dem prod-Befehl
gelesen, aber nicht direkt beschrieben werden. |
Hochwertige
Dividendenbits |
rDiv64 |
Enthält die
oberen 32 Bits (Bits 63..32) des Dividenden
für die nächste Division. Das Register kann mit dem div64p
Befehl beschrieben, aber nicht direkt ausgelesen werden. |
64-Bit-Vorbereitung |
div64Prep |
Flag, das angibt, ob die
nächste Division die hochwertigen Dividendenbits verwendet. |
Memory Protection |
rMemProt |
Register für
den Speicherschutz, mit dem Teile des
Datenspeichers zum Schreiben gesperrt werden können.
Beschreiben
durch smp möglich, Auslesen unmöglich. |
Befehle
Die meisten Befehle sind auch
als Immediate-Varianten
verfügbar. Zum Befehl OP heißt die Immediate-Version
OPI, diese sind erneut aufgeführt.
Hierbei ist der B-Operand durch eine 16-Bit-Konstante ersetzt, die vor
der Verarbeitung auf 32 Bit expandiert wird. Diese
Vorzeichenerweiterung geschieht bei den logischen Befehlen AND, OR, XOR
und XNOR unsigned, bei allen anderen Befehlen signed. Die sonstige
Abarbeitung entspricht genau den Drei-Register-Varianten.
Befehl |
Semantik |
Dauer
(ohne Cache-Misses) |
ADD
w,a,b
ADDI w,a,#k |
Addition
regs[w] = regs[a] + regs[b]
ovUns
= unsigned overflow
ovSgn
= signed overflow |
2
Takte |
SUB
w,a,b
SUBI w,a,#k |
Subtraktion
regs[w] = regs[a] - regs[b]
ovUns
= unsigned overflow
ovSgn
= signed overflow |
2
Takte |
|
MUL
w,a,b
MULI w,a,#k |
vorzeichenbehaftete
Multiplikation (32x32 -> 64 bit)
(rMulHigh,
regs[w]) = regs[a] * regs[b]
ovMul
wird gesetzt, wenn das Ergebnis nicht in 32 Bits passt; sonst
gelöscht |
19
Takte |
PROD
w |
Zugriff
auf die High-Bits des Ergebnisses der letzten
Multiplikation
regs[w] = rMulHigh |
2
Takte |
|
DIV
w,a,b
DIVI w,a,#k |
vorzeichenbehaftete
Division (64 oder 32/32 -> 32 bit)
temp
= (div64Prep ?
(rDiv64,
regs[a]) : regs[a])
regs[w] = temp / regs[b]
rMod
= temp % regs[b]
div64Prep
= 0
|
37
Takte |
DIV64P
a |
rDiv64
= regs[a]
div64Prep
= 1 |
|
MOD
w |
regs[w]
= rMod |
2
Takte |
|
MULFP
w,a,b
MULFPI w,a,#k |
vorzeichenbehaftete
Fixpoint-Multiplikation für Fixpunktzahlen mit 16 Bit Vor- und
Nachkomma
regs[w] = regs[a] *: regs[b] |
19 Takte |
DIVFP
w,a,b
DIVFPI w,a,#k |
vorzeichenbehaftete
Fixpoint-Division
regs[w] = regs[a] /: regs[b]
div64Prep
= 0 |
37
Takte |
|
AND
w,a,b
ANDI w,a,#k |
logisches
UND |
2 Takte |
OR
w,a,b
ORI w,a,#k |
logisches
ODER |
XOR
w,a,b
XORI w,a,#k |
logisches
Exklusiv-ODER |
XNOR
w,a,b
XNORI w,a,#k |
logisches
Not-Exklusiv-ODER (bitweiser Vergleich) |
|
SHL
w,a,b
SHLI w,a,#k |
nicht-zyklischer
Linksshift
ovShift
wird gesetzt, falls nicht nur Nullen herausgeschoben werden |
abhängig von der
Shiftweite b
3 + b/4 + b%4 Takte
4 Takte für b=1
11 Takte für b=31
|
CSHL
w,a,b
CSHLI w,a,#k |
zyklischer
Linksshift |
SHR
w,a,b
SHRI w,a,#k |
nicht-zyklischer
Rechtsshift (Nullen werden nachgeschoben) |
CSHR
w,a,b
CSHRI w,a,#k |
zyklischer
Rechtsshift |
SHAR
w,a,b
SHARI w,a,#k |
arithmetischer
Rechtsshift (das Vorzeichenbit wird
nachgeschoben) |
Set-Condition-Befehle
Diese
Befehle setzen das angegebene Zielregister w auf
den Wert 1 oder 0, je nachdem, ob der entsprechende
Registerinhalt-Vergleich zutraf oder nicht zutraf. Auch zu diesen
Befehlen gibt es jeweils eine Immediate-Variante SXXI.
Befehl |
Semantik |
Dauer |
SEQ
w,a,b |
Test
auf Gleichheit |
2
Takte |
SNE
w,a,b |
Test
auf
Ungleichheit |
SLT
w,a,b |
Test,
ob Reg[a] < Reg[b] |
SGT
w,a,b |
Test,
ob Reg[a] > Reg[b] |
SLE
w,a,b |
Test,
ob Reg[a] <
Reg[b] |
SGE
w,a,b |
Test,
ob Reg[a] >
Reg[b] |
Sprünge und
Verzweigungen
Interner Zustand
Folgende interne Spezialregister sind für die Verarbeitung von
Sprungbefehlen wichtig. Zu beachten ist hier, dass die HaDes XP kein
separates Stackpointer-Register besitzt. Es kann frei von der Anwendung
gewählt werden; in der HAL wird stets r15 benutzt. Auch
die Rücksprungadresse bei Funktionsaufrufen wird in ein
General-Purpose-Register gespeichert (in der HAL r1) und
lediglich bei Bedarf von der Anwendung in den Speicher kopiert.
Name |
Bezeichnung |
Beschreibung |
Program Counter |
pc |
Speicheradresse des aktuellen Befehls.
Wird am Ende der meisten Befehle einfach um eins erhöht und zeigt
damit auf den nächsten Befehl. |
Die HaDes XP verfügt
über folgende bedingte und unbedingte Sprungbefehle. Die
meisten sind Immediate-Befehle mit einer absoluten Sprungziel-Adresse
(=Befehlsnummer) im Immediate-Operanden. Einige Befehle sind aber auch
als indirekte Sprünge verfügbar, das Ziel wird hier
aus einem der Register geladen.
Befehl |
Semantik |
Dauer |
BEQZ
a,#k |
Sprung
nach Adresse k,
falls regs[a] = 0
pc = (regs[a] ? pc + 1 : k) |
2 Takte |
BNEZ
a,#k |
Sprung
nach Adresse k,
falls regs[a] != 0
pc = (!regs[a] ? pc + 1 : k) |
JMP
#k |
Unbedingter
Sprung
nach Adresse k
Entspricht BEQZ r0,k |
RET b
JMPR b |
Unbedingter Sprung nach
Adresse regs[b]
pc = regs[b] |
JAL
w,#k
JALR w,b |
Aufruf
des
Unterprogramms an Adresse k (bzw. regs[b])
regs[w] = pc + 1
pc = k (bzw. regs[b])
|
START #k
STARTR b |
Unbedingter Sprung zu Adresse k (bzw. regs[b])
Instruktions- und Datencache wird ungültig gesetzt
Zugriff auf Bootmemory wird deaktiviert |
ca. 258 Takte |
Lade- und Speicherbefehle
Die Lade- und Speicherbefehle LOAD und STORE ermöglichen den
Zugriff auf den Datenspeicher mit indirekter Adressierung +
Displacement. Der Adressraum beträgt volle 32 bit (d.h. 4 GB). Da
aber der tatsächliche Speicherausbau weitaus kleiner ist, sind nur
die unteren Adressen gültig. Ein Zugriff auf eine ungültige
Speicheradresse führt zu einem Memory Interrupt. Außerdem
ist das Schreiben nur auf Adressen gestattet, die nicht geschützt
sind. Dieser Speicherschutz wird durch den SMP-Befehl aktiviert; bei
Systemstart ist er ausgeschaltet.
Die Komfortbefehle LREGS und SREGS ermöglichen das Sichern und
Wiederherstellen mehrerer Register in einem Aufwasch. Dabei werden
stets die Register 1 bis b (jeweils einschließlich) bearbeitet
und an aufeinanderfolgende Speicheradressen, ausgehend von der
Speicheradresse regs[a] + k, abgelegt. Die Befehle werden im Prozessor
genau wie eine Folge von LOAD- bzw. STORE-Anweisungen verarbeitet.
Befehl |
Semantik |
Dauer |
LOAD
w,a,#k |
Laden
eines
32-Bit-Wortes aus dem Datenspeicher
regs[w] = mem[regs[a] + k]
Tipp: Für absolute Adressierung (globale Variablen) verwende LOAD
w,r0,#k.
Achtung: Der Immediate-Operand ist 16 bit groß und
vorzeichenbehaftet.
Dies funktioniert also nur für die Adressen 0 bis 0x7FFF. |
3 Takte
(+18 bei Data Cache Miss) |
STORE
b,a,#k |
Ablegen
eines
32-Bit-Wortes im Datenspeicher
mem[regs[a] + k] = regs[b] |
LREGS #b,a,#k |
Laden mehrerer Register
for i from 1 to b do
regs[i] = mem[regs[a] + k + (i-1)] |
3*b Takte
(+ Cache Misses) |
SREGS #b,a,#k |
Sichern mehrerer Register
for i from 1 to b do
mem[regs[a] + k + (i-1)] = regs[i] |
SMP b
SMPI #k |
Speicherschutz setzen: Schreibzugriff auf Speicherzellen,
deren
Adresse kleiner als rMemProt ist, ist nicht gestattet.
rMemProt = regs[b] |
2 Takte |
Kommunikation mit Peripherie
Die
folgenden Befehle stellen Zugriffsmöglichkeiten auf externe
Komponenten bereit. Falls eine angesprochene
Portadresse nicht vorhanden ist, wird ein XBus Not Available (XNA)
Interrupt ausgelöst.
Befehl |
Semantik |
Dauer |
IN
w,#k
INR w,b |
Lesen
von
Portadresse k (bzw. regs[b])
regs[w] = Port[k] |
2 Takte
+ Latenz der angesprochenen Komponente |
OUT
a,#k
OUTR a,b |
Schreiben
nach
Portadresse k (bzw. regs[b])
Port[k] = regs[a] |
Interrupt-Behandlung
Die
HaDes XP-CPU verfügt über fünfzehn Interrupts. Für jeden
Interrupt kann die Einsprungadresse der Interrupt Service Routine
eingestellt werden (SISA), die aufgerufen wird, falls ein Interrupt
auftritt und Interrupts global aktiviert sind (ENI).
Achtung: Nicht alle Interrupts sind in der aktuellen HaDes-Version implementiert. Nur die fett markierten Interrupts werden auch wirklich von der Hardware ausgelöst.
Kürzel |
Beschreibung |
Priorität |
USR1 |
Software-Interrupt zur besonderen Verwendung |
1 (niedrig) |
XDUMMY1 |
Reservierter Interrupt für XBus-Komponenten |
2 |
XSOUND |
XSound meldet "Puffer leer" |
3 |
XUSB |
XUSB meldet "Daten empfangen bzw. versandt" |
4 |
XTIMER |
XTimerPro meldet "Timer abgelaufen" |
5 |
XPS2 |
XPS2 meldet "Daten empfangen bzw. versandt" |
6 |
XCONSOLE |
XConsole meldet "Taster gedrückt" |
7 |
XJTAG |
XJtag meldet "Daten empfangen bzw. versandt" |
8 |
XDUMMY2 |
Reservierter Interrupt für XBus-Komponenten |
9 |
USR2 |
Software-Interrupt zur besonderen Verwendung |
10 |
OVF |
ALU Overflow (noch nicht implementiert) |
11 |
DIV0 |
ALU Division by zero (noch nicht implementiert) |
12 |
XADDR |
Eine nicht zugeordnete XBus-Adresse wurde angesprochen |
13 |
MEMADDR |
Memory. Die angegebene Speicheradresse existiert nicht (LOAD, STORE)
oder ist schreibgeschützt (STORE). |
14 |
PCADDR |
Ein Sprung auf ein nicht vorhandenes Sprungziel soll ausgeführt werden,
d.h. die Zieladresse ist kleiner als 0 oder größer als 0xFFFF.
|
15 (hoch) |
Zu jedem Interrupt kann eine (und nur eine) Anforderung gespeichert
werden, die ausgeführt wird, sobald Interrupts
wieder aktiviert wurden bzw. das Interrupt Level genügend
gesunken ist (durch RETI).
Interrupts werden stets zwischen Befehlen ausgeführt, d.h.
zuerst wird der auslösende Befehl vollständig abgearbeitet
(bei IN bzw. LOAD ist das Ergebnis des Befehls undefiniert, falls
dadurch ein Interrupt ausgelöst wird), dann wird die
Interrupt-Routine aufgerufen, und dann mit dem nächsten Befehl des
Hauptprogramms fortgefahren. Folgende Übersicht zeigt, nach
welchen Befehlen die Interrupts auftreten können, wenn Interrupts
global aktiviert wurden:
Interrupt |
Befehl |
XSOUND, XUSB, XTIMER, XPS2, XCONSOLE, XJTAG |
alle außer MUL, MULFP, DIV, DIV64P und deren
Immediate-Varianten, wenn der Interrupt bei der entsprechenden XBus-Komponente aktiviert wurde |
XADDR |
IN, OUT |
MEMADDR |
LOAD, STORE |
PCADDR |
BNEZ, BEQZ, START, JAL, JMP, RET und deren Register-Varianten |
Durch die Unterdrückung von Peripherie-Interrupts nach
Multiplikations- und Divisionsbefehlen wird sichergestellt, dass die
High Bits des Ergebnisses bzw. der Rest stets abgeholt werden
können und nicht durch eine Operation innerhalb eines Peripherie-Interrupt-Handlers zerstört werden.
Befehl |
Semantik |
ENI |
Enable
Interrupts |
DEI |
Disable
Interrupts |
SISAI a,#k
SISA a,b |
k (bzw. regs[b])
ist
ISR-Adresse für Interrupt regs[a] |
RETI |
Rücksprung
aus ISR |
Andere Befehle
Diese selten benötigten Befehle passen in keine andere
Kategorie.
Befehl |
Semantik |
Dauer |
LLEA w |
Lädt die zuletzt verwendete effektive Speicheradresse
(Ergebnis der Addition von regs[a]+k bei LOAD, STORE, LREGS und SREGS) |
2 Takte |
LIRA w |
Lädt die Interrupt-Rücksprungadresse. Falls der
Befehl außerhalb
eines Interrupt Handlers aufgerufen wird, ist das Verhalten
undefiniert. |
LFLAGS w |
Lädt das Overflow-Register. |
SFLAGS b
SFLAGSI #k |
Setzt das Overflow-Register. |
SLEEP |
Stoppt die Programmausführung bis zum Eintreten eines Peripherie-Interrupts
(XSOUND, XUSB, XTIMER, XPS2, XCONSOLE oder XJTAG) |
unbestimmt |
Registerladebefehle
Diese Pseudobefehle laden Werte in Register.
Befehl |
Semantik |
Dauer |
LDSI
w,#k |
Konstante
k (16 bit signed)
in Register laden
regs[w] = SignExpand(#k) |
2 Takte |
LDUI
w,#k |
Konstante
k (16 bit unsigned)
in Register laden
regs[w] = UnsignedExpand(#k) |
LD
w,a |
Kopieren
von
Registerinhalten
regs[w] = regs[a] |
|