Speichersegmentierung x86

Hier dürfen auch unregistrierte Besucher posten.
Antworten
tryn4xGuest

Speichersegmentierung x86

Beitrag von tryn4xGuest »

Hallo Community.
Ich würde gern das angegebene Thema "Speichersegmentierung" (etwas) verstehen wollen.
Ich versuche gerade herauszufinden was der "Offset" genau ist, um diesen am Ende auch berechnen zu können. Aber bis dahin stell ich mir die Frage:
Es ist wohl so, dass ein x86 Prozessor mit 16 Adressleitungen 2^16 Speicher adressieren kann ... jetzt eine dumme Frage:
Wieso schreibt man: 2 Zustände hoch 16 Leitungen? Und nicht 16 Leitungen hoch 2 Zustände?
2^16 = 65536
Aber:
16^2 = 256

Ich habe so viel gelesen, das ich leider seitTagen den Faden nicht mehr finde. Ich kann machen was ich will, ich komme auf keinen geraden Zweig mehr.
Überlesen..

Mit Dank und Grüßen.
Steffen.
Benutzeravatar
schubl
LAN Manager
Beiträge: 209
Registriert: So 17. Mär 2019, 19:14

Re: Speichersegmentierung x86

Beitrag von schubl »

tryn4xGuest hat geschrieben: Fr 6. Mai 2022, 22:07 jetzt eine dumme Frage:
Wieso schreibt man: 2 Zustände hoch 16 Leitungen? Und nicht 16 Leitungen hoch 2 Zustände?
2^16 = 65536
Aber:
16^2 = 256
Genau das ist die Erklärung. ;-)
Es ist eine 16-stellige binäre Zahl, deshalb 2^16.
16^2 ist eine 2-stellige hexadezimale Zahl.
Dabei sind die Zahlen von 0-9 und A-F = 16 "Zustände"
Um die Anzahl der Kombinationsmöglichkeiten zu errechnen, muss man die Anzahl der Möglichkeiten ^ Anzahl der Stellen rechnen.
Soviel Retro und nur sowenig Zeit... laufender WIP...
8086, 286, 386, 486, P1, P2, P3, P4 und dann noch Amiga, Atari, C64/128,...
Benutzeravatar
Dark_Lord
LAN Manager
Beiträge: 210
Registriert: So 25. Mai 2008, 19:44
Wohnort: Nähe Köln
Kontaktdaten:

Re: Speichersegmentierung x86

Beitrag von Dark_Lord »

Etwas einfacher liest es sich in Hexadezimal. Der x86 Real Mode (also 8086/8088 und 80186/80188 und alle Nachfolger bevor sie in den Protected Mode schalten) arbeitet mit 20 Bit Adressleitungen. In einer Flat/Linear-Adressierung liest sich das 00000-FFFFF, was in 20 Bit dargestellt werden kann, das sind 10^20=1048576 Bytes oder 1MB.

Üblicherweise nimmt man aber eine Segment-Offset-Darstellung, die verwirrenderweise, je nachdem, was man programmiert aber auch praktischerweise, ein 16-Bit Segment und ein 16-Bit Offset enthält. Die Segmente 0000 bis 9000 (im Prinzip also 0-9) sind dabei die 640KB, die für jeden genug sind, die Segmente A bis F sind für BIOS, Speicher auf Erweiterungskarten (Video-RAM, Pageframe für LIM-EMS...) und Option ROMs (z.B. Festplattencontroller) reserviert.

Jedes hexadezimale Symbol (0, 1, 2... , 9, A, B, C, D, E, F) hat 4 Bit, also das, was C64-Programmierer gerne "Nibble", also halbes Byte nenen. Damit geht der Speicher geschrieben in Hex in der "Flat"-Darstellung von 00000-FFFFF. oder in der Segment-Offset-Darstellung 0000:0000-F000:FFFF. Jedes Segment hat 0000-FFFF (also Hex 10000) Bytes, entsprechend in Dezimal 0-65535, also 65536 Bytes, alias 64kB.

Der Vorteil der Segment-Offset-Darstellung ist die Möglichkeit, bestimmte Adressen besser darzustellen. Das BIOS eines Festplattencontrollers (z.B. ein alter MFM-Controller mit eigenem BIOS oder der XTIDE, der die nicht vorhandenen Festplattenroutinen eines XTs supplementiert oder die vorhandenen aber nicht für große Laufwerke geeigneten Routinen von späteren Mainboard-BIOS Versionen ersetzt) belegt z.B. ein halbes 64KB Segment und ist typischerweise in der oberen Hälfte des C-Segments angesiedelt. Das könnte man jetzt C000:8000 schreiben oder C800:0000 oder einfach Segment C800. In Flat könnte man die Adresse auch C8000 nennen. Der Reset-Vektor, also der initiale Sprungbefehl in die BIOS-Selbsttest-Routine des Mainboards, die beim Einschalten/Reset abgespult wird, findet sich an der linearen Adresse FFFF0, in Segment-Offset geschrieben F000:FFF0 oder aber auch FFFF:0000. Letzteres liest sich sogar fast schon intuitiv.

Wie du an den Beispielen merkst, ist die Umrechnung recht einfach. Wenn du in 64KB-Segmenten arbeitest, ist das höchste Nibble der Linear-Adresse das höchste Nibble des Segments, die restlichen Segment-Nibbles sind 0. Die 4 restlichen Nibbles sind das Offset. A1234 ist also A000:1234. Wenn du z.B. in 32KB Segmenten arbeitest, z.B. für ein 32KB Option ROM werden die oberen zwei Nibbles der Linear-Adresse die oberen zwei Nibbles des Segments (Rest 0) und das höchste Nibble des Offsets ist 0, also die Adresse C8ABC wird zu C800:0ABC. Und so weiter.

Anders sollte man auch nicht rechnen, wenn man den umgekehrten Weg geht. Es ist also völlig egal, ob du z.B. beim Zugriff auf den VGA-Speicher bei Segment A000 auf A000:8ABC zugreifst, oder auf A800:0ABC. Zu vermeiden wäre aber A800:9ABC, da du hier schon im B-Segment landen würdest (A8000+9ABC=B1ABC). Die Adressen FFFF:0010 bis FFFF:FFFF ergeben einen Overflow, eine Adresse, die im linearen 20 Bit Adressbereich nicht existiert. Die letzte existente Adresse ist FFFFF, oder auch F000:FFFF oder FFFF:000F, wie man will, die 8-Bit Checksumme des BIOS.
Arbeitspferde: Xeon E5-2683v3 und Q6600

Retro:
P2-450
Commodore PC20-II/Tandy Sound
286/ET3000/Aztech NX-II
Amiga 500/Gotek/Vortex AT-once Plus 286
Pentium 166/FAST Video Machine

Projekt-PCs: C64, Dual Pentium MMX 233, 486 VLB, 486 PCI, K6, Athlon 64
Projekte: USB RetroArduInput
Antworten