; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ; HOLD v1.0 ; ; Last update: 29-Mar-85 ; By: Steve A. Kitahata ; ; HOLD is a timer routine which when invoked will delay ; the specified amount of time entered before returning ; to CP/M. It is most useful when used in a .SUB file to ; schedule the execution of programs at a later time. ; ; The syntax for HOLD is as follows: ; ; A>HOLD hh:mm:ss ; -or- ; A>HOLD mm:ss ; -or- ; A>HOLD ss ; ; 'hh' indicates hours ; 'mm' indicates minutes ; 'ss' indicates seconds ; ; Alternately, 2 digits need not be entered if only 1 ; digit is necessary, e.g. 'HOLD 1:2:3' is the same as ; 'HOLD 01:02:03'. ; ; If any key is pressed during the delay, ; program execution will be terminated. ; ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; system equates ; ~~~~~~~~~~~~~~ BDOS EQU 0005H ; BDOS entry point addr DBUFF EQU 0080H ; default DMA buffer addr TPA EQU 0100H ; transient program area base addr DCONIO EQU 6 ; direct console I/O function code ; timer equates ; ~~~~~~~~~~~~~ ; The 'TENTH' equate may need to be 'tweaked' for your ; particular system, depending on your clock speed. ; 15000 is a good starting point for a Z80 running at 4 Mhz. TENTH EQU 15000 ; 100 ms. delay count (for 4 Mhz) ; ASCII equates ; ~~~~~~~~~~~~~ BEL EQU 7 ; bell CR EQU 13 ; carriage return LF EQU 10 ; line feed ; start of program ; ~~~~~~~~~~~~~~~~ ORG TPA HOLD: JMP INIT ; jump around variable area ; variable area ; ~~~~~~~~~~~~~ TENTHC: DW TENTH ; 100 ms. delay count (patch w/ DDT @ 0103H) HOURS: DW 00 ; hours MINS: DW 00 ; minutes SECS: DW 00 ; seconds DS 32 STACK: DW $-$ ; initialize timer ; ~~~~~~~~~~~~~~~ INIT: LXI H,0 DAD SP SHLD STACK LXI SP,STACK CALL ILPRT ; display sign-on message DB CR,LF,0 LXI D,DBUFF ; point to command tail LDAX D ; get byte count ORA A JZ SYNTAX ; display syntax message if no input MVI H,0 MOV L,A DAD D ; point to last char XCHG CALL TWODIG ; get seconds SHLD SECS CALL TWODIG ; get minutes SHLD MINS CALL TWODIG ; get hours SHLD HOURS ; FALL THRU ; to start timer ; decrement seconds & display remaining time ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECSEC: CALL ILPRT ; display time remaining message DB CR,'Time remaining --> ',0 LHLD HOURS CALL DIGDSP ; display hours MVI A,':' CALL CONOUT LHLD MINS CALL DIGDSP ; display minutes MVI A,':' CALL CONOUT LHLD SECS CALL DIGDSP ; display seconds MVI A,' ' CALL CONOUT CALL CONIN ; check for abort JNZ ABORT ; if abort request LHLD SECS DCR L ; dec seconds JP DS1 ; if not decrementing ten's MVI L,9 ; else re-init one's DCR H ; dec ten's JP DS1 ; if not decrementing minutes MVI H,5 ; else re-init ten's CALL DECMIN ; dec minutes JM DONE ; if specified time has elapsed DS1: SHLD SECS ; set seconds remaining MVI B,10 ; init delay for one second DS2: LHLD TENTHC ; init delay for 100 milliseconds DS3: DCX H ; dec delay count MOV A,H ORA L JNZ DS3 ; until one millisecond elapsed DCR B JNZ DS2 ; until one second elapsed JMP DECSEC ; until specified time elapsed ; decrement minutes ; ~~~~~~~~~~~~~~~~~ DECMIN: PUSH H LHLD MINS ; get current minutes remaining DCR L ; dec minutes JP DM1 ; if not decrementing ten's MVI L,9 ; else re-init one's DCR H ; dec ten's JP DM1 ; if not decrementing hours MVI H,5 ; else re-init ten's CALL DECHR ; dec hours DM1: SHLD MINS ; set minutes remaining POP H RET ; decrement hours ; ~~~~~~~~~~~~~~~ DECHR: PUSH H LHLD HOURS ; get current hours remaining DCR L ; dec hours JP DH1 ; if not decrementing ten's MVI L,9 ; else re-init one's DCR H ; dec ten's DH1: SHLD HOURS ; set hours remaining POP H RET ; get two decimal digits from buffer ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; enter: D&E - buffer pointer ; ; exit: H&L - decimal digit pair ; TWODIG: LXI H,0 ; init digits LDAX D ; get char CPI ' ' RZ ; if no more chars SUI '0' ; convert to binary JC ERROR ; if invalid digit CPI 10 JNC ERROR ; if invalid digit MOV L,A ; else save one's digit DCX D ; bump to next char LDAX D ; get char CPI ' ' RZ ; if no more chars CPI ':' JZ DIG1 ; if delimiter SUI '0' ; convert to binary JC ERROR ; if invalid digit CPI 10 JNC ERROR ; if invalid digit MOV H,A ; else save ten's digit DCX D ; bump to next char LDAX D CPI ' ' RZ ; if no more chars CPI ':' JNZ ERROR ; if error DIG1: DCX D ; bump to next char LDAX D CPI ' ' JZ ERROR ; if error RET ; display syntax error message ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ERROR: CALL ILPRT ; display error message DB '++ Syntax error ++',BEL,CR,LF,CR,LF,0 ; FALL THRU ; to display syntax message ; display syntax message ; ~~~~~~~~~~~~~~~~~~~~~~ SYNTAX: CALL ILPRT ; display syntax message DB 'Syntax: A>HOLD hh:mm:ss',CR,LF DB ' A>HOLD mm:ss',CR,LF DB ' A>HOLD ss',CR,LF,0 JMP EXIT ; exit to CP/M ; abort request ; ~~~~~~~~~~~~~ ABORT: CALL ILPRT ; display abort message DB CR,LF DB CR,LF,'++ Aborted ++',0 ; FALL THRU DONE: CALL ILPRT DB BEL,CR,LF,0 EXIT: LHLD STACK SPHL RET ; return to CP/M ; display two digits ; ~~~~~~~~~~~~~~~~~~ ; entry: H&L - binary digits ; DIGDSP: MOV A,H ; ten's digit ADI '0' ; convert to ascii CALL CONOUT ; display ten's digit MOV A,L ; one's digit ADI '0' ; convert to ascii JMP CONOUT ; display one's digit ; in-line print ; ~~~~~~~~~~~~~ ILPRT: XTHL ; starting string addr PUSH PSW ILP1: MOV A,M ; get next char INX H ; bump pointer to next char ORA A JZ ILP2 ; if end of string reached CALL CONOUT ; else display char JMP ILP1 ILP2: POP PSW XTHL RET ; console input ; ~~~~~~~~~~~~~ ; exit: A - console char ; CONIN: PUSH B PUSH D PUSH H MVI E,0FFH ; console input code MVI C,DCONIO CALL BDOS ANI 7FH ; strip parity POP H POP D POP B RET ; console output ; ~~~~~~~~~~~~~~ ; entry: A - char to output ; CONOUT: PUSH PSW PUSH B PUSH D PUSH H ANI 7FH ; strip parity MOV E,A MVI C,DCONIO CALL BDOS POP H POP D POP B POP PSW RET ; ~~~~~~~~~~~~~~~~~~~~ END