Added -p command line option to allow selection of port dependent processor.
[fw/sdcc] / src / SDCCmain.c
index a87109afb9b5282ba0a648d9e7f7368591ddc5c0..fa2883d36e1f5f130f4d7ec6e7d6c443e61f851b 100644 (file)
@@ -28,6 +28,8 @@
 #include "SDCCerr.h"
 #include "BuildCmd.h"
 #include "MySystem.h"
+#include "SDCCmacro.h"
+#include "SDCCutil.h"
 
 #if NATIVE_WIN32
 #include <process.h>
 #include "spawn.h"
 #endif
 
-// This is a bit messy because we define link ourself
 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
-
+#include <sys/stat.h>
 #include <unistd.h>
-
-#else
-// No unistd.h in Borland C++
-/*
-extern int access (const char *, int);
-#define X_OK 1
-*/
-
 #endif
 
+/** Name of the environment variable checked for other instalations. */
+#define SDCCDIR_NAME "SDCCDIR"
+
 //REMOVE ME!!!
 extern int yyparse ();
 
@@ -61,7 +57,7 @@ const char *preArgv[128];     /* pre-processor arguments  */
 int currRegBank = 0;
 struct optimize optimize;
 struct options options;
-char *VersionString = SDCC_VERSION_STR /*"Version 2.1.8a" */ ;
+char *VersionString = SDCC_VERSION_STR;
 int preProcOnly = 0;
 int noAssemble = 0;
 char *linkOptions[128];
@@ -75,8 +71,16 @@ int nrelFiles = 0;
 bool verboseExec = FALSE;
 char *preOutName;
 
+/* uncomment JAMIN_DS390 to always override and use ds390 port
+  for mcs51 work.  This is temporary, for compatibility testing. */
+/* #define JAMIN_DS390 */
+#ifdef JAMIN_DS390
+int ds390_jammed = 0;
+#endif
+
 // Globally accessible scratch buffer for file names.
-char scratchFileName[FILENAME_MAX];
+char scratchFileName[PATH_MAX];
+char buffer[PATH_MAX];
 
 // In MSC VC6 default search path for exe's to path for this
 
@@ -109,6 +113,7 @@ char DefaultExePath[128];
 #define OPTION_LESS_PEDANTIC   "--lesspedantic"
 #define OPTION_NO_GCSE         "--nogcse"
 #define OPTION_SHORT_IS_8BITS  "--short-is-8bits"
