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.
CSEG segment para Public ' code '
Org 100h
Alarm proc Far
; Memory-resident to intercept the timer interrupt and display the
; System time in the upper right-hand corner of the display.
; This are 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 would
; Turn the clock on
INTADDR equ 1ch*4; Interrupt Address
SEGADDR equ 62h*4; Segment address of the
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, any else = on
Wait DW 18; Wait time-1 second or 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 is from 1 to 255-the
; Higher the number, the lower the frequency
Aleng DW 8080h; Alarm Length (loop count) May is 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 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 the 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 is 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