home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / dos_ency / 13 / divzero.asm next >
Encoding:
Assembly Source File  |  1988-08-11  |  7.8 KB  |  247 lines

  1.         name    divzero
  2.         title   'DIVZERO - Interrupt 00H Handler'
  3. ;
  4. ; DIVZERO.ASM: Demonstration Interrupt 00H Handler
  5. ; To assemble, link, and convert to COM file:
  6. ;
  7. ;       C>MASM DIVZERO;  <Enter>
  8. ;       C>LINK DIVZERO;  <Enter>
  9. ;       C>EXE2BIN DIVZERO.EXE DIVZERO.COM  <Enter>
  10. ;       C>DEL DIVZERO.EXE  <Enter>
  11. ;
  12.  
  13. cr      equ     0dh             ; ASCII carriage return
  14. lf      equ     0ah             ; ASCII linefeed
  15. eos     equ     '$'             ; end of string marker
  16.  
  17. _TEXT   segment word public 'CODE'
  18.  
  19.         assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
  20.  
  21.         org     100h
  22.  
  23. entry:  jmp     start           ; skip over data area
  24.  
  25. intmsg  db      'Divide by Zero Occurred!',cr,lf,eos
  26.  
  27. divmsg  db      'Dividing '     ; message used by demo
  28. par1    db      '0000h'         ; dividend goes here
  29.         db      ' by '
  30. par2    db      '00h'           ; divisor goes here
  31.         db      ' equals '
  32. par3    db      '00h'           ; quotient here
  33.         db      ' remainder '
  34. par4    db      '00h'           ; and remainder here
  35.         db      cr,lf,eos
  36.  
  37. oldint0 dd      ?               ; save old Int 00H vector
  38.  
  39. intflag db      0               ; nonzero if divide by
  40.                                 ; zero interrupt occurred
  41.  
  42. oldip   dw      0               ; save old IP value
  43.  
  44.  
  45. ;
  46. ; The routine 'int0' is the actual divide by zero
  47. ; interrupt handler.  It gains control whenever a
  48. ; divide by zero or overflow occurs.  Its action
  49. ; is to set a flag and then increment the instruction
  50. ; pointer saved on the stack so that the failing 
  51. ; divide will not be reexecuted after the IRET.
  52. ;
  53. ; In this particular case we can call MS-DOS to 
  54. ; display a message during interrupt handling
  55. ; because the application triggers the interrupt
  56. ; intentionally. Thus, it is known that MS-DOS or
  57. ; other interrupt handlers are not in control
  58. ; at the point of interrupt.
  59.  
  60. int0:   pop     cs:oldip        ; capture instruction pointer
  61.  
  62.         push    ax
  63.         push    bx
  64.         push    cx
  65.         push    dx
  66.         push    di
  67.         push    si
  68.         push    ds
  69.         push    es
  70.  
  71.         push    cs              ; set DS = CS
  72.         pop     ds
  73.  
  74.         mov     ah,09h          ; print error message
  75.         mov     dx,offset _TEXT:intmsg
  76.         int     21h
  77.  
  78.         add     oldip,2         ; bypass instruction causing
  79.                                 ; divide by zero error
  80.  
  81.         mov     intflag,1       ; set divide by 0 flag
  82.  
  83.         pop     es              ; restore all registers
  84.         pop     ds
  85.         pop     si
  86.         pop     di
  87.         pop     dx
  88.         pop     cx
  89.         pop     bx
  90.         pop     ax
  91.  
  92.         push    cs:oldip        ; restore instruction pointer
  93.  
  94.         iret                    ; return from interrupt
  95.  
  96.  
  97. ;
  98. ; The code beginning at 'start' is the application
  99. ; program.  It alters the vector for Interrupt 00H to
  100. ; point to the new handler, carries out some divide
  101. ; operations (including one that will trigger an
  102. ; interrupt) for demonstration purposes, restores
  103. ; the original contents of the Interrupt 00H vector,
  104. ; and then terminates.
  105. ;
  106.  
  107. start:  mov     ax,3500h        ; get current contents 
  108.         int     21h             ; of Int 00H vector
  109.  
  110.                                 ; save segment:offset
  111.                                 ; of previous Int 00H handler
  112.         mov     word ptr oldint0,bx
  113.         mov     word ptr oldint0+2,es
  114.  
  115.                                 ; install new handler...
  116.         mov     dx,offset int0  ; DS:DX = handler address
  117.         mov     ax,2500h        ; call MS-DOS to set
  118.         int     21h             ; Int 00H vector
  119.         
  120.                                 ; now our handler is active,
  121.                                 ; carry out some test divides.
  122.  
  123.         mov     ax,20h          ; test divide
  124.         mov     bx,1            ; divide by 1
  125.         call    divide      
  126.  
  127.         mov     ax,1234h        ; test divide
  128.         mov     bx,5eh          ; divide by 5EH
  129.         call    divide      
  130.  
  131.         mov     ax,5678h        ; test divide
  132.         mov     bx,7fh          ; divide by 127
  133.         call    divide      
  134.  
  135.         mov     ax,20h          ; test divide
  136.         mov     bx,0            ; divide by 0
  137.         call    divide          ; (triggers interrupt)
  138.  
  139.                                 ; demonstration complete,
  140.                                 ; restore old handler
  141.  
  142.         lds     dx,oldint0      ; DS:DX = handler address
  143.         mov     ax,2500h        ; call MS-DOS to set
  144.         int     21h             ; Int 00H vector
  145.  
  146.         mov     ax,4c00h        ; final exit to MS-DOS
  147.         int     21h             ; with return code = 0
  148.  
  149. ;
  150. ; The routine 'divide' carries out a trial division,
  151. ; displaying the arguments and the results.  It is
  152. ; called with AX = dividend and BL = divisor.
  153. ;
  154.  
  155. divide  proc    near
  156.  
  157.         push    ax              ; save arguments
  158.         push    bx
  159.  
  160.         mov     di,offset par1  ; convert dividend to 
  161.         call    wtoa            ; ASCII for display
  162.  
  163.         mov     ax,bx           ; convert divisor to
  164.         mov     di,offset par2  ; ASCII for display
  165.         call    btoa
  166.  
  167.         pop     bx              ; restore arguments
  168.         pop     ax
  169.  
  170.         div     bl              ; perform the division
  171.         cmp     intflag,0       ; divide by zero detected?
  172.         jne     nodiv           ; yes, skip display
  173.  
  174.         push    ax              ; no, convert quotient to
  175.         mov     di,offset par3  ; ASCII for display
  176.         call    btoa
  177.  
  178.         pop     ax              ; convert remainder to 
  179.         xchg    ah,al           ; ASCII for display
  180.         mov     di,offset par4
  181.         call    btoa
  182.  
  183.         mov     ah,09h          ; show arguments, results 
  184.         mov     dx,offset divmsg
  185.         int     21h
  186.  
  187. nodiv:  mov     intflag,0       ; clear divide by 0 flag
  188.         ret                     ; and return to caller
  189.  
  190. divide  endp
  191.  
  192.  
  193.  
  194. wtoa    proc    near            ; convert word to hex ASCII
  195.                                 ; call with AX = binary value
  196.                                 ;           DI = addr for string
  197.                                 ; returns AX, CX, DI destroyed
  198.  
  199.         push    ax              ; save original value
  200.         mov     al,ah
  201.         call    btoa            ; convert upper byte
  202.         add     di,2            ; increment output address
  203.         pop     ax
  204.         call    btoa            ; convert lower byte
  205.         ret                     ; return to caller
  206.  
  207. wtoa    endp
  208.  
  209.  
  210.  
  211. btoa    proc    near            ; convert byte to hex ASCII
  212.                                 ; call with AL = binary value
  213.                                 ;           DI = addr to store string
  214.                                 ; returns AX, CX destroyed
  215.  
  216.         mov     ah,al           ; save lower nibble
  217.         mov     cx,4            ; shift right 4 positions
  218.         shr     al,cl           ; to get upper nibble
  219.         call    ascii           ; convert 4 bits to ASCII
  220.         mov     [di],al         ; store in output string
  221.         mov     al,ah           ; get back lower nibble
  222.  
  223.         and     al,0fh          ; blank out upper one
  224.         call    ascii           ; convert 4 bits to ASCII
  225.         mov     [di+1],al       ; store in output string
  226.         ret                     ; back to caller
  227.  
  228. btoa    endp
  229.  
  230.  
  231.  
  232. ascii   proc    near            ; convert AL bits 0-3 to 
  233.                                 ; ASCII {0...9,A...F}
  234.         add     al,'0'          ; and return digit in AL
  235.         cmp     al,'9'
  236.         jle     ascii2     
  237.         add     al,'A'-'9'-1    ; "fudge factor" for A-F
  238. ascii2: ret                     ; return to caller
  239.  
  240. ascii   endp
  241.  
  242. _TEXT   ends
  243.  
  244.         end     entry
  245.