8086 汇编学习 Part 8

发布于:2024-05-06 ⋅ 阅读:(32) ⋅ 点赞:(0)

移位指令

C N T > 1 CNT > 1 CNT>1 时,CNT 必须是 CL 寄存器

逻辑左移

SHL OPR , CNT
将寄存器或内存单元中的数据向左移 CNT 位,最后移除的一位写入 CF,最低位用 0 补充

循环左移

ROL OPR , CNT
将寄存器中的值的最高位存入 CF 寄存器,其他位左移一位,将 CF 寄存器的值补给最低位,以此循环 CNT 次

逻辑右移

SHR OPR , CNT
将寄存器或内存单元中的数据向右移 CNT 位,最后移
除的一位写入 CF,最高位用 0 补充

循环右移

ROR OPR , CNT
将寄存器中的值的最低位存入 CF 寄存器,其他位右移一位,将 CF 寄存器的值补给最高位,以此循环 CNT 次

算数左移

SAL OPR , CNT
将寄存器中的值的最高位存入 CF 寄存器,其他位左移一位,最低位补 0,以此循环 CNT 次

算数右移

SAR OPR , CNT
将寄存器中的值的最低位存入 CF 寄存器,其他位右移一位,最高位保持不变,以此循环 CNT 次

带进位循环左移

RCL OPR CNT
将寄存器中的值的最高位存入 CF 寄存器,其他位左移一位,将 此次操作前的CF 寄存器的值补给最低位,以此循环 CNT 次

带进位循环右移

RCR OPR CNT
将寄存器中的值的最低位存入 CF 寄存器,其他位右移一位,将 此次操作前的CF 寄存器的值补给最高位,以此循环 CNT 次

操作显存数据

显示的原理

屏幕上的内容就是显存中的数据
在 8086 CPU 中显存地址是 [ A 0000 , B F F F F ] [A0000,BFFFF] [A0000,BFFFF] 的 128K RAM,其中 [ B 8000 H , B F F F F H ] [B8000H,BFFFFH] [B8000H,BFFFFH] 共 32K 的空间,是 80 × 25 80 \times 25 80×25 彩色字符模式第 0 页的显示缓冲区

显示缓冲区的结构

屏幕截图 2024 05 03 204051

描述内存单元的标号

标号

  • 代码段中的标号可以用来标记指令、段的起始地址
  • 代码段中的数据也可以用标号
  • 在段中使用的标号没有 “ : ” 它们同时描述内存地址单元长度的标号,同时规定了在此标号对应的内存地址后的内存单元的数据类型,这类标号称作数据标号

数据标号

  • 数据标号标记了存储数据的单元的地址和长度
  • 数据标号不同于仅仅表示地址的地址标号

数据段中的数据标号

数据最好专门存放到数据段中,实现分段管理,数据段中可以直接用数据标号
地址标号只能在代码段中使用,数据段中不可以使用地址标号,只能使用数据标号

扩展用法

将标号当作数据来定义

data segment
	a DB 1,2,3,4,5,6,7,8
	b DW 0
	c DW a,b
data ENDS

可以通过 c 间接的访问 a 和 b 指向的内存单元,相当于

data segment
	a DB 1,2,3,4,5,6,7,8
	b DW 0
	c DW OFFSET a,OFFSET b
data ENDS
data segment
	a DB 1,2,3,4,5,6,7,8
	b DW 0
	c DD a,b
data ENDS

相当于

data segment
	a DB 1,2,3,4,5,6,7,8
	b DW 0
	c DW OFFSET a,SEG a,OFFSET b,SEG b
data ENDS

SEG 操作符的作用是取段地址

直接定址表

直接定址表法

用查表得方法,通过依据数据,直接算出所要找得元素的位置

直接定址表分类

数据的直接定址表

用查表得方法解决问题
利用表,在两个数据集合之间建立一种映射关系,用查表得方法根据给出得数据得到其在另一集合中得对应数据。

映射关系
  • 数值 [ 0 , 9 ] + 30 H = 字符 [ ′ 0 ′ , ′ 9 ′ ] [0,9] + 30H = 字符 ['0','9'] [0,9]+30H=字符[0,9]
  • 数值 [ 10 , 15 ] + 37 H = 字符 [ ′ A ′ , ′ F ′ ] [10,15] + 37H = 字符 ['A','F'] [10,15]+37H=字符[A,F]
