Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Make a TSR

9 views
Skip to first unread message

almas

unread,
May 11, 2008, 1:32:23 PM5/11/08
to
Hi everybody.
I found a file : display time....
i modify it, the aim make a noise, or a red screen

In version "No TSR" it is ok, but computer must wait.
In version TSR, it is not ok.
I try on cession DOS of Windows XP

Below, the code i used
If somebody have an idea to make it fonctionnal

Best regards
Almas

Note : in UPPER CASES the original code
in lower cases, at left of screen, my lines

; Example, i type "time 11:10:45" then file 1111
; 15 seconds after, i would have a red screen !

Time SEGMENT
ORG 100h
ASSUME CS:Time,DS:Time

Start: JMP short Init

MoveIt: PUSH DS
PUSH ES
PUSH SI
PUSH DI
MOV SI,CS
MOV DS,SI
MOV ES,SI
MOV SI,(OFFSET NewInt1C) + 2 + 5
XOR DI,DI
CLD
MOV CX,Attente-(OFFSET NewInt1C)
REP MOVSB
MOV AX,251Ch
XOR DX,DX
INT 21h
POP DI
POP SI
POP ES
POP DS

NewInt1C PROC
DEC BYTE PTR CS:Attente
JZ MoveIt

PUSH AX
PUSH BX
PUSH CX
PUSH DX ; lors de l'int 1A, DL = DaylightBROL ..=> DL= buffer
PUSH ES
PUSH DI

CLD ; on affiche par addr video croissante (cnf CST)
MOV ES,AX

MOV AH,2
INT 1Ah ; get RTC value (HH-MM-SS in BCD !!!)
MOV BX,CX ; CX = count

MOV AL,BH ; heures
MOV CL,4 ; attention : il est utilise 3 fois !!!
SHR AL,CL ; clear lower nibble
OR AL,30h
mov ah,al
MOV AL,BH
AND AL,0Fh ; keep lower nibble
OR AL,30h
cmp ax, [offset heure]
jne again


MOV AL,BL ; minutes
SHR AL,CL
OR AL,30h
mov ah,al ;
MOV AL,BL
AND AL,0Fh
OR AL,30h
cmp ax, [offset minute]
jne again
mov ax,1000h
mov bx,0400h ; make red back ground
int 10h

again:
POP DI
POP ES
POP DX
POP CX
POP BX
POP AX

DB 0EAh ; opcode d'un jump far,direction l'ancien gestionnaire
Int1COfs DW ?
Int1CSeg DW ?
heure dw: ,0 ; hour
minute dw: ,0

NewInt1C ENDP

Attente DB 5 ; 5/18 sec d'attente !!! wait 1/4 of second
; hey DOS , cut here !!!

Init:
mov si,82h ; suppose i type " file.com 1111 " (hour=11 minute=11)
lodsw
mov [offset heure], ax
lodsw
mov [offset minute], ax

CLI ; let me work
MOV AX,351Ch
INT 21h ; get int 1C vector (timer)
MOV Int1COfs,BX
MOV Int1CSeg,ES

MOV AX,251Ch
MOV DX,OFFSET NewInt1C
INT 21h ; timer

PUSH CS
POP ES
MOV ES,WORD PTR ES:2Ch ; seg de l'envir contenu dans PSP
MOV AH,49h
INT 21h ; free environnement memory !!!

STI ;
MOV AX,3100h
lea dx, init
shr dx, 4
inc dx ; MOV DX,8 ; Cut PSP !!!
INT 21h ; rester resident
; Copyright DB 13,10,'Time! 3.4 - Coded By Sam In 1994 - The Flamoots $'
Time ENDS
END Start


Rod Pemberton

unread,
May 11, 2008, 1:24:02 PM5/11/08
to
"almas" <al...@naburo.com> wrote in message
news:482722f9$0$854$ba4a...@news.orange.fr...

> Hi everybody.
> I found a file : display time....
> i modify it, the aim make a noise, or a red screen
>
> In version "No TSR" it is ok, but computer must wait.
> In version TSR, it is not ok.

(I added comp.os.msdos.programmer in case someone there wants to help with
your TSR.)

Ben Lunt's TSR demo:
http://www.frontiernet.net/~fys/tsrdemo.htm

> I try on cession DOS of Windows XP

TSR under XP?. DOS under XP doesn't work quite correctly.

E.g., one issue with XP is that it doesn't update BIOS variables unless a
BIOS call is made:
http://groups.google.com/group/comp.os.msdos.djgpp/msg/67916cf4c1c73b7e?hl=en
http://groups.google.com/group/comp.os.msdos.djgpp/msg/30ac39382eb3560e?hl=en

<Almas' TSR code snipped. Can be read here.>
http://groups.google.com/group/alt.lang.asm/msg/9de6cb772bb707ba


Rod Pemberton

Benjamin David Lunt

unread,
May 11, 2008, 3:18:11 PM5/11/08
to

"Rod Pemberton" <do_no...@nohavenot.cmm> wrote in message
news:g079v9$uib$1...@aioe.org...

>
> TSR under XP?. DOS under XP doesn't work quite correctly.
>
> E.g., one issue with XP is that it doesn't update BIOS variables unless a
> BIOS call is made:
> http://groups.google.com/group/comp.os.msdos.djgpp/msg/67916cf4c1c73b7e?hl=en
> http://groups.google.com/group/comp.os.msdos.djgpp/msg/30ac39382eb3560e?hl=en
>

Hi Rod,

I threw together list little code snippet to see for myself. It seems
to update the timer tick just fine. It could be that WinXP emulates
the write to video memory by calling the BIOS print char service call.
I have WinXP SP2 [version 5.1.2600 is displayed at DOS prompt]

; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; assemble using NBASM (http://www.frontiernet.net/~fys/newbasic.htm)
.model tiny
.code
.386

org 100h

xor ax,ax
mov es,ax
mov si,046Ch


; depending on you CPU speed, adjust this value. It
; is simply a delay to end the program so we don't call
; a BIOS routine to check for keypress or something.
mov ecx,400000
main_loop: mov ax,es:[si]
call prthex
dec ecx
jnz main_loop

.exit

prthex proc near uses ax cx dx es di

mov cx,0B800h
mov es,cx
xor di,di

mov cx,04
PLoop: rol ax,04 ;
push ax ;
and al,0Fh ;
daa ;
add al,0F0h ;
adc al,40h ;

mov ah,07h
stosw

pop ax ;
loop PLoop ;
ret
prthex endp

.end
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Rod Pemberton

unread,
May 14, 2008, 3:39:18 PM5/14/08
to
"Benjamin David Lunt" <zf...@frontiernet.net> wrote in message
news:HFHVj.53628$kl6....@fe103.usenetserver.com...

> "Rod Pemberton" <do_no...@nohavenot.cmm> wrote in message
> news:g079v9$uib$1...@aioe.org...
> >
> > TSR under XP?. DOS under XP doesn't work quite correctly.
> >
> > E.g., one issue with XP is that it doesn't update BIOS variables unless
a
> > BIOS call is made:
> >
http://groups.google.com/group/comp.os.msdos.djgpp/msg/67916cf4c1c73b7e?hl=en
> >
http://groups.google.com/group/comp.os.msdos.djgpp/msg/30ac39382eb3560e?hl=en
> >
>
> I threw together list little code snippet to see for myself. It seems
> to update the timer tick just fine. It could be that WinXP emulates
> the write to video memory by calling the BIOS print char service call.
> I have WinXP SP2 [version 5.1.2600 is displayed at DOS prompt]

Thanks.

Now I'm wondering if the error he found is/was in DJGPP. Anyway, I'll stop
passing that information along assuming that whatever the problem was has
been fixed or was erroneous.

So, you tried and fixed Almas' TSR too? :-)


Rod Pemberton

Benjamin David Lunt

unread,
May 15, 2008, 11:23:48 AM5/15/08
to

"Rod Pemberton" <do_no...@nohavenot.cmm> wrote in message
news:g0ff0n$d59$1...@localhost.localdomain...

> "Benjamin David Lunt" <zf...@frontiernet.net> wrote in message
> news:HFHVj.53628$kl6....@fe103.usenetserver.com...
>>
>> I threw together list little code snippet to see for myself. It seems
>> to update the timer tick just fine. It could be that WinXP emulates
>> the write to video memory by calling the BIOS print char service call.
>> I have WinXP SP2 [version 5.1.2600 is displayed at DOS prompt]
>
> Thanks.
>
> Now I'm wondering if the error he found is/was in DJGPP. Anyway, I'll
> stop
> passing that information along assuming that whatever the problem was has
> been fixed or was erroneous.
>
> So, you tried and fixed Almas' TSR too? :-)

No. I didn't look at the code. I was just interested in the
timer tick. I thought for sure that WinXP would keep it tick'n
like it should.

Ben


Viel Spass

unread,
May 17, 2008, 9:07:01 AM5/17/08
to
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,'º' ;and write a 'º'
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,'º' ;and write a 'º'
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 = 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 = row, AH = 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 'Ø ÷÷÷÷÷÷ Ø Oil I Maintenance Services A. Kennedy 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 @ 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 ®cuckoo¯. 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 = 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 ; flashing colon flag
spkrstat db 0 ; old speaker status
video_port dw ? ; Video status port - 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 flashing 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_port ; This is the screen status
port
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 = clkcount / 65543
; mm = hh.remainder / 1092
; ss = 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) portion.
mov dx,cx ; Move high(hours) portion to AX.
mov ax,bx ; dx:ax = 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 port
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

Frank Kotler

unread,
May 17, 2008, 3:47:38 PM5/17/08
to
Viel Spass wrote:

...


> ;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)

...

Hi Andy,

That's the most convoluted "display BCD" code I've ever seen! I like
this one:

; From: qscgz at aol dot com (QSCGZ)
; display the time , 24 bytes
; nasm -f bin -o tinyclok.com tinyclok.asm

org 0100h

segment .text
mov ah,2
int 1ah ; time in BCD , dl=0
push cx
push dx
pop eax
m1:
mov al,163
sub dl,160 ; gives c,c,nc,c,c,nc,c,nc+z
ja $+3 ; h h : m m : s s
rol eax,4
int 29h
jne m1
ret
;------------------

That doesn't solve the "Make a TSR" question. Oh, and a86 won't assemble
it. Lemmee see...

mov ah,2
int 1ah ; time in BCD , dl=0
push cx
push dx
db 66h
pop ax
m1:
mov al,163
sub dl,160 ; gives c,c,nc,c,c,nc,c,nc+z
ja $+3 ; h h : m m : s s
db 66h
rol ax,4
int 29h
jne m1
ret
;------------------

I think a86'll assemble that (untested). I don't imagine int 29h is a
good idea in a TSR. If es:di were set to B800:<(row * 80 + column) * 2>
in advance...

stosb
mov byte [es:di], 7 ; or other color
lea di, [di + 1] ; so as not to mess with flags
jne m1

should replace the int 29h (untested). Save regs around it, and it ought
to pretty much be your ISR... Dunno if it'll work under XP, though...

No need to get *that* obsessive - any "print hex" routine should display
BCD correctly. Painfully converting BCD to binary, and then back to
decimal... looks like something a compiler would generate! :)

(Project: a countdown timer showing days/hours/minutes/seconds until 12
noon EST, 1/20/09)

Best,
Frank

Evenbit

unread,
May 17, 2008, 4:11:22 PM5/17/08
to
On May 17, 3:47 pm, Frank Kotler <fbkot...@verizon.net> wrote:
>
> (Project: a countdown timer showing days/hours/minutes/seconds until 12
> noon EST, 1/20/09)
>

The assasination of Clintobama?? :)

My local Mickey-Dees is selling McBush burgers...

Nathan.

Rod Pemberton

unread,
May 17, 2008, 5:29:46 PM5/17/08
to
"Frank Kotler" <fbko...@verizon.net> wrote in message
news:uDGXj.758$kZ1.214@trndny02...

> (Project: a countdown timer showing days/hours/minutes/seconds until 12
> noon EST, 1/20/09)
>

Wouldn't 12/21/12 be more useful?


RP

0 new messages