Annotation of uae/src/timerdev.c, revision 1.1.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.