; 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 ; ***************************************************************************** ; ; SWI OS_ResyncTime ; ; in: r0 = 0 - Real time clock soft copy only ; r0 <> 0 reserved for future expansion ; out: registers preserved ; or VS and R0 -> error ; ResyncTimeSWI ROUT Push "R1, R12, LR" BYTEWS WsPtr BL RTCToRealTime MOVVC R1, #Service_RTCSynchronised BLVC Issue_Service Pull "R1, R12, LR" B SLVK_TestV ; ***************************************************************************** ; ; SetTime - Write the CMOS clock time and update 5-byte RealTime ; ; in: UTC time: ; R0 = hours ; R1 = minutes ; R2 = day of month (1-based) ; R3 = month (1-based) ; R5 = year (lo) ; R6 = year (hi) ; R7 = seconds ; R8 = centiseconds ; out: registers preserved ; or VS and R0 -> error ; ; If R0,R2,R5 or R6 is -1 then the time,date,year,century (respectively) will not be written. ; However if R2=-1, R5 & R6 will also be -1, so only R0 (for time) and R2 (for D/M/Y) need checking. ; SetTime ROUT Push "R4, R9, LR" ; Prepare BCD data on stack ASSERT (RTCTimeStruct_Size :AND: 3)=0 SUB R13, R13, #RTCTimeStruct_Size MOV R9, R13 MOV R4, R0 ; Ensure struct matches our setting order ASSERT RTCTimeStruct_Centiseconds = 0 ASSERT RTCTimeStruct_Seconds = 1 ASSERT RTCTimeStruct_Minutes = 2 ASSERT RTCTimeStruct_Hours = 3 ASSERT RTCTimeStruct_DayOfMonth = 4 ASSERT RTCTimeStruct_Month = 5 ASSERT RTCTimeStruct_YearLO = 6 ASSERT RTCTimeStruct_YearHI = 7 ; Are we setting the time? CMP R4, #-1 STREQ R4, [R9], #4 ; Conveniently, 4 bytes of time info BEQ %FT11 MOV R0, R8 BL HTBS9 MOV R0, R7 BL HTBS9 MOV R0, R1 BL HTBS9 MOV R0, R4 BL HTBS9 11 ; Are we setting the date? CMP R2, #-1 STREQ R2, [R9], #4 ; Conveniently, 4 bytes of date info BEQ %FT12 MOV R0, R2 BL HTBS9 MOV R0, R3 BL HTBS9 MOV R0, R5 BL HTBS9 MOV R0, R6 BL HTBS9 12 MOV R0, SP SWI XRTC_Write ; Try update hardware MOV R0, R4 BL RegToRealTime ; Update soft copy regardless CLRV ADD SP, SP, #RTCTimeStruct_Size Pull "R4, R9, PC" ; ***************************************************************************** ; ; ReadTime - Read the CMOS clock time ; ; in: - ; out: R0 = hours ; R1 = minutes ; R2 = day of month (1-based) ; R3 = month (1-based) ; R5 = year (lo) ; R6 = year (hi) ; R7 = seconds ; R8 = centiseconds ; or VS and R0 -> error ReadTime ROUT Push "LR" ; Receive BCD data on stack ASSERT (RTCTimeStruct_Size :AND: 3)=0 SUB R13, R13, #RTCTimeStruct_Size MOV R0, R13 SWI XRTC_Read ADDVS R13, R13, #RTCTimeStruct_Size Pull "PC",VS ; Now convert the BCD ordinals LDRB R0, [R13, #RTCTimeStruct_Centiseconds] BL BCDToHex MOV R8, R0 ; centiseconds LDRB R0, [R13, #RTCTimeStruct_Seconds] BL BCDToHex MOV R7, R0 ; seconds LDRB R0, [R13, #RTCTimeStruct_Minutes] BL BCDToHex MOV R1, R0 ; minutes LDRB R0, [R13, #RTCTimeStruct_DayOfMonth] BL BCDToHex MOV R2, R0 ; days LDRB R0, [R13, #RTCTimeStruct_Month] BL BCDToHex MOV R3, R0 ; months LDRB R0, [R13, #RTCTimeStruct_YearLO] BL BCDToHex MOV R5, R0 ; year lo LDRB R0, [R13, #RTCTimeStruct_YearHI] BL BCDToHex MOV R6, R0 ; year hi LDRB R0, [R13, #RTCTimeStruct_Hours] BL BCDToHex ; hours CLRV ; We're done with our stack data, remove it ADD R13, R13, #RTCTimeStruct_Size Pull "PC" ; ***************************************************************************** ; ; RTCToRealTime - Set RealTime from actual RTC ; ; in: R12 -> BYTEWS ; out: all registers preserved ; or VS and R0 -> error ; RTCToRealTime ROUT Push "R0-R9, LR" BL ReadTime ; R0 := hours, R1 := minutes ; R2 := days, R3 := months ; R5 := year(lo), R6 := year(hi) ; R7 := seconds, R8 := centiseconds BVS %FT10 BL ConvertTo5Byte BL Store5ByteInRealTime CLRV 10 STRVS R0, [SP, #0] Pull "R0-R9, PC" ; ***************************************************************************** ; ; RegToRealTime - Set RealTime from a bunch of registers ; ; in: R12 -> BYTEWS ; R0-R3, R5-R8 = validated time and date ; out: all registers preserved ; RegToRealTime ROUT Push "R0-R9, LR" BL ConvertTo5Byte BL Store5ByteInRealTime Pull "R0-R9, PC" ; ***************************************************************************** ; ; Store5ByteInRealTime - put 5 byte centisecond UTC time into soft copy ; ; in: R7 = low word of time ; R8 = high byte of time ; R12 -> BYTEWS ; out: all registers preserved ; Store5ByteInRealTime Push "LR" PHPSEI ; disable IRQs for this bit STR R7, RealTime +0 STRB R8, RealTime +4 PLP Pull "PC" ; ***************************************************************************** ; ; ConvertTo5Byte - Convert ordinals to 5 byte time ; ; in: R12 -> BYTEWS ; R0-R3, R5-R8 = time and date ; out: R7 = low word ; R8 = high byte ; or R7 = R8 = -1 if conversion failed ; ConvertTo5Byte ROUT Push "LR" MOV R4, R5 ; R4 := year MOD 100 MOV R5, R6 ; R5 := year DIV 100 MOV R6, R7 ; R6 := seconds MOV R7, R8 ; R7 := centiseconds 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" ; ***************************************************************************** tickspersecond * 100 ticksperminute * tickspersecond * 60 ticksperhour * ticksperminute * 60 ticksperday * ticksperhour * 24 ticksperyear * ticksperday * 365 ; &BBF81E00 STMonths DCD &00000000 ; Jan DCD &0FF6EA00 ; Feb DCD &1E625200 ; Mar DCD &2E593C00 ; Apr DCD &3DCC5000 ; May DCD &4DC33A00 ; Jun DCD &5D364E00 ; Jul DCD &6D2D3800 ; Aug DCD &7D242200 ; Sep DCD &8C973600 ; Oct DCD &9C8E2000 ; Nov DCD &AC013400 ; Dec DCD &F0000000 ; terminator, must be less than this (+1) LTORG END