106 lines
3.9 KiB
NASM
106 lines
3.9 KiB
NASM
|
interrupts segment at 0h ; This is where the disk interrupt
|
||
|
org 13h*4 ; holds the address of its service routine
|
||
|
disk_int label dword
|
||
|
interrupts ends
|
||
|
|
||
|
screen segment at 0B000h ; A dummy segment to use as the Extra
|
||
|
screen ends ; Segment so we can write to the display
|
||
|
|
||
|
code_seg segment
|
||
|
assume cs:code_seg
|
||
|
org 0100h ; ORG = 100h to make this a .COM file
|
||
|
first: jmp load_watch ; First time through jump to initialize routine
|
||
|
|
||
|
msg_part_1 db 'Disk error: ' ; Here are the error messages
|
||
|
msg_part_2 db 'No response Failed Seek NEC Error '
|
||
|
db 'Bad CRC SeenDMA Overrun Impos Sector'
|
||
|
db 'No Addr MarkW. ProtectedErr Unknown '
|
||
|
first_position dw ? ; Position of 1st char on screen
|
||
|
flags dw ?
|
||
|
screen_seg_offset dw 0 ; 0 for mono, 8000h for graphics
|
||
|
old_disk_int dd ? ; Location of old disk interrupt
|
||
|
ret_addr label dword ; Used in fooling around with
|
||
|
ret_addr_word dw 2 dup(?) ; the stack
|
||
|
|
||
|
disk_watch proc far ; The disk interrupt will now come here
|
||
|
assume cs:code_seg
|
||
|
pushf ; First, call old disk interrupt
|
||
|
call old_disk_int
|
||
|
pushf ; Save the flags in memory location "FLAGS"
|
||
|
pop flags ; (cunning name)
|
||
|
jc error ; If there was an error, carry flag will have
|
||
|
jmp fin ; been set by Disk Interrupt
|
||
|
error: push ax ; AH has the status of the error
|
||
|
push cx ; Push all used registers for politeness
|
||
|
push dx
|
||
|
push di
|
||
|
push si
|
||
|
push es
|
||
|
lea si,msg_part_1 ; Always print "Disk Error: " part.
|
||
|
assume es:screen ; Use screen as extra segment
|
||
|
mov dx,screen
|
||
|
mov es,dx
|
||
|
mov di,screen_seg_offset ; DI will be pointer to screen position
|
||
|
add di,first_position ; Add to point to desired area on screen
|
||
|
call write_to_screen ; This writes 12 chars from [SI] to [DI]
|
||
|
mov dx,80h ; Initialize for later comparisons
|
||
|
mov cx,7 ; Loop seven times
|
||
|
e_loop: cmp ah,dh ; Are error code and DH the same?
|
||
|
je e_found ; If yes, Error has been found
|
||
|
add si,12 ; Point to next error message
|
||
|
shr dh,1 ; Divide DH by 2
|
||
|
loop e_loop ; Keep going until matched DH = 0
|
||
|
cmp ah,3 ; Error code no even number; 3 perhaps?
|
||
|
je e_found ; If yes, have found the error
|
||
|
add si,12 ; Err unknown; unknown error returned
|
||
|
e_found:call write_to_screen ; Write the error message to the screen
|
||
|
pop es ; Restore the registers
|
||
|
pop si
|
||
|
pop di
|
||
|
pop dx
|
||
|
pop cx
|
||
|
pop ax
|
||
|
fin: pop ret_addr_word ; Fooling with the stack. We want to
|
||
|
pop ret_addr_word[2] ; preserve the flags but the old flags
|
||
|
add sp,2 ; are still on the stack. First remove
|
||
|
push flags ; return address, then flags. Fill flags
|
||
|
popf ; from "FLAGS", return to correct addr.
|
||
|
jmp ret_addr
|
||
|
disk_watch endp
|
||
|
|
||
|
write_to_screen proc near ; Puts 12 characters on screen
|
||
|
mov cx,12 ; Loop 12 times
|
||
|
w_loop: movs es:byte ptr[di],cs:[si] ; Move to the screen
|
||
|
mov al,7 ; Move screen attribute into screen buffer
|
||
|
mov es:[di],al
|
||
|
inc di ; Point to next byte in screen buffer
|
||
|
loop w_loop ; Keep going until done
|
||
|
ret
|
||
|
write_to_screen endp
|
||
|
|
||
|
load_watch proc near ; This procedure initializes everything
|
||
|
assume ds:interrupts ; The data segment will be the interrupt area
|
||
|
mov ax,interrupts
|
||
|
mov ds,ax
|
||
|
|
||
|
mov ax,disk_int ; Get the old interrupt service routine
|
||
|
mov old_disk_int,ax ; address and put it into our location
|
||
|
mov ax,disk_int[2] ; OLD_DISK_INT so we can call it.
|
||
|
mov old_disk_int[2],ax
|
||
|
|
||
|
mov disk_int,offset disk_watch ; Now load the address of DskWatch
|
||
|
mov disk_int[2],cs ; routine into the disk interrupt
|
||
|
|
||
|
mov ah,15 ; Ask for service 15 of INT 10h
|
||
|
int 10h ; This tells us how display is set up
|
||
|
sub ah,25 ; Move to twenty five places before edge
|
||
|
shl ah,1 ; Mult. by two (char & attribute bytes)
|
||
|
mov byte ptr first_position,ah ; Set screen cursor
|
||
|
test al,4 ; Is it a monochrome display?
|
||
|
jnz exit ; Yes - jump out
|
||
|
mov screen_seg_offset,8000h ; No, set up for graphics display
|
||
|
exit: mov dx,offset load_watch ; Set up everything but this program to
|
||
|
int 27h ; stay and attach itself to DOS
|
||
|
load_watch endp
|
||
|
code_seg ends
|
||
|
end first ; END "FIRST" so 8088 will go to FIRST first.
|