|
|
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.