کد:
ClockCGROUP GROUP VECTOR,CODESEG
VECTOR SEGMENT AT 0H
DB 6CH DUP(?) ;FILLER
TIME_LO DW ? ;DOS TIME
TIME_HI DW ? ;DOS TIME
VEC_IP DW ;CLOCK UPDATE VECTOR IP
VEC_CS DW ;CLOCK UPDATE VECTOR CS
VECTOR ENDSCODESEG SEGMENT PARA
ASSUME CS:CODESEG,DS:CGROUP
ORG 100H
CLK PROC FAR
JMP SETUP ;ATTACH TO DOS
INTRPT LABEL DWORD
INT_IP DW 0 ;OLD UPDATE VECTOR IP
INT_CS DW 0 ;OLD UPDATE VECROR CS
TICKS DW 0 ;TICK COUNTER
SCR_OFF DB 0,0 ;SCREEN OFFSET IN BUFFER
CRT_PORT DW 0 ;SCREEN STATUS PORT
flag db 0
TIME DB 8 DUP(':',0BH) ;TIME SAVE AREA
CLK_INT LABEL NEAR
PUSH AX ;SAVE REGISTERS
PUSH CX
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSHF ; AND FLAGS
CALL CS:[INTRPT] ;DO OLD UPDATE INTERRUPT
MOV CX,0040H ;GET SEGMENT OF DOS TABLE
MOV DS,CX ;PUT IN DS
MOV CX,CS:TICKS ;GET TICK COUNT
INC CX ;INCREMENT IT
CMP CX,20 ;01F4H ;HAS A MINUTE GONE BY?
JB NO_MINUTE ;NO, MOVE ON
CALL UPDATE ;YES, UPDATE CLOCK AND
MOV CX,0 ; RESET TICK COUNTER
NO_MINUTE:
MOV CS:TICKS,CX ;SAVE UPDATED TICK COUNT
MOV CX,0B000H ;GET VIDEO SEGMENT
MOV ES,CX ;PUT IN ES
MOV DX,CS:CRT_PORT ;GET CRT STATUS PORT ADDR
MOV DI,WORD PTR CS:SCR_OFF ;GET SCREEN BUFFER OFFSET
LEA SI,CS:TIME ;GET DOS TIME
MOV CX,16 ;SET UP TO MOVE 10 BYTES
CLI ;DISABLE OTHER INTERRUPTS
WAIT1: IN AL,DX ;READ CRT STATUS
TEST AL,1 ;CHECK FOR VERTICAL RETRACE
JNZ WAIT1 ;WAIT FOR RETRACE LOW
MOV AH,CS:[SI] ;GET FIRST BYTE TO MOVE
WAIT2: IN AL,DX ;GET CRT STATUS
TEST AL,1 ;CHECK FOR VERTICAL RETRACE
JZ WAIT2 ;WAIT FOR RETRACE HIGH
MOV ES:[DI],AH ;MOVE BYTE TO SCREEN
INC DI ;INCREMENT INDEX
INC SI
LOOP WAIT1 ;MOVE NEXT BYTE
STI ;ENABLE INTERRUPTS
POP ES ;RESTORE REGISTERS
POP DS
POP SI
POP DI
POP CX
POP AX
IRET ;RETURN FROM INTERRUPT
CLK ENDP
UPDATE PROC NEAR
PUSH AX ;SAVE REGISTERS
PUSH BX
PUSH CX
PUSH DX
PUSH DS
MOV AX,0040H ;GET ADDRESS OF DOS TABLE
MOV DS,AX ;PUT IN DS
MOV AX,TIME_HI ;GET HIGH BYTE OF DOS TIME
mov flag,0 ;am flag
HOUR: CMP AX,0CH ;CONVERT TO HOURS
JLE H1
mov flag,1 ;set to pm
SUB AX,0CH
JMP HOUR
H1: AAM ;CONVERT TO ASCII
ADD AX,3030H
LEA BX,CS:TIME ;GET ADDRESS OF TIME AREA
MOV CS:[BX],AH ;SAVE HOURS FIRST DIGIT
MOV CS:[BX+2],AL ;SAVE HOURS SECOND DIGIT
MOV AX,TIME_LO ;GET DOS TIME LOW BYTE
MOV CX,8H ;CONVERT TO MINUTES
SHR AX,CL
MOV DX,3CH
MUL DL
SHR AX,CL
AAM ;CONVERT TO ASCII
ADD AX,3030H
MOV CS:[BX+6],AH ;SAVE MINUTES FIRST DIGIT
MOV CS:[BX+8],AL ;SAVE MINUTES SECOND DIGIT
mov byte ptr cs:[bx+12],'a'
cmp flag,0 ;is it am?
jz goahead
mov byte ptr cs:[bx+12],'p'
goahead:
mov byte ptr cs:[bx+14],'m'
POP DS ;RESTORE REGISTERS
POP DX
POP CX
POP BX
POP AX
RET
UPDATE ENDP
SETUP: MOV AX,0 ;GET ADDRESS OF VECTOR TABLE
MOV DS,AX ;PUT IN DS
CLI ;DISABLE FURTHER INTERRUPTS
MOV AX,[VEC_IP] ;GET ADDRESS OF OLD UPDATE IP
MOV CS:[INT_IP],AX ;SAVE IT
MOV AX,[VEC_CS] ;GET ADDRESS OF OLD UPDATE CS
MOV CS:[INT_CS],AX ;SAVE IT
MOV VEC_IP,OFFSET CLK_INT ;PUT ADDRESS OF CLK IN VECTOR IP
MOV VEC_CS,CS ;PUT CS OF CLK IN VECTOR CS
STI ;ENABLE INTERRUPTS
MOV AH,0FH ;READ VIDEO STATUS
INT 10H
SUB AH,8 ;SUBTRACT 8 CHAR TIME FROM NCOLS
SHL AH,1 ;MULTIPLY BY 2 FOR ATTRIBUTE
MOV CS:SCR_OFF,AH ;SAVE SCREEN TIME LOCATION
MOV WORD PTR CS:CRT_PORT,03BAH ;SAVE MONO STATUS PORT ADDR
TEST AL,4 ;CHECK FOR COLOR MONITOR
JNZ MONO ;IF MONO, MOVE ON
ADD WORD PTR CS:SCR_OFF,8000H ;ADD COLOR OFFSET TO TIME OFFSET
MOV WORD PTR CS:CRT_PORT,03DAH ;SAVE COLOR STATUS PORT ADDR
MONO: CALL UPDATE ;DO FIRST UPDATE & PRINT TIME
MOV DX,OFFSET SETUP ;GET END ADDRESS OF NEW INTERRUPT
INT 27H ;TERMINATE AND REMAIN RESIDENT
DB 117 DUP(0) ;FILLER
CODESEG ENDS
END CLK