babyos (二)——使用BIOS以及直接写显存绘制图形

来源:互联网 发布:淘宝店铺被关闭了24分 编辑:程序博客网 时间:2024/05/16 09:19

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


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

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

1.绘制像素

-----------------------------------------------------------------------INT 0x10可识别的视频图形模式--------------------------------------------------------------------模式分辨率(列*行,像素)  颜色数6640x20020DH320x200160EH640x350160FH640x350210H640x2001611H640x480212H640x4801613H320x2002566AH800x60016-----------------------------------------------------------------------
当视频控制器处于图形模式时,INT 0x10的功能0CH在屏幕上绘制一个像素点。(功能0CH执行的相当慢)

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

示例,画线程序:
# This program draws a straight line in graphics mode.# 2012-12-24 20:42# guzhoudiaoke@126.com.section .text.global _start.code16_start:jmpmainclear_screen:# 清屏函数movb$0x06,%ah# 功能号0x06movb$0,%al# 上卷全部行,即清屏movb$0,%ch# 左上角行movb$0,%ch# 左上角列movb$24,%dh# 右下角行movb$79,%dl# 右下角列movb$0x07,%bh# 空白区域属性int$0x10retmain:movw%cx,%axmovw%ax,%dsmovw%ax,%escallclear_screen# 清屏# 设置成图形模式,0x6a为800x600, 16种颜色movb$0,%ah# 功能号0x0movb$0x6a,%al# 显示模式int$0x10# 画一条直线movb$0x0,%bh# 视频页movw$300,%dx# y坐标movw$100,%cx# x坐标movb$0x0c,%ah# 功能号movb$9,%al# 像素值(颜色)1:int$0x10incw%cx# 下一个像素cmpw$700,%cx# 是否到了结束位置jne1b1:jmp1b.org0x1fe,0x90.word0xaa55

结果:


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

# 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:jmpmainclear_screen:# 清屏函数movb$0x06,%ah# 功能号0x06movb$0,%al# 上卷全部行,即清屏movb$0,%ch# 左上角行movb$0,%ch# 左上角列movb$24,%dh# 右下角行movb$79,%dl# 右下角列movb$0x07,%bh# 空白区域属性int$0x10retmain:movw%cx,%axmovw%ax,%dsmovw%ax,%escallclear_screen# 清屏# 设置成图形模式,0x6a为800x600, 16种颜色movb$0,%ah# 功能号0x0movb$0x6a,%al# 显示模式int$0x10# 显示文字movw$msgstr,%axmovw%ax,%bpmovwlen,%cxmovb$0x13,%ahmovb$0,%almovb$0x04,%blmovb$0x0,%bhmovb$0x02,%dhmovb$0x04,%dlint$0x10# 画一条直线movb$0x0,%bh# 视频页movw$300,%dx# y坐标movw$100,%cx# x坐标movb$0x0c,%ah# 功能号movb$9,%al# 像素值(颜色)1:int$0x10incw%cx# 下一个像素cmpw$700,%cx# 是否到了结束位置jne1b1:jmp1bmsgstr:.asciz"line: start(100, 300), end(700, 300)\n"len:.int. - msgstr.org0x1fe,0x90.word0xaa55

结果:


3.内存映射图形

