*****************************************************************
*                    AMPRO Computers Inc.                       *
*                          Date.asm                             *
*                                                               *
*                    Adapted from DATE.MAC                      *
*                       by Don Delwood,                         *
*                   with mods by Roger Warren                   *
*                                                               *
*  Additional modifications were made to allow update from      *
*  the Calendar/Clock board by Kenmore Computer Technologies    *
*                                                               *
*                 by Ernest J. Levesque                         *
*                                                               *
*       (changes are in lower case, ending with ******)         *
*                                                               *
*  Implementation is competed ajusting the equate "cbase" to the*
*  base port of the clock board.  Date functions as usual but   *
*  adding S after the command causes the date and time to be    *
*  taken from clock board.  Note that the time is also set.     *
*  Note that the posibility exists that if call to the clock    *
*  occurs during an update of the clock the wrong time could be *
*  set.  This could cured by looping through the clock update   *
*  routine until two passes match.  I may get around to that    *
*  implementation but current is satisfactory for my needs      *
*****************************************************************
;
; Version    date         by    History
; -------  --------     ------  --------
;   1.0    4 mar 86      fsw    Version 1.0 for use with bios 3.6
;
*---------------------------------------------------------------*

VER     EQU     10              ; version 1.0

CR      EQU     13
LF      EQU     10

LDIR    EQU     0B0EDH          ; z80 ldir

       ORG     100H
       JMP     BEGIN           ; jump over logo
HELP:   CALL    PRINT
       DB      CR,LF,LF
       DB      'DATE '
       DB      'Version ',VER/10+'0','.',VER MOD 10+'0',CR,LF
       DB      'AMPRO Computers Inc.'
       DB      CR,LF,'To change the date, enter change '
       DB      'on the command line as follows:',cr,lf,lf
       DB      'du>DATE mm-dd-yy',cr,lf
       DB      0
       JMP     EXIT
BEGIN:
       DW      73EDH,OLDSTK    ; save old stack pointer
       LXI     SP,LOCSTK       ; set new stack
;
       LXI     D,WBOOT         ; build bios entry table
       LHLD    1               ; get bios start
       LXI     B,51            ; bytes to move
       DW      LDIR            ; move it
;
       CALL    GETTBL          ; get address of next jmp tbl
       CPI     36              ; must be bios ver 3.6 or higher
       JC      BADVER          ; give message and exit
       LXI     D,NXTTBL        ; 'hl' has bios nxttbl address
       LXI     B,15            ;
       DW      LDIR            ; move the table
       LXI     H,0             ; make sure that clock is enabled
       CALL    TOD             ; get clock base address
       MOV     A,L             ; see if address of tick was returned
       ORA     H
       JZ      NOCLK           ; exit clock not enabled

; 'hl' has addres of clock

       LXI     D,SEC           ; move time
       LXI     B,6
       DW      LDIR            ; save time

; Everthing needed has been moved into program area now.
; parse command tail to see if time was entered on command line.
;
       LXI     H,80H           ; point to command tail
       MOV     A,M             ; get character count
       ANA     A               ; if zero nothing on cmd line
       STA     UPDATE          ; save possible entry on cmd line
       JZ      SHDATE          ; skip no char on command line
LOOP:   INX     H               ; point to first char on command line
       MOV     A,M
       CPI     ' '
       JZ      LOOP            ; filter leading spaces
                   ;*******                                       ******
      cpi 'S'      ;*******  See if set command is requested      ******
      jz  kendate  ;*******  Jump off to get date from clock port ******
                   ;*******                                       ******
       PUSH    H
       CALL    VALID           ; test for valid numeric ascii
       POP     H
       CALL    EVAL10
       CPI     12+1            ; see if more than december
       JNC     NVALMS
       STA     TMONTH          ; set temp month
       MOV     C,A             ; save month
       INX     H
       CALL    EVAL10
       PUSH    H
       LXI     H,MTHS-1        ;
       MVI     B,0
       DAD     B               ; point to number of days in month
       CMP     M               ; see if valid entry for the month
       POP     H
       JZ      CONT
       JNC     NVALMS
