BIOS 级编程与图形绘制
1. BIOS 级编程基础
在 BIOS 级编程中,有几个实用的过程值得我们关注。
1.1 光标移动与屏幕操作过程
-
AdvanceCursor 过程
:该过程用于将光标向右移动指定的列数,且不会换行。接收参数
CX为要移动的列数,不返回值。以下是其代码实现:
AdvanceCursor PROC
;
; Advances the cursor n columns to the right.
; (Cursor does not wrap around to the next line.)
; Receives: CX = number of columns
; Returns: nothing
;--------------------------------------------------
pusha
L1:
push
cx
; save loop counter
mov
ah,3
; get cursor position
mov
bh,0
; into DH, DL
int
10h
; changes CX register!
inc
dl
; increment column
mov
ah,2
; set cursor position
int
10h
pop
cx
; restore loop counter
loop
L1
; next column
popa
ret
AdvanceCursor ENDP
-
Gotoxy 过程
:用于设置视频页面 0 上的光标位置。接收参数
DH和DL分别为行和列,不返回值。代码如下:
Gotoxy PROC
;
; Sets the cursor position on video page 0.
; Receives: DH,DL = row, column
; Returns: nothing
;---------------------------------------------------
pusha
mov
ah,2
; set cursor position
mov
bh,0
; video page 0
int
10h
popa
ret
Gotoxy ENDP
- Clrscr 过程 :用于清除屏幕并将光标定位在视频页面 0 的第 0 行第 0 列。不接收参数,不返回值。代码如下:
Clrscr PROC
;
; Clears the screen (video page 0) and locates the
; cursor at row 0, column 0.
; Receives: nothing
; Returns: nothing
;-------------------------------------------------------
pusha
mov
ax,0600h
; scroll entire window up
mov
cx,0
; upper left corner (0,0)
mov
dx,184Fh
; lower right corner (24,79)
mov
bh,7
; normal attribute
int
10h
; call BIOS
mov
ah,2
; locate cursor at 0,0
mov
bh,0
; video page 0
mov
dx,0
; row 0, column 0
int
10h
popa
ret
Clrscr ENDP
1.2 相关问题回顾
以下是一些关于视频显示访问和 INT 10h 功能的常见问题及解答:
| 问题 | 解答 |
| ---- | ---- |
| 视频显示的三种访问级别是什么? | 未提及具体内容 |
| 哪种访问级别产生最快的输出? | 未提及具体内容 |
| 如何以全屏模式运行程序? | 未提及具体内容 |
| 计算机在 MS - DOS 中启动时,默认视频模式是什么? | 未提及具体内容 |
| 视频显示上的每个位置为单个字符保存什么信息? | 未提及具体内容 |
| 生成视频显示上的任何颜色需要哪些电子束? | 未提及具体内容 |
| 显示视频属性字节中前景色和背景色的映射。 | 未提及具体内容 |
| 哪个 INT 10h 功能在屏幕上定位光标? | INT 10h 功能 2 |
| 哪个 INT 10h 功能向上滚动矩形窗口? | INT 10h 功能 6 |
| 哪个 INT 10h 功能在当前光标位置写入字符和属性? | 未提及具体内容 |
| 哪个 INT 10h 功能设置光标大小? | 未提及具体内容 |
| 哪个 INT 10h 功能获取当前视频模式? | INT 10h 功能 0Fh |
| 使用 INT 10h 设置光标位置需要哪些参数? | AH = 2,BH 为视频页面,DH 为行,DL 为列 |
| 如何隐藏光标? | 未提及具体内容 |
| 向上滚动窗口需要哪些参数? | AX = 0600h,CX 为左上角坐标,DX 为右下角坐标,BH 为属性 |
| 在当前光标位置写入字符和属性需要哪些参数? | 未提及具体内容 |
| 哪个 INT 10h 功能设置闪烁/强度模式? | 未提及具体内容 |
| 使用 INT 10h 功能 6 清除屏幕时,应将哪些值移动到 AH 和 AL? | AH = 06h,AL = 00h |
2. 使用 INT 10h 绘制图形
2.1 INT 10h 图形模式
在使用 INT 10h 绘制图形之前,需要将视频适配器设置为标准图形模式之一。以下是 INT 10h 识别的视频图形模式:
| 模式 | 分辨率(像素) | 颜色数量 |
| ---- | ---- | ---- |
| 6 | 640 × 200 | 2 |
| 0Dh | 320 × 200 | 16 |
| 0Eh | 640 × 200 | 16 |
| 0Fh | 640 × 350 | 2 |
| 10h | 640 × 350 | 16 |
| 11h | 640 × 480 | 2 |
| 12h | 640 × 480 | 16 |
| 13h | 320 × 200 | 256 |
| 6Ah | 800 × 600 | 16 |
2.2 INT 10h 像素相关功能
2.2.1 写入图形像素(0Ch)
INT 10h 功能 0Ch 用于在视频控制器处于图形模式时在屏幕上绘制像素。但该功能执行速度较慢,尤其是绘制大量像素时。
-
接收参数
:
-
AH = 0Ch
-
AL
= 像素值
-
BH
= 视频页面
-
CX
= x 坐标
-
DX
= y 坐标
-
返回值
:无
-
示例调用
:
mov ah,0Ch
mov al,pixelValue
mov bh,videoPage
mov cx,x_coord
mov dx,y_coord
int 10h
-
注意事项
:视频显示必须处于图形模式。像素值范围和坐标范围取决于当前图形模式。如果
AL的第 7 位被设置,新像素将与当前像素内容进行异或运算(允许擦除像素)。
2.2.2 读取图形像素(0Dh)
INT 10h 功能 0Dh 用于从屏幕上的给定行和列位置读取图形像素,并在
AL
中返回像素值。
-
接收参数
:
-
AH = 0Dh
-
BH
= 视频页面
-
CX
= x 坐标
-
DX
= y 坐标
-
返回值
:
AL
= 像素值
-
示例调用
:
mov ah,0Dh
mov bh,0 ; video page 0
mov cx,x_coord
mov dx,y_coord
int 10h
mov pixelValue,al
- 注意事项 :视频显示必须处于图形模式。像素值范围和坐标范围取决于当前图形模式。
2.3 DrawLine 程序
DrawLine 程序使用 INT 10h 切换到图形模式,以文本形式写入程序名称,并绘制一条水平直线。以下是完整的程序代码:
TITLE DrawLine Program (DrawLine.asm)
; This program draws text and a straight line in graphics mode.
INCLUDE Irvine16.inc
;------------ Video Mode Constants -------------------
Mode_06 = 6
; 640 X 200, 2 colors
Mode_0D = 0Dh
; 320 X 200, 16 colors
Mode_0E = 0Eh
; 640 X 200, 16 colors
Mode_0F = 0Fh
; 640 X 350, 2 colors
Mode_10 = 10h
; 640 X 350, 16 colors
Mode_11 = 11h
; 640 X 480, 2 colors
Mode_12 = 12h
; 640 X 480, 16 colors
Mode_13 = 13h
; 320 X 200, 256 colors
Mode_6A = 6Ah
; 800 X 600, 16 colors
.data
saveMode BYTE ?
; save the current video mode
currentX WORD 100
; column number (X-coordinate)
currentY WORD 100
; row number (Y-coordinate)
COLOR = 1001b
; line color (cyan)
progTitle BYTE "DrawLine.asm"
TITLE_ROW = 5
TITLE_COLUMN = 14
; When using a 2-color mode, set COLOR to 1 (white)
.code
main PROC
mov
ax,@data
mov
ds,ax
; Save the current video mode.
mov
ah,0Fh
int
10h
mov
saveMode,al
; Switch to a graphics mode.
mov
ah,0
; set video mode
mov
al,Mode_6A
int
10h
; Write the program name, as text.
mov
ax,SEG progTitle
; get segment of progTitle
mov
es,ax
; store in ES
mov
bp,OFFSET progTitle
mov
ah,13h
; function: write string
mov
al,0
; mode: only character codes
mov
bh,0
; video page 0
mov
bl,7
; attribute = normal
mov
cx,SIZEOF progTitle
; string length
mov
dh,TITLE_ROW
; row (in character cells)
mov
dl,TITLE_COLUMN
; column (in character cells)
int
10h
; Draw a straight line.
LineLength = 100
mov
dx,currentY
mov
cx,LineLength
; loop counter
L1:
push
cx
mov
ah,0Ch
; write pixel
mov
al,COLOR
; pixel color
mov
bh,0
; video page 0
mov
cx,currentX
int
10h
inc
currentX
;inc
color
; enable to see a multi-color line
pop
cx
Loop
L1
; Wait for a keystroke.
mov
ah,0
int
16h
; Restore the starting video mode.
mov
ah,0
; set video mode
mov
al,saveMode
; saved video mode
int
10h
exit
main ENDP
END main
2.4 Cartesian Coordinates 程序
Cartesian Coordinates 程序将视频适配器设置为模式 6Ah(800 × 600,16 色),并绘制笛卡尔坐标系的 X 轴和 Y 轴。以下是程序代码:
TITLE Cartesian Coordinates (Pixel2.asm)
; This program switches into 800 X 600 graphics mode and
; draws the X and Y axes of a Cartesian coordinate system.
; Switch to full-screen mode before running this program.
; Color constants are defined in Irvine16.inc.
INCLUDE Irvine16.inc
Mode_6A = 6Ah
; 800 X 600, 16 colors
X_axisY = 300
X_axisX = 50
X_axisLen = 700
Y_axisX = 400
Y_axisY = 30
Y_axisLen = 540
.data
saveMode BYTE ?
.code
main PROC
mov
ax,@data
mov
ds,ax
; Save the current video mode
mov
ah,0Fh
; get video mode
int
10h
mov
saveMode,al
; Switch to a graphics mode
mov
ah,0
; set video mode
mov
al,Mode_6A
; 800 X 600, 16 colors
int
10h
; Draw the X-axis
mov
cx,X_axisX
; X-coord of start of line
mov
dx,X_axisY
; Y-coord of start of line
mov
ax,X_axisLen
; length of line
mov
bl,white
; line color (see IRVINE16.inc)
call
DrawHorizLine
; draw the line now
; Draw the Y-axis
mov
cx,Y_axisX
; X-coord of start of line
mov
dx,Y_axisY
; Y-coord of start of line
mov
ax,Y_axisLen
; length of line
mov
bl,white
; line color
call
DrawVerticalLine
; draw the line now
; Wait for a keystroke
mov
ah,10h
; wait for key
int
16h
; Restore the starting video mode
mov
ah,0
; set video mode
mov
al,saveMode
; saved video mode
int
10h
exit
main endp
;------------------------------------------------------
DrawHorizLine PROC
;
; Draws a horizontal line starting at position X,Y with
; a given length and color.
; Receives: CX = X-coordinate, DX = Y-coordinate,
; AX = length, and BL = color
; Returns: nothing
;------------------------------------------------------
.data
currX WORD ?
.code
pusha
mov
currX,cx
; save X-coordinate
mov
cx,ax
; loop counter
DHL1:
push
cx
; save loop counter
mov
al,bl
; color
mov
ah,0Ch
; draw pixel
mov
bh,0
; video page
mov
cx,currX
; retrieve X-coordinate
int
10h
inc
currX
; move 1 pixel to the right
pop
cx
; restore loop counter
loop
DHL1
popa
ret
DrawHorizLine ENDP
;------------------------------------------------------
DrawVerticalLine PROC
;
; Draws a vertical line starting at position X,Y with
; a given length and color.
; Receives: CX = X-coordinate, DX = Y-coordinate,
; AX = length, BL = color
; Returns: nothing
;------------------------------------------------------
.data
currY WORD ?
.code
pusha
mov
currY,dx
; save Y-coordinate
mov
currX,cx
; save X-coordinate
mov
cx,ax
; loop counter
DVL1:
push
cx
; save loop counter
mov
al,bl
; color
mov
ah,0Ch
; function: draw pixel
mov
bh,0
; set video page
mov
cx,currX
; set X-coordinate
mov
dx,currY
; set Y-coordinate
int
10h
; draw the pixel
inc
currY
; move down 1 pixel
pop
cx
; restore loop counter
loop
DVL1
popa
ret
DrawVerticalLine ENDP
END main
2.5 笛卡尔坐标转换为屏幕坐标
笛卡尔图上的点与 BIOS 图形系统使用的绝对坐标不对应。可以使用以下公式将笛卡尔坐标
(X, Y)
转换为屏幕坐标
(sx, sy)
:
-
sx = (sOrigX + X)
-
sy = (sOrigY - Y)
其中,
sOrigX
和
sOrigY
是笛卡尔坐标系原点的屏幕坐标。
例如,在 Cartesian Coordinates 程序中,直线相交于
sOrigX = 400
和
sOrigY = 300
,将原点置于屏幕中间。以下是一些测试点的转换结果:
| 笛卡尔坐标 (X, Y) | 转换公式 (sOrigX + X, sOrigY - Y) | 屏幕坐标 (sx, sy) |
| ---- | ---- | ---- |
| (0, 100) | (400 + 0, 300 - 100) | (400, 200) |
| (100, 0) | (400 + 100, 300 - 0) | (500, 300) |
| (0, -100) | (400 + 0, 300 - (-100)) | (400, 400) |
| (-100, 0) | (400 + (-100), 300 - 0) | (300, 300) |
2.6 相关问题回顾
| 问题 | 解答 |
|---|---|
| 哪个 INT 10h 功能在视频显示上绘制单个像素? | INT 10h 功能 0Ch |
使用 INT 10h 绘制单个像素时,必须在
AL
、
BH
、
CX
和
DX
寄存器中放置哪些值?
|
AL
= 像素值,
BH
= 视频页面,
CX
= x 坐标,
DX
= y 坐标
|
| 使用 INT 10h 绘制像素的主要缺点是什么? | 执行速度慢 |
| 编写将视频适配器设置为模式 11h 的 ASM 语句。 |
mov ah, 0; set video mode
mov al, 11h; mode 11h
int 10h; call BIOS routine
|
| 哪个视频模式是 800 × 600 像素,16 色? | 模式 6Ah |
| 将笛卡尔 X 坐标转换为屏幕像素坐标的公式是什么? |
sx = (sOrigX + X)
|
如果笛卡尔原点位于屏幕坐标
sy = 250
,
sx = 350
,将以下笛卡尔点
(X, Y)
转换为屏幕坐标
(sx, sy)
:
a. (0, 100) b. (25, 25) c. (-200, -150) |
a. (350, 150)
b. (375, 225) c. (150, 400) |
3. 内存映射图形
3.1 Mode 13h:320 X 200,256 色
视频模式 13h 是用于内存映射图形最容易使用的模式。屏幕像素被映射为一个二维字节数组,每个像素 1 个字节。该数组从屏幕左上角的像素开始,沿顶行延续 320 个字节。偏移量 320 处的字节映射到屏幕第二行的第一个像素,然后依次沿屏幕继续。其余行以类似方式映射。数组的最后一个字节映射到屏幕右下角的像素。每个像素使用一个完整字节的原因是,该字节保存着对 256 种不同颜色值之一的引用。
使用
OUT
指令将像素和颜色值传输到视频适配器硬件。16 位端口地址分配给
DX
,发送到端口的值在
AL
、
AX
或
EAX
中。例如,视频调色板位于端口地址 3C8h。以下指令将值 20h 发送到该端口:
mov dx,3c8h ; port address
mov al,20h ; value to be output
out dx,al ; send value to port
在模式 13h 中,颜色的有趣之处在于每个颜色整数并不直接表示一种颜色,而是表示一个称为调色板的颜色表的索引。调色板中的每个条目由三个整数值(0 到 63)组成,即 RGB(红、绿、蓝)。调色板中的条目 0 控制屏幕的背景颜色。
通过这种方案可以创建 262,144 种不同的颜色(64³)。在给定时间只能显示 256 种不同的颜色,但程序可以在运行时修改调色板以改变显示颜色。现代操作系统(如 Windows 和 Linux)提供(至少)24 位颜色,其中每个 RGB 值的范围是 0 到 255,这种方案提供 256³(1670 万)种不同的颜色。
RGB 颜色基于光的加性混合,与混合液体颜料时使用的减性方法相反。例如,通过将所有颜色强度级别保持为零来创建黑色。另一方面,通过将所有颜色级别设置为 63(最大值)来创建白色。实际上,当三个级别相等时,会得到不同深浅的灰色:
| 红色 | 绿色 | 蓝色 | 颜色 |
| ---- | ---- | ---- | ---- |
| 0 | 0 | 0 | 黑色 |
| 20 | 20 | 20 | 深灰色 |
| 35 | 35 | 35 | 中灰色 |
| 50 | 50 | 50 | 浅灰色 |
| 63 | 63 | 63 | 白色 |
纯色通过将除一个颜色级别之外的所有颜色级别设置为零来创建。要获得浅色,以相等的量增加其他两种颜色。以下是红色的变化示例:
| 红色 | 绿色 | 蓝色 | 颜色 |
| ---- | ---- | ---- | ---- |
| 63 | 0 | 0 | 亮红色 |
| 10 | 0 | 0 | 暗红色 |
| 30 | 0 | 0 | 中红色 |
| 63 | 40 | 40 | 粉红色 |
同样,可以创建亮蓝色、深蓝色、浅蓝色、亮绿色、深绿色和浅绿色。当然,也可以以其他比例混合两种颜色来创建诸如品红色和淡紫色等颜色。以下是一些示例:
| 红色 | 绿色 | 蓝色 | 颜色 |
| ---- | ---- | ---- | ---- |
| 0 | 30 | 30 | 青色 |
| 30 | 30 | 0 | 黄色 |
| 30 | 0 | 30 | 品红色 |
| 40 | 0 | 63 | 淡紫色 |
3.2 内存映射图形程序
以下是一个使用直接内存映射在模式 13h 下在屏幕上绘制一行 10 个像素的程序:
; Memory Mapped Graphics, Mode 13 (Mode13.asm)
INCLUDE Irvine16.inc
VIDEO_PALLETE_PORT = 3C8h
COLOR_SELECTION_PORT = 3C9h
COLOR_INDEX = 1
PALLETE_INDEX_BACKGROUND = 0
SET_VIDEO_MODE = 0
GET_VIDEO_MODE = 0Fh
VIDE0_SEGMENT = 0A000h
WAIT_FOR_KEYSTROKE = 10h
MODE_13 = 13h
.data
saveMode BYTE ? ; saved video mode
xVal WORD ? ; x-coordinate
yVal WORD ? ; y-coordinate
msg BYTE "Welcome to Mode 13!",0
.code
main PROC
mov ax,@data
mov ds,ax
call SetVideoMode
call SetScreenBackground
; Display a greeting message.
mov edx,OFFSET msg
call WriteString
call Draw_Some_Pixels
call RestoreVideoMode
exit
main ENDP
;------------------------------------------------
SetScreenBackground PROC
;
; Sets the screen's background color. Video
; palette index 0 is the background color.
;------------------------------------------------
mov dx,VIDEO_PALLETE_PORT
mov al,PALLETE_INDEX_BACKGROUND
out dx,al
; Set the screen background color to dark blue.
mov dx,COLOR_SELECTION_PORT
mov al,0 ; red
out dx,al
mov al,0 ; green
out dx,al
mov al,35 ; blue (intensity 35/63)
out dx,al
ret
SetScreenBackground endp
;-----------------------------------------------
SetVideoMode PROC
;
; Saves the current video mode, switches to a
; new mode, and points ES to the video segment.
;-----------------------------------------------
mov ah,GET_VIDEO_MODE
int 10h
mov saveMode,al ; save it
mov ah,SET_VIDEO_MODE
mov al,MODE_13 ; to mode 13h
int 10h
push VIDE0_SEGMENT ; video segment address
pop es ; ES points to video segment
ret
SetVideoMode ENDP
;---------------------------------------------
RestoreVideoMode PROC
;
; Waits for a key to be pressed and restores
; the video mode to its original value.
;----------------------------------------------
mov ah,WAIT_FOR_KEYSTROKE
int 16h
mov ah,SET_VIDEO_MODE ; reset video mode
mov al,saveMode ; to saved mode
int 10h
ret
RestoreVideoMode ENDP
;-----------------------------------------------
Draw_Some_Pixels PROC
; 此处代码未给出完整,推测后续会有绘制像素的具体逻辑
ret
Draw_Some_Pixels ENDP
END main
该程序的执行流程如下:
graph LR
A[开始] --> B[设置视频模式]
B --> C[设置屏幕背景]
C --> D[显示问候消息]
D --> E[绘制一些像素]
E --> F[恢复视频模式]
F --> G[结束]
3.3 总结
本文介绍了 BIOS 级编程中的光标移动和屏幕操作过程,如
AdvanceCursor
、
Gotoxy
和
Clrscr
过程。还详细阐述了使用 INT 10h 绘制图形的方法,包括设置图形模式、绘制像素、绘制直线以及笛卡尔坐标与屏幕坐标的转换。最后,介绍了内存映射图形,重点讲解了模式 13h 的特点和使用方法,并给出了相应的程序示例。
通过这些知识和代码示例,我们可以看到 BIOS 级编程和图形绘制在底层硬件交互方面的强大功能。在实际应用中,可以根据具体需求选择合适的图形模式和绘制方法,以实现高效、美观的图形输出。同时,对于内存映射图形,虽然它提供了更高效的图形绘制方式,但需要对硬件和内存映射有更深入的理解。
希望这些内容能帮助你更好地掌握 BIOS 级编程和图形绘制的相关知识,在实际项目中灵活运用。
超级会员免费看
3

被折叠的 条评论
为什么被折叠?