对于内存映射图形视频模式0x13最容易使用。这时屏幕像素映射为一个字节数组,每个像素一个字节。
共有320*200个像素,因为有256种颜色,所以每个像素一个字节。左上角像素对应地址0xa0000。
模式0x13中,每个整数色彩值表示调色板的色彩表的索引。调色板中每个项都由三个独立的整数(0~63)构成,称为RGB值。调色板的第0项控制着屏幕的背景色。
有两个输出端口用于控制视频调色板:送往端口0x3c8的值表示要修改的调色板表项,送往端口0x3c9的是要修改的颜色值。
示例:
# This program draws color pixels at mode 0x13# 2012-12-24 21:31# guzhoudiaoke@126.com.section .text.global _start.code16_start:jmpmain#--------------------------------------------------------------# 清屏函数:#设置屏幕背景色,调色板的索引0指代的颜色为背景色clear_screen:# 清屏函数movb$0x06,%ah# 功能号0x06movb$0,%al# 上卷全部行,即清屏movb$0,%ch# 左上角行movb$0,%ch# 左上角列movb$24,%dh# 右下角行movb$79,%dl# 右下角列movb$0x07,%bh# 空白区域属性int$0x10ret#----------------------------------------------------------------# 设置显示模式函数set_video_mode:movb$0,%ah# 功能号0x0movb$MODE_0X13,%al# 显示模式int$0x10ret#---------------------------------------------------------------# 显示一些文字函数:#使用INT 0x10中断0x13功能,显示计算机当前工作的显示模式draw_some_text:movw$msg_str,%bp# ES:BP为字符串地址movwmsg_len,%cx# 显示字符数movb$0x13,%ah# 功能号movb$0,%al# 显示模式movb$TEXT_COLOR,%bl# 属性值movb$0,%bh# 视频页movb$TEXT_ROW,%dh# 显示起始行movb$TEXT_COL,%dl# 显示起始列int$0x10ret#----------------------------------------------------------------# 设置背景颜色为深蓝色set_screen_bk_color:movw$VIDEO_PALLETE_PORT,%dxmovb$PA_INDEX_BACKGROUND,%aloutb%al,%dxmovw$COLOR_SELECTION_PORT,%dxmovb$0,%al# 红outb%al,%dxmovb$0,%al# 绿outb%al,%dxmovb$18,%al# 蓝(亮度18/63)outb%al,%dxret#----------------------------------------------------------------# 通过写显存绘制一些像素点:#首先设置调色板索引1处的颜色为白色#然后通过写显存的方式,向ES:DI写入数据(PA_INDEX_WHITE)draw_some_pixels:# 把索引1处的颜色改为白色(63,63,63)movw$VIDEO_PALLETE_PORT,%dxmovb$PA_INDEX_WHITE,%aloutb%al,%dxmovw$COLOR_SELECTION_PORT,%dxmovb$63,%al# 红outb%al,%dxmovb$63,%al# 绿outb%al,%dxmovb$63,%al# 蓝outb%al,%dx# 设置ES的值movw$VIDEO_SEG_GRAPHIC,%axmovw%ax,%es# 设置要显示的像素位置的显存地址(目的地址)movw$(PIXEL_ROW_ST*320 + PIXEL_COL_ST),%dimovb$PA_INDEX_WHITE,%almovw$PIXEL_COUNT,%cxdraw_a_pixel:stosbaddw$5,%diloopdraw_a_pixelretmain:movw%cx,%axmovw%ax,%dsmovw%ax,%escallclear_screen# 清屏callset_video_mode# 设置显示模式callset_screen_bk_color# 设置背景颜色calldraw_some_text# 绘制字符串calldraw_some_pixels# 绘制像素1:jmp1b# 常量定义:VIDEO_SEG_TEXT= 0xb800VIDEO_SEG_GRAPHIC= 0xa000VIDEO_PALLETE_PORT= 0x3c8COLOR_SELECTION_PORT= 0x3c9MODE_0X13= 0x13PA_INDEX_BACKGROUND= 0x0PA_INDEX_WHITE= 0x1TEXT_ROW= 0x01TEXT_COL= 0x00TEXT_COLOR= 0x04PIXEL_ROW_ST= 100PIXEL_COL_ST= 160-5*10PIXEL_COUNT= 20msg_str:msg_mode:.asciz"video mode: 0x13".orgmsg_mode+40,0msg_scr_res:.asciz"screen resolution:320x200".orgmsg_scr_res+40,0msg_color_num:.asciz"color num:256".orgmsg_color_num+40*4,0msg_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.org0x1fe,0x90.word0xaa55

结果:


注释:

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


原创粉丝点击