|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * timer.device emulation
5: *
6: * Copyright 1996 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include <assert.h>
13: #include <signal.h>
14: #include <ctype.h>
15:
16: #include "config.h"
17: #include "options.h"
18: #include "memory.h"
19: #include "custom.h"
20: #include "readcpu.h"
21: #include "newcpu.h"
22: #include "xwin.h"
23: #include "autoconf.h"
24: #include "osemu.h"
25: #include "execlib.h"
26:
27: #define UNIT_MICROHZ 0
28: #define UNIT_VBLANK 1
29: /* V36 additions - untested/unimplemented */
30: #define UNIT_ECLOCK 2
31: #define UNIT_WAITUNTIL 3
32: #define UNIT_WAITECLOCK 4
33:
34: #define TR_ADDREQUEST CMD_NONSTD
35: #define TR_GETSYSTIME (CMD_NONSTD+1)
36: #define TR_SETSYSTIME (CMD_NONSTD+2)
37:
38: #if defined(USE_EXECLIB) && defined(HAVE_SIGACTION)
39:
40: static struct timeval next_timer, next_schedule, base_time;
41: static struct itimerval itv;
42:
43: static CPTR timerbase;
44:
45: #ifdef __cplusplus
46: static RETSIGTYPE alarmhandler(...)
47: #else
48: static RETSIGTYPE alarmhandler(int foo)
49: #endif
50: {
51: /* FIXME: This should be an atomic operation throughout... but
52: * calling sigblock() each time we want to change the specialflags
53: * might be expensive. */
54: regs.spcflags |= SPCFLAG_TIMER;
55: }
56:
57: static void TIMER_bumpsched(void)
58: {
59: next_schedule.tv_usec += 20*1000;
60: if (next_schedule.tv_usec >= 1000*1000) {
61: next_schedule.tv_sec ++;
62: next_schedule.tv_usec -= 1000*1000;
63: }
64: }
65:
66: static int timer_sigmask;
67:
68: void TIMER_block(void)
69: {
70: sigset_t set;
71: EXEC_Forbid();
72: sigemptyset(&set); sigaddset(&set, SIGALRM);
73: sigprocmask(SIG_BLOCK, &set, NULL);
74: }
75: void TIMER_unblock(void)
76: {
77: sigset_t set;
78: sigpending(&set);
79: if (sigismember(&set, SIGALRM))
80: regs.spcflags |= SPCFLAG_TIMER;
81: sigemptyset(&set); sigaddset(&set, SIGALRM);
82: sigprocmask(SIG_UNBLOCK, &set, NULL);
83: EXEC_Permit();
84: }
85:
86: /*
87: * This must be called with timer blocked
88: * @@@ make this efficient some day
89: */
90: static void TIMER_rethink(void)
91: {
92: CPTR list = timerbase + 34, node, next;
93: struct timeval tv1, tv2, tv_next;
94:
95: gettimeofday(&tv1, NULL);
96:
97: while (tv1.tv_sec > next_schedule.tv_sec
98: || (tv1.tv_sec == next_schedule.tv_sec
99: && tv1.tv_usec >= next_schedule.tv_usec))
100: {
101: TIMER_bumpsched();
102: }
103: tv_next = next_schedule;
104: for (node = get_long(list); (next = get_long(node)) != 0; node = next) {
105: tv2.tv_sec = get_long(node + 32) + base_time.tv_sec;
106: tv2.tv_usec = get_long(node + 36);
107:
108: if (tv1.tv_sec > tv2.tv_sec
109: || (tv1.tv_sec == tv2.tv_sec && tv1.tv_usec > tv2.tv_usec))
110: {
111: /* Timer expired */
112: EXEC_Remove(node);
113: EXEC_ReplyMsg(node);
114: continue;
115: }
116:
117: if (tv_next.tv_sec > tv2.tv_sec
118: || (tv_next.tv_sec == tv2.tv_sec && tv_next.tv_usec > tv2.tv_usec))
119: {
120: tv_next = tv2;
121: }
122: }
123: tv_next.tv_usec -= tv1.tv_usec;
124: if (tv_next.tv_usec < 0)
125: tv_next.tv_usec += 1000*1000, tv_next.tv_sec--;
126: tv_next.tv_sec -= tv1.tv_sec;
127: if (tv_next.tv_sec < 0)
128: fprintf(stderr, "timer: Impossible\n");
129: itv.it_value = tv_next;
130: setitimer(ITIMER_REAL, &itv, NULL);
131: }
132:
133: void TIMER_Interrupt(void)
134: {
135: struct timeval tv;
136:
137: gettimeofday(&tv, NULL);
138:
139: if (tv.tv_sec > next_schedule.tv_sec
140: || (tv.tv_sec == next_schedule.tv_sec && tv.tv_usec >= next_schedule.tv_usec))
141: {
142: EXEC_QuantumElapsed();
143: TIMER_bumpsched();
144: }
145: TIMER_block();
146: TIMER_rethink();
147: TIMER_unblock();
148: }
149:
150: static ULONG tdev_BeginIO(void)
151: {
152: CPTR ioRequest = m68k_areg(regs, 1); /* IOReq */
153: int unit = get_long(ioRequest + 24);
154: int command = get_word(ioRequest + 28);
155: struct timeval tv;
156:
157: gettimeofday(&tv, NULL);
158: tv.tv_sec -= base_time.tv_sec;
159: if (unit == UNIT_WAITECLOCK || unit == UNIT_ECLOCK)
160: fprintf(stderr, "warning: eclock unit used\n");
161:
162: TIMER_block();
163: put_byte (ioRequest + 31, 0);
164: put_byte (ioRequest + 8, NT_MESSAGE);
165: switch (command) {
166: case TR_ADDREQUEST:
167: if (unit == UNIT_ECLOCK)
168: goto argh;
169:
170: if (unit == UNIT_VBLANK || unit == UNIT_MICROHZ) {
171: unsigned long int usec, sec;
172: sec = get_long(ioRequest + 32) + tv.tv_sec;
173: usec = get_long(ioRequest + 36) + tv.tv_usec;
174: if (usec > 1000*1000)
175: usec -= 1000*1000, sec++;
176: put_long(ioRequest + 32, sec);
177: put_long(ioRequest + 36, usec);
178: }
179:
180: /* clear Quick bit */
181: put_byte (ioRequest + 30, 0);
182: EXEC_Insert(timerbase + 34, ioRequest, 0);
183: TIMER_rethink();
184: break;
185:
186: case TR_GETSYSTIME:
187: put_long(ioRequest + 32, tv.tv_sec);
188: put_long(ioRequest + 36, tv.tv_usec);
189:
190: if ((get_byte(ioRequest + 30) & 1) == 0) {
191: EXEC_ReplyMsg(ioRequest);
192: }
193: break;
194: case TR_SETSYSTIME:
195: fprintf(stderr, "TR_SETSYSTIME\n");
196: /* No way dude */
197: if ((get_byte(ioRequest + 30) & 1) == 0) {
198: EXEC_ReplyMsg(ioRequest);
199: }
200: break;
201:
202: argh:
203: fprintf(stderr, "timer: bogus parameters\n");
204: default:
205: put_byte (ioRequest+31, (UBYTE)-1);
206: break;
207: }
208: TIMER_unblock();
209: return (LONG)(BYTE)get_byte(ioRequest + 31);
210: }
211:
212: static ULONG tdev_AbortIO(void)
213: {
214: CPTR ioRequest = m68k_areg(regs, 1);
215:
216: EXEC_Forbid();
217: TIMER_block();
218: if ((get_byte(ioRequest + 30) & 1) == 0
219: && get_byte(ioRequest + 8) != NT_REPLYMSG)
220: {
221: EXEC_Remove(ioRequest);
222: EXEC_ReplyMsg(ioRequest);
223: }
224:
225: TIMER_unblock();
226: EXEC_Permit();
227: return 0; /* ?? */
228: }
229:
230: static ULONG tdev_Open(void)
231: {
232: CPTR ioRequest = m68k_areg(regs, 1); /* IOReq */
233: int unit = m68k_dreg(regs, 0);
234:
235: /* Check unit number */
236: switch (unit) {
237: case UNIT_MICROHZ:
238: case UNIT_VBLANK:
239: case UNIT_ECLOCK:
240: case UNIT_WAITUNTIL:
241: case UNIT_WAITECLOCK:
242: break;
243:
244: default:
245: put_long (ioRequest+20, (ULONG)-1);
246: put_byte (ioRequest+31, (UBYTE)-1);
247: return (ULONG)-1;
248: }
249: put_word (timerbase + 32, get_word (timerbase + 32) + 1);
250: put_long (ioRequest+24, unit); /* io_Unit */
251: put_byte (ioRequest+31, 0); /* io_Error */
252: put_byte (ioRequest+8, NT_REPLYMSG);
253: return 0;
254: }
255:
256: static ULONG tdev_Close(void)
257: {
258: put_word (m68k_areg(regs, 6) + 32, get_word (m68k_areg(regs, 6) + 32) - 1);
259: return 0;
260: }
261:
262: static ULONG tdev_AddTime(void)
263: {
264: CPTR dest = m68k_areg(regs, 0), src = m68k_areg(regs, 1);
265: unsigned long int usec, sec;
266:
267: usec = get_long(dest + 4) + get_long(src + 4);
268: sec = get_long(dest) + get_long(src);
269: if (usec > 1000*1000)
270: usec -= 1000*1000, sec++;
271: put_long(dest, sec); put_long(dest + 4, usec);
272: return 0;
273: }
274:
275: static ULONG tdev_SubTime(void)
276: {
277: CPTR dest = m68k_areg(regs, 0), src = m68k_areg(regs, 1);
278: unsigned long int usec, sec;
279:
280: usec = get_long(dest + 4) - get_long(src + 4);
281: sec = get_long(dest) - get_long(src);
282: if (get_long(dest+4) < get_long(src+4))
283: usec += 1000*1000, sec--;
284: put_long(dest, sec); put_long(dest + 4, usec);
285: return 0;
286: }
287:
288: static ULONG tdev_CmpTime(void)
289: {
290: CPTR dest = m68k_areg(regs, 0), src = m68k_areg(regs, 1);
291:
292: if (get_long(dest) > get_long(src))
293: return -1;
294: if (get_long(dest) < get_long(src))
295: return 1;
296: if (get_long(dest + 4) > get_long(src + 4))
297: return -1;
298: if (get_long(dest + 4) < get_long(src + 4))
299: return 1;
300: return 0;
301: }
302:
303: static ULONG tdev_ReadEClock(void)
304: {
305: fprintf(stderr, "ReadEClock called\n");
306: return 0;
307: }
308:
309: static ULONG tdev_GetSysTime(void)
310: {
311: struct timeval tv;
312: gettimeofday(&tv, NULL);
313: put_long(m68k_areg(regs, 0), tv.tv_sec - base_time.tv_sec);
314: put_long(m68k_areg(regs, 0) + 4, tv.tv_usec);
315: }
316:
317: #define NR_TIMER_FUNCTIONS 12
318:
319: void timerdev_init(void)
320: {
321: struct sigaction act;
322:
323: timerbase = EXEC_AllocMem(6*NR_TIMER_FUNCTIONS + 34 + /* whatever */ 42, 0);
324:
325: timerbase += 6*NR_TIMER_FUNCTIONS;
326: put_long(timerbase + 10, ds("timer.device"));
327: put_byte(timerbase + 8, NT_DEVICE);
328:
329: EXEC_NewList(timerbase + 34); /* We queue time requests here */
330:
331: EXEC_Enqueue(EXEC_sysbase + 350, timerbase);
332:
333: libemu_InstallFunctionFlags(tdev_Open, timerbase, -6, 0, "timer: Open");
334: libemu_InstallFunctionFlags(tdev_Close, timerbase, -12, 0, "timer: Close");
335: put_word(timerbase - 18, 0x4EF9); put_long(timerbase - 16, EXPANSION_nullfunc);
336: put_word(timerbase - 24, 0x4EF9); put_long(timerbase - 22, EXPANSION_nullfunc);
337: libemu_InstallFunctionFlags(tdev_BeginIO, timerbase, -30, 0, "timer: BeginIO");
338: libemu_InstallFunctionFlags(tdev_AbortIO, timerbase, -36, 0, "timer: AbortIO");
339: libemu_InstallFunctionFlags(tdev_AddTime, timerbase, -42, 0, "timer: AddTime");
340: libemu_InstallFunctionFlags(tdev_SubTime, timerbase, -48, 0, "timer: SubTime");
341: libemu_InstallFunctionFlags(tdev_CmpTime, timerbase, -54, 0, "timer: CmpTime");
342: libemu_InstallFunctionFlags(tdev_ReadEClock, timerbase, -60, 0, "timer: ReadEClock");
343: libemu_InstallFunctionFlags(tdev_GetSysTime, timerbase, -66, 0, "timer: GetSysTime");
344:
345: gettimeofday(&base_time, 0);
346: /* Keep calculations simple */
347: base_time.tv_sec++;
348: base_time.tv_usec = 0;
349:
350: next_schedule = base_time;
351: TIMER_bumpsched();
352:
353: itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
354: act.sa_handler = alarmhandler;
355: sigemptyset(&act.sa_mask);
356: act.sa_flags = 0;
357: #ifdef SA_RESTART
358: act.sa_flags = SA_RESTART;
359: #endif
360: sigaction(SIGALRM, &act, NULL);
361: TIMER_block();
362: TIMER_rethink();
363: TIMER_unblock();
364: }
365:
366: #else
367:
368: void timerdev_init(void)
369: {
370: }
371:
372: void TIMER_block(void)
373: {
374: }
375:
376: void TIMER_unblock(void)
377: {
378: }
379:
380: void TIMER_Interrupt(void)
381: {
382: }
383: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.