From 0ac21a6202860fc8bd0fef3591328e6a70541872 Mon Sep 17 00:00:00 2001 From: sdattalo Date: Sun, 18 Feb 2001 04:16:09 +0000 Subject: [PATCH] Added pCode to the PIC port git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@627 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- src/pic/Makefile | 7 +- src/pic/Makefile.bcc | 4 +- src/pic/glue.c | 351 ++++++------ src/pic/pcode.c | 1242 ++++++++++++++++++++++++++++++++++++++++++ src/pic/pcode.h | 485 +++++++++++++++++ 5 files changed, 1917 insertions(+), 172 deletions(-) create mode 100644 src/pic/pcode.c create mode 100644 src/pic/pcode.h diff --git a/src/pic/Makefile b/src/pic/Makefile index c9556e90..aad06b82 100644 --- a/src/pic/Makefile +++ b/src/pic/Makefile @@ -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) diff --git a/src/pic/Makefile.bcc b/src/pic/Makefile.bcc index 4b17a92d..4e0e7470 100644 --- a/src/pic/Makefile.bcc +++ b/src/pic/Makefile.bcc @@ -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 diff --git a/src/pic/glue.c b/src/pic/glue.c index abd20a56..c21c9d54 100644 --- a/src/pic/glue.c +++ b/src/pic/glue.c @@ -25,8 +25,10 @@ #include "../common.h" #include #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=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 index 00000000..dae97df9 --- /dev/null +++ b/src/pic/pcode.c @@ -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 + +#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 index 00000000..a6eae940 --- /dev/null +++ b/src/pic/pcode.h @@ -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__ -- 2.39.5