This is the past DOS era of the compilation of source code, although has passed, but for the study of the assembly is still helpful, assembly language is just a basic programmer language, most people can grasp, not necessarily in-depth research.
; by Steve Holzner (from June 1985 issue of PC Magazine)
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; The 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'll now come here
Assume Cs:code_seg
PUSHF; The call old disk interrupt
Call Old_disk_int
PUSHF; Save the flags in memory location "flags"
Pop flags; (Cunning name)
JC Error; If There is an error, carry flag would 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 the screen as extra segment
MOV Dx,screen
MOV es,dx
MOV di,screen_seg_offset; DI'll is pointer to screen position
Add di,first_position; Add to point to desired
Call Write_to_screen; This is writes 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. The I-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 Characters on screen
MOV cx,12; Loop Times
W_loop:movs Es:byte Ptr[di],cs:[si]; Move to the screen
MOV al,7; Move screen attribute to screen buffer
MOV Es:[di],al
Inc di; Point to next byte on 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 is 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 in 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 INT 10h
int 10h; This tells us and 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 I
int 27h; Stay and attach itself to DOS
Load_watch ENDP
Code_seg ends
End I; End "A" so 8088 'll go to the.