diff --git a/src/c1p65/main.c b/src/c1p65/main.c index c15c77a88..467953c57 100644 --- a/src/c1p65/main.c +++ b/src/c1p65/main.c @@ -1,219 +1,221 @@ -/* Object file conversion utility for Challenger 1P - - by Stephan Muehlstrasser -*/ - - -#include -#include -#include -#include -#include -#include - -/* common stuff */ -#include "abend.h" -#include "cmdline.h" -#include "fname.h" -#include "chartype.h" -#include "target.h" -#include "version.h" -#include "xmalloc.h" - -static void Usage (void) -{ - printf ( - "Usage: %s [options] file\n" - "Short options:\n" - " -V\t\t\tPrint the version number\n" - " -h\t\t\tHelp (this text)\n" - " -o name\t\tName the C1P output file (default: )\n" - " -S addr\t\tLoad address (default 0x400)\n" - "\n" - "Long options:\n" - " --help\t\tHelp (this text)\n" - " --version\t\tPrint the version number\n", - ProgName); -} - -static void OptHelp (const char* Opt attribute ((unused)), - const char* Arg attribute ((unused))) -/* Print usage information and exit */ -{ - Usage (); - exit (EXIT_SUCCESS); -} - - -static void OptVersion (const char* Opt attribute ((unused)), - const char* Arg attribute ((unused))) -/* Print the program version */ -{ - fprintf (stderr, "grc65 V%s\n", GetVersionAsString ()); -} - - -static unsigned long CvtNumber (const char* Arg, const char* Number) -/* Convert a number from a string. Allow '$' and '0x' prefixes for hex - * numbers. Duplicated from ld65's main.c. - */ -{ - unsigned long Val; - int Converted; - - /* Convert */ - if (*Number == '$') { - ++Number; - Converted = sscanf (Number, "%lx", &Val); - } else { - Converted = sscanf (Number, "%li", (long*)&Val); - } - - /* Check if we do really have a number */ - if (Converted != 1) { - AbEnd ("Invalid number given in argument: %s\n", Arg); - } - - /* Return the result */ - return Val; -} - -/* Commands of C1P PROM monitor */ -#define ADDRESS_MODE_CMD '.' -#define DATA_MODE_CMD '/' -#define EXECUTE_CMD 'G' - -/* Transform the cc65 executable binary into a series of - commands that make the C1P PROM monitor load the bytes - into memory. -*/ -static void Transform (unsigned long StartAddress, FILE *In, FILE *Out) -{ - int c; - unsigned long CurrentAddress; - - /* Loop over all input bytes, position to current address, - switch to data mod, output input byte - */ - for (CurrentAddress = StartAddress, c = getc(In); - c != EOF; - c = getc(In), CurrentAddress += 1) { - fprintf (Out, "%c%04.4X%c%02.2X", - ADDRESS_MODE_CMD, (unsigned int) CurrentAddress & 0xFFFF, - DATA_MODE_CMD, (unsigned int) c & 0xFF); - } - - /* And execute - fprintf (Out, "%c%04.4x%c", - ADDRESS_MODE_CMD, (unsigned int) StartAddress & 0xFFFF, - EXECUTE_CMD); - */ -} - -/* Default suffix for C1P object file */ -#define C1P_SUFFIX ".c1p" - -int main (int argc, char *argv[]) -{ - /* Program long options */ - static const LongOpt OptTab[] = { - { "--help", 0, OptHelp}, - { "--version", 0, OptVersion}, - }; - - /* Initialize input and output file name */ - const char* InputFile = 0; - const char* OutputFile = 0; - char *GeneratedOutputFile = 0; - - /* Initialize file pointers */ - FILE *InputFileFp = 0; - FILE *OutputFileFp = 0; - - /* Initialize with default start address defined in c1p.cfg */ - unsigned long StartAddr = 0x400; - - unsigned int I; - - /* Initialize the cmdline module */ - InitCmdLine (&argc, &argv, "c1p65"); - - /* Check the parameters */ - I = 1; - while (I < ArgCount) { - - /* 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 'o': - OutputFile = GetArg (&I, 2); - break; - - case 'S': - StartAddr = CvtNumber (Arg, GetArg (&I, 2)); - break; - - case 'h': - case '?': - OptHelp (Arg, 0); - break; - - case 'V': - OptVersion (Arg, 0); - break; - - default: - UnknownOption (Arg); - } - - } else { - if (InputFile) { - fprintf (stderr, "additional file specs ignored\n"); - } else { - InputFile = Arg; - } - } - - /* Next argument */ - ++I; - } - - if (!InputFile) AbEnd ("No input file"); - - if (!OutputFile) { - const size_t len = strlen(InputFile) + sizeof(C1P_SUFFIX); - - GeneratedOutputFile = (char *) xmalloc(len); - sprintf(GeneratedOutputFile, "%s%s", InputFile, C1P_SUFFIX); - OutputFile = GeneratedOutputFile; - } - - /* Open input and output files */ - InputFileFp = fopen(InputFile, "rb"); - if (!InputFileFp) AbEnd ("Unable to open input file"); - - OutputFileFp = fopen(OutputFile, "wb"); - if (!OutputFileFp) AbEnd ("Unable to open output file"); - - /* Generate object file */ - Transform (StartAddr, InputFileFp, OutputFileFp); - - /* Cleanup */ - if (fclose(InputFileFp) == EOF) AbEnd ("Error closing input file"); - - if (fclose(OutputFileFp) == EOF) AbEnd ("Error closing output file"); - - if (GeneratedOutputFile) { - xfree(GeneratedOutputFile); - } - - return EXIT_SUCCESS; -} +/* Object file conversion utility for Challenger 1P + + by Stephan Muehlstrasser +*/ + + +#include +#include +#include +#include +#include +#include + +/* common stuff */ +#include "abend.h" +#include "cmdline.h" +#include "fname.h" +#include "chartype.h" +#include "target.h" +#include "version.h" +#include "xmalloc.h" + +static void Usage (void) +{ + printf ( + "Usage: %s [options] file\n" + "Short options:\n" + " -V\t\t\tPrint the version number\n" + " -h\t\t\tHelp (this text)\n" + " -o name\t\tName the C1P output file (default: )\n" + " -S addr\t\tLoad address (default 0x400)\n" + "\n" + "Long options:\n" + " --help\t\tHelp (this text)\n" + " --version\t\tPrint the version number\n", + ProgName); +} + +static void OptHelp (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print usage information and exit */ +{ + Usage (); + exit (EXIT_SUCCESS); +} + + +static void OptVersion (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print the program version */ +{ + fprintf (stderr, "grc65 V%s\n", GetVersionAsString ()); +} + + +static unsigned long CvtNumber (const char* Arg, const char* Number) +/* Convert a number from a string. Allow '$' and '0x' prefixes for hex + * numbers. Duplicated from ld65's main.c. + */ +{ + unsigned long Val; + int Converted; + + /* Convert */ + if (*Number == '$') { + ++Number; + Converted = sscanf (Number, "%lx", &Val); + } else { + Converted = sscanf (Number, "%li", (long*)&Val); + } + + /* Check if we do really have a number */ + if (Converted != 1) { + AbEnd ("Invalid number given in argument: %s\n", Arg); + } + + /* Return the result */ + return Val; +} + +/* Commands of C1P PROM monitor */ +#define ADDRESS_MODE_CMD '.' +#define DATA_MODE_CMD '/' +#define EXECUTE_CMD 'G' +#define DATA_MODE_ADDRESS 0x00FB + +/* Transform the cc65 executable binary into a series of + commands that make the C1P PROM monitor load the bytes + into memory. +*/ +static void Transform (unsigned long StartAddress, FILE *In, FILE *Out) +{ + int c; + + /* Position to the start address */ + fprintf(Out, "%c%04.4X%c", ADDRESS_MODE_CMD, + StartAddress & 0xFFFF, DATA_MODE_CMD); + + /* Loop over all input bytes and enter them one by one */ + for (c = getc(In); c != EOF; c = getc(In)) { + fprintf(Out, "%02.2X\n", (unsigned int) c & 0xFF); + } + + /* Store 00 to 0x00FB to enable keyboard input at the end */ + fprintf(Out, "%c%04.4X%c%02.2X\n", ADDRESS_MODE_CMD, + 0x00FB, DATA_MODE_CMD, 0x00); + + /* And execute + fprintf (Out, "%c%04.4x%c", + ADDRESS_MODE_CMD, (unsigned int) StartAddress & 0xFFFF, + EXECUTE_CMD); + */ +} + +/* Default suffix for C1P object file */ +#define C1P_SUFFIX ".c1p" + +int main (int argc, char *argv[]) +{ + /* Program long options */ + static const LongOpt OptTab[] = { + { "--help", 0, OptHelp}, + { "--version", 0, OptVersion}, + }; + + /* Initialize input and output file name */ + const char* InputFile = 0; + const char* OutputFile = 0; + char *GeneratedOutputFile = 0; + + /* Initialize file pointers */ + FILE *InputFileFp = 0; + FILE *OutputFileFp = 0; + + /* Initialize with default start address defined in c1p.cfg */ + unsigned long StartAddr = 0x400; + + unsigned int I; + + /* Initialize the cmdline module */ + InitCmdLine (&argc, &argv, "c1p65"); + + /* Check the parameters */ + I = 1; + while (I < ArgCount) { + + /* 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 'o': + OutputFile = GetArg (&I, 2); + break; + + case 'S': + StartAddr = CvtNumber (Arg, GetArg (&I, 2)); + break; + + case 'h': + case '?': + OptHelp (Arg, 0); + break; + + case 'V': + OptVersion (Arg, 0); + break; + + default: + UnknownOption (Arg); + } + + } else { + if (InputFile) { + fprintf (stderr, "additional file specs ignored\n"); + } else { + InputFile = Arg; + } + } + + /* Next argument */ + ++I; + } + + if (!InputFile) AbEnd ("No input file"); + + if (!OutputFile) { + const size_t len = strlen(InputFile) + sizeof(C1P_SUFFIX); + + GeneratedOutputFile = (char *) xmalloc(len); + sprintf(GeneratedOutputFile, "%s%s", InputFile, C1P_SUFFIX); + OutputFile = GeneratedOutputFile; + } + + /* Open input and output files */ + InputFileFp = fopen(InputFile, "rb"); + if (!InputFileFp) AbEnd ("Unable to open input file"); + + OutputFileFp = fopen(OutputFile, "wb"); + if (!OutputFileFp) AbEnd ("Unable to open output file"); + + /* Generate object file */ + Transform (StartAddr, InputFileFp, OutputFileFp); + + /* Cleanup */ + if (fclose(InputFileFp) == EOF) AbEnd ("Error closing input file"); + + if (fclose(OutputFileFp) == EOF) AbEnd ("Error closing output file"); + + if (GeneratedOutputFile) { + xfree(GeneratedOutputFile); + } + + return EXIT_SUCCESS; +}