汇编语言中断及外部设备操作篇--06
- 移位指令
- 示例:逻辑移位指令shl和shr
- 操作显存数据
- 显示的原理
- 显示缓冲区的结构
- 显示信息的一种“直接”方式
- 描述内存单元的
- 关于标号
- 去了冒号的数据标号
- 数据标号同时描述内存地址和单元长度
- 更常见的方式:数据段中的数据标号
- 数据的直接定址表
- 直接定址表:用查表的方法解决问题
- 最简解决方案
- 直接定址表
- 应用示例:为加快运算速度而采用查表方法
- 解决方案
- 代码的直接定址表
- 使用代码的直接定址表解决问题
- 各种功能的实现
- 直接写址表的优势
- 中断及其处理
- 中断的概念
- 8086的内中断
- 中断处理程序
- 案例:系统中的0号中断
- 中断过程
- 编制中断处理程序
- 中断处理程序及其结构
- 编制中断处理程序——以除法错误中断为例
- do0子程序应该放在哪里?
- 程序框架
- do0安装程序的实现
- do0子程序的实现
- 小结
- 单步中断
- 由Debug中的t命令说起……
- 单步中断过程与处理
- 应用:中断不响应的情况
- 由int指令引发的中断
- int n引起的中断
- 编写供应用程序调用的中断例程
- 示例 :中断7ch的中断例程
- BIOS和DOS中断处理
- BIOS——基本输入输出系统
- BIOS中断调用示例
- 有哪些BIOS中断,怎么用?
- 汇编的强大功能,还有DOS中断!
- int 21HDOS 中断例程的应用
- BIOS和DOS中断例程的安装过程
- 端口的读写
- 用端口访问外设:以发声为例
- CPU的邻居
- 端口的读写
- 端口的读写过程演示
- I/O端口分配
- 端口的读写指令示例
- 操作CMOS RAM芯片
- CMOS RAM 芯片
- 端口操作示例:提取CMOS RAM中存储的时间信息
- 在屏幕中间显示当前的月份
- 外设连接与中断
- CPU通过端口与外部设备“连接”
- 外中断:由外部设备发生的事件引起的中断
- 外中断处理过程
- PC机键盘的处理过程
- PC机键盘的处理过程
- 键盘上键的扫描码(通码)
- PC机键盘的处理过程——引发中断
- PC机键盘的处理过程——执行中断例程
- 输入 'a' 的处理过程
- 定制键盘输入处理
- PC机键盘的处理过程(int 9 中断例程)
- 实现:依次显示'a'~'z'(v0.2)
- 实现:依次显示”a”~”z”(v0.4)
- 按下 Esc 键后改变显示的颜色
- 实现: 按下 Esc 键后改变显示的颜色(v1.0)
- 改写中断例程的方法
- 改写中断例程-以int 9为例
- 实现方法
- 用中断响应外设
- 如何操作外部设备?
- 对键盘输入的处理的int 9h中断和int 16h中断
- 演示:输入A、B、C、D、E、Shift_A、A 引发的(int 9)“动作”
- 演示int 16h
- 调用int 16h 从键盘缓冲区中读取键盘的输入
- 应用示例:更改屏幕颜色
- 应用:字符串的输入
- 要解决的问题
- 程序的处理过程
- 子程序:字符栈的入栈、出栈和显示
- 实现字符栈的入栈、出栈和显示
- 读写磁盘
- 如何操作磁盘?
- BIOS提供的磁盘直接服务——int 13h
- 用BIOS int 13h对磁盘进行读操作
- 用BIOS int 13h对磁盘进行写操作
- DOS中断对磁盘文件的支持——int 21H
- 让计算机“唱歌”
- 外部设备与如何被控制的?
- 与"计算机唱歌"有关的硬件及控制
- “翻译”乐谱
- 演奏程序
本系列文章参考汇编语言第四版和汇编语言程序设计 贺利坚主讲整理而成
移位指令
示例:逻辑移位指令shl和shr
操作显存数据
显示的原理
显示缓冲区的结构
显示信息的一种“直接”方式
描述内存单元的标号
关于标号
上面的写法需要用offset来指明代码段中数据的地址
去了冒号的数据标号
a[si]---->[si a]
数据标号同时描述内存地址和单元长度
mov al,b报错是因为b操作的内存单元是字大小,而al是字节大小,不符合
更常见的方式:数据段中的数据标号
上面都是将数据放在了代码段中,但是一般都是各段分隔开来存放。
如果将数据标号当做数据来定义,那么对应保存的是这个数据标号指向的内存地址
a db 123
b dw 0
#c标号指向内存单元,保存了两个字数据,一个是a标号指向的内存偏移地址,另一个是b标号指向的内存偏移地址
#此时c可以看做是指针的指针
c dw a,b
代码语言:javascript复制a db 123
c dw 0
#c表示指向内存单元,保存了两个双字数据,对于每个双字数据而言,前一个保存了对应偏移地址,后一个保存了对应段地址
c dd a,b
当我们将数据标号作为数据定义的时候,是不是特别类似C语言中的指针的指针
数据的直接定址表
直接定址表:用查表的方法解决问题
最简解决方案
代码语言:javascript复制00101011 是作为低字节存放在al中的,其中前后四位各组成0-15中一个数字,然后去字符表中定位对应的位置的字符
- 因为最小操作单位是字节,所以将ah保存al的高四位,通过右移四位完成,而al保存低四位,通过一个与运算完成
直接定址表
应用示例:为加快运算速度而采用查表方法
解决方案
- 首先使用一张表记录每个角度对应的sin值,上面使用了数据标号的方式,相当于 table dw ag0…中ag0存放的是sin0对应值的偏移地址(指针指向指针)
- 预备动作: 将将会使用到的寄存器状态入栈,然后es附加段寄存器的段地址指向显存空间
- al存放角度,bl存放除数30,然后进行除法运行,由于是8位除法,因此商会被保存在al中,余数被保存在ah中,这里我们只关心商
- 将商保存到bl中,bh置空,此时bl中存放的就是偏移地址,但是单位是字节
- bx需要变为两倍,因为上面table表的单位是字,而这里是字节
- 从table表中根据偏移地址,取得对应字符串的偏移地址,因为这里是数据标号指向数据标号,可以看做是指针指向指针,指针的值就是他执行的内存地址
- 通过bx中保存的字符串偏移地址,定位到对应的内存地址,然后挨个字节依次输出,直到遇到0为止
- 恢复相关寄存器的状态
代码的直接定址表
使用代码的直接定址表解决问题
各种功能的实现
这里重点关注的不在是各个功能的具体实现了,而是主程序中通过查表得到每个子程序开始的地址,这个操作是如何完成的
- 通过在ah中设置需要执行的子程序在表中的相对偏移地址,但是ah保存的偏移地址单位是字节,而表单位是字,因此还需要*2,得到子程序在表中真实的偏移地址
直接写址表的优势
查表可以提高速度,并且可以使程序架构非常清晰易懂,也便于程序扩充。
查表的思想与策略模式类似,都是用来解决一堆IF...ELSE判断的
中断及其处理
中断的概念
8086的内中断
中断处理程序
- 因为8086CPU的中断向量表中,每个中断程序占据四个字节,前两个字节保存中断程序代码段的偏移地址,后两个字节保存中断程序代码段的段地址。
并且因为每个中断程序占据四个字节,因此IP与N是有规律可循的,IP=N4,CS=N4 2
当发生中断时,先查表得到中断程序的地址,然后设置CS和IP的值即可去执行中断程序
案例:系统中的0号中断
当发生除法错误时,触发0号中断,此时会去查表得到0号中断程序的地址,然后设置CS和IP指向中断程序地址,然后执行中断程序
中断过程
执行中断程序前需要先保护现场,这点很重要,主要是保存标志寄存器的状态和当前程序的地址
编制中断处理程序
中断处理程序及其结构
编制中断处理程序——以除法错误中断为例
do0子程序应该放在哪里?
程序框架
安装程序就是把程序代码送入到先前指定存放程序的内存空间中去,然后更改中断向量表0号表项存放的0号中断程序的地址即可。
do0安装程序的实现
程序占用的总共字节数,可以通过两个地址标号表示地址直接差值算出来
do0子程序的实现
显示字符,就是将对应字符写出到显示缓冲区即可,然后设置中断向量表就是将do0中断程序的入口地址,写入到中断向量表的0号表项中
因为do0中断程序中mov ax,4c00h int 21h会直接结束程序运行,返回DOS系统,因此并不会在中断程序执行结束后,返回原有程序继续执行。
小结
单步中断
由Debug中的t命令说起……
单步中断过程与处理
应用:中断不响应的情况
如果在执行向ss寄存器传送数据的指令时,发生了中断,那么CPU会将相关中断寄存器值设置为0,不允许中断产生,这样下一条指令会继续执行,执行完下一条指令后,再进入中断
因此右边的写法是错误的,因为这样写的话,mov ss,ax和mov ax,0会一起连续执行,而mov sp,10指令会单步执行
由int指令引发的中断
int n引起的中断
编写供应用程序调用的中断例程
示例 :中断7ch的中断例程
在执行int n中断之前,会把当前CS和IP寄存器状态入栈,还有标志寄存器状态入栈,然后中断例程执行结束后,再将相关状态出栈,进行现场还原。
如果中断程序中使用到了相关寄存器,也需要在使用前保存对应寄存器状态,程序结束后恢复
BIOS和DOS中断处理
BIOS——基本输入输出系统
BIOS中断调用示例
有哪些BIOS中断,怎么用?
汇编的强大功能,还有DOS中断!
int 21HDOS 中断例程的应用
BIOS和DOS中断例程的安装过程
端口的读写
用端口访问外设:以发声为例
CPU的邻居
CPU通过这些端口控制各种芯片的行为,这些端口实质就是寄存器,但是是与对应芯片相关的寄存器,不是cpu内部从寄存器,这些芯片通过读取这些寄存器的值,知道自己应该干什么
端口的读写
端口的读写过程演示
代码语言:javascript复制in al, 20h
out 21h, al
I/O端口分配
端口的读写指令示例
操作CMOS RAM芯片
CMOS RAM 芯片
端口操作示例:提取CMOS RAM中存储的时间信息
在屏幕中间显示当前的月份
外设连接与中断
CPU通过端口与外部设备“连接”
外中断:由外部设备发生的事件引起的中断
外中断处理过程
PC机键盘的处理过程
PC机键盘的处理过程
键盘上键的扫描码(通码)
PC机键盘的处理过程——引发中断
控制键和切换键由键盘状态字节负责存储,该字节每一位都代表一个按键的状态
PC机键盘的处理过程——执行中断例程
输入 ‘a’ 的处理过程
定制键盘输入处理
PC机键盘的处理过程(int 9 中断例程)
实现:依次显示’a’~‘z’(v0.2)
空循环的设计给出一个思路:dx和ax都赋值一个最大值,然后先把ax寄存器的值减到0结束,结束后再把dx的值也减到0
实现:依次显示”a”~”z”(v0.4)
按下 Esc 键后改变显示的颜色
实现: 按下 Esc 键后改变显示的颜色(v1.0)
在轮询显示a–z的过程中,按下任何键,如果触发了中断,首先会去调用其原本的中断例程,原本的中断例程执行结束后,如果按下的是ESC键还会去额外改变当前显示字体的颜色,如果是其他键,就没有额外的功能了
改写中断例程的方法
改写中断例程-以int 9为例
实现方法
- 安装新程序是先计算出int9和int9end数据标号之间的字节差值,即等于程序的大小,然后循环拷贝所有字节到0:204h处
- 将原先中断地址保存到2:200单元处
- 将int9中断调用的中断例程变为我们新写的中断例程地址,即0:204h,并且这个过程要保证不被可屏蔽中断打断,通过cli设置完成,结束后,再允许被打断,通过STI完成
- 程序返回
用中断响应外设
如何操作外部设备?
对键盘输入的处理的int 9h中断和int 16h中断
演示:输入A、B、C、D、E、Shift_A、A 引发的(int 9)“动作”
上面是输入完ABCDE后的,键盘输入缓冲区的状态,下面输入SHIFT_A
此时我们再按下一个A
Shift标志为还原
演示int 16h
用int 16h读取出 用int 9h存入缓 冲区的数据
键盘缓冲区的实现
- 共16字
- 用环形队列
- 可存储15个按 键扫描码
依次从键盘缓冲区读取出一个字,放入数据缓冲寄存器,然后再放入AX中,AH存放扫描码,AL存放ASCII
调用int 16h 从键盘缓冲区中读取键盘的输入
应用示例:更改屏幕颜色
应用:字符串的输入
要解决的问题
程序的处理过程
子程序:字符栈的入栈、出栈和显示
实现字符栈的入栈、出栈和显示
当一个程序中存在若干子功能的时候,一般不采用挨个判断方式,而采用查表法来决定当前应该调用哪一个子功能
读写磁盘
如何操作磁盘?
BIOS提供的磁盘直接服务——int 13h
用BIOS int 13h对磁盘进行读操作
用BIOS int 13h对磁盘进行写操作
DOS中断对磁盘文件的支持——int 21H
让计算机“唱歌”
外部设备与如何被控制的?
程序可以直接访问外设,是通过端口的形式进行访问的
与"计算机唱歌"有关的硬件及控制
让计算机唱歌,需要与8253和8255芯片打交道,而CPU想要控制这两个芯片,需要通过对应两个芯片提供的端口进行操控
因为进行了统一编址,所以我们可以很容易定位到这两个端口的地址都是什么,然后通过in和out指令写入数据操作它,获取从对应的端口读取出我们需要的数据。