| Zeile 84: | Zeile 84: | ||
|- | |- | ||
|} | |} | ||
| + | |||
| + | Die ersten 10 Register (0-9) steuern das Timing des CRT-Displays, sowie weitere Details der Darstellung, die über den Zweck dieses Artikels hinausgehen. Informationen dazu gibt es im Datenblatt des 6845 z.B. unter [http://bbc.nvg.org/doc/datasheets/MC6845.zip]. | ||
| + | |||
| + | Nur die Register 14 bis 17 können laut Spezifikation ausgelesen werden. Deswegen ist es notwendig die Werte der anderen Register in einer Variable zu speichern, wenn ihre Werte braucht. Das BIOS nutzt dafür zum Beispiel Teile der [[Bios Data Area#Grafik-Adapter-Informationen|Bios Data Area]]. | ||
| + | |||
| + | ==== Cursor Format ==== | ||
| + | Die Register 10 und 11 steuern die Form des Cursors. Die unteren 5 Bits dieser Register geben jeweils die Start- und End-Scanline des Cursors innerhalb eines Zeichens an. Außerdem steuern Bits 5 und 6 des Regster 10 das Blinken des Cursors. | ||
| + | |||
| + | {| {{Prettytable}} style="text-align: center;" | ||
| + | !Register | ||
| + | !width="10%"|7 | ||
| + | !width="10%"|6 | ||
| + | !width="10%"|5 | ||
| + | !width="10%"|4 | ||
| + | !width="10%"|3 | ||
| + | !width="10%"|2 | ||
| + | !width="10%"|1 | ||
| + | !width="10%"|0 | ||
| + | |- | ||
| + | |'''Cursor Start'''||n/a||Enable||Timing | ||
| + | |colspan="5"|Scanline | ||
| + | |- | ||
| + | |'''Cursor End''' | ||
| + | |colspan="3"|n/a | ||
| + | |colspan="5"|Scanline | ||
| + | |} | ||
| + | |||
| + | Die folgende Tabelle listet alle möglichen Belegungen von Enable und Timing dar: | ||
| + | |||
| + | {| {{Prettytable}} | ||
| + | !Enable!!Timing!!Effekt | ||
| + | |- | ||
| + | |0||0||Cursor blinkt nicht | ||
| + | |- | ||
| + | |0||1||Cursor wird nicht dargestellt | ||
| + | |- | ||
| + | |1||0||Cursor blinkt normal | ||
| + | |- | ||
| + | |1||1||Cursor blinkt schnell | ||
| + | |} | ||
| + | |||
| + | == Start Address == | ||
| + | Die Register 12 und 13 geben das Offset an, an der das erste darzustellende Zeichen auf dem Bildschirm, also das Zeichen oben links, steht. Dabei ist zu beachten, dass die Berechnung des Offsets wie Berechnung der Cursorposition (siehe unten) verläuft. Das heißt das Offset darf nicht mit 2 multipliziert werden, um die Attribute einzubeziehen. | ||
| + | |||
| + | Beispiel, das analog zum BIOS den Speicher in 8 Seiten unterteilt: | ||
| + | <c>/* Unsere Auflösung */ | ||
| + | #define ROWS 25 | ||
| + | #define COLS 80 | ||
| + | |||
| + | /* | ||
| + | * DISPLAY_PAGE_OFFSET gibt die Startadresse der übergebenen Seitennummer | ||
| + | * zurück. Dabei rundet es die Adresse einer Bildschirmseite auf das | ||
| + | * nächste Vielfache von 256 auf. Das Makro ist etwas komplizierter als nötig, | ||
| + | * falls es jemand mit anderen Auflösungen verwenden will. Für den 80x25- | ||
| + | * Modus vereinfacht es sich zu ((page) * 2048). | ||
| + | */ | ||
| + | #define DISPLAY_PAGE_OFFSET(page) ((page) * ((ROWS * COLS + 0xff) & 0xff00)) | ||
| + | |||
| + | /* Die Start Adresse der dargestellten Seite */ | ||
| + | unsigned short start_address; | ||
| + | |||
| + | void select_page(unsigned int page) | ||
| + | { | ||
| + | start_address = DISPLAY_PAGE_OFFSET(page); | ||
| + | |||
| + | outb(0x3D4, 13); | ||
| + | outb(0x3D5, start_address); // Low Byte schreiben | ||
| + | outb(0x3D4, 12); | ||
| + | outb(0x3D5, start_address >> 8); // High Byte schreiben | ||
| + | |||
| + | /* | ||
| + | * Hier muss noch die Cursorposition gesetzt werden, da diese für | ||
| + | * jede Page eine andere ist. Das heißt sie muss z.B. in einem Array | ||
| + | * gespeichert werden. | ||
| + | * | ||
| + | * Für das Setzen des Cursor siehe nächster Abschnitt. | ||
| + | */ | ||
| + | }</c> | ||
| + | |||
| + | == Cursor Address == | ||
| + | Die Register 14 und 15 setzen die Cursor Addresse, die sich aus der Cursor Position berechnet. Um den Cursor zum Beispiel in Zeile 10, Spalte 63 zu setzen muss man 10 * 80 + 63 = 863 rechnen. Dieser Wert wird dann in die High und Low Bytes der Register für die Cursor Addresse geschrieben. | ||
| + | |||
| + | Dabei ist zu beachten, dass wenn man wie im letzten Abschnitt beschrieben die Startadresse verändert, diese Startadresse auf die Cursor position addieren muss. | ||
| + | |||
| + | Beispiel: | ||
| + | <c>/* Unsere Auflösung */ | ||
| + | #define ROWS 25 | ||
| + | #define COLS 80 | ||
| + | |||
| + | /* Cursorposition, die durch dir Ausgabefunktionen gesetzt werden */ | ||
| + | unsigned int cursor_x; | ||
| + | unsigned int cursor_y; | ||
| + | |||
| + | void update_cursor() | ||
| + | { | ||
| + | unsigned short cursor_address = cursor_x + cursor_y * COLS; | ||
| + | |||
| + | // die Startadresse dazuaddieren (nur nötig, wenn man diese auch verändert hat) | ||
| + | cursor_address += start_address; | ||
| + | |||
| + | outb(0x3D4, 15); | ||
| + | outb(0x3D5, cursor_address); | ||
| + | outb(0x3D4, 14); | ||
| + | outb(0x3D5, cursor_address >> 8); | ||
| + | }</c> | ||
=== 16 Hintergrundfarben === | === 16 Hintergrundfarben === | ||