Grundlagen über die Hardware
Leider gehört zum Verständnis von Assembler auch ein wenig Theorie über die Hardware dazu. Keine Angst, dass Ganze ist doch recht interessant. Ich bin auch kein Lehrer, der nur sachlich irgendwo vorne vor sich hinredet (und man derzeit einschläft), sondern ich versuche das Ganze ein wenig schmackhaft zu präsentieren :) Ja und da wir nicht in der Schule sind, kann man sich nebenbei ruhig einen Kaffee, oder Sonstiges gönnen.
Wir werden die folgenden Bereiche mal näher unter die Lupe nehmen:
- wie ein PC funktioniert
- was niederwertige und höherwertige Bytes sind
- was ein Stack ist
- Zahlensysteme
Hört sich doch gar nicht so schrecklich an, oder?
1. Wie funktioniert denn nun eigentlich ein PC?
Ein Computer
ist immer nach dem selben Prinzip aufgebaut. Es nennt sich "Von-Neumann-Architektur".
Man hat vielleicht schon mal davon gehört, dass ein Computer aus folgenden
Teilen besteht:
- Rechenwerk
- Steuerwerk
- Speicher
- Register
- Eingabeeinheit
- Ausgabeeinheit
Das Rechenwerk
Man kann es eigentlich schon fast aus dem Namen herauslesen, um was es hier geht. Richtig, es handelt sich hier um einen Teil im Prozessor, der für Rechenoperationen und logische Entscheidungen (kleiner als, usw...) zuständig ist. Das Rechenwerk nennt man auch ALU (Arythmetik Logic Unit). Also grob übersetzt: "Mathematischer Logischer Abschnitt".
Das Steuerwerk
Auch hier kann man sich schon denken, worum es hier geht. Das Steuerwerk steuert Vorgänge. Als Vorgänge meine ich hiermit zum Beispiel das holen von Befehlen aus dem Speicher. Es schnappt sich also einen Befehl nach dem anderen aus dem Speicher und führt den Befehl mit Hilfe von anderen Teilen aus, wenn es nötig ist. Es steuert auch das Bussystem und schaut dass es nicht zu einem Datencrash kommt.
Der Speicher
Hier ist der
Arbeitsspeicher gemeint, in dem sich eine Menge von Daten befinden können.
Kommt immer ganz darauf an, wieviel MB gerade im Computer drinnen sind. Ich hab
derzeit z.B. eine 256 MB RAM-Bank eingebaut. Ich weis, dass ist nicht gerade
viel, aber man kommt damit aus :) Jedesmal, wenn ein Programm gestartet wird,
muss der Programmcode mal in den Speicher geladen werden. Hier kann dann der
Prozessor dann in aller Ruhe Variabeln, Befehle, usw... holen, wenn er sie
braucht und wenn das Programm beendet wird, schmeißt er wieder alles vom Speicher raus,
damit andere Programme Platz haben. Nicht nur Programme, sondern auch
andere Sachen werden hier verwahrt. Wenn ich jetzt zum Beispiel die Taste X
drücke, steht im Speicher drinnen, welche Taste ich gerade gedrückt habe. Auch
das hier steht gerade im Speicher. Natürlich wird der Speicher nicht einfach
blind verteilt, sondern jedem Programm wird ein eigener Bereich im Speicher zugewiesen.
Ein kleiner Test für die Praxis: Der Prozessor holt sich ja die Befehle aus dem
Arbeitsspeicher. Wenn er also keinen Arbeitsspeicher hat, hat er keine Befehle
und nix geht. Nehmt doch mal (auf eigene Gefahr) euren Rahmspeicher aus dem PC
und dreht dann den PC auf. Keine Angst, im Normalfall wird der PC nicht kaputt.
Beep, Beep, Beep, ... außer einem Beepen passiert nichts, da beim POST (Power
On Self Test) bemerkt wurde, dass es keinen Platz gibt, wo
man Befehle ablegen könnte. Für das überprüfen
ist übrigens der CMOS-Chip (der das BIOS enthält) zuständig.
Was aber, wenn der Speicher nicht mehr für die ganzen laufenden Programme
ausreicht? Ganze einfach, dann legt das Betriebssystem eine Auslagerungsdatei
(SWAP-Datei) auf der Festplatte an, die einen Arbeitsspeicher simuliert. Also
bräuchte man eigentlich nur soviel Speicher, wie das Betriebssystem für sich
selbst benötigt. Zu beachten sei dabei, dass der Zugriff auf die Festplatte viel
länger dauert, als auf eine RAM-Bank. So, nun sollte jeder wissen, warum der PC
einen Speicher braucht.
Register
Register sind Speicher, die sich im Prozessor befinden. Da sie im Prozessor sind, müssen sie relativ klein sein. Doch wozu brauche ich nun Register im Prozessor, wenn ich ja einen Arbeitsspeicher habe. Nun ja, sie sind ersten die schnellsten Speicher, die es im Computer gibt, da sie sich ja direkt im Prozessor befinden und zweitens sind sie das Wichtigste beim Programmieren in Assembler. Warum? Das werde ich hier gleich erklären. Die Register hatten bis zum 286er Prozessor immer nur eine Größe von 16 Bit, seit dem 386er ist diese Größe aber glücklicherweise auf 32 Bit gestiegen. Diese Register haben alle einen eindeutigen Namen. Keine Angst, diese sind recht einfach zu merken. Bitte lasst euch von der Vielzahl der Register nicht abschrecken. Ich möchte hier nun mal die Arten der Register auflisten, die es im Computer gibt:
REGISTERARTEN |
Die Register werden im Folgenden alle beschrieben. Ich möchte hier gleich erwähnen, dass es nicht notwendig ist, alles an einem Tag zu lernen!!! Ich finde, das sollte man bei den Registern sogar meiden, da diese doch eine Fülle an Lernstoff bieten und es Anfängern wie uns nicht gerade leicht fällt, alles gleich zu verstehen. Wen man jedoch alles sofort versteht, kann man durchaus den ganzen Abschnitt an einem Tag durcharbeiten.
Universalregister
Die Universalregister umfassen 4 Register mit dem Namen A, B, C und D. Das ist leider noch nicht der vollständige Name. Hat das Register A z.B. 16 Bit wird es AX genannt und hat es 32 Bit, dann wird es EAX genannt. AX kann man dabei wieder in 2 mal 8 Bit unterteilen. Diese haben den Namen AH (A High) und AL (A Low). Das Gleiche gilt für die Register B, C und D. Ich weis, dass ist jetzt ein wenig verwirrend, aber das gibt sich mit der Zeit recht schnell.
Hier eine kleine Grafik, um eine etwas bessere Vorstellung darüber zu bekommen, wie das jetzt mit den Bits in den Registern aussieht:
Bei einem 286er würde es nur ein AX Register geben, dass in AH und AL unterteilt werden kann. AH und AL haben hier jeweils 8 Bit. Man kann sie gemeinsam als AX, oder einzeln als AH und AL nutzen. Links sehen wir eine Erweiterung von 16 Bit, die es ab dem 386er Prozessor gibt. Das AX Register mit der Erweiterung wird dann EAX genannt, welches 32 Bit hat. Die Register EBX, ECX und EDX sind ebenfalls so aufgebaut.
Segmentregister
Um erklären zu können, welche Aufgabe diese Register haben, müssen wir das Thema "Speicher" mal genauer unter die Lupe nehmen. Befehle die im Speicher liegen, müssen ja eine Position haben. Diese Position nennt man Adresse. Beim Programmieren nennt man das Ganze "Zeiger". Ich zeige also auf eine bestimmte Stelle im Speicher. Es gibt nun aber 2 verschiedene Arten von Adressen. Wir hätten da die "Physikalische Adresse" und die "Logische Adresse". Jetzt wundert man sich natürlich, warum man 2 Adressen braucht, um eine Adresse anzugeben. Ich muss ehrlich zugeben, dass ich am ersten Blick auch nicht genau wusste, was das soll, doch als ich dann weitergelesen habe, ist mir klar geworden, dass es unumgänglich ist. Warum das so ist, will ich jetzt erklären:
Wie man an der Grafik sehen kann, sind
die Speicherzellen "numeriert". Da die Nummer gleichzeitig die Adresse
(diese wird "Physikalische Adresse" genannt) der Speicherzelle ist,
können wir die Speicherstelle recht einfach angeben, gäbe es da nicht ein kleines
Problem. Aus Geschwindigkeitsgründen, besitzen Register diese Adresse. Da ein
Register ja nur 16 Bit hat, haben wir nur 2 hoch 16, also 64 KB, zur
Adressierung zur Verfügung. Die Adressierung des Datenbusses hat aber 20 Bit.
Das sind 2 hoch 20, also 1 MB. Befinden wir uns im "Real Mode", wie es
z.B. unter DOS (nicht mit der Eingabeaufforderung in Windows verwechseln) ist,
können wir die Adresse als 16 Bit Wert angeben. Unter Windows befinden wir uns jedoch
nicht im "Real Mode" und müssen eine 20 Bit Adresse übergeben. Wie
machen wir das denn nun? Der Speicher wird nun in 65.536 Paragraphen
(Abschnitte) unterteilt, mit einer Größe von jeweils 16 Bit (64 KB). Die
Paragraphenadresse gibt ein Segment an und eine Stelle im Segment nennt
man "Offset Adresse". Die Adresse wird immer im folgenden Format
angegeben: Segmentadresse:Offsetadresse
Diese Adresse bezeichnet man nun als "Logische Adresse". Der Computer
rechnet diese immer in die Physikalische Adresse um. Man multipliziert einfach
die Segmentadresse mit 16 und zählt die Offsetadresse hinzu.
Wenn wir bei der Grafik hier von links oben zu zählen beginnen würden, würde die "Logische Adresse" folgend lauten: >> 1:B << , was übersetzt >> 1 Segment:Speicherzelle 11 << bedeutet. Das "B" deshalb, weil die Adresse im Hexadezimalen System angegeben wird (zu dem kommen wir später noch). Da die "Logische Adresse" aus 2 Werten besteht, brauchen wir natürlich auch 2 Register. Das ist der Punkt, wo die Segmentregister ins Spiel kommen. Insgesamt gibt es sechs Segmentregister, die ich hier (in kurzer Form) mal beschreiben will:
>
CS (Codesegment-Register)
Enthält die Adresse des Segmentes, wo sich der Code eines Programmes
befindet
>
DS (Datensegment-Register)
Enthält die Adresse des Segmentes, wo sich Variablen, Strings, etc...
eines Programmes befinden
>
SS (Stacksegment-Register)
Das Register zeigt immer auf den Anfang des Stacksegmentes, wo Daten
zwischengespeichert werden (Stack wird später noch erklärt)
>
ES, FS, GS
Diese Register haben keine besondere Bedeutung und könne frei zur
Adressierung verwendet werden
Index- und Zeigeregister
Diese
Register dienen als Adressierung innerhalb eines Segmentes und es gibt davon 5 Stück. Ganz schön nervig die vielen Register, oder? - aber leider brauchen wir
sie. Also "Fire up your brain" und weiter geht's :)
Ich werde die Register nun wieder in kurzer Form erklären:
SI
(Source Index Register)
Diese Register wird
verwendet, wenn man zum Beispiel eine Zeichenkette (String) kopieren will. Es
wird verwendet, um die Quelle (Source) anzugeben.
DI
(Destination Index Register)
DI tritt auch in
Aktion, wenn man einen String kopieren will. Der einzige Unterschied zu SI ist,
dass hier das Ziel (Destination) angegeben will.
BP
(Base Pointer)
Mit diesem Zeiger können wird auf den Stack zugreifen.
SP
(Stack Pointer)
SP zeigt immer auf die letzte Stelle im Stack, wo etwas gespeichert wurde.
IP
(Instruction Pointer)
Dieser Zeiger zeigt
immer auf die nächste Instruktion im Code-Segement, also dem Befehl, der als
nächstes kommt bzw. ausgeführt wird.
Flagregister
Nun ist es zeit, mal kräftig zu jubeln, da wir uns dem letzten Register nähern, nämlich dem Flagregister, welches leider auch das Schwierigste ist. Ich glaube ich sollte hier mal erwähnen, was überhaupt ein Flag ist. Hört sich irgendwie nach einer Flagge an. Wer das glaubt, liegt da aber leider falsch. Ein Flag ist eigentlich nichts anderes, als ein Bit, das entweder gesetzt ist (1), oder gelöscht ist (0). Da wir nun wissen, was überhaupt ein Flag ist, können wir uns zum "Flagregister" vorwagen. Tja... wie kann man das erklären... hier werden die Ergebnisse von bestimmten Operationen gespeichert. Jetzt werden sie einige unter euch denken, wie ich mit 0 und 1 ein Ergebnis speichern kann. Da hat man nicht ganz unrecht damit. Unter Ergebnis wird hier etwas anderes verstanden. Ich werde hier mal ein kleines Beispiel erläutern, wobei ich mich hier gleich auf die Funktion des Sing-Flag beziehen werde. Angenommen wir würden dem Computer die Rechnung 3 minus 8 rechnen lassen, dann würde er das SF (Sign-Flag) auf 1 setzen. Warum? Das Sign-Flag wird gesetzt, wenn bei einer Rechnung (arithmetischen Operation genannt) ein negativer Wert herauskommt. Das Ergebnis ist hier also nicht -5, sondern es wird einfach nur überprüft, ob das Ergebnis der Rechnung negativ, oder positiv ist. Ich hoffe, dass nun jeder begriffen hat, was ein Flag ist, da ich wieder mal eine kurze Aufzählung mit Erklärung mache :)
CF (Carry-Flag)
Dieses Flag wird
benutzt, wenn bei einer Addition, oder Subtraktion der Wertbereich für das
Register überschritten wird. Wenn ich z.B. in einem 8 Bit Register eine 16 Bit
Zahl speichern will, wird der "Wertbereich" überschritten und das
Flag gesetzt (1).
PF (Parity-Flag)
Dieses Flag wird heute
nicht mehr benutzt, da die Funktion von I/O (Input/Output) Bausteinen
übernommen wird. Es wurde früher zur überprüfung auf übertragungsfehler
verwendet.
AF (Auxiliary-Flag)
Dieses Flag wird
gesetzt, wenn bei einer BCD-Operation (BCD =
Binary Coded
Decimal) eine
übertragung von Bit 3 nach Bit 4 stattfindet.
ZF (Zero-Flag)
Hier kann man es
eigentlich erraten, welche Aufgabe dieses Flag hat. Das Flag wird gesetzt, wenn
das Ergebnis der letzten Operation 0 war.
SF (Sign-Flag)
Dieses Flag haben wir
oben bereits besprochen. Um keine halben Sachen zu machen, werde ich hier
nochmals die Funktion dieses Flags beschreiben. Das Flag wird gesetzt, wenn das
Ergebnis einer logischen, oder arithmetischen Operation negativ ist.
TF (Trap-Flag)
Beim Prozessor gibt es
einen sogenannten Einzelschrittmodus, welcher in der Fachsprache als
"Single Step Mode" bezeichnet wird. Wenn der Prozessor sich in diesem
Modus befindet, führt er nach jedem Befehl ein spezielles Unterprogramm aus.
Das könnte z.B. eine Fehlerüberprüfung sein.
IF (Interrupt-Flag)
Dieses Flag wird im
Grunde vom Programmierer gesetzt, oder gelöscht. Wenn das Flag gesetzt (1) ist,
dann werden Unterbrechungen des Programmes (z.B. über die Tastatur) ignoriert.
DF (Direction-Flag)
Wenn dieses Flag
gesetzt ist, dann werden alle String-Operationen von rechts nach links
durchgeführt, anstatt der Standardrichtung die von links nach rechts geht.
OF
(Overflow-Flag)
Dieses Flag wird
gesetzt, wenn nach einer Rechnung das Vorzeichenbit zerstört wurde. Falls ein
übertrag erfolgt, wird das Carry-Flag gesetzt.
Ja, das war's. Ich muss zugeben, dass ich beim Flagregister alles ein wenig mickrig geschrieben habe, doch dass liegt daran, dass ich derzeit noch nicht mehr darüber gelernt habe und es als Anfänger in Assembler auch noch nicht wirklich benötigt habe. Das soll aber nicht bedeuten, dass das so bleibt. Ich werde diesen Abschnitt erweitern, sobald ich das benötige Wissen dafür erlangt habe.
*** Bonusmaterial ***
Da wir hier am Ende für den Abschnitt Register angekommen sind und es nicht gerade leicht ist, alles zu verstehen, empfehle ich, die folgende Seite mal durchzulesen. Ich habe sie im Internet auf einer anscheinend chinesischen (oder japanischen) Seite gefunden, welche aber in englisch geschrieben wurde. Ich hoffe nur, dass diese Seite keinem Copyright unterliegt und ich sie hier in diesem Tutorial einfügen darf.
Die Quelle
der Seite:
http://www.culturecom.com.hk/HTML/intro/intro_d_e_9.html (nicht mehr online)
Hier klicken, um die Seite offline zu lesen
Eingabeeinheit
Zur Eingabeeinheit zählen beim PC z.B. die Tastatur, die Maus, oder ein Joystick. Hier gibt es natürlich auch noch andere Geräte, die man zur Eingabeeinheit zählen kann. Die Eingabeeinheit besteht also aus den Geräten, mit denen man Informationen in den Computer eingeben kann.
Ausgabeeinheit
Die Ausgabeeinheit ist das Gegenteil der Eingabeeinheit. Zur Ausgabe zählen alle Geräte, mit denen Informationen ausgegeben werden können. Solche Geräte können z.B. Drucker, oder Bildschirm sein.
Niederwertige und höherwertige Bytes
Ein 16 Bit Register besteht aus 2 mal 8 Bit, also aus 2 Bytes. Diese 2 Bytes bekommen nun die Bezeichnung "niederwertiges Byte" und "höherwertiges Byte". Nun stellt sich natürlich die Frage, welches das Niedere und welches das Höhere ist.
15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
höherwertiges Byte |
niederwertiges Byte |
Wie man sieht, gehen wir von rechts nach links. Ganz rechts befindet sich das niederwertige Byte und ganz links ist das höherwertige Byte. Diese 2 Bytes zusammen, nennt man auch ein WORD. Ein WORD kann 2 hoch 16 Zustände annehmen, also 65.536. Ein Register mit 32 Bit besteht aus 2 Words, also einem DWORD (Double Word). Soviel zu den Bytes, doch der Vollständigkeit halber, möchte ich auch noch die Bits erwähnen. Ein Byte besteht ja aus 8 Bits. Hier gibt es auch ein höherwertiges Bit und ein niederwertiges Bit. Wie man sich denken kann, steht das niederwertige Bit ganz rechts und das höherwertige Bit ganz links.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Der Stack
Der Stack ist nichts anderes, als eine Art Schrank, mit lauter Schubladen. Wenn wir etwas kurz ablegen wollen, dann geben wir es auf den Stack. In Assembler heist das dann PUSH. Man kann es sich dann wieder zurückholen, wenn es benötigt wird. Das Zurückholen heist in Assembler POP. Aha... der Stack ist also eine Schublade, wo man was POPPEN (nicht falsch verstehen ;)) und PUSHEN kann. Damit man sich jetzt auch was darunter vorstellen kann, hab ich wieder eine kleine Grafik (eher Tabelle) dazu erstellt:
STACK |
1 |
2 |
3 |
Angenommen, diese Grafik oben wäre unser Stack, dann sehen wir hier, dass in dem Stack 3 Werte abgelegt wurden. In der ersten Schublade liegt der Wert 1, in der 2ten der Wert 2 und in der 3ten der Wert 3. Nun kann man ja diese Werte nicht irgendwie in den Stack geben. Das funktioniert natürlich nach einem System, dem "LIFO Prinzip". Was ist denn nun bitte ein LIFO Prinzip??? LIFO steht für Last In First Out, was auf gut Deutsch bedeutet: Was zuletzt reingekommen ist, kommt als Erstes wieder raus. Nun wissen wir, in welcher Reihenfolge wir die 3 Werte ablegen müssten, damit sie so, wie oben in der Grafik zu sehen, eingeordnet werden würden. Zuerst kommt die 3, dann die 2 und am Ende die 1 in den Stack. Ja... das war's auch schon über den Stack. Ich glaube nicht, dass es kompliziert war, oder? - Darüber könnte man nun streiten. Den Stack zu benutzen, ist die eine Sache, aber ihn richtig zu benutzen, ist wieder eine andere Sache :) Es gibt in Assembler Unterprogramme, die Werte auf dem Stack ablegen und sich dann auch wieder holen. Das heißt, dass wir nicht einfach irgendwann was rauflegen können, da sonst das Unterprogramm unseren Wert rausholen würde. Wir müssen unseren Wert also vorher vom Stack wegnehmen, bevor das Unterprogramm sich wieder seine eigenen Werte holen will. Das ist nun schon komplizierter, aber dazu mehr, wenn es soweit ist :)
Zahlensysteme
Nun kommen wir zu einem der vielleicht wichtigsten Themen am Computer, nämlich den Zahlensystem. Das Wort Computer kommt ja von dem englischen Wort "compute", was soviel wie errechnen, berechnen bedeutet. Ein Computer ist nun mal nichts anderes als eine Rechenmaschine. Ob man es glaubt, oder nicht, der Computer kann eigentlich nicht wirklich rechnen, in dem Sinne, wie wir es verstehen. Er weis nicht einmal, dass nach 9 die 10 kommt. Er folgt nur einem System, dass nach bestimmten Regeln funktioniert, eben einem Zahlensystem. Vielleicht habt ihr schon mal was von der ASCII Tabelle gehört. ASCII steht für American Standard Code for Information Interchange. Wenn ich jetzt auf der Tastatur die Taste 1 drücke, dann schickt der Tastaturchip dem Prozessor den binären Tastencode. Der Computer schaut nun in der ASCII Tabelle nach, für welches Symbol dieser Code steht und verarbeitet dann dieses Symbol weiter. Somit ist eine 1 genau so ein Symbol, wie ein A, oder ein B. Es gibt für den Computer nur ein System, das "Binäre Zahlensystem". Er kann natürlich auch im Hexadezimalen- ,oder Dezimalsystem rechnen, was aber nur so aussieht, als ob, da er im Inneren wieder im Binären System rechnet. Beim Zählen, geht man nach einem bestimmten System vor, welches wir uns mal ansehen wollen.
a)
Das Dezimalsystem
Unsere Zahlen, haben
die folgenden Symbole: 0 1 2 3 4 5 6 7 8 9 0
Es sind deshalb 10 Symbole, weil der Mensch 10 Finger hat, und noch heute gerne
damit rechnet :) Die Symbole dafür sind übrigens im Mittelalter
entstanden.
Wir dürfen unsere Zahlen nicht als Zahlen, sondern als Symbole sehen. Man könnte ja statt der 1 auch ein A schreiben. Trotzdem würde das beim Zählen nichts ändern. Wir haben nun halt eben nur ein anderes Symbol: 0 A 2 3 4 5 6 7 8 9 Die Zahl 10 würde dann eben die Form A0 annehmen. Trotzdem behält sie einen Wert, mit dem wir etwas anfangen können. Doch warum genau kommt eigentlich nach der 9 die 10 und nicht 11, oder warum kommt nach 99 100 und nicht A00? Es sind ja alles nur Symbole. Das ist deshalb so, weil die Symbole nach einem bestimmten System aneinandergereiht werden. Ich will es mal durch die folgende Grafik veranschaulichen:
Wie
wir sehen, gibt es bei den Symbolen eine Rangordnung, was bedeutet, das z.B. das
Symbol 2 einen niedrigeren Wert, als das Symbol 9 hat. Im Fall 1 sehen wir eine
Taschenrechneranzeige, die den Wert 1 auf der Einerstelle anzeigt. Im 2ten Fall sehen wir den Wert 10.
Nun will ich erklären, wie man genau mit dem System an den Wert kommt.
Die Taschenrechneranzeige, die wir hier sehen, besitzt 9 Stellen. Diese werden
von rechts nach links benutzt. Wir beginn ganz rechts an der ersten Stelle,
unserer Einerstelle. Hier wird beim Zählen immer das Symbol mit der
nächsthöheren Rangordnung angezeigt, bis man beim letzten Symbol, der 9
angekommen ist. Danach fängt man wieder bei dem Symbol mit der niedrigsten
Rangordnung an, setzt aber zuvor die linke Stelle, in unserem Fall die 10er
Stelle, um ein Symbol höher, also eine 1, womit wir beim Fall 2 wären. Hier
wurden bei der Einerstelle alle Zeichen einmal angezeigt, womit die links davon
liegende Stelle (die Zehnerstelle) um eine Rangordnung erhöht wurde und das
Symbol 1 anzeigt. Kommt dann irgendwann mal die Zehnerstelle beim letzten
Symbol, der 9, an, dann wird diese wieder auf 0 gesetzt und die Stelle links
daneben, also die Hunderterstelle, um das Symbol mit der nächsten Rangordnung,
der 1, erhöht:
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
Nun wissen wir, wie der Computer beim Zählen im Dezimalsystem vorgeht und wir haben somit auch die Grundlagen, um die anderen Zahlensystem zu verstehen, da hier nur andere Symbole verwendet werden. Vielleicht hat man schon mal was über die Basis eines Zahlensystems gehört. Die Basis ist immer die Anzahl der Symbole, die es in dem Zahlensystem gibt. In Assembler wird eine Dezimale Zahl immer mit einem d am Schluss gekennzeichnet, was so aussehen kann: 100d
Ja, dass war es auch schon zum Thema Dezimalsystem. Es ist wichtig zu wissen, dass unsere Zahlen für den Computer nichts anderes als Symbole sind, da wir uns sonst etwas schwerer tun würden, um die nächsten Zahlensysteme zu verstehen.
b) Das Hexadezimalsystem
Im Hexadezimalen
System ist die Basis 16, womit wir wissen, dass es hier 16 Symbole gibt:
(Mit den Fingern kommen wir hier übrigens nicht mehr weiter, es sei denn, wir
rechnen auch noch mit den Zehen *g*)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
Wir zählen also von 0 bis F und dann wird die Stelle links von uns um eine Rangordnung, erhöht. Es ist eigentlich immer das gleiche System. Nach F kommt also 10, was im Dezimalen den Wert 16 hätte.
An dem
nächsten Beispiel, will ich demonstrieren, wie wir eine Hexadezimale Zahl ins
Dezimale umrechnen können. Wir wissen, dass die Basis des Hexadezimalen Systems
16 ist. Man muss jetzt nur die richtige Potenz, also die 16, nehmen und schon
kann man umrechnen. Angenommen, wir wollen die Zahl
1FA3
umrechnen, dann
benötigen wir die Potenzen von 16 hoch 0 bis 16 hoch 3.
160 = 1
161 = 16
162 = 256
163 = 4096
Das Ergebnis tragen wir von rechts nach links in eine Tabelle ein und schreiben darunter unsere Hexadezimale Zahl.
4096 |
256 |
16 |
1 |
1 |
F (15) |
A (10) |
3 |
Wir haben uns
nun eine Tabelle gemacht, und multiplizieren nun einfach die Zahlen der oberen
Zeilen mal dem Wert der darunterliegenden Zeile und Zählen dann alles zusammen.
3 * 1 = 3
16 * 10 (A) = 160
256 * 15 (F) = 3840
4096 * 1 = 4096
Zusammengezählt ergibt das dann 8099,
womit wir schon unseren Dezimalwert hätten :)
Der Vollständigkeit halber, werde ich auch noch erklären, wie wir von einer
Dezimalen Zahl auf eine Hexadezimale Zahl umrechnen. Wenn wir das Ganze als
Gleichung betrachten würden, müssten wir eigentlich nur dividieren und wir
hätten es. Jetzt darf man wieder mal jubeln, denn es steckt auch nicht mehr
dahinter :) Wir müssen einfach nur unsere Zahl durch die Basis des System
dividieren, welches wir haben wollen und den Rest umwandeln. Im Hexadezimalen,
haben wir, wie schon gesagt, 16 als Basis. Nehmen wir uns mal unsere Zahl 8099
her:
Rechenvorgang:
8099 / 16 = 506,1875
506 * 16 = 8096 REST: 3
Somit hätten wir schon mal unsere erste Zahl, die 3. Nun gehen wir immer
weiter, bis wir nicht mehr dividieren können. Das Weitergerechnet wird
übrigens immer mit dem letzten Ergebnis der Division, welches immer
abgerundet wird.
506/16 ERGEBNIS: 31,625 REST: 10
(A)
31/16 ERGEBNIS: 1,9375
REST: 15 (F)
1 REST 1
Von unten nach oben gelesen, haben wir dann wieder unsere Hexadezimale Zahl 1FA3! In Assembler wird eine Hexadezimale Zahl am Ende immer mit einem h gekennzeichnet. Das könnte so aussehen: 1FA3h.
c) Das
Binärsystem
Jetzt widmen wir uns dem Rechensystem des Computers, dem Binären
Zahlensystem. In diesem System gibt es nur 2 Symbole, nämlich 0 und 1. Mann
nennt sie auch Dualzahlen. Das Zählen funktioniert wieder nach dem gleichen
System, wie wir es beim Dezimalsystem und beim Hexadezimalsystem hatten:
0000
0001
0010
0011
0100
0101
0110
0111
1000
...
Nun
kommen wir wieder zum Umrechnen. Probieren wir mal eine die Binäre Zahl 1001
in eine Dezimalzahl umzuwandeln. Die Basis in diesem System ist 2, deshalb
benötigen wir bei 4 Stellen, die Potenzen 2 hoch 0 bis 2 hoch 3.
20 = 1
21 = 2
22 = 4
23 = 8
8 | 4 | 2 | 1 |
1 | 0 | 0 | 1 |
Hier brauchen
wir nicht zu multiplizieren, da es unnötig wäre, da 8*1=8 , 1*1=1, 4*0=0, ...
was bedeutet, dass wir einfach nur die oberen Zahlen zusammenzählen müssen, wo
eine 1 darunter steht:
- unter der 1 ist
eine 1 deshalb +1
- unter der 2 ist eine 0,
sie wird nicht dazugezählt
- unter der 4 ist eine 0,
sie wird nicht dazugezählt
- unter der 8 ist eine 1,
deshalb +8
Das Ergebnis ist 8+1, was 9
ergibt. Unsere Binäre Zahl 1001 ist im Dezimalen
eine 9. Nun könnten wir die Dezimale ins
Hexadezimale umrechnen, usw...
Das Zurückrechnen von einer Dezimalen in eine Binäre, funktioniert genau so,
wie im Hexadezimalen:
Rechenvorgang:
9/2=4,5
4*2=8 REST: 1
Das machen wir nun wieder, bis wir nicht mehr dividieren können:
4/2 ERGEBNIS: 2 REST 0
2/2 ERGEBNIS: 1 REST 0
1 REST: 1
Von unten nach
oben gelesen ergibt das wieder unsere ursprüngliche Binäre Zahl
1001. In Assembler
werden binäre Zahlen immer
mit einem b
am Ende gekennzeichnet. Das könnte so aussehen: 1001b.
So, dass war's auch
schon wieder zum Thema Zahlensysteme. Ist doch gar nicht so schwer, wenn man mal
das Grundsystem verstanden hat. Es gäbe jetzt auch noch das Octale
Zahlensystem, auf welches ich jetzt aber nicht näher eingehen möchte, da man
sich sowieso schon denken kann, wie das Umrechnen, Zählen usw... funktioniert.
Das Einzige was man braucht, ist die Basis. Im Octalen ist die Basis 8.
[Letzte Änderung: 02. März 2009]