CONT:   STA     TDAY            ; set temp month
       INX     H
       CALL    EVAL10
       STA     YEAR            ; set year
       CALL    MD2J            ; convert the month/day to julian

SHDATE: CALL    J2MD            ; convert julian date to month/day
       LDA     TMONTH
       DCR     A               ; adjust
       MOV     E,A             ;
       ADD     A               ; times 2
       ADD     E               ; times 3
       MOV     E,A
       MVI     D,0
       LXI     H,AMONTHS       ; find month in string
       DAD     D
       LXI     D,MON
       LXI     B,3             ; move 3 bytes
       DW      LDIR

       LDA     TDAY
       CALL    BINASC
       DW      43EDH,DAY
       LDA     YEAR
       CALL    BINASC
       DW      43EDH,YR


       CALL    PRINT           ; print message
CURDAT: DB      'Current date is '
MON:    DB      '    '
DAY:    DB      '  , 19'
YR:     DB      '  '
       DB      0

;
; if time was not changed from the command line, do not place
; the time prameters back into the bios clock area.
;
       LDA     UPDATE
       ANA     A               ; if zero time was only displayed
       JZ      EXIT
;
; move the newly set time prameters to bios clock area
;
    lda   kenflag           ; Load the Kenmorre clock flag       *****
    cpi   0ffh              ; See if we set the flag for Kenmore *****
    jnz   oldexit           ; exit through former method if not  *****
    call  tod               ; get address of time counters       *****
    xchg                    ; bios time counter addresss to 'de' *****
    lxi   h,sec             ;                                    *****
    lxi   b,6               ; date only, not time                *****
    dw    ldir              ; move it to bios memory             *****
    jmp   exit              ;                                    *****
oldexit: CALL   TOD             ; get address of time counters *****
       LXI     D,3             ; offset to date
       DAD     D               ; add offset to 'hl'
       XCHG                    ; bios time counter addresss to 'de'
       LXI     H,JDAY          ;
       LXI     B,3             ; date only, not time
       DW      LDIR            ; move it to bios memory
       JMP     EXIT
;
; Get the seconds, minutes, hours, day, and  month from Kenmore Clock board
;
kenflag: ds 1                    ;  Flag for Set from Kenmore clock   ******
cbase  equ 0e0H                  ;  Port address of millisecond clock ******
kendate: mvi a,0ffh              ;  Set Clock flag for exit update    ******
      sta kenflag               ;  Store flag                        ******
      in  cbase+7               ;  Port address of month             ******
      call fix                  ;  change BCD from clock to binary   ******
      sta tmonth                ;  Store the month temporary         ******
      in  cbase+6               ;  Port address of day               ******
      call fix                  ;  change BCD from clock to binary   ******
      sta tday                  ;  Store the day temporary           ******
      in  cbase+4               ;  Port address of hour              ******
      call fix                  ;  change BCD from clock to binary   ******
      sta hour                  ;  Store hours                       ******
      in  cbase+3               ;  Port address of minutes           ******
      call fix                  ;  change BCD from clock to binary   ******
      sta min                   ;  Store minutes                     ******
      in  cbase+2               ;  Port address of second            ******
      call fix                  ;  change BCD from clock to binary   ******
      sta sec                   ;  Store seconds                     ******
      call md2j                 ;  Convert temp day month to julian  ******
      mvi a,86                  ;  Load the year                     ******
      sta year                  ;  Store                             ******
      jmp  shdate               ;  Show the date and exit            ******
