#include "vga.h" #include static_assert(sizeof(VGA::Entry) == 2); VGA::VGA(vga_color fg, vga_color bg, uint32_t address) : color_fg(fg), color_bg(bg) { buffer = reinterpret_cast(address); // clear buffer for (size_t y = 0; y < max_rows; y++) { for (size_t x = 0; x < max_columns; x++) { const size_t index = y * max_columns + x; buffer[index].c = ' '; buffer[index].fg = color_fg; buffer[index].bg = color_bg; } } enable_cursor(14, 15); update_cursor(); } void VGA::set_color(vga_color fg, vga_color bg) { color_fg = fg; color_bg = bg; for (size_t y = 0; y < max_rows; y++) { for (size_t x = 0; x < max_columns; x++) { const size_t index = y * max_columns + x; buffer[index].fg = color_fg; buffer[index].bg = color_bg; } } } void VGA::enable_cursor(uint8_t start, uint8_t end) { p_3d4.write(0x0a); p_3d5.write((p_3d5.read() & 0xc0) | start); p_3d4.write(0x0b); p_3d5.write((p_3d5.read() & 0xe0) | end); } void VGA::disable_cursor() { p_3d4.write(0x0a); p_3d5.write(0x20); } void VGA::update_cursor() { const uint16_t pos = row * max_columns + column; p_3d4.write(0x0f); p_3d5.write(static_cast(pos & 0xff)); p_3d4.write(0x0e); p_3d5.write(static_cast((pos >> 8) & 0xff)); } void VGA::write(char c) { switch (c) { case '\n': column = 0; ++row; break; default: { const size_t index = row * max_columns + column; buffer[index].c = c; ++column; } } if (column == max_columns) { column = 0; ++row; } if (row == max_rows) { // scroll up - move rows 1~25 up by one for (size_t y = 1; y < max_rows; y++) { const auto prev_y = y - 1; for (size_t x = 0; x < max_columns; ++x) { const auto prev = prev_y * max_columns + x; const auto idx = y * max_columns + x; buffer[prev] = buffer[idx]; } } --row; } } void VGA::write(ViewIterator& iter) { while (iter) { write(iter.next()); } }