; SDATE Version 1.0 -- 11/15/87. ; ; SDATE is intended set the Z80DOS system date on systems that have ; no real time clock. The date is read from the disk label and the ; operater is prompted for changes. Valid replies include "+", "-", ; or a new date. To use: Enter "SDATE" at the CP/M prompt. There ; are no command line options. SDATE.ASM assembles with DRI's ASM. ; - Bill Duerr ; VER EQU 10 ; Current version number MO EQU 11 ; Month last modified DY EQU 15 ; Day YR EQU 87 ; Year ; FALSE EQU 0 TRUE EQU NOT FALSE ; ; System equates ; BDOS EQU 00005 ; CIO EQU 6 ; Console output RCONS EQU 10 ; Console buffer input OPEN EQU 15 ; Open file SRCHF EQU 17 ; Search for First Ambiguous File SETDAT EQU 104 ; Set Z80DOS date GETDAT EQU 105 ; Get Z80DOS date ; FCB1 EQU 5CH ; TBUF EQU 80H ; Temporary buffer (default) address ; LF EQU 0AH ; Line feed character CR EQU 0DH ; Carriage return character ; ; Program starts here ; ORG 100H ; START: LXI H,0 ; Make local stack DAD SP ; Add the address of CCP stack SHLD STACK ; And save it LXI SP,STACK ; Set the stack pointer to local stack ; ; Search the directory for the Label file (Format "-ddddddd.vvv") ; LXI D,FCB1+1 ; Address of default FCB + 1 LXI H,FCB1 ; Start of FCB MVI M,'?' ; Indicate any file will do PUSH H ; Save it MVI B,12 ; Move 12 bytes of the FCB CALL MOVE ; Propagate "?" through file extent POP D ; Get back address of default FCB MVI C,SRCHF ; Get first occurrence of requested file CALL BDOS LXI D,NOTFND ; Send warning message ORA A ; Zero returned for first file in block JNZ ABEXIT ; Go display message and quit ; LDA TBUF+1 ; Get the first byte of the first entry CPI '-' ; Is this a disk label JNZ ABEXIT ; Go display message and quit LDA TBUF+96 ; Get the first byte of the last entry CPI 021H ; Is this a date stamped directory block JNZ ABEXIT ; Go display message and quit LDA TBUF+105 ; Get the low order byte of the access date ORA A ; Is this a valid date JZ ABEXIT ; Go display message and quit LXI D,HEADER ; Display program name and header info CALL DSPMSG XRA A ; Set end of message STA TBUF+13 ; After volume number LXI D,TBUF+9 ; Get address of volume number CALL DSPMSG LXI D,COMMA ; Separate volume and description CALL DSPMSG XRA A ; Set end of message STA TBUF+9 ; After disk description LXI D,TBUF+1 ; Get address of disk description CALL DSPMSG ; ; Convert a two byte date value in the buffer returned by Search for first ; to binary day of the week ; DATCHK: LXI D,DATCAP ; Get date caption in DE CALL DSPMSG ; Display caption LHLD TBUF+104 ; Number of days since Dec 31, 1977 CHK1: LXI D,-7 ; Number of days in a week DAD D ; Subtract from our date JC CHK1 ; Loop till negative MOV A,L ; Move the complimented day in A CMA ; Complement it MVI H,0 MOV L,A ; Get day in HL LXI B,DAYS ; Point to english day table DAD B ; Add to find offset into table MOV L,M ; Get offset MVI H,0 DAD B ; Point to english day XCHG ; Get in DE for display routine CALL DSPMSG ; Display day of week LXI D,DAYCAP ; Separate day and month CALL DSPMSG ; ; Convert a two byte date value in the buffer returned by Search for first ; to binary values returned as "date", "month", and "year" ; LHLD TBUF+104 ; Number of days since Dec 31, 1977 DCX H ; DAD instruction below does not set zero flag LXI B,0024EH ; Set leap year counter in B, 1978 in C LXI D,-365 ; Amount to subtract per year ; CHK2: DAD D ; Subtract 1 year JNC CHK3 ; Went to far INR C ; Increment year by one DCR B ; Decrement leap year counter JNZ CHK2 ; Not leap year MVI B,4 ; Every four years it's leap year DCX H ; Subtract 1 more day for leap year JMP CHK2 ; Loop till we find our year ; CHK3: MOV A,C ; Get the calculated year STA YEAR ; Save calculated binary year ANI 003H ; Is this a leap year MVI A,28 ; Show that February has 28 days JNZ CHK4 ; No, bypass next instructions INR A ; And each leap year 29 CHK4: STA FEBL ; Save it in the table LXI B,MONTBL+12 ; Table of number of days/month MVI D,0 ; Clear D for 16 bit arithmetic ; CHK5: DCX B ; Move back to the previous month LDAX B ; Get number of days for this month MOV E,A ; Put it in DE DAD D ; Add in month JNC CHK5 ; Loop till till number of days positive INX H ; Compensate for DCX above MOV A,L ; The remainder is the day of month STA DAY MOV A,C ; Get the binary value for this month ANI 00FH ; Save only low order nibble STA MONTH ; Save for later ; ; Convert the binary values to english words ; MVI H,0 MOV L,A ; Use month as index into table DCX H ; Make relative to zero LXI B,MONTHS ; Point to english month DAD B ; Find offset into table MOV L,M MVI H,0 DAD B ; Point to english month XCHG ; Get in DE for display routine CALL DSPMSG ; Display month of year MVI E,' ' ; Get a space to be displayed MVI C,CIO ; Console I/O BDOS function CALL BDOS LHLD DAY ; Get the day of this month MVI H,0 CALL DSPDEC ; Display day as a decimal number LXI D,YCAP ; Get address of separator CALL DSPMSG ; Display it LHLD YEAR ; Get the current year MVI H,0 CALL DSPDEC ; Display year as a decimal number ; ; Ask if any changes are to be made, and get response ; DATASK: LXI D,ASKCAP ; Get date caption in DE CALL DSPMSG ; Display caption MVI A,9 ; Maximum of 8 characters and LXI D,BUFFER ; Program's console buffer STAX D ; Save size of buffer MVI C,RCONS ; Read Console buffer BDOS function CALL BDOS LXI H,BUFFER+1 ; Get number of characters entered MOV A,M ORA A ; Where any entered JZ DONE ; No, set date and return CPI 1 ; Has just 1 character been entered JNZ ASK2 ; No, go parse the date INX H ; Get the first character MOV A,M LHLD TBUF+104 ; Number of days since Dec 31, 1977 CPI '+' ; Should we add to the date JNZ ASK1 ; No INX H ; Add one to current date JMP ASK9 ; Go display it and see if any more changes ASK1: CPI '-' ; Should we subtract from the date JNZ DATASK ; No, don't know what to do DCX H ; Subtract one from current date JMP ASK9 ; Go display new date and see if any more ASK2: LXI H,BUFFER+2 ; Get address of console input PUSH H ; Save it MOV E,A ; Add length to find end of buffer MVI D,0 DAD D MOV M,D ; Make sure it's delimited by zero POP H ; Get address of console input CALL EDIT ; Edit the month for valid 2 digit number JZ DATASK ; Didn't pass edit, ask again CPI 12+1 ; Only 12 months in a year JNC DATASK ; Ask again STA MONTH ; Save the month MOV A,M ; Get next character in console buffer CPI '/' ; Are we pointing to a "/" separator JNZ DATASK ; Invalid character, ask again INX H ; Point to first character of day CALL EDIT ; Edit it for a valid number JZ DATASK ; Didn't pass edit, ask again STA DAY ; Save it MOV A,M ; Get next character in console buffer ORA A ; At end of buffer JZ ASK3 ; Keep the year we had before CPI '/' ; Are we pointing to a "/" separator JNZ DATASK ; Invalid character, ask again INX H ; Point to first character of year CALL EDIT ; Edit it for a valid number JZ DATASK ; Didn't pass edit, ask again STA YEAR ; Save the year ASK3: LDA YEAR ; Get the year CPI 80 ; Is year less than 1980 JC DATASK ; Invalid, ask again CPI 100 ; Is year greater that 1999 JNC DATASK ; Invalid, ask again PUSH A ; Save the year ANI 003H ; Is this a leap year MVI A,28 ; Show that February has 28 days JNZ ASK4 ; No, bypass next instructions INR A ; And each leap year 29 ASK4: STA FEBL ; Save it in the table POP A ; Get back the year SUI 77 ; Make relative to 1978 MVI B,003H ; Set leap year counter in B LXI D,365 ; Amount to add per year LXI H,0 ; Clear H for day counter ; ASK5: DCR A ; Decrement year by one JZ ASK6 ; Done calculating number of days so far DAD D ; Add 1 year DCR B ; Decrement leap year counter JNZ ASK5 ; Not leap year MVI B,4 ; Every four years it's leap year INX H ; Add 1 more day for leap year JMP ASK5 ; Loop till we're done ASK6: PUSH H ; Save number of days beginning of year LDA MONTH ; Get the month DCR A ; Make relative to 0 LXI D,MONTBL ; Table of number of days/month MOV L,A ; Get offset into table for this month MVI H,0 DAD D ; Point to entry for this month LDA DAY ; Get the day of the month DCR A ; Subtract one CMP M ; Compare to total number of days this month JNC DATASK ; Invalid day, ask again XCHG ; Get address of this month in DE LXI H,0 ; Clear day counter MOV B,L ; Clear number of day per month area ASK7: DCX D ; One less month to go MOV A,E ; Get the low part of table address ANI 00FH ; Save only the low part JZ ASK8 ; When zero, we're done LDAX D ; Get the number of days for this month MOV C,A ; Get in C to add DAD B ; Number of days so far this year JMP ASK7 ; Loop till done ; ASK8: LDA DAY ; Get the current day MOV E,A ; Into E for adding MVI D,0 ; Clear high order DAD D ; Add to find day of year POP D ; Get back beginning of year counter DAD D ; And add it all together ASK9: SHLD TBUF+104 ; Save it JMP DATCHK ; Go display it and see if any more changes ; ; End of program ; DONE: LXI H,0 ; Set time to zero SHLD TBUF+106 ; In default buffer area LXI D,TBUF+104 ; Number of days since Dec 31, 1977 MVI C,SETDAT ; Set Date BDOS function CALL BDOS LXI D,FCB1 ; Use default FCB MVI C,OPEN ; Set Date BDOS function CALL BDOS ; LXI D,DONEM ; Display "Done" JMP EXIT ; ; Aborted - display reason ; ABEXIT: CALL DSPMSG ; Display message pointed to in DE LXI D,ABORT ; Display "Aborted" message ; ; Exit with message ; EXIT: CALL DSPMSG ; Display message pointed to by DE ; ; Exit back to the CCP ; LHLD STACK ; Get original CCP return address SPHL RET ; Go back to CCP, no warm boot needed ; ; Edit input for valid one or two digit number ; EDIT: MOV C,M ; Get a character from memory MVI B,'0' ; Make tens position a zero INX H ; Point to next character MOV A,M ; Get it in A CMP B ; Check if number JC EDIT2 ; Not a number, must be units position MOV B,C ; Move to tens position MOV C,A ; Move to units position INX H ; Point to next character in input buffer EDIT2: MOV A,B SUI '0' ; Is it a valid number JC EDIT3 CPI 9+1 JNC EDIT3 MOV B,A ; Save the character ADD A ; Multiply by 10 ADD A ADD B ADD A MOV B,A ; Save the value MOV A,C SUI '0' ; Is it a valid number JC EDIT3 CPI 9+1 JNC EDIT3 ADD B ; Add in tens position ORA A ; Set return code to zero RET EDIT3: XRA A ; Set return to zero for invalid RET ; Return to caller ; ; Output zero terminated string pointed to by DE ; DSPMSG: LDAX D ; Get start of message ORA A ; At end? RZ ; Return to caller PUSH B PUSH D PUSH H MOV E,A ; Get the character to be displayed MVI C,CIO ; Console I/O BDOS function CALL BDOS POP H POP D POP B INX D ; Point to next character JMP DSPMSG ; Loop till done ; ; Move "B" bytes from "HL" to "DE", Uses A,B,DE,HL ; MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; DSPDEC: MVI D,0 ; Set for leading zero LXI B,-10 CALL CNVRT ; Convert to decimal ; MOV A,L ; One's digit was left in L JMP DSPDGT ; Display the digit and return to caller ; CNVRT: MVI A,0FFH ; Increments to zero first time used PUSH H ; CNVRT1: POP H ; Get the value in HL PUSH H ; Save as previous value INR A ; Add one for this position DAD B ; Subtract power of ten from binary value XTHL ; Get previous value back JC CNVRT1 ; Do it until we go negative POP B ; Get stack right, discard negative value MVI E,' ' ; Assume the character is a space ORA D ; Check for leading zeros JZ DSPSPC ; Return if digit is zero DSPDGT: MVI D,'0' ; Set D so all zeros will display after this ORA D ; Convert to ASCII MOV E,A DSPSPC: PUSH D PUSH H MVI C,CIO ; Console I/O BDOS function CALL BDOS POP H POP D RET ; ; Program storage area, initialized ; ABORT: DB CR,LF,'Aborted',0 DONEM: DB CR,LF,'Done',0 NOTFND: DB 'Label Not Found',0 ; DATCAP: DB CR,LF,'Current date set as ',0 ASKCAP: DB CR,LF,'Enter changes or : ',0 DAYCAP: DB 'day' COMMA: DB ', ',0 YCAP: DB ', 19',0 ; HEADER: DB 'SDATE Version ',VER / 10 + '0','.',VER MOD 10 + '0',' -- ' DB MO/10+'0',MO MOD 10+'0','/' DB DY/10+'0',DY MOD 10+'0','/' DB YR/10+'0',YR MOD 10+'0',CR,LF DB 'Current disk is volume ',0 MONTHS: DB JAN-MONTHS DB FEB-MONTHS DB MAR-MONTHS DB APR-MONTHS DB MAY-MONTHS DB JUN-MONTHS DB JUL-MONTHS DB AUG-MONTHS DB SEP-MONTHS DB OCT-MONTHS DB NOV-MONTHS DB DEC-MONTHS JAN: DB 'January',0 FEB: DB 'February',0 MAR: DB 'March',0 APR: DB 'April',0 MAY: DB 'May',0 JUN: DB 'June',0 JUL: DB 'July',0 AUG: DB 'August',0 SEP: DB 'September',0 OCT: DB 'October',0 NOV: DB 'November',0 DEC: DB 'December',0 DAYS: DB FRI-DAYS DB THR-DAYS DB WED-DAYS DB TUE-DAYS DB MON-DAYS DB SUN-DAYS DB SAT-DAYS SUN: DB 'Sun',0 MON: DB 'Mon',0 TUE: DB 'Tues',0 WED: DB 'Wednes',0 THR: DB 'Thurs',0 FRI: DB 'Fri',0 SAT: DB 'Satur',0 ; ; Get on 16 byte boundary + 1 (Low order 4 bits is the value of the month) ; ORG (($+15)/16*16)+1 MONTBL: DB 31 ; Jan FEBL: DB 28 ; Feb Value stored for leap years DB 31 ; Mar DB 30 ; Apr DB 31 ; May DB 30 ; Jun DB 31 ; Jul DB 31 ; Aug DB 30 ; Sep DB 31 ; Oct DB 30 ; Nov DB 31 ; Dec MONTH: DS 1 DAY: DS 1 YEAR: DS 1 ; ; ; Storage not initialized by assembler ; ; DS 64 ; Local stack ORG ($+255)/256*256 ; Get on page boundary ; STACK EQU $-2 ; Area for CCP stack pointer ; BUFFER EQU $ ; Area for console input END