2002-03-30 16:43:27 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
2013-05-09 11:56:54 +00:00
|
|
|
/* main.c */
|
2002-03-30 16:43:27 +00:00
|
|
|
/* */
|
|
|
|
/* sim65 main program */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
2009-09-28 20:10:01 +00:00
|
|
|
/* (C) 2002-2009, Ullrich von Bassewitz */
|
|
|
|
/* Roemerstrasse 52 */
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
2002-03-30 16:43:27 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
/* */
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
/* */
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
/* distribution. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
/* common */
|
|
|
|
#include "abend.h"
|
|
|
|
#include "cmdline.h"
|
|
|
|
#include "print.h"
|
|
|
|
#include "version.h"
|
|
|
|
|
2002-04-07 20:00:39 +00:00
|
|
|
/* sim65 */
|
2013-05-20 18:20:14 +00:00
|
|
|
#include "6502.h"
|
2002-04-08 18:52:47 +00:00
|
|
|
#include "error.h"
|
2002-04-01 17:42:24 +00:00
|
|
|
#include "memory.h"
|
2013-05-24 16:36:30 +00:00
|
|
|
#include "paravirt.h"
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Data */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Name of program file */
|
|
|
|
const char* ProgramFile;
|
2002-04-08 18:52:47 +00:00
|
|
|
|
2014-09-25 16:47:23 +00:00
|
|
|
/* exit simulator after MaxCycles Cycles */
|
2016-07-05 15:07:39 +00:00
|
|
|
unsigned long MaxCycles;
|
2002-03-30 16:43:27 +00:00
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Code */
|
2002-03-30 16:43:27 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void Usage (void)
|
|
|
|
{
|
2013-05-24 16:36:59 +00:00
|
|
|
printf ("Usage: %s [options] file [arguments]\n"
|
2005-03-24 20:08:41 +00:00
|
|
|
"Short options:\n"
|
|
|
|
" -h\t\t\tHelp (this text)\n"
|
2016-07-05 15:07:39 +00:00
|
|
|
" -c\t\t\tPrint amount of executed CPU cycles\n"
|
2005-03-24 20:08:41 +00:00
|
|
|
" -v\t\t\tIncrease verbosity\n"
|
2013-05-20 18:20:14 +00:00
|
|
|
" -V\t\t\tPrint the simulator version number\n"
|
2014-09-25 16:47:23 +00:00
|
|
|
" -x <num>\t\tExit simulator after <num> cycles\n"
|
2005-03-24 20:08:41 +00:00
|
|
|
"\n"
|
|
|
|
"Long options:\n"
|
|
|
|
" --help\t\tHelp (this text)\n"
|
2016-07-05 15:07:39 +00:00
|
|
|
" --cycles\t\tPrint amount of executed CPU cycles\n"
|
2005-03-24 20:08:41 +00:00
|
|
|
" --verbose\t\tIncrease verbosity\n"
|
|
|
|
" --version\t\tPrint the simulator version number\n",
|
|
|
|
ProgName);
|
2002-03-30 16:43:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void OptHelp (const char* Opt attribute ((unused)),
|
2013-05-09 11:56:54 +00:00
|
|
|
const char* Arg attribute ((unused)))
|
2002-03-30 16:43:27 +00:00
|
|
|
/* Print usage information and exit */
|
|
|
|
{
|
|
|
|
Usage ();
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void OptVerbose (const char* Opt attribute ((unused)),
|
2013-05-09 11:56:54 +00:00
|
|
|
const char* Arg attribute ((unused)))
|
2002-03-30 16:43:27 +00:00
|
|
|
/* Increase verbosity */
|
|
|
|
{
|
|
|
|
++Verbosity;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-07-05 15:07:39 +00:00
|
|
|
static void OptCycles (const char* Opt attribute ((unused)),
|
|
|
|
const char* Arg attribute ((unused)))
|
|
|
|
/* Set flag to print amount of cycles at the end */
|
|
|
|
{
|
|
|
|
PrintCycles = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-03-30 16:43:27 +00:00
|
|
|
static void OptVersion (const char* Opt attribute ((unused)),
|
2013-05-09 11:56:54 +00:00
|
|
|
const char* Arg attribute ((unused)))
|
2013-05-20 18:20:14 +00:00
|
|
|
/* Print the simulator version */
|
2002-03-30 16:43:27 +00:00
|
|
|
{
|
2016-08-11 23:46:48 +00:00
|
|
|
fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
|
|
|
|
exit(EXIT_SUCCESS);
|
2002-03-30 16:43:27 +00:00
|
|
|
}
|
|
|
|
|
2014-09-25 16:47:23 +00:00
|
|
|
static void OptQuitXIns (const char* Opt attribute ((unused)),
|
|
|
|
const char* Arg attribute ((unused)))
|
|
|
|
/* quit after MaxCycles cycles */
|
|
|
|
{
|
|
|
|
MaxCycles = strtoul(Arg, NULL, 0);
|
|
|
|
}
|
2002-03-30 16:43:27 +00:00
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
static void ReadProgramFile (void)
|
|
|
|
/* Load program into memory */
|
|
|
|
{
|
|
|
|
int Val;
|
|
|
|
unsigned Addr = 0x0200;
|
|
|
|
|
|
|
|
/* Open the file */
|
|
|
|
FILE* F = fopen (ProgramFile, "rb");
|
|
|
|
if (F == 0) {
|
|
|
|
Error ("Cannot open `%s': %s", ProgramFile, strerror (errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the CPU type from the file header */
|
|
|
|
if ((Val = fgetc(F)) != EOF) {
|
|
|
|
if (Val != CPU_6502 && Val != CPU_65C02) {
|
|
|
|
Error ("`%s': Invalid CPU type", ProgramFile);
|
|
|
|
}
|
|
|
|
CPU = Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the file body into memory */
|
|
|
|
while ((Val = fgetc(F)) != EOF) {
|
|
|
|
if (Addr == 0xFF00) {
|
|
|
|
Error ("`%s': To large to fit into $0200-$FFF0", ProgramFile);
|
|
|
|
}
|
|
|
|
MemWriteByte (Addr++, (unsigned char) Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for errors */
|
|
|
|
if (ferror (F)) {
|
|
|
|
Error ("Error reading from `%s': %s", ProgramFile, strerror (errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the file */
|
|
|
|
fclose (F);
|
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 1, "Loaded `%s' at $0200-$%04X\n", ProgramFile, Addr - 1);
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-03-30 16:43:27 +00:00
|
|
|
int main (int argc, char* argv[])
|
|
|
|
{
|
|
|
|
/* Program long options */
|
|
|
|
static const LongOpt OptTab[] = {
|
2013-05-09 11:56:54 +00:00
|
|
|
{ "--help", 0, OptHelp },
|
2016-07-05 15:07:39 +00:00
|
|
|
{ "--cycles", 0, OptCycles },
|
2013-05-09 11:56:54 +00:00
|
|
|
{ "--verbose", 0, OptVerbose },
|
|
|
|
{ "--version", 0, OptVersion },
|
2002-03-30 16:43:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
unsigned I;
|
|
|
|
|
|
|
|
/* Initialize the cmdline module */
|
|
|
|
InitCmdLine (&argc, &argv, "sim65");
|
|
|
|
|
|
|
|
/* Parse the command line */
|
|
|
|
I = 1;
|
|
|
|
while (I < ArgCount) {
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Get the argument */
|
|
|
|
const char* Arg = ArgVec[I];
|
|
|
|
|
|
|
|
/* Check for an option */
|
|
|
|
if (Arg [0] == '-') {
|
|
|
|
|
|
|
|
switch (Arg [1]) {
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
OptHelp (Arg, 0);
|
|
|
|
break;
|
|
|
|
|
2016-07-05 15:07:39 +00:00
|
|
|
case 'c':
|
|
|
|
OptCycles (Arg, 0);
|
|
|
|
break;
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
case 'v':
|
|
|
|
OptVerbose (Arg, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'V':
|
|
|
|
OptVersion (Arg, 0);
|
|
|
|
break;
|
|
|
|
|
2014-09-25 16:47:23 +00:00
|
|
|
case 'x':
|
|
|
|
OptQuitXIns (Arg, GetArg (&I, 2));
|
|
|
|
break;
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
default:
|
|
|
|
UnknownOption (Arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2013-05-24 16:36:30 +00:00
|
|
|
ProgramFile = Arg;
|
|
|
|
break;
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Next argument */
|
|
|
|
++I;
|
2002-03-30 16:43:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
/* Do we have a program file? */
|
|
|
|
if (ProgramFile == 0) {
|
|
|
|
AbEnd ("No program file");
|
2002-04-08 18:52:47 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
ParaVirtInit (I);
|
|
|
|
|
2003-04-27 15:31:00 +00:00
|
|
|
MemInit ();
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
ReadProgramFile ();
|
2002-04-14 19:14:52 +00:00
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
Reset ();
|
2003-05-04 21:51:13 +00:00
|
|
|
|
|
|
|
while (1) {
|
2013-05-20 18:20:14 +00:00
|
|
|
ExecuteInsn ();
|
2014-09-25 16:47:23 +00:00
|
|
|
if (MaxCycles && (GetCycles () >= MaxCycles)) {
|
|
|
|
Error ("Maximum number of cycles reached.");
|
2016-01-05 16:45:18 +00:00
|
|
|
exit (-99); /* do not use EXIT_FAILURE to avoid conflicts with the
|
2014-11-20 13:49:35 +00:00
|
|
|
same value being used in a test program */
|
2014-09-25 16:47:23 +00:00
|
|
|
}
|
2003-05-04 21:51:13 +00:00
|
|
|
}
|
2002-04-01 17:42:24 +00:00
|
|
|
|
2002-03-30 16:43:27 +00:00
|
|
|
/* Return an apropriate exit code */
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|