您的位置:首页 > 移动开发 > IOS开发

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

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

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

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

1.绘制像素

[cpp]
view plain
copy
print?

-----------------------------------------------------------------------  
                        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 plain
copy
print?

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

示例,画线程序:

[cpp]
view plain
copy
print?

# 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 plain
copy
print?

# 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 plain
copy
print?

# 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)吧~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: