小白都能看懂的实验4 8086标志寄存器及中断

实验四 8086标志寄存器及中断

  •  在实验开始之前,需要一些通用的基础知识,如果觉得自己基础知识不牢靠的同学可以看这里~
  • 在实验123中用到的知识这里不再赘述~ 
    1. 标志寄存器与常用标志位
      • 标志寄存器
        • 标志寄存器与其他寄存器不同,不是用来记录地址或者数据的
        • 标志寄存器的每一位都有不同的,特殊的含义
        • 标志寄存器中有一些常用的标志位被称为常用标志位
        • 下图是8086的标志寄存器的图示
          • 小白都能看懂的实验4 8086标志寄存器及中断
      • 常用标志位
        • 下面介绍一些常用标志位( CF,ZF,SF,IF,OF ),介绍顺序是从寄存器的低位到寄存器的高位
          1. CF( Carry Flag )
            • 表示进位
            • 反应无符号数运算时,最高位是否产生对更高位的进位或借位
              • 最高位进位: 做加法时, 最高位向更高位进行进位操作,如90+11=110, 最高位十位更高位百位进行了进位操作,这时CF被置为1
              • 最高位借位:做减法时, 最高位向更高位进行借位操作,如10-11=-1, 最高位十位更高位百位进行了借位操作,这时CF被置为1
              • 如果没有产生进位,则将CF置为0
          2. ZF( Zero Flag )
            • 表示是否为0
            • 反应运算结束后,结果是否为0
              • 若运算结果为0,则ZF被置为1
              • 若运算结果为1,则ZF被置为0
          3. SF( Sign Flag )
            • 表示符号位
            • 反应有符号数运算结果的符号情况
              • 若运算结果为正,则SF被置为0
              • 若运算结果为负,则SF被置为1
            • 在无符号数计算时也会影响SF的值,但是对于我们来说,此时SF的值没有意义
          4. IF( Interrupt-enable Flag )
            • 表示中断
            • 反应cpu是否可以响应cpu外部的可屏蔽中断请求
              • 若IF被置为1,则表示cpu可以响应cpu外部发出的可屏蔽中断的请求
              • 若IF被置为0,则表示cpu不可响应cpu外部发出的可屏蔽中断的请求
            • 两个注意点
              1. 无论IF被置为何值,cpu都必须相应cpu外部的不可屏蔽中断的请求
              2. 无论IF被置为何值,cpu都必须相应cpu内部的中断请求
          5. OF( Overflow Flag )
            • 表示溢出
            • 反应有符号数加减运算的结果是否溢出
            • 如果有溢出,则OF被设置为1(符合直觉的设置,1表示真,表示有溢出)
            • 如果没有移出,则OF被设置为0
          6. OF与CF的不同点
            • CF是对无符号数有意义的标志位
            • OF是对有符号数有意义的标志位
      • 标志位在debug中的表示
        • 小白都能看懂的实验4 8086标志寄存器及中断
          • 个人理解
            • 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
    2. 条件转移指令
      • 解释
        • "条件转移"中的"转移": 指的是能够修改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则转移
    3. 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为例)
        1. sf=0, of=0
          • sf=0表示ax-bx的运算结果为正,of=0表示没有溢出
          • 该结果表示ax>bx
        2. sf=0, of=1
          • sf=0表示ax-bx的运算结果为正, of=1表示有溢出
          • 该结果表示ax<bx
            • 因为运算结果溢出导致了运算结果为正. 
            • 众所周知, 溢出是指在计算时对符号位产生了影响
            • 现在的计算结果为正,且发生了溢出,则表示原来的运算结果为负
            • 所以结果表示ax<bx
        3. sf=1, of=0
          • sf=0表示运算结果为正, of=0表示未发生溢出
          • 该结果表示ax>bx
        4. sf=1, of=1
          • sf=1表示运算结果为负, of=1表示发生了溢出
          • 该结果表示ax>bx
            • 众所周知,溢出是指在计算时对符号位产生了影响
            • 现在的计算结果为负,且发生了溢出,则表示原来的运算结果为正
            • 所以结果表示ax>bx
      • 值得注意的是,并不是sf和of两个标志位能反应cmp的运算结果,其他标志位(如zf)也可以表示结果,由于比较简单,这里不再赘述
    4. adc指令
      • 指令格式
        • adc 操作对象a, 操作对象b
      • 实现功能
        • 将a中的数值,b中的数值,CF标志位的数值相加,放入a中,即
        • a = a + b +CF
      • 应用场景
        • 由于运算时加上了CF标志位,. 故而一般用作大整数加减法
  • 下面正式开始实验

四.实验内容

