; 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 nodes 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 (signed) number of centiseconds ; R1 is address to call ; R2 is value of R12 to pass to code CallAfter_Code ROUT MOV r10, #0 TickTockCommon Push "r0-r3, lr" CMP r0, #0 BLE %FT99 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 [ Fix14 ADD sp, sp, #1*4 ; junk old R0 Pull "r1-r3, lr" | Pull "r0-r3, lr" ] B SLVK_SetV MakeErrorBlock BadTime CallEvery_Code ADD r10, r0, #1 ; compensate for n+1 bug B TickTockCommon ; 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" MOV r10, pc ORR r10, r10, #I_bit TEQP r10, #0 LDR r10, =TickNodeChain 01 MOV r11, r10 LDR r10, [r11, #TickNodeLink] CMP r10, #0 BEQ %FT02 ; end of chain LDR r12, [r10, #TickNodeLeft] SUBS r0, r0, r12 BGE %BT01 ADD r0, r0, r12 SUB r12, r12, r0 STR r12, [r10, #TickNodeLeft] 02 STR r1, [r11, #TickNodeLink] STR r0, [r1, #TickNodeLeft] STR r10, [r1, #TickNodeLink] Pull "r0" MOVS pc, lr ProcessTickEventChain ROUT ; R0-R3, R10-R12 corruptible LDR r3, =TickNodeChain LDR r1, [r3, #MetroGnome-TickNodeChain] ADD r1, r1, #1 STR r1, [r3, #MetroGnome-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] MOVGT pc, lr ; nothing to call yet (was MOVPL) Push "lr" ; save IRQ_lr [ TickIrqReenter TEQP pc, #SVC_mode+I_bit ; switch to SVC mode, IRQ's off NOP 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 MOV lr, pc MOV pc, r11 ; call event handler LDR r0, [r1, #TickNodeRedo] CMP r0, #0 ; CallEvery? BLGT InsertTickerEvent ; yes, then re-insert timer BGT %FT10 ; Return spent ticker node to heap [ TickIrqReenter TEQP pc, #SVC_mode ; IRQ's ON for the S L O W bit MOV r2, r1 ; R2->node to free LDR r1, =SysHeapStart MOV r0, #HeapReason_Free SWI XOS_Heap TEQP pc, #SVC_mode+I_bit ; IRQ's off again ; Check for more events down the list 10 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 ; timed out? BLE %BT01 ; yes then jump 02 Pull "lr" ; restore SVC_lr TEQP pc, #IRQ_mode+I_bit ; back to IRQ mode NOP Pull "pc" ; pull IRQ_lr from IRQ stack | TEQP pc, #SVC_mode+I_bit MOV r0, #HeapReason_Free Push "r2, lr" MOV r2, r1 LDR r1, =SysHeapStart SWI XOS_Heap Pull "r2, lr" TEQP pc, #IRQ_mode+I_bit 10 CMP r2, #0 ; end of list? BEQ %FT02 ; yes then exit LDR r0, [r2, #TickNodeLeft] CMP r0, #0 MOVLE r1, r2 BLE %BT01 02 Pull "pc" ] RemoveTickerEvent_Code ; R0 is address of code to remove, R1 the R12 value TEQP pc, #SVC_mode+I_bit LDR r10, =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] BL FreeSysHeapNode Pull "r0-r2, lr" B %BT01 ReadMetroGnome MOV r0, #0 LDR r0, [r0, #MetroGnome] ExitSWIHandler LTORG END