home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
asmutl
/
wasm202.arc
/
RTIME.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-12-25
|
16KB
|
570 lines
Title 'Wolfware Sample Program', 'Resident Time Display'
;===============================================;
; Resident Time Display Version 1.10 ;
; ;
; A RAM resident utility which, if active, ;
; constantly displays the time in the the ;
; upper right corner. Once the utility is ;
; installed, the time is activated or ;
; deactivated with Alt-1 (hold down the Alt ;
; key and type 1 on the numeric keypad, then ;
; release the Alt key). The program is ;
; initially non-activated when first ;
; installed. Once assembled, to install, just ;
; type: ;
; ;
; RTIME ;
; ;
; The time is updated about three times a ;
; second, in the backround of whatever program ;
; is presently being executed. The time ;
; display overwrites whatever is on the screen ;
; at that location. The display can only be ;
; activated or deactivated when the foreground ;
; program does keyboard I/O via interrupt 16H. ;
; This utility uses about 1065 bytes of ;
; memory. ;
; ;
; For simplicity, the program assumes that ;
; there are 65535 ticks in an hour, though ;
; there are actually 65543. This means that ;
; the displayed time is 8 ticks fast for each ;
; hour past midnight. The most it is off ;
; occurs just before midnight, when it is ;
; 8 * 23 = 184 ticks, or about 10 seconds fast. ;
; As result of this the time actually runs to ;
; about 24:00:10 before switching to 00:00:00. ;
; ;
; This program may not be compatible with ;
; other RAM resident type programs. ;
;===============================================;
Proc Far
Jmp Install ;skip to installation routine
;===============================================;
; Equates ;
;===============================================;
True Equ -1 ;true flag
False Equ 0 ;false flag
;----- display location, location of first character of 8 byte string
Row Equ 1 ;row, 1 to 25
Column Equ 73 ;column, 1 to 80
;----- execution parameters
Key Equ 0001h ;int 16H key code to activate, Alt-1
Attribute Equ 70h ;display attribute, reverse video
Count_Set Equ 6 ;wait count, updated 18.2/COUNT_SET = 3/sec
;----- BIOS data, at segment 0
Equip_Flag Equ 0410h ;equipment word
Screen_Col Equ 044ah ;CRT columns
;----- interrupt location, at segement 0
Keyboard Equ 58h ;keyboard fetch, interrupt 16
Timer_Tick Equ 70h ;timer tick vector location, interrupt 1C
;----- clock information
Timer_Low Equ 046ch ;low word of timer, at segment 0
Timer_High Equ 046eh ;high word of timer, at segment 0
Counts_Sec Equ 18 ;counts in second
Counts_Min Equ 1092 ;counts in minute
Counts_Hor Equ 0ffffh ;counts in hour
;----- local stack size, stack just has to handle
;----- local routines and any hardware interrupts
Stack Equ 20 + 20 ;size
;===============================================;
; Int16 ;
; Alternate interrupt 16H (keyboard I/O) to ;
; handle normal function calls while ;
; intercepting display activation/deactivation ;
; commands. Check for command only if read key ;
; or get keyboard status (functions 0 and 1). ;
;===============================================;
Int16 Proc Far
Sti ;interrupts on
Pushf ;save entry flags
;----- read next key
Or Ah, Ah ;check if read key
Jnz Nonkey ;jump if not
I16get
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt
Cmp Ax, Key ;check scan code
Je Subkey ;jump if activate key
Iret
;----- activation key on read
Subkey
Call Toggle_Act ;toggle present setting
Sub Sp, 2 ;simulate flags for interrupt call
Sub Ah, Ah ;read next key function
Jmps I16get ;try again
;----- keyboard status
Nonkey
Cmp Ah, 1 ;check if keyboard status
Jne Nonstat ;jump if not
Popf ;restore entry flags
Pushf ;flags for interrupt call
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt
Pushf
Jnz I16chksk ;jump if key in buffer
Popf
Ret 2 ;throw away flags in stack on return
I16chksk
Cmp Ax, Key ;check scan code
Je I16fact ;jump if activate key
Popf
Ret 2 ;throw away flags in stack on return
;----- activation key on status
I16fact
Sub Ah, Ah ;get key function
Sub Sp, 2 ;simulate flags for interrupt call
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt, get key
Call Toggle_Act ;toggle present setting
Mov Ah, 1 ;status function
Jmps Nonkey ;try again, flags still on stack
;----- keyboard shift status or unknown function
Nonstat
Seg Cs ;code segment
Call Old_Int16 ;keyboard interrupt, (flags on stack)
Iret
Endp ;Int16
;===============================================;
; Toggle_Act ;
; Toggle active setting and reset screen info. ;
; Clears time display (sets to dashes). ;
;===============================================;
Toggle_Act Proc Near
Seg Cs
Cmp Activated, True ;check if on
Je Actoff ;jump if so, turn off
;----- activate
Seg Cs
Mov Activated, True ;activate
Seg Cs
Mov Counter, Count_Set ;reset counter
Jmps Screenres
;----- deactivate
Actoff Seg Cs
Mov Activated, False ;activate off
;----- reset screen information and clear display
;----- switch to local stack
Screenres Seg Cs
Mov Stack_Seg, Ss ;save stack segment
Seg Cs
Mov Temp, Cs
Seg Cs
Mov Ss, Temp ;new stack segment
Seg Cs
Mov Stack_Off, Sp ;save stack pointer
Seg Cs
Mov Sp, Local_Stk ;new stack
;----- save all registers
Push Ax
Push Bx
Push Cx
Push Dx
Push Di
Push Si
Push Ds
Push Es
Cld ;forward direction
;----- set screen information
Sub Ax, Ax
Mov Ds, Ax ;segement 0
Mov Bx, [Screen_Col] ;screen columns
Mov Ax, 0b800h ;graphics segment
Mov Dx, [Equip_Flag] ;get equipment flag
And Dx, 30h ;mask CRT bits
Cmp Dx, 30h ;check if BW card
Jne Notbw ;jump if not
Mov Ax, 0b000h ;BW segement
Notbw Mov Dx, Cs
Mov Ds, Dx
Mov Es, Dx ;set data segment registers
Mov Screen_Seg, Ax ;save segment
;----- calculate screen offset
Mov Ax, Bx
Sub Dx, Dx
Mul Ax, Time_Row ;row offset
Add Ax, Time_Col ;add for columns
Shl Ax ;times two, account for attribute bytes
Mov Screen_Off, Ax ;save
;----- clear time display (set numbers to dashes)
Mov Ax, 2d2dh ;dashes to clear time and date
Cli ;interrupts off while display
Mov Di, Offset Tdisplay;dislay line
Stosw ;hours
Inc Di
Stosw ;minutes
Inc Di
Stosw ;seconds
Call Display ;display new string
Sti ;interrupts back on
;----- restore registers
Pop Es
Pop Ds
Pop Si
Pop Di
Pop Dx
Pop Cx
Pop Bx
Pop Ax
;----- restore stack
Seg Cs
Mov Sp, Stack_Off ;stack pointer
Seg Cs
Mov Ss, Stack_Seg ;stack segment
Ret
Endp ;Toggle_Act
;===============================================;
; Int1c ;
; Alternate interrupt 1CH (timer tick). ;
; Executed every timer tick (about 18.2 times ;
; a second). ;
; ;
; One out of COUNT_SET cycles the time is ;
; displayed to its predetermined location, so ;
; the time is actually updated 18.2/COUNT_SET ;
; times per second. ;
; ;
; Each interrupt calls the original timer tick ;
; interrupt for the benefit of any other ;
; routines that were using it. ;
;===============================================;
Int1c Proc Near
Cli ;interrupts off
;----- check if activated
Seg Cs
Cmp Activated, True ;check if activated
Je Redischk ;jump if so
Exit Pushf ;flags for interrupt call
Seg Cs
Call Old_Int1c ;call original interrupt
Iret
Redischk Seg Cs
Dec Counter ;decrement counter
Jnz Exit ;jump if not zero
;----- redisplay time
;----- switch to internal stack
Seg Cs
Mov Activated, False ;deactivate
Seg Cs
Mov Stack_Seg, Ss ;save stack segment
Seg Cs
Mov Temp, Cs
Seg Cs
Mov Ss, Temp ;new stack segment
Seg Cs
Mov Stack_Off, Sp ;save stack pointer
Seg Cs
Mov Sp, Local_Stk ;new stack
;----- save all registers
Push Ax
Push Bx
Push Cx
Push Dx
Push Di
Push Si
Push Ds
Push Es
Cld ;forward direction
;----- get time
Sub Ax, Ax
Mov Ds, Ax ;segment 0
Mov Dx,[Timer_High] ;timer high
Mov Ax,[Timer_Low] ;timer low
;----- set time
Mov Bx, Cs
Mov Ds, Bx
Mov Es, Bx ;set segment registers
Mov Counter, Count_Set ;reset counter
Mov Di, Offset Tdisplay ;start of time display string
Mov Bx, Counts_Hor ;counts/hour
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Inc Di ;skip colon
Mov Ax, Dx ;remainder is new dividend
Sub Dx, Dx
Mov Bx, Counts_Min ;counts/minute
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Inc Di ;skip colon
Mov Ax, Dx ;remainder is new dividend
Sub Dx, Dx
Mov Bx, Counts_Sec ;counts/second
Div Ax, Bx ;divide
Call Number_Con ;convert to ASCII and store
Call Display ;display string to screen
;----- restore registers
Pop Es
Pop Ds
Pop Si
Pop Di
Pop Dx
Pop Cx
Pop Bx
Pop Ax
;----- restore stack
Seg Cs
Mov Sp, Stack_Off ;restore stack pointer
Seg Cs
Mov Ss, Stack_Seg ;restore stack segment
Seg Cs
Mov Activated, True ;reactivate
Jmp Exit ;exit routine
Endp ;Int1c
;===============================================;
; Number_Con ;
; Convert number in AL to two digit ASCII ;
; string and store result to DI. Number must ;
; be in range 0 to 99. DI returns pointing to ;
; byte after new string. ;
;===============================================;
Number_Con Proc Near
Shl Al
Sub Ah, Ah ;AX gets relative offset
Add Ax, Offset Numbers ;absolute offset
Mov Si, Ax
Movsw ;move word (two byte digits)
Ret
;----- data, 00 to 99
Numbers Label Byte
Db '00010203040506070809'
Db '10111213141516171819'
Db '20212223242526272829'
Db '30313233343536373839'
Db '40414243444546474849'
Db '50515253545556575859'
Db '60616263646566676869'
Db '70717273747576777879'
Db '80818283848586878889'
Db '90919293949596979899'
Endp ;Number_Con
;===============================================;
; Display ;
; Display the time string to the screen by ;
; writing it directly to the screen buffer. ;
;===============================================;
Display Proc Near
Mov Ah, Attribute ;display attribute
Mov Cx, Offset Tdisplay_End - Offset Tdisplay ;length
Mov Di, Screen_Off ;offset into screen
Mov Si, Offset Tdisplay ;start of time string
Mov Es, Screen_Seg ;segment of screen
;----- move string to screen buffer
Disloop Lodsb ;load character
Stosw ;store character and attribute
Loop Disloop ;loop CX times
Ret
Endp ;Display
;===============================================;
; Data ;
;===============================================;
Activated Db False ;activation status, initially off
Counter Db ? ;execution counter, set when activated
Time_Row Dw Row - 1 ;display row
Time_Col Dw Column - 1 ;display column
Stack_Off Dw ? ;storage for stack offset
Stack_Seg Dw ? ;storage for stack segment
Local_Stk Dw Offset End + Stack ;local stack top
Screen_Off Dw ? ;screen offset
Screen_Seg Dw ? ;screen segment
Temp Dw ? ;temporary storage
;----- display string
Tdisplay Label Byte ;start of string
Db '--:--:--'
Tdisplay_End Label Byte ;end of string (to calculate length)
;----- original interrupts
Old_Int16 Label Dword
Dw ? ;offset
Dw ? ;segment
Old_Int1c Label Dword
Dw ? ;offset
Dw ? ;segment
End Label Byte ;end of code and data, start of stack space
;===============================================;
; Install ;
; Install the alternate interrupts. ;
;===============================================;
Install Proc Near
;----- install new interrupt vectors
Mov Ax, Offset Int16 ;keyboard offset
Mov Bx, Cs ;present segement
Mov Cx, Offset Int1c ;timer offset
Mov Dx, Cs ;present segement
;----- get and save old interrupts
Mov Ax, 3516h ;function and interrupt 16h
Int 21h ;execute
Mov Word Old_Int16, Bx ;offset
Mov Word Old_Int16+2, Es ;segment
Mov Ax, 351ch ;function and interrupt 1ch
Int 21h ;execute
Mov Word Old_Int1c, Bx ;offset
Mov Word Old_Int1c+2, Es ;segment
;----- set new interrupts
Mov Ax, 2516h ;function and interrupt 16h
Mov Dx, Offset Int16 ;keyboard offset
Int 21h ;execute
Mov Ax, 251ch ;function and interrupt 1ch
Mov Dx, Offset Int1c ;timer offset
Int 21h ;execute (and it's off!)
;----- display message
Mov Dx, Offset Installm ;message location
Mov Ah, 9 ;print string function
Int 21h ;execute
;----- finish up
Mov Dx, Local_Stk ;end of interrupt, top of local stack
Mov Cl, 4
Shr Dx, Cl ;paragraph form
Inc Dx ;allow for fraction of paragraph
Mov Ax, 3100h ;exit function (stay resident)
Int 21h ;execute
;----- message
Installm Db 10
Db '/-------------------------------------------\', 13, 10
Db '| Resident time display utility installed |', 13, 10
Db '|----------------- Ver 1.10 ----------------|', 13, 10
Db '| press ALT-1 to activate/deactivate |', 13, 10
Db '\-------------------------------------------/', 13, 10,'$'
Endp ;Install
Endp ;main program