Added pCode to the PIC port
authorsdattalo <sdattalo@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 18 Feb 2001 04:16:09 +0000 (04:16 +0000)
committersdattalo <sdattalo@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 18 Feb 2001 04:16:09 +0000 (04:16 +0000)
git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@627 4a8a32a2-be11-0410-ad9d-d568d2c75423

src/pic/Makefile
src/pic/Makefile.bcc
src/pic/glue.c
src/pic/pcode.c [new file with mode: 0644]
src/pic/pcode.h [new file with mode: 0644]

index c9556e90ef7f4c1faf473e300946e8a5ec8fefef..aad06b82e5a6c7dda4b96166132df467ac452769 100644 (file)
@@ -2,7 +2,7 @@ PRJDIR = ../..
 
 include $(PRJDIR)/Makefile.common
 
-OBJ = gen.o ralloc.o main.o glue.o
+OBJ = gen.o ralloc.o main.o glue.o pcode.o
 LIB = port.a
 
 CFLAGS = -ggdb -Wall -O2
@@ -10,6 +10,11 @@ CFLAGS += -I.. -I. -I../..
 
 all: $(LIB)
 
+#hmm, now why don't we use automake instead of hardcoding
+#the dependencies?
+pcode.o: pcode.h
+gen.o: pcode.h
+
 main.o: main.c peeph.rul
 
 $(LIB): peeph.rul $(OBJ)
index 4b17a92d6e87baf9e768207bae6bdda19fbbcf13..4e0e747091b1b47211eee240a8cf888d90c3bb9f 100644 (file)
@@ -2,7 +2,7 @@ PRJDIR = ../..
 
 # !include $(PRJDIR)/Makefile.common
 
-OBJ = gen.obj ralloc.obj main.obj
+OBJ = gen.obj ralloc.obj main.obj pcode.obj
 LIB = port.lib
 
 !include ..\..\Bcc.inc
@@ -15,7 +15,7 @@ main.obj: main.c peeph.rul
 $(LIB): peeph.rul $(OBJ)
        del $(LIB)
        tlib /a $(LIB) +gen.obj +ralloc.obj +main.obj
-       
+
 peeph.rul: peeph.def
         gawk -f ../SDCCpeeph.awk peeph.def > peeph.rul
 
index abd20a56c9949e9bfd2a6d378d25e0915db55f6e..c21c9d548a44913af4d015b17bf718f4bf752b13 100644 (file)
 #include "../common.h"
 #include <time.h>
 #include "ralloc.h"
+#include "pcode.h"
 #include "newalloc.h"
 
+
 extern symbol *interrupts[256];
 void printIval (symbol *, sym_link *, initList *, FILE *);
 extern int noAlloc;
@@ -71,41 +73,55 @@ aopLiteral (value * val, int offset)
      void printIvalPtr (symbol * sym, sym_link * type, initList * ilist, FILE * oFile)
 #endif
 
+/*-----------------------------------------------------------------*/
+/* Allocation macros that replace those in SDCCalloc.h             */
+/*   Why? I dunno. I ran across a bug with those macros that       */
+/*   I couldn't fix, but I could work around...                    */
+/*-----------------------------------------------------------------*/
+
+#define  _ALLOC(x,sz) if (!(x = calloc((sz),1) ))      \
+         {                                          \
+            werror(E_OUT_OF_MEM,__FILE__,(long) sz);\
+            exit (1);                               \
+         }
+
+#define _ALLOC_ATOMIC(x,y) if (!((x) = malloc(y)))   \
+         {                                               \
+            werror(E_OUT_OF_MEM,__FILE__,(long) y);     \
+            exit (1);                                    \
+         }
+
 
 /*-----------------------------------------------------------------*/
 /* aopLiteral - string from a literal value                        */
 /*-----------------------------------------------------------------*/
-     char *pic14aopLiteral (value * val, int offset)
+int pic14aopLiteral (value *val, int offset)
 {
-  char *rs;
-  union
-    {
-      float f;
-      unsigned char c[4];
-    }
-  fl;
+  union {
+    float f;
+    unsigned char c[4];
+  } fl;
 
   /* if it is a float then it gets tricky */
   /* otherwise it is fairly simple */
-  if (!IS_FLOAT (val->type))
-    {
-      unsigned long v = floatFromVal (val);
+  if (!IS_FLOAT(val->type)) {
+    unsigned long v = floatFromVal(val);
 
-      v >>= (offset * 8);
-      sprintf (buffer, "0x%02x", ((char) v) & 0xff);
-      rs = Safe_calloc (1, strlen (buffer) + 1);
-      return strcpy (rs, buffer);
-    }
+    //v >>= (offset * 8);
+    return ( (v >> (offset * 8)) & 0xff);
+    //sprintf(buffer,"0x%02x",((char) v) & 0xff);
+    //_ALLOC_ATOMIC(rs,strlen(buffer)+1);
+    //return strcpy (rs,buffer);
+  }
 
   /* it is type float */
-  fl.f = (float) floatFromVal (val);
-#ifdef _BIG_ENDIAN
-  sprintf (buffer, "0x%02x", fl.c[3 - offset]);
+  fl.f = (float) floatFromVal(val);
+#ifdef _BIG_ENDIAN    
+  return fl.c[3-offset];
 #else
-  sprintf (buffer, "0x%02x", fl.c[offset]);
+  return fl.c[offset];
 #endif
-  rs = Safe_calloc (1, strlen (buffer) + 1);
-  return strcpy (rs, buffer);
+
 }
 
 
@@ -214,21 +230,21 @@ pic14emitRegularMap (memmap * map, bool addPublics, bool arFlag)
            }
          //fprintf (map->oFile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type) & 0xffff);
        }
-
-      /* if it has a initial value then do it only if
-         it is a global variable */
-      if (sym->ival && sym->level == 0)
-       {
-         ast *ival = NULL;
-
-         if (IS_AGGREGATE (sym->type))
-           ival = initAggregates (sym, sym->ival, NULL);
-         else
-           ival = newNode ('=', newAst_VALUE (symbolVal (sym)),
-                    decorateType (resolveSymbols (list2expr (sym->ival))));
-         codeOutFile = statsg->oFile;
-         eBBlockFromiCode (iCodeFromAst (ival));
-         sym->ival = NULL;
+       
+       /* if it has a initial value then do it only if
+          it is a global variable */
+       if (sym->ival && sym->level == 0) {
+           ast *ival = NULL;
+           
+           if (IS_AGGREGATE (sym->type))
+               ival = initAggregates (sym, sym->ival, NULL);
+           else
+               ival = newNode ('=', newAst_VALUE(symbolVal (sym)),
+                               decorateType (resolveSymbols (list2expr (sym->ival))));
+           codeOutFile = statsg->oFile;
+           GcurMemmap = statsg;
+           eBBlockFromiCode (iCodeFromAst (ival));
+           sym->ival = NULL;
        }
     }
 }
