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