;                                                                     ******
; FIX - Fix converts BCD from the Kenmorre clock to binary through    ******
;       existing routines                                             ******
;                                                                     ******
fix:   mov  c,a                  ;  place character in c for later    ******
      ani  0f0h                 ;  strip tens digit                  ******
      rrc                       ;  rotate to units                   ******
      rrc                       ;                                    ******
      rrc                       ;                                    ******
      rrc                       ;                                    ******
      adi 030h                  ; make into character                ******
      sta clockchr              ; store in two character string      ******
      mov a,c                   ; get back the character             ******
      ani 0fh                   ; strip units digit                  ******
      adi 030h                  ; make into character                ******
      sta clockchr+1            ; store in string                    ******
      lxi h,clockchr            ; point to clock string              ******
      jmp eval10                ; jmp to eval. let eval return       ******
clockchr: db '  ',0              ; this is the string that allows the ******
                                ; the use of eval10 to make binary   ******
;
; Test the command for valid time entry. Scan the command tail
; for along its legnth for the pattern hh:mm:ss. test for
; valid numeric characters. it has already been determined that
; somthing was entered on the command line
;
VALID:  LXI     H,80H           ; character count
       MOV     B,M             ; get number of characters typed
       INX     H
       DCR     B
       JZ      NVALMS          ; exit only spaces or one char on line
       MOV     A,M             ; get first char
       CPI     ' '
       JZ      VALID+4         ; filter the spaces

VAL1:   MOV     A,M
       INX     H               ; point to next char
       ANA     A               ; 00h is terminator or zero count
       RZ
       CPI     '/'
       JZ      HELP            ; show instructions
       CPI     '?'
       JZ      HELP            ; show insturctions
       CPI     '-'
       JZ      VAL1            ; delimeter ok
       CPI     '0'
       JC      NVALMS          ; less than ascii 0
       CPI     '9'+1
       JNC     NVALMS          ; more than ascii 9
       JMP     VAL1
;
NVALMS: CALL    PRINT
       DB      'Invalid date',cr,lf,0
       JMP     EXIT
;
; time of day TOD jmp was not in bios
;
NOCLK:
       CALL    PRINT
       DB      'Clock not installed',cr,lf,0
       JMP     EXIT
;
; wrong version bios
;
BADVER: CALL    PRINT
       DB      'Requires Bios 3.6 or higher.',cr,lf,0
                               ; fall through to exit

;
; Normal program exit. Restores system stack and returns
;
EXIT:
       DW      7BEDH,OLDSTK    ; recover old stack pointer
       RET

;
; Print string of characters terminated with zero '0'.
;
PRINT:  POP     H
       MOV     A,M             ; get byte
       ANA     A
       JZ      PRNEND
       PUSH    H               ;
       MOV     C,A
       CALL    CONOUT          ; call bios routine
       POP     H
       INX     H               ; next byte
       JMP     PRINT+1

PRNEND: XTHL                    ; hl has return
       RET

;***************************************************************
;               convert binary to ascii
; in:   a  - binary value
; out:  bc - ascii character (low high)   (mod. after Rich Conn)
;***************************************************************
BINASC: MVI     C,0             ; init count
       MVI     B,10

BIN1:   SUB     B
       JC      BINEXT
       INR     C
       JMP     BIN1

binext: ADD     B               ; A = ones digit  C = tens digit
       ADI     '0'
       MOV     B,A
       MOV     A,C
       ADI     '0'
       MOV     C,A
       RET

;***************************************************************
;       eval10 - convert ascii string to decimal value
; in:   hl - points to beginning of string
; out:  a  - e
;       de - value
;       hl - points to delimiter (error character)
;                                       (mod. after Rich Conn)
;***************************************************************

EVAL10: PUSH    B
       LXI     D,0             ; init de to zero

E10L:   MOV     A,M             ; next digit, check range '0'-'9'
       CPI     '0'
       JC      EVLOUT          ; less than ascii 0
       CPI     '9'+1
       JNC     EVLOUT          ; more than ascii 9
       SUI     '0'

