1 /** ADAMEm: Coleco ADAM emulator ********************************************/
2 /** **/
3 /** ADAMEm.c **/
4 /** **/
5 /** This file contains the main() function starting the emulator **/
6 /** **/
7 /** Copyright (C) Marcel de Kogel 1996,1997,1998,1999 **/
8 /** You are not allowed to distribute this software commercially **/
9 /** Please, notify me, if you make any changes to this file **/
10 /****************************************************************************/
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "Coleco.h"
17 #ifdef MSDOS
18 #include "MSDOS.h"
19 #include <sys/stat.h>
20 #include <conio.h>
21 #endif
22 #ifdef LINUX_SVGA
23 #include "SVGALib.h"
24 #endif
25 #ifdef UNIX_X
26 #include "X.h"
27 #endif
28 #include "Help.h"
29
30 /* Program title for -help output */
31 extern char Title[];
32
33 #define MAX_CONFIG_FILE_SIZE 1024
34 #define MAX_FILE_NAME 256
35
36 char *Options[]=
37 {
38 "verbose","help","cpuspeed","ifreq",
39 "cheat","video","sound","joystick","swapbuttons",
40 "expansion","calibrate","overscan","volume","soundtrack",
41 "trap","os7","sensitivity","reverb","chorus","uperiod",
42 "soundquality","speakerchannels","keys","printer","keypad",
43 "eos","wp","diska","diskb","diskc","diskd",
44 "tapea","tapeb","tapec","taped","sync","adam","cv","stereo",
45 "printertype","chipset","sprite","shm","savecpu","palette",
46 "ram","snap","autosnap","diskspeed","tapespeed","lpt","tdos",
47 NULL
48 };
49
50 char *AbvOptions[]=
51 {
52 "vb","he","cs","if",
53 "cheat","vi","so","js","sb",
54 "ex","ca","os","vo","st",
55 "trap","os7","se","re","ch","up",
56 "sq","sc","ke","pr","kp",
57 "eos","wp","da","db","dc","dd",
58 "ta","tb","tc","td","sy","adam","cv","stereo",
59 "pt","chipset","sprite","shm","savecpu","pal",
60 "ram","sn","asn","ds","ts","lpt","tdos",
61 NULL
62 };
63
64 #define PROGRAM_ADAMEM 0
65 #define PROGRAM_CVEM 1
66 static int Program;
67 static int CPUSpeed;
68 static int _argc;
69 static char *_argv[256];
70 static char MainConfigFile[MAX_CONFIG_FILE_SIZE];
71 static char SubConfigFile[MAX_CONFIG_FILE_SIZE];
72 static char szTempFileName[MAX_FILE_NAME];
73 static char _CartName[MAX_FILE_NAME];
74 static char CartNameNoExt[MAX_FILE_NAME];
75 static char _SnapshotName[MAX_FILE_NAME];
76 static char _OS7File[MAX_FILE_NAME];
77 static char _EOSFile[MAX_FILE_NAME];
78 static char _WPFile[MAX_FILE_NAME];
79 static char ProgramPath[MAX_FILE_NAME];
80 static char ProgramName[MAX_FILE_NAME];
81 static int CartNameSupplied=0;
82
83 #ifndef MSDOS
84 /* Get full path name, convert all backslashes to UNIX style slashes */
_fixpath(char * old,char * new)85 static void _fixpath (char *old,char *new)
86 {
87 strcpy (new,old);
88 }
89 #endif
90
91 #ifdef MSDOS
ParseSpeakerChannels(char * p)92 static void ParseSpeakerChannels (char *p)
93 {
94 int i,a;
95 memset (spk_channels,0,sizeof(spk_channels));
96 for (i=0;i<4&&p;++i)
97 {
98 a=atoi(p);
99 if (a<0 || a>4)
100 a=0;
101 spk_channels[i]=a;
102 p=strchr(p,',');
103 if (p)
104 {
105 *p='\0';
106 ++p;
107 }
108 }
109 }
110 #endif
111
ParseOptions(int argc,char * argv[])112 static int ParseOptions (int argc,char *argv[])
113 {
114 int N,I,J,tmp;
115 int misparm;
116 for(N=1,I=0;N<argc;N++)
117 {
118 misparm=0;
119 if(*argv[N]!='-')
120 switch(I++)
121 {
122 case 0: /* CartName=argv[N]; */
123 break;
124 default: printf("Excessive filename '%s'\n",argv[N]);
125 return 0;
126 }
127 else
128 {
129 for(J=0;Options[J];J++)
130 if(!strcmp(argv[N]+1,Options[J])) break;
131 if (!Options[J])
132 for(J=0;AbvOptions[J];J++)
133 if(!strcmp(argv[N]+1,AbvOptions[J])) break;
134 switch(J)
135 {
136 case 0: N++;
137 if(N<argc)
138 Verbose=atoi(argv[N]);
139 else
140 misparm=1;
141 break;
142 case 1: printf ("%s\n"
143 "Copyright (C) 1996 Marcel de Kogel\n"
144 "Usage: %s [-option1 [-option2...]] [filename]\n"
145 "[filename] = name of the file to load as a cartridge [CART.ROM]\n"
146 "[-option] =\n",Title,ProgramName);
147 tmp=5;
148 for(J=0;HelpText[J];J++)
149 {
150 if (HelpText[J][0]=='A')
151 {
152 if (Program==PROGRAM_ADAMEM)
153 {
154 puts (HelpText[J]+1);
155 ++tmp;
156 }
157 }
158 else if (HelpText[J][0]=='C')
159 {
160 if (Program==PROGRAM_CVEM)
161 {
162 puts (HelpText[J]+1);
163 ++tmp;
164 }
165 }
166 else
167 {
168 puts(HelpText[J]);
169 ++tmp;
170 }
171 #if defined(MSDOS) || defined(LINUX_SVGA)
172 if (tmp==24)
173 {
174 printf ("-- More --");
175 fflush (stdout);
176 #ifdef MSDOS
177 getch();
178 #else
179 fgetc (stdin);
180 #endif
181 fflush (stdin);
182 printf ("\n\n");
183 tmp=1;
184 }
185 #endif
186 }
187 return 0;
188 case 2: N++;
189 if(N<argc)
190 CPUSpeed=atoi(argv[N]);
191 else
192 misparm=1;
193 break;
194 case 3: N++;
195 if(N<argc)
196 IFreq=atoi(argv[N]);
197 else
198 misparm=1;
199 break;
200 case 13: N++;
201 if(N<argc)
202 {
203 #ifdef MSDOS
204 strcpy (szTempFileName,argv[N]);
205 strupr (szTempFileName);
206 if (!strcmp(szTempFileName,"NULL"))
207 SoundName=NULL;
208 else
209 #endif
210 SoundName=argv[N];
211 }
212 else
213 misparm=1;
214 break;
215 case 15: N++;
216 if(N<argc)
217 OS7File=argv[N];
218 else
219 misparm=1;
220 break;
221 case 19: N++;
222 if(N<argc)
223 UPeriod=atoi(argv[N]);
224 else
225 misparm=1;
226 break;
227 case 25: N++;
228 if(N<argc)
229 EOSFile=argv[N];
230 else
231 misparm=1;
232 break;
233 case 26: N++;
234 if(N<argc)
235 WPFile=argv[N];
236 else
237 misparm=1;
238 break;
239 case 27: case 28: case 29: case 30:
240 N++;
241 if(N<argc)
242 DiskName[J-27]=argv[N];
243 else
244 return 0;
245 break;
246 case 31: case 32: case 33: case 34:
247 N++;
248 if(N<argc)
249 TapeName[J-31]=argv[N];
250 else
251 return 0;
252 break;
253 case 23: N++;
254 if(N<argc)
255 PrnName=argv[N];
256 else
257 misparm=1;
258 break;
259 case 36: EmuMode=1;
260 break;
261 case 37: EmuMode=0;
262 break;
263 #ifdef SOUND
264 case 6: N++;
265 if(N<argc)
266 soundmode=atoi(argv[N]);
267 else
268 misparm=1;
269 break;
270 case 12: N++;
271 if(N<argc)
272 mastervolume=atoi(argv[N]);
273 else
274 misparm=1;
275 break;
276 case 20: N++;
277 if(N<argc)
278 soundquality=atoi(argv[N]);
279 else
280 misparm=1;
281 break;
282 case 38: N++;
283 if(N<argc)
284 panning=atoi(argv[N]);
285 else
286 misparm=1;
287 break;
288 case 17: N++;
289 if(N<argc)
290 reverb=atoi(argv[N]);
291 else
292 misparm=1;
293 break;
294 case 18: N++;
295 if(N<argc)
296 chorus=atoi(argv[N]);
297 else
298 misparm=1;
299 break;
300 #ifdef MSDOS
301 case 21: N++;
302 if(N<argc)
303 ParseSpeakerChannels(argv[N]);
304 else
305 misparm=1;
306 break;
307 #endif
308 #endif /* SOUND */
309 case 4: N++;
310 if(N<argc)
311 {
312 if (CheatCount<MAX_CHEATS)
313 Cheats[CheatCount++]=strtoul(argv[N],NULL,16);
314 else
315 printf ("WARNING: Maximum number of cheats (%d) reached\n",
316 MAX_CHEATS);
317 }
318 else
319 misparm=1;
320 break;
321 case 5: N++;
322 if(N<argc)
323 videomode=atoi(argv[N]);
324 else
325 misparm=1;
326 break;
327 #if defined(MSDOS) || defined(LINUX_SVGA)
328 case 11: N++;
329 if(N<argc)
330 useoverscan=atoi(argv[N]);
331 else
332 misparm=1;
333 break;
334 #endif
335 case 7: N++;
336 if(N<argc)
337 joystick=atoi(argv[N]);
338 else
339 misparm=1;
340 break;
341 case 8: N++;
342 if(N<argc)
343 swapbuttons=atoi(argv[N]);
344 else
345 misparm=1;
346 break;
347 case 9: N++;
348 if(N<argc)
349 expansionmode=atoi(argv[N]);
350 else
351 misparm=1;
352 break;
353 case 10: N++;
354 if(N<argc)
355 calibrate=atoi(argv[N]);
356 else
357 misparm=1;
358 break;
359 case 16: N++;
360 if(N<argc)
361 mouse_sens=atoi(argv[N]);
362 else
363 misparm=1;
364 break;
365 case 22: N++;
366 if(N<argc)
367 szKeys=argv[N];
368 else
369 misparm=1;
370 break;
371 case 24: N++;
372 if(N<argc)
373 keypadmode=atoi(argv[N]);
374 else
375 misparm=1;
376 break;
377 case 35: N++;
378 if(N<argc)
379 syncemu=atoi(argv[N]);
380 else
381 misparm=1;
382 break;
383 case 39: N++;
384 if(N<argc)
385 PrnType=atoi(argv[N]);
386 else
387 misparm=1;
388 break;
389 case 44: N++;
390 if(N<argc)
391 PalNum=atoi(argv[N]);
392 else
393 misparm=1;
394 break;
395 case 45: N++;
396 if(N<argc)
397 RAMPages=atoi(argv[N]);
398 else
399 misparm=1;
400 break;
401 case 46: N++;
402 if(N<argc)
403 SnapshotName=argv[N];
404 else
405 misparm=1;
406 break;
407 case 47: N++;
408 if(N<argc)
409 SaveSnapshot=atoi(argv[N]);
410 else
411 misparm=1;
412 break;
413 case 48: N++;
414 if(N<argc)
415 DiskSpeed=atoi(argv[N]);
416 else
417 misparm=1;
418 break;
419 case 49: N++;
420 if(N<argc)
421 TapeSpeed=atoi(argv[N]);
422 else
423 misparm=1;
424 break;
425 case 50: N++;
426 if(N<argc)
427 LPTName=argv[N];
428 else
429 misparm=1;
430 break;
431 #ifdef TEXT80
432 case 51: N++;
433 if(N<argc)
434 AutoText80=atoi(argv[N]);
435 else
436 misparm=1;
437 break;
438 #endif
439 #ifdef LINUX_SVGA
440 case 40: N++;
441 if(N<argc)
442 chipset=atoi(argv[N]);
443 else
444 misparm=1;
445 break;
446 #endif
447 case 41: N++;
448 if (N<argc)
449 Support5thSprite=atoi(argv[N]);
450 else
451 misparm=1;
452 break;
453 #ifdef UNIX_X
454 #ifdef MITSHM
455 case 42: N++;
456 if(N<argc)
457 UseSHM=atoi(argv[N]);
458 else
459 misparm=1;
460 break;
461 #endif
462 case 43: N++;
463 if(N<argc)
464 SaveCPU=atoi(argv[N]);
465 else
466 misparm=1;
467 break;
468 #endif
469 #ifdef DEBUG
470 case 14: N++;
471 if (!strcmp(argv[N],"now")) Z80_Trace=1;
472 else Z80_Trap=strtoul(argv[N],NULL,16);
473 break;
474 #endif
475 default: printf("Wrong option '%s'\n",argv[N]);
476 return 0;
477 }
478 if (misparm)
479 {
480 printf("%s: Missing parameter\n",argv[N-1]);
481 return 0;
482 }
483 }
484 }
485 return 1;
486 }
487
GetCartName(int argc,char * argv[])488 static int GetCartName (int argc,char *argv[])
489 {
490 int N,I,J,tmp;
491 for(N=1,I=0;N<argc;N++)
492 {
493 if(*argv[N]!='-')
494 switch(I++)
495 {
496 case 0: CartName=argv[N];
497 CartNameSupplied=1;
498 break;
499 default: return 0;
500 }
501 else
502 {
503 for(J=0;Options[J];J++)
504 if(!strcmp(argv[N]+1,Options[J])) break;
505 if (!Options[J])
506 for(J=0;AbvOptions[J];J++)
507 if(!strcmp(argv[N]+1,AbvOptions[J])) break;
508 switch(J)
509 {
510 case 1: return 0;
511 case 2: N++;
512 tmp=0;
513 if(N<argc)
514 tmp=atoi(argv[N]);
515 if (!tmp)
516 return 0;
517 break;
518 case 36: case 37:
519 break;
520 case 27: case 28: case 29: case 30:
521 N++;
522 if(N<argc)
523 DiskName[J-27]=argv[N];
524 else
525 return 0;
526 break;
527 case 31: case 32: case 33: case 34:
528 N++;
529 if(N<argc)
530 TapeName[J-31]=argv[N];
531 else
532 return 0;
533 break;
534 #if defined(MSDOS) || defined(LINUX_SVGA)
535 case 4: case 11:
536 #endif
537 #ifdef LINUX_SVGA
538 case 40:
539 #endif
540 #ifdef UNIX_X
541 #ifdef MITSHM
542 case 42:
543 #endif
544 case 43:
545 #endif
546 #ifdef SOUND
547 case 6: case 12: case 20:
548 case 38: case 17: case 18:
549 #ifdef MSDOS
550 case 21:
551 #endif
552 #endif
553 case 5: case 7: case 8: case 9: case 10:
554 case 16: case 22: case 24: case 35:
555 case 0: case 3: case 13: case 15: case 19:
556 case 23: case 25: case 26: case 39: case 41: case 44:
557 case 45: case 46: case 47: case 48: case 49: case 50:
558 #ifdef TEXT80
559 case 51:
560 #endif
561 #ifdef DEBUG
562 case 14:
563 #endif
564 N++;
565 if (N>=argc)
566 return 0;
567 break;
568 default: return 0;
569 }
570 }
571 }
572 return 1;
573 }
574
LoadConfigFile(char * szFileName,unsigned char * ptr)575 static void LoadConfigFile (char *szFileName,unsigned char *ptr)
576 {
577 FILE *infile;
578 infile=fopen (szFileName,"rb");
579 if (infile==NULL)
580 return;
581 fread (ptr,1,MAX_CONFIG_FILE_SIZE,infile);
582 fclose (infile);
583 while (*ptr)
584 {
585 while (*ptr && *ptr<=' ')
586 ++ptr;
587 if (*ptr)
588 {
589 _argv[_argc++]=ptr;
590 while (*ptr && *ptr>' ')
591 ++ptr;
592 if (*ptr)
593 *ptr++='\0';
594 }
595 }
596 }
597
FixFileNames(void)598 static void FixFileNames (void)
599 {
600 char *p=NULL,*q=NULL,*x=NULL;
601 int i;
602 CartNameNoExt[0]='\0';
603 if (!CartNameSupplied)
604 {
605 for (i=0;i<2;++i)
606 if (DiskName[i]) { _fixpath (DiskName[i],CartNameNoExt); break; }
607 if (CartNameNoExt[0]=='\0')
608 for (i=0;i<2;++i)
609 if (TapeName[i]) { _fixpath (TapeName[i],CartNameNoExt); break; }
610 }
611 if (CartNameNoExt[0]=='\0')
612 _fixpath (CartName,CartNameNoExt);
613 p=CartNameNoExt;
614 q=strchr(CartNameNoExt,'/');
615 while (q) /* get last '/' */
616 {
617 p=++q;
618 q=strchr(q,'/');
619 };
620 q=NULL;
621 while ((p=strchr(p,'.'))!=NULL) /* get last '.' */
622 {
623 q=p;
624 ++p;
625 }
626 if (q) /* remove extension */
627 *q='\0';
628
629 p=CartName;
630 q=strchr(CartName,'/'); if (!q) strchr(CartName,'\\');
631 while (q) /* get last '/' */
632 {
633 p=++q;
634 x=strchr(q,'/'); if (!x) x=strchr(q,'\\');
635 q=x;
636 };
637 q=NULL;
638 while ((p=strchr(p,'.'))!=NULL) /* get last '.' */
639 {
640 q=p;
641 ++p;
642 }
643 strcpy (_CartName,CartName);
644 if (!q)
645 strcat (_CartName,".rom");
646 CartName=_CartName;
647 }
648
FixROMPath(char ** file,char * storage)649 static void FixROMPath (char **file,char *storage)
650 {
651 char *p=NULL,*q=NULL;
652 if (!strchr(*file,'/') && !strchr(*file,'\\'))
653 { /* If no path is given, assume emulator path */
654 strcpy (storage,ProgramPath);
655 strcat (storage,*file);
656 }
657 else
658 {
659 _fixpath (*file,storage);
660 }
661 p=storage;
662 q=strchr(storage,'/');
663 while (q) /* get last '/' */
664 {
665 p=++q;
666 q=strchr(q,'/');
667 };
668 q=NULL;
669 while ((p=strchr(p,'.'))!=NULL) /* get last '.' */
670 {
671 q=p;
672 ++p;
673 }
674 if (!q) /* Default extension='.rom' */
675 strcat (storage,".rom");
676 *file=storage;
677 }
678
GetPath(char * szFullPath,char * szPath,char * szFile)679 static void GetPath (char *szFullPath,char *szPath,char *szFile)
680 {
681 char *p,*q;
682 strcpy (szPath,szFullPath);
683 p=szPath;
684 q=strchr(p,'/');
685 while (q) /* get last '/' */
686 {
687 p=++q;
688 q=strchr(q,'/');
689 };
690 if (szFile)
691 {
692 strcpy (szFile,p);
693 *p='\0'; /* remove filename */
694 p=szFile;
695 q=NULL;
696 while ((p=strchr(p,'.'))!=NULL) /* get last '.' */
697 {
698 q=p;
699 ++p;
700 }
701 if (q) *q='\0'; /* remove extension */
702 }
703 else
704 *p='\0'; /* remove filename */
705 }
706
main(int argc,char * argv[])707 int main (int argc,char *argv[])
708 {
709 Verbose=1;
710 CPUSpeed=100;
711 IFreq=50;
712 UPeriod=3;
713 CheatCount=0;
714 #ifdef MSDOS
715 PrnName=LPTName="PRN";
716 #endif
717 memset (MainConfigFile,0,sizeof(MainConfigFile));
718 memset (SubConfigFile,0,sizeof(SubConfigFile));
719 GetPath (argv[0],ProgramPath,ProgramName);
720 if (!strcmp(ProgramName,"cvem") || !strcmp(ProgramName,"cvemx"))
721 {
722 EmuMode=0;
723 Program=PROGRAM_CVEM;
724 }
725 else
726 {
727 EmuMode=1;
728 Program=PROGRAM_ADAMEM;
729 }
730 _argc=1;
731 _argv[0]=argv[0];
732 /* Load Config Files */
733 strcpy (szTempFileName,ProgramPath);
734 strcat (szTempFileName,ProgramName);
735 strcat (szTempFileName,".cfg");
736 strcpy (szJoystickFileName,ProgramPath);
737 strcat (szJoystickFileName,"adamem.joy");
738 #ifdef SOUND
739 strcpy (szSoundFileName,ProgramPath);
740 strcat (szSoundFileName,"/usr/local/share/adamem/adamem.snd");
741 #endif
742 LoadConfigFile (szTempFileName,MainConfigFile);
743 if (!ParseOptions(_argc,_argv))
744 return 1;
745 GetCartName (argc,argv);
746 FixFileNames ();
747 #if defined(MSDOS) || defined(LINUX_SVGA)
748 strcpy (szBitmapFile,CartNameNoExt);
749 strcat (szBitmapFile,".b00");
750 #endif
751 #if defined(MSDOS) || defined(LINUX_SVGA) || defined(UNIX_X)
752 strcpy (szSnapshotFile,CartNameNoExt);
753 strcat (szSnapshotFile,".s00");
754 #endif
755 strcpy (szTempFileName,CartNameNoExt);
756 strcat (szTempFileName,".cfg");
757 _argc=1;
758 LoadConfigFile (szTempFileName,SubConfigFile);
759 if (!ParseOptions(_argc,_argv))
760 return 1;
761 if (!ParseOptions(argc,argv))
762 return 1;
763 if (SaveSnapshot && !SnapshotName)
764 {
765 strcpy (_SnapshotName,CartNameNoExt);
766 strcat (_SnapshotName,".snp");
767 SnapshotName=_SnapshotName;
768 }
769 FixROMPath (&OS7File,_OS7File);
770 FixROMPath (&EOSFile,_EOSFile);
771 FixROMPath (&WPFile,_WPFile);
772 if (!UPeriod) UPeriod=3;
773 if (UPeriod>10) UPeriod=10;
774 if (IFreq<10) IFreq=10;
775 if (IFreq>200) IFreq=200;
776 if (CPUSpeed>1000) CPUSpeed=1000;
777 if (CPUSpeed<10) CPUSpeed=10;
778 Z80_IPeriod=(3579545*CPUSpeed)/(100*1000);
779 if (PalNum<0) PalNum=0;
780 if (PalNum>=NR_PALETTES) PalNum=NR_PALETTES-1;
781 #ifndef MSDOS
782 if (!InitMachine()) return 0;
783 #endif
784 StartColeco();
785 TrashColeco();
786 #ifndef MSDOS
787 TrashMachine ();
788 #endif
789 return 0;
790 }
791
792