3 #include <aros/debug.h>
4 #include <asm/mpc5200b.h>
7 #include <aros/asmcall.h>
8 #include <hardware/intbits.h>
9 #include <exec/execbase.h>
12 #include <proto/exec.h>
13 #include <proto/timer.h>
17 uint32_t tbc_expected
;
18 uint32_t tbc_achieved
;
21 volatile slt_t
*slice_timer
;
23 // tick2usec - 64424510 for 66.666666MHz
24 // tick2usec - 130150524 for 33.000000MHz
26 inline uint32_t __attribute__((const)) tick2usec(uint32_t tick
)
29 uint64_t tmp
= ((uint64_t)tick
) * 130150524;
31 retval
= (tmp
+ 0x7fffffff) >> 32;
36 inline uint32_t __attribute__((const)) usec2tick(uint32_t usec
)
39 // uint64_t tmp = ((uint64_t)usec) * 286331150203ULL;
41 // retval = (tmp + 0x7fffffff) >> 32;
48 void EClockUpdate(struct TimerBase
*TimerBase
)
55 diff
= (time
- TimerBase
->tb_prev_tick
);
56 TimerBase
->tb_prev_tick
= time
;
58 TimerBase
->tb_ticks_total
+= diff
;
60 TimerBase
->tb_ticks_sec
+= diff
;
61 TimerBase
->tb_ticks_elapsed
+= diff
;
63 if (TimerBase
->tb_ticks_sec
>= 33000000)
65 TimerBase
->tb_ticks_sec
-= 33000000;
66 TimerBase
->tb_CurrentTime
.tv_secs
++;
71 if (TimerBase
->tb_ticks_elapsed
>= 33000000)
73 TimerBase
->tb_ticks_elapsed
-= 33000000;
74 TimerBase
->tb_Elapsed
.tv_secs
++;
77 TimerBase
->tb_Elapsed
.tv_micro
= tick2usec(TimerBase
->tb_ticks_elapsed
);
78 TimerBase
->tb_CurrentTime
.tv_micro
= tick2usec(TimerBase
->tb_ticks_sec
);
82 // bug("[timer] CurrentTime: %d:%06d\n", TimerBase->tb_CurrentTime.tv_secs, TimerBase->tb_CurrentTime.tv_micro);
83 // bug("[timer] %08x %08x %d %d \n", tbc_expected, tbc_achieved, tbc_achieved-tbc_expected, corr);
87 void EClockSet(struct TimerBase
*TimerBase
)
89 TimerBase
->tb_ticks_sec
= usec2tick(TimerBase
->tb_CurrentTime
.tv_micro
);
92 void TimerSetup(struct TimerBase
*TimerBase
, uint32_t waste
)
94 int32_t delay
= 660000; /* 50Hz in worst case */
96 struct timerequest
*tr
;
97 uint32_t current_time
;
99 tr
= (struct timerequest
*)GetHead(&TimerBase
->tb_Lists
[TL_WAITVBL
]);
103 time
.tv_micro
= tr
->tr_time
.tv_micro
;
104 time
.tv_secs
= tr
->tr_time
.tv_secs
;
106 SubTime(&time
, &TimerBase
->tb_CurrentTime
);
108 if ((LONG
)time
.tv_secs
< 0)
112 else if (time
.tv_secs
== 0)
114 // if (time.tv_micro < 20000)
116 if (delay
> usec2tick(time
.tv_micro
))
117 delay
= usec2tick(time
.tv_micro
);
122 tr
= (struct timerequest
*)GetHead(&TimerBase
->tb_Lists
[TL_VBLANK
]);
126 time
.tv_micro
= tr
->tr_time
.tv_micro
;
127 time
.tv_secs
= tr
->tr_time
.tv_secs
;
129 SubTime(&time
, &TimerBase
->tb_Elapsed
);
131 if ((LONG
)time
.tv_secs
< 0)
135 else if (time
.tv_secs
== 0)
137 // if (time.tv_micro < 20000)
139 if (delay
> usec2tick(time
.tv_micro
))
140 delay
= usec2tick(time
.tv_micro
);
145 current_time
= mftbl();
146 delay
-= ((int32_t)(current_time
- waste
)) + corr
;
148 if (delay
< 256) delay
= 256;
150 tbc_expected
= current_time
+ delay
;
153 outl(SLT_CF_INTRENA
, &slice_timer
->slt_cf
);
155 outl(delay
, &slice_timer
->slt_tc
);
157 outl(SLT_CF_INTRENA
| SLT_CF_ENABLE
, &slice_timer
->slt_cf
);
158 /* Clear interrupt request. */
159 outl(SLT_TS_ST
, &slice_timer
->slt_ts
);
163 This is a slightly faster version of AddTime() that we use here. It
164 also saves the function call overhead...
166 #define FastAddTime(d, s)\
167 (d)->tv_micro += (s)->tv_micro;\
168 (d)->tv_secs += (s)->tv_secs;\
169 if((d)->tv_micro > 999999) {\
171 (d)->tv_micro -= 1000000;\
174 BOOL
timer_addToWaitList(struct TimerBase
*, struct MinList
*, struct timerequest
*);
176 void SliceHandler(struct TimerBase
*TimerBase
, struct ExecBase
*SysBase
)
178 uint32_t startup_time
= mftbl();
180 if (inl(&slice_timer
->slt_ts
) & SLT_TS_ST
)
182 struct timerequest
*tr
, *next
;
184 /* Clear interrupt request. */
185 outl(SLT_TS_ST
, &slice_timer
->slt_ts
);
188 outl(0, &slice_timer
->slt_cf
);
189 // outl(SLT_CF_RUNWAIT | SLT_CF_INTRENA | SLT_CF_ENABLE, &slice_timer->slt_cf);
191 // D(bug("[timer] SliceHandler on %08x%08x slt->cv=%08x\n", (uint32_t)(mftb() >> 32),mftbl(),inl(&slice_timer->slt_cv)));
193 EClockUpdate(TimerBase
);
195 tbc_achieved
= startup_time
;
197 /* Timer errors bigger than approx 15 microseconds shouldn't be taken into account */
198 //if (tbc_achieved > tbc_expected) // && (tbc_achieved - tbc_expected) < 1000)
200 corr
= ((int32_t)(tbc_achieved
- tbc_expected
))-1;
205 Go through the "wait for x seconds" list and return requests
206 that have completed. A completed request is one whose time
207 is less than that of the elapsed time.
209 ForeachNodeSafe(&TimerBase
->tb_Lists
[TL_VBLANK
], tr
, next
)
211 if(CmpTime(&TimerBase
->tb_Elapsed
, &tr
->tr_time
) <= 0)
213 if (tr
== &TimerBase
->tb_vblank_timerequest
)
215 struct IntVector
*iv
= &SysBase
->IntVects
[INTB_VERTB
];
221 AROS_UFC5(void, iv
->iv_Code
,
222 AROS_UFCA(ULONG
, 0, D1
),
223 AROS_UFCA(ULONG
, 0, A0
),
224 AROS_UFCA(APTR
, iv
->iv_Data
, A1
),
225 AROS_UFCA(APTR
, iv
->iv_Code
, A5
),
226 AROS_UFCA(struct ExecBase
*, SysBase
, A6
)
229 /* Automatically requeue/reactivate request */
231 Remove((struct Node
*)tr
);
232 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
233 tr
->tr_time
.tv_secs
= 0;
234 tr
->tr_time
.tv_micro
= 1000000 / SysBase
->VBlankFrequency
;
235 AddTime(&tr
->tr_time
, &TimerBase
->tb_Elapsed
);
237 timer_addToWaitList(TimerBase
, &TimerBase
->tb_Lists
[TL_VBLANK
], tr
);
241 /* This request has finished */
242 Remove((struct Node
*)tr
);
243 tr
->tr_time
.tv_secs
= tr
->tr_time
.tv_micro
= 0;
244 tr
->tr_node
.io_Error
= 0;
245 ReplyMsg((struct Message
*)tr
);
251 The first request hasn't finished, as all requests are in
252 order, we don't bother searching through the remaining
259 The other this is the "wait until a specified time". Here a request
260 is complete if the time we are waiting for is before the current time.
262 ForeachNodeSafe(&TimerBase
->tb_Lists
[TL_WAITVBL
], tr
, next
)
264 if(CmpTime(&TimerBase
->tb_CurrentTime
, &tr
->tr_time
) <= 0)
266 /* This request has finished */
267 Remove((struct Node
*)tr
);
268 tr
->tr_time
.tv_secs
= tr
->tr_time
.tv_micro
= 0;
269 tr
->tr_node
.io_Error
= 0;
270 ReplyMsg((struct Message
*)tr
);
275 The first request hasn't finished, as all requests are in
276 order, we don't bother searching through the remaining
281 TimerSetup(TimerBase
, startup_time
);