BIOS 与 MS-DOS 编程深度解析
1. BIOS 级编程概述
在 BIOS 级别进行编程,能比在 MS - DOS 级别对计算机的输入输出设备进行更精细的控制。通过 INT 16h 可对键盘编程,INT 10h 可控制视频显示,INT 33h 则用于鼠标操作。
1.1 键盘编程
INT 16h 对于读取扩展键盘按键(如功能键和光标箭头键)尤为实用。键盘硬件借助 INT 9h、INT 16h 和 INT 21h 处理器,将键盘输入提供给程序。以下是一个示例程序,它会轮询键盘,当按下 Esc 键时跳出循环:
; 示例代码:轮询键盘,按下 Esc 键跳出循环
.code
main PROC
L1:
mov ah, 01h
int 16h ; 检查键盘输入
jz L1 ; 如果没有按键,继续循环
mov ah, 00h
int 16h ; 读取按键
cmp al, 1Bh ; 检查是否为 Esc 键
je ExitProg ; 如果是,退出程序
jmp L1 ; 否则继续循环
ExitProg:
mov ax, 4C00h
int 21h ; 退出程序
main ENDP
END main
1.2 视频显示编程
视频显示通过原色的加法合成产生颜色,颜色位会映射到视频属性字节。INT 10h 包含众多实用功能,可在 BIOS 级别控制视频显示。以下是一个滚动彩色窗口并在其中写入文本的示例程序:
; 示例代码:滚动彩色窗口并写入文本
TITLE Scrolling Color Window
.MODEL SMALL
.STACK 100h
.DATA
msg DB 'Hello, World!', 0
.CODE
main PROC
MOV AX, @DATA
MOV DS, AX
; 设置视频模式
MOV AH, 00h
MOV AL, 13h
INT 10h
; 滚动窗口
MOV AH, 06h
MOV AL, 01h
MOV BH, 07h
MOV CX, 0000h
MOV DX, 184Fh
INT 10h
; 写入文本
MOV AH, 02h
MOV BH, 00h
MOV DH, 0Ah
MOV DL, 20h
INT 10h
MOV AH, 09h
LEA DX, msg
INT 21h
; 退出程序
MOV AH, 4Ch
INT 21h
main ENDP
END main
此外,还能使用 INT 10h 绘制彩色图形,可通过简单公式将笛卡尔坐标转换为屏幕坐标(像素位置)。还有示例程序展示了如何直接写入视频内存来绘制高速彩色图形。
1.3 鼠标编程
INT 33h 有众多函数可操作和读取鼠标,例如有示例程序可跟踪鼠标移动和鼠标按键点击。
1.4 编程挑战与练习
-
鼠标指针定位挑战
-
若要使鼠标指针指向文本模式下第 10 行、第 20 列字符单元格的左上角,假设每个字符水平占 8 像素、垂直占 16 像素,向 INT 33h 功能 4 传递的 X、Y 值计算如下:
- X = 20 * 8 = 160
- Y = 10 * 16 = 160
-
若要使鼠标指针指向文本模式下第 15 行、第 22 列字符单元格的中间,同样假设每个字符水平占 8 像素、垂直占 16 像素,向 INT 33h 功能 4 传递的 X、Y 值计算如下:
- X = 22 * 8 + 4 = 180
- Y = 15 * 16 + 8 = 248
-
若要使鼠标指针指向文本模式下第 10 行、第 20 列字符单元格的左上角,假设每个字符水平占 8 像素、垂直占 16 像素,向 INT 33h 功能 4 传递的 X、Y 值计算如下:
-
编程练习
- ASCII 表显示 :使用 INT 10h 显示 IBM 扩展 ASCII 字符集的 256 个字符,每行显示 32 列,每个字符后加一个空格。
-
滚动文本窗口
:定义一个约为视频显示四分之三大小的文本窗口,按顺序执行以下操作:
- 调用 Irvine16 库的 Random_range 函数在窗口顶行绘制一串随机字符。
- 将窗口向下滚动一行。
- 调用 Irvine16 库的 Delay 函数暂停程序约 200 毫秒。
- 绘制另一行随机文本。
- 持续滚动和绘制,直到显示 50 行。
- 滚动彩色列 :以滚动文本窗口练习为基础,随机字符串仅在第 0、3、6、9、…、78 列有字符,其他列空白,每列颜色不同。
- 不同方向滚动列 :同样以滚动文本窗口练习为基础,在循环开始前随机选择每列向上或向下滚动,程序运行期间保持同一方向。可将每列定义为单独的滚动窗口。
- 绘制矩形 :使用 INT 10h 的像素绘制功能,创建名为 DrawRectangle 的过程,该过程接受左上角和右下角的位置以及颜色作为输入参数。编写一个短测试程序,绘制多个不同大小和颜色的矩形。
- 绘制函数图形 :使用 INT 10h 的像素绘制功能,绘制由方程 Y = 2(X^2) 确定的直线。
- 模式 13 绘制单垂直线 :修改相关内存映射图形程序,使其绘制一条单垂直线。
- 模式 13 绘制多垂直线 :修改相关内存映射图形程序,使其绘制 10 条不同颜色的垂直线。
- 绘制框程序 :编写一个过程,在屏幕任意位置绘制单行框,使用特定的扩展 ASCII 代码(C0h、BFh、B3h、C4h、D9h 和 DAh)。该过程的唯一输入参数应为指向 FRAME 结构的指针:
FRAME STRUCT
Left BYTE ? ; 左边
Top BYTE ? ; 顶行
Right BYTE ? ; 右边
Bottom BYTE ? ; 底行
FrameColor BYTE ? ; 框颜色
FRAME ENDS
以下是测试该过程的程序示例:
TITLE Box Drawing Program
.MODEL SMALL
.STACK 100h
.DATA
Frame1 FRAME <10, 10, 30, 20, 0Ah>
.CODE
main PROC
MOV AX, @DATA
MOV DS, AX
LEA DX, Frame1
CALL DrawFrame ; 调用绘制框的过程
MOV AX, 4C00h
INT 21h ; 退出程序
main ENDP
DrawFrame PROC
; 绘制框的具体实现
RET
DrawFrame ENDP
END main
1.5 流程图:BIOS 级编程流程
graph LR
A[开始] --> B[键盘编程(INT 16h)]
A --> C[视频显示编程(INT 10h)]
A --> D[鼠标编程(INT 33h)]
B --> E[轮询键盘输入]
E --> F{是否为 Esc 键}
F -- 是 --> G[退出程序]
F -- 否 --> E
C --> H[设置视频模式]
H --> I[滚动窗口]
I --> J[写入文本]
D --> K[跟踪鼠标移动和点击]
G --> L[结束]
J --> L
K --> L
2. MS - DOS 编程进阶
2.1 简介
对于计划从事英特尔处理器硬件级工作的工程师,或者想了解 MS - DOS 专家在有限资源下所能实现的惊人成果的人来说,这部分内容非常有价值。它将展示如何从 .MODEL、.CODE、.STACK 等相关指令中获取最大灵活性,以及如何使用显式段指令从头定义段。建议安装早期版本的 Windows(如 Windows 95 或 Windows 98)以确保与程序完全兼容,也可使用软件工具创建虚拟机进行实验。
2.2 定义段
2.2.1 简化段指令
使用 .MODEL 指令时,汇编器会自动为近数据段定义 DGROUP。.DATA 和 .DATA? 指令都会创建近数据段,在实地址模式下最大可达 64Kb,会被放置在 DGROUP 组中,该组也限制为 64Kb。在小和中等内存模型中使用 .FARDATA 和 .FARDATA? 时,汇编器会分别创建名为 FAR_DATA 和 FAR_BSS 的远数据段。
-
识别变量的段
:可使用 SEG 运算符将段地址分配给段寄存器。例如,将 DS 设置为包含 farvar 的段:
mov ax, SEG farvar
mov ds, ax
- 代码段 :代码段由 .CODE 指令定义。在小内存模型程序中,.CODE 指令会使汇编器生成名为 _TEXT 的段。在中等、大及巨型模型程序中,每个源代码模块会被分配不同的段名,格式为模块名后跟 _TEXT。也可在同一模块中声明多个代码段,只需在 .CODE 指令后添加可选的段名:
.code MyCode
以下是一个包含两个代码段的示例程序:
TITLE Multiple Code Segments (MultCode.asm)
; This small model program contains multiple
; code segments.
.model small,stdcall
.stack 100h
WriteString PROTO
.data
msg1 db "First Message",0dh,0ah,0
msg2 db "Second Message",0dh,0ah,"$"
.code
main PROC
mov ax, @data
mov ds, ax
mov dx, OFFSET msg1
call WriteString ; NEAR call
call Display ; FAR call
.exit
main ENDP
.code OtherCode
Display PROC FAR
mov ah, 9
mov dx, offset msg2
int 21h
ret
Display ENDP
END main
2.2.2 显式段定义
在某些情况下,可能需要显式定义段。例如,定义多个带有额外内存缓冲区的数据段,或者将程序链接到使用自有专有段名的对象库,又或者编写供不使用微软段名的高级语言编译器调用的过程。显式段定义的程序需完成两项任务:一是在使用段之前将段寄存器(DS、ES 或 SS)设置为每个段的位置;二是告知汇编器如何在正确的段内计算标签的偏移量。
段使用 SEGMENT 和 ENDS 指令分别定义开始和结束,程序可包含任意数量的段,每个段有唯一名称,段也可组合。语法如下:
name SEGMENT [align] [combine] ['class']
statement - list
name ENDS
其中:
- name:标识段,可为唯一名称或现有段名。
- align:可为 BYTE、WORD、DWORD、PARA 或 PAGE。
- combine:可为 PRIVATE、PUBLIC、STACK、COMMON、MEMORY 或 AT address。
- class:是用单引号括起来的标识符,用于标识特定类型的段(如 CODE 或 STACK)。
以下是一个定义名为 ExtraData 的段的示例:
ExtraData SEGMENT PARA PUBLIC 'DATA'
var1 BYTE 1
var2 WORD 2
ExtraData ENDS
2.2.3 对齐类型
当两个或多个段要组合时,对齐类型告知链接器如何对齐它们的起始地址。默认对齐类型为 PARA,表示段必须从 16 字节边界开始。以下是不同对齐类型的说明:
| 对齐类型 | 说明 |
| ---- | ---- |
| BYTE | 段从前一个段后的下一个字节开始 |
| WORD | 段从下一个 16 位边界开始 |
| DWORD | 段从下一个 32 位边界开始 |
| PARA | 段从下一个 16 字节边界开始 |
| PAGE | 段从下一个 256 字节边界开始 |
如果程序可能在 8086 或 80286 处理器上运行,对于数据段,WORD 或更大的对齐类型更佳,因为这些处理器有 16 位数据总线。而 x86 处理器每次取 32 位数据,应使用 DWORD 对齐类型。
2.2.4 组合类型
段的组合类型告知链接器如何组合具有相同名称的段。默认组合类型为 PRIVATE,表示该段不会与其他段组合。以下是不同组合类型的说明:
| 组合类型 | 说明 |
| ---- | ---- |
| PUBLIC | 段将与所有其他同名的公共段组合成一个段,标签偏移量相对于新段的起始位置调整 |
| MEMORY | 与 PUBLIC 类似,段会与所有其他同名的内存段组合 |
| STACK | 所有其他栈段将与该段组合,MS - DOS 会自动将 SS 初始化为第一个具有 STACK 组合类型的段的起始位置,并在程序加载时将 SP 设置为段长度减 1 |
| COMMON | 段与其他同名的 COMMON 段从相同地址开始,段会相互覆盖,所有偏移量从相同起始地址计算,变量可能重叠 |
| AT address | 可在绝对地址创建段,常用于硬件或操作系统预定义位置的数据,不能初始化变量或数据,但可创建引用特定偏移量的变量名 |
以下是使用 AT address 组合类型的示例:
bios SEGMENT AT 40h
ORG 17h
keyboard_flag BYTE ? ; MS - DOS 键盘标志
bios ENDS
.code
mov ax, bios ; 指向 BIOS 段
mov ds, ax
and ds:keyboard_flag, 7Fh ; 清除高位
2.2.5 类类型
段的类类型提供了另一种组合段的方式,特别是对于不同名称的段。类类型是区分大小写的字符串,用单引号括起来。具有相同类类型的段会一起加载,尽管它们在原始程序中的顺序可能不同。链接器会识别标准类型 CODE,用于包含指令的段。如果计划使用调试器,必须包含此类标签。
2.2.6 ASSUME 指令
ASSUME 指令告知汇编器在汇编时如何计算代码和数据标签的偏移量。它通常紧跟代码段的 SEGMENT 指令之后。语法如下:
ASSUME segreg : segname
ASSUME 指令不会实际改变段寄存器的值,这需要在运行时使用指令将段值分配给段寄存器。代码中可包含多个 ASSUME 指令,遇到新的 ASSUME 指令时,汇编器会从该点开始修改地址计算方式。
以下是一个包含两个数据段的示例程序:
TITLE Multiple Data Segments (MultData.asm)
; This program shows how to explicitly declare
; multiple data segments.
cseg SEGMENT 'CODE'
ASSUME cs:cseg, ds:data1, es:data2, ss:mystack
main PROC
mov ax, data1 ; 指向 data1 段
mov ds, ax
mov ax, SEG val2 ; 指向 data2 段
mov es, ax
mov ax, val1 ; 假设为 data1 段
mov bx, val2 ; 假设为 data2 段
mov ax, 4C00h ; 退出程序
int 21h
main ENDP
cseg ENDS
data1 SEGMENT 'DATA'
val1 WORD 1001h
data1 ENDS
data2 SEGMENT 'DATA'
val2 WORD 1002h
data2 ENDS
mystack SEGMENT para STACK 'STACK'
BYTE 100h dup('S')
mystack ENDS
END main
程序中使用了两种设置段寄存器值的方法,第一种使用段名(data1):
mov ax, data1 ; 指向 data1 段
mov ds, ax
2.3 流程图:MS - DOS 段定义流程
graph LR
A[开始] --> B{是否使用简化段指令}
B -- 是 --> C[使用 .MODEL、.DATA 等指令]
B -- 否 --> D[使用显式段定义(SEGMENT 和 ENDS)]
C --> E[定义近数据段(DGROUP)]
C --> F[定义代码段(.CODE)]
D --> G[设置对齐类型(align)]
D --> H[设置组合类型(combine)]
D --> I[设置类类型(class)]
G --> J{选择对齐方式}
J -- BYTE --> K[段从下一字节开始]
J -- WORD --> L[段从下一个 16 位边界开始]
J -- DWORD --> M[段从下一个 32 位边界开始]
J -- PARA --> N[段从下一个 16 字节边界开始]
J -- PAGE --> O[段从下一个 256 字节边界开始]
H --> P{选择组合方式}
P -- PUBLIC --> Q[与同名公共段组合]
P -- STACK --> R[与其他栈段组合]
P -- COMMON --> S[与同名 COMMON 段重叠]
P -- AT address --> T[在绝对地址创建段]
I --> U{选择类类型}
U -- CODE --> V[用于包含指令的段]
U -- 其他 --> W[按类类型组合段]
K --> X[完成段定义]
L --> X
M --> X
N --> X
O --> X
Q --> X
R --> X
S --> X
T --> X
V --> X
W --> X
E --> X
F --> X
X --> Y[结束]
2.4 运行时程序结构
2.4.1 程序段前缀(PSP)
程序段前缀是 MS - DOS 加载程序时在程序开头创建的一个数据结构,它包含了程序运行所需的一些重要信息,如环境变量、命令行参数等。PSP 的段地址通常存储在程序开始执行时的 CS:0 处。在程序中可以通过这个地址来访问 PSP 中的信息。例如,若要获取环境变量字符串的地址,可以通过 PSP 中的特定偏移量来查找。
2.4.2 COM 程序
COM 程序是一种简单的可执行文件格式,它的代码、数据和栈都位于同一个 64KB 的段中。COM 程序的入口点固定为偏移地址 100h。在编写 COM 程序时,不需要显式地定义段,汇编器会自动将所有内容放在一个段中。以下是一个简单的 COM 程序示例:
; 简单的 COM 程序示例
ORG 100h
MOV AH, 09h
MOV DX, offset msg
INT 21h
MOV AH, 4Ch
INT 21h
msg DB 'Hello, COM Program!', '$'
2.4.3 EXE 程序
EXE 程序是一种更复杂的可执行文件格式,它可以包含多个段,如代码段、数据段和栈段。EXE 文件有一个文件头,其中包含了程序的段信息、入口点等。在加载 EXE 程序时,MS - DOS 会根据文件头中的信息来初始化各个段寄存器。以下是一个简单的 EXE 程序示例:
TITLE Simple EXE Program
.MODEL SMALL
.STACK 100h
.DATA
msg DB 'Hello, EXE Program!', 0
.CODE
main PROC
MOV AX, @DATA
MOV DS, AX
MOV AH, 09h
LEA DX, msg
INT 21h
MOV AX, 4C00h
INT 21h
main ENDP
END main
2.4.4 运行时程序结构对比
| 程序类型 | 段结构 | 入口点 | 特点 |
|---|---|---|---|
| COM 程序 | 单一 64KB 段 | 偏移地址 100h | 简单,适合小型程序 |
| EXE 程序 | 可包含多个段 | 文件头指定 | 灵活,可处理复杂程序 |
2.5 中断处理
2.5.1 硬件中断
硬件中断是由外部硬件设备(如键盘、鼠标、定时器等)触发的中断。每个硬件设备都有一个对应的中断请求(IRQ)级别,Intel 8259 可编程中断控制器(PIC)负责管理这些中断请求。当硬件设备产生中断请求时,PIC 会将其传递给 CPU,CPU 会暂停当前正在执行的程序,转去执行相应的中断处理程序。
2.5.2 中断控制指令
在汇编语言中,可以使用一些指令来控制中断的响应。例如,CLI 指令用于禁止中断,STI 指令用于允许中断。这些指令可以在程序中根据需要来控制中断的开关,以确保程序的稳定性和正确性。
2.5.3 编写自定义中断处理程序
编写自定义中断处理程序的步骤如下:
1. 保存当前的寄存器状态,以免在中断处理过程中破坏原有的数据。
2. 执行中断处理的具体操作,如读取硬件设备的数据、更新显示等。
3. 恢复寄存器状态。
4. 使用 IRET 指令从中断处理程序返回,恢复原来的程序执行。
以下是一个简单的自定义中断处理程序示例:
; 自定义中断处理程序示例
TITLE Custom Interrupt Handler
.MODEL SMALL
.STACK 100h
.DATA
old_int9 DD ? ; 保存原有的 INT 9 中断向量
.CODE
main PROC
; 保存原有的 INT 9 中断向量
MOV AX, 3509h
INT 21h
MOV WORD PTR old_int9, BX
MOV WORD PTR old_int9 + 2, ES
; 设置新的 INT 9 中断向量
MOV AX, 2509h
MOV DX, OFFSET new_int9
MOV DS, AX
INT 21h
; 主程序循环
MOV AH, 01h
INT 21h
; 恢复原有的 INT 9 中断向量
MOV AX, 2509h
MOV DX, WORD PTR old_int9
MOV DS, WORD PTR old_int9 + 2
INT 21h
MOV AX, 4C00h
INT 21h
main ENDP
new_int9 PROC
; 保存寄存器状态
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; 中断处理的具体操作
; 这里可以添加读取键盘数据等操作
; 恢复寄存器状态
POP DX
POP CX
POP BX
POP AX
; 调用原有的 INT 9 中断处理程序
MOV AX, WORD PTR old_int9
MOV DS, WORD PTR old_int9 + 2
JMP DWORD PTR old_int9
new_int9 ENDP
END main
2.5.4 终止并驻留程序(TSR)
终止并驻留程序是一种特殊的程序,它在执行完部分任务后,会将自己的一部分代码和数据驻留在内存中,以便后续继续响应特定的事件。编写 TSR 程序的关键步骤如下:
1. 保存原有的中断向量。
2. 设置新的中断向量,指向自己的中断处理程序。
3. 释放不需要的内存,将程序的一部分驻留在内存中。
4. 使用 INT 27h 指令终止程序并驻留。
以下是一个简单的 TSR 程序示例:
; 简单的 TSR 程序示例
TITLE TSR Program
.MODEL SMALL
.STACK 100h
.DATA
old_int9 DD ? ; 保存原有的 INT 9 中断向量
.CODE
main PROC
; 保存原有的 INT 9 中断向量
MOV AX, 3509h
INT 21h
MOV WORD PTR old_int9, BX
MOV WORD PTR old_int9 + 2, ES
; 设置新的 INT 9 中断向量
MOV AX, 2509h
MOV DX, OFFSET new_int9
MOV DS, AX
INT 21h
; 释放不需要的内存
MOV AH, 49h
MOV ES, AX
INT 21h
; 终止并驻留程序
MOV AH, 27h
MOV DX, ($ - main)
INT 21h
main ENDP
new_int9 PROC
; 保存寄存器状态
PUSH AX
PUSH BX
PUSH CX
PUSH DX
; 中断处理的具体操作
; 这里可以添加读取键盘数据等操作
; 恢复寄存器状态
POP DX
POP CX
POP BX
POP AX
; 调用原有的 INT 9 中断处理程序
MOV AX, WORD PTR old_int9
MOV DS, WORD PTR old_int9 + 2
JMP DWORD PTR old_int9
new_int9 ENDP
END main
2.5.5 应用:无复位程序
无复位程序是一种特殊的程序,它可以防止计算机在按下复位按钮时重启。实现无复位程序的关键是修改与复位相关的中断处理程序,使其忽略复位信号。以下是一个简单的无复位程序示例:
; 无复位程序示例
TITLE No_Reset Program
.MODEL SMALL
.STACK 100h
.DATA
old_int19 DD ? ; 保存原有的 INT 19h 中断向量
.CODE
main PROC
; 保存原有的 INT 19h 中断向量
MOV AX, 3519h
INT 21h
MOV WORD PTR old_int19, BX
MOV WORD PTR old_int19 + 2, ES
; 设置新的 INT 19h 中断向量
MOV AX, 2519h
MOV DX, OFFSET new_int19
MOV DS, AX
INT 21h
; 主程序循环
MOV AH, 01h
INT 21h
; 恢复原有的 INT 19h 中断向量
MOV AX, 2519h
MOV DX, WORD PTR old_int19
MOV DS, WORD PTR old_int19 + 2
INT 21h
MOV AX, 4C00h
INT 21h
main ENDP
new_int19 PROC
; 不执行复位操作,直接返回
IRET
new_int19 ENDP
END main
2.6 硬件控制使用 I/O 端口
2.6.1 输入 - 输出端口
输入 - 输出端口是计算机用于与外部硬件设备进行通信的接口。每个 I/O 端口都有一个唯一的地址,通过对这些端口进行读写操作,可以实现与硬件设备的数据交换。在汇编语言中,可以使用 IN 和 OUT 指令来进行 I/O 端口的读写操作。例如,读取键盘控制器的状态可以通过读取特定的 I/O 端口地址来实现。
2.6.2 PC 声音程序
可以通过控制 PC 机的扬声器来产生声音。PC 机的扬声器通过定时器和 I/O 端口来控制。以下是一个简单的 PC 声音程序示例:
; PC 声音程序示例
TITLE PC Sound Program
.MODEL SMALL
.STACK 100h
.CODE
main PROC
; 设置定时器频率
MOV AL, 0B6h
OUT 43h, AL
MOV AX, 1193 ; 频率为 1000Hz
OUT 42h, AL
MOV AL, AH
OUT 42h, AL
; 打开扬声器
IN AL, 61h
OR AL, 03h
OUT 61h, AL
; 延时
MOV CX, 10000
delay_loop:
LOOP delay_loop
; 关闭扬声器
IN AL, 61h
AND AL, 0FCh
OUT 61h, AL
MOV AX, 4C00h
INT 21h
main ENDP
END main
2.7 流程图:MS - DOS 运行时程序及中断处理流程
graph LR
A[开始] --> B{程序类型}
B -- COM 程序 --> C[单一 64KB 段,入口 100h]
B -- EXE 程序 --> D[多个段,按文件头初始化]
C --> E[执行程序]
D --> E
E --> F{是否处理中断}
F -- 是 --> G[保存原中断向量]
F -- 否 --> H[正常执行程序]
G --> I[设置新中断向量]
I --> J{是否为 TSR 程序}
J -- 是 --> K[释放内存,驻留程序]
J -- 否 --> L[正常执行中断处理]
K --> M[等待中断事件]
L --> M
M --> N{是否有中断事件}
N -- 是 --> O[执行中断处理程序]
N -- 否 --> M
O --> P[恢复原中断向量]
P --> Q[结束中断处理]
Q --> R[继续执行程序]
H --> R
R --> S[结束]
3. 总结
通过对 BIOS 级编程和 MS - DOS 编程的深入学习,我们了解到在不同层面进行编程可以实现不同的功能。BIOS 级编程能够让我们更直接地控制计算机的输入输出设备,如键盘、视频显示和鼠标等。而 MS - DOS 编程则提供了更多的灵活性,包括段的定义、运行时程序结构的管理、中断处理以及硬件控制等方面。掌握这些知识,不仅可以让我们理解计算机系统的底层运行机制,还能在有限的资源下实现一些复杂的功能,为成为一名优秀的系统级程序员打下坚实的基础。在实际应用中,可以根据具体的需求选择合适的编程方式和技术,以达到最佳的编程效果。
超级会员免费看
7

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



