ein Computer verarbeitet Informationen mit Hilfe von Vorschriften.
Zentraler Punkt ist:
eine CPU (Central Processing Unit),diese übernimmt viele Aufgaben:
- Lesen der Daten aus dem RAM
- Speichen der Daten im RAM
- Bereitstellung, Decodierung und Ausführung von Befehlen
- Verarbeitung der Eingabe von peripheren Geräten
- Verarbeitung der Ausgabe zur Peripherie
Aber bleiben wir mal bei der Informationsverabreitung und Rechenvorschrift(en):
Die Rechenvorschrift ist ein Programm. Um überhaupt irgendwas verarbeiten zu können, muss die CPU also sich diese Vorschrift holen. wir gehen mal von der heute verwendeten Von-Neumann-Architektur aus (
http://de.wikipedia.org/wiki/Von-Neumann-Architektur). Demnach
läuft das in etwa so ab: ein Befehl wird geholt und abgearbeitet, dann kommt der nächste Befehl dran. Da die Befehle von irgendjemandem geschrieben werden, müssten sie auch irgendwo definiert werden.
Desweiteren muss der Befehlschreiber(Programmierer) wissen, welche Befehle zugelassen sind, was er beachten muss, welche Funktionen zur Verfügung stehen usw. Es gibt daher eine
ISA (Instruction Set Architecture), wo diese Eigenschaften beschrieben werden.
Auch wird da beschrieben, wie die CPU zu steuern ist (ein Befehlssatz) - also wie man Werte laden, speichern und verrechnen kann. Diese Steuerung erfolgt über Zahlen: z.B könnte man sich auf ein bestimmtes Format einigen wie:
Die CPU liest immer zwei Zahlen aus dem Speicher ein:
Zahl1,Zahl2
Zahl1=Operation, Zahl2=Operand
und sagen: es gibt 3 Operationen,speichern,laden und addieren wobei dann
0000 = laden in Register0
0001 =laden in Register1
0010 = speichere Inhalt von Register0
0011 = Speichere Inhalt von Register1
1000 =Addiere Inhalt von Register1 zu Register0
und Zahl2 gibt immer die Speicheradresse an. Damit hätten wir schon einen klar definierten Befehlssatz erstellt. Wobei Zahl1 dann die
Opcodes (Operation codes) bilden würde (also eine Befehlsnummer).
---Exkurs---
Intern muss der Prozessor den geholten Befehl wiederum dekodieren um ihn auszuführen - da gibt es wiederum 2 Möglichkeiten - entweder ergibt der Befehl schon in der vorhandenen Form eine Art Codierung vor und steuert z.B über einen Decoder (also "richtigen" Hardwarebaustein-Decoder) durch die Belegung von Eingängen die Recheneinheit, so dass einzelne Funktionen sind ausführen lassen.
Oder: der Opcode ist bloß die Nummer eines Unterprogramms, welches auf der CPU gespeichert ist (auch
Microprogram genannt). Es wird also ein Befehl nicht direkt in Hardware umgesetzt, sondern von der CPU erstmal "interpretiert" - z.B siehe Intel IA-32 (0x86) Architektur bzw auch als "gemeiner Desktop/Aldi-rechner" bekannt

. Stichworte sind hier
CISC RISC
Wenn Du mehr wissen willst, wie es intern in einer CPU abläuft (wie die Befehle letztendlich "verstanden" werden können):
http://de.wikipedia.org/wiki/Mikroprozessor
---Ende----
Da die moderneren CPUs viel mehr unterschiedliche Befehle anbieten und diese nicht immer so einfach codiert sind (z.B
http://www.intel.com/products/processor/manuals/)
wäre es viel Aufwand, größere Programme durch direkte Codierungen zu schreiben.
So könnte man sich auch Abkürzungen überlegen und statt 1000 z.B ADD oder statt 0000 LOAD_0 schreiben. Wir bräuchten natürlich erstmal ein Programm, welches im Nachhinein daraus wieder die "Zahlenform" erstellt.
Wenn wir dieses Programm erst geschrieben haben, müssen wir bei anderen Programmen nicht mehr alles "selber" Kodieren und in CPU-Herstellertabellen nachschauen.
Jetzt können wir statt
|
Source code
|
1
2
3
4
5
6
7
8
9
|
0000 00010000
0001 00010001
1000 00000000
schreiben:
LOAD_0, 256
LOAD_1, 257
ADD
|
was doch schon um einiges verständlicher wäre.
Die von uns erfundenen Abkürzungen nennen wir mal Assembly, und das Programm zum Umwandeln dieser Abkürzungen in Opcodes könnten wir Assembler nennen
Um mal einen Sprung zu machen: LOAD_0 usw sind auch nicht der Weisheit letzen Schluss. Z.B kommt eine neue CPU heraus, die jetzt mehr Register hat oder mehr Rechenoperationen bietet oder größere Zahlen verarbeiten kann oder anders auf den Speicher zugreift - so müssten wir unsere Programme umschreiben und anpassen. Zusätzlich könnte es ja sein, dass gleich mehrere unterschiedliche CPUs genutzt werden und wir dann ein Programm jedesmal neuschreiben müssten (zusätzlich auch noch die ganzen Unterschiede zwischen den Architekturen lernen).
Wäre es nicht sinnvoller, wenn wir z.B eine von Registern und einzelnen Instruktionenen unabhänige Schreibweise verwenden könnten?
z.B
Wert3=Wert1+Wert2 ?
Solange wir uns an die Regeln der Definition unserer Sprache halten, können wir relativ einfach ein Programm schreiben, welches diese Konstrukte übersetzt/umwandelt(z.B zuerst in Assembly, denn da haben wir schon ein Programm geschrieben, welches dann aus Assembly Maschinencode generiert).
Wie das? Nun, z.B durch Schablonen - man braucht nur den Text etwas umzuordnen (auch nach Schablonenverfahren

) '=' ist unsere Zuweisung, also steht links vor dem '=' die Variable, in die gespeichert wird und rechts der Ausdruck.
Ausdruck: Wert1,Wert2,+ (das ist die umgekehrte polnische Notation
UPN )
Speicher: Wert3
Jetzt wendet man nochmal Schablonen an - von links nach rechts durchgehen (Schablone2: generiere für jede Variable im Ausdruck-Teil ein LOAD_Nr und für Rechenzeichen entsprechende Operation).
für Wert1 wird : LOAD_0 Wert1
generiert
Wert2: LOAD_1 Wert2
+ : ADD
für "Speicher: Wert3":
STORE_0, Wert3
also haben wir den Assemblycode erhalten:
LOAD_0 Wert1
LOAD_1 Wert2
ADD
STORE_0 Wert3
(ich hoffe, das Beispiel war verständlich

)
Klar, wir müssten uns erstmal die Arbeit machen, aber diese müssten wir nur einmal pro CPU-Architektur machen - haben wir erstmal einen Umwandler geschrieben, brauchen wir ein Programm nur einmal zu schreiben und könnten jedesmal, wenn wir ein Programm auf einer bestimmten CPU laufen lassen möchten, vorher den Umwandler anwerfen - was herauskommt ist der Code für die neue CPU. Willkommen bei höheren Programmiersprachen - jetzt ersetze nur noch "Umwandler" durch "Compiler"

Und da der Mensch immer noch nicht zufrieden ist, möchte er sich eben immer weniger an CPU/Technik anpassen und dieser seine Wünsche in möglichst natürlicher Sprache mitteilen - also werden diese immer weiterentwickelt. Die Idee dahinter - dass dann aus der höheren Sprache trotzdem letzendlich CPU-verständlicher Code generiert wird, bleibt. Also (i.R): Progarmm in Pascal -> wird zu einer Serie von Maschinenbefehlen.
Wenn wir jetzt aber als Programmierer einen Fehler drin hätten und den Ablauf verfolgen wollten - wie sollten wir das anstellen? Klar, zur Ablaufverfolgung könnten wir ein Programm schreiben, welches und den Zustand der CPU und des Speichers anzeigen könnte. Aber da im fertigen Programm nur noch Maschinencode drin ist, könnten wir es schlecht in Pascal anzeigen - also hätten wir die Option es entweder in Maschinencode darzustellen oder in Assembly (da Assembly ja 1 zu 1 in Maschinencode umgesetzt wird, können wir auch Maschinencode 1:1 in Assembly anzeigen)
Ok, moderne Programmierentwiklungstools bieten die Möglichkeit den Fehler zu suchen und dabei auf den Originalcode (also Pascal, C/C++ usw) zu schauen - es wird aber intern mit vielen Tricks gearbeitet um es so schön komfortabel darstellbar zu machen.
Assembly lässt sich aber immer noch in vielen Sprachen einbinden - wozu? Nun, um z.B auf spezifische Funktionen der CPU zugreifen zu können (die z.B nur auf einem Intelrechner zur Verfügung stehen), um Optimierungen zuzulassen oder Zugriff auf bestimmte Hardware zu ermöglichen.