Von Bitplane, Latch und 16 Farben... Beim Artikel ber das PCX-Format im 16 Farben Modus ist mir auf- gefallen, da es vielleicht sinnvoll ist, Euch ersteinmal den Modus berhaupt vorzustellen. Denn dieser ist, auch wenn man sich irgendwann daran gewhnt, weit nicht so einfach, wie vielleicht die Modis mit 256 Farben! Whrend dort ein Byte genau eine Farbe bzw. die Farbe eines Pixel wiedergab, ist das in den 16 Farben Modis nicht der Fall (siehe: '256 - Und keine Farbe weniger!'). Doch nun zum Modus 12h: 640x480 in 16 Farben. Da alle anderen 16 Farben Modis hnlich behandelt werden (die Auflsung ist schlie- lich anders), beschrnke ich mich auf diesen - die Umsetzung auf andere Modis drfte leicht fallen (wenn nicht: immer fragen!). Nun aber wirklich: Wie Ihr vielleicht wei, wird der Grafikspei- cher Eurer, und jeder anderen VGA Grafikkarte auch, in das Seg- ment beginnend bei $A000:$0000 eingeblendet. Es reicht bis zur Adresse $A000:$FFFF und ist somit (wie jedes Segment) genau 64 KB gro. Nun steht man, bzw. stand man vor etwa 11 Jahren als die VGA-Karte entwickelt wurde, vor dem Problem, die 153600 Bytes, die ein 16 Farbenbild der Auflsung 640x480 bentigt, dort sicht- bar zu machen (640 * 480 = 307200, ein Byte = 8 Bit, fr 16 Farben braucht man 4 Bit ---> 307200 / 2 = 153600). Man stand also scheinbar vor einem unlsbaren Problem... aber auch nur scheinbar! Man kam auf die dolle Idee, den gesamten Videospeicher (und der betrug damals maximal 256 KB) in 4 BitPlanes 64 KB aufzuteilen, die je nach Belieben eingeblendet werden konnten. Dadurch war und ist es mglich, die 256 KB zu benutzen. Wie man an den Rest der mitlerweile 1 MB (oder noch mehr) kommt, ist eine andere Sache und wird hier auch nicht behandelt. Man hat nun also Zugriff auf gengend Speicher, um den genannten Modus zu realisieren. Zwischen den User und den Bitplanes werden nun noch 4 Register gesetzt, die sogenannten Latch-Register, die jeweils einer Bit- plane zugeordnet werden. Latch #0 also Bitplane #0, Latch #1 Bitplane #1 usw.. Will man nun z.B. einen Wert aus dem Video- speicher holen, so wird jedes der vier Latch-Register mit dem Wert aus 'ihrer' Bitplane an der gewnschten Speicherstelle ge- laden. Beim Schreiben verhlt es sich hnlich - erst werden alle vier Latch-Register mit dem Wert geladen, tja... und dann werden alle an die gleiche Stelle in ihrer Bitplane geschrie- ben, oder wie? Nein! Dann wrde ja in jeder Bitplane das Gleiche drinne stehen, und man knnte ganz darauf verzichten! Daher: Ein wenig mehr zu den Bitplanes: Wie ich anfangs sagte, bentigt ein '16-Farben-Pixel', also ein Pixel im 16 Farben Modus, 4 Bit, um seine Farbinformation zu speichern (2^4 = 16). Man knnte nun annehmen, da diese Info nun nach und nach als 'Vierer-Bit'-Formation im Videospeicher zu finden ist. Auch wenn dieses nicht verstanden wurde: macht nichts - es ist sowieso falsch! Wir haben 4 Bitplanes, 4 Latch-Register und 4 Bit Farbinfo. Man ist also auf die Idee gekommen, die Farbinfo eines Pixels auf die 4 Bitplanes zu verteilen. So, ab jetzt wird's kompliziert: Man nehmen die 8 Farbinfos/Pixelfarben: Dezimal Binr 1 - 0001 2 - 0010 4 - 0100 5 - 0101 9 - 1001 10 - 1010 11 - 1011 12 - 1100 und stelle sich vor, da diese Pixel/Farben die ersten acht Pixel auf dem Bildschirm sind, also mit den Koordinaten (0,0),(1,0),(2,0)...(7,0). Nun betrachte man die vier Bitplanes: 7 6 5 4 3 2 1 0 Bitplane #0 1 0 0 1 1 0 1 0 Bitplane #1 0 1 0 0 0 1 1 0 Bitplane #2 0 0 1 1 0 0 0 1 Bitplane #3 0 0 0 0 1 1 1 1 Fllt etwas auf? Vielleicht ja folgendes: Nimmt man Bit Nummer 7 der BP #0 und schreibt es auf einen Zettel, nimmt man dann das Bit 7 der BP #1 und schreibt es links (!) daneben und ver- fhrt so mit BP #2 und BP #3, dann erhlt man den Farbcode des ersten Pixels. Genauso verhalten sich die anderen Bits. Liest man also die Werte aus der obigen Tabelle von oben nach unten, erhlt man den Wert aus der Tabelle darber von rechts nach links. Was folgern wir daraus? Der Farbcode eines Pixels wir so ber die 4 Bitplanes verteilt, da jeweils ein Bit an der selben Stelle in den verschiedenen Bitplanes diese Farbe trgt. Verstanden? Hoffentlich... sonst einfach noch einmal lesen! Es finden sich also 8 Pixel in vier Byte wieder, die ber die 4 Bitplanes verteilt sind. Das erste Byte im Videospeicher 'enthlt' also eigentlich vier Bytes, die aber auf die BPs verteilt sind. Im ersten Byte bzw. in den ersten Bytes der vier Bitplanes findet man die Information ber acht Pixel! Will man nun den 9. Pixel an- sprechen, so mu man die Speicherstelle mit der Adresse $A000: $0001 ansprechen. Will man den ersten Pixel in der 2. Zeile ansprechen, so entfllt dieser auf die Adresse $A000:$0050 bzw. auf das 81. Byte im Videospeicher (640 / 8 = 80)! Die dritte Zeile fngt somit bei der Speicheradresse $A000:$00A0 an usw... Dazu gibt's gleich noch mehr. Wie wre es mit ein wenig mehr Theorie? An der Port-Adresse $3CE existiert ein Adreregister, das Zugang zu neun Registern des Graphic-Controllers bietet. Man mu nur einen der Werte von $00 bis $08 'outputten' und kann dann mittels dem Datenregister an der Port-Adresse $3CF mit ihm Kontakt auf- nehmen. Die neun Register sind folgende: Register Aufgabe $00 Set / Reset $01 Enable Set / Reset $02 Color Compare $03 Function Select / Data Rotate $04 Read Map Select $05 Mode $06 Miscallaneous $07 Color Don't Care $08 Bit Mask Das Register mit der Nummer $05 hat die Aufgabe, den gewnschten Lese- bzw. Schreibmodus einzustellen. Insgesammt gibt es 2 Lese- modis (0/1) und 4 Schreibmodis (0/1/2/3), von denen aber nur der Lesemodus 0 (Readmode 0) und der Schreibmodus 2 (Writemode 2) von Interesse sind. Glaubt mir! Die anderen kann man eigentlich getrost unter den Tisch fallen lassen, da sie (zumindest von mir) bisher noch nie benutzt wurden. Doch nun zu den 'sinnvollen' Modis: Um beide Modis gleichzeitig einzustellen, mu man den Wert '2' in das Mode-Register laden. In Assembler wrde dieses mit folgender Anweisung geschehen: MOV AX,0205h ; 02 = Read0/Write2, 05 = Mode-Register MOV DX,3CEh ; Port-Adresse des Graphic-Controllers OUT DX,AX ; 'Raus' damit Readmode 0: In diesem Modus ist es mglich, ein Byte aus einer angegebenen Bitplane auszulesen. Dies geschieht wieder ber die Latch- Register, was aber nicht heit, da es komplizierter wird. Wie gesagt: Die Latch-Register schalten sich einfach immer nur da- zwischen und haben sonst keine Aufgabe. Mittels des Read Map Select Registers, in das man die gewnschte Bitplane vermerkt (0-3), kann man nun einen Wert aus der jewei- ligen Bitplane auslesen. Doch was will man schon mit einem Byte? Wie oben beschrieben enthlt ein Byte ja schlielich 8 Informa- tionen fr 8 verschiedene Pixel! Die Antwort ist einfach und banal: Will man die Farbe eines Pixels wissen, dann mu man halt alle vier Bitplanes auslesen, und die jeweiligen Bits 'heraus- holen'. Man kann diesen Modus aber auch benutzen, wenn man einen Teil des Videospeichers 'retten' mu, weil man z.B. ein Fenster oder hnliches ffnen will, da, wenn man es spter wieder schliet, mit dem alten Inhalt wieder gefllt werden soll. Man liest also den gewnschten Teil aus, indem man alle vier BPs ausliest und spter, wenn das Fenster wieder geschlossen werden soll, schreibt man diese Werte wieder hinein. Und damit habe ich mal wieder einen wunderbaren bergang zum Writemode 2: gefunden... Dieser Modus ist am besten geeignet, um Pixel im 16 Farben Modus zu setzen. Mchte man zum Beispiel den ersten Pixel links oben in gelb (Farbe 14) setzen, so lade man das Bit Mask Regis- ter mit dem Wert 1000000b (127) - man erinnere sich an das obige Beispiel mit den Bitplanes, dann drfte dieser Wert klar sein -, setze das Function Select Register auf 'ersetzen' (0) und schreibe dann einfach den Wert 14 an die Speicheradresse $A000:$0000. Durch die Hilfe des Bit Mask Registers lassen sich gleichzeitig bis zu acht nebeneinander liegende Pixel auf eine Farbe setzen - man setze dieses Register einfach auf 11111111b und verfahre wie oben - schon sind die ersten acht Pixel gelb! Noch einmal die wichtigsten Register: Register $03 - Function Select: Hier stellt man ein, wie der Writemode 2 funktionieren soll. 7 6 5 4 3 2 1 0 / / / ! ! ? ? ? Die Bits 3 und 4 geben dabei an: Wert Bedeutung 00 Ersetzen 01 AND 10 OR 11 XOR Die Bits 1-3 haben nur im Writemode 0 und 3 etwas zu sagen, und Bit 5-7 werden nicht benutzt. Was sollen diese Werte jetzt? In meinem Beispiel zur Funktionsweise des Writemode 2 lade ich den Wert '00' ins Function Select Register - ersetzen! Mchte ich nun aber den Inhalt des Videospeichers durch die Farbe, die ich hineinschreibe nicht 'ersetzen', also einen neue Farbe setzen, sondern den Inhalt lediglich 'manipulieren', eben durch eine AND, OR oder XOR Verknpfung, dann lade ich den gewn- schten Wert ins Function Select Register und freue mich auf das Ergebnis... Register $04 - Read Map Select: Dieses Register ist fr den Readmode 0 von Bedeutung. Da man in diesem Modus lediglich nur eine Bitplane auslesen kann, stellt man hier ein, welche es sein soll. 7 6 5 4 3 2 1 0 / / / / / / ! ! Die Werte fr die Bits 1 + 2 : Wert Bedeutung 00 Bitplane #0 auslesen 01 Bitplane #1 auslesen 10 Bitplane #2 auslesen 11 Bitplane #3 auslesen Register $05 - Graphics Mode: Hier wird der Read- und Writemode eingestellt. Wie gesagt: es gibt 2 Read-Modis und 4 Write-Modis. Doch nur der Read- mode 0 und der Writemode 2 sind von Bedeutung. Wie man sie einstellt, steht oben! Register $08 - Bit Mask: Die Bitmaske fr den Writemode 2 wird hier vermerkt. Dabei steht jedes Bit fr einen Pixel: Man will in der dritten Zeile den 20. Pixel setzen: Man erinnere sich: die dritte Zeile beginnt bei der Adresse $A000:$00A0. Nun will man den 20. Punkt setzen (19/2). Also addiert man den Wert 2 ($A000:$00A2) und setzt das Bit Mask Register auf 00010000b. Wie kommt man darauf? Man wei, da jedes Byte acht Pixel 'reprsentiert'. Nun nehme man die Koordinate (19) und teile sie durch 8 = 2 Rest 3. Die erste Zahl (2) mu man nun zur 'Basisadresse' (:$00A0) addieren und die zweite Zahl (3) gibt aufschlu darber, welches Bit man in der Bitmaske setze mu, allerdings mu man diesen Wert (3) ersteinmal von von 7 abziehen = 4. Nun betrachtet man die Nummerierung eines Bytes: Bit Stelle 8. 7. 6. 5. 4. 3. 2. 1. Bit Nummer 7 6 5 4 3 2 1 0 Hat man nun den Wert vier erhalten, dann mu man das Bit mit der Nummer 4 (das 5. Bit von rechts) setzen. Wie man das wesentlich einfacher macht, kommt gleich! So, damit drfte eigentlich alles Wichtige erklrt sein. Ihr wit jetzt ber 'Bitplane, Latch und 16 Farben' alles, was ich selber wei. Nur meine 'Erfahrung' damit, kann ich Euch nicht geben - selbst ist der Mann/die Frau! Nun aber noch ein paar Kleinigkeiten, die Euch das Leben er- leichtern drften: Punkte setzen: Wir befinden uns im Writemode 2. Frage: Ich habe eine x/y Koor- dinate und mchte nun ohne groen Aufwand die richtige Speicher- adresse sowie die richtige Bitmaske haben, wie mach ich das? Ganz einfach: Der Offset ergibt sich aus folgender Formel: Offset = y * (640 / 8) + (x DIV 8) = (80 * y) + (x DIV 8), wobei man die Klammern natrlich weglassen kann. Und das Bit, das in der Bitmaske gesetzt werden mu: Bit = 7 - (x MOD 8). Die Offsetadresse braucht man, damit man wei, wo man in den Speicher schreiben mu ($A000:Offset) und die Bitmaske bekommt man nun, indem man das Bit setzt, da 'Bit' (s.o.) angibt. Am einfachsten macht man das, indem man ein Byte nimmt, dieses auf 1 setzt (00000001b) und nun diese eins mittels des Schiebe- befehls SHL (Assembler/Pascal) nach links um soviele Stellen verschiebt, wie es 'Bit' angibt. Ihr erinnert Euch an das Beispiel mit der Koordinate (19/2)? Also: Offset = (80 * 2) + (19 DIV 8) = 160 + 2 = 162 oder $00A2! Nun das Bit = 7 - (19 MOD 8) = 7 - (19 AND 7) = 7 - 3 = 4. 00000001b SHL 4 = 00010000b = Bitmaske (vergleiche oben). Wie man sieht, kann man den 'x MOD 8' durch 'x AND 7' ersetzen - das Ergebnis bleibt immer das gleiche, es geht aber einfach schneller! Tja, ich glaube man nhert sich dem Ende. Am besten drfte es sein, wenn man den Artikel gleich noch einmal (oder zweimal, oder dreimal...) liest. Vielleicht werden dann noch einige Unklarhei- ten, die eventuell noch bestehen, ebenfalls geklrt. Wenn nicht stehe ich gerne fr jegliche Fragen (zum Thema...) bereit. Und wenn Ihr noch nicht genug habt, dann knnt Ihr Euch gleich auch noch den praktischen Teil reinziehen - vielleicht hilft's ja weiter... Frohes Schaffen wnscht Kemil!