+#define OPTION_TINI_LIBID      "--tini-libid"
 
 /** Table of all options supported by all ports.
     This table provides:
@@ -133,6 +138,7 @@ typedef struct {
 static const OPTION 
 optionsTable[] = {
     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
+    { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
     { 'd',  NULL,                   NULL, NULL },
     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
@@ -141,16 +147,17 @@ optionsTable[] = {
     { 'C',  NULL,                   NULL, "Preprocessor option" },
     { 'M',  NULL,                   NULL, "Preprocessor option" },
     { 'V',  NULL,                   &verboseExec, "Execute verbosely.  Show sub commands as they are run" },
-    { 'S',  NULL,                   &noAssemble, "Assemble only" },
-    { 'W',  NULL,                   NULL, "Pass through options to the assembler (a) or linker (l)" },
+    { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
+    { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
-    { 0,    OPTION_LARGE_MODEL,     NULL, "Far functions, far data" },
-    { 0,    OPTION_MEDIUM_MODEL,    NULL, "Far functions, near data" },
-    { 0,    OPTION_SMALL_MODEL,     NULL, "Small model (default)" },
-    { 0,    OPTION_FLAT24_MODEL,    NULL, NULL },
+    { 'l',  NULL,                   NULL, "Include the given library in the link" },
+    { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
+    { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
+    { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
+    { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
-    { 0,    OPTION_STACK_8BIT,      NULL, NULL },
-    { 0,    "--stack-10bit",        &options.stack10bit, NULL },
+    { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
+    { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
     { 0,    "--generic",            &options.genericPtr, "All unqualified ptrs converted to '_generic'" },
     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
@@ -158,8 +165,7 @@ optionsTable[] = {
     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
-    { 0,    "--regextend",          &options.regExtend, NULL },
-    { 'c',  "--compile-only",       &options.cc_only, "Compile only, do not assemble or link" },
+    { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
     { 0,    "--dumploop",           &options.dump_loop, NULL },
@@ -167,16 +173,17 @@ optionsTable[] = {
     { 0,    "--dumpliverange",      &options.dump_range, NULL },
     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
+    { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
-    { 0,    OPTION_XRAM_LOC,        NULL, NULL },
+    { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
-    { 0,    OPTION_PEEP_FILE,       NULL, NULL },
-    { 0,    OPTION_LIB_PATH,        NULL, NULL },
+    { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
+    { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
@@ -184,21 +191,30 @@ optionsTable[] = {
     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
     { 0,    "--nooverlay",          &options.noOverlay, NULL },
     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
+    { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
+    { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
     { 0,    "--peep-asm",           &options.asmpeep, NULL },
     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
-    { 0,    "--nodebug",            &options.nodebug, "Disable debugging symbol output" },
     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
-    { 0,    "--stack-after-data",   &options.stackOnData, NULL },
+    { 0,    "--stack-after-data",   &options.stackOnData, "initialize the stackpointer with the last byte use in DSEG" },
     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The input is preprocessed code, the output is assembly code." },
     { 0,    "--help",               NULL, "Display this help" },
-    { 0,    OPTION_CALLEE_SAVES,    NULL, "Cause the called function to save registers insted of the caller" },
+    { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
-    { 0,    "--nostdinc",           &options.nostdinc, NULL },
+    { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
-    { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" }
+    { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
+    { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
+    { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
+    { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
+    { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
+    { 0,    "--stack-probe",               &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
+    { 0,    "--tini-libid",        NULL,"<nnnn> LibraryID used in -mTININative"},
+    { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
+    { 0,    "--parms-in-bank1",            &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"}
 };
 
 /** Table of all unsupported options and help text to display when one
@@ -220,20 +236,24 @@ unsupportedOptTable[] = {
     { 'g',  NULL,      "use --generic instead" },
     { 'X',  NULL,      "use --xstack-loc instead" },
     { 'x',  NULL,      "use --xstack instead" },
-    { 'p',  NULL,      "use --stack-loc instead" },
-    { 'P',  NULL,      "use --stack-loc instead" },
     { 'i',  NULL,      "use --idata-loc instead" },
     { 'r',  NULL,      "use --xdata-loc instead" },
     { 's',  NULL,      "use --code-loc instead" },
     { 'Y',  NULL,      "use -I instead" }
 };
 
-static const char *_preCmd[] =
-{
-  "sdcpp", "-Wall", "-lang-c++", "-DSDCC=1",
-  "$l", "$1", "$2", NULL
+/** List of all default constant macros.
+ */
+static const char *_baseValues[] = {
+  "cpp", "{bindir}{sep}sdcpp",
+  "cppextraopts", "",
+  /* Path seperator character */
+  "sep", DIR_SEPARATOR_STRING,
+  NULL
 };
 
+static const char *_preCmd = "{cpp} -Wall -lang-c++ -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
+
 PORT *port;
 
 static PORT *_ports[] =
@@ -262,14 +282,19 @@ static PORT *_ports[] =
 #if !OPT_DISABLE_TLCS900H
   &tlcs900h_port,
 #endif
+#if !OPT_DISABLE_TININative
+  &tininative_port,
+#endif
+#if !OPT_DISABLE_XA51
+  &xa51_port,
+#endif
 };
 
 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
 
-/**
-   remove me - TSD a hack to force sdcc to generate gpasm format .asm files.
- */
+#if !OPT_DISABLE_PIC
 extern void picglue ();
+#endif
 
 /** Sets the port to the one given by the command line option.
     @param    The name minus the option (eg 'mcs51')
@@ -300,11 +325,34 @@ _validatePorts (void)
     {
       if (_ports[i]->magic != PORT_MAGIC)
        {
-         printf ("Error: port %s is incomplete.\n", _ports[i]->target);
-         wassert (0);
+         /* Uncomment this line to debug which port is causing the problem
+          * (the target name is close to the beginning of the port struct 
+          * and probably can be accessed just fine). */
+         fprintf(stderr,"%s :",_ports[i]->target);
+         wassertl (0, "Port definition structure is incomplete");
        }
     }
 }
+
+/* search through the command line options for the port */
+static void
+_findPort (int argc, char **argv)
+{
+  _validatePorts ();
+
+  while (argc--)
+    {
+      if (!strncmp (*argv, "-m", 2))
+       {
+         _setPort (*argv + 2);
+         return;
+       }
+      argv++;
+    }
+  /* Use the first in the list */
+  port = _ports[0];
+}
+
 /*-----------------------------------------------------------------*/
 /* printVersionInfo - prints the version info        */
 /*-----------------------------------------------------------------*/
@@ -322,8 +370,9 @@ printVersionInfo ()
 #ifdef SDCC_SUB_VERSION_STR
           "/" SDCC_SUB_VERSION_STR
 #endif
