鱼C论坛

 找回密码
 立即注册

操作系统自学笔记 20130915——C语言与画面显示的练习

热度 6已有 879 次阅读2013-9-15 13:43

            周五周六把实验项目的事情处理了一下,今天继续。
            话说之前在学习单片机的时候学习到了很多关于处理硬件结构,存储单元的知识。我想后面有空开个专门把8086CPU和单片机的CPU按照寄存器啊,结构啊的分类标准比较下。总之比较下总结下思路就会清晰很多。
            OK,我们开始。之前的内容还是要大概看些做了哪些事情的:之前我们了解了软盘的结构,然后我知道了磁盘的存储方式。紧接着学习了怎么调用BIOS函数,如何在C语言中调用汇编指令。如何将C语言的文件生成.sys。
            下面我们开始C语言与画面显示练习。
          
1、用C语言实现内存的写入。
            要想在屏幕上面显示什么的话只要往VRAM里面写入一些东西就好了。但是在C语言中是没有办法直接向内存地址写入语句的,也就是没办法直接用DB指令。(好吧,其实是有的)。于是我们就可以创建这个功能的函数。
           naskfunc.nas文件里面就是存放NASK这个作者自编的编译器的C语言function的。在最后作者加上了
           _write_mem8: ; void write_mem8(int addr, int data);
            MOV  ECX,[ESP+4]
            MOV  AL,[ESP+8]  
            MOV  [ECX],AL
            RET
           解释:1、ECX,当然,因为已经变成了32位的模式的话自然就ECX寄存器了。ESP是啥玩意来着。我查下:哦哦哦~是SP的加强版的含义吧,Extended Stack Pointer。是用于堆栈的指针寄存器。[ESP+4]存放的是地址。[ESP+8]存放的是数据。自然加上[]就意识到之前讲到的是存储单元的额内容。他们分别放在ECX和AL这个2个地方,然后要将AL的数据放到ECX的空里面去。
                       这么写的原因之前就看到过了,应该是要讲数据存到寄存器的话是不能直接就放进去的,必须先有个过渡下。够用于指定内存地址的寄存器只有4个。BX,BP,SI,DI。难道这里的ECX也可以指定内存地址么?
           (SI、DI、BX、BP是8086CPU可用来作指针使用的寄存器,一般用来表示一个偏移量,具体的和寻址方式有关。)
             如果C语言要用那个函数的话,直接用_write_mem8就可以了。其中每一个数组存放内存的地址要在之前的基础上+4.也就是[ESP+4][ESP+8][ESP+12][ESP+16]等等。
             这里还要注意的就是因为已经是32位的模式了,所以尽量用32位的寄存器。如果用16位的话会降低效率的。
             与C语言联合使用的话可以自由使用的寄存器只有EAX、BCX、EDX这三个。
             [INSTRSET "i486p"]这句的含义就是这个程序可以给486用,CPU的谱系图就是8086~80186~286~386~486~Pentium下去。其中386之后的处理器都是32位的,包括386.
             
              上面的都是准备的部分,现在开始正式的:
 2、C语言部分:
                void io_hlt(void);
