home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / PROGRAMS / CLOCKK / MDCLCK13.LBR / SETCLOCK.AZM / SETCLOCK.ASM
Assembly Source File  |  2000-06-30  |  19KB  |  834 lines

  1. ;     -=[ SETCLOCK - Sets Date & Time on Real-Time Clock/Calendar ]=-
  2. ;
  3. ; Hardware specific for Oki MSM5832 real-time clock/calendar accessed
  4. ; via port B of Z80 PIO (port 79h = data, port 7Bh = control) or via
  5. ; 8255 parallel interface (port 30h = clock data, port 31h = clock address,
  6. ; port 32h = clock control, port 33h = 8255 control)
  7. ;
  8. ; Written in 8080 mnemonics for assembly with ASM (or equivalent) by John
  9. ; D. Osnes, 1084 6th Street #41, Albany, CA (9/30/86).  The author grate-
  10. ; fully acknowledges Mike Allen for his contribution of a clock design for
  11. ; Morrow Designs Rev.2 computers accessed via an 8255 parallel interface
  12. ; and for the corresponding READTIME and SETTIME routines which the 8255
  13. ; option herein is based on.
  14. ;
  15. ; USER BE AWARE:  the author has a Legacy clock accessed via a Z80 PIO, so
  16. ; the 8255 option in SETCLOCK is UNTESTED.  What should work may not and no
  17. ; fault should be attributed to Mike Allen's fine work.  For that matter,
  18. ; the author specifically disclaims any warranties, implied or otherwise,
  19. ; as to the performance and suitability of SETCLOCK.
  20. ;
  21. ; ADDITIONAL NOTES BY MIKE ALLEN:  I am quite indebted to John for not only
  22. ; this exceptional program, but for the matching CLOCKOUT.ASM program as well
  23. ; as his additions to the code in CADPRINT.ASM for the OKI 92 and 93 printers.
  24. ; The above 'USER BE AWARE' notice is no longer valid.  I have checked this and
  25. ; the CLOCKOUT routines with the 8255 option on my home-brew 8255 clock
  26. ; installed in my MD3 and they function as advertised.  Please note that the
  27. ; 'HIGHLIGHT' code I have included is for reverse video on the Morrow MDT60/70
  28. ; series of terminals which may not be applicable to your particular terminal.
  29. ;                              Mike Allen 11/16/86
  30. ;
  31. ;
  32. FALSE    EQU    0
  33. TRUE    EQU    NOT FALSE
  34.  
  35.     ORG    0100H
  36.     JMP    CLOCK
  37.  
  38. VERSN:    DB    VERSN2,CR,LF
  39.     DB    '   SETCLOCK v1.0 for Oki MSM5832 Clock/Calendar',CR,LF
  40.     DB    '(SPACE increments value, CR enters it, ^C aborts)',CR,LF
  41.     DB    LF
  42. VERSN2    EQU    $-VERSN-1
  43.  
  44. ; *********************** USER SPECIFICATIONS **************************
  45.  
  46. ; If terminal has highlighting feature, specify start/stop sequence in
  47. ; form:  #bytes, byte1, byte2, ...  (simply zero the first byte of each
  48. ; sequence if terminal does not have highlighting feature).
  49.  
  50. HION:    DB    3        ; Sequence to start-highlighting
  51.     DB    ESC,'G','4',0,0    ; MDT60/70 Reverse Video.
  52.     DB    0,0,0,0,0
  53.  
  54. HIOFF:    DB    3        ; Sequence to stop-highlighting
  55.     DB    ESC,'G','0',0,0    ; MDT60/70 Normal Video
  56.     DB    0,0,0,0,0
  57.  
  58. HIPAR:    DB    0        ; If parity bit of highlighted chars
  59.                 ; must be set, make HIPAR 80h; otherwise,
  60.                 ; HIPAR must be zero!
  61.  
  62. ; ********************* END OF USER SPECIFICATIONS ************************
  63.  
  64. ; ************************ ASSEMBLY-TIME OPTIONS **************************
  65.  
  66. SPEED    EQU    40        ; 10 times speed of CPU in MHz (40=4 MHz)
  67.  
  68. Z80PIO    EQU    FALSE        ; If true, clock accessed via Z80 PIO
  69.                 ; If false, clock accessed via 8255
  70.  
  71.      IF    Z80PIO        ; Z80 PIO ports (defaults based on Legacy clock)
  72. CLKDAT    EQU    79H        ; Data port for clock (Z80 PIO port B)
  73. CLKCTL    EQU    7BH        ; Control port for clock (Z80 PIO port B)
  74.      ENDIF    ; Z80PIO
  75.  
  76.      IF    NOT Z80PIO    ; 8255 ports (defaults based on Mike Allen's
  77.                 ; design for Morrow Designs Rev.2 clock)
  78. CLKDAT    EQU    30H        ; Data port for clock (8255 port A)
  79. CLKADR    EQU    31H        ; Address port for clock (8255 port B)
  80. CLKCTL    EQU    32H        ; Control port for clock (8255 port C)
  81. PRTCTL    EQU    33H        ; 8255 control port
  82.      ENDIF    ; NOT Z80PIO (8255)
  83.  
  84. ; *************************** END OF OPTIONS ******************************
  85.  
  86. BDOS    EQU    0005H        ; BDOS entry point
  87.  
  88. DCONIO    EQU    06H        ; BDOS "Direct Console I/O" function
  89.  
  90. CNTLC    EQU    'C'-'@'        ; ^C=abort
  91. BELL    EQU    'G'-'@'        ; ^G=bell
  92. BS    EQU    'H'-'@'        ; ^H=backspace
  93. LF    EQU    'J'-'@'        ; ^J=linefeed
  94. CR    EQU    'M'-'@'        ; ^M=carriage return
  95. ESC    EQU    '['-'@'        ; ^[=escape
  96.  
  97. CLOCK:    LXI    H,0        ; Set up local stack
  98.     DAD    SP
  99.     SHLD    LSTACK
  100.     LXI    SP,LSTACK
  101.  
  102.     LXI    H,VERSN        ; Display signon msg
  103.     CALL    DSTRNG
  104.  
  105.     CALL    SWPCLK        ; Sweep thru 11 addresses of clock
  106.                 ; and store in memory (sec's not read)
  107.     LXI    H,MIN        ; Convert BCD digits to binary values
  108.     LXI    D,NUMIN
  109.     CALL    BCDBIN        ; Minutes
  110.     MOV    B,M        ; Hours
  111.     INX    H
  112.     MOV    C,M
  113.     MVI    A,8
  114.     ANA    C
  115.     STAX    D        ; 12/24-hour clock
  116.     INX    D
  117.     MVI    A,0
  118.     JNZ    CLOCK2
  119.     MVI    A,4
  120. CLOCK2:    ANA    C
  121.     STAX    D        ; a.m./p.m. if 12-hour clock
  122.     INX    D
  123.     MVI    A,3
  124.     ANA    C
  125.     MOV    C,A
  126.     CALL    BCDBI2        ; Hours
  127.     INX    H        ; Skip day-of-week
  128.     INX    D
  129.     MOV    B,M
  130.     INX    H
  131.     MOV    A,M
  132.     ANI    3
  133.     MOV    C,A
  134.     CALL    BCDBI2        ; Day-of-month
  135.     CALL    BCDBIN        ; Month
  136.     CALL    BCDBIN        ; Year
  137.  
  138.     LDA    FG1224        ; Get 12/24-hour selection
  139.     ORA    A
  140. CLOCK4:    MVI    A,12
  141.     JZ    CLOCK6
  142.     MVI    A,24
  143. CLOCK6:    CALL    HIDECI
  144.     PUSH    PSW
  145.     LXI    H,HRCLK
  146.     CALL    DSTRNG
  147.     POP    PSW
  148.     CALL    INPUT
  149.     JNZ    CLOCK8
  150.     CPI    24
  151.     JMP    CLOCK4
  152.  
  153. CLOCK8:    RRC            ; A=12 or 24 selection
  154.     ANI    8
  155.     LXI    H,FG1224
  156.     CMP    M        ; 12/24-hour selection changed?
  157.     JZ    CLCK11        ; NO
  158.     MOV    M,A        ; YES, store selection
  159.     INX    H
  160.     JC    CLCK10        ; Carry set if 24-hour -> 12-hour
  161.     MOV    A,M        ; 12-hour -> 24-hour
  162.     ORA    A        ; Is current time a.m.?
  163.     JZ    CLCK11        ; YES
  164.     MVI    M,0        ; NO, so clear p.m. flag
  165.     INX    H
  166.     MOV    A,M        ; Add 12 to current hour
  167.     ADI    12
  168.     MOV    M,A
  169.     JMP    CLCK11
  170. CLCK10:    INX    H        ; 24-hour -> 12-hour
  171.     MOV    A,M        ; Current hour > 11?
  172.     SUI    12
  173.     JC    CLCK11        ; NO
  174.     MOV    M,A        ; YES, so hour-12 p.m.
  175.     DCX    H
  176.     MVI    M,4
  177.  
  178. CLCK11:    MVI    D,HRCLK2+1    ; Clear line of display
  179. CLCK12:    MVI    E,' '
  180.     CALL    REPEAT
  181.     MVI    E,CR
  182.     CALL    DCHAR
  183.  
  184.     LDA    NUMNTH        ; Display current date
  185.     CALL    DECIML
  186.     MVI    E,'/'
  187.     CALL    DCHAR
  188.     LDA    NUDAY
  189.     CALL    DECIML
  190.     MVI    E,'/'
  191.     CALL    DCHAR
  192.     LDA    NUYEAR
  193.     CALL    DECIML
  194.     MVI    E,CR
  195.     CALL    DCHAR
  196.  
  197.     LDA    NUMNTH        ; Get month
  198.     MVI    B,1
  199.     MVI    C,13
  200.     CALL    GETVAL
  201.     STA    NUMNTH
  202.     CALL    DECIML
  203.     MVI    E,'/'
  204.     CALL    DCHAR
  205.  
  206.     DCR    A        ; Get day-of-month
  207.     LXI    H,DOM
  208.     ADD    L
  209.     MOV    L,A
  210.     MVI    A,0
  211.     ADC    H
  212.     MOV    H,A
  213.     MOV    C,M
  214.     INR    C
  215.     LDA    NUDAY
  216.     CALL    GETVAL
  217.     STA    NUDAY
  218.     CALL    DECIML
  219.     MVI    E,'/'
  220.     CALL    DCHAR
  221.  
  222.     LDA    NUYEAR        ; Get year
  223.     LXI    B,100
  224.     CALL    GETVAL
  225.     STA    NUYEAR
  226.     CALL    DECIML
  227.  
  228.     ORA    A        ; Leap year if year is multiple of 4
  229.     JZ    CLCK14        ; but not zero (for 20th century)
  230.     ANI    3
  231.     JNZ    CLCK14
  232.     MVI    A,4        ; Leap year
  233.     STA    LYFLAG
  234.     JMP    CLCK16
  235. CLCK14:    LXI    H,NUDAY        ; Not leap year, so can't be Feb 29
  236.     MOV    A,M
  237.     CPI    29
  238.     JNZ    CLCK16
  239.     INX    H
  240.     MOV    A,M
  241.     CPI    2
  242.     JNZ    CLCK16
  243.     LXI    H,FEB29        ; Feb 29 in non-leap year, so display
  244.     CALL    DSTRNG        ; error msg and wait for user to read
  245.     LDA    NUYEAR        ; it
  246.     CALL    DECIML
  247.     LXI    H,WAIT
  248.     CALL    DSTRNG
  249.     CALL    INPUT
  250.     MVI    E,CR        ; Clear error msg
  251.     CALL    DCHAR
  252.     MVI    D,FEB292+WAIT2+9
  253.     JMP    CLCK12        ; Get date again
  254.  
  255. CLCK16:    LXI    H,NUYEAR    ; Calculate day-of-week (algorithm for
  256.     MVI    D,0        ; 20th century courtesy DDJ, Jun'83)
  257.     MOV    E,M        ; DE=year
  258.     DCX    H
  259.     MOV    A,M        ; A=month
  260.     MOV    H,D
  261.     SUI    3        ; Jan or Feb?
  262.     JNC    CLCK18        ; NO
  263.     ADI    12        ; YES, so add 12 to month
  264.     DCX    D        ; and substract 1 from year
  265. CLCK18:    MOV    L,A        ; HL=month-3
  266.     MOV    A,D        ; Date before Mar 1, 1900?
  267.     ORA    A
  268.     JZ    CLCK20        ; NO
  269.     MOV    D,H        ; YES, so calculate day in 20th century
  270.     MOV    A,L        ; A=month (10=Jan, 11=Feb)
  271.     MOV    L,H
  272.     CPI    10        ; Jan, 1900?
  273.     JZ    CLCK22        ; YES, so day in 20th century=day of month
  274.     MVI    L,31        ; NO, so day in 20th century=day of month+31
  275.     JMP    CLCK22
  276.  
  277. CLCK20:    XCHG            ; DE=month, HL=year
  278.     PUSH    D        ; Save month
  279.     LXI    D,1461        ; Multiply year by 1461
  280.     CALL    MULWW
  281.     LXI    B,4        ; Divide product by 4
  282.     CALL    DIVLW
  283.     POP    H        ; Restore HL=month
  284.     PUSH    D        ; Save INT((1461*year)/4)
  285.     LXI    D,153        ; Multiply month by 153
  286.     CALL    MULWW
  287.     INX    H        ; Add 2 to product
  288.     INX    H
  289.     LXI    B,5        ; Divide sum by 5
  290.     CALL    DIVLW        ; DE=INT((153*month+2)/5)
  291.     POP    H        ; Restore HL=INT((1461*year)/4)
  292.     DAD    D        ; HL=days from 3/1/1900 to month/1/19yr
  293.     LXI    D,3        ; Add offset of 3 to days to make 3/1/1900
  294.     DAD    D        ; be day-of-week 4 (Thursday)
  295. CLCK22:    LDA    NUDAY
  296.     MOV    E,A        ; DE=day of month
  297.     DAD    D        ; HL=days from 3/1/1900 to date + 4
  298.     MOV    E,D
  299.     LXI    B,7        ; Divide days by 7
  300.     CALL    DIVLW        ; L=day-of-week (0=Sunday)
  301.     MOV    A,L
  302.     STA    NUDOW
  303.  
  304.     MVI    D,2        ; Skip a couple spaces
  305.     MVI    E,' '
  306.     CALL    REPEAT
  307.     LDA    FG1224        ; 12-hour clock?
  308.     ORA    A
  309.     JNZ    CLCK24        ; NO, 24-hour clock
  310.     MVI    A,STC        ; YES, so modify GETVAL routine to display
  311.     STA    GETVA6        ; a.m./p.m. when hour increments 11 -> 0
  312.     LXI    B,12
  313.     LDA    AMPMFG        ; a.m.?
  314.     ORA    A
  315.     JZ    CLCK26        ; YES, msg for a.m./p.m. display OK
  316.     MVI    A,'p'        ; NO, change msg for display to p.m.
  317.     STA    AMPM
  318.     JMP    CLCK26
  319.  
  320. CLCK24:    MVI    A,AMPM-TIMSG-2    ; 24-hour clock, so don't display a.m./p.m.
  321.     STA    TIMSG
  322.     LXI    B,24
  323.  
  324. CLCK26:    CALL    DTIME4        ; Display time
  325.  
  326.     LDA    NUHOUR        ; Get hour
  327.     CALL    GETVAL
  328.     STA    NUHOUR
  329.     CALL    DECIML
  330.     MVI    E,':'
  331.     CALL    DCHAR
  332.     MVI    A,0B7H        ; Restore GETVAL routine with op code
  333.     STA    GETVA6        ; B7h = ORA A (if 12-hour clock)
  334.  
  335.     LDA    NUMIN        ; Get minute
  336.     LXI    B,60
  337.     CALL    GETVAL
  338.     STA    NUMIN
  339.     CALL    DECIML
  340.     LXI    H,TIMSG
  341.     CALL    DSTRNG
  342.  
  343.     LXI    D,NUYEAR    ; Convert date/time to BCD digits
  344.     LXI    H,YEAR+1
  345.     CALL    BINBCD        ; Year
  346.     CALL    BINBCD        ; Month
  347.     CALL    BINBCD        ; Day-of-month
  348.     LDAX    D        ; Day-of-week (no conversion)
  349.     DCX    D
  350.     MOV    M,A
  351.     DCX    H
  352.     CALL    BINBCD        ; Hour
  353.     LDAX    D        ; a.m./p.m. flag
  354.     MOV    B,A
  355.     DCX    D
  356.     LDAX    D        ; 12/24-hour flag
  357.     ORA    B
  358.     PUSH    PSW        ; Save flags
  359.     DCX    D
  360.     CALL    BINBCD        ; Minute
  361.     MOV    A,M        ; Leap-year flag
  362.     MVI    M,0        ; Zero 10's digit of seconds
  363.     LXI    H,DAY+1        ; Add leap-year flag to 10's digit of
  364.     ORA    M        ; day-of-month
  365.     MOV    M,A
  366.     POP    PSW        ; Restore a.m./p.m. & 12/24-hour flags
  367.     LXI    H,HOUR+1    ; and add them to 10's digit of hour
  368.     ORA    M
  369.     MOV    M,A
  370.  
  371.     LXI    H,START        ; Display prompt to set clock on minute
  372.     CALL    DSTRNG        ; and wait for user's response
  373.     CALL    INPUT
  374.  
  375.     LXI    H,YEAR+1    ; Set 13 addr of clock with date/time
  376.     CALL    SETCLK
  377.  
  378. EXIT:    LHLD    LSTACK        ; Restore user's stack
  379.     SPHL
  380.     RET            ; Return to CCP
  381.  
  382. ; **************************** FUNCTIONS *******************************
  383.  
  384. ; Sweep through 11 addresses of clock calendar and store BCD contents
  385. ; (don't bother reading seconds, which are always zeroed)
  386.  
  387. SWPCLK:    MVI    A,11
  388.     MVI    E,2
  389.     LXI    H,MIN
  390. SWPCL2:    PUSH    PSW
  391.     CALL    RDCLOK
  392.     MOV    M,A
  393.     INR    E
  394.     INX    H
  395.     POP    PSW
  396.     DCR    A
  397.     JNZ    SWPCL2
  398.     RET
  399.  
  400. ; Convert pair of BCD digits pointed to by HL to binary value and
  401. ; store at addr in DE
  402.  
  403. BCDBIN:    MOV    B,M
  404.     INX    H
  405.     MOV    C,M
  406. BCDBI2:    INX    H
  407.     MOV    A,C
  408.     ADD    A
  409.     ADD    A
  410.     ADD    C
  411.     ADD    A
  412.     ADD    B
  413.     STAX    D
  414.     INX    D
  415.     RET
  416.  
  417. ; Convert binary value pointed to by DE to pair of BCD digits and store
  418. ; 10's digit at addr given in HL and 1's digit at addr in HL minus 1
  419.  
  420. BINBCD:    LDAX    D
  421.     DCX    D
  422.     MVI    C,0FFH
  423. BINBC2:    INR    C
  424.     MOV    B,A
  425.     SUI    10
  426.     JNC    BINBC2
  427.     MOV    M,C
  428.     DCX    H
  429.     MOV    M,B
  430.     DCX    H
  431.     RET
  432.  
  433. ; Display A in decimal with highlighting if possible
  434.  
  435. HIDECI:    PUSH    PSW
  436.     LXI    H,HION
  437.     CALL    DSTRNG
  438.     LDA    HIPAR
  439.     STA    PARITY
  440.     POP    PSW
  441.     CALL    DECIML
  442.     PUSH    PSW
  443.     LXI    H,HIOFF
  444.     CALL    DSTRNG
  445.     STA    PARITY
  446.     POP    PSW
  447.     RET
  448.  
  449. ; Toggle a.m./p.m. and display mm:00 x.m.
  450.  
  451. DTIME:    PUSH    PSW        ; Toggle a.m./p.m. flag and display
  452.     MVI    A,4
  453.     LXI    H,AMPMFG
  454.     XRA    M
  455.     MOV    M,A
  456.     MVI    A,'p'
  457.     LXI    H,AMPM
  458.     CMP    M
  459.     MOV    M,A
  460.     JNZ    DTIME2
  461.     MVI    M,'a'
  462. DTIME2:    POP    PSW
  463. DTIME4:    MVI    D,2        ; Skip a couple spaces (hours)
  464.     MVI    E,' '
  465.     CALL    REPEAT
  466.     MVI    E,':'        ; Colon separator
  467.     CALL    DCHAR
  468.     PUSH    PSW
  469.     LDA    NUMIN        ; Minutes
  470.     CALL    DECIML
  471.     LXI    H,TIMSG        ; :00 x.m. if 12-hour clock
  472.     CALL    DSTRNG        ; :00 if 24-hour clock
  473.     LDA    TIMSG        ; Backspace to beginning of time
  474.     ADI    5
  475.     MOV    D,A
  476.     MVI    E,BS
  477.     POP    PSW        ; Fall thru REPEAT
  478.  
  479. ; Display char in E, D times
  480.  
  481. REPEAT:    PUSH    D
  482.     CALL    DCHAR
  483.     POP    D
  484.     DCR    D
  485.     JNZ    REPEAT
  486.     RET
  487.  
  488. ; Display string pointed to by HL, where first byte is number
  489. ; of bytes in string
  490.  
  491. DSTRNG:    MOV    A,M
  492.     ORA    A
  493.     RZ
  494. DSTRN2:    INX    H
  495.     MOV    E,M
  496.     CALL    DCHAR
  497.     DCR    A
  498.     JNZ    DSTRN2
  499.     RET
  500.  
  501. ; Display A in decimal (2 digits with leading zeroes)
  502.  
  503. DECIML:    PUSH    PSW
  504.     MVI    E,0FFH
  505. DECIM2:    INR    E
  506.     MOV    D,A
  507.     SUI    10
  508.     JNC    DECIM2
  509.     MOV    A,E
  510.     CALL    DECIM3
  511.     CALL    DECIM3
  512.     POP    PSW
  513.     RET
  514. DECIM3:    ADI    '0'
  515. PARITY    EQU    $+1
  516.     ORI    0        ; Set parity bit if needed for highlighting
  517.     MOV    E,A
  518.     MOV    A,D        ; Fall thru DCHAR
  519.  
  520. ; Display char in E using Direct Console Output
  521.  
  522. DCHAR:    PUSH    PSW
  523.     PUSH    B
  524.     PUSH    H
  525.     MVI    C,DCONIO
  526.     CALL    BDOS
  527.     POP    H
  528.     POP    B
  529.     POP    PSW
  530.     RET
  531.  
  532. ; Get input using Direct Console Input (only SPACE, CR, and ^C recognized,
  533. ; where ^C aborts, zero flag set if SPACE, and zero flag clear if CR)
  534.  
  535. INPUT:    PUSH    PSW
  536.     PUSH    B
  537. INPUT2:    MVI    C,DCONIO
  538.     MVI    E,0FFH
  539.     CALL    BDOS
  540.     ORA    A
  541.     JZ    INPUT2
  542.     CPI    CNTLC
  543.     JZ    EXIT
  544.     CPI    CR
  545.     JZ    INPUT4
  546.     SUI    ' '
  547.     JNZ    INPUT2
  548.     DCR    A
  549. INPUT4:    MOV    E,A
  550.     POP    B
  551.     POP    PSW
  552.     INR    E
  553.     RET
  554.  
  555. ; Display value in A, increment it if user enters SPACE, and repeat
  556. ; until user enters CR (lower and upper bounds on A are B and C-1,
  557. ; respectively).
  558.  
  559. GETVAL:    CMP    B
  560.     JC    GETVA4
  561. GETVA2:    CMP    C
  562.     JC    GETVA8
  563. GETVA4:    MOV    A,B
  564. GETVA6:    ORA    A        ; ORA A will clear carry flag, so DTIME
  565.     CC    DTIME        ; routine will never be called unless ORA A
  566.                 ; is replaced by STC when hours are being
  567.                 ; entered on 12-hour clock
  568. GETVA8:    CALL    HIDECI
  569.     MVI    D,2
  570.     MVI    E,BS
  571.     CALL    REPEAT
  572.     CALL    INPUT
  573.     RNZ
  574.     INR    A
  575.     JMP    GETVA2
  576.  
  577. ; Multiply HL*DE and return 32-bit product in (DE,HL)
  578.  
  579. MULWW:    MOV    B,H
  580.     MOV    C,L
  581.     LXI    H,0
  582.     MVI    A,16
  583. MULWW1:    PUSH    PSW
  584.     DAD    H
  585.     XCHG
  586.     MOV    A,L
  587.     ADC    L
  588.     MOV    L,A
  589.     MOV    A,H
  590.     ADC    H
  591.     MOV    H,A
  592.     XCHG
  593.     JNC    MULWW2
  594.     DAD    B
  595.     JNC    MULWW2
  596.     INX    D
  597. MULWW2:    POP    PSW
  598.     DCR    A
  599.     JNZ    MULWW1
  600.     RET
  601.  
  602. ; Divide (DE,HL) by BC and return quotient to DE and
  603. ; remainder (modulo) to HL
  604.  
  605. DIVLW:    XCHG
  606.     MVI    A,16
  607. DIVLW1:    PUSH    PSW
  608.     XCHG
  609.     DAD    H
  610.     XCHG
  611.     MOV    A,L
  612.     ADC    L
  613.     MOV    L,A
  614.     MOV    A,H
  615.     ADC    H
  616.     MOV    H,A
  617.     MOV    A,L
  618.     SBB    C
  619.     MOV    L,A
  620.     MOV    A,H
  621.     SBB    B
  622.     MOV    H,A
  623.     JNC    DIVLW3
  624.     DAD    B
  625. DIVLW2:    POP    PSW
  626.     DCR    A
  627.     JNZ    DIVLW1
  628.     RET
  629. DIVLW3:    INX    D
  630.     JMP    DIVLW2
  631.  
  632.      IF    Z80PIO
  633. ; *************************************************************************
  634. ; *    Routine reads E=addr from clock interfaced by Z80 PIO and returns *
  635. ; *    1 BCD digit in A                          *
  636. ; *************************************************************************
  637.  
  638. HOLD    EQU    10H        ; Mask to halt clock
  639. READ    EQU    20H        ; Mask to read clock
  640. WRITE    EQU    40H        ; Mask to set clock
  641. ADDRIN    EQU    80H        ; Mask to enter addr
  642. MODE3    EQU    0CFH        ; Byte to set clock port (Z80 PIO) to mode 3
  643.  
  644. RDCLOK:    MVI    A,MODE3        ; Set clock port to mode 3
  645.     OUT    CLKCTL        ; With all bits for output
  646.     XRA    A
  647.     OUT    CLKCTL
  648.     MVI    A,ADDRIN    ; Send addr to clock
  649.     ORA    E
  650.     OUT    CLKDAT
  651.     MOV    A,E        ; Latch addr
  652.     OUT    CLKDAT
  653.     MVI    A,MODE3        ; Set lower 4 bits of clock port
  654.     OUT    CLKCTL        ; To input
  655.     MVI    A,0FH
  656.     OUT    CLKCTL
  657.     MVI    A,HOLD        ; Halt clock
  658.     OUT    CLKDAT
  659. RDCLK1    EQU    (150*SPEED)/170
  660.     MVI    A,RDCLK1    ; Wait 150 microseconds
  661. RDCLK2:    SUI    1
  662.     JNC    RDCLK2
  663.     MVI    A,READ+HOLD    ; Send read request
  664.     OUT    CLKDAT
  665. RDCLK3    EQU    (6*SPEED)/170
  666.     MVI    A,RDCLK3    ; Wait 6 microseconds
  667. RDCLK4:    SUI    1
  668.     JNC    RDCLK4
  669.     IN    CLKDAT        ; Get BCD digit (in lower 4 bits)
  670.     ANI    0FH        ; Strip 4 high bits
  671.     MOV    B,A        ; Save digit
  672.     XRA    A        ; Clear read request & restart clock
  673.     OUT    CLKDAT
  674.     MOV    A,B        ; Return BCD digit in A
  675.     RET
  676.  
  677. ; *************************************************************************
  678. ; *    Routine sets 13 addresses of clock interfaced by Z80 PIO with BCD *
  679. ; *    digits, beginning at 10's digit of years (addr 12) pointed to by  *
  680. ; *    HL and working down to 1's digit of seconds (addr 0)          *
  681. ; *************************************************************************
  682.  
  683. SETCLK:    MVI    D,12        ; Set addr 12->0 of clock
  684.     MVI    A,MODE3        ; Set clock port to mode 3
  685.     OUT    CLKCTL        ; with all bits for output
  686.     XRA    A
  687.     OUT    CLKCTL
  688.     MVI    A,HOLD        ; Halt clock
  689.     OUT    CLKDAT
  690. SETCL1    EQU    (150*SPEED)/170
  691.     MVI    A,SETCL1    ; Wait 150 microseconds
  692. SETCL2:    SUI    1
  693.     JNC    SETCL2
  694. SETCL3:    MVI    A,ADDRIN+HOLD    ; Send addr to clock
  695.     ORA    D
  696.     OUT    CLKDAT
  697.     MVI    A,HOLD        ; Latch addr
  698.     ORA    D
  699.     OUT    CLKDAT
  700.     MVI    A,HOLD        ; Send value to clock
  701.     ORA    M
  702.     OUT    CLKDAT
  703.     MOV    E,A
  704.     MVI    A,WRITE        ; Strobe write on
  705.     ORA    E
  706.     OUT    CLKDAT
  707.     DCX    H        ; Decrement digit pointer
  708.     MOV    A,E        ; Strobe write off
  709.     OUT    CLKDAT
  710.     MOV    A,D        ; Decrement clock addr
  711.     SUI    1
  712.     MOV    D,A
  713.     JNC    SETCL3        ; Set next addr if non-negative
  714.     XRA    A        ; Restart clock
  715.     OUT    CLKDAT
  716.     RET
  717.      ENDIF    ; Z80PIO
  718.  
  719.      IF    NOT Z80PIO    ; (8255)
  720. ; *************************************************************************
  721. ; *    Routine reads E=addr from clock interfaced by 8255 and returns      *
  722. ; *    1 BCD digit in A (based on Mike Allen's READTIME in MDCLCK11.LBR) *
  723. ; *************************************************************************
  724.  
  725. RDCLOK:    MVI    A,90H        ; Set up 8255
  726.     OUT    PRTCTL
  727.     MVI    A,20H        ; Send read request to clock
  728.     OUT    CLKCTL
  729.     MOV    A,E        ; Send address to clock
  730.     OUT    CLKADR
  731. RDCLK1    EQU    (6*SPEED)/170
  732.     MVI    A,RDCLK1    ; Wait 6 microseconds
  733. RDCLK2:    SUI    1
  734.     JNC    RDCLK2
  735.     IN    CLKDAT        ; Get BCD digit (in lower 4 bits)
  736.     ANI    0FH        ; Strip 4 high bits
  737.     MOV    B,A        ; Save digit
  738.     XRA    A        ; Clear read request
  739.     OUT    CLKCTL
  740.     MOV    A,B        ; Return BCD digit in A
  741.     RET
  742.  
  743. ; *************************************************************************
  744. ; *    Routine sets 13 addresses of clock interfaced by 8255 with BCD      *
  745. ; *    digits, beginning at 10's digit of years (addr 12) pointed to by  *
  746. ; *    HL and working down to 1's digit of seconds (addr 0) (based on      *
  747. ; *    Mike Allen's SETTIME in MDCLCK11.LBR)                  *
  748. ; *************************************************************************
  749.  
  750. SETCLK:    MVI    D,12        ; Set addr 12->0 of clock
  751.     MVI    A,80H        ; Set up 8255
  752.     OUT    PRTCTL
  753.     MVI    A,10H        ; Halt clock
  754.     OUT    CLKCTL
  755. SETCL1    EQU    (150*SPEED)/170
  756.     MVI    A,SETCL1    ; Wait 150 microseconds
  757. SETCL2:    SUI    1
  758.     JNC    SETCL2
  759. SETCL3:    MOV    A,D        ; Send addr to clock
  760.     OUT    CLKADR
  761.     MOV    A,M        ; Send value to clock
  762.     OUT    CLKDAT
  763.     MVI    A,50H        ; Strobe write on
  764.     OUT    CLKCTL
  765.     DCX    H        ; Decrement digit pointer
  766.     MVI    A,10H        ; Strobe write off
  767.     OUT    CLKCTL
  768.     MOV    A,D        ; Decrement clock addr
  769.     SUI    1
  770.     MOV    D,A
  771.     JNC    SETCL3        ; Set next addr if non-negative
  772.     XRA    A        ; Restart clock
  773.     OUT    CLKCTL
  774.     MVI    A,90H        ; Restore 8255
  775.     OUT    PRTCTL
  776.     RET
  777.      ENDIF    ; NOT Z80PIO (8255)
  778.  
  779. ; ***************************** DATA AREAS ********************************
  780.  
  781. HRCLK:    DB    HRCLK2
  782.     DB    '-Hour Clock',CR
  783. HRCLK2    EQU    $-HRCLK-1
  784.  
  785. FEB29:    DB    FEB292
  786.     DB    BELL,'  No Feb 29 in 19'
  787. FEB292    EQU    $-FEB29-1
  788.  
  789. WAIT:    DB    WAIT2
  790.     DB    '!  CR to continue: '
  791. WAIT2    EQU    $-WAIT-1
  792.  
  793. TIMSG:    DB    TIMSG2
  794.     DB    ':00 '
  795. AMPM:    DB    'a.m.'
  796. TIMSG2    EQU    $-TIMSG-1
  797.  
  798. START:    DB    START2
  799.     DB    '  CR on minute to set clock: '
  800. START2    EQU    $-START-1
  801.  
  802. DOM:    DB    31,29,31,30    ; Number of days in each
  803.     DB    31,30,31,31    ; month (in leap years)
  804.     DB    30,31,30,31
  805.  
  806.     DB    0
  807. LYFLAG:    DB    0        ; Leap year mask
  808.  
  809. MIN    EQU    $
  810. HOUR    EQU    MIN+2
  811. DOW    EQU    HOUR+2
  812. DAY    EQU    DOW+1
  813. MNTH    EQU    DAY+2
  814. YEAR    EQU    MNTH+2
  815.  
  816. NUMIN    EQU    YEAR+2
  817. FG1224    EQU    NUMIN+1
  818. AMPMFG    EQU    FG1224+1
  819. NUHOUR    EQU    AMPMFG+1
  820. NUDOW    EQU    NUHOUR+1
  821. NUDAY    EQU    NUDOW+1
  822. NUMNTH    EQU    NUDAY+1
  823. NUYEAR    EQU    NUMNTH+1
  824.  
  825. LSTACK    EQU    NUMNTH+41    ; Local stack (40 bytes = 20 entries max)
  826.                 ; User's stack pointer stored on top
  827.  
  828.     END
  829.     NUMNTH+1
  830.  
  831. LSTACK    EQU    NUMNTH+41    ; Local stack (40 bytes = 20 entries max)
  832.                 ; User's stack pointer stored on top
  833.  
  834.