@@ -978,81 +994,81 @@ pic14emitOverlay (FILE * afile)
 void
 pic14glue ()
 {
+
   FILE *vFile;
   FILE *asmFile;
-  FILE *ovrFile = tempfile ();
+  FILE *ovrFile = tempfile();
   int i;
 
-  addSetHead (&tmpfileSet, ovrFile);
+  addSetHead(&tmpfileSet,ovrFile);
   /* print the global struct definitions */
   if (options.debug)
-    cdbStructBlock (0, cdbFile);
+    cdbStructBlock (0,cdbFile);
 
-  vFile = tempfile ();
+  vFile = tempfile();
   /* PENDING: this isnt the best place but it will do */
-  if (port->general.glue_up_main)
-    {
-      /* create the interrupt vector table */
-      pic14createInterruptVect (vFile);
-    }
-
-  addSetHead (&tmpfileSet, vFile);
+  if (port->general.glue_up_main) {
+    /* create the interrupt vector table */
+    pic14createInterruptVect (vFile);
+  }
 
+  addSetHead(&tmpfileSet,vFile);
+    
   /* emit code for the all the variables declared */
   pic14emitMaps ();
   /* do the overlay segments */
-  pic14emitOverlay (ovrFile);
+  pic14emitOverlay(ovrFile);
 
-  /* now put it all together into the assembler file */
-  /* create the assembler file name */
 
-  if (!options.c1mode)
-    {
-      sprintf (buffer, srcFileName);
-      strcat (buffer, ".asm");
-    }
-  else
-    {
-      strcpy (buffer, options.out_name);
-    }
+  pcode_test();
 
-  if (!(asmFile = fopen (buffer, "w")))
-    {
-      werror (E_FILE_OPEN_ERR, buffer);
-      exit (1);
-    }
 
+  /* now put it all together into the assembler file */
+  /* create the assembler file name */
+    
+  if (!options.c1mode) {
+    sprintf (buffer, srcFileName);
+    strcat (buffer, ".asm");
+  }
+  else {
+    strcpy(buffer, options.out_name);
+  }
+
+  if (!(asmFile = fopen (buffer, "w"))) {
+    werror (E_FILE_OPEN_ERR, buffer);
+    exit (1);
+  }
+    
   /* initial comments */
   pic14initialComments (asmFile);
-
+    
   /* print module name */
   fprintf (asmFile, ";\t.module %s\n", moduleName);
-
+    
   /* Let the port generate any global directives, etc. */
   if (port->genAssemblerPreamble)
     {
-      port->genAssemblerPreamble (asmFile);
+      port->genAssemblerPreamble(asmFile);
     }
-
+    
   /* print the global variables in this module */
   pic14printPublics (asmFile);
-
+    
 
   /* copy the sfr segment */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; special function registers\n");
   fprintf (asmFile, "%s", iComments2);
   copyFile (asmFile, sfr->oFile);
-
+    
 
   /* Put all variables into a cblock */
   fprintf (asmFile, "\n\n\tcblock  0x13\n\n");
 
-  for (i = 0; i < pic14_nRegs; i++)
-    {
-      if (regspic14[i].wasUsed && (regspic14[i].offset >= 0x0c))
-       fprintf (asmFile, "\t%s\n", regspic14[i].name);
-    }
+  for(i=0; i<pic14_nRegs; i++) {
+    if(regspic14[i].wasUsed && (regspic14[i].offset>=0x0c) )
+      fprintf (asmFile, "\t%s\n",regspic14[i].name);
+  }
   //fprintf (asmFile, "\tr0x0C\n");
   //fprintf (asmFile, "\tr0x0D\n");
 
@@ -1072,7 +1088,7 @@ pic14glue ()
   fprintf (asmFile, "; special function bits \n");
   fprintf (asmFile, "%s", iComments2);
   copyFile (asmFile, sfrbit->oFile);
-
+    
   /* copy the data segment */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; internal ram data\n");
@@ -1083,42 +1099,40 @@ pic14glue ()
   /* create the overlay segments */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; overlayable items in internal ram \n");
-  fprintf (asmFile, "%s", iComments2);
+  fprintf (asmFile, "%s", iComments2);    
   copyFile (asmFile, ovrFile);
 
   /* create the stack segment MOF */
-  if (mainf && mainf->fbody)
-    {
-      fprintf (asmFile, "%s", iComments2);
-      fprintf (asmFile, "; Stack segment in internal ram \n");
-      fprintf (asmFile, "%s", iComments2);
-      fprintf (asmFile, ";\t.area\tSSEG\t(DATA)\n"
-              ";__start__stack:\n;\t.ds\t1\n\n");
-    }
+  if (mainf && mainf->fbody) {
+    fprintf (asmFile, "%s", iComments2);
+    fprintf (asmFile, "; Stack segment in internal ram \n");
+    fprintf (asmFile, "%s", iComments2);    
+    fprintf (asmFile, ";\t.area\tSSEG\t(DATA)\n"
+            ";__start__stack:\n;\t.ds\t1\n\n");
+  }
 
   /* create the idata segment */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; indirectly addressable internal ram data\n");
   fprintf (asmFile, "%s", iComments2);
   copyFile (asmFile, idata->oFile);
-
+    
   /* if external stack then reserve space of it */
-  if (mainf && mainf->fbody && options.useXstack)
-    {
-      fprintf (asmFile, "%s", iComments2);
-      fprintf (asmFile, "; external stack \n");
-      fprintf (asmFile, "%s", iComments2);
-      fprintf (asmFile, ";\t.area XSEG (XDATA)\n");    /* MOF */
-      fprintf (asmFile, ";\t.ds 256\n");
-    }
-
-
+  if (mainf && mainf->fbody && options.useXstack ) {
+    fprintf (asmFile, "%s", iComments2);
+    fprintf (asmFile, "; external stack \n");
+    fprintf (asmFile, "%s", iComments2);
+    fprintf (asmFile,";\t.area XSEG (XDATA)\n"); /* MOF */
+    fprintf (asmFile,";\t.ds 256\n");
+  }
+       
+       
   /* copy xtern ram data */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; external ram data\n");
   fprintf (asmFile, "%s", iComments2);
   copyFile (asmFile, xdata->oFile);
-
+    
 
   fprintf (asmFile, "\tendc\n");
 
@@ -1133,63 +1147,61 @@ pic14glue ()
   fprintf (asmFile, "\tORG 0\n");
 
   /* copy the interrupt vector table */
-  if (mainf && mainf->fbody)
-    {
-      fprintf (asmFile, "%s", iComments2);
-      fprintf (asmFile, "; interrupt vector \n");
-      fprintf (asmFile, "%s", iComments2);
-      copyFile (asmFile, vFile);
-    }
-
+  if (mainf && mainf->fbody) {
+    fprintf (asmFile, "%s", iComments2);
+    fprintf (asmFile, "; interrupt vector \n");
+    fprintf (asmFile, "%s", iComments2);
+    copyFile (asmFile, vFile);
+  }
+    
   /* copy global & static initialisations */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; global & static initialisations\n");
   fprintf (asmFile, "%s", iComments2);
-
-  /* Everywhere we generate a reference to the static_name area,
-   * (which is currently only here), we immediately follow it with a
+    
+  /* Everywhere we generate a reference to the static_name area, 
+   * (which is currently only here), we immediately follow it with a 
    * definition of the post_static_name area. This guarantees that
    * the post_static_name area will immediately follow the static_name
    * area.
    */
-  fprintf (asmFile, ";\t.area %s\n", port->mem.static_name);   /* MOF */
+  fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); /* MOF */
   fprintf (asmFile, ";\t.area %s\n", port->mem.post_static_name);
   fprintf (asmFile, ";\t.area %s\n", port->mem.static_name);
+    
+  if (mainf && mainf->fbody) {
+    fprintf (asmFile,"__sdcc_gsinit_startup:\n");
+    /* if external stack is specified then the
+       higher order byte of the xdatalocation is
+       going into P2 and the lower order going into
+       spx */
+    if (options.useXstack) {
+      fprintf(asmFile,";\tmov\tP2,#0x%02x\n",
+             (((unsigned int)options.xdata_loc) >> 8) & 0xff);
+      fprintf(asmFile,";\tmov\t_spx,#0x%02x\n",
+             (unsigned int)options.xdata_loc & 0xff);
+    }
 
-  if (mainf && mainf->fbody)
-    {
-      fprintf (asmFile, "__sdcc_gsinit_startup:\n");
-      /* if external stack is specified then the
-         higher order byte of the xdatalocation is
-         going into P2 and the lower order going into
-         spx */
-      if (options.useXstack)
-       {
-         fprintf (asmFile, ";\tmov\tP2,#0x%02x\n",
-                  (((unsigned int) options.xdata_loc) >> 8) & 0xff);
-         fprintf (asmFile, ";\tmov\t_spx,#0x%02x\n",
-                  (unsigned int) options.xdata_loc & 0xff);
-       }
-
-      /* initialise the stack pointer */
-      /* if the user specified a value then use it */
-      if (options.stack_loc)
-       fprintf (asmFile, ";\tmov\tsp,#%d\n", options.stack_loc);
-      else
-       /* no: we have to compute it */
+    /* initialise the stack pointer */
+    /* if the user specified a value then use it */
+    if (options.stack_loc) 
+      fprintf(asmFile,";\tmov\tsp,#%d\n",options.stack_loc);
+    else 
+      /* no: we have to compute it */
       if (!options.stackOnData && maxRegBank <= 3)
-       fprintf (asmFile, ";\tmov\tsp,#%d\n", ((maxRegBank + 1) * 8) - 1);
+       fprintf(asmFile,";\tmov\tsp,#%d\n",((maxRegBank + 1) * 8) -1); 
       else
-       fprintf (asmFile, ";\tmov\tsp,#__start__stack\n");      /* MOF */
-
-      fprintf (asmFile, ";\tlcall\t__sdcc_external_startup\n");
-      fprintf (asmFile, ";\tmov\ta,dpl\n");
-      fprintf (asmFile, ";\tjz\t__sdcc_init_data\n");
-      fprintf (asmFile, ";\tljmp\t__sdcc_program_startup\n");
-      fprintf (asmFile, ";__sdcc_init_data:\n");
-
-    }
-  copyFile (asmFile, statsg->oFile);
+       fprintf(asmFile,";\tmov\tsp,#__start__stack\n"); /* MOF */
+
+    fprintf (asmFile,";\tlcall\t__sdcc_external_startup\n");
+    fprintf (asmFile,";\tmov\ta,dpl\n");
+    fprintf (asmFile,";\tjz\t__sdcc_init_data\n");
+    fprintf (asmFile,";\tljmp\t__sdcc_program_startup\n");
+    fprintf (asmFile,";__sdcc_init_data:\n");
+       
+  }
+  //copyFile (asmFile, statsg->oFile);
+  copypCode(asmFile, statsg->dbName);
 
   if (port->general.glue_up_main && mainf && mainf->fbody)
     {
@@ -1197,42 +1209,43 @@ pic14glue ()
        * This area is guaranteed to follow the static area
        * by the ugly shucking and jiving about 20 lines ago.
        */
-      fprintf (asmFile, ";\t.area %s\n", port->mem.post_static_name);
-      fprintf (asmFile, ";\tljmp\t__sdcc_program_startup\n");
+      fprintf(asmFile, ";\t.area %s\n", port->mem.post_static_name);
+      fprintf (asmFile,";\tljmp\t__sdcc_program_startup\n");
     }
