 GET TimLib:hdr.System
 GET TimLib:hdr.Macros
 GET hdr.GlobHdr
 GET hdr.Division

 EXPORT Mem_Clear
 EXPORT Mem_Move
 EXPORT Mem_FastMove
 EXPORT Timer_Init
 EXPORT Timer_GetTime

; default area assignment

 AREA |Assembler|,READONLY,CODE

;-------------------------------------------------------------------------------
; Mem_Clear
;
; In  - R0 pos
;       R1 len
;
; Out -
;-------------------------------------------------------------------------------
 ALIGN

Mem_Clear _FNAME
 _DEFPROC "R0-R6"

 MOV     R3,#0
 MOV     R4,#0
 MOV     R5,#0
 MOV     R6,#0

Mem_Clear_StartLoop
 CMP     R1,#0
 BLE     Mem_Clear_End
 TST     R0,#&F
 STRNEB  R3,[R0],#1
 SUBNE   R1,R1,#1
 BNE     Mem_Clear_StartLoop
 AND     R2,R1,#&F
 MOVS    R1,R1,LSR #4
 BLE     Mem_Clear_EndLoopTest

Mem_Clear_MiddleLoop
 STMIA   R0!,{R3-R6}
; STR     R3,[R0],#4
; STR     R3,[R0],#4
; STR     R3,[R0],#4
; STR     R3,[R0],#4
 SUBS    R1,R1,#1
 BGT     Mem_Clear_MiddleLoop

Mem_Clear_EndLoopTest
 CMP     R2,#0
 BEQ     Mem_Clear_End

Mem_Clear_EndLoop
 STRB    R3,[R0],#1
 SUBS    R2,R2,#1
 BGT     Mem_Clear_EndLoop

Mem_Clear_End
 _ENDPROC

;-------------------------------------------------------------------------------
; Mem_Move
;
; In - R0 = ptr new
;      R1 = ptr old
;      R2 = len
;
; Out -
;-------------------------------------------------------------------------------
 ALIGN

Mem_Move _FNAME
 CMP     R0,#0
 MOVEQ   PC,R14
 CMP     R2,#0
 MOVLE   PC,R14
 _DEFPROC "R0-R3"
 CMP     R0,R1
 BHI     Mem_Move_Reverse

Mem_Move_Loop
 LDRB    R3,[R1],#1
 SUBS    R2,R2,#1
 STRB    R3,[R0],#1
 BGT     Mem_Move_Loop
 _ENDPROC

Mem_Move_Reverse
 ADD     R1,R1,R2
 SUB     R1,R1,#1
 ADD     R0,R0,R2
 SUB     R0,R0,#1
Mem_Move_Reverse_Loop
 LDRB    R3,[R1],#-1
 SUBS    R2,R2,#1
 STRB    R3,[R0],#-1
 BGT     Mem_Move_Reverse_Loop
 _ENDPROC

;-------------------------------------------------------------------------------
; Mem_FastMove
;
; In - R0 = ptr new
;      R1 = ptr old
;      R2 = len
;
; Out -
;-------------------------------------------------------------------------------
 ALIGN

Mem_FastMove _FNAME
 CMP     R0,#0
 MOVEQ   PC,R14
 CMP     R2,#0
 MOVLE   PC,R14
 _DEFPROC "R0-R3"
 CMP     R0,R1
 BHI     Mem_FastMove_Reverse

Mem_FastMove_Loop
 LDR     R3,[R1],#4
 SUBS    R2,R2,#4
 STR     R3,[R0],#4
 BGT     Mem_FastMove_Loop
 _ENDPROC

Mem_FastMove_Reverse
 ADD     R1,R1,R2
 SUB     R1,R1,#4
 ADD     R0,R0,R2
 SUB     R0,R0,#4
Mem_FastMove_Reverse_Loop
 LDR     R3,[R1],#-4
 SUBS    R2,R2,#4
 STR     R3,[R0],#-4
 BGT     Mem_FastMove_Reverse_Loop
 _ENDPROC

TimerType_None      * 0
TimerType_HAL       * 1

;-------------------------------------------------------------------------------
; TimerInit
;
; In  - R12 Global header
;-------------------------------------------------------------------------------
Timer_Init
 _DEFPROC "R1-R11"
 ; Timer 0 can be read ?
 ; Assume it is used to construct OS_ReadMonotonicTime
 MOV     R0,#0
 MOV     R8,#0
 MOV     R9,#21
 SWI     XOS_Hardware
 BVS     TimerInit_TimerNoHal
 ; Yes, get timer ticks per second and period
 MOV     R0,#0
 MOV     R8,#0
 MOV     R9,#19
 SWI     XOS_Hardware
 BVS     TimerInit_TimerNoHal
 MOV     R6,#100
 _DIVIDE R3,R0,R6,R7
 STR     R3,[R12,#Glb_TimerTicksPerCS]
 MOV     R0,#0
 MOV     R8,#0
 MOV     R9,#20
 SWI     XOS_Hardware
 BVS     TimerInit_TimerNoHal
 STR     R0,[R12,#Glb_TimerPeriod]
 ; If HAL Timer0 doesn't cover exactly a cs, the assumption is incorrect
 LDR     R1,[R12,#Glb_TimerTicksPerCS]
 CMP     R0,R1
 BNE     TimerInit_TimerNoHal
 MOV     R0,#TimerType_HAL
 STR     R0,[R12,#Glb_TimerType]
 B       TimerInit_TimerEnd
TimerInit_TimerNoHal
 MOV     R0,#&1
 STR     R0,[R12,#Glb_TimerTicksPerCS]
 MOV     R0,#&1
 STR     R0,[R12,#Glb_TimerPeriod]
 MOV     R0,#TimerType_None
 STR     R0,[R12,#Glb_TimerType]
TimerInit_TimerEnd
 _ENDPROC

;-------------------------------------------------------------------------------
; Timer_GetTime
;
; In  - R12 Global header
;
; Out - R0 monotonic time (in cs)
;       R1 timer ticks (assumes fraction of cs)
;-------------------------------------------------------------------------------
 ALIGN

Timer_GetTime _FNAME
 _DEFPROC "R2-R11"
 LDR     R0,[R12,#Glb_TimerType]
 CMP     R0,#(Timer_GetTime_tableend-Timer_GetTime_tablestart)
 ADDCC   PC,PC,R0,LSL#2
 B       Timer_GetTime_None
Timer_GetTime_tablestart
 B       Timer_GetTime_None
 B       Timer_GetTime_HAL
Timer_GetTime_tableend

Timer_GetTime_None
 MOV     R1,#0
 B       Timer_GetTime_Monotonic

Timer_GetTime_HAL
 MOV     R0,#0
 MOV     R8,#0
 MOV     R9,#21
 SWI     XOS_Hardware
 LDR     R1,[R12,#Glb_TimerTicksPerCS]
 ADD     R0,R0,#1
 SUB     R1,R1,R0

Timer_GetTime_Monotonic
 SWI     XOS_ReadMonotonicTime
 MOVVS   R0,#0

Timer_GetTime_CheckIncreasingTicks
 LDR     R2,[R12,#Glb_TimerLastCS]
 LDR     R3,[R12,#Glb_TimerLastTicks]
 CMP     R0,R2
 BNE     Timer_GetTime_SaveLast
 CMP     R1,R3
 ADDLT   R0,R0,#1
Timer_GetTime_SaveLast
 STR     R0,[R12,#Glb_TimerLastCS]
 STR     R1,[R12,#Glb_TimerLastTicks]
 _ENDPROC

 END