void write_mem8(int addr, int data);
void HariMain(void)
{
 int i; /* 曄悢愰尵丅i偲偄偆曄悢偼丄32價僢僩偺惍悢宆 */
 for (i = 0xa0000; i <= 0xaffff; i++) {
  write_mem8(i, 15); /* MOV BYTE [i],15 */
 }
 for (;;) {
  io_hlt();
 }
}
           作者写的结构很清晰的说。申明然后及时主函数部分。里面调用了之前说的往内存写入的函数。0xa000~0xaffff全部写入。
         做完之后显示就是白屏。我也做了,看到了~
        但是为什么是白色?因为之前的程序部分里调用的时候写的是write_mem8(i, 15); /* MOV BYTE [i],15 */,15是15种颜色,就是白色。
       
        之前显示的是白色的话这次显示条纹:(作者的意图)
       本来这就是改写下的节奏,几步就搞定了。
        for (i = 0xa0000; i <= 0xaffff; i++) {
  write_mem8(i, 15);
        这里改动下,变成    write_mem8(i, i & 0x0f);
        这里实现的就是写进去的颜色不再是单纯的15了,而是   i & 0x0f,这里实现的是颜色的运算,&也就是与。
        make run 之后显示的就是条纹状。
         
         之前的认为定义的一个函数然后写进内存的语句可以被代替。代替的方法是使用 * i = i & 0x0f ;但是这里有个数据类型的错误问题,因为编译器不知道这里的数据到底是Byte 还是 word 还是 dword。
        解决办法:
        char *p   ; /*变量P是指定内存地址的专用变量,positon嘛~ */
        然后写           * p = i & 0x0f    就可以了,因为编译器认为P是地址专用变量,用于存放字符的,所以就是byte。OK~那么word和dword 呢~咋办?
        char *p是byte
        short *p 是word
        int * p是dword
        他们都是4字节的,那么1字节的就是 char i;   short i;就是2字节的。int i;是4字节的。
        然后坐着用这个语句就代替了之前的调用汇编的那个函数。实现了一样的结果。
       cast的含义原本是将XXX压入模具,然后计算机语言中是类型转换。
        指针式表示内存地址的数值,当然,在汇编中是用的内存地址,而在C语言中是指针。      
       因为C在设计的时候是认为的普通数值和指针数值是2种不同的数值,于是如果在C中要是不先转换类型就使用的话就会出现警告。那么如何解决这个问题呢:
       p = (char *) i;就是实现了数据类型的转换,之前char *很眼熟。将数值变成了表示内存地址的整数。
         
     因为上面讲了指针,然后作者就将原来的程序中改写了一句话,   for (i = 0xa0000; i <= 0xaffff; i++) {
  write_mem8(i, 15);改为
      *(p + i) = i & 0x0f ;
     这里就体现了指针的简洁。短小精悍。
      *(p + i) 可以用p[i]代替。
          
        下面就是颜色的问题了。
      要想绘制一个操作系统模样的画面,只要有16种颜色就足够了。然后又很多的编号,这些编号要在bootback.c中标出来。
      下面就是开始对init_palette进行解释。
      这部分都讲的一些简单的内容,就不做笔记了。
      哟~下面讲了中断,但是作者不打算细讲,马上我加个单片机中断的总结。
      void HariMain(void)
{
 int i; /* 曄悢愰尵丅i偲偄偆曄悢偼丄32價僢僩偺惍悢宆 */
 char *p; /* p偲偄偆曄悢偼丄BYTE [...]梡偺斣抧 */
 init_palette(); /* 僷儗僢僩傪愝掕 */
 p = (char *) 0xa0000; /* 斣抧傪戙擖 */
 for (i = 0; i <= 0xffff; i++) {
  p[i] = i & 0x0f;
 }
 for (;;) {
  io_hlt();
 }
}
       这里显示的main函数的要注意的就是调用调色板。
       颜色OK了下面就开始弄形状了。
       
  VRAM的的地址计算有个公式。320X200像素的。
      0xa0000+x+y+320
       地址知道了,再加上之前学的写进颜色的话就可以显示自己想要的画面了。
      绘制矩形的程序也很简单,贴上代码:
      void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
#define COL8_000000  0
#define COL8_FF0000  1
#define COL8_00FF00  2
#define COL8_FFFF00  3
#define COL8_0000FF  4
#define COL8_FF00FF  5
#define COL8_00FFFF  6
#define COL8_FFFFFF  7
#define COL8_C6C6C6  8
#define COL8_840000  9
#define COL8_008400  10
#define COL8_848400  11
#define COL8_000084  12
#define COL8_840084  13
#define COL8_008484  14
#define COL8_848484  15
void HariMain(void)
{
 char *p; /* p偲偄偆曄悢偼丄BYTE [...]梡偺斣抧 */
 init_palette(); /* 僷儗僢僩傪愝掕 */
 p = (char *) 0xa0000; /* 斣抧傪戙擖 */
 boxfill8(p, 320, COL8_FF0000,  20,  20, 120, 120);
 boxfill8(p, 320, COL8_00FF00,  70,  50, 170, 150);
 boxfill8(p, 320, COL8_0000FF, 120,  80, 220, 180);
 for (;;) {
  io_hlt();
 }
}
void init_palette(void)
{
 static unsigned char table_rgb[16 * 3] = {
  0x00, 0x00, 0x00, /*  0:崟 */
  0xff, 0x00, 0x00, /*  1:柧傞偄愒 */
  0x00, 0xff, 0x00, /*  2:柧傞偄椢 */
  0xff, 0xff, 0x00, /*  3:柧傞偄墿怓 */
  0x00, 0x00, 0xff, /*  4:柧傞偄惵 */
  0xff, 0x00, 0xff, /*  5:柧傞偄巼 */
  0x00, 0xff, 0xff, /*  6:柧傞偄悈怓 */
  0xff, 0xff, 0xff, /*  7:敀 */
  0xc6, 0xc6, 0xc6, /*  8:柧傞偄奃怓 */
  0x84, 0x00, 0x00, /*  9:埫偄愒 */
  0x00, 0x84, 0x00, /* 10:埫偄椢 */
  0x84, 0x84, 0x00, /* 11:埫偄墿怓 */
  0x00, 0x00, 0x84, /* 12:埫偄惵 */
  0x84, 0x00, 0x84, /* 13:埫偄巼 */
  0x00, 0x84, 0x84, /* 14:埫偄悈怓 */
  0x84, 0x84, 0x84 /* 15:埫偄奃怓 */
 };
 set_palette(0, 15, table_rgb);
 return;
 /* static char 柦椷偼丄僨乕僞偵偟偐巊偊側偄偗偳DB柦椷憡摉 */
}
void set_palette(int start, int end, unsigned char *rgb)
{
 int i, eflags;
 eflags = io_load_eflags(); /* 妱傝崬傒嫋壜僼儔僌偺抣傪婰榐偡傞 */
 io_cli();      /* 嫋壜僼儔僌傪0偵偟偰妱傝崬傒嬛巭偵偡傞 */
 io_out8(0x03c8, start);
 for (i = start; i <= end; i++) {
  io_out8(0x03c9, rgb[0] / 4);
  io_out8(0x03c9, rgb[1] / 4);
  io_out8(0x03c9, rgb[2] / 4);
  rgb += 3;
 }
 io_store_eflags(eflags); /* 妱傝崬傒嫋壜僼儔僌傪尦偵栠偡 */
 return;
}
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
 int x, y;
 for (y = y0; y <= y1; y++) {
  for (x = x0; x <= x1; x++)
   vram[y * xsize + x] = c;
 }
 return;
}
      这样就可以显示3个矩形了。
      这玩意不过也就是认为一个一个定义像素点然后显示想显示的东西而已。
       这一小节完成。
       看看下一个:
      结构体、文字显示、GDT/IDT初始化。
     加油搞,慢慢慢慢把这一个蓝图填满。
     
 
  

路过

鸡蛋

鲜花
6

握手

雷人

刚表态过的朋友 (6 人)

发表评论 评论 (6 个评论)

回复 豪翔天下 2013-9-15 20:48
                                                           
回复 风萧水寒 2013-9-16 09:01
豪翔天下:                                                                   [em:28: ...
                                         [em:2:][em:2:][em:2:]
回复 Crazy迷恋. 2013-10-4 14:04
                                         [em:28:][em:28:][em:28:][em:28:][em:28:][em:28:][em:28:]
回复 牡丹花下死做鬼 2013-10-4 14:54
O(∩_∩)O  给力啊
回复 小甲鱼 2013-10-5 16:19
你们这群表情帝~~~
回复 123de7 2013-10-11 08:15
厉害,厉害;厉害!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-13 00:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部