-
+       
   /* copy over code */
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, "; code\n");
   fprintf (asmFile, "%s", iComments2);
   fprintf (asmFile, ";\t.area %s\n", port->mem.code_name);
-  if (mainf && mainf->fbody)
-    {
-
-      /* entry point @ start of CSEG */
-      fprintf (asmFile, "__sdcc_program_startup:\n");
-
-      /* put in the call to main */
-      fprintf (asmFile, "\tcall\t_main\n");
-      if (options.mainreturn)
-       {
+  if (mainf && mainf->fbody) {
+       
+    /* entry point @ start of CSEG */
+    fprintf (asmFile,"__sdcc_program_startup:\n");
+       
+    /* put in the call to main */
+    fprintf(asmFile,"\tcall\t_main\n");
+    if (options.mainreturn) {
+
+      fprintf(asmFile,";\treturn from main ; will return to caller\n");
+      fprintf(asmFile,"\treturn\n");
+
+    } else {
+                  
+      fprintf(asmFile,";\treturn from main will lock up\n");
+      fprintf(asmFile,"\tgoto\t$\n");
+    }
+  }
 
-         fprintf (asmFile, ";\treturn from main ; will return to caller\n");
-         fprintf (asmFile, "\treturn\n");
+  AnalyzepCode(code->dbName);
+  //copyFile (asmFile, code->oFile);
+  copypCode(asmFile, code->dbName);
 
-       }
-      else
-       {
-
-         fprintf (asmFile, ";\treturn from main will lock up\n");
-         fprintf (asmFile, "\tgoto\t$\n");
-       }
-    }
-  copyFile (asmFile, code->oFile);
+  printCallTree(stderr);
 
-  fprintf (asmFile, "\tend\n");
+  fprintf (asmFile,"\tend\n");
 
   fclose (asmFile);
-  applyToSet (tmpfileSet, closeTmpFiles);
-  applyToSet (tmpfileNameSet, rmTmpFiles);
+  applyToSet(tmpfileSet,closeTmpFiles);
+  applyToSet(tmpfileNameSet, rmTmpFiles);
 }
diff --git a/src/pic/pcode.c b/src/pic/pcode.c
new file mode 100644 (file)
index 0000000..dae97df
--- /dev/null
@@ -0,0 +1,1242 @@
+/*-------------------------------------------------------------------------
+
+   pcode.h - post code generation
+   Written By -  Scott Dattalo scott@dattalo.com
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-------------------------------------------------------------------------*/
+
+#include <stdio.h>
+
+#include "common.h"   // Include everything in the SDCC src directory
+
+#include "pcode.h"
+
+// Eventually this will go into device depended files:
+pCodeOp pc_status    = {PO_STATUS,  "status"};
+pCodeOp pc_indf      = {PO_INDF,    "indf"};
+pCodeOp pc_fsr       = {PO_FSR,     "fsr"};
+
+
+//static char *PIC_mnemonics[] = {
+static char *scpADDLW = "ADDLW";
+static char *scpADDWF = "ADDWF";
+static char *scpANDLW = "ANDLW";
+static char *scpANDWF = "ANDWF";
+static char *scpBCF = "BCF";
+static char *scpBSF = "BSF";
+static char *scpBTFSC = "BTFSC";
+static char *scpBTFSS = "BTFSS";
+static char *scpCALL = "CALL";
+static char *scpCOMF = "COMF";
+static char *scpCLRF = "CLRF";
+static char *scpCLRW = "CLRW";
+static char *scpDECF = "DECF";
+static char *scpDECFSZ = "DECFSZ";
+static char *scpGOTO = "GOTO";
+static char *scpINCF = "INCF";
+static char *scpINCFSZ = "INCFSZ";
+static char *scpIORLW = "IORLW";
+static char *scpIORWF = "IORWF";
+static char *scpMOVF = "MOVF";
+static char *scpMOVLW = "MOVLW";
+static char *scpMOVWF = "MOVWF";
+static char *scpNEGF = "NEGF";
+static char *scpRETLW = "RETLW";
+static char *scpRETURN = "RETURN";
+static char *scpSUBLW = "SUBLW";
+static char *scpSUBWF = "SUBWF";
+static char *scpTRIS = "TRIS";
+static char *scpXORLW = "XORLW";
+static char *scpXORWF = "XORWF";
+
+
+static pFile *the_pFile = NULL;
+
+/****************************************************************/
+/****************************************************************/
+static pBlock *peepSnippets=NULL;
+
+/****************************************************************/
+/*                      Forward declarations                    */
+/****************************************************************/
+
+static void unlink(pCode *pc);
+static void genericAnalyze(pCode *pc);
+static void AnalyzeGOTO(pCode *pc);
+static void AnalyzeSKIP(pCode *pc);
+static void AnalyzeRETURN(pCode *pc);
+
+static void genericDestruct(pCode *pc);
+static void genericPrint(FILE *of,pCode *pc);
+
+static void pCodePrintLabel(FILE *of, pCode *pc);
+static void pCodePrintFunction(FILE *of, pCode *pc);
+static char *get_op( pCodeInstruction *pcc);
+
+void copypCode(FILE *of, char dbName)
+{
+  pBlock *pb;
+
+  if(!of || !the_pFile)
+    return;
+
+  fprintf(of,";dumping pcode to a file");
+
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    if(pb->cmemmap->dbName == dbName)
+      printpBlock(of,pb);
+  }
+
+}
+void pcode_test(void)
+{
+
+  printf("pcode is alive!\n");
+
+  if(the_pFile) {
+
+    pBlock *pb;
+    FILE *pFile;
+    char buffer[100];
+
+    /* create the file name */
+    strcpy(buffer,srcFileName);
+    strcat(buffer,".p");
+
+    if( !(pFile = fopen(buffer, "w" ))) {
+      werror(E_FILE_OPEN_ERR,buffer);
+      exit(1);
+    }
+
+    fprintf(pFile,"pcode dump\n\n");
+
+    for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+      fprintf(pFile,"\n\tNew pBlock\n\n");
+      fprintf(pFile,"%s, dbName =%c\n",pb->cmemmap->sname,pb->cmemmap->dbName);
+      printpBlock(pFile,pb);
+    }
+  }
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCode - create and return a newly initialized pCode          */
+/*-----------------------------------------------------------------*/
+pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
+{
+  pCodeInstruction *pci ;
+    
+
+  _ALLOC(pci,sizeof(pCodeInstruction));
+  pci->pc.analyze = genericAnalyze;
+  pci->pc.destruct = genericDestruct;
+  pci->pc.type = PC_OPCODE;
+  pci->op = op;
+  pci->pc.prev = pci->pc.next = NULL;
+  pci->pcop = pcop;
+  pci->dest = 0;
+  pci->bit_inst = 0;
+  pci->num_ops = 2;
+  pci->pc.print = genericPrint;
+  pci->pc.from = pci->pc.to = pci->pc.label = NULL;
+
+  if(pcop && pcop->name)
+    printf("newpCode  operand name %s\n",pcop->name);
+
+  switch(op) { 
+
+  case POC_ANDLW:
+    pci->mnemonic = scpANDLW;
+    pci->num_ops = 1;
+    break;
+  case POC_ANDWF:
+    pci->dest = 1;
+  case POC_ANDFW:
+    pci->mnemonic = scpANDWF;
+    break;
+
+  case POC_ADDLW:
+    pci->mnemonic = scpADDLW;
+    pci->num_ops = 1;
+    break;
+  case POC_ADDWF:
+    pci->dest = 1;
+  case POC_ADDFW:
+    pci->mnemonic = scpADDWF;
+    break;
+  case POC_BCF:
+    pci->bit_inst = 1;
+    pci->mnemonic = scpBCF;
+    break;
+  case POC_BSF:
+    pci->bit_inst = 1;
+    pci->mnemonic = scpBSF;
+    break;
+  case POC_BTFSC:
+    pci->bit_inst = 1;
+    pci->mnemonic = scpBTFSC;
+    pci->pc.analyze = AnalyzeSKIP;
+    break;
+  case POC_BTFSS:
+    pci->bit_inst = 1;
+    pci->mnemonic = scpBTFSS;
+    pci->pc.analyze = AnalyzeSKIP;
+    break;
+  case POC_CALL:
+    pci->num_ops = 1;
+    pci->mnemonic = scpCALL;
+    break;
+  case POC_COMF:
+    pci->mnemonic = scpCOMF;
+    break;
+  case POC_CLRF:
+    pci->num_ops = 1;
+    pci->mnemonic = scpCLRF;
+    break;
+  case POC_CLRW:
+    pci->num_ops = 0;
+    pci->mnemonic = scpCLRW;
+    break;
+  case POC_DECF:
+    pci->dest = 1;
+  case POC_DECFW:
+    pci->mnemonic = scpDECF;
+    break;
+  case POC_DECFSZ:
+    pci->dest = 1;
+  case POC_DECFSZW:
+    pci->mnemonic = scpDECFSZ;
+    pci->pc.analyze = AnalyzeSKIP;
+    break;
+  case POC_GOTO:
+    pci->num_ops = 1;
+    pci->mnemonic = scpGOTO;
+    pci->pc.analyze = AnalyzeGOTO;
+    break;
+  case POC_INCF:
+    pci->dest = 1;
+  case POC_INCFW:
+    pci->mnemonic = scpINCF;
+    break;
+  case POC_INCFSZ:
+    pci->dest = 1;
+  case POC_INCFSZW:
+    pci->mnemonic = scpINCFSZ;
+    pci->pc.analyze = AnalyzeSKIP;
+    break;
+  case POC_IORLW:
+    pci->num_ops = 1;
+    pci->mnemonic = scpIORLW;
+    break;
+  case POC_IORWF:
+    pci->dest = 1;
+  case POC_IORFW:
+    pci->mnemonic = scpIORWF;
+    break;
+  case POC_MOVF:
+    pci->dest = 1;
+  case POC_MOVFW:
+    pci->mnemonic = scpMOVF;
+    break;
+  case POC_MOVLW:
+    pci->num_ops = 1;
+    pci->mnemonic = scpMOVLW;
+    break;
+  case POC_MOVWF:
+    pci->num_ops = 1;
+    pci->mnemonic = scpMOVWF;
+    break;
+  case POC_NEGF:
+    pci->mnemonic = scpNEGF;
+    break;
+  case POC_RETLW:
+    pci->num_ops = 1;
+    pci->mnemonic = scpRETLW;
+    pci->pc.analyze = AnalyzeRETURN;
+    break;
+  case POC_RETURN:
+    pci->num_ops = 0;
+    pci->mnemonic = scpRETURN;
+    pci->pc.analyze = AnalyzeRETURN;
+    break;
+  case POC_SUBLW:
+    pci->mnemonic = scpSUBLW;
+    pci->num_ops = 1;
+    break;
+  case POC_SUBWF:
+    pci->dest = 1;
+  case POC_SUBFW:
+    pci->mnemonic = scpSUBWF;
+    break;
+  case POC_TRIS:
+    pci->mnemonic = scpTRIS;
+    break;
+  case POC_XORLW:
+    pci->num_ops = 1;
+    pci->mnemonic = scpXORLW;
+    break;
+  case POC_XORWF:
+    pci->dest = 1;
+  case POC_XORFW:
+    pci->mnemonic = scpXORWF;
+    break;
+
+  default:
+    pci->pc.print = genericPrint;
+  }
+   
+  return (pCode *)pci;
+}      
+
+
+/*-----------------------------------------------------------------*/
+/* newPcodeCharP - create a new pCode from a char string           */
+/*-----------------------------------------------------------------*/
+
+pCode *newpCodeCharP(char *cP)
+{
+
+  pCodeComment *pcc ;
+    
+  _ALLOC(pcc,sizeof(pCodeComment));
+   
+  pcc->pc.type = PC_COMMENT;
+  pcc->pc.prev = pcc->pc.next = NULL;
+  pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
+
+  pcc->pc.analyze = genericAnalyze;
+  pcc->pc.destruct = genericDestruct;
+  pcc->pc.print = genericPrint;
+
+  if(cP) {
+    _ALLOC_ATOMIC(pcc->comment,strlen(cP)+1);
+    strcpy(pcc->comment,cP);
+  } else
+    pcc->comment = NULL;
+
+  return ( (pCode *)pcc);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCodeGLabel - create a new global label                      */
+/*-----------------------------------------------------------------*/
+
+
+pCode *newpCodeFunction(char *mod,char *f)
+{
+  pCodeFunction *pcf;
+
+  _ALLOC(pcf,sizeof(pCodeFunction));
+
+  pcf->pc.type = PC_FUNCTION;
+  pcf->pc.prev = pcf->pc.next = NULL;
+  pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
+
+  pcf->pc.analyze = genericAnalyze;
+  pcf->pc.destruct = genericDestruct;
+  pcf->pc.print = pCodePrintFunction;
+
+  if(mod) {
+    _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
+    strcpy(pcf->modname,mod);
+  } else
+    pcf->modname = NULL;
+
+  if(f) {
+    _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
+    strcpy(pcf->fname,f);
+  } else
+    pcf->fname = NULL;
+
+  return ( (pCode *)pcf);
+
+}
+
+
+pCode *newpCodeLabel(int key)
+{
+
+  pCodeLabel *pcl;
+    
+  _ALLOC(pcl,sizeof(pCodeLabel));
+   
+  pcl->pc.type = PC_LABEL;
+  pcl->pc.prev = pcl->pc.next = NULL;
+  pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
+
+  pcl->pc.analyze = genericAnalyze;
+  pcl->pc.destruct = genericDestruct;
+  pcl->pc.print = pCodePrintLabel;
+
+  pcl->key = key;
+
+  return ( (pCode *)pcl);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* newpBlock - create and return a pointer to a new pBlock         */
+/*-----------------------------------------------------------------*/
+pBlock *newpBlock(void)
+{
+
+  pBlock *PpB;
+
+  _ALLOC(PpB,sizeof(pBlock));
+  PpB->next = PpB->prev = NULL;
+
+  return PpB;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCodeChain - create a new chain of pCodes                    */
+/*-----------------------------------------------------------------*
+ *
+ *  This function will create a new pBlock and the pointer to the
+ *  pCode that is passed in will be the first pCode in the block.
+ *-----------------------------------------------------------------*/
+
+
+pBlock *newpCodeChain(memmap *cm,pCode *pc)
+{
+
+  pBlock *pB = newpBlock();
+
+  pB->pcHead = pB->pcTail = pc;
+  pB->cmemmap = cm;
+
+  return pB;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+
+pCodeOp *newpCodeOp(char *name)
+{
+  pCodeOp *pcop;
+
+  _ALLOC(pcop,sizeof(pCodeOp) );
+  pcop->type = PO_NONE;
+  pcop->name = strdup(name);   
+
+  return pcop;
+}
+
+pCodeOp *newpCodeOpLabel(int key)
+{
+  char *s = buffer;
+  pCodeOp *pcop;
+
+  _ALLOC(pcop,sizeof(pCodeOpLabel) );
+  sprintf(s,"_%05d_DS_",key);
+  pcop->type = PO_LABEL;
+  pcop->name = strdup(s);
+  ((pCodeOpLabel *)pcop)->key = key;
+
+  return pcop;
+}
+
+pCodeOp *newpCodeOpLit(int lit)
+{
+  char *s = buffer;
+  pCodeOp *pcop;
+
+
+  _ALLOC(pcop,sizeof(pCodeOpLit) );
+  pcop->type = PO_LITERAL;
+  sprintf(s,"0x%02x",lit);
+  _ALLOC_ATOMIC(pcop->name,strlen(s)+1);
+  strcpy(pcop->name,s);
+  ((pCodeOpLit *)pcop)->lit = lit;
+
+  return pcop;
+}
+
+pCodeOp *newpCodeOpWild(int id)
+{
+  char *s = buffer;
+  pCodeOp *pcop;
+
+
+  _ALLOC(pcop,sizeof(pCodeOpWild) );
+  pcop->type = PO_WILD;
+  sprintf(s,"%%%d",id);
+  _ALLOC_ATOMIC(pcop->name,strlen(s)+1);
+  strcpy(pcop->name,s);
+  ((pCodeOpWild *)pcop)->id = id;
+
+  return pcop;
+}
+
+pCodeOp *newpCodeOpBit(char *s, int bit)
+{
+  pCodeOp *pcop;
+
+  _ALLOC(pcop,sizeof(pCodeOpBit) );
+  pcop->type = PO_BIT;
+  pcop->name = strdup(s);   
+  ((pCodeOpBit *)pcop)->bit = bit;
+  ((pCodeOpBit *)pcop)->inBitSpace = 1;
+
+  return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* addpCode2pBlock - place the pCode into the pBlock linked list   */
+/*-----------------------------------------------------------------*/
+void addpCode2pBlock(pBlock *pb, pCode *pc)
+{
+
+  pb->pcTail->next = pc;
+  pc->prev = pb->pcTail;
+  pc->next = NULL;
+  pb->pcTail = pc;
+}
+
+/*-----------------------------------------------------------------*/
+/* addpBlock - place a pBlock into the pFile                       */
+/*-----------------------------------------------------------------*/
+void addpBlock(pBlock *pb)
+{
+
+  if(!the_pFile) {
+    /* First time called, we'll pass through here. */
+    _ALLOC(the_pFile,sizeof(the_pFile));
+    the_pFile->pbHead = the_pFile->pbTail = pb;
+    the_pFile->functions = NULL;
+    return;
+  }
+
+  the_pFile->pbTail->next = pb;
+  pb->prev = the_pFile->pbTail;
+  pb->next = NULL;
+  the_pFile->pbTail = pb;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* printpCode - write the contents of a pCode to a file            */
+/*-----------------------------------------------------------------*/
+void printpCode(FILE *of, pCode *pc)
+{
+
+  if(!pc || !of)
+    return;
+
+  if(pc->print) {
+    pc->print(of,pc);
+    return;
+  }
+
+  fprintf(of,"warning - unable to print pCode\n");
+}
+
+/*-----------------------------------------------------------------*/
+/* printpBlock - write the contents of a pBlock to a file          */
+/*-----------------------------------------------------------------*/
+void printpBlock(FILE *of, pBlock *pb)
+{
+  pCode *pc;
+
+  if(!pb)
+    return;
+
+  if(!of)
+    of = stderr;
+
+  for(pc = pb->pcHead; pc; pc = pc->next)
+    printpCode(of,pc);
+
+}
+
+/*-----------------------------------------------------------------*/
+/*                                                                 */
+/*       pCode processing                                          */
+/*                                                                 */
+/*    The stuff that follows is very PIC specific!                 */
+/*                                                                 */
+/*                                                                 */
+/*                                                                 */
+/*                                                                 */
+/*-----------------------------------------------------------------*/
+
+static void unlink(pCode *pc)
+{
+  if(pc  && pc->prev && pc->next) {
+
+    pc->prev->next = pc->next;
+    pc->next->prev = pc->prev;
+  }
+}
+static void genericDestruct(pCode *pc)
+{
+  unlink(pc);
+
+  fprintf(stderr,"warning, calling default pCode destructor\n");
+  free(pc);
+}
+
+static char *get_op( pCodeInstruction *pcc)
+{
+  if(pcc && pcc->pcop && pcc->pcop->name)
+    return pcc->pcop->name;
+  return "NO operand";
+#if 0
+  operand *op;
+
+  switch(pcc->lrr) {
+
+  case POT_RESULT:
+    op = IC_RESULT(pcc->ic);
+    break;
+  case POT_LEFT:
+    op = IC_LEFT(pcc->ic);
+    break;
+  case POT_RIGHT:
+    op = IC_RIGHT(pcc->ic);
+    break;
+
+  default:
+    return "get_op bad lrr";
+  }
+
+  return(OP_SYMBOL(op)->rname[0] ? OP_SYMBOL(op)->rname : OP_SYMBOL(op)->name);
+  
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* genericPrint - the contents of a pCode to a file                */
+/*-----------------------------------------------------------------*/
+static void genericPrint(FILE *of, pCode *pc)
+{
+
+  if(!pc || !of)
+    return;
+
+  switch(pc->type) {
+  case PC_COMMENT:
+    fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
+    break;
+
+  case PC_OPCODE:
+    // If the opcode has a label, print that first
+    {
+      pBranch *pbl = pc->label;
+      while(pbl) {
+       if(pbl->pc->type == PC_LABEL)
+         pCodePrintLabel(of, pbl->pc);
+       pbl = pbl->next;
+      }
+    }
+
+    fprintf(of, "\t%s\t", PCI(pc)->mnemonic);
+    if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
+
+      if(PCI(pc)->bit_inst) {
+       if(PCI(pc)->pcop->type == PO_BIT) {
+         if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
+           fprintf(of,"(%s >> 3), (%s & 7)", 
+                   PCI(pc)->pcop->name ,
+                   PCI(pc)->pcop->name );
+         else
+           fprintf(of,"%s,%d", get_op(PCI(pc)), (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
+       } else
+         fprintf(of,"%s,0 ; ?bug", get_op(PCI(pc)));
+       //PCI(pc)->pcop->t.bit );
+      } else {
+
+       if(PCI(pc)->pcop->type == PO_BIT) {
+         if( PCI(pc)->num_ops == 2)
+           fprintf(of,"(%s >> 3),%c",PCI(pc)->pcop->name,((PCI(pc)->dest) ? 'F':'W'));
+         else
+           fprintf(of,"(1 << (%s & 7))",PCI(pc)->pcop->name);
+       }else {
+         fprintf(of,"%s",get_op(PCI(pc)));
+
+         if( PCI(pc)->num_ops == 2)
+           fprintf(of,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
+       }
+      }
+    }
+
+    {
+      pBranch *dpb = pc->to;   // debug
+      while(dpb) {
+       switch ( dpb->pc->type) {
+       case PC_OPCODE:
+         fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
+         break;
+       case PC_LABEL:
+         fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
+         break;
+       case PC_FUNCTION:
+         fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
+         break;
+       case PC_COMMENT:
+       case PC_WILD:
+         break;
+       }
+       dpb = dpb->next;
+      }
+      fprintf(of,"\n");
+    }
+
+    break;
+
+  case PC_LABEL:
+  default:
+    fprintf(of,"unknown pCode type %d\n",pc->type);
+  }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodePrintFunction - prints function begin/end                  */
+/*-----------------------------------------------------------------*/
+
+static void pCodePrintFunction(FILE *of, pCode *pc)
+{
+
+  if(!pc || !of)
+    return;
+
+  if( ((pCodeFunction *)pc)->modname) 
+    fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
+
+  if(PCF(pc)->fname) {
+    pBranch *exits = pc->to;
+    int i=0;
+    fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
+    while(exits) {
+      i++;
+      exits = exits->next;
+    }
+    if(i) i--;
+    fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
+    
+  }else {
+    if(pc->from && 
+       pc->from->pc->type == PC_FUNCTION &&
+       PCF(pc->from->pc)->fname) 
+      fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
+    else
+      fprintf(of,"; exit point [can't find entry point]\n");
+  }
+}
+/*-----------------------------------------------------------------*/
+/* pCodePrintLabel - prints label                                  */
+/*-----------------------------------------------------------------*/
+
+static void pCodePrintLabel(FILE *of, pCode *pc)
+{
+
+  if(!pc || !of)
+    return;
+
+  fprintf(of,"_%05d_DS_:\n",((pCodeLabel *)pc)->key);
+
+}
+
+/*-----------------------------------------------------------------*/
+
+static pBranch * pBranchAppend(pBranch *h, pBranch *n)
+{
+  pBranch *b;
+
+  if(!h)
+    return n;
+
+  b = h;
+  while(b->next)
+    b = b->next;
+
+  b->next = n;
+
+  return h;
+  
+}  
+/*-----------------------------------------------------------------*/
+/* pBranchLink - given two pcodes, this function will link them    */
+/*               together through their pBranches                  */
+/*-----------------------------------------------------------------*/
+static void pBranchLink(pCode *f, pCode *t)
+{
+  pBranch *b;
+
+  // Declare a new branch object for the 'from' pCode.
+
+  _ALLOC(b,sizeof(pBranch));
+  b->pc = t;                    // The link to the 'to' pCode.
+  b->next = NULL;
+
+  f->to = pBranchAppend(f->to,b);
+
+  // Now do the same for the 'to' pCode.
+
+  _ALLOC(b,sizeof(pBranch));
+  b->pc = f;
+  b->next = NULL;
+
+  t->from = pBranchAppend(t->from,b);
+  
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* pBranchFind - find the pBranch in a pBranch chain that contains */
+/*               a pCode                                           */
+/*-----------------------------------------------------------------*/
+static pBranch *pBranchFind(pBranch *pb,pCode *pc)
+{
+  while(pb) {
+
+    if(pb->pc == pc)
+      return pb;
+
+    pb = pb->next;
+  }
+
+  return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
+/*-----------------------------------------------------------------*/
+static void pCodeUnlink(pCode *pc)
+{
+  pBranch *pb1,*pb2;
+  pCode *pc1;
+
+  if(!pc->prev || !pc->next) {
+    fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
+    exit(1);
+  }
+
+  /* first remove the pCode from the chain */
+  pc->prev->next = pc->next;
+  pc->next->prev = pc->prev;
+
+  /* Now for the hard part... */
+
+  /* Remove the branches */
+
+  pb1 = pc->from;
+  while(pb1) {
+    pc1 = pb1->pc;    /* Get the pCode that branches to the
+                      * one we're unlinking */
+
+    /* search for the link back to this pCode (the one we're
+     * unlinking) */
+    if(pb2 = pBranchFind(pc1->to,pc)) {
+      pb2->pc = pc->to->pc;  // make the replacement
+
+      /* if the pCode we're unlinking contains multiple 'to'
+       * branches (e.g. this a skip instruction) then we need
+       * to copy these extra branches to the chain. */
+      if(pc->to->next)
+       pBranchAppend(pb2, pc->to->next);
+    }
+    
+    pb1 = pb1->next;
+  }
+
+
+}
+#endif
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void genericAnalyze(pCode *pc)
+{
+  switch(pc->type) {
+  case PC_WILD:
+  case PC_COMMENT:
+    return;
+  case PC_LABEL:
+  case PC_FUNCTION:
+  case PC_OPCODE:
+    {
+      // Go through the pCodes that are in pCode chain and link
+      // them together through the pBranches. Note, the pCodes
+      // are linked together as a contiguous stream like the 
+      // assembly source code lines. The linking here mimics this
+      // except that comments are not linked in.
+      // 
+      pCode *npc = pc->next;
+      while(npc) {
+       if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
+         pBranchLink(pc,npc);
+         return;
+       } else
+         npc = npc->next;
+      }
+    }
+  }
+}
+
+/*-----------------------------------------------------------------*/
+/* findLabel - Search the pCode for a particular label             */
+/*-----------------------------------------------------------------*/
+pCode * findLabel(pCodeOpLabel *pcop_label)
+{
+  pBlock *pb;
+  pCode  *pc;
+  pBranch *pbr;
+
+  if(!the_pFile)
+    return NULL;
+
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    for(pc = pb->pcHead; pc; pc = pc->next) {
+      if(pc->type == PC_LABEL) {
+       if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
+         return pc;
+      }
+      if(pc->type == PC_OPCODE) {
+       pbr = pc->label;
+       while(pbr) {
+         if(pbr->pc->type == PC_LABEL) {
+           if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
+             return pc;
+         }
+         pbr = pbr->next;
+       }
+      }
+
+    }
+  }
+
+  fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
+  return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* findNextInstruction - given a pCode, find the next instruction  */
+/*                       in the linked list                        */
+/*-----------------------------------------------------------------*/
+pCode * findNextInstruction(pCode *pc)
+{
+
+  while(pc) {
+    if(pc->type == PC_OPCODE)
+      return pc;
+
+    pc = pc->next;
+  }
+
+  fprintf(stderr,"Couldn't find instruction\n");
+  return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* findFunctionEnd - given a pCode find the end of the function    */
+/*                   that contains it     t                        */
+/*-----------------------------------------------------------------*/
+pCode * findFunctionEnd(pCode *pc)
+{
+
+  while(pc) {
+    if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
+      return pc;
+
+    pc = pc->next;
+  }
+
+  fprintf(stderr,"Couldn't find function end\n");
+  return NULL;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* AnalyzeLabel - if the pCode is a label, then merge it with the  */
+/*                instruction with which it is associated.         */
+/*-----------------------------------------------------------------*/
+static void AnalyzeLabel(pCode *pc)
+{
+
+  pCodeUnlink(pc);
+
+}
+#endif
+
+static void AnalyzeGOTO(pCode *pc)
+{
+
+  pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
+
+}
+
+static void AnalyzeSKIP(pCode *pc)
+{
+
+  pBranchLink(pc,findNextInstruction(pc->next));
+  pBranchLink(pc,findNextInstruction(pc->next->next));
+
+}
+
+static void AnalyzeRETURN(pCode *pc)
+{
+
+  //  branch_link(pc,findFunctionEnd(pc->next));
+
+}
+
+
+void optimizepBlock(pBlock *pb)
+{
+  pCode *pc;
+
+  if(!pb)
+    return;
+
+  for(pc = pb->pcHead; pc; pc = pc->next)
+    pc->analyze(pc);
+
+}
+/*-----------------------------------------------------------------*/
+/* pBlockMergeLabels - remove the pCode labels from the pCode      */
+/*                     chain and put them into pBranches that are  */
+/*                     associated with the appropriate pCode       */
+/*                     instructions.                               */
+/*-----------------------------------------------------------------*/
+void pBlockMergeLabels(pBlock *pb)
+{
+  pBranch *pbr;
+  pCode *pc, *pcnext=NULL;
+
+  if(!pb)
+    return;
+
+  for(pc = pb->pcHead; pc; pc = pc->next) {
+
+    if(pc->type == PC_LABEL) {
+      if( !(pcnext = findNextInstruction(pc)) ) 
+       return;  // Couldn't find an instruction associated with this label
+
+      // Unlink the pCode label from it's pCode chain
+      if(pc->prev) 
+       pc->prev->next = pc->next;
+      if(pc->next)
+       pc->next->prev = pc->prev;
+
+      // And link it into the instruction's pBranch labels. (Note, since
+      // it's possible to have multiple labels associated with one instruction
+      // we must provide a means to accomodate the additional labels. Thus
+      // the labels are placed into the singly-linked list "label" as 
+      // opposed to being a single member of the pCodeInstruction.)
+
+      _ALLOC(pbr,sizeof(pBranch));
+      pbr->pc = pc;
+      pbr->next = NULL;
+
+      pcnext->label = pBranchAppend(pcnext->label,pbr);
+    }
+
+  }
+
+}
+/*-----------------------------------------------------------------*/
+/* AnalyzepCode - parse the pCode that has been generated and form */
+/*                all of the logical connections.                  */
+/*                                                                 */
+/* Essentially what's done here is that the pCode flow is          */
+/* determined.                                                     */
+/*-----------------------------------------------------------------*/
+
+void AnalyzepCode(char dbName)
+{
+  pBlock *pb;
+  pCode *pc;
+  pBranch *pbr;
+
+  if(!the_pFile)
+    return;
+
+  fprintf(stderr," Analyzing pCode");
+
+  /* First, merge the labels with the instructions */
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    if(pb->cmemmap->dbName == dbName)
+      pBlockMergeLabels(pb);
+  }
+
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    if(pb->cmemmap->dbName == dbName)
+      optimizepBlock(pb);
+  }
+
+  /* Now build the call tree.
+     First we examine all of the pCodes for functions.
+     
+   */
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    if(pb->cmemmap->dbName == dbName) {
+      pCode *pc_fstart=NULL;
+      for(pc = pb->pcHead; pc; pc = pc->next) {
+       if(pc->type == PC_FUNCTION) {
+         if (PCF(pc)->fname) {
+           // Found the beginning of a function.
+           _ALLOC(pbr,sizeof(pBranch));
+           pbr->pc = pc_fstart = pc;
+           pbr->next = NULL;
+
+           the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
+         } else {
+           // Found an exit point in a function, e.g. return
+           // (Note, there may be more than one return per function)
+           if(pc_fstart)
+             pBranchLink(pc_fstart, pc);
+         }
+       }
+      }
+    }
+  }
+}
+
+/*-----------------------------------------------------------------*/
+/* ispCodeFunction - returns true if *pc is the pCode of a         */
+/*                   function                                      */
+/*-----------------------------------------------------------------*/
+bool ispCodeFunction(pCode *pc)
+{
+
+  if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
+    return 1;
+
+  return 0;
+}
+
+void printCallTree(FILE *of)
+{
+  pBranch *pbr;
+
+  if(!the_pFile)
+    return;
+
+  if(!of)
+    of = stderr;
+
+  pbr = the_pFile->functions;
+
+  fprintf(of,"Call Tree\n");
+  while(pbr) {
+    if(pbr->pc) {
+      pCode *pc = pbr->pc;
+      if(!ispCodeFunction(pc))
+       fprintf(of,"bug in call tree");
+
+
+      fprintf(of,"Function: %s\n", PCF(pc)->fname);
+
+      while(pc->next && !ispCodeFunction(pc->next)) {
+       pc = pc->next;
+       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
+         fprintf(of,"\t%s\n",get_op(PCI(pc)));
+      }
+    }
+
+    pbr = pbr->next;
+  }
+}
+#if 0
+/*-----------------------------------------------------------------*/
+/* pCodePeep */
+/*-----------------------------------------------------------------*/
+int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
+{
+  pCode *pcfrom,*pcto;
+
+  pcfrom = pc;
+  for( pcto=pcp->target; pcto; pcto=pcto->next) {
+
+    pcfrom = findNextInstruction(pcfrom);
+
+    if( pcfrom &&  
+       (PCI(pcfrom)->op == PCI(pcto)->op || 
+        PCI(pcto)->op == POC_WILD))
+      continue;
+    return 0;
+  }
+  return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodePeep */
+/*-----------------------------------------------------------------*/
+void pCodePeepSearch(pCodePeep *snippet)
+{
+  pBlock *pb;
+  pCode *pc;
+
+  if(!the_pFile)
+    return;
+
+  /* compare the chain to the pCode that we've 
+     got so far. If a match is found, then replace
+     the pCode chain.
+  */
+  for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+    for(pc = pb->pcHead; pc; pc = pc->next) {
+      pCodePeepCompare(pc,snippet);
+    }
+  }
+
+}
+#endif
+
+#if 0
+pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
+{
+  pBlock *pb;
+
+  if(!pb1->tail)
+    return pb2;
+
+  pb = pb1->tail;
+
+  pb2->head = pb1;
+  pb2->tail = NULL;
+  pb1->tail = pb2;
+
+}
+
+#endif
+
+void pCodePeepInit(void)
+{
+  pBlock *pb;
+  //  pCode *pc;
+
+  if(!peepSnippets)
+    _ALLOC(peepSnippets,sizeof(pBlock));
+
+
+  pb = newpCodeChain(NULL,newpCodeCharP("; Starting pCode block"));
+
+  if(!peepSnippets->next)
+    peepSnippets->next = pb;
+  else {
+    peepSnippets->next->next = pb;
+    pb->prev = peepSnippets->next;
+  }
+  // now create some sample peep pcodes
+
+  addpCode2pBlock( pb, newpCode(POC_MOVWF, newpCodeOpWild(1)) );
+  addpCode2pBlock( pb, newpCode(POC_MOVFW, newpCodeOpWild(1)) );
+  // addpBlock(pb);
+
+}
diff --git a/src/pic/pcode.h b/src/pic/pcode.h
new file mode 100644 (file)
index 0000000..a6eae94
--- /dev/null
@@ -0,0 +1,485 @@
+/*-------------------------------------------------------------------------
+
+   pcode.h - post code generation
+   Written By -  Scott Dattalo scott@dattalo.com
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+   
+-------------------------------------------------------------------------*/
+
+/*
+   Post code generation
+
+   The post code generation is an assembler optimizer. The assembly code
+   produced by all of the previous steps is fully functional. This step
+   will attempt to analyze the flow of the assembly code and agressively 
+   optimize it. The peep hole optimizer attempts to do the same thing.
+   As you may recall, the peep hole optimizer replaces blocks of assembly
+   with more optimal blocks (e.g. removing redundant register loads).
+   However, the peep hole optimizer has to be somewhat conservative since
+   an assembly program has implicit state information that's unavailable 
+   when only a few instructions are examined.
+     Consider this example:
+
+   example1:
+     movwf  t1
+     movf   t1,w
+
+   The movf seems redundant since we know that the W register already
+   contains the same value of t1. So a peep hole optimizer is tempted to
+   remove the "movf". However, this is dangerous since the movf affects
+   the flags in the status register (specifically the Z flag) and subsequent
+   code may depend upon this. Look at these two examples:
+
+   example2:
+     movwf  t1
+     movf   t1,w     ; Can't remove this movf
+     skpz
+      return
+
+   example3:
+     movwf  t1
+     movf   t1,w     ; This  movf can be removed
+     xorwf  t2,w     ; since xorwf will over write Z 
+     skpz
+      return
+
+*/
+
+
+#ifndef __PCODE_H__
+#define __PCODE_H__
+
+/***********************************************************************
+ *  PIC status bits - this will move into device dependent headers
+ ***********************************************************************/
+#define PIC_C_BIT    0
+#define PIC_DC_BIT   1
+#define PIC_Z_BIT    2
+
+/***********************************************************************
+ *  Operand types 
+ ***********************************************************************/
+#define POT_RESULT  0
+#define POT_LEFT    1
+#define POT_RIGHT   2
+
+
+/***********************************************************************
+ *
+ *  PIC_OPTYPE - Operand types that are specific to the PIC architecture
+ *
+ *  If a PIC assembly instruction has an operand then here is where we
+ *  associate a type to it. For example,
+ *
+ *     movf    reg,W
+ *
+ *  The movf has two operands: 'reg' and the W register. 'reg' is some
+ *  arbitrary general purpose register, hence it has the type PO_GPR_REGISTER.
+ *  The W register, which is the PIC's accumulator, has the type PO_W.
+ *
+ ***********************************************************************/
+
+
+
+typedef enum 
+{
+  PO_NONE=0,         // No operand e.g. NOP
+  PO_W,              // The 'W' register
+  PO_STATUS,         // The 'STATUS' register
+  PO_FSR,            // The "file select register" (in 18c it's one of three)
+  PO_INDF,           // The Indirect register
+  PO_GPR_REGISTER,   // A general purpose register
+  PO_SFR_REGISTER,   // A special function register (e.g. PORTA)
+  PO_LITERAL,        // A constant
+  PO_IMMEDIATE,      //  (8051 legacy)
+  PO_DIR,            // Direct memory (8051 legacy)
+  PO_CRY,            // bit memory (8051 legacy)
+  PO_BIT,            // bit operand.
+  PO_STR,            //  (8051 legacy)
+  PO_LABEL,
+  PO_WILD            // Wild card operand in peep optimizer
+} PIC_OPTYPE;
+
+
+/***********************************************************************
+ *
+ *  PIC_OPCODE
+ *
+ *  This is not a list of the PIC's opcodes per se, but instead
+ *  an enumeration of all of the different types of pic opcodes. 
+ *
+ ***********************************************************************/
+
+typedef enum
+{
+  POC_WILD=-1,   /* Wild card - used in the pCode peep hole optimizer
+                 * to represent ANY pic opcode */
+  POC_ADDLW=0,
+  POC_ADDWF,
+  POC_ADDFW,
+  POC_ANDLW,
+  POC_ANDWF,
+  POC_ANDFW,
+  POC_BCF,
+  POC_BSF,
+  POC_BTFSC,
+  POC_BTFSS,
+  POC_CALL,
+  POC_COMF,
+  POC_CLRF,
+  POC_CLRW,
+  POC_DECF,
+  POC_DECFW,
+  POC_DECFSZ,
+  POC_DECFSZW,
+  POC_GOTO,
+  POC_INCF,
+  POC_INCFW,
+  POC_INCFSZ,
+  POC_INCFSZW,
+  POC_IORLW,
+  POC_IORWF,
+  POC_IORFW,
+  POC_MOVF,
+  POC_MOVFW,
+  POC_MOVLW,
+  POC_MOVWF,
+  POC_NEGF,
+  POC_RETLW,
+  POC_RETURN,
+  POC_SUBLW,
+  POC_SUBWF,
+  POC_SUBFW,
+  POC_TRIS,
+  POC_XORLW,
+  POC_XORWF,
+  POC_XORFW
+} PIC_OPCODE;
+
+
+/***********************************************************************
+ *  PC_TYPE  - pCode Types
+ ***********************************************************************/
+
+typedef enum
+{
+  PC_COMMENT=0,   // pCode is a comment
+  PC_OPCODE,      // PORT dependent opcode
+  PC_LABEL,       // assembly label
+  PC_FUNCTION,    // Function start or end
+  PC_WILD         // wildcard - an opcode place holder
+} PC_TYPE;
+
+/************************************************/
+/***************  Structures ********************/
+/************************************************/
+struct pCode;
+
+/*************************************************
+  pBranch
+
+  The first step in optimizing pCode is determining
+ the program flow. This information is stored in
+ single-linked lists in the for of 'from' and 'to'
+ objects with in a pcode. For example, most instructions
+ don't involve any branching. So their from branch
+ points to the pCode immediately preceding them and
+ their 'to' branch points to the pcode immediately
+ following them. A skip instruction is an example of
+ a pcode that has multiple (in this case two) elements
+ in the 'to' branch. A 'label' pcode is an where there
+ may be multiple 'from' branches.
+ *************************************************/
+
+typedef struct pBranch
+{
+  struct pCode   *pc;    // Next pCode in a branch
+  struct pBranch *next;  /* If more than one branch
+                         * the next one is here */
+
+} pBranch;
+
+/*************************************************
+  pCodeOp
+
+  pCode Operand structure.
+  For those assembly instructions that have arguments, 
+  the pCode will have a pCodeOp in which the argument
+  can be stored. For example
+
+    movf   some_register,w
+
+  'some_register' will be stored/referenced in a pCodeOp
+
+ *************************************************/
+
+typedef struct pCodeOp
+{
+  PIC_OPTYPE type;
+  char *name;
+  
+} pCodeOp;
+
+typedef struct pCodeOpBit
+{
+  pCodeOp pcop;
+  int bit;
+  unsigned int inBitSpace: 1; /* True if in bit space, else
+                                just a bit of a register */
+} pCodeOpBit;
+
+typedef struct pCodeOpLit
+{
+  pCodeOp pcop;
+  int lit;
+} pCodeOpLit;
+
+typedef struct pCodeOpLabel
+{
+  pCodeOp pcop;
+  int key;
+} pCodeOpLabel;
+
+typedef struct pCodeOpWild
+{
+  pCodeOp pcop;
+  int id;
+} pCodeOpWild;
+
+
+/*************************************************
+    pCode
+
+    Here the basic build block of a PIC instruction.
+    Each pic instruction will get allocated a pCode.
+    A linked list of pCodes makes a program.
+
+**************************************************/
+
+typedef struct pCode
+{
+  PC_TYPE    type;
+
+  struct pCode *prev;  // The pCode objects are linked together
+  struct pCode *next;  // in doubly linked lists.
+
+  pBranch *from;       // pCodes that execute before this one
+  pBranch *to;         // pCodes that execute after
+  pBranch *label;      // pCode instructions that have labels
+
+  /* "virtual functions"
+   *  The pCode structure is like a base class
+   * in C++. The subsequent structures that "inherit"
+   * the pCode structure will initialize these function
+   * pointers to something useful */
+  void (*analyze) (struct pCode *_this);
+  void (*destruct)(struct pCode *_this);
+  void (*print)  (FILE *of,struct pCode *_this);
+
+} pCode;
+
+
+/*************************************************
+    pCodeComment
+**************************************************/
+
+typedef struct pCodeComment
+{
+
+  pCode  pc;
+
+  char *comment;
+
+} pCodeComment;
+
+/*************************************************
+    pCodeInstruction
+
+    Here we describe all the facets of a PIC instruction
+    (expansion for the 18cxxx is also provided).
+
+**************************************************/
+
+typedef struct pCodeInstruction
+{
+
+  pCode  pc;
+
+  PIC_OPCODE op;        // The opcode of the instruction.
+
+  char *mnemonic;       // Pointer to mnemonic string
+
+  pCodeOp *pcop;        // Operand
+
+  unsigned int num_ops;
+  unsigned int dest:     1;       // If destination is W or F, then 1==F
+  unsigned int bit_inst: 1;
+
+} pCodeInstruction;
+
+
+/*************************************************
+    pCodeLabel
+**************************************************/
+
+typedef struct pCodeLabel
+{
+
+  pCode  pc;
+
+  int key;
+} pCodeLabel;
+
+/*************************************************
+    pCodeFunction
+**************************************************/
+
+typedef struct pCodeFunction
+{
+
+  pCode  pc;
+
+  char *modname;
+  char *fname;     /* If NULL, then this is the end of
+                     a function. Otherwise, it's the
+                     start and the name is contained
+                     here */
+
+} pCodeFunction;
+
+
+/*************************************************
+    pBlock
+
+    Here are PIC program snippets. There's a strong
+    correlation between the eBBlocks and pBlocks.
+    SDCC subdivides a C program into managable chunks.
+    Each chunk becomes a eBBlock and ultimately in the
+    PIC port a pBlock.
+
+**************************************************/
+
+typedef struct pBlock
+{
+  memmap *cmemmap;   /* The snippet is from this memmap */
+  pCode *pcHead;     /* A pointer to the first pCode in a link list of pCodes */
+  pCode *pcTail;     /* A pointer to the last pCode in a link list of pCodes */
+
+  struct pBlock *next;      /* The pBlocks will form a doubly linked list */
+  struct pBlock *prev;
+
+} pBlock;
+
+/*************************************************
+    pFile
+
+    The collection of pBlock program snippets are
+    placed into a linked list that is implemented
+    in the pFile structure.
+
+    The pcode optimizer will parse the pFile.
+
+**************************************************/
+
+typedef struct pFile
+{
+  pBlock *pbHead;     /* A pointer to the first pBlock */
+  pBlock *pbTail;     /* A pointer to the last pBlock */
+
+  pBranch *functions; /* A SLL of functions in this pFile */
+
+} pFile;
+
+
+/*************************************************
+  pCodePeep
+
+  The pCodePeep object mimics the peep hole optimizer
+  in the main SDCC src (e.g. SDCCpeeph.c). Essentially
+  there is a target pCode chain and a replacement
+  pCode chain. The target chain is compared to the
+  pCode that is generated by gen.c. If a match is
+  found then the pCode is replaced by the replacement
+  pCode chain.
+**************************************************/
+typedef struct pCodePeep {
+
+  pBlock *target;    // code we'd like to optimize
+  pBlock *replace;   // and this is what we'll optimize it with.
+
+} pCodePeep;
+
+/*************************************************
+    pCode Macros
+
+**************************************************/
+#define PCI(x)  ((pCodeInstruction *)(x))
+#define PCL(x)  ((pCodeLabel *)(x))
+#define PCF(x)  ((pCodeFunction *)(x))
+
+/*-----------------------------------------------------------------*
+ * pCode functions.
+ *-----------------------------------------------------------------*/
+
+pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop); // Create a new pCode given an operand
+pCode *newpCodeCharP(char *cP);              // Create a new pCode given a char *
+pCode *newpCodeFunction(char *g, char *f);   // Create a new function
+pCode *newpCodeLabel(int key);               // Create a new label
+pBlock *newpCodeChain(memmap *cm,pCode *pc); // Create a new pBlock
+void printpBlock(FILE *of, pBlock *pb);      // Write a pBlock to a file
+void printpCode(FILE *of, pCode *pc);        // Write a pCode to a file
+void addpCode2pBlock(pBlock *pb, pCode *pc); // Add a pCode to a pBlock
+void addpBlock(pBlock *pb);                  // Add a pBlock to a pFile
+void copypCode(FILE *of, char dbName);       // Write all pBlocks with dbName to *of
+void AnalyzepCode(char dbName);
+void printCallTree(FILE *of);
+
+pCodeOp *newpCodeOpLabel(int key);
+pCodeOp *newpCodeOpLit(int lit);
+pCodeOp *newpCodeOpBit(char *name, int bit);
+pCodeOp *newpCodeOp(char *name);
+extern void pcode_test(void);
+
+/*-----------------------------------------------------------------*
+ * pCode objects.
+ *-----------------------------------------------------------------*/
+
+extern pCodeOp pc_status;
+extern pCodeOp pc_indf;
+extern pCodeOp pc_fsr;
+
+
+////////////////////   DELETE THIS ///////////////////
+/*-----------------------------------------------------------------*/
+/* Allocation macros that replace those in SDCCalloc.h             */
+/*   Why? I dunno. I ran across a bug with those macros that       */
+/*   I couldn't fix, but I could work around...                    */
+/*-----------------------------------------------------------------*/
+# define GC_malloc(x) calloc((x), 1)
+
+#define  _ALLOC(x,sz) if (!(x = calloc((sz),1) ))      \
+         {                                          \
+            werror(E_OUT_OF_MEM,__FILE__,(long) sz);\
+            exit (1);                               \
+         }
+
+#define _ALLOC_ATOMIC(x,y) if (!((x) = malloc(y)))   \
+         {                                               \
+            werror(E_OUT_OF_MEM,__FILE__,(long) y);     \
+            exit (1);                                    \
+         }
+
+#endif // __PCODE_H__