Hey Almas,
Been awhile since I wrote dos code, but most of this works up thru
XP.
Good luck. :-)
; clock.asm Works thru Win 98
;
.MODEL SMALL
.CODE
ORG 100H
FIRST: jmp Install
old_int_label label word
old_int dd ?
H db ? ; hours
M db ? ; minutes
S db ? ; seconds
LD db ? ; lower digit
HD db ? ; higher digit
new_int PROC
push ax ;save registers and flags
push bx
push cx
push dx
pushf
mov ah,03 ; save the original x,y coord.
mov bh,0
int 10h ; dh:row,dl:col
push cx
push dx
mov ah,1 ; and hide cursor for a while
mov cx,2000h
int 10h
;Begin WRITE TIME
mov ah,2 ; Get time from CMOS directly, (not
from
DOS)
int 1Ah ; Use the interrrupt 1Ah to get real
time
cmp ch,25 ; from RTC (CMOS)
jle h1
sub ch,12
jmp h2
h1: cmp ch,9 ; Adjust the hour's value from RTC to
resolve
jle h2 ; the actual time
sub ch,6
h2: mov H,ch
cmp cl,73
jle m1
sub cl,30 ; Adjust the minutes' value from RTC to
resolve
jmp m5 ; the correct minutes' value
m1: cmp cl,57
jle m2
sub cl,24
jmp m5
m2: cmp cl,41
jle m3
sub cl,18
jmp m5
m3: cmp cl,25
jle m4
sub cl,12
jmp m5
m4: cmp cl,9
jle m5
sub cl,6
m5: mov M,cl
cmp dh,73
jle s1 ;Adjust the seconds' value from RTC to
resolve
sub dh,30 ;the correct seconds' value
jmp s5
s1: cmp dh,57
jle s2
sub dh,24
jmp s5
s2: cmp dh,41
jle s3
sub dh,18
jmp s5
s3: cmp dh,25
jle s4
sub dh,12
jmp s5
s4: cmp dh,9
jle s5
sub dh,6
s5: mov S,dh
mov ah,0 ;Since we can only type one digit at a
time,
mov al,H ;with the int 10H, We should partition
the
mov bl,10 ;BCD value of H, M, and S to 2
digits(LD,HD)
div bl
mov HD,al
mov LD,ah ;get HD & LD of hours (low and high
digits)
mov ah,2 ;go to position (2,70)
mov dh,0
mov dl,70
int 10h
mov ah,9
mov al,'=BA' ;and write a '=BA'
mov bl,27
mov cx,1
int 10h
mov ah,2 ;go to hour position (2,71)
mov dl,71
int 10h
mov ah,9
add HD,48
mov al,HD ;and First write HD of the Hours
mov bl,27
int 10h
mov ah,2 ;go to hour position (2,72)
mov dl,72
int 10h
mov ah,9
add LD,48
mov al,LD ;and write the LD of Hours
mov bl,27
int 10h
mov ah,2 ;go to hour's : position (2,73)
mov dl,73
int 10h
mov ah,9
mov al,':' ;and write a ':'
mov bl,27
int 10h
mov ah,0
mov al,M
mov bl,10
div bl ;get HD & B of Minutes
mov HD,al
mov LD,ah
mov ah,2 ;go to hour position (2,74)
mov dl,74
int 10h
mov ah,9
add HD,48
mov al,HD ;and First write HD of the Minutes
mov bl,27
int 10h
mov ah,2 ;go to Minute position (2,75)
mov dl,75
int 10h
mov ah,9
add LD,48
mov al,LD ;and write the LD of Minutes
mov bl,27
int 10h
mov ah,2 ;go to position (2,76)
mov dl,76
int 10h
mov ah,9
mov al,58 ;and write a blinking ':'
mov bl,155
int 10h
mov ah,0
mov al,S
mov bl,10
div bl ;get HD & LD of Seconds
mov HD,al
mov LD,ah
mov ah,2 ;go to second's position (2,77)
mov dl,77
int 10h
mov ah,9
add HD,48
mov al,HD ;and First write HD of the Seconds
mov bl,27
mov cx,1
int 10h
mov ah,2 ;go to hour position (2,78)
mov dl,78
int 10h
mov ah,9
add LD,48
mov al,LD ;and write the LD of Seconds
mov bl,27
int 10h
mov ah,2 ;go to position (2,79)
mov dl,79
int 10h
mov ah,9
mov al,'=BA' ;and write a '=BA'
mov bl,27
int 10h
;End write time
exit: mov ah,1 ;enable cursor
mov ch,6
mov cl,7
int 10h
pop dx
mov ah,02 ;go back to where you were
int 10h
pop cx
mov ah,1 ;with the same cursor type
int 10h
popf
pop dx ;restore registers
pop cx
pop bx
pop ax
pushf
call old_int ;and call old_int (original int 8)
iret
new_int ENDP
Install PROC
mov ax,3508h
int 21h
mov old_int_label, bx
mov old_int_label[2], es ;save the old int 8
mov ah, 25h
lea dx, new_int
int 21h ;associate new_int with int 8
mov dx, offset Install
int 27h
Install ENDP
END FIRST
; saver.asm Com program Modified 6/13/2002 Andrew Kennedy
; Works up to Win 98
; Screen saver (blanks screen) COM file..
; Only works in 80x25 screen modes (2,3,7) [could easily be adapted/
others]
; Uses F-8 key to activate, uninstall by typing name of program
again
;
; **** ADJUSTABLE time interval to pop up
;
; There is a conflict when this is run when chime.com is also
loaded.
;
;
SEQ ; store segment sequentially as they appear
286 ; use 80286+ code
MODEL tiny ; TINY model to make it a .COM program
;* Macros *
StAlloc MACRO sizew ; macro to allocate stack, size "sizew" words
MOV BX,((sizew*2)+15) SHR 4 ; BX =3D size in paragraphs
MOV AH,48h ; allocate memory function
INT 21h ; call DOS
CLI ; freeze interrupts
MOV SS,AX ; set stack segment to allocated segment returned
in AX
MOV SP,sizew*2-2 ; set stack pointer to end of segment (goes top
down)
STI ; restore interrupts
ENDM
StDeAlloc MACRO ; macro to deallocate stack
MOV AX,SS
MOV ES,AX
MOV AH,49h ; call DOS deallocate block function
INT 21h
ENDM
;* Code Segment *
code SEGMENT PARA PUBLIC 'CODE' ; code segment
ASSUME CS:code, DS:code, ES:code, SS:code ; assume CS->"code" etc.
ORG 100h ; start assembling at offset 0h
(default)
;* Program Start *
start: ; label for start of program
JMP init
;* Procedures *
; Save screen and display (init) screen saver logo
ScreenSaver PROC NEAR
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET ScrData
MOV DS,CS:ScrAddress
XOR SI,SI
CLD
MOV CX,2000
REP MOVSW ; save screen
MOV CS:SSOn,1
MOV AH,0Fh
INT 10h ; get current page in BH
MOV AH,03h
INT 10h ; get old cursor size
MOV CS:OldCursor,CX
MOV AH,01h
MOV CX,0100h
INT 10h ; hide cursor
CALL RunSaver ; clear screen
CALL DrawSaver ; draw logo
RET
ENDP
; Restore screen and deinitialize screen saver
RemoveSaver PROC NEAR
MOV ES,CS:ScrAddress
XOR DI,DI
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET ScrData
CLD
MOV CX,2000
REP MOVSW
MOV CS:SSOn,0
MOV AH,01h
MOV CX,CS:OldCursor
INT 10h ; restore cursor
RET
ENDP
; Re-hide screen to cover any writing
RunSaver PROC NEAR
MOV ES,CS:ScrAddress
XOR DI,DI
MOV CX,2000
XOR AX,AX
REP STOSW
RET
ENDP
; Find parts of screen that were changed and save to virtual screen
DeltaSaver PROC NEAR
CLD
MOV DS,CS:ScrAddress
XOR SI,SI ; DS:SI -> physical screen
MOV AX,CS
MOV ES,AX
MOV DI,OFFSET ScrData ; ES:DI -> virtual screen
XOR BH,BH ; row 0
ds_nextrow:
MOV CX,80
CMP BH,CS:Row
JZ ds_check ; if row of copyright string handle separately
ds_loop:
LODSW
CMP AX,0 ; check if still zero (as set by screen saver)
JZ ds_again
MOV ES:[DI],AX ; set to new value
ds_again:
INC DI
INC DI
LOOP ds_loop
ds_new:
INC BH
CMP BH,25
JNZ ds_nextrow
RET
ds_check:
MOV BP,OFFSET Copyright
MOV BL,CS:Color
ds_loop2:
LODSW
CMP AL,ES:[BP]
JNZ ds_delta
CMP AH,BL
JZ ds_ok
ds_delta:
MOV ES:[DI],AX
ds_ok:
INC DI
INC DI
INC BP
LOOP ds_loop2
JMP SHORT ds_new
ENDP
; Draw copyright string
DrawSaver PROC NEAR
MOV AX,WORD PTR CS:Row2
MOV WORD PTR CS:Row,AX ; now safe to copy incremented data
MOV AH,CS:Row
MOV AL,160
MUL AH
MOV DI,AX
MOV AX,CS
MOV DS,AX
MOV SI,OFFSET CS:Copyright
MOV AH,CS:Color
ds_write:
LODSB
OR AL,AL
JZ ds_donemsg
STOSW
JMP SHORT ds_write
ds_donemsg:
RET
ENDP
; move message and change color
IncSaver PROC NEAR
MOV AX,WORD PTR CS:Row2 ; AL =3D row, AH =3D attribute
ADD AX,101h ; increment both
CMP AL,25
JNZ is_rowset
XOR AL,AL
is_rowset:
CMP AH,16
JNZ is_colset
MOV AH,1
is_colset:
MOV WORD PTR CS:Row2,AX
RET
ENDP
; INT 09h interrupt handler
; checks for hotkey combinations and deinstalls or activates program
if found
Int09Handler PROC FAR
PUSHF
CALL CS:OldInt09 ; call old handler
PUSHA
PUSH DS
PUSH ES
MOV AX,40h
MOV ES,AX
MOV DI,ES:[1Ah]
CMP DI,ES:[1Ch] ; quit if no keys in keyboard buffer
JZ i9_exit
MOV CS:SSTimer,0 ; zero timer for screen saver
CMP CS:SSOn,0
JZ i9_skip
CALL RemoveSaver ; if screen saver active, restore screen
i9_skip:
MOV DI,ES:[DI] ; get key in keyboard buffer
CMP DI,4200h ; check for F8 , zeroes needed after scan code
JNZ i9_exit
PUSH DI
PUSH ES
CALL ScreenSaver ; startup screen saver
POP ES
POP DI
i9_remove:
INC WORD PTR ES:[1Ah]
INC WORD PTR ES:[1Ah] ; remove key from buffer
CMP WORD PTR ES:[1Ah],3Eh
JNZ i9_exit
MOV WORD PTR ES:[1Ah],1Eh ; wrap around if required
i9_exit:
POP ES
POP DS
POPA
IRET
ENDP
; INT 1Ch interrupt handler
; activates screen saver when timeout occurs
Int1CHandler PROC FAR
PUSHF
CALL CS:OldInt1C
PUSHA
PUSH DS
PUSH ES
CMP CS:SSOn,0
JZ i1c_off
CALL DeltaSaver ; store changes to virtual screen
CALL RunSaver ; blank screen
CALL DrawSaver ; draw message or graphic
i1c_off:
MOV AL,CS:Timer1
DEC AL
MOV CS:Timer1,AL
JNZ i1c_exit
MOV AH,18
MOV AL,CS:Timer2
DEC AL
JNZ i1c_not19
INC AH
MOV AL,5
i1c_not19:
MOV CS:Timer2,AL
MOV CS:Timer1,AH
CMP CS:SSOn,0
JZ i1c_count
CALL IncSaver
JMP SHORT i1c_exit
i1c_count:
MOV AX,CS:SSTimer
INC AX
MOV CS:SSTimer,AX
CMP AX,180 ; 3 minutes (min x 60 secs)
JNZ i1c_exit
XOR AX,AX
MOV CS:SSTimer,AX ; set to zero
CALL ScreenSaver ; startup screen saver
i1c_exit:
POP ES
POP DS
POPA
IRET
ENDP
; TSR data
ScrAddress DW 0
OldCursor DW 0
OldInt09 DD 0
OldInt1C DD 0
SSTimer DW 0
SSOn DB 0
Timer1 DB 18
Timer2 DB 5
ScrData DW 2000 DUP (?)
Row DB 0
Color DB 1
Row2 DB 0
Color2 DB 1
Copyright DB '=D8 =F7=F7=F7=F7=F7=F7 =D8 Oil I Maintenance Services A.
Kenn=
edy May
2002(c)',0
Sig DB 'VXSS'
TSR_end LABEL BYTE
; * Main Program *
init:
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV BX,OFFSET code_end
ADD BX,15
SHR BX,4
MOV AH,4AH
INT 21H ; free unneeded memory given to
program
StAlloc 50h ; allocate stack (saves memory on
disk)
XOR AX,AX
MOV ES,AX
PUSH DS
MOV DS,ES:[26h]
CMP WORD PTR DS:Sig,'XV'
JNZ i_skip
CMP WORD PTR DS:Sig+2,'SS'
JNZ i_skip
MOV AX,WORD PTR DS:OldInt09
MOV BX,WORD PTR DS:OldInt09+2
CLI
MOV ES:[24h],AX
MOV ES:[26h],BX
MOV AX,WORD PTR DS:OldInt1C
MOV BX,WORD PTR DS:OldInt1C+2
MOV ES:[70h],AX
MOV ES:[72h],BX
STI
MOV AX,DS
MOV ES,AX
MOV AH,49h
INT 21h
POP DS
MOV AH,09h
MOV DX,OFFSET Deinstall
INT 21h
StDeAlloc
MOV AX,4C00h
INT 21h
i_skip:
POP DS
MOV AX,0B800h
CMP BYTE PTR ES:[0449h],7 ; check if current mode @[EMAIL PROTECTED]
0:449 is 7
(mono)
JNZ i_gotmode
MOV AX,0B000h
i_gotmode:
MOV ScrAddress,AX ; store screen address
MOV AX,ES:[24h]
MOV BX,ES:[26h]
MOV WORD PTR OldInt09,AX
MOV WORD PTR OldInt09+2,BX ; save old interrupt 09h
MOV AX,OFFSET Int09Handler
MOV BX,CS
CLI
MOV ES:[24h],AX
MOV ES:[26h],BX
STI
MOV AX,ES:[70h]
MOV BX,ES:[72h]
MOV WORD PTR OldInt1C,AX
MOV WORD PTR OldInt1C+2,BX ; save old interrupt 1Ch
MOV AX,OFFSET Int1CHandler
MOV BX,CS
CLI
MOV ES:[70h],AX
MOV ES:[72h],BX
STI
MOV AH,49h
MOV ES,CS:[2Ch]
INT 21h ; deallocate environment block
MOV AH,09h
MOV DX,OFFSET Install
INT 21h ; display message
StDeAlloc ; deallocate stack
MOV DX,OFFSET TSR_end
ADD DX,15
SHR DX,4
MOV AX,3100h
INT 21h ; go TSR, exit with errorlevel 0
;* Data Area *
; main program data
Install DB 13,10,'Screen Saver now installed - press F8 to '
DB 'activate.',13,10,10,'$'
Deinstall DB 13,10,'Screen Saver deinstalled Ok.',13,10,10,'$'
;* End Program *
code_end LABEL BYTE ; mark end of code segment (end of
program)
code ENDS ; end code segment "code"
END start ; end program, start execution at
"start:"
; chime.asm
; Chimes every 15 minutes
;
; RESIDENT TIME CLOCK DISPLAY with optional chime
;
; Original author unidentified
;
; Revised by Thomas A. Lundin
; Graphics Unlimited Inc.
; 3000 Second St. No.
; Minneapolis, MN 55411
; (612) 588-7571
;
; Later revisions -- 1/22/91
;
; usage: chime [/c]
; /c to toggle chiming. No chimes by default.
;
; Clock display can be toggled on and off by repeating 'chime'.
;
; Chimes should be toggled off when using heavy interrupt-driven
; software such as communications to avoid losing characters or
; hanging the system.
;
; 9/4/87 note:
; This version uses the clock tick to regulate the duration of
the
; chimes, meaning that the chimes should be the same length from
; one system to another, no matter what the CPU speed.
; Also modified start-up routines to automatically set the time
; display background to color or monochrome.
;
; 9/21/87 note:
; This version alterates a date display with the time display,
every
; 1.5 seconds. The date display is static, i.e., it is not
updated
; at midnight (it would be inefficient to check every hour for
an
; event which occurs once every 24 hours).
;
; Turning the chime off and on (typing chime, twice) will reset
the date.
;
; 1/05/88 note:
; This revision sets the clock display in the lower right corner
; instead of the upper right.
;
; 1/22/91 note:
; This revision causes the clock to automatically position itself
; according to the number of columns in the display. The
; program did this before, but only when it was initially loaded.
; Thus if you switched between an 80 and 132 column mode, the
clock would
; no longer be displayed in the upper right hand corner or
wherever.
; The program now reads the number of columns every time the clock
is
; displayed.
;
; 2/1/91 The chime has now been replaced by a =AEcuckoo=AF. The clock
will
now
; cuckoo for the appropriate hourly figure and cuckoo once on
the
; quarter hour.
;
;v1.1 Toad Hall Tweak, 17 Apr 93
; - Retabified, reformatted for consistent upper, lower case.
; - Minor tweaks, tightening.
; David Kirschbaum, Toad Hall
TICKS EQU 27 ; number of ticks between updates (1.5
sec)
;old value -- 27
BEEPS1 EQU 1 ; duration of first beep in clock
ticks
BEEPS2 EQU 3 ; duration of second beep in clock
ticks
BEEPS3 EQU 1 ; pause between cuckoos
TONE1 EQU 5e7h ; first chime tone 5f7h
TONE2 EQU 74ch ; second chime tone
CR EQU 0DH ;v1.1
LF EQU 0AH ;v1.1
INTERRUPTS segment at 0h
org 1ch*4 ; This is to use INT 1Ch
timer_int label dword ; which is the timer interupt
INTERRUPTS ends
SCREEN SEGMENT AT 0B000H ; A dummy segment to use
SCREEN ENDS ; as the Extra Segment
CSEG SEGMENT
ASSUME CS:CSEG
ORG 100h ; org =3D 100 to make this into
; a .COM file
First: jmp Load_Clock
old_time_int dd ? ; The address INT 1Ch normally
uses
count500 dw TICKS ; Used to update clock every
nnn
counts
beepticks dw 0 ; number of ticks for a BEEP
beepsleft db 0 ; number of beeps to output
cuckoo dw 0 ; number of cuckoos to output
cursor dw 0 ; Location of the cursor on
the screen
beept db 0 ; have-we-beeped flag
inbeep db 0 ; beep-in-progress flag
flash db 1 ; fla****ng colon flag
spkrstat db 0 ; old speaker status
video_****t dw ? ; Video status ****t - check
for scanning
numcol db ? ; number of columns
hh dw 0 ; hours
mm dw 0 ; minutes
sc dw 0 ; seconds
hh1 dw 0 ; 12-hour value for cuckoo
hhdiv dw 32771 ; hours divisor (65543/2)
mmdiv dw 546 ; minutes divisor (1092/2)
ssdiv dw 9 ; second divisor (18/2)
display dw (7020h) ; leading space
dw 5 dup(703ah) ; Initial value for the clock
dw 2 dup(7020h) ; Add 2 ' 's for am/pm.
day_of_wk dw 0 ; day of the week
month dw 0 ; month
day dw 0 ; day
chimon dw 1 ; flag for chime in use or not
clokon dw 1 ; flag for chime in use or not
Clock PROC NEAR ; The timer INT will now come
here
cmp CS:clokon,1 ; is this interrupt silent ?
jz NewInt ; no, go execute it
jmp dword ptr old_time_int ; silent, just execute old int
NewInt:
pushf ; First call old time interrupt to
update
count
call dword ptr old_time_int
call NeedBeep ; need to continue beep ?
dec CS:count500 ; should recalculate the
time ?
jnz Dont_Recalculate
push ax ; Save the registers - good
form
push cx
push di
push si
push ES
xor CS:flash,1 ; toggle the fla****ng colon
call Calc ; Recalculate the time
mov CS:count500,TICKS ; Reset Count500
;
;Dont_Recalculate:
;This is the routine for recalculating clock position when you switch
in
and
;out of different column modes
mov ax,0 ;move memory location for column
numbers
mov ES,ax ;into ES:di
mov ax,044ah ;
mov di,ax
mov ah,ES:[di] ;move number of columns into ah
sub ah,8 ; Move to eight places before edge
shl ah,1 ; Mult by two (char and attribute
bytes)
;end of clock position routine
assume ES:SCREEN ; Set up screen as the Extra Segment
mov cx,SCREEN
mov ES,cx
mov dx,video_****t ; This is the screen status
****t
mov byte ptr cursor,ah ; Move cursor to it's memory
location
mov di,cursor ; Set up cursor on screen as
destination
mov si,offset display ;v1.1
mov cx,16 ; To move char and attributes
Scan_Low:
mov ah,CS:[si] ; Move byte to be written into AH
mov ES:[di],ah ; Move to screen one byte at a time.
inc di ; Position to attribute byte
inc si ; on screen.
loop Scan_Low ; Go back foe next byte
pop ES ; Here are required pops to exit
pop si
pop di
pop cx
pop ax
Dont_Recalculate:
iret ; An interrupt needs an IRET
Clock ENDP
Calc PROC NEAR ; Here we recalculate the time and
store
it
push ax ; Pushes to save everything that
push bx ; gets destroyed
push cx
push dx
cmp CS:flash,1 ; do date or time?
jz Dtime ; TIME
mov bx,offset display
mov ax,CS:month
mov CS:[bx+0],ah ; Move first month digit into
display
mov CS:[bx+2],al ; Then the second digit
mov byte ptr CS:[bx+4],'-' ; a hyphen
mov ax,CS:day ; get day
mov CS:[bx+6],ah ; and move them into the
display
in memory
mov CS:[bx+8],al
mov byte ptr CS:[bx+10],' ' ; move space into display
mov ax,CS:day_of_wk
mov CS:[bx+12],ah ; move day of the week into
display
mov CS:[bx+14],al
jmp Restore
Dtime:
; note: Peter Norton p.223 explains that the time formula is more
precisely
; shown as:
; hh =3D clkcount / 65543
; mm =3D hh.remainder / 1092
; ss =3D mm.remainder / 18
;
; trouble is, the 65543 value won't work as a single-word divisor,
; so our trick is to divide the clock count and divisor values in
half,
; which should have no appreciable affect on the accuracy of the time.
xor ax,ax ; Set up for clock read.
INT 1Ah ; Read the clock.
mov bx,dx ; Save low(minutes) ****tion.
mov dx,cx ; Move high(hours) ****tion to AX.
mov ax,bx ; dx:ax =3D clock count
clc
rcr dx,1 ; div count by 2 so we can use a
rcr ax,1 ; single precision dividend
div CS:hhdiv ; compute hours
mov CS:hh,ax ; save it
mov ax,dx ; prepare remainder for minutes
xor dx,dx
div CS:mmdiv ; compute minutes
cmp ax,60 ; 60 minutes shows up sometimes
jl Mm_Ok ; mostly it doesn't
xor ax,ax ; but if it does, zero out the minutes
inc CS:hh ; and bump up the hour
Mm_Ok: mov CS:mm,ax ; save it
mov bx,offset display ;v1.1
mov byte ptr CS:[bx],' ' ; blank out first and last
positions
mov byte ptr CS:[bx+14],' '
mov ax,CS:hh
cmp ax,12 ; is it am or pm?
jl Am ; am
;Pm:
mov byte ptr CS:[bx+12],'p' ; Otherwise move 'P' into the
display.
sub ax,12 ; pm, subtract 12
jmp short Chek12 ; Continue.
Am: mov byte ptr CS:[bx+12],'a' ; Move an 'A' into the
display.
Chek12: or ax,ax ; Make zero hour...
jnz Am_Pm_Done
mov ax,12 ; ...a twelve
Am_Pm_Done:
mov CS:hh1,ax ; hour value for cuckoo
aam ; Convert AX to BCD - a nice
command
add ax,3030h ; Add '0' to both bytes in AX
to
make ascii
cmp ah,'0' ; Is the 1st digit '0'?
jne Dont_Edit ; Then don't blank the
character.
mov ah,' ' ; Otherwise, put a space in
AH.
Dont_Edit:
mov CS:[bx+2],ah ; Move first hours digit into
display
mov CS:[bx+4],al ; Then the second digit
;----------------------------------
mov byte ptr CS:[bx+6],':' ; in which case use a colon
mov ax,CS:mm ; get minutes
aam ; Again convert AX to Binary
Coded
Decimal
add ax,3030h ; Add to make two ASCII
characters
mov CS:[bx+8],ah ; and move them into the
display
in memory
mov CS:[bx+10],al
;---------routine for alarm chime goes
here------------------------------------
cmp CS:chimon,0 ; chimes off?
jz Restore ; yes, don't beep
cmp CS:inbeep,1 ; already in a beep loop?
jz Restore ; yes, don't be redundant
cmp ax,3030h ; on the hour (full cuckoo
routine)
jz Alarm3
cmp ax,3135h ; on the 1/4 hour (single
cuckoo)
jz Alarm2
cmp ax,3330h ; on the 1/2 hour (single
cuckoo)
jz Alarm2
cmp ax,3435h ; on the 3/4 hour (single
cuckoo)
jz Alarm2
mov CS:beept,0 ; we have not beeped
;---------------------------------------------------------------------------=
---
Restore: ; Restore registers
pop dx
pop cx
ImRet2: pop bx
ImRet1: pop ax
ImRet: ret
;---------------------------------------------------------------------------=
--
NeedBeep:
cmp CS:inbeep,1 ; are we beeping right now ?
jnz ImRet ; no, immediate return
dec CS:beepticks ; yes, done beeping?
jnz ImRet ; no, immediate return
push ax
mov al,CS:spkrstat ; yes, shut off speaker
out 61h,al
dec CS:beepsleft ; any more beeps waiting?
jz NoBeeps ; no, go home
cmp CS:beepsleft,1 ; how many await?
jnz Onward
call Pause
jmp ImRet1
Onward:
push bx
mov bx,TONE2 ; second tone in cuckoo
mov CS:beepticks,BEEPS2 ; second tone is longer than
first
tone
call Tone_a ; start it beeping
jmp ImRet2 ; go home
NoBeeps:
dec CS:cuckoo ; are there any more cuckoos?
jz No_Cuckoo ; no more cuckoos
push bx
mov bx,TONE1 ; beginning of next cuckoo
mov CS:beepsleft,3
call Tone ;start it beeping
jmp ImRet2
;---------------------------------------------------------------------------=
---
Alarm3: push ax ;save the register
mov ax,hh1 ;move hour value into ax
mov CS:cuckoo,ax ; hourly cuckoo - repeat for
number
of hours
pop
ax
mov bx,TONE1 ; send tone 1
mov CS:beepsleft,3
call Tone
jmp Restore
Alarm2: mov CS:cuckoo,1 ; only a single cuckoo for
quarter
hour
; intervals
mov bx,TONE1 ; send tone 2
mov CS:beepsleft,2
call Tone
jmp Restore
;---------------------------------------
No_Cuckoo:
mov CS:beept,1 ; we have beeped
mov CS:inbeep,0 ; and we're not in one any
more
jmp ImRet1
;---------------------------------------
Tone:
cmp CS:beept,1 ; do nothing if chime has been
beeped
jz NoTone ; earlier in this clock update
mov CS:beepticks,BEEPS1 ; this long on beeps
Tone_a:
MOV AL,0B6H ; else condition the timer
OUT 43H,AL
MOV AX,BX ; this is the freq
OUT 42H,AL
MOV AL,AH
OUT 42H,AL ; out you all go
IN AL,61H ; read spkr ****t
MOV CS:spkrstat,AL
OR AL,3
OUT 61H,AL ; send a beep
mov CS:inbeep,1
NoTone: ret
;--------------------------------------------------------
Pause:
mov CS:beepticks,BEEPS3
ret
;---------------------------------------------------------------------------=
---
Calc ENDP
Load_Clock PROC NEAR ; This procedure initializes
everything
assume DS:INTERRUPTS ; The Data Segment will be the
interrupt
area
; mov ax,INTERRUPTS
xor ax,ax ;0 v1.1
mov DS,ax
MOV SI,0081H ; addr of command line arguments
Next: MOV AL,CS:[SI] ; get command line char
CMP AL,0DH ; Return ends it.
JZ Again
CMP AL,'/' ; switch char
JZ GetSwitch ; see what it is
Next1: INC SI ; else point to next char
JMP Next ; and loop
GetSwitch:
inc si
mov al,CS:[si]
cmp al,'c' ; chime toggle switch
jnz Next1 ; wrong
switch
mov CS:togchim,1 ; toggle them chimes
jmp Next1 ; get next switch if there is one
Again: mov ax,CS:sig_vector ; get signature vector
cmp ax,5fh ; if less than 0x60
jg Vok
jmp No


|