Ja, dann willkommen zur Vorlesung.
Semester nähert sich so langsam dem Ende.
Diese Woche und nächste Woche, dann ist es schon irgendwie vorbei.
Aber das passt wunderbar.
Mit unserem Staff kriegen wir auf jeden Fall bis dahin locker durch.
Wir hatten angefangen uns anzuschauen letztes Mal Busse, wie Busse
funktionieren.
Also es gibt zehn Millionen verschiedene Busse und alle funktionieren
ein bisschen anders, aber so grob, ja, so vom Konzept, was für
Möglichkeiten es gibt.
Und im Detail muss man immer nachschauen, welchen man gerade wirklich
vor Augen hat.
Das gucken wir uns nochmal kurz an.
Danach kommt noch ein kleines Kapitel mit dem Bus noch nicht ganz
durch, wie man dann quasi externe Peripherie anschließen kann.
Dann haben wir noch Systemsteuer-Schnittstellen-Bausteine, also im
Sinne von Kommunikation.
Also was ist auf der anderen Seite von dem Bus?
Auf der einen Seite ist der CPU, dann kommt der Bus und was gibt es
denn danach so?
Das wären so Systemsteuer- und dann noch Ausnahmebehandlung und dann
wäre dieses Kapitel fertig.
Ja, was wir schon gesehen hatten, es gibt drei verschiedene Arten, wie
diese Bus- Protokolle funktionieren können.
Es gibt Synchrone, Semisynchrone, Asynchrone.
Drei gucken wir uns kurz nochmal in den Bildern an.
Die Synchronen waren einfach nur, dass es quasi immer einen Buszyklus
gibt.
Das ist so ein Konzept, gibt es bei allen und der ist hier aufgeteilt
in zwei Phasen.
Das wäre hier die erste und zweite Phase A und B.
Die könnten halt einen halben Takt lang sein, die könnten noch länger
lang sein.
Das ist halt unterschiedlich.
Zumindest ist in die Idee häufig, dass in der einen Phase irgendwie
gesagt wird, hey, Gerät am anderen Ende des Busses, ich will was von
dir.
Hier Adresse und hier Anforderung.
Anforderung könnte halt eben sein, schreiben oder lesen.
Wenn schreiben, dann gleich mit Daten vielleicht.
Also unterschiedlich.
Und die zweite Hälfte wäre dann die Reaktion von dem Gerät, die dann
sagt, gut, hab es erledigt, falls es schreibend war oder gut, hier
sind die Daten, die du von mir lesen wolltest.
Und dann gibt es eben Unterschiede, ob halt eben auf welchen der
Flanken das Ganze funktioniert.
Hier wird offenbar bei der fallenden Flanke von dem Gerät an der
anderen Seite des Busses die Adresse und die Anforderungen
entgegengenommen.
Schreiben wird offenbar erst bei der steigenden Flanke.
Hier hinten werden die Daten wirklich übergeben.
Im Fall eines Lesens kommen sie da schon zurück von dem angesprochenen
Gerät, dass man dann die Details immer im Einzelnen nachschauen muss.
Das waren die Synchronen, die Semisynchronen-Busse.
Ich habe mal zwei Varianten von gesehen.
Springen wir gleich zu der zweiten Variante davon, der etwas
flexiblere.
Er hatte die Idee, dass eventuell nicht immer alle Geräte gleich
schnell sind und dann mal gucken muss, dass entweder alle genauso
langsam sind, wie das Langsamste.
Das ist aber auch nicht gut.
Oder man langsame verbietet.
Das ist auch nicht gut.
Also verschieden schnelle Zugriffsgeschwindigkeiten möchte man zu
supporten und verschieden schnell, auch bitte in der Version von
Variabel verschieden schnell, also mal so schnell, mal so schnell.
Wie macht man das?
Man führt ein neues Signal ein, das Ready-Signal, die Peripherie sagt,
wenn sie fertig ist.
Gucken wir uns einfach an dem Beispielbild an.
Zum einen haben wir jetzt wieder unseren Buszyklus hier oben, der hat
seine zwei Teile A, B und dazwischen können noch Wartezyklen eingebaut
werden, nämlich so lange, bis die Peripherie fertig ist.
Und die eine Variante von dem Semisynchron war noch, das muss nicht
unbedingt nur konstant irgendwie ein halber Takt sein, das können auch
durchaus mehrere sein, aber hier drin mehrere konstant.
Wie viele Wartezyklen kommen, variabel.
So lange, bis es halt erledigt ist.
Und hier wird quasi wieder im ersten Adresse und im Fall eines
Schreibens sogar schon die Daten hier angelegt.
Dann sagt die Peripherie hier unten zum Beispiel Low Active Ready,
also solange es 1 ist, ist es noch nicht fertig.
Die Peripherie sagt, ich bin noch nicht soweit, bitte warten.
Und irgendwann sagt sie, jetzt habe ich es und dann können wir auch
erledigen, dann können wir die ganze Sache abschließen.
Ansonsten, wenn jetzt hier immer noch ein 1-Pegel gewesen wäre, wäre
halt ein zweiter Wartezyklus eingebaut worden, bis die Peripherie
irgendwann fertig ist.
Das waren die Semisynchronen.
Was ich ja noch mal wiederholen wollte, früher sagen würde,
hervorheben wollte, ist, was heißt jetzt hier Semisynchronen, der
Nächste ist Asynchronen.
Die haben trotzdem immer alle noch einen Takt und sie halten sich an
den Takt, nur es ist nicht mehr, das Busprotokoll ist nicht mehr starr
ausgerichtet im Sinne von ein Takt hierfür, zwei Takte dafür und immer
genau ein hierfür, zwei dafür, sondern da ist die Variabilität.
Aber es ist immer noch alles ganz streng an steigenden und fallenden
Flanken des Taktsignals ausgerichtet.
Dann gibt es die Asynchronen Systembusse, wo es jetzt nicht dieses
Konzept von, es gibt hier einen Bereich, da dürften Wartezyklen sein,
woanders nicht, sondern einfach jede Art von Kommunikation wird über
einen Handschlag, Handshake gemacht, Zweiwege Handschlag, wo quasi
erst der Anfragesteller, nehmen wir das mal CPU und Speicher, wo die
CPU sagt, Speicher, ich will was.
Irgendwann sagt der Speicher, schau mal kurz, hier wäre das Speicher,
ich will was.
Low Active Address Strobe.
Address Strobe heißt einfach nur die Adresse, die jetzt auf dem
Adressbus anliegt, ist gültig.
Und das heißt implizit, bitte mach was damit.
Irgendwann sagt die Peripherie der Speicher, habe ich verstanden und
hier ist die Antwort, also Low Active Data Acknowledge, zusammen mit
entsprechend den Daten beim Lesen oder wenn die Daten zu schreiben
sind, wurden sie dann eben übernommen von der Peripherie.
Jetzt muss irgendwie, also eigentlich wäre die Arbeit jetzt erledigt.
Die Peripherie hat geantwortet, erledigt.
Aber um wieder in die Ausgangssituation zurückzukommen, können wir
jetzt nicht sagen, dass einfach beide, egal welcher Zeit, ihre Signale
wieder auf Ausgang zurücksetzen.
Ausgang war offenbar 1, das wäre dann also hier Wartezustand, beide
Signale auf 1, sondern die Peripherie muss jetzt ihrerseits wieder
warten, bis der Auftraggeber, CPU, sicher mitbekommen hat, dass das
erledigt ist.
Die Peripherie kann ja nicht sagen, ich bin fertig, ich gehe davon
aus, du hast das gemerkt, ich bin wieder bereit.
Sondern ihr muss jetzt halt eben warten, bis der Auftraggeber wirklich
gesehen hat, dass es fertig ist, sonst wartet er ja weiter.
Angenommen, der würde jetzt hier nur, die Peripherie würde ganz, nur
ganz kurz, ganz, ganz kurz Data Acknowledge auf 0 setzen und gleich
wieder auf 1, wenn die CPU dann nicht in dem ganz kurzen Moment
hinguckt und das verpasst, dann sieht die CPU, hier war es 1, da war
es 1, danach ist immer noch 1, dass es zwischendurch 0 war, also
fertig, hat sie vielleicht nie mitbekommen.
Um das zu vermeiden, sagt die Peripherie, so lange ich bin fertig, bis
der Auftraggeber, CPU, sagt, ich habe es gemerkt.
Und das macht er, indem er sein Adverse Trope Signal wieder auf 1
zurücksetzt und damit sagt, ich habe bemerkt, dass du fertig bist,
dann bin ich jetzt auch fertig.
Und nachdem das wiederum die Peripherie, der Speicher, gemerkt hat,
kann er auch sein Data Acknowledge wieder auf Ausgangssituation setzen
und jetzt kann irgendwann danach der nächste Zug für startet werden.
Das ist dieses Two-Phase-Handshake.
Dann hatten wir uns ein paar Beispiele angeschaut, die gucken wir uns
aber im Detail nicht noch mal durch, also einfach nur CPU-Busse, wo es
sowas gibt, ein externes RAM-Sprecherchip, den wir einfach in der
Vergangenheit mal benutzt haben, wo wir mal eingeschaut haben, wie
sieht denn so ein Datenblatt aus, was steht denn da alles drin, was
ist denn da alles angegeben, das gucken wir uns aber nicht mehr alles
durch.
Das war ganz witzig an dem Sprecherchip halt eben, zum einen halt
relativ schnell, also für Off-Chip, also über Platine zu
kommunizieren, relativ schnelle Frequenz.
Dann ist der Speicher innen drin gepipelined.
Dann hatten wir dieses Feature oder der Chip hat dieses Feature, das
No -Bus-Latency-Feature, was immer dann relevant wird, wenn es
gepipelined ist.
Hätte ich hier als Beispiel zu zeigen angenommen, ich hatte Leser
-Anfrage, Leser-Anfrage, Leser-Anfrage, die abgeschickt werden und
irgendwann kommt auf die Leser-Anfrage kommt eine Antwort, das blaue
Kästchen hier, die zweite Leser-Anfrage kommt eine Antwort, dritte
kommt eine Antwort und so weiter.
Und irgendwann kommt zwischendurch mal eine Schreibanfrage, rotes
Kästchen.
Wenn die Schreibanfrage jetzt quasi die Daten, die zu schreiben sind,
sofort an den Speicher schicken würden über den gemeinsamen Datenbus,
dann würden sie in diesem geschickt gewählten Beispiel kollidieren mit
der ersten Leser-Anfrage, die er gepipelined später zurück bekommt,
zurückkommt über den Bus.
Deswegen müssen die Daten, also das geht nicht, böse, und deswegen
müssen die Daten, wo eigentlich hier die Schreibanfrage geschickt
wurde und die Daten sind ja schon da, die müssen verzögert auf den Bus
gelegt werden.
Nämlich genau dann, wenn in dieser gepipelinden Reihenfolge die Lücke
ist, weil hier eben keine Leser-Anfrage war.
Genau in dem Moment muss der Anfragesteller die Daten auf den Bus
legen.
Nur da ist der Bus frei.
Und da muss sich halt eben der Antragesteller darum kümmern, sonst
wird das komisch schief gehen.
Gut, wir hatten die Platine gesehen, die wir dafür gebaut haben, mit
dem Speicher oben drauf.
Wir hatten gesehen, dass wir Platinen selber herstellen können.
Nochmal, wenn jemand Interesse hat, Platinen zu bauen, sagt Bescheid.
Alles, was ein- oder zweilagig ist, ist geschenkt.
Vierlagig ist lästig, aber im Zweifelsfall geht es auch.
Und es macht Spaß, ist ganz lustig.
Gut, bis dahin waren wir gekommen.
Ja, und jetzt gibt es halt eben noch ein paar, es gibt hunderte von
Spezialfällen, aber ein paar, die so häufiger mal auftreten, im Fall
Allgemeinheit.
Und einer davon wäre der Multiplex-Bus.
Was soll das sein, ein Multiplex-Bus?
Also erst mal ein ganz normaler Bus, aber irgendwie gibt es weniger
Leitungen, als er eigentlich brauchen würde.
Und deswegen muss man die paar Leitungen, die da sind, irgendwie
multiplexen, also für mehrere Zwecke benutzen, mal für das eine, mal
für das andere.
Und ein Beispiel dafür wäre zum Beispiel der PCI-Bus.
Den gibt es ja jetzt wirklich überall.
Der hat eben nicht über eine getrennte Daten-Adress-Leitung, also über
zwei, also jeweils eine getrennte Daten-Adress-Leitung verfügt,
sondern der einen gemeinsamen Bus hat, über den dann entweder die
Daten oder die Adressen drüber gehen, aber eben nicht beides
gleichzeitig.
Trotzdem ist es ja so, dass der Bus macht ja nur die Kommunikation,
die Kommunikation mit der Peripherie, die angesprochen werden soll.
Die Peripherie am anderen Ende, die braucht irgendwann mal Daten und
Adresse gleichzeitig, um ihre Operationen schreiben, durchführen zu
können.
Das heißt, die Peripherie muss dann irgendwie die Adresse sich selbst
merken.
Sollte also quasi zuerst über die gemeinsamen Daten-Adress-Leitungen
erst die Adresse übertragen, dann muss der Peripherie noch gesagt
werden, das waren die Adressen, nicht die Daten, sondern Adressen.
Die Peripherie merkt sich dann lokal bei sich diese Adresse, wo es hin
soll.
Danach werden irgendwann die Daten übertragen oder das eine Datenwort
zum Beispiel.
Jetzt hat die Peripherie beides vorliegen und kann jetzt mit beidem
zusammen den Speicher oder was auch immer wirklich ansprechen.
Wie sieht das aus oder wie könnte das aussehen?
Wir hätten hier oben die CPU, wo es eben hier die Schnellstelle nach
außen gibt, außen einfach nur im Sinne von außen der CPU, wo es
irgendwie eine Busleitung gibt, die sowohl für Adresse als auch für
Daten benutzt werden soll.
Und hier unten haben wir irgendwie die Peripherie, zum Beispiel
einfach ein Speicher, der angebunden ist.
Und da ist klar, wir erinnern uns, wie Speicher funktionieren.
Ich brauche die Adresse, die muss hier irgendwie rein, die wählt eine,
das liegt jetzt ein bisschen quer, die wählt eine Zeile, das waren
Zeilen eigentlich, wählt eine Zeile von der Speichermatrix aus.
Komisch gemalt.
Naja zumindest in dieses eine Ding, was ausgewählt wurde, kann dann
quasi was reingeschrieben werden.
Naja und dafür gibt es halt für gewöhnlich noch ein paar Steuersignale
und es gibt dieses Fletch, Fletch, Flipflop auf der Empfängerseite,
also quasi das Ding, in dem die Adresse gemerkt werden kann.
Und dafür gibt es ein Steuersignal, Adress Fletch Enable heißt es
häufig, es gibt noch ein paar andere Namen, aber das wäre so ein
typisches Signal, was einfach nur sagt, also es gibt ein Adress Fletch
und das soll jetzt, Enable, die Daten, die auf dem Bus liegen,
übernehmen und sich merken.
Also sobald dieser Enable wieder weg geht, nicht mehr merken, sondern
die davor, wo Enable war, die sollen gemerkt werden.
Das heißt, es wird wie schon vorhin gesagt, zuerst die Adresse
übertragen, die geht sowohl hier hin, als auch hier hin.
Hier wird sie einfach noch ignoriert, weil der Speicher sieht, ach das
war die Adresse, weil das Adress Fletch Enable sagt, das soll als
Adresse gemerkt werden.
Deswegen werden die hier einfach ignoriert.
Aber sie werden hier drin, also dieses Adress Fletch Enable, dieses
Flipflop, dass es sich die Daten, die hier anliegen, halt eben merken
soll.
Danach werden die Daten einfach dauerhaft hierhin ausgegeben und in
dem nächsten Buszyklus werden wieder über den gemeinsamen Adress
Datenbus jetzt die Daten, zum Beispiel zum Schreibern übertragen.
Die gehen wiederum hier hin, als auch hier hin.
Hier werden sie ignoriert, weil das Adress Fletch Enable halt eben
nicht sagt, merken, sondern es sagt, die alten Daten, die du schon
drin hast, die sollen weiterhin anliegen und die liegen jetzt halt
eben als Adresse am Speicher an.
Jetzt werden halt eben, weil AdWords Fletch sagt, das sind Daten,
werden die halt eben hier für das Speicher-Array als Daten zum
Schreiben benutzt.
Okay und die obere Seite wäre halt einfach nur, irgendwie gibt es eine
Schnittstelle und da könnten halt oben drüber mehrere andere Dinger
sein, zum Beispiel, wie wir es bei der CPU gesehen hatten, vielleicht
ein Adress-Buffer, ein Datenbus-Buffer, Befehlszähler, alles
potenzielle Sachen, die entweder Adresse oder Daten enthalten könnten.
Also das hier wären typische Kandidaten, wo eine Adresse herkommen
könnte, das wäre ein typischer Kandidat, wo Daten herkommen könnten.
Im zeitlichen Verlauf ist auch keine wirklich große Überraschung drin.
Wir haben unseren Bus-Transfer, weil wir jetzt die Adress-Daten
-Leitung für mehrere Sachen benutzen.
Gibt es auch mehrere Unterteile, also nicht mehr unbedingt nur noch
einer für Anfrage und einer für Antwort, weil der eine mit Anfrage war
ja früher, dieses TA, das war ja früher Daten und Adresse.
Jetzt ist es nacheinander, wenn es wohl mehr werden.
Hätten wir jetzt also hier eine Adresse, die auf dem gemeinsamen
Adress -Datenbus anliegt, zusammen mit dem Adress-Valid, AVD ist auch
eine typische Bezeichnung für so ein Signal, die sagt, jetzt sind die
Daten gültig.
Was da gemacht werden soll, das kann die Peripherie selber
entscheiden.
Also irgendwie muss sie sich merken.
Die Daten, die in dem Fall die Adresse sind, werden übernommen in ein
internes Adress-Register, das wäre das Ledge, was wir gerade gesehen
hatten, das Flip-Flop da.
Hier liegen jetzt quasi die ganze Zeit die gültigen Daten an und
später werden dann die eigentlichen Daten übertragen und jetzt sind
auf der Peripherie-Seite sowohl die Adresse, wo es hin soll, als auch
die Daten vorhanden und damit kann dann die Operation durchgeführt
werden.
Ja, es gibt es noch vier Wörter.
Also Adress Trope hatten wir auch schon mal gesehen.
Einfach sagt, hier neuer Satz an gültigen Adressen, mach was damit.
Valid Memory Address, noch nicht so häufig gehört, aber warum nicht.
Ledge Enable hatten wir schon gesehen.
Und hier bei dem Beispiel gerade, wenn man sich das Zeitdiagram ein
bisschen genauer angeschaut hätte, hätte man gesehen, dass hier
irgendwie mit der Fallenden Flanke des Ledge Enabled Signals oder wie
hieß es da, des Adress Valid Signals, mit der fallenden Flanke werden
die Daten übernommen.
Also in diesem gemalten Beispiel so.
Kann man so machen, muss man aber nicht.
Also normalerweise gibt es genau ein Ding, an dessen Flanken was
übernommen werden und das ist die Glocke und das ist die eine Glocke,
die Busglocke in dem Fall.
Und Flanken von irgendwas anderem zu pfuschen, sollte man echt
vermeiden.
Da muss man halt eben bei diesen anderen Sachen dafür sorgen, dass die
um Gottes Willen glitschfrei sind und dass die um Gottes Willen
irgendwie synchron zum Takt ankommen, nicht irgendwie kurz davor oder
kurz dahinter wäre für gewöhnlich schlecht.
Also da hat man sich eine Menge Kopfschmerzen ein und die Idee von dem
Takt war ja wirklich Kopfschmerzen zu vermeiden.
Und ja, also man kann das machen, synchron zu anderen Taktgebern sein,
aber nein, lasst es.
Okay und nachdem dann quasi dieses Übernehmen der Adresse da ist,
vergeht ein bisschen Zeit.
Man kann hier sehen auf dem Bild, da ist hier so eine Lücke dazwischen
und die Lücke ist einfach dafür da, dass irgendwas am Bus gemacht
werden muss, weil die Daten, die Adressen, also bisher lagen die
Adressen auf dem Bus, die dürfen jetzt nicht mehr auf den Bus.
Also muss ich erst, wer auch immer der Puffer für die Adresse ist, dem
muss ich sagen, bitte nicht mehr auf den Bus schreiben und wer auch
immer die Daten hat, dem muss ich sagen, jetzt du, jetzt du bitte auf
den Bus schreiben.
Und das muss ich so machen, dass es niemals passieren kann, dass
zwischendurch beide auf den Bus schreiben, weil dann ist irgendwie
Kurzschlussgefahr.
Das heißt, ich muss da eine Sicherheitslücke zwischenlassen, also so
klein wie ich garantieren kann halt eben, aber eine kleine Lücke
sollte es halt schon sein.
Deswegen sage ich erst dem einen, du die Adresse nicht mehr auf den
Bus und danach, also wirklich zeitlich danach, sage ich dem anderen,
jetzt du die Daten auf den Bus.
Das ist hier mit dem Umschalten gemeint.
Ach ja, und dann gibt es halt eben noch, das war jetzt eine Form von
diesem Multiplex-Bussen, aber man kann dieses Multiplex für viele
andere oder es wird auch für viele andere Zwecke benutzt.
Generell eigentlich immer dann, wenn man weniger physikalisch
vorhandene Leitungen hat, als man logisch eigentlich braucht.
Was man zum Beispiel häufig sieht, ist, dass nicht genug
Adressleitungen da sind.
Das ist quasi eine CPU, eine ganz kleine, also alte CPUs, 8-Bit-CPUs
hatten halt für gewöhnlich auch nur 8-Bit-Adressleitungen.
Da kommt man nicht weit mit.
Und das war denen auch damals klar, dass man mit 8-Bit-Adressleitungen
nicht so wahnsinnig viel Speicher adressieren kann, das reichte nicht.
Also haben sie einfach gesagt, gut, dann machen wir halt 16-Bit
-Adresse und muss man halt zweimal nacheinander die Adresse
übertragen.
Einmal die einen 8-Bit und einmal die anderen 8-Bit.
Also einmal die niedrigen 8-Bit und danach von mir aus die hohen 8
-Bit.
Das waren so quasi zwei nacheinander vollzogene Transaktionen über den
Bus, weil eben der Bus nur 8-Adressleitungen hatte.
Der Speicher aber durchaus genug Speicherinhalt, um 16-Adress-Bits zu
brauchen.
Zumindest mal um mehr als 8-Adress-Bits zu brauchen.
8051.
Der 8051 hat das zum Beispiel so gemacht, dass halt die Adress-Bits
nacheinander übertragen wurden.
Höher- und niederwertige Daten-Bits könnte man auch, also das gleiche
mit Daten-Bits machen.
Das gleiche kann man gemischt machen, dass quasi zum Beispiel erst die
niederwertigen Adress-Bits, dann die höherwertigen Adress-Bits und
dann die Daten-Bits alles nacheinander quasi übertragen wird.
Kann man auch machen, also alle Varianten vorstellbar.
Ja,
das war eigentlich alles soweit zu Bussen.
Jetzt weiß ich nicht, ich glaube, ich hatte das letztes Mal nicht
erzählt, aber ich wollte es einfach gerne mal erwähnen.
Also zu Bussen vielleicht noch was.
Und zwar die meisten, also was ist ein Bus?
Ein Bus ist immer irgendwie ein Ding, wo es mehrere Sachen gibt, die
darauf schreiben können.
Also mehrere Busteilnehmer gibt, die schreiben können.
Okay, um das zu realisieren, also um mehrere Schreiber, potenzielle
Schreiber zu haben, brauche ich dieses Tree-State-Gate.
Ja, so ein Gatter, was mit einem Enable-Signal mich abtrennen kann vom
Bus.
Also ich habe hier irgendwie einen Bus und hier habe ich einen
potenziellen Schreiber.
Der Schreiber hat dieses Tree-State-Gate, was einfach Daten rein,
Daten raus und ein Enable-Signal.
Ein Enable-Signal heißt, es soll schreiben, kein Enable-Signal heißt,
es soll sich abtrennen vom Bus.
Das wäre quasi der Schreib-Port, das soll eine Fallspitze sein und
dann wäre halt eben quasi noch der Lese-Port, also man kann immer
lesen von dem Bus.
Und genau so würden halt eben mehrere Bus-Komponenten an diesem Bus
dranhängen.
Jetzt ist es aber so, dass diese Tree-State-Gates nicht
notwendigerweise schnell sind.
Das heißt, die werden nicht benutzt.
Also zumindest, also die wurden mal benutzt, irgendwann mal, aber so
in Wirklichkeit werden die eigentlich nicht mehr benutzt.
Wenn man irgendwie eine Hardware-Programmierung, also eine Hardware
-Schaltung beschreibt mit einer Hardware-Beschreibungssprache, dann
kann man da diese Tree-State-Gates hinschreiben.
Also man kann das ausdrücken, genau beschreiben, dass so ein Gatter
erzeugt werden soll.
Wenn man sich da anschaut, was da rausgekommen ist, merkt man, da ist
kein Gatter, da ist kein Tree-State-Gate erzeugt worden.
Sondern stattdessen wird quasi einfach nur ein riesiges Netzwerk aus
Multiplexern gebastelt.
Im Sinne von, angenommen, ich hätte jetzt, was weiß ich, drei Bus
-Teilnehmer, alle halt eben diesem Tree-State-Gate angebunden.
Dann wird in Wirklichkeit sowas gebaut, dass Bus-Teilnehmer 1 halt
quasi einen Eingangs-Multiplexer hat, wo er Daten entgegennehmen kann
von Bus-Teilnehmer 2 oder Bus-Teilnehmer 3.
Die können da quasi reinschreiben und die quasi die gleichen Eingangs
-Multiplexer sind halt eben bei den anderen Bus-Teilnehmern auch.
Also der hier unten hätte einen Multiplexer, wo 1 oder 3 reinschreiben
kann.
Der hat einen Multiplexer, wo 1 oder 2 reinschreiben kann.
Also damit können sie quasi Daten entgegennehmen von den anderen
Komponenten.
Und zum Schreiben, also zum Loswerden von Daten, wäre quasi der
Ausgang, der Schreibausgang hier, der geht halt eben hier in den Input
-Mux und der geht halt eben hier in den Input-Mux.
So ist quasi alles, jeder kann mit allen irgendwie kommunizieren.
So kann man das auch realisieren.
Ich brauche noch einen vierten für das nächste Beispiel.
Und jetzt ist es halt so, wenn man das ganze Zeug mit Multiplexern
implementiert, dann ist es rein von der Logik, von den Gattern, die
vorhanden sind, überhaupt kein Problem, dass quasi gleichzeitig
Komponente 1 und 2 miteinander reden.
Also zum einen und gleichzeitig zum anderen.
Das habe ich gerade gesagt 1 und 2 und gleichzeitig 3 und 4.
Gibt es überhaupt keinen Grund, dass das nicht funktionieren sollte.
Die können ja miteinander reden über die Multiplexer, weil diese Idee
von dem gemeinsamen Bus ist wirklich nur noch eine Idee, aber sie
existiert bei den Gattern nicht mehr.
Aber das Protokoll, das Busprotokoll verhindert das, weil das
Busprotokoll davon ausgeht, dass immer nur einer mit einem
kommunizieren kann.
Und deswegen geht es inzwischen immer mehr in die Richtung, dass man
diese Busse einfach ad acta legt und sagt, wenn die Hardware das kann,
dass jeder mit jedem reden kann oder zumindest mehrere gleichzeitig
reden kann, dann sollte man das doch auch wirklich als
Kommunikationsfeature anbieten.
Und ARM hat das, glaube ich, als einer der ersten wirklich
durchgezogen.
Das war halt eben früher hatte ARM diese beiden Busse, also der AMBA
Bus, bestehend aus dem AMBA High Speed Bus und dem AMBA Peripheral Bus
sind jetzt quasi alt, gibt es nicht mehr und wurden ersetzt von AXI,
wobei ich jetzt gerade gar nicht genau weiß, was AXI eigentlich heißt,
AXI AMBA Crossbar Interconnect, glaube ich, also X wie Crossbar.
Wo halt einfach nicht nur physikalisch auf Sicht der Gatter diese
Möglichkeit vorhanden ist und auch vom Protokoll ist vorgesehen ist,
dass jeder mit jedem reden kann, wobei man auch noch sagen kann, zum
Beispiel Komponente 1 am AXI Bus kann kommunizieren mit Komponente 4,
7 und 9, aber nicht mit den anderen, dann werden die Multiplexer
kleiner.
Man kann sogar noch angeben, wer überhaupt mit wem alles kommunizieren
möchte und dann können wirklich gleichzeitig parallel verschiedene
Kommunikationen ablaufen.
Also selbst bei Sachen, wo man denkt, gibt seit 100 Jahren,
funktioniert, warum noch ändern, so alle paar Jahrzehnte ändert sich
doch nochmal was in den Konzepten.
Okay, soviel zu den Bussen.
Ja und dann gibt es halt eben weitere Komponenten, die am Bus oder was
auch immer dranhängen, zum Beispiel die Systemsteuerbausteine.
Dabei ist im Wesentlichen alles gemeint, was ja also Funktionen, die
gebraucht werden, die aber aus irgendwelchen Gründen nicht im
Prozessor selbst integriert sind.
Wenn man sich dieses Wort anguckt, Baustein, ja damit ist
normalerweise gemeint ein Ding, was sich in die Hand nehmen kann, also
ein extra zusätzlicher externer Chip.
Und das war früher auch so, da gab es quasi einen oder vielleicht
sogar mehrere Chips für die CPU und da gab es halt eben noch einen
Chip, der war für Schnittstelle, Kommunikation mit dem einen und noch
ein Chip für Schnittstelle, Kommunikation mit dem anderen und so
weiter.
Das waren wirklich mehrere Chips.
Heute sind quasi alle von diesen Kommunikationsschnittstellen-Dingsies
auf dem gleichen Chip mit drauf.
Deswegen ist das Wort Baustein irgendwie ein bisschen irreführend.
Heißt aber irgendwie immer noch so.
Also heute ist quasi fast immer gemeint, dass es auf dem gleichen Chip
drauf ist, aber trotzdem außerhalb der CPU.
Ich habe immer noch meine CPU und den Bussen, an den Bussen noch
andere Komponenten, aber dieses Ganze zusammen ist auf einem Chip
drauf.
System und Chip.
Also mit dem Begriff Baustein nicht verwirren lassen.
Gut, da gibt es halt eben verschiedene Arten von diesen Bausteinen.
Und die Nicht-Programmierbaren.
Die Nicht-Programmierbaren, die sind deswegen nicht programmierbar,
weil sie es nicht brauchen.
Also die machen irgendwelche Sachen, wo man nichts einstellen können
muss, sondern die einfach immer genau das gleiche machen, ohne dass
man mit denen irgendwie reden müsste.
Zum Beispiel sowas wie, na gut, also zum Beispiel sowas wie ein
Taktgenerator.
Also man könnte sich vorstellen, dass ein Taktgenerator ja immer die
gleiche Taktfrequenz ausgibt.
Deswegen muss man nicht mit dem reden können.
Deswegen ist er nicht programmierbar.
Könnte man sich so vorstellen und war auch lange Zeit so.
Inzwischen ist es natürlich so, dass man jede CPU kann ja selber
sagen, der Takt soll jetzt gerade mal ein bisschen schneller oder ein
bisschen langsamer sein.
So gesehen würden die heutigen Taktgeneratoren eher zu den
programmierbaren Systembausteinen gehören.
Aber früher waren die halt einfach nur fest, nicht änderbar.
So gesehen, das war ein klassisches Beispiel.
Heute kommt es darauf an, ob man den Takt wechseln kann,
Taktgeschwindigkeit wechseln kann oder nicht.
Bussteuerbausteine, also Buscontroller sind auf jeden Fall immer noch
in dieser Kategorie.
Das sind einfach die Dinger, die das Busprotokoll implementieren.
Also die halt eben dafür sorgen, dass die Kommunikation auf dem Bus in
geregelten Bahnen verläuft.
Also jeder sich an das Protokoll hält.
Wenn er sich nicht daran hält, dass dann halt eben an der zentralen
Stelle, dass der Steuerbaustein eine Fehlermeldung ausgeschickt wird,
damit derjenige weiß, das hätte nicht passieren dürfen, das hat nicht
funktioniert.
Solche Sachen halt eben.
Ähnlich oder fast eigentlich ein Teil davon der Busarbeiter.
Wenn mehrere Leute gleichzeitig einen Zugriff machen wollen über
wirklich so einen geteilten, eingescherten Bus und das halt eben nur
einer gleichzeitig machen kann, dann muss irgendjemand entscheiden,
wer darf den Buszugriff machen und da muss ich auch merken, der andere
kommt danach oder irgendwann später zumindest.
Das ist der Arbeiter.
Eine Arbitrierung immer im Sinne von mehrere Anfragen in Reihenfolge
bringen, hier halt eben die Anfrage über den Bus zu kommunizieren.
D-RAM Controller ist für gewöhnlich auch nicht programmierbar,
zumindest nicht von außen programmierbar.
Einfach das Ding, was mit dem D-RAM Speicher redet.
Das ist halt sehr D-RAM spezifisch.
Es muss die Timings von dem Speicher genau wissen.
Es kümmert sich darum, dass die Zugriffe, die gewünscht sind, wirklich
in Signale für den D-RAM Speicher Baustein umgesetzt werden.
Es kümmert sich darum, dass die einzelnen D-RAM Bänke regelmäßig
refreshed werden.
Also quasi, ihr wisst ja noch, das mit den Kondensatoren, die sich
entladen.
Also muss man die ab und zu mal auslesen, wieder reinschreiben, dass
sowas halt eben alles automatisch funktioniert und sich die CPU nicht
um sowas kümmern muss.
Das wären typische Beispiele für nicht programmierbare Bausteine.
Die sind einfach da, die machen ihren Job und sie machen es, ohne dass
ich ihnen sagen muss, dass sie es machen sollen und ohne dass ich eine
Chance habe, ihnen zu sagen, mach es anders.
Die machen es einfach.
Andererseits programmierbare Systemsteuer Bausteine, offensichtlich
Sachen auch am Bus, übernehmen auch Funktionen, die außerhalb der CPU
sind.
Aber ich kann und muss ihnen zu einem gewissen Grad sagen können, was
genau ich von ihnen erwarte.
Ein DMA-Controller wäre das Ding, was quasi, also Direct Memory
Access, was selbstständig Speicher- Kopier-Operationen durchführen
kann.
Nämlich also die CPU kann den DMA-Controller programmieren, kann ihm
sagen, von der Basisadresse kopiere mal 4 Kilobyte zu der
Basisadresse.
Und das macht er dann von alleine.
Das macht er dann für alleine für gewöhnlich, indem er halt eben nicht
ein Byte nach dem anderen oder ein Wort nach dem anderen, sondern
indem er Bursts macht.
Also von mir aus immer 16 Byte von dem einen lesen, in den
Zwischenpuffer speichern und dann 16 Byte zu dem anderen hinschreiben.
Und das so häufig, bis es erledigt ist.
Einfach weil Bursts meistens schneller funktionieren.
Bei Bursts muss man nicht immer den Bus neu anfordern.
Man hat ihn halt eben einmal und er kann dann nur Daten, Daten, Daten
direkt nacheinander.
Also dieser Overhead des Bus-Protokolls hat man nur einmal und danach
die reine Menge an Datenübertragung.
Deswegen machen die Bursts.
Und am Ende sagen sie dann der CBU Bescheid.
Das gibt es auf verschiedene Arten, die das Bescheid sagen machen
können.
Die verschiedenen Arten sehen wir gleich noch.
Cash-Controller, Cash hatten wir schon gesehen.
Da gibt es zum Beispiel solche Sachen, wie dass man einen Cash flashen
können muss.
Wir hatten überlegt, als diese virtuelle Speicherweitung, wo die MMO
hinkommt, vor den Cash, nach den Cash, wo die halt eben hin soll.
Und in manchen Fällen muss der Cash-Inhalt geleert werden.
Also muss man dem Cash offensichtlich sagen können, leere deinen
Inhalt.
Im Sinne von, alles was noch nicht zurückgeschrieben ist, schreibst
zurück und alles andere, also alles, was ungültig markieren.
Das muss man dem Cash-Controller irgendwie sagen können, als
Mindestanforderung.
Da gibt es meist noch Cashes, die man zum gewissen Grad konfigurieren
kann, wo man sagen kann, gewisse Cash-Zeilen, also Adressbereiche,
bitte in den Cash reinladen.
Also obwohl die jemand gefragt hat, ich sage einfach, hol die doch
schon mal rein, Prefetching und behalte sie auch drin, Pinning.
Die dürfen dann nicht mehr verdrängt werden.
Die werden von der normalen Verdrängungsstrategie, können die nicht
mehr verdrängt werden.
Über solche Sachen, also solche Sachen kann man häufig konfigurieren
bei den Cash-Controllern.
Manchmal kann man auch die Verdrängungsstrategie einstellen, man kann
einige Sachen einstellen.
Speicherweitung, MMU, also da geht es einfach nur darum, die Tabellen,
wo im Speicher sind die Übersetzungstabellen.
Wenn die MMU das nicht weiß, kann sie nicht übersetzen.
Zeitgeberzähler, das ist einfach nur, also im Allgemeinen gibt es
Zähler, die zählen Events.
Zum Beispiel könnten die die Anzahl der Cash-Misses zählen oder die
Anzahl der Bustransaktionen zählen, einfach um dann den Benutzer zu
sagen, wie viel Misses gab es, wie viel Bustransaktionen gab es, wie
war das System so ausgelastet.
Und als Spezialfall die Zähler, die das Event Rising Edge von der
Clock zählen, das sind dann Zeitzähler, also Taktzähler.
Und die Zähler kann man offensichtlich sagen, setzt sich auf null
zurück, fang neu an zu zählen, also schon muss ich sie schreiben
können.
Und ich kann ihnen häufig auch sagen, was sie zählen sollen.
Es gibt dann quasi sowas wie von mir aus 20 verschiedene Zähler und
100 verschiedene Events, die gezählt werden könnten.
Man muss ihnen sagen, welche sie zählen sollen.
Echtzeituhren, die muss man halt mal stellen.
Die werden von außen gestellt, dafür muss man sie schreiben können.
Unterbrechungssteuerbausteine, Interrupts kommen gleich noch dran.
Die muss man eben auch sagen können, was für Interrupts gerade erlaubt
sind, welche verboten sind.
Wenn Interrupt passiert, wo es dann weitergehen soll, das sehen wir
gleich noch.
Gut, Schnittstellenbausteine.
Das sind ja eigentlich fast schon Schnittstellen.
Hier ist jetzt gemeint, Schnittstellen zu wirklich externer
Peripherie, wobei Prozessor, also Hauptsprecher ist irgendwie schon
externer und dann andere sonstige externe Peripherie.
Diese Schnittstellenbausteine, also dieser Schnittstellenbaustein ist
quasi immer noch auf dem Chip mit drauf, aber die externe Peripherie
ist dann wirklich extern.
Zum Beispiel der Hauptsprecher, der ja normalerweise extern ist.
Oder irgendwas anderes, also ein Drucker wird immer extern sein.
Da wird auch ein Chip drauf sein.
Und wann immer ich mit einer externen Peripherie reden will, muss ich
mehrere Sachen machen, weil die Kommunikation auf dem Chip ist anders
als die Kommunikation außerhalb von dem Chip.
Die Kommunikation auf dem Chip hat eine ganz andere Spannung und ganz
andere Treiberstärke als alles, was rausgeht.
Weil was rausgeht, ist weit weg, im Sinne von mehrere Millimeter weit
weg.
Und im Chip, da redet man nicht von Millimeterentfernung.
Also manchmal schon, aber das hat alles sehr nah beieinander.
Deswegen kann man mit kleinen Spannungen arbeiten und so weiter.
Also alles, was rausgeht, muss die Spannung angepasst werden, von dem
internen Level auf den externen Level.
Das kostet Zeit.
Das muss man einfach machen.
Genau durch die umgekehrte Richtung, alles, was reingeht.
Es müssen Schutzmechanismen vorhanden sein.
Also wenn die externe Peripherie irgendwie mit einer zu hohen Spannung
kommt oder wenn jemand mit dem Fingernchip anfasst, soll es nicht
gleich kaputt gehen.
Solche Sachen müssen da alle umgesetzt werden.
Was auch häufig ist, SerDes-Einheiten, also Seriell deserialisieren,
deserialisieren, SerDes, die quasi aus parallelen Daten serielle Daten
machen.
Also zum Beispiel sowas auf der einen Seite, ein 8-Bit-Eingang mit 100
Megahertz, auf der anderen Seite ein 1-Bit-Ausgang mit 800 Megahertz.
Quasi einfach einen Schreibzugriff mit 8-Bit nehmen, die dann mit
achtfach höherer Frequenz als 1-Bit ausgegeben werden.
Damit man halt eben auf Chip vielleicht nur einen Pin dafür braucht.
Und natürlich wieder zurück.
Also das ist ein einfaches Schieberegister.
Also diese Wandlung von seriellen auf parallelen Daten.
Oder auch analog-digital Wandlungen.
Also wenn nicht nur externe Peripherie mit einer klaren 1 oder klaren
0 angesprochen werden kann.
Wenn zum Beispiel irgendein Temperatursensor vielleicht einen
Spannungsbereich hat, der proportional zur Temperatur ist, dann muss
ich diesen Spannungswert digitalisieren.
Oder wenn ich irgendwas habe, was ich ausgeben möchte, irgendeinen
Stellmotor, der eine gewisse Position erreichen soll.
Da wird quasi intern ein digitaler Wert gesagt, die Position soll er
haben.
Das muss dann vielleicht als analoger Wert ausgegeben werden, dass der
Motor dann weiß, was er tun soll.
Gut, also es müssen Steuersignale auch noch gemacht werden und die
externe Peripherie antwortet irgendwann und zwar mit Interrupts,
Unterbrechungen, die müssen irgendwie behandelt werden.
Und dieses alles zusammen, das sind dann also diese
Systemsteuerbausteine, die wir gerade gesehen hatten und die
Schnittstellenbausteine, die wir hier sehen.
Allgemein zusammengefasst werden das die Systembausteine.
Also alles, was irgendwie um die CPU drumherum zum Gesamtsystem
dazugehört, aber nicht Teil von der CPU ist.
Hier hätten wir mal ein Beispiel für sowas.
Hier hat man eine CPU, die aus mir völlig unerklärlichen Gründen drei
Taktsignale bekommt.
Also zum einen, warum drei, keine Ahnung, aber der Takt sollte halt
eben auch an die anderen Komponenten gehen.
Ja, sehen wir das mal ein bisschen abstrakter.
Hier wäre der eine Systembus, an den dann quasi alle externen
Komponenten angeschlossen sind.
Da sehen wir, wir hatten glaube ich alle schon die beiden Speicher,
Hauptspeicher, ROM, wobei jetzt hier ROM könnte durchaus eine Sache
sein, die on-chip ist und RAM wäre dann eher so eine Sache, der
Controller dafür ist on-chip und der eigentliche DRAM-Hauptspeicher,
also der ist ganz bestimmt off-chip.
Das wird dann quasi nur eine Schnittstelle nach außen sein.
Intrupt-Controller, aus Intrupts nehmen wir gleich noch, DMA hatten
wir, Timer hatten wir, ich glaube die anderen hatten wir alle.
So wären die quasi alle zusammen an einem Gesamtsystem.
Das wäre quasi ein Gesamtsystem, was an sich so, wie es dahin gemalt
ist, funktionsfähig wäre.
Okay, wenn ich jetzt so viele Komponenten am Bus habe, wie rede ich
dann eigentlich mit denen?
Also klar, über den Bus, okay, geschenkt.
Aber auf was hören die denn jetzt eigentlich?
Also wie genau spreche ich die an?
Und da gibt es zwei verschiedene Arten, wie man die ansprechen kann
und geht irgendwie um die Adressierung.
Das eine wäre eine deutsch-speicherbezogene Adressierung, Memory
-Mapped -IO hat man vielleicht häufiger schon mal gehört und eine
isolierte Adressierung, Isolated-IO, sind eigentlich sehr ähnliche
Sachen.
Minimaler Unterschied irgendwo.
Was einfach gemeint ist, ist das folgende.
Bei dem Memory-Mapped-IO habe ich quasi meinen ganz normalen
Adressraum.
Also im Sinne von, ich habe eine 32-Bit-CPU, die hat einen 32-Bit
-Adress -Ausgang, also können sie 2 hoch 32 Adressen ansprechen.
Und jetzt müssen ja nicht alle von diesen 2 hoch 32 Adressen irgendwie
wirklich Hauptspeicher, DEREM, Off-Chip, DEREM sein, sondern es sind
vielleicht nur die Hälfte davon, also 2 hoch 31, Adressen wirklich
DEREM und der Rest könnte ja was anderes sein.
Und dieses was anderes könnte man halt eben genau dafür nutzen, um
damit eine Peripherie anzusprechen.
Also man sagt sozusagen, in meinem großen Adressraum von 2 hoch 32
Adressen sage ich, hier ist ein Block, dahinter verbirgt sich kein
Speicher, sondern damit kannst du die Peripherie DMA-Einheit
ansprechen.
Also die DMA-Einheit kann irgendwie konfiguriert werden.
Wir hatten ja gesagt, die braucht eine Startadresse, eine Zieladresse
und wie viele Daten übertragen werden sollen.
Also muss ich offenbar, also die hat offenbar innen drin 3 Register,
wo ich reinschreiben können muss.
Startadresse, Zieladresse, Anzahlwerte.
Also mache ich quasi 3 Schreibzugriffe auf den Bereich von meinem
Adressraum.
Also ich habe hier meinen Adressraum.
In dem Adressraum ist ein Teil reserviert, wo hinterlegt ist, das ist
kein Speicher, da ist Peripherie, sagen wir mal DMA.
Und wenn ich da rauszoome, oder auch nicht.
Wenn ich da rauszoome, dann habe ich da quasi eine gewisse Menge an
Adressen, die da drin sind.
Und die eine Adresse ist vielleicht die Startadresse, Source und das
andere, sagen wir mal Formulierung unten, wahrscheinlich werden die
eher nacheinander kommen, aber sie könnten irgendwo sein, will ich
damit andeuten.
Ist vielleicht die Zieladresse und irgendwo ganz anders ist dann, wie
viel übertragen werden muss und die restlichen Adressen haben einfach
keine Bedeutung.
Vielleicht gibt es auch ein paar Sachen für Steuersignale, aber
prinzipiell haben nicht alle davon eine Bedeutung.
So, die kann ich reinschreiben und dann kann ich vielleicht noch sowas
machen, wie wenn ich diese Adresse lese, steht da vielleicht eine Art
Status drin, da steht vielleicht drin, wie weit ist die DMA
-Kopieoperation schon fortgeschritten in Prozent oder bist du fertig
damit oder gab es einen Fehler.
Also gibt es vielleicht irgendeine Adresse, die ich lesen kann, die
mir etwas über den Status der Peripherie sagt.
Wie geht es dir gerade?
Bist du beschäftigt?
Bist du wach?
Irgendwie solche Sachen halt eben.
Das ist mit diesem Memory-Mapped-IO gemeint, wo quasi gewisse Adressen
aus dem Adressraum nicht Speicheradressen sind, sondern für
Verwaltungssachen.
Der untere Teil, die isolierten Adressen, sind quasi das Gleiche mit
dem einen kleinen Unterschied, dass es halt eben nicht ein Adressraum
ist, sondern es sind auf einmal zwei Adressräume, einer für nur
Speicher und einer für nur Peripherie.
Das ist mit dem isolierten gemeint.
Also es sind zwei verschiedene, die sind getrennt voneinander und
irgendwer muss sagen, ist der Speicher oder ist der IO gemeint?
Also gibt es hier unten halt so ein Auswahlsignal, das sagt Memory
oder IO.
Sehen wir hier nochmal als Beispiel.
Wir hätten quasi das eine Auswahl gerade schon gesehen haben, wo quasi
irgendwo innen drin eine IO-Page, also eine Seite liegt, wo die
Speichereinstellungen der DMA-Einheit sind und noch eine andere Seite
für die Speichereinstellungen der was auch immer Einheit, keine
Ahnung, egal.
Andere Alternative, der Adressraum, der genauso groß ist wie hier
links, 2n-1, genauso groß ist, ist nur für Speicher vorgesehen.
Und dann gibt es aber noch einen zweiten Adressraum, der mit einem
Signal umschaltbar ist, der ist deutlich kleiner, der ist für die
Peripherien.
Jetzt habe ich gesagt, es ist eigentlich ein minimaler Unterschied,
warum habe ich das gesagt?
Ich kann mir einfach vorstellen, als wäre das hier noch ein
zusätzliches Adressbit und dann ist es irgendwie doch wieder dasselbe,
also fast dasselbe.
Also als wäre das quasi angenommen, dass hier wäre ein 32-Bit
-Adressraum, dann wäre das hier ein 32-Bit-Adressraum und das ein sehr
schlecht ausgenutzter 32-Bit-Adressraum und hier habe ich dann ein 33.
Bit.
Was sagt, soll der eine oder soll der andere benutzt werden?
Von der Vorstellung her.
Unterschied ist aber, die Anwendung, die darauf läuft, die kann nicht
notwendigerweise auf dieses 33.
Bit zugreifen, die kann vielleicht nur auf die normalen 32-Adressbits
zugreifen und dieses 33.
Bit ist dann vielleicht nur über Spezialbefehle änderbar, damit nicht
jede Anwendung nach Belieben auf Peripherie herumlesen, schreiben
darf.
Also das ist dann noch ein Unterschied, also Zugriffsrechte von diesem
Extra -Bit.
Gut.
Ja, als Wort einfach nur IO-Page, wir hatten es gerade schon gesehen,
so wird es häufig genannt, also hier so ein Bereich, den man dann
zugreifen kann, häufig deutlich größer als was benötigt wird, einfach
weil es immer an einem relativ großen Zweierpotenz-Sachen ausgerichtet
wird.
Zum Beispiel einfach eine 4-Kilobyte-Seite, auch wenn dann vielleicht
nur drei Wörter wirklich eine Bedeutung haben oder 10 oder wie viel
auch immer und das isolierte durch ein Spezialsignal.
Gut, was gibt es noch an diesen Schnellstellen-Bausteinen?
Es gibt auch tatsächlich immer noch einige jetzt wirklich extern
gemeinte Schnellstellen-Bausteine, also extern jetzt wirklich im Sinne
von Extra-Chip außerhalb.
Die gibt es und die werden benutzt und die machen irgendwas und die
gab es schon immer, man benutzt sie immer noch und die haben nur eine
8 -Bit-Adresse, also die haben nur 8-Bit-Daten, nur eine 8-Bit
-Datenbreite.
Die müssen jetzt irgendwie angeschlossen werden an unseren 32-64-Bit
-Bus vom System.
Wo kommt sowas her?
Das war halt früher so, dass Sachen nur 8-Bit groß waren, das reicht
halt für viele Sachen und Sachen, die funktionieren, werden nicht
automatisch geändert.
Also es ist verwunderlich, aber es ist nicht alles auf USB umgestellt
worden.
Ich würde mal wetten, dass es irgendwelchen alten Geräten, die seit
mehreren Jahrzehnten so vor sich hin funktionieren, Atomkraftwerke,
hat wahrscheinlich ziemlich wenig von der Steuerung ist per USB.
Okay, da wird irgendwas anderes benutzt werden und das irgendwas
anderes wurde halt damals gemacht oder vielleicht Flugzeuge werden
garantiert kein USB für ihre Steuerung benutzen.
Die müssen ja alles verifizieren und überprüfen und tausendfach
redundant und keine Ahnung.
Und bei Flugzeugen ist es so, die wurden ja irgendwann mal entwickelt.
Es kommen ja nicht so viele neue Flugzeugmodelle raus pro Jahr.
Die wurden irgendwann mal entwickelt.
Boeing 747 ist uralt vom Design her, vom Prinzip her zumindest.
Die wurde dann in neun Versionen, aber egal.
Also vom Prinzip her ziemlich alt.
Und was auch immer damals verifiziert worden ist, das benutzen die
heute noch, weil das ist verifiziert worden.
Das wurde getestet und es funktioniert.
Und jetzt was Neues zu benutzen, hätte überschaubare Vorteile.
Es wäre quasi wahrscheinlich kleiner als das alte Design, aber so ein
paar Kubikmeter mehr Raum kannst du jetzt auch nicht so gut brauchen.
Bringt nicht so viel im Flugzeug, was halt eh schon relativ viel
Innenraum hat eigentlich.
Also du kriegst keinen neuen Passagier rein, also kann man keinen
Nutzen daraus ziehen.
Es wäre ein bisschen leichter, aber ein paar hundert Gramm von mir
sogar ein Kilogramm leichter ist bei einem paar Tonnen Flugzeug auch
relativ schnuppe.
Also der Nutzen ist überschaubar, aber die Verifizierungskosten, um
neue Technologie zu benutzen, wären so hoch.
Wer zahlt das?
Das kommt ja nicht wieder rein, das Geld.
Und das sind Beispiele, wo wirklich solche uralt Komponenten noch
existieren, wo sie dann aber trotzdem irgendwann mit aktuelleren
Komponenten kommunizieren müssen.
Das ist dann genau die Schnittstelle, also die Stelle, wo man
irgendwie von dem 32 Bit Systembus auf eine externe Komponente ran
muss, die nur 8 Bit hat.
Und um das zu tun, also ich meine, das war absehbar, dass sowas
passieren würde.
Und um es zu tun, gibt es bei vielen CPUs noch innen drin
Steuersignale, so einzelne byte enable Steuersignale, mit denen man
eben sagen kann, dass eben nicht der komplette 64 Bit Datenbus gemeint
ist, der kommunizieren soll, sondern dass nur einige wenige, also eins
vielleicht sogar nur byte davon gemeint ist.
Und das ist insbesondere, dass die Daten an dieses Byte sollen.
Das sehen wir gleich mal hier in einem Beispiel.
Wir haben hier einen Datenbus von mir aus 32 Bittig, ist egal, könnte
auch 40 sein.
Und wir haben hier alte Komponenten, die jeweils nur 8 Bittig sind.
Jetzt ist erstmal die Frage, wie schließe ich die an?
Also 8 Bit brauche ich, 32 Bit habe ich, also schließe ich sie an
irgendeines der Byte an?
Also ich werde zum Beispiel die Bits 0 bis 7 benutzen oder hier sind
es die Bits 8 bis 15 oder hier wären es dann die Bits 16 bis 23.
Also an eins der Bytes schließe ich es an.
Und jetzt muss ich der CPU, wenn die CPU jetzt quasi zum Beispiel
schreibend auf so eine Komponente oder lesend, egal, auf eine
Komponente zugreifen will, muss ich ihr sagen folgendes.
Die CPU wird ja die kompletten 32 Bit entgegennehmen, als zum Beispiel
lesen, also als Lesezugriff, die kompletten 32 Bit reingeladen.
Jetzt weiß ich zum einen aber nur ein Byte davon ist überhaupt gültig,
weil diese Peripherie ergibt nur ein Byte an Daten aus.
Und jetzt will man gleichzeitig noch, dass dieses Byte im Idealfall an
dem least significant Byte hin platziert wird, auch wenn es hier nicht
notwendigerweise am least significant Byte platziert ist.
Und dafür gibt es ja diese Steuersignale, die dann eben sagen, also
quasi ein Multimedia Umschalter, der genau weiß, wo kommen die Daten
rein und wo sollen sie hin.
Dann schreiben wir eben genauso in die andere Richtung.
Und damit kann man relativ einfach mit so alten Komponenten reden,
könnte man auch ohne.
Da müsste man quasi immer die 32 Bit reinlesen.
Die restlichen Byte Signale, also diese drei nicht benutzten Bytes,
könnten zufällige Werte enthalten.
Also müsste man die erstmal raus maskieren, also mit und
überschreiben, dann das eine Datenwort, das eine Datenbyte an die
richtige Stelle schieben, könnte man alles in Software machen.
Aber das ist eine Sache, die ist überschaubar einfach.
Das kann man auch durch so eine einfache Hardware Schaltung erledigen
lassen.
Damit kann man dann einfach 8 Bit Komponenten noch benutzen.
Okay, jetzt haben wir ein paar Beispiele gesehen für diese
Systembausteine.
Also Systembausteine waren die Sachen, die wir zuvor gesehen hatten.
Alles so als Oberfamilie ist Systembaustein.
Und wenn wir uns mal überlegen, was wir eigentlich gesehen haben oder
was die alles können müssen, könnte man sowas sagen, wie hier gemalt
ist.
Im Wesentlichen sehen die alle grob aus wie dieses schematische Bild
hier.
Es gibt einmal eine Seite, wo der Systembaustein mit dem Bus und
danach der CPU kommuniziert.
Datenbus, Adressbus und noch eine Menge Steuersignale.
Und dann gibt es zum anderen die Seite, wo der Systembaustein mit der
wirklichen Peripherie redet, die er eigentlich abstrahieren soll, die
dann vielleicht sogar wirklich off-chip ist, je nachdem was es ist.
DMA wäre immer noch on-chip, irgendein Drucker wäre dann off-chip, was
auch immer es dann sein soll.
Und zwischendurch, ich meine nicht zwischendurch, sondern innen drin,
hat er halt auch solche Sachen, dass es einen Puffer gibt, der
Datenbus Sachen speichern kann, also zwischen speichern kann.
Dass es eine Art Steuerwerk gibt, was halt eben sagt, in welchem
Zustand ist diese Steuer, diese Peripherie Baustein gerade?
Was macht der gerade?
Ist der bereit?
Soll der Daten entgegennehmen?
Soll der irgendwas ausgeben vielleicht?
Also die Ausführung steuert mit Statusregister, Steuerregister,
Befehlsregister, quasi wie man es von einer einfachen CPU her kennen
würde und dann noch eine Ausführungseinheit, die quasi direkt
angeschlossen ist an die eigentliche Peripherie und die kommunizieren
dann über diesen internen Bus hier.
Gucken wir uns die Komponenten einzeln an.
Das Steuerwerk wäre das Ding hier oben.
Das redet, macht die Kommunikation mit dem Bus und somit mit der CPU.
Das steuert erstmal alle internen Komponenten, die es gibt, also
Register, wo Anfragen zum Beispiel zwischen gepuffert werden und es
steuert die nach innen halt eben, also die Register zur eigentlichen
Peripherie hin.
Die Ausführung, also das ist die Abstraktion quasi, die von außen
zugreifbar, direkt zugreifbar ist und die halt eben Systemzustände
nach außen weitergibt, wenn jeder von außen entgegen nimmt.
Die Ausführungseinheit ist dann spezifischer, die macht dann quasi die
wirkliche Arbeit, die wirkliche Kommunikation.
Die muss dann entsprechend auch spezifisch sein für was auch immer für
einen Baustein hierhinter eigentlich kommt.
Was kann der, wie will der angesprochen werden?
Das muss alles in der Ausführungseinheit hier unten drin sein.
Ein Beispiel, wie man es komplett zusammenhängend sehen würde.
Wir hätten jetzt quasi hier den Prozessor zusammen mit jetzt mal
repräsentativ einem allgemeinen mehreren Schnittstellenbausteinen.
Das wäre das, was man den Microcontroller nennt, also quasi das
eigentlich ein großer Teil von dem Gesamtsystem, zumindest von dem On
-Chip -System.
Und dann gibt es wirklich externe, also Off-Chip-Peripherie Geräte,
ein paar natürlich On-Chip, DMA und sowas, aber auch wirklich welche,
die Off-Chip sind, die gehören dann wirklich irgendwie nicht mehr zum
Control dazu, denn das sind externe Geräte, die irgendwie angesprochen
werden können.
Hier kann man sehen, dass es immer über diese mehreren Kommunikationen
gibt.
Diese Kommunikation hier wäre über den Bus.
Also an diesem Daten-Adress-Bus hängen noch viele andere Sachen mit
dran.
Wohingegen hier ist wirklich eine normalerweise Punkt-zu-Punkt
-Verbindung gemeint.
Also der eine Schnittstellenbaustein wird mit genau einem Peripherie
-Gerät reden.
Hängt im Detail auch wieder davon ab.
Es gibt zum Beispiel verschiedene Peripherie-Protokolle, wo dann quasi
auch wieder externe Busse aufgezogen werden können, wo dann mehrere
Sachen dranhängen.
Gibt verschiedene Varianten.
Aber hier auf jeden Fall hängen mehrere dran, hier häufig nur eine.
Kommt drauf an, was dann im Einzelnen ist.
Datenleitungen sind meistens, ja können beide Richtungen sein,
parallel, seriell.
Also On-Chip-Sachen sind eigentlich quasi immer parallel, weil so ein
paar mehr Metallleitungen, das stört jetzt nicht so unglaublich viel.
Wogegen Off-Chip ist es häufig, also früher gab es viele parallele
Leitungen, bis es halt eben angefangen hat, nicht mehr zu
funktionieren.
Im Sinne von bei hohen Taktfrequenzen gibt es Schwierigkeiten bei
parallelen Datenleitungen.
Zum Beispiel, wenn ich sehr, sehr viele 64 parallele Datenleitungen
habe und die schlimmste Fall wäre, alle gleichzeitig toggeln, den Wert
ändern.
Und zwar alle gleichzeitig vom Extremfall 0 zum Extremfall 1.
Dann gibt es ein unglaubliches Rauschen im Gesamtsystem, was andere
Komponenten stören könnte.
Einfach, weil einfach unglaublich viele Leitungen gleichzeitig
umgeladen werden müssen.
Also das könnte andere Komponente stören.
Es gibt auch Fälle, wo so eine Leitung, so ein Bus sich selber
gründlich stören kann.
Angenommen, ich habe alle Leitungen bis auf eine, die sind 0, die eine
ist 1 und jetzt ändern alle ihre Wert.
Also quasi 63 Leitungen gehen von 1 auf 0 und die eine einzige Leitung
irgendwo in der Mitte, die vielleicht gerne 1 bleiben würde oder die
von 0 auf 1 wechseln würde, die wird ein ganz fürchterliches Rauschen
in ihrer Umgebung wahrnehmen und der, der diesen 64-Bit-Bus lesen
möchte, wird wahrscheinlich nicht das lesen, was er erwartet.
Also quasi, wenn ich ganz viele Leitungen habe, die alle von 1 auf 0
wechseln und eine einzige Leitung, die von mir aus von 1 auf 1 bleibt,
gut versteckt in ganz vielen anderen und das hier alles ungefähr
ziemlich genau gleichzeitig passiert, dann wird man auf der Leitung,
wenn ich da mal rauszoome, würde ich halt eben auch was sehen, die
soll 1 sein, die wird am Ende auch wieder 1 sein, aber zwischendurch
wird die einen ganz gewaltigen Einbrecher haben.
Also wird einfach runtergezogen, von den anderen Leitungen wird die
mit runtergezogen.
Und wenn ich halt eben dann in dem Moment die Messung mache, dann lese
ich vielleicht noch eine 0 oder vielleicht wieder eine 1, je nachdem,
welche Leitung ich angucke.
Also so große parallele Datenbusse haben auch Schwierigkeiten, vor
allem dann, wenn die Taktfrequenz hochgeht.
Wenn die Taktfrequenz langsam bleibt, dann werde ich ja eher weiter
hier hinten lesen, weil der nächste Takt kommt erst sehr spät.
Wenn die Taktfrequenz hoch ist, werde ich, je höher der kommt, desto
näher hier dran werde ich rücken, weil die Takte kommen sehr kurz
nacheinander.
Desto höher ist die Chance, dass ich genau in dem Moment lese, in dem
das Signal noch irgendeinen Blödsinnswert hat.
Also rauscht.
Also das ist die Schwierigkeit von parallelen Leitungen.
Deswegen ist man gerade bei Off-Chip-Sachen häufig auf serielle
Leitungen gewechselt.
Also USB ist sicherlich das Paradebeispiel.
Also Datenleitungen, Steuerleitungen, Meldeleitungen, einfach nur die
verschiedenen Richtungen.
Steuerleitung heißt immer, die Peripherie wird gesteuert, wenn man
sagt, was sie tun soll.
Meldeleitung heißt, sie informiert zurück, wie es ihr gerade geht,
womit sie beschäftigt ist, ob sie bereit ist, ob es Störungen gab.
Solche Sachen.
Wenn ich jetzt diese Komponenten habe, die sind Memory-Mapped oder
Isolated Address Space, wie auch immer, ich kann mit denen reden und
dann gibt es immer noch verschiedene Varianten, wie ich mit denen
rede, was im Wesentlichen bedeutet, wie ich auf Antwort warte.
Das eine, die einfachste Variante wäre dieses Programmable IO,
Programmierte Ein-Ausgabe, die einfach so funktioniert, es gibt eine
Speicherseite für die Peripherie, da gibt es ein paar Steuerwerte, wo
man hier DMA, wo man beim DMA sagen kann, Start, Ziel, Länge und dann
gibt es vielleicht irgendeine Adresse an dieser Seite, die man lesen
kann.
Und wenn man sie liest, stehen da Statuswörter drin, die sagt, DMA,
Kopieoperation abgeschlossen oder hat einen Fehler verursacht, weil
die Adresse gab es überhaupt nicht.
Irgendwie sowas.
Und die CPU bei diesem Programmable IO würde quasi dauernd diese
Zieladresse lesen, um dieses Statusregister über das Memory Map der
Statusregister zu lesen, um zu fragen oder um zu warten, bist du
fertig?
Also quasi einmal hinschicken, Start, Ziel, Länge, danach fängt das
Ding an.
Eventuell brauchst du noch einen speziellen Schreibzeug, der sagt, das
waren jetzt gültige Daten, fangen an.
Danach macht es zumindest, dauert eine Weile.
Währenddessen könnte die CPU entweder was anderes machen und dann
zwischendurch mal fragen, bist du fertig?
Oder es könnte einfach, wenn es nichts anderes zu tun hat, die ganze
Zeit fragen, bist du fertig, bist du fertig?
Was eigentlich nur heißt, immer wieder diese Adresse lesen, um zu
gucken, ob das Fleck sich geändert hat.
Jetzt fällt einem auf, da gibt es ein Problem bei.
Ich meine, da gibt es mehrere Probleme bei.
Aber eins, was einem vielleicht nicht sofort auffällt, ist Folgendes.
Wir hatten doch mal dieses Kapitel über diese Dinge, die hießen
irgendwie Cache oder so ähnlich.
Wenn jetzt eine CPU immer wieder die gleiche Adresse liest, nämlich
dieses Statusregister, was wird der Cache machen?
Dann wird sich die Adresse merken und dann wird quasi die Anfrage der
CPU aus dem Cache beantwortet.
Und die eigentliche Peripherie, die wird gar nicht mehr gefragt.
Das würde also quasi jetzt pauschal mit dem System, wie wir es bisher
gesehen haben, überhaupt nicht funktionieren.
Der erste Zugriff auf das Statusregister würde noch wirklich, miss,
einen Zugriff auf die Peripherie ergeben.
Und danach würde der Cache sagen, hey, das habe ich schon, die ist
noch nicht fertig, glaub mir.
Also der weiß ja nicht, was die Daten bedeuten.
Der würde einfach nur die Daten zurücklegen, die Daten wären das
gleiche wie vorhin.
Also hier haben wir einen Fall, wo man auf jeden Fall in der Lage sein
muss, dem Cache zu sagen, also diesen Eintrag brauchst du dir gar
nicht merken, denn der ändert sich, der ändert sich außerhalb
irgendwo.
Der muss jedes Mal neu gelesen werden.
Und das ist dann auch gleich ein Beispiel für, wir hatten vorhin
gesehen, Cache, Cache Controller sind auch programmierbare
Steuergeräte.
Und das wäre halt genau so eine Sache, wo man denen sagen muss,
gewisse Adressbereiche sind non-cacheable.
Die dürfen nicht im Cache eingelagert werden.
Weder beim Lesen, also das ist quasi eine Peripherie, dass man das gar
nicht sehen würde, eine Änderung in dem Statusregister.
Das darf nicht im Cache landen, das darf nicht aus dem Cache
beantwortet werden.
Zum Lesen nicht, aber auch zum Schreiben nicht.
Ich will ja nicht in der DMA-Einheit sagen, ich schreibe mal dies,
also Startadresse, Zieladresse, Länge.
Und der Befehl hängt im Cache fest, weil das ein Writeback-Cache ist
und kommt nie bei der DMA-Einheit an.
Nie im Sinne von, bis es da mal raus verdrängt wird.
Also auch beim Schreiben muss es direkt durch den Cache durch, auch
wenn es eigentlich ein Writeback-Cache ist, direkt zur Peripherie.
Und deswegen gibt es in dem Cache, kann man einstellen, also bei quasi
allen Caches kann man einstellen, gewisse Adressbereiche sind nicht
cachebar.
Oder alternativ, wenn das nicht geht, es gibt auch Caches, wo das
nicht geht, muss die Software dafür sorgen, dass sie quasi sagt,
Schreibzugriff, das wird jetzt wohl im Cache gelandet sein,
Cacheflush.
Entweder der Cache muss komplett geflushed werden oder vielleicht kann
man sagen, einzelne Adressbereiche müssen geflushed werden, um es
wirklich raus zu zwingen zur Peripherie.
Genauso beim Lesen.
Ich habe es schon mal gelesen oder ich habe es vielleicht schon mal
gelesen, also muss ich erst Adresse invalidieren.
Also muss ich im Cache sagen, Cacheflush, wieder die Adresse, damit
sie auf keinen Fall mehr im Cache drin ist.
Und dann lesen, weil dann ist es ein Miss und der Cache muss es neu
holen.
Also je nachdem, was für ein System das ist, muss man es so oder so
machen.
Als Programmierer hat man es zum Glück ein bisschen einfacher, muss
man sich nicht so genau darum kümmern.
Aber es gibt da zum Beispiel, in C müsste man jetzt auch angeben, ist
das ein normaler Hauptspeicherzugriff, der an Speicher geht, der kann
gecached werden.
Oder geht es an eine Peripherie, der muss immer neu gelesen werden.
Gibt es ein Schlüsselwort für, würde in C volatile heißen.
Und hätte ich quasi ein volatile in I, würde das für den Compiler
heißen, alle Zugriffe auf I dürfen nicht gecached werden.
Und dann muss der Compiler, der ist ja architekturspezifisch, der
Compiler, der würde dann wissen, kann der Cache eingestellt werden auf
eine non-cacheable region.
Dann würde er die Variable I halt eben im Bereich anlegen, wo er dem
Cache sagt, der Bereich ist nicht cachebar.
Oder wenn der Cache das nicht kann, müsste er halt eben immer beim
Zugriff auf das I den Cache vorher oder nachher, je nachdem, ob es ein
Lese - oder Schreibzugriff war, flaschen.
Aber zum Glück kümmert sich der Compiler darum.
Aber das darf man nicht vergessen, wenn man solche Zugriffe hat.
Ich meine, bei normalen CPU macht man das nicht.
Aber wenn man mit irgendeinem kleinen Controller arbeitet, arbeitet
man häufiger mit Peripherien.
Wenn man dann dieses volatile vergisst, kann es sein, dass es halt
manchmal funktioniert und manchmal nicht.
Das kann dann sehr ärgerlich sein.
Gut, das wäre jetzt so eine Konsequenz, die sich aus dem Programmable
IO ergibt.
Man muss irgendwie dafür sorgen, dass es auch wirklich am Cache vorbei
an der Peripherie ankommt.
Das ist der eine Nachteil sozusagen.
Der andere Nachteil ist, ich muss natürlich jetzt auch immer selber
prüfen, ob es fertig ist.
Und der Extremfall des Selberprüfens, er wird Busy Waiting genannt.
Das heißt einfach, ich habe nichts, was ich sonst tun kann.
Ich muss darauf warten, dass die Anfrage fertig ist.
Und habe darum in einer sehr kurzen Schleife, frage ich immer wieder
diese Peripherie an.
Das erzeugt unnötige CPU-Last.
Das erzeugt aber auch unnötige Buslast.
Zum Beispiel, ich habe ja DMA gesagt von nach Länge.
Der Bus sollte jetzt im Idealfall beschäftigt sein, diese
Kopieoperationen zu machen.
Aber wenn die CPU jetzt dauernd fragt, bist du schon fertig?
Bist du schon fertig?
Das braucht ja auch Buszeit.
Ja, weil dieses bist du schon fertig?
Muss ja zur DMA-Einheit gehen und die muss sagen, nein, jetzt, Gott,
warte.
Also das kostet auch dann wirklich, die Kopieoperationen wird
langsamer dadurch.
Es dauert wirklich Zeit.
Nicht nur, dass die CPU nichts anderes macht, sondern auch das
Kopieren wird langsamer dadurch.
Aber, ja, also hohe Reaktionsgeschwindigkeit.
Wenn es dann irgendwann fertig ist, bekommt man es wahrscheinlich auch
ziemlich früh mit.
Also es ist zwar langsamer, also später fertig geworden, aber wenn es
dann fertig ist, bekommt man es ziemlich schnell mit.
Okay, das wäre die eine Variante.
Die andere Variante, interrupt-gesteuerte Einausgabe.
Das würde jetzt einfach heißen, ich sage der DMA-Einheit von nach
Länge und wenn du fertig bist, informiere mich mit einem Interrupt.
Und das heißt, die CPU würde dann quasi danach irgendwas anderes
machen.
Die DMA-Einheit würde selbstständig auf dem Bus die Kopieoperationen
machen.
Und wenn die DMA-Einheit fertig ist mit dem Kopieren, würde sie eine
Unterbrechung an die CPU schicken.
Die CPU wird mit dem, was sie gerade macht, unterbrochen.
Und es wird ein Händler, ein Abarbeiter, ein Händler, ein Ding, was
die Unterbrechung bearbeitet, aufgerufen.
Und der kann dann sich überlegen, was er eigentlich tun wollte.
Zum Beispiel könnte der sowas machen wie, wenn die eine DMA-Operation
fertig ist, dann startet doch danach die nächste.
Das könnte er dann quasi machen, ohne dass die eigentliche Anwendung
davon überhaupt informiert wird.
Oder der könnte sowas machen wie, setze eine Variable von der
Anwendung auf einen gewissen Wert.
Und dann fragt irgendwann die Anwendung diese Variable ab.
Und jetzt ist ja magischerweise der Wert geändert.
Das wäre dann quasi aber eine Abfrage von dieser Variable, also ein
Register zum Beispiel, ja, Register 7.
Das wäre dann nicht, dass dann dauernd ein Buszugriff passieren muss,
weil Register 7 ist im Registerfall.
Also die kann quasi was anderes machen, kann ab und zu mal Register 7
abfragen, wo dann drinstehen sollte, ist es fertig, ja oder nein.
Irgendwann schreibt der InShop-Händler das Register 7 rein, hab's
erledigt.
Oder mir wurde gesagt, es wurde erledigt, lieber Soren.
Und das merkt dann die Anwendung, indem sie das Register abfragt.
Also nicht den Cache und den Bus, also da stört sie niemanden, sondern
einfach, es bleibt innerhalb der CPU.
Das heißt, die CPU kann währenddessen quasi beliebig andere Sachen
machen.
Und vor allem, wenn die Transaktion lange dauert, ist das wichtig.
Lange entweder, weil viel Daten kopiert werden müssen oder weil die
Peripherie einfach sehr langsam war.
Also egal, welcher der beiden Gründe ist, aber zumindest wenn es lange
dauert.
Hat aber auch einen Nachteil, nämlich diese Interrupts, die erzeugen
auch einen gewissen Overhead.
Also dieses Stören der CPU in der Ausführung und Wechsel in diesen
InShop -Händler, das kostet halt irgendwie auch Zeit.
Und dann hängt es von der CPU ab, ob es mehr oder weniger Zeit kostet,
wie viel Aufwand das eigentlich ist.
Also das hängt von Fall zu Fall ab.
Viele Systeme versuchen wirklich Features anzubieten, die diesen
Overhead reduzieren, damit die InShops möglichst schnell abgearbeitet
werden können.
Gut, also natürlich ist die DMA-Einheit, ich habe sie immer als
Beispiel benutzt, aber sie ist auch eine Möglichkeit, wie man
Transaktionen machen kann.
Also sprich, anstatt dass man selbst mit einer Peripherie redet, die
ja eventuell sehr langsam ist, weil dahinter eine Off-Chip-Peripherie
sitzt, kann man halt eben dieses Reden mit der Peripherie, also das
man ganz entweder machen, indem man Memory-Maps programmiert, also
schreiben, warten bis das Schreiben an die Peripherie fertig ist,
irgendwann mal lesen, hast du es erledigt, oder schreiben an die
Peripherie und warten bis ein InShop kommt, dass es erledigt wurde.
Und anstatt das selber zu machen, kann man halt eben auch die DMA
-Einheit damit beauftragen.
Also nicht nur Memory kopieren, wie von Speicher A nach Speicher B,
sondern eben auch Memory kopieren von Speicherbereich nach sehr
langsame externe Peripherie.
Also man kann die DMA-Einheit wirklich hier auch als Feature benutzen,
um halt eben mit langsamen externen Geräten zu kommunizieren.
Und die DMA-Einheit selber, mit der würde man dann auch wieder reden,
also man würde quasi mit der DMA-Einheit reden, anstatt mit der
Peripherie reden.
Und das Reden mit der DMA-Einheit, das wäre dann entweder Interrupt
oder Programmable I.O.
Gut, ja, das Synchronisieren.
Also es ist einfach nur, ich habe jetzt hier irgendwie, was hatten wir
vorhin?
Wir hatten so ein ähnliches Bild.
Hier war der Microcontroller-CPU, danach kam der
Schnittstellenbaustein und hier dann eventuell die Off- oder
vielleicht auch On-Chip, sagen wir mal jetzt Off-Chip-Peripherie.
Das Synchronisieren ist hier einfach nur, dass es irgendwie so Signale
gibt, die eine Anfrage stellen und ein Signal gibt, was sagt, ich habe
es erledigt.
So wie Quest und Acknowledge.
Das ist alles.
Und das kann jetzt Hardware- oder Software-mäßig gemacht werden.
Hardware-mäßig würde heißen, die CPU redet mit dem Steuerwerk von dem
Schnittstellenbaustein, sagt ihm, das soll getan werden und danach
weiß der Schnittstellenbaustein, dass er erst eine Request schicken
muss, zusammen mit Daten, mit was auch immer und dann muss er warten,
bis irgendwann das Acknowledge kommt und so weiter.
Das wäre die Hardware-Lösung.
Alternativ könnte man das hier auch relativ minimalistisch halten und
die Daten für Request und Acknowledge quasi einfach durchgeben an die
CPU und die CPU könnte quasi selber sagen, ich mache einen
Schreibzugriff an eine gewisse Adresse und setze ein gewisses Bit auf
1 und dieses Bit ist das Request-Signal der Peripherie.
Und danach lese ich die CPU die ganze Zeit das Acknowledge-Bit.
Also ein Speicherwort im Speicher, wo ich weiß, an dem Bit ist das
Acknowledge -Signal von der Peripherie angebunden.
Hört sich jetzt irgendwie blöd an, ist es prinzipiell ja auch, weil so
ein Hardware-Baustein ist meistens relativ klein, flächenmäßig, also
günstig, stört nicht, schadet niemandem.
Aber wenn er nicht da ist, ist er nicht da.
Wenn ich zum Beispiel irgendwie eine CPU, einen Controller habe, also
ich habe einen Chip gekauft, da ist ein Microcontroller drauf und der
hat von mir aus leider keine Peripherie, keinen Peripherie
-Schnittstellen -Baustein für ein Protokoll, was ich gerne benutzen
möchte.
Sagen wir mal I²C, ist egal, egal was es ist.
Irgendein ziemlich langsames, serielles Protokoll, das hat ein
gewisses Protokoll.
Also ja, muss man gewisse Sachen, manchmal muss man auf 1, manchmal
auf 0, das wird dann vorgegeben.
Und wenn es jetzt keinen Hardware-Baustein gibt auf dem Chip, der das
für einen macht, dann kann man das selber machen in Software.
Und das klappt deswegen, weil diese Off-Chip-externen Peripherien
langsam sind.
Die arbeiten im Kilohertz-Bereich, vielleicht sogar so, die können
auch so um einen knapp zweistelligen Megahertz-Bereich hochkommen.
Aber viel mehr ist das meistens nicht.
Und wenn ich dann mit einer 100 Megahertz oder noch schneller CPU
arbeite, dann kann ich quasi mit Software die einzelnen Bits von dem
Protokoll auf 1 und auf 0 setzen und lesen, was die Antwort war und
damit diese Peripherie, dieses Protokoll selber sprechen.
Was ist dumm und ungeschickt und kostet unnötig viel Zeit.
Aber wenn ich diesen Schnittstellen-Baustein nicht habe, ist es halt
trotzdem eine Lösung, die funktioniert.
Und dafür wird das wirklich eingesetzt.
Da gibt es wirklich Software, die dann quasi diese Protokolle, i
Quadrat C wäre ein typisches Beispiel dafür, in Software
nachimplementieren für die Fälle, dass man mal keine Hardware
-Implementierung dafür hat.
Im Normalfall würde man das mit Hardware machen, aber geht alles auch
mit Software.
Was sollte man noch unterscheiden können?
Die Leitungen, immer wie die benutzt werden können.
Da gibt es diese verschiedenen Varianten von Duplex-Betrieb.
Voll-Duplex heißt, dass ich beide Richtungen gleichzeitig
kommunizieren kann.
Also Adresse geschenkt, mehr brauche ich nicht.
Aber Daten will ich halt eben für Lesen und Schreiben.
Und gleichzeitig heißt während eine Schreib-Anfrage zum Beispiel
gerade jetzt Daten schickt, kann gleichzeitig von einer vorherigen
Leser -Anfrage, die dauert ja ein bisschen, bis die Daten da sind,
kann gleichzeitig zurückgeschickt werden.
Also es muss einen Adressbus geben, einen Schreib-Datenbus und einen
Lese -Datenbus.
Muss irgendwie alles da sein, sonst könnte ich es nicht gleichzeitig
machen.
Halb -Duplex ist das Normale, was man hat.
Also jetzt für so CPU-Sachen das Normale.
Ich habe eine Datenleitung, die entweder in die eine oder in die
andere, aber nicht in beide gleichzeitig Richtungen benutzt werden
kann.
Wenn ich Voll-Duplex in beide Richtungen gleichzeitig kommunizieren
kann, dann habe ich häufig auch getrennte Request-Acknowledge
-Leitungen für beide Richtungen getrennt.
Und ich habe vielleicht sogar getrennte Adressleitungen, sodass man
wirklich völlig verschiedene Anfragen parallel laufen lassen kann.
Ja, was Request-Acknowledge machen, ist glaube ich relativ klar.
Gut, das wäre von Bussen und Peripherie-Komponenten und so weiter
glaube ich.
So als grobe Übersicht von was es an sich so für Konzepte gibt.
Ja, das wäre es mal alles gewesen.
Dann gibt es halt viele im Detail, aber als grobe Übersicht, was es so
gibt, soll es mal ausreichen an der Stelle.
Okay, jetzt kommen wir endlich mal zu dem Kapitel Interrupts, wo mir
schon ein paar Mal aufgefallen ist, dass man es doch hätte drastisch
früher dran hätte kommen lassen sollen.
Sollte man mal nach vorne schieben.
Na gut, jetzt haben wir es schon häufig genannt.
Jetzt müssen wir mal gucken, was es eigentlich ist.
Also das allgemeine Wort dafür wäre eine Ausnahme.
Im Sinne von, also Exception.
Im Sinne von die Anwendung läuft so fröhlich vor sich hin, dann
passiert irgendwas, naja, vielleicht nicht unvorhergesehen, aber halt
eben nicht Teil der normalen Anwendungsausführung, sondern halt immer
eine Ausnahme davon.
Und das sorgt dafür, dass diese Ausnahme irgendwie jetzt behandelt
werden muss.
Entweder jetzt sofort oder jetzt demnächst.
Was könnten Ursachen für solche Ausnahmen sein?
Das könnte zum Beispiel sein, Fehler im System, bitte ausführen von
Anwendungsprogramms.
Also, naja, sehen wir gleich noch mehr Beispiele, so ein bisschen
konkretere, aber angenommen, das Anwendungsprogramm wird ausgeführt.
Ach, wir hatten doch, Wörter über Speicherhaltung hatten wir doch
schon.
Also, Programm wird ausgeführt, es kommt ein Load auf eine Seite, die
Seite ist nicht da.
Dann kann das Programm nicht weiterlaufen, das geht nicht.
Die Seite muss erst in den Speicher reingeholt werden.
Das wäre eine Ausnahme.
Normal wäre, das Programm läuft weiter, aber nein, Ausnahme.
Programm wird unterbrochen, die Seite wird reingeholt.
Danach kann es weiterlaufen.
Anderer pauschaler Grund, mehr Details später.
Eine externe Systemkomponente, eine Peripherie, könnte der CPU sagen,
hey, du wolltest doch vorhin was von mir.
Ich habe es jetzt erledigt.
Also, können weitermachen.
Das wäre zum Beispiel so, was wir gerade gesehen hatten, als dieses...
...intergesteuerte Ein-Ausgabe.
Das wäre genau das, wenn die Komponente irgendwann sagt, bin fertig.
Das wäre ein Grund für eine Ausnahme.
Okay, und dann gibt es eine Behandlung von der Ausnahme durch eine
spezielle Routine.
Das ist einfach nur wiederum ein Stück Software, ein Stück Code, der
dann irgendwas tut, was die Ausnahme löst, oder irgendwie darauf
reagiert zumindest.
Wird häufig In-Job-Service-Routine genannt.
Okay, und für dieses ganze Zeug, diese Steuerung, wann kommen
Ausnahmen rein, was dürfen sie eigentlich machen, wo geht es dann
weiter, gibt es eben Hardware, die das Ganze unterstützt.
Prinzipiell, diese Ausnahmeroutine hat starke Ähnlichkeiten mit dem
Aufbau von einem Unterprogramm.
Ein paar Unterschiede gibt es.
Ein Unterprogrammaufruf wird immer erwarten, dass er quasi
Eingabedaten bekommt, an einer gewissen Stelle, an gewissen Registern.
Das ist bei einer Ausnahme nicht der Fall.
Da werden nicht erst irgendwelche Registerinhalte mit Werten gefüllt,
und dann wird die Ausnahme ausgelöst.
Warum nicht?
Naja, die Registerinhalte, da sind ja schon Werte drin.
Ich kann ja nicht einfach von der Anwendung die Registerinhalte
überschreiben.
Das wäre irgendwie schlecht.
Und das heißt, die Eingabedaten müssen irgendwo anders herkommen,
nicht über Register.
Was ist noch bei dem Unterprogrammaufruf?
Ich baue mir normalerweise einen neuen Stackframe auf.
Da kann ich dann noch zusätzliche Parameter übergeben oder sowas.
Und das Unterprogramm arbeitet dann in diesem neuen Stackframe.
Habe ich hier auch nicht, weil die Unterbrechung passiert ja nicht
zufällig, aber die passiert irgendwann.
Das meine ich.
Die passiert quasi unvorhergesehen irgendwann.
Und da habe ich jetzt wahrscheinlich nicht gerade einen Stackframe
vorbereitet.
Ich muss aber trotzdem irgendwie gewisse Sachen sicherstellen.
Ich muss sicherstellen, dass ich da weitermachen kann, wo ich
aufgehört habe.
Also ich muss irgendwie eine Hardware haben, die mindestens mal den
Programme -Counter rettet.
Ich werde jetzt offenbar irgendwo anders hinspringen und den Ausnahme
-Händler, den Händler, den Interrupt-Service-Routine, hier die
Interrupt -Service-Routine, werde ich bearbeiten.
Und danach, wenn die fertig ist, muss ich ja genau dahin zurück, wo
ich gerade herkam, als wäre nichts gewesen.
Das muss irgendwie passieren.
Also muss ich den Programme-Counter retten, wo ich herkam.
Und dann muss die Interrupt-Service-Routine, die muss den ganzen
anderen Kram retten.
Wenn die Register benutzen möchte, dann muss sie die gefälligst vorher
irgendwo hinsichern und nachher wieder herstellen.
Und wohin soll sie die denn sichern?
Die kann sie ja nur irgendwo hinmachen.
Und dafür wird dann meistens noch ein spezieller Stack von der
Hardware bereitgestellt, wo dann quasi Sachen hingerettet werden
können und wo sie dann auch wieder zurück gesichert werden können am
Ende.
Das sind dann alles Sachen, die dann quasi in Software, bei manchen
CPUs mit Hardware-Support, in dieser Interrupt-Service-Routine
abgearbeitet werden würden.
Nochmal die beiden.
Wir haben bei einem Unterprogramm, da steht im Quellcode explizit
drin, dass und wann es aufgerufen wird.
Und bei einer Interrupt wäre es quasi die Ausführung, der Start, der
Trigger kommt durch Hardware durch ein externes Signal, der sagt, hey,
ich will was.
Es gibt meistens eigentlich immer verschiedene Rücksprungbefehle.
Einen Rücksprungbefehl für normale Unterprogramme, einen
Rücksprungbefehl für Ausnahmebehandlungen.
Weil quasi, die müssen noch ein paar Sachen, muss die Hardware wieder
aufräumen.
Was sie am Anfang gerettet hat, muss sie auch am Ende wieder
herstellen.
Und dann ist noch die große Frage, wo ist denn dieses der Händler,
diese Interrupt-Service-Routine, die sich darum kümmert, dass der
Interrupt bearbeitet wird, wo ist der eigentlich im Speicher?
Und dafür gibt es eine Sprungtabelle.
Eine Sprungtabelle, wo quasi für jeden Interrupt, der passieren kann,
also eine Liste von, weiß ich nicht, 100 Interrupts, die passieren
können, steht drin, Interrupt 1, die Software, die das bearbeitet, ist
dort.
Ein Zeiger auf, dort ist der Händler.
Interrupt 2 ist dort, Interrupt 3 ist dort und so weiter.
Das sehen wir gleich noch auf dem Bild.
Der normale durch Software getriggerte Unterprogramm-Aufruf, der muss
meist nur den Program-Counter retten.
Zusätzlich muss die Ausnahme auch das Konzessor-Status-Wort retten.
Warum?
Die Ausnahme kann irgendwann passieren, zum Beispiel auch in einer
Code -Sequenz, die da lautet, vergleiche zwei Zahlen, abhängig von dem
Ergebnis des Vergleichs, springe, also bedingter Sprung, abhängig von
dem Vergleich.
Jetzt gibt es CPUs, wo man quasi den Vergleich der zwei Zahlen, das
Ergebnis davon, explizit in einem Register speichert.
Und es gibt aber auch CPUs, die eben so ein Prozessor-Status-Wort
haben, wo quasi Status-Flags drin sind, die sich das Ergebnis von dem
letzten Vergleich merken.
Also ich würde quasi einen Befehl haben, der heißt, vergleiche zwei
Zahlen.
Dann habe ich eine Menge Flags in dem Prozessor-Status-Wort, die da
heißen, die waren gleich, der eine war größer, das war eine negative
Zahl, die waren null.
Also die verschiedene Varianten an Ergebnissen sich merken und das
wird dann benutzt für den Sprungbefehl, der danach kommt, um bedingt
zu springen.
Wenn jetzt genau zwischen diesen beiden Compare und bedingter Sprung
ein Interrupt passiert und der Interrupt irgendwelche Software
ausrechnet, macht er ja nun mal, dann würde diese Software-Ausrechnung
auch das Prozessor-Status-Wort ändern und dann würde der bedingte
Sprung, wenn wir da wieder zurückkommen von dem Interrupt-Händler
zurück in die normale Software, eventuell anders springen, als er
eigentlich sollte.
Und deswegen muss auch das Prozessor-Status-Wort gerettet und wieder
hergestellt werden.
Und das ist eine Sache, die die Software normalerweise nicht machen
kann, weil einfach nur das Wort anzufassen, ändert schon irgendwelche
Flags darin.
Also das muss durch Hardware passieren.
Das macht quasi dieser Interrupt-Hardware-Mechanismus automatisch,
noch bevor der Interrupt-Händler eigentlich ausgeführt wird.
Dieser spezielle Rücksprung-Befehl hier würde quasi automatisch auch
das Prozessor-Status-Wort wieder auf den alten Wert wiederherstellen.
Was haben wir hier noch?
Naja, okay.
Wenn ich ein Unterprogramm habe, noch ein Unterschied, vergleich
Subroutine vs.
Interrupt.
Ein Unterprogramm, wenn ich meine Software drin stehen habe, Call,
Printf, whatever, das wird sofort gemacht.
Also da kann ich nicht vorher noch was anderes machen und später mal
Printf.
Nein, das wird jetzt gemacht.
Wohingegen, wenn ein Interrupt von außen reinkommt, dann ist das
erstmal nur eine Anfrage.
Eine Anfrage von außen, ich hätte da was, einen Grund für eine
Unterbrechung.
Jetzt kann die CPU aber in einem Modus sein, wo sie sagt, jetzt habe
ich aber gerade keine Lust.
Jetzt mache ich gerade was Wichtiges, störe mich jetzt nicht.
Zum Beispiel, wenn irgendeine langsame externe Peripherie sagt, ich
bin fertig, die CPU ist gerade in irgendwas Zeitkritischem dran, dann
kann sie explizit sagen, jetzt bitte mich nicht stören, das InShot
Enabled Flag ausschalten, ich kann jetzt nicht unterbrochen werden.
Hat man zum Beispiel auch immer in folgender Situation, angenommen, es
ist ein InShot passiert und der InShot Händler wurde gestartet, also
es wird gerade jetzt im Moment Software ausgeführt, nämlich Software
aus dem InShot Händler.
Was ist, wenn jetzt noch ein InShot reinkommt?
Wenn der jetzt auch ausgeführt werden würde, der erste InShot Händler
hat ja quasi den Program Counter gerettet und das Statuswort gerettet.
Wenn jetzt noch ein InShot passiert, dann würde der ja auch den
Program Counter und das Statuswort retten und damit das zuvor
Gerettete überschreiben.
Das wäre irgendwie schlecht.
Das heißt, wenn so ein InShot Händler beginnt, werden automatisch
erstmal InShots ausgeschaltet, es dürfen keine verschachtelten InShots
ausgeführt werden und wenn der InShot Händler, der den programmiert
hat, sich Mühe gibt, dann kann der sowas machen wie den Program
Counter selbst irgendwo anders hinretten auf dem eigenen Stack und das
Prozessor -Statuswort selbst irgendwo anders hinretten und dann kann
er sagen, ich, der InShot Händler, bin jetzt wieder unterbrechbar,
falls irgendwelche noch dringenderen InShots kommen, kann InShot
wieder auf Enabled setzen.
Er lohnt sich eigentlich nur dann, wenn man relativ langlaufende
InShot Händler hat, also wo der InShot Händler selber viele tausend
Befehle lang ist, denn es ist eine gute Idee, den unterbrechbar zu
machen oder es ist auch teilweise erforderlich, ich meine, eine von
den Unterbrechungen könnte ja zum Beispiel sein, das wird häufig gern
mal vergessen, Page Faults, was wir bei der Speichererwaltung schon
hatten, wenn quasi der InShot Händler ein Load Store auf eine Adresse
macht und wenn man nicht garantieren kann, dass diese Adresse
garantiert im Hauptspeicher ist, wenn es passieren könnte, dass man
ein Load Store macht im InShot Händler, dieser Load Store löst ein
Page Fault aus, der Page Fault schickt ein InShot zurück an die CPU,
die CPU sagt, also ich arbeite gerade an dem InShot Händler, ich kann
gerade nicht unterbrochen werden, aber der InShot Händler ist ja
derjenige, der wartet auf das Ergebnis, dass der Page Fault aufgelöst
wird, dann geht da gar nichts mehr.
Die warten alle aufeinander, es passiert einfach nichts mehr.
Das ist ein Deadlock.
Das heißt, wenn man Load Store benutzt in dem InShot Händler, muss man
entweder garantieren können, die Seiten sind auf jeden Fall da, es
gibt ja Seiten, die sind gepinnt, die dürfen nicht verdrängt werden,
oder man muss unterbrechbar sein.
Man muss selbst Progencounter und PSW retten und am Ende
wiederherstellen und dann sagen, jetzt bin ich selbst wieder
unterbrechbar.
Es gibt auch andere Gründe, wo sowas passieren kann, also da muss man
aufpassen.
Verschachtelte Interrupts, nested Interrupts können auch Kopfschmerzen
verursachen.
Vor allem ist sowas sehr lästig zu debuggen.
Gut.
Das war noch Übersicht, dann gibt es noch eine grobe Unterscheidung
von diesen Interrupts.
Es gibt zwei verschiedene Arten, die sich im Wesentlichen daran
unterscheiden, was der Grund war für den Interrupt.
Es gibt externe Ursachen und es gibt interne Ursachen.
Externe heißt immer, irgendwas kommt von außen rein.
Ich sage gleich noch was dazu, aber sagen wir erstmal Asynchron.
Die werden Interrupts genannt und dann gibt es welche, die sind
irgendwie Synchron, die werden dann Traps genannt.
Und mit Asynchron und Synchron ist das folgende gemeint.
Ich habe ein Stück Software, das läuft, Befehl für Befehl wird das
ausgeführt und wenn einer dieser Befehle Schuld ist daran, dass der
Interrupt kommt, zum Beispiel PageFault, weil es ein LoadStore Befehl
ist, das wäre ein Trap.
Beides Unterbrechungen, also Ausnahmen, die zu Unterbrechungen führen
und in dem Fall wäre die Unterbrechung ein Trap.
Nennt man meist nicht so ganz genau, aber korrekterweise wäre das ein
Trap, der ist Synchron zum Befehlsablauf passiert.
Der kann nicht irgendwann passieren, also ein PageFault Trap kann
nicht irgendwann passieren.
Der kann nur nach einem Load Befehl passieren oder nach einem Store
Befehl passieren.
Es wird niemals ein MUL Befehl ein PageFault auslösen.
Das wird einfach nicht passieren.
Außer bei x86, wo ein MUL Befehl ja auch wieder die Adressen aus dem
Speicher holen kann.
Aber ihr wisst, was ich meine.
Wohingegen Interrupts sind Asynchron zum Programmauflauf.
Der Grund für ein Interrupt hat nichts mit dem Programm zu tun.
Einfach irgendwann sagt irgendeine externe Peripherie, jetzt bin ich
fertig und will was.
Das sind die beiden verschiedenen Sachen, Interrupts und Traps.
Meistens wird von Interrupts geredet, aber prinzipiell müsste man
unterscheiden können.
Was haben wir hier noch?
Division by Zero, also ich kann natürlich ein DIV Befehl hinschreiben,
der teilt durch die Note von einem Register.
Und wenn das Register gerade den Wert Null enthält, dann wird eine,
das kann die Divisionsanhalt nicht ausrechnen, ist halt nicht
definiert, dann wird halt auch ein Trap, korrekterweise würde man Trap
sagen, ausgelöst, der halt eben sagt, also dieser Divisionsbefehl, das
wird nichts mehr.
Das wäre dann quasi der Unterschied nochmal zwischen Interrupts und
Traps.
Und jetzt einfach mal ein paar Beispiele.
Prozessor externe Ursachen, also Interrupts, die von außen reinkommen.
Reset, klar, ist ein Interrupt.
Es ist ein externes Signal, es ist sogar ein Knopf angeschlossen, da
kann man einfach draufdrücken und dann wird halt einfach ein Signal an
die CPU geschickt, die ist ja gerade beschäftigt, die arbeitet ja, die
läuft ja, die rechnet vor sich hin, hat irgendeinen Frogen-Konterwert
und arbeitet.
Dann drücke ich den Knopf und er sagt im Wesentlichen, hör mal mit dem
auf, was du gerade gemacht hast und mach stattdessen was anderes,
nämlich den Interrupt-Händler namens Reset ausführen.
Und der hat jetzt die Spezialeigenschaft, dass er normalerweise nicht
dahin zurückkehrt, wo er hergekommen ist, sondern dass er halt
irgendwo anders hin zurückspringt und das irgendwo anders hin ist halt
eben dann gut mal neu.
Genau, also man kann durch eine Taste, kann man den auslösen, es gibt
auch verschiedene andere Varianten, zum Beispiel gibt es viele
Microcontroller, wahrscheinlich auch CPUs, haben eine Brownout
-Detection.
Brownout ist quasi das Wort für Stromausfall, was aber hier einfach
nur heißt, wenn die Versorgungsspannung auffällig ist, auffällig im
Sinne von stark schwankt oder einfach stark runter geht, einbricht.
Also Versorgungsspannung ist eine Spannung, ist ein physikalischer
Prozess.
Er ändert sich relativ langsam, also die Spannung, Stromausfall sieht
aus, als würde es sofort passieren, aber sofort kann aus Sicht von der
CPU sein, dass man durchaus noch tausend Takte was rechnen kann, bis
das dann wirklich der Strom weg ist.
Also wenn die merkt, die Spannung geht gerade steil runter, dann kann
es durchaus Sinn machen, in den InShot-Händler rein zu hüpfen, der
nämlich die Informationen hält, die Spannung bricht gerade ein, dann
kann die noch was machen, die CPU.
Zum Beispiel wäre es eine gute Idee, wenn man merkt, die Spannung geht
weg, halt irgendwie der Festpaddel zu sagen, hey, du hast noch Daten
in deinem Cache, schreib die nochmal schnell auf die Platte,
vielleicht braucht man die ja noch.
Also solche Sachen so ein bisschen aufräumen halt eben, bevor die
Spannung dann ganz weg ist.
Einen halbwegs sinnvollen Strom geht aus Zustand zu bringen.
Watchdog ist eine andere Peripherie, die es auch in vielen Controllern
gibt.
Das ist quasi, ja, Wachhund.
Mein Gott, warum haben wir das?
Naja, heißt halt so.
Das ist einfach nur ein Zähler.
Der Zähler wird durch Software auf Null gesetzt und der Zähler zählt
danach jeden Takt hoch.
Und er wurde vorher einmal konfiguriert mit der Information, wenn
dieser Zähler jemals den Wert, ich weiß nicht, 2 hoch 30
überschreitet, dann ist was nicht in Ordnung.
Denn eigentlich sollte die Software den Zähler ganz regelmäßig auf
Null zurücksetzen.
Und wenn sie das nicht macht, dann ist irgendwas schiefgegangen.
Dann ist die Software irgendwo hängen geblieben, ist in irgendeiner
Schleife hängen geblieben, wartet auf eine Peripherie, die nicht
antwortet.
Also der Zähler sollte niemals überlaufen.
Und wenn der Zähler doch überläuft, dann weiß der Watchdog, hätte
nicht passieren sollen, dann resette ich das System einfach mal.
Dann hänge ich zumindest nicht mehr, aber ich bin nach einer kurzen
Boot -Up-Zeit wieder in einer stabilen Ausgangssituation.
Dafür sind diese Watchdogs gedacht.
Okay, dann haben wir hier noch ein paar andere Beispiele, die gucken
wir uns nächstes Mal an.
Das sind externe Ursachen.
Dann haben wir noch ein paar Beispiele für interne Ursachen und gucken
uns an, wie jetzt genau wir eigentlich rausfinden, wo der Händler
dafür ist.
Das wäre dann der Rest von diesem Kapitel.
Dann haben wir noch ein nächstes Kapitel hinterher, wo wir uns einen
Spezialfall von Prozessoren angucken, nämlich die digitalen
Signalprozessoren.
Was die eigentlich für eine Aufgabe haben und was an denen so ein
bisschen anders funktioniert als an normalen Controllern.
Am Mittwoch ist Übung, nächste Woche Montag würden wir dann
weitermachen.
Das wäre dann schon die letzte Vorlesung.
Und dann ja, bis nächste Woche.
Dankeschön.