TITLE *** XEROX 820 REAL-TIME CLOCK UTILITY *** .Z80 BDOS EQU 5 ;BDOS ENTRY POINT PRTSTG EQU 9 ;CP/M PRINT STRING FUNCTION CLRSCN EQU 1AH ;CLEAR SCREEN CODE CR EQU 0DH ;CARRIAGE RETURN CODE LF EQU 0AH ;LINE FEED CODE CTC3 EQU 0FF16H ;CTC CHANNEL 3 INTERRUPT VECTOR BASE1 EQU 0FF75H ;BASE VARIABLE (1.0 ROM) BASE2 EQU 0FF78H ;BASE VARIABLE (2.0 ROM) CLKORG EQU 0FE00H ;ORIGIN FOR CLOCK ROUTINE HOURS EQU 0FF5CH ;HOURS VARIABLE LOCATION MINUTE EQU HOURS + 1 ;MINUTES VARIABLE LOCATION SECNDS EQU MINUTE + 1 ;SECONDS VARIABLE LOCATION ; ; FIRST CHECK FOR CLOCK MODULE ALREADY LOADED, IF IT IS DISPLAY ; MESSAGE AND GO BACK TO CP/M ; BEGIN: LD A,(0FE00H) CP 0FFH ;CHECK FOR CLOCK ALREADY LOADED JR Z,PROCED ;PROCEED IF NOT LD DE,RESET ;POINT TO RESET MESSAGE LD C,PRTSTG ;PRINT STRING FUNCTION TO C CALL BDOS ;CALL BDOS RST 0 ;BACK TO CP/M ; ; CHECK LENGTH OF COMMAND LINE (MUST BE 9 CHARACTERS) IF NOT GIVE ; USER INSTRUCTIONS ON WHAT MUST BE ON COMMAND LINE ; PROCED: LD A,(80H) ;GET COMMAND LINE LENGTH CP 9 ;CHECK FOR 9 CHARACTERS JP Z,PARMOK ;IF COUNT = 9 THEN GO AHEAD LD DE,INSTR ;ELSE PRINT INSTRUCTIONS LD C,PRTSTG ;PRINT STRING FUNCTION TO C CALL BDOS ;GO PRINT THROUGH CP/M RST 0 ;GO BACK TO CP/M ; ; IF CLOCK IS NOT LOADED AND COMMAND LINE PARAMETER COUNT IS OK ; MOVE IMAGE OF CLOCK ROUTINE TO HIGH MEMORY ; PARMOK: LD HL,START ;SOURCE ADDRESS FOR MOVE LD DE,CLKORG ;DESTINATION ADDRESS FOR MOVE LD BC,LENGTH ;NUMBER OF BYTES TO MOVE LDIR ;Z-80 BLOCK MOVE DI ;DISABLE INTERRUPTS LD HL,(CTC3) ;ADDRESS OF 1 SEC. INTERRUPT ROUTINE LD DE,12 ;OFFSET INTO ROUTINE ADD HL,DE ;COMPUTE ADDRESS LD E,(HL) ;GET LOW BYTE OF CALL TO E INC HL ;BUMP POINTER LD D,(HL) ;GET HIGH BYTE OF CALL TO D DEC HL ;ROLL HL BACK LD BC,CLOCK ;GET ADDRESS OF CLOCK ROUTINE LD (HL),C ;RE-ROUTE INTERRUPT TO CLOCK ROUTINE INC HL LD (HL),B LD HL,GETOUT+1 ;POINT TO CLOCK EXIT LD (HL),E ;SAVE ORIGINAL LOW BYTE INC HL LD (HL),D ;SAVE ORIGINAL HIGH BYTE LD A,(0F001H) ;GET BYTE FROM MONITOR CP 45H ;CHECK FOR 2.0 ROM JR NZ,ROM1 ;SKIP IF NOT LD HL,BASE2 ;NEW BASE ADDRESS LD (CLOCK+7),HL ;SAVE NEW VALUE ROM1: LD A,(82H) ;GET STD/MILITARY OPTION CP 'M' ;CHECK FOR M JR NZ,BASEOK ;DEFAULT STD TIME SKIP OVER LD A,25D ;NEW VALUE LD (BASE+1),A ;SAVE NEW VALUE BASEOK: LD A,(83H) ;GET DISPLAY OPTION CP 'N' ;CHECK FOR NO DISPLAY JR NZ,DISOK ;DEFAULT ON SKIP AROUND LD A,0C3H ;GET JUMP INSTRUCTION LD (CLOCK+6),A ;SAVE IN PLACE OF CALL LD HL,(GETOUT+1) LD (CLOCK+7),HL DISOK: LD HL,(84H) ;GET HOURS VALUE CALL CONV ;GO CONVERT TO BINARY LD (HOURS),A ;SAVE IN HOURS VARIABLE LD HL,(86H) ;GET MINUTES VALUE CALL CONV ;GO CONVERT TO BINARY LD (MINUTE),A ;SAVE IN MINUTES VARIABLE LD HL,(88H) ;GET SECONDS VALUE CALL CONV ;GO CONVERT TO BINARY LD (SECNDS),A ;SAVE IN SECONDS VARIABLE EI LD A,1AH ;CLEAR SCREEN CODE CALL 0F00FH ;GO THROUGH MONITOR RET ; ; CONVERT ASCII VALUE IN H&L TO BINARY VALUE & RETURN IN A REGISTER. ; UNITS IN H -- TENS IN L ; CONV: LD A,H ;MOVE TO A SUB 30H ;REMOVE ASCII OFFSET LD H,A ;PUT BACK IN H LD A,L ;MOVE L TO A SUB 30H ;REMOVE ASCII OFFSET LD L,A ;PUT BACK IN L ADD A,A ;DOUBLE A ADD A,A ;DOUBLE AGAIN ADD A,L ;ADD ONE IN ADD A,A ;A = A * 10 ADD A,H ;ADD IN UNITS VALUE RET ;ALL DONE ; ; MAIN CLOCK ROUTINE - THIS CODE IS MOVED INTO HIGH MEMORY AND EXECUTED ; EVERYTIME A ONE SECOND INTERRUPT OCCURS ; START: .PHASE CLKORG CLOCK: LD HL,SECNDS ;POINT HL TO SECONDS VARIABLE CALL INCTIM ;INCREMENT TIME IN BINARY LD A,(BASE1) ;GET LINE# OF BOTTOM LINE ON SCREEN INC A ;ADD 1 TO WRAP AROUND TO TOP LINE CP 24 JR C,CLOCK2 ;WATCH FOR MODULO 24 THING XOR A CLOCK2: SRL A ;TRANSFORM LINE# INTO 16 BIT ADDRESS LD L,70*2 ; WITH COL# COMPONENT=70 RR L LD DE,3000H OR D LD H,A IN A,(1CH) SET 7,A OUT (1CH),A ;ENABLE CRT RAM BANK LD DE,HOURS ;POINT DE TO CLOCK HOURS LD (HL),' ' INC HL CALL PUTDEC ;CALL PUTDEC TO DISPLAY HOURS LD (HL),':' INC HL CALL PUTDEC ;CALL PUTDEC TO DISPLAY MINUTES LD (HL),':' INC HL CALL PUTDEC ;CALL PUTDEC TO DISPLAY SECONDS LD (HL),' ' IN A,(1CH) RES 7,A OUT (1CH),A ;DISABLE CRT ROM BANK GETOUT: JP 0 ; ; SUBROUTINE TO PUT DECIMAL CONTENTS OF CLOCK VARIABLE LOCATIONS ON THE ; SCREEN. ENTER WITH THE DE REGISTER POINTING TO THE DESIRED VARIABLE ; PUTDEC: LD A,(DE) INC DE LD C,0 PUTD1: SUB 10 JR C,PUTD2 INC C JR PUTD1 PUTD2: ADD A,10 PUSH AF LD A,C CALL PUTDIG ;DISPLAY 10'S DIGIT OF TIME POP AF PUTDIG: OR '0' ;MAKE MSB OF ACC INTO ASCII LD (HL),A INC HL ;STORE CHARACTER AND BUMP POINTER RET ; ; INCREMENT TIME IN SECONDS VARIABLE BY ONE, CHECK FOR: ; SECONDS = 59, MINUTES = 59, AND HOURS = 12. ; INCTIM: INC (HL) LD A,(HL) ;BUMP CLOCK SECONDS AND CHECK FOR CP 60 ; ROLL-OVER AT END OF MINUTE RET C ;EXIT IF NO CARRY TO MINUTES LD (HL),0 ;ELSE RESET SECONDS TO ZERO DEC HL ; AND POINT NEXT TO MINUTES INC (HL) LD A,(HL) ;BUMP CLOCK MINUTES AND CHECK FOR CP 60 ; ROLL-OVER AT END OF HOUR RET C ;EXIT IF NO CARRY INTO HOURS LD (HL),0 ;ELSE RESET MINUTES TO ZERO DEC HL ; AND POINT NEXT TO HOURS INC (HL) LD A,(HL) ;BUMP CLOCK HOURS AND CHECK FOR BASE: CP 13 ; ROLL-OVER AFTER 24 HOURS RET C ;EXIT IF NO ROLL-OVER LD (HL),1 ;ELSE RESET HOURS TO 1 AND RET ;START OVER LENGTH EQU $-CLOCK ;CALCULATE LENGTH OF CODE .DEPHASE ; ; MESSAGES ; INSTR: DEFB CLRSCN,LF DEFM ' CLOCK UTILITY INSTRUCTIONS' DEFM ' VER 1.0' DEFB CR,LF,LF DEFM 'THE COMMAND LINE TO SET & RUN THE CLOCK MUST BE AS ' DEFM 'FOLLOWS:' DEFB CR,LF,LF DEFM 'A>CLOCK ABHHMMSS' DEFB CR,LF,LF DEFM ' A = S FOR STANDARD TIME' DEFB CR,LF DEFM ' M FOR MILITARY TIME' DEFB CR,LF,LF DEFM ' B = D TO DISPLAY TIME ON SCREEN' DEFB CR,LF DEFM ' N NO DISPLAY ON SCREEN' DEFB CR,LF,LF DEFM ' HH = HOUR' DEFB CR,LF,LF DEFM ' MM = MINUTE' DEFB CR,LF,LF DEFM ' SS = SECOND' DEFB CR,LF,LF,LF DEFM '$' RESET: DEFB CLRSCN,LF,LF DEFM 'THE CLOCK MODULE IS ALREADY LOADED, PRESS RESET' DEFM ' IF YOU WANT TO RELOAD IT.' DEFB CR,LF,LF,LF,LF,LF,LF,LF,LF DEFB ' CLOCK VARIABLE MEMORY LOCATIONS' DEFB CR,LF,LF,LF DEFM ' DECIMAL HEX VARIABLE' DEFB CR,LF,LF DEFM ' 65372 FF5C HOURS' DEFB CR,LF DEFM ' 65373 FF5D MINUTES' DEFB CR,LF DEFM ' 65374 FF5E SECONDS' DEFB CR,LF,LF,LF DEFM '$' END BEGIN