-#ifdef __CYGWIN32__
-          " (CYGWIN32)\n"
+           " (" __DATE__ ")"
+#ifdef __CYGWIN__
+          " (CYGWIN)\n"
 #else
 #ifdef __DJGPP__
           " (DJGPP) \n"
@@ -340,27 +389,6 @@ printVersionInfo ()
     );
 }
 
-/*
-       "\t-m<proc>             -     Target processor <proc>.  Default %s\n"
-          "\t                           Try --version for supported values of <proc>\n"
-          "\t--model-large        -     Large Model\n"
-          "\t--model-small        -     Small Model (default)\n"
-          "\t--stack-auto         -     Stack automatic variables\n"
-          "\t--xstack             -     Use external stack\n"
-          "\t--xram-loc <nnnn>    -     External Ram start location\n"
-          "\t--xstack-loc <nnnn>  -     Xternal Stack Location\n"
-          "\t--code-loc <nnnn>    -     Code Segment Location\n"
-          "\t--stack-loc <nnnn>   -     Stack pointer initial value\n"
-          "\t--data-loc <nnnn>    -     Direct data start location\n"
-          "\t--idata-loc <nnnn>   -     Indirect data start location\n"
-          "\t--iram-size <nnnn>   -     Internal Ram size\n"
-          "\t--nojtbound          -     Don't generate boundary check for jump tables\n"
-          "\t--generic            -     All unqualified ptrs converted to '_generic'\n"
-          "PreProcessor Options :-\n"
-          "\t-Dmacro   - Define Macro\n"
-          "\t-Ipath    - Include \"*.h\" path\n"
-      "Note: this is NOT a complete list of options see docs for details\n",
-*/
 /*-----------------------------------------------------------------*/
 /* printUsage - prints command line syntax         */
 /*-----------------------------------------------------------------*/
@@ -393,7 +421,7 @@ parseWithComma (char **dest, char *src)
 {
   int i = 0;
 
-  strtok (src, "\n \t");
+  strtok (src, "\r\n \t");
   /* skip the initial white spaces */
   while (isspace (*src))
     src++;
@@ -438,7 +466,7 @@ setDefaultOptions ()
   options.nostdlib = 0;
   options.nostdinc = 0;
   options.verbose = 0;
-  options.shortis8bits = 1;
+  options.shortis8bits = 0;
 
   options.stack10bit=0;
 
@@ -493,14 +521,21 @@ processFile (char *s)
        {
          werror (E_FILE_OPEN_ERR, s);
          exit (1);
-       }
+       }
 
       /* copy the file name into the buffer */
       strcpy (buffer, s);
 
-      /* get rid of the "." */
-      strtok (buffer, ".");
-      srcFileName = Safe_calloc (1, strlen (buffer) + 1);
+      /* get rid of the "."-extension */
+
+      /* is there a dot at all? */
+      if (strchr (buffer, '.') &&
+          /* is the dot in the filename, not in the path? */
+          (strrchr (buffer, '/' ) < strrchr (buffer, '.') ||
+           strrchr (buffer, '\\') < strrchr (buffer, '.')))
+        *strrchr (buffer, '.') = '\0';
+
+      srcFileName = Safe_alloc ( strlen (buffer) + 1);
       strcpy (srcFileName, buffer);
 
       /* get rid of any path information
@@ -513,7 +548,7 @@ processFile (char *s)
             *(fext - 1) != '/' &&
             *(fext - 1) != ':')
        fext--;
-      moduleName = Safe_calloc (1, strlen (fext) + 1);
+      moduleName = Safe_alloc ( strlen (fext) + 1);
       strcpy (moduleName, fext);
 
       return;
@@ -550,7 +585,7 @@ _processC1Arg (char *s)
          werror (W_TOO_MANY_SRC, s);
          return;
        }
-      options.out_name = strdup (s);
+      options.out_name = Safe_strdup (s);
     }
   else
     {
@@ -558,21 +593,6 @@ _processC1Arg (char *s)
     }
 }
 
-static void
-_addToList (const char **list, const char *str)
-{
-  /* This is the bad way to do things :) */
-  while (*list)
-    list++;
-  *list = strdup (str);
-  if (!*list)
-    {
-      werror (E_OUT_OF_MEM, __FILE__, 0);
-      exit (1);
-    }
-  *(++list) = NULL;
-}
-
 static void
 _setModel (int model, const char *sz)
 {
@@ -582,17 +602,36 @@ _setModel (int model, const char *sz)
     werror (W_UNSUPPORTED_MODEL, sz, port->target);
 }
 
