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
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)
# !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
$(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
#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;
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);
+
}
}
//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;
}
}
}
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");
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");
/* 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");
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)
{
* 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);
}
--- /dev/null
+/*-------------------------------------------------------------------------
+
+ 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);
+
+}
--- /dev/null
+/*-------------------------------------------------------------------------
+
+ 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__