Segmentation of 8086/8088 real mode

09/05/2016 16:52 C_O_R_E#1
Heyllo,

ich lerne Assembler für die obige Architektur und hänge am Anfang des Kapitels schon.


Der Adressbus der Architektur beträgt 2^20. Damit sind 2^20 Adressen addressibar und maximal benutzbarer Arbeitspeicher auf 1 MiB festgelegt.
Wenn ich nun einen 2^16 breiten Register habe und den Speicherplatz für Programme, OS,... adressieren möchte, kann ich es mit zwei Registern erreichen.
Ich verteile über den gesamten Speicher mehrere 65.536 Byte Segmente.
Jedes Segment hat einen Anfang und ein Ende. Die Gesamtgröße beträgt 64kByte. Wie muss ich mir dieses Segment vorstellen, bildlich? Was enthält es?
[Only registered and activated users can see links. Click Here To Register...]
Wie ich aus diesem Bild erkenne, besitzt ein Segment zeilenweise 2 Byte Adressen (denn unsere Register können nur 16 Bits adressieren). Diese können Code-/Datensegmente aufnehmen. Die Anzahl der 2 Byte Adressen beträgt 8. Insgesamt sind es also 16 Byte an Code/Daten. Das erklärt auch die Gesamtgröße, denn ich habe 2 Bytes, die jeweils 2 Byte groß sind und somit eine einheitliche Größe von 2 Byte^16 Byte bilden. 65.536 aber keine 64kByte...Liegt es daran, dass das Wiki zwischen den SI-Präfixen switcht ohne sich bemerkbar zu machen?


Das Bild, welches ich einige Zeilen zuvor beigelegt habe, enthält eine Trennung in der Mitte. Was bedeutet diese Trennung?


Vielleicht klärt sich die ein oder andere Frage, wenn ich jetzt mal weiterlese und im Hintergedanken das mir mal genauer anschaue.
09/05/2016 17:27 Krotus#2
#moved…
09/05/2016 17:41 C_O_R_E#3
Ich bin mir nicht sicher, ob es hier in die Sektion gehört....Es ist in Bezug auf Assembler programmieren, doch es handelt sich hier um eine Hardware Frage. Register und Segmentierung haben an sich nichts mit "Coding" zu tun.
09/05/2016 18:12 Jeoni#4
Ich denke, dass die Kollegen aus der Hardware-Abteilung sich in ihrem Metier auskennen und sicher ein paar Kniffe und Tricks der Hardwarehersteller kennen, um fundiertere Kaufentscheidungen treffen und Technik bewerten zu können. Dein Problem haben aber nur Leute, die Assembler programmieren und kaum bis niemand, der sich in heutiger Zeit mit Hardware beschäftigt.
Noch dazu ist Segmentierung auf modernen Prozessoren zwar noch vorhanden wird in den modernen 32- und 64-Bit Anwendungen aber nur sehr selten genutzt. Daher, rein aus Eigeninteresse, dürfte ich wohl erfahren, warum du dich für so "alte" Technik interessierst? Wissen ist nie schlecht und es gibt sicher gute Gründe, ich will nur deinen wissen.

Erstmal zu den "64 kByte": ja, das sollte nicht das SI-Präfix sein, wie man sich gut vorstellen kann.
Zur "Trennung": bedeutet sowas wie "...". Dort gibt es also noch mehr Speicherzellen, welche aber nicht abgebildet sind, um das Bild nicht zu lang werden zu lassen.
"Was enthält ein Segment?" Speicher. Segmentierung erfüllt zwei Funktionen:
a) mehr nutzbaren Speicher. Wie du bereits erwähntest, haben die genannten Architekturen nur 16 Bit Register. Damit könnte man lediglich 64 KiB an Speicher adressieren. Um mehr nutzen zu können, teilt man mehr (die besagten 1 MiB) in Segmente auf. Es wurden entsprechend Segment-Register (cs, ds, ss, ...) eingeführt, welche quasi das Segment ausweisen. Dabei wird jeder Speicherzugriff in einem der Segmente ausgeführt. Zusätzlich hat man halt noch ein Register oder sonst wie gestaltetes Offset, um die konkrete Adresse innerhalb des Segments zu bestimmen. Code wird von cs gelesen, der Stack wird über ss angesprochen, Daten mit ds. So lässt sich selbst in einer Anwendung mehr als nur die 64 KiB nutzen, die ein Register adressierbar machen würden.
b) Schutz. Programme sollen nicht im Speicher von anderen Programmen wühlen. Heutzutage haben wir Pages statt Segmente. Funktioniert alles etwas anders, aber Segmente wurden damals auch dazu benutzt, dass Programme voneinander getrennten Speicher nutzen.
Ferner bin ich mir nicht sicher, ob die Einteilung des Speichers in 2-Byte Zellen wirklich anschaulich korrekt ist. Das mag für frühere Architekturen anders sein, aber eigentlich gibt es keinen Zwang den Speicherzugriff auf Registergröße (hier 2 Byte) zu alignen. Man kann sein 2 Byte Register sowohl mit dem Inhalt aus den Adressen 0x01 und 0x02 füllen, wie auch aus 0x02 und 0x03. Ich hoffe, du verstehst, was ich meine.

Mit freundlichen Grüßen
Jeoni
09/05/2016 19:13 C_O_R_E#5
Ich lese mich in die Architektur hinein und die Erklärung ist echt mager, doch ich kenne kein besseres online Wiki, um es in Ruhe zu lesen. Das ist etwas lückenhaft erklärt und ich stutze es mit einigen Interpretationen zusammen.


