Forum: PC-Programmierung Nummerierung der Opcodes bei der 8086 Architektur


von Nano (Gast)


Lesenswert?

Weiß jemand, warum bei der Definition der Opcodes für die 4 Register AX, 
BX, CX, DX eine aufsteigende Reihenfolge von AX, CX, DX, BX verwendet 
wurde, anstatt AX, BX, CX, DX wie man es erwarten könnte?

Hat das irgendwelche Vorteile, CX und DX vor BX zu setzen?
Sparte es bspw. Transistoren?
Erlaubte es schnellere Berechnungen?

Aus Programmierersicht wäre jedenfalls eine aufsteigende Reihenfolge AX, 
BX, CX, DX verständlicher gewesen, dann könnte man den Opcode im Hex 
Editor ohne Disassembler viel leichter lesen.

Bsp:
1
MOV AX, 00h   ; B8 0000
2
MOV BX, 00h   ; BB 0000  // WTF?
3
MOV CX, 00h   ; B9 0000
4
MOV DX, 00h   ; BA 0000
5
6
MOV AL, 01h   ; B0 01
7
MOV BL, 01h   ; B3 01    // hier auch und so geht es geradezu unten weiter.
8
MOV CL, 01h   ; B1 01
9
MOV DL, 01h   ; B2 01
10
11
MOV AH, 02h   ; B4 02
12
MOV BH, 02h   ; B7 02
13
MOV CH, 02h   ; B5 02
14
MOV DH, 02h   ; B6 02
15
16
INC AX        ; 40
17
INC BX        ; 43
18
INC CX        ; 41
19
INC DX        ; 42
20
21
INC AL        ; FEC0
22
INC BL        ; FEC3
23
INC CL        ; FEC1
24
INC DL        ; FEC2
25
26
INC AH        ; FEC4
27
INC BH        ; FEC7
28
INC CH        ; FEC5
29
INC DH        ; FEC6
30
31
ADD AX, 00h   ; 83C0 00
32
ADD BX, 00h   ; 83C3 00
33
ADD CX, 00h   ; 83C1 00
34
ADD DX, 00h   ; 83C2 00
35
36
ADD AX, 1000h ; 05   0010 // WTF?
37
ADD BX, 1000h ; 83C3 0010
38
ADD CX, 1000h ; 83C1 0010
39
ADD DX, 1000h ; 83C2 0010
40
41
ADD AL, 00h   ; 04   00   // WTF?
42
ADD BL, 00h   ; 80C3 00
43
ADD CL, 00h   ; 80C1 00
44
ADD DL, 00h   ; 80C2 00
45
46
ADD AH, 00h   ; 80C4 00
47
ADD BH, 00h   ; 80C7 00
48
ADD CH, 00h   ; 80C5 00
49
ADD DH, 00h   ; 80C6 00

Und warum wird bei MOV AX, 1000h nicht einfach 83C0 0010 verwendet, wie 
man es erwarten könnte? Kann es daran liegen, dass das Akkumulator 
Register gesondert zu betrachten ist und es somit eigene, kurze Opcodes 
hat. Die 05 wären nämlich kürzer, als eine 83C0, also nur 1 Byte, 
anstatt 2 Byte, das könnte als Zeit einsparen.

Aber wenn dem so ist, warum wird dann bei Übergabe von nur 1 Byte an den 
ADD Befehl des AX Registers dann für den Opcode doch wieder die Langform 
83C0 verwendet?
Mal davon abgesehen, dass das verwunderlich ist, dass das so 
funktioniert. Denn das AX Register ist eigentlich 2 Byte breit und 
müsste somit einen 2 Byte breiten Input erwarten.
Will man das nicht, dann könnte man ja das AL Register nehmen und hätte 
dafür dann den kürzeren Opcode 04 was dann wiederum performanter als 
diese 83C0 langform ist.

von Bauform B. (bauformb)


Lesenswert?

Da hat ein Chip-Designer zwei Leitungen verwechselt und sein Kollege 
meinte nur "egal, das merkt nie einer" ;) Andererseits war "orthognaler 
Befehlssatz" mal ein Werbeargument...

Schau dir mal die Vorgänger an, man konnte ja zwecks Kompatibilität nur 
die Lücken füllen.

von Sebastian E. (sbe_15)


Lesenswert?

Wer sagt, dass die Registernamen alphabetisch sortiert sind?
Die Register sind nach Funktion benannt:

AX = Akkumulator
CX = Counter
DX = Data
BX = Base

Heute sind die Register gleichwertig. Damals war das anders, nicht jeder 
Befehl erlaubte jedes Register als Operand und einige Befehle verwenden 
Register implizit, z.B.:

8086
- MUL: AL bzw AX ist als linker operand fix. Bei 16bitx16bit, ist das 
Ergebnis immer in DX:AX
- REP: Befehl wird CX-mal ausgeführt

von Nano (Gast)


Lesenswert?

Sebastian E. schrieb:
> Wer sagt, dass die Registernamen alphabetisch sortiert sind?
> Die Register sind nach Funktion benannt:
>
> AX = Akkumulator
> CX = Counter
> DX = Data
> BX = Base

Okay, die Erklärung macht Sinn.
Dann hat man wohl einfach vergessen, dass man das auch alphabetisch 
durchzählen könnte und dann die Opcodes der Reihe nach vergeben können.
Schade, irgendwie eine vertane Chance. Denn bereits in den diversen 
Debuggern werden die Register meist alphabetisch aufgezählt.

