1 #include "config.h"
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 // Specification https://www.hvsc.c64.org/download/C64Music/DOCUMENTS/SID_file_format.txt
14
15 // typical run method
16 // dumpsid mysidfile.sid --color|iconv -f cp1252 -t utf8|less -r
17
18 #include "dumpsid_6502_dis.c"
19
20 //#define DEBUG_TODO 1
21
22 int usecolor = 0;
23
24 static char *FONT_RESET = "";
25 static char *FONT_BRIGHT_BLACK = "";
26 static char *FONT_BRIGHT_RED = "";
27 static char *FONT_BRIGHT_GREEN = "";
28 static char *FONT_BRIGHT_YELLOW = "";
29 static char *FONT_BRIGHT_BLUE = "";
30 static char *FONT_BRIGHT_PURPLE = "";
31 static char *FONT_BRIGHT_CYAN = "";
32
33 static unsigned char MOS65xx_memory[65536];
34 static unsigned char MOS65xx_flags[65536];
35 #define FLAG_CODE_DIRECT0 1
36 #define FLAG_CODE_DIRECT1 2
37 #define FLAG_CODE_DIRECT2 3
38 #define FLAG_CODE_DIRECT 7
39
40 #define FLAG_CODE_INDIRECT0 8
41 #define FLAG_CODE_INDIRECT1 16
42 #define FLAG_CODE_INDIRECT2 32
43 #define FLAG_CODE_INDIRECT 56
44
45
46 static void breakme (void)
47 {
48
49 }
50
_gda_sql_statement_begin_get_infos(void)51 static void DumpPrefix (unsigned char *mem, int len, int base, int baselen)
52 {
53 int i;
54 printf ("[%s%08x%s]%s", FONT_BRIGHT_BLUE, base, FONT_RESET, FONT_BRIGHT_PURPLE);
55 for (i=0; i < baselen; i++)
56 {
57 if (base+i >= len)
58 {
59 printf (" \?\?");
60 } else {
61 printf (" %02x", mem[base+i]);
62 }
63 }
64 switch (baselen)
65 {
66 case 2: printf ( "%s ", FONT_RESET); break;
67 case 1: printf ( "%s ", FONT_RESET); break;
68 case 0: printf ( "%s ", FONT_RESET); break;
69 default: printf ("%s\n ", FONT_RESET); break;
70 }
71 }
72
_gda_sql_statement_commit_get_infos(void)73 static int load_siddata (uint16_t *load, int ntsc, int PSID, unsigned char *buffer, int base, int length)
74 {
75 int targetlength;
76
77 MOS65xx_memory[0x02a6] = !ntsc;
78
79 printf ("[%sDATA%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
80
81 if (PSID)
82 {
83 // VIC = any number lower than 0x100 if speed flag is 0
84 if (ntsc)
85 {
86 //CIA1_timer_A = 0x4025;
87 // timer tune = 0x3ffb;
88 } else {
89 //CIA1_timer_A = 0x4295;
90 // timer tune = 0x5021;
91 }
92 /*
93 if (init and play) is smaller than 0xa000 bank = 0x37;
94 else if (init and play) is smaller than 0xd000 bank = 0x36;
95 else if (init and play) is larger or equal than 0xe000 bank = 0x35;
96 else bank = 0x34;
97 */
98 } else { /* if (RSID) */
99 //VIC = 0x137; but irq disabled
100 if (ntsc)
101 {
102 //CIA1_timer_A = 0x4025;
103 } else {
104 //CIA1_timer_A = 0x4295;
105 }
106 //CIA1_timer_A IRQ enabled
107 // init/play => bank = 0x37;
108 // if C64_BASIC is true, target song is written to 65xx_memory[0x30c] = song - 1;
109 }
110 if (*load == 0)
111 {
112 if ((base + 2) > length)
113 {
114 fprintf (stderr, "%sERROR: datalen > 2 - needed (to read out data target address) (%d + 2 > %d)%s\n", FONT_BRIGHT_RED, base, length, FONT_RESET);
115 return -1;
116 }
117 *load = (buffer[base+1]<<8) | buffer[base];
118 printf ("load ptr: 0x%04x # where in the memory space should this be loaded into\n",(int)*load);
119
120 base += 2;
121 }
122 if (base >= length)
123 {
124 fprintf (stderr, "%sERROR: no data to load%s\n", FONT_BRIGHT_RED, FONT_RESET);
125 return -1;
126 }
127
128 targetlength = length - base;
129 if ((targetlength + *load) >= 0x10000)
130 {
131 fprintf (stderr, "%sWARNING: data exceeds memory-space (data 0x%04x + length 0x%x > 0x10000)%s\n", FONT_BRIGHT_YELLOW, length-base, *load, FONT_RESET);
132 targetlength = 0x10000 - *load;
133 }
134 memcpy (MOS65xx_memory + *load, buffer + base, targetlength);
135
136 return 0;
137 }
138
_gda_sql_statement_rollback_savepoint_get_infos(void)139 static void pre_disassemble(uint16_t load, uint16_t init, uint16_t play)
140 {
141
142 uint16_t *todo_ptrs = malloc (sizeof (uint16_t *)*16);
143 int todo_n = 0;
144 int todo_size = 16;
145
146 //bzero (MOS65xx_flags, sizeof (MOS65xx_flags));
147
148 if (!load)
149 {
150 load = init;
151 }
152 if (!play)
153 {
154 play = init;
155 }
156
157 if (load)
158 {
159 todo_ptrs[todo_n++] = load;
160 }
161
162 if (play && (play != load))
163 {
164 todo_ptrs[todo_n++] = play;
165 }
166
167 while (todo_n)
168 {
169 char opcode[16];
170 char param1[16];
171 char param2[16];
172 char comment[32];
173 int length;
174 uint16_t ptr = todo_ptrs[0];
175 uint16_t alt_ptr;
176 int retval;
177
178 opcode[0] = 0;
179 param1[0] = 0;
180 param2[0] = 0;
181 comment[0] = 0;
182
183 if (MOS65xx_flags[ptr] & FLAG_CODE_DIRECT)
184 {
185 #ifdef DEBUG_TODO
186 fprintf (stderr, "pre-emptive remove, already scanned\n");
187 #endif
188 memmove (todo_ptrs, todo_ptrs+1, sizeof (todo_ptrs[0]) * (todo_n - 1));
189 todo_n--;
190 continue;
191 }
192
193 retval = disassemble (MOS65xx_memory, ptr, opcode, param1, param2, comment, &length, &alt_ptr);
194 if (retval != -2)
195 {
196 MOS65xx_flags[ptr] |= length; /* matches up with FLAG_CODE_DIRECT */
197 if (MOS65xx_flags[ptr] & FLAG_CODE_INDIRECT)
198 {
199 breakme();
200 }
201 if (length>1)
202 {
203 if (MOS65xx_flags[ptr+1] & FLAG_CODE_DIRECT)
204 {
205 breakme();
206 }
207 MOS65xx_flags[ptr+1] |= FLAG_CODE_INDIRECT0;
208 }
209 if (length>2)
210 {
211 if (MOS65xx_flags[ptr+2] & FLAG_CODE_DIRECT)
212 {
213 breakme();
214 }
215 MOS65xx_flags[ptr+2] |= FLAG_CODE_INDIRECT1;
216 }
217 if (length>3)
218 {
219 if (MOS65xx_flags[ptr+3] & FLAG_CODE_DIRECT)
220 {
221 breakme();
222 }
223 MOS65xx_flags[ptr+3] |= FLAG_CODE_INDIRECT2;
224 }
225 todo_ptrs[0] += length;
226
227 if ((retval == -1)||(retval == 2)||((todo_n > 1) && (todo_ptrs[0] == todo_ptrs[1])))
228 {
229 #ifdef DEBUG_TODO
230 fprintf (stderr, "removing todo[0], due to jump or duplication\n");
231 #endif
232 memmove (todo_ptrs, todo_ptrs+1, sizeof (todo_ptrs[0]) * (todo_n - 1));
233 todo_n--;
234 }
235
236 if (todo_n > 1)
237 {
238 /* did we overtake the queue? */
239 if (todo_ptrs[0] > todo_ptrs[1])
240 {
241 uint16_t temp = todo_ptrs[0];
242 todo_ptrs[0] = todo_ptrs[1];
243 todo_ptrs[1] = temp;
244
245 fprintf (stderr, "swapping todo[0] and todo[1]\n");
246 }
247 }
248 } else {
249 /* failed, remove from list */
250 #ifdef DEBUG_TODO
251 fprintf (stderr, "removing todo[0], due to failure of decoding 0x%02x\n", MOS65xx_memory[todo_ptrs[0]]);
252 #endif
253 memmove (todo_ptrs, todo_ptrs+1, sizeof (todo_ptrs[0]) * (todo_n - 1));
254 todo_n--;
255 }
256 if ((retval == 1) || (retval == 2))
257 {
258 if (MOS65xx_flags[alt_ptr] & FLAG_CODE_DIRECT)
259 {
260 #ifdef DEBUG_TODO
261 fprintf (stderr, "Not adding %d, already decoded\n", alt_ptr);
262 #endif
263 } else {
264 int i;
265 int skip = 0;
266 for (i=0;i<todo_n;i++)
267 {
268 if (todo_ptrs[i] == alt_ptr)
269 {
270 #ifdef DEBUG_TODO
271 fprintf (stderr, "Skipping injecting, already on list %04x\n", alt_ptr);
272 #endif
273 skip = 1;
274 break;
275 }
276 if (todo_ptrs[i] > alt_ptr)
277 {
278 break;
279 }
280 }
281 if (!skip)
282 {
283 if (todo_n == todo_size)
284 {
285 todo_size += 16;
286 todo_ptrs = realloc (todo_ptrs, sizeof (todo_ptrs[0]) * todo_size);
287 }
288 memmove (todo_ptrs + i + 1, todo_ptrs + i, (todo_n - i) * sizeof (todo_ptrs[0]));
289 todo_ptrs[i] = alt_ptr;
290 todo_n++;
291 #ifdef DEBUG_TODO
292 fprintf (stderr, "Injected todo[%d]=%04x\n", i, alt_ptr);
293 #endif
294 }
295 }
296 }
297
298 #ifdef DEBUG_TODO
299 {
300 int i;
301 for (i=0;i<todo_n;i++)
302 {
303 fprintf (stderr, "%s%04x", i?", ":"", todo_ptrs[i]);
304 }
305 fprintf (stderr, "\n");
306 }
307 #endif
308 }
309 free (todo_ptrs);
310 }
311
312 static void print_disassemble (void)
313 {
314 int prev = -1;
315 int prevprev = -1;
316 uint32_t ptr;
317
318 for (ptr=0; ptr < 0x10000;)
319 {
320 char opcode[16];
321 char param1[16];
322 char param2[16];
323 char comment[32];
324 int length;
325 uint16_t alt_ptr;
326
327 if ((length=(MOS65xx_flags[ptr] & FLAG_CODE_DIRECT)))
328 {
329 int j;
330
331 opcode[0] = 0;
332 param1[0] = 0;
333 param2[0] = 0;
334 comment[0] = 0;
335
336 disassemble (MOS65xx_memory, ptr, opcode, param1, param2, comment, &length, &alt_ptr);
337 switch (length)
338 {
339 case 1: printf ("%s%04x %s%02x __ __%s %s %s%s%s%s%s\n",
340 FONT_BRIGHT_BLUE,
341 ptr,
342 FONT_BRIGHT_PURPLE,
343 MOS65xx_memory[ptr],
344 FONT_RESET,
345 opcode, param1, param2[0]?", ":"", param2, comment[0]?" # ":"", comment); break;
346 case 2: printf ("%s%04x %s%02x %02x __%s %s %s%s%s%s%s\n",
347 FONT_BRIGHT_BLUE,
348 ptr,
349 FONT_BRIGHT_PURPLE,
350 MOS65xx_memory[ptr],
351 MOS65xx_memory[ptr+1],
352 FONT_RESET,
353 opcode, param1, param2[0]?", ":"", param2, comment[0]?" # ":"", comment); break;
354 case 3: printf ("%s%04x %s%02x %02x %02x%s %s %s%s%s%s%s\n",
355 FONT_BRIGHT_BLUE,
356 ptr,
357 FONT_BRIGHT_PURPLE,
358 MOS65xx_memory[ptr],
359 MOS65xx_memory[ptr+1],
360 MOS65xx_memory[ptr+2],
361 FONT_RESET,
362 opcode, param1, param2[0]?", ":"", param2, comment[0]?" # ":"", comment); break;
363 }
364
365 for (j=1; j < length; j++)
366 {
367 if (MOS65xx_flags[ptr+j] & FLAG_CODE_DIRECT)
368 {
369 printf ("%sANTI DISASSEMBLER DETECTED at PTR %s%04x%s\n", FONT_BRIGHT_RED, FONT_BRIGHT_BLUE, j + ptr, FONT_RESET);
370 }
371 }
372 ptr++;
373 prev = -1;
374 prevprev = -1;
375 } else if (MOS65xx_flags[ptr] & FLAG_CODE_INDIRECT)
376 {
377 ptr++;
378 } else {
379 if (!((MOS65xx_memory[ptr] == prev) && ((prev == 0x00) || (prev == 0xff))))
380 {
381 printf ("%s%04x %s%02x%s\n",
382 FONT_BRIGHT_BLUE,
383 ptr,
384 FONT_BRIGHT_PURPLE,
385 MOS65xx_memory[ptr],
386 FONT_RESET);
387 prev = MOS65xx_memory[ptr];
388 prevprev = -1;
389 } else {
390 if (prevprev < 0)
391 {
392 printf ("...\n");
393 prevprev = prev;
394 }
395 }
396
397 ptr++;
398 }
399 }
400
401 }
402
403 static int parse_sidfile (unsigned char *buffer, int length)
404 {
405 int i;
406 int PSID, RSID;
407 uint16_t version, data, load, init, play, songs;
408 uint32_t speeds;
409
410 int flags_C64BASIC = 0;
411 int flags_PlaySIDSpecific = 1;
412 int isNTSC = 1;
413
414 if (length < 0x76)
415 {
416 fprintf (stderr, "%sERROR: len < sizeof(FileHeader)%s\n", FONT_BRIGHT_RED, FONT_RESET);
417 return -1;
418 }
419
420 printf ("[%sHEADER%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
421
422 PSID = !memcmp (buffer, "PSID", 4);
423 RSID = !memcmp (buffer, "RSID", 4);
424 if (RSID || PSID)
425 {
426 DumpPrefix (buffer, length, 0, 4);
427 printf ("id: \"%c%c%c%c\" %sOK%s\n",
428 buffer[0], buffer[1], buffer[2], buffer[3], FONT_BRIGHT_GREEN, FONT_RESET);
429
430 DumpPrefix (buffer, length, 4, 2);
431 version = buffer[5] | (buffer[4]<<8);
432 if ((PSID && (version>=1) && (version<=4)) ||
433 (RSID && (version>=2) && (version<=4)))
434 {
435 printf("version: %d - %s OK%s\n", version, FONT_BRIGHT_GREEN, FONT_RESET);
436 } else {
437 printf("version: %s%d - Out of range%s\n", FONT_BRIGHT_RED, version, FONT_RESET);
438 }
439
440 if ((version >= 2) && (length >= 0x007c))
441 {
442 flags_C64BASIC = RSID && (buffer[0x76] & 0x02);
443 flags_PlaySIDSpecific = PSID && (buffer[0x76] & 0x02);
444 }
445
446 DumpPrefix (buffer, length, 6, 2);
447 data = buffer[7] | (buffer[8]<<8);
448 if ((version == 1) && (data != 0x0076))
449 {
450 printf ("data ptr: %s0x%04x - expected 0x0076%s\n", FONT_BRIGHT_RED, (int)data, FONT_RESET);
451 } else if ((version >= 2) && (version <= 4) && (data != 0x007c))
452 {
453 printf ("data ptr: %s0x%04x - expected 0x007c%s\n", FONT_BRIGHT_RED, (int)data, FONT_RESET);
454 } else {
455 printf ("data ptr: 0x%04x # where in this SID file is memory-dump located\n", (int)data);
456 }
457
458 DumpPrefix (buffer, length, 8, 2);
459 load = buffer[9] | (buffer[8]<<8);
460 if (RSID && load)
461 {
462 printf ("load ptr: %s0x%04x - expected 0x0000 (address is in the two first bytes of the memory-dump)%s\n", FONT_BRIGHT_RED, (int)load, FONT_RESET);
463 } else {
464 printf ("load ptr: 0x%04x # where in the memory space should this be loaded into (if value is 0x0000, ptr is stored as the two first bytes in the data-dump)\n", (int)load);
465 }
466
467 DumpPrefix (buffer, length, 10, 2);
468 init = buffer[11] | (buffer[10]<<8);
469 if (init && flags_C64BASIC)
470 {
471 printf ("init ptr: %s0x%04x - expected 0x0000 due to C64BASIC flag # where in the memory space is the init subroutine%s\n", FONT_BRIGHT_RED, (int)init, FONT_RESET);
472 } else if (!init)
473 {
474 printf ("init ptr: 0x%04x - same as load ptr # where in the memory space is the init subroutine\n", (int)init);
475 } else if (RSID && ((init < 0x07e8) || ((init >= 0xa000) && (init < 0xc000)) || (init >= 0xd000)))
476 {
477 printf ("init ptr: %s0x%04x - Out of range # where in the memory space is the init subroutine%s\n", FONT_BRIGHT_RED, (int)init, FONT_RESET);
478 } else {
479 printf ("init ptr: 0x%04x # where in the memory space is the init subroutine\n", (int)init);
480 }
481
482 DumpPrefix (buffer, length, 12, 2);
483 play = buffer[13] | (buffer[12]<<8);
484 if (RSID && play)
485 {
486 printf ("play ptr: %s0x%04x - RSID expects init function to install interrupt vectors # where in the memory space is the play subroutine%s\n", FONT_BRIGHT_RED, (int)play, FONT_RESET);
487 } else {
488 printf ("play ptr: 0x%04x # where in the memory space is the play subroutine (0x0000 means that init function installs interrupt vectors)\n", (int)play);
489 }
490
491 DumpPrefix (buffer, length, 14, 2);
492 songs = buffer[15] | (buffer[14]<<8);
493 if ((songs == 0) || (songs > 256))
494 {
495 printf ("songs: %s0x%04x - Out of range%s\n", FONT_BRIGHT_RED, (int)songs, FONT_RESET);
496 } else {
497 printf ("songs: 0x%04x\n", (int)songs);
498 }
499
500 DumpPrefix (buffer, length, 16, 2);
501 i = buffer[17] | (buffer[16]<<8);
502 if ((i < 1) || (i > songs))
503 {
504 printf ("default song: %s0x%04x - Out of range%s\n", FONT_BRIGHT_RED, i, FONT_RESET);
505 } else {
506 printf ("default song: %04x\n", i);
507 }
508
509 DumpPrefix (buffer, length, 18, 4);
510 speeds = buffer[21] | (buffer[20]<<8) | (buffer[19]<<16) | (buffer[18] << 24);
511 if (PSID)
512 {
513 printf ("speeds: 0x%08x\n", speeds);
514 for (i=0; i < songs; i++)
515 {
516 printf ("Song %d - %s\n", i+1,
517 (flags_PlaySIDSpecific?
518 (speeds & (i << (i%31)))
519 :
520 (i < 32)?speeds & (1 << i):(speeds & 0x8000000)
521 ) ? "Use VBLANK - 50Hz PAL / 60Hz NTSC" : "Use CIA 1 timer interrupt (default 60Hz)");
522 }
523 if (i<32)
524 {
525 for (;i<32;i++)
526 {
527 if (speeds & (1 << i))
528 {
529 printf ("%sSong %d specified???%s\n", FONT_BRIGHT_RED, i+1, FONT_RESET);
530 }
531 }
532 }
533 } else { /* if (RSID) */
534 if (speeds)
535 {
536 printf ("speeds: %s0x%08x - Expected 0x00000000 for RSID%s\n", FONT_BRIGHT_RED, speeds, FONT_RESET);
537 } else {
538 printf ("speeds: 0x%08x\n", speeds);
539 }
540 }
541
542 DumpPrefix (buffer, length, 0x16, 0x20);
543 printf ("Name: \"");
544 for (i=0; i < 0x20; i++)
545 {
546 if (!buffer[0x16+i])
547 break;
548 printf ("%c", (char)buffer[0x16+i]);
549 }
550 printf ("\"\n");
551
552 DumpPrefix (buffer, length, 0x36, 0x20);
553 printf ("Author: \"");
554 for (i=0; i < 0x20; i++)
555 {
556 if (!buffer[0x36+i])
557 break;
558 printf ("%c", (char)buffer[0x36+i]);
559 }
560 printf ("\"\n");
561
562 DumpPrefix (buffer, length, 0x56, 0x20);
563 printf ("Copyright/Released: \"");
564 for (i=0; i < 0x20; i++)
565 {
566 if (!buffer[0x56+i])
567 break;
568 printf ("%c", (char)buffer[0x56+i]);
569 }
570 printf ("\"\n");
571
572 if (version >= 2)
573 {
574 uint16_t flags;
575
576 if (length < 0x007c)
577 {
578 fprintf (stderr, "%sERROR: len < sizeof(FileHeaderExtended)%s\n", FONT_BRIGHT_RED, FONT_RESET);
579 return -1;
580 }
581
582 DumpPrefix (buffer, length, 0x76, 2);
583 flags = buffer[0x77] | (buffer[0x76]<<8);
584 printf ("flags: 0x%04x\n", (int)flags);
585 printf (" bit 0: %d - %s\n", !!(flags & 0x0001), (flags & 0x0001) ? "Compute!'s Sidplayer MUS data, music player must be merged" : "built-in music player");
586 if (!(flags & 0x0002))
587 {
588 printf (" bit 1: 0 - C64 compatible\n");
589 } else {
590 if (PSID)
591 {
592 printf (" bit 1: 1 - PlaySID specific file / playback on C64 will have samples played wrong\n");
593 } else { /* if (RSID) */
594 printf (" bit 1: 1 - C64 BASIC (must be available)\n");
595 }
596 }
597 switch (flags & 0x000c) /* only PSID ?? */
598 {
599 case 0x0000: printf (" bit 2-3: 00 - Video Standard: Unknown\n"); break;
600 case 0x0004: printf (" bit 2-3: 01 - Video Standard: PAL\n"); isNTSC = 0; break;
601 case 0x0008: printf (" bit 2-3: 10 - Video Standard: NTSC only\n"); break;
602 case 0x000c: printf (" bit 2-3: 11 - Video Standard: PAL and NTSC\n"); break;
603 }
604 switch (flags & 0x0030)
605 {
606 case 0x0000: printf (" bit 4-5: 00 - sidModel position 1: Unknown\n"); break;
607 case 0x0010: printf (" bit 4-5: 01 - sidModel position 1: MOS6581\n"); break;
608 case 0x0020: printf (" bit 4-5: 10 - sidModel position 1: MOS8580\n"); break;
609 case 0x0030: printf (" bit 4-5: 11 - sidModel position 1: MOS6581 and MOS8580\n"); break;
610 }
611
612 if (version >= 3)
613 {
614 switch (flags & 0x00c0)
615 {
616 case 0x0000: printf (" bit 6-7: 00 - sidModel position 2: Same as position 1\n"); break;
617 case 0x0040: printf (" bit 6-7: 01 - sidModel position 2: MOS6581\n"); break;
618 case 0x0080: printf (" bit 6-7: 10 - sidModel position 2: MOS8580\n"); break;
619 case 0x00c0: printf (" bit 6-7: 11 - sidModel position 2: MOS6581 and MOS8580\n"); break;
620 }
621 }
622 if (version >= 4)
623 {
624 switch (flags & 0x0300)
625 {
626 case 0x0000: printf (" bit 8-9: 00 - sidModel position 3: Same as position 2\n");
627 case 0x0100: printf (" bit 8-9: 01 - sidModel position 3: MOS6581\n"); break;
628 case 0x0200: printf (" bit 8-9: 10 - sidModel position 3: MOS8580\n"); break;
629 case 0x0300: printf (" bit 8-9: 11 - sidModel position 3: MOS6581 and MOS8580\n"); break;
630 }
631 }
632
633 /* PSID only ??? */
634 DumpPrefix (buffer, length, 0x78, 1);
635 printf ("startPage: 0x%02x\n", buffer[0x78]);
636 DumpPrefix (buffer, length, 0x79, 1);
637 printf ("pageOnly: 0x%02x\n", buffer[0x79]);
638 if (buffer[0x78] == 0x00)
639 {
640 printf (" SID file is clean, only occupies loaded area\n");
641 } else if (buffer[0x78] == 0xff)
642 {
643 printf (" SID file uses the entire memory-map, driver-relocation not possible\n");
644 } else {
645 printf (" free memory for driver-relocation at 0x%02x00-0x%02xff\n", buffer[0x78], buffer[0x78]+buffer[0x79]-1);
646 }
647
648 if (version >= 3) /* only RSID ?? */
649 {
650 DumpPrefix(buffer, length, 0x7a, 1);
651 printf ("secondSIDAddress: 0x%02x\n", buffer[0x7a]);
652 if (buffer[0x7a] == 0x00)
653 {
654 printf (" No second SID chip need to be installed ??\n");
655 } else if ((buffer[0x7a] & 0x01) && (!(((buffer[0x7a] >= 0x42) && (buffer[0x7a] <= 0x7f)) || ((buffer[0x7a] >= 0xe0) && (buffer[0x7a] <= 0xfe)))))
656 {
657 printf (" %sSecond SID is in invalid range: 0xD%02xx%s\n", FONT_BRIGHT_RED, buffer[0x7a], FONT_RESET);
658 } else {
659 printf (" Second SID should be in range: 0xD%02xx\n", buffer[0x7a]);
660 }
661 } else {
662 #warning we can add a zero-test here
663 }
664
665 if (version >= 4) /* only RSID ?? */
666 {
667 DumpPrefix(buffer, length, 0x7b, 1);
668 printf ("thirdSIDAddress: 0x%02x\n", buffer[0x7b]);
669 if (buffer[0x7b] == 0x00)
670 {
671 printf (" No third SID chip need to be installed ?? \n");
672 } else if ((buffer[0x7b] & 0x01) && (!(((buffer[0x7b] >= 0x42) && (buffer[0x7b] <= 0x7f)) || ((buffer[0x7b] >= 0xe0) && (buffer[0x7b] <= 0xfe)))))
673 {
674 printf (" %sThird SID is in invalid range: 0xD%02xx%s\n", FONT_BRIGHT_RED, buffer[0x7b], FONT_RESET);
675 } else {
676 printf (" Third SID should be in range: 0xD%02xx\n", buffer[0x7b]);
677 }
678 } else {
679 #warning we can add a zero-test here
680 }
681 }
682 if (load_siddata (&load, isNTSC, PSID, buffer, data, length))
683 {
684 return -1;
685 }
686 pre_disassemble (load, init, play);
687 print_disassemble ();
688 return 0;
689 } else {
690 #warning TODO
691 return -1;
692 }
693 }
694
695 int main (int argc, char *argv[])
696 {
697 int fd;
698 unsigned char *buffer = malloc (1024*1024); // way to big buffer
699 int length;
700 int c;
701 char *color = "auto";
702 int help = 0;
703
704 while (1)
705 {
706 int option_index = 0;
707 static struct option long_options[] =
708 {
709 {"color", optional_argument, 0, 0},
710 {"help", no_argument, 0, 'h'},
711 {0, 0, 0, 0}
712 };
713
714 c = getopt_long(argc, argv, "hsp", long_options, &option_index);
715 if (c == -1)
716 break;
717
718 switch (c)
719 {
720 case 0:
721 if (option_index == 0)
722 {
723 color = optarg;
724 }
725 break;
726 case 'h':
727 help = 1;
728 break;
729 case '?':
730 help = 3;
731 break;
732 default:
733 printf("?? getopt returned character code 0%o ??\n", c);
734 }
735 }
736
737 if (optind != (argc-1))
738 {
739 help = 4;
740 }
741
742 if (!color)
743 {
744 usecolor = 1;
745 } else if (!strcmp (color, "auto"))
746 {
747 usecolor = isatty ( 1 );
748 } else if ((strcmp (color, "never")) && (strcmp (color, "no")))
749 {
750 usecolor = 1;
751 } else {
752 usecolor = 0;
753 }
754
755 if (help)
756 {
757 fprintf (stderr, "Usage:\n%s [--color=auto/never/on] [--help] file.sid (%d)\n", argv[0], help);
758 return 1;
759 }
760
761 fd = open (argv[optind], O_RDONLY);
762 if (fd < 0)
763 {
764 fprintf (stderr, "open(%s) failed: %s\n", argv[1], strerror (errno));
765 return -1;
766 }
767
768 length = read (fd, buffer, 1024*1024);
769 if (length < 0)
770 {
771 fprintf (stderr, "read() failed: %s\n", strerror (errno));
772 free (buffer);
773 close (fd);
774 return -1;
775 }
776
777 close (fd);
778
779 if (usecolor)
780 {
781 FONT_RESET = "\033[0m";
782 FONT_BRIGHT_BLACK = "\033[30;1m";
783 FONT_BRIGHT_RED = "\033[31;1m";
784 FONT_BRIGHT_GREEN = "\033[32;1m";
785 FONT_BRIGHT_YELLOW = "\033[33;1m";
786 FONT_BRIGHT_BLUE = "\033[34;1m";
787 FONT_BRIGHT_PURPLE = "\033[35;1m";
788 FONT_BRIGHT_CYAN = "\033[36;1m";
789 }
790
791 parse_sidfile (buffer, length);
792
793 free (buffer);
794
795 return 0;
796 }
797