--- /dev/null
+/*****************************************************************************/
+/* */
+/* convert.c */
+/* */
+/* Actual conversion routines for the co65 object file converter */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* common */
+#include "debugflag.h"
+#include "print.h"
+#include "version.h"
+#include "xmalloc.h"
+#include "xsprintf.h"
+
+/* co65 */
+#include "error.h"
+#include "global.h"
+#include "model.h"
+#include "o65.h"
+#include "convert.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void PrintO65Stats (const O65Data* D)
+/* Print information about the O65 file if --verbose is given */
+{
+ Print (stdout, 1, "Size of text segment: %5lu\n", D->Header.tlen);
+ Print (stdout, 1, "Size of data segment: %5lu\n", D->Header.dlen);
+ Print (stdout, 1, "Size of bss segment: %5lu\n", D->Header.blen);
+ Print (stdout, 1, "Size of zeropage segment: %5lu\n", D->Header.zlen);
+ Print (stdout, 1, "Number of imports: %5u\n", CollCount (&D->Imports));
+ Print (stdout, 1, "Number of exports: %5u\n", CollCount (&D->Exports));
+ Print (stdout, 1, "Number of text segment relocations: %5u\n", CollCount (&D->TextReloc));
+ Print (stdout, 1, "Number of data segment relocations: %5u\n", CollCount (&D->DataReloc));
+}
+
+
+
+static void SetupSegLabels (FILE* F)
+/* Setup the segment label names */
+{
+ if (BssLabel) {
+ fprintf (F, ".export\t\t%s\n", BssLabel);
+ } else {
+ BssLabel = xstrdup ("BSS");
+ }
+ if (CodeLabel) {
+ fprintf (F, ".export\t\t%s\n", CodeLabel);
+ } else {
+ CodeLabel = xstrdup ("CODE");
+ }
+ if (DataLabel) {
+ fprintf (F, ".export\t\t%s\n", DataLabel);
+ } else {
+ DataLabel = xstrdup ("DATA");
+ }
+ if (ZeropageLabel) {
+ fprintf (F, ".export\t\t%s\n", ZeropageLabel);
+ } else {
+ ZeropageLabel = xstrdup ("ZEROPAGE");
+ }
+}
+
+
+
+static void ConvertImports (FILE* F, const O65Data* D)
+/* Convert the imports */
+{
+ unsigned I;
+
+ if (CollCount (&D->Imports) > 0) {
+ for (I = 0; I < CollCount (&D->Imports); ++I) {
+
+ /* Get the next import */
+ const O65Import* Import = CollConstAt (&D->Imports, I);
+
+ /* Import it by name */
+ fprintf (F, ".import\t%s\n", Import->Name);
+ }
+ fprintf (F, "\n");
+ }
+}
+
+
+
+static void ConvertExports (FILE* F, const O65Data* D)
+/* Convert the exports */
+{
+ unsigned I;
+
+ if (CollCount (&D->Exports) > 0) {
+ for (I = 0; I < CollCount (&D->Exports); ++I) {
+
+ /* Get the next import */
+ const O65Export* Export = CollConstAt (&D->Exports, I);
+
+ /* First define it */
+ fprintf (F, "%s = XXX\n", Export->Name); /* ### */
+
+ /* Then export it by name */
+ fprintf (F, ".export\t%s\n", Export->Name);
+ }
+ fprintf (F, "\n");
+ }
+}
+
+
+
+static const char* LabelPlusOffs (const char* Label, long Offs)
+/* Generate "Label+xxx" in a static buffer and return a pointer to the buffer */
+{
+ static char Buf[256];
+ xsprintf (Buf, sizeof (Buf), "%s%+ld", Label, Offs);
+ return Buf;
+}
+
+
+
+static const char* RelocExpr (const O65Data* D, const O65Reloc* R, unsigned long Val)
+/* Generate the segment relative relocation expression */
+{
+ const O65Import* Import;
+
+ switch (R->SegID) {
+
+ case O65_SEGID_UNDEF:
+ if (R->SymIdx >= CollCount (&D->Imports)) {
+ Error ("Import index out of range (input file corrupt)");
+ }
+ Import = CollConstAt (&D->Imports, R->SymIdx);
+ return LabelPlusOffs (Import->Name, Val);
+
+ case O65_SEGID_TEXT:
+ return LabelPlusOffs (CodeLabel, Val - D->Header.tbase);
+
+ case O65_SEGID_DATA:
+ return LabelPlusOffs (DataLabel, Val - D->Header.dbase);
+
+ case O65_SEGID_BSS:
+ return LabelPlusOffs (BssLabel, Val - D->Header.bbase);
+
+ case O65_SEGID_ZP:
+ return LabelPlusOffs (ZeropageLabel, Val - D->Header.zbase);
+
+ case O65_SEGID_ABS:
+ return LabelPlusOffs ("", Val);
+
+ default:
+ Internal ("Cannot handle this segment reference in reloc entry");
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+
+
+static void ConvertSeg (FILE* F, const O65Data* D, const Collection* Relocs,
+ const unsigned char* Data, unsigned long Size)
+/* Convert one segment */
+{
+ const O65Reloc* R;
+ unsigned RIdx;
+ unsigned long Byte;
+
+ /* Get the pointer to the first relocation entry if there are any */
+ R = (CollCount (Relocs) > 0)? CollConstAt (Relocs, 0) : 0;
+
+ /* Initialize for the loop */
+ RIdx = 0;
+ Byte = 0;
+
+ /* Walk over the segment data */
+ while (Byte < Size) {
+
+ if (R && R->Offs == Byte) {
+ /* We've reached an entry that must be relocated */
+ unsigned long Val;
+ switch (R->Type) {
+
+ case O65_RTYPE_WORD:
+ if (Byte >= Size - 1) {
+ Error ("Found WORD relocation, but not enough bytes left");
+ } else {
+ Val = (Data[Byte+1] << 8) + Data[Byte];
+ Byte += 2;
+ fprintf (F, "\t.word\t%s\n", RelocExpr (D, R, Val));
+ }
+ break;
+
+ case O65_RTYPE_HIGH:
+ Val = (Data[Byte++] << 8) + R->Val;
+ fprintf (F, "\t.byte\t>(%s)\n", RelocExpr (D, R, Val));
+ break;
+
+ case O65_RTYPE_LOW:
+ Val = Data[Byte++];
+ fprintf (F, "\t.byte\t<(%s)\n", RelocExpr (D, R, Val));
+ break;
+
+ case O65_RTYPE_SEGADDR:
+ if (Byte >= Size - 2) {
+ Error ("Found SEGADDR relocation, but not enough bytes left");
+ } else {
+ Val = (((unsigned long) Data[Byte+2]) << 16) +
+ (((unsigned long) Data[Byte+1]) << 8) +
+ (((unsigned long) Data[Byte+0]) << 0) +
+ R->Val;
+ Byte += 3;
+ fprintf (F, "\t.faraddr\t%s\n", RelocExpr (D, R, Val));
+ }
+ break;
+
+ case O65_RTYPE_SEG:
+ /* FALLTHROUGH for now */
+ default:
+ Internal ("Cannot handle relocation type %d at %lu",
+ R->Type, Byte);
+ }
+
+ /* Get the next relocation entry */
+ if (++RIdx < CollCount (Relocs)) {
+ R = CollConstAt (Relocs, RIdx);
+ } else {
+ R = 0;
+ }
+
+ } else {
+ /* Just a constant value */
+ fprintf (F, "\t.byte\t$%02X\n", Data[Byte++]);
+ }
+ }
+
+ fprintf (F, "\n");
+}
+
+
+
+static void ConvertCodeSeg (FILE* F, const O65Data* D)
+/* Do code segment conversion */
+{
+ /* Header */
+ fprintf (F,
+ ";\n; CODE SEGMENT\n;\n"
+ ".segment\t\"%s\"\n"
+ "%s:\n",
+ CodeSeg,
+ CodeLabel);
+
+ /* Segment data */
+ ConvertSeg (F, D, &D->TextReloc, D->Text, D->Header.tlen);
+}
+
+
+
+static void ConvertDataSeg (FILE* F, const O65Data* D)
+/* Do data segment conversion */
+{
+ /* Header */
+ fprintf (F,
+ ";\n; DATA SEGMENT\n;\n"
+ ".segment\t\"%s\"\n"
+ "%s:\n",
+ DataSeg,
+ DataLabel);
+
+ /* Segment data */
+ ConvertSeg (F, D, &D->DataReloc, D->Data, D->Header.dlen);
+}
+
+
+
+static void ConvertBssSeg (FILE* F, const O65Data* D)
+/* Do bss segment conversion */
+{
+ /* Header */
+ fprintf (F,
+ ";\n; BSS SEGMENT\n;\n"
+ ".segment\t\"%s\"\n"
+ "%s:\n",
+ BssSeg,
+ BssLabel);
+
+ /* Segment data */
+ fprintf (F, "\t.res\t%lu\n", D->Header.blen);
+ fprintf (F, "\n");
+}
+
+
+
+static void ConvertZeropageSeg (FILE* F, const O65Data* D)
+/* Do zeropage segment conversion */
+{
+ /* Header */
+ fprintf (F, ";\n; ZEROPAGE SEGMENT\n;\n");
+
+ if (Model == O65_MODEL_CC65_MODULE) {
+ /* o65 files of type cc65-module are linked together with a definition
+ * file for the zero page, but the zero page is not allocated in the
+ * module itself, but the locations are mapped to the zp locations of
+ * the main file.
+ */
+ fprintf (F, ".import\t__ZP_START__\t\t; Linker generated symbol\n");
+ fprintf (F, "%s = __ZP_START__\n", ZeropageLabel);
+ } else {
+ /* Header */
+ fprintf (F, ".segment\t\"%s\", zeropage\n%s:\n", ZeropageSeg, ZeropageLabel);
+
+ /* Segment data */
+ fprintf (F, "\t.res\t%lu\n", D->Header.zlen);
+ }
+ fprintf (F, "\n");
+}
+
+
+
+void Convert (const O65Data* D, const char* OutputFile)
+/* Convert the o65 file in D using the given output file. */
+{
+ FILE* F;
+ unsigned I;
+ char* Author = 0;
+
+ /* For now, we do only accept o65 files generated by the ld65 linker which
+ * have a specific format.
+ */
+ if (!Debug && D->Header.mode != O65_MODE_CC65) {
+ Error ("Cannot convert o65 files of this type");
+ }
+
+ /* Output statistics */
+ PrintO65Stats (D);
+
+ /* Walk through the options and print them if verbose mode is enabled.
+ * Check for a os=cc65 option and bail out if we didn't find one (for
+ * now - later we switch to special handling).
+ */
+ for (I = 0; I < CollCount (&D->Options); ++I) {
+
+ /* Get the next option */
+ const O65Option* O = CollConstAt (&D->Options, I);
+
+ /* Check the type of the option */
+ switch (O->Type) {
+
+ case O65_OPT_FILENAME:
+ Print (stdout, 1, "O65 filename option: `%s'\n",
+ GetO65OptionText (O));
+ break;
+
+ case O65_OPT_OS:
+ if (O->Len == 2) {
+ Warning ("Operating system option without data found");
+ } else {
+ Print (stdout, 1, "O65 operating system option: `%s'\n",
+ GetO65OSName (O->Data[0]));
+ switch (O->Data[0]) {
+ case O65_OS_CC65_MODULE:
+ if (Model != O65_MODEL_NONE &&
+ Model != O65_MODEL_CC65_MODULE) {
+ Warning ("Wrong o65 model");
+ } else {
+ Model = O65_MODEL_CC65_MODULE;
+ }
+ break;
+ }
+ }
+ break;
+
+ case O65_OPT_ASM:
+ Print (stdout, 1, "O65 assembler option: `%s'\n",
+ GetO65OptionText (O));
+ break;
+
+ case O65_OPT_AUTHOR:
+ if (Author) {
+ xfree (Author);
+ }
+ Author = xstrdup (GetO65OptionText (O));
+ Print (stdout, 1, "O65 author option: `%s'\n", Author);
+ break;
+
+ case O65_OPT_TIMESTAMP:
+ Print (stdout, 1, "O65 timestamp option: `%s'\n",
+ GetO65OptionText (O));
+ break;
+
+ default:
+ Warning ("Found unknown option, type %d, length %d",
+ O->Type, O->Len);
+ break;
+ }
+ }
+
+ /* Open the output file */
+ F = fopen (OutputFile, "wb");
+ if (F == 0) {
+ Error ("Cannot open `%s': %s", OutputFile, strerror (errno));
+ }
+
+ /* Create a header */
+ fprintf (F, ";\n; File generated by co65 v %u.%u.%u using model `%s'\n;\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH, GetModelName (Model));
+
+ /* Select the CPU */
+ if ((D->Header.mode & O65_CPU_MASK) == O65_CPU_65816) {
+ fprintf (F, ".p816\n");
+ }
+
+ /* Object file options */
+ fprintf (F, ".fopt\t\tcompiler,\"co65 v %u.%u.%u\"\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ if (Author) {
+ fprintf (F, ".fopt\t\tauthor, \"%s\"\n", Author);
+ xfree (Author);
+ Author = 0;
+ }
+
+ /* Several other assembler options */
+ fprintf (F, ".case\t\ton\n");
+ fprintf (F, ".debuginfo\t%s\n", (DebugInfo != 0)? "on" : "off");
+
+ /* Setup/export the segment labels */
+ SetupSegLabels (F);
+
+ /* End of header */
+ fprintf (F, "\n");
+
+ /* Imported identifiers */
+ ConvertImports (F, D);
+
+ /* Exported identifiers */
+ ConvertExports (F, D);
+
+ /* Code segment */
+ ConvertCodeSeg (F, D);
+
+ /* Data segment */
+ ConvertDataSeg (F, D);
+
+ /* BSS segment */
+ ConvertBssSeg (F, D);
+
+ /* Zero page segment */
+ ConvertZeropageSeg (F, D);
+
+ /* End of data */
+ fprintf (F, ".end\n");
+ fclose (F);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* convert.h */
+/* */
+/* Actual conversion routines for the co65 object file converter */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* 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. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef CONVERT_H
+#define CONVERT_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Forward definition */
+struct O65Data;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Convert (const struct O65Data* D, const char* OutputFile);
+/* Convert the o65 file in D using the given output file. */
+
+
+
+/* End of convert.h */
+
+#endif
+
+
+
/* common */
#include "chartype.h"
#include "cmdline.h"
+#include "debugflag.h"
#include "fname.h"
#include "print.h"
#include "segnames.h"
#include "xsprintf.h"
/* co65 */
+#include "convert.h"
#include "error.h"
#include "global.h"
+#include "model.h"
#include "o65.h"
" -V\t\t\tPrint the version number\n"
" -g\t\t\tAdd debug info to object file\n"
" -h\t\t\tHelp (this text)\n"
+ " -m model\t\tOverride the o65 model\n"
" -o name\t\tName the output file\n"
" -v\t\t\tIncrease verbosity\n"
"\n"
" --data-name seg\tSet the name of the DATA segment\n"
" --debug-info\t\tAdd debug info to object file\n"
" --help\t\tHelp (this text)\n"
+ " --o65-model model\tOverride the o65 model\n"
" --verbose\t\tIncrease verbosity\n"
" --version\t\tPrint the version number\n"
" --zeropage-label name\tDefine and export a ZEROPAGE segment label\n"
+static void OptDebug (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
+/* Enable debugging code */
+{
+ ++Debug;
+}
+
+
+
static void OptDebugInfo (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Add debug info to the object file */
+static void OptO65Model (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --o65-model option */
+{
+ /* Search for the model name */
+ Model = FindModel (Arg);
+ if (Model == O65_MODEL_INVALID) {
+ Error ("Unknown o65 model `%s'", Arg);
+ }
+}
+
+
+
static void OptVerbose (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Increase verbosity */
-static const char* SegReloc (const O65Data* D, const O65Reloc* R, unsigned long Val)
-{
- static char Buf[256];
- const O65Import* Import;
-
- switch (R->SegID) {
-
- case O65_SEGID_UNDEF:
- if (R->SymIdx >= CollCount (&D->Imports)) {
- Error ("Import index out of range (input file corrupt)");
- }
- Import = CollConstAt (&D->Imports, R->SymIdx);
- xsprintf (Buf, sizeof (Buf), "%s%+ld", Import->Name, (long) Val);
- break;
-
- case O65_SEGID_TEXT:
- xsprintf (Buf, sizeof (Buf), "%s%+ld", CodeLabel, (long) (Val - D->Header.tbase));
- break;
-
- case O65_SEGID_DATA:
- xsprintf (Buf, sizeof (Buf), "%s%+ld", DataLabel, (long) (Val - D->Header.dbase));
- break;
-
- case O65_SEGID_BSS:
- xsprintf (Buf, sizeof (Buf), "%s%+ld", BssLabel, (long) (Val - D->Header.bbase));
- break;
-
- case O65_SEGID_ZP:
- xsprintf (Buf, sizeof (Buf), "%s%+ld", ZeropageLabel, (long) Val - D->Header.zbase);
- break;
-
- case O65_SEGID_ABS:
- Error ("Relocation entry contains O65_SEGID_ABS");
- break;
-
- default:
- Internal ("Cannot handle this segment reference in reloc entry");
- }
-
- return Buf;
-}
-
-
-
-static void ConvertSeg (FILE* F, const O65Data* D, const Collection* Relocs,
- const unsigned char* Data, unsigned long Size)
-/* Convert one segment */
-{
- const O65Reloc* R;
- unsigned RIdx;
- unsigned long Byte;
-
- /* Get the pointer to the first relocation entry if there are any */
- R = (CollCount (Relocs) > 0)? CollConstAt (Relocs, 0) : 0;
-
- /* Initialize for the loop */
- RIdx = 0;
- Byte = 0;
-
- /* Walk over the segment data */
- while (Byte < Size) {
-
- if (R && R->Offs == Byte) {
- /* We've reached an entry that must be relocated */
- unsigned long Val;
- switch (R->Type) {
-
- case O65_RTYPE_WORD:
- if (Byte >= Size - 1) {
- Error ("Found WORD relocation, but not enough bytes left");
- } else {
- Val = (Data[Byte+1] << 8) + Data[Byte];
- Byte += 2;
- fprintf (F, "\t.word\t%s\n", SegReloc (D, R, Val));
- }
- break;
-
- case O65_RTYPE_HIGH:
- Val = (Data[Byte++] << 8) + R->Val;
- fprintf (F, "\t.byte\t>(%s)\n", SegReloc (D, R, Val));
- break;
-
- case O65_RTYPE_LOW:
- Val = Data[Byte++];
- fprintf (F, "\t.byte\t<(%s)\n", SegReloc (D, R, Val));
- break;
-
- case O65_RTYPE_SEGADDR:
- if (Byte >= Size - 2) {
- Error ("Found SEGADDR relocation, but not enough bytes left");
- } else {
- Val = (((unsigned long) Data[Byte+2]) << 16) +
- (((unsigned long) Data[Byte+1]) << 8) +
- (((unsigned long) Data[Byte+0]) << 0) +
- R->Val;
- Byte += 3;
- fprintf (F, "\t.faraddr\t%s\n", SegReloc (D, R, Val));
- }
- break;
-
- case O65_RTYPE_SEG:
- /* FALLTHROUGH for now */
- default:
- Internal ("Cannot handle relocation type %d at %lu",
- R->Type, Byte);
- }
-
- /* Get the next relocation entry */
- if (++RIdx < CollCount (Relocs)) {
- R = CollConstAt (Relocs, RIdx);
- } else {
- R = 0;
- }
-
- } else {
- /* Just a constant value */
- fprintf (F, "\t.byte\t$%02X\n", Data[Byte++]);
- }
- }
-
- fprintf (F, "\n");
-}
-
-
-
-static void Convert (void)
+static void ConvertOneFile (const char* InputFile, const char* OutputFile)
/* Do file conversion */
{
- FILE* F;
- unsigned I;
- int cc65;
- char* Author = 0;
-
/* Read the o65 file into memory */
- O65Data* D = ReadO65File (InputName);
-
- /* For now, we do only accept o65 files generated by the ld65 linker which
- * have a specific format.
- */
- if (D->Header.mode != O65_MODE_CC65) {
- Error ("Cannot convert o65 files of this type");
- }
-
- /* Output statistics */
- Print (stdout, 1, "Size of text segment: %5lu\n", D->Header.tlen);
- Print (stdout, 1, "Size of data segment: %5lu\n", D->Header.dlen);
- Print (stdout, 1, "Size of bss segment: %5lu\n", D->Header.blen);
- Print (stdout, 1, "Size of zeropage segment: %5lu\n", D->Header.zlen);
- Print (stdout, 1, "Number of imports: %5u\n", CollCount (&D->Imports));
- Print (stdout, 1, "Number of exports: %5u\n", CollCount (&D->Exports));
- Print (stdout, 1, "Number of text segment relocations: %5u\n", CollCount (&D->TextReloc));
- Print (stdout, 1, "Number of data segment relocations: %5u\n", CollCount (&D->DataReloc));
-
- /* Walk through the options and print them if verbose mode is enabled.
- * Check for a os=cc65 option and bail out if we didn't find one (for
- * now - later we switch to special handling).
- */
- cc65 = 0;
- for (I = 0; I < CollCount (&D->Options); ++I) {
-
- /* Get the next option */
- const O65Option* O = CollConstAt (&D->Options, I);
-
- /* Check the type */
- switch (O->Type) {
- case O65_OPT_FILENAME:
- Print (stdout, 1, "O65 filename option: `%s'\n",
- GetO65OptionText (O));
- break;
- case O65_OPT_OS:
- if (O->Len == 2) {
- Warning ("Operating system option without data found");
- } else {
- cc65 = (O->Data[0] == O65_OS_CC65_MODULE);
- Print (stdout, 1, "O65 operating system option: `%s'\n",
- GetO65OSName (O->Data[0]));
- }
- break;
- case O65_OPT_ASM:
- Print (stdout, 1, "O65 assembler option: `%s'\n",
- GetO65OptionText (O));
- break;
- case O65_OPT_AUTHOR:
- if (Author) {
- xfree (Author);
- }
- Author = xstrdup (GetO65OptionText (O));
- Print (stdout, 1, "O65 author option: `%s'\n", Author);
- break;
- case O65_OPT_TIMESTAMP:
- Print (stdout, 1, "O65 timestamp option: `%s'\n",
- GetO65OptionText (O));
- break;
- default:
- Warning ("Found unknown option, type %d, length %d",
- O->Type, O->Len);
- break;
- }
- }
-
- /* Open the output file */
- F = fopen (OutputName, "wb");
- if (F == 0) {
- Error ("Cannot open `%s': %s", OutputName, strerror (errno));
- }
-
- /* Create a header */
- fprintf (F, ";\n; File generated by co65 v %u.%u.%u\n;\n",
- VER_MAJOR, VER_MINOR, VER_PATCH);
-
- /* Select the CPU */
- if ((D->Header.mode & O65_CPU_MASK) == O65_CPU_65816) {
- fprintf (F, "\t.p816\n");
- }
-
- /* Object file options */
- fprintf (F, "\t.fopt\t\tcompiler,\"co65 v %u.%u.%u\"\n",
- VER_MAJOR, VER_MINOR, VER_PATCH);
- if (Author) {
- fprintf (F, "\t.fopt\t\tauthor, \"%s\"\n", Author);
- xfree (Author);
- Author = 0;
- }
-
- /* Several other assembler options */
- fprintf (F, "\t.case\t\ton\n");
- fprintf (F, "\t.debuginfo\t%s\n", (DebugInfo != 0)? "on" : "off");
+ O65Data* D = ReadO65File (InputFile);
- /* Setup/export the segment labels */
- if (BssLabel) {
- fprintf (F, "\t.export\t\t%s\n", BssLabel);
- } else {
- BssLabel = xstrdup ("__BSS__");
- }
- if (CodeLabel) {
- fprintf (F, "\t.export\t\t%s\n", CodeLabel);
- } else {
- CodeLabel = xstrdup ("__CODE__");
- }
- if (DataLabel) {
- fprintf (F, "\t.export\t\t%s\n", DataLabel);
- } else {
- DataLabel = xstrdup ("__DATA__");
- }
- if (ZeropageLabel) {
- fprintf (F, "\t.export\t\t%s\n", ZeropageLabel);
- } else {
- /* If this is a cc65 module, override the name for the zeropage segment */
- if (cc65) {
- ZeropageLabel = "__ZP_START__";
- fprintf (F, "\t.import\t\t__ZP_START__\t; Linker generated symbol\n");
- } else {
- ZeropageLabel = xstrdup ("__ZEROPAGE__");
- }
- }
-
- /* End of header */
- fprintf (F, "\n");
-
- /* Imported identifiers */
- if (CollCount (&D->Imports) > 0) {
- for (I = 0; I < CollCount (&D->Imports); ++I) {
-
- /* Get the next import */
- O65Import* Import = CollAtUnchecked (&D->Imports, I);
-
- /* Import it by name */
- fprintf (F, "\t.import\t%s\n", Import->Name);
- }
- fprintf (F, "\n");
- }
-
- /* Exported identifiers */
- if (CollCount (&D->Exports) > 0) {
- for (I = 0; I < CollCount (&D->Exports); ++I) {
-
- /* Get the next import */
- O65Export* Export = CollAtUnchecked (&D->Exports, I);
-
- /* First define it */
- fprintf (F, "%s = XXX\n", Export->Name); /* ### */
-
- /* The export it by name */
- fprintf (F, "\t.export\t%s\n", Export->Name);
- }
- fprintf (F, "\n");
- }
-
- /* Code segment */
- fprintf (F, ".segment\t\"%s\"\n", CodeSeg);
- fprintf (F, "%s:\n", CodeLabel);
- ConvertSeg (F, D, &D->TextReloc, D->Text, D->Header.tlen);
-
- /* Data segment */
- fprintf (F, ".segment\t\"%s\"\n", DataSeg);
- fprintf (F, "%s:\n", DataLabel);
- ConvertSeg (F, D, &D->DataReloc, D->Data, D->Header.dlen);
+ /* Do the conversion */
+ Convert (D, OutputFile);
- /* BSS segment */
- fprintf (F, ".segment\t\"%s\"\n", BssSeg);
- fprintf (F, "%s:\n", BssLabel);
- fprintf (F, "\t.res\t%lu\n", D->Header.blen);
- fprintf (F, "\n");
+ /* Free the o65 module data */
+ /* ### */
- fprintf (F, "\t.end\n");
- fclose (F);
}
{ "--code-name", 1, OptCodeName },
{ "--data-label", 1, OptDataLabel },
{ "--data-name", 1, OptDataName },
+ { "--debug", 0, OptDebug },
{ "--debug-info", 0, OptDebugInfo },
- { "--help", 0, OptHelp },
+ { "--help", 0, OptHelp },
+ { "--o65-model", 1, OptO65Model },
{ "--verbose", 0, OptVerbose },
{ "--version", 0, OptVersion },
{ "--zeropage-label", 1, OptZeropageLabel },
OptHelp (Arg, 0);
break;
+ case 'm':
+ OptO65Model (Arg, GetArg (&I, 2));
+ break;
+
case 'o':
OutputName = GetArg (&I, 2);
break;
}
/* Do the conversion */
- Convert ();
+ ConvertOneFile (InputName, OutputName);
/* Return an apropriate exit code */
return EXIT_SUCCESS;
EBIND = emxbind
LDFLAGS =
-OBJS = error.o \
+OBJS = convert.o \
+ error.o \
fileio.o \
global.o \
main.o \
+ model.o \
o65.o
LIBS = $(COMMON)/common.a
# ------------------------------------------------------------------------------
# All library OBJ files
-OBJS = error.obj \
+OBJS = convert.obj \
+ error.obj \
fileio.obj \
global.obj \
main.obj \
+ model.obj \
o65.obj
LIBS = ..\common\common.lib
--- /dev/null
+/*****************************************************************************/
+/* */
+/* model.c */
+/* */
+/* o65 model definitions for the co65 object file converter */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* 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. */
+/* */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "strutil.h"
+
+/* co65 */
+#include "error.h"
+#include "model.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Current model */
+O65Model Model = O65_MODEL_NONE;
+
+/* Name table */
+static const char* NameTable[O65_MODEL_COUNT] = {
+ "none",
+ "cc65-module"
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* GetModelName (O65Model M)
+/* Map the model to its name. */
+{
+ if (M < 0 || M >= O65_MODEL_COUNT) {
+ Internal ("O65 Model %d not found", M);
+ }
+ return NameTable[M];
+}
+
+
+
+O65Model FindModel (const char* ModelName)
+/* Map a model name to its identifier. Return O65_MODEL_INVALID if the name
+ * could not be found. Case is ignored when comparing names.
+ */
+{
+ O65Model M;
+ for (M = O65_MODEL_NONE; M < O65_MODEL_COUNT; ++M) {
+ if (StrCaseCmp (ModelName, NameTable[M]) == 0) {
+ return M;
+ }
+ }
+ return O65_MODEL_INVALID;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* model.h */
+/* */
+/* o65 model definitions for the co65 object file converter */
+/* */
+/* */
+/* */
+/* (C) 2003 Ullrich von Bassewitz */
+/* Römerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* 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. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MODEL_H
+#define MODEL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Supported models */
+typedef enum {
+ O65_MODEL_INVALID = -1, /* Invalid model */
+ O65_MODEL_NONE, /* No model given */
+ O65_MODEL_CC65_MODULE,
+
+ O65_MODEL_COUNT /* Number of available models */
+} O65Model;
+
+
+
+/* Current model */
+extern O65Model Model;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* GetModelName (O65Model M);
+/* Map the model to its name. */
+
+O65Model FindModel (const char* ModelName);
+/* Map a model name to its identifier. Return O65_MODEL_INVALID if the name
+ * could not be found. Case is ignored when comparing names.
+ */
+
+
+
+/* End of model.h */
+
+#endif
+
+
+
/* Define a structure for the o65 file header */
-typedef struct {
+typedef struct O65Header O65Header;
+struct O65Header {
char marker[2]; /* Non-C64 marker */
char magic[3]; /* o65 magic */
char version; /* Version number */
unsigned long zbase; /* Original zp segment address */
unsigned long zlen; /* Size of zp segment */
unsigned long stack; /* Stacksize needed */
-} O65Header;
+};
/* o65 option */
-typedef struct {
+typedef struct O65Option O65Option;
+struct O65Option {
unsigned char Len; /* Option length */
unsigned char Type; /* Option type */
unsigned char Data[1]; /* Option data (dynamically allocated) */
-} O65Option;
+};
/* o65 relocation entry */
-typedef struct {
+typedef struct O65Reloc O65Reloc;
+struct O65Reloc {
unsigned long Offs; /* Offset in segment */
unsigned char Type; /* Relocation type */
unsigned char SegID; /* Segment ID */
unsigned Val; /* Any offset value needed for relocation */
unsigned long SymIdx; /* Index into list of imported symbols */
-} O65Reloc;
+};
/* o65 import */
-typedef struct {
+typedef struct O65Import O65Import;
+struct O65Import {
char Name[1]; /* Name of the import (dynamically allocated) */
-} O65Import;
+};
/* o65 export */
-typedef struct {
+typedef struct O65Export O65Export;
+struct O65Export {
unsigned char SegID; /* Segment ID */
unsigned long Val; /* Relocation value */
char Name[1]; /* Name of the export (dynamically allocated) */
-} O65Export;
+};
/* Complete o65 file data */
-typedef struct {
+typedef struct O65Data O65Data;
+struct O65Data {
O65Header Header; /* File header */
Collection Options; /* O65 options */
unsigned char* Text; /* Text segment data (unrelocated) */
Collection DataReloc; /* Relocation entries for the data segment */
Collection Imports; /* Imported symbols */
Collection Exports; /* Exported symbols */
-} O65Data;
+};