Die Übung fällt auch nicht aus.
Das ist noch nie ausgefallen bei diesem Sportfest oder so.
Außerdem denken wir uns, es ist besser für Sie, wenn wir jetzt noch
den Stoff durchziehen und dann in der letzten Woche ein bisschen
langsamer die Sache angehen lassen, damit Sie sich da schon ein
bisschen auf die Klausur einrichten können.
Wir werden auch am Montag in der letzten Woche keine Vorlesung, keine
richtige Vorlesung haben, sondern Professor Weibel wird kommen.
Das ist der Leiter unseres Instituts, an dem ich bin, der teilweise
auch im Vorlesungsverzeichnis drinsteht zu dieser Vorlesung.
Und Professor Weibel wird so ein paar interessante Sachen erzählen
darüber, was wir machen.
Wir werden Demos vorführen von Spracherkennern, von
Handschrifterkennern, von Gesichterkennern und was auch immer.
Und das wird also so eine Art lustige Vorlesung, eine Fun-Vorlesung
werden.
Und wir versuchen, den Stoff bis dahin vorher schon fertig zu haben.
Deswegen machen wir heute lieber eine richtige Vorlesung und die
letzte Woche dann ein bisschen weniger.
Und für die, die keine Newsgroup lesen, weil die Frage jetzt schon so
oft gekommen ist, die beiden Klausuren werden zufällig ausgewählt.
Wir machen zwei Klausuren, verteilen die Aufgaben zufällig drauf und
wählen zufällig eine als die erste und eine als die zweite aus.
Es ist nicht so, dass die eine schwerer als die andere entworfen wird.
Das kann gar nicht sein.
Es ist auch egal, welche Sie mitschreiben, nur wenn Sie die zweite
mitschreiben, dann müssen Sie halt sich mit dem Gedanken anfreunden,
dass wenn es nicht klappt, dass Sie nächstes Jahr bei einem anderen
Prof mit der anderen Vorlesung dann die Info 2 machen müssen.
So, okay.
Dann kommen wir zu dem Thema, dem letzten Thema von dieser Info 2
Vorlesung.
Wir nennen das Kapitel eigentlich so wie vom Programm zur Maschine.
Also was passiert auf dem ganzen Weg zwischen dem, was der Mensch sich
ausdenkt und dem, was dann unten in der Maschine tatsächlich abläuft.
Wie Sie gleich hier auf der ersten Folie sehen, haben wir da sehr
viele verschiedene Ebenen, die man so irgendwie hierarchisch anordnen
könnte.
Ganz außen auf der obersten Ebene, wenn wir das jetzt als Programm
ansehen würden, können wir die Umgangssprache nehmen.
Und da wäre es schön, wenn man es einfach sagen könnte, zum Computer
hingehen, mach mal Primzahl und dann weiß er schon, was zu tun ist.
Da sind wir noch ziemlich weit weg davon, dass das funktioniert.
Schon eher in Richtung Realität gehen Spezifikationssprachen, wo wir
also nicht definieren, was der Rechner tun soll, sondern was
rauskommen soll.
Das wäre dann also die etwas formalere Version von mach Primzahl.
Da steht nicht drin, was getan werden soll, aber es ist spezifiziert,
was rein und raus kommen soll.
Das, was Sie sicher kennen, sind eben höhere Programmiersprachen.
Das ist das wohl, womit Informatiker als erstes heutzutage in Kontakt
kommen.
Das ist eben die Version in Java, oder der Anfang davon, für mach
Primzahl.
Und was uns ab heute interessieren soll, ist, wie sieht es in diesen
tieferen Ebenen aus?
Tieferen Ebenen, also höhere Programmiersprachen abwärts.
Und zwar werden wir uns jetzt, also ab heute, mit Assembler
beschäftigen.
Sie werden auch Übungsaufgaben in Assembler programmieren.
Und da sehen die Sachen ein bisschen anders aus.
Man hat nicht mehr diese schönen Konstrukte wie in hohen
Programmiersprachen, sondern man muss sich ein bisschen mehr auskennen
mit dem, was die Maschine kann.
Und man muss mehr zu Fuß machen, als man hier oben schon fertig in
Funktionen vorgegeben kriegt.
Unterhalb von Assembler finden wir dann den sogenannten Maschinencode.
Und das ist eher das, was die Maschine versteht.
Assembler versteht sie eigentlich nicht.
Sondern der Assembler muss in etwas umgewandelt werden, was nur noch
aus Ziffern besteht, aus Bits besteht.
Einsen und Nullen.
Dieser Maschinencode ist jetzt allerdings hier noch ein bisschen
menschenlesbar dargestellt.
Nämlich so, dass das jetzt im 16er-System, im C-Dezimalsystem
dargestellt ist.
Da kann man eigentlich gar nicht mehr als Mensch so auf Anhieb
erkennen, was hier abläuft.
Wer hat schon mal mit dem 6502 programmiert in Assembler?
Ah, ja, doch.
Interessant.
Gibt es tatsächlich noch.
Ja, dann wissen Sie sicher, dass zum Beispiel diese erste Zeile
bedeutet Lade-Akkumulator direkt mit dem Wert 2.
Na gut, also das weiß man vielleicht, wenn man mal damit umgegangen
ist.
Aber wenn man es nicht kennt, kann man da gar nichts mehr dran
erkennen.
Ja, schauen wir noch eine Ebene tiefer.
Noch eine Ebene tiefer finden wir den sogenannten Micro-Code.
Dieser Micro-Code besteht also tatsächlich jetzt nur aus Nullen und
Einsen.
Und es gibt sehr wenige Maschinen, wo man noch als Mensch überhaupt
Zugriff auf diesen Micro-Code hat.
In der Regel hat man da als Benutzer überhaupt keine... weder Zugriff,
noch Möglichkeiten, da was dran zu ändern, noch was zu sehen.
In diesem Micro-Code hat jedes Bit typischerweise die Bedeutung, dass
irgendein Gatter geöffnet werden soll.
Ich kann das mal kurz skizzieren, was sowas bedeutet im Wesentlichen.
Wenn Sie mal bei uns im Flur waren, im zweiten Stock, im
Informatikgebäude, vielleicht haben Sie ja diesen Rechner gesehen,
diesen Relais-Rechner.
Diesen Think-1 für Fast, Fast, Intelligent, Interactive, Nice
Computer.
Das ist so ein Relais-Computer.
Und wenn Sie sich da angucken, wie der funktioniert, dann stellen Sie
fest, wo der Micro-Code, welche Rolle der spielt.
Da können Sie zum Beispiel solche Sachen sehen, wie, dass man ein Und
mithilfe eines Relais programmieren kann, indem man halt eben solche
zwei Relais hintereinander schaltet.
Und wenn man dann hier A dran setzt an das eine und B an das andere
Relais, dann ist der Ausgang hier C, ist eben A und B.
Entsprechend können Sie sich natürlich auch leicht vorstellen, dass
man auf diese Art O das machen kann.
Nichts kann man mit anderen Relais machen.
Und auf die Art kann man, wenn Sie schon Und, Oder und Nicht haben,
können Sie alles Mögliche machen.
Zum Beispiel auch ein Addierer.
Da können Sie ein komplettes Additionswerk basteln, das dann zum
Beispiel eben zwei Bit addiert.
A0, A1 kommen da rein.
B0, B1 kommen rein.
Und C0, C1 kommen raus.
Meinetwegen kommt noch irgendwo ein Übertrag rein.
Und typischerweise funktioniert jetzt auf dem niedrigsten Level von so
einem Computer, gibt es ja solche Sachen wie Busse.
Also das wären dann hier so ein Bus, das sind dann zwei Datenleitungen
in diesem Fall.
Und wenn wir jetzt addieren wollten, also das Programm, das sagt
addiere.
Das würde jetzt zum Beispiel darin bestehen, dass es sagt, hier haben
wir vielleicht irgendwo Speicher.
Speicherzelle 1, da gibt es ein Bit 0 und ein Bit 1.
Und dann würden wir sagen, typischerweise haben wir hier so eine Art
Gate.
Und dieses Gate legt dann diese Bits von dem Speicher auf den Bus oder
auch nicht.
Und so ein Gate hat eine Ansteuerleitung.
Wenn wir hier auf diese Ansteuerleitung jetzt einen Plus dransetzen,
dann heißt das, dieses Gate oder Tor öffnet sich.
Und was in dieser Speicherzelle drin steht, wird auf den Bus gelegt
und liegt dann somit jetzt auch an den Eingängen des Addierers dran.
Natürlich würde man auch, damit man ordentlich addieren kann, auch
hier Gates noch dransetzen.
Damit natürlich nicht beide Argumente des Addierers gleichzeitig
gesetzt werden.
Und A plus B addieren würde zum Beispiel so aussehen, öffne das Gate
aus dem Speicher 0,1.
Öffne das Gate hier in dem Addierer und dann ist das erste Argument
vom Bus gelesen.
Dann käme als nächstes, öffne ein Gate aus dem Speicher 2.
Öffne das zweite Gate aus dem Addierer, dann ist das zweite Wort im
Addierer drin.
Irgendwann haben wir vielleicht auch hier noch ein Gate.
Das sagt uns dann, ob wir die Ausgabe C0, C1 auf den Bus legen sollen.
Und andere Gates vielleicht, die dann wieder aus dem Bus herauslesen
in den Speicher.
Also das ganze Ding besteht aus Gates.
Natürlich müssen Sie sich das jetzt nicht merken.
Ich will nur kurz grob skizzieren, wo Mikro-Codes angreifen.
Und so ein Mikro-Code, das können Sie sich vorstellen, das ist eben
diese Zusammenfassung von Gates.
Welche Gates sind geöffnet?
Wir haben hier 1, 2, 3, 4, 5, 6 Gates dargestellt.
Das heißt, unser Mikro-Code würde so aus 6 Bits bestehen.
Irgend so was 0,1, 0,1, 0,1, 0 oder so.
Das würde bedeuten, öffne Gate 1, 3 und 5.
Das nächste Stückchenprogramm würde dann irgendwie anders aussehen.
Hat halt vielleicht überall Nullen, nur 1,1.
Öffne dieses Gates, wäre dann das nächste Stück.
Und dadurch durch dieses Öffnen und Schließen der Gates können dann so
die Daten durch diesen Computer durchwandern.
Das ist also der Mikro-Code.
Noch tiefer in der Ebene, damit wollen wir uns jetzt hier nicht
beschäftigen.
Das ist eher Sache der technischen Informatik, was Sie dann auch noch
kennenlernen werden.
Da liegen dann die Gatte, also wie werden tatsächlich solche ANDs und
ORs realisiert.
Und noch tiefer ist dann eben die Physikebene, wie funktionieren
Transistoren und so weiter.
Auch das ist eher Sache der technischen Informatik.
Wir wollen uns damit nicht beschäftigen.
Womit wir uns jetzt vor allem beschäftigen wollen, ist dieser Teil des
Assemblers und dann eben auch vor allem der Übergang von der hohen
Programmiersprache auf Assembler.
Ja, okay, was haben wir hier?
Gucken wir uns mal an...
Diese Hierarchie kann man jetzt nicht nur so hierarchisch sehen von
der Komplexität oder von der Ebene, auf der programmiert wird.
Man kann die Geschichte drin sehen, man sieht sogar einen Zeitstrang.
Eigentlich ist diese Sache hier auch ein Zeitstrang, also aus der
Vergangenheit in die Zukunft.
Angefangen hat man damit, dass man eben früher Computer gebaut hat,
indem man echt diese Bauteile verdrahtet hat.
Programmieren ging auch dadurch, dass man Drähte abgeknipst, woanders
drangelötet oder drangeschraubt hat.
So hat man in den Anfängen programmiert.
Später hat man sich dann überlegt, das könnte man eigentlich
automatisieren.
Und diese Reihenfolge, was man wo mit verdrahtet und wieder weglöst,
könnte man kodieren in so einer Art Micro-Code.
Und dann mithilfe irgendeiner Maschine diesen Micro-Code die
Verdrahtung automatisch durchführen lassen.
Später dann wurden diese Micro-Codes so kompliziert, dass kein Mensch
mehr aus diesen 001 herauslesen konnte, was gemeint war.
Dann hat man sich gedacht, definieren wir doch eine Maschinensprache
und schreiben diese Sachen statt in binär Darstellungen in Hex-Code,
so dass man sofort weiß, sowas wie A9 bedeutet Addiere, B2 bedeutet
Multipliziere und so weiter.
Und als dann auch das irgendwann zu kompliziert wurde, weil es zu viel
Funktionalität hatte, dann ist man dazu übergegangen, um es für den
Menschen einfacher zu machen, nicht mehr Hex-Code zu verwenden,
sondern sogenannten Assembler.
Das ist eine Sprache, wo man auch Buchstaben benutzt und Wörter
benutzt, an denen ein Mensch etwas erkennen kann.
Dann heißt Addieren nicht mehr B2, sondern Addieren heißt dann ADD für
Addieren.
Also etwas, was man viel besser lesen kann.
Außerdem konnten dann diese Assembler noch weitere Sachen drin haben,
wie Makros, wo man also immer wieder verwendete Prozeduren definieren
konnte.
Variablen kann man definieren, so dass man nicht immer Zahlen
schreiben muss.
Wurde dann also schon viel leichter.
Später dann kamen Programmiersprachen.
Da war dann die Idee, meine Güte, wir haben jetzt hier einen Rechner
von IBM, dort einen von Digital, da einen von was weiß ich was.
Und auf jedem gibt es irgendeine andere Art von Hex-Code oder
Assembler, mit dem man die programmiert.
Wäre es dann nicht schön, wenn wir eine Programmiersprache hätten, die
auf allen funktioniert.
Man bräuchte dann natürlich einen Übersetzer, der aus dieser hohen
Programmiersprache einen Assembler erzeugt.
Aber es würde das Leben der Informatiker sehr erleichtern.
Ja, und eine der ersten Sprachen war ALGOL für Algorithmic Language.
Also eine Sprache, in der man Algorithmen definieren kann.
Lisp ist auch eine ziemlich alte Sprache, Java kam erst viel später,
so in den 90ern oder Ende 80er erst zur Welt.
Ja, und heute gibt es schon deklarative Programmiersprachen, zum
Beispiel Prolog, wo also deklarativ gemeint ist, es wird nicht genau
angegeben, tu das, tu jenes, sondern das ist der Input, der Output
soll diese Spezifikation erfüllen.
Jetzt such mal, unter welchen Bedingungen wird diese Spezifikation
erfüllt.
Und dann ist die Hauptarbeit einer Prolog-Maschine eben suchen.
Und natürlich gibt es auch Spezifikationssprachen.
Allerdings sind die wenigsten so gestaltet, dass dabei direkt
Programme daraus entstehen.
Meistens entstehen daraus irgendwelche Skelette oder Makros, mit denen
man dann hinterher noch als Programmierer weiterarbeiten muss, die
nicht jetzt automatisch sofort ausgeführt werden können.
So ungefähr ist, also man sieht hier richtig diese geschichtliche
Entwicklung, entspricht ungefähr dieser hierarchischen Darstellung von
ganz unten von der Physik ausgehend bis zur beinahe schon
Umgangssprache.
Ja, wenn wir also den Computer etwas machen lassen, dann sieht das im
Wesentlichen so aus.
Wir haben irgendeinen Quelltext, zum Beispiel in Java.
Dieser wird typischerweise umgewandelt in einen Assembler-Quellcode,
und zwar mit Hilfe eines sogenannten Übersetzers oder Compiler auch.
Sehr selten hört man im Deutschen Compilator.
Der typische Begriff, also der meistverwendete, ist wohl Compiler,
aber auch Übersetzer ist im Deutschen üblich.
Dieser Assembler-Quellcode ist schon schwerer lesbar, aber immer noch
nicht direkt von der Maschine ausführbar.
Das Programm, das aus diesem Assembler-Quellcode dann Maschinen-Code
macht, das was also die Maschine tatsächlich lesen kann, diese Instanz
heißt Assembler.
Wir haben also hier zwei Instanzen, die etwas tun, ein Compiler und
ein Assembler.
Wenn es zum Beispiel um Java geht, dann ist dieser Assembler-Code, der
dazwischen entsteht, eigentlich selbst eine ziemlich hohe
Programmiersprache.
Der sogenannte Java-Byte-Code ist es da, der dabei entsteht.
Und das, was der Assembler liefert, ist typischerweise auch nicht
Maschinen -Code, der von der Maschine verstanden wird, sondern von der
Java -Virtual-Machine, also nicht vom Computer selbst, sondern von
einem Programm.
Aber das gucken wir uns später noch genauer an.
Ja, das ist ungefähr hier nochmal im Groben dargestellt.
Wir haben einen Quelltext, einen Compiler, das ist jetzt hier
zusammengefasst, Compiler und Assembler, alles in einem.
Was rauskommt, ist Maschinen-Code.
Dieser Maschinen-Code kann dann direkt auf der Maschine ausgeführt
werden.
Die andere Alternative, die es gibt, ist die, dass der Quelltext nicht
durch einen Compiler und Assembler geschickt wird, sondern durch einen
Interpretierer.
Der Unterschied hierbei ist, dass der Quelltext nicht umgewandelt wird
in irgendwas, was die Maschine versteht, sondern auf der Maschine
läuft ein Programm, das diesen Quelltext versteht und abarbeitet.
Der Vorteil von dieser rechten Version ist die, dass man, wenn man für
verschiedene Maschinen einen Interpretierer hat, dann kann man die
Quelltexte einfach so laufen lassen.
Ein anderer Vorteil ist, dass typischerweise interpretierte Sprachen
solche lustigen Eigenschaften haben, wie sie können ihre Programme
während sie laufen ändern.
Das ist bei den normalerweise übersetzten Programmen, die aus dem
Maschinen -Code übersetzt werden, nicht möglich.
Was hier außerdem noch dargestellt ist, ist diese Geschichte mit
mehreren Maschinen-Codes, die herauskommen, wenn wir mehrere
Quelltexte erzeugen würden.
Also es gibt dann auch mehrere Quelltexte, die alle übersetzt werden.
Rauskommen mehrere Maschinen-Code-Stückchen.
Das ist typisch, wenn Sie zum Beispiel in einem Projekt arbeiten, wo
mehrere Programmierer dran arbeiten und jeder arbeitet an seinem
Stückchen Quellcode.
Es wäre nun lästig, wenn man dauernd, wenn man ein neues Programm
erzeugen möchte, von allen Programmierern den Quellcode zusammensuchen
müsste und übersetzen müsste, um dann ein Programm herauszukriegen.
Einfacher ist es, wenn man solche fertigen, vorübersetzten Maschinen
-Code -Stückchen hat, von diesen Quellcodes der anderen Programmierer
und dann halt bei Bedarf, mit Hilfe eines sogenannten Binders oder
Linker, auch manchmal genannt, dieses Stückchen Maschinen-Code zu
einem gesamten Maschinen-Code zusammentut und den dann der Maschine
präsentiert.
Diese Sachen werden Sie sich sicher später noch genauer angucken oder
die Idee davon haben Sie sowieso schon und vielleicht auch aus Info 1
schon ein bisschen mitgekriegt.
Es soll uns auch nicht ganz sich so detailliert hier interessieren.
Ich will es nur aufzeichnen, damit Sie wissen, wo wir uns grob
befinden.
Ja, manchmal, wenn es darum geht, dass wir uns Maschinen-Sprache
angucken, höre ich den Vorwurf, Maschinen-Sprache, wer macht denn das
heutzutage noch?
Macht da kaum jemand.
Das ist ja so ähnlich wie in dieser Hierarchie-Ebene in der Zeit, das
ist ja uralt, das interessiert heute kaum noch jemand.
Na, ganz so ist es nicht.
Meiner Meinung nach ist das Verständnis von Maschinen-Sprache, was
passiert im Computer auf dieser Ebene, sehr wichtig, um zu verstehen,
wie funktioniert der Computer überhaupt.
Als Informatiker ist es eine sehr wichtige Sache.
Ich stelle immer wieder fest, dass Leute in Hochsprachen Dinge
programmieren und sich gar nicht bewusst sind, was dabei passiert im
Inneren und dann völlig unsinnigen Code machen.
Solche Sachen passieren immer wieder.
Mit dem Wissen, was auf der untersten Ebene im Computer passiert,
denkt man auch ganz anders auf der obersten Ebene.
Man produziert einfach sauberere Programme.
Wozu braucht man noch das Wissen über Maschinenprogrammierung?
Wenn Sie Übersetzer bauen wollen, wenn Sie einen Java-Interpretierer
bauen wollen oder irgendeinen C-Compiler oder so, dann müssen Sie
natürlich wissen, wie Maschinen-Sprache funktioniert.
Also für den Bau von solchen Systemen, das ist immer noch ein
aktuelles Thema, da ist es sehr wohl interessant zu wissen, was läuft
auf dem untersten Niveau ab.
Und dann ist es noch so, wenn Sie irgendwann mal fertig sind und
vielleicht irgendwo mal bei einer Bank oder sonst wo anfangen, die
Banken haben die ältesten Rechner, die sie sich vorstellen können,
noch aus den 50ern und 60ern, wo noch Cobol und Algol und so
draufläuft, und auch Maschinen-Sprache.
Manchmal sind solche trägen Firmen relativ vorsichtig beim Umstellen
auf neue Systeme.
Und es gibt tatsächlich immer noch einiges an Computern, die in
Maschinen -Sprache programmiert werden.
Und es gibt noch viele Programme, die gewartet werden müssen.
Es ist also immer noch nicht tot.
Dann ist es so, dass ständig neue Prozessoren rauskommen.
Jedes Jahr ein neuer Pentium oder alle 2-3 Jahre ein neuer Pentium.
Auch andere Hersteller produzieren ständig neue Prozessoren.
Wenn Sie irgendwann mal Prozessoren entwickeln wollen,
selbstverständlich werden Sie sich dann mit Maschinen-Sprache
auseinandersetzen müssen.
Und dann ist es noch so, dass die Informatik nicht nur in Desktop-PCs
stattfindet.
Informatik breitet sich aus in viele Kleinstgeräte.
In Waschmaschinen, in Videorekordern, in Fernsehern.
Da ist überall schon was drin.
Wenn Sie einen Digital-Satelliten-Receiver haben, da ist im Prinzip
ein PC drin.
Da ist fast ein kompletter PC drin.
Also viele kleine Geräte haben auch kleine CPUs.
Nur würde man da jetzt ungern große Festplatten reinmachen und ein
Windows -System und ein Java-Virtual-Machine und alles Mögliche
reinstecken, oft werden solche kleinen Systeme eben in Maschinen
-Sprache programmiert.
Also auch dafür ist es wichtig, zu wissen, wie das geht.
Und dann ist es noch so, manchmal ist es wirklich wichtig, super,
super schnell zu sein.
Oft ist es so, dass wenn Sie irgendein Programm in der Hochsprache
schreiben, stellen Sie fest hinterher, das läuft ja sehr langsam, wo
könnte man es verschnellern.
Es gibt Optimierer, die können da manches schon noch rausholen.
Aber es kommt trotzdem immer wieder mal vor, dass wenn man noch das
letzte Stückchen herausholen will, vielleicht nochmal einen Faktor
zwei, drei herausholen will aus der Geschwindigkeit, dass man dann
einen Teil der Software in Assembler, also in Maschinen-Sprache
schreibt und nicht in dieser Hochsprache.
Also Maschinen-Sprache ist überhaupt nicht tot, ist sehr wohl wichtig
und spielt sehr wohl eine große Rolle.
Und deswegen gucken wir uns das auch an.
Ohne jetzt großartig herzuleiten oder drauf einzugehen, wie ein von
Neumann Rechner funktioniert, ich wiederhole hier nur mal ganz kurz,
hatten Sie ja schon den Info 1, ich rufe es nur nochmal in Erinnerung.
Die erste Vorstellung von einem Rechner, so wie wir ihn heute kennen,
stammt von John von Neumann, schon ziemlich lange her.
Und die Idee hierbei war, es gibt einen Bus, einen Speicher, in dem
nicht nur die Daten drinstehen, sondern auch das Programm und an dem
Bus sind angeschlossen eine Recheneinheit, eine Ausgabeeinheit und
irgendein Leitwerk, das bestimmt, was jetzt zu tun ist.
Meistens werden diese beiden zusammen heute als CPU bezeichnet.
Und als Einausgabe zählt eigentlich alles, wie Tastaturen,
Bildschirme, Festplatten, das ist alles mehr oder weniger eine
Einausgabesache.
Und das Besondere an dieser Architektur ist die Vorstellung, dass
Daten und Programme im selben Speicher sind.
Das war gar nicht so selbstverständlich für die damalige Zeit.
Oder dass es einen zentralen Bus gibt, an dem alle Teile angeschlossen
sind.
Auch das war nicht so selbstverständlich.
Diese Vorstellung von Neumann-Rechner, die kann man sagen, die hat
sich durch bis heute noch bestehen geblieben und die Prozessoren von
heute orientieren sich zumindest immer noch an dieser Art von Rechner
-Architektur.
Ich habe jetzt die Folien ein kleines bisschen umsortiert.
Es fehlt nichts, es sind alle da.
Ich wollte nur mal sagen, nicht, dass Sie gleich stöhnen, es kommt
jetzt ein bisschen eine andere Reihenfolge.
Okay, also 1946 hat von Neumann sich vorgestellt, wie so ein Rechner
ist.
Und eigentlich ist so ein von Neumann-Rechner im Prinzip auch ein
Programm wie eine CPU.
Jede CPU kann man als Programm ansehen, auch der von Neumann-Rechner
kann man eigentlich als Programm ansehen oder als Algorithmus, der
nämlich so abläuft, wie es hier dargestellt ist.
Es gibt einen PC, einen Programmzähler, Programm-Counter, der wird
irgendwann am Anfang auf Null gesetzt und dann läuft der Rechner in
einer Schleife, solange bis irgendwas sagt, dass jetzt gestoppt werden
soll, wie sein Stopp-Kommando ausgeführt wird.
Und was in dieser Schleife getan wird, ist aus dem aktuellen Speicher,
wo der PC drauf zeigt, einen Maschinenbefehl B herausholen, diesen
Maschinenbefehl B ausführen und dann den Programmzähler weiterschalten
und das nächste Stückchen Programm ausführen.
Also einen Prozessor oder einen von Neumann-Rechner könnte man auch
als Programm hier ansehen.
Was wurde inzwischen aus diesem von Neumann-Rechner oder aus dieser
Idee?
Typischerweise ist es so, dass heutige Prozessoren mehrere Beats
gleichzeitig verwenden.
Typischerweise eine Zweierpotenz, das sind ja die Größen der Worte.
Dann ist es außerdem typisch, dass wir nicht nur einen Bus haben, auf
dem irgendwelche Daten transportiert werden, sondern wir haben
außerdem noch solche kleinen seitlichen Busse, die Steuerleitungen,
also die Steuerinformation transportieren.
Solche Informationen wie jetzt soll gelesen werden, jetzt soll
geschrieben werden.
Das sind typischerweise Sachen in einem von Neumann-CPU.
Dann ist es typisch so, dass der Speicher Nummern hat, die
Speicherzellen haben Nummern.
Vorne anfangen mit einer 0 und die Nummer eines Speichers nennen wir
Adresse.
Normalerweise gibt es immer so eine Art Programmzähler, manchmal sogar
mehrere, manchmal auch Befehlszähler genannt.
Und in diesem Befehlszähler steht die Nummer der Speicherzelle oder
die Adresse der Speicherzelle, wo der nächste Befehl drin steht.
Und das, was in einer Zelle steht, diese zwei hohen Bits, die nennen
wir üblicherweise Wort.
Es ist unterschiedlich lang, was ein Wort ist.
Bei Pentiums ist ein Wort etwas anderes als bei irgendwelchen
Mainframes.
Typischerweise gibt es aber eben Byte als 8-Bit-Wort, als 16-Bit und
dann gibt es noch Langwort, 32-Bit.
Das sind so die häufigsten Längen.
Allerdings ist es natürlich sehr wohl so, dass was ein Wort ist, von
dem Rechner abhängt.
So eine typische CPU, haben wir jetzt gesehen, hat einen
Befehlszähler.
Außerdem hat so eine CPU besonderen Speicher.
Nicht den Speicher, wie er jetzt vorgesehen war bei dem von Neumann
Rechner, der irgendwo das Programm auch drin steht, sondern ein
Extraspeicher, der Teil der CPU ist.
Diesen Speicher nennen wir Register.
Dieser Speicher hat den Vorteil, dass, weil er innerhalb der CPU ist,
nicht erst geholt werden muss oder geschrieben werden muss, sondern
schon in der CPU gleich direkt verarbeitet werden kann.
Geht also schneller.
Und es kann auch sein, dass diese Register also ziemlich groß sind.
Typischerweise ist der Speicher organisiert in Worten.
Solche Register können sehr wohl auch Langworte sein.
Dann gibt es außerdem meistens einen Stapelzeiger oder auch mehrere.
Das gucken wir uns später auch noch genauer an.
So ein Stapelzeiger ist dazu da, um Unterprogrammaufrufe mit zu
protokollieren, damit man hinterher, wenn das Unterprogramm fertig
ist, wieder weiß, wo es weitergeht.
Wird oft auch gern Stackpointer genannt.
Außerdem gibt es sogenannte Flags.
Das sind also typischerweise einzelne Bits, die in einem Extraregister
zusammengefasst sind, die solche Zustände anzeigen, wie zum Beispiel,
bei der letzten Division ist 0 herausgekommen oder bei der letzten
Addition ist ein Überlauf passiert.
Oder auch zum Beispiel, es liegt eine Unterbrechung an.
Jemand möchte, dass wir das Programm unterbrechen und etwas anderes
tun.
Das ist dann die nächste Eigenschaft von typischen CPUs.
Es gibt einen Unterbrechungsmechanismus.
Ein Programm kann laufen und irgendwann kann ein Signal kommen, das
sagt, halt, stopp, jetzt machen wir etwas anderes zwischendurch.
Und wenn das abgelaufen ist, das andere, dann geht es wieder zurück zu
der Adresse, zu dem Stückprogramm, das unterbrochen wurde.
So ungefähr sehen diese typischen CPUs aus.
Auf dieser Folie sehen wir, wie sich die Geschichte der CPUs grob
entwickelt hat.
Es ist jetzt nicht mehr ganz die neueste, also vor zehn Jahren
aufgehört.
Allerdings ist trotzdem noch die Tendenz, die hier zu sehen ist, immer
noch gültig.
Es gibt im Wesentlichen zwei große Zweige.
Diesen Intel-Zweig und den Motorola-Zweig.
Wobei der Intel-Zweig eben vor allem in den Pentiums mündet und der
Motorola -Zweig in den Power-PCs mündet.
Die Intels haben schon früh angefangen mit 4-Bit-Prozessoren, dann die
8 -Bit-Prozessoren.
8.0.0.80, ich gehe jetzt da nicht darauf ein, was die alle können.
Vielleicht erinnern sich manche von Ihnen noch an die 80.3.86.
Von hier, von 80.2.86 auf 80.3.86, da wurde ein großer Sprung gemacht.
Das war so ein richtiger Quantensprung, kann man fast sagen, in der
Prozessoreigenschaft.
Weil da wurde es zum ersten Mal richtig möglich, echte Mehr-Prozessor
-Betriebssysteme, Mehr-Prozess-Betriebssysteme drauflaufen zu lassen.
Inzwischen heißen diese Nachfolger immer noch Pentiums.
Das Weiterzählen mit 2.86.3, 4.86, das hat dann irgendwann aufgehört.
Die Pentiums heißen weiter Pentiums, Pentium 1, 2, 3, 4 oder so.
Aber es geht hier weiter auf dieser Schiene.
Die anderen, so wie AMD oder so, das sind halt eben Abzweige von
dieser Schiene.
Von diesem Semiconductor, also MOS mit 6502, dieser Zweig ist
eigentlich schon nicht mehr so wichtig.
Es gibt vielleicht noch ganz wenige Kleinstgeräte, in denen 6502s
verwendet werden, aber ist heute nicht mehr so wichtig.
Der andere, noch einigermaßen wichtige Abzweig ist der mit den Power
-PCs.
Diese sind entstanden aus dem 68.000er.
Der 68.000er, das ist auch der, mit dem Sie die Experimente machen
werden.
Warum haben wir den 68.000er gewählt?
Also gut, wir geben es zu.
Es war auch für uns am einfachsten.
Wir haben bisher schon immer den 68.000er benutzt, also brauchen wir
uns nicht neue Aufgaben ausdenken.
Aber nee, im Ernst, der 68.000er ist immer noch eine sehr geeignete
Maschine, um Maschinenprogrammierung kennenzulernen.
Einmal, er ist weit genug unten hier, also Ende der 70er, Anfang 80er,
um noch relativ einfach zu sein.
Die heutigen Pentiums sind sowas von kompliziert, dass man dann sagen
müsste, entweder wir gucken uns eh nur einen Teil der Funktionalität
an, oder wenn wir uns alles angucken würden, das ist sowas von
erschlagend kompliziert und hässlich.
Sodass wir also lieber etwas nehmen, was noch nicht so kompliziert
ist.
Und deswegen halt den 68.000er da hinten.
Außerdem ist es so, dass, wie wir gleich sehen werden, der 68.000er
sehr wohl noch viele Freunde hat.
Vielleicht noch eine Erwähnung wert ist die Reihe der ARM-Prozessoren,
die inzwischen auch Strong-ARMS und so weiter sind.
Das sind Hochleistungscomputer, könnte man sagen, in einem Chip.
Typischerweise haben die auch sehr viel Speicher gleich mit auf dem
Chip.
Und es gibt auch schon Betriebssysteme wie Linux, die auf dem Chip
laufen.
Und vielleicht haben Sie auch schon gesehen, von IBM gibt es eine
Armbanduhr.
Ja, ist vielleicht ein bisschen dick die Armbanduhr, aber es ist eine
Armbanduhr.
Auf dieser Armbanduhr läuft Linux drauf, sogar eine verkleinerte
Version von X-Windows.
Und das läuft auf einem ARM-Prozessor.
Also die ARMs, das sind die Hochleistungsprozessoren in Kleinformat.
Werden wir in Zukunft vermutlich öfter begegnen.
Okay, warum ist der 68.000er noch nicht tot?
Also in der Apple-Reihe, da wird heute zwar nicht mehr der 68.000er
verwendet, sondern der Power-PC.
Aber auch der stammt ja aus dem 68.000er.
Von daher, wenn man den programmieren will, ist auch Wissen über den
68.000er schon hilfreich.
Früher gab es noch diese Atari STs, TTs, weiß nicht, ob Sie sich da
noch erinnern, oder die Commodore Amigas.
Das war so eine richtige verfeindete Gemeinde hier.
Die haben sich auch richtig angegiftet, wie verfeindete
Fußballvereine.
Das waren damals die verbreitetsten Homecomputer, die gibt es heute
auch kaum noch.
Aber was es heute sehr wohl gibt, ist zum Beispiel ein Palm Pilots,
oder ich weiß nicht mehr Pilots, sondern irgendwie anders.
Palm 5, 6, 7 oder was.
Diese verwenden einen sogenannten Dragon Ball Prozessor.
Und das ist einfach nur eine neuere, kleinere, sparsamere Version des
68.000er.
Also dieser wird auch mit 68.000er-Code programmiert.
Man kann sagen, das ist der heute immer noch verbreitetste
Handflächencomputer.
Wenn Sie dafür Programmchen schreiben wollen, bietet es sich auch an,
in 68.000er das zu machen.
Dann ist es noch so, dass diese 68.000er in vielen Geräten vorkommen.
Fernsehgeräte, Satelliten-Receiver und vor allem auch in Autos.
Ich habe zwar jetzt nicht die Zahlen parat, aber letztes Jahr
zumindest war es noch so, dass es hieß, dass die beliebtesten
Prozessoren in der Autoindustrie die 68.000er sind.
Also vieles, was in der Autoelektronik gesteuert wird, wird mit Hilfe
des 68.000er gemacht.
Es ist also sehr wohl noch lebendig, diese 68.000er.
Es ist kein uraltes Teil, das kein Mensch mehr heute verwenden möchte.
Ich sehe gerade, wenn ich hier weiterblätter, verschwinden die
Annotationen.
Das ist ein Bug, sorry.
So, was hat so eine typische CPU jetzt nun so?
Was kann die normalerweise?
Die wenigsten CPUs können solche Sachen wie berechnen eine Primzahl
oder sowas.
Typischerweise hat eine CPU solche Sachen wie Sprungbefehle.
Also Befehle, die sagen, führe das nächste Kommando an einer
bestimmten Stelle im Speicher aus.
Da gibt es also unbedingte Sprungbefehle, die sagen, geh da hin.
An dieser Speicherstelle, da steht, was du als nächstes tun sollst.
Da gibt es bedingte Sprungbefehle, die dann nur dann ausgeführt
werden, wenn irgendwas erfüllt ist, wie zum Beispiel die letzte
Division hat eine Eins ergeben oder irgendwas derartiges.
Rechenoperationen haben CPUs, sonst könnte man eigentlich nicht so
viel damit machen.
Die unterscheiden wir normalerweise in arithmetische Operationen.
Die vier Grundrechenarten hat fast jede CPU.
Nicht unbedingt für Fließkommazahlen.
Also die arithmetischen Operationen sind meistens nur für Ganzzahlen.
Manchmal auch für Fließkommazahlen.
Bei den modernen CPUs, bei den Pentiums oder so, da ist es
selbstverständlich, dass auch für Fließkommazahlen, Multiplikationen,
Divisionen und so mit drin ist.
Manchmal sogar fehlerhaft.
Dann gibt es logische Operationen.
Typischerweise und, oder, nicht.
Viele haben auch noch anderes, wie XOR.
Aber sonst braucht man eigentlich kaum was.
Damit lässt sich ja alles andere zusammenbasteln.
Und relativ wichtige Operationen sind noch sogenannte Verschiebe
-Operationen.
Shifts oder Rotations.
Also ein Shift, das bedeutet, alle Bits einer Zahl nach links oder
nach rechts verschieben.
Rotieren würde bedeuten, das herausgeschobene Bit an einem anderen
Ende wieder reinschieben.
So ein Shift ist deswegen interessant, denn wenn wir uns überlegen,
was bedeutet es, wenn wir eine Zahl X um N Bits nach links shiften,
also die Zahl, sagen wir 0 0 1 0 1, das ist die Zahl 5.
Wenn wir die um 2 Bit nach rechts schieben, dann sieht die aus wie 1 0
1 0 0.
Das ist die Zahl 16 und 4, 20.
Das bedeutet also, 20 ist 5 mal 2 hoch 2.
Also 5 mal 2 hoch, wie viele Bits haben wir verschoben?
Wollen wir also eine Zahl multiplizieren mit 2, 4, 8, 16, heißt es,
wir können das machen, indem wir die Bits rüberschieben, nach links
schieben.
Das sind also sozusagen die Basis-Operationen für daraus aufgebauten
Multiplikationen.
Natürlich hat jede CPU auch noch solche Datentransportbefehle, wenn
nicht sogar die häufigst verwendeten sind, solche
Datentransportbefehle, wo im Wesentlichen es darum geht, Daten aus
irgendeinem Speicher in einen anderen Speicher zu tun oder auch in
einen Register zu tun oder aus einem Register in einen Speicher zu
tun.
Viele haben auch Befehle, mit denen man ganze Blöcke verschieben kann,
nicht nur einzelne Speicherzellen auslesen, sondern ganze Blöcke von
Speicherzellen auf einmal verschieben kann.
Ja, und dann gibt es natürlich noch ein paar andere Sachen.
Also jede CPU hat da noch irgendwelche Spezialitäten.
Man kann diese Flags, solche, wie sagen, Division durch Null ist
passiert oder Übertrag ist eingetreten.
Diese Flags kann man typischerweise auch setzen und löschen.
Dafür gibt es Befehle.
Man kann sie natürlich auch abfragen.
Das ist vielleicht eher das, was häufiger passiert.
Also in Abhängigkeit von diesen Flags dann bedingte Sprünge machen.
Und dann gibt es noch solche speziellen Sachen, wie soll man die
nennen?
Nennen wir es einmal Direktiven, die irgendwas tun, wie eine
Unterbrechung explizit auslösen.
Also nicht warten, dass ein Unterbrechungssignal kommt, sondern der
CPU sagen, tu so, als wäre jetzt eine Unterbrechung passiert.
Und vermutlich noch diverse andere Sachen.
Also das gibt es alles.
Wie sieht das ganz grob im 68.000er aus?
Nur so um einen Eindruck davon zu gewinnen.
Der Datentransportbefehl heißt MOVE.
MOVE, also da ist noch eine E dabei im Gegensatz zu der Intel-Sparte.
Und zwar typischerweise eben, von wo soll etwas bewegt werden, wohin
soll etwas bewegt werden.
MOVE von nach.
Auch da gibt es in anderen Prozessoren die andere Konvention, dass das
Ziel als erstes genannt wird und die Quelle als zweites.
Beim 68.000er ist es halt eben so.
Bewege Daten von nach irgendwo.
Dann gibt es arithmetische Operationen.
Addieren wird mit dem Befehl ADD gemacht.
Subtrahieren mit dem Befehl SUB.
Dividieren mit dem Befehl DIFF.
Da gibt es zwei Versionen, einmal mit DIFF U und DIFF S.
Das eine steht für UNSIGNED, das andere für SIGNED.
Das heißt, wir können Divisionen machen mit Vorzeichen und ohne
Vorzeichen.
Die Idee hierbei ist, dass man einmal diese Zahl, wie sie im Speicher
steht, die Bits, als natürliche Zahl ansieht, von 0 bis 2 hoch N.
Oder man kann sagen, wir betrachten die als Zahl im Zweierkomplement.
Hatten Sie ja schon in Info 1, nehme ich an.
Also als Zahl mit Vorzeichen.
Dann ist die Zahl anders zu interpretieren und wenn man damit rechnen
will, dann verwendet man halt den DIFF S Befehl für Divisionen mit
Vorzeichen.
Das gleiche gibt es auch beim Multiplizieren.
Da gibt es den Befehl MUL.
Auch wieder mit U und S.
Für die logischen Sachen, UNT, für das UNT gibt es den Befehl AND.
Für ODE den Befehl OR.
Für Exklusiv-ODE gibt es auch den Befehl EOR.
Und auch ein NOT gibt es auch zum Umkippen der Bits.
Schiebeoperationen oder Rotationen, da gibt es zum Beispiel Rotate
Left und Rotate Right.
Damit können die Bits hin und her rotiert werden innerhalb eines
Wortes oder Langwortes auch.
Sprünge sehen typischerweise so aus.
Da gibt es ein B für Branch.
Und dann hinterher eine Bedingung.
Also CC steht für Condition.
Also Branch on Condition.
Wobei CC typischerweise irgendwas anderes ist.
Da steht dann sowas drin wie NE.
Als Abkürzung für Not Equal.
Und das wäre dann zu interpretieren Branch if Not Equal.
Also für Zweigefalls ungleich.
Wenn also der vorgehende Vergleich ein Ungleich ergeben hat, dann
verzweigen wir, falls das ungleich war, zum Beispiel.
Also diese Befehle B, irgendwas, irgendwas, heißen dann Branch, falls
diese Bedingung erfüllt ist.
Gibt es auch noch als Variante mit einem D dazu.
Decrement and Branch.
Da kann man noch ein Register angeben, dessen Inhalt um 1 erniedrigt
wird.
Das ist dann für Schleifen zum Beispiel ganz nett.
Wenn Sie Schleifen programmieren wollen, da haben Sie auch Schleifen,
wo typischerweise irgendeine Variable runtergezählt wird.
Und am Ende der Schleife würde man dann normalerweise so ein Decrement
and Branch verwenden, wo in CC die normale Bedingung zum Aussteigen
aus der Schleife ist.
Und im Decrement dann halt eben ausgestiegen wird, wenn die Schleife
zu Ende abgestiegen ist.
Unbedingte Sprünge, also ohne irgendwelche Bedingungen, sind
typischerweise der Jump-Befehl.
Abgekürzt JMP.
Auch der BRA ist ein Branch-Befehl.
Das ist einfach nur eine Anlehnung an dieses B, wo halt eben RA dran
steht als Bedingung, wo aber keine Bedingung mit gemeint ist.
Das heißt einfach nur Branch.
Im Prinzip tun die das gleiche, Branch und Jump, nur dass Branch nicht
so weit jumpen kann wie ein Jump.
Dann gibt es Jump to Subroutines.
Das ist ein Sprung zu einer Unterroutine.
Das ist ein bisschen anders als ein Jump.
Wenn man einen normalen Jump aufruft, dann vergessen wir, wo wir
hergekommen sind.
Bei einem Jump to Subroutine merken wir uns, wo wir standen, bevor wir
in die Unterroutine gesprungen sind.
Und bei dem RTS, das ist dann der Return from Subroutine, wenn der
ausgeführt wird, dann gucken wir nach, wo wir uns gemerkt haben, wo
wir vor dem Jump to Subroutine waren und springen da zurück.
Ja, Sie werden das sicher noch in der Übung und auf den Übungsblättern
genauer kennenlernen.
An dieser Stelle ist es eher so gedacht, um Ihnen einen Eindruck zu
vermitteln, wie sieht denn so ein Befehlssatz von einer normalen CPU
aus.
Ja, was macht die noch?
Was haben wir noch so im Inneren von so einem Rechner?
Was läuft da noch ab?
Wir haben jetzt die Maschinenbefehle gesehen und typischerweise müssen
die Maschinenbefehle ja auch irgendwelche Operanten haben.
Und diese Operanten, da ist jetzt die Frage, wo kommen die her?
Da gibt es viele verschiedene Möglichkeiten, wo die herkommen können.
Wenn Sie sich das hier als Ausschnitt aus dem Speicher vorstellen,
also so etwas wie Speicherzelle 0, 1, 2, 3 und so weiter, dann kann es
sein, dass irgendwo in dem Speicher ein Befehl drinsteht, wie zum
Beispiel, lade ein Register mit einem bestimmten Wert und die Frage
ist, wo steht nun dieser Wert, also dieser Operant?
Da kann es sein, dass der Operant hier direkt hinter dem Befehl steht.
Also hier könnte dann so etwas drinstehen wie LDA für Laderegister A
und hier hinten, da steht dann sowas wie 7.
Dann würde das eben bedeuten, man würde eventuell noch hier hinten
dran schreiben, dass man weiß, irgendein Symbol, typischerweise für
einen Gatter als direkt, das uns sagt, die Daten, die jetzt dieser
Befehl braucht, dieser Operant, der folgt direkt hinten dran im
Speicher.
Deswegen heißt auch diese Adressierungsart oder Speicherzugriffsart
direkt.
Also ein Befehl im Speicher, sofort danach das Argument für den
Befehl, das nennen wir direkte Adressierung oder direkte
Speicherzugriffsart.
Die andere Möglichkeit, die es gibt, ist, dass hinter dem Befehl nicht
die Daten stehen, die er braucht, sondern dass da eine Adresse steht,
wo die Daten zu finden sind.
Diese Art der Adressierung nennen wir üblicherweise absolute
Adressierung.
Das heißt, hinter dem Befehl steht nicht das Datum selbst oder der
Operant, sondern die Adresse des Operanten.
Wenn die CPU also so etwas tun sollte, wie wenn dann hier stehen
würde, Lade-Akkumulator mit 7, ohne dass jetzt hier ein Hinweis dafür
da ist, dass das direkt hinterher kommt, dann würde halt hier irgendwo
in der Speicherzelle 7 der tatsächliche Operant stehen.
Die CPU holt sich dann also erst mal den Befehl LDA, dann stellt sich
fest, aha, der ist absolut adressiert, dann hole ich mal jetzt die
Adresse von dem Operanten.
Die Adresse steht direkt dahinter, da steht 7 drin, also nachgucken,
was steht in der Speicherzelle 7, da ist der Operant und dann weiß das
System, was in das Register A hinein soll.
Andere Möglichkeiten, die es auch noch gibt, ist noch indirekter zu
adressieren.
Das heißt, dem Befehl folgt nicht nur der Operant nicht, auch nicht
die Adresse des Operanten, sondern die Adresse der Adresse.
Also das ist eine doppelte Verzeigerung.
Das können Sie sich zum Beispiel vorstellen, dass das besonders
interessant ist, wenn Sie Felder adressieren wollen.
Also ein Feld hat ja irgendwo eine Anfangsadresse und in dem Feld zum
Beispiel stehen dann Zeiger drin auf irgendwelche Objekte, die
irgendwo im Speicher liegen.
Dann würden Sie auch hier eventuell erst mal in das Feld hineingehen
und dann aus dem Feld auf das Objekt zugreifen, das Sie eigentlich
verwenden wollen.
Also diese, eigentlich könnte man es fast doppelt indirekt nennen,
aber typischerweise nennt man diese Art der Adressierung einfach nur
indirekt.
Und noch eine vierte Art ist die sogenannte indizierte Adressierung.
Ist im Prinzip ähnlich wie die absolute, nur dass dann halt zusätzlich
noch ein Register angegeben wird, das dann noch da hinten drauf
addiert wird.
Das ist also wie absolut plus Register.
Also da steht drin, wo die Daten zu finden sind.
Außerdem müssen wir zu diesem Dings noch dazu addieren irgendwas, was
in einem Register drin steht.
Manchmal geht es auch sogar direkt mit, was man noch dazu tut, also
statt Register sowas wie eine Zahl.
Also da, wo diese absolute Adresse hinzeigt, plus 3, plus 4, da gibt
es verschiedene Varianten davon.
Also das ist nur so eine grobe Entsprechung.
Aber auch da werden Sie sich in der Übung und wenn Sie selber
programmieren ein paar dazu angucken.
Ja, das hier ist jetzt selbstverständlich, müssen Sie sich die ganzen
Null - und Einzelfolgen merken können für jeden Befehl.
Wow, das ist aber wenig Protest.
Natürlich nicht, ist ja klar.
Sie müssen auch nicht in der Klausur sich alle Syntax hier merken
können.
Wenn in der Klausur was kommt, wenn Sie sich dann die Syntax
vertippen, verschreiben oder so, das ist unwichtig.
Es reicht, wenn Sie wissen, was es an Kommandos gibt und was Sie tun
und so weiter.
Also ob Sie da jetzt einen Strichpunkt oder einen Komma setzen, das
ist egal.
Und das hier, wie so ein Befehl im Speicher aussieht, müssen Sie
natürlich auch nicht wissen.
Trotzdem möchte ich das hier mal zeigen, damit Sie sich eine
Vorstellung kriegen, was ist eigentlich so ein Maschinenbefehl.
Gucken wir uns einen der häufigsten Maschinenbefehle im 68.000er an,
nämlich ein Datentransportbefehl.
Haben wir ja schon gesagt, der heißt MOVE.
Dann gibt es eine Quelle und ein Ziel, das heißt bewege Daten von
Register D1 in Register D2.
Das bedeutet dieser Befehl.
Dann ist noch typisch 68.000er, aber auch in vielen anderen
Prozessoren zu finden, eine Beschreibung der Daten, die transportiert
werden sollen.
Zum Beispiel dieses Punkt W.
Da gibt es auch noch einen Punkt B und einen Punkt L als Alternative.
Wenn Punkt W da steht, heißt es transportiere ein Wort.
Dieser Befehl, der in Assembler so aussehen würde, MOVE.WD1,D2, der
sieht im Maschinencode so aus, wie hier unten dargestellt.
Wir haben also hier 16 Bit, die stehen irgendwo im Speicher.
Die vordersten Bits, wenn da 2 mal 0 steht, dann weiß der Rechner,
damit ist gemeint ein MOVE-Befehl.
Also alle Befehle, die mit 2 mal 0 anfangen, sind im 68.000er ein MOVE
-Befehl.
Dann weiß er, die nächsten beiden Bits bestimmen, ob es sich um ein
Wort, ein Byte oder ein Langwort handelt.
Wenn da 0,1 steht, dann ist damit ein Wort gemeint.
Wenn da 1,0 steht, ist ein Langwort gemeint.
Danach kommt eben erstmal eine Quelle.
Die ersten 6 Bit ist der erste Operand, die nächsten 6 Bit sind der
zweite Operand.
Und jeder von diesen Operanden ist nochmal unterteilt in
Informationen.
Da zum Beispiel 0,0,0 bedeutet, es handelt sich um ein Datenregister.
Und die 0,1,0 sagt dann an, das ist das Datenregister 2.
Also so ungefähr würde so ein Befehl im Speicher aussehen.
Der also tut, nimm ein Wort aus dem Datenregister 1, wobei Wort beim
68.000er 16 Bit bedeutet.
Und übertrage diese 16 Bit ins Register D2.
Vielleicht zum Vergleich hier unten ein anderer Befehl.
Auch wieder ein Datentransportbefehl.
Ein Move, diesmal ein Langwort.
Das sind jetzt 32 Bit.
32 Bit, die auf einmal bewegt werden sollen.
Auch hier wieder 0,0 bedeutet, es handelt sich um ein Movebefehl.
1,0 bedeutet, es ist ein Langwort.
Und dann zwei Operanden, jeweils 6 Bit.
Wobei hier wieder einmal der Index des Registers steht.
Also 0,1,1 heißt Index Nummer 3, also das dritte Register.
Hier steht jetzt nicht 0,0,0, sondern 0,1,0.
Das heißt, es handelt sich um ein Adressregister.
Also, mit anderen Worten, Bewegedaten aus dem Adressregister Nummer 3.
Allerdings handelt es sich nicht um irgendeine Art Adressregister,
sondern um eine absolute Indizierung.
Also in dem Adressregister steht eine Adresse drin und es wird nicht
der Inhalt des Adressregisters übertragen, sondern das, was in dem
Speicher steht, an der Adresse, die in A3 drin steht.
Also A3 ist ein Register, da drin steht eine Adresse, die zeigt
irgendwohin auf den Speicher und das, was dort drin steht, diese 32
Bit, die sollen übertragen werden.
Wohin sollen die übertragen werden?
Das ist der zweite Operand.
Und der zweite Operand, diese ganzen 6 Bit, so wie sie da stehen,
bedeuten, es folgt jetzt eine absolute Adresse, also hinter dem Befehl
im Speicher steht eine Adresse, wo die Daten hin kopiert werden
sollen.
Und zwar steht hier ein Wort, das heißt die 1916 Bit im Speicher, das
sind diese hier, die geben an, wo die Daten hin sollen.
Wenn wir die interpretieren als Adresse, dann kommen wir hier im
Hexadezimalsystem F1E0 raus.
Das heißt, dieser Befehl bedeutet, guck erstmal im Register A3 nach,
da steht eine Adresse drin, hole aus dieser Adresse, aus dem Speicher,
der diese Adresse trägt, 32 Bit heraus und übertrage diese 32 Bit in
den Speicher ab der Adresse F1E0.
So sieht zum Beispiel ein anderer MOV-Befehl aus.
Vielleicht noch zwei andere Befehlchen, die es auch noch gibt.
Ein Jump-Befehl zum Beispiel, das ist ein Jump-Befehl, der hat einen
Operanten, nämlich wohin soll gesprungen werden.
Hier ist es so, dass er jetzt nicht mit 0,0 anfängt, sonst wäre es ja
ein MOV.
Er fängt jetzt halt mit 0,1 an, es gibt aber auch noch andere, die mit
0,1 anfangen und um die von den anderen zu unterscheiden, gibt es hier
halt noch mehr Bits.
Also diese ganzen ersten Teil hier, ich weiß gar nicht, wie viele das
sind, die geben an, es handelt sich um ein Jump-Befehl und die letzten
sechs, also waren es zehn vorher, die letzten sechs Bits geben den
Operanten an, was für eine Art Operant das ist.
Wenn das so ist, wie es hier dasteht, heißt das, das wohin gesprungen
werden soll, das steht im Speicher
Warum absolut, würde ich nicht so nennen, vergessen wir mal.
Also es folgt jetzt hier im Speicher, es sollen ja hier keine Daten
transportiert werden.
Es ist ja nur die Frage, wo steht die Sprungadresse, die steht im
Speicher jetzt hinter dem Befehl.
Die nächsten L, Langwort, 32 Bit, und die heißen jetzt in dem Fall,
wenn man da jeweils 4 Bit zusammenfasst und einen Hexcode daraus
bildet, eben A0, B1, C2, D3.
Dieser Befehl, so wie er da steht, hieße dann Springe zu dieser
Adresse, die hinter dem Befehl im Speicher steht.
Das war jetzt also ein Befehl mit einem Operanten, der hat keine zwei
Operanten, sondern nur einen.
Es gibt auch Befehle ganz ohne Operanten, zum Beispiel eben dieser
Return from Subroutine Befehl, RTS.
Das sind alle Bits, die werden verwendet, um den Befehl RTS damit zu
spezifizieren.
Der hat zwar auch am Anfang 01, wie der Jump, aber danach geht es
anders weiter.
Insbesondere hier ist ein Unterschied.
Und daran erkennt es die Maschine, dass es sich um einen Return from
Subroutine Befehl handelt, der bedeutet eben, springe aus dem
Unterprogramm zurück.
So sehen diese Dinge aus.
Gucken wir uns noch etwas an.
Wir hatten festgestellt, dass die Daten an verschiedenen Orten im
Speicher stehen können.
Direkt hinter dem Befehl oder irgendwo anders oder auch in Registern
können die stehen.
Typischerweise ist es so, dass die nicht an jeder beliebigen Stelle
stehen dürfen.
Nicht nur beim 68000er ist es so, dass er eine bestimmte Anordnung der
Daten verlangt, sondern auch bei anderen CPUs.
Meistens ist es nämlich so, dass eine Speicheradresse, also so etwas
wie 117, 118, 119, also der Name einer Adresse spezifiziert ein Byte,
das ist der Normalfall, also 8 Bits.
Das hat sich halt so etabliert und ist bei fast allen CPUs, die heute
im Umlauf sind, immer noch so geblieben.
Wenn wir eine Adresse, eine Speicheradresse meinen, dann ist damit ein
Byte gemeint.
Das heißt, ein Wort aus der Sicht des 68000er wären das 16 Bit.
Wenn ein Wort 16 Bit lang ist, dann zieht es sich über zwei Bytes
hinweg, belegt also zwei Speicherzellen im Speicher.
Beim 68000er gibt es auch noch Langworte mit 32 Bit, die belegen also
vier Speicherzellen.
Und jetzt ist es so, dass normalerweise ein Wort nur an einer geraden
Stelle anfangen darf.
Also so wie ich es da vorne hingeschrieben habe, wäre das illegal,
also sagen wir 116, 117, 118.
Dann wäre es okay, ein Wort darf an der Stelle 116, 117 stehen.
Oder wenn man es eben bis ganz nach oben durchzieht, an der Stelle 0
und 1, da darf auch ein Wort stehen.
Also immer nur so, als wäre der Speicher in Worte eingeteilt.
Was illegal wäre, wäre ein Wort, das an einer ungeraden Adresse
anfängt, so wie es hier dargestellt ist, und den zweiten Teil an einer
geraden hat.
Ähnliche Anforderungen stellen wir auch an Langworte.
Hier ist allerdings beim 68000er nicht verlangt, dass das Langwort an
einer durch vier teilbaren Adresse anfängt.
Auch Langworte dürfen an durch zwei teilbaren Adressen anfangen, aber
nicht an ungeraden.
Das ist oft eine Fehlerquelle.
Manchmal stürzen Programme ab, weil man, ohne sich Gedanken zu machen,
versucht, ein Wort oder ein Langwort aus einer ungeraden Adresse
herauszulesen oder in eine ungerade reinzuschreiben.
Dann geht da eben manchmal was schief.
Dann haben wir noch andere Dinge.
Es ist oft so, dass der Speicher nicht, wie wir eben gesehen haben,
einfach nur irgendwie ein lineares System ist, von 0 bis N, und sonst
gibt es nichts mehr.
Sondern oft ist es so, dass wenn wir mehrere Prozesse laufen lassen
wollen, und heutzutage hat das fast jedes Betriebssystem, sogar
Windows kann das inzwischen, dass dann mehrere Prozesse parallel
ablaufen, dann wäre es doch entsetzlich, wenn Sie sich als
Programmierer vorher überlegen müssten, in welchem Stückchen Speicher
kann ich mein Programm laufen lassen.
Solche Sachen wie Springen an eine bestimmte Adresse können Sie doch
gar nicht verwenden.
Woher wissen Sie denn, wo Ihr Programm im Speicher stehen wird?
Oder wenn Sie Daten lesen wollen, die Sie irgendwo abspeichern wollen,
dann sagen Sie, okay, die Daten speichere ich in der Adresse 2345 ab.
Was aber, wenn die schon ein anderer Prozess benutzt?
Solche Sachen muss man natürlich vermeiden.
Da ist die typische Vorgehensweise bei einem Mehrprozesssystem die,
dass es außer dem einfachen Zugriff auf Speicher noch eine sogenannte
dazwischenliegende Memory Management Unit gibt.
Der 68.000er, wie wir ihn benutzen werden, hat das nicht.
Wir werden das auch nicht benutzen in unseren Übungen, trotzdem möchte
ich es hier mal kurz erklären.
Normalerweise haben wir hier also die CPU, das ist der CPU-Teil, so
wie wir ihn bisher kennen.
Zusätzlich hat jeder Prozess irgendwo im Speicher eine
Prozessumgebung, die beschreibt, wo im Speicher der Prozess liegt,
welche Flags bei diesem Prozess gesetzt sind, wo der Programmzähler
gerade sich befindet und so weiter.
Also eine Beschreibung des gerade laufenden Prozesses.
Wenn Prozesse wechseln, weil zum Beispiel eben beim Parallelbetrieb
jeder Prozess ein Stückchen Zeit kriegt und dann, wenn er die Zeit
abgearbeitet hat, ein anderer dran kommt, dann werden alle
Informationen, die den Prozess beschreiben, also seine Umgebung,
abgespeichert vom Betriebssystem.
Das Betriebssystem weiß sehr wohl, wo Platz ist, um das abzuspeichern.
Und dann wird die Umgebung eines anderen Prozesses geladen und der
andere Prozess kann laufen.
Damit sich die jetzt nicht in die Quere kommen und damit es für jeden
Prozessor aussieht, als hätte er den kompletten Rechner für sich
allein, werden jetzt diese Adressen oder die Zugriffe auf
Speicheradressen übersetzt innerhalb dieser Memory Management Unit.
Die Memory Management Unit stellt nun fest, dieser Prozess möchte
gerne auf Speicher Nummer 550 zugreifen oder sowas.
Von hier unten kommt die Information, es handelt sich um Prozess 7 und
dieser Prozess 7 fängt irgendwo in einem Speicherbereich ab 100 an.
Dann sagt sich die Memory Management Unit, aha, dann übersetze ich das
nach 150.
Also in der Umgebung von P7 steht zum Beispiel irgendwo, ab 100 legen
wir los, also wird das nach 50 übersetzt.
Der Prozess merkt davon gar nichts.
Für ihn sieht es so aus, als würde er auf Speicher Zelle 50 zugreifen.
In Wirklichkeit greift er auf Speicher Zelle 150 zu, kriegt von dort
seine Informationen zurück und glaubt, als hätte er den kompletten
Speicher für sich.
Genauso gilt es dann auch für diese anderen Prozesse in der anderen
Umgebung, wenn dann der andere kommt, hat er dann seine Daten sonst
irgendwo drin stehen.
Also das ist vor allem deswegen da, damit man Programme
positionsunabhängig schreiben kann.
Sie müssen sich also nicht Gedanken machen, wo im Speicher wird
hinterher mein Programm stehen und ablaufen, wo werden die Daten sein,
die ich benutzen werde.
Und eben die Vermeidung von Konflikten, dass mehrere Prozesse
gleichzeitig nebenläufig abgearbeitet werden können, ohne dass die
sich in die Quere kommen.
So kann man auf den Speicher zugreifen, verschiedene Zugriffsarten,
typischerweise haben moderne Prozessoren eben so eine Memory
Management Unit.
Hier ist so eine Zusammenstellung von, ich glaube, fast allen, wenn
nicht sogar tatsächlich allen Adressierungsarten des 68.000er.
Die werden Sie sicher wohl noch in der Übung öfter mal sehen, auch auf
dem Übungsblatt noch bearbeiten.
Ich habe die mal hier einfach so aufgelistet, wir können mal die
wichtigsten durchgehen.
Die oberste ist vielleicht die einfachste Adressierungsart.
Ich habe hier für alle jeweils nur den Move-Befehl verwendet.
Diese, so wie sie da steht, Move Operant 1, Operant 2, wobei der erste
Operant mit einem Gutter gekennzeichnet ist, bedeutet, die Daten, die
zu bewegen sind, sind genau diese.
Also das ist weder eine Adresse, noch ein Name eines Registers, noch
sonst irgendwie, das sind die Daten, deswegen direkt.
Also Move direkt 123 irgendwo hin, nach X, wobei X ein Register sein
könnte oder eine absolute Adressierung sein könnte oder sonst was.
Das heißt, im Speicher steht direkt nach dem Move-Befehl die Zahl 123.
Wobei das jetzt die Zahl 123 im Dezimalsystem ist, und zwar deswegen,
weil kein Dollar davor steht.
Hier unten zum Beispiel haben wir einen Dollar 123 an dieser Stelle.
Hier würde es eben bedeuten, diese Zahl 123 ist in Hexadezimal
-Schreibweise geschrieben.
Ich weiß, Hexadezimal ist kein korrektes Deutsch, aber hat sich halt
etabliert.
C -Dezimal wäre wahrscheinlich korrekter, aber nennen wir es mal
Hexadezimal.
Andere Adressierungsarten, zum Beispiel diese hier, das zweite, bewege
die Daten aus X, irgendeine Adressierungsart für den ersten Operanten,
wohin, wenn hier jetzt eine Zahl steht, ohne ein Gatter, hier kann
sowieso kein Gatter da hinten dran stehen, als zweiter Operant.
Also wenn hier eine Zahl steht, so wie sie da steht, Dollar 5000, dann
ist es eine Hexadezimal-Zahl, die gibt einen Ort im Speicher an.
In diesem Ort im Speicher, also an die Adresse 5000, soll
reingeschrieben werden ein Datum.
Also hier steht jetzt nicht dabei, ob Punkt L oder Punkt W, aber das
zu bewegende Datum soll an die Speicherstelle 50000 Hex geschrieben
werden.
Wenn das so da steht wie hier, dann ist damit gemeint, dass diese
Adresse hier hinten ein Langwort ist.
Das muss die CPU deswegen wissen, damit sie weiß, wie viele Bits
hinter dem Befehl sie sich aus dem Speicher holen muss, um diesen
zweiten Operanten zu kriegen.
Wenn wir im Assembler hier einen Punkt W schreiben, dann heißt das,
nimm nur die nächsten 16 Bit aus dem Speicher hinter dem Befehl und in
diesen nächsten 16 Bit steht die Adresse drin.
Die 16 Bit würden ja nicht reichen, um 50.000 zu adressieren, aber um
Dollar 500 zu adressieren, dafür reicht das.
Sehr häufig verwendet man die Adressierungsart Register.
Bewege Daten in ein Register hinein.
Da gibt es im 68.000er zwei verschiedene Daten- und Adressregister.
Die kann man im Prinzip willkürlich benutzen.
Nur ein bestimmtes Adressregister kann man nicht willkürlich benutzen,
das A7, das ist ein spezielles.
Aber alle anderen, man kann in Adressregister auch Daten rein
speichern, ist also kein Problem.
Dann gibt es zum Beispiel diese interessante Adressierung.
Adressregister indirekt mit Postinkrement.
Ein Befehl, der so aussieht.
Bewege X nach, in Klammern A0+.
Was der tut, ist also zunächst mal das bewegende Datum aus X
herausholen.
Dann gucken, was steht im Register A0 drin.
Da ist eine Adresse drin.
Dann gucken wir im Speicher nach, was in dieser Adresse drinsteht.
Also das ist eben diese Indirektion, deswegen Adressregister indirekt,
nicht Adressregister absolut, sondern Adressregister indirekt.
Das wird durch die Klammern drumherum angedeutet.
Also nicht im Adressregister steht die Adresse, die uns interessiert,
sondern im Adressregister steht die Adresse der Adresse, die uns
interessiert.
Und dieses Plus bedeutet, wenn wir übertragen haben, dass X an deren
Adresse in A0 steht, dann wird hinterher A0 erhöht.
Dann wird also der Inhalt von A0 erhöht.
Das ist sehr sinnvoll auch für Schleifen.
Wenn Sie also typischerweise so ein ganzes Feld kopieren würden von
einem Stück Speicher in einen anderen Stück Speicher, dann würden Sie
eben zum Beispiel ein Adressregister auf den einen Speicher setzen,
eins auf den anderen Speicher Anfang setzen und dann in einer Schleife
lauter Move A0 plus nach A1 plus zum Beispiel machen.
Das heißt, Bewege von A0 nach A1 und erhöhe jeweils A0 und A1 und beim
nächsten Mal wird dann das nächste Datum übertragen und dann kommen
halt hier noch die Schleifenkommandos drumherum.
Also so ein Befehl ist eben so ein Adressregister indirekt mit
Postinkrement wäre sinnvoll, um Daten zu verschieben.
Gibt es auch mit Minus, also das Minus zum Heruntersetzen, allerdings
gibt es das nicht mit Postinkrement, sondern nur mit Prädekrement.
Also es gibt nur ein Adressregister hinten dran mit Plus oder ein
Adressregister vorne dran mit Minus.
Das heißt, man kann nicht hinterher erniedrigen, sondern nur vorher
erniedrigen und nur hinterher erhöhen, nicht vorher.
Sie sehen schon, es ist nicht alle Kombinationen von
Adressierungsarten möglich.
Es ist auch nicht alles möglich, dass an beliebiger Stelle bei jedem
Befehl der erste und zweite Operant jede beliebige Adressierungsart
hat.
Manche sind an manchen Befehlen oder in manchen Kombinationen nicht
möglich.
Die wenigsten komplizierten werden wir sowieso verwenden, also
meistens sind sowieso nur diese einfachen Befehle.
Solche komplizierten Sachen, also das ist ja wohl das Komplizierteste,
was man sich vorstellen kann, die gibt es sehr selten und wenn, dann
sowieso nur bei Move-Befehlen.
Andere Befehle haben diese Adressierungsart gar nicht.
Vielleicht nochmal kurz, was macht diese Adressierungsart?
Das ist Adressregister Indirekt, das hatten wir schon gesehen, also A0
in Klammern.
Allerdings jetzt halt nicht mit einem Inkrement, sondern zusätzlich
gibt es noch ein Offset.
Das heißt, außerdem wird noch das Register D0, also der Inhalt des
Registers D0 zu A0 drauf addiert.
Dieses Punkt W heißt, nimm nur die letzten 16 Bit aus D0 zum drauf
addieren.
Und zusätzlich wird noch eine konstante $12 drauf addiert auf das, was
dann rauskommt.
Also derart komplizierte Sachen kann man machen.
Das können Sie sich vorstellen, dass das sinnvoll ist, wenn Sie
komplizierte Objekte, wo dieses 12 zeigt an irgendeiner Stelle
innerhalb eines Objektes.
Sie wissen, innerhalb eines Objektes ist immer ab der 12.
Stelle etwas Bestimmtes gespeichert.
Also könnte man sich, der Name von irgendeinem Tier steht immer an der
Adresse 12 innerhalb dieses Objektes.
Damit würde man also, wenn der Rest in Klammern den Anfang eines
Objekts im Speicher darstellt, mit $12 davor auf diesen Namen dieses
Objekts zugreifen können.
Das ist aber ziemlich kompliziert, das wird wohl kaum verwendet.
Ganz selten gibt es auch noch solche Sachen, dass man relativ zu dem,
wo man sich gerade befindet, relativ zum Programm-Counter, also auch
der Programm-Counter ist im Prinzip ein Register, dass man relativ
dazu auch einen Offset angibt und von dort aus Daten bewegt.
Findet man aber eher selten.
Ja, vielleicht noch ein kleines Programmchen, jetzt wo wir gesehen
haben, was es so alles im 68000 ergibt.
Ein oder zwei kleine Programmchen, damit wir mal sehen, wie so ein
bisschen was aussieht, was da passiert.
Erstmal eine relativ einfache Aufgabe.
Das Programm, was es tun soll, ist den Inhalt der Speicherzelle 1234
Hexadezimal und den Inhalt der Speicherzelle 3456, auch Hexadezimal,
miteinander multiplizieren.
Das heißt, wir haben hier irgendwo Speicher, fängt bei 0 irgendwo an,
geht runter, irgendwo haben wir 1234 Hexadezimal, da steht irgendwas
drin, ein X, dann geht es weiter, irgendwo haben wir dann 3456
Hexadezimal, da steht irgendein Y drin und so weiter.
Und irgendwo haben wir dann die Speicherzelle 5678, da soll Z rein,
also hinterher soll sein Z gleich X mal Y.
Das soll das Programm tun.
Und zwar haben wir gesagt, ein Byte soll gelesen werden, also mit
1234, damit ist ein Byte spezifiziert.
Wir meinen also nicht die zwei Bytes, das Wort ab dieser Adresse,
sondern wir meinen das Byte in dieser einen Adresse.
Okay, das Programm dazu sieht so aus.
Hier ist der Multiplikationsbefehl, hier wird Register D0 mit Register
D1 multipliziert.
Bevor wir das tun können, müssen wir natürlich in die Register die zu
multiplizierenden Daten reinladen.
Also erstmal in Register 0 den Inhalt der Adresse 1234 reinladen, das
ist also absolute Adressierung hier.
Also in 1234, also direkt nach dem Befehl steht die Adresse, wo die
Daten stehen.
In Assembler sieht es so aus, hier die Zahl ohne ein Gatter davor.
Hole also aus 1234 Daten und kopiere sie nach D0.
Wie viele?
Wir brauchen ein Byte, deswegen ein B.
Das muss nach D0.
Jetzt wissen wir vielleicht, aber vielleicht noch nicht, wir können
uns vorstellen, dass diese Register natürlich mehr als ein Byte
aufnehmen können.
Beim 68000er sind es 32 Bit, also 4 Byte passen in so ein Register.
Würden wir also nur diese 8 Byte hier reinladen, so wie es da steht,
was passiert dann mit den anderen 24 Bits?
Die bleiben in der Regel unverändert.
Deswegen haben wir hier ein anderes Kommando vorgeschaltet.
Lade direkt 0, und zwar als Langwort, in Register D0.
Das heißt, das Register D0 wird zunächst mal komplett auf 0 gesetzt.
Jetzt können wir die 8 Bit draufladen und die vorderen 24 Bit bleiben
unverändert.
Das, was jetzt in D0 steht, ist okay.
Genau das Gleiche machen wir bei D1.
Machen Sie erst mal D1 auf leer, alle Bits auf 0 setzen, dann das Byte
aus 3, 4, 5, 6 holen.
Jetzt die Multiplikation, die ist jetzt hier ohne Vorzeichen
anzeigend.
Und hinterher schreiben wir das Ergebnis.
Wenn wir zwei Bytes multipliziert haben, dann ist das Ergebnis unter
Umständen eben 16 Bit lang.
Das heißt, wir schreiben das komplette Wort in die Adresse 5678.
Das ist hier eben als Wort angegeben.
So sieht also ein Programm aus, das zwei Zahlen multipliziert.
Jetzt gucken wir uns ein Programm an, das sieht eigentlich sogar
kürzer aus und macht noch etwas viel Schlimmeres, nämlich es berechnet
die Fakultät.
Das ist auch ein zweites Beispiel.
Wie berechnet man in 68.000er N-Fakultät?
Gut, die Spezifikation ist jetzt ein bisschen einfacher.
Wir haben jetzt das Datum schon im Register gegeben.
Also in Register D6 soll eine Zahl N drinstehen, von der wir die
Fakultät berechnen wollen.
Und wenn das Programm fertig ist, soll im Register D0 N-Fakultät
drinstehen.
Okay, zum Fakultät berechnen.
Wir machen es jetzt mit einer Schleife, nicht mit einer Tabelle
nachguckend.
Das hätten wir ja machen können, aber wir machen jetzt diese Schleife.
Hier ist diese Schleife, also erst ist hier erstmal die
Initialisierungsphase und dann haben wir hier eine Schleife.
Okay, der erste Schritt ist, wir initialisieren unser Produkt, in D0
soll das Produkt drinstehen, mit 1.
Wenn wir eine Fakultät berechnen wollen, heißt das, D0 anfangen mit 1.
Ich mache mal hier eine quasi Java-ähnliche Schreibweise, D0 gleich 1.
Als nächster Schritt brauchen wir jetzt eine Laufvariable, die nennen
wir D1, die Schleifenvariable.
Die wird initialisiert mit dem Wert N.
Also dieser Befehl, Move-Wert D6 nach D1, heißt D1 ist D6.
Das ist so die Java-Entsprechung dazu.
So, jetzt können wir Schleifen drehen.
In der Schleife wird multipliziert.
Multipliziere D1 zu D0 drauf, das heißt, in Java wird das heißen D0
mal gleich D1, also D0 gleich D0 mal D1.
D0 haben wir mit 1 initialisiert, das heißt in der Schleife wird immer
auf dieses gemerkte Produkt D0 D1 drauf multipliziert.
So, jetzt müssen wir, um die Fakultät zu berechnen, wie weit runter
gehen.
Theoretisch bis zu 1, aber zum Schluss nochmal 1 multiplizieren, was
soll das?
Also reicht es, wenn wir bis 2 runter gehen.
Deswegen vergleichen wir hier, sind wir schon bei 2 angekommen?
Das heißt, haben wir schon mit 2 drauf multipliziert?
Also das hier heißt, if D2 gleich 2, wobei hier Hexadezimal 2 oder
Dezimal 2 keinen Unterschied macht.
Falls das so ist, dann haben wir hier eine Schleife, zunächst mal den
BMI -Anteil, der heißt Branch If Minus, also Verzweige, falls bei dem
Vergleich unterschritten wurde.
Minus, das würde bedeuten, wenn also dieses 2 kleiner ist als das D1.
Also solange 2 kleiner ist als das D1, verzweigen wir.
Und zwar an die Stelle Loop.
Also am Ende.
Das haben wir ja schon.
Dann Go to Loop, meinetwegen.
Und dazwischen hier, dieser Teil, dieser Decrement, D1-Teil, der
entspricht einem D1 Minus Minus.
Warum hat niemand gemeckert, als ich hier D2 geschrieben habe?
D1 natürlich.
Offensichtlich ist heute irgendein Bug hier in diesem Tablett.
Wenn nicht Blätter verschwinden, die Sachen wieder, können wir also
schnell wieder sauber machen.
Sorry, ich weiß auch nicht, was los ist.
Auf jeden Fall, was Sie hier eben sehen ist, wir haben einmal
Initialisierung, Produkt wird mit 1 initialisiert, die
Schleifenvariable wird mit N initialisiert, multipliziere das aktuelle
N immer auf dieses Produkt drauf, vergleiche mit 2, wenn die 2
unterschritten wurde, oder solange die 2 noch kleiner ist als D1,
verzweigen wir zu Loop und dekrementieren D1.
So sieht also eine Fakultätsberechnung im 68.000er aus.
Ziemlich klein, gar nicht mal so übel.
So, ja, jetzt haben wir uns angeguckt, was es für Prozessoren gibt,
was die für Eigenschaften haben, wie das beim 68.000er aussieht.
In der Übung werden Sie dazu noch einiges mehr machen.
Die Vorlesung ist noch nicht ganz beendet.
Ich wollte die letzten 10 Minuten noch nutzen für eine
Vorlesungsbefragung, die wir immer machen, wo Sie uns dann Tipps geben
können, was wir besser machen können.
Wahrscheinlich wurde die auch letztes Mal gemacht, also vermutlich ist
das nichts Neues für Sie.
Ich habe das jetzt gemacht, weil Sie sowieso nachher in der Übung sind
und deswegen jetzt nicht abhauen.
Also wäre nett, wenn Sie da mal so ein bisschen Ihre Kommentare
abgeben.
Die Ergebnisse werden dann auf der Infoseite veröffentlicht.
Wenn Sie fertig sind, werfen Sie sie einfach vorne in die Kiste da.
Ansonsten vielen Dank für die Aufmerksamkeit und bis Montag dann.