Files
bsb2/kernel/arch/cga.cc
Niklas Gollenstede 174fe17e89 Handout
2025-10-31 22:37:36 +01:00

79 lines
2.5 KiB
C++

#include "cga.h"
#include "../utils/math.h"
#include "ioport.h"
namespace CGA {
// I/O Ports required for hardware cursor
constexpr IOPort index_port(0x3d4); ///< Graphic card register selection
constexpr IOPort data_port(0x3d5); ///< Read/Write selected register
/*! \brief Helper structure for the hardware cursor
*/
union Cursor {
uint16_t value;
struct {
uint16_t low : 8;
uint16_t high : 6;
uint16_t : 2;
} __attribute__((packed));
} __attribute__((packed));
/*! \brief Register (for index_port)
*/
enum RegisterIndex {
CURSOR_START =
10, ///< Control the cursor (blink timing and start scanline)
CURSOR_END = 11, ///< Control the cursors end scanline
START_ADDRESS_HIGH = 12, ///< Base offset address for output (high)
START_ADDRESS_LOW = 13, ///< Base offset address for output (low)
CURSOR_HIGH = 14, ///< Cursor offset address (high)
CURSOR_LOW = 15, ///< Cursor offset address (low)
};
void setCursor(unsigned abs_x, unsigned abs_y) {
// Using the hardware cursor is quite important:
// The access to the IO Ports is rather slow and -- if interrupted by
// another output -- it will result in a strange word jumble.
// Hence this helps in a quite visible manner to understand the
// necessity of correct synchronization (and its performance impact).
if (abs_x < COLUMNS && abs_y < ROWS) {
Cursor pos = {static_cast<uint16_t>((abs_y * COLUMNS) + abs_x)};
// Select index 14 / CURSOR_HIGH register
index_port.outb(CURSOR_HIGH);
// Write high part of value to selected register (cursor high)
data_port.outb(pos.high);
// Select index 15 / CURSOR_LOW register
index_port.outb(CURSOR_LOW);
// Write low part of value to selected register (cursor low)
data_port.outb(pos.low);
}
}
void getCursor(unsigned& abs_x, unsigned& abs_y) {
Cursor pos = {.value = 0};
// Select index 14 / CURSOR_HIGH register
index_port.outb(CURSOR_HIGH);
// Read high part part of value from selected register (cursor high)
pos.high = data_port.inb();
// Select index 15 / CURSOR_LOW register
index_port.outb(CURSOR_LOW);
// Read low part of value from selected register (cursor low)
pos.low = data_port.inb();
// Calculate absolute position
abs_x = pos.value % COLUMNS;
abs_y = Math::min(pos.value / COLUMNS, ROWS - 1);
}
void show(unsigned abs_x, unsigned abs_y, char character, Attribute attrib) {
// Output only on current page
if (abs_x < COLUMNS && abs_y < ROWS) {
Cell cell(character, attrib);
TEXT_BUFFER_BASE[(abs_y * COLUMNS) + abs_x] = cell;
}
}
}; // namespace CGA