小白都能看懂的实验4 8086标志寄存器及中断
作者:互联网
实验四 8086标志寄存器及中断
- 在实验开始之前,需要一些通用的基础知识,如果觉得自己基础知识不牢靠的同学可以看这里~
- 在实验123中用到的知识这里不再赘述~
- 标志寄存器与常用标志位
- 标志寄存器
- 标志寄存器与其他寄存器不同,不是用来记录地址或者数据的
- 标志寄存器的每一位都有不同的,特殊的含义
- 标志寄存器中有一些常用的标志位被称为常用标志位
- 下图是8086的标志寄存器的图示
- 常用标志位
- 下面介绍一些常用标志位( CF,ZF,SF,IF,OF ),介绍顺序是从寄存器的低位到寄存器的高位
- CF( Carry Flag )
- 表示进位
- 反应无符号数运算时,最高位是否产生对更高位的进位或借位
- 最高位进位: 做加法时, 最高位向更高位进行进位操作,如90+11=110, 最高位十位向更高位百位进行了进位操作,这时CF被置为1
- 最高位借位:做减法时, 最高位向更高位进行借位操作,如10-11=-1, 最高位十位向更高位百位进行了借位操作,这时CF被置为1
- 如果没有产生进位,则将CF置为0
- ZF( Zero Flag )
- 表示是否为0
- 反应运算结束后,结果是否为0
- 若运算结果为0,则ZF被置为1
- 若运算结果为1,则ZF被置为0
- SF( Sign Flag )
- 表示符号位
- 反应有符号数运算结果的符号情况
- 若运算结果为正,则SF被置为0
- 若运算结果为负,则SF被置为1
- 在无符号数计算时也会影响SF的值,但是对于我们来说,此时SF的值没有意义
- IF( Interrupt-enable Flag )
- 表示中断
- 反应cpu是否可以响应cpu外部的可屏蔽中断请求
- 若IF被置为1,则表示cpu可以响应cpu外部发出的可屏蔽中断的请求
- 若IF被置为0,则表示cpu不可响应cpu外部发出的可屏蔽中断的请求
- 两个注意点
- 无论IF被置为何值,cpu都必须相应cpu外部的不可屏蔽中断的请求
- 无论IF被置为何值,cpu都必须相应cpu内部的中断请求
- OF( Overflow Flag )
- 表示溢出
- 反应有符号数加减运算的结果是否溢出
- 如果有溢出,则OF被设置为1(符合直觉的设置,1表示真,表示有溢出)
- 如果没有移出,则OF被设置为0
- OF与CF的不同点
- CF是对无符号数有意义的标志位
- OF是对有符号数有意义的标志位
- CF( Carry Flag )
- 下面介绍一些常用标志位( CF,ZF,SF,IF,OF ),介绍顺序是从寄存器的低位到寄存器的高位
- 标志位在debug中的表示
-
- 个人理解
- OF
- OV = Over
- NV = Not Over
- IF
- EI = Enable Interruption
- DI = Deny Interruption
- SF
- NG = Negative
- PL = Positive
- ZF
- ZR = Zero
- NZ = Not Zero
- CF
- CY = Carry
- NC = Not Carry
- OF
- 个人理解
-
- 标志寄存器
- 条件转移指令
- 解释
- "条件转移"中的"转移": 指的是能够修改IP
- "条件转移"中的"条件":指的是能够根据某种条件,决定是否更改IP
- 所有条件转移指令的转移位移都是[-128,127]
- 条件转移指令的构成
- 字母j:表示转移指令jump
- 字母e:表示equl
- ne:表示not equal
- 字母b:表示below
- nb:表示not below
- 字母a:表示above
- na:表示not above
- 常见的条件转移指令
- je:jump equal,表示等于则转移
- 使用时会检查常用标志位zf的值,若为1则转移
- 一般zf标志位的值通过cmp指令更改,若zf=1说明cmp指令对应的两个操作数相等,所以可以实现"相等则转移"
- 下面的条件跳转指令中常用标志位的作用大体相同,不再赘述
- jne: jump not equal,表示不等于则转移
- 使用时会检查常用标志位zf的值,若为0则转移
- jb: jump below,表示低于则转移
- 使用时会检查常用标志位cf的值,若为1则转移
- jnb: jump not below, 表示不低于则转移
- 使用时会检查常用标志位cf的值,若为0则转移
- ja: jump above, 表示高于(>)则转移
- 使用时会检查cf和zf的值, 若cf=0且zf=0则转移
- jna: jump not above, 若不高于(<=)则转移
- 使用时会检查cf和zf的值,若cf=1或zf=1则转移
- je:jump equal,表示等于则转移
- 解释
- cmp指令
- 指令格式
- cmp 操作对象a, 操作对象b
- 功能
- 计算a-b的值, 并根据结果修改相应标志位的值
- 例子
- cmp ax, ax
- 执行该指令后, zf=1 sf=0 cf=0 of=0
- debug中的表示为 ZR PL NC NV
- cmp指令修改后标志寄存器sf,of的值以及表示的含义(以cmp ax, bx为例)
- sf=0, of=0
- sf=0表示ax-bx的运算结果为正,of=0表示没有溢出
- 该结果表示ax>bx
- sf=0, of=1
- sf=0表示ax-bx的运算结果为正, of=1表示有溢出
- 该结果表示ax<bx
- 因为运算结果溢出导致了运算结果为正.
- 众所周知, 溢出是指在计算时对符号位产生了影响
- 现在的计算结果为正,且发生了溢出,则表示原来的运算结果为负
- 所以结果表示ax<bx
- sf=1, of=0
- sf=0表示运算结果为正, of=0表示未发生溢出
- 该结果表示ax>bx
- sf=1, of=1
- sf=1表示运算结果为负, of=1表示发生了溢出
- 该结果表示ax>bx
- 众所周知,溢出是指在计算时对符号位产生了影响
- 现在的计算结果为负,且发生了溢出,则表示原来的运算结果为正
- 所以结果表示ax>bx
- sf=0, of=0
- 值得注意的是,并不是sf和of两个标志位能反应cmp的运算结果,其他标志位(如zf)也可以表示结果,由于比较简单,这里不再赘述
- 指令格式
- adc指令
- 指令格式
- adc 操作对象a, 操作对象b
- 实现功能
- 将a中的数值,b中的数值,CF标志位的数值相加,放入a中,即
- a = a + b +CF
- 应用场景
- 由于运算时加上了CF标志位,. 故而一般用作大整数加减法
- 指令格式
- 标志寄存器与常用标志位
- 下面正式开始实验
四.实验内容
实验任务1
- 验证实验
- 对于add指令,先输入相应的汇编代码,单步执行查看结果
- 可以发现,add指令会对标志位ZF和CF产生影响
- ZF位从NZ变成了ZR,表示运算结果为0
- CF位从NC变成了CY,表示运算中最高位向更高位产生了进位
- 可以发现,add指令会对标志位ZF和CF产生影响
- 对于inc指令,输入相应的汇编代码,单步执行查看结果
- 可以发现,inc指令只会对ZF位产生影响, 对CF位不会产生影响
- ZF位从NZ变为ZR,表示运算结果位0
- CF位未发生变化
- 可以发现,inc指令只会对ZF位产生影响, 对CF位不会产生影响
- 对于add指令,先输入相应的汇编代码,单步执行查看结果
- 问答问题
- 实验代码如下所示
-
1 assume cs:code, ds:data 2 3 data segment 4 x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h 5 y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h 6 data ends 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov di, offset y 13 call add128 14 15 mov ah, 4ch 16 int 21h 17 18 add128: 19 push ax 20 push cx 21 push si 22 push di 23 24 sub ax, ax 25 26 mov cx, 8 27 s: mov ax, [si] 28 adc ax, [di] 29 mov [si], ax 30 31 inc si 32 inc si 33 inc di 34 inc di 35 loop s 36 37 pop di 38 pop si 39 pop cx 40 pop ax 41 ret 42 code ends 43 end start
- 回答问题
-
- inc指令不能换成add指令,理由如下
- 理论:
- 我们知道, 在进行128位大整数加法时,需要用到adc指令
- 而adc指令运算时会被CF标志位影响
- 大整数加法时,adc中存储的应该是低几位(此题中是低16个二进制位)向更高位的进位
- 而我们知道,inc指令不会影响CF标志位, add指令会影响CF标志位
- 此题:
- 此题是大整数加法, 所以进行加法运算时运用的是adc指令,会用到CF标志位的数值
- 若使用了add si, 2和add di, 2指令, 则会对CF标志位产生影响
- 进而影响到adc指令的执行结果
- 最终影响到计算结果
- 所以不能换成add指令
- 理论:
- inc指令不能换成add指令,理由如下
-
- 在程序运行前, x(第一行)和y(第二行)的数据如下
- 在程序运行后, x(第一行)和y(第二行)的数据如下
- 可以发现, 确实是完成了128位二进制数的加法
- 在程序运行前, x(第一行)和y(第二行)的数据如下
实验任务2
- 在本题中,需要一些另外的汇编语言知识
- int 21h指令
- 在实验3中讲过,int 21h指令会根据寄存器ah中的值的不同作出不同的反应
- ah=1, 程序中断, 等待用户输入,将用户输入的内容(单个字符)存放在AL中
- ah=2, 程序根据ASCII码输出存放在寄存器DL中的字符串
- 在实验3中讲过,int 21h指令会根据寄存器ah中的值的不同作出不同的反应
- int 21h指令
- 下面正式开始实验
- 题目如下
- task2.asm源码如下所示
-
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 s1: 12 mov ah, 1 13 int 21h 14 mov [si], al 15 cmp al, '#' 16 je next 17 inc si 18 jmp s1 19 next: 20 mov ah, 2 21 mov dl, 0ah 22 int 21h 23 24 mov cx, si 25 mov si, 0 26 s2: mov ah, 2 27 mov dl, [si] 28 int 21h 29 inc si 30 loop s2 31 32 mov ah, 4ch 33 int 21h 34 code ends 35 end start
-
- 运行结果如下
- 回答问题①
- 功能总览
- 读取用户输入的字符, 并将之保存在ds:[si]中.如果是"#"则跳转到"next"处执行,否则继续读入下一个字符串
- 功能详解
- line12~13: 调整寄存器AH中的值为1, 并通过int 21h指令中断程序, 等待用户输入
- line14: 将用户输入的值移动到ds:[si]中
- line15~16: 将用户输入的输入的字符与"#"比较, 如果相等则跳转到"next"处
- line17: si自加
- line18: 程序跳转到S1处,重复line12-18
- 功能总览
- 回答问题②
- 功能总览
- 换行
- 功能详解
- line20: 将2存放在寄存器AH中,供下面的int 21h使用
- line21: 将换行的ASCII码放在寄存器DL中, 供下面的int 21h使用
- line22: 打印换行
- 功能总览
- 回答问题③
- 功能总览
- 打印输出除了"#"以外用户输入的所有字符
- 功能详解
- line24: 将si的数值放在cx中,此时si中存放着字符串的终结地址, 字符串终结地址-字符串的开始地址=字符串长度,而开始地址为0(line10 mov si,0),所以此时si的值就是字符串长度,放入cx中为循环做准备
- line25: 将si的数值设置为0, 即用户输入的字符串的开头的地址(line 10 mov si,0), 为循环做准备
- line26-28: 设置AH,DL的值,将si指向的字符的ASCII码放入DL中, 并使用int 21h指令输出
- line29: si自加, 指针下移, 准备输出下一个字符
- 功能总览
- 题目如下
实验任务3
- 实验题目
- 初见印象(可以先看实验三的实验任务3)
- 与上一次实验,实验三的题目类似, 需要先将存储的数值型数据转换成对应的ASCII码,再将其进行输出
- 与实验三不同的是, 实验三的每一个数据都是两位数, 所以每个数循环两次除法即可,此题需要用cmp进行判断,以确定当前处理的数据需要进行几次除法
- 题目思路
- 总体思路
- 先将对应的数据段送至ds中
- 循环处理ds中的每个数字, 调用printNumber代码段进行输出, 再调用printSpace代码段进行输出
- 编写子程序printNumber(以91为例)
- 首先取出91的个位数, 将个位数1转换为对应的ASCII码
- 判断此时的数是否为0,不为0,继续
- 取出91的十位数, 将十位数9转换成对应的ASCII码
- 判断此时的数是否为0,为0,终止
- 编写子程序printSpace
- 比较简单,与实验三的试验任务3的printSpace完全一致,不再赘述
- 总体思路
- 代码设计
- 子程序printNumber
- 将待输入的数据存放在寄存器AX中, 等待处理
- 使用div指令对AX中的数据做除法
- 使用or指令对余数进行处理, 将数值型数据改成相应的ASCII码, 并将之压入栈中
- 这里使用栈的原因: 因为最先处理的低位(如个位), 而输出时需要先输出高位(如十位), 所以使用栈"先进后出"的特点, 将最先处理的最后输出
- 使用mov指令对商进行处理,将商放在AX中, 以供判断
- 使用or指令对余数进行处理, 将数值型数据改成相应的ASCII码, 并将之压入栈中
- 使用cmp指令判断AX中的数据是否为0
- 若不为0则表示尚未处理完成, 使用jne指令跳转至printNumber的第二步
- 若为0则表示已经对该数值型数据处理完毕, 继续进行下一步
- 将AH中的值改为02h, 使用pop指令将栈中的数据送至DL中
- 运用int 21h指令输出
- 注意! 子程序printNumber编写时应该注意
- 由于运算过程中商可能会大于两个十六进制位(也就是大于AL的存储范围), 也就是说,16位/8位的除法不能使用, 所以需要使用32位/16位除法
- 当被除数被放在16位寄存器中, 进行除法时, 会将dx:ax当作被除数, dx中存放余数, ax中存放商
- 子程序printNumber
- 思路设计完成, 实现方式已经规划好, 下面开始编写代码, 代码如下
-
1 assume ds:data, cs:code 2 data segment 3 x dw 91, 792, 8536, 65521, 2021 4 len equ $ - x 5 y db 200 dup(?) ;为栈的使用开辟空间 6 leny equ $ - y 7 data ends 8 9 code segment 10 start: 11 mov ax, offset y 12 mov ss, ax 13 mov sp, leny ;设置栈顶 14 15 mov ax, data ;将x数据段放入ds:[si]中 16 mov ds, ax 17 mov si, 0 18 mov cx, 5 ;一共五个数, 所以循环5次 19 s2: 20 call printNumber 21 call printSpace 22 add si, 2 23 loop s2 24 25 mov ah, 4ch 26 int 21h 27 28 29 30 printNumber: 31 push cx ;将外部循环s2的剩余次数压入栈中 32 mov ax, ds:[si] ;将被除数放入ax中 33 mov dx, 0 ;由于数值最大位65521, 小于8位16进制能表达的最大数6535, 所以被除数的高16位可以设置位0 34 mov bx, 10 ;将除数10放入bx中 35 mov cx, 0h ;cx寄存器用于计数 36 s1: 37 inc cx ;每做一次除法都进行一次计数 38 div bx ;除法操作, 由于除数是16位, 被除数就被解读为dx:ax, 余数在dx中, 商在ax中 39 or dx, 30h ;将余数转为相应的ASCII码 40 push dx ;将结果压入栈中 41 mov dx, 0 ;作用与33行的一样, 同时起到将余数清空为0的作用 42 cmp ax, 0 43 jne s1 44 s3: 45 pop dx ;将栈顶数据放入dx中 46 mov ah, 02h 47 int 21h ;使用int 21h指令输出 48 loop s3 ;循环输出, 次数为做除法的次数 49 pop cx ;将栈底的外部循环次数放入cx中 50 ret 51 52 printSpace: 53 mov dl, ' ' 54 mov ah, 02h 55 int 21h 56 ret 57 58 59 code ends 60 end start
- 运行结果如下
-
-
实验任务4
- 实验题目
- 初见印象
- 如果用C或者java等高级语言会很好写
- 用汇编写的思路和用高级语言的差不多
- 说的很对, "汇编语言, 不难但是很烦"
- 题目思路
- 总体思路
- 先将对应的数据地址送入ds中
- 运用循环, 对字符串的每一个字符, 判断是否是小写字母
- 如果是小写字母,就把它变成大写字符, 运用实验一的实验任务5中学到的or ax, 0dfh指令就可以做到(减去32), 在此之后将之输出
- 如果不是小写字母, 就直接输出, 并进行下一轮循环
- 编写子程序strupr
- 判断ds:[si]中的数值是否大于(97)10, 即是否大于小写字母a的ASCII码
- 如果不是, 则可以将该字符放入DL中, 使用int 21h指令直接输出
- 如果是. 则可以断言该字符是小写字母
- 原因如下
- 需要处理的字符串中, 只包含了小写字母,单引号,逗号和空格
- 小写字母的ASCII码范围是[97,112]
- 单引号的ASCII码为39
- 逗号的ASCII码为44
- 空格的ASCII码为32
- 所以大于97的一定是小写字母
- 确定了该字符是小写字母, 则
- 使用or指令或sub指令将之转为大写字母
- 将大写化后的字符存入DL中, 并使用int 21h指令输出
- 原因如下
- 判断ds:[si]中的数值是否大于(97)10, 即是否大于小写字母a的ASCII码
- 总体思路
- 代码设计
- 整体代码
- 将对应的数据段存入ds中
- 使用mov指令将len放入cx中
- 运用循环, 调用strupr代码段
- 结束程序
- 子程序strupr
- 判断ds:[si]中的数值是否大于(97)10, 即是否大于小写字母a的ASCII码
- 如果不是, 说明该字符是空格或大写字母, 则可以将该字符放入DL中, 使用int 21h指令直接输出
- 如果是, 说明该字符是小写字母
- 使用or指令或sub指令将之转为大写字母
- 将大写化后的字符存入DL中, 并使用int 21h指令输出
- 判断ds:[si]中的数值是否大于(97)10, 即是否大于小写字母a的ASCII码
- 整体代码
- 思路设计完成, 实现方式已经规划好, 下面开始编写代码, 代码如下
-
1 assume ds:data, cs:code 2 data segment 3 str db "assembly language, it's not difficult but tedious" 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 10 mov ax, data 11 mov ds, ax 12 mov si, offset str 13 14 mov cx, len 15 16 s1: 17 call strupr 18 inc si 19 loop s1 20 21 mov ah, 4ch 22 int 21h 23 24 strupr: 25 cmp byte ptr ds:[si], 96 26 jna s2 ;如果当前的字符小于等于96,则直接输出 27 sub byte ptr ds:[si], 32 ;否则转为大写字母 28 s2: 29 mov dx, ds:[si] 30 mov ah, 2 31 int 21h 32 ret 33 34 code ends 35 end start
- 测试结果如下
-
实验任务5
- 实验题目
- task5.asm源码如下
-
1 assume cs:code, ds:data 2 3 data segment 4 str1 db "yes", '$' 5 str2 db "no", '$' 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 13 mov ah, 1 14 int 21h 15 16 mov ah, 2 17 mov bh, 0 18 mov dh, 24 19 mov dl, 70 20 int 10h 21 22 cmp al, '7' 23 je s1 24 mov ah, 9 25 mov dx, offset str2 26 int 21h 27 28 jmp over 29 30 s1: mov ah, 9 31 mov dx, offset str1 32 int 21h 33 over: 34 mov ah, 4ch 35 int 21h 36 code ends 37 end start
-
- 运行结果如下
- 程序功能分析
- 总体功能分析
- 接收用户输入的一个字符
- 如果输入的是7, 则在(第27行, 第70列)输出yes
- 如果输入的不是7, 则在(第27行, 第70列)输出no
- 接收用户输入的一个字符
- 逐行分析
- line10-11: 将需要处理的数据送入ds中
- line13-14: 设置寄存器ah的值, 调用int 21h指令中断, 并等待用户输入
- line16-20: 设置一系列寄存器的值, 并最后调用int 10h指令将光标位置定在第24行第70列
- line22-32: 判断用户输入的字符是否为'7',如果是则输出yes, 若不是则输出no
- line22: 将用户输入的字符与字符'7'进行比较, 并根据比较结果设置标志寄存器的值, 这里主要用到了ZF标志位
- line23: 使用je指令, 查看标志位ZF的值是否为0
- 若为0则说明用户输入的字符和字符'7'相同, 此时跳转到s1代码段
- 若不为0则说明用户输入的字符不是字符'7', 无视je指令, 继续执行
- line24-28
- 当je指令未跳转时执行
- 使用int 21h的9号子功能, 输出一个以'$'结尾的字符串(不输出$), 这里输出no
- 执行完成后直接跳转到line33
- line30-32
- 当je指令跳转时执行
- 使用int 21h的9号子功能, 输出一个以'$'结尾的字符串(不输出$), 这里输出yes
- line33-35:
- 程序退出
- 总体功能分析
实验任务6
- 实验开始之前, 我们需要一些基础知识
- 8086cpu是如何处理中断的?
- 8086cpu在收到中断请求后, 会执行内存中特定的某段程序
- 在这段程序执行完毕后返回中断的地方
- 这里面涉及到几个问题
- 1. 如何得知需要执行的中断程序在哪里?
- 2. 如何存储中断前的位置?
- 对以上几个问题做出如下回答
- 对于问题1
- 在中断时, 中断请求会给出一个中断类型码N
- 中断触发时运行的程序的地址为(N*4) : (N*4+2)号内存中存放的地址
- 这句话看着比较难受, 举个例子就很清楚
- 假设现在有个中断程序, 他的起始位置是0000:0200h
- 那么就会把0000放在标号为N*4的地址空间里
- 把0200放在标号为(N*4+2)的地址空间里
- 若想知道中断程序的起始地址, 就去(N*4) : (N*4+2)里找吧!
- 计算机会让[IP]=[N*4+2], [CS] = [N*4]
- 这句话看着比较难受, 举个例子就很清楚
- 以int指令为例
- int 21h的中断类型码就是21h
- 对于问题2
- 在执行中断程序之前, cpu会将一系列数据进行入栈操作, 其中就包括了中断执行前的CS,IP值
- 在中断程序的最后,会有iret指令将CS,IP的值出栈并保存在相应位置
- 对于问题1
- rep movsb命令
- movsb指令用于把字节从ds:si 搬到es:di;
- rep是repeat的意思,rep movsb 就是多次搬运。
- 搬运前先把字符串的长度存在cx寄存器中,然后重复的次数就是cx寄存器所存数据的值。
- 8086cpu是如何处理中断的?
- 对于该实验, 我们先逐步理解老师给出的代码
- 老师给出了两个文件: task6_1.asm和task6_2.asm
- 为什么是两个文件捏?
- 上面说过, 执行中断时会直接到相应的内存空间去寻找中断程序的起始地址, 所以得先将中断程序装入内存中, 这就是task6_1.asm的功能
- task6_2.asm就是一段测试代码, 测试task6_1.asm编写的中断是否生效
- 为什么是两个文件捏?
- task6_1.asm源代码如下
-
1 assume cs:code 2 3 code segment 4 start: 5 ; 42 interrupt routine install code 6 mov ax, cs 7 mov ds, ax 8 mov si, offset int42 ; set ds:si 9 10 mov ax, 0 11 mov es, ax 12 mov di, 200h ; set es:di 13 14 mov cx, offset int42_end - offset int42 15 cld 16 rep movsb 17 18 ; set IVT(Interrupt Vector Table) 19 mov ax, 0 20 mov es, ax 21 mov word ptr es:[42*4], 200h 22 mov word ptr es:[42*4+2], 0 23 24 mov ah, 4ch 25 int 21h 26 27 int42: 28 jmp short int42_start 29 str db "welcome to 2049!" 30 len equ $ - str 31 32 ; display string "welcome to 2049!" 33 int42_start: 34 mov ax, cs 35 mov ds, ax 36 mov si, 202h 37 38 mov ax, 0b800h 39 mov es, ax 40 mov di, 24*160 + 32*2 41 42 mov cx, len 43 s: mov al, [si] 44 mov es:[di], al 45 mov byte ptr es:[di+1], 2 46 inc si 47 add di, 2 48 loop s 49 50 iret 51 int42_end: 52 nop 53 code ends 54 end start
-
- task6_2.asm源代码如下
-
1 assume cs:code 2 3 code segment 4 start: 5 int 42 6 7 mov ah, 4ch 8 int 21h 9 code ends 10 end start
-
- 老师给出了两个文件: task6_1.asm和task6_2.asm
- 下面着重理解task6_1.asm
- 功能总览
- 将中断时执行的代码line27-50装入0000:0200开始的内存中
- 逐行理解
- line6-8: 设置ds:[si]为该段程序的开始地址, 为下面line16行程序复制做准备
- line10-12: 将es:[di]设置为0000:0200, 即中断程序的开始地址, 为下面line16行程序复制做准备
- line14: 将需要存入内存的代码段的长度放入cx中, 为下面line16行程序复制做准备
- line15: 用于设置标志位
- line16: 利用rep mobsb的命令, 将line27- 50代码装入es:[di]中, 即装入中断程序开始地址
- line19-22: 将中断程序的开始地址的段地址部分放入es:[42*4+2]中, 将开始地址的偏移地址部分放入es:[42*4]中
- 因为此题编写的是中断标志码为42的中断程序, 所以放入了es:[42*4+2]和es:[42*4]中
- line27-50: 运用80*25彩色字符显示空间显示彩色字符, 实验三已经学过, 不再赘述
- 功能总览
- 理解完毕
- 运行结果如下
- 如果需要自己写一个中断其实不难....
- 只要仿制老师写的再写一个就行了, 大致都是相同的, 最大的不同就是line27-50这一段
- 大致思路如下
- 首先设置ds,si , es,di的值,并用rep movsb指令往内存中存入代码
- 其次将中断程序的开始地址放入对应位置(也就是es的值放入[N*4+2]中, 将di的值放入[N*4]中)
- 最后编写一段中断程序即可
- 大致思路如下
- 因为懒, 所以不写了, 欸嘿
- 只要仿制老师写的再写一个就行了, 大致都是相同的, 最大的不同就是line27-50这一段
标签:8086,int,mov,si,指令,能看懂,寄存器,ax,21h 来源: https://www.cnblogs.com/Nekasu/p/15670550.html