                    NAME CLOCK
                    ENTRY CLOCK


CLKBAS EQU 50H        = CLOCK PORT BASE ADDRESS
CLKCMD EQU CLKBAS+10  =   "   COMMAND PORT ADDRESS
CLKDTA EQU CLKBAS+11  =   "   DATA     "      "
BIOS EQU 5
TO_CPM EQU 0
NO_OP EQU 00H
RDFREE EQU 10H
WRFREE EQU 20H
HOLD EQU 40H
RDHELD EQU 50H
WRHELD EQU 60H
SECS01 EQU 00H
SECS10 EQU 01H
MINS01 EQU 02H
MINS10 EQU 03H
HRS01 EQU 04H
HRS10 EQU 05H
AM_PM EQU 05H
WKDAY EQU 06H
DAYS01 EQU 07H
DAYS10 EQU 08H
LEAPYR EQU 08H
MTHS01 EQU 09H
MTHS10 EQU 0AH
YRS01 EQU 0BH
YRS10 EQU 0CH
ROW EQU 01
COLM EQU 55

                    **********************
                    *                    *
                    *        MACROS      *
                    *                    *
                    **********************

TYPE:   MACRO MSG
        LXI D,MSG
        CALL TYPIST
        ENDMAC


PRNT1:  MACRO
        MOV A,M
        CALL RDDGT
        ADI 30H
        CALL PRNTCHAR
        ENDMAC
       
                   *****************************
                   *                           *
                   *         MAIN LOOP         *
                   *                           *
                   *****************************


CLOCK:   LXI SP,STACK    SETUP LOCAL STACK
CLKBGN:  CALL CLRHOM
         CALL BEEP
CLKRPT:  TYPE SIGNON
         CALL RESPONSE
         CPI 'X'
         JZ TO_CPM
         CPI 'S'
         JZ SETTIME
         CPI 'P'
         JZ PRNTTIME
         CPI 'C'
         JZ FOREVER
         TYPE BOOBOO
         JMP CLKBGN


                  ******************************
                  *                            *
                  *        SUBROUTINES         *
                  *                            *
                  ******************************

* CLEAR THE SCREEN AND HOME THE CURSOR :

clrhom:  TYPE CLEAR
         RET
clear:   db 1Ah,1Eh,24h ;1A=ASCII for clear screen
                        ;1E   "    "  home cursor
                        ;24   "    "  end/TEXT

                  *********************

* RING CURSOR BELL :

BEEP:   TYPE DING
        RET
ding:   DB 07h,24h     ;07=ASCII for bell,24=end/TEXT

                  *********************

* MASTER ROUTINE FOR GETTING TIME AND DATE INPUT FROM USER.
* POINTS HL AND DE TO BUFFER AND COMMAND TABLE RESPECTIVELY.
* BUFFER IS FILLED AND THEN DIGITS WRITTEN FROM BUFFER TO CLOCK.

SETTIME: CALL GETTIME    FILL THE TIME/DATE DIGIT BUFFER
         LXI H,DTABLE    POINT HL TO BUFFER
         LXI D,ATABLE    POINT DE TO COMMAND TABLE
         MVI B,14        SETUP B AS COUNTER
         MVI A,HOLD      STOP THE CLOCK
         OUT CLKCMD
SET1:    DCR B
         JZ SET2        IF ALL DONE THEN ------.
         MOV A,M        ELSE:GET DIGIT > A     |
         MOV C,A        & MOVE IT > C,         |
         LDAX D         GET COMMAND > A &      |
         CALL WRTDGT    WRITE DIGIT > CLOCK.   |
         INX H          BUMP                   |
         INX D          POINTERS               |
         JMP SET1       & LOOP.                |
SET2:    MVI A,NO_OP    CLEAR CMND PORT,  <----'
         OUT CLKCMD     
         CALL CLKPRNT
         JMP CLKBGN     & EXIT SUBROUTINE.

                   ****************

* NEXT S/R GETS DIGITS FROM CONSOLE INTO THE
* BUFFER POINTED TO BY HL.

GETTIME: TYPE ASKTIME
         LXI H,DTABLE
GET1:    CALL GETNUMB
         CPI 0DH
         JZ GETDATE
         ANI 0FH
         MOV M,A
         INX H
         JMP GET1