Die andere Erklärung mit den Vorgängern passt nicht.
Die Opcodes des 8080 und 8085 passen nicht, sind also nicht 
binärkompatibel zum 8086:
http://www.emulator101.com/reference/8080-by-opcode.html
https://www.developerravi.com/opcode-table-of-intel-8085/

Und so steht's auch in der WP:
> "Eine direkte Kompatibilität, also die Möglichkeit, die 8080-Programme auch ohne 
Neuassemblierung ablaufen zu lassen, bestand aber nicht."
https://de.wikipedia.org/wiki/Intel_8086


> Heute sind die Register gleichwertig. Damals war das anders, nicht jeder
> Befehl erlaubte jedes Register als Operand und einige Befehle verwenden
> Register implizit, z.B.:

Ja, das ist mir bekannt. Trotzdem danke.

Es wundert mich nur, dass die Opcodes des AX Register an  manchen 
Stellen trotzdem deutlich abweichen.

Eine Erklärung könnte auf den ersten Blick sein, dass das historisch so 
gewachsen ist und als man dann die anderen Register später vollwertig 
machen wollte, man dann die Opcodes an den bestehenden Opcodebefehlssatz 
weiter unten dran drängen musste, so dass die BX, CX und DX Register 
andere Hexcodes für die ADD Befehle bekommen.
Allerdings habe ich mit JWASM (kompatibel zu MASM) darauf geachtet, dass 
der erzeugte Programmcode für eine 8086 CPU erzeugt wird und somit nur 
Opcodes verwendet werden, die bereits diese CPU kennt. Und da werden 
dann halt genau diese obigen Opcodes verwendet.
D.h. auch damals war das schon so. Diese Erklärung passt also nicht.

von (prx) A. K. (prx)


Lesenswert?

Nano schrieb:
> Kann es daran liegen, dass das Akkumulator
> Register gesondert zu betrachten ist und es somit eigene, kurze Opcodes
> hat.

Ja.

> Aber wenn dem so ist, warum wird dann bei Übergabe von nur 1 Byte an den
> ADD Befehl des AX Registers dann für den Opcode doch wieder die Langform
> 83C0 verwendet?

Warum nicht?

> Denn das AX Register ist eigentlich 2 Byte breit und
> müsste somit einen 2 Byte breiten Input erwarten.

Es gibt bei den generischen Opcodes für 16-Bit Operationen mit 
Konstanten zwei Varianten, 8-Bit sign-extended und 16-Bit. Nicht aber 
bei den speziellen Opcodes für AX.

von (prx) A. K. (prx)


Lesenswert?

Nano schrieb:
> Es wundert mich nur, dass die Opcodes des AX Register an  manchen
> Stellen trotzdem deutlich abweichen.

Als der 8086 rauskam gab es eine Menge 8080-Code. Der liess sich direkt 
in 8086-Code umsetzen (in ASM, nicht binär), es gibt für fast alles eine 
1:1 Entsprechung. Damit der solcherart erzeugte Code aber nicht zu gross 
wurde, hat Intel manche dafür wichtigen Operationen speziell codiert. 
Und hat ein paar Befehle spendiert, die nur aus diesem Grund existieren, 
wie LAHF,SAHF.

Eine solche Befehlsgruppe, INC/DEC 16-Bit Register als 1-Byte Befehl, 
wurde bei AMD64 für den REX Präfix geopfert. Diese Operationen sind auch 
über generische Reg/Mem-Adressierung codierbar.

: Bearbeitet durch User
von Nano (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Nano schrieb:
>> Aber wenn dem so ist, warum wird dann bei Übergabe von nur 1 Byte an den
>> ADD Befehl des AX Registers dann für den Opcode doch wieder die Langform
>> 83C0 verwendet?
>
> Warum nicht?

Hab den Fehler gefunden, dachte bisher
ADD AL, 00h
wäre genauso gut, aber bei einem ADD kann natürlich trotzdem das 
höherwertige Byte in AH betroffen sein, selbst dann, wenn man nur
1 Byte im AL hinzuaddiert.

Insofern ja, daher braucht man dann natürlich einen anderen Opcode.
Denn der von ADD AL, 00h würde lediglich einen Überlauf im AL Register
produzieren und keinen Übertrag nach AH.


>> Denn das AX Register ist eigentlich 2 Byte breit und
>> müsste somit einen 2 Byte breiten Input erwarten.
>
> Es gibt bei den generischen Opcodes für 16-Bit Operationen mit
> Konstanten zwei Varianten, 8-Bit sign-extended und 16-Bit. Nicht aber
> bei den speziellen Opcodes für AX.

Verstehe.

von Nano (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Nano schrieb:
>> Es wundert mich nur, dass die Opcodes des AX Register an  manchen
>> Stellen trotzdem deutlich abweichen.
>
> Als der 8086 rauskam gab es eine Menge 8080-Code. Der liess sich direkt
> in 8086-Code umsetzen (in ASM, nicht binär), es gibt für fast alles eine
> 1:1 Entsprechung. Damit der solcherart erzeugte Code aber nicht zu gross
> wurde, hat Intel manche dafür wichtigen Operationen speziell codiert.
> Und hat ein paar Befehle spendiert, die nur aus diesem Grund existieren,
> wie LAHF,SAHF.
>
> Eine solche Befehlsgruppe, INC/DEC 16-Bit Register als 1-Byte Befehl,
> wurde bei AMD64 für den REX Präfix geopfert. Diese Operationen sind auch
> über generische Reg/Mem-Adressierung codierbar.

Danke für die gute Erklärung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.