home *** CD-ROM | disk | FTP | other *** search
- ;------------------------------------------------------------------------
- ; source available from DAN OBRIEN upon request via message on GENE PLANTZ's
- ; PC-BBS in CHICAGO, IL.
- ;------------------------------------------------------------------------
- ; cgclock.asm - real time clock display for color/graphics
- ; display. adapted from clock.asm found on one of
- ; the PC-BBS in Chicago. Allows any color for time
- ; by patching color value using DEBUG. Look for
- ;
- ; "Color value of time display="
- ;
- ; and set byte follow "=" to BASIC color value.
- ; Currently set to YELLOW (color number is 14 decimal).
- ;
- ; Displays time in human form not computer, i.e.,
- ; 24 hour military time.
- ;
- ; To enable military (24 hour) time display patch
- ; using DEBUG the statement that says
- ;
- ; "Military time=N"
- ;
- ; from "N" to "Y".
- ;
- ; Also beeps the speaker every quarter hour.
- ;
- ; To disable beeping on the quarter hours patch
- ; using DEBUG the statement that says
- ;
- ; "Beep=Y"
- ;
- ; from "Y" to "N".
- ;
- ; Timer display is refreshed every N tics as defined
- ; by a patchable area using DEBUG. Look for
- ;
- ; "Timer tics before time display refresh="
- ;
- ; and the value after the "=" is binary 4. Patch to higher or
- ; lower value as you wish to lengthen or shorten interval
- ; between refreshes. Tics occur 18.5 times a second,
- ; and after 4 (default) the display is refreshed with the time.
- ; This keeps overhead of running cgclock to about 4 percent.
- ;
- ; To start cgclock just enter "cgclock".
- ; To toggle off and on enter "cgclock" repeatedly.
- ;
- ; NOTE:
- ; 1. Uses user timer exit int 1Ch for timer display
- ; 2. Defines int 60h to toggle time off and on.
- ; 3. Displays time without annoying "snow"!
- ; Technique from PC-Tech Journal Premier Issue.
- ; 4. Developed under DOS 2.0. Not tested under DOS 1.1
- ; but should work.
- ;
- ; adapted from clock.asm by DANIEL M. O'BRIEN - 9 July 83 (Version 1.0)
- ;
- ; 1) meaningful labels added
- ; 2) made to work on color/graphics
- ; 3) use user timer exit int 1ch instead of 08h directly - slows down
- ; disk drives, also allows BASIC to gain direct control of timer.
- ; And use int 60h instead of 44h (44h defined by DOS 2.0)!
- ; 4) allow patching of time display color using DEBUG (Version 1.1)
- ; 5) meaningful comments added
- ; 6) include salutation
- ;
- ; DMO - 10 July 83 (Version 1.2)
- ; 7) beep on quarter hour and allow patching off
- ; 8) 12 hour clock with AM and PM indicator and allow patch for military time
- ;
- ; DMO - 21 July 83 (Version 1.3)
- ; 9) keep counter and update screen only after specified tics count.
- ; currently set to 4 which yields an overhead of about 4 percent.
- ; if set to 1, i.e., update every clock tic, then cgclock has a
- ; overhead of about 20 percent.
- ;
- ; DMO - 31 July 83 (Version 1.4)
- ; 10) move some temporary data areas below init routine for less
- ; resident space requirements.
- ;
- ; DMO - 12 Sept 83 (Version 1.5)
- ; 11) try different algorithm to stuff display into memory to reduce
- ; possible interference with BASIC display to terminal
- ; 12) fix bug whereby BX was not being saved and restored when BEEP occured
- ; 13) fix bug whereby direction flag not set causing stray characters on
- ; display
- ; 14) speedup entry and exit when not time to display
- ;
- ; DMO - 29 Dec 83 (Version 1.6)
- ; 15) do not disable interrupts for beeper - just disable entry to cgclock
- ; 16) also use private stack area to prevent stack overflow
- ;
- ; FUTURE work
- ; 1) date
- ; 2) alarm clock
- ; 3) any suggestions?
- ;---------------------------------------------------------------
- ;
- port_b equ 61h ; 8255 port b addr
- timer equ 40h ; timer port address
-
- int segment at 0 ; segment 0 8088 interrupt vectors
- org 4*1ch
- timer_offset label word ; user timer exit for int 1ch
- org 4*1ch+2
- timer_segment label word
- org 4*60h
- toggle_timer_offset label word ; our int 60h timer toggle routine
- org 4*60h+2
- toggle_timer_segment label word
- int ends
- ;
- data segment at 40h ; BIOS data/work area
- org 65h
- video_display label byte ; display status byte
- org 6ch
- timer_low label word ; BIOS time counters
- org 6eh
- timer_high label word
- data ends
- ;
- display_segment segment at 0b80h ; color/graphics display memory
- display_segment ends
- ;
- cseg segment
- assume cs:cseg,ds:cseg
- org 100h ; .COM begin at 100h
- start:
- jmp initialize ; first time - go to our intitialization routine
-
- ; data poked into display memory
- tenhrs dw 0700h ; h
- onehrs dw 0700h ; h
- dw 073ah ; :
- tenmins dw 0700h ; m
- onemins dw 0700h ; m
- dw 073ah ; :
- tensecs dw 0700h ; s
- onesecs dw 0700h ; s
- am_pm_indicator dw 0720h ; a - am, p - pm
- time_length equ $-tenhrs
-
- timer_toggle db 0 ; timer toggle value
- beep_count db 0 ; number of quarter hour beeps
- need_beep db 0ffh ; set to ffh indicates need to beep
- tics db 0 ; tics before next display
- mil_flag db 0 ; military time indicator - N
- beep_flag db 0 ; beep on the quarter hours
- tics_before_display db 0 ; Tics before next display update
- save_stack_ss dw ? ; previous stack segment
- save_stack_sp dw ? ; previous stack pointer
-
- ;
- ; timer_interrupt - entered 18.5 times / sec from BIOS routine
- ; via int 1ch
- ;
- timer_interrupt label word
- jmp short timer_bypass ; replaced by "push ax push cx"
-
- cli ; no interrupts
- mov al,1
- add al,cs:tics ; bump tics
- cmp al,cs:tics_before_display
- mov cs:tics,al ; keep counter
- jb skip_maketime ;
-
- mov save_stack_ss,ss
- mov save_stack_sp,sp
- mov ax,cs
- mov ss,ax
- mov sp,offset stack_ptr
-
- mov ax,jmparound ;timer toggled off
- mov timer_interrupt,ax ;setup by-pass
-
- sti ; enable interrupts
-
- push bx
- push ds
- push es
- push si
- push di
- push dx
-
- call maketime ; go do time stuff
- mov cs:tics,1 ; start counting again
-
- pop dx
- pop di
- pop si
- pop es
- pop ds
- pop bx
-
- mov ss,save_stack_ss ; get back old stack
- mov sp,save_stack_sp ; segment and pointer
-
- mov word ptr timer_interrupt,5150h ; replace with "push ax push cx"
-
- skip_maketime:
- sti ; interrupts back on
- pop cx
- pop ax
- ;
- ; bypass jmp to here - when timer toggled off
- ;
- timer_bypass:
- db 0eah ; 'jmp far' - to any other 1ch timer routine
- jmpseg dw 0 ; filled in by initial to other int 1ch routine
- jmpoffset dw 0
-
- ;
- ; create time display and beep if necessary
- ;
- maketime:
- mov ax,0b800h ; set display segment address
- mov es,ax
- assume es:display_segment
- mov ax,40h ; set display status segment
- mov ds,ax
- assume ds:data
-
- mov al,video_display ; get display status byte
- cmp al,2dh ; 80 x 25 alpha b/w?
- je maketime_100 ; yes-continue
- cmp al,29h ; 80 x 25 alpha color?
- je maketime_100 ; yes-continue
- jmp early_exit ; else-get out
-
- maketime_100:
- mov si,timer_low ; get current timer values
- mov cx,timer_high
-
- mov ax,cs ; restore our data segment pointer
- mov ds,ax
- assume ds:cseg
-
- mov ax,cx ; make hrs
- cmp mil_flag,'Y' ; desire military time
- je maketime_200 ; yes-then bypass conversion to am/pm
-
- mov byte ptr am_pm_indicator,'a' ; no-then assume am
- cmp ax,24 ; 2400 hours?
- jne maketime_150 ; no-then with am/pm continue
- mov ax,0 ; make it 0000 hours
- jmp maketime_200 ; and continue
-
- maketime_150:
- cmp ax,12 ; after noon?
- jb maketime_200 ; no
- mov byte ptr am_pm_indicator,'p' ; mark pm
- je maketime_200 ; oops-exactly noon
- sub ax,12 ; else-just subtract out 12 hours
-
- maketime_200:
- aam ; make printable
- or ax,'00'
- cmp ah,'0' ; leading zero?
- jne maketime_225 ; no-then just continue
- mov ah,' ' ; else-suppress it
-
- maketime_225:
- mov byte ptr onehrs,al
- mov byte ptr tenhrs,ah
-
- mov ax,si ; make minutes
- mov dx,0
- mov cx,0fh
- mul cx
- mov cx,4002h
- div cx
- push ax
- aam
- or ax,'00'
- mov byte ptr onemins,al
- mov byte ptr tenmins,ah
-
- cmp beep_flag,'Y' ; do you want to beep the quarter hours?
- jne maketime_250 ; no-zero beep count and continue
-
- mov beep_count,1 ; just one beep
- ;stub mov beep_count,4 ; assume on the hour
- cmp ax,'00' ; on the hour?
- je maketime_300 ; yes-use count
- ;stub sub beep_count,1 ; dec for next interval
- cmp ax,'45' ; three-quarter hour?
- je maketime_300 ; yes-use count
- ;stub sub beep_count,1 ; dec for next interval
- cmp ax,'30' ; half hour?
- je maketime_300 ; yes-use count
- ;stub sub beep_count,1 ; dec for next interval
- cmp ax,'15' ; quarter hour?
- je maketime_300 ; yes-use count
-
- maketime_250:
- mov beep_count,0 ; assume no beeps required now
-
- maketime_300:
- pop ax ; make seconds
- mul cx
- mov cx,0fh
- div cx
- xchg ax,si
- sub ax,si
- mul cx
- mov cx,111h
- div cx
- aam
- or ax,'00'
- mov byte ptr onesecs,al
- mov byte ptr tensecs,ah
-
- mov si,offset tenhrs ; get start address of time
- mov di,((0*80)+71)*2 ; set display memory address - line 0
- mov cx,time_length ; #digits to move to display area
- mov dx,3dah ; io address of c/g status reg
-
- move_time:
- in al,dx ; get c/g status
- test al,01h ; is it low - horizontal retrace
- jnz move_time ; no-try again - not time yet
- move_time1:
- in al,dx ; get c/g status
- test al,01h ; is it high - horizontal retrace
- jz move_time1 ; no-try again - not time yet
- cld ; forward direction
- movsb ; yes-move a byte of time at a time
- loop move_time ; and loop till done
-
- ;move_time:
- ; in al,dx ; get c/g status
- ; test al,08h ; ok to write? - vertical retrace
- ; jz move_time ; no-try again - not time yet
- ; movsb ; yes-move a byte of time at a time
- ; loop move_time ; and loop till done
-
- mov cl,beep_count ; get count of consectitive beeps
- and cx,0ffh ; clear ch and test for no beeps
- jnz do_beep ; beep!
- mov need_beep,0ffh ; else-set need beep flag
- ; beep once per quarter hour interval
- jmp early_exit ; exit
-
- do_beep:
- cmp need_beep,0 ; do we really need beep?
- mov need_beep,0 ; don't need beep till next quarter
- je early_exit ; no-already beeped this quarter hour
-
- beep_loop:
- mov bl,1 ; beep speaker short beep
- call beep ; go beep
- loop beep_loop ; beep again
-
- early_exit:
- ret
- ;
- ; invoked by int 60H to toggle time display on/off
- ;
- toggle_my_timer:
- push ax
- push ds
- mov ax,cs
- mov ds,ax
- mov al,tics_before_display
- mov tics,al
- xor timer_toggle,0ffh ;toggle time on/off
- jz enable_timer ;branch-timer toggled on
-
- mov ax,jmparound ;timer toggled off
- mov timer_interrupt,ax ;setup by-pass
- pop ds
- pop ax
- iret
-
- enable_timer:
- mov word ptr timer_interrupt,5150h ; replace with "push ax push cx"
- pop ds
- pop ax
- iret
- ;
- jmparound dw 0 ; saved by initialization for by-pass
- ;
- ; beep - derived from BIOS listing Tech. Ref. A-18
- ;
- beep:
- push cx
- mov al,10110110b ; sel tim 2,lsb,msb,binary
- out timer+3,al ; write the timer mode reg
- mov ax,533h ; divisor for 1000 hz
- out timer+2,al ; write timer 2 cnt - lsb
- mov al,ah
- out timer+2,al ; write timer 2 cnt - msb
- in al,port_b ; get current setting of port
- mov ah,al ; save that setting
- or al,03 ; turn speaker on
- out port_b,al
-
- mov cx,03fffh ; set cnt to wait 125 ms
- g7: loop g7 ; delay before turning off
-
- dec bl ; delay cnt expired?
- jnz g7 ; no-continue beep spk
-
- mov al,ah ; recover value of port
- out port_b,al
- pop cx
- ret ; return to caller
-
- org $+64 ; our stack area
- stack_ptr equ $
-
- ;
- ; initialization routine - thrown away afterwards!
- ;
- initialize:
- jmp around_constants
-
- hello db "Color Graphics CLOCK (v1.6) by Daniel M. O'Brien (29 Dec 1983)"
- db 13,10,'$' ; my salutation - better than pat on the back!
-
- ; variables to allow DEBUG patching
-
- db 'Color value of time display='
- color db 14 ; Yellow for now
-
- db 'Military time='
- mil_flag1 db 'N' ; military time indicator - N
-
- db 'Beep='
- beep_flag1 db 'Y' ; beep on the quarter hours
-
- db 'Timer tics before time display refresh='
- tics_before_display1 db 4 ; about 4 times per second
-
- around_constants:
- push ds
-
- mov dx,offset hello ; say hello
- mov ah,9
- int 21h
-
- mov ax,timer_interrupt ; set up for bypass
- mov jmparound,ax
- mov timer_interrupt,5150h ; push ax push cx
- xor ax,ax ; point to interrupt segment
- assume ds:int
- mov ds,ax
- mov si,toggle_timer_offset ; get timer toggle int address
- mov cx,toggle_timer_segment
- mov ds,cx
- cmp word ptr [si],1e50h ; already set to "push ax push ds"?
- jnz install_timer ; no-branch and install this as driver
-
- pop ds
- int 60h ; else-toggle timer on/off and
- int 20h ; exit without remaining resident
-
- install_timer:
- xor ax,ax ; point to interrupt segment again
- mov ds,ax
- mov ax,timer_offset ; save current 1ch timer routine adrs
- mov dx,timer_segment
- pop ds
- mov jmpseg,ax ; need these for when we are done
- mov jmpoffset,dx
-
- mov al,beep_flag1
- mov beep_flag,al
-
- mov al,mil_flag1
- mov mil_flag,al
-
- mov al,tics_before_display1
- mov tics_before_display,al
- mov tics,al
-
- mov al,color ; set up desired time display color
- mov di,offset tenhrs+1 ; allows patching of color
- mov cx,time_length/2 ; number of attribute bytes
- cld ; march in a forward direction
-
- color_loop:
- stosb ; plug in color value into attribute field
- inc di ; skip time field
- loop color_loop ; continue
-
- mov dx,offset timer_interrupt ; set up our interrupt routine
- mov ax,251ch ; 25h = set up int, 1ch = user timer exit
- int 21h ; call dos
-
- mov dx,offset toggle_my_timer ; set up toggle display routine
- mov ax,2560h ; 25h = set up int, 60h = our toggle routine
- int 21h ; call dos
-
- mov dx,offset initialize+1 ; throw away init routine and
- int 27h ; exit, but stay resident
-
- cseg ends
-
- end start