GETDATE: TYPE ASKDATE
GET2:    CALL GETNUMB
         CPI 0DH
         JZ GETDAY
         ANI 0FH
         MOV M,A
         INX H
         JMP GET2
GETDAY:  TYPE ASKDAY
GET3:    CALL GETNUMB
         CPI 0DH
         RZ
         ANI 0FH
         MOV M,A
         INX H
         JMP GET3

                    ******************

* NEXT S/R GETS A CHARACTER FROM CONSOLE :
*        :RETURNS ONLY 'LEGAL' CHARACTERS
*        :(i.e. A  C/R OR A NUMERAL)

GETNUMB: CALL RESPONSE
         CPI 0DH
         RZ
         CPI '0'
         JC GETNUMB
         CPI '9'+1
         JNC GETNUMB
         RET

                    ******************

* WRITE A DIGIT TO THE CLOCK :
* SET THE 24hr & LEAPYEAR BITS :
* ON CALL DIGIT COMMAND IS IN A :
*  "  "     "   IS IN C :

WRTDGT: PUSH PSW           SAVE THE COMMAND
        ADI HOLD           ADD HOLD COMMAND
        OUT CLKCMD         INSTRUCT CLOCK
        CPI AM_PM+HOLD     24 HR BYTE ?
        JNZ WRT1
        MOV A,C            IF SO :
        ADI 08H            SET 24 HR BIT.
        JMP WRT3
WRT1:   CPI LEAPYR+HOLD    LEAP YEAR BYTE ?
        JNZ WRT2
        MOV A,C            IF SO :
        ANI 03H            SET LEAPYEAR BIT.
        JMP WRT3
WRT2:   MOV A,C            DIGIT > A
WRT3:   OUT CLKDTA         DIGIT > CLOCK
        POP PSW            COMMAND > A
        ADI WRHELD         ADD WRITE & HOLD COMMANDS
        OUT CLKCMD
        SUI WRFREE         REMOVE 'WRITE' FROM COMMAND
        OUT CLKCMD         SEND LAST COMMAND OF SEQUENCE
        RET

                 *************************

* THE NEXT S/R READS A DIGIT FROM THE CLOCK : 
*             :THE LEAPYEAR AND 24hr MODE BITS ARE MASKED.
*             :ON CALL THE DIGIT COMMAND MUST BE IN A.
*             :ON RETURN THE DIGIT VALUE IS IN A.

RDDGT: ADI RDFREE          ADD 'READ' TO COMMAND.
       OUT CLKCMD
       CPI RDFREE+AM_PM   WILL IT CONTAIN 24hr BIT?
       IN CLKDTA          GET DIGIT
       RNZ
       SUI 8              KILL 24hr BIT
       RET

                ***************************

* MOVE CURSOR TO PREDEFINED ROW/COLUMN LOCATION

CRSR:    PUSH H       ;
         PUSH D
         PUSH B
         MVI E,1BH    ;ESC
         MVI C,2
         CALL 5
         MVI E,3DH    ;=
         MVI C,2
         CALL 5
         MVI E,ROW+31 ;ROW OUT
         MVI C,2
         CALL 5
         MVI E,COLM+31;COLUMN OUT
         MVI C,2
         CALL 5
         POP B
         POP D
         POP H         
         RET

                *************************

* NEXT S/R PRINTS THE CURRENT TIME AND DATE ONCE,COMPLETE
* WITH COLONS AND SLASHES,THEN RETURNS.

CLKPRNT: CALL CRSR
         LXI H,ATABLE      POINT HL TO TABLE OF COMMANDS
         CALL PRINT2       PRINT 1ST 2 DIGITS
         MVI A,':'
         CALL PRNTCHAR
         CALL PRINT2       PRINT NEXT 2 DIGITS
         MVI A,':'
         CALL PRNTCHAR
         CALL PRINT2       & NEXT 2
         MVI A,' '
         CALL PRNTCHAR
         MVI A,' '         & 2 SPACES
         CALL PRNTCHAR
         CALL PRINT2       & 2 MORE DIGITS
         MVI A,'/'
         CALL PRNTCHAR
         CALL PRINT2       & 2 MORE
         MVI A,'/'
         CALL PRNTCHAR
         CALL PRINT2       & LAST 2
         RET

                 **********************

