home *** CD-ROM | disk | FTP | other *** search
/ The CIA World Factbook 1992 / k3bimage.iso / sel / 12 / 0097 / cgclock.asm next >
Encoding:
Assembly Source File  |  1991-12-02  |  13.4 KB  |  501 lines

  1. ;------------------------------------------------------------------------
  2. ; source available from DAN OBRIEN upon request via message on GENE PLANTZ's
  3. ; PC-BBS in CHICAGO, IL.
  4. ;------------------------------------------------------------------------
  5. ; cgclock.asm - real time clock display for color/graphics
  6. ;        display. adapted from clock.asm found on one of
  7. ;        the PC-BBS in Chicago. Allows any color for time
  8. ;        by patching color value using DEBUG. Look for
  9. ;
  10. ;              "Color value of time display="
  11. ;
  12. ;        and set byte follow "=" to BASIC color value.
  13. ;        Currently set to YELLOW (color number is 14 decimal).
  14. ;
  15. ;        Displays time in human form not computer, i.e.,
  16. ;        24 hour military time.
  17. ;
  18. ;        To enable military (24 hour) time display patch
  19. ;        using DEBUG the statement that says
  20. ;
  21. ;                 "Military time=N"
  22. ;
  23. ;        from "N" to "Y".
  24. ;
  25. ;        Also beeps the speaker every quarter hour.
  26. ;
  27. ;        To disable beeping on the quarter hours patch
  28. ;        using DEBUG the statement that says
  29. ;
  30. ;                 "Beep=Y"
  31. ;
  32. ;        from "Y" to "N".
  33. ;
  34. ;        Timer display is refreshed every N tics as defined
  35. ;        by a patchable area using DEBUG. Look for
  36. ;
  37. ;              "Timer tics before time display refresh="
  38. ;
  39. ;        and the value after the "=" is binary 4. Patch to higher or
  40. ;        lower value as you wish to lengthen or shorten interval
  41. ;        between refreshes. Tics occur 18.5 times a second,
  42. ;        and after 4 (default) the display is refreshed with the time.
  43. ;        This keeps overhead of running cgclock to about 4 percent.
  44. ;
  45. ;        To start cgclock just enter "cgclock".
  46. ;        To toggle off and on enter "cgclock" repeatedly.
  47. ;
  48. ;    NOTE:
  49. ;        1. Uses user timer exit int 1Ch for timer display
  50. ;        2. Defines int 60h to toggle time off and on.
  51. ;        3. Displays time without annoying "snow"!
  52. ;            Technique from PC-Tech Journal Premier Issue.
  53. ;        4. Developed under DOS 2.0. Not tested under DOS 1.1
  54. ;            but should work.
  55. ;
  56. ; adapted from clock.asm by DANIEL M. O'BRIEN - 9 July 83 (Version 1.0)
  57. ;
  58. ; 1) meaningful labels added
  59. ; 2) made to work on color/graphics
  60. ; 3) use user timer exit int 1ch instead of 08h directly - slows down
  61. ;    disk drives, also allows BASIC to gain direct control of timer.
  62. ;    And use int 60h instead of 44h (44h defined by DOS 2.0)!
  63. ; 4) allow patching of time display color using DEBUG (Version 1.1)
  64. ; 5) meaningful comments added
  65. ; 6) include salutation
  66. ;
  67. ; DMO - 10 July 83 (Version 1.2)
  68. ; 7) beep on quarter hour and allow patching off
  69. ; 8) 12 hour clock with AM and PM indicator and allow patch for military time
  70. ;
  71. ; DMO - 21 July 83 (Version 1.3)
  72. ; 9) keep counter and update screen only after specified tics count.
  73. ;    currently set to 4 which yields an overhead of about 4 percent.
  74. ;    if set to 1, i.e., update every clock tic, then cgclock has a
  75. ;    overhead of about 20 percent.
  76. ;
  77. ; DMO - 31 July 83 (Version 1.4)
  78. ; 10) move some temporary data areas below init routine for less
  79. ;     resident space requirements.
  80. ;
  81. ; DMO - 12 Sept 83 (Version 1.5)
  82. ; 11) try different algorithm to stuff display into memory to reduce
  83. ;     possible interference with BASIC display to terminal
  84. ; 12) fix bug whereby BX was not being saved and restored when BEEP occured
  85. ; 13) fix bug whereby direction flag not set causing stray characters on
  86. ;     display
  87. ; 14) speedup entry and exit when not time to display
  88. ;
  89. ; DMO - 29 Dec 83 (Version 1.6)
  90. ; 15) do not disable interrupts for beeper - just disable entry to cgclock
  91. ; 16) also use private stack area to prevent stack overflow
  92. ;
  93. ; FUTURE work
  94. ; 1) date
  95. ; 2) alarm clock
  96. ; 3) any suggestions?
  97. ;---------------------------------------------------------------
  98. ;
  99. port_b    equ    61h        ; 8255 port b addr
  100. timer    equ    40h        ; timer port address
  101.  
  102. int    segment at 0        ; segment 0 8088 interrupt vectors
  103.     org    4*1ch
  104. timer_offset    label    word    ; user timer exit for int 1ch
  105.     org    4*1ch+2
  106. timer_segment    label    word
  107.     org    4*60h
  108. toggle_timer_offset    label    word    ; our int 60h timer toggle routine
  109.     org    4*60h+2
  110. toggle_timer_segment    label    word
  111. int    ends
  112. ;
  113. data    segment at 40h        ; BIOS data/work area
  114.     org    65h
  115. video_display    label    byte    ; display status byte
  116.     org    6ch
  117. timer_low    label    word    ; BIOS time counters
  118.     org    6eh
  119. timer_high    label    word
  120. data    ends
  121. ;
  122. display_segment segment at 0b80h    ; color/graphics display memory
  123. display_segment ends
  124. ;
  125. cseg    segment
  126.     assume    cs:cseg,ds:cseg
  127.     org    100h        ; .COM begin at 100h
  128. start:
  129.     jmp    initialize    ; first time - go to our intitialization routine
  130.  
  131.                 ; data poked into display memory
  132. tenhrs    dw    0700h        ; h
  133. onehrs    dw    0700h        ; h
  134.     dw    073ah        ; :
  135. tenmins dw    0700h        ; m
  136. onemins dw    0700h        ; m
  137.     dw    073ah        ; :
  138. tensecs dw    0700h        ; s
  139. onesecs dw    0700h        ; s
  140. am_pm_indicator dw    0720h    ; a - am, p - pm
  141. time_length    equ    $-tenhrs
  142.  
  143. timer_toggle    db    0    ; timer toggle value
  144. beep_count    db    0    ; number of quarter hour beeps
  145. need_beep    db    0ffh    ; set to ffh indicates need to beep
  146. tics        db    0    ; tics before next display
  147. mil_flag    db    0    ; military time indicator - N
  148. beep_flag    db    0    ; beep on the quarter hours
  149. tics_before_display    db    0    ; Tics before next display update
  150. save_stack_ss    dw    ?    ; previous stack segment
  151. save_stack_sp    dw    ?    ; previous stack pointer
  152.  
  153. ;
  154. ;    timer_interrupt - entered 18.5 times / sec from BIOS routine
  155. ;        via int 1ch
  156. ;
  157. timer_interrupt label    word
  158.     jmp    short    timer_bypass    ; replaced by "push ax  push cx"
  159.  
  160.     cli            ; no interrupts
  161.     mov    al,1
  162.     add    al,cs:tics    ; bump tics
  163.     cmp    al,cs:tics_before_display
  164.     mov    cs:tics,al    ; keep counter
  165.     jb    skip_maketime    ;
  166.  
  167.     mov    save_stack_ss,ss
  168.     mov    save_stack_sp,sp
  169.     mov    ax,cs
  170.     mov    ss,ax
  171.     mov    sp,offset stack_ptr
  172.  
  173.     mov    ax,jmparound        ;timer toggled off
  174.     mov    timer_interrupt,ax    ;setup by-pass
  175.  
  176.     sti            ; enable interrupts
  177.  
  178.     push    bx
  179.     push    ds
  180.     push    es
  181.     push    si
  182.     push    di
  183.     push    dx
  184.  
  185.     call    maketime    ; go do time stuff
  186.     mov    cs:tics,1    ; start counting again
  187.  
  188.     pop    dx
  189.     pop    di
  190.     pop    si
  191.     pop    es
  192.     pop    ds
  193.     pop    bx
  194.  
  195.     mov    ss,save_stack_ss    ; get back old stack
  196.     mov    sp,save_stack_sp    ; segment and pointer
  197.  
  198.     mov    word ptr timer_interrupt,5150h    ; replace with "push ax push cx"
  199.  
  200. skip_maketime:
  201.     sti            ; interrupts back on
  202.     pop    cx
  203.     pop    ax
  204. ;
  205. ; bypass jmp to here - when timer toggled off
  206. ;
  207. timer_bypass:
  208.     db    0eah    ; 'jmp far' - to any other 1ch timer routine
  209. jmpseg    dw    0        ; filled in by initial to other int 1ch routine
  210. jmpoffset    dw    0
  211.  
  212. ;
  213. ;    create time display and beep if necessary
  214. ;
  215. maketime:
  216.     mov    ax,0b800h    ; set display segment address
  217.     mov    es,ax
  218.     assume    es:display_segment
  219.     mov    ax,40h        ; set display status segment
  220.     mov    ds,ax
  221.     assume    ds:data
  222.  
  223.     mov    al,video_display    ; get display status byte
  224.     cmp    al,2dh        ; 80 x 25 alpha b/w?
  225.     je    maketime_100    ; yes-continue
  226.     cmp    al,29h        ; 80 x 25 alpha color?
  227.     je    maketime_100    ; yes-continue
  228.     jmp    early_exit    ; else-get out
  229.  
  230. maketime_100:
  231.     mov    si,timer_low    ; get current timer values
  232.     mov    cx,timer_high
  233.  
  234.     mov    ax,cs        ; restore our data segment pointer
  235.     mov    ds,ax
  236.     assume    ds:cseg
  237.  
  238.     mov    ax,cx        ; make hrs
  239.     cmp    mil_flag,'Y'    ; desire military time
  240.     je    maketime_200    ; yes-then bypass conversion to am/pm
  241.  
  242.     mov    byte ptr am_pm_indicator,'a'     ; no-then assume am
  243.     cmp    ax,24        ; 2400 hours?
  244.     jne    maketime_150    ; no-then with am/pm continue
  245.     mov    ax,0        ; make it 0000 hours
  246.     jmp    maketime_200    ; and continue
  247.  
  248. maketime_150:
  249.     cmp    ax,12        ; after noon?
  250.     jb    maketime_200    ; no
  251.     mov    byte ptr am_pm_indicator,'p'     ; mark pm
  252.     je    maketime_200    ; oops-exactly noon
  253.     sub    ax,12        ; else-just subtract out 12 hours
  254.  
  255. maketime_200:
  256.     aam            ; make printable
  257.     or    ax,'00'
  258.     cmp    ah,'0'          ; leading zero?
  259.     jne    maketime_225    ; no-then just continue
  260.     mov    ah,' '          ; else-suppress it
  261.  
  262. maketime_225:
  263.     mov    byte ptr onehrs,al
  264.     mov    byte ptr tenhrs,ah
  265.  
  266.     mov    ax,si        ; make minutes
  267.     mov    dx,0
  268.     mov    cx,0fh
  269.     mul    cx
  270.     mov    cx,4002h
  271.     div    cx
  272.     push    ax
  273.     aam
  274.     or    ax,'00'
  275.     mov    byte ptr onemins,al
  276.     mov    byte ptr tenmins,ah
  277.  
  278.     cmp    beep_flag,'Y'   ; do you want to beep the quarter hours?
  279.     jne    maketime_250    ; no-zero beep count and continue
  280.  
  281.     mov    beep_count,1    ; just one beep
  282. ;stub    mov    beep_count,4    ; assume on the hour
  283.     cmp    ax,'00'         ; on the hour?
  284.     je    maketime_300    ; yes-use count
  285. ;stub    sub    beep_count,1    ; dec for next interval
  286.     cmp    ax,'45'         ; three-quarter hour?
  287.     je    maketime_300    ; yes-use count
  288. ;stub    sub    beep_count,1    ; dec for next interval
  289.     cmp    ax,'30'         ; half hour?
  290.     je    maketime_300    ; yes-use count
  291. ;stub    sub    beep_count,1    ; dec for next interval
  292.     cmp    ax,'15'         ; quarter hour?
  293.     je    maketime_300    ; yes-use count
  294.  
  295. maketime_250:
  296.     mov    beep_count,0    ; assume no beeps required now
  297.  
  298. maketime_300:
  299.     pop    ax        ; make seconds
  300.     mul    cx
  301.     mov    cx,0fh
  302.     div    cx
  303.     xchg    ax,si
  304.     sub    ax,si
  305.     mul    cx
  306.     mov    cx,111h
  307.     div    cx
  308.     aam
  309.     or    ax,'00'
  310.     mov    byte ptr onesecs,al
  311.     mov    byte ptr tensecs,ah
  312.  
  313.     mov    si,offset tenhrs    ; get start address of time
  314.     mov    di,((0*80)+71)*2    ; set display memory address - line 0
  315.     mov    cx,time_length        ; #digits to move to display area
  316.     mov    dx,3dah         ; io address of c/g status reg
  317.  
  318. move_time:
  319.     in    al,dx            ; get c/g status
  320.     test    al,01h            ; is it low - horizontal retrace
  321.     jnz    move_time        ; no-try again - not time yet
  322. move_time1:
  323.     in    al,dx            ; get c/g status
  324.     test    al,01h            ; is it high - horizontal retrace
  325.     jz    move_time1        ; no-try again - not time yet
  326.     cld                ; forward direction
  327.     movsb                ; yes-move a byte of time at a time
  328.     loop    move_time        ; and loop till done
  329.  
  330. ;move_time:
  331. ;     in     al,dx             ; get c/g status
  332. ;     test     al,08h          ; ok to write? - vertical retrace
  333. ;     jz     move_time         ; no-try again - not time yet
  334. ;     movsb                 ; yes-move a byte of time at a time
  335. ;     loop     move_time         ; and loop till done
  336.  
  337.     mov    cl,beep_count        ; get count of consectitive beeps
  338.     and    cx,0ffh         ; clear ch and test for no beeps
  339.     jnz    do_beep         ; beep!
  340.     mov    need_beep,0ffh        ; else-set need beep flag
  341.                     ; beep once per quarter hour interval
  342.     jmp    early_exit        ; exit
  343.  
  344. do_beep:
  345.     cmp    need_beep,0        ; do we really need beep?
  346.     mov    need_beep,0        ; don't need beep till next quarter
  347.     je    early_exit        ; no-already beeped this quarter hour
  348.  
  349. beep_loop:
  350.     mov    bl,1            ; beep speaker short beep
  351.     call    beep            ; go beep
  352.     loop    beep_loop        ; beep again
  353.  
  354. early_exit:
  355.     ret
  356. ;
  357. ;    invoked by int 60H to toggle time display on/off
  358. ;
  359. toggle_my_timer:
  360.     push    ax
  361.     push    ds
  362.     mov    ax,cs
  363.     mov    ds,ax
  364.     mov    al,tics_before_display
  365.     mov    tics,al
  366.     xor    timer_toggle,0ffh    ;toggle time on/off
  367.     jz    enable_timer        ;branch-timer toggled on
  368.  
  369.     mov    ax,jmparound        ;timer toggled off
  370.     mov    timer_interrupt,ax    ;setup by-pass
  371.     pop    ds
  372.     pop    ax
  373.     iret
  374.  
  375. enable_timer:
  376.     mov    word ptr timer_interrupt,5150h    ; replace with "push ax push cx"
  377.     pop    ds
  378.     pop    ax
  379.     iret
  380. ;
  381. jmparound    dw    0    ; saved by initialization for by-pass
  382. ;
  383. ;    beep - derived from BIOS listing Tech. Ref. A-18
  384. ;
  385. beep:
  386.     push    cx
  387.     mov    al,10110110b        ; sel tim 2,lsb,msb,binary
  388.     out    timer+3,al        ; write the timer mode reg
  389.     mov    ax,533h         ; divisor for 1000 hz
  390.     out    timer+2,al        ; write timer 2 cnt - lsb
  391.     mov    al,ah
  392.     out    timer+2,al        ; write timer 2 cnt - msb
  393.     in    al,port_b        ; get current setting of port
  394.     mov    ah,al            ; save that setting
  395.     or    al,03            ; turn speaker on
  396.     out    port_b,al
  397.  
  398.     mov    cx,03fffh        ; set cnt to wait 125 ms
  399. g7:    loop    g7            ; delay before turning off
  400.  
  401.     dec    bl            ; delay cnt expired?
  402.     jnz    g7            ; no-continue beep spk
  403.  
  404.     mov    al,ah            ; recover value of port
  405.     out    port_b,al
  406.     pop    cx
  407.     ret                ; return to caller
  408.  
  409.     org    $+64            ; our stack area
  410. stack_ptr    equ    $
  411.  
  412. ;
  413. ;    initialization routine - thrown away afterwards!
  414. ;
  415. initialize:
  416.     jmp    around_constants
  417.  
  418. hello    db    "Color Graphics CLOCK (v1.6) by Daniel M. O'Brien (29 Dec 1983)"
  419.     db    13,10,'$'       ; my salutation - better than pat on the back!
  420.  
  421.                 ; variables to allow DEBUG patching
  422.  
  423.     db    'Color value of time display='
  424. color    db    14        ; Yellow for now
  425.  
  426.     db    'Military time='
  427. mil_flag1    db    'N'     ; military time indicator - N
  428.  
  429.     db    'Beep='
  430. beep_flag1    db    'Y'     ; beep on the quarter hours
  431.  
  432.     db    'Timer tics before time display refresh='
  433. tics_before_display1    db    4    ; about 4 times per second
  434.  
  435. around_constants:
  436.     push    ds
  437.  
  438.     mov    dx,offset hello     ; say hello
  439.     mov    ah,9
  440.     int    21h
  441.  
  442.     mov    ax,timer_interrupt    ; set up for bypass
  443.     mov    jmparound,ax
  444.     mov    timer_interrupt,5150h    ; push ax  push cx
  445.     xor    ax,ax            ; point to interrupt segment
  446.     assume    ds:int
  447.     mov    ds,ax
  448.     mov    si,toggle_timer_offset    ; get timer toggle int address
  449.     mov    cx,toggle_timer_segment
  450.     mov    ds,cx
  451.     cmp    word ptr [si],1e50h    ; already set to "push ax  push ds"?
  452.     jnz    install_timer        ; no-branch and install this as driver
  453.  
  454.     pop    ds
  455.     int    60h    ; else-toggle timer on/off and
  456.     int    20h    ; exit without remaining resident
  457.  
  458. install_timer:
  459.     xor    ax,ax        ; point to interrupt segment again
  460.     mov    ds,ax
  461.     mov    ax,timer_offset     ; save current 1ch timer routine adrs
  462.     mov    dx,timer_segment
  463.     pop    ds
  464.     mov    jmpseg,ax        ; need these for when we are done
  465.     mov    jmpoffset,dx
  466.  
  467.     mov    al,beep_flag1
  468.     mov    beep_flag,al
  469.  
  470.     mov    al,mil_flag1
  471.     mov    mil_flag,al
  472.  
  473.     mov    al,tics_before_display1
  474.     mov    tics_before_display,al
  475.     mov    tics,al
  476.  
  477.     mov    al,color        ; set up desired time display color
  478.     mov    di,offset tenhrs+1    ;  allows patching of color
  479.     mov    cx,time_length/2    ; number of attribute bytes
  480.     cld                ; march in a forward direction
  481.  
  482. color_loop:
  483.     stosb        ; plug in color value into attribute field
  484.     inc    di        ; skip time field
  485.     loop    color_loop    ; continue
  486.  
  487.     mov    dx,offset timer_interrupt    ; set up our interrupt routine
  488.     mov    ax,251ch    ; 25h = set up int, 1ch = user timer exit
  489.     int    21h        ; call dos
  490.  
  491.     mov    dx,offset toggle_my_timer    ; set up toggle display routine
  492.     mov    ax,2560h    ;  25h = set up int, 60h = our toggle routine
  493.     int    21h        ; call dos
  494.  
  495.     mov    dx,offset initialize+1    ; throw away init routine and
  496.     int    27h        ; exit, but stay resident
  497.  
  498. cseg    ends
  499.  
  500.     end    start
  501.