|
|
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: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include <assert.h>
13: #include <signal.h>
1.1.1.2 ! root 14: #include <ctype.h>
1.1 root 15:
16: #include "config.h"
17: #include "options.h"
1.1.1.2 ! root 18: #include "machdep/exectasks.h"
! 19: #include "machdep/m68k.h"
1.1 root 20: #include "memory.h"
21: #include "custom.h"
1.1.1.2 ! root 22: #include "readcpu.h"
1.1 root 23: #include "newcpu.h"
24: #include "xwin.h"
25: #include "autoconf.h"
26: #include "osemu.h"
1.1.1.2 ! root 27: #include "execlib.h"
1.1 root 28:
1.1.1.2 ! root 29: #ifdef USE_EXECLIB
! 30:
! 31: CPTR EXEC_sysbase;
1.1 root 32:
33: /*
34: * Exec list management
35: */
36:
37: void EXEC_NewList(CPTR list)
38: {
39: put_long(list, list + 4);
40: put_long(list + 4, 0);
41: put_long(list + 8, list);
42: }
43:
44: void EXEC_Insert(CPTR list, CPTR node, CPTR pred)
45: {
46: CPTR succ;
47: if (pred == 0)
48: pred = list;
49: put_long(node, succ = get_long(pred));
50: put_long(pred, node);
51: put_long(succ + 4, node);
52: put_long(node + 4, pred);
53: }
54:
55: void EXEC_Enqueue(CPTR list, CPTR node)
56: {
57: int pri = (BYTE)get_byte (node + 9);
58: CPTR lnode = get_long(list); /* lh_Head */
59: CPTR prev = 0, next;
60:
61: for (;(next = get_long(lnode)) != 0 && (BYTE)get_byte(lnode + 9) >= pri;) {
62: prev = lnode;
63: lnode = next;
64: }
65: EXEC_Insert(list, node, prev);
66: }
67:
68: void EXEC_Remove(CPTR node)
69: {
70: CPTR pred = get_long(node + 4), succ = get_long(node);
71: put_long(pred, succ);
72: put_long(succ + 4, pred);
73: }
74:
75: ULONG EXEC_RemHead(CPTR list)
76: {
77: CPTR head = get_long(list);
78: if (get_long(head) == 0)
79: return 0;
80: EXEC_Remove(head);
81: return head;
82: }
83:
84: ULONG EXEC_RemTail(CPTR list)
85: {
86: CPTR tail = get_long(list + 8);
87: if (get_long(tail + 4) == 0)
88: return 0;
89:
90: EXEC_Remove(tail);
91: return tail;
92: }
93:
94: void EXEC_AddTail(CPTR list, CPTR node)
95: {
96: EXEC_Insert(list, node, get_long(list + 8));
97: }
98:
99: CPTR EXEC_FindName(CPTR start, char *name)
100: {
1.1.1.2 ! root 101: CPTR node, next;
! 102:
1.1 root 103: if (name == NULL)
104: return 0;
105:
1.1.1.2 ! root 106: for (node = get_long(start);(next = get_long(node)) != 0; node = next) {
1.1 root 107: CPTR nnp;
108: char *nn;
109:
110: nnp = get_long(node + 10);
1.1.1.2 ! root 111: if (nnp != 0 && (nn = raddr(nnp)) != NULL)
1.1 root 112: if (strcmp(nn, name) == 0)
113: return node;
114: start = node;
115: }
116: return 0;
117: }
118:
1.1.1.2 ! root 119: static ULONG execl_Enqueue(void) { EXEC_Enqueue(m68k_areg(regs, 0), m68k_areg(regs, 1)); return 0; }
! 120: static ULONG execl_Insert(void) { EXEC_Insert(m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_areg(regs, 2)); return 0; }
! 121: static ULONG execl_AddHead(void) { EXEC_Insert(m68k_areg(regs, 0), m68k_areg(regs, 1), 0); return 0; }
! 122: static ULONG execl_AddTail(void) { EXEC_Insert(m68k_areg(regs, 0), m68k_areg(regs, 1), get_long(m68k_areg(regs, 0) + 8)); return 0; }
! 123: static ULONG execl_Remove(void) { EXEC_Remove(m68k_areg(regs, 1)); return 0; }
! 124: static ULONG execl_RemHead(void) { return EXEC_RemHead(m68k_areg(regs, 0)); }
! 125: static ULONG execl_RemTail(void) { return EXEC_RemTail(m68k_areg(regs, 0)); }
! 126: static ULONG execl_FindName(void) { CPTR n = EXEC_FindName(m68k_areg(regs, 0), raddr(m68k_areg(regs, 1))); ZFLG = n == 0; return n; }
1.1 root 127:
128: /*
129: * Miscellaneous
130: */
131:
132: void EXEC_InitStruct(CPTR inittable, CPTR memory, unsigned long size)
133: {
134: CPTR dptr = memory;
1.1.1.2 ! root 135: UBYTE *mem = (UBYTE *)raddr(memory);
1.1 root 136: if (memory == 0 || mem == NULL || !valid_address(memory, size)) {
137: fprintf(stderr, "Foo\n");
138: return;
139: }
140: memset(mem, 0, size);
141: fprintf(stderr, "InitStruct\n");
142: for (;;) {
143: UBYTE command;
144: int count, desttype, srcloc;
145: ULONG offset;
146:
147: /* Read commands from even bytes */
148: inittable = (inittable + 1) & ~1;
149:
150: command = get_byte(inittable);
151: if (command == 0)
152: break;
153: desttype = (command >> 6) & 3;
154: srcloc = (command >> 4) & 3;
155: count = (command & 15) + 1;
156:
157: if (desttype == 3) {
158: dptr = memory + (get_long(inittable) & 0xFFFFFF);
159: inittable += 4;
160: } else if (desttype == 2) {
161: dptr = memory + get_byte(inittable+1), inittable += 2;
162: } else
163: inittable++;
164:
165: if (srcloc != 0)
166: inittable = (inittable + 1) & ~1;
167:
168: if (desttype != 1) {
169: for(; count > 0; count--) {
170: switch (srcloc) {
171: case 0: put_long(dptr, get_long(inittable)); dptr += 4; inittable += 4; break;
172: case 1: put_word(dptr, get_word(inittable)); dptr += 2; inittable += 2; break;
173: case 2: put_byte(dptr, get_byte(inittable)); dptr += 1; inittable += 1; break;
174: }
175: }
176: } else {
177: ULONG data;
178: switch (srcloc) {
179: case 0: data = get_byte(inittable); inittable += 1; break;
180: case 1: data = get_word(inittable); inittable += 2; break;
181: case 2: data = get_long(inittable); inittable += 4; break;
182: default: data = 0; /* Alert */ break;
183: }
184: for(; count > 0; count--) {
185: switch (srcloc) {
186: case 0: put_long(dptr, data); dptr += 4; break;
187: case 1: put_word(dptr, data); dptr += 2; break;
188: case 2: put_byte(dptr, data); dptr += 1; break;
189: }
190: }
191: }
192: }
193: }
194: /* The size parameter sometimes seems to contain garbage in the top 16 bit */
1.1.1.2 ! root 195: static ULONG execl_InitStruct(void) { EXEC_InitStruct(m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_dreg(regs, 0) & 0xFFFF); return 0; }
! 196:
! 197: static ULONG execl_GetCC(void)
! 198: {
! 199: MakeSR();
! 200: m68k_dreg(regs, 0) = regs.sr & 0xFF;
! 201: return 0; /* ignored */
! 202: }
1.1 root 203:
204: /*
205: * Interrupts
206: * This is all very confusing. As I see things, the IntVects field of the
207: * ExecBase is set up as follows:
208: * One interrupt may either be assigned an IntServer, or an IntHandler.
209: * PORTS, COPER, VERTB EXTER and NMI are set up as Servers (at least that's
210: * what the AutoDocs say), the others as IntHandlers.
211: * An IntServer field has a pointer to an Exec list in the iv_Data field,
212: * the list contains all the server Interrupt nodes in a nice chain. The
213: * iv_Node field is zero. For an IntHandler, the iv_Node field contains a
214: * pointer to the node that was passed in SetIntVector.
215: */
216:
217: CPTR EXEC_SetIntVector(int number, CPTR interrupt)
218: {
1.1.1.2 ! root 219: CPTR oldvec = get_long(EXEC_sysbase + 84 + 12*number + 8);
1.1 root 220: if (interrupt == 0) {
1.1.1.2 ! root 221: put_long(EXEC_sysbase + 84 + 12*number, 0);
! 222: put_long(EXEC_sysbase + 84 + 12*number + 4, 0);
! 223: put_long(EXEC_sysbase + 84 + 12*number + 8, 0);
1.1 root 224: } else {
1.1.1.2 ! root 225: put_long(EXEC_sysbase + 84 + 12*number, get_long(interrupt + 14));
! 226: put_long(EXEC_sysbase + 84 + 12*number + 4, get_long(interrupt + 18));
! 227: put_long(EXEC_sysbase + 84 + 12*number + 8, interrupt);
1.1 root 228: }
229: return oldvec;
230: }
231:
232: void EXEC_RemIntServer(ULONG nr, CPTR interrupt)
233: {
1.1.1.2 ! root 234: CPTR list = get_long(EXEC_sysbase + 84 + nr*12);
1.1 root 235:
236: EXEC_Remove(interrupt);
237: /* Disable interrupt if necessary */
238: if (get_long(get_long(list)) == 0)
239: put_word(0xDFF09A, 1 << nr);
240: }
241:
242: void EXEC_AddIntServer(ULONG nr, CPTR interrupt)
243: {
1.1.1.2 ! root 244: CPTR list = get_long(EXEC_sysbase + 84 + nr*12);
1.1 root 245: int was_empty;
246:
247: /* Disable interrupt if necessary */
248: was_empty = get_long(get_long(list)) == 0;
249:
250: EXEC_Enqueue(list, interrupt);
251: if (was_empty)
252: put_word(0xDFF09A, 0x8000 | (1 << nr));
253:
254: }
255:
1.1.1.2 ! root 256: static ULONG execl_SetIntVector(void) { return EXEC_SetIntVector(m68k_dreg(regs, 0), m68k_areg(regs, 1)); }
! 257: static ULONG execl_AddIntServer(void) { EXEC_AddIntServer(m68k_dreg(regs, 0) & 15, m68k_areg(regs, 1)); return 0; }
! 258: static ULONG execl_RemIntServer(void) { EXEC_RemIntServer(m68k_dreg(regs, 0) & 15, m68k_areg(regs, 1)); return 0; }
1.1 root 259:
260: /*
261: * Memory functions
262: */
263:
264: #define MEMF_PUBLIC 1
265: #define MEMF_CHIP 2
266: #define MEMF_FAST 4
267: #define MEMF_LOCAL 256
268: #define MEMF_24BITDMA 512
269: #define MEMF_CLEAR (1<<16)
270: #define MEMF_LARGEST (1<<17)
271: #define MEMF_REVERSE (1<<18)
272: #define MEMF_TOTAL (1<<19)
273:
274: CPTR EXEC_Allocate(CPTR memheader, unsigned long size)
275: {
276: CPTR chunk, chunkpp;
277: unsigned long avail;
278:
279: size = (size + 7) & ~7;
280:
281: if (size == 0 || size > get_long(memheader + 28))
282: return 0;
283:
284: for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk))
285: if ((avail = get_long(chunk + 4)) >= size) {
286: CPTR nextchunk = get_long(chunk);
287: if (avail-size == 0)
288: put_long(chunkpp, nextchunk);
289: else {
290: put_long(chunkpp, chunk + size);
291: put_long(chunk + size, nextchunk);
292: put_long(chunk + size + 4, avail - size);
293: }
294: put_long(memheader + 28, get_long(memheader + 28) - size);
295: return chunk;
296: }
297: return 0;
298: }
299:
300: void EXEC_Deallocate(CPTR memheader, CPTR addr, unsigned long size)
301: {
302: CPTR chunk, chunkpp;
303: CPTR areaend;
304:
305: if (addr == 0)
306: return;
307:
308: size = (size + 7) & ~7;
309: areaend = addr + size;
310:
311: put_long(memheader + 28, get_long(memheader + 28) + size);
312:
313: for (chunk = get_long(chunkpp = memheader + 16); chunk != 0; chunkpp = chunk, chunk = get_long(chunk)) {
314: if (chunk + get_long(chunk + 4) == addr) {
315: /* Merge with this and go ahead so we can also merge with the next */
316: put_long(chunkpp, get_long(chunk));
317: addr = chunk; size += get_long(chunk + 4);
318: chunk = chunkpp;
319: continue;
320: }
321: if (areaend == chunk) {
322: /* Merge with previous */
323: put_long(chunkpp, addr);
324: put_long(addr, get_long(chunk));
325: put_long(addr + 4, get_long(chunk + 4) + size);
326: return;
327: }
328: if (chunk > addr)
329: break;
330: }
331: put_long(chunkpp, addr);
332: put_long(addr, chunk);
333: put_long(addr + 4, size);
334: }
335:
336: CPTR EXEC_AllocMem(unsigned long size, ULONG requirements)
337: {
1.1.1.2 ! root 338: CPTR nextmh, memheader = get_long(EXEC_sysbase + 322);
1.1 root 339: ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
340: CPTR result = 0;
341:
342: size = (size + 7) & ~7;
343:
344: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
345: if ((get_word(memheader + 14) & attrs) != attrs)
346: continue;
347: result = EXEC_Allocate(memheader, size);
348: if (result != 0)
349: break;
350: }
351: if (result) {
352: if (requirements & MEMF_CLEAR)
1.1.1.2 ! root 353: memset(raddr(result), 0, size);
1.1 root 354: }
355: return result;
356: }
357:
358: CPTR EXEC_AllocEntry(CPTR ml)
359: {
360: CPTR newml = EXEC_AllocMem(16 + 8*get_word(ml + 14), MEMF_PUBLIC|MEMF_CLEAR);
361: int i;
362:
363: if (newml == 0)
364: return 0x80000000|MEMF_PUBLIC;
365: for (i = 0; i < get_word(ml + 14); i++) {
366: ULONG reqs = get_long(ml + 16 + 8*i);
367: ULONG addr = EXEC_AllocMem(get_long(ml + 16 + 8*i + 4), reqs);
368: if (addr == 0)
369: /* Thank god for SetPatch */
370: return 0x80000000 | reqs;
371: put_long(newml + 16 + 8*i, addr);
372: put_long(newml + 16 + 8*i + 4, reqs);
373: }
374: return newml;
375: }
376:
377: void EXEC_FreeMem(CPTR addr, unsigned long size)
378: {
1.1.1.2 ! root 379: CPTR nextmh, memheader = get_long(EXEC_sysbase + 322);
1.1 root 380:
381: size = (size + 7) & ~7;
382: if (addr == 0)
383: return;
1.1.1.2 ! root 384: if (size == 0) {
! 385: fprintf(stderr, "warning: Freemem(..., 0)\n");
! 386: return;
! 387: }
1.1 root 388:
389: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
390: if (get_long(memheader + 20) <= addr
391: && get_long(memheader + 24) > addr) {
392: EXEC_Deallocate(memheader, addr, size);
393: return;
394: }
395: }
396: }
397:
398: unsigned long EXEC_AvailMem(ULONG requirements)
399: {
400: ULONG attrs = requirements & (MEMF_PUBLIC | MEMF_CHIP | MEMF_FAST);
1.1.1.2 ! root 401: CPTR nextmh, memheader = get_long(EXEC_sysbase + 322);
1.1 root 402: CPTR result = 0;
403:
404: for (;(nextmh = get_long(memheader)) != 0; memheader = nextmh) {
405: if ((get_word(memheader + 14) & attrs) != attrs)
406: continue;
407: if (attrs & MEMF_LARGEST) {
408: unsigned long maxsize = 0;
409: CPTR chunk;
410: for (chunk = get_long(memheader + 16); chunk != 0; chunk = get_long(chunk))
411: if (get_long(chunk+4) > maxsize)
412: maxsize = get_long(chunk + 4);
413: result += maxsize;
414: } else if (attrs & MEMF_TOTAL) {
415: result += get_long(memheader + 24) - get_long(memheader + 20);
416: } else result += get_long(memheader + 28);
417: }
418: return result;
419: }
420:
421: void EXEC_AddMemList(unsigned long size, ULONG attrs, int pri, CPTR base,
422: CPTR name)
423: {
1.1.1.2 ! root 424: if (size == 0xFFFFFFFF) {
! 425: fprintf(stderr, "Weird AddMemList call\n");
! 426: return;
! 427: }
! 428:
1.1 root 429: put_byte(base + 8, 0);
430: put_byte(base + 9, pri);
431: put_long(base + 10, name);
432: put_word(base + 14, attrs);
433: put_long(base + 16, base + 32);
434: put_long(base + 20, base + 32);
435: put_long(base + 36, size - 32);
436: put_long(base + 28, size - 32);
437: put_long(base + 24, base + size);
1.1.1.2 ! root 438: EXEC_Enqueue(EXEC_sysbase + 322, base);
1.1 root 439: }
440:
441: static ULONG execl_AddMemList(void)
442: {
1.1.1.2 ! root 443: EXEC_AddMemList(m68k_dreg(regs, 0), m68k_dreg(regs, 1), (LONG)m68k_dreg(regs, 2), m68k_areg(regs, 0), m68k_areg(regs, 1));
1.1 root 444: return 0;
445: }
446:
447: static ULONG execl_CopyMem(void)
448: {
1.1.1.2 ! root 449: UBYTE *src = (UBYTE *)raddr(m68k_areg(regs, 0));
! 450: UBYTE *dst = (UBYTE *)raddr(m68k_areg(regs, 1));
1.1 root 451:
452: if (src != NULL && dst != NULL
1.1.1.2 ! root 453: && valid_address(m68k_areg(regs, 0), m68k_dreg(regs, 0))
! 454: && valid_address(m68k_areg(regs, 1), m68k_dreg(regs, 0)))
! 455: memcpy(dst, src, m68k_dreg(regs, 0));
! 456: else {
! 457: /* Ho hum. This happens when copying expansion card data. We
! 458: * better do something sensible in this case */
! 459: unsigned long int i;
! 460: for(i = 0; i < m68k_dreg(regs, 0); i++)
! 461: put_byte(m68k_areg(regs, 1) + i, get_byte(m68k_areg(regs, 0) + i));
! 462: }
1.1 root 463: return 0;
464: }
465:
1.1.1.2 ! root 466: static ULONG execl_AllocMem(void) { return EXEC_AllocMem(m68k_dreg(regs, 0), m68k_dreg(regs, 1)); }
! 467: static ULONG execl_AllocEntry(void) { return EXEC_AllocEntry(m68k_areg(regs, 0)); }
! 468: static ULONG execl_Allocate(void) { return EXEC_Allocate(m68k_areg(regs, 0), m68k_dreg(regs, 0)); }
! 469: static ULONG execl_FreeMem(void) { EXEC_FreeMem(m68k_areg(regs, 1), m68k_dreg(regs, 0)); return 0; }
! 470: static ULONG execl_AvailMem(void) { return EXEC_AvailMem(m68k_dreg(regs, 1)); }
! 471: static ULONG execl_Deallocate(void) { EXEC_Deallocate(m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_dreg(regs, 0)); return 0; }
1.1 root 472:
473: /*
474: * Scheduling
475: */
476:
477: #define TS_RUN 2
478: #define TS_READY 3
479: #define TS_WAIT 4
480: #define TS_EXCEPT 5
1.1.1.2 ! root 481: #define TS_REMOVED 6
1.1 root 482:
483: struct NewTask {
484: struct NewTask *next, *prev;
485: CPTR exectask;
1.1.1.2 ! root 486: struct switch_struct sws;
1.1 root 487: void *stack;
488: struct regstruct regs;
489: struct flag_struct flags;
490: };
491:
492: static struct NewTask idle_task;
1.1.1.2 ! root 493: static int intr_count, need_resched, quantum_elapsed;
! 494: static struct NewTask *task_to_kill;
1.1 root 495:
496: static struct NewTask *find_newtask(CPTR task)
497: {
498: /* Ugh, this is ugly */
499: struct NewTask *t = &idle_task;
500: do {
501: if (t->exectask == task)
502: return t;
503: t = t->next;
504: } while (t != &idle_task);
505: fprintf(stderr, "Uh oh. Task list corrupt\n");
1.1.1.2 ! root 506: return 0;
1.1 root 507: }
508:
1.1.1.2 ! root 509: void EXEC_QuantumElapsed(void)
! 510: {
! 511: need_resched = 1;
! 512: quantum_elapsed = 1;
! 513: }
! 514:
! 515: static int trace_schedules = 0;
! 516:
1.1 root 517: static void schedule(void)
518: {
1.1.1.2 ! root 519: CPTR readylist = EXEC_sysbase + 406;
1.1 root 520: CPTR readytask = get_long(readylist);
1.1.1.2 ! root 521: CPTR runtask = get_long(EXEC_sysbase + 276);
1.1 root 522: struct NewTask *runtask_nt, *readytask_nt;
523: unsigned long oldflags;
1.1.1.2 ! root 524: UBYTE oldstate;
1.1 root 525: int idis;
526:
1.1.1.2 ! root 527: TIMER_block();
! 528:
1.1 root 529: need_resched = 0;
530: /* Any ready tasks? */
531: if (get_long(readytask) == 0)
1.1.1.2 ! root 532: goto dont_schedule;
1.1 root 533:
1.1.1.2 ! root 534: /* If the running task is going to sleep, don't check priorities */
! 535: oldstate = get_byte(runtask + 15);
! 536: if (oldstate != TS_WAIT && oldstate != TS_REMOVED) {
1.1 root 537: /* Has the running task a higher priority than any ready tasks? */
538: if ((BYTE)get_byte(runtask + 9) > (BYTE)get_byte(readytask + 9))
1.1.1.2 ! root 539: goto dont_schedule;
! 540: if ((BYTE)get_byte(runtask + 9) == (BYTE)get_byte(readytask + 9)
! 541: && !quantum_elapsed)
! 542: goto dont_schedule;
! 543: quantum_elapsed = 0;
! 544: }
! 545: if (oldstate == TS_RUN)
! 546: put_byte(runtask + 15, oldstate = TS_READY);
! 547: if (oldstate == TS_WAIT)
! 548: EXEC_Enqueue(EXEC_sysbase + 420, runtask);
! 549: else
! 550: /* Removed tasks end up here also, so we can safely Remove() them
! 551: * always. */
1.1 root 552: EXEC_Enqueue(readylist, runtask);
553: put_byte(readytask + 15, TS_RUN);
554: EXEC_Remove(readytask);
555:
556: readytask_nt = find_newtask(readytask);
557: runtask_nt = find_newtask(runtask);
558:
559: oldflags = regs.spcflags;
560: runtask_nt->regs = regs;
561: runtask_nt->flags = regflags;
562: regs = readytask_nt->regs;
563: regflags = readytask_nt->flags;
564: regs.spcflags = (regs.spcflags & ~PRESERVED_FLAGS) | (oldflags & PRESERVED_FLAGS);
1.1.1.2 ! root 565: regs.isp = runtask_nt->regs.isp;
! 566: regs.msp = runtask_nt->regs.msp;
! 567: put_byte(runtask + 16, get_byte(EXEC_sysbase + 294));
! 568: put_byte(runtask + 17, get_byte(EXEC_sysbase + 295));
! 569: put_byte(EXEC_sysbase + 294, idis = get_byte(readytask + 16));
! 570: put_byte(EXEC_sysbase + 295, get_byte(readytask + 17));
! 571: put_long(EXEC_sysbase + 276, readytask);
1.1 root 572: /* Set INTENA according to new interrupt enable status */
573: if (idis == 0xFF)
574: put_word(0xDFF09A, 0xC000);
575: else
576: put_word(0xDFF09A, 0x4000);
1.1.1.2 ! root 577:
! 578: if (trace_schedules)
! 579: fprintf(stderr, "Task switch: new task %s\n", raddr(get_long(readytask + 10)));
! 580:
! 581: EXEC_SWITCH_TASKS(runtask_nt, readytask_nt);
! 582:
1.1 root 583: regs.spcflags &= ~SPCFLAG_BRK;
1.1.1.2 ! root 584:
! 585: dont_schedule:
! 586:
! 587: TIMER_unblock();
! 588:
! 589: /* Now we know we are running in a live task, so we can safely remove
! 590: * a corpse if necessary */
! 591: if (task_to_kill != NULL) {
! 592: struct NewTask *nt = task_to_kill;
! 593: task_to_kill = NULL;
! 594: EXEC_Remove(nt->exectask);
! 595: EXEC_FreeMem(nt->exectask, 92);
! 596: free(nt->stack);
! 597: nt->prev->next = nt->next;
! 598: nt->next->prev = nt->prev;
! 599: free(nt);
! 600: }
1.1 root 601: }
602:
603: static __inline__ void maybe_schedule(void)
604: {
605: /* @@@ Should we avoid a schedule when supervisor bit is set?
606: * Definitely not if the running task is the idle task */
1.1.1.2 ! root 607: if (intr_count == 0 && get_byte(EXEC_sysbase + 294) == 0xFF && get_byte(EXEC_sysbase + 295) == 0xFF && need_resched)
1.1 root 608: schedule();
609: }
610:
611: /*
612: * Signals
613: */
614:
615: int EXEC_AllocSignal(int signum)
616: {
1.1.1.2 ! root 617: CPTR thistask = get_long(EXEC_sysbase + 276);
1.1 root 618: ULONG sigalloc = get_long(thistask + 18);
619: if (signum == -1)
620: for (signum = 0; signum < 32; signum++)
621: if ((sigalloc & (1 << signum)) == 0)
622: break;
623:
624: if ((sigalloc & (1 << signum)) == 0) {
625: put_long(thistask + 18, sigalloc | (1 << signum));
626: } else
627: signum = -1;
628:
629: return signum;
630: }
631:
632: void EXEC_FreeSignal(int signum)
633: {
1.1.1.2 ! root 634: CPTR thistask = get_long(EXEC_sysbase + 276);
1.1 root 635: if (signum != -1)
636: return;
637: put_long(thistask + 18, get_long(thistask + 18) & ~(1 << signum));
638: }
639:
640: ULONG EXEC_SetSignal(ULONG newsig, ULONG exec_sigmask)
641: {
1.1.1.2 ! root 642: CPTR task = get_long(EXEC_sysbase + 276);
1.1 root 643: ULONG signals = get_long(task + 26);
644: /* @@@ check SigExcept here */
645: put_long(task + 26, (signals & ~exec_sigmask) | (newsig & exec_sigmask));
646: return signals;
647: }
648:
649: void EXEC_Signal(CPTR task, ULONG exec_sigmask)
650: {
651: ULONG exec_sigs = get_long(task + 26);
652: ULONG sigwait = get_long(task + 22);
1.1.1.2 ! root 653:
! 654: if (task == 0) {
! 655: /* fprintf(stderr, "Signalling NULL task. Bad\n");*/
! 656: return;
! 657: }
1.1 root 658: put_long(task + 26, exec_sigs | exec_sigmask);
659: if (get_byte(task + 15) == TS_WAIT && (sigwait & exec_sigmask) != 0) {
660: EXEC_Remove(task);
1.1.1.2 ! root 661: put_byte(task + 15, TS_READY);
! 662: EXEC_Enqueue(EXEC_sysbase + 406, task);
1.1 root 663: need_resched = 1;
664: maybe_schedule();
665: }
666: }
667:
668: ULONG EXEC_Wait(ULONG exec_sigmask)
669: {
1.1.1.2 ! root 670: CPTR task = get_long(EXEC_sysbase + 276);
1.1 root 671: ULONG exec_sigs = get_long(task + 26);
672: if ((exec_sigs & exec_sigmask) != 0) {
673: put_long(task + 26, exec_sigs & ~exec_sigmask);
674: return exec_sigs & exec_sigmask;
675: }
1.1.1.2 ! root 676: if (get_byte(EXEC_sysbase + 294) != 0xFF || get_byte(EXEC_sysbase + 295) != 0xFF)
1.1 root 677: {
678: fprintf(stderr, "Arrgh, task Wait()ing when it shouldn't\n");
679: }
680: if (intr_count || regs.s) {
681: fprintf(stderr, "Arrgh, task Wait()ing when it _really_ shouldn't\n");
682: }
683:
684: put_byte(task + 15, TS_WAIT);
685: put_long(task + 22, exec_sigmask);
686: schedule();
687: exec_sigs = get_long(task + 26);
688: if ((exec_sigs & exec_sigmask) != 0) {
689: put_long(task + 26, exec_sigs & ~exec_sigmask);
690: return exec_sigs & exec_sigmask;
691: }
692: fprintf(stderr, "Bug: task woke up without signals\n");
693: return 0;
694: }
695:
1.1.1.2 ! root 696: static ULONG execl_SetSignal(void) { return EXEC_SetSignal(m68k_dreg(regs, 0), m68k_dreg(regs, 1)); }
! 697: static ULONG execl_Signal(void) { EXEC_Signal(m68k_areg(regs, 1), m68k_dreg(regs, 0)); return 0; }
! 698: static ULONG execl_Wait(void) { return EXEC_Wait(m68k_dreg(regs, 0)); }
! 699: static ULONG execl_AllocSignal(void) { return EXEC_AllocSignal((BYTE)m68k_dreg(regs, 0)); }
! 700: static ULONG execl_FreeSignal(void) { EXEC_FreeSignal((BYTE)m68k_dreg(regs, 0)); return 0; }
1.1 root 701:
702: /*
703: * Semaphores
704: */
705:
706: void EXEC_InitSemaphore(CPTR exec_sigsem)
707: {
708: EXEC_NewList(exec_sigsem + 16);
709: put_word(exec_sigsem + 14, 0);
710: put_word(exec_sigsem + 44, 0xFFFF);
711: }
712:
713: ULONG EXEC_AttemptSemaphore(CPTR exec_sigsem)
714: {
1.1.1.2 ! root 715: CPTR task = get_long(EXEC_sysbase + 276);
1.1 root 716: UWORD count = get_word(exec_sigsem + 44);
717: if (count == 0xFFFF) {
718: /* Semaphore free -> lock it */
719: put_word(exec_sigsem + 44, 0);
720: put_long(exec_sigsem + 40, task);
721: put_word(exec_sigsem + 14, 1);
722: return 1;
723: }
724: if (get_long(exec_sigsem + 40) == task) {
725: /* Locked by same task -> Increment NestCount */
726: put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
727: return 1;
728: }
729: return 0;
730: }
731:
732: void EXEC_ObtainSemaphore(CPTR exec_sigsem)
733: {
1.1.1.2 ! root 734: CPTR task = get_long(EXEC_sysbase + 276);
1.1 root 735: UWORD count = get_word(exec_sigsem + 44);
1.1.1.2 ! root 736: CPTR n;
! 737:
1.1 root 738: if (count == 0xFFFF) {
739: /* Semaphore free -> lock it */
740: put_word(exec_sigsem + 44, 0);
741: put_long(exec_sigsem + 40, task);
742: put_word(exec_sigsem + 14, 1);
743: return;
744: }
745: if (get_long(exec_sigsem + 40) == task) {
746: /* Locked by same task -> Increment NestCount */
747: put_word(exec_sigsem + 14, get_word(exec_sigsem + 14) + 1);
748: return;
749: }
750: /* Need to wait. */
751: /* @@@ None of the predefined signals in exec/tasks.h seem to be used
752: * for this. We use 0x8000, which appears not to be used otherwise */
753: put_word(exec_sigsem + 44, count + 1);
1.1.1.2 ! root 754: n = EXEC_AllocMem(12, 0); /* Ugh... is there a cleaner way? */
! 755: put_long(n + 8, task);
! 756: EXEC_AddTail(exec_sigsem + 16, n);
1.1 root 757: if (EXEC_Wait(0x8000) != 0x8000)
758: fprintf(stderr, "BUG\n");
1.1.1.2 ! root 759: EXEC_FreeMem(n, 12);
1.1 root 760: /* Now it's mine, all mine! */
761: put_long(exec_sigsem + 40, task);
762: put_word(exec_sigsem + 14, 1);
763: }
764:
765: void EXEC_ReleaseSemaphore(CPTR exec_sigsem)
766: {
767: UWORD nest = get_word(exec_sigsem + 14);
768: put_word(exec_sigsem + 14, nest - 1);
769: if (nest == 1) {
770: /* We're losing it. Signal the first task on the wait queue
771: * (that one will in turn wake the next, etc.) */
1.1.1.2 ! root 772: CPTR task = get_long(EXEC_RemHead(exec_sigsem + 16) + 8);
1.1 root 773: UWORD count = get_word(exec_sigsem + 44);
774: put_word(exec_sigsem + 44, count - 1);
775: if (task) {
776: EXEC_Signal(task, 0x8000);
777: }
778: }
779: }
780:
1.1.1.2 ! root 781: /* Assumption: Semaphores on the list are only handled through these two
! 782: * functions. I don't see how it could work reliably otherwise. But I don't
! 783: * see either why these functions ought to be used: You might as well have
! 784: * one semaphore instead of a list of them.
! 785: * For safety, these functions try hard to function even in cases where they
! 786: * might otherwise deadlock or break.
! 787: * @@@ what should happen if the task already owns semaphores on the list?
! 788: */
! 789:
! 790: void EXEC_ObtainSemaphoreList(CPTR l)
! 791: {
! 792: CPTR task = get_long(EXEC_sysbase + 276);
! 793: CPTR n;
! 794:
! 795: int retry;
! 796: EXEC_Forbid();
! 797: do {
! 798: retry = 0;
! 799: /* See if any semaphores on the list are locked. If so, go to
! 800: * sleep */
! 801: n = get_long(l);
! 802: while(get_long(n) != 0) {
! 803: if (get_word(n + 44) != 0xFFFF && get_long(n + 40) != task) {
! 804: /* Semaphore is locked. Obtain it the normal way */
! 805: EXEC_Permit();
! 806: EXEC_ObtainSemaphore(n);
! 807: EXEC_ReleaseSemaphore(n);
! 808: EXEC_Forbid();
! 809: retry = 1;
! 810: break;
! 811: }
! 812: n = get_long(n);
! 813: }
! 814: } while (retry);
! 815: /* All semaphores on the list are unlocked. */
! 816: for (n = get_long(l); get_long(n) != 0; n = get_long(n)) {
! 817: put_word(n + 44, get_word(n + 44) + 1);
! 818: put_long(n + 40, task);
! 819: put_word(n + 14, get_word(n + 14) + 1);
! 820: }
! 821: EXEC_Permit();
! 822: }
! 823:
! 824: void EXEC_ReleaseSemaphoreList(CPTR l)
! 825: {
! 826: CPTR n;
! 827:
! 828: EXEC_Forbid();
! 829: for (n = get_long(l); get_long(n) != 0; n = get_long(n)) {
! 830: EXEC_ReleaseSemaphore(n);
! 831: }
! 832: EXEC_Permit();
! 833: }
! 834:
! 835: static ULONG execl_ObtainSemaphore(void) { EXEC_ObtainSemaphore(m68k_areg(regs, 0)); return 0; }
! 836: static ULONG execl_ReleaseSemaphore(void) { EXEC_ReleaseSemaphore(m68k_areg(regs, 0)); return 0; }
! 837: static ULONG execl_ObtainSemaphoreList(void) { EXEC_ObtainSemaphoreList(m68k_areg(regs, 0)); return 0; }
! 838: static ULONG execl_ReleaseSemaphoreList(void) { EXEC_ReleaseSemaphoreList(m68k_areg(regs, 0)); return 0; }
! 839: static ULONG execl_FindSemaphore(void) { return EXEC_FindName(EXEC_sysbase + 532, raddr(m68k_areg(regs, 1))); }
! 840: static ULONG execl_InitSemaphore(void) { EXEC_InitSemaphore(m68k_areg(regs, 0)); return 0; }
! 841: static ULONG execl_AttemptSemaphore(void) { return EXEC_AttemptSemaphore(m68k_areg(regs, 0)); }
! 842: static ULONG execl_AddSemaphore(void) { put_byte(m68k_areg(regs, 1) + 8, NT_SIGNALSEM); EXEC_Enqueue(EXEC_sysbase + 532, m68k_areg(regs, 1)); return 0; }
1.1 root 843:
844: /*
845: * Messages and ports
846: */
847:
848: CPTR EXEC_GetMsg(CPTR port)
849: {
850: return EXEC_RemHead(port + 20);
851: }
852:
853: /* This is shared between PutMsg and ReplyMsg */
854: static void EXEC_doputmsg(CPTR port, CPTR msg)
855: {
856: UBYTE flags = get_byte (port + 14);
857: EXEC_AddTail(port + 20, msg);
858: if (flags == 0)
859: EXEC_Signal(get_long(port + 16), 1 << get_byte(port + 15));
860: else if (flags == 1)
861: fprintf(stderr, "PA_SOFTINT unsupported\n");
862:
863: }
864:
865: void EXEC_PutMsg(CPTR port, CPTR msg)
866: {
1.1.1.2 ! root 867: put_byte(msg + 8, NT_MESSAGE);
1.1 root 868: EXEC_doputmsg(port, msg);
869: }
870:
871: void EXEC_ReplyMsg(CPTR msg)
1.1.1.2 ! root 872: {
! 873: CPTR p = get_long(msg + 14);
! 874: if (p == 0) {
! 875: put_byte(msg + 8, NT_FREEMSG);
! 876: } else {
! 877: put_byte(msg + 8, NT_REPLYMSG);
! 878: EXEC_doputmsg(p, msg);
! 879: }
1.1 root 880: }
881:
882: CPTR EXEC_WaitPort(CPTR port)
883: {
884: for (;;) {
885: CPTR msg = get_long(port + 20);
886: if (get_long(msg) != 0)
887: return msg;
888: if (get_byte(port + 14) != 0)
889: fprintf(stderr, "Don't know how to WaitPort()\n");
890: EXEC_Wait(1 << get_byte(port + 15));
891: }
892: }
893:
1.1.1.2 ! root 894: void EXEC_AddPort(CPTR port)
! 895: {
! 896: put_byte(port + 8, NT_MSGPORT);
! 897: EXEC_Enqueue(EXEC_sysbase + 392, port);
! 898: EXEC_NewList(port + 20);
! 899: /* should we put the task into the appropriate place? */
! 900: }
! 901:
! 902: void EXEC_RemPort(CPTR port)
! 903: {
! 904: EXEC_Remove(port);
! 905: }
! 906:
! 907: static ULONG execl_GetMsg(void) { return EXEC_GetMsg(m68k_areg(regs, 0)); }
! 908: static ULONG execl_PutMsg(void) { EXEC_PutMsg(m68k_areg(regs, 0), m68k_areg(regs, 1)); return 0; }
! 909: static ULONG execl_ReplyMsg(void) { EXEC_ReplyMsg(m68k_areg(regs, 1)); return 0; }
! 910: static ULONG execl_WaitPort(void) { return EXEC_WaitPort(m68k_areg(regs, 0)); }
! 911: static ULONG execl_FindPort(void) { return EXEC_FindName(EXEC_sysbase + 392, raddr(m68k_areg(regs, 1))); }
! 912: static ULONG execl_AddPort(void) { EXEC_AddPort(m68k_areg(regs, 1)); return 0; }
! 913: static ULONG execl_RemPort(void) { EXEC_RemPort(m68k_areg(regs, 1)); return 0; }
1.1 root 914:
915: /*
916: * I/O
917: */
918:
919: LONG EXEC_WaitIO(CPTR ioreq)
920: {
921: /* The device is supposed to clear the IO_QUICK bit if it's going to
922: * reply to the command */
923: if ((get_byte(ioreq + 30) & 1) == 1)
924: return (LONG)(BYTE)get_byte(ioreq + 31);
925:
926: for (;;) {
1.1.1.2 ! root 927: if (get_byte(ioreq + 8) == NT_REPLYMSG)
1.1 root 928: break;
929: /* We'll just hope that this a) has a ReplyPort and b) that port
930: * is of type PA_SIGNAL
931: * Don't WaitPort() here: WaitPort() returns a message, and we
932: * aren't sure it's for us. */
933:
934: EXEC_Wait(1 << get_byte(get_long(ioreq + 14) + 15));
935: }
936: EXEC_Remove(ioreq);
937: return (LONG)(BYTE)get_byte(ioreq + 31);
938: }
939:
940: static void EXEC_BeginIO(CPTR ioreq)
941: {
942: CPTR dev = get_long(ioreq + 20);
1.1.1.2 ! root 943: m68k_areg(regs, 6) = dev;
! 944: m68k_areg(regs, 1) = ioreq;
1.1 root 945: Call68k(dev - 30, 1);
1.1.1.2 ! root 946: m68k_areg(regs, 6) = EXEC_sysbase;
1.1 root 947: }
948:
1.1.1.2 ! root 949: LONG EXEC_DoIO(CPTR ioreq)
1.1 root 950: {
951: put_byte(ioreq + 30, 1);
952: EXEC_BeginIO(ioreq);
1.1.1.2 ! root 953: return EXEC_WaitIO(ioreq);
1.1 root 954: }
1.1.1.2 ! root 955:
1.1 root 956: void EXEC_SendIO(CPTR ioreq)
957: {
958: put_byte(ioreq + 30, 0);
959: EXEC_BeginIO(ioreq);
960: }
961:
962: CPTR EXEC_CheckIO(CPTR ioreq)
963: {
964: if ((get_byte(ioreq + 30) & 1) == 1)
965: return ioreq;
1.1.1.2 ! root 966: if (get_byte(ioreq + 8) == NT_REPLYMSG)
1.1 root 967: return ioreq;
968: return 0;
969: }
970:
1.1.1.2 ! root 971: void EXEC_AbortIO(CPTR ioRequest)
! 972: {
! 973: CPTR dev = get_long(ioRequest + 20);
! 974: m68k_areg(regs, 6) = dev;
! 975: m68k_areg(regs, 1) = ioRequest;
! 976: /* The example code returns a value here. What should we do with it? */
! 977: Call68k(dev - 36, 1);
! 978: m68k_areg(regs, 6) = EXEC_sysbase;
! 979: }
! 980:
! 981: static ULONG execl_WaitIO(void) { return EXEC_WaitIO(m68k_areg(regs, 1)); }
! 982: static ULONG execl_DoIO(void) { return EXEC_DoIO(m68k_areg(regs, 1)); }
! 983: static ULONG execl_SendIO(void) { EXEC_SendIO(m68k_areg(regs, 1)); return 0; }
! 984: static ULONG execl_CheckIO(void) { return EXEC_CheckIO(m68k_areg(regs, 1)); }
! 985: static ULONG execl_AbortIO(void) { EXEC_AbortIO(m68k_areg(regs, 1)); return 0; }
1.1 root 986:
987: /*
988: * Libraries
989: */
990:
991: void EXEC_SumLibrary(CPTR lib)
992: {
993: CPTR start = lib - get_word(lib + 16);
994: int len = get_word(lib + 16) + get_word(lib + 18);
995: ULONG sum = 0;
996: UWORD flags = get_word(lib + 14);
997:
998: if (flags & 1) /* SUMMING? */
999: return;
1000: if (!(flags & 4)) /* SUMUSED? */
1001: return;
1002: put_word(lib + 14, flags & ~2); /* mark as not changed */
1003: /* Pretend the checksum is OK, I don't care enough */
1004: }
1005:
1006: CPTR EXEC_SetFunction(CPTR lib, int funcOffset, CPTR function)
1007: {
1008: CPTR oldfunc = get_long(lib + funcOffset + 2);
1009: put_word(lib + funcOffset, 0x4EF9);
1010: put_long(lib + funcOffset + 2, function);
1011: put_word(lib + 14, get_word(lib + 14) | 2);
1012: EXEC_SumLibrary(lib);
1013: return oldfunc;
1014: }
1015:
1016: void EXEC_AddLibrary(CPTR lib)
1017: {
1.1.1.2 ! root 1018: EXEC_Enqueue(EXEC_sysbase + 378, lib);
1.1 root 1019: put_word(lib + 14, 2); /* mark as changed */
1020: EXEC_SumLibrary(lib);
1021: }
1022:
1023: CPTR EXEC_OpenLibrary(char *name, int version)
1024: {
1.1.1.2 ! root 1025: CPTR lib = EXEC_FindName(EXEC_sysbase + 378, name);
! 1026:
! 1027: if (lib != 0 && get_word(lib + 20) < version)
! 1028: return 0;
! 1029:
1.1 root 1030: if (lib != 0) {
1.1.1.2 ! root 1031: CPTR lib2;
! 1032: m68k_areg(regs, 6) = lib;
! 1033: m68k_dreg(regs, 0) = version;
! 1034: lib2 = Call68k(lib - 6, 1);
! 1035: if (lib2 == 0)
! 1036: lib = 0;
! 1037: else if (lib2 != lib)
! 1038: fprintf(stderr, "OpenLibrary: weirdness\n");
! 1039: m68k_areg(regs, 6) = EXEC_sysbase;
1.1 root 1040: }
1041: return lib;
1042: }
1043:
1044: CPTR EXEC_OpenDevice(char *name, ULONG unit, CPTR ioRequest, ULONG flags)
1045: {
1.1.1.2 ! root 1046: CPTR dev = EXEC_FindName(EXEC_sysbase + 350, name);
1.1 root 1047: CPTR replyport = get_long(ioRequest + 14);
1048: put_long(ioRequest + 20, dev);
1049: put_byte(ioRequest + 31, 0);
1050: put_byte(ioRequest + 30, flags); /* is this right? */
1051: if (replyport == 0)
1052: fprintf(stderr, "ioRequest has no ReplyPort\n");
1053: else {
1054: CPTR rtask = get_long(replyport + 16);
1.1.1.2 ! root 1055: if (rtask == 0) {
1.1 root 1056: fprintf(stderr, "replyTask == 0\n");
1.1.1.2 ! root 1057: put_long(replyport + 16, get_long(EXEC_sysbase + 276));
! 1058: }
! 1059: else if (rtask != get_long(EXEC_sysbase + 276))
1.1 root 1060: fprintf(stderr, "replyTask != current\n");
1.1.1.2 ! root 1061: /* put_long(replyport + 16, get_long(EXEC_sysbase + 276));*/
1.1 root 1062: }
1063: if (dev != 0) {
1.1.1.2 ! root 1064: m68k_areg(regs, 6) = dev;
! 1065: m68k_areg(regs, 1) = ioRequest;
! 1066: m68k_dreg(regs, 0) = unit;
! 1067: m68k_dreg(regs, 1) = flags;
! 1068: EXEC_Forbid();
1.1 root 1069: dev = Call68k(dev - 6, 1);
1.1.1.2 ! root 1070: EXEC_Permit();
! 1071: m68k_areg(regs, 6) = EXEC_sysbase;
1.1 root 1072: }
1073: return (LONG)(BYTE)get_byte(ioRequest + 31);
1074: }
1075:
1.1.1.2 ! root 1076: /*
! 1077: * There seems to be some magic involved here. These functions are documented
! 1078: * as returning void. However, if we leave D0 unmodified by giving
! 1079: * TRAPFLAG_NORETVAL, there are bogus FreeMem calls; these go away if we
! 1080: * return 0 in D0 as the old code did. I guess these are really supposed to
! 1081: * return the value that was given to them by the library's Close routine
! 1082: * (for the DOS CloseDevice()/CloseLibrary() calls, probably)
! 1083: */
! 1084:
! 1085: ULONG EXEC_CloseDevice(CPTR ioRequest)
! 1086: {
! 1087: CPTR dev = get_long(ioRequest + 20);
! 1088: ULONG retval;
! 1089:
! 1090: m68k_areg(regs, 6) = dev;
! 1091: m68k_areg(regs, 1) = ioRequest;
! 1092: EXEC_Forbid();
! 1093: retval = Call68k(dev - 12, 1);
! 1094: EXEC_Permit();
! 1095: return retval;
! 1096: }
! 1097:
! 1098: ULONG EXEC_CloseLibrary(CPTR lib)
! 1099: {
! 1100: ULONG retval;
! 1101:
! 1102: m68k_areg(regs, 6) = lib;
! 1103: EXEC_Forbid();
! 1104: retval = Call68k(lib - 12, 1);
! 1105: EXEC_Permit();
! 1106: return retval;
! 1107: }
! 1108:
1.1 root 1109: void EXEC_AddDevice(CPTR lib)
1110: {
1.1.1.2 ! root 1111: EXEC_Enqueue(EXEC_sysbase + 350, lib);
1.1 root 1112: }
1113:
1114: void EXEC_AddResource(CPTR lib)
1115: {
1.1.1.2 ! root 1116: EXEC_Enqueue(EXEC_sysbase + 336, lib);
1.1 root 1117: }
1118:
1119: CPTR EXEC_OpenResource(char *name)
1120: {
1.1.1.2 ! root 1121: CPTR lib = EXEC_FindName(EXEC_sysbase + 336, name);
1.1 root 1122: return lib;
1123: }
1124:
1125: void EXEC_MakeFunctions(CPTR target, CPTR funcarray, CPTR funcdispb)
1126: {
1127: if (funcdispb != 0) {
1128: WORD tmp;
1129: for (;;) {
1130: tmp = get_word(funcarray); funcarray += 2;
1131: if (tmp == -1)
1132: break;
1133: target -= 6;
1134: put_word(target, 0x4EF9); /* JMP.L */
1135: put_long(target + 2, funcdispb + tmp);
1136: }
1137: } else {
1138: CPTR tmp;
1139: for (;;) {
1140: tmp = get_long(funcarray); funcarray += 4;
1141: if (tmp == (CPTR)-1)
1142: break;
1143: target -= 6;
1144: put_word(target, 0x4EF9); /* JMP.L */
1145: put_long(target + 2, tmp);
1146: }
1147: }
1148: }
1149:
1150: CPTR EXEC_MakeLibrary(CPTR vectors, CPTR structure, CPTR init,
1151: unsigned long dsize, ULONG seglist_b)
1152: {
1153: CPTR seglist = seglist_b << 2;
1154: int vec_cnt = 0;
1155: unsigned long negsize;
1156: CPTR base, fdispb = 0, funcarray = vectors;
1157: ULONG retval = 0;
1158:
1159: if (get_word (vectors) == (UWORD)-1) {
1160: int offs = 2;
1161: fdispb = vectors;
1162: funcarray += 2;
1163: while (get_word (vectors+offs) != (UWORD)-1) {
1164: offs += 2;
1165: vec_cnt++;
1166: }
1167: } else {
1168: int offs = 0;
1.1.1.2 ! root 1169: while (get_long (vectors+offs) != (ULONG)-1) {
1.1 root 1170: offs += 4;
1171: vec_cnt++;
1172: }
1173: }
1174: negsize = (vec_cnt * 6 + 3) & ~3;
1175: dsize = (dsize + 3) & ~3;
1176:
1177: base = EXEC_AllocMem(negsize + dsize, MEMF_PUBLIC|MEMF_CLEAR);
1178: if (base == 0) /* Uh oh */
1179: return 0;
1180: EXEC_MakeFunctions(base + negsize, funcarray, fdispb);
1181: base += negsize;
1182: put_word(base + 16, negsize);
1183: put_word(base + 18, dsize);
1184: if (structure != 0) {
1185: /* Size is set to 0 so we won't clear it again */
1186: EXEC_InitStruct(structure, base, 0);
1187: }
1188: if (init != 0) {
1.1.1.2 ! root 1189: m68k_areg(regs, 6) = EXEC_sysbase;
! 1190: m68k_areg(regs, 0) = seglist; /* BCPL seglist here? */
! 1191: m68k_dreg(regs, 0) = base;
1.1 root 1192: /* call it */
1193: retval = Call68k(init, 0);
1194: } else
1195: retval = base;
1196:
1.1.1.2 ! root 1197: fprintf(stderr, "MakeLibrary: %s\n", raddr(get_long(base+10)));
1.1 root 1198: return retval;
1199: }
1200:
1201: CPTR EXEC_InitResident(CPTR resident, ULONG segList)
1202: {
1203: UBYTE flags = get_byte(resident + 10);
1.1.1.2 ! root 1204:
1.1 root 1205: if (flags & 0x80) {
1206: CPTR autoinit = get_long(resident + 22);
1.1.1.2 ! root 1207: CPTR lib;
! 1208: lib = EXEC_MakeLibrary(get_long(autoinit + 4), get_long(autoinit + 8),
! 1209: get_long(autoinit + 12), get_long(autoinit),
! 1210: segList >> 2);
! 1211:
! 1212: /* Is this right? Some libraries never get added if we don't do
! 1213: * this. */
! 1214: if (get_byte(resident + 12) == NT_LIBRARY)
! 1215: EXEC_AddLibrary(lib);
! 1216: else if (get_byte(resident + 12) == NT_DEVICE)
! 1217: EXEC_AddDevice(lib);
! 1218: else if (get_byte(resident + 12) == NT_RESOURCE)
! 1219: EXEC_AddResource(lib);
! 1220: return lib;
! 1221:
1.1 root 1222: }
1.1.1.2 ! root 1223:
! 1224: m68k_dreg(regs, 0) = 0;
! 1225: m68k_areg(regs, 0) = segList;
! 1226: m68k_areg(regs, 6) = EXEC_sysbase;
1.1 root 1227: return Call68k(get_long(resident + 22), 0);
1228: }
1229:
1.1.1.2 ! root 1230: CPTR EXEC_FindResident(char *name)
! 1231: {
! 1232: CPTR rmods = get_long(EXEC_sysbase + 300);
! 1233: CPTR tmp2;
! 1234:
! 1235: if (name == NULL)
! 1236: return 0;
! 1237:
! 1238: for (; (tmp2 = get_long(rmods)) != 0; rmods += 4) {
! 1239: char *name2 = raddr(get_long(tmp2 + 14));
! 1240: if (strcmp(name, name2) == 0)
! 1241: return tmp2;
! 1242: }
! 1243: return 0;
! 1244: }
! 1245:
! 1246: static ULONG execl_MakeFunctions(void) { EXEC_MakeFunctions(m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_areg(regs, 2)); return 0; }
! 1247: static ULONG execl_SumLibrary(void) { EXEC_SumLibrary(m68k_areg(regs, 1)); return 0; }
! 1248: static ULONG execl_SetFunction(void) { return EXEC_SetFunction(m68k_areg(regs, 1), (WORD)m68k_areg(regs, 0), m68k_dreg(regs, 0)); }
! 1249: static ULONG execl_AddLibrary(void) { EXEC_AddLibrary(m68k_areg(regs, 1)); return 0; }
! 1250: static ULONG execl_AddDevice(void) { EXEC_AddDevice(m68k_areg(regs, 1)); return 0; }
! 1251: static ULONG execl_AddResource(void) { EXEC_AddResource(m68k_areg(regs, 1)); return 0; }
! 1252: static ULONG execl_OpenLibrary(void) { return EXEC_OpenLibrary(raddr(m68k_areg(regs, 1)), m68k_dreg(regs, 0)); }
! 1253: static ULONG execl_OldOpenLibrary(void) { return EXEC_OpenLibrary(raddr(m68k_areg(regs, 1)), 0); }
! 1254: static ULONG execl_CloseLibrary(void) { return EXEC_CloseLibrary(m68k_areg(regs, 1)); }
! 1255: static ULONG execl_OpenDevice(void) { return EXEC_OpenDevice(raddr(m68k_areg(regs, 0)), m68k_dreg(regs, 0), m68k_areg(regs, 1), m68k_dreg(regs, 1)); }
! 1256: static ULONG execl_CloseDevice(void) { return EXEC_CloseDevice(m68k_areg(regs, 1)); }
! 1257: static ULONG execl_OpenResource(void) { return EXEC_OpenResource(raddr(m68k_areg(regs, 1))); }
! 1258: static ULONG execl_MakeLibrary(void) { return EXEC_MakeLibrary(m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_dreg(regs, 0), m68k_dreg(regs, 1)); }
! 1259: static ULONG execl_FindResident(void) { return EXEC_FindResident(raddr(m68k_areg(regs, 1))); }
! 1260: static ULONG execl_InitResident(void) { return EXEC_InitResident(m68k_areg(regs, 1), m68k_dreg(regs, 1)); }
1.1 root 1261:
1262: /*
1263: * Tasks
1264: */
1265:
1266: static void task_startup(void)
1267: {
1268: m68k_setpc(regs.pc);
1.1.1.2 ! root 1269: Call68k_retaddr(regs.pc, 0, get_long(m68k_areg(regs, 7) - 4));
1.1 root 1270: fprintf(stderr, "Task fell through at the end\n");
1271: }
1272:
1.1.1.2 ! root 1273: void EXEC_RemTask(CPTR task)
! 1274: {
! 1275: if (task == 0)
! 1276: task = get_long(EXEC_sysbase + 276);
! 1277: /* We can't easily delete it here while we use it's stack. Let schedule()
! 1278: * do it. */
! 1279: put_byte(task + 15, TS_REMOVED);
! 1280: task_to_kill = find_newtask(task);
! 1281: schedule();
! 1282: }
! 1283:
1.1 root 1284: CPTR EXEC_AddTask(CPTR task, CPTR initPC, CPTR finalPC)
1285: {
1286: struct NewTask *nt = (struct NewTask *)malloc(sizeof (struct NewTask));
1.1.1.2 ! root 1287:
1.1 root 1288: nt->exectask = task;
1289: nt->prev = &idle_task;
1290: nt->next = idle_task.next;
1291: idle_task.next->prev = nt;
1292: idle_task.next = nt;
1293: memset(&nt->regs, 0, sizeof (nt->regs));
1294: nt->regs.pc = initPC;
1.1.1.2 ! root 1295: m68k_areg(nt->regs, 7) = get_long(task + 54);
1.1 root 1296:
1297: if (finalPC == 0)
1298: finalPC = 0xF0FFF0; /* standard "return from 68k mode" calltrap */
1299: put_byte(task + 16, 0xFF);
1300: put_byte(task + 17, 0xFF);
1.1.1.2 ! root 1301: put_long(m68k_areg(nt->regs, 7) - 4, finalPC);
1.1 root 1302: nt->stack = malloc(65536); /* @@@ make this smaller after checking that
1303: * no parts of the emulator need much stack
1.1.1.2 ! root 1304: * space */
! 1305: EXEC_SETUP_SWS(nt);
! 1306:
1.1 root 1307: put_byte(task + 15, TS_READY);
1308: put_long(task + 18,0x0000FFFF); /* all tasks have the lower 16 signals allocated */
1.1.1.2 ! root 1309: EXEC_Enqueue(EXEC_sysbase + 406, task);
1.1 root 1310: need_resched = 1;
1.1.1.2 ! root 1311: fprintf(stderr, "AddTask: %s\n", raddr(get_long(task + 10)));
1.1 root 1312: maybe_schedule();
1313: return task;
1.1.1.2 ! root 1314: }
! 1315:
! 1316: int EXEC_SetTaskPri(CPTR task, int pri)
! 1317: {
! 1318: int oldpri = get_byte(task + 9);
! 1319:
! 1320: if (task == get_long(EXEC_sysbase + 276)) {
! 1321: put_byte(task + 9, pri);
! 1322: return oldpri;
! 1323: }
! 1324: if (get_byte(task + 15) == TS_WAIT) {
! 1325: EXEC_Remove(task);
! 1326: put_byte(task + 9, pri);
! 1327: EXEC_Enqueue(EXEC_sysbase + 420, task);
! 1328: return oldpri;
! 1329: }
! 1330: EXEC_Remove(task);
! 1331: put_byte(task + 9, pri);
! 1332: EXEC_Enqueue(EXEC_sysbase + 406, task);
! 1333: schedule();
! 1334: return oldpri;
1.1 root 1335: }
1336:
1337: CPTR EXEC_FindTask(char *name)
1338: {
1339: char *n;
1340: CPTR v;
1341:
1.1.1.2 ! root 1342: if (name == NULL || ((n = raddr(get_long(get_long(EXEC_sysbase + 276) + 10))) != NULL
1.1 root 1343: && strcmp(n, name) == 0))
1.1.1.2 ! root 1344: return get_long(EXEC_sysbase + 276);
1.1 root 1345:
1.1.1.2 ! root 1346: v = EXEC_FindName(EXEC_sysbase + 406, name); /* ready tasks */
1.1 root 1347: if (v != 0)
1348: return v;
1.1.1.2 ! root 1349: return EXEC_FindName(EXEC_sysbase + 420, name); /* waiting tasks */
1.1 root 1350: }
1351:
1.1.1.2 ! root 1352: static ULONG execl_FindTask(void) { return EXEC_FindTask(raddr(m68k_areg(regs, 1))); }
! 1353: static ULONG execl_AddTask(void) { return EXEC_AddTask(m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 3)); }
! 1354: static ULONG execl_RemTask(void) { EXEC_RemTask(m68k_areg(regs, 1)); return 0; }
! 1355: static ULONG execl_SetTaskPri(void) { return EXEC_SetTaskPri(m68k_areg(regs, 1), (BYTE)m68k_dreg(regs, 0)); }
1.1 root 1356:
1357: ULONG EXEC_Forbid(void)
1358: {
1.1.1.2 ! root 1359: int count = (BYTE)get_byte(EXEC_sysbase + 295);
1.1 root 1360: count++;
1.1.1.2 ! root 1361: put_byte(EXEC_sysbase + 295, count);
1.1 root 1362: return 0;
1363: }
1364: ULONG EXEC_Permit(void)
1365: {
1.1.1.2 ! root 1366: int count = (BYTE)get_byte(EXEC_sysbase + 295);
1.1 root 1367: if (count == -1)
1368: fprintf(stderr, "Too many Permit() calls\n");
1369: else
1370: count--;
1.1.1.2 ! root 1371: put_byte(EXEC_sysbase + 295, count);
1.1 root 1372: maybe_schedule();
1373: return 0;
1374: }
1375:
1376: ULONG EXEC_Disable(void)
1377: {
1.1.1.2 ! root 1378: int count = (BYTE)get_byte(EXEC_sysbase + 294);
1.1 root 1379: count++;
1.1.1.2 ! root 1380: put_byte(EXEC_sysbase + 294, count);
1.1 root 1381: put_word(0xDFF09A, 0x4000);
1382: return 0;
1383: }
1384:
1385: ULONG EXEC_Enable(void)
1386: {
1.1.1.2 ! root 1387: int count = (BYTE)get_byte(EXEC_sysbase + 294);
1.1 root 1388: if (count == -1)
1389: fprintf(stderr, "Too many Enable() calls\n");
1390: else
1391: count--;
1392: if (count == -1)
1393: put_word(0xDFF09A, 0xC000);
1.1.1.2 ! root 1394: put_byte(EXEC_sysbase + 294, count);
1.1 root 1395: maybe_schedule();
1396: return 0;
1397: }
1.1.1.2 ! root 1398:
! 1399: /*
! 1400: * Annoyances...
! 1401: */
! 1402:
! 1403: enum rdf_state { rdf_flags, rdf_width, rdf_limit, rdf_type };
! 1404:
! 1405: CPTR EXEC_RawDoFormat(UBYTE *fstr, CPTR data, CPTR pcp, ULONG pcd)
! 1406: {
! 1407: if (fstr == NULL)
! 1408: return data;
! 1409: for (;;) {
! 1410: UBYTE c = *fstr++;
! 1411:
! 1412: if (c == 0)
! 1413: break;
! 1414:
! 1415: if (c == '%') {
! 1416: enum rdf_state rdfs = rdf_flags;
! 1417: int ljust = 0, fill0 = 0, islong = 0;
! 1418: int w = 0, lim = 0, havelim = 0;
! 1419:
! 1420: for (;;) {
! 1421: c = *fstr++;
! 1422:
! 1423: if (c == 0)
! 1424: break;
! 1425:
! 1426: if (rdfs == rdf_flags) {
! 1427: rdfs = rdf_width;
! 1428: if (c == '-') {
! 1429: ljust = 1;
! 1430: continue;
! 1431: }
! 1432: }
! 1433: if (rdfs == rdf_width && c == '.') {
! 1434: rdfs = rdf_limit;
! 1435: continue;
! 1436: } else if (rdfs == rdf_width && isdigit(c)) {
! 1437: w = w*10 + c - '0';
! 1438: if (w == 0)
! 1439: fill0 = 1;
! 1440: continue;
! 1441: } else if (rdfs == rdf_limit && isdigit(c)) {
! 1442: lim = lim*10 + c - '0';
! 1443: havelim = 1;
! 1444: continue;
! 1445: } else if ((rdfs == rdf_limit || rdfs == rdf_width) && c == 'l') {
! 1446: islong = 1;
! 1447: rdfs = rdf_type;
! 1448: continue;
! 1449: }
! 1450: switch (c) {
! 1451: CPTR tmp;
! 1452: ULONG tmp1;
! 1453: unsigned int tmpl;
! 1454: char tmps1[20], tmps2[20], *tmpsp;
! 1455:
! 1456: case 'b':
! 1457: tmp = get_long(data);
! 1458: data += 4;
! 1459: tmpl = get_byte(tmp++);
! 1460: for(; tmpl > 0; tmpl--) {
! 1461: m68k_dreg(regs, 0) = get_byte(tmp++);
! 1462: m68k_areg(regs, 3) = pcd;
! 1463: Call68k(pcp, 0);
! 1464: }
! 1465: break;
! 1466:
! 1467: case 'd':
! 1468: case 'u':
! 1469: case 'x':
! 1470: if (islong) {
! 1471: tmp1 = get_long(data); data += 4;
! 1472: } else {
! 1473: tmp1 = get_word(data); data += 2;
! 1474: if (c == 'd')
! 1475: tmp1 = (LONG)(WORD)tmp1;
! 1476: }
! 1477: tmpsp = tmps1;
! 1478: *tmpsp++ = '%';
! 1479: if (fill0)
! 1480: *tmpsp++ = '0';
! 1481: if (w != 0)
! 1482: sprintf(tmpsp, "%d", w);
! 1483: tmpsp += strlen(tmpsp);
! 1484: *tmpsp++ = c;
! 1485: *tmpsp++ = 0;
! 1486: sprintf(tmps2, tmps1, tmp1);
! 1487: for (tmpsp = tmps2; ;) {
! 1488: m68k_dreg(regs, 0) = *tmpsp++;
! 1489: if (m68k_dreg(regs, 0) == 0)
! 1490: break;
! 1491: m68k_areg(regs, 3) = pcd;
! 1492: Call68k(pcp, 0);
! 1493: }
! 1494: break;
! 1495:
! 1496: case 's':
! 1497: tmp = get_long(data);
! 1498: data += 4;
! 1499: for(;!havelim || lim-- > 0;) {
! 1500: m68k_dreg(regs, 0) = get_byte(tmp++);
! 1501: if (m68k_dreg(regs, 0) == 0)
! 1502: break;
! 1503: m68k_areg(regs, 3) = pcd;
! 1504: Call68k(pcp, 0);
! 1505: }
! 1506: break;
! 1507:
! 1508: case 'c':
! 1509: if (islong) {
! 1510: m68k_dreg(regs, 0) = get_long(data); data += 4;
! 1511: } else {
! 1512: m68k_dreg(regs, 0) = get_word(data); data += 2;
! 1513: }
! 1514: m68k_areg(regs, 3) = pcd;
! 1515: Call68k(pcp, 0);
! 1516: }
! 1517: break;
! 1518: }
! 1519:
! 1520: } else {
! 1521: m68k_dreg(regs, 0) = c;
! 1522: m68k_areg(regs, 3) = pcd;
! 1523: Call68k(pcp, 0);
! 1524: }
! 1525: }
! 1526: return data;
! 1527: }
! 1528:
! 1529: static ULONG execl_RawDoFormat(void)
! 1530: {
! 1531: return EXEC_RawDoFormat((UBYTE *)raddr(m68k_areg(regs, 0)), m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 3));
! 1532: }
! 1533:
1.1 root 1534: /*
1535: * Initialization
1536: */
1537: static ULONG execlib_init(void)
1538: {
1.1.1.2 ! root 1539: EXEC_sysbase = get_long(4);
! 1540: #if 1
1.1 root 1541: /* CopyMem and CopyMemQuick */
1.1.1.2 ! root 1542: libemu_InstallFunctionFlags(execl_CopyMem, EXEC_sysbase, -630, 0, "CopyMem");
! 1543: libemu_InstallFunctionFlags(execl_CopyMem, EXEC_sysbase, -624, 0, "CopyMem");
! 1544: libemu_InstallFunctionFlags(execl_Allocate, EXEC_sysbase, -186, 0, "Allocate");
! 1545: libemu_InstallFunctionFlags(execl_AllocMem, EXEC_sysbase, -198, 0, "AllocMem");
! 1546: libemu_InstallFunctionFlags(execl_Deallocate, EXEC_sysbase, -192, 0, "Deallocate");
! 1547: libemu_InstallFunctionFlags(execl_FreeMem, EXEC_sysbase, -210, 0, "FreeMem");
! 1548: libemu_InstallFunctionFlags(execl_AvailMem, EXEC_sysbase, -216, 0, "AvailMem");
1.1 root 1549:
1550: /* List management */
1.1.1.2 ! root 1551: libemu_InstallFunctionFlags(execl_Insert, EXEC_sysbase, -234, TRAPFLAG_NORETVAL, "Insert");
! 1552: libemu_InstallFunctionFlags(execl_AddHead, EXEC_sysbase, -240, TRAPFLAG_NORETVAL, "AddHead");
! 1553: libemu_InstallFunctionFlags(execl_AddTail, EXEC_sysbase, -246, TRAPFLAG_NORETVAL, "AddTail");
! 1554: libemu_InstallFunctionFlags(execl_Enqueue, EXEC_sysbase, -270, TRAPFLAG_NORETVAL, "Enqueue");
! 1555: libemu_InstallFunctionFlags(execl_RemHead, EXEC_sysbase, -258, 0, "RemHead");
! 1556: libemu_InstallFunctionFlags(execl_RemTail, EXEC_sysbase, -264, 0, "RemTail");
! 1557: libemu_InstallFunctionFlags(execl_Remove, EXEC_sysbase, -252, TRAPFLAG_NORETVAL, "Remove");
! 1558: libemu_InstallFunctionFlags(execl_FindName, EXEC_sysbase, -276, 0, "FindName");
1.1 root 1559:
1560: /* Signals */
1.1.1.2 ! root 1561: libemu_InstallFunctionFlags(execl_AllocSignal, EXEC_sysbase, -330, 0, "AllocSignal");
! 1562: libemu_InstallFunctionFlags(execl_FreeSignal, EXEC_sysbase, -336, 0, "FreeSignal");
1.1 root 1563:
1564: /* Semaphores */
1.1.1.2 ! root 1565: libemu_InstallFunctionFlags(execl_FindSemaphore, EXEC_sysbase, -594, 0, "FindSemaphore");
! 1566: libemu_InstallFunctionFlags(execl_InitSemaphore, EXEC_sysbase, -558, 0, "InitSemaphore");
! 1567: libemu_InstallFunctionFlags(execl_AddSemaphore, EXEC_sysbase, -600, TRAPFLAG_NORETVAL, "AddSemaphore");
1.1 root 1568:
1569: /* Messages/Ports */
1.1.1.2 ! root 1570: libemu_InstallFunctionFlags(execl_FindPort, EXEC_sysbase, -390, 0, "FindPort");
! 1571: libemu_InstallFunctionFlags(execl_GetMsg, EXEC_sysbase, -372, 0, "GetMsg");
1.1 root 1572:
1573: /* Libraries */
1.1.1.2 ! root 1574: libemu_InstallFunctionFlags(execl_MakeFunctions, EXEC_sysbase, -90, 0, "MakeFunctions");
! 1575: libemu_InstallFunctionFlags(execl_SumLibrary, EXEC_sysbase, -426, TRAPFLAG_NORETVAL, "SumLibrary");
! 1576: libemu_InstallFunctionFlags(execl_SetFunction, EXEC_sysbase, -420, 0, "SetFunction");
1.1 root 1577:
1578: /* Tasks */
1.1.1.2 ! root 1579: libemu_InstallFunctionFlags(execl_FindTask, EXEC_sysbase, -294, 0, "FindTask");
1.1 root 1580:
1581: /* Interrupts */
1.1.1.2 ! root 1582: libemu_InstallFunctionFlags(execl_SetIntVector, EXEC_sysbase, -162, 0, "SetIntVector");
! 1583: libemu_InstallFunctionFlags(execl_AddIntServer, EXEC_sysbase, -168, TRAPFLAG_NORETVAL, "AddIntServer");
! 1584: libemu_InstallFunctionFlags(execl_RemIntServer, EXEC_sysbase, -174, 0, "RemIntServer");
1.1 root 1585:
1586: /* Miscellaneous */
1.1.1.2 ! root 1587: libemu_InstallFunctionFlags(execl_InitStruct, EXEC_sysbase, -78, 0, "InitStruct");
! 1588: libemu_InstallFunctionFlags(execl_GetCC, EXEC_sysbase, -528, TRAPFLAG_NORETVAL|TRAPFLAG_NOREGSAVE, "InitStruct");
! 1589: #elif 0
! 1590: libemu_InstallFunctionFlags(NULL, EXEC_sysbase, -564, TRAPFLAG_NORETVAL, "ObtainSemaphore");
! 1591: libemu_InstallFunctionFlags(NULL, EXEC_sysbase, -570, TRAPFLAG_NORETVAL, "ReleaseSemaphore");
! 1592: libemu_InstallFunctionFlags(NULL, EXEC_sysbase, -576, 0, "AttemptSemaphore");
! 1593: libemu_InstallFunctionFlags(NULL, EXEC_sysbase, -582, TRAPFLAG_NORETVAL, "ObtainSemaphoreList");
! 1594: libemu_InstallFunctionFlags(NULL, EXEC_sysbase, -588, TRAPFLAG_NORETVAL, "ReleaseSemaphoreList");
! 1595: #endif
1.1 root 1596: return 0;
1597: }
1598:
1.1.1.2 ! root 1599: static ULONG execl_Open(void) { return EXEC_sysbase; }
! 1600:
1.1 root 1601: static ULONG execlib_init2(void)
1602: {
1.1.1.2 ! root 1603: EXEC_sysbase = get_long(4);
1.1 root 1604:
1.1.1.2 ! root 1605: libemu_InstallFunctionFlags(execl_Open, EXEC_sysbase, -6, 0, "Open");
! 1606: libemu_InstallFunctionFlags(execl_AllocEntry, EXEC_sysbase, -222, 0, "AllocEntry");
! 1607: libemu_InstallFunctionFlags(execl_AddMemList, EXEC_sysbase, -618, 0, "AddMemList");
! 1608:
! 1609: libemu_InstallFunctionFlags(execl_AddLibrary, EXEC_sysbase, -396, TRAPFLAG_NORETVAL, "AddLibrary");
! 1610: libemu_InstallFunctionFlags(execl_AddDevice, EXEC_sysbase, -432, TRAPFLAG_NORETVAL, "AddDevice");
! 1611: libemu_InstallFunctionFlags(execl_AddResource, EXEC_sysbase, -486, TRAPFLAG_NORETVAL, "AddResource");
! 1612: libemu_InstallFunctionFlags(execl_OpenLibrary, EXEC_sysbase, -552, 0, "OpenLibrary");
! 1613: libemu_InstallFunctionFlags(execl_OldOpenLibrary, EXEC_sysbase, -408, 0, "OldOpenLibrary");
! 1614: libemu_InstallFunctionFlags(execl_OpenDevice, EXEC_sysbase, -444, 0, "OpenDevice");
! 1615: libemu_InstallFunctionFlags(execl_CloseDevice, EXEC_sysbase, -450, 0, "CloseDevice");
! 1616: libemu_InstallFunctionFlags(execl_OpenResource, EXEC_sysbase, -498, 0, "OpenResource");
! 1617: libemu_InstallFunctionFlags(execl_MakeLibrary, EXEC_sysbase, -84, 0, "MakeLibrary");
! 1618: libemu_InstallFunctionFlags(execl_CloseLibrary, EXEC_sysbase, -414, 0, "CloseLibrary");
! 1619:
! 1620: libemu_InstallFunctionFlags(execl_RawDoFormat, EXEC_sysbase, -522, 0, "RawDoFmt");
! 1621: libemu_InstallFunctionFlags(execl_InitResident, EXEC_sysbase, -102, 0, "InitResident");
! 1622:
! 1623: libemu_InstallFunctionFlags(EXEC_Disable, EXEC_sysbase, -120, TRAPFLAG_NORETVAL, "");
! 1624: libemu_InstallFunctionFlags(EXEC_Enable, EXEC_sysbase, -126, TRAPFLAG_NORETVAL, "");
! 1625: libemu_InstallFunctionFlags(EXEC_Permit, EXEC_sysbase, -138, TRAPFLAG_NORETVAL, "Permit");
! 1626: libemu_InstallFunctionFlags(EXEC_Forbid, EXEC_sysbase, -132, TRAPFLAG_NORETVAL, "Forbid");
! 1627:
! 1628: libemu_InstallFunctionFlags(execl_AddTask, EXEC_sysbase, -282, 0, "AddTask");
! 1629: libemu_InstallFunctionFlags(execl_RemTask, EXEC_sysbase, -288, TRAPFLAG_NORETVAL, "RemTask");
! 1630: libemu_InstallFunctionFlags(execl_SetTaskPri, EXEC_sysbase, -300, 0, "SetTaskPri");
! 1631:
! 1632: libemu_InstallFunctionFlags(execl_SetSignal, EXEC_sysbase, -306, 0, "SetSignal");
! 1633: libemu_InstallFunctionFlags(execl_Signal, EXEC_sysbase, -324, TRAPFLAG_NORETVAL, "Signal");
! 1634: libemu_InstallFunctionFlags(execl_Wait, EXEC_sysbase, -318, 0, "Wait");
! 1635:
! 1636: libemu_InstallFunctionFlags(execl_PutMsg, EXEC_sysbase, -366, 0, "PutMsg");
! 1637: libemu_InstallFunctionFlags(execl_ReplyMsg, EXEC_sysbase, -378, 0, "ReplyMsg");
! 1638: libemu_InstallFunctionFlags(execl_WaitPort, EXEC_sysbase, -384, 0, "WaitPort");
! 1639: libemu_InstallFunctionFlags(execl_AddPort, EXEC_sysbase, -354, TRAPFLAG_NORETVAL, "AddPort");
! 1640: libemu_InstallFunctionFlags(execl_RemPort, EXEC_sysbase, -360, TRAPFLAG_NORETVAL, "RemPort");
! 1641:
! 1642: libemu_InstallFunctionFlags(execl_WaitIO, EXEC_sysbase, -474, 0, "WaitIO");
! 1643: libemu_InstallFunctionFlags(execl_DoIO, EXEC_sysbase, -456, 0, "DoIO");
! 1644: libemu_InstallFunctionFlags(execl_SendIO, EXEC_sysbase, -462, TRAPFLAG_NORETVAL, "SendIO");
! 1645: libemu_InstallFunctionFlags(execl_CheckIO, EXEC_sysbase, -468, 0, "CheckIO");
! 1646: libemu_InstallFunctionFlags(execl_AbortIO, EXEC_sysbase, -468, 0, "AbortIO");
! 1647:
! 1648: libemu_InstallFunctionFlags(execl_ObtainSemaphore, EXEC_sysbase, -564, TRAPFLAG_NORETVAL, "ObtainSemaphore");
! 1649: libemu_InstallFunctionFlags(execl_ReleaseSemaphore, EXEC_sysbase, -570, TRAPFLAG_NORETVAL, "ReleaseSemaphore");
! 1650: libemu_InstallFunctionFlags(execl_AttemptSemaphore, EXEC_sysbase, -576, 0, "AttemptSemaphore");
! 1651: libemu_InstallFunctionFlags(execl_ObtainSemaphoreList, EXEC_sysbase, -582, TRAPFLAG_NORETVAL, "ObtainSemaphoreList");
! 1652: libemu_InstallFunctionFlags(execl_ReleaseSemaphoreList, EXEC_sysbase, -588, TRAPFLAG_NORETVAL, "ReleaseSemaphoreList");
1.1 root 1653:
1.1.1.2 ! root 1654: libemu_InstallFunctionFlags(execl_FindResident, EXEC_sysbase, -96, 0, "FindResident");
1.1 root 1655: return 0;
1656: }
1657:
1658: /*
1659: * These functions are one day going to bootstrap the emulated Exec
1660: */
1661:
1662: #define NR_EXEC_FUNCTIONS 105 /* V34 (1.3) maximum */
1663:
1664: static ULONG EXEC_ENOSYS(void)
1665: {
1666: fprintf(stderr, "Not a system call\n");
1667: return 0;
1668: }
1669:
1670: static ULONG EXEC_StandardIntVec(void)
1671: {
1.1.1.2 ! root 1672: int num = m68k_areg(regs, 1);
1.1 root 1673: /* Call the IntHandlers */
1674: return 0;
1675: }
1676:
1.1.1.2 ! root 1677: static int trace_ints = 0;
! 1678:
1.1 root 1679: static ULONG EXEC_IntTrap(void)
1680: {
1.1.1.2 ! root 1681: struct regstruct rtmp = regs;
! 1682: struct flag_struct ftmp = regflags;
! 1683:
1.1 root 1684: UWORD intsreq = get_word(0xDFF01E) & get_word(0xDFF01C);
1.1.1.2 ! root 1685: int i, do_timer = 0;
1.1 root 1686: intr_count++;
1.1.1.2 ! root 1687:
! 1688: if ((intena & 0x4000) == 0)
! 1689: fprintf(stderr, "Interrupt came in with interrupts off (%x, %x)!\n", get_byte(EXEC_sysbase + 294), get_byte(EXEC_sysbase + 295));
! 1690:
! 1691: TIMER_block();
! 1692:
! 1693: if (regs.spcflags & SPCFLAG_TIMER) {
! 1694: regs.spcflags &= ~SPCFLAG_TIMER;
! 1695: do_timer = 1;
! 1696: }
! 1697:
! 1698: TIMER_unblock();
! 1699:
! 1700: if (do_timer)
! 1701: TIMER_Interrupt();
1.1 root 1702:
1703: for (i = 13; i >= 0; i--) {
1704: if ((intsreq & (1 << i)) != 0) {
1.1.1.2 ! root 1705: if (trace_ints)
! 1706: fprintf(stderr, "INT: %d\n", i);
! 1707: /* Is this a server chain? */
1.1 root 1708: if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15) {
1.1.1.2 ! root 1709: CPTR slist = get_long(EXEC_sysbase + 84 + 12*i);
1.1 root 1710: CPTR snode = get_long(slist);
1711: for (;;) {
1712: if (get_long(snode) == 0)
1713: break;
1.1.1.2 ! root 1714: m68k_areg(regs, 0) = 0xDFF000;
! 1715: m68k_areg(regs, 5) = get_long(snode + 18);
! 1716: m68k_areg(regs, 1) = get_long(snode + 14);
! 1717: Call68k(m68k_areg(regs, 5), 0);
1.1 root 1718: if (ZFLG == 0)
1719: break;
1720: snode = get_long(snode);
1721: }
1722: put_word(0xDFF09C, 1 << i);
1723: } else {
1.1.1.2 ! root 1724: CPTR intnode = get_long(EXEC_sysbase + 84 + 12*i + 8);
! 1725: /* Blitter interrupts happen before vector is set up :-/ */
! 1726: if (intnode != 0) {
! 1727: m68k_dreg(regs, 1) = intsreq;
! 1728: m68k_areg(regs, 1) = get_long(intnode + 14);
! 1729: m68k_areg(regs, 0) = 0xDFF000;
! 1730: m68k_areg(regs, 5) = get_long(intnode + 18);
! 1731: m68k_areg(regs, 6) = EXEC_sysbase;
! 1732: Call68k(m68k_areg(regs, 5), 0);
! 1733: }
1.1 root 1734: }
1735: break;
1736: }
1737: }
1738: if (i < 0)
1739: fprintf(stderr, "So what interrupt am I supposed to serve?\n");
1740: intr_count--;
1.1.1.2 ! root 1741:
! 1742: /* This usually is a great indicator that the ExecBase pointer at
! 1743: * address 4 has been messed with... */
! 1744: if ((intena & 0x4000) == 0)
! 1745: fprintf(stderr, "Interrupt left interrupts off (%x, %x)!\n", get_byte(EXEC_sysbase + 294), get_byte(EXEC_sysbase + 295));
! 1746: regflags = ftmp;
! 1747: regs = rtmp;
! 1748: /* Perform a RTE */
! 1749: {
! 1750: CPTR sra = m68k_areg(regs, 7);
! 1751: regs.sr = get_word(sra);
! 1752: m68k_setpc_rte(get_long(sra+2));
! 1753: m68k_areg(regs, 7) = sra + 6;
! 1754: MakeFromSR();
! 1755: }
! 1756:
1.1 root 1757: maybe_schedule();
1.1.1.2 ! root 1758: return 0; /* ignored */
1.1 root 1759: }
1760:
1761: void execlib_sysinit(void)
1762: {
1763: CPTR tmp, tmp2;
1764: CPTR enosys = deftrap(EXEC_ENOSYS);
1765: CPTR intvec = deftrap(EXEC_StandardIntVec);
1.1.1.2 ! root 1766: CPTR inttrap = deftrap2(EXEC_IntTrap, TRAPFLAG_NORETVAL|TRAPFLAG_NOREGSAVE, "");
1.1 root 1767: CPTR sysstack;
1768: int i;
1769:
1770: tmp = here();
1771: calltrap2(enosys); dw(RTS);
1772:
1773: /* why 0x400? */
1.1.1.2 ! root 1774: EXEC_sysbase = 0x400 + NR_EXEC_FUNCTIONS*6;
! 1775: memset(raddr(EXEC_sysbase), 0, 558);
! 1776: put_long(4, EXEC_sysbase);
1.1 root 1777:
1778: /* Build vectors. We initialize SetFunction so we can call execlib_Init() */
1779: tmp2 = here();
1780: calltrap(deftrap(execl_SetFunction));
1781: dw(RTS);
1782: for (i = 0; i < NR_EXEC_FUNCTIONS; i++) {
1.1.1.2 ! root 1783: put_word(EXEC_sysbase - 6*(i+1), 0x4EF9);
! 1784: put_long(EXEC_sysbase - 6*(i+1) + 2, i == 69 ? tmp2 : tmp);
1.1 root 1785: }
1786:
1787: /* Build syslists */
1.1.1.2 ! root 1788: EXEC_NewList(EXEC_sysbase + 322); /* MemList */
! 1789: EXEC_NewList(EXEC_sysbase + 336); /* ResourceList */
! 1790: EXEC_NewList(EXEC_sysbase + 350); /* ResourceList */
! 1791: EXEC_NewList(EXEC_sysbase + 364); /* List */
! 1792: EXEC_NewList(EXEC_sysbase + 378); /* LibList */
! 1793: EXEC_NewList(EXEC_sysbase + 392); /* PortList */
! 1794: EXEC_NewList(EXEC_sysbase + 406); /* TaskReady */
! 1795: EXEC_NewList(EXEC_sysbase + 420); /* TaskWait */
! 1796: EXEC_NewList(EXEC_sysbase + 434); /* SoftInts[5] */
! 1797: EXEC_NewList(EXEC_sysbase + 450);
! 1798: EXEC_NewList(EXEC_sysbase + 466);
! 1799: EXEC_NewList(EXEC_sysbase + 482);
! 1800: EXEC_NewList(EXEC_sysbase + 498);
! 1801: EXEC_NewList(EXEC_sysbase + 532); /* SemaphoreList */
! 1802:
! 1803: put_long(EXEC_sysbase + 10, ds("exec.library"));
! 1804: put_word(EXEC_sysbase + 20, 34); put_word(EXEC_sysbase + 22, 0);
! 1805: put_byte(EXEC_sysbase + 8, NT_LIBRARY);
! 1806: put_byte(EXEC_sysbase + 9, 0);
! 1807:
! 1808: put_long(EXEC_sysbase + 42, 0);
! 1809: put_long(EXEC_sysbase + 46, 0);
! 1810: put_long(EXEC_sysbase + 50, 0);
! 1811: put_long(EXEC_sysbase + 62, chipmem_size);
! 1812: put_long(EXEC_sysbase + 514, 0xFFFFFFFF);
! 1813: put_long(EXEC_sysbase + 518, 0); /* seems to contain random values */
! 1814: put_long(EXEC_sysbase + 522, 0);
! 1815: put_long(EXEC_sysbase + 526, 0);
! 1816: put_word(EXEC_sysbase + 530, 0x3232);
! 1817: put_long(EXEC_sysbase + 546, 0);
! 1818: put_long(EXEC_sysbase + 550, 0);
! 1819: put_long(EXEC_sysbase + 554, 0);
! 1820: EXEC_Enqueue(EXEC_sysbase + 378, EXEC_sysbase);
! 1821:
! 1822: tmp = EXEC_sysbase + 558; /* sizeof struct V34 execbase */
1.1 root 1823: /* We put the supervisor stack at the end, the user stack for our new
1824: * task at the end - 0x800, and build the ResModules array at the bottom
1825: * of the stack */
1826: sysstack = chipmem_size - 0x2000;
1827:
1828: /* Don't mess with Fast or Bogo for now, just set up Chip */
1829: EXEC_AddMemList(sysstack - tmp, MEMF_CHIP|MEMF_PUBLIC, -10, tmp,
1830: ds("Chip Memory"));
1831:
1832: /* Set up the CPU */
1833: regs.usp = chipmem_size - 0x800;
1834: regs.isp = chipmem_size; /* What about MSP? */
1.1.1.2 ! root 1835: m68k_areg(regs, 7) = regs.usp;
1.1 root 1836: regs.s = 0; regs.m = 0;
1837: regs.vbr = 0;
1838: regs.t0 = regs.t1 = 0;
1839: regs.intmask = 0;
1840: put_word(0xDFF09A, 0x7FFF);
1841: put_word(0xDFF096, 0x7FFF);
1842: put_word(0xDFF09C, 0x7FFF);
1843: put_word(0xDFF09A, 0xC000);
1.1.1.2 ! root 1844: put_word(0xDFF096, 0x8200);
1.1 root 1845: /* Initialize our supported functions */
1846: execlib_init();
1847: execlib_init2();
1848:
1849: /* Initialize interrupts */
1850: intr_count = 0;
1.1.1.2 ! root 1851: put_byte(EXEC_sysbase + 294, 0xFF);
! 1852: put_byte(EXEC_sysbase + 295, 0xFF);
1.1 root 1853:
1854: tmp = here();
1855: calltrap2(inttrap);
1856: dw(RTE);
1857: for (i = 0; i < 8; i++)
1858: put_long((24+i)*4, tmp);
1859:
1860: tmp = here();
1861: calltrap2(intvec); dw(RTS);
1862: for (i = 0; i < 16; i++) {
1863: tmp2 = 0;
1864: /* Is this a server chain? */
1865: if (i == 3 || i == 4 || i == 5 || i == 13 || i == 15)
1866: EXEC_NewList(tmp2 = EXEC_AllocMem(14, MEMF_PUBLIC));
1.1.1.2 ! root 1867: put_long(EXEC_sysbase + 84 + i*12, tmp2);
! 1868: put_long(EXEC_sysbase + 84 + i*12 + 4, tmp);
! 1869: put_long(EXEC_sysbase + 84 + i*12 + 8, 0);
1.1 root 1870: }
1871: put_word(0xDFF09A, 0xAFC3); /* Enable everything but the server chains */
1.1.1.2 ! root 1872:
! 1873: task_to_kill = NULL;
1.1 root 1874: /* Set up the init task. We don't really set it up properly. */
1875: tmp = EXEC_AllocMem(92, MEMF_CLEAR);
1.1.1.2 ! root 1876: put_long(EXEC_sysbase + 276, tmp);
! 1877: put_byte(tmp + 8, NT_TASK);
1.1 root 1878: put_byte(tmp + 9, -127);
1879: put_long(tmp + 10, ds("init"));
1880: put_byte(tmp + 16, 0xFF);
1881: put_byte(tmp + 17, 0xFF);
1882: put_long(tmp + 54, chipmem_size - 0x804);
1883: put_long(tmp + 58, chipmem_size - 0x1800);
1884: put_long(tmp + 62, chipmem_size - 0x800);
1885: put_byte(tmp + 15, TS_RUN);
1886: put_long(tmp + 18,0x0000FFFF);
1887: EXEC_NewList(tmp + 74);
1888: idle_task.next = idle_task.prev = &idle_task;
1889: idle_task.exectask = tmp;
1890: idle_task.stack = NULL; /* we have a stack for this one already */
1891:
1892: /* Set up an idle task */
1893: tmp2 = here();
1.1.1.2 ! root 1894: dw (0xFF0D); dw (0x4eF9); dl (tmp2);
1.1 root 1895:
1896: tmp = EXEC_AllocMem(92, MEMF_CLEAR);
1.1.1.2 ! root 1897: put_byte(tmp + 8, NT_TASK);
1.1 root 1898: put_byte(tmp + 9, -128);
1899: put_long(tmp + 10, ds("idle"));
1.1.1.2 ! root 1900: put_byte(tmp + 16, 0xFF);
! 1901: put_byte(tmp + 17, 0xFF);
1.1 root 1902: put_long(tmp + 58, chipmem_size - 0x2000);
1903: put_long(tmp + 62, chipmem_size - 0x1800);
1904: put_long(tmp + 54, chipmem_size - 0x1804);
1905: EXEC_NewList(tmp + 74);
1906: EXEC_AddTask(tmp, tmp2, 0); /* This won't start executing yet */
1.1.1.2 ! root 1907: /* find_newtask(tmp)->regs.s = 1;*/
1.1 root 1908:
1909:
1910: /* Grep Kickstart for resident modules */
1.1.1.2 ! root 1911: m68k_areg(regs, 7) -= 4;
! 1912: put_long(m68k_areg(regs, 7), 0);
! 1913: tmp2 = m68k_areg(regs, 7);
1.1 root 1914: for (tmp = 0xF80000; tmp < 0xFFFFFF; tmp += 2) {
1915: if (get_word(tmp) == 0x4AFC && get_long(tmp + 2) == tmp) {
1.1.1.2 ! root 1916: m68k_areg(regs, 7) -= 4; put_long(m68k_areg(regs, 7), tmp);
1.1 root 1917: }
1918: }
1.1.1.2 ! root 1919: put_long(EXEC_sysbase + 300, m68k_areg(regs, 7));
1.1 root 1920: /* Bubble me do */
1.1.1.2 ! root 1921: for (tmp = m68k_areg(regs, 7); tmp < tmp2; tmp += 4) {
1.1 root 1922: CPTR tmp3;
1923: for (tmp3 = tmp2 - 4; tmp3 > tmp; tmp3 -= 4) {
1924: if ((BYTE)get_byte(get_long(tmp3) + 13) > (BYTE)get_byte(get_long(tmp3 - 4) + 13)) {
1925: CPTR tmp4 = get_long(tmp3);
1926: put_long(tmp3, get_long(tmp3 - 4));
1927: put_long(tmp3 - 4, tmp4);
1928: }
1929: }
1930: }
1931:
1.1.1.2 ! root 1932: need_resched = quantum_elapsed = 0;
! 1933:
1.1 root 1934: /* Initialize them and watch everything blow up. */
1.1.1.2 ! root 1935: for (tmp = m68k_areg(regs, 7); (tmp2 = get_long(tmp)) != 0; tmp += 4) {
1.1 root 1936: UBYTE flags = get_byte(tmp2 + 10);
1937: if (!(flags & 1)) /* RTF_COLDSTART? */
1938: continue;
1.1.1.2 ! root 1939: fprintf(stderr, "Initializing %s\n", raddr(get_long(tmp2 + 18)));
! 1940: /* if (strcmp("timer.device", raddr(get_long(tmp2 + 14))) == 0) {
! 1941: timerdev_init();
! 1942: continue;
! 1943: }*/
! 1944: m68k_areg(regs, 6) = EXEC_sysbase;
1.1 root 1945: EXEC_InitResident(tmp2, /* ? */ 0);
1.1.1.2 ! root 1946:
1.1 root 1947: }
1948: /* Idle task */
1949: for(;;) {
1950: Call68k(0xF0FFF0 - 4, 0);
1951: schedule();
1952: }
1953: }
1954:
1955: /*
1956: * Install the gfx-library-replacement
1957: */
1958: void execlib_install(void)
1959: {
1960: ULONG begin, end, resname, resid;
1961: int i;
1962:
1963: if (!use_gfxlib)
1964: return;
1965:
1966: resname = ds("UAEexeclib.resource");
1967: resid = ds("UAE execlib 0.1");
1968:
1969: begin = here();
1970: dw(0x4AFC); /* RTC_MATCHWORD */
1971: dl(begin); /* our start address */
1972: dl(0); /* Continue scan here */
1973: dw(0x0101); /* RTF_COLDSTART; Version 1 */
1974: dw(0x0805); /* NT_RESOURCE; pri 5 */
1975: dl(resname); /* name */
1976: dl(resid); /* ID */
1977: dl(here() + 4); /* Init area: directly after this */
1978:
1979: calltrap(deftrap(execlib_init)); dw(RTS);
1980:
1981: end = here();
1982: org(begin + 6);
1983: dl(end);
1984:
1985: org(end);
1986:
1987: intr_count = 1; /* So we don't try to schedule if we don't emulate
1988: * all of Exec */
1989: }
1.1.1.2 ! root 1990: #else
! 1991: ULONG EXEC_Forbid(void) { return 0; }
! 1992: ULONG EXEC_Permit(void) { return 0; }
! 1993: ULONG EXEC_Enable(void) { return 0; }
! 1994: ULONG EXEC_Disable(void) { return 0; }
! 1995: void execlib_install (void) { abort (); }
! 1996: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.