1
Files
lecture-operating-system-de…/c_os/devices/CGA.cc
2022-07-24 21:12:31 +02:00

209 lines
9.1 KiB
C++
Executable File

/*****************************************************************************
* *
* C G A *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Mit Hilfe dieser Klasse kann man auf den Bildschirm des *
* PCs zugreifen. Der Zugriff erfolgt direkt auf der Hard- *
* wareebene, d.h. ueber den Bildschirmspeicher und den *
* I/O-Ports der Grafikkarte. *
* *
* Autor: Olaf Spinczyk, TU Dortmund *
* Aenderungen von Michael Schoettner, HHU, 21.8.2016 *
*****************************************************************************/
#include "devices/CGA.h"
#include "user/lib/Memory.h"
const IOport CGA::index_port(0x3d4);
const IOport CGA::data_port(0x3d5);
/*****************************************************************************
* Methode: CGA::setpos *
*---------------------------------------------------------------------------*
* Beschreibung: Setzen des Cursors in Spalte x und Zeile y. *
*****************************************************************************/
void CGA::setpos(unsigned int x, unsigned int y) {
/* Hier muess Code eingefuegt werden */
// NOTE: The cursor addresses positions on screen, not bytes
unsigned short pos = x + y * COLUMNS;
unsigned char cursor_low = pos & 0xFF;
unsigned char cursor_high = (pos >> 8) & 0xFF;
index_port.outb(0xF); // Cursor(low)
data_port.outb(cursor_low);
index_port.outb(0xE); // Cursor(high)
data_port.outb(cursor_high);
}
/*****************************************************************************
* Methode: CGA::getpos *
*---------------------------------------------------------------------------*
* Beschreibung: Abfragem der Cursorposition *
* *
* Rückgabewerte: x und y *
*****************************************************************************/
void CGA::getpos(unsigned int& x, unsigned int& y) {
/* Hier muess Code eingefuegt werden */
index_port.outb(0xF); // Cursor(low)
unsigned char cursor_low = data_port.inb();
index_port.outb(0xE); // Cursor(high)
unsigned char cursor_high = data_port.inb();
unsigned short cursor =
(cursor_low & 0xFF) | ((cursor_high << 8) & 0xFF00);
x = cursor % COLUMNS;
y = (cursor / COLUMNS);
}
/*****************************************************************************
* Methode: CGA::show *
*---------------------------------------------------------------------------*
* Beschreibung: Anzeige eines Zeichens mit Attribut an einer bestimmten *
* Stelle auf dem Bildschirm. *
* *
* Parameter: *
* x,y Position des Zeichens *
* character Das auszugebende Zeichen *
* attrib Attributbyte fuer das Zeichen *
*****************************************************************************/
void CGA::show(unsigned int x, unsigned int y, char character, unsigned char attrib) {
/* Hier muess Code eingefuegt werden */
if (x >= COLUMNS || y >= ROWS) {
// Out of bounds
return;
}
cga_char_t* pos = reinterpret_cast<cga_char_t*>(CGA_START) + x + y * COLUMNS;
pos->cga_char = character;
pos->cga_attribute = attrib;
}
/*****************************************************************************
* Methode: CGA::print *
*---------------------------------------------------------------------------*
* Beschreibung: Anzeige mehrerer Zeichen ab der aktuellen Cursorposition *
* '\n' fuer Zeilenvorschub. *
* *
* Parameter: *
* string Auszugebende Zeichenkette *
* n Laenger der Zeichenkette *
* attrib Attributbyte fuer alle Zeichen der Zeichenkette *
*****************************************************************************/
void CGA::print(const char* string, unsigned int n, unsigned char attrib) const {
/* Hier muess Code eingefuegt werden */
unsigned int cursor_x = 0;
unsigned int cursor_y = 0; // Don't poll registers every stroke
getpos(cursor_x, cursor_y);
for (int byte = 0; byte < n; ++byte) {
char current = *(string + byte);
if (current == '\n') {
cursor_x = 0;
cursor_y = cursor_y + 1;
if (cursor_y >= ROWS) {
// Bottom of screen reached
scrollup();
cursor_y = cursor_y - 1;
}
continue;
}
if (current == '\0') {
// Don't need to run to end if null terminated
break;
}
show(cursor_x, cursor_y, current, attrib);
cursor_x = cursor_x + 1;
if (cursor_x >= COLUMNS) {
// Right of screen reached
cursor_x = 0;
cursor_y = cursor_y + 1;
if (cursor_y >= ROWS) {
// Bottom of screen reached
scrollup();
cursor_y = cursor_y - 1;
}
}
}
setpos(cursor_x, cursor_y);
}
void CGA::print(const bse::string& string, const unsigned int n, const unsigned char attrib) const {
print(static_cast<const char*>(string), n, attrib);
}
void CGA::print(const bse::string& string, const unsigned char attrib) const {
print(static_cast<const char*>(string), string.size(), attrib);
}
/*****************************************************************************
* Methode: CGA::scrollup *
*---------------------------------------------------------------------------*
* Beschreibung: Verschiebt den Bildschirminhalt um eine Zeile nach oben. *
* Die neue Zeile am unteren Bildrand wird mit Leerzeichen *
* gefuellt. *
*****************************************************************************/
void CGA::scrollup() const {
/* Hier muss Code eingefuegt werden */
// Move up
bse::memcpy<cga_line_t>(reinterpret_cast<cga_line_t*>(CGA_START),
reinterpret_cast<cga_line_t*>(CGA_START) + 1,
ROWS - 1);
// Clear last line
bse::zero<cga_line_t>(reinterpret_cast<cga_line_t*>(CGA_START) + ROWS - 1);
}
/*****************************************************************************
* Methode: CGA::clear *
*---------------------------------------------------------------------------*
* Beschreibung: Lösche den Textbildschirm. *
*****************************************************************************/
void CGA::clear() {
/* Hier muess Code eingefuegt werden */
bse::zero<cga_page_t>(reinterpret_cast<cga_page_t*>(CGA_START));
setpos(0, 0);
}
/*****************************************************************************
* Methode: CGA::attribute *
*---------------------------------------------------------------------------*
* Beschreibung: Hilfsfunktion zur Erzeugung eines Attribut-Bytes aus *
* Hintergrund- und Vordergrundfarbe und der Angabe, ob das *
* Zeichen blinkend darzustellen ist. *
* *
* Parameter: *
* bg Background color *
* fg Foreground color *
* blink ywa/no *
*****************************************************************************/
unsigned char CGA::attribute(CGA::color bg, CGA::color fg, bool blink) {
/* Hier muess Code eingefuegt werden */
return static_cast<int>(blink) << 7 // B0000000
| (bg & 0x7) << 4 // 0HHH0000 (Hintergrund)
| (fg & 0xF); // 0000VVVV (Vordergrund)
}