programming-examples/assembly/Disk Watch.asm
2019-11-15 12:59:38 +01:00

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.