ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/timer.cpp
Revision: 1.5
Committed: 2001-07-09T11:21:59Z (23 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.4: +2 -4 lines
Log Message:
- ADB has its own interrupt flag, INTFLAG_ADB
- ADBMouseMoved(), ADBMouseDown/Up() and ADBKeyDown/Up() trigger the ADB
  interrupt
- ADB mutex is only used for mouse movement (the only input state where it
  matters)
- adb.cpp: toggling relative mouse mode resets mouse_x/y
- PrimeTime(0) schedules a timer task with 0 delay time; this is still not
  the correct implementation, but it makes MacSyndicate work...
- Unix: pthreads are preferred to POSIX.4 timers for 60Hz ticks because the
  timers drift badly under Linux and the thread can compensate for drifting
  well enough
- Unix: moved GetTicks_usec() and Delay_usec() to timer_unix.cpp
- video_x.cpp: X mouse acceleration is disabled in relative mouse mode because
  MacOS does its own acceleration
- video_x.cpp: palette[].pixel and palette[].flags are always preset
- video_x.cpp: decoupled X event handling from 60Hz video refresh cycle by
  using select() with a timeout on the X fd

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * timer.cpp - Time Manager emulation
3     *
4 cebix 1.4 * Basilisk II (C) 1997-2001 Christian Bauer
5 cebix 1.1 *
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 cebix 1.3 printf("WARNING: RmvTime(%08x): Descriptor not found\n", tm);
200 cebix 1.1 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 cebix 1.3 D(bug(" tmCount %d\n", ReadMacInt32(tm + tmCount)));
218 cebix 1.1
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 cebix 1.3 D(bug("PrimeTime %08x, time %d\n", tm, time));
232 cebix 1.1
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 cebix 1.5 if (time == 0)
253     printf("WARNING: Unsupported PrimeTime(0)\n");
254 cebix 1.1
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     }