小白都能看懂的實驗4 8086標志寄存器及中斷


實驗四 8086標志寄存器及中斷

  •  在實驗開始之前,需要一些通用的基礎知識,如果覺得自己基礎知識不牢靠的同學可以看這里~
  • 在實驗123中用到的知識這里不再贅述~ 
    1. 標志寄存器與常用標志位
      • 標志寄存器
        • 標志寄存器與其他寄存器不同,不是用來記錄地址或者數據的
        • 標志寄存器的每一位都有不同的,特殊的含義
        • 標志寄存器中有一些常用的標志位被稱為常用標志位
        • 下圖是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中的表示
          • 個人理解
            • 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. 驗證實驗
    • 對於add指令,先輸入相應的匯編代碼,單步執行查看結果
      • 可以發現,add指令會對標志位ZF和CF產生影響
        • ZF位從NZ變成了ZR,表示運算結果為0
        • CF位從NC變成了CY,表示運算中最高位向更高位產生了進位
    • 對於inc指令,輸入相應的匯編代碼,單步執行查看結果
      • 可以發現,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

       

    • 回答問題
      • inc指令不能換成add指令,理由如下
        • 理論:
          • 我們知道, 在進行128位大整數加法時,需要用到adc指令
          • 而adc指令運算時會被CF標志位影響
          • 大整數加法時,adc中存儲的應該是低幾位(此題中是低16個二進制位)向更高位的進位
          • 而我們知道,inc指令不會影響CF標志位, add指令會影響CF標志位
        • 此題:
          • 此題是大整數加法, 所以進行加法運算時運用的是adc指令,會用到CF標志位的數值
          • 若使用了add si, 2和add di, 2指令, 則會對CF標志位產生影響
          • 進而影響到adc指令的執行結果
          • 最終影響到計算結果
          • 所以不能換成add指令
      • 在程序運行前, x(第一行)和y(第二行)的數據如下
      • 在程序運行后, x(第一行)和y(第二行)的數據如下
      • 可以發現, 確實是完成了128位二進制數的加法

實驗任務2

  • 在本題中,需要一些另外的匯編語言知識
    • int 21h指令
      • 在實驗3中講過,int 21h指令會根據寄存器ah中的值的不同作出不同的反應
        • ah=1, 程序中斷, 等待用戶輸入,將用戶輸入的內容(單個字符)存放在AL中
        • ah=2, 程序根據ASCII碼輸出存放在寄存器DL中的字符串
  • 下面正式開始實驗
    • 題目如下
      •  
    • 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中, 以供判斷
      • 使用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

  • 實驗題目
  •  初見印象
    • 如果用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

       

    • 測試結果如下

實驗任務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的值出棧並保存在相應位置
    • 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彩色字符顯示空間顯示彩色字符, 實驗三已經學過, 不再贅述
  • 理解完畢
  • 運行結果如下
  • 如果需要自己寫一個中斷其實不難....
    • 只要仿制老師寫的再寫一個就行了, 大致都是相同的, 最大的不同就是line27-50這一段
      • 大致思路如下
        • 首先設置ds,si , es,di的值,並用rep movsb指令往內存中存入代碼
        • 其次將中斷程序的開始地址放入對應位置(也就是es的值放入[N*4+2]中, 將di的值放入[N*4]中)
        • 最后編寫一段中斷程序即可
    • 因為懶, 所以不寫了, 欸嘿


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM