1 /* Object file conversion utility for Challenger 1P
3 by Stephan Muehlstrasser
23 static void Usage (void)
26 "Usage: %s [options] file\n"
28 " -V\t\t\tPrint the version number\n"
29 " -h\t\t\tHelp (this text)\n"
30 " -o name\t\tName the C1P output file (default: <input.c1p>)\n"
31 " -S addr\t\tLoad address (default 0x400)\n"
34 " --help\t\tHelp (this text)\n"
35 " --version\t\tPrint the version number\n",
39 static void OptHelp (const char* Opt attribute ((unused)),
40 const char* Arg attribute ((unused)))
41 /* Print usage information and exit */
48 static void OptVersion (const char* Opt attribute ((unused)),
49 const char* Arg attribute ((unused)))
50 /* Print the program version */
52 fprintf (stderr, "grc65 V%s\n", GetVersionAsString ());
56 static unsigned long CvtNumber (const char* Arg, const char* Number)
57 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
58 * numbers. Duplicated from ld65's main.c.
67 Converted = sscanf (Number, "%lx", &Val);
69 Converted = sscanf (Number, "%li", (long*)&Val);
72 /* Check if we do really have a number */
74 AbEnd ("Invalid number given in argument: %s\n", Arg);
77 /* Return the result */
81 /* Commands of C1P PROM monitor */
82 #define ADDRESS_MODE_CMD '.'
83 #define DATA_MODE_CMD '/'
84 #define EXECUTE_CMD 'G'
86 /* Transform the cc65 executable binary into a series of
87 commands that make the C1P PROM monitor load the bytes
90 static void Transform (unsigned long StartAddress, FILE *In, FILE *Out)
93 unsigned long CurrentAddress;
95 /* Loop over all input bytes, position to current address,
96 switch to data mod, output input byte
98 for (CurrentAddress = StartAddress, c = getc(In);
100 c = getc(In), CurrentAddress += 1) {
101 fprintf (Out, "%c%04.4X%c%02.2X",
102 ADDRESS_MODE_CMD, (unsigned int) CurrentAddress & 0xFFFF,
103 DATA_MODE_CMD, (unsigned int) c & 0xFF);
107 fprintf (Out, "%c%04.4x%c",
108 ADDRESS_MODE_CMD, (unsigned int) StartAddress & 0xFFFF,
113 /* Default suffix for C1P object file */
114 #define C1P_SUFFIX ".c1p"
116 int main (int argc, char *argv[])
118 /* Program long options */
119 static const LongOpt OptTab[] = {
120 { "--help", 0, OptHelp},
121 { "--version", 0, OptVersion},
124 /* Initialize input and output file name */
125 const char* InputFile = 0;
126 const char* OutputFile = 0;
127 char *GeneratedOutputFile = 0;
129 /* Initialize file pointers */
130 FILE *InputFileFp = 0;
131 FILE *OutputFileFp = 0;
133 /* Initialize with default start address defined in c1p.cfg */
134 unsigned long StartAddr = 0x400;
138 /* Initialize the cmdline module */
139 InitCmdLine (&argc, &argv, "c1p65");
141 /* Check the parameters */
143 while (I < ArgCount) {
145 /* Get the argument */
146 const char* Arg = ArgVec [I];
148 /* Check for an option */
153 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
157 OutputFile = GetArg (&I, 2);
161 StartAddr = CvtNumber (Arg, GetArg (&I, 2));
179 fprintf (stderr, "additional file specs ignored\n");
189 if (!InputFile) AbEnd ("No input file");
192 const size_t len = strlen(InputFile) + sizeof(C1P_SUFFIX);
194 GeneratedOutputFile = (char *) xmalloc(len);
195 sprintf(GeneratedOutputFile, "%s%s", InputFile, C1P_SUFFIX);
196 OutputFile = GeneratedOutputFile;
199 /* Open input and output files */
200 InputFileFp = fopen(InputFile, "rb");
201 if (!InputFileFp) AbEnd ("Unable to open input file");
203 OutputFileFp = fopen(OutputFile, "wb");
204 if (!OutputFileFp) AbEnd ("Unable to open output file");
206 /* Generate object file */
207 Transform (StartAddr, InputFileFp, OutputFileFp);
210 if (fclose(InputFileFp) == EOF) AbEnd ("Error closing input file");
212 if (fclose(OutputFileFp) == EOF) AbEnd ("Error closing output file");
214 if (GeneratedOutputFile) {
215 xfree(GeneratedOutputFile);