von Dark_Lord » Fr 6. Mai 2022, 23:01
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.
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.