Talk About Network

Google


Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > Assembly Language > Re: Make a TSR
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 6 of 9 Topic 5006 of 5163
Post > Topic >>

Re: Make a TSR

by Viel Spass <andy77017@[EMAIL PROTECTED] > May 17, 2008 at 06:07 AM

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,'=BA'        ;and write a '=BA'
        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,'=BA'        ;and write a '=BA'
        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 =3D 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 =3D row, AH =3D 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 '=D8 =F7=F7=F7=F7=F7=F7 =D8 Oil I Maintenance Services A.
Kenn=
edy 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 @[EMAIL PROTECTED]
 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 =AEcuckoo=AF.  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 =3D 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               ; fla****ng colon flag
spkrstat        db      0               ; old speaker status
video_****t      dw      ?               ; Video status ****t - 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 fla****ng 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_****t           ; This is the screen status
****t
        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 =3D clkcount / 65543
;       mm =3D hh.remainder / 1092
;       ss =3D 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) ****tion.
        mov     dx,cx           ; Move high(hours) ****tion to AX.
        mov     ax,bx           ; dx:ax =3D 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 ****t
        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
 




 9 Posts in Topic:
Make a TSR
"almas" <alm  2008-05-11 19:32:23 
Re: Make a TSR
"Rod Pemberton"  2008-05-11 13:24:02 
Re: Make a TSR
"Benjamin David Lunt  2008-05-11 12:18:11 
Re: Make a TSR
"Rod Pemberton"  2008-05-14 15:39:18 
Re: Make a TSR
"Benjamin David Lunt  2008-05-15 08:23:48 
Re: Make a TSR
Viel Spass <andy77017@  2008-05-17 06:07:01 
Re: Make a TSR
Frank Kotler <fbkotler  2008-05-17 19:47:38 
Re: Make a TSR
"Rod Pemberton"  2008-05-17 17:29:46 
Re: Make a TSR
Evenbit <nbaker2328@[E  2008-05-17 13:11:22 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Sat Oct 11 18:13:18 CDT 2008.