Annotation of uae/src/timerdev.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.