home *** CD-ROM | disk | FTP | other *** search
- title ZERODIV --- Divide by zero handler
- page 55,132
-
- ;
- ; ZERODIV.ASM --- Terminate-and-stay-resident handler
- ; for divide-by-zero interrupts
- ;
- ; Copyright 1988 Ray Duncan
- ;
- ; Build: C>MASM ZERODIV;
- ; C>LINK ZERODIV;
- ; C>EXE2BIN ZERODIV.EXE ZERODIV.COM
- ; C>DEL ZERODIV.EXE
- ;
- ; Usage: C>ZERODIV
- ;
-
- cr equ 0dh ; ASCII carriage return
- lf equ 0ah ; ASCII line feed
- beep equ 07h ; ASCII bell code
- backsp equ 08h ; ASCII backspace code
-
- _TEXT segment word public 'CODE'
-
- org 100H
-
- assume cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
-
-
- init proc near ; entry point at load time
-
- ; capture vector for
- ; interrupt zero ...
- mov dx,offset zdiv ; DS:DX = handler address
- mov ax,2500h ; Fxn 25H = set vector
- ; interrupt type = 0
- int 21h ; transfer to MS-DOS
-
- ; print sign-on message
- mov dx,offset msg1 ; DS:DX = message address
- mov ah,9 ; Fxn 09H = display string
- int 21h ; transfer to MS-DOS
-
- ; DX = paragraphs to reserve
- mov dx,((offset pgm_len+15)/16)+10h
- mov ax,3100h ; Fxn 31H = terminate and
- ; stay resident
- int 21h ; transfer to MS-DOS
-
- init endp
-
-
- zdiv proc far ; this is the divide by
- ; zero interrupt handler
-
- sti ; enable interrupts
-
- push ax ; save registers
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
-
- mov ax,cs ; make data addressable
- mov ds,ax
-
- ; display message
- ; "Continue or Quit?"
- mov dx,offset msg2 ; DS:DX = message address
- mov ah,9 ; Fxn 09H = display string
- int 21h ; transfer to MS-DOS
-
- zdiv1: mov ah,1 ; Fxn 01H = read keyboard
- int 21h ; transfer to MS-DOS
-
- or al,20h ; fold char. to lower case
-
- cmp al,'c' ; is it C or Q?
- je zdiv3 ; jump, it's a C
-
- cmp al,'q'
- je zdiv2 ; jump, it's a Q
-
- ; illegal entry, send beep
- ; and erase the character
- mov dx,offset msg3 ; DS:DX = message address
- mov ah,9 ; Fxn 09H = display string
- int 21h ; transfer to MS-DOS
-
- jmp zdiv1 ; try again
-
- zdiv2: ; user picked "Quit"
- mov ax,4cffh ; terminate current program
- int 21h ; with return code = 255
-
- zdiv3: ; user picked "Continue"
- ; send CR-LF pair
- mov dx,offset msg4 ; DS:DX = message address
- mov ah,9 ; Fxn 09H = print string
- int 21h ; transfer to MS-DOS
-
- ; what CPU type is this?
- xor ax,ax ; to find out, we'll put
- push ax ; zero in the CPU flags
- popf ; and see what happens
- pushf
- pop ax
- and ax,0f000h ; 8086/88 forces
- cmp ax,0f000h ; bits 12-15 true
- je zdiv5 ; jump if 8086/88
-
- ; otherwise we must adjust
- ; return address to bypass
- ; the divide instruction...
- mov bp,sp ; make stack addressable
-
- lds bx,[bp+18] ; get address of the
- ; faulting instruction
-
- mov bl,[bx+1] ; get addressing byte
- and bx,0c7h ; isolate mod & r/m fields
-
- cmp bl,6 ; mod 0, r/m 6 = direct
- jne zdiv4 ; not direct, jump
-
- add word ptr [bp+18],4
- jmp zdiv5
-
- zdiv4: mov cl,6 ; otherwise isolate mod
- shr bx,cl ; field and get instruction
- mov bl,cs:[bx+itab] ; size from table
- add [bp+18],bx
-
- zdiv5: pop es ; restore registers
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- iret ; return from interrupt
-
- zdiv endp
-
-
- msg1 db cr,lf ; load-time signon message
- db 'Divide by Zero Interrupt '
- db 'Handler installed.'
- db cr,lf,'$'
-
- msg2 db cr,lf,lf ; interrupt-time message
- db 'Divide by Zero detected: '
- db cr,lf,'Continue or Quit (C/Q) ? '
- db '$'
-
- msg3 db beep ; used if bad entry
- db backsp,' ',backsp,'$'
-
- msg4 db cr,lf,'$' ; carriage return-line feed
-
- ; instruction size table
- itab db 2 ; mod = 0
- db 3 ; mod = 1
- db 4 ; mod = 2
- db 2 ; mod = 3
-
- pgm_len equ $-init ; program length
-
- _TEXT ends
-
- end init
-
-