

    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!