PRINT2:  PRNT1
         INX H
         PRNT1
         INX H
         RET

               ***********************

PRNTTIME: CALL CLRHOM
          CALL CLKPRNT
          JMP CLKRPT

               ************************

* NEXT S/R PRINTS THE TIME, UPDATES IT ONCE EVERY SECOND,
* AND CONTINUES DOING SO UNTIL A ^C IS TYPED.

FOREVER: CALL CLRHOM
         MVI A,0AH
         CALL PRNTCHAR
FOR1:    MVI A,0DH
         CALL PRNTCHAR
         CALL CLKPRNT
         MVI A,SECS01
         CALL RDDGT
         MOV B,A
FOR2:    MVI A,SECS01
         CALL RDDGT
         CMP B
         JZ FOR2
         JMP FOR1

                   ***********************

RESPONSE: PUSH H
          MVI C,01    BIOS CHAR/IN
          CALL BIOS
          POP H
          CPI 'a'    RANGE CHECK UPPER CASE
          JC SKIP
          ANI 5FH    CONVERT TO UPPER CASE
SKIP:     ANI 7FH    STRIP OFF PARITY
          CPI 03H    CHECK FOR ^C
          JZ TO_CPM
          RET

                   ************************

* NEXT S/R PRINTS A CHARACTER ON THE SCREEN :
*   (ALSO WATCHES FOR ^C INPUT FROM CONSOLE).

PRNTCHAR: PUSH D      -.
          MOV E,A      |
          MVI C,2      | = PRINT CHARACTER
          PUSH H       |
          CALL BIOS   _|

          MVI C,0BH   -.
               *       | = CHECK CONSOLE
          CALL BIOS   _|

          POP H
          POP D

          ORA A        -.   IF A KEY WAS STRUCK
          CNZ RESPONSE  |   THEN GET CHARACTER 
               *        |   & CHECK FOR ^C.
               *       _|
          RET

                 **********************

TYPIST: PUSH H
        MVI C,09H
        CALL BIOS
        POP H
        RET

                     ************************
                     *                      *
                     *     MESSAGES,etc.    *
                     *                      *
                     ************************

SIGNON: DB 0DH,0AH,'                 CALENDER-CLOCK MASTER PROGRAM'
        DB 0DH,0AH,0DH,0AH
        DB 'TO SELECT A FUNCTION PLEASE HIT CORRESPONDING COMMAND KEY'
        DB 0DH,0AH,0DH,0AH
        DB '            FUNCTION                      COMMAND KEY',0DH,0AH
        DB ' SET THE TIME , DATE & WEEKDAY      =         S',0DH,0AH
        DB ' PRINT THE TIME & DATE (ONCE)       =         P',0DH,0AH
        DB ' PRINT THE TIME & DATE CONTINUOUSLY =         C',0DH,0AH
        DB ' EXIT TO OPERATING SYSTEM           =         X',0DH,0AH
        DB 0DH,0AH,'COMMAND = ?',08H,'$'


BOOBOO: DB 0DH,0AH,'SORRY,I DID NOT RECOGNIZE THAT COMMAND.'
        DB 0DH,0AH,'PLEASE TRY AGAIN.$'


ASKTIME: DB 0DH,0AH,'WHAT IS THE TIME (24hr FORMAT - HH:MM:SS)?'
         DB 0DH,0AH,'$'


ASKDATE: DB 0DH,0AH,'WHAT IS THE DATE (MM/DD/YY)?',0DH,0AH,'$'

ASKDAY:  DB 0DH,0AH,'WHAT IS THE WEEKDAY (SUNDAY = 0) ?',0DH,0AH,'$'

* DIGIT ADDRESS TABLE :
ATABLE: DB HRS10,HRS01,MINS10,MINS01,SECS10,SECS01,MTHS10,MTHS01
        DB DAYS10,DAYS01,YRS10,YRS01,WKDAY

* DIGIT INPUT BUFFER :
DTABLE: DS 13

* LOCAL STACK AREA :
        DS 32  16 LEVEL STACK
STACK:         * N.B.: STACKS GROW INTO LOW MEMORY!


                    *********************

                          END CLOCK