peredOS/drivers/vga.c

110 lines
3.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "vga.h"
#include "../kernel/io.h"
#include <stdint.h>
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_ADDRESS 0xB8000
static volatile char *video_mem = (volatile char*)VGA_ADDRESS;
static int cursor_x = 0;
static int cursor_y = 0;
static char current_color = 0x07; // По умолчанию серый на черном
// Локальная функция для сдвига экрана вверх на одну строку
static void vga_scroll(void) {
// Копируем строки с 1-й по 24-ю на место строк с 0-й по 23-ю
// Каждая строка занимает VGA_WIDTH * 2 байт (символ + атрибут)
for (int i = 0; i < (VGA_HEIGHT - 1) * VGA_WIDTH * 2; i++) {
video_mem[i] = video_mem[i + VGA_WIDTH * 2];
}
// Очищаем самую нижнюю строку (заполняем пробелами с текущим цветом)
int last_row_start = (VGA_HEIGHT - 1) * VGA_WIDTH * 2;
for (int i = 0; i < VGA_WIDTH; i++) {
video_mem[last_row_start + i * 2] = ' ';
video_mem[last_row_start + i * 2 + 1] = current_color;
}
}
void vga_update_cursor(int x, int y) {
// Вычисляем плоский индекс в видеопамяти
uint16_t pos = y * VGA_WIDTH + x;
// Передаем контроллеру VGA младший байт позиции (регистр 15)
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t)(pos & 0xFF));
// Передаем старший байт позиции (регистр 14)
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}
void vga_init(void) {
cursor_x = 0;
cursor_y = 0;
// Заполняем весь экран пробелами
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
video_mem[i * 2] = ' ';
video_mem[i * 2 + 1] = current_color;
}
vga_update_cursor(0,0);
}
void vga_set_color(char fg, char bg) {
current_color = (bg << 4) | (fg & 0x0F);
}
void vga_putchar(char c) {
// Обработка бэкспейса (стирание символа)
if (c == '\b') {
if (cursor_x > 0) {
cursor_x--;
} else if (cursor_y > 0) {
cursor_y--;
cursor_x = VGA_WIDTH - 1;
}
int index = (cursor_y * VGA_WIDTH + cursor_x) * 2;
video_mem[index] = ' ';
video_mem[index + 1] = current_color;
vga_update_cursor(cursor_x, cursor_y);
return; // Выходим, чтобы не двигать курсор вперед
}
// Обработка переноса строки
if (c == '\n') {
cursor_x = 0;
cursor_y++;
} else if (c >= ' ') { // Печатаем только видимые символы
int index = (cursor_y * VGA_WIDTH + cursor_x) * 2;
video_mem[index] = c;
video_mem[index + 1] = current_color;
cursor_x++;
}
// Если вышли за правый край — перенос
if (cursor_x >= VGA_WIDTH) {
cursor_x = 0;
cursor_y++;
}
// Если экран кончился — скроллим вверх, пока курсор не встанет на последнюю строку
if (cursor_y >= VGA_HEIGHT) {
vga_scroll();
cursor_y = VGA_HEIGHT - 1;
}
vga_update_cursor(cursor_x, cursor_y);
}
void vga_print(const char *str) {
for (int i = 0; str[i] != '\0'; i++) {
vga_putchar(str[i]);
}
}
void vga_println(const char *str) {
for (int i = 0; str[i] != '\0'; i++) {
vga_putchar(str[i]);
}
vga_putchar('\n');
}