MUL10:  PUSH    H               ; multiply DE by 10
       MOV     H,D
       MOV     L,E
       DAD     H               ; *2
       DAD     H               ; *4
       DAD     D               ; *5
       DAD     H               ; *10
       MOV     E,A             ; add in latest digit
       MVI     D,0
       DAD     D
       XCHG
       POP     H
       INX     H
       JMP     E10L

EVLOUT: MOV     A,E
       POP     B
       RET

;****************************************************************
;                 convert month/day to julian
;****************************************************************
MD2J:   LXI     D,MTHS-1        ; init month pointer
       LXI     H,0
       LDA     TMONTH          ; get binary month
       MOV     B,A             ; set count

MD2J1:  LDAX    D               ; get number of days in month
       ADD     L
       MOV     L,A             ; update 'l'
       CC      MD2J3           ; adjust 'h' if carry
       DCR     B
       INX     D               ; next month
       JNZ     MD2J1

MD2J2:  LDA     TDAY            ; get binary day
       MOV     E,A             ;
       MVI     D,0
       DAD     D               ; add the day
       DCX     H               ; adjust for ordinal 0
       SHLD    JDAY
       RET

MD2J3:  MVI     A,1             ; if carry add 1 to 'h'
       ADD     H
       MOV     H,A
       RET

;****************************************************************
;                 convert julian to month/day
;****************************************************************
J2MD:   LXI     D,MTHS          ; int month pointer
       LHLD    JDAY            ; julian day in 'hl'
       INX     H               ; adjust for ordinal 0
       XRA     A
       MOV     B,A             ; init high byte of sub with 0
       INR     A
       STA     TMONTH          ; init month to 1

J2MD1:  LDAX    D
       ORA     A               ; clear carry
       MOV     C,A
       MOV     A,L             ; may be day
       DW      42EDH           ; sbc hl,bc
       JC      J2MD2
       JZ      J2MD2
       LDA     TMONTH
       INR     A               ; update month
       STA     TMONTH
       INX     D
       JMP     J2MD1

J2MD2:  STA     TDAY            ; set day
       RET



       DB      0
MTHS:   DB      31,29,31,30,31,30,31,31,30,31,30,31
AMONTHS:
       DB      'JanFebMarAprMayJunJulAugSepOctNovDec'
; local stack area
;
       DS      32              ; 16 level stack
LOCSTK: DW      EXIT            ; exit point on top of stack
OLDSTK: DS      2               ; save for old stack
UPDATE  DS      1               ; flag for command entry
;
; bios jmp table, moved from the bios during init.
;
WBOOT:  DS      3               ; Warm start
CONST:  DS      3               ; Console status
CONIN:  DS      3               ; Console character in
CONOUT: DS      3               ; Console character out
LIST:   DS      3               ; List character out
PUNCH:  DS      3               ; Punch character out
READER: DS      3               ; Reader character in
HOME:   DS      3               ; Seek to home position
SELDSK: DS      3               ; Select disk
SETTRK: DS      3               ; Set track number
SETSEC: DS      3               ; Set sector number
SETDMA: DS      3               ; Set DMA address
READ:   DS      3               ; Read disk
WRITE:  DS      3               ; Write disk
LISTST: DS      3               ; Return list status
SECTRAN:DS      3               ; Sector translate

GETTBL: DS      3               ; Point to more jumps, returns bioss
                               ; version in 'a'.
NXTTBL:
SWAP:   DS      3               ; jmp swap
HD$INF: DS      3               ; get hd table info
PHTBAC: DS      3               ; get/set phytab acces
PAGET:  DS      3               ; get phytab entry address
TOD:    DS      3               ; get base address of clock tick

; time/date counters from bios

SEC:    DS      1
MIN:    DS      1
HOUR:   DS      1
JDAY:   DS      2               ; julian day 0-366 for leap year
YEAR:   DS      1 ; PRESET YEAR

TMONTH: DS      1               ; temp storage for month
TDAY:   DS      1               ; temp storage for day
TYEAR:  DS      1               ; temp storage for year

       END