; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > $.Source.PMF.realtime

; *****************************************************************************
;
;       CheckYear - Check for year wrap (year in RTC <> year "YearCMOS")
;       and for leap year fudging
;

CheckYear ROUT
        Push    "R0,R1,R2,R14"
        LDR     R0, =ZeroPage
        LDR     R0, [R0, #RTCFitted]
 [ HAL
        CMP     R0, #2048
  [ RTCSupport
        BLO     %FT8
  |
        BLO     %FT15
  ]
         ; Ask the RTC what it thinks the year is
        Push    "R3,R10,R12"
        MOV     R10, R0
        SUB     R13, R13, #RTCTimeStruct_BCD_Size
        MOV     R1, R13
        ADRL    R2, HALRTC_IICOp
        MOV     LR, PC
        LDR     PC, [R0, #HALDevice_RTCReadTime]
        ; Did we succeed?
        CMP     R0, #RTCRetCode_OK
        LDRB    R0, [R13, #RTCTimeStruct_BCD_YearLO]
        LDRB    R1, [R13, #RTCTimeStruct_BCD_YearHI]
        ADD     R13, R13, #RTCTimeStruct_BCD_Size
        LDRB    R2, [R10, #HALDevice_RTCFormatFlags]
        Pull    "R3,R10,R12"
        BNE     %FT15
        ASSERT  RTCFormatFlags_BCD_NeedsYearHelp = 1 :SHL: 2
        ASSERT  RTCFormatFlags_BCD_YearLOIsGood = 1 :SHL: 3
        AND     LR, R2, #RTCFormatFlags_BCD_NeedsYearHelp + RTCFormatFlags_BCD_YearLOIsGood
        MOVS    LR, LR, ROR #3 ; CC = good, CS+EQ = 2 bit, CS+NE = BCD
        ADDCS   R1, LR, #RTCAddressPHI+1 ; 2 bit=RTCAddressPHI+1, BCD!=RTCAddressPHI+1
        BCS     %FT9
        ; Year is reliable; convert R0 & R1 to ints and update CMOS if necessary.
        BL      BCDToHex
        MOV     R2, R1
        MOV     R1, R0 ; YearLO
        MOV     R0, #YearCMOS
        BL      Read
        CMP     R0, R1
        MOVNE   R0, #YearCMOS
        BLNE    Write
        MOV     R0, R2
        BL      BCDToHex
        MOV     R1, R0 ; YearHI
        MOV     R0, #YearCMOS+1
        BL      Read
        CMP     R0, R1
        MOVNE   R0, #YearCMOS+1
        BLNE    Write
        B       %FT15
8
 ] ; HAL
 [ RTCSupport :LOR: :LNOT: HAL
        TEQ     R0, #RTCAddressPHI
        MOVEQ   R1, #5
        MOVNE   R1, #6                  ; year address (dependant on RTC)
        STRB    R1, [R13, #-4]!
        MOV     R1, R13
        ORR     R0, R0, #1:SHL:29
        MOV     R2, #1
        BL      IIC_Op
        ORR     R0, R0, #1
        BL      IIC_Op
        AND     R1, R0, #&FF
        LDRB    R0, [R13], #4

        TEQ     R1, #RTCAddressPHI+1
 ] ; RTCSupport :LOR: :LNOT: HAL
9
        MOVEQ   R0, R0, LSR #6          ; R0= year MOD 4.
        BLNE    BCDToHex
        MOV     R2, R0                  ; remember RTC value
        MOV     R0, #YearCMOS
        BL      Read
        TEQ     R1, #RTCAddressPHI+1
        ANDEQ   R1, R0, #3
        MOVNE   R1, R0
        MOVEQ   R14,#4
        MOVNE   R14,#100

        SUBS    R2, R2, R1              ; same year ?
        Pull    "R0,R1,R2,PC", EQ       ; [yes, so no bother]
        ADDCC   R2, R2, R14             ; if lower, then must be carry
        ADD     R2, R0, R2              ; new year value
        CMP     R2, #100
        BCC     %FT10                   ; no carry thru to next century

        SUB     R2, R2, #100
        MOV     R0, #YearCMOS +1
        BL      Read
        ADD     R1, R0, #1
        TEQ     R1, #100
        MOVEQ   R1, #0                  ; wrap century
        MOV     R0, #YearCMOS +1
        BL      Write
10
        MOV     R1, R2
        MOV     R0, #YearCMOS
        BL      Write
15
        BL      RTCToRealTime
        Pull    "R0,R1,R2,PC"

; *****************************************************************************
;
;       RTCToRealTime - Set RealTime from actual RTC
;
; in:   R12 -> BYTEWS
; out:  all registers preserved
;

        [ {FALSE}
Construct5Byte ROUT
        Push    R14
        B       Construct5ByteEntry
        ]

RTCToRealTime ROUT
        Push    "R0-R9, R14"
        BL      ReadTime                ; R0 := hours, R1 := minutes
                                        ; R2 := days, R3 := months
                                        ; R5 := year(lo), R6 := year(hi)
                                        ; R7 := seconds, R8 := centiseconds
        ; R0 will be negative on error. Just skip the update.
        CMP     R0,#0
        Pull    "R0-R9, PC",LT
        BL      ConvertTo5Byte
        BL      Store5ByteInRealTime
        Pull    "R0-R9, PC"

RegToRealTime ROUT
        Push    "R0-R9, R14"
        BL      ConvertTo5Byte
        BL      Store5ByteInRealTime
        Pull    "R0-R9, PC"

ConvertTo5Byte ROUT
        Push    R14

        MOV     R4, R5                  ; R4 := year MOD 100
        MOV     R5, R6                  ; R5 := year DIV 100
        MOV     R6, R7                  ; R6 := seconds
        MOV     R7, R8                  ; R7 := centiseconds

Construct5ByteEntry
        MOV     R9, #24
        SUB     R2, R2, #1              ; decrement day (day=1 => nowt to add)
        MLA     R0, R9, R2, R0          ; R0 = hours + day*24
        MOV     R9, #60
        MLA     R1, R0, R9, R1          ; R1 = mins + hours*60
        MLA     R6, R1, R9, R6          ; R6 = secs + mins*60
        MOV     R9, #100
        MLA     R7, R6, R9, R7          ; R7 = centisecs + secs*100

        ADR     R0, STMonths-4          ; Point to table (month = 1..12)
        LDR     R1, [R0, R3, LSL #2]    ; get word of offset
        ADD     R7, R7, R1              ; add to total

; if not had leap day in this year yet, then exclude this year from the
; leap day calculations

        CMP     R3, #3                  ; if month >= 3
        SBCS    R0, R4, #0              ; then R0,R1 = R4,R5
        MOVCC   R0, #99                 ; else R0,R1 = R4,R5 -1
        SBC     R1, R5, #0

; want (yl+100*yh) DIV 4 - (yl+100*yh) DIV 100 + (yl+100*yh) DIV 400
; = (yl DIV 4)+ (25*yh) - yh + (yh DIV 4)
; = (yl >> 2) + 24*yh + (yh >> 2)

        MOV     R0, R0, LSR #2          ; yl >> 2
        ADD     R0, R0, R1, LSR #2      ; + yh >> 2
        ADD     R0, R0, R1, LSL #4      ; + yh * 16
        ADD     R0, R0, R1, LSL #3      ; + yh * 8

; now subtract off the number of leap days in first 1900 years = 460

        SUBS    R0, R0, #460
        BCC     BadYear                 ; before 1900, so bad
        CMP     R0, #86                 ; if more than 86 days, then it's
        BCS     BadYear                 ; after 2248, so bad

        LDR     R9, =ticksperday        ; multiply by ticksperday and add to
        MLA     R7, R9, R0, R7          ; total (no overflow possible as this
                                        ; can never be more than 85+31 days)

; now add on (year-1900)*ticksperyear

        SUBS    R5, R5, #19             ; subtract off 1900
        BCC     BadYear
        MOV     R9, #100
        MLA     R4, R9, R5, R4          ; R4 = year-1900

        LDR     R0, =ticksperyear       ; lo word of amount to add on
        MOV     R1, #0                  ; hi word of amount to add on
        MOV     R8, #0                  ; hi word of result
10
        MOVS    R4, R4, LSR #1
        BCC     %FT15

        ADDS    R7, R7, R0              ; if bit set then add on amount
        ADCS    R8, R8, R1
        BCS     BadYear                 ; overflow => bad time value
15
        ADDS    R0, R0, R0              ; shift up amount
        ADCS    R1, R1, R1
        TEQ     R4, #0                  ; if still bits to add in
        BNE     %BT10                   ; then loop

        CMP     R8, #&100               ; R8 must only be a byte
        Pull    PC, CC

BadYear
        MOV     R7, #-1
        MOV     R8, #-1
        Pull    PC


Store5ByteInRealTime
        Push    R14
        PHPSEI                          ; disable IRQs for this bit
        STR     R7, RealTime +0
        STRB    R8, RealTime +4

        [ :LNOT: AssemblingArthur :LAND: :LNOT: Module
; for now, also put into normal time

        LDRB    R0, TimerState
        TEQ     R0, #5

        ADREQ   R3, TimerAlpha +0
        ADRNE   R3, TimerBeta +0

        STR     R7, [R3]
        STRB    R8, [R3, #4]
        ]
        PLP

        Pull    PC

; *****************************************************************************

tickspersecond  * 100
ticksperminute  * tickspersecond * 60
ticksperhour    * ticksperminute * 60
ticksperday     * ticksperhour   * 24
ticksperyear    * ticksperday    * 365  ; &BBF81E00

STMonths
        &       &00000000       ; Jan
        &       &0FF6EA00       ; Feb
        &       &1E625200       ; Mar
        &       &2E593C00       ; Apr
        &       &3DCC5000       ; May
        &       &4DC33A00       ; Jun
        &       &5D364E00       ; Jul
        &       &6D2D3800       ; Aug
        &       &7D242200       ; Sep
        &       &8C973600       ; Oct
        &       &9C8E2000       ; Nov
        &       &AC013400       ; Dec
        &       &F0000000       ; terminator, must be less than this (+1)


        LTORG

        END