79 lines
2.5 KiB
C++
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
|