ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/timer.cpp
Revision: 1.9
Committed: 2008-01-01T09:40:31Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -1 lines
Error occurred while calculating annotation data.
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * timer.cpp - Time Manager emulation
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 * SEE ALSO
23 * Inside Macintosh: Processes, chapter 3 "Time Manager"
24 * Technote 1063: "Inside Macintosh: Processes: Time Manager Addenda"
25 */
26
27 #include <stdio.h>
28
29 #include "sysdeps.h"
30 #include "cpu_emulation.h"
31 #include "main.h"
32 #include "macos_util.h"
33 #include "timer.h"
34
35 #define DEBUG 0
36 #include "debug.h"
37
38
39 // Set this to 1 to enable TMQueue management (doesn't work)
40 #define TM_QUEUE 0
41
42
43 // Definitions for Time Manager
44 enum { // TMTask struct
45 tmAddr = 6,
46 tmCount = 10,
47 tmWakeUp = 14,
48 tmReserved = 18
49 };
50
51
52 // Array of additional info for each installed TMTask
53 struct TMDesc {
54 uint32 task; // Mac address of associated TMTask
55 tm_time_t wakeup; // Time this task is scheduled for execution
56 bool in_use; // Flag: descriptor in use
57 };
58
59 const int NUM_DESCS = 64; // Maximum number of descriptors
60 static TMDesc desc[NUM_DESCS];
61
62
63 /*
64 * Allocate descriptor for given TMTask in list
65 */
66
67 static int alloc_desc(uint32 tm)
68 {
69 // Search for first free descriptor
70 for (int i=0; i<NUM_DESCS; i++)
71 if (!desc[i].in_use) {
72 desc[i].task = tm;
73 desc[i].in_use = true;
74 return i;
75 }
76 return -1;
77 }
78
79
80 /*
81 * Free descriptor in list
82 */
83
84 inline static void free_desc(int i)
85 {
86 desc[i].in_use = false;
87 }
88
89
90 /*
91 * Find descriptor associated with given TMTask
92 */
93
94 inline static int find_desc(uint32 tm)
95 {
96 for (int i=0; i<NUM_DESCS; i++)
97 if (desc[i].in_use && desc[i].task == tm)
98 return i;
99 return -1;
100 }
101
102
103 /*
104 * Enqueue task in Time Manager queue
105 */
106
107 static void enqueue_tm(uint32 tm)
108 {
109 #if TM_QUEUE
110 uint32 tm_var = ReadMacInt32(0xb30);
111 WriteMacInt32(tm + qLink, ReadMacInt32(tm_var));
112 WriteMacInt32(tm_var, tm);
113 #endif
114 }
115
116
117 /*
118 * Remove task from Time Manager queue
119 */
120
121 static void dequeue_tm(uint32 tm)
122 {
123 #if TM_QUEUE
124 uint32 p = ReadMacInt32(0xb30);
125 while (p) {
126 uint32 next = ReadMacInt32(p + qLink);
127 if (next == tm) {
128 WriteMacInt32(p + qLink, ReadMacInt32(next + qLink));
129 return;
130 }
131 }
132 #endif
133 }
134
135
136 /*
137 * Initialize Time Manager
138 */
139
140 void TimerInit(void)
141 {
142 // Mark all descriptors as inactive
143 for (int i=0; i<NUM_DESCS; i++)
144 free_desc(i);
145 }
146
147
148 /*
149 * Exit Time Manager
150 */
151
152 void TimerExit(void)
153 {
154 }
155
156
157 /*
158 * Emulator reset, remove all timer tasks
159 */
160
161 void TimerReset(void)
162 {
163 // Mark all descriptors as inactive
164 for (int i=0; i<NUM_DESCS; i++)
165 free_desc(i);
166 }
167
168
169 /*
170 * Insert timer task
171 */
172
173 int16 InsTime(uint32 tm, uint16 trap)
174 {
175 D(bug("InsTime %08lx, trap %04x\n", tm, trap));
176 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x1fff | (trap << 4) & 0x6000);
177 if (find_desc(tm) >= 0)
178 printf("WARNING: InsTime(): Task re-inserted\n");
179 else {
180 int i = alloc_desc(tm);
181 if (i < 0)
182 printf("FATAL: InsTime(): No free Time Manager descriptor\n");
183 }
184 return 0;
185 }
186
187
188 /*
189 * Remove timer task
190 */
191
192 int16 RmvTime(uint32 tm)
193 {
194 D(bug("RmvTime %08lx\n", tm));
195
196 // Find descriptor
197 int i = find_desc(tm);
198 if (i < 0) {
199 printf("WARNING: RmvTime(%08x): Descriptor not found\n", tm);
200 return 0;
201 }
202
203 // Task active?
204 if (ReadMacInt16(tm + qType) & 0x8000) {
205
206 // Yes, make task inactive and remove it from the Time Manager queue
207 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
208 dequeue_tm(tm);
209
210 // Compute remaining time
211 tm_time_t remaining, current;
212 timer_current_time(current);
213 timer_sub_time(remaining, desc[i].wakeup, current);
214 WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining));
215 } else
216 WriteMacInt32(tm + tmCount, 0);
217 D(bug(" tmCount %d\n", ReadMacInt32(tm + tmCount)));
218
219 // Free descriptor
220 free_desc(i);
221 return 0;
222 }
223
224
225 /*
226 * Start timer task
227 */
228
229 int16 PrimeTime(uint32 tm, int32 time)
230 {
231 D(bug("PrimeTime %08x, time %d\n", tm, time));
232
233 // Find descriptor
234 int i = find_desc(tm);
235 if (i < 0) {
236 printf("FATAL: PrimeTime(): Descriptor not found\n");
237 return 0;
238 }
239
240 // Extended task?
241 if (ReadMacInt16(tm + qType) & 0x4000) {
242
243 // Convert delay time
244 tm_time_t delay;
245 timer_mac2host_time(delay, time);
246
247 // Yes, tmWakeUp set?
248 if (ReadMacInt32(tm + tmWakeUp)) {
249
250 //!! PrimeTime(0) means continue previous delay
251 // (save wakeup time in RmvTime?)
252 if (time == 0)
253 printf("WARNING: Unsupported PrimeTime(0)\n");
254
255 // Yes, calculate wakeup time relative to last scheduled time
256 tm_time_t wakeup;
257 timer_add_time(wakeup, desc[i].wakeup, delay);
258 desc[i].wakeup = wakeup;
259
260 } else {
261
262 // No, calculate wakeup time relative to current time
263 tm_time_t now;
264 timer_current_time(now);
265 timer_add_time(desc[i].wakeup, now, delay);
266 }
267
268 // Set tmWakeUp to indicate that task was scheduled
269 WriteMacInt32(tm + tmWakeUp, 0x12345678);
270
271 } else {
272
273 // Not extended task, calculate wakeup time relative to current time
274 tm_time_t delay;
275 timer_mac2host_time(delay, time);
276 timer_current_time(desc[i].wakeup);
277 timer_add_time(desc[i].wakeup, desc[i].wakeup, delay);
278 }
279
280 // Make task active and enqueue it in the Time Manager queue
281 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
282 enqueue_tm(tm);
283 return 0;
284 }
285
286
287 /*
288 * Timer interrupt function (executed as part of 60Hz interrupt)
289 */
290
291 void TimerInterrupt(void)
292 {
293 // Look for active TMTasks that have expired
294 tm_time_t now;
295 timer_current_time(now);
296 for (int i=0; i<NUM_DESCS; i++)
297 if (desc[i].in_use) {
298 uint32 tm = desc[i].task;
299 if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc[i].wakeup, now) < 0) {
300
301 // Found one, mark as inactive and remove it from the Time Manager queue
302 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
303 dequeue_tm(tm);
304
305 // Call timer function
306 uint32 addr = ReadMacInt32(tm + tmAddr);
307 if (addr) {
308 D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr));
309 M68kRegisters r;
310 r.a[0] = addr;
311 r.a[1] = tm;
312 Execute68k(addr, &r);
313 }
314 }
315 }
316 }