+static void
+_setProcessor (char *_processor)
+{
+  port->processor = _processor;
+  fprintf(stderr,"Processor: %s\n",_processor);
+}
+
 /** Gets the string argument to this option.  If the option is '--opt'
     then for input of '--optxyz' or '--opt xyz' returns xyz.
 */
 static char *
-getStringArg(const char *szStart, char **argv, int *pi)
+getStringArg(const char *szStart, char **argv, int *pi, int argc)
 {
-    if (argv[*pi][strlen(szStart)]) {
-        return &argv[*pi][strlen(szStart)];
+  if (argv[*pi][strlen(szStart)]) 
+    {
+      return &argv[*pi][strlen(szStart)];
     }
-    else {
-        return argv[++(*pi)];
+  else 
+    {
+      ++(*pi);
+      if (*pi >= argc) 
+        {
+          werror (E_ARGUMENT_MISSING, szStart);
+          /* Die here rather than checking for errors later. */
+          exit(-1);
+        }
+      else 
+        {
+          return argv[*pi];
+        }
     }
 }
 
@@ -600,9 +639,18 @@ getStringArg(const char *szStart, char **argv, int *pi)
     getStringArg. 
 */
 static int
-getIntArg(const char *szStart, char **argv, int *pi)
+getIntArg(const char *szStart, char **argv, int *pi, int argc)
 {
-    return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi)));
+    return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
+}
+
+static void
+verifyShortOption(const char *opt)
+{
+  if (strlen(opt) != 2)
+    {
+      werror (W_EXCESS_SHORT_OPTIONS, opt);
+    }
 }
 
 static bool
@@ -664,22 +712,29 @@ tryHandleSimpleOpt(char **argv, int *pi)
                 }
 
             for (i = 0; i < LENGTH(optionsTable); i++) 
-                {
-                    if (optionsTable[i].shortOpt == shortOpt || 
-                        (longOpt && optionsTable[i].longOpt && strcmp(optionsTable[i].longOpt, longOpt) == 0))
-                        {
-                            // If it is a flag then we can handle it here
-                            if (optionsTable[i].pparameter != NULL) 
-                                {
-                                    (*optionsTable[i].pparameter)++;
-                                    return 1;
-                                }
-                            else {
-                                // Not a flag.  Handled manually later.
-                                return 0;
-                            }
-                        }
-                }
+              {
+                if (optionsTable[i].shortOpt == shortOpt ||
+                    (longOpt && optionsTable[i].longOpt && 
+                     strcmp(optionsTable[i].longOpt, longOpt) == 0))
+                  {
+
+                    // If it is a flag then we can handle it here
+                    if (optionsTable[i].pparameter != NULL) 
+                      {
+                        if (optionsTable[i].shortOpt == shortOpt)
+                          {
+                            verifyShortOption(argv[*pi]);
+                          }
+
+                        (*optionsTable[i].pparameter)++;
+                        return 1;
+                      }
+                    else {
+                      // Not a flag.  Handled manually later.
+                      return 0;
+                    }
+                  }
+              }
             // Didn't find in the table
             return 0;
         }
@@ -773,13 +828,13 @@ parseCmdLine (int argc, char **argv)
 
          if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
            {
-                options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i);
+                options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
             {
-               libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i);
+               libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
                 continue;
            }
 
@@ -792,49 +847,49 @@ parseCmdLine (int argc, char **argv)
 
          if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
            {
-                parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i));
+                parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
            {
-                options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i);
+                options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
            {
-                options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i);
+                options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
            {
-                options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i);
+                options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
            {
-                options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i);
+                options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
            {
-                options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i);
+                options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
            {
-                options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i);
+                options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
                 continue;
            }
 
          if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
            {
-                options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i);
+                options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
                 continue;
            }
 
@@ -857,15 +912,23 @@ parseCmdLine (int argc, char **argv)
            }
 
           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
-              {
-                  setErrorLogLevel(ERROR_LEVEL_WARNING);
-                  continue;
-              }
+            {
+             options.lessPedantic = 1;
+              setErrorLogLevel(ERROR_LEVEL_WARNING);
+              continue;
+            }
 
