; ; clock.asm ; ; Put the time in the upper right corner ; ; David lindauer, August 28,1995 ; .386 TSRHOOK = 082h TSRLOADED = 5 TSRUNLOAD = 6 absseg segment word use16 at 0 org 02ch env dw ? ; ENV is in PSP org 6ch timer dd ? ; TiMER is in bios data seg 40h org 01ch*4 int1ch dd ? ; Ints are in seg 0 org 80h*4 int80h dd ? absseg ends cseg segment word use16 'CODE' assume cs:cseg org 100h assume ds:nothing, es:nothing begin: jmp start ; Program start count db 1 ; Tick counter. Update time every ; 18 ticks old1c dd 0 ; Old int 1c old80 dd 0 ; old int 80 ; ; Procedure to display the time ; handler1c proc dec count ; See if it is time yet jnz short follow1c ; Nope, next handler mov [count],18 ; Yep reset time count push eax ; Save regs push ebx push ecx push edx push es push 40h ; ES = BIOS data seg pop es mov eax,es:[timer] ; Get ticks today mov ebx,10 ; Divide by 18.2 to get seconds mul ebx ; mov ebx,182 ; div ebx ; mov ebx,60 ; Divide by 60 to get mins sub edx,edx ; div ebx ; mov cl,dl ; secons in CL, mins in ax sub dx,dx ; div bx ; Divide by 60 to get hrs mov ch,dl ; mins in ch, hrs in al push 0b800h ; Screen seg, VGA color pop es mov bx,(80-8)*2 ; Initial screen pos call putnum ; Put hrs mov al,':' ; A : call putchar ; mov al,ch ; Put mins call putnum ; a : mov al,':' ; call putchar ; mov al,cl ; put secs call putnum ; pop es ; Restore regs pop edx ; pop ecx ; pop ebx ; pop eax ; follow1c: jmp [old1c] handler1c endp ; ; Put a number on the screen ; putnum proc sub ah,ah ; AH = 0 push bx mov bl,10 ; Divide by 10 div bl ; pop bx call putdig ; Put msd mov al,ah ; Get remainder putdig: add al,'0' ; ASCII for digits putchar: mov es:[bx],al ; Save character inc bx mov byte ptr es:[bx],070h ; Black fg, white bg inc bx ret putnum endp ; ; Hook handler ; handler80 proc pushf ; See if valid request cmp ah,TSRHOOK ; jz short hooked ; Yep, get it followint: push ax ; Else see if was an old handler mov ax,word ptr [old80] ; or ax,word ptr [old80+2] ; pop ax ; jz short noold ; return if not popf ; Else go to next handler jmp [old80] ; noold: popf iret hooked: cmp al,TSRLOADED ; See if is load test jnz short checkunload ; Nope, look for unload popf ; mov al,0ffh ; Return loaded status iret checkunload: cmp al,TSRUNLOAD ; See if is unload jnz short followint ; Nope, follow interrupt chain popf mov bx,80h ; Reset int vectors to original state mov si,offset old80 ; call unloadint ; mov bx,1ch ; mov si,offset old1c ; call unloadint ; push cs pop es mov es,es:[env] ; Free environment mov ah,49h ; int 21h ; push cs pop es mov ah,49h ; Free prog seg int 21h ; sub ax,ax ; iret handler80 endp ; ; Routine to unload ints ; unloadint proc shl bx,2 ; Get int address push 0 ; pop es ; ES = 0 mov ax,cs:[si] ; Move lo word mov es:[bx],ax ; mov ax,cs:[si+2] ; mov es:[bx+2],ax ; ret unloadint endp endtsr label BYTE ; ; End of TSR. Init routines come next ; loadmsg db "Loading Clock",10,13,'$' unloadmsg db "Unloading Clock",10,13,'$' ; ; Routine to load an interrupt ; loadint proc shl bx,2 ; Get int address push 0 ; ES = 0 pop es mov di,es:[bx] ; Get old int mov cs:[si],di mov di,es:[bx+2] mov cs:[si+2],di cli mov es:[bx],ax ; Save new int mov es:[bx+2],cs ; sti ret loadint endp ; ; Main program ; start proc assume ds:cseg, es:absseg push 0 ; Check for int 80h pop es ; mov ax,word ptr [int80h] ; or ax,word ptr [int80h + 2]; jz short notloaded ; Not there, let's go load mov ah,TSRHOOK ; See if TSR is hooked mov al,TSRLOADED ; int 80h ; cmp al,0ffh ; jnz short notloaded ; Nope, go load mov dx,offset unloadmsg ; Unnloading mov ah,9 ; int 21h ; mov ah,TSRHOOK ; Tell TSR to unload mov al,TSRUNLOAD ; int 80h ; mov ah,4ch ; Get out int 21h notloaded: mov dx,offset loadmsg ; Loading mov ah,9 ; int 21h ; mov si,offset old80 ; Set int80h mov ax,offset handler80 mov bx,80h call loadint mov si,offset old1c ; Set int 1ch mov ax,offset handler1c ; mov bx,1ch ; call loadint ; mov dx,offset endtsr ; Set up keep space & exit add dx,15 ; shr dx,4 ; mov ah,31h ; int 21h ; start endp cseg ends end begin