|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Memory management
5: *
6: * (c) 1995 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "config.h"
13: #include "options.h"
1.1.1.3 root 14: #include "uae.h"
1.1 root 15: #include "memory.h"
16: #include "ersatz.h"
17: #include "zfile.h"
1.1.1.9 root 18: #include "custom.h"
19: #include "events.h"
20: #include "newcpu.h"
1.1.1.11 root 21: #include "autoconf.h"
1.1.1.9 root 22: #include "savestate.h"
1.1.1.15! root 23: #include "crc32.h"
1.1 root 24:
1.1.1.2 root 25: #ifdef USE_MAPPED_MEMORY
1.1 root 26: #include <sys/mman.h>
27: #endif
28:
1.1.1.8 root 29: /* Set by each memory handler that does not simply access real memory. */
30: int special_mem;
31:
1.1 root 32: int ersatzkickfile = 0;
33:
1.1.1.4 root 34: uae_u32 allocated_chipmem;
35: uae_u32 allocated_fastmem;
36: uae_u32 allocated_bogomem;
37: uae_u32 allocated_gfxmem;
38: uae_u32 allocated_z3fastmem;
39: uae_u32 allocated_a3000mem;
40:
1.1.1.9 root 41: static long chip_filepos;
42: static long bogo_filepos;
43: static long rom_filepos;
44:
1.1.1.14 root 45: /* ROM management. */
46: struct romlist {
47: char *path;
48: struct romdata *rd;
49: };
50:
51: static struct romlist *rl;
52: static int romlist_cnt;
53:
54: void romlist_add (char *path, struct romdata *rd)
55: {
56: struct romlist *rl2;
57:
58: romlist_cnt++;
59: rl = realloc (rl, sizeof (struct romlist) * romlist_cnt);
60: rl2 = rl + romlist_cnt - 1;
61: rl2->path = my_strdup (path);
62: rl2->rd = rd;
63: }
64:
65: char *romlist_get (struct romdata *rd)
66: {
67: int i;
1.1.1.15! root 68:
1.1.1.14 root 69: if (!rd)
70: return 0;
71: for (i = 0; i < romlist_cnt; i++) {
72: if (rl[i].rd == rd)
73: return rl[i].path;
74: }
75: return 0;
76: }
77:
78: void romlist_clear (void)
79: {
80: free (rl);
81: rl = 0;
82: romlist_cnt = 0;
83: }
84:
85: static struct romdata roms[] = {
86: { "Cloanto Amiga Forever ROM key", 0, 0, 0x869ae1b1, 2069, 0, 0, 1, ROMTYPE_KEY },
87:
88: { "Kickstart v1.0 (A1000)(NTSC)", 0, 0, 0x299790ff, 262144, 1, 0, 0, ROMTYPE_KICK },
89: { "Kickstart v1.1 (A1000)(NTSC)", 31, 34, 0xd060572a, 262144, 2, 0, 0, ROMTYPE_KICK },
90: { "Kickstart v1.1 (A1000)(PAL)", 31, 34, 0xec86dae2, 262144, 3, 0, 0, ROMTYPE_KICK },
91: { "Kickstart v1.2 (A1000)", 33, 166, 0x9ed783d0, 262144, 4, 0, 0, ROMTYPE_KICK },
92: { "Kickstart v1.2 (A500,A1000,A2000)", 33, 180, 0xa6ce1636, 262144, 5, 0, 0, ROMTYPE_KICK },
93: { "Kickstart v1.3 (A500,A1000,A2000)", 34, 5, 0xc4f0f55f, 262144, 6, 60, 0, ROMTYPE_KICK },
94: { "Kickstart v1.3 (A3000)", 34, 5, 0xe0f37258, 262144, 32, 0, 0, ROMTYPE_KICK },
95:
96: { "Kickstart v2.04 (A500+)", 37, 175, 0xc3bdb240, 524288, 7, 0, 0, ROMTYPE_KICK },
97: { "Kickstart v2.05 (A600)", 37, 299, 0x83028fb5, 524288, 8, 0, 0, ROMTYPE_KICK },
98: { "Kickstart v2.05 (A600HD)", 37, 300, 0x64466c2a, 524288, 9, 0, 0, ROMTYPE_KICK },
99: { "Kickstart v2.05 (A600HD)", 37, 350, 0x43b0df7b, 524288, 10, 0, 0, ROMTYPE_KICK },
100:
101: { "Kickstart v3.0 (A1200)", 39, 106, 0x6c9b07d2, 524288, 11, 0, 0, ROMTYPE_KICK },
102: { "Kickstart v3.0 (A4000)", 39, 106, 0x9e6ac152, 524288, 12, 2, 0, ROMTYPE_KICK },
103: { "Kickstart v3.1 (A4000)", 40, 70, 0x2b4566f1, 524288, 13, 2, 0, ROMTYPE_KICK },
104: { "Kickstart v3.1 (A500,A600,A2000)", 40, 63, 0xfc24ae0d, 524288, 14, 0, 0, ROMTYPE_KICK },
105: { "Kickstart v3.1 (A1200)", 40, 68, 0x1483a091, 524288, 15, 1, 0, ROMTYPE_KICK },
106: { "Kickstart v3.1 (A4000)(Cloanto)", 40, 68, 0x43b6dd22, 524288, 31, 2, 1, ROMTYPE_KICK },
107: { "Kickstart v3.1 (A4000)", 40, 68, 0xd6bae334, 524288, 16, 2, 0, ROMTYPE_KICK },
108: { "Kickstart v3.1 (A4000T)", 40, 70, 0x75932c3a, 524288, 17, 2, 0, ROMTYPE_KICK },
109:
110: { "CD32 Kickstart v3.1", 40, 60, 0x1e62d4a5, 524288, 18, 1, 0, ROMTYPE_KICKCD32 },
111: { "CD32 Extended", 40, 60, 0x87746be2, 524288, 19, 1, 0, ROMTYPE_EXTCD32 },
112:
113: { "CDTV Extended v1.00", 0, 0, 0x42baa124, 262144, 20, 0, 0, ROMTYPE_EXTCDTV },
114: { "CDTV Extended v2.30", 0, 0, 0x30b54232, 262144, 21, 0, 0, ROMTYPE_EXTCDTV },
115: { "CDTV Extended v2.07", 0, 0, 0xceae68d2, 262144, 22, 0, 0, ROMTYPE_EXTCDTV },
116:
117: { "A1000 Bootstrap", 0, 0, 0x62f11c04, 8192, 23, 0, 0, ROMTYPE_KICK },
118: { "A1000 Bootstrap", 0, 0, 0x0b1ad2d0, 65536, 24, 0, 0, ROMTYPE_KICK },
119:
120: { "Action Replay Mk I v1.50", 0, 0, 0xd4ce0675, 65536, 25, 0, 0, ROMTYPE_AR },
121: { "Action Replay Mk II v2.05", 0, 0, 0x1287301f , 131072, 26, 0, 0, ROMTYPE_AR },
122: { "Action Replay Mk II v2.12", 0, 0, 0x804d0361 , 131072, 27, 0, 0, ROMTYPE_AR },
123: { "Action Replay Mk II v2.14", 0, 0, 0x49650e4f, 131072, 28, 0, 0, ROMTYPE_AR },
124: { "Action Replay Mk III v3.09", 0, 0, 0x0ed9b5aa, 262144, 29, 0, 0, ROMTYPE_AR },
125: { "Action Replay Mk III v3.17", 0, 0, 0xc8a16406, 262144, 30, 0, 0, ROMTYPE_AR },
126:
127: { "SportTime Table Hockey\0ar_airh", 0, 0, 0, 0, 33, 0, 0, ROMTYPE_ARCADIA },
128: { "SportTime Bowling\0ar_bowl", 0, 0, 0, 0, 34, 0, 0, ROMTYPE_ARCADIA },
129: { "World Darts\0ar_dart", 0, 0, 0, 0, 35, 0, 0, ROMTYPE_ARCADIA },
130: { "Magic Johnson's Fast Break\0ar_fast", 0, 0, 0, 0, 36, 0, 0, ROMTYPE_ARCADIA },
131: { "Leader Board Golf\0ar_ldrb", 0, 0, 0, 0, 37, 0, 0, ROMTYPE_ARCADIA },
132: { "Leader Board Golf (alt)\0ar_ldrba", 0, 0, 0, 0, 38, 0, 0, ROMTYPE_ARCADIA },
133: { "Ninja Mission\0ar_ninj", 0, 0, 0, 0, 39, 0, 0, ROMTYPE_ARCADIA },
134: { "Road Wars\0ar_rdwr", 0, 0, 0, 0, 40, 0, 0, ROMTYPE_ARCADIA },
135: { "Sidewinder\0ar_sdwr", 0, 0, 0, 0, 41, 0, 0, ROMTYPE_ARCADIA },
136: { "Cool Spot\0ar_spot", 0, 0, 0, 0, 42, 0, 0, ROMTYPE_ARCADIA },
137: { "Space Ranger\0ar_sprg", 0, 0, 0, 0, 43, 0, 0, ROMTYPE_ARCADIA },
138: { "Xenon\0ar_xeon", 0, 0, 0, 0, 44, 0, 0, ROMTYPE_ARCADIA },
139:
140: { NULL, 0, 0, 0, 0, 0, 0, 0, 0 }
141: };
142:
1.1.1.15! root 143: static void decode_cloanto_rom_do (uae_u8 *mem, int size, int real_size, uae_u8 *key, int keysize)
! 144: {
! 145: long cnt, t;
! 146: for (t = cnt = 0; cnt < size; cnt++, t = (t + 1) % keysize) {
! 147: mem[cnt] ^= key[t];
! 148: if (real_size == cnt + 1)
! 149: t = keysize - 1;
! 150: }
! 151: }
! 152:
1.1.1.14 root 153: static int decode_cloanto_rom (uae_u8 *mem, int size, int real_size)
154: {
155: FILE *keyf;
156: uae_u8 *p;
157: int keysize;
158:
159: if (strlen (currprefs.keyfile) == 0) {
160: write_log ("No filename given for ROM key file and ROM image is an encrypted \"Amiga Forever\" ROM file.\n");
161: return 0;
162: }
163: keyf = zfile_open (currprefs.keyfile, "rb");
164: if (keyf == 0) {
165: write_log ("Could not find specified ROM key-file.\n");
166: return 0;
167: }
168:
169: p = (uae_u8 *) xmalloc (524288);
170: keysize = fread (p, 1, 524288, keyf);
1.1.1.15! root 171: decode_cloanto_rom_do (mem, size, real_size, p, keysize);
1.1.1.14 root 172: fclose (keyf);
173: free (p);
174: return 1;
175: }
176:
1.1.1.15! root 177: struct romdata *getromdatabyname (char *name)
! 178: {
! 179: char tmp[1024];
! 180: int i = 0;
! 181: while (roms[i].name) {
! 182: getromname (&roms[i], tmp);
! 183: if (!strcmp (tmp, name) || !strcmp (roms[i].name, name))
! 184: return &roms[i];
! 185: i++;
! 186: }
! 187: return 0;
! 188: }
! 189:
! 190: struct romdata *getromdatabyid (int id)
! 191: {
! 192: int i = 0;
! 193: while (roms[i].name) {
! 194: if (id == roms[i].id)
! 195: return &roms[i];
! 196: i++;
! 197: }
! 198: return 0;
! 199: }
! 200:
! 201: struct romdata *getromdatabycrc (uae_u32 crc32)
! 202: {
! 203: int i = 0;
! 204: while (roms[i].name) {
! 205: if (crc32 == roms[i].crc32)
! 206: return &roms[i];
! 207: i++;
! 208: }
! 209: return 0;
! 210: }
! 211:
! 212: struct romdata *getromdatabydata (uae_u8 *rom, int size)
! 213: {
! 214: int i;
! 215: uae_u32 crc32a, crc32b, crc32c;
! 216: uae_u8 tmp[4];
! 217: uae_u8 *tmpbuf = NULL;
! 218:
! 219: if (size > 11 && !memcmp (rom, "AMIROMTYPE1", 11)) {
! 220: uae_u8 *tmpbuf = xmalloc (size);
! 221: int tmpsize = size - 11;
! 222: memcpy (tmpbuf, rom + 11, tmpsize);
! 223: decode_cloanto_rom (tmpbuf, tmpsize, tmpsize);
! 224: rom = tmpbuf;
! 225: size = tmpsize;
! 226: }
! 227: crc32a = get_crc32 (rom, size);
! 228: crc32b = get_crc32 (rom, size / 2);
! 229: /* ignore AR IO-port range until we have full dump */
! 230: memcpy (tmp, rom, 4);
! 231: memset (rom, 0, 4);
! 232: crc32c = get_crc32 (rom, size);
! 233: memcpy (rom, tmp, 4);
! 234: i = 0;
! 235: while (roms[i].name) {
! 236: if (roms[i].crc32) {
! 237: if (crc32a == roms[i].crc32 || crc32b == roms[i].crc32)
! 238: return &roms[i];
! 239: if (crc32c == roms[i].crc32 && roms[i].type == ROMTYPE_AR)
! 240: return &roms[i];
! 241: }
! 242: i++;
! 243: }
! 244: free (tmpbuf);
! 245: return 0;
! 246: }
! 247:
! 248: void getromname (struct romdata *rd, char *name)
! 249: {
! 250: name[0] = 0;
! 251: if (rd->type == ROMTYPE_ARCADIA)
! 252: strcat (name, "Arcadia ");
! 253: strcat (name, rd->name);
! 254: if (rd->revision)
! 255: sprintf (name + strlen (name), " rev %d.%d", rd->version, rd->revision);
! 256: if (rd->size > 0)
! 257: sprintf (name + strlen (name), " (%dk)", (rd->size + 1023) / 1024);
! 258: }
! 259:
1.1.1.3 root 260: addrbank *mem_banks[65536];
1.1.1.9 root 261:
262: /* This has two functions. It either holds a host address that, when added
263: to the 68k address, gives the host address corresponding to that 68k
264: address (in which case the value in this array is even), OR it holds the
265: same value as mem_banks, for those banks that have baseaddr==0. In that
266: case, bit 0 is set (the memory access routines will take care of it). */
267:
268: uae_u8 *baseaddr[65536];
1.1 root 269:
1.1.1.2 root 270: #ifdef NO_INLINE_MEMORY_ACCESS
1.1.1.5 root 271: __inline__ uae_u32 longget (uaecptr addr)
1.1.1.2 root 272: {
1.1.1.5 root 273: return call_mem_get_func (get_mem_bank (addr).lget, addr);
1.1.1.2 root 274: }
1.1.1.5 root 275: __inline__ uae_u32 wordget (uaecptr addr)
1.1.1.2 root 276: {
1.1.1.5 root 277: return call_mem_get_func (get_mem_bank (addr).wget, addr);
1.1.1.2 root 278: }
1.1.1.5 root 279: __inline__ uae_u32 byteget (uaecptr addr)
1.1.1.2 root 280: {
1.1.1.5 root 281: return call_mem_get_func (get_mem_bank (addr).bget, addr);
1.1.1.2 root 282: }
1.1.1.5 root 283: __inline__ void longput (uaecptr addr, uae_u32 l)
1.1.1.2 root 284: {
1.1.1.5 root 285: call_mem_put_func (get_mem_bank (addr).lput, addr, l);
1.1.1.2 root 286: }
1.1.1.5 root 287: __inline__ void wordput (uaecptr addr, uae_u32 w)
1.1.1.2 root 288: {
1.1.1.5 root 289: call_mem_put_func (get_mem_bank (addr).wput, addr, w);
1.1.1.2 root 290: }
1.1.1.5 root 291: __inline__ void byteput (uaecptr addr, uae_u32 b)
1.1.1.2 root 292: {
1.1.1.5 root 293: call_mem_put_func (get_mem_bank (addr).bput, addr, b);
1.1.1.2 root 294: }
295: #endif
296:
1.1.1.12 root 297: uae_u32 chipmem_mask, kickmem_mask, extendedkickmem_mask, bogomem_mask, a3000mem_mask;
1.1 root 298:
1.1.1.11 root 299: static int illegal_count;
1.1.1.3 root 300: /* A dummy bank that only contains zeros */
301:
1.1.1.4 root 302: static uae_u32 dummy_lget (uaecptr) REGPARAM;
303: static uae_u32 dummy_wget (uaecptr) REGPARAM;
304: static uae_u32 dummy_bget (uaecptr) REGPARAM;
305: static void dummy_lput (uaecptr, uae_u32) REGPARAM;
306: static void dummy_wput (uaecptr, uae_u32) REGPARAM;
307: static void dummy_bput (uaecptr, uae_u32) REGPARAM;
308: static int dummy_check (uaecptr addr, uae_u32 size) REGPARAM;
309:
310: uae_u32 REGPARAM2 dummy_lget (uaecptr addr)
311: {
1.1.1.8 root 312: special_mem |= S_READ;
1.1.1.11 root 313: if (currprefs.illegal_mem) {
314: if (illegal_count < 20) {
315: illegal_count++;
316: write_log ("Illegal lget at %08lx\n", addr);
317: }
318: }
1.1.1.4 root 319:
1.1.1.9 root 320: return 0xFFFFFFFF;
1.1 root 321: }
322:
1.1.1.4 root 323: uae_u32 REGPARAM2 dummy_wget (uaecptr addr)
1.1 root 324: {
1.1.1.8 root 325: special_mem |= S_READ;
1.1.1.11 root 326: if (currprefs.illegal_mem) {
327: if (illegal_count < 20) {
328: illegal_count++;
329: write_log ("Illegal wget at %08lx\n", addr);
330: }
331: }
1.1.1.12 root 332:
1.1.1.9 root 333: return 0xFFFF;
1.1 root 334: }
335:
1.1.1.4 root 336: uae_u32 REGPARAM2 dummy_bget (uaecptr addr)
1.1 root 337: {
1.1.1.8 root 338: special_mem |= S_READ;
1.1.1.11 root 339: if (currprefs.illegal_mem) {
340: if (illegal_count < 20) {
341: illegal_count++;
342: write_log ("Illegal bget at %08lx\n", addr);
343: }
344: }
1.1.1.4 root 345:
1.1.1.9 root 346: return 0xFF;
1.1 root 347: }
348:
1.1.1.4 root 349: void REGPARAM2 dummy_lput (uaecptr addr, uae_u32 l)
1.1 root 350: {
1.1.1.8 root 351: special_mem |= S_WRITE;
1.1.1.11 root 352: if (currprefs.illegal_mem) {
353: if (illegal_count < 20) {
354: illegal_count++;
355: write_log ("Illegal lput at %08lx\n", addr);
356: }
357: }
1.1.1.3 root 358: }
1.1.1.4 root 359: void REGPARAM2 dummy_wput (uaecptr addr, uae_u32 w)
1.1.1.3 root 360: {
1.1.1.8 root 361: special_mem |= S_WRITE;
1.1.1.11 root 362: if (currprefs.illegal_mem) {
363: if (illegal_count < 20) {
364: illegal_count++;
365: write_log ("Illegal wput at %08lx\n", addr);
366: }
367: }
1.1.1.3 root 368: }
1.1.1.4 root 369: void REGPARAM2 dummy_bput (uaecptr addr, uae_u32 b)
1.1.1.3 root 370: {
1.1.1.8 root 371: special_mem |= S_WRITE;
1.1.1.11 root 372: if (currprefs.illegal_mem) {
373: if (illegal_count < 20) {
374: illegal_count++;
375: write_log ("Illegal bput at %08lx\n", addr);
376: }
377: }
1.1 root 378: }
379:
1.1.1.4 root 380: int REGPARAM2 dummy_check (uaecptr addr, uae_u32 size)
1.1 root 381: {
1.1.1.9 root 382: special_mem |= S_READ;
1.1.1.11 root 383: if (currprefs.illegal_mem) {
384: if (illegal_count < 20) {
385: illegal_count++;
386: write_log ("Illegal check at %08lx\n", addr);
387: }
388: }
1.1.1.4 root 389:
1.1 root 390: return 0;
391: }
392:
1.1.1.3 root 393: /* A3000 "motherboard resources" bank. */
1.1.1.4 root 394: static uae_u32 mbres_lget (uaecptr) REGPARAM;
395: static uae_u32 mbres_wget (uaecptr) REGPARAM;
396: static uae_u32 mbres_bget (uaecptr) REGPARAM;
397: static void mbres_lput (uaecptr, uae_u32) REGPARAM;
398: static void mbres_wput (uaecptr, uae_u32) REGPARAM;
399: static void mbres_bput (uaecptr, uae_u32) REGPARAM;
400: static int mbres_check (uaecptr addr, uae_u32 size) REGPARAM;
1.1.1.3 root 401:
402: static int mbres_val = 0;
403:
1.1.1.4 root 404: uae_u32 REGPARAM2 mbres_lget (uaecptr addr)
1.1.1.3 root 405: {
1.1.1.8 root 406: special_mem |= S_READ;
1.1.1.4 root 407: if (currprefs.illegal_mem)
408: write_log ("Illegal lget at %08lx\n", addr);
409:
1.1 root 410: return 0;
411: }
412:
1.1.1.4 root 413: uae_u32 REGPARAM2 mbres_wget (uaecptr addr)
1.1 root 414: {
1.1.1.8 root 415: special_mem |= S_READ;
1.1.1.4 root 416: if (currprefs.illegal_mem)
417: write_log ("Illegal wget at %08lx\n", addr);
418:
1.1 root 419: return 0;
420: }
421:
1.1.1.4 root 422: uae_u32 REGPARAM2 mbres_bget (uaecptr addr)
1.1.1.3 root 423: {
1.1.1.8 root 424: special_mem |= S_READ;
1.1.1.4 root 425: if (currprefs.illegal_mem)
426: write_log ("Illegal bget at %08lx\n", addr);
427:
1.1.1.3 root 428: return (addr & 0xFFFF) == 3 ? mbres_val : 0;
429: }
430:
1.1.1.4 root 431: void REGPARAM2 mbres_lput (uaecptr addr, uae_u32 l)
1.1 root 432: {
1.1.1.8 root 433: special_mem |= S_WRITE;
1.1.1.4 root 434: if (currprefs.illegal_mem)
435: write_log ("Illegal lput at %08lx\n", addr);
1.1 root 436: }
1.1.1.4 root 437: void REGPARAM2 mbres_wput (uaecptr addr, uae_u32 w)
1.1 root 438: {
1.1.1.8 root 439: special_mem |= S_WRITE;
1.1.1.4 root 440: if (currprefs.illegal_mem)
441: write_log ("Illegal wput at %08lx\n", addr);
1.1 root 442: }
1.1.1.4 root 443: void REGPARAM2 mbres_bput (uaecptr addr, uae_u32 b)
1.1 root 444: {
1.1.1.8 root 445: special_mem |= S_WRITE;
1.1.1.4 root 446: if (currprefs.illegal_mem)
447: write_log ("Illegal bput at %08lx\n", addr);
448:
1.1.1.3 root 449: if ((addr & 0xFFFF) == 3)
450: mbres_val = b;
1.1 root 451: }
452:
1.1.1.4 root 453: int REGPARAM2 mbres_check (uaecptr addr, uae_u32 size)
1.1 root 454: {
1.1.1.4 root 455: if (currprefs.illegal_mem)
456: write_log ("Illegal check at %08lx\n", addr);
457:
1.1 root 458: return 0;
459: }
460:
461: /* Chip memory */
462:
1.1.1.3 root 463: uae_u8 *chipmemory;
1.1 root 464:
1.1.1.4 root 465: static int chipmem_check (uaecptr addr, uae_u32 size) REGPARAM;
466: static uae_u8 *chipmem_xlate (uaecptr addr) REGPARAM;
1.1 root 467:
1.1.1.4 root 468: uae_u32 REGPARAM2 chipmem_lget (uaecptr addr)
1.1 root 469: {
1.1.1.3 root 470: uae_u32 *m;
1.1.1.8 root 471:
1.1 root 472: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 473: addr &= chipmem_mask;
1.1.1.3 root 474: m = (uae_u32 *)(chipmemory + addr);
1.1.1.5 root 475: return do_get_mem_long (m);
1.1 root 476: }
477:
1.1.1.4 root 478: uae_u32 REGPARAM2 chipmem_wget (uaecptr addr)
1.1 root 479: {
1.1.1.3 root 480: uae_u16 *m;
1.1.1.8 root 481:
1.1 root 482: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 483: addr &= chipmem_mask;
1.1.1.3 root 484: m = (uae_u16 *)(chipmemory + addr);
1.1.1.5 root 485: return do_get_mem_word (m);
1.1 root 486: }
487:
1.1.1.4 root 488: uae_u32 REGPARAM2 chipmem_bget (uaecptr addr)
1.1 root 489: {
490: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 491: addr &= chipmem_mask;
1.1 root 492: return chipmemory[addr];
493: }
494:
1.1.1.4 root 495: void REGPARAM2 chipmem_lput (uaecptr addr, uae_u32 l)
1.1 root 496: {
1.1.1.3 root 497: uae_u32 *m;
1.1.1.8 root 498:
1.1 root 499: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 500: addr &= chipmem_mask;
1.1.1.3 root 501: m = (uae_u32 *)(chipmemory + addr);
1.1.1.5 root 502: do_put_mem_long (m, l);
1.1 root 503: }
504:
1.1.1.4 root 505: void REGPARAM2 chipmem_wput (uaecptr addr, uae_u32 w)
1.1 root 506: {
1.1.1.3 root 507: uae_u16 *m;
1.1.1.8 root 508:
1.1 root 509: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 510: addr &= chipmem_mask;
1.1.1.3 root 511: m = (uae_u16 *)(chipmemory + addr);
1.1.1.5 root 512: do_put_mem_word (m, w);
1.1 root 513: }
514:
1.1.1.4 root 515: void REGPARAM2 chipmem_bput (uaecptr addr, uae_u32 b)
1.1 root 516: {
517: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 518: addr &= chipmem_mask;
1.1 root 519: chipmemory[addr] = b;
520: }
521:
1.1.1.4 root 522: int REGPARAM2 chipmem_check (uaecptr addr, uae_u32 size)
1.1 root 523: {
524: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 525: addr &= chipmem_mask;
1.1.1.4 root 526: return (addr + size) <= allocated_chipmem;
1.1 root 527: }
528:
1.1.1.4 root 529: uae_u8 REGPARAM2 *chipmem_xlate (uaecptr addr)
1.1 root 530: {
531: addr -= chipmem_start & chipmem_mask;
1.1.1.2 root 532: addr &= chipmem_mask;
1.1 root 533: return chipmemory + addr;
534: }
535:
536: /* Slow memory */
537:
1.1.1.3 root 538: static uae_u8 *bogomemory;
1.1 root 539:
1.1.1.4 root 540: static uae_u32 bogomem_lget (uaecptr) REGPARAM;
541: static uae_u32 bogomem_wget (uaecptr) REGPARAM;
542: static uae_u32 bogomem_bget (uaecptr) REGPARAM;
543: static void bogomem_lput (uaecptr, uae_u32) REGPARAM;
544: static void bogomem_wput (uaecptr, uae_u32) REGPARAM;
545: static void bogomem_bput (uaecptr, uae_u32) REGPARAM;
546: static int bogomem_check (uaecptr addr, uae_u32 size) REGPARAM;
547: static uae_u8 *bogomem_xlate (uaecptr addr) REGPARAM;
1.1 root 548:
1.1.1.4 root 549: uae_u32 REGPARAM2 bogomem_lget (uaecptr addr)
1.1 root 550: {
1.1.1.3 root 551: uae_u32 *m;
1.1 root 552: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 553: addr &= bogomem_mask;
1.1.1.3 root 554: m = (uae_u32 *)(bogomemory + addr);
1.1.1.5 root 555: return do_get_mem_long (m);
1.1 root 556: }
557:
1.1.1.4 root 558: uae_u32 REGPARAM2 bogomem_wget (uaecptr addr)
1.1 root 559: {
1.1.1.3 root 560: uae_u16 *m;
1.1 root 561: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 562: addr &= bogomem_mask;
1.1.1.3 root 563: m = (uae_u16 *)(bogomemory + addr);
1.1.1.5 root 564: return do_get_mem_word (m);
1.1 root 565: }
566:
1.1.1.4 root 567: uae_u32 REGPARAM2 bogomem_bget (uaecptr addr)
1.1 root 568: {
569: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 570: addr &= bogomem_mask;
1.1 root 571: return bogomemory[addr];
572: }
573:
1.1.1.4 root 574: void REGPARAM2 bogomem_lput (uaecptr addr, uae_u32 l)
1.1 root 575: {
1.1.1.3 root 576: uae_u32 *m;
1.1 root 577: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 578: addr &= bogomem_mask;
1.1.1.3 root 579: m = (uae_u32 *)(bogomemory + addr);
1.1.1.5 root 580: do_put_mem_long (m, l);
1.1 root 581: }
582:
1.1.1.4 root 583: void REGPARAM2 bogomem_wput (uaecptr addr, uae_u32 w)
1.1 root 584: {
1.1.1.3 root 585: uae_u16 *m;
1.1 root 586: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 587: addr &= bogomem_mask;
1.1.1.3 root 588: m = (uae_u16 *)(bogomemory + addr);
1.1.1.5 root 589: do_put_mem_word (m, w);
1.1 root 590: }
591:
1.1.1.4 root 592: void REGPARAM2 bogomem_bput (uaecptr addr, uae_u32 b)
1.1 root 593: {
594: addr -= bogomem_start & bogomem_mask;
1.1.1.2 root 595: addr &= bogomem_mask;
1.1 root 596: bogomemory[addr] = b;
597: }
598:
1.1.1.4 root 599: int REGPARAM2 bogomem_check (uaecptr addr, uae_u32 size)
1.1 root 600: {
1.1.1.2 root 601: addr -= bogomem_start & bogomem_mask;
602: addr &= bogomem_mask;
1.1.1.4 root 603: return (addr + size) <= allocated_bogomem;
1.1 root 604: }
605:
1.1.1.4 root 606: uae_u8 REGPARAM2 *bogomem_xlate (uaecptr addr)
1.1 root 607: {
1.1.1.2 root 608: addr -= bogomem_start & bogomem_mask;
609: addr &= bogomem_mask;
1.1 root 610: return bogomemory + addr;
611: }
612:
1.1.1.3 root 613: /* A3000 motherboard fast memory */
614:
615: static uae_u8 *a3000memory;
1.1 root 616:
1.1.1.4 root 617: static uae_u32 a3000mem_lget (uaecptr) REGPARAM;
618: static uae_u32 a3000mem_wget (uaecptr) REGPARAM;
619: static uae_u32 a3000mem_bget (uaecptr) REGPARAM;
620: static void a3000mem_lput (uaecptr, uae_u32) REGPARAM;
621: static void a3000mem_wput (uaecptr, uae_u32) REGPARAM;
622: static void a3000mem_bput (uaecptr, uae_u32) REGPARAM;
623: static int a3000mem_check (uaecptr addr, uae_u32 size) REGPARAM;
624: static uae_u8 *a3000mem_xlate (uaecptr addr) REGPARAM;
1.1.1.3 root 625:
1.1.1.4 root 626: uae_u32 REGPARAM2 a3000mem_lget (uaecptr addr)
1.1.1.3 root 627: {
628: uae_u32 *m;
629: addr -= a3000mem_start & a3000mem_mask;
630: addr &= a3000mem_mask;
631: m = (uae_u32 *)(a3000memory + addr);
1.1.1.5 root 632: return do_get_mem_long (m);
1.1.1.3 root 633: }
1.1 root 634:
1.1.1.4 root 635: uae_u32 REGPARAM2 a3000mem_wget (uaecptr addr)
1.1.1.3 root 636: {
637: uae_u16 *m;
638: addr -= a3000mem_start & a3000mem_mask;
639: addr &= a3000mem_mask;
640: m = (uae_u16 *)(a3000memory + addr);
1.1.1.5 root 641: return do_get_mem_word (m);
1.1.1.3 root 642: }
1.1 root 643:
1.1.1.4 root 644: uae_u32 REGPARAM2 a3000mem_bget (uaecptr addr)
1.1 root 645: {
1.1.1.3 root 646: addr -= a3000mem_start & a3000mem_mask;
647: addr &= a3000mem_mask;
648: return a3000memory[addr];
1.1 root 649: }
650:
1.1.1.4 root 651: void REGPARAM2 a3000mem_lput (uaecptr addr, uae_u32 l)
1.1 root 652: {
1.1.1.3 root 653: uae_u32 *m;
654: addr -= a3000mem_start & a3000mem_mask;
655: addr &= a3000mem_mask;
656: m = (uae_u32 *)(a3000memory + addr);
1.1.1.5 root 657: do_put_mem_long (m, l);
1.1.1.3 root 658: }
659:
1.1.1.4 root 660: void REGPARAM2 a3000mem_wput (uaecptr addr, uae_u32 w)
1.1.1.3 root 661: {
662: uae_u16 *m;
663: addr -= a3000mem_start & a3000mem_mask;
664: addr &= a3000mem_mask;
665: m = (uae_u16 *)(a3000memory + addr);
1.1.1.5 root 666: do_put_mem_word (m, w);
1.1.1.3 root 667: }
668:
1.1.1.4 root 669: void REGPARAM2 a3000mem_bput (uaecptr addr, uae_u32 b)
1.1.1.3 root 670: {
671: addr -= a3000mem_start & a3000mem_mask;
672: addr &= a3000mem_mask;
673: a3000memory[addr] = b;
674: }
675:
1.1.1.4 root 676: int REGPARAM2 a3000mem_check (uaecptr addr, uae_u32 size)
1.1.1.3 root 677: {
678: addr -= a3000mem_start & a3000mem_mask;
679: addr &= a3000mem_mask;
1.1.1.4 root 680: return (addr + size) <= allocated_a3000mem;
1.1 root 681: }
682:
1.1.1.12 root 683: uae_u8 REGPARAM2 *a3000mem_xlate (uaecptr addr)
1.1.1.3 root 684: {
685: addr -= a3000mem_start & a3000mem_mask;
686: addr &= a3000mem_mask;
687: return a3000memory + addr;
688: }
689:
690: /* Kick memory */
691:
692: uae_u8 *kickmemory;
693:
1.1.1.12 root 694: /*
695: * A1000 kickstart RAM handling
696: *
697: * RESET instruction unhides boot ROM and disables write protection
698: * write access to boot ROM hides boot ROM and enables write protection
699: *
700: */
701: static int a1000_kickstart_mode;
702: static uae_u8 *a1000_bootrom;
703: static void a1000_handle_kickstart (int mode)
704: {
705: if (mode == 0) {
706: a1000_kickstart_mode = 0;
707: memcpy (kickmemory, kickmemory + 262144, 262144);
708: } else {
709: a1000_kickstart_mode = 1;
710: memset (kickmemory, 0, 262144);
711: memcpy (kickmemory, a1000_bootrom, 8192);
712: memcpy (kickmemory + 131072, a1000_bootrom, 8192);
713: }
714: }
715:
1.1.1.4 root 716: static uae_u32 kickmem_lget (uaecptr) REGPARAM;
717: static uae_u32 kickmem_wget (uaecptr) REGPARAM;
718: static uae_u32 kickmem_bget (uaecptr) REGPARAM;
1.1.1.12 root 719: static void kickmem_lput (uaecptr, uae_u32) REGPARAM;
720: static void kickmem_wput (uaecptr, uae_u32) REGPARAM;
721: static void kickmem_bput (uaecptr, uae_u32) REGPARAM;
722: static int kickmem_check (uaecptr addr, uae_u32 size) REGPARAM;
1.1.1.4 root 723: static uae_u8 *kickmem_xlate (uaecptr addr) REGPARAM;
1.1.1.3 root 724:
1.1.1.4 root 725: uae_u32 REGPARAM2 kickmem_lget (uaecptr addr)
1.1 root 726: {
1.1.1.3 root 727: uae_u32 *m;
1.1 root 728: addr -= kickmem_start & kickmem_mask;
1.1.1.2 root 729: addr &= kickmem_mask;
1.1.1.3 root 730: m = (uae_u32 *)(kickmemory + addr);
1.1.1.5 root 731: return do_get_mem_long (m);
1.1 root 732: }
733:
1.1.1.4 root 734: uae_u32 REGPARAM2 kickmem_wget (uaecptr addr)
1.1 root 735: {
1.1.1.3 root 736: uae_u16 *m;
1.1 root 737: addr -= kickmem_start & kickmem_mask;
1.1.1.2 root 738: addr &= kickmem_mask;
1.1.1.3 root 739: m = (uae_u16 *)(kickmemory + addr);
1.1.1.5 root 740: return do_get_mem_word (m);
1.1 root 741: }
742:
1.1.1.4 root 743: uae_u32 REGPARAM2 kickmem_bget (uaecptr addr)
1.1 root 744: {
745: addr -= kickmem_start & kickmem_mask;
1.1.1.2 root 746: addr &= kickmem_mask;
1.1 root 747: return kickmemory[addr];
748: }
749:
1.1.1.4 root 750: void REGPARAM2 kickmem_lput (uaecptr addr, uae_u32 b)
1.1 root 751: {
1.1.1.12 root 752: uae_u32 *m;
753: if (a1000_kickstart_mode) {
754: if (addr >= 0xfc0000) {
755: addr -= kickmem_start & kickmem_mask;
756: addr &= kickmem_mask;
757: m = (uae_u32 *)(kickmemory + addr);
758: do_put_mem_long (m, b);
759: return;
760: } else
761: a1000_handle_kickstart (0);
762: } else if (currprefs.illegal_mem)
1.1.1.4 root 763: write_log ("Illegal kickmem lput at %08lx\n", addr);
1.1 root 764: }
765:
1.1.1.4 root 766: void REGPARAM2 kickmem_wput (uaecptr addr, uae_u32 b)
1.1 root 767: {
1.1.1.12 root 768: uae_u16 *m;
769: if (a1000_kickstart_mode) {
770: if (addr >= 0xfc0000) {
771: addr -= kickmem_start & kickmem_mask;
772: addr &= kickmem_mask;
773: m = (uae_u16 *)(kickmemory + addr);
774: do_put_mem_word (m, b);
775: return;
776: } else
777: a1000_handle_kickstart (0);
778: } else if (currprefs.illegal_mem)
1.1.1.4 root 779: write_log ("Illegal kickmem wput at %08lx\n", addr);
1.1 root 780: }
781:
1.1.1.4 root 782: void REGPARAM2 kickmem_bput (uaecptr addr, uae_u32 b)
1.1 root 783: {
1.1.1.12 root 784: if (a1000_kickstart_mode) {
785: if (addr >= 0xfc0000) {
786: addr -= kickmem_start & kickmem_mask;
787: addr &= kickmem_mask;
788: kickmemory[addr] = b;
789: return;
790: } else
791: a1000_handle_kickstart (0);
792: } else if (currprefs.illegal_mem)
1.1.1.4 root 793: write_log ("Illegal kickmem lput at %08lx\n", addr);
1.1 root 794: }
795:
1.1.1.4 root 796: int REGPARAM2 kickmem_check (uaecptr addr, uae_u32 size)
1.1 root 797: {
1.1.1.2 root 798: addr -= kickmem_start & kickmem_mask;
799: addr &= kickmem_mask;
1.1.1.4 root 800: return (addr + size) <= kickmem_size;
1.1 root 801: }
802:
1.1.1.4 root 803: uae_u8 REGPARAM2 *kickmem_xlate (uaecptr addr)
1.1 root 804: {
1.1.1.2 root 805: addr -= kickmem_start & kickmem_mask;
806: addr &= kickmem_mask;
1.1 root 807: return kickmemory + addr;
808: }
809:
1.1.1.12 root 810: /* CD32/CDTV extended kick memory */
1.1.1.3 root 811:
1.1.1.12 root 812: uae_u8 *extendedkickmemory;
813: static int extendedkickmem_size;
814: static uae_u32 extendedkickmem_start;
815:
816: #define EXTENDED_ROM_CD32 1
817: #define EXTENDED_ROM_CDTV 2
818:
819: static int extromtype (void)
820: {
821: switch (extendedkickmem_size) {
822: case 524288:
823: return EXTENDED_ROM_CD32;
824: case 262144:
825: return EXTENDED_ROM_CDTV;
826: }
1.1.1.3 root 827: return 0;
828: }
829:
1.1.1.12 root 830: static uae_u32 extendedkickmem_lget (uaecptr) REGPARAM;
831: static uae_u32 extendedkickmem_wget (uaecptr) REGPARAM;
832: static uae_u32 extendedkickmem_bget (uaecptr) REGPARAM;
833: static void extendedkickmem_lput (uaecptr, uae_u32) REGPARAM;
834: static void extendedkickmem_wput (uaecptr, uae_u32) REGPARAM;
835: static void extendedkickmem_bput (uaecptr, uae_u32) REGPARAM;
836: static int extendedkickmem_check (uaecptr addr, uae_u32 size) REGPARAM;
837: static uae_u8 *extendedkickmem_xlate (uaecptr addr) REGPARAM;
838:
839: uae_u32 REGPARAM2 extendedkickmem_lget (uaecptr addr)
1.1.1.3 root 840: {
1.1.1.12 root 841: uae_u32 *m;
842: addr -= extendedkickmem_start & extendedkickmem_mask;
843: addr &= extendedkickmem_mask;
844: m = (uae_u32 *)(extendedkickmemory + addr);
845: return do_get_mem_long (m);
1.1.1.3 root 846: }
847:
1.1.1.12 root 848: uae_u32 REGPARAM2 extendedkickmem_wget (uaecptr addr)
1.1 root 849: {
1.1.1.12 root 850: uae_u16 *m;
851: addr -= extendedkickmem_start & extendedkickmem_mask;
852: addr &= extendedkickmem_mask;
853: m = (uae_u16 *)(extendedkickmemory + addr);
854: return do_get_mem_word (m);
855: }
1.1.1.3 root 856:
1.1.1.12 root 857: uae_u32 REGPARAM2 extendedkickmem_bget (uaecptr addr)
858: {
859: addr -= extendedkickmem_start & extendedkickmem_mask;
860: addr &= extendedkickmem_mask;
861: return extendedkickmemory[addr];
862: }
1.1.1.3 root 863:
1.1.1.12 root 864: void REGPARAM2 extendedkickmem_lput (uaecptr addr, uae_u32 b)
865: {
866: if (currprefs.illegal_mem)
867: write_log ("Illegal extendedkickmem lput at %08lx\n", addr);
868: }
1.1.1.3 root 869:
1.1.1.12 root 870: void REGPARAM2 extendedkickmem_wput (uaecptr addr, uae_u32 b)
871: {
872: if (currprefs.illegal_mem)
873: write_log ("Illegal extendedkickmem wput at %08lx\n", addr);
874: }
1.1.1.3 root 875:
1.1.1.12 root 876: void REGPARAM2 extendedkickmem_bput (uaecptr addr, uae_u32 b)
877: {
878: if (currprefs.illegal_mem)
879: write_log ("Illegal extendedkickmem lput at %08lx\n", addr);
880: }
1.1.1.3 root 881:
1.1.1.12 root 882: int REGPARAM2 extendedkickmem_check (uaecptr addr, uae_u32 size)
883: {
884: addr -= extendedkickmem_start & extendedkickmem_mask;
885: addr &= extendedkickmem_mask;
886: return (addr + size) <= extendedkickmem_size;
887: }
1.1.1.3 root 888:
1.1.1.12 root 889: uae_u8 REGPARAM2 *extendedkickmem_xlate (uaecptr addr)
890: {
891: addr -= extendedkickmem_start & extendedkickmem_mask;
892: addr &= extendedkickmem_mask;
893: return extendedkickmemory + addr;
894: }
1.1.1.2 root 895:
1.1.1.12 root 896: /* Default memory access functions */
897:
898: int REGPARAM2 default_check (uaecptr a, uae_u32 b)
899: {
900: return 0;
901: }
902:
903: uae_u8 REGPARAM2 *default_xlate (uaecptr a)
904: {
905: write_log ("Your Amiga program just did something terribly stupid\n");
1.1.1.15! root 906: uae_reset (1);
1.1.1.12 root 907: return kickmem_xlate (get_long (0xF80000)); /* So we don't crash. */
1.1 root 908: }
909:
910: /* Address banks */
911:
912: addrbank dummy_bank = {
913: dummy_lget, dummy_wget, dummy_bget,
914: dummy_lput, dummy_wput, dummy_bput,
1.1.1.9 root 915: default_xlate, dummy_check, NULL
1.1 root 916: };
917:
1.1.1.3 root 918: addrbank mbres_bank = {
919: mbres_lget, mbres_wget, mbres_bget,
920: mbres_lput, mbres_wput, mbres_bput,
1.1.1.9 root 921: default_xlate, mbres_check, NULL
1.1.1.3 root 922: };
923:
1.1 root 924: addrbank chipmem_bank = {
925: chipmem_lget, chipmem_wget, chipmem_bget,
926: chipmem_lput, chipmem_wput, chipmem_bput,
1.1.1.9 root 927: chipmem_xlate, chipmem_check, NULL
1.1 root 928: };
929:
930: addrbank bogomem_bank = {
931: bogomem_lget, bogomem_wget, bogomem_bget,
932: bogomem_lput, bogomem_wput, bogomem_bput,
1.1.1.9 root 933: bogomem_xlate, bogomem_check, NULL
1.1 root 934: };
935:
1.1.1.3 root 936: addrbank a3000mem_bank = {
937: a3000mem_lget, a3000mem_wget, a3000mem_bget,
938: a3000mem_lput, a3000mem_wput, a3000mem_bput,
1.1.1.9 root 939: a3000mem_xlate, a3000mem_check, NULL
1.1.1.3 root 940: };
941:
1.1 root 942: addrbank kickmem_bank = {
943: kickmem_lget, kickmem_wget, kickmem_bget,
944: kickmem_lput, kickmem_wput, kickmem_bput,
1.1.1.9 root 945: kickmem_xlate, kickmem_check, NULL
1.1 root 946: };
947:
1.1.1.12 root 948: addrbank extendedkickmem_bank = {
949: extendedkickmem_lget, extendedkickmem_wget, extendedkickmem_bget,
950: extendedkickmem_lput, extendedkickmem_wput, extendedkickmem_bput,
951: extendedkickmem_xlate, extendedkickmem_check, NULL
952: };
953:
954: static int kickstart_checksum (uae_u8 *mem, int size)
955: {
956: uae_u32 cksum = 0, prevck = 0;
957: int i;
958: for (i = 0; i < size; i += 4) {
959: uae_u32 data = mem[i] * 65536 * 256 + mem[i + 1] * 65536 + mem[i + 2] * 256 + mem[i + 3];
960: cksum += data;
961: if (cksum < prevck)
962: cksum++;
963: prevck = cksum;
964: }
965: if (cksum != 0xFFFFFFFFul) {
966: write_log ("Kickstart checksum incorrect. You probably have a corrupted ROM image.\n");
967: }
968: return 0;
969: }
970:
971: static int read_kickstart (FILE *f, uae_u8 *mem, int size, int dochecksum, int *cloanto_rom)
972: {
973: unsigned char buffer[20];
974: int i, cr = 0;
975:
976: if (cloanto_rom)
977: *cloanto_rom = 0;
978: i = fread (buffer, 1, 11, f);
979: if (strncmp ((char *) buffer, "AMIROMTYPE1", 11) != 0) {
980: fseek (f, 0, SEEK_SET);
981: } else {
982: cr = 1;
983: }
984:
985: i = fread (mem, 1, size, f);
986: if (i == 8192) {
987: a1000_bootrom = malloc (8192);
988: memcpy (a1000_bootrom, kickmemory, 8192);
989: a1000_handle_kickstart (1);
990: } else if (i == size / 2) {
991: memcpy (mem + size / 2, mem, i);
992: } else if (i != size) {
993: write_log ("Error while reading Kickstart.\n");
994: zfile_close (f);
995: return 0;
996: }
997: zfile_close (f);
998:
999: if (cr)
1000: decode_cloanto_rom (mem, size, i);
1001: if (dochecksum && i >= 262144)
1002: kickstart_checksum (mem, size);
1003: if (cloanto_rom)
1004: *cloanto_rom = cr;
1005: return 1;
1006: }
1007:
1008: static int load_extendedkickstart (void)
1009: {
1010: FILE *f;
1011: int size;
1012:
1013: if (strlen (currprefs.romextfile) == 0)
1014: return 0;
1015: f = zfile_open (currprefs.romextfile, "rb");
1016: if (!f) {
1017: write_log ("No extended Kickstart ROM found");
1018: return 0;
1019: }
1020:
1021: fseek (f, 0, SEEK_END);
1022: size = ftell (f);
1023: if (size > 300000)
1024: extendedkickmem_size = 524288;
1025: else
1026: extendedkickmem_size = 262144;
1027: fseek (f, 0, SEEK_SET);
1028:
1029: switch (extromtype ()) {
1030: case EXTENDED_ROM_CDTV:
1031: extendedkickmemory = (uae_u8 *) mapped_malloc (extendedkickmem_size, "rom_f0");
1032: extendedkickmem_bank.baseaddr = (uae_u8 *) extendedkickmemory;
1033: break;
1034: case EXTENDED_ROM_CD32:
1035: extendedkickmemory = (uae_u8 *) mapped_malloc (extendedkickmem_size, "rom_e0");
1036: extendedkickmem_bank.baseaddr = (uae_u8 *) extendedkickmemory;
1037: break;
1038: }
1039: read_kickstart (f, extendedkickmemory, 524288, 0, 0);
1040: fclose (f);
1041: return 1;
1042: }
1043:
1044:
1045: static int load_kickstart (void)
1046: {
1047: FILE *f = zfile_open (currprefs.romfile, "rb");
1048:
1049: if (f == NULL) {
1050: #if defined(AMIGA)||defined(__POS__)
1051: #define USE_UAE_ERSATZ "USE_UAE_ERSATZ"
1052: if (!getenv (USE_UAE_ERSATZ)) {
1053: write_log ("Using current ROM. (create ENV:%s to " "use uae's ROM replacement)\n", USE_UAE_ERSATZ);
1054: memcpy (kickmemory, (char *) 0x1000000 - kickmem_size, kickmem_size);
1055: kickstart_checksum (kickmemory, kickmem_size);
1056: goto chk_sum;
1057: }
1058: #endif
1059: return 0;
1060: }
1061:
1062: if (!read_kickstart (f, kickmemory, kickmem_size, 1, &cloanto_rom))
1063: return 0;
1064:
1065: #if defined(AMIGA)
1066: chk_sum:
1067: #endif
1068:
1069: if (currprefs.kickshifter) {
1070: /* Patch Kickstart ROM for ShapeShifter - from Christian Bauer.
1071: Changes 'lea $400,a0' to 'lea $2000,a0' for ShapeShifter compatability.
1072: NOTE: lea is 0x41f8, so we should do this better with a search for
1073: 0x41f80400 --> 0x41f82000
1074: */
1075: if (kickmemory[0x24a] == 0x04 && kickmemory[0x24b] == 0x00) { /* Kick 3.0 */
1076: kickmemory[0x24a] = 0x20;
1077: kickmemory[0x7ffea] -= 0x1c;
1078: write_log ("Kickstart KickShifted\n");
1079: } else if (kickmemory[0x26e] == 0x04 && kickmemory[0x26f] == 0x00) { /* Kick 3.1 */
1080: kickmemory[0x26e] = 0x20;
1081: kickmemory[0x7ffea] -= 0x1c;
1082: write_log ("Kickstart KickShifted\n");
1083: } else if (kickmemory[0x24e] == 0x04 && kickmemory[0x24f] == 0x00) { /* Kick 2.04 */
1084: kickmemory[0x24e] = 0x20;
1085: kickmemory[0x7ffea] -= 0x1c;
1086: write_log ("Kickstart KickShifted\n");
1087: }
1088: }
1089: return 1;
1090: }
1091:
1.1 root 1092: char *address_space, *good_address_map;
1093: int good_address_fd;
1.1.1.4 root 1094:
1.1.1.9 root 1095: #ifndef NATMEM_OFFSET
1096:
1.1.1.12 root 1097: uae_u8 *mapped_malloc (size_t s, char *file)
1.1.1.4 root 1098: {
1.1.1.13 root 1099: return calloc (s, 1);
1.1.1.4 root 1100: }
1101:
1.1.1.9 root 1102: void mapped_free (uae_u8 *p)
1.1 root 1103: {
1.1.1.9 root 1104: free (p);
1105: }
1106: #else
1.1.1.3 root 1107:
1.1.1.9 root 1108: #include <sys/ipc.h>
1109: #include <sys/shm.h>
1110: #include <unistd.h>
1111: #include <sys/mman.h>
1112:
1.1.1.12 root 1113: shmpiece *shm_start = NULL;
1114: int canbang = 1;
1.1.1.9 root 1115:
1.1.1.12 root 1116: static void dumplist (void)
1.1.1.9 root 1117: {
1.1.1.12 root 1118: shmpiece *x = shm_start;
1.1.1.9 root 1119: printf ("Start Dump:\n");
1120: while (x) {
1121: printf (" this=%p, Native %p, id %d, prev=%p, next=%p, size=0x%08x\n",
1.1.1.12 root 1122: x, x->native_address, x->id, x->prev, x->next, x->size);
1.1.1.9 root 1123: x = x->next;
1.1.1.2 root 1124: }
1.1.1.9 root 1125: printf ("End Dump:\n");
1126: }
1.1 root 1127:
1.1.1.9 root 1128: static shmpiece *find_shmpiece (uae_u8 *base)
1129: {
1130: shmpiece *x = shm_start;
1.1 root 1131:
1.1.1.9 root 1132: while (x && x->native_address != base)
1133: x = x->next;
1134: if (!x) {
1.1.1.12 root 1135: printf ("NATMEM: Failure to find mapping at %p\n", base);
1136: dumplist ();
1.1.1.9 root 1137: canbang = 0;
1138: return 0;
1139: }
1140: return x;
1141: }
1.1.1.3 root 1142:
1.1.1.9 root 1143: static void delete_shmmaps (uae_u32 start, uae_u32 size)
1144: {
1145: if (!canbang)
1146: return;
1147:
1148: while (size) {
1.1.1.12 root 1149: uae_u8 *base = mem_banks[bankindex (start)]->baseaddr;
1.1.1.9 root 1150: if (base) {
1151: shmpiece *x;
1.1.1.12 root 1152: base = ((uae_u8 *) NATMEM_OFFSET) + start;
1.1.1.9 root 1153:
1154: x = find_shmpiece (base);
1.1.1.12 root 1155: if (!x)
1.1.1.9 root 1156: return;
1157:
1158: if (x->size > size) {
1.1.1.12 root 1159: printf ("NATMEM: Failure to delete mapping at %08x(size %08x, delsize %08x)\n", start, x->size, size);
1160: dumplist ();
1.1.1.9 root 1161: canbang = 0;
1162: return;
1163: }
1164: shmdt (x->native_address);
1165: size -= x->size;
1166: start += x->size;
1167: if (x->next)
1.1.1.12 root 1168: x->next->prev = x->prev; /* remove this one from the list */
1.1.1.9 root 1169: if (x->prev)
1170: x->prev->next = x->next;
1171: else
1172: shm_start = x->next;
1.1.1.12 root 1173: free (x);
1.1.1.9 root 1174: } else {
1175: size -= 0x10000;
1176: start += 0x10000;
1177: }
1.1.1.3 root 1178: }
1.1.1.9 root 1179: }
1.1.1.12 root 1180:
1.1.1.9 root 1181: static void add_shmmaps (uae_u32 start, addrbank *what)
1182: {
1183: shmpiece *x = shm_start;
1184: shmpiece *y;
1185: uae_u8 *base = what->baseaddr;
1186:
1187: if (!canbang)
1188: return;
1189: if (!base)
1190: return;
1191:
1192: x = find_shmpiece (base);
1.1.1.12 root 1193: if (!x)
1.1.1.9 root 1194: return;
1195: y = malloc (sizeof (shmpiece));
1196: *y = *x;
1.1.1.12 root 1197: base = ((uae_u8 *) NATMEM_OFFSET) + start;
1198: y->native_address = shmat (y->id, base, 0);
1199: if (y->native_address == (void *) -1) {
1200: printf ("NATMEM: Failure to map existing at %08x(%p)\n", start, base);
1201: perror ("shmat");
1202: dumplist ();
1.1.1.9 root 1203: canbang = 0;
1204: return;
1.1.1.2 root 1205: }
1.1.1.9 root 1206: y->next = shm_start;
1207: y->prev = NULL;
1208: if (y->next)
1209: y->next->prev = y;
1210: shm_start = y;
1211: }
1212:
1213: uae_u8 *mapped_malloc (size_t s, char *file)
1214: {
1.1.1.12 root 1215: int id;
1.1.1.9 root 1216: void *answer;
1217: shmpiece *x;
1218:
1.1.1.12 root 1219: if (!canbang)
1.1.1.9 root 1220: return malloc (s);
1221:
1.1.1.12 root 1222: id = shmget (IPC_PRIVATE, s, 0x1ff, file);
1.1.1.9 root 1223: if (id == 1) {
1224: canbang = 0;
1225: return mapped_malloc (s, file);
1226: }
1.1.1.12 root 1227: answer = shmat (id, 0, 0);
1228: shmctl (id, IPC_RMID, NULL);
1229: if (answer != (void *) -1) {
1230: x = malloc (sizeof (shmpiece));
1.1.1.9 root 1231: x->native_address = answer;
1232: x->id = id;
1233: x->size = s;
1234: x->next = shm_start;
1235: x->prev = NULL;
1236: if (x->next)
1237: x->next->prev = x;
1238: shm_start = x;
1239:
1240: return answer;
1241: }
1242: canbang = 0;
1243: return mapped_malloc (s, file);
1244: }
1245:
1.1.1.10 root 1246: void mapped_free (uae_u8 *base)
1.1.1.9 root 1247: {
1248: shmpiece *x = find_shmpiece (base);
1.1.1.12 root 1249: if (!x)
1.1.1.9 root 1250: abort ();
1251: shmdt (x->native_address);
1252: }
1253:
1.1 root 1254: #endif
1.1.1.6 root 1255:
1.1.1.9 root 1256: static void init_mem_banks (void)
1257: {
1258: int i;
1259: for (i = 0; i < 65536; i++)
1260: put_mem_bank (i << 16, &dummy_bank, 0);
1261: }
1262:
1263: static void allocate_memory (void)
1264: {
1265: if (allocated_chipmem != currprefs.chipmem_size) {
1266: if (chipmemory)
1267: mapped_free (chipmemory);
1268: chipmemory = 0;
1269:
1270: allocated_chipmem = currprefs.chipmem_size;
1271: chipmem_mask = allocated_chipmem - 1;
1272:
1273: chipmemory = mapped_malloc (allocated_chipmem, "chip");
1274: if (chipmemory == 0) {
1275: write_log ("Fatal error: out of memory for chipmem.\n");
1276: allocated_chipmem = 0;
1277: } else
1278: do_put_mem_long ((uae_u32 *)(chipmemory + 4), 0);
1279: }
1280:
1281: if (allocated_bogomem != currprefs.bogomem_size) {
1282: if (bogomemory)
1283: mapped_free (bogomemory);
1284: bogomemory = 0;
1285:
1286: allocated_bogomem = currprefs.bogomem_size;
1287: bogomem_mask = allocated_bogomem - 1;
1288:
1289: if (allocated_bogomem) {
1290: bogomemory = mapped_malloc (allocated_bogomem, "bogo");
1291: if (bogomemory == 0) {
1292: write_log ("Out of memory for bogomem.\n");
1293: allocated_bogomem = 0;
1294: }
1295: }
1296: }
1297: if (allocated_a3000mem != currprefs.a3000mem_size) {
1298: if (a3000memory)
1299: mapped_free (a3000memory);
1300: a3000memory = 0;
1301:
1302: allocated_a3000mem = currprefs.a3000mem_size;
1303: a3000mem_mask = allocated_a3000mem - 1;
1304:
1305: if (allocated_a3000mem) {
1306: a3000memory = mapped_malloc (allocated_a3000mem, "a3000");
1307: if (a3000memory == 0) {
1308: write_log ("Out of memory for a3000mem.\n");
1309: allocated_a3000mem = 0;
1310: }
1311: }
1312: }
1313:
1314: if (savestate_state == STATE_RESTORE) {
1315: fseek (savestate_file, chip_filepos, SEEK_SET);
1316: fread (chipmemory, 1, allocated_chipmem, savestate_file);
1317: if (allocated_bogomem > 0) {
1318: fseek (savestate_file, bogo_filepos, SEEK_SET);
1319: fread (bogomemory, 1, allocated_bogomem, savestate_file);
1320: }
1321: }
1322: chipmem_bank.baseaddr = chipmemory;
1323: bogomem_bank.baseaddr = bogomemory;
1324: }
1325:
1326: void memory_reset (void)
1327: {
1328: int i, custom_start;
1329:
1330: #ifdef NATMEM_OFFSET
1331: delete_shmmaps (0, 0xFFFF0000);
1332: #endif
1.1.1.4 root 1333: init_mem_banks ();
1.1.1.3 root 1334:
1.1.1.9 root 1335: currprefs.chipmem_size = changed_prefs.chipmem_size;
1336: currprefs.bogomem_size = changed_prefs.bogomem_size;
1337: currprefs.a3000mem_size = changed_prefs.a3000mem_size;
1338:
1339: allocate_memory ();
1340:
1.1.1.12 root 1341: if (strcmp (currprefs.romfile, changed_prefs.romfile) != 0 || strcmp (currprefs.keyfile, changed_prefs.keyfile) != 0) {
1.1.1.10 root 1342: ersatzkickfile = 0;
1343: memcpy (currprefs.romfile, changed_prefs.romfile, sizeof currprefs.romfile);
1344: memcpy (currprefs.keyfile, changed_prefs.keyfile, sizeof currprefs.keyfile);
1345: /* Clear out whatever data remains across a reset. */
1346: memset (chipmemory, 0, allocated_chipmem);
1.1.1.12 root 1347: if (!load_kickstart ()) {
1.1.1.10 root 1348: init_ersatz_rom (kickmemory);
1349: ersatzkickfile = 1;
1350: }
1.1.1.12 root 1351: }
1.1.1.9 root 1352: /* Map the chipmem into all of the lower 8MB */
1353: i = allocated_chipmem > 0x200000 ? (allocated_chipmem >> 16) : 32;
1354: map_banks (&chipmem_bank, 0x00, i, allocated_chipmem);
1355:
1.1.1.3 root 1356: custom_start = 0xC0;
1.1 root 1357:
1.1.1.9 root 1358: map_banks (&custom_bank, custom_start, 0xE0 - custom_start, 0);
1359: map_banks (&cia_bank, 0xA0, 32, 0);
1360: map_banks (&clock_bank, 0xDC, 1, 0);
1.1.1.3 root 1361:
1362: /* @@@ Does anyone have a clue what should be in the 0x200000 - 0xA00000
1363: * range on an Amiga without expansion memory? */
1.1.1.4 root 1364: custom_start = allocated_chipmem >> 16;
1.1.1.3 root 1365: if (custom_start < 0x20)
1366: custom_start = 0x20;
1.1.1.9 root 1367: map_banks (&dummy_bank, custom_start, 0xA0 - custom_start, 0);
1.1.1.12 root 1368: /*map_banks (&mbres_bank, 0xDE, 1); */
1.1.1.3 root 1369:
1.1.1.9 root 1370: if (bogomemory != 0) {
1371: int t = allocated_bogomem >> 16;
1372: if (t > 0x1C)
1373: t = 0x1C;
1374: map_banks (&bogomem_bank, 0xC0, t, allocated_bogomem);
1375: }
1.1.1.4 root 1376: if (a3000memory != 0)
1.1.1.12 root 1377: map_banks (&a3000mem_bank, a3000mem_start >> 16, allocated_a3000mem >> 16, allocated_a3000mem);
1.1.1.9 root 1378:
1.1.1.11 root 1379: map_banks (&rtarea_bank, RTAREA_BASE >> 16, 1, 0);
1.1.1.9 root 1380:
1381: map_banks (&kickmem_bank, 0xF8, 8, 0);
1.1.1.12 root 1382: if (a1000_bootrom)
1383: a1000_handle_kickstart (1);
1.1.1.9 root 1384: map_banks (&expamem_bank, 0xE8, 1, 0);
1385:
1.1.1.12 root 1386: switch (extromtype ()) {
1387: case EXTENDED_ROM_CDTV:
1388: map_banks (&extendedkickmem_bank, 0xF0, 4, 0);
1389: break;
1390: case EXTENDED_ROM_CD32:
1391: map_banks (&extendedkickmem_bank, 0xE0, 8, 0);
1392: break;
1393: default:
1394: if (cloanto_rom)
1395: map_banks (&kickmem_bank, 0xE0, 8, 0);
1396: }
1.1.1.9 root 1397: }
1398:
1399: void memory_init (void)
1400: {
1401: allocated_chipmem = 0;
1402: allocated_bogomem = 0;
1403: allocated_a3000mem = 0;
1404: kickmemory = 0;
1.1.1.12 root 1405: extendedkickmemory = 0;
1.1.1.9 root 1406: chipmemory = 0;
1407: a3000memory = 0;
1408: bogomemory = 0;
1409:
1410: kickmemory = mapped_malloc (kickmem_size, "kick");
1411: kickmem_bank.baseaddr = kickmemory;
1.1.1.3 root 1412:
1.1.1.12 root 1413: load_extendedkickstart ();
1414: if (!load_kickstart ()) {
1.1.1.3 root 1415: init_ersatz_rom (kickmemory);
1.1 root 1416: ersatzkickfile = 1;
1417: }
1.1.1.3 root 1418:
1.1.1.9 root 1419: init_mem_banks ();
1420: memory_reset ();
1.1.1.4 root 1421:
1422: kickmem_mask = kickmem_size - 1;
1.1.1.12 root 1423: extendedkickmem_mask = extendedkickmem_size - 1;
1.1 root 1424: }
1425:
1.1.1.12 root 1426: void memory_cleanup (void)
1.1.1.10 root 1427: {
1428: if (a3000memory)
1429: mapped_free (a3000memory);
1430: if (bogomemory)
1431: mapped_free (bogomemory);
1432: if (kickmemory)
1433: mapped_free (kickmemory);
1.1.1.12 root 1434: if (a1000_bootrom)
1435: free (a1000_bootrom);
1.1.1.10 root 1436: if (chipmemory)
1437: mapped_free (chipmemory);
1.1.1.12 root 1438:
1.1.1.10 root 1439: a3000memory = 0;
1440: bogomemory = 0;
1441: kickmemory = 0;
1.1.1.12 root 1442: a1000_bootrom = 0;
1.1.1.10 root 1443: chipmemory = 0;
1444: }
1445:
1.1.1.9 root 1446: void map_banks (addrbank *bank, int start, int size, int realsize)
1.1 root 1447: {
1448: int bnr;
1.1.1.3 root 1449: unsigned long int hioffs = 0, endhioffs = 0x100;
1.1.1.12 root 1450: addrbank *orgbank = bank;
1.1.1.9 root 1451: uae_u32 realstart = start;
1.1.1.12 root 1452:
1453: flush_icache (1); /* Sure don't want to keep any old mappings around! */
1.1.1.9 root 1454: #ifdef NATMEM_OFFSET
1455: delete_shmmaps (start << 16, size << 16);
1456: #endif
1.1.1.12 root 1457:
1.1.1.9 root 1458: if (!realsize)
1459: realsize = size << 16;
1460:
1461: if ((size << 16) < realsize) {
1.1.1.11 root 1462: write_log ("Please report to [email protected], and mention:\n");
1.1.1.12 root 1463: write_log ("Broken mapping, size=%x, realsize=%x\n", size, realsize);
1464: write_log ("Start is %x\n", start);
1.1.1.11 root 1465: write_log ("Reducing memory sizes, especially chipmem, may fix this problem\n");
1.1.1.9 root 1466: abort ();
1467: }
1.1.1.3 root 1468:
1469: if (start >= 0x100) {
1.1.1.10 root 1470: int real_left = 0;
1.1.1.9 root 1471: for (bnr = start; bnr < start + size; bnr++) {
1472: if (!real_left) {
1473: realstart = bnr;
1.1.1.12 root 1474: real_left = realsize >> 16;
1.1.1.9 root 1475: #ifdef NATMEM_OFFSET
1476: add_shmmaps (realstart << 16, bank);
1477: #endif
1478: }
1.1.1.12 root 1479: put_mem_bank (bnr << 16, bank, realstart << 16);
1.1.1.9 root 1480: real_left--;
1481: }
1.1.1.3 root 1482: return;
1483: }
1.1.1.10 root 1484: if (currprefs.address_space_24)
1485: endhioffs = 0x10000;
1.1.1.9 root 1486: for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) {
1.1.1.10 root 1487: int real_left = 0;
1.1.1.12 root 1488: for (bnr = start; bnr < start + size; bnr++) {
1.1.1.9 root 1489: if (!real_left) {
1490: realstart = bnr + hioffs;
1491: real_left = realsize >> 16;
1492: #ifdef NATMEM_OFFSET
1493: add_shmmaps (realstart << 16, bank);
1494: #endif
1495: }
1.1.1.12 root 1496: put_mem_bank ((bnr + hioffs) << 16, bank, realstart << 16);
1.1.1.9 root 1497: real_left--;
1498: }
1499: }
1500: }
1501:
1502:
1503: /* memory save/restore code */
1504:
1505: uae_u8 *save_cram (int *len)
1506: {
1507: *len = allocated_chipmem;
1508: return chipmemory;
1509: }
1510:
1511: uae_u8 *save_bram (int *len)
1512: {
1513: *len = allocated_bogomem;
1514: return bogomemory;
1515: }
1516:
1517: void restore_cram (int len, long filepos)
1518: {
1519: chip_filepos = filepos;
1520: changed_prefs.chipmem_size = len;
1521: }
1522:
1523: void restore_bram (int len, long filepos)
1524: {
1525: bogo_filepos = filepos;
1526: changed_prefs.bogomem_size = len;
1527: }
1528:
1529: uae_u8 *restore_rom (uae_u8 *src)
1530: {
1.1.1.15! root 1531: uae_u32 crc32;
! 1532: int i;
! 1533:
1.1.1.9 root 1534: restore_u32 ();
1535: restore_u32 ();
1536: restore_u32 ();
1537: restore_u32 ();
1.1.1.15! root 1538: crc32 = restore_u32 ();
! 1539:
! 1540: for (i = 0; i < romlist_cnt; i++) {
! 1541: if (rl[i].rd->crc32 == crc32 && crc32) {
! 1542: strncpy (changed_prefs.romfile, rl[i].path, 255);
! 1543: break;
! 1544: }
! 1545: }
1.1.1.9 root 1546:
1547: return src;
1548: }
1549:
1.1.1.15! root 1550: uae_u8 *save_rom (int first, int *len, uae_u8 *dstptr)
1.1.1.9 root 1551: {
1552: static int count;
1553: uae_u8 *dst, *dstbak;
1554: uae_u8 *mem_real_start;
1555: int mem_start, mem_size, mem_type, i, saverom;
1556:
1557: saverom = 0;
1.1.1.12 root 1558: if (first)
1559: count = 0;
1.1.1.9 root 1560: for (;;) {
1561: mem_type = count;
1.1.1.12 root 1562: switch (count) {
1563: case 0: /* Kickstart ROM */
1.1.1.9 root 1564: mem_start = 0xf80000;
1565: mem_real_start = kickmemory;
1566: mem_size = kickmem_size;
1567: /* 256KB or 512KB ROM? */
1.1.1.12 root 1568: for (i = 0; i < mem_size / 2 - 4; i++) {
1569: if (longget (i + mem_start) != longget (i + mem_start + mem_size / 2))
1570: break;
1.1.1.9 root 1571: }
1.1.1.12 root 1572: if (i == mem_size / 2 - 4) {
1.1.1.9 root 1573: mem_size /= 2;
1574: mem_start += 262144;
1575: }
1576: mem_type = 0;
1577: break;
1.1.1.12 root 1578: default:
1.1.1.9 root 1579: return 0;
1580: }
1.1.1.12 root 1581: count++;
1582: if (mem_size)
1583: break;
1.1.1.9 root 1584: }
1.1.1.15! root 1585: if (dstptr)
! 1586: dstbak = dst = dstptr;
! 1587: else
! 1588: dstbak = dst = malloc (4 + 4 + 4 + 4 + 4 + mem_size);
1.1.1.9 root 1589: save_u32 (mem_start);
1590: save_u32 (mem_size);
1591: save_u32 (mem_type);
1.1.1.12 root 1592: save_u32 (longget (mem_start + 12)); /* version+revision */
1.1.1.15! root 1593: save_u32 (get_crc32 (kickmemory, mem_size));
1.1.1.12 root 1594: sprintf (dst, "Kickstart %d.%d", wordget (mem_start + 12), wordget (mem_start + 14));
1.1.1.9 root 1595: dst += strlen (dst) + 1;
1596: if (saverom) {
1.1.1.12 root 1597: for (i = 0; i < mem_size; i++)
1598: *dst++ = byteget (mem_start + i);
1.1.1.9 root 1599: }
1600: *len = dst - dstbak;
1601: return dstbak;
1.1 root 1602: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.