]> git.sur5r.net Git - cc65/blob - src/c1p65/main.c
Enter bytes in a loop in data mode
[cc65] / src / c1p65 / main.c
1 /* Object file conversion utility for Challenger 1P\r
2 \r
3    by Stephan Muehlstrasser\r
4 */\r
5 \r
6 \r
7 #include <stdio.h>\r
8 #include <stdlib.h>\r
9 #include <stdarg.h>\r
10 #include <string.h>\r
11 #include <errno.h>\r
12 #include <time.h>\r
13 \r
14 /* common stuff */\r
15 #include "abend.h"\r
16 #include "cmdline.h"\r
17 #include "fname.h"\r
18 #include "chartype.h"\r
19 #include "target.h"\r
20 #include "version.h"\r
21 #include "xmalloc.h"\r
22 \r
23 static void Usage (void)\r
24 {\r
25     printf (\r
26         "Usage: %s [options] file\n"\r
27         "Short options:\n"\r
28         "  -V\t\t\tPrint the version number\n"\r
29         "  -h\t\t\tHelp (this text)\n"\r
30                 "  -o name\t\tName the C1P output file (default: <input.c1p>)\n"\r
31                 "  -S addr\t\tLoad address (default 0x400)\n"\r
32         "\n"\r
33         "Long options:\n"\r
34         "  --help\t\tHelp (this text)\n"\r
35         "  --version\t\tPrint the version number\n",\r
36         ProgName);\r
37 }\r
38 \r
39 static void OptHelp (const char* Opt attribute ((unused)),\r
40                      const char* Arg attribute ((unused)))\r
41 /* Print usage information and exit */\r
42 {\r
43     Usage ();\r
44     exit (EXIT_SUCCESS);\r
45 }\r
46 \r
47 \r
48 static void OptVersion (const char* Opt attribute ((unused)),\r
49                         const char* Arg attribute ((unused)))\r
50 /* Print the program version */\r
51 {\r
52     fprintf (stderr, "grc65 V%s\n", GetVersionAsString ());\r
53 }\r
54 \r
55 \r
56 static unsigned long CvtNumber (const char* Arg, const char* Number)\r
57 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex\r
58  * numbers. Duplicated from ld65's main.c.\r
59  */\r
60 {\r
61     unsigned long Val;\r
62     int           Converted;\r
63 \r
64     /* Convert */\r
65     if (*Number == '$') {\r
66         ++Number;\r
67         Converted = sscanf (Number, "%lx", &Val);\r
68     } else {\r
69         Converted = sscanf (Number, "%li", (long*)&Val);\r
70     }\r
71 \r
72     /* Check if we do really have a number */\r
73     if (Converted != 1) {\r
74         AbEnd ("Invalid number given in argument: %s\n", Arg);\r
75     }\r
76 \r
77     /* Return the result */\r
78     return Val;\r
79 }\r
80 \r
81 /* Commands of C1P PROM monitor */\r
82 #define ADDRESS_MODE_CMD     '.'\r
83 #define DATA_MODE_CMD        '/'\r
84 #define EXECUTE_CMD          'G'\r
85 #define DATA_MODE_ADDRESS       0x00FB\r
86 \r
87 /* Transform the cc65 executable binary into a series of\r
88    commands that make the C1P PROM monitor load the bytes\r
89    into memory.\r
90 */\r
91 static void Transform (unsigned long StartAddress, FILE *In, FILE *Out)\r
92 {\r
93         int c;\r
94 \r
95         /* Position to the start address */\r
96         fprintf(Out, "%c%04.4X%c", ADDRESS_MODE_CMD,\r
97                 StartAddress & 0xFFFF, DATA_MODE_CMD);\r
98 \r
99         /* Loop over all input bytes and enter them one by one */\r
100         for (c = getc(In); c != EOF; c = getc(In)) {\r
101                 fprintf(Out, "%02.2X\n", (unsigned int) c & 0xFF);\r
102         }\r
103 \r
104         /* Store 00 to 0x00FB to enable keyboard input at the end */\r
105         fprintf(Out, "%c%04.4X%c%02.2X\n", ADDRESS_MODE_CMD,\r
106                 0x00FB, DATA_MODE_CMD, 0x00);\r
107 \r
108         /* And execute\r
109         fprintf (Out, "%c%04.4x%c",\r
110                         ADDRESS_MODE_CMD, (unsigned int) StartAddress & 0xFFFF,\r
111                         EXECUTE_CMD);\r
112                          */\r
113\r
114 \r
115 /* Default suffix for C1P object file */\r
116 #define C1P_SUFFIX ".c1p"\r
117 \r
118 int main (int argc, char *argv[])\r
119 {\r
120     /* Program long options */\r
121     static const LongOpt OptTab[] = {\r
122         { "--help",    0, OptHelp},\r
123         { "--version", 0, OptVersion},\r
124     };\r
125 \r
126         /* Initialize input and output file name */\r
127     const char* InputFile = 0;\r
128     const char* OutputFile = 0;\r
129         char *GeneratedOutputFile = 0;\r
130 \r
131         /* Initialize file pointers */\r
132         FILE *InputFileFp = 0;\r
133         FILE *OutputFileFp = 0;\r
134 \r
135         /* Initialize with default start address defined in c1p.cfg */\r
136         unsigned long StartAddr = 0x400;\r
137 \r
138     unsigned int I;\r
139 \r
140     /* Initialize the cmdline module */\r
141     InitCmdLine (&argc, &argv, "c1p65");\r
142 \r
143     /* Check the parameters */\r
144     I = 1;\r
145     while (I < ArgCount) {\r
146 \r
147         /* Get the argument */\r
148         const char* Arg = ArgVec [I];\r
149 \r
150         /* Check for an option */\r
151         if (Arg[0] == '-') {\r
152             switch (Arg[1]) {\r
153 \r
154                 case '-':\r
155                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));\r
156                     break;\r
157 \r
158                 case 'o':\r
159                     OutputFile = GetArg (&I, 2);\r
160                     break;\r
161 \r
162                 case 'S':\r
163                     StartAddr = CvtNumber (Arg, GetArg (&I, 2));\r
164                     break;\r
165 \r
166                 case 'h':\r
167                 case '?':\r
168                     OptHelp (Arg, 0);\r
169                     break;\r
170 \r
171                 case 'V':\r
172                     OptVersion (Arg, 0);\r
173                     break;\r
174 \r
175                 default:\r
176                     UnknownOption (Arg);\r
177             }\r
178 \r
179         } else {\r
180             if (InputFile) {\r
181                 fprintf (stderr, "additional file specs ignored\n");\r
182             } else {\r
183                 InputFile = Arg;\r
184             }\r
185         }\r
186 \r
187         /* Next argument */\r
188         ++I;\r
189     }\r
190 \r
191     if (!InputFile) AbEnd ("No input file");\r
192 \r
193         if (!OutputFile) {\r
194                 const size_t len = strlen(InputFile) + sizeof(C1P_SUFFIX);\r
195                 \r
196                 GeneratedOutputFile = (char *) xmalloc(len);\r
197                 sprintf(GeneratedOutputFile, "%s%s", InputFile, C1P_SUFFIX);\r
198                 OutputFile = GeneratedOutputFile;\r
199         }\r
200 \r
201         /* Open input and output files */\r
202         InputFileFp = fopen(InputFile, "rb");\r
203         if (!InputFileFp) AbEnd ("Unable to open input file");\r
204 \r
205         OutputFileFp = fopen(OutputFile, "wb");\r
206         if (!OutputFileFp) AbEnd ("Unable to open output file");\r
207 \r
208         /* Generate object file */\r
209         Transform (StartAddr, InputFileFp, OutputFileFp);\r
210 \r
211         /* Cleanup */\r
212         if (fclose(InputFileFp) == EOF) AbEnd ("Error closing input file");\r
213 \r
214         if (fclose(OutputFileFp) == EOF) AbEnd ("Error closing output file");\r
215 \r
216         if (GeneratedOutputFile) {\r
217                 xfree(GeneratedOutputFile);\r
218         }\r
219 \r
220     return EXIT_SUCCESS;\r
221 }\r