字符模式显卡驱动

字符模式显卡驱动

在物理内存低1MB地区,有显示适配器缓存的内存空间,可以直接通过改写缓存来改变显示内容。

所有在PC上工作的显卡,在加电初始化之后都会自动初始化到80*25的文本模式。上图中的CGA/EGA+ Chroma Text Video Buffer区域映射的就是工作在文本模式的显存。一些低版本显卡不支持彩色字符,只支持单色字符,其显存映射的区域就是Mono Text Video Buffer

显存数据结构

在彩色文字显存区域,每2个字节表示屏幕上显示的一个字符。格式如下。

R G B 背景色,K=0闪烁 前景色I=0 前景色I=1
0 0 0
0 0 1 浅蓝
0 1 0 绿 绿 浅绿
0 1 1 前青
1 0 0 浅红
1 0 1 品红 品红 浅品红
1 1 0
1 1 1 亮白

游标位置

显示适配器会自动记录当前的游标位置,并将闪烁的游标展示在显示器上。下面展示了更新游标位置的代码。

#define CGA_BASE 0x3D4

static uint16_t g_cursor_pos; // 当前游标的位置,等于行数*80+列数

void move_cursor()
{
    // 移动游标到新的位置
    outb(CGA_BASE, 14);
    outb(CGA_BASE + 1, g_cursor_pos >> 8);
    outb(CGA_BASE, 15);
    outb(CGA_BASE + 1, g_cursor_pos);
}

写字符

写字符直接修改显存就可以。重要的是怎么处理游标位置和滚动效果。

#define CRT_ROWS 25
#define CRT_COLS 80
#define CRT_SIZE (CRT_ROWS * CRT_COLS)

static uint16_t g_cursor_pos; // 当前游标的位置,等于行数*80+列数
static uint16_t *g_crt_buf;   // 显存数组

static void cga_putc(int c)
{
    // 没有设置颜色的默认白字黑底
    if (!(c & ~0xFF))
    {
        c |= 0x0700;
    }

    switch (c & 0xff)
    {
    case '\b':
        if (g_cursor_pos > 0)
        {
            g_cursor_pos--;
            g_crt_buf[g_cursor_pos] = (c & ~0xff) | ' ';
        }
        break;
    case '\n':
        g_cursor_pos += CRT_COLS;
    case '\r':
        g_cursor_pos -= (g_cursor_pos % CRT_COLS);
        break;
    default:
        g_crt_buf[g_cursor_pos++] = c;
        break;
    }

    // 当超过一页,向后滚动一行
    if (g_cursor_pos >= CRT_SIZE)
    {
        memmove(g_crt_buf, g_crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));
        for (int i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
        {
            // 最后一行内容初始化为空格
            g_crt_buf[i] = 0x0700 | ' ';
        }
        g_cursor_pos -= CRT_COLS;
    }

    // 移动游标到新的位置
    move_cursor();
}

参考资料

posted @ 2022-12-11 18:44  HachikoT  阅读(150)  评论(0编辑  收藏  举报