home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / SYSTEM / CUCKOO.ZIP / CUCKOO.ASM next >
Encoding:
Assembly Source File  |  1991-02-08  |  23.9 KB  |  555 lines

  1. ; RESIDENT TIME CLOCK DISPLAY with optional chime
  2. ;
  3. ;       Original author unidentified
  4. ;
  5. ;       Revised by Thomas A. Lundin
  6. ;                  Graphics Unlimited Inc.
  7. ;                  3000 Second St. No.
  8. ;                  Minneapolis, MN 55411
  9. ;                  (612) 588-7571
  10. ;
  11. ;       Later revisions -- 1/22/91
  12. ;
  13. ; usage: clok [/c]
  14. ;              /c to toggle chiming. No chimes by default.
  15. ;
  16. ; Clock display can be toggled on and off by repeating 'clok'.
  17. ;
  18. ;     Chimes should be toggled off when using heavy interrupt-driven
  19. ;     software such as communications to avoid losing characters or
  20. ;     hanging the system.
  21. ;
  22. ; 9/4/87 note:
  23. ;        This version uses the clock tick to regulate the duration of the
  24. ;        chimes, meaning that the chimes should be the same length from
  25. ;        one system to another, no matter what the CPU speed.
  26. ;        Also modified start-up routines to automatically set the time
  27. ;        display background to color or monochrome.
  28. ;
  29. ; 9/21/87 note:
  30. ;        This version alterates a date display with the time display, every
  31. ;        1.5 seconds.  The date display is static, i.e., it is not updated
  32. ;        at midnight (it would be inefficient to check every hour for an 
  33. ;        event which occurs once every 24 hours).
  34. ;
  35. ;        Turning the clok off and on (typing clok, twice) will reset the date.
  36. ;
  37. ; 1/05/88 note:
  38. ;        This revision sets the clock display in the lower right corner
  39. ;        instead of the upper right.
  40. ;
  41. ; 1/22/91 note:
  42. ;         This revision causes the clock to automatically position itself according
  43. ;         to the number of columns in the display.  The program did this before,
  44. ;         but only when it was initially loaded.  Thus if you switched between an
  45. ;         80 and 132 column mode, the clock would no longer be displayed in the 
  46. ;         upper right hand corner or wherever.  The program now reads the number of
  47. ;         columns every time the clock is displayed. 
  48. ;
  49. ; 2/1/91  The chime has now been replaced by a «cuckoo».  The clock will now cuckoo
  50. ;         for the appropriate hourly figure and cuckoo once on the quarter hour.
  51.  
  52. TICKS   EQU     27              ; number of ticks between updates (1.5 sec) 
  53.                                 ;old value -- 27
  54. BEEPS1   EQU     1               ; duration of first beep in clock ticks
  55. BEEPS2  EQU     3               ; duration of second beep in clock ticks
  56. BEEPS3  EQU     1               ; pause between cuckoos
  57. TONE1   EQU     5e7h            ; first chime tone 5f7h
  58. TONE2   EQU     74ch            ; second chime tone
  59.  
  60. interrupts segment at 0h
  61.           org      1ch*4          ; This is to use INT 1Ch
  62. timer_int label    dword          ; which is the timer interupt
  63. interrupts ends
  64.  
  65. screen    segment at 0b000h       ; A dummy segment to use
  66. screen    ends                    ; as the Extra Segment
  67.  
  68. code_seg  segment
  69.           assume   cs:code_seg
  70.           org      100h           ; org = 100 to make this into
  71.                                   ; a .COM file
  72. first:    jmp      load_clock
  73.  
  74. old_time_int dd    ?              ; The address INT 1Ch normally uses
  75. count500  dw       TICKS          ; Used to update clock every nnn counts
  76. beepticks dw       0              ; number of ticks for a BEEP
  77. beepsleft db       0              ; number of beeps to output
  78. cuckoo    dw       0              ; number of cuckoos to output
  79. cursor    dw       0              ; Location of the cursor on the screen
  80. beept     db       0              ; have-we-beeped flag
  81. inbeep    db       0              ; beep-in-progress flag
  82. flash     db       1              ; flashing colon flag
  83. spkrstat  db       0              ; old speaker status
  84. video_port         dw   ?         ; Video status port - check for scanning
  85. numcol    db        ?             ; number of columns
  86.  
  87. hh        dw       0              ; hours
  88. mm        dw       0              ; minutes
  89. sc        dw       0              ; seconds
  90. hh1       dw       0              ; 12-hour value for cuckoo
  91. hhdiv     dw       32771          ; hours divisor (65543/2)
  92. mmdiv     dw       546            ; minutes divisor (1092/2)
  93. ssdiv     dw       9              ; second divisor (18/2)
  94.  
  95. display   dw            (7020h)   ; leading space
  96.           dw       5 dup(703ah)   ; Initial value for the clock
  97.           dw       2 dup(7020h)   ; Add 2 ' 's for am/pm.
  98.  
  99. day_of_wk dw       0                 ; day of the week
  100. month     dw       0                 ; month
  101. day       dw       0                 ; day
  102. chimon    dw       1                 ; flag for chime in use or not
  103. clokon    dw       1                 ; flag for clok in use or not
  104.  
  105. clock     proc     near           ; The timer INT will now come here
  106.  
  107.           cmp      cs:clokon,1    ; is this interrupt silent ?
  108.           jz       newint         ; no, go execute it
  109.           jmp      dword ptr old_time_int ; silent, just execute old int
  110. newint:
  111.           pushf                   ; First call old time interrupt to update count
  112.           call     dword ptr old_time_int
  113.  
  114.           call     needbeep       ; need to continue beep ?
  115.           dec      cs:count500    ; should recalculate the time ?
  116.           jnz      dont_recalculate
  117.  
  118.           push     ax             ; Save the registers - good form
  119.           push     cx
  120.           push     di
  121.           push     si
  122.           push     es
  123.  
  124.           xor      cs:flash,1     ; toggle the flashing colon
  125.           call     calc           ; Recalculate the time
  126.           mov      cs:count500,TICKS  ; Reset Count500
  127. ;
  128. ;dont_recalculate:
  129. ;This is the routine for recalculating clock position when you switch in and
  130. ;out of different column modes
  131.           mov       ax,0              ;move memory location for column numbers
  132.           mov       es,ax             ;into es:di
  133.           mov       ax,044ah           ;
  134.           mov       di,ax             ;
  135.           mov       ah,es:[di]        ;move number of columns into ah
  136.           sub      ah,8               ; Move to eight places before edge
  137.           shl      ah,1               ; Mult by two (char and attribute bytes)
  138.  
  139. ;end of clock position routine
  140.           assume   es:screen      ; Set up screen as the Extra Segment
  141.           mov      cx,screen
  142.           mov      es,cx
  143.           mov      dx,video_port  ; This is the screen status port
  144.           mov      byte ptr cursor,ah ; Move cursor to it's memory location
  145.  
  146.           mov      di,cursor      ; Set up  cursor on screen as destination
  147.           lea      si,display     ; Set up the display in memory as source
  148.           mov      cx,16          ; To move char and attributes
  149. scan_low:
  150. ;taking out the snow avoidance routines for CGA
  151. ;scan_low:                         ; Start waiting for a new horizontal scan
  152. ;          in       al,dx          ; i.e. the the vidio controller scan
  153. ;          test     al,1           ; status is low.
  154. ;          jnz      scan_low
  155.  
  156.           mov      ah,cs:[si]     ; Move byte to be written into AH
  157.  
  158. ;scan_high:                        ; After port has gone low, it must go high
  159. ;         in       al,dx          ; before it is safe to write directly
  160. ;          test     al,1           ; to the screen buffer in memory
  161. ;          jz       scan_high
  162.  
  163.           mov      es:[di],ah     ; Move to screen one byte at a time.
  164.           inc      di             ; Position to attribute byte
  165.           inc      si             ; on screen.
  166.  
  167.           loop     scan_low       ; Go back foe next byte
  168.  
  169.           pop      es             ; Here are required pops to exit
  170.           pop      si
  171.           pop      di
  172.           pop      cx
  173.           pop      ax
  174.  
  175. dont_recalculate:
  176.           iret                    ; An interrupt needs an IRET
  177.  
  178. clock     endp
  179.  
  180. calc      proc near               ; Here we recalculate the time and store it
  181.           push     ax             ; Puushes to save everytheing that
  182.           push     bx             ; gets destroyed
  183.           push     cx
  184.           push     dx
  185.  
  186.          cmp      cs:flash,1                 ; do date or time?
  187.          jz       dtime                      ; TIME
  188.                                              ; DATE
  189.  
  190.          lea      bx,display     ; Set up BX as pointer to display in memory
  191.          mov      ax,cs:month
  192.          mov      cs:[bx+0],ah   ; Move first month digit into display
  193.          mov      cs:[bx+2],al   ; Then the second digit
  194.          mov      byte ptr cs:[bx+4],'-'  ; a hyphen
  195.          mov      ax,cs:day      ; get day
  196.          mov      cs:[bx+6],ah   ; and move them into the display in memory
  197.          mov      cs:[bx+8],al
  198.          mov      byte ptr cs:[bx+10],' ' ; move space into display
  199.          mov      ax,cs:day_of_wk
  200.          mov      cs:[bx+12],ah  ; move day of the week into display
  201.          mov      cs:[bx+14],al
  202.          jmp      restore
  203.  
  204. dtime:
  205. ; note: Peter Norton p.223 explains that the time formula is more precisely
  206. ; shown as:
  207. ;       hh = clkcount / 65543
  208. ;       mm = hh.remainder / 1092
  209. ;       ss = mm.remainder / 18
  210. ;
  211. ; trouble is, the 65543 value won't work as a single-word divisor,
  212. ; so our trick is to divide the clock count and divisor values in half,
  213. ; which should have no appreciable affect on the accuracy of the time.
  214.  
  215.           xor      ax,ax          ; Set up for clock read.
  216.           INT      1Ah            ; Read the clock.
  217.           mov      bx,dx          ; Save low(minutes) portion.
  218.           mov      dx,cx          ; Move high(hours) portion to AX.
  219.           mov      ax,bx          ; dx:ax = clock count
  220.  
  221.           clc
  222.           rcr      dx,1             ; div count by 2 so we can use a
  223.           rcr      ax,1             ; single precision dividend
  224.  
  225.           div      cs:hhdiv         ; compute hours
  226.           mov      cs:hh,ax         ; save it
  227.           mov      ax,dx            ; prepare remainder for minutes
  228.           xor      dx,dx
  229.           div      cs:mmdiv         ; compute minutes
  230.  
  231.           cmp      ax,60            ; 60 minutes shows up sometimes
  232.           jl       mm_ok            ; mostly it doesn't
  233.           xor      ax,ax            ; but if it does, zero out the minutes
  234.           inc      cs:hh            ; and bump up the hour
  235.  
  236. mm_ok:    mov      cs:mm,ax         ; save it
  237. ;         mov      ax,dx            ; prepare remainder for seconds
  238. ;         xor      dx,dx
  239. ;         div      cs:ssdiv         ; compute seconds
  240. ;         mov      cs:sc,ax         ; save it
  241.  
  242.           lea      bx,display     ; Set up BX as pointer to display in memory
  243.  
  244.           mov      byte ptr cs:[bx],' '    ; blank out first and last positions
  245.           mov      byte ptr cs:[bx+14],' '
  246.           mov      ax,cs:hh
  247.           cmp      ax,12          ; is it am or pm?
  248.           jl       am             ; am
  249. pm:       mov      byte ptr cs:[bx+12],'p' ; Otherwise move 'P' into the display.
  250.           sub      ax,12          ; pm, subtract 12
  251.           jmp      chek12         ; Continue.
  252.  
  253. am:       mov      byte ptr cs:[bx+12],'a' ; Move an 'A' into the display.
  254. chek12:   or       ax,ax          ; Make zero hour...
  255.           jnz      am_pm_done
  256.           mov      ax,12          ; ...a twelve
  257. am_pm_done:
  258.           mov      cs:hh1,ax         ; hour value for cuckoo
  259.           aam                     ; Convert AX to BCD - a nice command
  260.           add      ax,3030h       ; Add '0' to both bytes in AX to make ASCII
  261.           cmp      ah,'0'         ; Is the 1st digit '0'?
  262.           jne      dont_edit      ; Then don't blank the character.
  263.           mov      ah,' '         ; Otherwise, put a space in AH.
  264. dont_edit:
  265.           mov      cs:[bx+2],ah   ; Move first hours digit into display
  266.           mov      cs:[bx+4],al   ; Then the second digit
  267. ;----------------------------------
  268.           mov      byte ptr cs:[bx+6],':'     ; in which case use a colon
  269.           mov      ax,cs:mm       ; get minutes
  270.           aam                     ; Again convert AX to Binary Coded Decimal
  271.           add      ax,3030h       ; Add to make two ASCII characters
  272.           mov      cs:[bx+8],ah   ; and move them into the display in memory
  273.           mov      cs:[bx+10],al
  274.  
  275. ;---------routine for alarm chime goes here------------------------------------
  276.         cmp     cs:chimon,0             ; chimes off?
  277.         jz      restore                 ; yes, don't beep
  278.         cmp     cs:inbeep,1             ; already in a beep loop?
  279.         jz      restore                 ; yes, don't be redundant
  280.  
  281.         cmp     ax,3030h                ; on the hour  (full cuckoo routine)
  282.         jz      alarm3
  283.         cmp     ax,3135h                ; on the 1/4 hour (single cuckoo)
  284.         jz      alarm2
  285.         cmp     ax,3330h                ; on the 1/2 hour (single cuckoo)
  286.         jz      alarm2
  287.         cmp     ax,3435h                ; on the 3/4 hour (single cuckoo)
  288.         jz      alarm2
  289.         mov     cs:beept,0              ; we have not beeped
  290. ;------------------------------------------------------------------------------
  291. restore:                                  ; Restore registers
  292.           pop      dx
  293.           pop      cx
  294. imret2:   pop      bx
  295. imret1:   pop      ax
  296.  
  297. imret:    ret
  298. ;-----------------------------------------------------------------------------
  299. needbeep:
  300.          cmp      cs:inbeep,1                ; are we beeping right now ?
  301.          jnz      imret                      ; no, immediate return
  302.          dec      cs:beepticks               ; yes, done beeping?
  303.          jnz      imret                      ; no, immediate return
  304.          push     ax
  305.          mov      al,cs:spkrstat             ; yes, shut off speaker
  306.          out      61h,al
  307.          dec      cs:beepsleft               ; any more beeps waiting?
  308.          jz       nobeeps                    ; no, go home
  309.          cmp      cs:beepsleft,1             ; how many await?
  310.          jnz      onward
  311.          call     pause
  312.          jmp      imret1
  313. onward:
  314.          push     bx
  315.          mov      bx,TONE2                   ; second tone in cuckoo
  316.          mov      cs:beepticks,BEEPS2        ; second tone is longer than first tone
  317.          call     tone_a                      ; start it beeping
  318.          jmp      imret2                     ; go home
  319. nobeeps:
  320.          dec      cs:cuckoo                  ; are there any more cuckoos?
  321.          jz       no_cuckoo                  ; no more cuckoos
  322.          push     bx
  323.         mov     bx,TONE1                     ; beginning of next cuckoo
  324.         mov     cs:beepsleft,3
  325.         call    tone                         ;start it beeping
  326.          jmp     imret2
  327. ;------------------------------------------------------------------------------
  328. alarm3: push        ax                 ;save the register
  329.         mov         ax,hh1              ;move hour value into ax
  330.         mov         cs:cuckoo,ax        ; hourly cuckoo - repeat for number of hours
  331.         pop         ax
  332.         mov     bx,TONE1                ; send tone 1
  333.         mov     cs:beepsleft,3
  334.         call    tone
  335.         jmp     restore
  336. alarm2: mov     cs:cuckoo,1             ; only a single cuckoo for quarter hour 
  337.                                         ; intervals
  338.         mov     bx,TONE1                ; send tone 2
  339.         mov     cs:beepsleft,2
  340.         call    tone
  341.         jmp     restore
  342. ;---------------------------------------
  343. no_cuckoo:
  344.         mov       cs:beept,1                 ; we have beeped
  345.         mov       cs:inbeep,0                ; and we're not in one any more
  346.         jmp       imret1
  347. ;---------------------------------------
  348. tone:
  349.         cmp     cs:beept,1              ; do nothing if chime has been beeped
  350.         jz      notone                  ; earlier in this clock update
  351.         mov     cs:beepticks,BEEPS1      ; this long on beeps
  352. tone_a:
  353.         MOV     AL,0B6H                 ; else condition the timer
  354.         OUT     43H,AL
  355.         MOV     AX,BX                   ; this is the freq
  356.         OUT     42H,AL
  357.         MOV     AL,AH
  358.         OUT     42H,AL                  ; out you all go
  359.         IN      AL,61H                  ; read spkr port
  360.         MOV     cs:spkrstat,AL
  361.         OR      AL,3
  362.         OUT     61H,AL                  ; send a beep
  363.         mov     cs:inbeep,1
  364. notone: ret
  365. ;--------------------------------------------------------
  366. pause:
  367.         mov         cs:beepticks,BEEPS3
  368.         ret
  369. ;------------------------------------------------------------------------------
  370. calc      endp
  371.  
  372.  
  373. load_clock proc near              ; This procedure initializes everything
  374.           assume   ds:interrupts  ; The Data Segment will be the interrupt area
  375.           mov      ax,interrupts
  376.           mov      ds,ax
  377.  
  378.         MOV     SI,0081H        ; addr of command line arguments
  379. NEXT:   MOV     AL,CS:[SI]      ; get command line char
  380.         CMP     AL,0DH          ; Return ends it.
  381.         JZ      again
  382.         CMP     AL,'/'          ; switch char
  383.         JZ      getswitch       ; see what it is
  384. next1:  INC     SI              ; else point to next char
  385.         JMP     NEXT            ; and loop
  386. getswitch:
  387.         inc     si
  388.         mov     al,cs:[si]
  389.         cmp     al,'c'          ; chime toggle switch
  390.         jz      sw_c
  391.         jmp     next1           ; wrong switch
  392.  
  393. sw_c:
  394.         mov     cs:togchim,1    ; toggle them chimes
  395.         jmp     next1           ; get next switch if there is one
  396.  
  397. again:    mov      ax,cs:sig_vector     ; get signature vector
  398.           cmp      ax,5fh               ; if less than 0x60
  399.           jg       vok
  400.           jmp      noload               ; forget it
  401. vok:      add      ax,3500h
  402.           int      21h
  403.           mov      ax,es
  404.           cmp      ax,434ch             ; are we already loaded ?
  405.           jnz      nosig                ; no
  406.           cmp      bx,4f4bh
  407.           jnz      nosig                ; and no
  408.           mov      bx,word ptr timer_int ; yes
  409.           mov      es,word ptr timer_int+2
  410.           call     gdate                ; get the system date
  411.           cmp      cs:togchim,1
  412.           jnz      no1                  ; no toggle chimes
  413.           call     toglchim             ; go toggle chimes
  414.           jmp      exit
  415.  
  416. no1:
  417.           mov      ax,es:[bx-2]
  418.           xor      ax,1                 ; toggle activation mode
  419.           mov      word ptr es:[bx-2],ax
  420. exit:     mov      ax,4c00h             ; return to DOS
  421.           int      21h
  422.  
  423. ;---------------------------------------
  424. toglchim:
  425.           mov      ax,es:[bx-4]         ; get the chime flag
  426.           xor      ax,1                 ; toggle it
  427.           mov      word ptr es:[bx-4],ax
  428.           push     ds
  429.           mov      di,cs
  430.           mov      ds,di
  431.           cmp      ax,1                 ; beep if it's been turned on
  432.           jz       beepmsg
  433.           mov      dx,offset chimoffmsg        ; chimes off
  434.           jmp      print
  435. beepmsg:  mov      dx,offset chimonmsg         ; chimes on
  436. print:    mov      ah,9
  437.           int      21h
  438.           pop      ds
  439.           ret
  440. ;---------------------------------------
  441. nosig:    mov      ax,es                ; no current signature...
  442.           or       ax,bx                ; ...but is it safe to load one?
  443.           jz       setsig               ; yes
  444.           mov      ax,cs:sig_vector     ; no, try another slot
  445.           dec      ax
  446.           mov      cs:sig_vector,ax
  447.           jmp      again
  448. ;---------------------------------------
  449. gdate:
  450.         push    bx
  451.         mov     ah,2ah          ; call DOS GetDate command
  452.         int     21h
  453.         xor     ah,ah           ; make an offset out of the day of the week
  454.         clc
  455.         rcl     ax,1
  456.         mov     si,ax
  457.         lea     bp,days
  458.         mov     ax,[bp+si]      ; get the ASCII day of the week
  459.         pop     bx
  460.         mov     word ptr es:[bx-10],ax  ; save it
  461.         mov     al,dh           ; month
  462.         xor     ah,ah
  463.         aam                     ; Convert AX to BCD - a nice command
  464.         add     ax,3030h        ; Add '0' to both bytes in AX to make ASCII
  465.         cmp     ah,'0'         ; Is the 1st digit '0'?
  466.         jne     gd1            ; Then don't blank the character.
  467.         mov     ah,' '         ; Otherwise, put a space in AH.
  468. gd1:    mov     word ptr es:[bx-8],ax
  469.         mov     al,dl           ; day
  470.         xor     ah,ah
  471.         aam                     ; Convert AX to BCD - a nice command
  472.         add     ax,3030h        ; Add '0' to both bytes in AX to make ASCII
  473.         mov     word ptr es:[bx-6],ax
  474.         ret                     ; go home
  475. ;---------------------------------------
  476. noload    label near
  477.           mov      ax,4c01h             ; abort with error
  478.           int      21h
  479.  
  480. setsig:
  481.           cli
  482.           push     ds
  483.           mov      ax,cs:sig_vector
  484.           add      ax,2500h             ; signature reads:
  485.           mov      dx,434ch             ; 'CL'
  486.           mov      ds,dx
  487.           mov      dx,4f4bh             ; 'OK'
  488.           int      21h
  489.           pop      ds
  490.  
  491.           mov      ax,word ptr timer_int       ; Get the old interrupt service routine
  492.           mov      word ptr old_time_int,ax    ; address and put it into our location
  493.           mov      ax,word ptr timer_int+2     ; OLD_TIME_INT so we can still call it
  494.           mov      word ptr old_time_int+2,ax
  495.  
  496.           mov      word ptr timer_int,offset clock ; Now load the address of our clock
  497.           mov      word ptr timer_int+2,cs    ; routine into TIMER_INT so the timer
  498.                                       ; interrupt will call CLOCK
  499.           sti
  500.  
  501.           mov      ah,15              ; Ask for service 15 of INT 10H
  502.           int      10h                ; This tells us how the display is set up
  503.           sub      ah,8               ; Move to eight places before edge
  504.           shl      ah,1               ; Mult by two (char and attribute bytes)
  505.           mov      byte ptr cursor,ah ; Move cursor to it's memory location
  506. ;          mov      bx,3840 ;;;;;;;;;;;; *** move to lower right corner ***
  507. ;          add      cursor,bx ;;;;;;;;;; *** move to lower right corner ***
  508.           mov      video_port,03bah   ; Assume this is a monochrome display
  509.           test     al,4               ; Is it?
  510.           jnz      get_time           ; Yes - jump out
  511.           add      cursor,8000h       ; No - set up for graphics display
  512.           mov      video_port,03dah
  513.           mov      cx,8
  514.           mov      ax,4f20h
  515.           lea      di,display
  516. color:    mov      cs:[di],ax
  517.           inc      di
  518.           inc      di
  519.           loop     color
  520.  
  521. get_time:
  522.         mov     bx,offset clock ; yes        ; get addr of clok
  523.         mov     ax,cs
  524.         mov     es,ax
  525.         cmp     cs:togchim,1    ; need to toggle ?
  526.         jnz     noct            ; no
  527.         call    toglchim
  528. noct:   call    gdate
  529.  
  530.           mov      di,cs
  531.           mov      ds,di
  532.           mov      dx,offset hello             ; chimes on
  533.           mov      ah,9
  534.           int      21h
  535.           call     calc  ; This is to avoid showing 00:00 for first 500 counts
  536.           mov      dx,offset load_clock   ; Set up for everything but LOAD_CLOCK
  537.           int      27h                ; to stay attached to DOS
  538.  
  539. sig_vector      dw      67h             ; signature vector
  540. togchim         db      0               ; to toggle chimes
  541. days            db      'uSoMuTeWhTrFaS'
  542. chimonmsg       db      'Chime ON',0dh,0ah,'$'
  543. chimoffmsg      db      'Chime OFF',0dh,0ah,'$'
  544. hello           db      'usage: clok [/c]  (/c: toggle chimes)',0dh,0ah
  545.                 db      'clok by itself toggles display',0dh,0ah
  546.                 db      'CLOK INSTALLED',0dh,0ah,'$'
  547.  
  548. load_clock         endp
  549.  
  550.           code_seg ends
  551.  
  552.           end      first ; END FIRST so 8088 will go to FIRST first
  553.  
  554. )B
  555.