anmachen. Gut. Ja,
letzte Woche hatte ich ja quasi aufgehört mit letztendlich diesem Bild,
was ein bisschen motiviert, wo wir uns jetzt eben befinden.
Nämlich also quasi an der Schnittstelle jetzt von Hardware zu Software und das,
was wir jetzt in diesem Kapitel,
also jetzt diese Woche genau betrachten werden, ist dann eben das,
was wir so typischerweise dann als Instruction-Set Architecture bezeichnen,
beziehungsweise was ich jetzt hier also immer irgendwie dann so grob mit Befehlssatz übersetzt habe.
Was sind da eigentlich jetzt die typischen Merkmale, die jetzt also unterschiedliche Befehlssätze auszeichnen?
Zum einen erstmal generell sowas wie wortbreite Adressierungsmodi,
dann welche Art von Rechnerklasse handelt es sich?
Welche Register gibt es, wie werden die angesprochen?
Dann natürlich den eigentlichen Befehlsatz, also sprich das,
was also dann wirklich als Assembler-Code verwendet werden kann.
Also sprich die Art der Befehle, dort dann eben,
wie die aufgebaut sind, wie viele Operanten, wie die funktionieren.
Dann für die jeweiligen Befehle dann die Datentypen, wie die Daten dann,
also letztendlich gehandhabt werden und dann eben an der Schnittstelle eigentlich zum praktischen Betrieb,
also dann eben auch zum Betriebssystem, grob die Art und Weise,
welche Möglichkeiten gibt es jetzt eben, sowas wie Interrap zu behandeln,
wie sind da dann eben die Schnittstellen zu dem,
was dann eben letztendlich die Systemsoftware ist.
Wir werden jetzt hier im Laufe dieses Kapitels davon,
also sagen wir mal nur so einen groben Überblick bekommen,
also sprich generell, wie speicheradressiert wird, wie solche Befehlssatzarchitekturen aussehen können.
Im folgenden Kapitel werden wir dann am Beispiel des X86-Befehlssatzes dann ein bisschen was kennenlernen,
wo also dann auch nicht richtig jetzt Assembler-Programmierung,
aber zumindest so in Ansätzen,
grob gezeigt wird,
wie im Prinzip jetzt also Befehle aufgebaut sind und dann eben
von der darunter liegenden Hardware interpretiert und abgearbeitet werden können und da
dann eben auch noch ein bisschen was zu diesem Teil Darstellung der Daten beziehungsweise dann am Ende des folgenden Kapitels dann also ein bisschen zum Lademechanismus dann auch kennenlernen.
Gut, wie gesagt, also hier werde ich jetzt letztendlich
am Beispielen immer folgendes benutzen. Also wie gesagt,
X-86-Befehl ist das im folgenden Kapitel, ist eben das,
was eigentlich jetzt typischerweise in PC-Architekturen inzwischen eigentlich alleine dominantes System ist.
Beispiel eigentlich für einen klassischen Sisk-Befehlssatz, was Sisk ist
Folgt dann auch gleich noch in diesem Kapitel weiter.
Dann werde ich auch hier kurz immer noch mal ansprechen,
so was wie die Architektur von MIPS-Rechnern.
Das ist dann ein klassisches Risk-System. Wird uns dann später
auch noch weiter begegnen in dem Kapitel 16,
wenn es dann nämlich um Pipelining geht,
weil das eigentlich so das klassische Beispiel ist,
wie also Pipelining-Architekturen eigentlich funktionieren.
Und gut, im Praktikum wird dann also quasi hier dann
dieser Demo-Rechner zum Beispiel für so ein kleines Mikro programmiertes 16-Bit-System
dann immer genommen
Ansonsten, jetzt also weiter ins Detail eingehen, also sprich welche Befehlssitzarchitekturen gibt es, wie unterscheiden
die sich voneinander. Auch da muss man immer leider sagen,
wäre es schön, wenn man also irgendwie Rechnerstrukturen dann,
also jetzt nicht nur über ein Semester,
sondern über mehrere Semester halten könnte,
weil dann könnte man eben zum Beispiel auch nochmal sowas auf irgendwie so Armarrchitektur genauer darauf eingehen,
also das, was typischerweise im Mikrocontrollern verwendet wird.
So kann ich immer nur sagen, okay, also grundsätzlich so,
also hier grob die Konzepte vorgestellt werden und alles andere folgt,
also entweder in anderen Veranstaltungen oder wird dann noch entsprechend woanders angemacht.
Ja, hier auch nur noch mal kurz angedeutet. Also das,
was eigentlich, sagen wir mal, den Großteil von Rechnern oder Rechnerarchitekturen ausmacht.
Mich war also die meisten CPUs oder Rechenkerne sind nicht in
irgendwelchen Desktops oder Servern oder was weiß ich wo untergebracht,
sondern in irgendwelchen kleinen eingebetteten Systemen.
Und da so im Größenordnung mehr als das,
was also sonst alles an irgendwie rechnen oder so ausmacht.
Das, was ja auf dieser Folie grob dargestellt ist,
sind jetzt sag mal, also alles ein bisschen eltlichere Beispiele.
Nicht von daher stimmt das auch nicht mehr so ganz,
aber man sieht da eigentlich nochmal, also wie gesagt,
so eingebettete Systeme, nicht man kann man jetzt immer so sagen,
gut, also im normalen Kleinwagen ein bisschen Mittelklasse wagen,
habe ich so um die 80 bis 90 Mikrocontroller verbaut.
Wenn man so an das denkt,
was jetzt also so unter dem Stichwort Internet of Things,
Smart Home, was weiß ich was,
ist Kann man dann eben sagen, na gut,
also irgendwann soll es eben mal so weit kommen,
dass also wirklich jede Glühbirne also quasi einen eigenen Prozessor beinhaltet,
nicht und damit arbeitet.
Und das ist dann eigentlich die große Anzahl der Architekturen.
Das meiste davon sind dann natürlich extrem einfache Sachen. Also gut,
wie gesagt, hier sind das jetzt so ein bisschen,
ja, sagen wir mal, zumindest teilweise antiquierte Beispiele.
Ich höre es immer jetzt hier irgendwie so einen alten Nokia-Irgendwas-Knochen nimmt.
Das hat natürlich jetzt mit einem aktuellen Smartphone also auch nicht mehr so richtig was zu tun. Nicht aber das,
was hier eigentlich nur gezeigt werden soll, ist,
dass die eben von dem,
was er so früher mal so Telefonkarte war oder eben so als Mikrocontroller in so einer einfachen Haushaltsgerätesteuerung verbaut ist,
ihm von sehr einfachen kleinen 8-Bit-Controllern gehen kann,
bis zu ihm etwas komplexeren Systemen jetzt im Bereich Automotive oder eben auch vergleichsweise anspruchsvolle Anwendung,
also in einem Bereich der Medizintechnik, wo man dann sagen kann,
okay, da habe ich dann eben schon entsprechend komplexe Programme,
die dann dort also auch letztendlich irgendwo hinterlegt sind.
Ich habe harte Echtzeitanforderungen. Das heißt, wenn ich,
also jetzt ist irgendeine Bestrahlungsthomographen bzw. irgendeine Maschine da laufen lasse, dann ist das also lebensnotwendig,
dass das Ding also innerhalb einer bestimmten Zeit reagiert, auf bestimmte Eingaben bzw. eben die Stellwerte passend überwacht. Und ich habe in solchen Fällen dann eben auch entsprechend hohe Sicherheitsanforderungen,
also in Bezug auf sowohl Betriebssicherheit,
das heißt also diese gesamte Sache, Verlässlichkeit,
nicht dann aber eben auch Sicherheit gegenüber Störungen,
gegenüber Teilausfällen,
sowas wie eine interne Sicherheit oder Sicherung von Daten,
also irgendwelche Vertraulichkeitssachen,
die dann also zum Beispiel in der Medizintechnik dann logischerweise auch
noch mit drin sind und so war es alles und das sind dann eben wirklich so ein ganzer Zoo von sehr vielen sehr unterschiedlichen Anforderungen von jetzt eben wirklich irgendwelchen Wegwerfartikeln,
nicht wo also der Mikrocontroller, also maximal im Cent-Bereich kosten darf,
nicht bis zu irgendwelchen millionenschweren Geräten, wo man dann sagen kann,
okay, da ist natürlich kein Problem, dann also auch entsprechende anspruchsvolle Hardware einzubauen.
Gut, die entsprechenden unterschiedlichen Anforderungen, hat er ja schon gesagt, also wirklich sehr breites Spektrum. Das ist eben das,
was man dann eigentlich typischerweise dann so als eingebettete Systeme hat,
wo man dann auch sagen muss, gut, das ist,
wie man in diesem Beispiel ja auch schon sieht,
nicht so, dass man sagen kann,
ein eingebettetes System zeichnet sich dadurch speziell aus,
sondern das kann eben von einem ganz kleinen zitierten Controller gehen,
bis zu irgendeinem großen verteilten Netzwerk, was weiß ich,
jetzt also hier irgendwie die Kommunikation von GSM-Netzen, also untereinander vermittelt,
was dann also quasi über das gesamte Land verteilt ist,
wo man dann eben auch sagen kann,
da habe ich dann eben auch entsprechend unterschiedliche Anforderungen hinsichtlich,
nicht wenn es hier heißt, also Leistungsaufnahmen,
ja gut, das einzelne stationäre Geräte,
da ist mir die Leistungsaufnahme völlig egal,
wenn ich also jetzt hier irgendwie mal ein Smartphone nehme oder eben hier irgendwie so eine Sportuhr nicht,
dann will ich sagen,
okay,
das Ding soll eben mit möglichst wenig Leistung
möglichst lange laufen
Gut, wir bewegen uns jetzt aber hier eigentlich bei dem Bereich,
vor dem wir also in der Regel vor der Tastatur sitzen,
also sprich Computerarchitekturen, jetzt im Sinne klassischer Estore beziehungsweise Workstation-Rechner.
Das, was ich jetzt hier als erstes vorstellen werde,
ist also eigentlich alles, was jetzt unter diesem Begriff Speicherorganisation zusammengefasst werden kann.
Also da geht es einmal grundsätzlich um die Art der Adressierung,
dann welche Wortbreiten, welche Speicherkapazitäten ich habe, dann unter dem Stichwort Big Endian,
Little Andian, wie der Speicher oder Speicheradressen angesprochen werden.
Und abschließend wird dann also dieser Tal dann nochmal so ein bisschen mit dem Begriff der Memory Map motiviert,
wo es also darum geht,
wie man also typischerweise bei Computersystemen dann also letztendlich den Speicheraufbau gemacht hat,
muss ich jetzt also auch schon sagen,
weil, also wie gesagt,
bei aktuellen Betriebssystemen war ich das dann also doch wieder noch ein bisschen von dem ab, was dann also hier noch vorgestellt werden wird.
Gut, später, ganz am Ende der Vorlesungs,
werden uns dann noch,
was dann eigentlich auch noch zu dem Thema Speicher gehört,
Cash-Speicherwart wieder begegnen und virtueller Speicherkonzepte und was dann also im Zusammenhang mit Cash-Speicher dann auch noch interessant ist,
ist dann eben Synchronisation beim Multi-Prozessor-System.
Ich war also da ja auch da, das also Thema,
wo man gesagt hat, na gut,
früher war das Großrechnerbereich, inzwischen kann man sagen nicht,
also jeder poplige PC hat mindestens ein Vier-Kern-Rechner.
Was passiert jetzt, wenn jetzt letztendlich über Shared Memory Informationen zwischen den Prozessoren,
beziehungsweise zwischen Tasks auf den Prozessoren ausgetauscht werden soll.
Nicht der eine Prozessor veränderten wird. Was passiert,
wird der zweite Prozessor dann also quasi benachrichtigt, dass der Wert verändert worden ist.
Wann kriegt er das mit? Wie sieht das aus im
Zusammenhang dann eben mit der Sparcherhierarchie? Weil das,
wo die Prozessoren drauf arbeiten, ist natürlich dann auch nicht der Hauptspeicher,
sondern also im Sinne der Sparcherhierarchie dann also irgendein vorgelagerter Cash-Speicher.
Nicht, weil bis sie den Hauptspeicher zurückaktualisiert haben,
das dauert viel zu lange. Ich führt aber dazu,
dass also ein zweiter Prozess natürlich jetzt also erstmal nicht zwingend mitbekommt,
wenn Prozessor 1 jetzt in seinem Cash, also irgendein Datum verändert hat,
sondern dafür sind dann eben auch entsprechende Protokolle notwendig,
die dann eben genau dort die Kommunikation machen.
Und also auch das, beziehungsweise überhaupt erstmal auf die Problematik
wird dann also auch dann nochmal ganz kurz darauf eingegangen.
Gut, generell kann man sagen, was wollen wir mit dem Speicher machen?
Also zum einen wollen wir jetzt natürlich oder liegt in dem Speicher,
wenn ich jetzt also dieses klassische von Neumann-Konzept nehme,
also mein eigentliches Programm, also die eigentlichen Anweisungen,
also das, was gleich noch kommen wird.
Zum anderen werde ich dort ja also dann irgendwelche Zahlen, Zeichen,
Strinks, was auch immer, hinterlegen, also sprich alles,
was wir so in den ersten Kapiteln in Rechnerstrukturen kennengelernt haben,
wo es also im Prinzip irgendwelche Zahlendarstellungen oder beziehungsweise um irgendwelche Textdarstellungen und Codierungen gegangen ist.
Was dabei jetzt eben interessant ist, ist, dass man sagt,
na gut, also in der Regel wird Speicher,
wahrheitweise adressiert, zumindest im PC-Bereich ist das dann eigentlich
auch immer noch üblich
Meistens hat man dann die Daten immer als Vielfache davon. Nicht,
also sprich allein schon, weil ich dann natürlich größere Zahlen
als vielleicht den Wertebereich von minus 128 bis 127 ansprechen möchte,
dass ich da dann eben auch noch natürlich dann also entsprechend größere Zahlendarstellungen habe, beziehungsweise Fließkommerzahlen.
Also im Prinzip die A-Triple i 754 Formate haben wir
dann ja auch schon grob kennengelernt. Gut,
Was dabei jetzt aber natürlich ist, spare ich eine Badwaise adressieren,
der Speicher selber ist aber jetzt ja so als Rahmensspeicher irgendwie wortweise adressiert mit entsprechend breiteren Speicherwörtern.
Hier jetzt typischerweise erstmal mit 32 oder 64 Bit beschrieben.
Was sich daraus dann also für Konsequenzen ergeben, ist jetzt nämlich also das,
was jetzt hier gleich auf den vorhangenden Folien quasi noch kommen wird.
Nicht zum einen Da muss man sich jetzt erst mal fragen,
wie ist der Speicher generell organisiert, nicht?
Also hier jetzt ein Beispiel aus dem Buch von Tarnbaum und Austin,
wo man sagen kann, gut, also ich habe 96 Bit Speicher,
kann ich eben als zwölf mal acht Bit beschreiben,
als acht mal zwölf Bit oder als sechs mal 16 Bit,
nicht also jemals mit entsprechend unterschiedlichen Varianten,
das heißt also wichtig dann eben immer die eigentliche Speicherwortbreite,
wie gesagt,
hier in den Beispielen werde ich jetzt immer von
92 oder 34 Bit ausgehen
Wie gesagt, früher hatte man da also relativ krude andere Werte. Also in den Anfängen der Computertechnik,
also von wirklich einzelnen der Adressierung Einzelner Bits,
bis zu hier irgendwelchen 48 oder 60 Bit-Formaten,
was dann also, sagen wir mal so,
in den 60er Jahren von den Rechnern dann also immer irgendwelche,
sagen wir mal, selbstgebauten Fließkomma-Formate waren,
die dann also mit so komischen Wortlängen ankamen.
Wie gesagt, das, was wir heute eigentlich dann typischerweise immer noch haben,
was eigentlich auch eine Altlast ist, ist eben im Prinzip diese Byteweise-Adressierung,
die also PC-Bereich dann eigentlich üblich ist.
Gut, und was man da jetzt eben macht, ist,
dass man sagt, okay, ihr seht es hier bei badweiser Adressierung.
In der Regel habe ich als Speicherwortbreite vielfacher davon,
wie gesagt, also typischerweise inzwischen eigentlich 64-Bit-Adressen.
Man kann dann damit dann eben sehr einfach die Standarddatentypen,
die wir schon alle kennengelernt haben, dort abbilden.
Also sprich 8-Bit-Usky, irgendwie sowas wie Unicode oder OTF-Kodierung und dann eben hier die Floating-Point-Formate.
Und gut, hat dann eben je nach Programmiersprache da dann eben entsprechend,
also hier ist an dem Beispiel C, da dann eben wirklich jetzt seine passenden Datentypen.
Gut, was heißt das jetzt eigentlich für den Speicherzugriff? Also wenn ich mir jetzt vorstelle,
dass da noch nicht C die eigenen Speicher,
die die einzelnen Speicherzellen sein, jetzt jeweils immer beidweise adressiert,
wenn ich jetzt eben einen Speicher habe,
der also 32 Bit Worte beinhaltet, heißt es,
dass sich also quasi das erste Wort unter der Adresse null,
das zweite Wort dann eben unter der dresse 4,
8, 12 und so weiter, anspreche,
beziehungsweise wenn ich von 64 bin, speicher Wortbreite ausgehe,
habe ich dann eben jeweils zwischen zwei Speicherworten in meinen entsprechenden Adressoffsittern eben von 8 mit drin.
Gut, wie sieht das, diese Folie hatte ich relativ am Anfang,
beziehungsweise die nächste auch noch, relativ am Anfang schon mal aufgelegt,
also da geht es also auch nochmal so grob um die Datentypen,
die dann eigentlich so auf Maschinenebene drauf sind,
also Hier haben wir nochmal aus dem PC-Bereich jetzt also für die Programmiersprache C,
also so die üblichen Datentypen,
also Word ist aber dann eben eine Referenz auf eine Speicheradresse.
Da kann man jetzt eben sagen, okay, beim 92-Bit-System,
demzufolge dann vier Byte lang. Ich war der Intel-Architektur mit 32 Bitwortbreite,
auch Deck, Alpha war, sagen wir mal so,
die erste Architektur, die dann, also ein 64-Bit-System hat,
wie gesagt, heute haben wir X 86, 64,
was dann also hier dann also auch entsprechend mit 8 hätte.
Ansonsten ist das ähnlich. Also da gibt es dann eben
nur noch entsprechende Unterschiede jetzt, zum Beispiel bei solchen Darstellungen wie Long Double.
Generell muss man sagen, also mit solchen Datentypen,
wie groß sind die, was kann man damit abbilden.
Nicht diese Folie hatte ich ja auch schon mal drauf,
ist das Ganze letztendlich immer davon abhängig,
also auf welchem Prozessor bin ich,
mit welchem Compiler arbeite ich,
welches Betriebssystem habe ich laufen
Ist das in der Programmiersprache definiert? Da muss man sagen,
okay, in Java ist das das entsprechende Fest in der Sprache vorgegeben.
In C, was also jetzt hier mal untersucht worden ist,
gibt es da also wirklich entsprechend sehr starke Unterschiede,
eben teilweise auch wirklich schon abhängig davon, welchen Compiler ich benutze.
Das heißt also, der eine Compiler auf dem 32-Bit-System fällt,
sich eben jetzt anders als beim gleichen Betriebssystem dann also ein anderer Compiler.
Das heißt also, da Kann man dann auch immer nur sagen,
muss man sich dann eben wirklich im Zweifelsfall in die entsprechende Dokumentation dann nochmal jeweils einlesen, beziehungsweise gucken, wie das definiert ist. Gut,
bei vielen Sachen kann man auch sagen, ist,
also hier sieht das jetzt immer sehr grauslich aus,
ist es aber eben auch so,
also es gibt eben sowas wie Ansi, Standard, C,
also sprich Sandardisierte Sachen, wenn das dann also entsprechend eingeschaltet,
beziehungsweise unterstützt es, kann man natürlich auch ausgehen,
dass das also auf unterschiedlichen Systemen dann trotzdem immer noch einigermaßen kompatibel ist,
aber der Worst Case ist dann eben wirklich, dass man,
was man dann hier irgendwie so aus dieser Tabelle rauslesen kann,
also wirklich je nach Betriebssystemversion,
also mit den Datentypen dann eben entsprechend unterschiedliche Sachen ansprechen kann.
Gut, Wassern, auch schon mal ganz kurz angesprochen wurde,
was jetzt hier noch mal ein bisschen weiter vertiefe,
ist dann der Begriff der Indians, also der Byte Order. Da geht es darum,
wie jetzt also einzelne Byte innerhalb eines Speicherworts angeordnet werden,
also angenommen, wir haben 32 Bedaten, Typen,
entsprechend langen Indiger, wenn ich jetzt meine Werte weitweise adressiere,
geht es darum, Bei, aufeinanderfolgenden Speicheradressen, 0123,
unterspare ich Adresse Null, habe ich das höchstwertigste Byte,
meines 32 Bitwards und fange damit an zu lesen,
oder habe ich das niederwärtigste Byte meines 32 Bitwards.
Demzufolge habe ich da zwei mögliche Kombinationen,
werden dann in Anspielung auf Gullivers Reisen immer Big Andien und Little Andien genannt,
bei Big Andien System, was also im Prinzip,
also Früher ältere Workstation sind oder waren, also im Prinzip Sun,
Sun, Marcos System, das wurde dann von Oracle übernommen.
Inzwischen machen die also eigentlich eher, ja, war Software, Datenbanken natürlich.
Aber jetzt eigentlich keine Rechenarchitekturen mehr. War das ein typisches Beispiel,
Mac, muss man auch sagen, die älteren Macs,
also sprich als Apple noch eigene Prozessoren gebaut hat,
inzwischen mit X86 in Leben, sind das also auch Little-Andien-Systeme geworden.
Aber im Prinzip kann man eben sagen, okay,
Big Indian ist, dass ich also letztendlich mit dem Most Significant byte,
bei der niedrigsten Adresse anfange und dann eben zu den Least Agnificant Byte,
bei der höchsten Adresse gehe, bei Little Indian System,
das ist also das, was X686 Architekturen sind,
habe ich das eben genau umgekehrt.
Wie sieht das dann rein? Praktisch aus? Also hier haben wir jetzt,
also angedeutet im Prinzip mein 32 Bitwort. Hier wäre dann immer quasi höchstwertigstes Bit,
ihr niederwertigstes Bild beim Big-Andian-System würde ich quasi mit der Adresse null,
die höchstwertigsten 8-Bit ansprechen und unter der Adresse 3 dann eben
das niederwertigste Bite bei Little-Andian-System ist das eben quasi umgekehrt,
da fange ich mit der Adresse null quasi jetzt hier hinten
bei den niederwertigen Bits an und arbeite mich dann mit höher laufenden Adressen und eben nach vorne hin.
Letztendlich kann man sagen, Je nachdem,
also ob ich Stringbearbeitung oder Zahnbearbeitung mache,
kann mal das eine, mal das andere System Vorteile haben.
Woher ergeben sich jetzt diese Unterschiede nicht? Also zum Beispiel bei Zahlenbearbeitung,
wenn ich jetzt zwei Zahlen miteinander vergleiche und quasi vom Most Significant Byte anfange zu lesen,
kann ich im Zweifelsfall natürlich schon nach dem ersten Byte entscheiden,
wie ob die Zahlen größer oder kleiner sind
Little-Anion-System müsste ich das dann eben entsprechend anders machen.
Also das ist dann immer die Art und Weise,
wie dann, also die Bearbeitung, also vielleicht günstiger ist.
Auf der anderen Seite hat man da dann eben vielleicht auch wieder einen Nachteil.
Also letztendlich nimmt sich das nichts, beziehungsweise wird dann eben entsprechend umgerechnet.
Hier sieht man das jetzt also nochmal als Beispiel.
Also ich habe jetzt hier als Zahl 15.213. Wäre Hexadezimal 3b6D
und auf Little-Andien-System würde ich dann quasi hier mit der niedrigsten Speicheradresse
dann eben genau die 6D stehen haben mit der zweiten Speicheradresse
dann eben die 3B und die beiden oberen Waldwehren nicht benutzt bei Big Indian System ist es dann quasi entsprechend genau gedreht.
Hier sieht man dann eben auch nochmal, nicht gut,
hier habe ich jetzt ja immer nur die Nullen stehen,
wenn ich also quasi jetzt aus dem ganzen Zweier-Kompliments-Zahn mache,
nicht, dass ich dann eben entsprechend dann da dann natürlich meine Vorzeichenerweiterung habe,
das heißt, dass sie nicht benutzten,
es werden dann also entsprechend zu F bzw. FF
dann jeweils
Gut, hier ist nochmal so ein praktisches Beispiel,
was ich ja so inzwischen nicht mehr vorführen kann,
vor ein paar Jahren konnten wir das noch machen,
weil da hatten wir noch irgendwie so ein paar Artestanzen in Betrieb,
in C programmiert, also im Prinzip eine Datenstruktur,
wo ich also hier zwei Indiager-Werte habe und hier also irgendwie ein String einer fixen Länge,
ich weiß, kein schöner Code,
weil so kann man wunderschön also irgendwelche Pufferüberläufe sich da rein programmieren,
aber gut, So würde jetzt hier also irgendwie mal statisch initialisiert mit irgendwelchen Werten,
nämlich also dem Alter von dem Angestellten, also mit 23 und seinem Jahresgehalt von 50.000 Quiumble und ihm irgendwie seinen Namen.
Und wenn man das jetzt also entsprechend übersetzt,
in diesem Fall jetzt sind es 32-Bit-System, X86-Architektur,
wo ich eben ein Little-Andian-System habe, dann sieht man also,
dass hier quasi beispielsweise bei dem Gehalt,
also die ist C350 quasi hier in der Objektdatei,
dann nämlich also quasi von diesem Rekord 5.0,
dann kommt C3 und dann kommen eben die beiden nicht belegten Wahls,
also hier die Nullen stehen,
wenn ich das Ganze jetzt also hier für ein 32-Bit auf einer 32-Bit-Sun übersetzt habe,
sieht man also hier genau an dieser Stelle eben sehr schön,
wie das Ganze dann eben entsprechend dann immer beidweise dann getauscht
worden ist und ich dann eben hier mit dem Big
Andian Format quasi hier mit dem höchstwertigsten Wald anfange und dann
mich dann eben entsprechend so weit durcharbeite
Gut, bei Strings sieht man bei beiden Systemen Würdern,
also letztendlich das gleich behandelt werden. Gut,
in der Regel muss man sich um sowas natürlich nicht kümmern,
weil glücklicherweise müssen wir uns also in den seltensten Fällen irgendwelche irgendwelchen SML-Code bzw. irgendwelchen Datenstrukturen wie näher ansehen.
Es sei denn, man will jetzt also irgendwie sowas wie Computerforensik machen oder so. Also da ist sowas dann schon mal wieder ganz interessant. Nicht,
also da kann man sagen, okay,
das fällt in der eigentlichen Außencompiler raus, wo sowas noch interessant ist,
auch das hatte ich ja schon mal kurz als Beispiel genannt,
ist vor diesem Hintergrund der Network-Bart-Order,
wo im Prinzip bei der Datenübertragung nach dem IP-Protokoll,
nämlich ein Big-Andien-Format quasi zum Einsatz kommt und alle Rechner,
die also intern quasi mit Little-Andien ihre Zahlen darstellen,
wenn die eben entsprechend übertragen werden,
werden die dann also in das Big-Andien-Format umgerechnet.
Dafür gibt es dann Also hier wäre jetzt also die Art und Weise,
wo das also jetzt hier bei irgendwelchen Unix-artigen Systemen steht,
dann eben irgendwelche Hilfsfunktionen oder Markus,
die das dann also hier beispielsweise jetzt für einen C-Compiler dann also quasi breitweise umswappen,
wo ich dann eben sowas habe, wie Funktionen,
Network to Host und Host to Network,
was eben in die eine oder in die andere Richtung das konvertiert.
Und wenn ich jetzt eben auf einem Big-Andian-System arbeite,
Während diese Funktion quasi leer definiert, wenn ich auf einem Little-Andian-System arbeite,
wird da dann im Prinzip dann also hier sowas wie so ein Bye-Zwap gemacht.
Also dieses Beispiel hatte ich ja relativ am Anfang der Vorlesung dann schon mal,
als es da so um die Beidweisen-Operationen ging,
also sprich dies baldweise schieben,
beziehungsweise hier mit diesem Bedweisen oder mit dieser Bedweisen- oder Verknüpfung,
wo man dann also im Prinzip also mit diesen Ausdrücken
dann immer die entsprechenden Bytes ausschneidet,
verschiebt und dann wieder passend zusammensetzt
Gut, hier auch nur ein Beispiel,
also aus dem Buch von Brian, unseren Hellerrand,
wie man eben auch jetzt für sein eigenes System,
also quasi hier diesen C-Code nehmen könnte,
also nochmal in ein Hauptprogramm verpacken müsste,
das Ganze dann übersetzen, ausführen lassen kann,
da könnte man sich dann eben jetzt hier für irgendein Argument,
also eine Double-Zahl, die dann also wirklich beidweise ausgeben lassen,
auch da würde man dann also sehr einfach sehen,
wie das eigene System dann eben entsprechend da arbeitet.
Was in dem Zusammenhang dann eben auch noch interessant ist,
was passiert bei sogenannten Missalline zu griffen, Weil ich habe ja gesagt,
wir haben letztendlich ja die Situation der Speicher ist irgendwie jetzt Wortweise adressiert,
beispielsweise jetzt bei 34 mit Speicherwortbreiter,
habe ich eben die Adresse 08 1624 und so weiter.
Wenn ich jetzt eben ein einzelnes Speicherwort adressiere und dort also irgendwo ein 64-Bit-Wert untergebracht habe,
kann ich natürlich sagen, ja gut,
also im Idealfall gehe ich ja erstmal davon aus,
der belegt eben genau ein Wort und gut ist.
Jetzt habe ich ja gesagt, in x686 Architektur ist es eigentlich so,
dass man Speicher breitweise adressieren kann. Das heißt, es kann eben sein,
dass also hier irgendwelche Datenstrukturen oder irgendwas liegen, was,
also in dem Speicher quasi hier die, diese Bereiche,
also irgendwie belegt und dieses 64 Bitward dann eben beispielsweise bei der Adresse 12 anfängt und sich dann physikalisch gesehen über zwei Speicherworte erstreckt.
Demzufolge, das ist eben das,
woraus sich dann eben auch diese Begriffe ergeben,
kann man dann eben unterscheiden zwischen Aligned wo im Prinzip die Datenstrukturen
eben auch an den Speicherwortgrenzen ausgerichtet sind und eben nicht aligned,
wo die dann eben irgendwie jetzt verschoben sind.
So, Frage ist jetzt, was passiert eben jetzt bei solchen Nicht-Alarm-Zugriffen?
Im Prinzip in der X86-Architektur kann das richtig gehandhabt werden, wird in der Regel dann eben auch automatisch umgesetzt. In anderen Rechnerarchitekturen ist das das überhaupt nicht zulässig. Nichtsdestotrotz ist es eben auch so,
meistens das, was man an Programmen hat,
das, was man also auch an Programmen erzeugt,
werden die Speicheradressen schon irgendwie aligned und man riskiert,
sage ich mal, jetzt lieber irgendwo Verschnitt,
also sprich hier ungenutzte Speicherbereiche, als jetzt zu sagen,
ich lege jetzt wirklich jedes einzelne Byte,
wenn ich jetzt also wirklich kleine Datenstrukturen habe,
die also jetzt nur irgendwie als Charakter ein Byte belegen,
hier in ein Wort und das nächste Byte hier, weil,
wie gesagt, bei solchen Nicht-Alien-Sachen habe ich dann eben nachher das Problem,
dass ich, also um dieses Wort zu lesen,
also eigentlich zwei Speicherzugriffe physikalisch machen muss.
Früher wäre das, sagen wir jetzt auch noch ein bisschen mehr Problem gewesen heutzutage,
geht sowas dann also auch in der Speicherhierarchie,
das heißt in einem Cash unter,
weil dieser Zugriff auf den Hauptspeicher dann eben eigentlich in größeren Blöcken,
also irgendwo im Cash landet und dort dann erst auseinandergenommen wird,
Ja, aber der Worst Case ist halt eben,
wenn ich jetzt also von diesem ganzen einfachen, von Neumann Paradigma ausgehe,
dass ich als ich adressiere jetzt eben wirklich direkt nur den Hauptspeicher,
dann habe ich eben hier wirklich jetzt also das Problem,
dass ich, um ein Wort zu lesen,
zwei Speicherzugriffe machen muss.
Nächstes Thema in Bezug auf die Speicherorganisation ist dann eigentlich das,
was ich jetzt hier immer irgendwie so unter Memory Map angesprochen habe.
Da muss man jetzt ja auch sagen, gut,
also die CPU kann in der Regel eigentlich erstmal entsprechend der Wortbreit im gesamten Adressbereich ansprechen.
Früher bei 32-Bit-Systemen waren das vier GB.
Jetzt bei 64-Bit-Systemen ist das deutlich mehr Speicher,
als man überhaupt als Hauptspeicher irgendwo in seinem Rechner verbaut hat.
Und im Zweifelsfall also auch noch deutlich mehr Speicher als das,
was dann vielleicht noch irgendwie als Auslagerungsdatei auf der Festplatte rumliegt.
Das heißt, in der Regel muss man immer davon ausgehen,
dass ich eigentlich erstmal keinen voll ausgebauten Speicher habe
Nun ist es ja immer so,
für den Programmierer ist der Speicher ein linearer Adressraum,
der fängt irgendwo bei null an und hört bei, ja,
nicht zwei Hochwortbreite minus eins, byte auf. So,
ob das Ding jetzt physikalisch ein Rechner vorhanden ist oder was da passiert,
das ist dann eigentlich immer noch außen vor und das ist dann eben das,
wo dann also letztendlich Compiler und Betriebssystem dann eben noch dazwischen setzen und eben irgendwann nur sagen,
okay,
der Speicher ist mir ausgegangen und das Programm kann dann eben
nicht mehr weiterlaufen
Oder, ja, das ist dann eigentlich das, was dann also letztendlich passiert. Und er im Stichwort Memory Map ist hier jetzt aber eigentlich noch ein bisschen mehr gemeint,
als jetzt nur die Sichtweise des Programmierers,
weil das wird uns dann nachher noch ein bisschen in dem Kapitel dann zur Speicherhierarchie begegnen,
sondern da geht es jetzt also auch noch mehr um die Sache,
wie jetzt, also generell der Speicher unterteilt wird im letzten Kapitel,
hat ja schon mal an diesem Beispiel Armarchitektur angesprochen,
dass man also typischerweise gesamten Speicherbereich dann immer noch mal irgendwie unterteilen kann in sowas wie RAM und RAM-Bereiche,
nicht also Teile,
die dann also letztendlich jetzt für Betriebssystem bzw. irgendwelche Sachen dort fest vorgegeben sind,
was man eben auch typischerweise hat,
um jetzt überhaupt erst mal so ein Anfahren bzw. das Buden des Prozessors hinzubekommen.
Eine andere Sache,
was dann eigentlich auch immer über den Hauptspeicher abgewickelt wird,
ist dann sogenanntes Memory Map IO,
weil da geht es darum,
dass ich sage,
ich möchte an meinen Rechner jetzt
irgendwelche ein Ausgabegeräte anschließen
Jetzt kann ich natürlich sagen, gut,
ich beschränke mich auf Tastatur,
Maus und Monitor und für jedes dieser,
ein Ausgabegeräte definiere ich mir jetzt in meinem Befehlssatz spezielle Befehle,
wo ich sagen kann, lese von der Tastatur ein Zeichen.
Lese von der Maus, meinetwegen,
wie viel sie jetzt innerhalb der letzten so und so
viel Zeit in X und Y Richtung sich bewegt hat
Kann man machen, kann man auch also direkt so in
einem Befehlssatz implementieren. Ist aber natürlich fürchterlich unflexibel,
weil das, was wir eigentlich heutzutage gewohnt sind,
also ich nehme jetzt also irgendeinen USB-Gerät,
stöpsel das dran und habe dann eben nochmal ein zusätzliches ein Ausgabegerät.
Also ich habe dann also hier einen Printer,
da einen Scanner, mache also irgendwie jetzt also auf einmal
über USB dann also nochmal irgendeine andere Videoausgabe mit auf.
Netzwerkschnittstelle und,
und, und
Da kann man jetzt natürlich nichts sagen. Ich erwarte jetzt
mal eben hier nochmal den Befehlssatz, so ein paar neue Befehle.
Deswegen wird das dann typischerweise so gemacht,
dass man also ein- und ausgabegeräte quasi auf Speicheradressen abbildet,
die halt sonst nicht benutzt werden,
weil das Speicher oder ich ja einen entsprechend großen Adressraum habe.
Und ich dann eben sagen kann, okay,
wenn ich jetzt also von der Tastatur was lesen möchte,
lese ich einfach von der und der Speicheradresse und dahinter verbirgt
sich dann aber eben eine entsprechende Controller bzw. einen Ausgabeschip,
der dann also quasi die Tastatur abgefragt hat
Guten Schreiben auf diese Adresse wäre in dem Fall dann also irgendwie witzlos.
Also das wäre dann also auch Sinn des Betriebssystems dann,
also nur sowas wie so ein Read-Only-Device, beziehungsweise red Only-Speicher.
Nicht, also das ist eigentlich das,
was dann unter dieser Idee des Memory-Waped-IO dann eben dahinter steht.
Gut, das Ganze passiert rein praktisch dann eben auch durch irgendwelche Hardware-Einheiten, die dann also letztendlich diese Adressen übersetzen. Also ich hatte ja schon mal dieses Beispiel in der letzten Woche,
also von dem Armprozess, wo man auch sagt,
okay, also ich habe jetzt hier meinen Rammspeicher,
ich habe hier irgendwie einen Rom-Speicher bei 32-Bit-Wort-Breitet,
wird das jetzt eben hier irgendwie aus vier solchen acht-Bit-Blöcken zusammengesetzt und ich verzweige dann einfach nur aufgrund der Adressen,
die hier rausgehen,
entweder in diesen Speicherbereich oder in diesen Speicherbereich und rein praktisch passiert das dann eben hier bei diesem Adressdecoda,
wo ich dann eben sage, hier nehme ich das höchstwertigste Bitte-Adresse,
nämlich also Adressbitt 31 nicht und wenn ich das wenn das jetzt eben hier beispielsweise dann null ist, dann spreche ich hier eben das Rom an.
Nicht, dass es dann diese Negierung, wenn das eins ist,
dann spreche ich eben das Rahmen an und bin dann eben quasi in einem anderen Speicherbereich.
Und bei den eigentlichen Speicheradressen für Ramo und Rom
taucht dieses Bit dann eben letztendlich dann nicht mehr auf.
Also das ist, damit hat man dann zwar seinen Speicherbereich,
also einmal komplett halbiert, andererseits,
wenn ich jetzt also nicht wirklich diese großen Speicherbereiche brauche jetzt für mein kleines eingebettetes System,
kann man damit also wunderbar leben und Conbrand,
also es ist relativ einfach zu streichen.
Gut, wie sieht so ein Memory Map-System aus? Nicht also,
wie gesagt, ein Beispiel wäre dann also die Art und Weise,
wie das so in reiner Strukturenpraktikum genutzt wird, nicht?
Da habe ich eben auch 16 Bit-System,
64K Adressen kann man damit unterscheiden,
nicht und dort wird dann eben auch unterteilt, Amazon Rom-Bereich,
RAM-Bereich für einen Hauptspeicherrahmenbereich jetzt für irgendwelche Tale des Betriebssystems und
eben irgendwelche IO-Bereiche die dann eben eigentlich auch auf Memory Map abgebildet sind.
Hier, wie das Ganze einmal in der Praxis ausgesehen hat,
Windows 9X, also Windows 95 maximal.
Beispiel für ein 32-Bit-System. Ich kann also vier Gigabyte adressieren.
Und dort wurden halt die Adressen letztendlich so verwaltet, dass man gesagt hat,
okay, hier in dem Oberen Gigabyte habe ich im Prinzip mein Betriebssystemkern rumfliegen.
Dann habe ich hier Das nächste Gigabyte,
da sind halt gemeinsam genutzte Bibliotheksfunktionen, beziehungsweise ja,
Bibliotheksfunktionen in dem Fall dann eigentlich mit abgelegt und beziehungsweise Tali,
die dann eben von allen Anwendungen gemeinsam genutzt werden,
bin ich also bei Windows-Systemen sind das dann zum Beispiel eben diese typischen DLLs,
Dana McLink Libraries,
die dann also dort dann also reingemappt werden.
So,
und dann gibt es eben irgendwo so einen Bereich von knapp 2 Gigabyte,
was dann eigentlich für die Anwendung benutzt werden konnte,
das heißt also jedes Anwendungsprogramm konnte dann eben
knapp 2 Gigabyte mit ansprechen
Mhm. Ja, also rechts habe ich das,
also links war die Grafik, die ich also im Prinzip,
also aus dem Buch müsste jetzt irgendwie lügen,
ich glaube Tarnbaum oder irgendwas, stimmt,
da habe ich also jetzt das Zitat passend vergessen.
Rechts habe ich dann meinen Text, also eigentlich Gibbi, weil,
wie gesagt, also gerade bei solchen Hardware-nahen Sachen rechnet man natürlich mit zwei Appotenzen.
Das heißt also,
demzufolge sind das dann immer 2048 die dann eben entsprechend beziehungsweise dann in dem Fall dann,
also nicht also das, was dann dort angesprochen wird,
also umgangssprachlichen geht man da ja dann immer doch sehr unsauber vor und nimmt dann einfach nur GB oder Gigabyte oder so,
aber eigentlich sind das also GB da mit drin.
Also letztendlich ergibt sich das ja also hier schon also aus den entsprechenden Adressen, wenn man das jetzt also nehmen würde. Gut,
und dann gab es eben historisch dann hier unten noch,
also irgendwo so im Bereich,
der ist dann also noch irgendwo so aus Zeiten,
86, 86, 8 Bit, erster EBM-PC,
wo ich dann also sowieso, also nur deutlich weniger überhaupt adressieren konnte,
war es dann also im Prinzip, wenn also hier in diesem Bereich war,
wo dann also hier noch so ein bisschen Boot-System und sowas dann also mit rumlag.
Gut, was man sich also damals bei Windows 95 dann also auch immer noch so mit angucken konnte,
ist also dann letztendlich, also irgendwo in der Systemsteuerung,
wie das Ganze dann also ein bisschen aufgeteilt war,
also im Prinzip so ein Zugriff oder Zuteilung von Speicherbereichen dann eben zu dem,
wo dann eben diese gesamten Memory-Map-Sachen rumlagen,
wo man eben sieht, also im Prinzip,
also hier PCI-Boss, Grafikkarte, irgendwie die entsprechenden Komponenten,
also hier dann also irgendwas vom Chipsatz,
wurden dann eben immer auf bestimmte Adressen bzw. Adressbereiche des Systems
quasi abgebildet
Je nachdem, wo man dann dort ist,
hat man dann eben einmal diesen ganzen System nahen Bereich,
dann hier dann irgendwie dann sowas wie serielle Schnittstelle und so weiter,
wo dann eben zum Beispiel dann die ganzen einen Ausgabegeräte dann mit drin sind und so weiter.
So, das Ganze wurde dann typischerweise vom Bios des Rechners
geregelt bzw. verwaltet. Gut, inzwischen muss man sagen,
ist das also bei aktuellen Betriebssystemen wird das dann eben vom Betriebssystem Colonel dann eben auch entsprechend vergeben.
Andererseits natürlich bei den aktuellen Bereichsbereichen habe ich da jetzt also nicht mehr so das Problem war,
dass man sagen muss,
also je nach Zahl der Geräte, fast voll ausgenutzt,
sondern das kriegt man also jetzt bei 64-Bit-Systemen natürlich problemlos hin.
Gut, hier auch noch mal so grob als Teaser.
Ich hatte, war ich jetzt immer irgendwie davon schon spreche,
Speicher, Hierarchie und Cash und was ist das alles?
Wie gesagt, unter Speicherhierarchie, hier die Grafik auch von
Brian Onno Halleran. Nicht,
also zum einen habe ich in der CPU in meinem Rechner
jetzt also irgendwelche Register auf die ich entsprechend schnell drauf zugreifen kann,
nämlich mit vollem Prozessortakt.
Dann hat man, also hier jetzt an beispielsweise Level One-Level Two-Cash,
nicht dann den Hauptspeicher. Dann gibt es Lokan-Hintergrundsspeicher,
also Festplatten oder SSDs und eben Remote-Speicher, also irgendwas,
was übers Netzwerk bereitgestellt wird.
Also sprich über irgendwelche Protokolle
NFS, Samba oder was auch immer man sich da jetzt ausdenkt,
also irgendwelche Netzwerkspeicher,
der dann eben noch irgendwo extern letztendlich rumliegt und das Ganze bildet dann eben insofern eine Pyramide,
dass man sagen kann, okay, hier bin ich entsprechend schnell,
hier bin ich entsprechend langsam mit dem Speicher,
habe dafür dann aber immer größere Speichermengen zur Verfügung,
die also auch immer deutlich weniger kosten und der Trick von dem Ganzen ist halt eben,
damit das Ganze eben vernünftig funktioniert,
dass ich eben hier von meinem langsamen Speicher,
also sprich beispielsweise von der Festplatte,
entsprechend große Bereiche in den Hauptspeicherlade und von dort an eben auch immer gleich möglichst große Bereiche,
dann eben hier quasi in meine Cash-Hierarchie mit rein,
um dann eben wirklich zu sagen,
wenn ich jetzt also auf irgendwelche Werte drauf zugreife von meinem Register,
dass ich das dann eben möglichst passend dann also hier dran finde.
Was hier also auch noch drinsteht, nicht also Onship,
Level One Cash, of Ship Level 2 Cash,
auch da muss man sagen, das ist also irgendwie,
also auch wenn das also in der aktuellen Ausgabe von 2015
ist nicht mehr so ganz aktuell.
Also inzwischen ist man also typischerweise bei Mehrkernsystemen,
bei drei Cash-Ebenen und die sind eigentlich inzwischen auch schon alle Onship.
Das ist also noch irgendwie so aus der Zeit. Ja,
ich sag mal, Mitte der 90er oder Ende der 90er Jahre,
als im Prinzip First-Level-Cash noch,
also in der CPU drin war und der Rest irgendwo auf dem Motherboard verbaut.
Deswegen heißt es You Onship und Offship Cash.
Ein bisschen genauer werde ich darauf dann also noch in dem
entsprechenden Kapitel zur Speicherhierarchie drauf eingehen,
deswegen also dazu später mir
Nicht, also das, was dann aber eben letztendlich also die Schwierigkeit ist,
also das ist dann eigentlich das,
was ich hier nur noch mal kurz motiviert werden soll,
ist im Prinzip bei dieser Sache mit dem Cash.
Ich habe hier meinen langsamen Hauptspeicher, habe hier jetzt also irgendwelche Strukturen,
die mir da also jetzt irgendwie die Information oder die Daten
in den schnelleren oder in den noch schnelleren, noch kleineren Cash entsprechend irgendwie transferieren.
Dadurch, dass ich natürlich Von meinem Programm eigentlich sowieso erstmal
mehr Speicher ansprechen kann, als überhaupt hier verbaut ist.
Ich dann aber im Prinzip jetzt mit meinem Cash,
also davon also auch nur, immer nur einen kleinen Abschnitt abbilden kann,
ist natürlich dann also das Problem oder steckt mal so vor der Schwierigkeit, welche Daten packe ich in den Cash.
Und da kann man jetzt sagen, ja gut,
also idealerweise natürlich, dass, wenn ich jetzt sage,
also ich arbeite ein Programm ab,
war es dann quasi der nächste Teil Assembler Code ist,
der dann also irgendwie jetzt mit den nächsten paar Befehlen irgendwo angesprochen wird,
wo man dann aber schon sagen kann, ja,
was passiert denn jetzt, wenn ich also irgendwie Sprünge mache,
wenn ich Unterprogrammaufrufe habe, sind die dann auch nach dem Cash.
Und das ist dann eben genau der Grund,
wo man dann sagen kann, okay,
da gibt es dann eben auch unterschiedliche Cash-Strategien, also sprich,
welche Werte hole ich da rein, wie verfahre ich mit Daten,
was passiert, wenn ich in Kontext wechsel habe,
das heißt also irgendwie jetzt mein Programm,
mal das Red unterbrochen wird,
irgendwas anderes auf dem Prozess so weiterläuft.
Dann irgendwann ist der Cash fall, was schmeiße ich raus?
Und da kommen dann eben so die Problematiken,
wo man dann auch sagen kann, ja, Kontextwechsel,
das Programm läuft nicht mehr, schmeiße ich raus,
nicht dann dauert das also vielleicht ein paar Takte, dann soll es weiterlaufen.
Jetzt sind aber seine Daten aus dem Cash gerade rausgeschmissen worden.
Also da kann man dann eben auch entsprechend viele unterschiedliche Strategien fahren,
die sich dann eben auch teilweise ein bisschen immer widersprechen und das ist dann eigentlich die große Kunst beim Entwurf von Rechnerarchitekturen,
dass eben irgendwie so aufeinander abzustimmen und so zu einem Gesamtpaket zu bringen,
dass man sagen kann, ich kriege eben wirklich so eine maximale Overall-Performance.
Nicht, dass man eben sagen kann,
also wirklich für alle Arten von Anwendungen, wenn ich jetzt,
also bei so einem General-Purpose-System, wie es also irgendwie so ein Desktop-Rechner bin,
bei allen Arten von Anwendungen funktioniert das eben ähnlich gut bzw. ähnlich schlecht.
Sind wieder ganz andere Anforderungen als eben einige Sachen,
die ich also beispielsweise bei eingebetteten Systemen habe,
wo ich dann eben sagen kann, okay,
wenn ich da irgendwie was Zeitkritisches habe, dann will ich jetzt nicht sagen,
mach den Durchschnittsfall möglichst gut, sondern will ich sagen, okay,
Wenn irgendein Prozess nach so und so viel Millisekunden auf irgendein Ereignis reagieren muss,
weil er beispielsweise dann eben irgendwie das ESP in meinem Auto steuert,
dann nützt es nichts,
wenn das also in 90 Prozent der Fälle vernünftig funktioniert,
sondern da muss sich eben wirklich diesen Worst Case den einen Fall,
der da rausfällt, auch noch irgendwie gerade hinbringen.
Und das sind dann wieder ganz andere Optimierungskriterien. Da würde man
dann eben auch wieder mit anderen Strategien jetzt rangehen und sagen,
na gut, also mit Cash mache ich immer diesen Durchschnittsfall gut.
Das bewährt sich so bei Standardcomputerarchitekturen. Ich habe gerade bei
vielen anderen Sachen Echtzeitbetriebs- oder Echtzeitssysteme, ist also Cash dann eigentlich auch schon eher umstritten.
Gut, welche Arten von Cashes es gibt,
wie abgebildet werden, wie die funktionieren,
wie man jetzt also aus irgendwelchen Programmadressen überhaupt erstmal herausfindet,
ist das hier im Cash, ist das hier im Cash,
ist das im Hauptspeicher.
Das wird dann eben alles später auch zumindest kurz im Prinzip vorgestellt.
Gut, ja, Speicher ist nicht unbegrenzt, hatte ich
entsprechend soweit eigentlich alles schon beschrieben. Also was hier vielleicht noch wichtig ist, nicht Fehler, die auf den Speicher verweisen, sind da also entsprechend besonders gefährlich. Das ist also eigentlich das,
wo man auch sagen muss,
da widersprechen sich dann eben auch schon wieder so ein bisschen die Konzepte,
wo man sagt, also das, was ich jetzt hier vorstelle,
ist immer der ganz allgemeine Fall von Neumann-Architektur,
gemeinsamer Speicher für Programme und Daten, linearer Adressraum und,
und, und, wenn ich ein aktuelles modernes Betriebssystem habe,
eine entsprechende Prozessor-Architektur, dann möchte ich im Sinne der Sicherheit von Daten,
also sprich, ich habe hier irgendwie meinen Prozess laufen und irgendein anderer Prozess,
der jetzt also vielleicht also irgendwie vom Webbrowser heraus gestartet wurde durch irgendeinen Unachtsam eingestelltes Applet,
soll jetzt also vielleicht nicht an meine Passwortverwaltung rankommen,
die also vielleicht auch gerade auf einem Rechner läuft,
dass da dann eben so Konzepte drin sind, wie kriege ich Speicherbereiche gegeneinander abgeschottet, wie kriege ich das hin, dass die Programme dann eben nicht in andere Programmteile kommen oder ein Betriebssystem teile kommen.
Das führt dann dazu, dass eben rein technisch gesehen meistens,
dass also eben auch so läuft, dass,
also dieser lineare Adresseum, wie ich ihn jetzt hier vorstelle,
so auf dem Rechner dann eben auch nicht mehr eins zu eins so abgebildet wird,
sondern gibt es dann eben auch so Techniken, wie also irgendwie Adressverwürflung,
wo dann eben bestimmte kleine Teile generiert werden und das dann eben über den Adressbereich verstreut wird,
sodass eben Programme dann also auch nicht raten können und sagen, okay,
in dem und dem Adressbereich liegt Betriebssystem und wenn ich also irgendwie das schaffe,
dort also irgendwie das und das anzusprechen,
wenn ich also auf einmal in irgendwelchen Privilegierten Routinen,
mit denen man da also irgendwie beliebigen Unsinn machen kann.
Also das sind dann immer so ein bisschen die Sachen,
wo, sagen wir jetzt, diese grundlegenden Konzepte, ja,
sagen wir mal von 30 Jahren Historie dann also inzwischen doch schon wieder überholt worden sind.
Und inzwischen, also die Situation da also teilweise deutlich komplizierter ist.
Nichtsdestotrotz muss man sagen, okay, also das,
wenn man das jetzt wirklich genauer betrachten möchte, dann,
ja gut, würde ich sagen, brauch ich mal an ihm entsprechend.
Also irgendwie Vorlesung zu Betriebssystemen,
beziehungsweise irgendwie in einem Bereich der Sicherheit bei uns,
wo dann sowas, also teilweise auch noch mitgemacht,
nicht fuhr das Ganze dann eben so ein bisschen mit angesprochen wird.
Also dass jetzt hier nur zu diesem Punkt
Gut, ja, und ja, Speicherleistung ist nicht leicht bleibend.
Ich hatte eben schon gesagt, also Cash ist eben eigentlich
vor dem Programmierer verborgen und letztendlich transparent. Das heißt also,
ich habe meinen Code und der sollte eigentlich genauso aussehen,
egal ob ich jetzt auf einem System bin mit dem und
dem Prozessor und zwei Cash-Ebenen oder einen Prozessor von einer Konkurrenz,
wo das also irgendwie ganz anders organisiert ist.
Nichtsdestotrotz haben natürlich, also im Prinzip teilweise diese Cashes beziehungsweise
diese Grundideen von Wörtelmspeicher,
also schon Auswirkungen auf die Performance
Man kann eben immer,
und das ist eigentlich immer das Gemeine, irgendwie so,
sag ich mal, irgendwelche bösartigen Beispiele konstruieren,
wo man also mit geeigneten Datenstrukturen und Zugriffsmustern auf diese Daten,
also dafür sorgen kann,
dass also letztendlich der Cash sich dann also irgendwie ausbremst und dass
das System dann also wirklich entsprechend eine ganze Zeit lang gut läuft und dann also wirklich plötzlich Performance-Einbrüche hat.
Also da sieht man schon, wie das Speichersystem dann eben auch die entsprechende Geschwindigkeit beeinflusst.
Im Idealfall. Deswegen sage ich, brauchen wir uns darum nicht kümmern.
Ist das aber etwas, wo man sagen kann, okay,
dafür habe ich hoffentlich einen vernünftig programmierten Compiler, der,
wenn ich das jetzt eben für eine X86-Architektur und die da noch ein bisschen genauer spezifiziere, übersetze,
dann eben solche Effekte vielleicht dann eben entsprechend schon mit berücksichtigen kann.
Gut, also alles Weitere zu diesem Stichwort Speicher-Cash,
folgt dann eben letztendlich im Kapitel 18. Gut, das,
was ich dann heute eigentlich jetzt noch,
beziehungsweise diese Woche dann noch genauer vorstellen werde,
ist dann eigentlich die Eigenschaften jetzt also von diesem Befehlssatz wieder aufgebaut ist.
Dazu komme ich erstmal nochmal zu dem Das ist eine Abarbeitung
von den Befehlen, also diesem klassischen Befehlszyklus.
Dann werde ich ein bisschen was zu den unterschiedlichen Arten von Befehlen sagen.
Und dann eben nochmal so auf Adressierungsarten eingehen. Gut,
Befehlszyklus können wir uns eigentlich immer an diesem ganz primitiven von Neumann-Konzept
klar machen, wo wir dann sagen, okay,
ich habe gemeinsamen Speicher für Daten und Instruktionen.
Ich habe sowas wie ein Programmzähler
Wo ich dann weiß, okay, in meinem Instruktionsspeicher,
die Instruktion möchte ich jetzt abarbeiten,
dessen Adresse steht also demzufolge im Programmzähler, der adressiert den Speicher,
die Instruktion wird geholt, landet Demonstruktionsregister.
Dort wird dieser Befehl dann eben entsprechend dekodiert. Das heißt also,
dieses Bitmoster wird dann eben nicht als Zahl oder als Tal eines Drinks interpretiert,
sondern das ist jetzt in meinem Befehlssatz in meiner Instruction-Set Architecture
eben ein Maschinenbefehl oder ein Teil davon
Wird dann ebenentsprechend ausgeführt. Anschließend wird dann eben dieser Programmzähler
passend inkrementiert und der nächste Befehl ausgeholt. Das heißt,
generell brauche ich in der Art und Weise dann also schon mal mindestens diese beiden speziellen Register, nämlich Program-Counter und Instruktionsregister. Dann typischerweise eigentlich noch,
wenn ich jetzt bei minimalen Register setzen bin,
sowas wie ein Akkumulator, rein praktisch das,
was wir dann eigentlich immer sehen oder kennenlernen,
werden hier auch in sämtlichen Beispielen,
ist dann also wirklich so eine ganze Registerbank,
wo ich dann eben quasi in der im Operationswerk des Reichners,
also sprich, neben der Alu dann eben den ganzen Satz von Registern,
also typischerweise irgendwelche Zweierpotenzen quasi,
also hier in diesem Beispiel jetzt 32 Stück,
irgendwie als Reichsneugister zur Verfügung habe.
So, und wie sehen jetzt diese einzelnen Phasen dieses Befehlszyklus aus?
Erster Teil wäre eben Instruction Fetch, das heißt Befehl holen.
Dazu habe ich dann eben im Programmzähler die Speicheradresse, lese vom Speicher
Das Ergebnis landet im Instruktionsregister und der Programmszähler wird inkrementiert,
das kann gegebenenfalls dann auch noch später passieren. Nicht,
das heißt, wenn ich jetzt so einen einfachen Befehlssatz,
Röstbefehlssatz habe, 32 Bit, Wortbreite, 32 Bit,
Befehle, nicht dann würde ich ihm hier sagen,
in so einer memo,
memonischen Notation,
dass Instruktionsregister,
da landet eben
der Wert vom Hauptspeicher
Und dann eben entsprechend vom Befehlszähler adressiert.
Und anschließend wird dann eben der Befehlszähler um vier inkrementiert,
weil in diesem Fall ich jetzt also hier bereitweise rechne,
32 Bit-Wort, Breite, nächste Speicheradresse wäre dann dem zuvor genannt plus vier.
Gut, bei Cis-Befehlen gibt es jetzt eben breites Sammelsurium an Befehlen,
wo ich dann eben nicht nur die Befehle genau ein Maschinenwort lang habe,
sondern eben auch vielleicht kürzer, vielleicht aber auch deutlich länger.
Demzufolge kann es eben sein,
dass man also nur ein Teil des Befehls,
also jetzt gelesen hat und anschließend dann eben noch mehr Speicherzugriffe machen muss,
um jetzt eben noch weitere Teile des Befehls zu lesen.
Das ist aber dann letztendlich ja dann wirklich jetzt
genau von der Architektur und vom Befehlssatz abhängig. Gut,
zweiter Schritt in dem Befehlszyklus wäre dann also die Instruktion zu dekodieren,
Voraussetzung, der Befehl steht jetzt also im Instruktionsregister.
Ich dekodiere das Ganze, sage jetzt, okay,
mit den und den Witz interpretiere ich so.
Und daraus werden dann letztendlich irgendwelche Steuersignale an irgendwelche Funktionseinheiten angesprochen,
beziehungsweise, wenn ich also bei solchen Mikroprogrammiertensystemen bin,
wie man das so jetzt zum Beispiel in dem Rechnerstrukturenpraktikum gemacht wird,
würde man da dann eben in den entsprechenden Mikropoker oder auf die entsprechenden Mikroprogrammadresse springen.
Das, was dann häufig an dieser Stelle dann auch noch
mit passiert,
ist dann eben Operan Fetch
Wird typischerweise gerade bei Rissrechnern dann eben auch in dieser Instruktionsdekot-Phase gemacht.
Ich war, hier habe ich jetzt also meinen Obcode und
es stehen ihm vielleicht auch schon drin, welche Operanten.
Also jetzt quasi in der, für irgendwelche Allo-Operationen benutzt werden sollen.
Demzufolge werden die dann eben schon an dieser Stelle geholt.
Nicht Barcisk gerechnet und kann das dann eben teilweise auch noch anders aussehen.
Aber letztendlich wäre da dann also der nächste logische Schritt dann eben die Operanen zu holen,
sofern es sich da dann jetzt eben irgendwelche Befehle handelt,
die dann also damit arbeiten.
Gut, dann kommt eben der Tal Execute-Ausführung von den Befehlen.
Der Befehl steht im Register, der die Coda hat,
die Operanen, den Opkut entschlüsselt. Die Steuersignale liegen an den Funktionseinheiten,
also beispielsweise es soll jetzt eben von der A- und Addition gemacht werden.
Demzufolge wird dann also quasi an den entsprechenden Eingängen der A-Ran
eben schon irgendwie multiplexermäßig das Ganze so eingeschaltet,
dass dann eben diese Addition gemacht wird.
Nicht dann wird quasi diese Operation ausgeführt. Und wenn das
also nicht schon ganz am Anfang gemacht wird,
wird dann eben der Programmzähler gesetzt, beziehungsweise inkrementiert.
So, warum kann es vorteilhaft sein, den Programmzähler an
dieser Stelle zu inkrementieren, anstatt das hier zu machen?
Wenn ich als Befehl sowas wie bedingte Sprünge habe,
sieht das typischerweise so aus, dass ich sage,
wenn also beispielsweise der Inhalt eines Registers gleich null ist
So, und dieses Ermitteln, Inhalt eines Registers ist
gleich null passiert, rein technisch gesehen, als Alu-Operation.
Das heißt also, an dieser Stelle nicht. Und demzuvor
kann ich dann eben erst nach diesem Instruction Execute entscheiden,
soll, inkrementiert werden. Das heißt, der nächste Befehl
normal ausgeführt werden oder habe ich eben bedingten Sprung.
Das heißt, soll der Befehlszähler jetzt mit irgendeinem anderen Wert geladen werden?
Also letztendlich ist ein bedingter Sprung ja nichts anderes,
als dass ich jetzt eben nicht den nächsten folgenden Befehl nehme,
sondern sage,
in irgendeinem ganz anderen oder gehe um irgendein Offset nach vorne oder nach hinten und hole dann dort den entsprechenden Befehl.
Nicht deswegen hat man meistens dann diese Ausführung quasi dann erst im Bereich dieser Execute-Phase. Gut,
letztendlich ist das aber dann wirklich vom Befehlssatz konkret abhängig,
wie das Ganze rein praktisch aussieht,
wie dann auch die Ausführungszeit von dem Ganzen ist.
Also das, was ich jetzt immer beschreibe,
ist also wirklich immer so
einzelne Schritte
Dieses Befehlsaberwartungszyklus. Später beim Pipelining werden wir dann kennenlernen,
dass man das Ganze dann also wirklich überlappend machen kann,
mit mehreren Befehlen gleichzeitig in der Abarbeitung. Diejenigen,
die jetzt also gerade in rechner Struktur im Praktikum,
also jetzt quasi mit der Aufgabe 4-0 irgendwie angefangen haben,
werden dann ja also auch schon festgestellt haben, gut,
dort ist das Ganze dann also eigentlich noch weiter entzerrt,
nämlich über diese Mikroprogrammierung in dem Raum,
Mikroprogrammierung hatte ich ja am Ende des letzten Kapitels auch schon kurz vorgestellt,
was sich dahinter verbirgt.
Das heißt, jeder Teil hier beziehungsweise jeder Schritt hier kann im Zweifelsfall
dann eben auch noch mehrere Prozessortakte beziehungsweise mehrere Teilschritte umfassen.
Nicht, das ist dann eben das, was dann hier
dann als mikroprogrammierte Realisierung dann eben auch noch mit angesprochen ist.
Alternativ dazu kann ich das Ganze dann eben auch fest
vertraten beziehungsweise eben jetzt irgendwie anlassen als endlichen Automaten realisieren
Gut, wenn man sich jetzt die einzelnen Befehle ansieht, was braucht man generell?
Da kann man erst mal so grob unterteilen in einige Befehlsklassen.
Also ich brauche irgendwie sowas wie arathmetische Operationen, also Additionssubtraktionen,
inkrementieren, dekrementieren, Multiplikationen, die Visionen, gut,
da kann man sich schon drüber streiten,
ob man das braucht,
weil das kann ich ja zur Not also auch über Unterprogrammtechniken auf Additionen bzw. so Traktionen und Schieberoperationen abbilden.
Gut, ist eben auch wieder davon abhängig nicht.
Also habe ich den Cent-Rechner eines A8 mit eingebetteten Systems
zur Verfügung oder habe ich also hier irgendeinen hochradig elaborierten,
mehr Kernrechner, also irgendeinen Agnes aktuellen Desktop-Systems oder sowas.
Gut, dann logische Operationen, also diese ganzen BIT-Visen,
logischen Operationen, Schieberoperationen. Nicht, dann braucht man typischerweise
noch sowas wie irgendwelche Vergleiche, also Equal Greater,
Lestern, wie auch immer die jetzt genau aussehen mögen.
Nicht, da hat man häufig explizite Befehle für Datentransfers,
wo ich eben sagen kann,
ich möchte von einer Speicheradresse in ein Registerladen beziehungsweise vom Register
wieder auf eine Speicheradresse zurückschreiben, also Load and Store.
Und sofern ich nicht mit Memory-Map-IO arbeite, dann immer noch
spezielle Ein- und Ausgabebefehle. Nicht, dann braucht man so
für einen Programmfloss, Jump. Unbedingt der Sprung,
dann irgendwelche bedingten Sprünge, also was wie Jump Eakle,
vielleicht Mehrfachverzweigung, Branches,
unter Programmaufrufe,
Call and Return
Also da kann man sich dann eben auch einen
ganzen Satz von Befehlen für so eine Befehlsatzarchitektur ausdenken.
Wie gesagt, einiges davon werden wir dann im nächsten Kapitel
bei der Assembler-Programmierung, ist beim X86-Befehlsatz ganz kurz kennenlernen.
Und da kann man auch irgendwie sowas mit hinzunehmen,
wie irgendwelche Befehle, die ich brauche,
um jetzt also den Ablauf auf dem Rechner zu steuern,
Interradbehandlung,
irgendwelche Ausnahmebehandlungen,
was auch immer
Gut, das erstmal nur grob unterteilt als Vorstellung,
welche Arten von Befehlen man grundsätzlich braucht,
wie die dann aussehen können, wie die abgearbeitet werden.
Wird jetzt im Weiteren dann also in diesem Kapitel noch
ein bisschen weiter erläutert. Da geht es dann eben auch
ganz am Ende dann nochmal so ein bisschen darum,
wie sie das generell jetzt mit Befehl setzen aus.
Also ich hatte die Begriffe hier also auch schon öfter.
Zisk, komplexe Instruction, Set Computer oder Risk Reduced Instruction
Set Computer
Da werde ich dann ganz am Ende noch kurz drauf eingehen. Ich inzwischen muss man sagen,
also das, was wir hier machen, lernen, das,
was ich jetzt also vorstelle, auch an den Beispielen,
auch wenn es eigentlich, also eine Cisco-Maschine ist,
wird eher sowas in Richtung Riskbefehl setzen und Abarbeitung sein. Das,
was, sagen wir mal, Ende der 90er Jahre,
also immer noch für heiße Diskussionen bei den Computerarchitekten gesorgt hat,
ist inzwischen insofern, also auch schon wieder obsolet geworden,
weil man jetzt sagen kann, okay,
also inzwischen ist das eigentlich so ein munteres Mischmarsch,
weil wenn man sich die Befehle, der X-86-Architektur beispielsweise ansieht,
ist es eigentlich ein klassischer Risk, Cisk-Befehlsatz,
mit sehr komplexen Befehlen, mit sehr fummeligen Adressierungsmöglichkeiten,
Zugriffen auf den Hauptspeicher und so weiter.
Rein praktisch, wenn man sich das ansieht,
was eigentlich der Compiler inzwischen daraus macht, sind das eigentlich eher klassische Load Store,
Befehlssequenzen, das heißt also von den gesamten Befehlen wird,
also nur ein kleiner Teil genommen und das jene dann eigentlich eher einem Riskbefehlssatz.
Auf der anderen Seite wurden Gerade für solche Sachen wie Multimedia-Verarbeitung,
beziehungsweise dann eben für solche Eigenheiten, hatte ich auch schon gesagt,
in einer aktuellen, oder in aktuellen CPUs,
da habe ich ja nicht nur eine einzige Recheneinheit und bearbeite nicht nur einen Befehl,
sondern ich habe eben auch teilweise, nein,
nicht teilweise,
sondern rein praktisch dann eben deutlich mehr Recheneinheiten zur Verfügung.
Man kann die entweder automatisch ablaufen lassen, wo dann eben
quasi immer so ein gesamtes Befehlsfenster untersucht wird, Wie sind Datenabhängigkeiten?
Was kann ich auf welche Rechnern einen verteilen? Es gibt
aber auch explizit sowas wie Very Long Instruction Word Befehle,
also sehr lange Befehle, mit denen ich also auch als Programmierer explizit,
also wirklich sämtliche sechs Indiger-Recheneinheiten meines Prozessors,
in einem Befehl ansprechen kann,
was also beispielsweise bei vielen Multimedia-Algorithmen,
also dann zum Beispiel sinnvoll ist,
weil man da
entsprechend effizient mitarbeiten kann
Ja, das, wie gesagt, also Befehlssätze wird dann also nachher
noch so ein bisschen und mal grob auf diese Unterteilung eingegangen.
Gut, wie sieht das jetzt überhaupt erst mal aus mit der Befehlsdekodierung? Ich hatte gesagt,
also ich habe Befehlsregister, also irgendwie den aktuellen Befehl,
also wenn wir jetzt also bei so einem kleinen 32-Bit-System sind,
habe ich da also irgendeinen wilden String aus Nullen und Einsen.
Und das, was da ja passieren muss, ist,
wie interpretiert die Hardware jetzt diesen Wert?
Das kann ich natürlich sagen, gut,
also hiermit kann ich dann also 2 hoch 32,
minus 1, unterschiedliche Befehle beschreiben.
Würde dann aber heißen, dass sich also eine entsprechend große Tabelle haben müsste.
Nein, also nichts, nein, logischerweise 2 auf 32, sorry.
Anträge haben müsste, also eine entsprechend große Tabelle haben müsste,
in der er nachguckt. Das will man natürlich nicht,
sondern das, was man typischerweise macht, ist,
dass man jetzt eben diesen Befehl in Bereiche oder in Felder unterteilt,
wo ich dann eben sagen kann, also einige Bits von denen, unterscheiden eben zwischen der Arthur-Operation.
Nicht mache ich jetzt hier irgendwelche Allo-Operationen oder mache ich Vergleichsoperationen oder bin ich bei Datentransfers? Nicht,
dass da komme ich dann eben beispielsweise vielleicht mit 5 Bit,
6 Bit, wie viel auch immer,
von meinem Befehlswort aus,
um dort,
also quasi jetzt diese Befehle zu unterscheiden und der Rest sind dann eben irgendwelche Argumente von den Befehlen,
nämlich wenn ich jetzt also zum Beispiel eine Allo-Operation mache und sage,
nimm den Inhalt von Register 2 addiere dem zum Inhalt von Register 4 und speichere das Ergebnis in dem und dem Register,
dann habe ich eben hier in irgendwelchen Bits dann eben entsprechend einfach die Indizes beziehungsweise die Adressen von diesen Registern drin oder noch irgendwelche anderen Meta-Informationen.
Nicht dem zufolge dann eben die Aufteilung in solche Felder und letztendlich
wird dann also über mehrere kleinere Look-up-Tabellen oder irgendwelche Hardware-Maßnahmen entsprechend unterschieden,
wo man ist.
So, das führt dann eben dazu, dass je nachdem,
wie so ein Befehlswort dann eben zerstückelt wird,
man dann eben von unterschiedlichen Befehlsformaten spricht
Nicht, also Grundidee, hier ist es nochmal aufgezeichnet,
so ein bisschen farbig, nicht, also dass man sagt,
also ein Parbit brauche ich dann eben für diesen Ob-Code.
Ein paar Sachen nicht. Nicht hier,
wenn ich jetzt zum Beispiel sowas habe,
nehme irgendeinen Emediate-Wert und schreibe den in einen Registern.
Dann habe ich eben hier wirklich einfach eine,
wenn auch jetzt kleinere Indiger-Zahl stehen und kann eben sagen,
die soll eben in das Register geschrieben werden.
Typischerweise das, was dann eben mit diesen Feldern passiert,
ist Ob-Code,
Art der Alo-Operation,
Indiziehung von Registern
Speicheradressen oder eben direkt irgendwelche Emilietwerte.
Das heißt also wirklich jetzt also irgendwie direkt Enterger beziehungsweise,
ja, Enterger-Werter in Form von zwei Kompliment oder Unsight-Darstellung.
So, wie das Ganze dann also wirklich konkret aussieht,
wie die miteinander verteilt sind, dass es dann eben wirklich
von der Prozessorarchitektur beziehungsweise von dem dort eigentlich zugehörigen Befehlssatz dann eben abhängig.
Gut, Beispielarchitekturen, wie gesagt, das,
was ich jetzt hier noch so ein bisschen vorstellen werde,
ist dann als eben Beispiel für so eine 32 Petrisk-Architektur.
Also jeder Befehl ist genau 32 Bitt lang. Es gibt
da eigentlich auch nur drei Befehlsformate, die also auch wirklich
sehr einfach und sehr stringent gehalten sind und entsprechend aufgebaut sind.
Im Rechnerstruktur- und Praktikum haben wir dann ja also auch in Form von einer 16-Bit-Architektur,
dann so ein relativ einfaches Befehlsformat, also bei diesem Deko-Prozessor.
Und im nächsten Kapitel werden wir dann also ein bisschen was zur Assembler-Programmierung dann eben noch kennenlernen werden,
werde ich dann eben nochmal so ein bisschen NTL X-86-Architekturen nehmen,
wo man dann eben sagen kann, okay,
das ist eben so ein Klasse, klassischer Cis-Befehlssatz,
also vergleichsweise irreguläre Struktur, sehr viele unterschiedliche Formate.
Und das Ganze geht dann eben so, dass ich also Befehle habe,
die also wirklich nur ein einziges Byte groß sind und welche,
die dann eben 36 Byte umfassen.
Gut, einfachstes Beispiel an eben sowas für so eine MIPS-Architektur.
Ich habe ein festes Befehlsformat. Ob Code hat bei allen Befehlen
dann eben auch wirklich nur eine einzige Breite, sechs Bitch,
nicht dem zufolge, kann ich dann also 64 Befehle nur unterscheiden.
Es gibt dann eben ein Format für Alu-Operationen,
die dann auch immer nur auf Registern stattfinden können und es
gibt dann eben noch zwei Formate für Sprünge bzw. für Emediate-Operationen,
nicht was dann eben als I bzw. als J
für Jump letztendlich beschrieben wird
Da, wie gesagt, das,
was sie jetzt hier immer anspreche, Mips, ist ein Akronym,
was dann für Microprocessor with out interlocked Pipeline Stages gilt,
wurde Anfang der 80er Jahre an der Universität Stanford von den Herren Hennessey und Patterson entwickelt,
die da also dann auch als, sagen wir mal so,
mit die Koryphäen in dem Bereich der Rechnerarchitektur,
dann also auch relativ viele sehr gute Lehrbücher geschrieben haben.
Habe ich dann also auch immer hier demzufolge
relativ häufig dann auch irgendwo in der Literaturliste
mit drin
Mips ist eigentlich immer das, was man wirklich so als klassische 32-Bit-Riskalarchitektur nimmt. Nicht,
weil die also wirklich sehr einfach aufgebaut sind, also das,
was heute die meisten Mikrocontroller einsetzen, also die Armarchitektur,
hat da also schon etwas kompliziertere Befehlsformate, auch gerade dadurch,
dass sie dann eben auch noch mit unterschiedlichen Wortbreiten arbeiten kann,
weil da gibt es also einen Befehlssatz,
der jetzt also für sehr kleine Systeme ausgelegt ist und relativ wenig Speicher braucht,
der dann quasi komprimiert ist, das nennt sich daran,
also Samplefehlsatz,
während also Wenn ich jetzt also einen leistungsfähigen 64-Bit-Arm-Prozessor nehme,
wird, also irgendwie einen aktuellen Smartphones verbaut wird,
habe ich natürlich dann also auch wieder ganz andere Leistungsanforderungen und vielleicht jetzt also nicht irgendwie die Speichereinschränkung von irgendeinem kleinen Mikrocontroller-System,
wo man dann eben auch wieder jetzt entsprechend andere Befehle,
Befehlsätze zur Verfügung hat.
Gut, aber einfachster Rissbefehlssatz ist eben als Beispiel dann immer
dieser Müpselfehlssatz, wie gesagt, also sowohl Speicherwortbreite,
als auch eben alle Formate, sind immer 32 Bit breit.
Es gibt genau 32 Register, letztendlich eigentlich nur 31,
weil ein Register ist konstant null,
fragt man sich auch, was soll denn der Unsinn?
Weil eigentlich ist es gar kein Register,
weil in Hardware wird da natürlich nichts für eingebaut.
Kann man aber ganz gut, zeige ich gleich auf der nächsten Folie,
also für einige Rechenoperationen und entsprechende Tricks mit verwenden.
Und das ist eben die klassische Load-Store-Architektur. Das heißt,
um den Hauptspeicher anzusprechen, es nur genau zwei Operationen,
nämlich aus dem HauptspeicherInnen Register lesen und aus dem Register in den Hauptspeicher zurückschreiben.
Mehr nicht. Und alles, was Alu-Operationen sind,
also sämtliche Rechenbefehle, gehen eben nur von Register zu Register.
Im Gegensatz dazu bei CIS-Befehl setzen, beziehungsweise im ganzen Allgemeinen Fall,
kann ich natürlich auch sagen, hohle Operant A, A,
Ihre Operant B und schreibe das Ergebnis irgendwo hin und alles drei sind Hauptspeicheradressen.
Das heißt, mit einem Alu-Befehl brauche ich dann also
drei Hauptspeicherzugriffe
Nicht. Das ist dann aber eben ein anderes Paradigma,
das ist dann eben das, was eigentlich,
also ursprünglich mal nach dem, ich sag jetzt mal,
alten von Neumann-Prinzip eigentlich eher ausgerichtet ist,
was dann eben so klassische X86-Architektur beziehungsweise an eben Spielern,
eben die gesamten Cisca-Architekturen gewesen sind.
Bei diesen Load-Store-Architekturen eben wirklich nur laden und speichern und
alles andere findet auf Registern statt.
Das ist eben sehr allfarbefehlsatz mit drei Adressbefehlen,
das heißt, ich kann bei den Allo-Operationen immer genau
drei Register mit ansprechen und ja
Es ist eben vergleichsweise erstmal primitiv aufgebaut. Nicht also auch in Bezug auf das,
was dann also irgendwie an komplexeren Befehlen oder Sachen da mit drin sind,
wird dann in der Regel über irgendwelche Unterprogramme mitgemacht.
Gut, wie sieht da das Registermodell aus? 32 Pitt Register.
Eins ist konstant null. Kann man aber eben nutzen,
um zu sagen, okay, wenn ich also eine Zahl negieren möchte,
die in einem Register ist, also sprich R5 soll zugewiesen bekommen, minus R5.
Ich kann nicht das eh machen, Subtraktion R5,
R0 R5. Ich war es dann also letztendlich rechnet, er null,
konstant null, minus R5 und das Ergebnis landet in R5. Deswegen,
da ist das Ganze nicht.
Wenn ich ein Register auf null setzen möchte, auch ganz einfach, Addition,
R0 und R0 und das Ganze landet in einem Register,
wenn ich hier irgendwie sowas wie ein Emediate generieren möchte.
Ich brauche keine speziellen Befehle für Emediates,
sondern ich kann das über ein Ad-Imedian machen, wo ich dann einfach sage,
Null plus meinen Imediate-Wert und das landet in einem Register,
nicht dienst zuvor gebraucht, weil jetzt also keine speziellen Befehle um Load mit Imediate zu machen.
Also das sind so Sachen, die die,
die sich da so irgendwie haben einfallen lassen,
wofür das also mit dieser konstanten Null und bei diesem kleinen Buffetsatz dann eben ganz sinnig ist.
Was dann dort auch noch so eine Besonderheit ist, ist,
es gibt eben keine separaten Statusflex, also bei einer Strukturen in dem Dekor,
gibt es ja also quasi aus dem Alu,
irgendwie sowas wie ein Fleckregister, wo ich dann eben sage,
habe ich außen irgendwo einen Überüberlauf, was man dann eben braucht,
um eben sowas wie bedingte Sprünge oder irgendwie sowas zu machen.
Hier sieht das dann eben so aus,
dass man dort bei irgendwelchen Vergleichsoperationen im Prinzip einfach nur das Zielregister auf null oder auf eins setzt und dann eben abhängig von dem Inhalt dann eben beispielsweise springen kann,
was dann also über so ein Set Les Dan Befehl nicht,
also das heißt, da wird eben quasi gerechnet, er 2 minus R3,
letztendlich geguckt ist das Ergebnis negativ und wenn das negativ ist,
wird er eins eben auf eins gesetzt, wenn nicht,
blöd ist also auf null gesetzt und letztendlich in memonischer Schreibweise,
wo dann eben letztendlich diese Operation dann ausgeführt werden.
Also das ist dann eigentlich so das,
was es bei diesen Mips-Register-Modell dann dahinter steht.
Gut, Ja, letzte Folie für heute. Mips Befehlssatz,
wie gesagt, Details finden sich also in den Büchern von Petters and the Tennessee,
Computer Organization and Design, The Hardware Software Interface.
Davon gibt es also auch eine deutsche Version. Dort wird dann also,
wenn sie das also irgendwann später mal brauchen sollten,
also auch die entsprechende Hardwarestruktur relativ gut und genau erklärt.
Nicht ansonsten ist das dann eben ein typisches Beispiel eigentlich für so ein Pipelining-System,
wo man dann eben quasi diese einzelnen Stufen dieser Befehlsabarbeitung holen, dekodieren,
ausführen, Speicherzugriff, beziehungsweise Schreibt Zugriff von Ergebnissen inneres Register, dann eben in so eine Pipeline parkt.
Gut, alles andere, dazu folgt dann entsprechend später,
das soll es ja vor heute gewesen sein und dann bis Freitag,
letzten Termin vor Weihnachten