Wie viele Speicherzellen sind das? Das müsste doch konstant sein. Allmählich hasse ich das Bild...
Gesamtgröße eines Segments sind doch 65 536 Bytes. Eine Speicherzele ist laut Bild 16 Bits(2Byte groß).
Um also 65 536 Bytes pro Segment zu liefern, teile ich doch die Größe des Segments durch die Größe einer Speicherzelle (2Byte).
Damit sind es ja dann 32 768 Speicherzellen, die jeweils 2 Byte groß sind.
Zusammengefasst:
Bei einer 20 breitigen Adressbus
existieren 16 Segmente, da 1 MiB / 2^16 (Größe eines Segments)
jedes Segment ist 65 536 Byte groß und besitzt 32 768 Speicherzellen, da 65 536 Byte / 2 Byte


Ich vermute mal ich stelle mir das Ganze total anders vor, weil ich nen Fehler im Gedanken habe und dadurch das Ganze nicht im Puzzle zusammenkriege.


Diesen Teil verstehe ich nicht so ganz, aber ich werde darauf mal zurückgreifen, sobald ich den Kern an sich verstehe.



Edit:// Im Wiki steht folgendes zusammengefasst:


*Jedes Segment fasst maxial 64 kByte, weil die Register der CPU 16 Bit breit sind.
* Speicheradressen innerhalb eines Segments erreicht man mit Hilfe eines Offsets(verstanden)
* Es gibt 65 536 Segmente... wtf?! Wie kommt er bitte auf die Anzahl? 2^16?
09/07/2016 16:00 C_O_R_E#6
Das Thema hat sich erledigt. Sollte nun alles verstanden haben, dabei halfen mir viele andere Quellen.

https://de.wikipedia.org/wiki/Intel_8086


https://de.wikipedia.org/wiki/Segmentierung_(Speicherverwaltung
und die Präsentationsfolien von Sing Tatla
[Only registered and activated users can see links. Click Here To Register...]
09/10/2016 00:24 NotThatBad#7
2^4 * 2^16 = 2^(4+16) = 2^20

mit 4 bits adressierst du das segment im arbeitsspeicher, mit den 16 bits adressierst du innerhalb des segments.

dein ganzer hauptspeicher ist in 2^4 (16) segmente unterteilt, deine absolute adresse setzt sich also aus den 4 bit (startadresse des segments im hauptspeicher (also das 2^16 bit große segment)) und 16 bit (der offset innerhalb des segments)
09/10/2016 00:36 Jeoni#8
Quote:
Originally Posted by NotThatBad View Post
2^4 * 2^16 = 2^(4+16) = 2^20

mit 4 bits adressierst du das segment im arbeitsspeicher, mit den 16 bits adressierst du innerhalb des segments.

dein ganzer hauptspeicher ist in 2^4 (16) segmente unterteilt, deine absolute adresse setzt sich also aus den 4 bit (startadresse des segments im hauptspeicher (also das 2^16 bit große segment)) und 16 bit (der offset innerhalb des segments)
Das ist nicht ganz korrekt. Du schreibst, es gäbe 16 Segmente und ein Segment trägt nur 4 bit an Informationen. Ein Segment trägt 16 bit an Informationen (daher gibt es 2^16 Segmente wie @[Only registered and activated users can see links. Click Here To Register...] bereits fragend anmerkte). Das Segment wird mit 16 multipliziert, also um 4 bit nach links geshiftet. Anschließend wird das 16 bit große Offset addiert. Durch den Shift und Addition erhält man eine 20 bit große Adresse.
Man kann den 20 bit großen Adressraum in 16 überlappungsfreie Segmente á 2^16 bit einteilen, aber das muss nicht (und wird vermutlich auch nicht) so gemacht werden.
Ferner kann ein Segment afaik bis zu 2^16 bit groß sein ("maximal" wurde auch bereits erwähnt). Heißt, es kann auch kleiner sein und ich nehme an, dass die MMU oder irgendeine derartige Komponente dann für Range-Checks verantwortlich ist. Wie genau man das funktioniert, entzieht sich allerdings meiner Kenntnis.
Wäre auch Verschwendung (für die damalige Zeit), wenn ein Segment stets 2^16 bit groß wäre und es lediglich 16 Segmente gäbe.
Mit freundlichen Grüßen
Jeoni
09/10/2016 00:51 C_O_R_E#9
Ich sollte meine Frage etwas präziser ausdrücken, aber es war schon richtig, was @[Only registered and activated users can see links. Click Here To Register...] dazu beigetragen hat. Mich hat anfangs nur dieser Wechsel der Präfixe gestört, da ich eher ein Fan von klarer Struktur bin.

Wie dem auch sei, die Architektur habe ich nun verstanden und auch das Programmieren in der Architektur klappte in den vergangen Tagen super.


Vielen Dank

Edit:// Um die 16 zu erklären.
Das 2^4 bildet sich aus den Segmentenanfang. Das verwirrte mich anfangs auch, aber beim Betrachten der Register mit Ollydb, sieht man, dass es sich um den Segmentanfang handelt.
Jeder Anfang eines Segment zum Anderen beträgt 16.
09/10/2016 09:52 NotThatBad#10
Quote:
Originally Posted by Jeoni View Post
Das ist nicht ganz korrekt. Du schreibst, es gäbe 16 Segmente und ein Segment trägt nur 4 bit an Informationen. Ein Segment trägt 16 bit an Informationen
ich hab nichts anderes geschrieben, mit den 4 bit wird eins der 16 segmente innerhalb des hauptspeichers adressiert, mit den 16 bit können insgesamt 2^16 adressen innerhalb des segments adressiert werden. ob das segment tatsächlich 2^16 bit groß ist sei dahingestellt, es geht nur darum, dass man maximal 2^16 adresse pro segment mit dem offset adressieren kann