汇编语言中断及外部设备操作篇--06

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编语言中断及外部设备操作篇--06相关的知识,希望对你有一定的参考价值。

汇编语言中断及外部设备操作篇--06


本系列文章参考汇编语言第四版和汇编语言程序设计 贺利坚主讲整理而成


移位指令


示例:逻辑移位指令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
a db 123
c dw 0
#c表示指向内存单元,保存了两个双字数据,对于每个双字数据而言,前一个保存了对应偏移地址,后一个保存了对应段地址
c dd a,b

当我们将数据标号作为数据定义的时候,是不是特别类似C语言中的指针的指针


数据的直接定址表

直接定址表:用查表的方法解决问题


最简解决方案

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内部从寄存器,这些芯片通过读取这些寄存器的值,知道自己应该干什么


端口的读写


端口的读写过程演示

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指令写入数据操作它,获取从对应的端口读取出我们需要的数据。


“翻译”乐谱


演奏程序


以上是关于汇编语言中断及外部设备操作篇--06的主要内容,如果未能解决你的问题,请参考以下文章

函数名定址

STM32基本GPIO操作:按键输入(扫描+外部中断)

操作系统中断的运行细节

散列表的开放定址法以及再散列法(C语言)

汇编语言流程转移与子程序篇--05

STM32 HAL库学习系列第9篇---NVIC按键外部中断函数