; 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.
;
        TTL   => TickEvents

; This file revised by TMD 28-Jan-94 to
; a) Correct internals to time n ticks not n+1
; b) Change externals to add 1 to compensate for user subtracting 1
; c) Fix RemoveTickerEvent to add this node's time onto the next one
; These fix bug MED-02498.

; There are two (centisecond) ticker SWIs :
; SWI CallAfter calls the given address once, after the given number of ticks
; SWI CallEvery  "     "    "    "      every N centiseconds

; In :  R0 is unsigned number of centiseconds
;       R1 is address to call
;       R2 is value of R12 to pass to code

CallEvery_Code
        ADD     r10, r0, #1             ; compensate for n+1 bug
        B       TickTockCommon
CallAfter_Code   ROUT
        MOV     r10, #0
TickTockCommon
        Push    "r0-r3, lr"
        ADD     r14, r0, #1024
        CMP     r14, #1024
        BLS     %FT99                   ; reject 0 and >= &FFFFFC00

  [ ChocolateSysHeap
        ASSERT  ChocolateTKBlocks = ChocolateBlockArrays + 8
        LDR     r3,=ZeroPage+ChocolateBlockArrays
        LDR     r3,[r3,#8]
        BL      ClaimChocolateBlock
        MOVVS   r3, #TickNodeSize
        BLVS    ClaimSysHeapNode
  |
        MOV     r3, #TickNodeSize
        BL      ClaimSysHeapNode
  ]
        BVS     %FT97

        MOV     r3, r2
        LDMFD   stack, {r0-r2}
        STR     r1,  [r3, #TickNodeAddr]
        STR     r10, [r3, #TickNodeRedo]
        STR     r2,  [r3, #TickNodeR12]
        MOV     r1, r3

        ADD     r0, r0, #1              ; compensate for n+1 bug
        BL      InsertTickerEvent

        Pull    "r0-r3, lr"
        ExitSWIHandler

99      ADR     r0, ErrorBlock_BadTime
      [ International
        BL      TranslateError
      ]
97
        ADD     sp, sp, #1*4            ; junk old R0
        Pull    "r1-r3, lr"
        B       SLVK_SetV

        MakeErrorBlock BadTime


; Data structure :
; chain of nodes
;
;       +----------------------------------+
;       |   Link to next node or 0         |
;       +----------------------------------+
;       |   Reload flag                    |
;       +----------------------------------+
;       |   Address to call                |
;       +----------------------------------+
;       |   Value of R12                   |
;       +----------------------------------+
;       |   No of ticks to go before call  |
;       +----------------------------------+
;
; The head node's no of ticks is decremented until 0
;  Subsequent nodes contain the no of ticks to wait when they reach the
;  chain head.
; If the reload flag is non-0, the node is reinserted at that number of ticks
; down the chain after every use.

             ^  0
TickNodeLink #  4        ;
TickNodeRedo #  4        ; These are together
TickNodeAddr #  4        ;
TickNodeR12  #  4        ;  so can LDM them

TickNodeLeft #  4

TickNodeSize #  0

InsertTickerEvent   ROUT
; R1 is node pointer, R0 ticks to wait
; R10-R12 corrupted

        Push    "r0,lr"
        PHPSEI  r14
        LDR     r10, =ZeroPage+TickNodeChain
01
        MOV     r11, r10
        LDR     r10, [r11, #TickNodeLink]
        CMP     r10, #0
        BEQ     %FT02                           ; end of chain
        LDR     r12,  [r10, #TickNodeLeft]
        CMP     r12, r0
        SUBLS   r0, r0, r12
        BLS     %BT01                           ; node R10 is earlier (or equal) to node R1
        SUB     r12, r12, r0
        STR     r12, [r10, #TickNodeLeft]
02
        STR     r1, [r11, #TickNodeLink]
        STR     r0, [r1, #TickNodeLeft]
        STR     r10, [r1, #TickNodeLink]

        PLP     r14
        Pull    "r0,pc"

ProcessTickEventChain  ROUT
; R0-R3, R10-R12 corruptible
        LDR     r3, =ZeroPage+TickNodeChain

        LDR     r1, [r3, #TickNodeLink]
        CMP     r1, #0
        MOVEQ   pc, lr                          ; no timers

        LDR     r2, [r1, #TickNodeLeft]
        SUBS    r2, r2, #1
        STR     r2, [r1, #TickNodeLeft]
        MOVHI   pc, lr                          ; nothing to call yet (HI to cope with ordinary 1 -> 0 transition, and 0 -> -1 transition if re-entered while processing two or more events which are due to fire at the same time)

        Push    "lr"                            ; save IRQ_lr
        MSR     CPSR_c, #SVC32_mode+I32_bit     ; switch to SVC mode, IRQ's off
        Push    "lr"                            ; save SVC_lr
01
        LDMIA   r1, {r2, r10, r11, r12}         ; load next ptr, redo state,
                                                ;     address and R12val
        STR     r2, [r3]                        ; de-link from chain
      [ NoARMv5
        MOV     lr, pc
        MOV     pc, r11                         ; call event handler
      |
        BLX     r11                             ; call event handler
      ]

        MOVS    r0, r10                         ; CallEvery?
        BEQ     %FT05

        BL      InsertTickerEvent               ; yes, then re-insert timer
        B       %FT10

05
; Return spent ticker node to heap

        MSR     CPSR_c, #SVC32_mode             ; IRQ's ON for the  S L O W  bit
        MOV     r2, r1                          ; R2->node to free
  [ ChocolateSysHeap
        ASSERT  ChocolateTKBlocks = ChocolateBlockArrays + 8
        LDR     r1,=ZeroPage+ChocolateBlockArrays
        LDR     r1,[r1,#8]
        BL      FreeChocolateBlock
        LDRVS   r1, =SysHeapStart
        MOVVS   r0, #HeapReason_Free
        SWIVS   XOS_Heap
  |
        LDR     r1, =SysHeapStart
        MOV     r0, #HeapReason_Free
        SWI     XOS_Heap
  ]

; Check for more events at the same level in the list
10
        MSR     CPSR_c, #SVC32_mode+I32_bit     ; IRQ's off again (after returning node to heap, or after naughty CallEvery exits with IRQs on)

        LDR     r1, [r3, #TickNodeLink]         ; get top of list
        CMP     r1, #0                          ; list empty?
        BEQ     %FT02                           ; yes then exit

        LDR     r0, [r1, #TickNodeLeft]
        CMP     r0, #0                          ; zero time delta?
        BEQ     %BT01                           ; yes then jump
02
        Pull    "lr"                            ; restore SVC_lr
        MSR     CPSR_c, #IRQ32_mode+I32_bit     ; back to IRQ mode
        Pull    "pc"                            ; pull IRQ_lr from IRQ stack

RemoveTickerEvent_Code
; R0 is address of code to remove, R1 the R12 value
        MSR     CPSR_c, #SVC32_mode+I32_bit
        LDR     r10, =ZeroPage+TickNodeChain
01
        LDR     r11, [r10]
        CMP     r11, #0
        ExitSWIHandler EQ
        LDR     r12, [r11, #TickNodeAddr]
        CMP     r12, r0
        LDREQ   r12, [r11, #TickNodeR12]
        CMPEQ   r12, r1
        MOVNE   r10, r11
        BNE     %BT01

        Push    "r0-r2, lr"
        MOV     r2, r11
        LDR     r11, [r11, #TickNodeLink]       ; prev->link = this->link
        STR     r11, [r10]

        TEQ     r11, #0                         ; if next node exists
        LDRNE   r14, [r11, #TickNodeLeft]       ; then add our time-to-go onto its
        LDRNE   r0, [r2, #TickNodeLeft]
        ADDNE   r14, r14, r0
        STRNE   r14, [r11, #TickNodeLeft]

  [ ChocolateSysHeap
        ASSERT  ChocolateTKBlocks = ChocolateBlockArrays + 8
        LDR     r1,=ZeroPage+ChocolateBlockArrays
        LDR     r1,[r1,#8]
        BL      FreeChocolateBlock
        BLVS    FreeSysHeapNode
  |
        BL      FreeSysHeapNode
  ]
        Pull    "r0-r2, lr"
        B       %BT01

ReadMetroGnome
        LDR     r0, =ZeroPage
        LDR     r0, [r0, #MetroGnome]
        ExitSWIHandler

        LTORG

        END