1/*****************************************************************************/
2/* */
3/* main.c */
4/* */
5/* sim65 main program */
6/* */
7/* */
8/* */
9/* (C) 2002-2009, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <string.h>
37#include <stdlib.h>
38#include <errno.h>
39
40/* common */
41#include "abend.h"
42#include "cmdline.h"
43#include "print.h"
44#include "version.h"
45
46/* sim65 */
47#include "6502.h"
48#include "error.h"
49#include "memory.h"
50#include "paravirt.h"
51
52
53
54/*****************************************************************************/
55/* Data */
56/*****************************************************************************/
57
58
59
60/* Name of program file */
61const char* ProgramFile;
62
63/* exit simulator after MaxCycles Cycles */
64unsigned long MaxCycles;
65
66/* Header signature 'sim65' */
67static const unsigned char HeaderSignature[] = {
68 0x73, 0x69, 0x6D, 0x36, 0x35
69};
70#define HEADER_SIGNATURE_LENGTH (sizeof(HeaderSignature)/sizeof(HeaderSignature[0]))
71
72static const unsigned char HeaderVersion = 2;
73
74
75
76/*****************************************************************************/
77/* Code */
78/*****************************************************************************/
79
80
81
82static void Usage (void)
83{
84 printf ("Usage: %s [options] file [arguments]\n"
85 "Short options:\n"
86 " -h\t\t\tHelp (this text)\n"
87 " -c\t\t\tPrint amount of executed CPU cycles\n"
88 " -v\t\t\tIncrease verbosity\n"
89 " -V\t\t\tPrint the simulator version number\n"
90 " -x <num>\t\tExit simulator after <num> cycles\n"
91 "\n"
92 "Long options:\n"
93 " --help\t\tHelp (this text)\n"
94 " --cycles\t\tPrint amount of executed CPU cycles\n"
95 " --verbose\t\tIncrease verbosity\n"
96 " --version\t\tPrint the simulator version number\n",
97 ProgName);
98}
99
100
101
102static void OptHelp (const char* Opt attribute ((unused)),
103 const char* Arg attribute ((unused)))
104/* Print usage information and exit */
105{
106 Usage ();
107 exit (EXIT_SUCCESS);
108}
109
110
111
112static void OptVerbose (const char* Opt attribute ((unused)),
113 const char* Arg attribute ((unused)))
114/* Increase verbosity */
115{
116 ++Verbosity;
117}
118
119
120
121static void OptCycles (const char* Opt attribute ((unused)),
122 const char* Arg attribute ((unused)))
123/* Set flag to print amount of cycles at the end */
124{
125 PrintCycles = 1;
126}
127
128
129
130static void OptVersion (const char* Opt attribute ((unused)),
131 const char* Arg attribute ((unused)))
132/* Print the simulator version */
133{
134 fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
135 exit(EXIT_SUCCESS);
136}
137
138static void OptQuitXIns (const char* Opt attribute ((unused)),
139 const char* Arg attribute ((unused)))
140/* quit after MaxCycles cycles */
141{
142 MaxCycles = strtoul(Arg, NULL, 0);
143}
144
145static unsigned char ReadProgramFile (void)
146/* Load program into memory */
147{
148 unsigned I;
149 int Val, Val2;
150 int Version;
151 unsigned Addr;
152 unsigned Load, Reset;
153 unsigned char SPAddr = 0x00;
154
155 /* Open the file */
156 FILE* F = fopen (ProgramFile, "rb");
157 if (F == 0) {
158 Error ("Cannot open '%s': %s", ProgramFile, strerror (errno));
159 }
160
161 /* Verify the header signature */
162 for (I = 0; I < HEADER_SIGNATURE_LENGTH; ++I) {
163 if ((Val = fgetc(F)) != HeaderSignature[I]) {
164 Error ("'%s': Invalid header signature.", ProgramFile);
165 }
166 }
167
168 /* Get header version */
169 if ((Version = fgetc(F)) != HeaderVersion) {
170 Error ("'%s': Invalid header version.", ProgramFile);
171 }
172
173 /* Get the CPU type from the file header */
174 if ((Val = fgetc(F)) != EOF) {
175 if (Val != CPU_6502 && Val != CPU_65C02) {
176 Error ("'%s': Invalid CPU type", ProgramFile);
177 }
178 CPU = Val;
179 }
180
181 /* Get the address of sp from the file header */
182 if ((Val = fgetc(F)) != EOF) {
183 SPAddr = Val;
184 }
185
186 /* Get load address */
187 if (((Val = fgetc(F)) == EOF) ||
188 ((Val2 = fgetc(F)) == EOF)) {
189 Error ("'%s': Header missing load address", ProgramFile);
190 }
191 Load = Val | (Val2 << 8);
192
193 /* Get reset address */
194 if (((Val = fgetc(F)) == EOF) ||
195 ((Val2 = fgetc(F)) == EOF)) {
196 Error ("'%s': Header missing reset address", ProgramFile);
197 }
198 Reset = Val | (Val2 << 8);
199
200 /* Read the file body into memory */
201 Addr = Load;
202 while ((Val = fgetc(F)) != EOF) {
203 if (Addr >= PARAVIRT_BASE) {
204 Error ("'%s': To large to fit into $%04X-$%04X", ProgramFile, Addr, PARAVIRT_BASE);
205 }
206 MemWriteByte (Addr++, (unsigned char) Val);
207 }
208
209 /* Check for errors */
210 if (ferror (F)) {
211 Error ("Error reading from '%s': %s", ProgramFile, strerror (errno));
212 }
213
214 /* Close the file */
215 fclose (F);
216
217 Print (stderr, 1, "Loaded '%s' at $%04X-$%04X\n", ProgramFile, Load, Addr - 1);
218 Print (stderr, 1, "File version: %d\n", Version);
219 Print (stderr, 1, "Reset: $%04X\n", Reset);
220
221 MemWriteWord(0xFFFC, Reset);
222 return SPAddr;
223}
224
225
226
227int main (int argc, char* argv[])
228{
229 /* Program long options */
230 static const LongOpt OptTab[] = {
231 { "--help", 0, OptHelp },
232 { "--cycles", 0, OptCycles },
233 { "--verbose", 0, OptVerbose },
234 { "--version", 0, OptVersion },
235 };
236
237 unsigned I;
238 unsigned char SPAddr;
239
240 /* Initialize the cmdline module */
241 InitCmdLine (&argc, &argv, "sim65");
242
243 /* Parse the command line */
244 I = 1;
245 while (I < ArgCount) {
246
247 /* Get the argument */
248 const char* Arg = ArgVec[I];
249
250 /* Check for an option */
251 if (Arg [0] == '-') {
252
253 switch (Arg [1]) {
254
255 case '-':
256 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
257 break;
258
259 case 'h':
260 case '?':
261 OptHelp (Arg, 0);
262 break;
263
264 case 'c':
265 OptCycles (Arg, 0);
266 break;
267
268 case 'v':
269 OptVerbose (Arg, 0);
270 break;
271
272 case 'V':
273 OptVersion (Arg, 0);
274 break;
275
276 case 'x':
277 OptQuitXIns (Arg, GetArg (&I, 2));
278 break;
279
280 default:
281 UnknownOption (Arg);
282 break;
283 }
284 } else {
285 ProgramFile = Arg;
286 break;
287 }
288
289 /* Next argument */
290 ++I;
291 }
292
293 /* Do we have a program file? */
294 if (ProgramFile == 0) {
295 AbEnd ("No program file");
296 }
297
298 MemInit ();
299
300 SPAddr = ReadProgramFile ();
301
302 ParaVirtInit (I, SPAddr);
303
304 Reset ();
305
306 while (1) {
307 ExecuteInsn ();
308 if (MaxCycles && (GetCycles () >= MaxCycles)) {
309 ErrorCode (SIM65_ERROR_TIMEOUT, "Maximum number of cycles reached.");
310 }
311 }
312
313 /* Return an apropriate exit code */
314 return EXIT_SUCCESS;
315}
316