home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / pcmag / vol6n03.arc / TIMEKEY.ASM < prev    next >
Encoding:
Assembly Source File  |  1987-12-13  |  17.0 KB  |  330 lines

  1. ;TIMEKEY.COM for the IBM Personal Computer - 1986 by Jeff Prosise
  2. ;
  3. kb_data       equ 60h                       ;keyboard data port
  4. kb_ctrl       equ 61h                       ;keyboard control port
  5. l_key         equ 38                        ;scan code for 'L' key
  6. s_key         equ 31                        ;scan code for 'S' key
  7. t_key         equ 20                        ;scan code for 'T' key
  8. alt_key       equ 8                         ;shift code for Alt key
  9. eoi           equ 20h                       ;EOI value
  10. int_ctrl_port equ 20h                       ;8259 port address
  11. ;
  12. bios_data     segment at 40h                ;BIOS data area
  13.               org 1Ah
  14. buffer_head   dw ?                          ;head of keyboard buffer
  15. buffer_tail   dw ?                          ;tail of keyboard buffer
  16.               org 80h
  17. buffer_start  dw ?                          ;starting keyboard buffer address
  18. buffer_end    dw ?                          ;ending keyboard buffer address
  19. bios_data     ends
  20. ;
  21. code          segment para public 'code'
  22.               assume cs:code
  23.               org 100h
  24. begin:        jmp init1
  25. ;
  26. copyright          db "TIMEKEY (C) 1986, Ziff-Davis Publishing Co.",1Ah
  27. author             db "programmed by Jeff Prosise",1Ah
  28. long_date          db 19 dup (?)            ;long date string buffer
  29. short_date         db 9 dup (?)             ;short date string buffer
  30. time_buffer        db 11 dup (?)            ;time string buffer
  31. hour               db ?                     ;current hour count
  32. minutes            db ?                     ;current minutes count
  33. buffer_flag        db 0                     ;status of output routine
  34. buffer_ptr         dw ?                     ;index into output buffer
  35. time_text          db 32,'X.M.',0           ;AM/PM designator
  36. old_int_9          label dword              ;old interrupt 9 vector
  37. old_keyboard_int   dw 2 dup (?)
  38. old_int_1Ch        label dword              ;old interrupt 1Ch vector
  39. old_timer_int      dw 2 dup (?)
  40. ;
  41. ;------------------------------------------------------------------------------
  42. ;This routine will be executed at every tick of the time-of-day clock.
  43. ;------------------------------------------------------------------------------
  44. timer_int     proc near
  45.               pushf                         ;push flags to simulate INT
  46.               call old_int_1Ch              ;call original timer routine
  47.               cmp buffer_flag,0             ;anything waiting to be output?
  48.               je timer_exit                 ;no, then exit
  49.               push ax                       ;save registers that will be used
  50.               push bx
  51.               push dx
  52.               push si
  53.               call fill_buffer              ;output to keyboard buffer
  54.               pop si                        ;restore register values
  55.               pop dx
  56.               pop bx
  57.               pop ax
  58. timer_exit:   iret                          ;exit and enable interrupts
  59. timer_int     endp
  60. ;
  61. ;------------------------------------------------------------------------------
  62. ;Execution will come here every time a key is pressed or released.
  63. ;------------------------------------------------------------------------------
  64. kb_int        proc near
  65.               sti                           ;enable interrupts
  66.               push ax                       ;save AX
  67.               mov ah,2                      ;get status of shift keys
  68.               int 16h
  69.               test al,alt_key               ;is the Alt key depressed?
  70.               je kb_exit                    ;no, then exit to normal handler
  71.               in al,kb_data                 ;get scan code
  72.               cmp al,t_key                  ;is it the 'T' key?
  73.               je kbint1                     ;yes, then continue
  74.               cmp al,l_key                  ;is it the 'L' key?
  75.               je kbint1                     ;yes, then continue
  76.               cmp al,s_key                  ;is it the 'S' key?
  77.               je kbint1                     ;yes, then continue
  78. kb_exit:      pop ax                        ;restore AX
  79.               jmp old_int_9                 ;goto normal int 9 handler
  80. ;
  81. ;One of the trigger key combinations was pressed.  Save register values and
  82. ;reset the keyboard.
  83. ;
  84. kbint1:       push bx                       ;save remaining registers
  85.               push cx
  86.               push dx
  87.               push si
  88.               push di
  89.               push ds
  90.               push es
  91.               push ax                       ;save scan code
  92.               in al,kb_ctrl                 ;get keyboard control byte
  93.               mov ah,al                     ;save it in AH
  94.               or al,80h                     ;set high bit
  95.               out kb_ctrl,al                ;send it to control port
  96.               mov al,ah                     ;get original byte value
  97.               out kb_ctrl,al                ;OUT it to enable keyboard
  98.               pop ax                        ;restore scan code
  99.               push cs                       ;set DS and ES to code segment
  100.               pop es
  101.               push cs
  102.               pop ds
  103.               assume ds:code
  104.               cmp al,t_key                  ;Alt-T pressed?
  105.               je kbint2                     ;yes, then branch
  106. ;
  107. ;Alt-L or Alt-S was pressed.  Set BUFFER_PTR to proper date string.
  108. ;
  109.               mov buffer_ptr,offset long_date    ;set pointer for long date
  110.               cmp al,l_key                       ;was Alt-L pressed?
  111.               je kbint6                          ;yes, then skip ahead
  112.               mov buffer_ptr,offset short_date   ;set pointer for short date
  113.               jmp kbint6                         ;goto output routine
  114. ;
  115. ;Alt-T was pressed.  Convert time to ASCII form and set BUFFER_PTR.
  116. ;
  117. kbint2:       mov ah,0                      ;get clock count from BIOS
  118.               int 1Ah                       ;time count in DX:CX
  119.               mov ax,cx                     ;get high part of count (hours)
  120.               mov bl,24                     ;prepare BL for division
  121.               div bl                        ;divide hours by 24
  122.               mov hour,ah                   ;save remainder as current hour
  123.               mov ax,60                     ;now multiply DX by 60
  124.               mul dx                        ;result in AX:DX
  125.               mov minutes,dl                ;save current count of minutes
  126.               cld                           ;clear DF for string instructions
  127.               lea di,time_buffer            ;set buffer pointer
  128.               mov al,hour                   ;get hour in AL
  129.               cmp al,0                      ;is the hour zero?
  130.               jne kbint3                    ;no
  131.               add al,12                     ;yes, then set it to 12
  132. kbint3:       cmp al,12                     ;hour > 12 ?
  133.               jbe kbint4                    ;no
  134.               sub al,12                     ;yes, then subtract 12
  135. kbint4:       mov bl,30h                    ;set BL for call to BIN2ASC
  136.               call bin2asc                  ;convert value to text form
  137.               mov al,':'                    ;write colon to time string
  138.               stosb
  139.               mov al,minutes                ;get minutes in AL
  140.               mov bl,0                      ;print leading zeroes
  141.               call bin2asc                  ;output minutes
  142.               mov time_text[1],'P'          ;set designator to 'P.M.'
  143.               cmp hour,11                   ;hour > 11 ?
  144.               ja kbint5                     ;yes, then leave it
  145.               mov time_text[1],'A'          ;no, then set it for 'A.M.'
  146. kbint5:       lea si,time_text              ;add designator to time string
  147.               mov cx,6                      ;six characters including ASCII 0
  148.               rep movsb                     ;write them
  149.               mov buffer_ptr,offset time_buffer       ;set pointer for output
  150. ;
  151. ;Output buffer is indexed by variable BUFFER_PTR.  Insert as much as possible
  152. ;of the indicated string into the keyboard buffer, then exit.
  153. ;
  154. kbint6:       call fill_buffer              ;output until done or buffer full
  155.               cli                           ;disable interrupts
  156.               mov al,eoi                    ;end interrupt
  157.               out int_ctrl_port,al
  158.               pop es                        ;restore saved register values
  159.               pop ds
  160.               pop di
  161.               pop si
  162.               pop dx
  163.               pop cx
  164.               pop bx
  165.               pop ax
  166.               iret                          ;exit
  167. kb_int        endp
  168. ;
  169. ;------------------------------------------------------------------------------
  170. ;BIN2ASC converts a binary value less than 100 into its text equivalent.
  171. ;Entry: ES:DI - buffer address
  172. ;       AL    - byte value
  173. ;       BL    - 0 = print leading zeroes, 30h = suppress leading zeroes
  174. ;------------------------------------------------------------------------------
  175. bin2asc       proc near
  176.               aam                           ;convert AL to BCD value in AX
  177.               add ax,3030h                  ;binary to ASCII
  178.               cmp ah,bl                     ;suppress leading zeroes?
  179.               je bin1                       ;yes, then jump
  180.               xchg ah,al                    ;get first digit in AL
  181.               stosb                         ;print first digit
  182.               xchg ah,al                    ;restore original value of AL
  183. bin1:         stosb                         ;print second digit
  184.               ret
  185. bin2asc       endp
  186. ;
  187. ;------------------------------------------------------------------------------
  188. ;FILL_BUFFER outputs a string of bytes delimited by a zero byte directly to
  189. ;the keyboard buffer.
  190. ;Entry: BUFFER_PTR - offset address of next byte to transmit
  191. ;------------------------------------------------------------------------------
  192. fill_buffer   proc near
  193.               push ds                       ;save DS
  194.               mov ax,bios_data              ;then set it to BIOS data segment
  195.               mov ds,ax
  196.               assume ds:bios_data
  197.               mov bx,buffer_tail            ;get location of buffer tail
  198.               mov si,buffer_ptr             ;get value of buffer index
  199.               xor ah,ah                     ;zero AH
  200. filbuf1:      mov al,cs:[si]                ;get next character to output
  201.               or al,al                      ;is it zero?
  202.               je done                       ;yes, then we're done
  203.               mov dx,bx                     ;get buffer tail into DX
  204.               add dx,2                      ;increment to next location
  205.               cmp dx,buffer_end             ;do we need to wrap around?
  206.               jne filbuf2                   ;no, so jump
  207.               mov dx,buffer_start           ;wrap around to start address
  208. filbuf2:      cmp dx,buffer_head            ;head = tail ?
  209.               je buffer_full                ;yes, then buffer is full
  210.               mov [bx],ax                   ;deposit character into buffer
  211.               mov bx,dx                     ;advance keyboard buffer pointer
  212.               mov buffer_tail,bx            ;update BIOS record of buffer tail
  213.               inc si                        ;advance index
  214.               inc buffer_ptr                ;advance output buffer pointer
  215.               jmp filbuf1                   ;loop back for more
  216. buffer_full:  mov buffer_flag,1             ;set flag to indicate not done
  217.               jmp done1
  218. done:         mov buffer_flag,0             ;all done - set flag
  219. done1:        pop ds                        ;restore DS
  220.               assume ds:code
  221.               ret
  222. fill_buffer   endp
  223. ;
  224. ;------------------------------------------------------------------------------
  225. ;INITIALIZE routine places the string equivalents of the current date (long
  226. ;form and short form) into their respective storage areas and sets interrupt
  227. ;vectors to enable the resident portion of the code.
  228. ;------------------------------------------------------------------------------
  229. initialize    proc near
  230. ;
  231. month_text    db 7,'January  '              ;text of month names
  232.               db 8,'February '
  233.               db 5,'March    '
  234.               db 5,'April    '
  235.               db 3,'May      '
  236.               db 4,'June     '
  237.               db 4,'July     '
  238.               db 6,'August   '
  239.               db 9,'September'
  240.               db 7,'October  '
  241.               db 8,'November '
  242.               db 8,'December '
  243. ;
  244. month         db ?                          ;month number (1-12)
  245. day           db ?                          ;day number (1-31)
  246. year          db ?                          ;year number (0-99)
  247. text1         db ', 19'                     ;partial text of long date string
  248. ;
  249. ;Get the current month, day, and year from DOS and save the values.
  250. ;
  251. init1:        mov ah,42                     ;get system date from DOS
  252.               int 21h
  253.               sub cx,1900                   ;subtract 1900 from year
  254.               mov month,dh                  ;save month, day, and year
  255.               mov day,dl
  256.               mov year,cl
  257.               cld                           ;clear DF for string operations
  258. ;
  259. ;Create the long date string in the LONG_DATE buffer.
  260. ;
  261.               dec dh                        ;find table offset of month text
  262.               mov al,10                     ;set multiplier
  263.               mul dh                        ;(month-1) * 10
  264.               mov si,ax                     ;transfer table offset to SI
  265.               add si,offset month_text      ;complete offset address
  266.               mov cl,[si]                   ;get length of month name
  267.               inc si                        ;point SI to text of string
  268.               xor ch,ch                     ;byte to word in CX
  269.               lea di,long_date              ;point DI to LONG_DATE area
  270.               rep movsb                     ;transfer name of month to buffer
  271.               mov al,32                     ;add space character after month
  272.               stosb
  273.               mov al,dl                     ;get day in AL
  274.               mov bl,30h                    ;suppress zeroes
  275.               call bin2asc                  ;add day to the buffer
  276.               lea si,text1                  ;add ', 19' text
  277.               mov cx,4                      ;four characters to transfer
  278.               rep movsb
  279.               mov al,year                   ;get year in AL
  280.               mov bl,0                      ;print zeroes
  281.               call bin2asc                  ;add it to the buffer
  282.               mov al,0                      ;terminate string with ASCII zero
  283.               stosb
  284. ;
  285. ;Create the short date string in the SHORT_DATE buffer.
  286. ;
  287.               lea di,short_date             ;point DI to short date buffer
  288.               mov al,month                  ;get month in AL
  289.               mov bl,30h                    ;suppress zeroes
  290.               call bin2asc                  ;write it to the buffer
  291.               mov al,'-'                    ;add dash separator
  292.               stosb
  293.               mov al,day                    ;get day of month in AL
  294.               mov bl,30h                    ;suppress zeroes
  295.               call bin2asc                  ;write it to the buffer
  296.               mov al,'-'                    ;add dash separator
  297.               stosb
  298.               mov al,year                   ;get year in AL
  299.               mov bl,0                      ;print zeroes
  300.               call bin2asc                  ;write it to the buffer
  301.               mov al,0                      ;terminate string with ASCII zero
  302.               stosb
  303. ;
  304. ;Save and set the interrupt 9 and 1Ch vectors to enable our new routines.
  305. ;
  306.               mov ah,35h                    ;get interrupt 1Ch vector
  307.               mov al,1Ch
  308.               int 21h
  309.               mov old_timer_int,bx          ;save it
  310.               mov old_timer_int[2],es
  311.               mov ah,25h                    ;set interrupt 1Ch vector
  312.               mov al,1Ch
  313.               lea dx,timer_int              ;point it to our timer routine
  314.               int 21h
  315.               mov ah,35h                    ;get old interrupt 9 vector
  316.               mov al,9
  317.               int 21h
  318.               mov old_keyboard_int,bx       ;save it
  319.               mov old_keyboard_int[2],es
  320.               mov ah,25h                    ;set interrupt 9 vector
  321.               mov al,9
  322.               lea dx,kb_int                 ;point to our keyboard handler
  323.               int 21h
  324.               lea dx,initialize             ;point DX to end of resident code
  325.               int 27h                       ;terminate-but-stay-resident
  326. initialize    endp
  327. ;
  328. code          ends
  329.               end begin
  330.