<30天自制操作系统>第五天

这章节内容比上一章节的更进了一步,不只是显示图像,而是显示文字。一个字符可以用8x16的长方形像素点阵来表示。例如:
这里写图片描述
将这些数据整理成一组数组,即static char font_A[16] = {0x00, 0x18, 0x18, 0x18, 0x18…}
有了这些数据之后只需将其写到VRAM中即可,下列函数实现该功能:

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
    int i;
    char *p, d /* data */;
    for (i = 0; i < 16; i++) {
        p = vram + (y + i) * xsize + x;
        d = font[i];
        if ((d & 0x80) != 0) { p[0] = c; }
        if ((d & 0x40) != 0) { p[1] = c; }
        if ((d & 0x20) != 0) { p[2] = c; }
        if ((d & 0x10) != 0) { p[3] = c; }
        if ((d & 0x08) != 0) { p[4] = c; }
        if ((d & 0x04) != 0) { p[5] = c; }
        if ((d & 0x02) != 0) { p[6] = c; }
        if ((d & 0x01) != 0) { p[7] = c; }
    }
    return;
}

具体更多的文字数据有很多的字体库,本书中已经提供了其中一种。
对于以上的函数,一次调用只是显示单个字符,若要一次显示一个字符串,可以在此基础上再进行封装,即如下函数:

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
    extern char hankaku[4096];
    for (; *s != 0x00; s++) {
        putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
        x += 8;
    }
    return;
}

接下来让鼠标图像显示出来:


void init_mouse_cursor8(char *mouse, char bc)
/* 准备鼠标指针(16x16) */
{
    static char cursor[16][16] = {
        "**************..",
        "*OOOOOOOOOOO*...",
        "*OOOOOOOOOO*....",
        "*OOOOOOOOO*.....",
        "*OOOOOOOO*......",
        "*OOOOOOO*.......",
        "*OOOOOOO*.......",
        "*OOOOOOOO*......",
        "*OOOO**OOO*.....",
        "*OOO*..*OOO*....",
        "*OO*....*OOO*...",
        "*O*......*OOO*..",
        "**........*OOO*.",
        "*..........*OOO*",
        "............*OO*",
        ".............***"
    };
    int x, y;

    for (y = 0; y < 16; y++) {
        for (x = 0; x < 16; x++) {
            if (cursor[y][x] == '*') {
                mouse[y * 16 + x] = COL8_000000;    //黑色
            }
            if (cursor[y][x] == 'O') {
                mouse[y * 16 + x] = COL8_FFFFFF;   //白色
            }
            if (cursor[y][x] == '.') {
                mouse[y * 16 + x] = bc;   //bc背景色
            }
        }
    }
    return;
}

/* 以下函数将buf中的数据复制到vram中 
 * vram, vxsize是关于VRAM的信息,pxsize和pysize是想要
 * 显示的图形的大小。px0和py0指定图形在画面上的显示位置
 * 最后的buf和bxsize分别指定图形的存放地址和每一行含有的像素数
 */
void putblock8_8(char *vram, int vxsize, int pxsize,
    int pysize, int px0, int py0, char *buf, int bxsize)
{
    int x, y;
    for (y = 0; y < pysize; y++) {
        for (x = 0; x < pxsize; x++) {
            vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
        }
    }
    return;
}

接下来只需要使用以下两个函数即可:
init_mouse_cursor8(mcursor, COL8_008484);
putblock8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);

至此鼠标图形已经可以显示出来,但却无法移动。要让它移动首先要初始化GDT和IDT。它们两个都是与CPU有关的设定。GDT是全局段号记录表,而IDT则是中断记录表。

在这之前首先要了解什么是段还有为什么分段。操作系统能同时运行多个程序,这种时候内存使用范围重叠怎么办,所以就要分段。分段则是将合计4GB内存分成很多块,每一块的起始地址都看作0来处理,任何程序都可以先写上ORG 0。

为了表示一个段,需要以下信息:
段的大小是多少
段的起始地址在哪里
段的管理属性(禁止写入,禁止执行,系统专用等)

段寄存器只有16位,可以模仿图像调色板的做法,先有一个段号,存放在寄存器里,然后预先设计好段号与段的对应关系

在调色板中,色号可以使用0~255的数,段号可以使用0~8191的数,虽然段寄存器是16位,但是低3位不能使用。

关于GDT设定如下:

struct SEGMENT_DESCRIPTOR {
    short limit_low, base_low;
    char base_mid, access_right;
    char limit_high, base_high;
};

struct GATE_DESCRIPTOR {
    short offset_low, selector;
    char dw_count, access_right;
    short offset_high;
};


void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
    int i;

    /* GDT的初始化 */
    for (i = 0; i < 8192; i++) {
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);
    set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);
    load_gdtr(0xffff, 0x00270000);

    /* IDT的初始化 */
    for (i = 0; i < 256; i++) {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(0x7ff, 0x0026f800);

    return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
    if (limit > 0xfffff) {
        ar |= 0x8000; /* G_bit = 1 */
        limit /= 0x1000;
    }
    sd->limit_low    = limit & 0xffff;
    sd->base_low     = base & 0xffff;
    sd->base_mid     = (base >> 16) & 0xff;
    sd->access_right = ar & 0xff;
    sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
    sd->base_high    = (base >> 24) & 0xff;
    return;
}

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
    gd->offset_low   = offset & 0xffff;
    gd->selector     = selector;
    gd->dw_count     = (ar >> 8) & 0xff;
    gd->access_right = ar & 0xff;
    gd->offset_high  = (offset >> 16) & 0xffff;
    return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值