建立表依次存储字符 [ ′ 0 ′ , ′ F ′ ] ['0','F'] [0,F],通过数值 [ 0 , 15 ] [0,15] [0,15] 直接查找到对应字符

TABLE DB '0123456789ABCDEF'
####优点

  • 算法清晰和简洁
  • 加快运算速度
  • 使程序易于扩充

代码的直接定址表

  1. 将若干个功能写成若干个对应的子程序
  2. 将这些功能子程序的入口地址存储在一个表中,它们在表中的位置和功能号对应
  3. 对应关系为 功能号 × 2 = 对应的功能子程序在地址表中的偏移 功能号 \times 2 = 对应的功能子程序在地址表中的偏移 功能号×2=对应的功能子程序在地址表中的偏移

中断及其处理

中断

定义

CPU 不再接着(刚执行完的指令)向下执行,而是转去处理中断信息

内中断

定义

CPU 内部发生的事件而引起的中断

CPU 内部产生的中断信息及中断号
除法错误(0)
单步执行(1)
执行 INTO 指令(4)
执行 INT n 指令(立即数 N)

外中断

定义

外部设备发生的事件而引起的中断

中断处理程序

  • CPU 接到中断信息后会执行处理程序
  • 中断信息和其处理程序的入口地址入口之间有某种联系,CPU 根据中断信息可以找到要执行的处理程序
  • 标志寄存器断点是中断隐指令入栈,IRET 指令出栈
  • 其他子程序是中断处理程序内部出入栈

中断处理程序的常规的步骤

  1. 保存用到的寄存器
  2. 处理中断
  3. 恢复用到的寄存器
  4. 用 IRET 指令返回

中断向量表

由中断类型码,查表得到中断处理程序的入口地址,从而定位中断程序
8086 CPU 的中断向量表,每个中断程序入口地址占用 4 字节
( I P ) = ( 中断类型码 × 4 ) , ( C S ) = ( 中断类型码 × 4 + 2 ) (IP) = (中断类型码 \times 4) , (CS) = (中断类型码 \times 4 + 2) (IP)=(中断类型码×4),(CS)=(中断类型码×4+2)
屏幕截图 2024 05 03 214140

中断过程

屏幕截图 2024 05 03 214547

  • 中断过程由CPU硬件自动完成
  • 用中断类型码找到中断向量,并用它设置 CS 和 IP

8086 CPU 的中断过程

  1. 从中断信息中取得中断类型码
  2. 标志寄存器的值入栈(中断过程中要改变标志器的值,要先行保护)
  3. 设置标志寄存器的第 8 位 TF 和 第 9 位 IF 的值为 0
  4. CS 的内容入栈
  5. IP 的内容入栈
  6. 从中断向量表读取中断处理程序的入口地址,设置 IP 和 CS
代码流程
取得中断类型码 N
PUSHF
TF = 0
IF = 0
PUSH CS
PUSH IP
(IP) = (N * 4)
(CS) = (N * 4 + 2)