实验任务1

  1. 验证实验
    • 小白都能看懂的实验4 8086标志寄存器及中断
    • 对于add指令,先输入相应的汇编代码,单步执行查看结果
      • 小白都能看懂的实验4 8086标志寄存器及中断
      • 可以发现,add指令会对标志位ZF和CF产生影响
        • ZF位从NZ变成了ZR,表示运算结果为0
        • CF位从NC变成了CY,表示运算中最高位向更高位产生了进位
    • 对于inc指令,输入相应的汇编代码,单步执行查看结果
      • 小白都能看懂的实验4 8086标志寄存器及中断
      • 可以发现,inc指令只会对ZF位产生影响, 对CF位不会产生影响
        • ZF位从NZ变为ZR,表示运算结果位0
        • CF位未发生变化
  2. 问答问题
    • 实验代码如下所示
    •  
       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

       

    • 回答问题
    • 小白都能看懂的实验4 8086标志寄存器及中断
      • inc指令不能换成add指令,理由如下
        • 理论:
          • 我们知道, 在进行128位大整数加法时,需要用到adc指令
          • 而adc指令运算时会被CF标志位影响
          • 大整数加法时,adc中存储的应该是低几位(此题中是低16个二进制位)向更高位的进位
          • 而我们知道,inc指令不会影响CF标志位, add指令会影响CF标志位
        • 此题:
          • 此题是大整数加法, 所以进行加法运算时运用的是adc指令,会用到CF标志位的数值
          • 若使用了add si, 2和add di, 2指令, 则会对CF标志位产生影响
          • 进而影响到adc指令的执行结果
          • 最终影响到计算结果
          • 所以不能换成add指令
    • 小白都能看懂的实验4 8086标志寄存器及中断
      • 在程序运行前, x(第一行)和y(第二行)的数据如下
        • 小白都能看懂的实验4 8086标志寄存器及中断
      • 在程序运行后, x(第一行)和y(第二行)的数据如下
        • 小白都能看懂的实验4 8086标志寄存器及中断
      • 可以发现, 确实是完成了128位二进制数的加法

实验任务2

  • 在本题中,需要一些另外的汇编语言知识
    • int 21h指令
      • 在实验3中讲过,int 21h指令会根据寄存器ah中的值的不同作出不同的反应
        • ah=1, 程序中断, 等待用户输入,将用户输入的内容(单个字符)存放在AL中
        • ah=2, 程序根据ASCII码输出存放在寄存器DL中的字符串
  • 下面正式开始实验
    • 题目如下
      •  小白都能看懂的实验4 8086标志寄存器及中断
    • 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

         

    • 运行结果如下
      • 小白都能看懂的实验4 8086标志寄存器及中断
    • 回答问题①
      • 功能总览
        • 读取用户输入的字符, 并将之保存在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

  • 实验题目
    • 小白都能看懂的实验4 8086标志寄存器及中断
  • 初见印象(可以先看实验三的实验任务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中, 以供判断
      • 使用cmp指令判断AX中的数据是否为0
        • 若不为0则表示尚未处理完成, 使用jne指令跳转至printNumber的第二步
        • 若为0则表示已经对该数值型数据处理完毕, 继续进行下一步
      • 将AH中的值改为02h, 使用pop指令将栈中的数据送至DL中
      • 运用int 21h指令输出
    • 注意! 子程序printNumber编写时应该注意
      • 由于运算过程中商可能会大于两个十六进制位(也就是大于AL的存储范围), 也就是说,16位/8位的除法不能使用, 所以需要使用32位/16位除法
      • 当被除数被放在16位寄存器中, 进行除法时, 会将dx:ax当作被除数, dx中存放余数, ax中存放商
  • 思路设计完成, 实现方式已经规划好, 下面开始编写代码, 代码如下
    •  
       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 8086标志寄存器及中断

         

         

实验任务4

  • 实验题目
    • 小白都能看懂的实验4 8086标志寄存器及中断
  •  初见印象
    • 如果用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中
      • 使用mov指令将len放入cx中
      • 运用循环, 调用strupr代码段
      • 结束程序
    • 子程序strupr
      • 判断ds:[si]中的数值是否大于(97)10, 即是否大于小写字母a的ASCII码
        • 如果不是, 说明该字符是空格或大写字母, 则可以将该字符放入DL中, 使用int 21h指令直接输出
        • 如果是, 说明该字符是小写字母
          • 使用or指令或sub指令将之转为大写字母
          • 将大写化后的字符存入DL中, 并使用int 21h指令输出
  • 思路设计完成, 实现方式已经规划好, 下面开始编写代码, 代码如下
    •  
       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

       

    • 测试结果如下
      • 小白都能看懂的实验4 8086标志寄存器及中断

实验任务5

  • 实验题目
    • 小白都能看懂的实验4 8086标志寄存器及中断
  • 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

       

  • 运行结果如下
    • 小白都能看懂的实验4 8086标志寄存器及中断
    • 小白都能看懂的实验4 8086标志寄存器及中断
  • 程序功能分析
    • 总体功能分析
      • 接收用户输入的一个字符
        • 如果输入的是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的值出栈并保存在相应位置
    • rep movsb命令
      • movsb指令用于把字节从ds:si 搬到es:di;
      • rep是repeat的意思,rep movsb 就是多次搬运。
        • 搬运前先把字符串的长度存在cx寄存器中,然后重复的次数就是cx寄存器所存数据的值。
  • 对于该实验, 我们先逐步理解老师给出的代码
    •  老师给出了两个文件: 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
    • 功能总览
      • 将中断时执行的代码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彩色字符显示空间显示彩色字符, 实验三已经学过, 不再赘述
  • 理解完毕
  • 运行结果如下
    • 小白都能看懂的实验4 8086标志寄存器及中断
  • 如果需要自己写一个中断其实不难....
    • 只要仿制老师写的再写一个就行了, 大致都是相同的, 最大的不同就是line27-50这一段
      • 大致思路如下
        • 首先设置ds,si , es,di的值,并用rep movsb指令往内存中存入代码
        • 其次将中断程序的开始地址放入对应位置(也就是es的值放入[N*4+2]中, 将di的值放入[N*4]中)
        • 最后编写一段中断程序即可
    • 因为懒, 所以不写了, 欸嘿
上一篇:实验4 8086标志寄存器及中断


下一篇:实验4 8086标志寄存器及中断