欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

使用BIOS以及直接写显存绘制图形

发布时间:2025/6/15 编程问答 35 豆豆
生活随笔 收集整理的这篇文章主要介绍了 使用BIOS以及直接写显存绘制图形 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

注:以下程序系由相应的Intel格式汇编改编而来,略有修改,若发现bug,欢迎指正。若有问题,欢迎交流。若能帮助一二访客,幸甚。


一年前仿照Skelix 写过一个简单的内核,并命名为BabyOS。当时代码大部分用的Skelix的,终究有些遗憾,所以想趁今年寒假--工作前最后一个假期,重新实现一下BabyOS,力求尽量用自己的代码实现。所以前几天学习了一下AT&T 汇编、内联汇编及C与汇编的相互调用。下一个问题就是显示,经过许多考虑,这次准备尝试一下图形界面的系统(因为看上去更有趣些),或许有点舍本求末的嫌疑,但我写个OS kernel主要是好玩,从未想有正式应用,所以怎么好玩就怎么来。

昨晚研究了下BIOS INT 0x10显示字符,今晚决定不管有用没有先学习一下BIOS INT 0x10及实模式下写显存来显示图形的知识。

1.绘制像素

[cpp] view plaincopyprint?
  • -----------------------------------------------------------------------  
  •                         INT 0x10可识别的视频图形模式  
  • --------------------------------------------------------------------  
  • 模式          分辨率(列*行,像素)   颜色数  
  • 6                   640x200                 2  
  • 0DH                 320x200                 16  
  • 0EH                 640x350                 16  
  • 0FH                 640x350                 2  
  • 10H                 640x200                 16  
  • 11H                 640x480                 2  
  • 12H                 640x480                 16  
  • 13H                 320x200                 256  
  • 6AH                 800x600                 16  
  • -----------------------------------------------------------------------  
  • 当视频控制器处于图形模式时,INT 0x10的功能0CH在屏幕上绘制一个像素点。(功能0CH执行的相当慢)

    [cpp] view plaincopyprint?
  • -----------------------------------------------------------------------  
  •                         INT 0x10 功能0CH  
  • ---------------------------------------------------------------  
  • 描述:  
  •     写像素  
  • 接受参数:  
  •     AH          0CH  
  •     AL          像素值  
  •     BH          视频页  
  •     CX          X坐标  
  •     DX          Y坐标  
  • 返回值:  
  •     无  
  • 注意:  
  •     视频显示必须处于图形模式下。像素值的范围和坐标范围与当前的图形模式有关。  
  •     如果AL的位7置位,新的像素同当前像素的内容进行异或运算。  
  • -------------------------------------------------------------------------  

  • 示例,画线程序:
    [cpp] view plaincopyprint?
  • # This program draws a straight line in graphics mode.  
  • # 2012-12-24 20:42  
  • # guzhoudiaoke@126.com  
  •   
  • .section .text  
  • .global _start  
  • .code16  
  •   
  • _start:  
  •     jmp     main  
  •   
  • clear_screen:               # 清屏函数  
  •     movb    $0x06,  %ah     # 功能号0x06  
  •     movb    $0,     %al     # 上卷全部行,即清屏  
  •     movb    $0,     %ch     # 左上角行  
  •     movb    $0,     %ch     # 左上角列    
  •     movb    $24,    %dh     # 右下角行  
  •     movb    $79,    %dl     # 右下角列  
  •     movb    $0x07,  %bh     # 空白区域属性  
  •     int     $0x10  
  •     ret  
  •   
  • main:  
  •     movw    %cx,    %ax  
  •     movw    %ax,    %ds  
  •     movw    %ax,    %es  
  •   
  •     call    clear_screen    # 清屏  
  •   
  •     # 设置成图形模式,0x6a为800x600, 16种颜色  
  •     movb    $0,     %ah     # 功能号0x0  
  •     movb    $0x6a,  %al     # 显示模式  
  •     int     $0x10  
  •   
  •     # 画一条直线  
  •     movb    $0x0,   %bh     # 视频页  
  •     movw    $300,   %dx     # y坐标  
  •     movw    $100,   %cx     # x坐标  
  •     movb    $0x0c,  %ah     # 功能号  
  •     movb    $9,     %al     # 像素值(颜色)  
  • 1:    
  •     int     $0x10  
  •     incw    %cx             # 下一个像素  
  •     cmpw    $700,   %cx     # 是否到了结束位置  
  •     jne     1b  
  •   
  • 1:  
  •     jmp     1b  
  •   
  •     .org    0x1fe,  0x90  
  •     .word   0xaa55  

  • 结果:


    2.图形模式用功能0x13显示字符串

    [cpp] view plaincopyprint?
  • # This program draws text and a straight line in graphics mode.  
  • # 2012-12-24 20:42  
  • # guzhoudiaoke@126.com  
  •   
  • .section .text  
  • .global _start  
  • .code16  
  •   
  • _start:  
  •     jmp     main  
  •   
  • clear_screen:               # 清屏函数  
  •     movb    $0x06,  %ah     # 功能号0x06  
  •     movb    $0,     %al     # 上卷全部行,即清屏  
  •     movb    $0,     %ch     # 左上角行  
  •     movb    $0,     %ch     # 左上角列    
  •     movb    $24,    %dh     # 右下角行  
  •     movb    $79,    %dl     # 右下角列  
  •     movb    $0x07,  %bh     # 空白区域属性  
  •     int     $0x10  
  •     ret  
  •   
  • main:  
  •     movw    %cx,    %ax  
  •     movw    %ax,    %ds  
  •     movw    %ax,    %es  
  •   
  •     call    clear_screen    # 清屏  
  •   
  •     # 设置成图形模式,0x6a为800x600, 16种颜色  
  •     movb    $0,     %ah     # 功能号0x0  
  •     movb    $0x6a,  %al     # 显示模式  
  •     int     $0x10  
  •   
  •     # 显示文字  
  •     movw    $msgstr,%ax  
  •     movw    %ax,    %bp  
  •     movw    len,    %cx  
  •     movb    $0x13,  %ah  
  •     movb    $0,     %al  
  •     movb    $0x04,  %bl  
  •     movb    $0x0,   %bh  
  •     movb    $0x02,  %dh  
  •     movb    $0x04,  %dl  
  •     int     $0x10  
  •   
  •     # 画一条直线  
  •     movb    $0x0,   %bh     # 视频页  
  •     movw    $300,   %dx     # y坐标  
  •     movw    $100,   %cx     # x坐标  
  •     movb    $0x0c,  %ah     # 功能号  
  •     movb    $9,     %al     # 像素值(颜色)  
  • 1:    
  •     int     $0x10  
  •     incw    %cx             # 下一个像素  
  •     cmpw    $700,   %cx     # 是否到了结束位置  
  •     jne     1b  
  •   
  • 1:  
  •     jmp     1b  
  •   
  • msgstr:  
  •     .asciz  "line: start(100, 300), end(700, 300)\n"  
  • len:  
  •     .int    . - msgstr  
  •   
  •     .org    0x1fe,  0x90  
  •     .word   0xaa55  

  • 结果:


    3.内存映射图形

    对于内存映射图形视频模式0x13最容易使用。这时屏幕像素映射为一个字节数组,每个像素一个字节。
    共有320*200个像素,因为有256种颜色,所以每个像素一个字节。左上角像素对应地址0xa0000。
    模式0x13中,每个整数色彩值表示调色板的色彩表的索引。调色板中每个项都由三个独立的整数(0~63)构成,称为RGB值。调色板的第0项控制着屏幕的背景色。
    有两个输出端口用于控制视频调色板:送往端口0x3c8的值表示要修改的调色板表项,送往端口0x3c9的是要修改的颜色值。
    示例:
    [cpp] view plaincopyprint?
  • # This program draws color pixels at mode 0x13  
  • # 2012-12-24 21:31  
  • # guzhoudiaoke@126.com  
  •   
  • .section .text  
  • .global _start  
  • .code16  
  •   
  • _start:  
  •     jmp     main  
  •   
  • #--------------------------------------------------------------  
  • # 清屏函数:  
  • #   设置屏幕背景色,调色板的索引0指代的颜色为背景色  
  • clear_screen:               # 清屏函数  
  •     movb    $0x06,  %ah     # 功能号0x06  
  •     movb    $0,     %al     # 上卷全部行,即清屏  
  •     movb    $0,     %ch     # 左上角行  
  •     movb    $0,     %ch     # 左上角列    
  •     movb    $24,    %dh     # 右下角行  
  •     movb    $79,    %dl     # 右下角列  
  •     movb    $0x07,  %bh     # 空白区域属性  
  •     int     $0x10  
  •     ret  
  •   
  • #----------------------------------------------------------------  
  • # 设置显示模式函数  
  • set_video_mode:  
  •     movb    $0,         %ah         # 功能号0x0  
  •     movb    $MODE_0X13, %al         # 显示模式  
  •     int     $0x10  
  •     ret  
  •   
  • #---------------------------------------------------------------  
  • # 显示一些文字函数:  
  • #   使用INT 0x10中断0x13功能,显示计算机当前工作的显示模式  
  • draw_some_text:  
  •     movw    $msg_str,   %bp         # ES:BP为字符串地址  
  •     movw    msg_len,    %cx         # 显示字符数  
  •     movb    $0x13,      %ah         # 功能号  
  •     movb    $0,         %al         # 显示模式  
  •     movb    $TEXT_COLOR,%bl         # 属性值  
  •     movb    $0,         %bh         # 视频页  
  •     movb    $TEXT_ROW,  %dh         # 显示起始行  
  •     movb    $TEXT_COL,  %dl         # 显示起始列  
  •     int     $0x10  
  •   
  •     ret  
  •   
  • #----------------------------------------------------------------  
  • # 设置背景颜色为深蓝色  
  • set_screen_bk_color:  
  •     movw    $VIDEO_PALLETE_PORT,    %dx  
  •     movb    $PA_INDEX_BACKGROUND,   %al  
  •     outb    %al,                    %dx  
  •   
  •     movw    $COLOR_SELECTION_PORT,  %dx  
  •     movb    $0,                     %al     # 红  
  •     outb    %al,                    %dx  
  •     movb    $0,                     %al     # 绿  
  •     outb    %al,                    %dx  
  •     movb    $18,                    %al     # 蓝(亮度18/63)  
  •     outb    %al,                    %dx  
  •     ret  
  •   
  • #----------------------------------------------------------------  
  • # 通过写显存绘制一些像素点:  
  • #   首先设置调色板索引1处的颜色为白色  
  • #   然后通过写显存的方式,向ES:DI写入数据(PA_INDEX_WHITE)  
  • draw_some_pixels:  
  •     # 把索引1处的颜色改为白色(63,63,63)  
  •     movw    $VIDEO_PALLETE_PORT,    %dx  
  •     movb    $PA_INDEX_WHITE,        %al  
  •     outb    %al,                    %dx  
  •     movw    $COLOR_SELECTION_PORT,  %dx  
  •     movb    $63,                    %al     # 红  
  •     outb    %al,                    %dx  
  •     movb    $63,                    %al     # 绿  
  •     outb    %al,                    %dx  
  •     movb    $63,                    %al     # 蓝  
  •     outb    %al,                    %dx  
  •   
  •     # 设置ES的值  
  •     movw    $VIDEO_SEG_GRAPHIC,     %ax  
  •     movw    %ax,                    %es  
  •   
  •     # 设置要显示的像素位置的显存地址(目的地址)  
  •     movw    $(PIXEL_ROW_ST*320 + PIXEL_COL_ST), %di  
  •     movb    $PA_INDEX_WHITE,        %al  
  •     movw    $PIXEL_COUNT,           %cx  
  •   
  • draw_a_pixel:  
  •     stosb  
  •     addw    $5,                     %di  
  •     loop    draw_a_pixel  
  •   
  •     ret  
  •   
  • main:  
  •     movw    %cx,    %ax  
  •     movw    %ax,    %ds  
  •     movw    %ax,    %es  
  •   
  •     call    clear_screen        # 清屏  
  •     call    set_video_mode      # 设置显示模式  
  •     call    set_screen_bk_color # 设置背景颜色  
  •     call    draw_some_text      # 绘制字符串  
  •     call    draw_some_pixels    # 绘制像素  
  •   
  • 1:  
  •     jmp     1b  
  •   
  • # 常量定义:  
  •     VIDEO_SEG_TEXT      = 0xb800  
  •     VIDEO_SEG_GRAPHIC   = 0xa000  
  •   
  •     VIDEO_PALLETE_PORT  = 0x3c8  
  •     COLOR_SELECTION_PORT= 0x3c9  
  •       
  •     MODE_0X13           = 0x13  
  •   
  •     PA_INDEX_BACKGROUND = 0x0  
  •     PA_INDEX_WHITE      = 0x1  
  •   
  •     TEXT_ROW            = 0x01  
  •     TEXT_COL            = 0x00  
  •     TEXT_COLOR          = 0x04  
  •   
  •     PIXEL_ROW_ST        = 100  
  •     PIXEL_COL_ST        = 160-5*10  
  •     PIXEL_COUNT         = 20  
  •   
  • msg_str:  
  • msg_mode:  
  •     .asciz  "video mode: 0x13"  
  •     .org    msg_mode+40,        0  
  • msg_scr_res:  
  •     .asciz  "screen resolution:320x200"  
  •     .org    msg_scr_res+40,     0  
  • msg_color_num:  
  •     .asciz  "color num:256"  
  •     .org    msg_color_num+40*4, 0  
  • msg_babyos:  
  •     .asciz  "The new Baby OS will have a GUI,but now it can only draw some pixels, haha..And merry Christmas!"  
  • msg_len:  
  •     .int    . - msg_str - 1  
  •   
  •     .org    0x1fe,  0x90  
  •     .word   0xaa55  

  • 结果:


    注释:

    文字是用的BIOS INT 0x10显示的,VGA的0x13模式下显示的文字为40列x25行,字符框8x8,看上去有点丑,以后再研究下超级VGA(SVGA)吧~


    总结

    以上是生活随笔为你收集整理的使用BIOS以及直接写显存绘制图形的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。