-         if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) {
-           options.shortis8bits=1;
-           continue;
-         }
+         if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
+            {
+              options.shortis8bits=1;
+              continue;
+            }
+
+         if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
+           {
+                options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
+                continue;
+           }
           
          if (!port->parseOption (&argc, argv, &i))
            {
@@ -883,6 +946,8 @@ parseCmdLine (int argc, char **argv)
          switch (argv[i][1])
            {
            case 'h':
+              verifyShortOption(argv[i]);
+
              printUsage ();
              exit (0);
              break;
@@ -892,35 +957,50 @@ parseCmdLine (int argc, char **argv)
              _setPort (argv[i] + 2);
              break;
 
+           case 'p':
+             /* Used to select the processor in port */
+             _setProcessor (getStringArg("-p", argv, &i, argc));
+             break;
+
            case 'c':
+              verifyShortOption(argv[i]);
+
              options.cc_only = 1;
              break;
 
            case 'L':
-                libPaths[nlibPaths++] = getStringArg("-L", argv, &i);
+                libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
+                break;
+
+            case 'l':
+                libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
                 break;
 
            case 'W':
+              /* pre-processer options */
+              if (argv[i][2] == 'p')
+                {
+                  parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
+                }
              /* linker options */
-             if (argv[i][2] == 'l')
+             else if (argv[i][2] == 'l')
                {
-                    parseWithComma(linkOptions, getStringArg("-Wl", argv, &i));
-               }
-             else
-               {
-                 /* assembler options */
-                 if (argv[i][2] == 'a')
-                   {
-                       parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i));
-                   }
-                 else
-                   {
-                     werror (W_UNKNOWN_OPTION, argv[i]);
-                   }
+                  parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
                }
+              /* assembler options */
+             else if (argv[i][2] == 'a')
+                {
+                  parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
+                }
+              else
+                {
+                  werror (W_UNKNOWN_OPTION, argv[i]);
+                }
              break;
 
            case 'v':
+              verifyShortOption(argv[i]);
+
              printVersionInfo ();
              exit (0);
              break;
@@ -929,12 +1009,12 @@ parseCmdLine (int argc, char **argv)
            case 'M':
              {
                preProcOnly = 1;
-               _addToList (preArgv, "-M");
+               addToList (preArgv, "-M");
                break;
              }
            case 'C':
              {
-               _addToList (preArgv, "-C");
+               addToList (preArgv, "-C");
                break;
              }
            case 'd':
@@ -967,7 +1047,7 @@ parseCmdLine (int argc, char **argv)
                  sOpt = 'I';
 
                sprintf (buffer, "-%c%s", sOpt, rest);
-               _addToList (preArgv, buffer);
+               addToList (preArgv, buffer);
              }
              break;
 
@@ -993,7 +1073,7 @@ parseCmdLine (int argc, char **argv)
     options.xstack_loc = options.xdata_loc;
 
   /* if debug option is set the open the cdbFile */