编写中断处理程序

  • CPU 随时都可能检测到中断信息,所以中断处理程序必须常驻内存(一直存储在内存某段空间之中)。
  • 中断处理程序的入口地址(即中断向量),必须存储在对硬的中断向量表表项中( [ 0000 : 0000 , 0000 : 03 F F ] [0000 : 0000,0000 : 03FF] [0000:0000,0000:03FF]
  • 如果中断程序需要用到固定的数据,将数据写到中断程序的代码区,保证与代码一起加载

自己编写的中断处理程序应该放在哪?

  • 应该存放在内存的确定位置,要重新找个地方,不破坏原有的系统
  • 在操作系统之上使用计算机,所有的硬件资源都在操作系统的管理之下,应该向操作系统申请获得存放程序的内存,但是要引入好多技术细节
  • 最简便的方案是绕过操作系统,直接在找到一块别的程序不会用到的内存区,将程序传送到其中即可
  • 内存 [ 0000 : 0000 , 0000 : 03 F F ] [0000 : 0000,0000 : 03FF] [0000:0000,0000:03FF] 大小为 1KB 的空间是系统存放中断向量表, DOS 系统和其他应用程序都不会随便使用这段空间。
  • 8086 支持 256 个中断,但实际上系统中要处理的中断事件远没有达到 256 个
  • 利用中断向量表中的空闲单元来存放我们的程序,选用合适的空间来存放程序

安装中断程序

  1. 设置 DS : IP 指向程序源地址
  2. 设置 ES : DI 指向目标地址
  3. 设置 CX 为传输长
    (在程序结尾写一个标号, 程序长度 = 程序结尾的标号地址 − 程序标号对应的地址 程序长度 = 程序结尾的标号地址 - 程序标号对应的地址 程序长度=程序结尾的标号地址程序标号对应的地址
  4. 设置传输方向为正
  5. REP MOVSB

设置中断向量表

将中断程序入口地址,写到中断向量表的对应表项中(逻辑同查表过程)

单步中断

Debug 的 T 命令

  • Debug 提供了单步中断的中断处理程序,功能为显示所有寄存器中的内容后等待输入命令
  • Debug 利用了 CPU提供的单步中断功能
  • 使用 T 命令时,Debug 将 TF 标志设置为 1,使 CPU 工作在单步中断方式下

单步中断过程

当 CPU 执行完一条指令之后,如果检测到标志寄存器 TF 位为 1,则产生单步中断(中断类型码为 1,引发中孤单程序,执行中断处理程序)

TF 陷阱标志(Trap Flag)
  • 用于调试时的单步方式操作。
  • 当 TF = 1 时,每条指令执行完后产生陷阱,由系统控制计算机
  • 当 TF = 0 时,CPU 正常工作,不产生陷阱
IF 中断标志(Interrupt Flag)
  • 当 IF = 1 时,允许 CPU 相应可屏蔽中断请求
  • 当 IF = 0 时,关闭中断
8086 CPU 提供的设置 IF 的指令
  • STI 设置 IF = 1
  • CLI 设置 IF = 0
为什么中断过程要把 TF 位设置为 0
  • 中断处理程序也由若干条代码组成
  • 如果在执行中断处理程序之前, TF = 1,则 CPU 在执行完中断程序的第一条指令后,又要产生单步中断,转去执行单步中断的中断处理程序的第一条指令,形成死循环
中断不响应的情况
  • 一般情况下 CPU 在执行完当前指令后,如果检测到中断信息,就响应中断,引发中断过程
  • 在有些情况下, CPU 在执行完当前指令后,即便发生中断,也不会响应
  • 例如 在执行完向 SS 寄存器传送数据的指令后,即便是发生中断, CPU 也不会响应,是因为 SS : SP 是联合指向栈顶的,对它们的设置必须连续完成,以此保证对栈的正确操作。

由 INT 指令引发的中断

格式

INT 中断类型码

功能

引发中断过程

中断过程

  1. 取中断类型码
  2. 标志寄存器入栈,IF = 0, TF = 0
  3. CS 和 IP 入栈
  4. ( I P ) = ( N × 4 ) , ( C S ) = ( 中断类型码 × 4 + 2 ) (IP) = (N \times 4) , (CS) = (中断类型码 \times 4 + 2) (IP)=(N×4),(CS)=(中断类型码×4+2)

编写供应用程序调用的中断程序

技术手段
  • 编程时,可以用 INT 指令调用子程序
  • 此子程序即中断处理程序,简称为中断例程
  • 可以自定义中断例程,实现特定功能

BIOS 和 DOS 中断处理

BIOS

含义

是在系统板的 ROM 中存放着一套程序

容量

8 KB

地址

从 FE000H 开始

主要内容
  1. 硬件系统的检测和初始化程序
  2. 外部中断和内部中断的中断例程
  3. 用于对硬件设备进行 I/O 操作的中断例程
  4. 其他和硬件系统相关的中断例程
BIOS 功能调用表

AH

功能

调用参数

返回参数

00

设置显示方式

AL=0040x25黑白文本方式
AL=01
40x25彩色文本方式
AL=02
80x25黑白文本方式
AL=03
80x25彩色文本方式
AL=04
320x200彩色图形方式
AL=05
320x200黑白图形方式
AL=06
640x200黑白图形方式
AL=07
80x25黑白文本方式
AL=0D
320x200彩色图形方式(EGA)
AL=0E
640x200彩色图形方式(EGA)
AL=0F
640x350黑白图形方式(EGA)
AL=10
640x350彩色图形方式(EGA)
AL=11
640x480黑白图形方式(VGA)
AL=12
640x480彩色图形方式(VGA)
AL=13
320x200256色图形方式
(VGA)

01

置光标类型

CH0-3=光标起始行;CL0-3=光标结束行

02

置光标位置

BH=显示页号;DH:DL=行:列

03

读光标位置

BH=显示页号

CH=光标起始行
DH:DL=
行:列

04

读光笔位置

AH=0:光笔未触发
AH=1
:光笔触发
CX=
像素行
BX=
像素列
DH=
字符行
DL=
字符列

05

置显示页

AL=页号

06

窗口上卷

AL=上卷行数;AL=0:整个窗口空白
BH=
卷入行属性
CH:CL=
左上角行号:列号
DH:DL=
右下角行号:列号

07

窗口下卷

06功能

08

读光标位置的字符和属性

BH=显示页

AH=属性
AL=
字符的ASCII

09

在光标位置显示字符和属性

BH=显示页;BL=字符属性
AL=
字符;CX=
字符重复个数

0A

在光标位置显示字符和属性

BH=显示页
AL=
字符;CX=
字符重复个数

0B

置彩色调色板

BH=彩色调色板ID
BL=
ID
配套使用的颜色

0C

写像素

DX=行(0-199CX=列(0-639
AL=
像素值

0D

读像素

DX=行(0-199CX=列(0-639

AL=像素值

0E

显示字符

AL=字符;BL=前景颜色

0F

取当前显示方式

AH=字符列数
AL=
显示方式

13

显示字符串

ES:BP=串首地址;CX=串长度
DH:DL=
起始行号:列号
BH=0
显示页号
显示方式说明:
AL=0
BL=属性
 串结构:字符、字符、字符...
AL=1
BL=属性
 串结构:字符、字符、字符...
AL=2
 串结构:字符、属性、字符、属性...
AL=3
 串结构:字符、属性、字符、属性
...

光标返回起始位置光标跟随移动光标返回起始位置光标跟随移动

### DOS中断 由操作系统提供 #### DOS功能调用表

AH

功能

调用参数

返回参数

00

终止进程

CS=程序段前缀段地址

01

带回显的键盘输入

AL=输入字符

02

显示一个字符

DL=待输出字符的ASCII

03

异步通讯输入

AL=输入的数据

04

异步通讯输出

DL=待输出的数据

05

打印机输出

DL=待输出的字符

06

直接控制台I/O

DL=0FFH:输入
DL=
字符的ASCII码:输出

AL=输入的字符

07

无回显的键盘输入

AL=输入的字符

08

无回显的键盘输入(检测Ctrl-C

AL=输入的字符

09

字符串输出

DS:DX=字符串首

0A

键盘输入至缓冲区

DS:DX=缓冲区首
DS:[DX]=
缓冲区最大容量

DS:[DX+1]=输入的字符数
DS:DX+2=
字符串首

0B

检测键盘状态

AL=00:有输入
AL=FF
:无输入

0C

清除缓冲区并请求指定的输入功能

AL=输入功能的功能号
1678A

0D

磁盘复位

清除文件缓冲区

0E

指定当前缺省磁盘驱动器

DL=驱动器号0A1B

0F

打开文件

DS:DX=FCB首地址

AL=00:文件打开
AL=0FFH
:出错

10

关闭文件

DS:DX=FCB首地址

AL=00:文件关闭
AL=FF
:出错

11

查找第一个目录项

DS:DX=FCB首地址

AL=00:找到
AL=FF
:出错

12

查找下一个目录项

DS:DX=FCB首地址
(文件名中带*?

AL=00:找到
AL=FF
:出错

13

删除文件

DS:DX=FCB首地址

AL=00:成功删除
AL=FF
:出错

14

顺序读

DS:DX=FCB首地址

AL=00:读成功
AL=01
:文件已到末尾
AL=02
DTA溢出
AL=03
:读入部分数据

15

顺序写

DS:DX=FCB首地址

AL=00:写成功
AL=01
:磁盘满
AL=02
DTA溢出

16

建立文件

DS:DX=FCB首地址

AL=00:文件成功建立
AL=FF
:出错

17

文件改名

DS:DX=特殊的FCB首地址

AL=00:改名成功
AL=FF
:出错

19

取当前缺省驱动器名

AL=缺省驱动器号
0
A1B...

1A

DTA地址

DS:DX=DTA首地址

1B

取缺省驱动器的FAT信息

AL=每簇扇区数
DS:BX=FAT
标识字节
CX=
物理扇区的大小
DX=
缺省驱动器的簇数

1C

取任意驱动器的FAT信息

DL=驱动器号

1BH功能

21

随机读

DS:DX=FCB首地址

AL=00:读成功
AL=01
:文件已到末尾
AL=02
DTA溢出
AL=03
:读入部分数据

22

随机写

DS:DX=FCB首地址

AL=00:写成功
AL=01
:磁盘满
AL=02
DTA溢出

23

测定文件大小

DS:DX=FCB首地址

AL=00:成功,文件长度写入FCB
AL=FF
:失败

24

设置随机记录号

DS:DX=FCB首地址

25

设置中断向量

DS:DX=中断向量
AL=
中断号

26

建立程序段前缀

DS:DX=新的程序段前缀

27

随机块读

DS:DX=FCB首地址
CX=
读入记录数

AL=00:读成功
AL=01
:文件已到末尾
AL=02
DTA溢出
AL=03
:读入部分数据

28

随机块写

DS:DX=FCB首地址
CX=
写出记录数

AL=00:写成功
AL=01
:磁盘满
AL=02
DTA溢出

29

分析文件名

ES:DI=FCB首地址
DS:SI=ASCIIZ

AL=
控制分析标志

AL=00:标准文件
AL=01
多义文件
AL=FF
:非法盘符

2A

取日期

CX=
DH:DL=
:日(二进制)

2B

设置日期

CX:DH:DL=年:月:日

AL=00:成功
AL=FF
:出错

2C

取时间

CH:CL=时:分
DH:DL=
秒:1/100

2D

设置时间

CH:CL=时:分
DH:DL=
秒:1/100

AL=00:成功
AL=FF
:出错

2E

置磁盘自动读写标志

AL=00:关闭标志
AL=01
:打开标志

2F

取磁盘缓冲区首地址

ES:BX=缓冲区首地址

30

DOS版本号

AH=发行号;AL=版号

31

结束进程并驻留

AL=返回码
DX=
驻留区大小(节)

33

Ctrl-Break检测

AL=00:取状态
AL=01
:置状态(DL
DL=00
:关闭检测
DL=01
:打开检测

DL=00:关闭Ctrl-Break检测
DL=01
:打开Ctrl-Break检测

35

取中断向量

AL=中断号

ESBX=中断向量

36

取空闲磁盘空间

DL=驱动器号
0
:缺省;1A2B...

成功:AX=每簇扇区数
   BX=有效簇数
   CX=每扇区字节数
   DX=总簇数
失败:AX=FFFF

38

/取国家信息

DS:DX=信息区首地址

BX=国家码;AX=错误码

39

建立子目录

DS:DX=ASCIIZ串首地址

AX=错误码

3A

删除子目录

DS:DX=ASCIIZ串首地址

AX=错误码

3B

改变当前目录

DS:DX=ASCIIZ串首地址

AX=错误码

3C

建立文件

DS:DX=ASCIIZ串首地址
CX=
文件属性

成功:AX=文件句柄
失败:AX=错误码

3D

打开文件

DS:DX=ASCIIZ串首地址
AL=0
:读
AL=1
:写
AL=2
:读/

成功:AX=文件句柄
失败:AX=错误码

3E

关闭文件

BX=文件句柄

失败:AX=错误码

3F

读文件或设备

BX=文件句柄
DS:DX=
缓冲区首
CX=
读取的字节数

成功:AX=实际读入的字节数
失败:AX=错误码

40

写文件或设备

BX=文件句柄
DS:DX=
缓冲区首
CX=
写出的字节数

成功:AX=实际写出的字节数
失败:AX=错误码

41

删除文件

DS:DX=ASCIIZ串首地址

成功:AX=00
失败:AX=错误码

42

移动文件指针

BX=文件句柄
CX:DX=
位移量
AL=
移动方式(012

成功:DX:AX=新指针的位置
失败:AX=错误码

43

/取文件属性

DS:DX=ASCIIZ串首地址
AL=0
:取文件属性
AL=1
:置文件属性
CX=
文件属性

成功:CX=文件属性
失败:AX=错误码

44

设备文件I/O控制

BX=文件句柄
AL=0:
取状态 AL=1:置状态
AL=2:
读数据 AL=3:写数据
AL=6:
取输入状态
AL=7:
取输出状态

DX=设备信息

45

复制文件句柄

BX=文件句柄1

成功:AX=文件句柄2
失败:AX=错误码

46

强制复制文件句柄

BX=文件句柄1
CX=
文件句柄2

失败:AX=错误码

47

取当前目录路径名

DL=驱动器号
DS:SI=ASCIIZ
串首地址

成功:DS:SI=ASCIIZ
失败:AX=错误码

48

分配内存空间

BX=申请的内存数量(节)

成功:AX=分到的内存首址
失败:BX=最大可用空间

49

释放内存空间

ES=内存起始段地址

失败:AX=错误码

4A

调整已分配的内存块

ES=原内存起始段地址
BX=
调整后的尺寸

失败:AX=错误码
   BX=最大可用空间

4B

装入/执行进程

DS:DX=ASCIIZ串首地址
ES:BX=
参数区首地址
AL=0
:装入执行
AL=3
:装入不执行

失败:AX=错误码

4C

带返回码结束

AL=返回码

4D

取返回代码

AX=返回代码

4E

查找第一个匹配文件

DS:DX=ASCIIZ串首地址
CX=
文件属性

AX=错误代码

4F

查找下一个匹配文件

DS:DX=ASCIIZ串首地址
(文件名中带*?

AX=错误代码

54

取盘自动读写标志

AL=当前标志值

56

文件改名

DS:DX=ASCIIZ串(旧)
ES:DI=ASCIIZ
串(新)

AX=错误代码

57

/取文件日期和时间

BX=文件句柄
AL=0
:读取
AL=1
:设置(DXCX

成功:DX:CX=日期和时间
失败:AX=错误码

58

/置分配策略码

AL=0:取码
AL=1
:置码(BX

成功:AX=策略码
失败:AX=错误码

59

取扩充错误码

AX=扩充错误码
BH=
错误类型
BL=
建议的操作
CH=
错误场所

5A

建立临时文件

DS:DX=ASCIIZ串首地址
CX=
文件属性

成功:AX=文件句柄
失败:AX=错误码

5B

建立新文件

DS:DX=ASCIIZ串首地址
CX=
文件属性

成功:AX=文件句柄
失败:AX=错误码

5C

控制文件存取

AL=00:封锁 AL=01:开启
BX=
文件句柄
CX:DX=
文件位移
SI:DI=
文件长度

62

PSP地址

BX=PSP地址

调用中断流程

屏幕截图 2024 05 03 224740

  • BIOS 和 DOS 在所提供的中断例程中包含了许多子程序
  • 和硬件设备相关的 DOS 中断例程中,一般都调用 BIOS 的中断例程

BIOS 和 DOS 中断例程的安装过程

屏幕截图 2024 05 03 225506

  1. CPU 加电后,初始化 (CS) = 0FFFFH,(IP) = 0,自动从 FFFF : 0 单元开始执行程序。FFFF : 0 处有一条跳转指令, CPU 执行该指令后,转去执行 BIOS 中的硬件系统检测和初始化程序
  2. 初始化化程序将建立 BIOS 所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表
  3. 硬件系统检测和初始化完成后,调用 INT 19H 进行操作系统的引导,从此计算机交由操作系统控制
  4. DOS 启动后,除完成其他工作外,还将它提供的中断例程装入内存,并建立相应的中断向量。