374 lines
7.9 KiB
NASM
374 lines
7.9 KiB
NASM
|
cseg segment para public 'code'
|
||
|
org 100h
|
||
|
alarm proc far
|
||
|
|
||
|
; Memory-resident program to intercept the timer interrupt and display the
|
||
|
; system time in the upper right-hand corner of the display.
|
||
|
; This program is run as 'ALARM hh:mm x', where hh:mm is the alarm time and
|
||
|
; x is '-' to turn the display off. Any other value of x or no value will
|
||
|
; turn the clock on
|
||
|
|
||
|
intaddr equ 1ch*4 ; interrupt address
|
||
|
segaddr equ 62h*4 ; segment address of first copy
|
||
|
mfactor equ 17478 ; minute conversion factor * 16
|
||
|
whozat equ 1234h ; signature
|
||
|
color equ 14h ; color attribute
|
||
|
|
||
|
assume cs:cseg,ds:cseg,ss:nothing,es:nothing
|
||
|
jmp p150 ; start-up code
|
||
|
|
||
|
jumpval dd 0 ; address of prior interrupt
|
||
|
signature dw whozat ; program signature
|
||
|
state db 0 ; '-' = off, all else = on
|
||
|
wait dw 18 ; wait time - 1 second or 18 ticks
|
||
|
hour dw 0 ; hour of the day
|
||
|
atime dw 0ffffh ; minutes past midnite for alarm
|
||
|
acount dw 0 ; alarm beep counter - number of seconds (5)
|
||
|
atone db 5 ; alarm tone - may be from 1 to 255 - the
|
||
|
; higher the number, the lower the frequency
|
||
|
aleng dw 8080h ; alarm length (loop count) may be from 1-FFFF
|
||
|
|
||
|
dhours dw 0 ; display hours
|
||
|
db ':'
|
||
|
dmins dw 0 ; display minutes
|
||
|
db ':'
|
||
|
dsecs dw 0 ; display seconds
|
||
|
db '-'
|
||
|
ampm db 0 ; 'A' or 'P' for am or pm
|
||
|
db 'm'
|
||
|
|
||
|
tstack db 16 dup('stack ') ; temporary stack
|
||
|
estack db 0 ; end of stack
|
||
|
holdsp dw 0 ; original sp
|
||
|
holdss dw 0 ; original ss
|
||
|
|
||
|
p000: ; interrupt code
|
||
|
push ax ; save registers
|
||
|
push ds
|
||
|
pushf
|
||
|
|
||
|
push cs
|
||
|
pop ds ; make ds=cs
|
||
|
mov ax,wait ; check wait time
|
||
|
dec ax ; zero?
|
||
|
jz p010 ; yes - 1 second has elapsed
|
||
|
mov wait,ax ; not this time
|
||
|
jmp p080 ; return
|
||
|
|
||
|
p010: cli ; disable interrupts
|
||
|
mov ax,ss ; save stack
|
||
|
mov holdss,ax
|
||
|
mov holdsp,sp
|
||
|
mov ax,ds
|
||
|
mov ss,ax ; point to internal stack
|
||
|
mov sp,offset estack
|
||
|
sti ; allow interrupts
|
||
|
|
||
|
push bx ; save other registers
|
||
|
push cx
|
||
|
push dx
|
||
|
push es
|
||
|
push si
|
||
|
push di
|
||
|
push bp
|
||
|
|
||
|
mov ax,18 ; reset wait time
|
||
|
mov wait,ax
|
||
|
|
||
|
mov al,state ; are we disabled?
|
||
|
cmp al,'-'
|
||
|
jnz p015 ; no
|
||
|
jmp p070
|
||
|
|
||
|
p015: mov ah,0 ; read time
|
||
|
int 1ah ; get time of day
|
||
|
mov ax,dx ; low part
|
||
|
mov dx,cx ; high part
|
||
|
mov cl,4
|
||
|
shl dx,cl ; multiply by 16
|
||
|
mov bx,ax
|
||
|
mov cl,12
|
||
|
shr bx,cl ; isolate top 4 bits of ax
|
||
|
add dx,bx ; now in upper
|
||
|
mov cl,4
|
||
|
shl ax,cl ; multiply by 16
|
||
|
mov bx,mfactor ; compute minutes
|
||
|
div bx ; minutes in ax, remainder in dx
|
||
|
cmp ax,atime ; time to sound the alarm?
|
||
|
jnz p020 ; no
|
||
|
call p100 ; yes - beep the speaker twice
|
||
|
push ax
|
||
|
mov ax,acount ; get beep count
|
||
|
dec ax ; down by 1
|
||
|
mov acount,ax ; save beep count
|
||
|
cmp ax,0 ; is it zero?
|
||
|
jnz p018 ; no - keep alarm on
|
||
|
mov ax,0ffffh ; turn off alarm
|
||
|
mov atime,ax
|
||
|
p018: pop ax
|
||
|
|
||
|
p020: mov dsecs,dx ; save remainder
|
||
|
mov bx,60 ; compute hours
|
||
|
xor dx,dx ; zero it
|
||
|
div bx ; hours in ax, minutes in dx
|
||
|
mov dmins,dx ; save minutes
|
||
|
|
||
|
cmp ax,0 ; midnight?
|
||
|
jnz p030 ; no
|
||
|
mov ax,12 ; yes
|
||
|
jmp p040a ; set am
|
||
|
|
||
|
p030: cmp ax,12 ; before noon?
|
||
|
jb p040a ; yes - set am
|
||
|
jz p040p ; noon - set pm
|
||
|
sub ax,12 ; convert the rest
|
||
|
p040p: mov bl,'p'
|
||
|
jmp p040x
|
||
|
|
||
|
p040a: mov bl,'a'
|
||
|
|
||
|
p040x: mov ampm,bl
|
||
|
aam ; fix up hour
|
||
|
cmp ax,hour ; top of the hour?
|
||
|
jz p060 ; no
|
||
|
|
||
|
mov hour,ax
|
||
|
call p120 ; beep the speaker once
|
||
|
|
||
|
p060: add ax,3030h ; convert hours to ascii
|
||
|
xchg ah,al
|
||
|
mov dhours,ax
|
||
|
|
||
|
mov ax,dmins ; get minutes
|
||
|
aam
|
||
|
add ax,3030h ; convert to ascii
|
||
|
xchg ah,al
|
||
|
mov dmins,ax
|
||
|
|
||
|
mov ax,dsecs ; get seconds (remainder)
|
||
|
xor dx,dx
|
||
|
mov bx,60
|
||
|
mul bx
|
||
|
mov bx,mfactor
|
||
|
div bx ; seconds in ax
|
||
|
aam
|
||
|
add ax,3030h
|
||
|
xchg ah,al
|
||
|
mov dsecs,ax
|
||
|
|
||
|
xor ax,ax ; check monitor type
|
||
|
mov es,ax
|
||
|
mov ax,es:[410h] ; get config byte
|
||
|
and al,30h ; isolate monitor type
|
||
|
cmp al,30h ; color?
|
||
|
mov ax,0b000h ; assume mono
|
||
|
jz p061 ; its mono
|
||
|
|
||
|
mov ax,0b800h ; color screen address
|
||
|
|
||
|
p061: mov dx,es:[463h] ; point to 6845 base port
|
||
|
add dx,6 ; point to status port
|
||
|
|
||
|
mov es,ax ; point to monitor
|
||
|
mov bh,color ; color in bh
|
||
|
mov si,offset dhours ; point to time
|
||
|
mov di,138 ; row 1, col 69
|
||
|
cld
|
||
|
mov cx,11 ; loop count
|
||
|
|
||
|
p062: mov bl,[si] ; get next character
|
||
|
|
||
|
p063: in al,dx ; get crt status
|
||
|
test al,1 ; is it low?
|
||
|
jnz p063 ; no - wait
|
||
|
cli ; no interrupts
|
||
|
|
||
|
p064: in al,dx ; get crt status
|
||
|
test al,1 ; is it high?
|
||
|
jz p064 ; no - wait
|
||
|
|
||
|
mov ax,bx ; move color & character
|
||
|
stosw ; move color & character again
|
||
|
sti ; interrupts back on
|
||
|
inc si ; point to next character
|
||
|
loop p062 ; done?
|
||
|
|
||
|
p070: pop bp ; restore registers
|
||
|
pop di
|
||
|
pop si
|
||
|
pop es
|
||
|
pop dx
|
||
|
pop cx
|
||
|
pop bx
|
||
|
cli ; no interrupts
|
||
|
mov ax,holdss
|
||
|
mov ss,ax
|
||
|
mov sp,holdsp
|
||
|
sti ; allow interrupts
|
||
|
|
||
|
p080: popf
|
||
|
pop ds
|
||
|
pop ax
|
||
|
jmp cs:[jumpval]
|
||
|
|
||
|
p100 proc near ; beep the speaker twice
|
||
|
call p120
|
||
|
push cx
|
||
|
mov cx,20000
|
||
|
p105: loop p105 ; wait around
|
||
|
pop cx
|
||
|
call p120
|
||
|
push cx
|
||
|
mov cx,20000
|
||
|
p106: loop p106 ; wait around
|
||
|
pop cx
|
||
|
call p120
|
||
|
ret
|
||
|
p100 endp
|
||
|
|
||
|
p120 proc near ; beep the speaker once
|
||
|
push ax
|
||
|
push cx
|
||
|
mov al,182
|
||
|
out 43h,al ; setup for sound
|
||
|
mov al,0
|
||
|
out 42h,al ; low part
|
||
|
mov al,atone ; get alarm tone
|
||
|
out 42h,al ; high part
|
||
|
in al,61h
|
||
|
push ax ; save port value
|
||
|
or al,3
|
||
|
out 61h,al ; turn speaker on
|
||
|
mov cx,aleng ; get loop count
|
||
|
p125: loop p125 ; wait around
|
||
|
pop ax ; restore original port value
|
||
|
out 61h,al ; turn speaker off
|
||
|
pop cx
|
||
|
pop ax
|
||
|
ret
|
||
|
p120 endp
|
||
|
|
||
|
p150: ; start of transient code
|
||
|
mov dx,offset copyr
|
||
|
call p220 ; print copyright
|
||
|
mov ax,0
|
||
|
mov es,ax ; segment 0
|
||
|
mov di,segaddr+2 ; this program's prior location
|
||
|
mov ax,es:[di] ; get prior code segment
|
||
|
mov es,ax ; point to prior program segment
|
||
|
mov di,offset signature
|
||
|
mov cx,es:[di] ; is it this program?
|
||
|
cmp cx,whozat
|
||
|
jnz p160 ; no - install it
|
||
|
call p200 ; set state & alarm
|
||
|
int 20h ; terminate
|
||
|
|
||
|
p160: mov di,segaddr+2 ; point to int 62h
|
||
|
mov ax,0
|
||
|
mov es,ax ; segment 0
|
||
|
mov ax,ds ; get current ds
|
||
|
mov es:[di],ax ; set int 62h
|
||
|
mov si,offset jumpval
|
||
|
mov di,intaddr ; point to timer interrupt
|
||
|
mov bx,es:[di] ; get timer ip
|
||
|
mov ax,es:[di+2] ; and cs
|
||
|
mov [si],bx ; save prior ip
|
||
|
mov [si+2],ax ; and cs
|
||
|
mov bx,offset p000
|
||
|
mov ax,ds
|
||
|
cli ; clear interrupts
|
||
|
mov es:[di],bx ; set new timer interrupt
|
||
|
mov es:[di+2],ax
|
||
|
sti ; set interrupts
|
||
|
push ds
|
||
|
pop es
|
||
|
call p200 ; set state & alarm
|
||
|
mov dx,offset p150 ; last byte of resident portion
|
||
|
inc dx
|
||
|
int 27h ; terminate
|
||
|
|
||
|
p200 proc near ; set state & alarm
|
||
|
mov si,80h ; point to command line
|
||
|
mov ax,0
|
||
|
mov di,0ffffh ; init hours
|
||
|
mov bh,0
|
||
|
mov ch,0
|
||
|
mov dh,0 ; : counter
|
||
|
mov es:[state],bh ; turn clock on
|
||
|
mov cl,[si] ; get length
|
||
|
jcxz p210 ; it's zero
|
||
|
|
||
|
p203: inc si ; point to next char
|
||
|
mov bl,[si] ; get it
|
||
|
cmp bl,'-' ; is it a minus?
|
||
|
jnz p204 ; no
|
||
|
mov es:[state],bl ; turn clock off
|
||
|
push dx
|
||
|
mov dx,offset msg3 ; print msg
|
||
|
call p220
|
||
|
pop dx
|
||
|
jmp p206
|
||
|
|
||
|
p204: cmp dh,2 ; seen 2nd colon?
|
||
|
jz p206 ; yes - ignore seconds
|
||
|
cmp bl,':' ; colon?
|
||
|
jnz p205 ; no
|
||
|
inc dh
|
||
|
cmp dh,2 ; second colon?
|
||
|
jz p206 ; yes - ignore seconds
|
||
|
push cx
|
||
|
push dx
|
||
|
mov cx,60
|
||
|
mul cx ; multiply current ax by 60
|
||
|
pop dx
|
||
|
pop cx
|
||
|
mov di,ax ; save hours
|
||
|
mov ax,0
|
||
|
jmp p206
|
||
|
p205: cmp bl,'0'
|
||
|
jb p206 ; too low
|
||
|
cmp bl,'9'
|
||
|
ja p206 ; too high - can be a problem
|
||
|
sub bl,'0' ; convert it to binary
|
||
|
push cx
|
||
|
push dx
|
||
|
mov cx,10
|
||
|
mul cx ; multiply current value by 10
|
||
|
add ax,bx ; and add latest digit
|
||
|
pop dx
|
||
|
pop cx
|
||
|
p206: loop p203 ; done yet?
|
||
|
cmp di,0ffffh ; any time to set?
|
||
|
jz p210 ; no
|
||
|
add ax,di ; add hours
|
||
|
cmp ax,24*60
|
||
|
jb p209 ; ok
|
||
|
mov dx,offset msg1 ; print error message
|
||
|
call p220
|
||
|
jmp p210
|
||
|
|
||
|
p209: mov es:[atime],ax ; save minutes past midnight
|
||
|
mov ax,5
|
||
|
mov es:[acount],ax ; set alarm count
|
||
|
mov dx,offset msg2 ; print set msg
|
||
|
call p220
|
||
|
p210: ret
|
||
|
p200 endp
|
||
|
|
||
|
p220 proc near ; print message
|
||
|
push ax
|
||
|
mov ah,9
|
||
|
int 21h
|
||
|
pop ax
|
||
|
ret
|
||
|
p220 endp
|
||
|
|
||
|
copyr db 'Alarm - Clock',10,13,'$'
|
||
|
msg1 db 'Invalid time - must be from 00:00 to 23:59',10,13,'$'
|
||
|
msg2 db 'Resetting alarm time',10,13,'$'
|
||
|
msg3 db 'Turning clock display off',10,13,'$'
|
||
|
|
||
|
alarm endp
|
||
|
cseg ends
|
||
|
end alarm
|