-  if (!options.nodebug && srcFileName)
+  if (options.debug && srcFileName)
     {
       sprintf (scratchFileName, "%s.cdb", srcFileName);
       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
@@ -1035,14 +1115,14 @@ linkEdit (char **envp)
   if (options.iram_size)
     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
 
-  /*if (options.debug) */
-  fprintf (lnkfile, "-z\n");
+  if (options.debug)
+    fprintf (lnkfile, "-z\n");
 
 #define WRITE_SEG_LOC(N, L) \
-    segName = strdup(N); \
+    segName = Safe_strdup(N); \
     c = strtok(segName, " \t"); \
     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
-    if (segName) { free(segName); }
+    if (segName) { Safe_free(segName); }
 
   /* code segment start */
   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
@@ -1054,7 +1134,9 @@ linkEdit (char **envp)
   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
 
   /* indirect data */
-  WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
+  if (IDATA_NAME) {
+    WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
+  }
 
   /* bit segment start */
   WRITE_SEG_LOC (BIT_NAME, 0);
@@ -1070,36 +1152,44 @@ linkEdit (char **envp)
   /* standard library path */
   if (!options.nostdlib)
     {
-      if (TARGET_IS_DS390)
+      switch (options.model)
        {
+       case MODEL_SMALL:
+         c = "small";
+         break;
+       case MODEL_LARGE:
+         c = "large";
+         break;
+       case MODEL_FLAT24:
+         /* c = "flat24"; */
          c = "ds390";
+         break;
+       case MODEL_PAGE0:
+         c = "xa51";
+         break;
+       default:
+         werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+         c = "unknown";
+         break;
        }
-      else
-       {
-         switch (options.model)
-           {
-           case MODEL_SMALL:
-             c = "small";
-             break;
-           case MODEL_LARGE:
-             c = "large";
-             break;
-           case MODEL_FLAT24:
-             c = "flat24";
-             break;
-           default:
-             werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
-             c = "unknown";
-             break;
-           }
-       }
-      fprintf (lnkfile, "-k %s/%s\n", SDCC_LIB_DIR /*STD_LIB_PATH */ , c);
+      mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
 
       /* standard library files */
-      if (strcmp (port->target, "ds390") == 0)
+#if !OPT_DISABLE_DS390
+      if (options.model == MODEL_FLAT24)
        {
          fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
        }
+#endif
+
+#if !OPT_DISABLE_XA51 
+#ifdef STD_XA51_LIB
+      if (options.model == MODEL_PAGE0)
+       {
+         fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
+       }
+#endif
+#endif
       fprintf (lnkfile, "-l %s\n", STD_LIB);
       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
@@ -1123,7 +1213,17 @@ linkEdit (char **envp)
   if (options.verbose)
     printf ("sdcc: Calling linker...\n");
 
-  buildCmdLine (buffer, port->linker.cmd, srcFileName, NULL, NULL, NULL);
+  if (port->linker.cmd)
+    {
+      char buffer2[PATH_MAX];
+      buildCmdLine (buffer2, port->linker.cmd, srcFileName, NULL, NULL, NULL);
+      buildCmdLine2 (buffer, buffer2);
+    }
+  else
+    {
+      buildCmdLine2 (buffer, port->linker.mcmd);
+    }
+
   if (my_system (buffer))
     {
       exit (1);
@@ -1132,7 +1232,7 @@ linkEdit (char **envp)
   if (strcmp (srcFileName, "temp") == 0)
     {
       /* rename "temp.cdb" to "firstRelFile.cdb" */
-      char *f = strtok (strdup (relFiles[0]), ".");
+      char *f = strtok (Safe_strdup (relFiles[0]), ".");
       f = strcat (f, ".cdb");
       rename ("temp.cdb", f);
       srcFileName = NULL;
@@ -1145,17 +1245,24 @@ linkEdit (char **envp)
 static void
 assemble (char **envp)
 {
-  buildCmdLine (buffer, port->assembler.cmd, srcFileName, NULL, NULL, asmOptions);
-  if (my_system (buffer))
-    {
-      /* either system() or the assembler itself has reported an error
-         perror ("Cannot exec assembler");
-       */
-      exit (1);
+    if (port->assembler.do_assemble) {
+       port->assembler.do_assemble(asmOptions);
+       return ;
+    } else if (port->assembler.cmd) {
+       buildCmdLine (buffer, port->assembler.cmd, srcFileName, NULL,
+                     options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
+                     asmOptions);
+    } else {
+       buildCmdLine2 (buffer, port->assembler.mcmd);
     }
-}
-
 
+    if (my_system (buffer)) {
+       /* either system() or the assembler itself has reported an error
+          perror ("Cannot exec assembler");
+       */
+       exit (1);
+    }
+}
 
 /*-----------------------------------------------------------------*/
 /* preProcess - spawns the preprocessor with arguments       */
@@ -1163,73 +1270,81 @@ assemble (char **envp)
 static int
 preProcess (char **envp)
 {
-  char procDef[128];
-
   preOutName = NULL;
 
   if (!options.c1mode)
     {
       /* if using external stack define the macro */
       if (options.useXstack)
-       _addToList (preArgv, "-DSDCC_USE_XSTACK");
+       addToList (preArgv, "-DSDCC_USE_XSTACK");
 
       /* set the macro for stack autos  */
       if (options.stackAuto)
-       _addToList (preArgv, "-DSDCC_STACK_AUTO");
+       addToList (preArgv, "-DSDCC_STACK_AUTO");
 
       /* set the macro for stack autos  */
       if (options.stack10bit)
-       _addToList (preArgv, "-DSDCC_STACK_TENBIT");
+       addToList (preArgv, "-DSDCC_STACK_TENBIT");
+
+      /* set the macro for no overlay  */
+      if (options.noOverlay)
+        addToList (preArgv, "-DSDCC_NOOVERLAY");
 
       /* set the macro for large model  */
       switch (options.model)
        {
        case MODEL_LARGE:
-         _addToList (preArgv, "-DSDCC_MODEL_LARGE");
+         addToList (preArgv, "-DSDCC_MODEL_LARGE");
          break;
        case MODEL_SMALL:
-         _addToList (preArgv, "-DSDCC_MODEL_SMALL");
+         addToList (preArgv, "-DSDCC_MODEL_SMALL");
          break;
        case MODEL_COMPACT:
-         _addToList (preArgv, "-DSDCC_MODEL_COMPACT");
+         addToList (preArgv, "-DSDCC_MODEL_COMPACT");
          break;
        case MODEL_MEDIUM:
-         _addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
+         addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
          break;
        case MODEL_FLAT24:
-         _addToList (preArgv, "-DSDCC_MODEL_FLAT24");
+         addToList (preArgv, "-DSDCC_MODEL_FLAT24");
+         break;
+       case MODEL_PAGE0:
+         addToList (preArgv, "-DSDCC_MODEL_PAGE0");
          break;
        default:
          werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
          break;
        }
 
+      /* add port (processor information to processor */
+      addToList (preArgv, "-DSDCC_{port}");
+      addToList (preArgv, "-D__{port}");
+
       /* standard include path */
       if (!options.nostdinc) {
-       _addToList (preArgv, "-I" SDCC_INCLUDE_DIR);
+       addToList (preArgv, "-I{includedir}");
       }
 
-      /* add port (processor information to processor */
-      sprintf (procDef, "-DSDCC_%s", port->target);
-      _addToList (preArgv, procDef);
-      sprintf (procDef, "-D__%s", port->target);
-      _addToList (preArgv, procDef);
-
+      setMainValue ("cppextraopts", join(preArgv));
+      
       if (!preProcOnly)
-       preOutName = strdup (tmpnam (NULL));
+          preOutName = Safe_strdup (tempfilename ());
 
+      /* Have to set cppoutfilename to something, even if just pre-processing. */
+      setMainValue ("cppoutfilename", preOutName ? preOutName : "");
+       
       if (options.verbose)
        printf ("sdcc: Calling preprocessor...\n");
 
-      buildCmdLine (buffer, _preCmd, fullSrcFileName,
-                   preOutName, srcFileName, preArgv);
+      buildCmdLine2 (buffer, _preCmd);
+
       if (my_system (buffer))
        {
           // @FIX: Dario Vecchio 03-05-2001
           if (preOutName)
             {
               unlink (preOutName);
-              free (preOutName);
+              Safe_free (preOutName);
             }
           // EndFix
          exit (1);
@@ -1255,22 +1370,145 @@ preProcess (char **envp)
   return 0;
 }
 
-static void
-_findPort (int argc, char **argv)
+static bool
+_setPaths (const char *pprefix)
 {
-  _validatePorts ();
+  /* Logic:
+      Given the prefix and how the directories were layed out at
+      configure time, see if the library and include directories are
+      where expected.  If so, set.
+  */
+  getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
+  strcpy (scratchFileName, pprefix);
+  strcat (scratchFileName, buffer);
+
+  if (pathExists (scratchFileName))
+    {
+      setMainValue ("includedir", scratchFileName);
+    }
+  else
+    {
+      return FALSE;
+    }
 
-  while (argc--)
+  getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
+  strcpy (scratchFileName, pprefix);
+  strcat (scratchFileName, buffer);
+
+  if (pathExists (scratchFileName))
     {
-      if (!strncmp (*argv, "-m", 2))
-       {
-         _setPort (*argv + 2);
-         return;
-       }
-      argv++;
+      setMainValue ("libdir", scratchFileName);
     }
-  /* Use the first in the list */
-  port = _ports[0];
+  else
+    {
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+_discoverPaths (const char *argv0)
+{
+  /* Logic:
+      1.  Try the SDCCDIR environment variable.
+      2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
+      and library paths with respect to that.  Note that under win32
+      argv[0] is always the full path to the program.
+      3.  If (1) and (2) fail, fall back to the compile time defaults.
+
+      Detecting assumes the same layout as when configured.  If the
+      directories have been further moved about then discovery will
+      fail.
+  */
+
+  /* Some input cases:
+        "c:\fish\sdcc\bin\sdcc"
+        "../bin/sdcc"
+        "/home/fish/bin/sdcc"
+
+      Note that ./sdcc is explicitly not supported as there isn't
+      enough information.
+  */
+  /* bindir is handled differently to the lib and include directories.
+     It's rather unfortunate, but required due to the different
+     install and development layouts.  Logic is different as well.
+     Sigh.
+   */
+  if (strchr (argv0, DIR_SEPARATOR_CHAR))
+    {
+      strcpy (scratchFileName, argv0);
+      *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
+      setMainValue ("bindir", scratchFileName);
+      ExePathList[0] = Safe_strdup (scratchFileName);
+    }
+  else if (getenv (SDCCDIR_NAME) != NULL)
+    {
+      getPathDifference (buffer, PREFIX, BINDIR);
+      strcpy (scratchFileName, getenv (SDCCDIR_NAME));
+      strcat (scratchFileName, buffer);
+      setMainValue ("bindir", scratchFileName);
+      ExePathList[0] = Safe_strdup (scratchFileName);
+    }
+  else
+    {
+      setMainValue ("bindir", BINDIR);
+      ExePathList[0] = BINDIR;
+    }
+
+  do 
+    {
+      /* Case 1 */
+      if (getenv (SDCCDIR_NAME) != NULL)
+        {
+          if (_setPaths (getenv (SDCCDIR_NAME)))
+            {
+              /* Successfully set. */
+              break;
+            }
+          else
+            {
+              /* Include and lib weren't where expected. */
+            }
+        }
+      /* Case 2 */
+      if (strchr (argv0, DIR_SEPARATOR_CHAR))
+        {
+          char *pbase = getPrefixFromBinPath (argv0);
+
+          if (pbase == NULL)
+            {
+              /* A bad path.  Skip. */
+            }
+          else
+            {
+              if (_setPaths (pbase))
+                {
+                  /* Successfully set. */
+                  break;
+                }
+              else
+                {
+                  /* Include and lib weren't where expected. */
+                }
+            }
+        }
+      /* Case 3 */
+      setMainValue ("includedir", SDCC_INCLUDE_DIR);
+      setMainValue ("libdir", SDCC_LIB_DIR);
+    } while (0);
+}
+
+static void
+initValues (void)
+{
+  populateMainValues (_baseValues);
+  setMainValue ("port", port->target);
+  setMainValue ("objext", port->linker.rel_ext);
+  setMainValue ("asmext", port->assembler.file_ext);
+
+  setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
+  setMainValue ("srcfilename", srcFileName ? srcFileName : "srcfilename");
 }
 
 /*
@@ -1292,6 +1530,13 @@ main (int argc, char **argv, char **envp)
   }
 
   _findPort (argc, argv);
+#ifdef JAMIN_DS390
+  if (strcmp(port->target, "mcs51") == 0) {
+    printf("DS390 jammed in A\n");
+         _setPort ("ds390");
+    ds390_jammed = 1;
+  }
+#endif
   /* Initalise the port. */
   if (port->init)
     port->init ();
@@ -1299,22 +1544,15 @@ main (int argc, char **argv, char **envp)
   // Create a default exe search path from the path to the sdcc command
 
 
-
-  if (strchr (argv[0], DIR_SEPARATOR_CHAR))
-    {
-      strcpy (DefaultExePath, argv[0]);
-      *(strrchr (DefaultExePath, DIR_SEPARATOR_CHAR)) = 0;
-      ExePathList[0] = DefaultExePath;
-    }
-
-
   setDefaultOptions ();
+#ifdef JAMIN_DS390
+  if (ds390_jammed) {
+    options.model = MODEL_SMALL;
+    options.stack10bit=0;
+  }
+#endif
   parseCmdLine (argc, argv);
 
-  initMem ();
-
-  port->finaliseOptions ();
-
   /* if no input then printUsage & exit */
   if ((!options.c1mode && !srcFileName && !nrelFiles) || 
       (options.c1mode && !srcFileName && !options.out_name))
@@ -1323,13 +1561,21 @@ main (int argc, char **argv, char **envp)
       exit (0);
     }
 
+  initValues ();
+  _discoverPaths (argv[0]);
+
   if (srcFileName)
     {
+
+      initMem ();
+
+      port->finaliseOptions ();
       preProcess (envp);
 
       initSymt ();
       initiCode ();
       initCSupport ();
+      initBuiltIns();
       initPeepHole ();
 
       if (options.verbose)
@@ -1360,12 +1606,12 @@ main (int argc, char **argv, char **envp)
                   if (yyin && yyin != stdin)
                     fclose (yyin);
                   unlink (preOutName);
-                  free (preOutName);
+                  Safe_free (preOutName);
                 }
               // EndFix
              return 1;
            }
-         if (!options.c1mode)
+         if (!options.c1mode && !noAssemble)
            {
              if (options.verbose)
                printf ("sdcc: Calling assembler...\n");
@@ -1380,9 +1626,12 @@ main (int argc, char **argv, char **envp)
               if (yyin && yyin != stdin)
                 fclose (yyin);
               unlink (preOutName);
-              free (preOutName);
+              Safe_free (preOutName);
             }
           // EndFix
+          #if defined (__MINGW32__) || defined (__CYGWIN__) || defined (_MSC_VER)
+          rm_tmpfiles();
+          #endif
          return 1;
        }
 
@@ -1393,6 +1642,12 @@ main (int argc, char **argv, char **envp)
   if (cdbFile)
     fclose (cdbFile);
 
+  if (preOutName && !options.c1mode)
+    {
+      unlink (preOutName);
+      Safe_free (preOutName);
+    }
+
   if (!options.cc_only &&
       !fatalError &&
       !noAssemble &&
@@ -1408,12 +1663,6 @@ main (int argc, char **argv, char **envp)
   if (yyin && yyin != stdin)
     fclose (yyin);
 
-  if (preOutName && !options.c1mode)
-    {
-      unlink (preOutName);
-      free (preOutName);
-    }
-
   return 0;
 
 }