... langsam aber sichere Plätze einzunehmen.
Ich darf Sie zunächst recht herzlich begrüßen zur zwölften Übung.
Sie merken, wir kommen also dem Ende des Semesters immer näher und
damit auch dem Termin der Klausur.
Und ich möchte hierzu einfach noch ein paar Hinweise geben, bzw.
ich hoffe, Ihnen auch etwas die Angst nehmen zu können.
Weil in der einen oder anderen E-Mail bereits hier die Nervosität
sichtbar geworden ist.
Zum anderen bedanke ich mich hier auch persönlich bei Ihnen für diesen
regen Rücklauf.
Also wir nehmen diese Umfragen sehr ernst.
Das wird auch Ende des Semesters bzw.
dann im Folgesemester immer publiziert.
Die Auswertung entsprechend der Veranstaltungen von Grundvorlesungen
bzw.
auch der Vertiefungsfachvorlesungen.
Und wir versuchen hier auch Ihre Anmerkungen, ich hoffe, das haben Sie
mitgekriegt während des Semesters, immer aufzugreifen, um hier
entsprechend dann eine Qualitätsverbesserung herbeizuführen.
Bitte sehen Sie es uns nach, wenn wir nicht jeder Anforderung gerecht
werden können.
Wir müssen hier so einen Kompromiss finden und bei 700 Leuten können
Sie sich, also gut 700 insgesamt, aber hier selbst sind noch ein paar
hundert drinnen, können Sie sich vorstellen, dass hier durchaus nicht
konvergierende Anforderungen gestellt werden.
Also vielen Dank hier nochmal für die Umfragen.
Ich habe gesehen, ein Kritikpunkt hier an der Übung ist, dass man
vielleicht zu wenig Möglichkeit hat, Fragen zu stellen bzw.
Fragen und Antworten sogar zu diskutieren.
Sie können sich vorstellen, also das eine oder andere Mal kam ein
Zwischenruf, ich habe versucht, das aufzugreifen, aber selbst in der
großen Übung ist es schwer, dass man hier also mehr Zeit aufwendet,
ohne dass man dann nicht zu stark in Verzug kommt mit dem Stoff.
Und ich hoffe doch, dass ich hier mit der einen oder anderen
Übungsaufgabe Ihnen noch ein paar Tipps geben konnte, was sehr gut
funktioniert und ich hoffe auch, Sie merken, dass wir hier
entsprechend auch dran sind, das möglichst schnell zu beantworten.
Das sind zum Beispiel Fragen in Newsgroups.
Oder kommen Sie einfach zu uns in die Sprechstunde, dann können wir
vielleicht nochmal detailliertere Fragen stellen.
Oder nutzen Sie vor allem auch die Tutorien in den kleineren Kreisen.
So, zuerst einmal möchte ich mich auch nochmal entschuldigen für den
Ausfall unseres Webservers.
Ich denke, Herr Rogina hat hierzu ein paar Worte auch verloren.
Wir sind hier etwas ohnmächtig, sage ich mal, Ende letzter Woche vor
dem Problem gestanden, dass hier einige Verbindungen einfach gesperrt
wurden.
Und Herr Rogina, bei dem also der Server läuft, alles dran gesetzt
hat, dass er den wieder zum Laufen gebracht hat.
Ich glaube, selbst heute früh, ich weiß nicht, ob er im Moment sogar
läuft, aber heute früh gab es noch massive Netzprobleme irgendwo im
Institutsnetz von Weibel.
Und wir sind also dran, dass wir das so schnell wie möglich hier
zusammen mit der Artis wiederherstellen.
Also soll es hier größere Probleme geben, dann einfach nochmal E-Mail
an mich oder an Herrn Rogina.
Wir versuchen alles Mögliche, dass Sie hier rechtzeitig zu Ihren
Übungsblättern kommen oder auch wichtige Informationen zur Klausur
erhalten.
Es gab einige Anfragen.
Es waren auch ein paar Leute bei mir in der Sprechstunde.
Zu einzelnen Themen der Vorlesung und wie auch der Übung.
Und ein brisantes Thema war unter anderem die Definition von
Determinismus, Nicht-Determinismus, Indeterminismus.
Mein Hinweis hierzu ist ganz einfach, konsultieren Sie die News Group.
Herr Rogina hat hier zum einen eine sehr ausführliche Unterscheidung
dieser Begriffe reingestellt und zum anderen auch eine sehr
ausführliche News zu den Themen und der Relevanz der Themen für die
Klausur.
Also wenn jemand die Frage stellt, was kann dran kommen oder was kommt
dran, was ist Stoff der Klausur?
Fakt ist, der Stoff umfasst die Vorlesungsthemen sowie die
Übungsthemen, wobei Sie sich auch aufgrund der Randbedingungen der
Klausur an fünf Fingern abziehen können, was wirklich klausurrelevante
Fragestellungen sind.
Bedenken Sie dabei den Zeitfaktor.
Auch wir können zum Beispiel nicht so eine Aufgabe wie auf dem
Übungsblatt 8 stellen, wo Sie eine halbe Stunde brauchen, um die
Aufgabe zu verstehen.
Das liegt Ihnen vielleicht noch schwer im Magen.
Beziehungsweise denken Sie auch an die Korrektur.
Also wir müssen schauen, dass wir hier entsprechend auch die Größe der
Teilnehmerzahl effizient korrigieren können.
Und Sie finden hierzu einige Hinweise eben in der News von Herrn
Rugginer in der News Group.
Zum Übungsbetrieb vorweg noch, es wird jetzt noch nach der heutigen
Veranstaltung eine 13.
und wahrscheinlich eine 14.
Übung geben.
Wir werden hier diese Woche noch das zwölfte Übungsblatt bearbeiten.
Das ist also das letzte Übungsblatt, das auch von unseren Tutoren
korrigiert werden wird.
Ich werde aber dennoch auch aufgrund des Stoffes, der also für die
Klausur relevant ist, ein 13.
Übungsblatt stellen oder zur Verfügung stellen und auch eine
Musterlösung dazu ins Netz stellen.
Das 13.
Übungsblatt wird aber in dem Sinne nicht mehr korrigiert und ist nicht
mehr Teil des Bonussystems.
Der Grund ist dafür, wir können nicht so schnell korrigieren, dass Sie
hier entsprechend dann auch noch irgendwie einen Benefit daraus
ziehen.
Das wäre in der letzten Woche dann irgendwann nochmal zur Abgabe
fällig und da schaffen wir es dann nicht mehr, das vor der Klausur
entsprechend zurückzugeben.
Sie können aber, denke ich, aufgrund der Musterlösung selbst auch
nochmal eine Abschätzung treffen, inwieweit Sie hier im Bereich
Assembler, Assemblerprogrammierung, entsprechend den Stand erreicht
haben, um hier eventuelle Klausuraufgaben beantworten zu können.
So, also ich habe hier vorweg bereits schon angedeutet, 12.
Übungsblatt und 13.
Übungsblatt.
Einige von Ihnen hatten Probleme, was Java angeht.
Also ich kann Ihnen jetzt vergewissern, dass wir auf dem 12.
und 13.
Übungsblatt kein Java mehr machen.
Dafür steigen wir eine Ebene tiefer in Richtung Hardware und
programmieren in Assembler.
Da ist die Frage, ob das jetzt ein Vorteil ist, ob das einfacher ist
oder schwerer, das ist vielleicht Ansichtssache.
Aus Sicht der Maschine ist es sicherlich einfacher, aus Sicht des
Entwicklers ist es in der Regel, sage ich mal, schwieriger.
Wir werden also maschinennah programmieren und das bedeutet, Dinge,
die uns eine höhere Programmiersprache heute abnimmt, müssen wir als
Entwickler entsprechend selbst beachten.
Dazu werden wir sicherlich einiges kennenlernen.
Auf dem 12.
Übungsblatt gibt es noch eine Aufgabe zur parallelen Programmierung,
das betrifft also Algorithmen, systemische Automaten und ich denke
aber, da haben Sie in der Vorlesung genug Hinweise bekommen, dass Sie
ohne weiteres diese Übungsaufgabe rechnen können sollten, sodass wir
uns heute entsprechend auf dem Weg von dem Bediener, also von dem
Nutzer eines Rechners rein in die Maschine begeben können.
Und ich werde das anhand eines Beispielsystems durchführen, also einen
bestimmten Prozessor herausgreifen.
Das ist hier von Motorola der 68.000er.
Das mache ich deshalb an diesem Beispiel fest, weil es hierzu einen
sehr schönen Simulator gibt, anhand dessen wir oder mithilfe dessen
wir entsprechend auch die einzelnen Programmaufgaben, Übungsaufgaben
am Rechner dann praktisch durchführen können.
Die Themen, die wir heute besprechen werden, sind zum einen hier mal
grundsätzlich diese Hardware-Software-Schnittstelle.
Also der Rechner der 68.000er ist eine Hardware, Java in dem Sinne war
eine Software.
Und die Frage ist, was passiert jetzt, wenn wir die Ebene einer hohen
Programmiersprache in Richtung Maschine verlassen?
Wie sieht hier die Schnittstelle aus?
Wie sieht die Betrachtungsweise aus?
Wie sehen wir die Maschine, die Hardware, aus Sicht des Entwicklers?
Wie sieht dann entsprechend die Befehlscodierung aus?
Also es gibt hier auch wiederum eine Programmiersprache, mit der ich
auf einem sehr niedrigen Abstraktionsniveau diese Maschine
programmieren kann und damit steuern kann.
Und dann ist die Frage, wie ist diese Maschine intern organisiert?
Wie sieht der Speicher aus?
Wie sieht das Layout des Speichers aus?
Was steckt da wo drinnen?
Das brauche ich, dieses Wissen, um dann auch entsprechend von außen
direkt auf die richtigen Inhalte zugreifen zu können.
Und wie ist der Adressraum entsprechend aufgeteilt?
Ich möchte Ihnen dann am Schluss nochmal wieder Tipps geben bezüglich
der praktischen Arbeiten auf den Übungsblättern und hier insbesondere
Installationshinweise für diesen 68.000er Simulator geben.
Wir haben hierzu unterhalb des Übungsblattes auf unserer Info2
-Webseite einen Link vorgesehen, der Sie auf eine Beschreibung dieses
Simulators weiterführt.
Und da finden Sie die Sourcen, die Sie benötigen, um hier die
praktischen Programmieraufgaben zu bearbeiten.
Sie können hier also das beispielsweise auf einem PC installieren,
auch zu Hause, wenn Sie das wollen, beziehungsweise, ich habe jetzt
auch den Hinweis noch bekommen, den Link auf die Originalseite
einzubauen, wo Sie dann den Link auch für die entsprechenden Sourcen
für die Unix-Umgebung finden.
Also ich habe den Link aus dem Unix-Computer auch noch draufgepackt.
Und damit haben wir jetzt ein paar Übungen, sodass Sie ein paar
praktische Übungen mit diesem Simulator durchführen können.
Das Übungsblatt 12 als Hinweis enthält auch dieses Mal eine praktische
Aufgabe, die, ich sage mal, einfache Befehle für Assembler
-Programmierung beschreibt.
Sie sind, ich glaube, heute erst oder Sie kommen diese Woche
eigentlich erst in den Genuss, nächste Woche, korrekt, der richtigen
Assembler -Programmierung.
Sie werden also die ganzen Befehle in ihrer Schönheit erst nächste
Woche kennenlernen, sodass wir auch erst nächsten Mittwoch dann ein
paar Beispiele der Assembler-Programmierung konkretisieren werden.
Das Übungsblatt 12 enthält aber eine praktische Aufgabe, die Sie auf
Papier lösen können.
Sie werden jetzt ein kleines Assembler-Programm schreiben und ich bin
der Meinung, dass Sie das also anhand der Aufgabenstellung sehr
einfach lösen können sollten.
So, dann starten wir mal durch.
Und die Frage ist an dieser Stelle, wir kennen höhere
Programmiersprachen, wir haben eine davon kennen gelernt und die Frage
ist, Sie wissen also, wenn ich ein Java-Programm schreibe, dann muss
dieses Java-Programm zunächst einmal kompiliert werden und aus einer
Sprache, die also der Entwickler versteht, in eine Sprache übersetzt
werden, die die Maschine versteht.
Und die Assembler-Programmierung ist nun eine Sprache, die, ich sag
mal konzeptionell, unterhalb dieser hochwertigen oder höheren
Programmiersprache Java angesiedelt ist und entsprechend
maschinenverständlicher ist, dennoch aber noch einmal dann, ich sag
mal, assembliert werden muss, wir werden das nachher kennenlernen, was
dieser Vorgang bedeutet, bevor sie dann endgültig abgearbeitet werden
kann.
Die Frage ist nun, wie sieht die Schnittstelle aus, wenn ich hier aus
dieser Software-Sicht meine Hardware betrachte.
Also Sie können sich vorstellen, Sie stehen jetzt aus Sicht der
Software direkt vor der Hardware, vor dem Prozessor, und die Frage ist
nun, wie bediene ich diesen Prozessor oder wie spreche ich dessen
Funktionen an.
Und das Prinzip, das hier angewendet wird, ist ähnlich dem der
Objektorientierung.
Sie betrachten hier einen derartigen Mikroprozessor als Objekt.
Und wie Sie bereits wissen, beschreibe ich ein Objekt von außen.
Also wenn ich eine Sichtweise von außen auf den Prozessor einnehme und
die Objektsichtweise sehe, dann kann ich dieses Objekt beschreiben mit
Methoden, Funktionen, Funktionalität und Daten.
Also die Frage ist, welche Funktionen bietet mir der Prozessor an, und
auf der anderen Seite als zweite Information, welche Daten kann ich
mithilfe dieser Funktionen verarbeiten.
Und das ist genau die Sichtweise, die ich auch entsprechend hier
einnehme, wenn ich einen Prozessor betrachte.
Ich habe auf der einen Seite Daten, diese Daten können abgelegt werden
in sogenannte Register.
Wir werden später kennenlernen, welche Register es gibt und wie diese
aufgebaut sind.
Und zum anderen habe ich zum Verarbeiten der Daten Methoden zur
Verfügung.
Methoden, also im Sinne des Objektes, die hier auf der Hardware-Ebene
entsprechend Befehle oder Operationen genannt werden.
Diese Operationen greifen dann entsprechend hier auf die Daten in den
Registern zu und verarbeiten diese.
Das sind aber Operationen, die bei Weitem einfacher gestaltet sind als
beispielsweise eine Java-Methode oder gar ein Java-Programm.
Also Sie können hier diese Stichwort Objektorientierung sich zu Hilfe
nehmen als Brücke.
Das ist also die Sichtweise eines Prozessors oder auf einem Prozessor
von außen.
Und das weitere Konzept, das die Objektorientierung mit sich führt,
kommt hier auch wieder zum Tragen.
Uns interessiert als hardware-naher Entwickler wiederum nur, wie ich
die Funktionen in Anspruch nehmen kann und nicht, wie der Prozessor im
Detail realisiert ist.
Das lernen Sie in technischer Informatik, ich glaube im dritten und
vierten Semester.
Da schauen Sie dann in diese Innereien hinein und stellen dann fest,
wie diese Funktionalität mithilfe von Transistoren gelötet und
dergleichen ist oder aufgedampft ist.
Also das werden wir hier nicht in Informatik 2 durchnehmen.
Implementierung der
Funktionen bleibt verborgen.
Zunächst stellt sich die Frage, wie kann ich Daten hier in meinem
Prozessor verarbeiten bzw.
speichern oder wie werden diese Daten hier im Prozessor gehalten?
Und dazu gibt es die sogenannten Register.
Das sind also genau die Speicherplätze, in denen ich meine
Informationen ablegen kann.
Und auf diesen Registern kann ich dann entsprechende Operationen
anwenden und diese beispielsweise bitweise nach links, nach rechts
verschieben und damit die Informationen in den Registern manipulieren.
Wir haben hier entsprechend einen Beispielprozessor ausgesucht.
Das ist also der 68.000er von Motorola, nur als Information.
Und zu diesem Prozessor gibt es, wie erwähnt, einen Simulator, der
sich dann nennt BSVC.
Ich habe lange gesucht, was diese Abkürzung genau bedeutet.
Ich muss ehrlich zugeben, ich habe sie nicht gefunden.
Wichtig für Sie ist, das ist ein Simulator-Framework, das auf einem PC
die Funktionalität und die Eigenschaften von diesem 68.000er von
Motorola simuliert.
Es ist also eine virtuelle Maschine, mit deren Hilfe Sie hier
entsprechend Ihre Übungsaufgaben durchführen können.
Zu den Registern ist zu sagen, dass es hier zwei große Klassen gibt.
Zum einen die internen Register, die also in dem Prozessor stecken und
ich im Prinzip keinen unmittelbaren Zugriff von außen drauf habe, da
diese Register der Prozessor selbst verwendet, zum Beispiel zum
Dekodieren von Befehlen.
Also ein Befehl ist für einen Prozessor auch wiederum eine Art Datum.
Dieses Datum liegt in speziellen Registern, in Befehlsregistern und
muss von dem Prozessor ausgelesen werden, aus diesem Register und
entsprechend dekodiert und verarbeitet werden können, bis es zur
Ausführung gebracht wird.
Wir werden das später noch genauer kennenlernen, wie das funktioniert.
Es werden zum einen die Befehle in diesen internen Registern dekodiert
und zum anderen Zwischenergebnisse abgelegt.
Es gibt noch eine Reihe anderer Verwendungszwecke.
Wichtig für Sie ist, es gibt also interne Register, auf die wir
zunächst keinen unmittelbaren Zugriff haben.
Im Gegensatz zu externen Registern, und das sind eigentlich die
Register, die wir an der Schnittstelle von außen dann auch sehen und
benutzen können, zum einen zum Aufnehmen von Operanden, also die
Operationen, die Sie spezifizieren in Ihrem Maschinenprogramm, in
Ihrem Assemblerprogramm, werden hier in entsprechende Register
abgelegt.
Es werden Ergebnisse von Ihren Operationen gespeichert in Registern
und können von dort wiederum ausgelesen und weiterverarbeitet werden.
Und Sie benötigen diese Register, um die Adressen zu berechnen,
Adressen von Speicherplätzen, in denen Sie Ihre eigentlichen Daten
dann finden.
Des Weiteren können Sie hier temporär Daten auf Stapel finden.
Sie wissen, ein Stapel ist ein anderes Wort für Keller, ein Keller ist
also eine Speicherform, mit dessen Hilfe Sie entsprechend mehrere
Daten aufeinander stapeln können.
Sie können hier durch Push & Pull Daten auf diesen Stapel legen oder
wieder vom Stapel nehmen und entsprechend Ihre Operationen ausführen.
Auch hierfür nehmen Sie externe Register zur Verfügung, um temporär
hier Daten entsprechend zu finden.
Des Weiteren benötigen Sie diese Register auch, um spezielle
Bedingungen darzustellen, die Sie beispielsweise für Sprungadressen
benötigen.
Also wichtig ist, interne Unterscheidungen zwischen internen und
externen Registern als Mechanismus eines Prozessors.
Und das führt entsprechend hier zu Private Data, also der Prozessor
hält Daten für sich in den internen Registern.
Und Public Data, das sind Informationen, die ich von außen aus den
externen Registern auslesen kann und weiterverarbeiten kann.
So, das ist eine grundsätzliche Unterscheidung.
Die Frage, die sich jetzt nun stellt, ist, wie sieht der Speicher aus?
Also, wenn ich jetzt tatsächlich mal Einblick nehme in diese
Speicheraufteilung und damit auch in die Platzierung der Operationen
und der Daten in meinem Speicher, dann habe ich hier einmal die Frage
gestellt zunächst, wo liegen Ihre Befehle oder wo werden Ihre Befehle
abgelegt?
Wenn Sie ein Programm schreiben, ein Assemblerprogramm, ein
maschinennahes Programm, dann ist die Frage, in welcher Form werden
hier Ihre Operationen gespeichert?
Und die Frage, die sich da zunächst stellt, ist, welche Art von
Operationen oder welcher Typ oder wie lang ist Ihre Operation, die Sie
speichern müssen?
Und Sie können sich vorstellen, dass je nach Art der Operation
unterschiedlich Speicherplatz benötigt wird.
Stellen Sie sich vor, Sie wollen einen Addierbefehl durchführen.
Dazu brauchen Sie zwei Operanden.
Also, Sie haben eine erste Zahl, eine zweite Zahl und die beiden
wollen Sie addieren und vielleicht in den zweiten Speicherplatz
schreiben, wo also zuerst ein Operand drin entstand.
Dann überschreiben Sie damit im Ergebnis, dann haben Sie einen Befehl,
nämlich den Addierbefehl und zwei Operanden.
Sie brauchen jeweils für den Befehl und für die Operanden
Speicherplatz.
Genauso könnte aber sein, dass Sie sagen, Sie nehmen drei Operanden,
addieren den ersten und den zweiten und schreiben ihn in den dritten.
Das ist jetzt Frage der Implementierung und auch Frage des Prozessors,
wie diese einzelnen Befehle implementiert sind und wie viel
Speicherplatz Sie entsprechend benötigen.
In unserem Beispiel des 68.000er gehen wir wie folgt vor.
Wir können hier die Befehle in sogenannte Wortadressen schreiben,
wobei ein Wort entsprechend 16 Bit lang ist.
Also im Endeffekt, wenn Sie sich das Ganze dann im Speicher ansehen,
dann haben Sie dann Nullen und Einsen.
Und die Frage ist eben, wie viele Nullen und Einsen brauchen Sie hier,
um beispielsweise so eine Addieroperation abzulegen, zusammen mit den
entsprechenden Operanden.
Wir können also hier mal davon ausgehen, dass eine derartige Adresse
ausgerichtet ist an einem Wort.
Ein Wort ist definiert durch 16 Bit, während ein Byte 8 Bit hat, hat
ein Wort 16 Bit und ein Langwort oder Doubleword entsprechend 32 Bit.
Sie sehen also, dass hier diese Adressierung und die Einteilung des
Speichers entsprechend jeweils gerade vielfache einer Byte-Adresse
sind oder eines Bytes, ein Byte, zwei Bytes und dergleichen.
Man beginnt hier entsprechend im Hauptspeicher beginnend mit der
kleinsten Adresse, das ist also hier unten, und wächst hier
entsprechend in Richtung der größten Speicheradresse.
Wir haben hier bei unserem 68.000er, wie bei vielen, vielen anderen
heutigen Rechnern, das sogenannte Von-Neumann-Konzept oder die Von
-Neumann -Architektur implementiert.
Weiß jemand nicht, was das ist?
Haben Sie heute in der Vorlesung dran gehabt oder am Montag, oder?
Ja?
Die fünf Komponenten eines Von-Neumann-Rechners muss jeder und jede
nachts um zwei, wenn sie aufgeweckt werden und gefragt werden,
aufsagen können.
Ein Diplom-Informatiker, und das kommt vor, der nicht weiß, was die
Komponenten eines Von-Neumann-Rechners sind, ist die Frage, ob der
sein Diplom verdient.
Also das ist eine ganz grundlegende Architektur.
Und wenn Sie heute die High-End-Rechner aufschrauben, dann stellen Sie
fest, dass viele oder die meisten nach dem Von-Neumann-Prinzip, nach
der Architektur implementiert sind.
Und ich betone das deshalb, weil ein Prinzip von dem Von-Neumann
-Rechner unter anderem ist, Sie haben hier die Operationen, das heißt
Ihre Befehle und damit Ihr Programm, plus die Operationen.
Falsch, plus die Operanden.
Und die Daten, die Sie verarbeiten wollen mit Ihren Operationen, in
einem Speicher, in einem Hauptspeicher.
Es gibt einen Speicher und deswegen betone ich hier bei der Ablage
unserer Operationen, Sie beginnen hier am unteren Ende des Speichers
und das Programm wächst hier nach oben.
Sie werden später sehen, dass Daten, die Sie ablegen in den Speicher
und die Sie verarbeiten wollen, genau am anderen Ende abgelegt werden,
sodass das Programm und die Daten entsprechend entgegenwachsen.
Und Ende ist dann, sage ich mal, also Ende des Hauptspeichers ist dann
erreicht, wenn sich die beiden quasi treffen.
Dann müssen Sie schauen, dass Sie das irgendwie aus dem Hauptspeicher
auslagern und dergleichen.
Aber das ist ein Prinzip von dem Von-Neumann-Rechner.
So, wir haben hier also eine 16-Bit-Wortadresse und Sie sehen dann
entsprechend hier die Adressierung, die Adresse jeweils angegeben.
16-Bit sind zwei Byte.
Das bedeutet, wir haben hier beispielsweise, also hier, das ist
einfach mal schematisch angedeutet, eine Operation bzw.
den Code für eine Operation plus entsprechend die Speichernutzung für
die Operanten.
Diese zwei oder dieser Operator plus die Operanten benötigen hier ein
Wort.
Das bedeutet also zwei Byte.
Das heißt, die nächste freie Speicheradresse ist hier entsprechend mit
zwei zu kennzeichnen und so weiter.
Ich könnte hier also entsprechend dann eine weitere Operation plus
zwei Operanten beispielsweise ablegen.
Also als Hinweis können Sie sich hier nochmal merken.
Gut, das ist hier entsprechend Operation plus Operanten.
Das ist okay.
So, die Frage, die sich nun stellt, ist, ich habe es angedeutet, ob
alle Befehle in meinem Maschinenprogramm gleich lang sind oder ob sie
grundsätzlich mal gleich lang sind.
Und dem ist nicht so.
Sie können sich also vorstellen, dass beispielsweise, oder glauben Sie
es mir, ich zeige es Ihnen ganz kurz dann nachher, dass zum Beispiel
ein Move-Befehl unterschiedliche Länge haben kann.
Ich kann also beispielsweise ein Move-Befehl mit zwei Operanten
betrachten, sodass ich also hier von einem Operanten den Inhalt, den
Wert von einem Operanten in den zweiten shifte oder transferiere,
beziehungsweise hier auch entsprechend mehrere Operanten dann angeben
kann, um hier Inhalte in meinem Register zu bewegen.
In unserem Beispiel sieht das Ganze wie folgt aus.
Wir haben hier für unseren Move-Befehl zwei Byte Operationscode, das
bedeutet also ein Wort.
Zwei Byte ist hier abzulesen, einfach anhand der Adressierung.
Ich habe hier den Operationscode drinnen und dann entsprechend hier
erst an der zweiten Stelle, an der Adresse 2, meinen ersten Operanten.
Der erste Operant ist wieder ein Wort lang, also 16 Bit lang, genauso
wie der zweite,
sodass ich insgesamt hier für eine Operation plus deren Operanten
einen Speicherbedarf habe von drei Worten und das entspricht also 6
Byte.
Weiß jemand, wie viel der C64 hatte?
Weiß das jemand?
Keinen mehr gehabt zu Hause?
Bitte?
Speicherlänge eines C64?
Acht?
Ein Byte.
Den kennt keiner mehr von Ihnen?
Schon noch, oder?
Ich denke mir schon, das gibt es doch nicht.
Gut, also wie gesagt, so sieht hier in unserem Beispiel die Ablage der
Operationen und Operanten aus.
Genauso könnte es, wenn es eine andere Maschine ist, ein anderer
Prozessor, entsprechend eine andere Speicheraufteilung geben,
beispielsweise nur ein Byte lang oder nur ein Byte Speicherplatz für
Operationen oder eventuell doppelte Wortlänge, um hier meine
Operationen plus Operanten abspeichern zu können.
Das ist Spezifikationssache des jeweiligen Prozessors, das ist
implementierungsabhängig.
Sowas liest man entsprechend in der Spezifikation des Rechners oder
des jeweiligen Prozessors.
Die Frage ist nun, wie wird dieses Programm, das hier nun in meinem
Speicher sich befindet, abgearbeitet?
Und hierzu gibt es einen Befehlshole- und Ausführungszyklus, der im
Groben, der ganz grob befolgt aussieht.
Sie werden diesen Zyklus in technischer Informatik, denke ich, noch
ausführlicher kennenlernen, wenn nicht dort, dann spätestens in
Rechnerarchitekturen.
Da gibt es also noch ein paar Phasen, die man hier unterscheiden kann
und danach noch mal ein paar Details, die also gerade im Hinblick auf
Effizienzsteigerung relevant sind.
Sie haben hier eine erste Phase in Ihrem Prozess, in Ihrem Zyklus,
nämlich das Herausholen des Befehles in dieser Fetch-Phase oder durch
diesen Fetch-Befehl, das Auslesen also des Befehles aus meinem
Hauptspeicher.
Nach diesem Auslesen wird der Pointer, also dieser Program-Counter, zu
dem ich gleich noch mal kommen werde, entsprechend um zwei Byte
erhöht.
Das heißt, Sie wandern dann von Ihrem Operationscode zu Ihrem ersten
Operanten und eventuell zu Ihrem nächsten Operanten.
Das ist also die Phase, wie der Prozessor, genauer gesagt wie das
Leitwerk, jetzt aus dem Hauptspeicher auf Ihr Programm zugreift.
Die Frage ist, wie hier entsprechend konkret die Codierung der
Operationen aussieht und welche Länge jeweils eine Operation besitzt.
Das kann ich hier innerhalb der Execute-Phase oder des Executes
entsprechend noch mal neu berechnen.
Ich komme dann nach dem Fetch also zu dem Punkt, wo ich den Befehl
ausführe.
Und hier kann es sein, dass ich für eine Operation den Program-Counter
noch einmal erhöhen muss, nämlich wenn zum Beispiel ein zweiter
Operant noch zusätzlich ausgelesen werden muss.
Das erfahre ich, indem ich hier den abgeholten Befehl auswerte und
entsprechend dann auch auf seine Länge schließen kann.
Also hier die Befehlslänge des aktuellen Befehls kann jeweils noch mal
berechnet werden müssen und kann noch mal dazu führen, dass nochmals
dieser Program-Counter erhöht werden muss, um die vollständige
Operation plus Operanten auslesen zu können.
Sie sehen hier, für die erste Phase ist das Leitwerk zuständig.
Das steuert also die Vorgänge auf den Datenbus.
Und die eigentliche Berechnung nimmt die ALU vor, also diese
Arithmetic Logic Unit,
die dann auch das Ergebnis berechnet von der Operation und dann
zurückschreibt in eines der Register.
Ich gehe mal davon aus, dass Sie neben diesen zwei Komponenten jetzt
die anderen drei Komponenten des von Neumann Rechners aufzählen
können, die da wären.
Was haben wir noch?
Was haben wir?
Bytes?
Lauter!
Speicher?
Was noch?
Haben wir drei?
Da drinnen steht, hier wird zu wenig diskutiert und es werden zu wenig
Fragen gestellt.
Also ich frage jetzt einfach mal, was haben wir noch?
Bus und?
Bitte?
Windows ist hier vorne gefragt.
Haben Sie sich zur Klausur angemeldet?
Das war eine rhetorische Frage, die ich wieder zurückziehe.
Also, letzte Komponente.
I.O.
war hier vorne irgendwo, also Eingabe-Ausgabe-Prozessor, um hier
entsprechend die Schnittstelle nach außen hin zur Peripherie zu
garantieren.
Also wie gesagt, merken Sie sich entsprechend diese fünf Komponenten,
prägen Sie sich am besten ein Bild ein.
Es gibt hier wirklich wunderschöne Bilder, ich glaube auch im Rahmen
der Vorlesung ist hier eins gezeichnet, wo Sie die wichtigsten, also
die fünf Komponenten und ihre Beziehungen sich vor Augen führen
können.
Sollten Sie irgendwann gefragt werden, wie funktioniert ein Rechner
auf tiefster Ebene, Sie können sich das am Hand dieses Schemas
herleiten.
Aber das ist was wirklich ganz Grundlegendes hier im Rahmen der
Informatik.
Hinweis ist hier noch an dieser Stelle, mit Prefetching können auch
mehrere Befehle spekulativ im Voraus geholt und zumindest teilweise
dekodiert werden.
Das bedeutet, wenn Sie hier eventuell einen zusätzlichen Prozessor
haben, mehrere Prozessoren beispielsweise, einen Hauptspeicher, dann
können Sie parallelisieren auf der Hardware-Ebene, indem Sie während
der erste Prozessor beispielsweise Execute ausführt, den zweiten
Befehl bereits auslesen und versuchen zu dekodieren.
Das geht sogar so weit, dass man parallel versucht gleichzeitig
Operationen auszuführen, um schneller entsprechend das Gesamtprogramm
abarbeiten zu können.
Das lernen Sie beispielsweise bei den Rechner-Architekturen, wenn es
zum Beispiel um Echtzeitsysteme geht.
So, das hier nur als Hinweis.
Dieser grobe Zyklus dient aber dazu, um das Vorgehen des
entsprechenden Prozessors beim Verarbeiten seiner Operationen zu
verstehen.
Lassen Sie mich einen Kommentar noch zu diesem Begriff Programm
-Counter geben.
Also, ich habe hier auf dieser Folie oder auf einer Folie noch eine
viel schärfere Aussage gefunden.
Ich habe es mal so hingeschrieben.
Dieser Begriff Programm-Counter ist sehr unglücklich gewählt und kann
vielleicht den einen oder anderen irreführen.
Es werden hier keine Programme gezählt.
Was hier eigentlich die Aufgabe ist, ist, dass hier ein Zeiger
existiert, der jeweils auf den aktuellen Befehl zeigt.
Auf die aktuelle Speicheradresse, wo dann der Befehl drinnen steht,
der als nächstes bearbeitet werden muss.
Also, treffender wäre hier viel besser ein Begriff wie Instruction
-Pointer oder Befehlszeiger, der also hier auf den aktuellen oder
nächsten Befehl zeigt.
Also, einmal zeigt reicht.
Also, als Hinweis, der zählt keine Programme.
Wie Sie sicherlich auch schon kennengelernt haben, lebt die Informatik
von Abkürzungen.
Was hier dazu kommt ist, PC ist hier noch einmal doppelt belegt.
Das finden Sie auch noch öfters an anderer Stelle.
PC ist unter anderem zu verwechseln mit Personal Computer.
Also, wenn es darum geht, hier eine eindeutige Antwort auf Fragen zu
geben, schreiben Sie es aus.
Hinweis für Klausur beispielsweise.
Kürzen Sie nicht zu viel ab, das führt zu Missverständnissen.
Schreiben Sie es so aus, dass auf jeden Fall die Korrektoren ihre
richtige Meinung interpretieren können.
So, obwohl nun ein PC... Also, wichtig ist jetzt die Frage, wie
arbeitet dieser Programme-Counter.
Das ist also hier im Rahmen der Abarbeitung von Maschinenprogrammen
ein wichtiges Element.
Die Frage ist, wie ist dieser Programme-Counter aufgebaut?
Im Prinzip ist das wiederum auch eine Art Register, nämlich ein 32-Bit
-Register.
Ein 32-Bit-Register, von dem jedoch nur eine gewisse Anzahl von Bits
genutzt werden, um die Adressen entsprechend anzusteuern.
Nämlich genau 24 Bit.
Und jetzt stellt sich die Frage, oder Sie könnten gefragt werden, wenn
Sie 24 Bit zur Verfügung haben, wie viele Speicher können Sie damit
ansteuern?
Wie viele Speicher können Sie adressieren?
Wenn Sie also als größte Möglichkeit diese 24 Bit zusammen haben, dann
können Sie sich ausrechnen, Sie können es ableiten, dass Sie also ca.
maximalen Adressraum von 16 MB entsprechend ansteuern können.
Das ist genau die Anzahl von Speicheradressen, die Sie hier im Rahmen
des Programme-Counters kodieren können.
Ich denke mal, der Zusammenhang ist klar.
Sie können sich ja selber mal ausrechnen, wenn Sie hier die ganzen
Einsen eintragen und dann die Kodierung von Binär nach Dezimal
überführen, dann erhalten Sie hier entsprechend dieses Ergebnis.
So, wie arbeitet im Prinzip dieser Programme-Counter, wenn Sie
beispielsweise hier in diesem Register, in diesem Zeigerregister, den
Eintrag vorfinden, die 1,0.
1,0, wissen Sie, dass das Binär die Kodierung für 2 darstellt und dann
ist der Zeiger entsprechend gesetzt auf die Speicheradresse mit dem
Wert 2.
Das heißt, ich würde jetzt als Leitwerk entsprechend hier zunächst
einmal den Programme-Counter befragen und aus dem Programme-Counter
dann weitergeleitet werden auf die Speicheradresse 2 in Erwartung,
dass hier meine nächste Operation zu finden ist.
Also in der Regel sind solche ausgezeichneten Adressen für besondere
Zwecke reserviert.
Also diese ausgezeichneten Adressen, die jetzt hier grün und gelb
eingefärbt sind, das heißt, am untersten Ende meines Speichers sich
befinden, sind für besondere Zwecke reserviert.
Also gar nicht mal so sehr für allgemeine Operationen, sondern zum
Beispiel für die Platzierung sogenannter Unterbrechungsvektortabellen.
Jetzt ist die Frage, was ist eine Unterbrechungsvektortabelle?
Das ist zunächst einmal eine Tabelle mit Unterbrechungsvektoren.
Das ist sinnig, gell?
Ich habe das deswegen so ausgedrückt, weil es hier eine Tabelle gibt,
in der mehr als ein Unterbrechungsvektor drin ist oder drin sein kann.
Und diese Unterbrechungsvektoren geben
jeweils die Startadresse
für sogenannte Service-Routinen an.
Diese Service-Routinen sind quasi Unterroutinen zur Bearbeitung von
Ausnahmebehandlungen, Exceptions.
Die
Frage ist nun, was können Ausnahmen sein und wie komme ich zu der
Information, ob eine Ausnahme vorliegt?
Auch hierfür gibt es ein spezielles Register, in dem der Prozessor
Informationen über bestimmte Ausnahmen festhält.
Tritt eine dieser Ausnahmen auf, dann kann der Prozessor genau in
diesem Unterbrechungsvektor oder in dieser Tabelle nachsehen und sich
gemäß der Ausnahme die entsprechende Startadresse raussuchen, an die
er springen muss, um hier die entsprechende Ausnahmebehandlung
anzustoßen.
Also soweit zu der Erklärung dieser Unterbrechungsvektortabellen.
Als Hinweis, die sind jeweils am untersten Ende in speziellen
Registern meines Speichers zu finden.
Und da finde ich auch noch eine ganz andere Menge von Registern.
Diese Statusregister und diese Ausnahmebehandlungen finde ich hier
genau in diesem sogenannten Statusregister.
Sie sehen hier auch entsprechend unseren sogenannten Programme
-Counter, diesen Befehlszeiger, der jeweils auf die nächst
auszuführende Operation zeigt.
Diese Statusregister signalisiert Eigenschaften
eines abgearbeiteten ALU-Befehls.
Nachdem also das Leitwerk, der Prozessor den Operation-Code und die
Operanten in die ALU geladen hat, wird die Operation ausgeführt.
Zum Beispiel die Addition wird praktiziert, die zwei Operanten werden
zusammengeführt.
Diese Statusregister hält nun Eigenschaften des Ergebnisses fest, also
bezüglich der Berechnung durch die ALU.
Diese unterschiedlichen Ausnahmen oder diese Eigenschaften, die hier
auftreten können, sind hier unten aufgelistet.
Also diese Eigenschaften führen zum Setzen ganz bestimmter Bits.
Zum Beispiel hier eines Carry-Bits.
Das ist also das Auftreten eines Übertrags.
Ich muss also bei einer Berechnung, zum Beispiel bei einer Addition,
einen Übertrag nachziehen.
Oder wir haben hier einen Overflow, einen Überlauf, einen
arithmetischen Überlauf.
Wir haben hier eine Null, eine Nulldivision beispielsweise oder
irgendwie eine Berechnung, die zu einer Null führt.
Oder das Ergebnis ist negativ
oder wir haben hier entsprechend einen Überlauf bei einer erweiterten
Genauigkeit.
Das drückt dieses Extension-Flag aus.
Wichtig für Sie ist nun, dass diese Informationen aus diesem
Statusregister genutzt werden können.
Beispielsweise für die Bearbeitung Ihres Programmes durch ganz
bestimmte Befehle, zum Beispiel die Abfrage, ob eine Berechnung Null
ergibt.
Ob etwas größer ist oder kleiner ist, ob etwas gleich Null oder
kleiner Null ist, ob es negativ ist.
All das kann ich nun ausnutzen, ob ein Ergebnis einer Berechnung
negativ ist.
All das kann ich ausnutzen, um beispielsweise im Fortlauf meines
Programmes mit ganz bestimmten Befehlen zum Beispiel eine bedingte
Verzweigung herbeizuführen.
Oder aber ich kann hier entsprechend diese Informationen nutzen, um
ganz bestimmte Ausnahmen oder Ausnahmebehandlungen anzustoßen.
Als zusätzliche Information ist vielleicht noch wichtig, dass dieses
Statusregister sich in zwei Bereiche aufteilen lässt.
Nämlich in diesem CCR-Bereich, in das Code Condition Register.
Das ist der Bereich, den Sie als Nutzer, als Entwickler eines
Maschinenprogramms nutzen können.
Und in einem Bereich, der nur vom Betriebssystem genutzt werden kann.
Hierin wird also der Status für das Betriebssystem gespeichert.
Als zusätzlicher Hinweis sei gesagt, dass das im Prinzip hier
unabhängige Bits sind.
Unabhängige Informationen, ob jetzt hier ein Overflow passiert oder
ein Übertrag vorliegt.
Aufgrund der, ich sage mal, semantischen Zusammenhänge, des
Zusammenhangs, dass das also Statusinformationen der Berechnung sind,
hat man das aber in ein separates Register, eben in das Statusregister
zusammengeführt.
So, die Frage ist, was steckt noch hier in unserem Statusregister?
Nämlich hier in diesem linken Bereich, in dem es um Informationen
unseres Betriebssystems geht.
Wir haben hier die Möglichkeit, oder das System bietet hier die
Möglichkeit an, zum Beispiel mit Hilfe eines Trace Bits den Trace Mode
zu setzen.
Dieser Trace Mode sagt aus, in welcher Form mein Programmcode
ausgeführt wird.
Zum Beispiel schrittweise...
oder entsprechend in einem Durchlauf von Anfang bis Ende.
Ich kann hier durch das Setzen des Trace Bits beispielsweise
schrittweise durch meinen Programmcode durchgehen und hier nach
Fehlern suchen.
Ich habe ein weiteres Bit, dieses Modus Bit, das mir die Möglichkeit
bietet, zwischen einem User Mode und einem Supervisor Mode zu
unterscheiden.
Wir haben hier im Rahmen des Betriebssystems wiederum Operationen,
beziehungsweise es gibt hier in diesem Betriebssystem-Kontext
Operationen, die nicht von jedem Benutzer genutzt werden können
sollten.
Sie können sich vorstellen, dass also der Zugriff auf zentrale
Register, was weiß ich, alle möglichen Programme beeinflussen kann,
sodass hier also, ich sage mal, eine rechte Unterscheidung stattfindet
zwischen einem User und einem Supervisor.
Dieser Supervisor Mode wird beispielsweise benötigt, um ganz bestimmte
Betriebssystem -Operationen zum Ablauf zu bringen.
Ich habe dann nochmal eine weitere Möglichkeit, nämlich das Setzen von
sogenannten Unterbrechungsmasken.
Mit diesen Masken kann ich die Klasse akzeptierter Unterbrechungen
definieren.
Ich kann also festlegen, inwieweit ich oder welche
Ausnahmebehandlungen, die ich vorher aufgezeigt habe, also dieses
Overflow oder Carry beispielsweise...
Habe ich irgendwas verpasst?
Diese Ausnahmen kann ich entsprechend maskieren.
Das heißt, ich muss nicht immer alle Ausnahmen zulassen.
Ich kann hier eine entsprechende Auswahl und auch eine Bearbeitung der
Routinen dann entsprechend vorsehen.
Soweit die Interpretation des Statusregisters.
Wie sieht es mit unseren eigentlichen Datenregistern aus und
entsprechend Adressregistern?
Wir haben hier im 68.000er die Möglichkeit, entsprechend ein Bit Daten
oder Daten in Datenregistern mit einem Bit, mit einem Byte Länge
abzulegen.
Wir können hier in Wortlänge unsere Daten speichern.
Das ist hier, dann schreiben wir es mal vielleicht hier rein, Byte
Länge, Wortlänge.
Dann steht es englisch Longword drinnen.
Also Langwort, das ist nochmal das doppelte Wort mit insgesamt 32 Bit
Länge.
Und wir haben hier entsprechend 8 Datenregister dieser Art zur
Verfügung, durchnummeriert von 0 bis 7.
Das ist also relevant, wenn es dann um die Adressierung unserer
Datenregister im Code geht.
Um die Adressen entsprechend zu spezifizieren, stehen uns Longword
-Register zur Verfügung.
Beziehungsweise wir können hier als Longword unsere Register nutzen
oder auch in der Länge eines Wortes.
Das heißt also 2 Byte lang.
Und auch hier haben wir Adressregister der Anzahl 7 durchnummeriert,
beziehungsweise hier haben wir 7 Adressregister zur Verfügung im
Gegensatz zu 8 Datenregister, durchnummeriert von 0 bis 6.
Diese Nutzung der Datenregister, beziehungsweise die Art der Operation
in Bezug auf die Datenregister, wird jeweils durch einen Suffix, also
durch einen Befehlszusatz angegeben.
Zum Beispiel Longword am Ende eines Befehles, wenn wir mit der Länge
eines Datenregisters von 32 Bit arbeiten, oder Wort, wenn wir ein
Datenregister als Wortlänge oder in Wortlänge behandeln wollen und
entsprechend als Byte mit B abgekürzt, wenn wir ein Register als Byte
behandeln wollen.
Das führt uns entsprechend zu unterschiedlichen Operationen oder zu
unterschiedlichen Arten von Operationen.
Der Bezugspunkt ist hier jeweils die Nutzung oder die Unterscheidung
ist die Nutzung des Datenregisters, also in welcher Länge oder welche
Teile des Datenregisters benutze ich im Rahmen meiner Operationen.
Und hier unten steht, das ist ein wichtiger Hinweis, deswegen ist er
auch rot geschrieben, hier liegen also die meisten Anfängerfehler,
weil hier zu wenig Acht gegeben wird auf die korrekte Nutzung und
Spezifikation der Befehle und damit eine falsche Nutzung der
Datenregister.
Wir werden nachher sehen, welche Auswirkungen das hat.
Merken Sie sich noch einmal, es gibt Byte-Operationen, Wort
-Operationen und Langwort-Operationen auf den gleichen Datenregistern.
Wir haben nur sieben, nein, acht Datenregister zur Auswahl, D0 bis D7,
die ich aber jetzt in unterschiedlicher Art und Weise verwenden kann.
Nämlich durch die Spezifikation, ob ich sie in der Länge Double-Word
oder Langwort oder Wort oder Byte verwende.
Sie können sich dann ausrechnen oder Sie können sich jetzt schon
vorstellen, dass es hier jeweils unterschiedliche Effekte oder
unterschiedliche Ergebnisse geben wird.
Hinweis ist hier eben, dass eben viele Anfänger entsprechend diese
unterschiedlichen Operantenformen vergessen.
Der Grund ist einfach auch, der Entwickler von Assembler-Programmen
steht hier in einer höheren Verantwortung oder ich sage mal, muss mehr
Aspekte betrachten als auf einer höheren Programmiersprache.
Wir haben hier drinnen, also auf dieser Ebene der Programmierung
beispielsweise keine Typ-Prüfung, nimmt uns keiner ab, muss der
Entwickler machen.
Genauso haben wir hier keine automatische Typ-Wandlung, die uns
beispielsweise ein Compiler vielleicht abnehmen könnte oder bestimmte
Programmbefehle.
Also allgemein kann man sagen, die Assembler-Sprache ist ganz schön
hinterhältig.
Das Hinterhältige möchte ich nochmal konkretisieren.
Der Entwickler hat darauf zu achten, dass er unerwünschte
Seiteneffekte vermeidet.
Das Programm mag im Prinzip korrekt sein, läuft auch, der Assembler
spuckt auch keinen Fehler aus.
Es läuft, es funktioniert, es liefert ein Ergebnis, bloß das Ergebnis
ist einfach falsch, weil sie an irgendeiner Stelle entsprechend zum
Beispiel die Handhabung der Datenregister falsch programmiert haben.
Deswegen wollen wir uns die Wirkung dieser unterschiedlichen
Operationen etwas genauer vor Augen führen.
Wir haben zum einen die Byte-Operationen.
Das sind also Operationen, die jeweils auf 8 Bit eines Datenregisters
zugreifen oder wirksam werden.
Und als Beispiel dient hier ein Additionsbefehl.
Sie sollen also vor dem Additionsbefehl haben, zum Beispiel D0, das
ist also das erste Datenregister, folgenden Inhalt.
Wir haben hier an dieser Stelle eine 1 stehen und dann entsprechend
hier noch einmal dieses zweite Bit hier gesetzt.
Wenn Sie das umrechnen in eine Dezimaldarstellung, dann erhalten Sie
hier den Wert 65.538, das ist trivial.
Sie wissen auch, dass das gesamte Datenregister entsprechend eine
Länge von 32 Bit aufweist.
Wir haben hier 8, 1 Byte, doppelte Wortlänge, 1 Wort und doppelte
Wortlänge.
Jetzt ist die Frage, Sie sollen also hier jetzt als Byte-Operation
diese 2 entsprechend auf den Inhalt des bestehenden Datenregisters
aufaddieren.
Das heißt also, diese Zahl 2, den Wert 2 angegeben durch dieses Zaun
-Symbol, wird direkt aufaddiert hier auf den Inhalt des
Datenregisters.
Diese Abkürzung, das ist genau dieses Suffix, von dem ich vorher
gesprochen habe, drückt also aus, dass es sich hier um eine Byte
-Operation handelt.
Dieses I hier drückt aus, das kommt später nochmal, drückt aus, dass
hier direkt ein Wert als erster Operand auf den zweiten hier
draufgerechnet wird.
Sie könnten sich hier entsprechend der unterschiedlichen möglichen
Adressierungsarten, Speicherzugriffsarten, auch andere
Befehlsausprägungen vorstellen.
In einer der Übungsaufgaben von Übungsblatt 12 werden Sie nach diesen
unterschiedlichen Adressierungsarten gefragt, deshalb möchte ich hier
auch nicht weiter darauf eingehen.
Addieren Sie also die dezimale Ziffer 2 beidweise in das Register D0
und Sie erhalten hier entsprechend an dieser Stelle das
Ergebnis 0100.
Wichtig ist, der Rest des Registers, der Rest des Registers D0 wird im
Rahmen dieses Befehles ganz einfach nicht betrachtet.
Also die Frage ist, ob hier hinten jetzt was drinnen steht oder nicht,
das interessiert an der Stelle des Additionsbefehls einfach nicht.
Der guckt nur das erste Byte an, die ersten 8 Bits, die Frage ist dann
entsprechend, wie der Folgebefehl das gesamte Register betrachtet.
Ob der wiederum nur auf diesen Byte weiter arbeitet oder ob er
entsprechend auch diese hinteren Informationen benutzt und je nachdem
kann es hier zu gewünschten oder nicht gewünschten Effekten kommen,
wie wir später auch nochmal eindeutig sehen werden.
Der Hinweis ist, bei einem Überlauf im Byte werden Flags im CCR
gesetzt.
Sie sehen also, wenn Sie hier auf dieses D0 mit dem Inhalt 0010 an
dieser Stelle nochmal eine 2 aufaddieren, 2 ist ja genau 1 0, dann
wird hier entsprechend in unserem Statusregister der Übertragflag
gesetzt und eine entsprechende Ausnahmebehandlung angestoßen, um hier
diese Addition durchzuführen.
Das ist aber hier nur ein Hinweis, der am Rande bemerkt wird.
Also wichtig ist, prägen Sie sich das ein, das B hier betrachtet nur
diesen Teil eines Registers.
Das Ganze kann zu Problemen führen im Rahmen von Byte-Operationen.
Ich habe es angedeutet, was steht nun als Ergebnis im Datenregister
D0?
Und da ist wieder die Frage, wie, um zu entscheiden, zu
interpretieren, was da drinnen steht, stellt sich die Frage, welcher
Befehl, welche Art des Befehles greift auf dieses Register nach der
Addition zu?
Ist das wiederum eine Byte-Operation?
Dann erhalten wir den Wert 4, weil uns dann auch wiederum nur das hier
interessiert.
Ist es aber zum Beispiel eine Langwort-Operation, dann erhalten wir
einen ganz anderen Wert, nämlich 65.570.
Und das ist genau der Grund, warum es also hier bei ungenauem
Hinsehen, bei unscharfer Entwicklung von unseren Programmen zu Fehlern
kommen kann.
Das Programm mag korrekt sein, aber das Ergebnis ist dennoch falsch.
Eine Lösung hierfür ist, dass Sie, bevor Sie ein Datenregister nutzen,
dieses erstmal säubern, also erstmal auf 0 den Inhalt setzen und dann
entsprechend erst Ihre Operationen ausführen.
Also hier ist es wieder die Verantwortung des Entwicklers,
entsprechend sauber mit den Speicherregistern umzugehen.
Die Ausgabe oder für die Ausgabe von Ergebnissen, das ist etwas, was
Sie für das kommende Übungsblatt eventuell, sage ich auch, für die
Bearbeitung von Klausuraufgaben nutzen können sollten.
Das stellt eine Art der Vereinfachung dar, wie Sie Programmcode
spezifizieren können.
Jetzt mal für das Übungsblatt beispielsweise, auf dem 13er vielleicht.
Und zwar können Sie auch auf der Assembler-Ebene mit dem 68.000er
beispielsweise oder mit entsprechenden neueren Prozessoren Makros
einbinden.
Ich denke mal, Makros sollten bekannt sein, Sie können hier mithilfe
vereinfachter Befehlskonstrukte entsprechend komplexere Programme
verschatten oder hier durch die Spezifikation eines Makros komplexere
Programmabfolgen zusammenführen und dann nur als einen Operationscode
oder als einen Programmaufruf spezifizieren.
Und genauso gibt es hier die Möglichkeit im Rahmen einer Bibliothek,
die Sie einbinden können in Assembler-Programme, beispielsweise die
Ausgabe von einem Register auf einem Bildschirm entsprechend hier
durch WriteByte, WriteWord und WriteLong zu vereinfachen.
Das sind in dem Sinne jetzt keine, oder mag sein, dass das keine
korrekten Programmaufrufe oder korrekten Makros sind, die jetzt im 68
.000er in unserem Simulator drinnen sind.
Aber wenn es darum geht jetzt eine Übungsaufgabe zu bearbeiten oder
auch für die Klausur, ja, wichtig, hat jeder gehört, dann bitte ich
Sie zur Vereinfachung Ihrer Programmierung beispielsweise hier diese
Makros zu verwenden.
Nicht, dass mal wieder einer kommt, die Übungsaufgabe ist zu schwer.
Ja?
Also, genauso gibt es die Möglichkeit, dass wir sagen, dass WriteHello
soll hier ein Makro sein zur Ausgabe einer Stringkonstanten oder
WriteLine ist ein Makro zur Positionierung einer Zeile.
Wichtig für das Verständnis ist, dass diese Makros in dem Sinne keine
richtigen Unterprogramme darstellen, sondern wirklich nur Abkürzungen
von Programmteilen.
Diese Makros werden vor dem Assemblieren eingebunden und zum Zeitpunkt
der Assemblierung eines Programms wird das Makro durch den kompletten
oder jedes Makro durch den kompletten Assembler-Code, der sich hinter
diesem Makro versteckt, ersetzt.
Sodass Sie dann in dem fertig assemblierten Programm jeweils an der
Stelle des Makros ein Vielfaches entsprechend des dahintersteckenden
Programm -Codes wiederfinden.
Ein Unterprogramm würde ja nur einmal irgendwo stehen und von
verschiedenen Orten entsprechend aufgerufen werden.
Das ist hier der Unterschied zum Makro.
Probleme bei einer Ausgabe?
Ich sage hier, schauen Sie ein paar Folien davor nochmal nach, ist
hier wiederum die Semantik Ihres Operators, Ihrer Operation.
Arbeiten wir hier auf Byte-, Wort- oder Doppelwortlänge und
dementsprechend bekommen Sie auch hier wiederum ein unterschiedliches
Ergebnis.
Der Hinweis gilt also hier, das Programm mag korrekt sein, aber
fehlerhafte Ausgabe liefern.
Oftmals werden genau diese Makros oder diese Ausgaben auch verwendet,
um das Debugging zu unterstützen, also um Fehler zu suchen.
Dementsprechend sollten Sie also hier auch besonders darauf achten,
welche Art von Operation Sie hier wählen.
Dann nochmal ganz kurz zum Vergleich die Wirkung der Wort-Operation.
Vor dem Additionsbefehl hat also hier das D0 folgenden Inhalt.
Wir haben hier also auf der gesamten Breite entsprechend einen Inhalt
drinnen, der hier noch zusätzlich negativ gesetzt ist.
Also hier ist zum Beispiel ein Negativfleck gesetzt und Sie sollen nun
mithilfe des Add Immediate Word entsprechend die Zahl 512 aufaddieren.
Und da es sich hier um eine Wort-Operation handelt, interessiert uns
in diesem Fall nur dieser Bereich des Datenregisters, D0, was wiederum
zu dem Problem führt, dass wir hier auch bei der Ergebnisbetrachtung
zunächst nur den hinteren Teil unseres Datenregisters betrachten und
nicht einmal hier dieses gesetzte Fleck uns angucken.
Und das führt wiederum, je nachdem wie Sie jetzt weiterarbeiten mit
diesem Datenregister, zu dem Problem, wenn jetzt eine Long-Word
-Operation dieses Ergebnis ausliest, habe ich dann wiederum das
Problem, dass es, ich sage mal in dem Sinne, zu einer falschen Ausgabe
oder zu einer Ausgabe eines falschen Ergebnisses kommt, weil ich
eventuell hier bei der Addition wirklich nur diesen Bereich hier
hinten betrachtet habe.
Also analog entsprechend zu dem Problem des Byte, der Bytelänge.
Und ähnlich sieht es also aus, wenn es darum geht, Long-Word
-Operationen durchzuführen.
Vor dem Additionsbefehl habe also die 0 folgenden Inhalt.
Wir haben hier an dieser Stelle eine 1 und hier hinten eine 1 gesetzt.
Ich habe das zum Vergleich mal in die Dezimalschreibweise überführt.
Wir haben hier den Wert 65.538 drinnen stehen und greifen nun oder
addieren nun die Dezimalzahl 65.536 auf dieses Register auf.
Dieses Mal entsprechend auf die gesamte Breite und erhalten dann
entsprechend hier wiederum, wenn Sie die Addition also auf Bytebit
-Ebene durchführen, entsprechend das Ergebnis.
Also die 65.536 ist binär geschrieben, eine 1 und dann folgen 16
Nullen.
So und wenn Sie das mal hier aufaddieren, dann stellen Sie also fest,
dass Sie genau an dieser Stelle entsprechend folgendes Ergebnis
erhalten oder insgesamt folgendes Ergebnis erhalten.
Hier hinten ändert sich nichts, da kommt also nichts Neues hinzu.
Und genau an dieser Stelle müssen Sie darauf achten, dass Sie hier
entsprechend diesen Übertrag mitführen.
Das Ergebnis, das Sie erhalten, ist auch einfach nachzurechnen.
Sie können das wiederum entsprechend umwandeln in das 131074, das Sie
auch richtigerweise wiederum nur erhalten, wenn Sie hier mit einem
Write, was muss rauskommen?
Write, Byte, was muss es heißen, wie muss es heißen?
Write Long, korrekt, ich habe es irgendwo gehört, ganz hinten.
Write Long liefert auch wiederum hier das richtige Ergebnis.
Also, wichtiger Hinweis, beachten Sie mit welcher Registerlänge Sie
entsprechend Ihre Befehle absetzen.
Zusammenfassend sind hier noch einmal die Möglichkeiten
zusammengeführt.
Sie haben also diese drei Suffixe, das sind also Erweiterungen am
Befehl.
Wir haben hier ein B, ein W und wir haben hier ein L.
Sie haben auch die Möglichkeit, also es gibt den Befehl, wie Sie also
in der Liste der Befehle für den 68.000ern nachlesen können, hier
entsprechend einen reinen Addi-Befehl abzusetzen, der hier eben das
niederwertige Wort bearbeitet und hier beispielsweise die 512
aufaddiert.
Das heißt, die Semantik oder die Länge, in der dieser Befehl agiert,
hängt quasi ab von der Größe dieses Wertes, der hier addiert werden
soll.
Die Frage ist, wie viel Byte brauche ich hier, um die 512 zu addieren?
Und das kann wiederum zu ungewünschten Problemen, zu Effekten führen,
die Sie vielleicht mit den anderen Befehlen nicht bekommen hätten.
Weil Sie hier vielleicht nicht darauf geachtet haben, dass das jetzt
vielleicht doch Wortlänge benötigt und Sie sind davon ausgeschlagen,
dass hier Bytelänge notwendig ist und dergleichen.
Also arbeiten Sie hier bewusst und gewissenhaft auf dieser
maschinennahen Ebene, da es sonst zu unerwünschten Effekten kommt.
So, wir haben entsprechend angemerkt, dass wir zu unseren
Datenregistern eben unsere Adressregister haben.
Wir haben hier die Möglichkeit, entweder Wortoperationen auszuführen
oder Langwortoperationen.
Also Sie können Adressen genauso verarbeiten wie Daten.
Sie können Adressen addieren, Sie können sie verschieben, Sie können
sie von einem Ort zum anderen bewegen und, und, und.
Beispiele sind hier angegeben.
Sie können hier also mit Move Address entsprechend
hier eine Adresse mit dem Wert 2 in das Adressregister 0 reinlegen
oder hineinschieben.
Beide Operationen mit gleichem Effekt, aber der erste Befehl ist nur
ein Wort groß, während der zweite Befehl entsprechend zwei Wörter lang
ist oder die Länge von zwei Wörtern hat.
Und da gilt der Grundsatz, dass kürzere Befehle in der Regel schneller
sind.
Also wenn Sie hier auch wieder auf effizientes Programmieren achten,
achten Sie darauf, dass Sie möglichst kurze Befehle verwenden, es sei
denn, Sie brauchen längere.
Aber wenn es möglich ist, nehmen Sie kurze Befehle, weil Sie dann
sicher gehen, dass Ihr Programm entsprechend effizienter und schneller
arbeitet.
So, neben unseren Datenregistern und Adressregistern gibt es noch
weitere Register.
Zum einen den sogenannten Nutzerstapelzeiger.
Das ist also wiederum ein Zeiger, der dieses Mal auf einen Stapel
zeigt, nämlich auf einen Stapel, den der Nutzer in Anspruch nehmen
kann.
Deswegen Nutzerstapelzeiger, das ist ein kompliziertes Wort, abgekürzt
oftmals auch USP als User Stack Pointer.
Also Sie wissen, wie ein Stapel funktioniert.
Ich habe so einen Stapel und ich habe einen Zeiger, der mir quasi auf
das oberste Element verweist, das ich also verarbeiten kann, vom
Stapel nehmen kann und wieder eins drauflegen kann.
Das ist dieser Nutzerstapelzeiger im Gegensatz zu dem System Stack
Pointer SSP.
Wie der Name sagt, ist das wiederum ein Stapel bzw.
ein Zeiger auf einen Stapel, der ausschließlich vom Betriebssystem
genutzt werden kann.
Ich habe hier also die Nutzung durch das Betriebssystem, das ja auch
Daten verarbeiten muss.
Und ich habe hier die Nutzung durch den Benutzer oder durch das
Benutzerprogramm.
Hier ist nochmal schematisch angedeutet, wie dieser Nutzerstapelzeiger
funktioniert.
Wir haben hier beispielsweise einen Inhalt in unserem Register, der
hier durch diese Binärzahl angegeben ist.
Und wenn Sie das einmal in die entsprechende Adresse überführen, die
Adresse, also wenn das die Binärdarstellung ist,
dann werden Adressen, wie Sie wissen, in Hexadezimal-Schreibweise
angegeben.
Und wenn Sie das einmal umrechnen, dann stellen Sie also genau fest,
dass dieser Registerinhalt auf das aktuell oberste Stapelelement
zeigt.
Und wie ich einleitend gesagt habe, sind unsere Daten genau am anderen
Ende platziert.
Das ist also jetzt wiederum wichtig für das Verständnis, deswegen male
ich das hier nochmal dick.
Das heißt, die Daten wachsen den Programmen von oben entgegen.
Hinweis, der Stapel beginnt bei den großen Adressen, Sie sehen das
hier, wächst in Richtung kleinerer Adressen bzw.
je nachdem, schrumpft in Richtung der größeren Adressen.
Je nachdem, wie Sie das lesen wollen.
Als Beispiel kann man sich also vorstellen, ein Befehl.
Wie funktioniert ein Befehl JSR A0?
Das bedeutet, dieser Befehl heißt ausgeschrieben Jump to Subroutine.
Und dieses Unterprogramm beginnt an der Adresse, die hier in diesem
Register A0 drin steht.
Und
dieses A0 zeigt die Adresse an des Folgebefehls auf
dem Stapel.
Das bedeutet, bevor hier diese Jump-Routine ausgeführt wird, das
heißt, bevor gesprungen wird, wird die Folgeadresse dieses Befehls auf
den Stapel gelegt.
Warum wird das gemacht?
Ich verlasse hier die Sequenz meines Programmes durch einen Sprung an
eine andere Adresse.
Wenn das Unterprogramm an dieser Stelle, zu der ich gesprungen bin,
abgearbeitet ist, muss ich ja wieder zurückspringen.
Und das bedeutet, ich merke mir die Folgeadresse hier entsprechend
nach dieser Jump-Anweisung.
Und das Merken geschieht, indem ich sie hier entsprechend auf den
Stapel lege.
Und nach der Abarbeitung entsprechend greife ich mir die letzte
Information vom Stapel und springe wieder zurück.
Die Frage ist nun, wie diese Adresse, diese Information auf den
Speicher abgebildet wird bzw.
wie hier entsprechend diese Information der Speicheradresse abgelegt
wird.
Und die Frage ist wiederum, in welcher Form oder in welcher
Reihenfolge entsprechend die einzelnen Bits in meine Register
geschrieben werden oder in den Adressraum geschrieben werden.
Und die Frage an dieser Stelle ist, es soll nun die Adresse oder die
Adressinformation 00, dann fehlen hier zwei Nullen aufgrund der Farbe,
00, 00 und 02 gepusht werden, auf den Stapel, auf den Stapel gelegt
werden.
Und da ist die Frage, fange ich hier von hinten an, diese Information
entsprechend auf in den Adressraum einzuschreiben oder von vorne.
Das muss eindeutig festgelegt werden, damit hier entsprechend der
Prozessor das auch wieder richtig interpretieren kann.
Und die Frage ist, das ist wiederum maschinenabhängig, in welcher Form
der Prozessor den Adressraum implementiert.
Es gibt ja die Möglichkeit, nach dem Big-Endian-Prinzip das Ganze zu
implementieren, im Gegensatz zu Little-Endian,
was bei uns beim 68.000er nicht der Fall ist.
Wir haben also hier die Big-Endian-Variante vor uns.
Das bedeutet, der höherwertige Teil unserer Information wird an die
niederwertige Adresse geschrieben.
Das bedeutet, wenn wir hier entsprechend die Information in blauer
Schrift noch festhalten,
dass wir bei dem niederwertigen Adressteil mit dem höherwertigen
Bereich unsere eigentlichen Adressinformationen anfangen.
Wir legen also hier beginnend mit dem 31.
Bit, oder mit dem 32., wenn man es hier vorne bis zur 1 durchzählt,
das legen wir an die kleinere Adresse und schreiben das quasi von dem
kleineren Adressteil zu dem höheren fort, sodass bei dem höherwertigen
Adressteil oder bei dem niederwertigen Adressteil der höhere Teil
unserer Information drin steht.
Also ist das einigermaßen nachvollziehbar.
Ich hoffe, aufgrund der Farben ist das klar.
Wir haben hier bei einer niedrigen Adresse, Sie wissen, der Adressraum
wird nach unten kleiner, den höherwertigeren Teil unserer
Adressinformation.
Umgekehrt bei Little Endian.
Das ist nochmal wichtig für das Verständnis zum Behandeln des
Adressraums.
Die Semantik von diesem Beispielbefehl Jump to Subroutine steht hier
nochmal beschrieben.
Dieser Sprungbefehl arbeitet also nicht anders als das hier zunächst.
Also das ist der Befehl, den wir semantisch beschreiben wollen.
Das ist entsprechend hier die Beschreibung dazu.
Der macht nichts anderes als MOV L, Program Counter und dann hier
entsprechend zählt ja den SP, Abkürzung für Stack Pointer,
entsprechend nach unten.
Und zwar um 4 Bytes, also der pusht die Adresse auf der nächsten
Instruktion, das ist also die Instruktion, die hier entsprechend auf
die der PC verweist, auf den Stack.
Dafür benötigt er 4 Bytes, weil wir hier Longword Adressierung
benutzen.
Und die Begründung dafür ist, da der PC-Counter also 24 Bit benötigt,
aber im Endeffekt auch wiederum aus 32 Bits besteht.
Also dementsprechend brauche ich hier diese 4 Bytes, um hier den
nächsten Befehl auf meinem Stack zu speichern, bevor dann der
eigentliche Jump ausgeführt wird.
Also ich könnte hier diesen JSR-Befehl entsprechend genauso
implementieren, wie er hier steht.
Die Frage hier unten ist trivial, also diese Abkürzung dient eben
dazu, dass ich hier komfortabler mein Programm spezifizieren kann.
Ähnlich ist dann der Rücksprung meiner Adresse oder zu meiner Adresse
durch den Befehl Jump oder Return vom Subroutine,
durch dieses RTS, das also ähnlich hier wiederum arbeitet, wie hier
spezifiziert.
Die Begründung hier wiederum liegt, ähnlich wie bei dem Jump-Befehl
vorhin, in der Größe des Programm-Counters.
Ganz kurz noch, der Systemstapelzeiger dient eben dem Betriebssystem,
entsprechend zur Verzeigerung auf dem Betriebssystemstapel.
Und dieser kann im Endeffekt nur genutzt werden, wenn dieses
sogenannte Supervisor-Bit gesetzt ist und ich damit ein Programm oder
eine Operation als Supervisor oder mit Supervisor-Rechten ablaufen
lassen kann.
So, ganz kurz noch hier die letzte Folie zum Systemstapel.
Wir haben hier also auch, ähnlich wie bei dem Nutzerstapel, den
Zeiger, der im Endeffekt hier entsprechend auf die Adresse in meinem
Adressraum zeigt.
Und als Hinweis wird eben benötigt, dieser Zeiger, um Exception
-Handling durchzuführen, also beispielsweise Exceptions Division by
Null oder entsprechende privilegierte Befehle im Systemmodus
durchzuführen.
Als Beispiel sind hier das Setzen der Memory Management Unit genannt.
So, ich denke an dieser Stelle sind wir für heute durch.
Bis zum nächsten Mal.
Da geht es dann bereits um die Assembler-Programmierung.
Ich würde Sie bitten, dass Sie vielleicht schon mal ein bisschen mit
dem Simulator rumspielen, um hier erste Erfahrungen zu sammeln.
Danke vielmals!