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

1.1     ! root        1:  /*
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   *
        !             4:   * exec.library emulation
        !             5:   *
        !             6:   * Copyright 1996 Bernd Schmidt
        !             7:   */
        !             8: 
        !             9: #undef USE_EXECLIB
        !            10: 
        !            11: #include "sysconfig.h"
        !            12: #include "sysdeps.h"
        !            13: 
        !            14: #include <assert.h>
        !            15: #include <signal.h>
        !            16: #ifdef USE_EXECLIB
        !            17: #include <setjmp.h>
        !            18: #endif
        !            19: 
        !            20: #include "config.h"
        !            21: #include "options.h"
        !            22: #include "memory.h"
        !            23: #include "custom.h"
        !            24: #include "newcpu.h"
        !            25: #include "xwin.h"
        !            26: #include "autoconf.h"
        !            27: #include "osemu.h"
        !            28: 
        !            29: static CPTR sysbase;
        !            30: 
        !            31: /*
        !            32:  * Exec list management
        !            33:  */
        !            34: 
        !            35: void EXEC_NewList(CPTR list)
        !            36: {
        !            37:     put_long(list, list + 4);
        !            38:     put_long(list + 4, 0);
        !            39:     put_long(list + 8, list);
        !            40: }
        !            41: 
        !            42: void EXEC_Insert(CPTR list, CPTR node, CPTR pred)
        !            43: {
        !            44:     CPTR succ;
        !            45:     if (pred == 0)
        !            46:        pred = list;
        !            47:     put_long(node, succ = get_long(pred));
        !            48:     put_long(pred, node);
        !            49:     put_long(succ + 4, node);
        !            50:     put_long(node + 4, pred);
        !            51: }
        !            52: 
        !            53: void EXEC_Enqueue(CPTR list, CPTR node)
        !            54: {
        !            55:     int pri = (BYTE)get_byte (node + 9);
        !            56:     CPTR lnode = get_long(list); /* lh_Head */
        !            57:     CPTR prev = 0, next;
        !            58:     
        !            59:     for (;(next = get_long(lnode)) != 0 && (BYTE)get_byte(lnode + 9) >= pri;) {
        !            60:        prev = lnode;
        !            61:        lnode = next;
        !            62:     }
        !            63:     EXEC_Insert(list, node, prev);
        !            64: }
        !            65: 
        !            66: void EXEC_Remove(CPTR node)
        !            67: {
        !            68:     CPTR pred = get_long(node + 4), succ = get_long(node);
        !            69:     put_long(pred, succ);
        !            70:     put_long(succ + 4, pred);
        !            71: }
        !            72: 
        !            73: ULONG EXEC_RemHead(CPTR list)
        !            74: {
        !            75:     CPTR head = get_long(list);
        !            76:     if (get_long(head) == 0)
        !            77:        return 0;
        !            78:     EXEC_Remove(head);
        !            79:     return head;
        !            80: }
        !            81: 
        !            82: ULONG EXEC_RemTail(CPTR list)
        !            83: {
        !            84:     CPTR tail = get_long(list + 8);
        !            85:     if (get_long(tail + 4) == 0)
        !            86:        return 0;
        !            87:     
        !            88:     EXEC_Remove(tail);
        !            89:     return tail;
        !            90: }
        !            91: 
        !            92: void EXEC_AddTail(CPTR list, CPTR node) 
        !            93: {
        !            94:     EXEC_Insert(list, node, get_long(list + 8)); 
        !            95: }
        !            96: 
        !            97: CPTR EXEC_FindName(CPTR start, char *name)
        !            98: {
        !            99:     CPTR node = start;
        !           100:     if (name == NULL)
        !           101:        return 0;
        !           102:     
        !           103:     for (;;) {
        !           104:        CPTR nnp;
        !           105:        char *nn;
        !           106: 
        !           107:        node = get_long(start);
        !           108: 
        !           109:        if (node == 0)
        !           110:            break;
        !           111:        nnp = get_long(node + 10);
        !           112:        if (nnp != 0 && (nn = get_real_address(nnp)) != NULL)
        !           113:            if (strcmp(nn, name) == 0)
        !           114:                return node;
        !           115:        start = node;
        !           116:     }
        !           117:     return 0;
        !           118: }
        !           119: 
        !           120: static ULONG execl_Enqueue(void) { EXEC_Enqueue(regs.a[0], regs.a[1]); return 0; }
        !           121: static ULONG execl_Insert(void) { EXEC_Insert(regs.a[0], regs.a[1], regs.a[2]); return 0; }
        !           122: static ULONG execl_AddHead(void) { EXEC_Insert(regs.a[0], regs.a[1], 0); return 0; }
        !           123: static ULONG execl_AddTail(void) { EXEC_Insert(regs.a[0], regs.a[1], get_long(regs.a[0] + 8)); return 0; }
        !           124: static ULONG execl_Remove(void) { EXEC_Remove(regs.a[1]); return 0; }
        !           125: static ULONG execl_RemHead(void) { return EXEC_RemHead(regs.a[0]); }
        !           126: static ULONG execl_RemTail(void) { return EXEC_RemTail(regs.a[0]); }
        !           127: static ULONG execl_FindName(void) { CPTR n = EXEC_FindName(regs.a[0], get_real_address(regs.a[1])); ZFLG = n == 0; return n; }
        !           128: 
        !           129: /*
        !           130:  * Miscellaneous
        !           131:  */
        !           132: 
        !           133: void EXEC_InitStruct(CPTR inittable, CPTR memory, unsigned long size)
        !           134: {
        !           135:     CPTR dptr = memory;
        !           136:     UBYTE *mem = get_real_address(memory);
        !           137:     if (memory == 0 || mem == NULL || !valid_address(memory, size)) {
        !           138:        fprintf(stderr, "Foo\n");
        !           139:        return;
        !           140:     }
        !           141:     memset(mem, 0, size);
        !           142:     fprintf(stderr, "InitStruct\n");
        !           143:     for (;;) {
        !           144:        UBYTE command;
        !           145:        int count, desttype, srcloc;
        !           146:        ULONG offset;
        !           147: 
        !           148:        /* Read commands from even bytes */
        !           149:        inittable = (inittable + 1) & ~1;
        !           150: 
        !           151:        command = get_byte(inittable);
        !           152:        if (command == 0)
        !           153:            break;
        !           154:        desttype = (command >> 6) & 3;
        !           155:        srcloc = (command >> 4) & 3;
        !           156:        count = (command & 15) + 1;
        !           157: 
        !           158:        if (desttype == 3) {
        !           159:            dptr = memory + (get_long(inittable) & 0xFFFFFF);
        !           160:            inittable += 4;
        !           161:        } else if (desttype == 2) {
        !           162:            dptr = memory + get_byte(inittable+1), inittable += 2;
        !           163:        } else 
        !           164:            inittable++;
        !           165: 
        !           166:        if (srcloc != 0)
        !           167:            inittable = (inittable + 1) & ~1;
        !           168: 
        !           169:        if (desttype != 1) {
        !           170:            for(; count > 0; count--) {
        !           171:                switch (srcloc) {
        !           172:                 case 0: put_long(dptr, get_long(inittable)); dptr += 4; inittable += 4; break;
        !           173:                 case 1: put_word(dptr, get_word(inittable)); dptr += 2; inittable += 2; break;
        !           174:                 case 2: put_byte(dptr, get_byte(inittable)); dptr += 1; inittable += 1; break;
        !           175:                }
        !           176:            }
        !           177:        } else {
        !           178:            ULONG data;
        !           179:            switch (srcloc) {
        !           180:             case 0: data = get_byte(inittable); inittable += 1; break;
        !           181:             case 1: data = get_word(inittable); inittable += 2; break;
        !           182:             case 2: data = get_long(inittable); inittable += 4; break;
        !           183:             default: data = 0; /* Alert */ break;
        !           184:            }
        !           185:            for(; count > 0; count--) {
        !           186:                switch (srcloc) {
        !           187:                 case 0: put_long(dptr, data); dptr += 4; break;
        !           188:                 case 1: put_word(dptr, data); dptr += 2; break;
        !           189:                 case 2: put_byte(dptr, data); dptr += 1; break;
        !           190:                }
        !           191:            }
        !           192:        }
        !           193:     }
        !           194: }
        !           195: /* The size parameter sometimes seems to contain garbage in the top 16 bit */
        !           196: static ULONG execl_InitStruct(void) { EXEC_InitStruct(regs.a[1], regs.a[2], regs.d[0] & 0xFFFF); return 0; }
        !           197: 
        !           198: /*
        !           199:  * Interrupts
        !           200:  * This is all very confusing. As I see things, the IntVects field of the
        !           201:  * ExecBase is set up as follows:
        !           202:  *   One interrupt may either be assigned an IntServer, or an IntHandler.
        !           203:  *   PORTS, COPER, VERTB EXTER and NMI are set up as Servers (at least that's
        !           204:  *   what the AutoDocs say), the others as IntHandlers.
        !           205:  *   An IntServer field has a pointer to an Exec list in the iv_Data field,
        !           206:  *   the list contains all the server Interrupt nodes in a nice chain. The
        !           207:  *   iv_Node field is zero. For an IntHandler, the iv_Node field contains a
        !           208:  *   pointer to the node that was passed in SetIntVector.
        !           209:  */
        !           210: 
        !           211: CPTR EXEC_SetIntVector(int number, CPTR interrupt)
        !           212: {
        !           213:     CPTR oldvec = get_long(sysbase + 84 + 12*number + 8);
        !           214:     if (interrupt == 0) {
        !           215:        put_long(sysbase + 84 + 12*number, 0);
        !           216:        put_long(sysbase + 84 + 12*number + 4, 0);
        !           217:        put_long(sysbase + 84 + 12*number + 8, 0);
        !           218:     } else {
        !           219:        put_long(sysbase + 84 + 12*number, get_long(interrupt + 14));
        !           220:        put_long(sysbase + 84 + 12*number + 4, get_long(interrupt + 18));
        !           221:        put_long(sysbase + 84 + 12*number + 8, interrupt);
        !           222:     }
        !           223:     return oldvec;
        !           224: }
        !           225: 
        !           226: void EXEC_RemIntServer(ULONG nr, CPTR interrupt)
        !           227: {
        !           228:     CPTR list = get_long(sysbase + 84 + nr*12);
        !           229:     
        !           230:     EXEC_Remove(interrupt);
        !           231:     /* Disable interrupt if necessary */
        !           232:     if (get_long(get_long(list)) == 0)
        !           233:        put_word(0xDFF09A, 1 << nr);
        !           234: }
        !           235: 
        !           236: void EXEC_AddIntServer(ULONG nr, CPTR interrupt)
        !           237: {
        !           238:     CPTR list = get_long(sysbase + 84 + nr*12);
        !           239:     int was_empty;
        !           240: 
        !           241:     /* Disable interrupt if necessary */
        !           242:     was_empty = get_long(get_long(list)) == 0;
        !           243:     
        !           244:     EXEC_Enqueue(list, interrupt);
        !           245:     if (was_empty)
        !           246:        put_word(0xDFF09A, 0x8000 | (1 << nr));
        !           247:     
        !           248: }
        !           249: 
        !           250: static ULONG execl_SetIntVector(void) { return EXEC_SetIntVector(regs.d[0], regs.a[1]); }
        !           251: static ULONG execl_AddIntServer(void) { EXEC_AddIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
        !           252: static ULONG execl_RemIntServer(void) { EXEC_RemIntServer(regs.d[0] & 15, regs.a[1]); return 0; }
        !           253: 
        !           254: /*
        !           255:  * Memory functions
        !           256:  */
        !           257: 
        !           258: #define MEMF_PUBLIC 1
        !           259: #define MEMF_CHIP 2
        !           260: #define MEMF_FAST 4
        !           261: #define MEMF_LOCAL 256
        !           262: #define MEMF_24BITDMA 512
        !           263: #define MEMF_CLEAR (1<<16)
        !           264: #define MEMF_LARGEST (1<<17)
        !           265: #define MEMF_REVERSE (1<<18)
        !           266: #define MEMF_TOTAL (1<<19)
        !           267: 
        !           268: CPTR EXEC_Allocate(CPTR memheader, unsigned long size)
        !           269: {
        !           270:     CPTR chunk, chunkpp;
        !           271:     unsigned long avail;
        !           272:     
        !           273:     size = (size + 7) & ~7;
        !           274:     
        !           275:     if (size == 0 || size > get_long(memheader + 28))
        !           276:        return 0;
        !           277:        
        !           278:     for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk))
        !           279:        if ((avail = get_long(chunk + 4)) >= size) {
        !           280:            CPTR nextchunk = get_long(chunk);
        !           281:            if (avail-size == 0)
        !           282:                put_long(chunkpp, nextchunk);
        !           283:            else {
        !           284:                put_long(chunkpp, chunk + size);
        !           285:                put_long(chunk + size, nextchunk);
        !           286:                put_long(chunk + size + 4, avail - size);
        !           287:            }
        !           288:            put_long(memheader + 28, get_long(memheader + 28) - size);
        !           289:            return chunk;
        !           290:        }
        !           291:     return 0;
        !           292: }
        !           293: 
        !           294: void EXEC_Deallocate(CPTR memheader, CPTR addr, unsigned long size)
        !           295: {
        !           296:     CPTR chunk, chunkpp;
        !           297:     CPTR areaend;
        !           298: 
        !           299:     if (addr == 0)
        !           300:        return;
        !           301: 
        !           302:     size = (size + 7) & ~7;
        !           303:     areaend = addr + size;
        !           304:     
        !           305:     put_long(memheader + 28, get_long(memheader + 28) + size);
        !           306:     
        !           307:     for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk)) {
        !           308:        if (chunk + get_long(chunk + 4) == addr) {
        !           309:            /* Merge with this and go ahead so we can also merge with the next */
        !           310:            put_long(chunkpp, get_long(chunk));
        !           311:            addr = chunk; size += get_long(chunk + 4);
        !           312:            chunk = chunkpp;
        !           313:            continue;
        !           314:        }
        !           315:        if (areaend == chunk) {
        !           316:            /* Merge with previous */
        !           317:            put_long(chunkpp, addr);
        !           318:            put_long(addr, get_long(chunk));
        !           319:            put_long(addr + 4, get_long(chunk + 4) + size);
        !           320:            return;
        !           321:        }
        !           322:        if (chunk > addr)
        !           323:            break;
        !           324:     }
        !           325:     put_long(chunkpp, addr);
        !           326:     put_long(addr, chunk);
        !           327:     put_long(addr + 4, size);
        !           328: }
        !           329: 
        !           330: CPTR EXEC_AllocMem(unsigned long size, ULONG requirements)
        !           331: {
        !           332:     CPTR nextmh,  memheader = get_long(sysbase + 322);
        !           333:     ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
        !           334:     CPTR result = 0;
        !           335: 
        !           336:     size = (size + 7) & ~7;
        !           337: 
        !           338:     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
        !           339:        if ((get_word(memheader + 14) & attrs) != attrs)
        !           340:            continue;
        !           341:        result = EXEC_Allocate(memheader, size);
        !           342:        if (result != 0)
        !           343:            break;
        !           344:     }
        !           345:     if (result) {
        !           346:        if (requirements & MEMF_CLEAR)
        !           347:            memset(get_real_address(result), 0, size);
        !           348:     }
        !           349:     return result;
        !           350: }
        !           351: 
        !           352: CPTR EXEC_AllocEntry(CPTR ml)
        !           353: {
        !           354:     CPTR newml = EXEC_AllocMem(16 + 8*get_word(ml + 14), MEMF_PUBLIC|MEMF_CLEAR);
        !           355:     int i;
        !           356: 
        !           357:     if (newml == 0)
        !           358:        return 0x80000000|MEMF_PUBLIC;
        !           359:     for (i = 0; i < get_word(ml + 14); i++) {
        !           360:        ULONG reqs = get_long(ml + 16 + 8*i);
        !           361:        ULONG addr = EXEC_AllocMem(get_long(ml + 16 + 8*i + 4), reqs);
        !           362:        if (addr == 0)
        !           363:            /* Thank god for SetPatch */
        !           364:            return 0x80000000 | reqs;
        !           365:        put_long(newml + 16 + 8*i, addr);
        !           366:        put_long(newml + 16 + 8*i + 4, reqs);
        !           367:     }
        !           368:     return newml;
        !           369: }
        !           370: 
        !           371: void EXEC_FreeMem(CPTR addr, unsigned long size)
        !           372: {
        !           373:     CPTR nextmh,  memheader = get_long(sysbase + 322);
        !           374: 
        !           375:     size = (size + 7) & ~7;
        !           376:     if (addr == 0)
        !           377:        return;
        !           378: 
        !           379:     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
        !           380:        if (get_long(memheader + 20) <= addr
        !           381:            && get_long(memheader + 24) > addr) {
        !           382:            EXEC_Deallocate(memheader, addr, size);
        !           383:            return;
        !           384:        }
        !           385:     }
        !           386: }
        !           387: 
        !           388: unsigned long EXEC_AvailMem(ULONG requirements)
        !           389: {
        !           390:     ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
        !           391:     CPTR nextmh, memheader = get_long(sysbase + 322);
        !           392:     CPTR result = 0;
        !           393: 
        !           394:     for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
        !           395:        if ((get_word(memheader + 14) & attrs) != attrs)
        !           396:            continue;
        !           397:        if (attrs & MEMF_LARGEST) {
        !           398:            unsigned long maxsize = 0;
        !           399:            CPTR chunk;
        !           400:            for (chunk = get_long(memheader + 16); chunk != 0; chunk = get_long(chunk))
        !           401:                if (get_long(chunk+4) > maxsize)
        !           402:                    maxsize = get_long(chunk + 4);
        !           403:            result += maxsize;
        !           404:        } else if (attrs & MEMF_TOTAL) {
        !           405:            result += get_long(memheader + 24) - get_long(memheader + 20);
        !           406:        } else result += get_long(memheader + 28);
        !           407:     }
        !           408:     return result;
        !           409: }
        !           410: 
        !           411: void EXEC_AddMemList(unsigned long size, ULONG attrs, int pri, CPTR base,
        !           412:                     CPTR name)
        !           413: {
        !           414:     put_byte(base + 8, 0);
        !           415:     put_byte(base + 9, pri);
        !           416:     put_long(base + 10, name);
        !           417:     put_word(base + 14, attrs);
        !           418:     put_long(base + 16, base + 32);
        !           419:     put_long(base + 20, base + 32);
        !           420:     put_long(base + 36, size - 32);
        !           421:     put_long(base + 28, size - 32);
        !           422:     put_long(base + 24, base + size);
        !           423:     EXEC_Enqueue(sysbase + 322, base);
        !           424: }
        !           425: 
        !           426: static ULONG execl_AddMemList(void)
        !           427: {
        !           428:     EXEC_AddMemList(regs.d[0], regs.d[1], (LONG)regs.d[2], regs.a[0], regs.a[1]);
        !           429:     return 0;
        !           430: }
        !           431: 
        !           432: static ULONG execl_CopyMem(void)
        !           433: {
        !           434:     UBYTE *src = get_real_address(regs.a[0]);
        !           435:     UBYTE *dst = get_real_address(regs.a[1]);
        !           436: 
        !           437:     if (src != NULL && dst != NULL
        !           438:        && valid_address(regs.a[0], regs.d[0])
        !           439:        && valid_address(regs.a[1], regs.d[0]))
        !           440:        memcpy(dst, src, regs.d[0]);
        !           441:     else
        !           442:        fprintf(stderr, "CopyMem with bogus parameters\n");
        !           443:     return 0;
        !           444: }
        !           445: 
        !           446: static ULONG execl_AllocMem(void) { return EXEC_AllocMem(regs.d[0], regs.d[1]); }
        !           447: static ULONG execl_AllocEntry(void) { return EXEC_AllocEntry(regs.a[0]); }
        !           448: static ULONG execl_Allocate(void) { return EXEC_Allocate(regs.a[0], regs.d[0]); }
        !           449: static ULONG execl_FreeMem(void) { EXEC_FreeMem(regs.a[1], regs.d[0]); return 0; }
        !           450: static ULONG execl_AvailMem(void) { return EXEC_AvailMem(regs.d[1]); }
        !           451: static ULONG execl_Deallocate(void) { EXEC_Deallocate(regs.a[0], regs.a[1], regs.d[0]); return 0; }
        !           452: 
        !           453: /*
        !           454:  * Scheduling
        !           455:  */
        !           456: 
        !           457: #define TS_RUN 2
        !           458: #define TS_READY 3
        !           459: #define TS_WAIT 4
        !           460: #define TS_EXCEPT 5
        !           461: 
        !           462: struct NewTask {
        !           463:     struct NewTask *next, *prev;
        !           464:     CPTR exectask;
        !           465: #ifdef USE_EXECLIB
        !           466:     jmp_buf j;
        !           467: #endif
        !           468:     void *stack;
        !           469:     struct regstruct regs;
        !           470:     struct flag_struct flags;
        !           471: };
        !           472: 
        !           473: static struct NewTask idle_task;
        !           474: static int intr_count, need_resched;
        !           475: 
        !           476: static struct NewTask *find_newtask(CPTR task)
        !           477: {
        !           478:     /* Ugh, this is ugly */
        !           479:     struct NewTask *t = &idle_task;
        !           480:     do {
        !           481:        if (t->exectask == task)
        !           482:            return t;
        !           483:        t = t->next;
        !           484:     } while (t != &idle_task);
        !           485:     fprintf(stderr, "Uh oh. Task list corrupt\n");
        !           486: }
        !           487: 
        !           488: static void schedule(void)
        !           489: {
        !           490: #ifdef USE_EXECLIB
        !           491:     CPTR readylist = sysbase + 406;
        !           492:     CPTR readytask = get_long(readylist);
        !           493:     CPTR runtask = get_long(sysbase + 276);
        !           494:     struct NewTask *runtask_nt, *readytask_nt;
        !           495:     unsigned long oldflags;
        !           496: 
        !           497:     int idis;
        !           498:     
        !           499:     need_resched = 0;
        !           500:     /* Any ready tasks? */
        !           501:     if (get_long(readytask) == 0)
        !           502:        return;
        !           503:     
        !           504:     /* If the running task is going to sleep, don't check priorities*/
        !           505:     if (get_byte(runtask + 15) != TS_WAIT) {
        !           506:        /* Has the running task a higher priority than any ready tasks? */
        !           507:        if ((BYTE)get_byte(runtask + 9) > (BYTE)get_byte(readytask + 9))
        !           508:        return;
        !           509:        /* We should only preempt a task of the same priority if the quantum
        !           510:         * has expired. Hmmm... */
        !           511:     }
        !           512:     if (get_byte(runtask + 15) == TS_RUN)
        !           513:        put_byte(runtask + 15, TS_READY);
        !           514:     if (get_byte(runtask + 15) == TS_WAIT)
        !           515:        EXEC_Enqueue(sysbase + 420, runtask);
        !           516:     else
        !           517:        EXEC_Enqueue(readylist, runtask);
        !           518:     put_byte(readytask + 15, TS_RUN);
        !           519:     EXEC_Remove(readytask);
        !           520:     
        !           521:     readytask_nt = find_newtask(readytask);
        !           522:     runtask_nt = find_newtask(runtask);
        !           523:     
        !           524: 
        !           525:     oldflags = regs.spcflags;
        !           526:     runtask_nt->regs = regs;
        !           527:     runtask_nt->flags = regflags;
        !           528:     regs = readytask_nt->regs;
        !           529:     regflags = readytask_nt->flags;
        !           530:     regs.spcflags = (regs.spcflags & ~PRESERVED_FLAGS) | (oldflags & PRESERVED_FLAGS);
        !           531:     
        !           532:     put_byte(runtask + 16, get_byte(sysbase + 294));
        !           533:     put_byte(runtask + 17, get_byte(sysbase + 295));
        !           534:     put_byte(sysbase + 294, idis = get_byte(readytask + 16));
        !           535:     put_byte(sysbase + 295, get_byte(readytask + 17));
        !           536:     put_long(sysbase + 276, readytask);
        !           537:     /* Set INTENA according to new interrupt enable status */
        !           538:     if (idis == 0xFF)
        !           539:        put_word(0xDFF09A, 0xC000);
        !           540:     else
        !           541:        put_word(0xDFF09A, 0x4000);
        !           542:     /* Whee... */
        !           543:     fprintf(stderr, "Task switch: new task %s\n", get_real_address(get_long(readytask + 10)));
        !           544:     if (setjmp(runtask_nt->j) == 0)
        !           545:        longjmp(readytask_nt->j, 1);
        !           546:     regs.spcflags &= ~SPCFLAG_BRK;
        !           547: #endif
        !           548: }
        !           549: 
        !           550: static __inline__ void maybe_schedule(void)
        !           551: {
        !           552:     /* @@@ Should we avoid a schedule when supervisor bit is set?
        !           553:      * Definitely not if the running task is the idle task */
        !           554:     if (intr_count == 0 && get_byte(sysbase + 294) == 0xFF && get_byte(sysbase + 295) == 0xFF && need_resched)
        !           555:        schedule();
        !           556: }
        !           557: 
        !           558: /*
        !           559:  * Signals
        !           560:  */
        !           561: 
        !           562: int EXEC_AllocSignal(int signum)
        !           563: {
        !           564:     CPTR thistask = get_long(sysbase + 276);
        !           565:     ULONG sigalloc = get_long(thistask + 18);
        !           566:     if (signum == -1)
        !           567:        for (signum = 0; signum < 32; signum++)
        !           568:            if ((sigalloc & (1 << signum)) == 0)
        !           569:                break;
        !           570:     
        !           571:     if ((sigalloc & (1 << signum)) == 0) {
        !           572:        put_long(thistask + 18, sigalloc | (1 << signum));
        !           573:     } else
        !           574:        signum = -1;
        !           575: 
        !           576:     return signum;
        !           577: }
        !           578: 
        !           579: void EXEC_FreeSignal(int signum)
        !           580: {
        !           581:     CPTR thistask = get_long(sysbase + 276);
        !           582:     if (signum != -1)
        !           583:        return;
        !           584:     put_long(thistask + 18, get_long(thistask + 18) & ~(1 << signum));
        !           585: }
        !           586: 
        !           587: ULONG EXEC_SetSignal(ULONG newsig, ULONG exec_sigmask)
        !           588: {
        !           589:     CPTR task = get_long(sysbase + 276);
        !           590:     ULONG signals = get_long(task + 26);
        !           591:     /* @@@ check SigExcept here */
        !           592:     put_long(task + 26, (signals & ~exec_sigmask) | (newsig & exec_sigmask));
        !           593:     return signals;
        !           594: }
        !           595: 
        !           596: void EXEC_Signal(CPTR task, ULONG exec_sigmask)
        !           597: {
        !           598:     ULONG exec_sigs = get_long(task + 26);
        !           599:     ULONG sigwait = get_long(task + 22);
        !           600:     put_long(task + 26, exec_sigs | exec_sigmask);
        !           601:     if (get_byte(task + 15) == TS_WAIT && (sigwait & exec_sigmask) != 0) {
        !           602:        EXEC_Remove(task);
        !           603:        EXEC_Enqueue(sysbase + 406, task);
        !           604:        need_resched = 1;
        !           605:        maybe_schedule();
        !           606:     }
        !           607: }
        !           608: 
        !           609: ULONG EXEC_Wait(ULONG exec_sigmask)
        !           610: {
        !           611:     CPTR task = get_long(sysbase + 276);
        !           612:     ULONG exec_sigs = get_long(task + 26);
        !           613:     if ((exec_sigs & exec_sigmask) != 0) {
        !           614:        put_long(task + 26, exec_sigs & ~exec_sigmask);
        !           615:        return exec_sigs & exec_sigmask;
        !           616:     }
        !           617:     if (get_byte(sysbase + 294) != 0xFF || get_byte(sysbase + 295) != 0xFF)
        !           618:     {
        !           619:        fprintf(stderr, "Arrgh, task Wait()ing when it shouldn't\n");
        !           620:     }
        !           621:     if (intr_count || regs.s) {
        !           622:        fprintf(stderr, "Arrgh, task Wait()ing when it _really_ shouldn't\n");
        !           623:     }
        !           624: 
        !           625:     put_byte(task + 15, TS_WAIT);
        !           626:     put_long(task + 22, exec_sigmask);
        !           627:     schedule();
        !           628:     exec_sigs = get_long(task + 26);
        !           629:     if ((exec_sigs & exec_sigmask) != 0) {
        !           630:        put_long(task + 26, exec_sigs & ~exec_sigmask);
        !           631:        return exec_sigs & exec_sigmask;
        !           632:     } 
        !           633:     fprintf(stderr, "Bug: task woke up without signals\n");
        !           634:     return 0;
        !           635: }
        !           636: 
        !           637: static ULONG execl_SetSignal(void) { return EXEC_SetSignal(regs.d[0], regs.d[1]); }
        !           638: static ULONG execl_Signal(void) { EXEC_Signal(regs.a[1], regs.d[0]); return 0; }
        !           639: static ULONG execl_Wait(void) { return EXEC_Wait(regs.d[0]); }
        !           640: static ULONG execl_AllocSignal(void) { return EXEC_AllocSignal((BYTE)regs.d[0]); }
        !           641: static ULONG execl_FreeSignal(void) { EXEC_FreeSignal((BYTE)regs.d[0]); return 0; }
        !           642: 
        !           643: /*
        !           644:  * Semaphores
        !           645:  */
        !           646: 
        !           647: void EXEC_InitSemaphore(CPTR exec_sigsem)
        !           648: {
        !           649:     EXEC_NewList(exec_sigsem + 16);
        !           650:     put_word(exec_sigsem + 14, 0);
        !           651:     put_word(exec_sigsem + 44, 0xFFFF);
        !           652: }
        !           653: 
        !           654: ULONG EXEC_AttemptSemaphore(CPTR exec_sigsem)
        !           655: {
        !           656:     CPTR task = get_long(sysbase + 276);
        !           657:     UWORD count = get_word(exec_sigsem + 44);
        !           658:     if (count == 0xFFFF) {
        !           659:        /* Semaphore free -> lock it */
        !           660:        put_word(exec_sigsem + 44, 0);
        !           661:        put_long(exec_sigsem + 40, task);
        !           662:        put_word(exec_sigsem + 14, 1);
        !           663:        return 1;
        !           664:     }
        !           665:     if (get_long(exec_sigsem + 40) == task) {
        !           666:        /* Locked by same task -> Increment NestCount */
        !           667:        put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
        !           668:        return 1;
        !           669:     }
        !           670:     return 0;
        !           671: }
        !           672: 
        !           673: void EXEC_ObtainSemaphore(CPTR exec_sigsem)
        !           674: {
        !           675:     CPTR task = get_long(sysbase + 276);
        !           676:     UWORD count = get_word(exec_sigsem + 44);
        !           677:     if (count == 0xFFFF) {
        !           678:        /* Semaphore free -> lock it */
        !           679:        put_word(exec_sigsem + 44, 0);
        !           680:        put_long(exec_sigsem + 40, task);
        !           681:        put_word(exec_sigsem + 14, 1);
        !           682:        return;
        !           683:     }
        !           684:     if (get_long(exec_sigsem + 40) == task) {
        !           685:        /* Locked by same task -> Increment NestCount */
        !           686:        put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
        !           687:        return;
        !           688:     }
        !           689:     /* Need to wait. */
        !           690:     /* @@@ None of the predefined signals in exec/tasks.h seem to be used
        !           691:      * for this. We use 0x8000, which appears not to be used otherwise */
        !           692:     put_word(exec_sigsem + 44, count + 1);
        !           693:     EXEC_AddTail(exec_sigsem + 16, task);
        !           694:     if (EXEC_Wait(0x8000) != 0x8000)
        !           695:        fprintf(stderr, "BUG\n");
        !           696: 
        !           697:     /* Now it's mine, all mine! */
        !           698:     put_long(exec_sigsem + 40, task);
        !           699:     put_word(exec_sigsem + 14, 1);
        !           700: }
        !           701: 
        !           702: void EXEC_ReleaseSemaphore(CPTR exec_sigsem)
        !           703: {
        !           704:     UWORD nest = get_word(exec_sigsem + 14);
        !           705:     put_word(exec_sigsem + 14, nest - 1);
        !           706:     if (nest == 1) {
        !           707:        /* We're losing it. Signal the first task on the wait queue
        !           708:         * (that one will in turn wake the next, etc.) */
        !           709:        CPTR task = EXEC_RemHead(exec_sigsem + 16);
        !           710:        UWORD count = get_word(exec_sigsem + 44);
        !           711:        put_word(exec_sigsem + 44, count - 1);
        !           712:        if (task) {
        !           713:            EXEC_Signal(task, 0x8000);
        !           714:        }
        !           715:     }
        !           716: }
        !           717: 
        !           718: static ULONG execl_ObtainSemaphore(void) { EXEC_ObtainSemaphore(regs.a[0]); return 0; }
        !           719: static ULONG execl_ReleaseSemaphore(void) { EXEC_ReleaseSemaphore(regs.a[0]); return 0; }
        !           720: static ULONG execl_FindSemaphore(void) { return EXEC_FindName(sysbase + 532, get_real_address(regs.a[1])); }
        !           721: static ULONG execl_InitSemaphore(void) { EXEC_InitSemaphore(regs.a[0]); return 0; }
        !           722: static ULONG execl_AttemptSemaphore(void) { return EXEC_AttemptSemaphore(regs.a[0]); }
        !           723: static ULONG execl_AddSemaphore(void) { put_byte(regs.a[1] + 8, 15); EXEC_Enqueue(sysbase + 532, regs.a[1]); return 0; }
        !           724: 
        !           725: /*
        !           726:  * Messages and ports
        !           727:  */
        !           728: 
        !           729: CPTR EXEC_GetMsg(CPTR port)
        !           730: {
        !           731:     return EXEC_RemHead(port + 20);
        !           732: }
        !           733: 
        !           734: /* This is shared between PutMsg and ReplyMsg */
        !           735: static void EXEC_doputmsg(CPTR port, CPTR msg)
        !           736: {
        !           737:     UBYTE flags = get_byte (port + 14);
        !           738:     EXEC_AddTail(port + 20, msg);
        !           739:     if (flags == 0)
        !           740:        EXEC_Signal(get_long(port + 16), 1 << get_byte(port + 15));
        !           741:     else if (flags == 1)
        !           742:        fprintf(stderr, "PA_SOFTINT unsupported\n");
        !           743:     
        !           744: }
        !           745: 
        !           746: void EXEC_PutMsg(CPTR port, CPTR msg)
        !           747: {
        !           748:     put_byte(msg + 8, 5);
        !           749:     EXEC_doputmsg(port, msg);
        !           750: }
        !           751: 
        !           752: void EXEC_ReplyMsg(CPTR msg)
        !           753: {    
        !           754:     put_byte(msg + 8, 7);
        !           755:     EXEC_doputmsg(get_long(msg + 14), msg);
        !           756: }
        !           757: 
        !           758: CPTR EXEC_WaitPort(CPTR port)
        !           759: {
        !           760:     for (;;) {
        !           761:        CPTR msg = get_long(port + 20);
        !           762:        if (get_long(msg) != 0)
        !           763:            return msg;
        !           764:        if (get_byte(port + 14) != 0)
        !           765:            fprintf(stderr, "Don't know how to WaitPort()\n");
        !           766:        EXEC_Wait(1 << get_byte(port + 15));
        !           767:     }
        !           768: }
        !           769: 
        !           770: static ULONG execl_GetMsg(void) { return EXEC_GetMsg(regs.a[0]); }
        !           771: static ULONG execl_PutMsg(void) { EXEC_PutMsg(regs.a[0], regs.a[1]); return 0; }
        !           772: static ULONG execl_ReplyMsg(void) { EXEC_ReplyMsg(regs.a[1]); return 0; }
        !           773: static ULONG execl_WaitPort(void) { return EXEC_WaitPort(regs.a[0]); }
        !           774: static ULONG execl_FindPort(void) { return EXEC_FindName(sysbase + 392, get_real_address(regs.a[1])); }
        !           775: static ULONG execl_AddPort(void) { put_byte(regs.a[1] + 8, 4); EXEC_Enqueue(sysbase + 392, regs.a[1]); return 0; }
        !           776: 
        !           777: /*
        !           778:  * I/O
        !           779:  */
        !           780: 
        !           781: LONG EXEC_WaitIO(CPTR ioreq)
        !           782: {
        !           783:     /* The device is supposed to clear the IO_QUICK bit if it's going to
        !           784:      * reply to the command */
        !           785:     if ((get_byte(ioreq + 30) & 1) == 1)
        !           786:        return (LONG)(BYTE)get_byte(ioreq + 31);
        !           787: 
        !           788:     for (;;) {
        !           789:        if (get_byte(ioreq + 8) == 7) /* NT_REPLYMSG? */
        !           790:            break;
        !           791:        /* We'll just hope that this a) has a ReplyPort and b) that port
        !           792:         * is of type PA_SIGNAL 
        !           793:         * Don't WaitPort() here: WaitPort() returns a message, and we
        !           794:         * aren't sure it's for us. */
        !           795:        
        !           796:        EXEC_Wait(1 << get_byte(get_long(ioreq + 14) + 15));
        !           797:     }
        !           798:     EXEC_Remove(ioreq);
        !           799:     return (LONG)(BYTE)get_byte(ioreq + 31);
        !           800: }
        !           801: 
        !           802: static void EXEC_BeginIO(CPTR ioreq)
        !           803: {
        !           804:     CPTR dev = get_long(ioreq + 20);
        !           805:     regs.a[6] = dev;
        !           806:     regs.a[1] = ioreq;
        !           807:     Call68k(dev - 30, 1);
        !           808: }
        !           809: 
        !           810: void EXEC_DoIO(CPTR ioreq)
        !           811: {
        !           812:     put_byte(ioreq + 30, 1);
        !           813:     EXEC_BeginIO(ioreq);
        !           814:     EXEC_WaitIO(ioreq);
        !           815: }
        !           816:     
        !           817: void EXEC_SendIO(CPTR ioreq)
        !           818: {
        !           819:     put_byte(ioreq + 30, 0);
        !           820:     EXEC_BeginIO(ioreq);
        !           821: }
        !           822: 
        !           823: CPTR EXEC_CheckIO(CPTR ioreq)
        !           824: {
        !           825:     if ((get_byte(ioreq + 30) & 1) == 1)
        !           826:        return ioreq;
        !           827:     if (get_byte(ioreq + 8) == 7)
        !           828:        return ioreq;
        !           829:     return 0;
        !           830: }
        !           831: 
        !           832: static ULONG execl_WaitIO(void) { return EXEC_WaitIO(regs.a[1]); }
        !           833: static ULONG execl_DoIO(void) { EXEC_DoIO(regs.a[1]); return 0;  }
        !           834: static ULONG execl_SendIO(void) { EXEC_SendIO(regs.a[1]); return 0;  }
        !           835: static ULONG execl_CheckIO(void) { return EXEC_CheckIO(regs.a[1]); }
        !           836: 
        !           837: /*
        !           838:  * Libraries
        !           839:  */
        !           840: 
        !           841: void EXEC_SumLibrary(CPTR lib)
        !           842: {
        !           843:     CPTR start = lib - get_word(lib + 16);
        !           844:     int len = get_word(lib + 16) + get_word(lib + 18);
        !           845:     ULONG sum = 0;
        !           846:     UWORD flags = get_word(lib + 14);
        !           847:     
        !           848:     if (flags & 1) /* SUMMING? */
        !           849:        return;
        !           850:     if (!(flags & 4)) /* SUMUSED? */
        !           851:        return;
        !           852:     put_word(lib + 14, flags & ~2); /* mark as not changed */
        !           853:     /* Pretend the checksum is OK, I don't care enough */
        !           854: }
        !           855: 
        !           856: CPTR EXEC_SetFunction(CPTR lib, int funcOffset, CPTR function)
        !           857: {
        !           858:     CPTR oldfunc = get_long(lib + funcOffset + 2);
        !           859:     put_word(lib + funcOffset, 0x4EF9);
        !           860:     put_long(lib + funcOffset + 2, function);
        !           861:     put_word(lib + 14, get_word(lib + 14) | 2);
        !           862:     EXEC_SumLibrary(lib);
        !           863:     return oldfunc;
        !           864: }
        !           865: 
        !           866: void EXEC_AddLibrary(CPTR lib)
        !           867: {
        !           868:     EXEC_Enqueue(sysbase + 378, lib);
        !           869:     put_word(lib + 14, 2); /* mark as changed */
        !           870:     EXEC_SumLibrary(lib);
        !           871: }
        !           872: 
        !           873: CPTR EXEC_OpenLibrary(char *name, int version)
        !           874: {
        !           875:     CPTR lib = EXEC_FindName(sysbase + 378, name);
        !           876:     if (lib != 0) {
        !           877:        regs.a[6] = lib;
        !           878:        regs.d[0] = version;
        !           879:        lib = Call68k(lib - 6, 1);
        !           880:     }
        !           881:     return lib;
        !           882: }
        !           883: 
        !           884: CPTR EXEC_OpenDevice(char *name, ULONG unit, CPTR ioRequest, ULONG flags)
        !           885: {
        !           886:     CPTR dev = EXEC_FindName(sysbase + 350, name);
        !           887:     CPTR replyport = get_long(ioRequest + 14);
        !           888:     put_long(ioRequest + 20, dev);
        !           889:     put_byte(ioRequest + 31, 0);
        !           890:     put_byte(ioRequest + 30, flags); /* is this right? */
        !           891:     if (replyport == 0)
        !           892:        fprintf(stderr, "ioRequest has no ReplyPort\n");
        !           893:     else {
        !           894:        CPTR rtask = get_long(replyport + 16);
        !           895:        if (rtask == 0)
        !           896:            fprintf(stderr, "replyTask == 0\n");
        !           897:        else if (rtask != get_long(sysbase + 276))
        !           898:            fprintf(stderr, "replyTask != current\n");
        !           899: /*     put_long(replyport + 16, get_long(sysbase + 276));*/
        !           900:     }
        !           901:     if (dev != 0) {
        !           902:        regs.a[6] = dev;
        !           903:        regs.a[1] = ioRequest;
        !           904:        regs.d[0] = unit;
        !           905:        regs.d[1] = flags;
        !           906:        dev = Call68k(dev - 6, 1);
        !           907:     }
        !           908:     return (LONG)(BYTE)get_byte(ioRequest + 31);
        !           909: }
        !           910: 
        !           911: void EXEC_AddDevice(CPTR lib)
        !           912: {
        !           913:     EXEC_Enqueue(sysbase + 350, lib);
        !           914: }
        !           915: 
        !           916: void EXEC_AddResource(CPTR lib)
        !           917: {
        !           918:     EXEC_Enqueue(sysbase + 336, lib);
        !           919: }
        !           920: 
        !           921: CPTR EXEC_OpenResource(char *name)
        !           922: {
        !           923:     CPTR lib = EXEC_FindName(sysbase + 336, name);
        !           924:     return lib;
        !           925: }
        !           926: 
        !           927: void EXEC_MakeFunctions(CPTR target, CPTR funcarray, CPTR funcdispb)
        !           928: {
        !           929:     if (funcdispb != 0) {
        !           930:        WORD tmp;
        !           931:        for (;;) {
        !           932:            tmp = get_word(funcarray); funcarray += 2;
        !           933:            if (tmp == -1)
        !           934:                break;
        !           935:            target -= 6;
        !           936:            put_word(target, 0x4EF9); /* JMP.L */
        !           937:            put_long(target + 2, funcdispb + tmp);
        !           938:        }
        !           939:     } else {
        !           940:        CPTR tmp;
        !           941:        for (;;) {
        !           942:            tmp = get_long(funcarray); funcarray += 4;
        !           943:            if (tmp == (CPTR)-1)
        !           944:                break;
        !           945:            target -= 6;
        !           946:            put_word(target, 0x4EF9); /* JMP.L */
        !           947:            put_long(target + 2, tmp);
        !           948:        }
        !           949:     }
        !           950: }
        !           951: 
        !           952: /* This doesn't work yet */
        !           953: CPTR EXEC_MakeLibrary(CPTR vectors, CPTR structure, CPTR init,
        !           954:                      unsigned long dsize, ULONG seglist_b)
        !           955: {
        !           956:     CPTR seglist = seglist_b << 2;
        !           957:     int vec_cnt = 0;
        !           958:     unsigned long negsize;
        !           959:     CPTR base, fdispb = 0, funcarray = vectors;
        !           960:     ULONG retval = 0;
        !           961: 
        !           962:     fprintf(stderr, "MakeLibrary\n");
        !           963:     if (get_word (vectors) == (UWORD)-1) {
        !           964:        int offs = 2;
        !           965:        fdispb = vectors;
        !           966:        funcarray += 2;
        !           967:        while (get_word (vectors+offs) != (UWORD)-1) {
        !           968:            offs += 2;
        !           969:            vec_cnt++;
        !           970:        }
        !           971:     } else {
        !           972:        int offs = 0;
        !           973:        while (get_long (vectors+offs) != (LONG)-1) {
        !           974:            offs += 4; 
        !           975:            vec_cnt++;
        !           976:        }
        !           977:     }
        !           978:     negsize = (vec_cnt * 6 + 3) & ~3;
        !           979:     dsize = (dsize + 3) & ~3;
        !           980: 
        !           981:     base = EXEC_AllocMem(negsize + dsize, MEMF_PUBLIC|MEMF_CLEAR);
        !           982:     if (base == 0) /* Uh oh */
        !           983:        return 0;
        !           984:     EXEC_MakeFunctions(base + negsize, funcarray, fdispb);
        !           985:     base += negsize;
        !           986:     put_word(base + 16, negsize);
        !           987:     put_word(base + 18, dsize);
        !           988:     if (structure != 0) {
        !           989:        /* Size is set to 0 so we won't clear it again */
        !           990:        EXEC_InitStruct(structure, base, 0);
        !           991:     }
        !           992:     if (init != 0) {
        !           993:        regs.a[6] = sysbase;
        !           994:        regs.a[0] = seglist_b; /* BCPL seglist here? */
        !           995:        regs.d[0] = base;
        !           996:        /* call it */
        !           997:        retval = Call68k(init, 0);
        !           998:     } else
        !           999:        retval = base;
        !          1000:     
        !          1001:     return retval;
        !          1002: }
        !          1003: 
        !          1004: CPTR EXEC_InitResident(CPTR resident, ULONG segList)
        !          1005: {
        !          1006:     UBYTE flags = get_byte(resident + 10);
        !          1007:     
        !          1008:     if (flags & 0x80) {
        !          1009:        CPTR autoinit = get_long(resident + 22);
        !          1010:        return EXEC_MakeLibrary(get_long(autoinit + 4), get_long(autoinit + 8),
        !          1011:                                get_long(autoinit + 12), get_long(autoinit), segList >> 4);
        !          1012:     }
        !          1013:     
        !          1014:     regs.d[0] = 0; regs.a[0] = segList; regs.a[6] = sysbase;
        !          1015:     return Call68k(get_long(resident + 22), 0);
        !          1016: }
        !          1017: 
        !          1018: static ULONG execl_MakeFunctions(void) { EXEC_MakeFunctions(regs.a[0], regs.a[1], regs.a[2]); return 0; }
        !          1019: static ULONG execl_SumLibrary(void) { EXEC_SumLibrary(regs.a[1]); return 0; }
        !          1020: static ULONG execl_SetFunction(void) { return EXEC_SetFunction(regs.a[1], (WORD)regs.a[0], regs.d[0]); }
        !          1021: static ULONG execl_AddLibrary(void) { EXEC_AddLibrary(regs.a[1]); return 0; }
        !          1022: static ULONG execl_AddDevice(void) { EXEC_AddDevice(regs.a[1]); return 0; }
        !          1023: static ULONG execl_AddResource(void) { EXEC_AddResource(regs.a[1]); return 0; }
        !          1024: static ULONG execl_OpenLibrary(void) { return EXEC_OpenLibrary(get_real_address(regs.a[1]), regs.d[0]); }
        !          1025: static ULONG execl_OpenDevice(void) { return EXEC_OpenDevice(get_real_address(regs.a[0]), regs.d[0], regs.a[1], regs.d[1]); }
        !          1026: static ULONG execl_OpenResource(void) { return EXEC_OpenResource(get_real_address(regs.a[1])); }
        !          1027: static ULONG execl_MakeLibrary(void) { return EXEC_MakeLibrary(regs.a[0], regs.a[1], regs.a[2], regs.d[0], regs.d[1]); }
        !          1028: 
        !          1029: /*
        !          1030:  * Tasks
        !          1031:  */
        !          1032: 
        !          1033: static void task_startup(void)
        !          1034: {
        !          1035:     m68k_setpc(regs.pc);
        !          1036:     Call68k_retaddr(regs.pc, 0, get_long(regs.a[7] - 4));
        !          1037:     fprintf(stderr, "Task fell through at the end\n");
        !          1038: }
        !          1039: 
        !          1040: CPTR EXEC_AddTask(CPTR task, CPTR initPC, CPTR finalPC)
        !          1041: {
        !          1042: #ifdef USE_EXECLIB
        !          1043:     struct NewTask *nt = (struct NewTask *)malloc(sizeof (struct NewTask));
        !          1044:     nt->exectask = task;
        !          1045:     nt->prev = &idle_task;
        !          1046:     nt->next = idle_task.next;
        !          1047:     idle_task.next->prev = nt;
        !          1048:     idle_task.next = nt;
        !          1049:     memset(&nt->regs, 0, sizeof (nt->regs));
        !          1050:     nt->regs.pc = initPC;
        !          1051:     nt->regs.a[7] = get_long(task + 54);
        !          1052: 
        !          1053:     if (finalPC == 0)
        !          1054:        finalPC = 0xF0FFF0; /* standard "return from 68k mode" calltrap */
        !          1055:     put_byte(task + 16, 0xFF);
        !          1056:     put_byte(task + 17, 0xFF);
        !          1057:     put_long(nt->regs.a[7] - 4, finalPC);
        !          1058:     nt->stack = malloc(65536); /* @@@ make this smaller after checking that
        !          1059:                                * no parts of the emulator need much stack
        !          1060:                                * space */
        !          1061:     nt->j[0].__sp = nt->stack + 65536;
        !          1062:     nt->j[0].__pc = &task_startup;
        !          1063:     put_byte(task + 15, TS_READY);
        !          1064:     put_long(task + 18,0x0000FFFF); /* all tasks have the lower 16 signals allocated */
        !          1065:     EXEC_Enqueue(sysbase + 406, task);
        !          1066:     need_resched = 1;
        !          1067:     maybe_schedule();
        !          1068:     return task;
        !          1069: #endif
        !          1070: }
        !          1071: 
        !          1072: CPTR EXEC_FindTask(char *name)
        !          1073: {
        !          1074:     char *n;
        !          1075:     CPTR v;
        !          1076: 
        !          1077:     if (name == NULL || ((n = get_real_address(get_long(get_long(sysbase + 276) + 10))) != NULL
        !          1078:                         && strcmp(n, name) == 0))
        !          1079:        return get_long(sysbase + 276);
        !          1080:     
        !          1081:     v = EXEC_FindName(sysbase + 406, name); /* ready tasks */
        !          1082:     if (v != 0)
        !          1083:        return v;
        !          1084:     return EXEC_FindName(sysbase + 420, name); /* waiting tasks */
        !          1085: }
        !          1086: 
        !          1087: static ULONG execl_FindTask(void) { return EXEC_FindTask(regs.a[1] == 0 ? NULL : get_real_address(regs.a[1])); }
        !          1088: static ULONG execl_AddTask(void) { return EXEC_AddTask(regs.a[1], regs.a[2], regs.a[3]); }
        !          1089: 
        !          1090: ULONG EXEC_Forbid(void)
        !          1091: {
        !          1092:     int count = (BYTE)get_byte(sysbase + 295);
        !          1093:     count++;
        !          1094:     put_byte(sysbase + 295, count);
        !          1095:     return 0; 
        !          1096: }
        !          1097: ULONG EXEC_Permit(void) 
        !          1098: {
        !          1099:     int count = (BYTE)get_byte(sysbase + 295);
        !          1100:     if (count == -1)
        !          1101:        fprintf(stderr, "Too many Permit() calls\n");
        !          1102:     else
        !          1103:        count--;
        !          1104:     put_byte(sysbase + 295, count);    
        !          1105:     maybe_schedule();
        !          1106:     return 0;
        !          1107: }
        !          1108: 
        !          1109: ULONG EXEC_Disable(void) 
        !          1110: {
        !          1111:     int count = (BYTE)get_byte(sysbase + 294);
        !          1112:     count++;
        !          1113:     put_byte(sysbase + 294, count);
        !          1114:     put_word(0xDFF09A, 0x4000);
        !          1115:     return 0;
        !          1116: }
        !          1117: 
        !          1118: ULONG EXEC_Enable(void)
        !          1119: {
        !          1120:     int count = (BYTE)get_byte(sysbase + 294);
        !          1121:     if (count == -1)
        !          1122:        fprintf(stderr, "Too many Enable() calls\n");
        !          1123:     else
        !          1124:        count--;
        !          1125:     if (count == -1)
        !          1126:        put_word(0xDFF09A, 0xC000);
        !          1127:     put_byte(sysbase + 294, count);
        !          1128:     maybe_schedule();
        !          1129:     return 0;
        !          1130: }
        !          1131: /*
        !          1132:  *  Initialization
        !          1133:  */
        !          1134: static ULONG execlib_init(void)
        !          1135: {
        !          1136:     sysbase = get_long(4);
        !          1137:     
        !          1138:     /* CopyMem and CopyMemQuick */
        !          1139:     libemu_InstallFunction(execl_CopyMem, sysbase, -630);
        !          1140:     libemu_InstallFunction(execl_CopyMem, sysbase, -624);
        !          1141:     libemu_InstallFunction(execl_Allocate, sysbase, -186);
        !          1142:     libemu_InstallFunction(execl_AllocMem, sysbase, -198);
        !          1143:     libemu_InstallFunction(execl_Deallocate, sysbase, -192);
        !          1144:     libemu_InstallFunction(execl_FreeMem, sysbase, -210);
        !          1145:     libemu_InstallFunction(execl_AvailMem, sysbase, -216);
        !          1146:     
        !          1147:     /* List management */
        !          1148:     libemu_InstallFunction(execl_Insert, sysbase, -234);
        !          1149:     libemu_InstallFunction(execl_AddHead, sysbase, -240);
        !          1150:     libemu_InstallFunction(execl_AddTail, sysbase, -246);
        !          1151:     libemu_InstallFunction(execl_Enqueue, sysbase, -270);
        !          1152:     libemu_InstallFunction(execl_RemHead, sysbase, -258);
        !          1153:     libemu_InstallFunction(execl_RemTail, sysbase, -264);
        !          1154:     libemu_InstallFunction(execl_Remove, sysbase, -252);
        !          1155:     libemu_InstallFunction(execl_FindName, sysbase, -276);
        !          1156:     
        !          1157:     /* Signals */
        !          1158:     libemu_InstallFunction(execl_AllocSignal, sysbase, -330);
        !          1159:     libemu_InstallFunction(execl_FreeSignal, sysbase, -336);
        !          1160: 
        !          1161:     /* Semaphores */
        !          1162:     libemu_InstallFunction(execl_FindSemaphore, sysbase, -594);
        !          1163:     libemu_InstallFunction(execl_InitSemaphore, sysbase, -558);
        !          1164:     libemu_InstallFunction(execl_AddSemaphore, sysbase, -600);
        !          1165: 
        !          1166:     /* Messages/Ports */
        !          1167:     libemu_InstallFunction(execl_FindPort, sysbase, -390);
        !          1168:     libemu_InstallFunction(execl_GetMsg, sysbase, -372);
        !          1169: 
        !          1170:     /* Libraries */
        !          1171:     libemu_InstallFunction(execl_MakeFunctions, sysbase, -90);
        !          1172:     libemu_InstallFunction(execl_SumLibrary, sysbase, -426);
        !          1173:     libemu_InstallFunction(execl_SetFunction, sysbase, -420);
        !          1174:     
        !          1175:     /* Tasks */
        !          1176:     libemu_InstallFunction(execl_FindTask, sysbase, -294);
        !          1177: 
        !          1178:     /* Interrupts */
        !          1179:     libemu_InstallFunction(execl_SetIntVector, sysbase, -162);
        !          1180:     libemu_InstallFunction(execl_AddIntServer, sysbase, -168);
        !          1181:     libemu_InstallFunction(execl_RemIntServer, sysbase, -174);
        !          1182:     
        !          1183:     /* Miscellaneous */
        !          1184:     libemu_InstallFunction(execl_InitStruct, sysbase, -78);
        !          1185: 
        !          1186:     return 0;
        !          1187: }
        !          1188: 
        !          1189: static ULONG execlib_init2(void)
        !          1190: {
        !          1191:     sysbase = get_long(4);
        !          1192:     
        !          1193:     libemu_InstallFunction(execl_AllocEntry, sysbase, -222);
        !          1194:     
        !          1195:     libemu_InstallFunction(execl_AddLibrary, sysbase, -396);
        !          1196:     libemu_InstallFunction(execl_AddDevice, sysbase, -432);
        !          1197:     libemu_InstallFunction(execl_AddResource, sysbase, -486);
        !          1198:     libemu_InstallFunction(execl_OpenLibrary, sysbase, -552);
        !          1199:     libemu_InstallFunction(execl_OpenDevice, sysbase, -444);
        !          1200:     libemu_InstallFunction(execl_OpenResource, sysbase, -498);
        !          1201:     libemu_InstallFunction(execl_MakeLibrary, sysbase, -84);
        !          1202: 
        !          1203:     libemu_InstallFunctionFlags(EXEC_Disable, sysbase, -120, TRAPFLAG_NORETVAL);
        !          1204:     libemu_InstallFunctionFlags(EXEC_Enable, sysbase, -126, TRAPFLAG_NORETVAL);
        !          1205:     libemu_InstallFunctionFlags(EXEC_Permit, sysbase, -138, TRAPFLAG_NORETVAL);
        !          1206:     libemu_InstallFunctionFlags(EXEC_Forbid, sysbase, -132, TRAPFLAG_NORETVAL);
        !          1207:     
        !          1208:     libemu_InstallFunction(execl_AddTask, sysbase, -282);
        !          1209: 
        !          1210:     libemu_InstallFunction(execl_SetSignal, sysbase, -306);
        !          1211:     libemu_InstallFunction(execl_Signal, sysbase, -324);
        !          1212:     libemu_InstallFunction(execl_Wait, sysbase, -318);
        !          1213: 
        !          1214:     libemu_InstallFunction(execl_PutMsg, sysbase, -366);
        !          1215:     libemu_InstallFunction(execl_ReplyMsg, sysbase, -378);
        !          1216:     libemu_InstallFunction(execl_WaitPort, sysbase, -384);
        !          1217: 
        !          1218:     libemu_InstallFunction(execl_WaitIO, sysbase, -474);
        !          1219:     libemu_InstallFunction(execl_DoIO, sysbase, -456);
        !          1220:     libemu_InstallFunction(execl_SendIO, sysbase, -462);
        !          1221:     libemu_InstallFunction(execl_CheckIO, sysbase, -468);
        !          1222:     
        !          1223:     libemu_InstallFunctionFlags(execl_ObtainSemaphore, sysbase, -564, TRAPFLAG_NORETVAL);
        !          1224:     libemu_InstallFunctionFlags(execl_ReleaseSemaphore, sysbase, -570, TRAPFLAG_NORETVAL);
        !          1225:     libemu_InstallFunction(execl_AttemptSemaphore, sysbase, -576);
        !          1226: 
        !          1227:     return 0;
        !          1228: }
        !          1229: 
        !          1230: /*
        !          1231:  * These functions are one day going to bootstrap the emulated Exec
        !          1232:  */
        !          1233: 
        !          1234: #define NR_EXEC_FUNCTIONS 105 /* V34 (1.3) maximum */
        !          1235: 
        !          1236: static ULONG EXEC_ENOSYS(void)
        !          1237: {
        !          1238:     fprintf(stderr, "Not a system call\n");
        !          1239:     return 0;
        !          1240: }
        !          1241: 
        !          1242: static ULONG EXEC_StandardIntVec(void)
        !          1243: {
        !          1244:     int num = regs.a[1];
        !          1245:     /* Call the IntHandlers */
        !          1246:     return 0;
        !          1247: }
        !          1248: 
        !          1249: static ULONG EXEC_IntTrap(void)
        !          1250: {
        !          1251:     UWORD intsreq = get_word(0xDFF01E) & get_word(0xDFF01C);
        !          1252:     int i;
        !          1253:     intr_count++;
        !          1254:     
        !          1255:     for (i = 13; i >= 0; i--) {
        !          1256:        if ((intsreq & (1 << i)) != 0) {
        !          1257:        /* Is this a server chain? */
        !          1258:            if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15) {
        !          1259:                CPTR slist = get_long(sysbase + 84 + 12*i);
        !          1260:                CPTR snode = get_long(slist);
        !          1261:                for (;;) {
        !          1262:                    if (get_long(snode) == 0)
        !          1263:                        break;
        !          1264:                    regs.a[0] = 0xDFF000;
        !          1265:                    regs.a[5] = get_long(snode + 18);
        !          1266:                    regs.a[1] = get_long(snode + 14);
        !          1267:                    Call68k(regs.a[5], 0);
        !          1268:                    if (ZFLG == 0)
        !          1269:                        break;
        !          1270:                    snode = get_long(snode);
        !          1271:                }
        !          1272:                put_word(0xDFF09C, 1 << i);
        !          1273:            } else {
        !          1274:                CPTR intnode = get_long(sysbase + 84 + 12*i + 8);
        !          1275:                regs.d[1] = intsreq;
        !          1276:                regs.a[1] = get_long(intnode + 14);
        !          1277:                regs.a[0] = 0xDFF000;
        !          1278:                regs.a[5] = get_long(intnode + 18);
        !          1279:                regs.a[6] = sysbase;
        !          1280:                Call68k(regs.a[5], 0);
        !          1281:            }
        !          1282:            break;
        !          1283:        }
        !          1284:     }
        !          1285:     if (i < 0)
        !          1286:        fprintf(stderr, "So what interrupt am I supposed to serve?\n");
        !          1287:     intr_count--;
        !          1288:     maybe_schedule();
        !          1289: }
        !          1290: 
        !          1291: void execlib_sysinit(void)
        !          1292: {
        !          1293:     CPTR tmp, tmp2;
        !          1294:     CPTR enosys = deftrap(EXEC_ENOSYS);
        !          1295:     CPTR intvec = deftrap(EXEC_StandardIntVec);
        !          1296:     CPTR inttrap = deftrap2(EXEC_IntTrap, TRAPFLAG_NORETVAL);
        !          1297:     CPTR sysstack;
        !          1298:     int i;
        !          1299: 
        !          1300:     tmp = here();
        !          1301:     calltrap2(enosys); dw(RTS);
        !          1302:     
        !          1303:     /* why 0x400? */
        !          1304:     sysbase = 0x400 + NR_EXEC_FUNCTIONS*6;
        !          1305:     memset(get_real_address(sysbase), 0, 558);
        !          1306:     put_long(4, sysbase);
        !          1307: 
        !          1308:     /* Build vectors. We initialize SetFunction so we can call execlib_Init() */
        !          1309:     tmp2 = here();
        !          1310:     calltrap(deftrap(execl_SetFunction));
        !          1311:     dw(RTS);
        !          1312:     for (i = 0; i < NR_EXEC_FUNCTIONS; i++) {
        !          1313:        put_word(sysbase - 6*(i+1), 0x4EF9);
        !          1314:        put_long(sysbase - 6*(i+1) + 2, i == 69 ? tmp2 : tmp);
        !          1315:     }
        !          1316: 
        !          1317:     /* Build syslists */
        !          1318:     EXEC_NewList(sysbase + 322); /* MemList */
        !          1319:     EXEC_NewList(sysbase + 336); /* ResourceList */
        !          1320:     EXEC_NewList(sysbase + 350); /* ResourceList */
        !          1321:     EXEC_NewList(sysbase + 364); /* List */
        !          1322:     EXEC_NewList(sysbase + 378); /* LibList */
        !          1323:     EXEC_NewList(sysbase + 392); /* PortList */
        !          1324:     EXEC_NewList(sysbase + 406); /* TaskReady */
        !          1325:     EXEC_NewList(sysbase + 420); /* TaskWait */
        !          1326:     EXEC_NewList(sysbase + 434); /* SoftInts[5] */
        !          1327:     EXEC_NewList(sysbase + 450); 
        !          1328:     EXEC_NewList(sysbase + 466); 
        !          1329:     EXEC_NewList(sysbase + 482); 
        !          1330:     EXEC_NewList(sysbase + 498); 
        !          1331:     EXEC_NewList(sysbase + 532); /* SemaphoreList */
        !          1332: 
        !          1333:     tmp = sysbase + 558; /* sizeof struct V34 execbase */
        !          1334:     /* We put the supervisor stack at the end, the user stack for our new
        !          1335:      * task at the end - 0x800, and build the ResModules array at the bottom
        !          1336:      * of the stack */
        !          1337:     sysstack = chipmem_size - 0x2000;
        !          1338:     
        !          1339:     /* Don't mess with Fast or Bogo for now, just set up Chip */
        !          1340:     EXEC_AddMemList(sysstack - tmp, MEMF_CHIP|MEMF_PUBLIC, -10, tmp, 
        !          1341:                    ds("Chip Memory"));
        !          1342: 
        !          1343:     /* Set up the CPU */
        !          1344:     regs.usp = chipmem_size - 0x800;
        !          1345:     regs.isp = chipmem_size; /* What about MSP? */
        !          1346:     regs.a[7] = regs.usp;
        !          1347:     regs.s = 0; regs.m = 0;
        !          1348:     regs.vbr = 0;
        !          1349:     regs.t0 = regs.t1 = 0;
        !          1350:     regs.intmask = 0;
        !          1351:     put_word(0xDFF09A, 0x7FFF);
        !          1352:     put_word(0xDFF096, 0x7FFF);
        !          1353:     put_word(0xDFF09C, 0x7FFF);
        !          1354:     put_word(0xDFF09A, 0xC000);
        !          1355:     put_word(0xDFF096, 0xE100);
        !          1356:     /* Initialize our supported functions */
        !          1357:     execlib_init();
        !          1358:     execlib_init2();
        !          1359:     
        !          1360:     /* Initialize interrupts */
        !          1361:     intr_count = 0; 
        !          1362:     put_byte(sysbase + 294, 0xFF);
        !          1363:     put_byte(sysbase + 295, 0xFF);
        !          1364: 
        !          1365:     tmp = here();
        !          1366:     calltrap2(inttrap);
        !          1367:     dw(RTE);
        !          1368:     for (i = 0; i < 8; i++)
        !          1369:        put_long((24+i)*4, tmp);
        !          1370:     
        !          1371:     tmp = here();
        !          1372:     calltrap2(intvec); dw(RTS);
        !          1373:     for (i = 0; i < 16; i++) {
        !          1374:        tmp2 = 0;
        !          1375:        /* Is this a server chain? */
        !          1376:        if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15)
        !          1377:            EXEC_NewList(tmp2 = EXEC_AllocMem(14, MEMF_PUBLIC));
        !          1378:        put_long(sysbase + 84 + i*12, tmp2);
        !          1379:        put_long(sysbase + 84 + i*12 + 4, tmp);
        !          1380:        put_long(sysbase + 84 + i*12 + 8, 0);
        !          1381:     }
        !          1382:     put_word(0xDFF09A, 0xAFC3); /* Enable everything but the server chains */
        !          1383:     /* Set up the init task.  We don't really set it up properly. */
        !          1384:     tmp = EXEC_AllocMem(92, MEMF_CLEAR);
        !          1385:     put_long(sysbase + 276, tmp);
        !          1386:     put_byte(tmp + 8, 1);
        !          1387:     put_byte(tmp + 9, -127);
        !          1388:     put_long(tmp + 10, ds("init"));
        !          1389:     put_byte(tmp + 16, 0xFF);
        !          1390:     put_byte(tmp + 17, 0xFF);
        !          1391:     put_long(tmp + 54, chipmem_size - 0x804);
        !          1392:     put_long(tmp + 58, chipmem_size - 0x1800);
        !          1393:     put_long(tmp + 62, chipmem_size - 0x800);
        !          1394:     put_byte(tmp + 15, TS_RUN);
        !          1395:     put_long(tmp + 18,0x0000FFFF);
        !          1396:     EXEC_NewList(tmp + 74);
        !          1397:     idle_task.next = idle_task.prev = &idle_task;
        !          1398:     idle_task.exectask = tmp;
        !          1399:     idle_task.stack = NULL; /* we have a stack for this one already */
        !          1400: 
        !          1401:     /* Set up an idle task */
        !          1402:     tmp2 = here();
        !          1403:     dw (0x4E72); dw(0x2000); dw (0x4eF9); dl (tmp2);
        !          1404: 
        !          1405:     tmp = EXEC_AllocMem(92, MEMF_CLEAR);
        !          1406:     put_byte(tmp + 8, 1);
        !          1407:     put_byte(tmp + 9, -128);
        !          1408:     put_long(tmp + 10, ds("idle"));
        !          1409:     put_long(tmp + 58, chipmem_size - 0x2000);
        !          1410:     put_long(tmp + 62, chipmem_size - 0x1800);
        !          1411:     put_long(tmp + 54, chipmem_size - 0x1804);
        !          1412:     EXEC_NewList(tmp + 74);
        !          1413:     EXEC_AddTask(tmp,  tmp2, 0); /* This won't start executing yet */
        !          1414:     find_newtask(tmp)->regs.s = 1;
        !          1415: 
        !          1416: 
        !          1417:     /* Grep Kickstart for resident modules */
        !          1418:     regs.a[7] -= 4;
        !          1419:     put_long(regs.a[7], 0);
        !          1420:     tmp2 = regs.a[7];
        !          1421:     for (tmp = 0xF80000; tmp < 0xFFFFFF; tmp += 2) {
        !          1422:        if (get_word(tmp) == 0x4AFC && get_long(tmp + 2) == tmp) {
        !          1423:            regs.a[7] -= 4; put_long(regs.a[7], tmp);
        !          1424:        }
        !          1425:     }
        !          1426:     put_long(sysbase + 300, regs.a[7]);
        !          1427:     /* Bubble me do */
        !          1428:     for (tmp = regs.a[7]; tmp < tmp2; tmp += 4) {
        !          1429:        CPTR tmp3;
        !          1430:        for (tmp3 = tmp2 - 4; tmp3 > tmp; tmp3 -= 4) {
        !          1431:            if ((BYTE)get_byte(get_long(tmp3) + 13) > (BYTE)get_byte(get_long(tmp3 - 4) + 13)) {
        !          1432:                CPTR tmp4 = get_long(tmp3);
        !          1433:                put_long(tmp3, get_long(tmp3 - 4));
        !          1434:                put_long(tmp3 - 4, tmp4);
        !          1435:            }
        !          1436:        }
        !          1437:     }
        !          1438:     
        !          1439:     /* Initialize them and watch everything blow up. */
        !          1440:     for (tmp = regs.a[7]; (tmp2 = get_long(tmp)) != 0; tmp += 4) {
        !          1441:        UBYTE flags = get_byte(tmp2 + 10);
        !          1442:        if (!(flags & 1)) /* RTF_COLDSTART? */
        !          1443:            continue;
        !          1444:        if (strncmp("alert", get_real_address(get_long(tmp2 + 18)), 5) == 0)
        !          1445:            /*continue*/;
        !          1446:        fprintf(stderr, "Initializing %s\n", get_real_address(get_long(tmp2 + 18)));
        !          1447:        EXEC_InitResident(tmp2, /* ? */ 0);
        !          1448:     }
        !          1449:     /* Idle task */
        !          1450:     for(;;) {
        !          1451:        Call68k(0xF0FFF0 - 4, 0);
        !          1452:        schedule();
        !          1453:     }
        !          1454: }
        !          1455: 
        !          1456: /* 
        !          1457:  *  Install the gfx-library-replacement 
        !          1458:  */
        !          1459: void execlib_install(void)
        !          1460: {
        !          1461:     ULONG begin, end, resname, resid;
        !          1462:     int i;
        !          1463:     
        !          1464:     if (!use_gfxlib)
        !          1465:        return;
        !          1466:     
        !          1467:     resname = ds("UAEexeclib.resource");
        !          1468:     resid = ds("UAE execlib 0.1");
        !          1469: 
        !          1470:     begin = here();
        !          1471:     dw(0x4AFC);             /* RTC_MATCHWORD */
        !          1472:     dl(begin);              /* our start address */
        !          1473:     dl(0);                  /* Continue scan here */
        !          1474:     dw(0x0101);             /* RTF_COLDSTART; Version 1 */
        !          1475:     dw(0x0805);             /* NT_RESOURCE; pri 5 */
        !          1476:     dl(resname);            /* name */
        !          1477:     dl(resid);              /* ID */
        !          1478:     dl(here() + 4);         /* Init area: directly after this */
        !          1479: 
        !          1480:     calltrap(deftrap(execlib_init)); dw(RTS);
        !          1481: 
        !          1482:     end = here();
        !          1483:     org(begin + 6);
        !          1484:     dl(end);
        !          1485: 
        !          1486:     org(end);
        !          1487: 
        !          1488:     intr_count = 1; /* So we don't try to schedule if we don't emulate
        !          1489:                     * all of Exec */
        !          1490: }

unix.superglobalmegacorp.com

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