+ sym_link *dtype;
+ symbol *sym;
+ unsigned char *name;
+ int isExtern;
+
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters(ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ dtype = operandType(IC_LEFT(ic));
+ if (currFunc && dtype &&
+ (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype)) &&
+ IFFUNC_ISISR(currFunc->type) &&
+ !ic->bankSaved)
+
+ saverbank(FUNC_REGBANK(dtype),ic,TRUE);
+
+ /* if send set is not empty the assign */
+ if (_G.sendSet) {
+ iCode *sic;
+ /* For the Pic port, there is no data stack.
+ * So parameters passed to functions are stored
+ * in registers. (The pCode optimizer will get
+ * rid of most of these :).
+ */
+ int psuedoStkPtr=-1;
+ int firstTimeThruLoop = 1;
+
+ _G.sendSet = reverseSet(_G.sendSet);
+
+ /* First figure how many parameters are getting passed */
+ for (sic = setFirstItem(_G.sendSet) ; sic ;
+ sic = setNextItem(_G.sendSet)) {
+
+ aopOp(IC_LEFT(sic),sic,FALSE);
+ psuedoStkPtr += AOP_SIZE(IC_LEFT(sic));
+ freeAsmop (IC_LEFT(sic),NULL,sic,FALSE);
+ }
+
+ for (sic = setFirstItem(_G.sendSet) ; sic ;
+ sic = setNextItem(_G.sendSet)) {
+ int size, offset = 0;
+
+ aopOp(IC_LEFT(sic),sic,FALSE);
+ size = AOP_SIZE(IC_LEFT(sic));
+
+ while (size--) {
+ DEBUGpic14_emitcode ("; ","%d left %s",__LINE__,
+ AopType(AOP_TYPE(IC_LEFT(sic))));
+
+ if(!firstTimeThruLoop) {
+ /* If this is not the first time we've been through the loop
+ * then we need to save the parameter in a temporary
+ * register. The last byte of the last parameter is
+ * passed in W. */
+ emitpcode(POC_MOVWF,popRegFromIdx(Gstack_base_addr - --psuedoStkPtr));
+
+ }
+ firstTimeThruLoop=0;
+
+ mov2w (AOP(IC_LEFT(sic)), offset);
+ offset++;
+ }
+ freeAsmop (IC_LEFT(sic),NULL,sic,TRUE);
+ }
+ _G.sendSet = NULL;
+ }
+ /* make the call */
+ sym = OP_SYMBOL(IC_LEFT(ic));
+ name = sym->rname[0] ? sym->rname : sym->name;
+ isExtern = IS_EXTERN(sym->etype);
+ if (isExtern) {
+ emitpcode(POC_PAGESEL,popGetWithString(name,1)); /* Extern functions maybe on another page - must call pagesel */
+ }
+ emitpcode(POC_CALL,popGetWithString(name,isExtern));
+ if (isExtern) {
+ emitpcode(POC_PAGESEL,popGetWithString("$",0)); /* May have returned from another page - must call pagesel to restore PCLATH before next goto or call instruction */
+ }
+ GpsuedoStkPtr=0;
+ /* if we need assign a result value */
+ if ((IS_ITEMP(IC_RESULT(ic)) &&
+ (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
+ OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
+ IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
+
+ _G.accInUse++;
+ aopOp(IC_RESULT(ic),ic,FALSE);
+ _G.accInUse--;
+
+ assignResultValue(IC_RESULT(ic));
+
+ DEBUGpic14_emitcode ("; ","%d left %s",__LINE__,
+ AopType(AOP_TYPE(IC_RESULT(ic))));
+
+ freeAsmop(IC_RESULT(ic),NULL, ic,TRUE);
+ }
+
+ /* adjust the stack for parameters if
+ required */
+ if (ic->parmBytes) {
+ int i;
+ if (ic->parmBytes > 3) {
+ pic14_emitcode("mov","a,%s",spname);
+ pic14_emitcode("add","a,#0x%02x", (- ic->parmBytes) & 0xff);
+ pic14_emitcode("mov","%s,a",spname);
+ } else
+ for ( i = 0 ; i < ic->parmBytes ;i++)
+ pic14_emitcode("dec","%s",spname);
+
+ }
+
+ /* if register bank was saved then pop them */
+ if (ic->bankSaved)
+ unsaverbank(FUNC_REGBANK(dtype),ic,TRUE);
+
+ /* if we hade saved some registers then unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
+ unsaveRegisters (ic);
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPcall - generates a call by pointer statement */
+/*-----------------------------------------------------------------*/
+static void genPcall (iCode *ic)
+{
+ sym_link *dtype;
+ symbol *albl = newiTempLabel(NULL);
+ symbol *blbl = newiTempLabel(NULL);
+ PIC_OPCODE poc;
+ pCodeOp *pcop;
+ operand *left;
+
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters(ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ dtype = operandType(IC_LEFT(ic));
+ if (currFunc && dtype &&
+ IFFUNC_ISISR(currFunc->type) &&
+ (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype)))
+ saverbank(FUNC_REGBANK(dtype),ic,TRUE);
+
+ left = IC_LEFT(ic);
+ aopOp(left,ic,FALSE);
+ DEBUGpic14_AopType(__LINE__,left,NULL,NULL);
+
+ pushSide(IC_LEFT(ic), FPTRSIZE);
+
+ /* if send set is not empty, assign parameters */
+ if (_G.sendSet) {
+
+ DEBUGpic14_emitcode ("; ***","%s %d - WARNING arg-passing to indirect call not supported",__FUNCTION__,__LINE__);
+ /* no way to pass args - W always gets used to make the call */
+ }
+ /* first idea - factor out a common helper function and call it.
+ But don't know how to get it generated only once in its own block
+
+ if(AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) {
+ char *rname;
+ char *buffer;
+ rname = IC_LEFT(ic)->aop->aopu.aop_dir;
+ DEBUGpic14_emitcode ("; ***","%s %d AOP_DIR %s",__FUNCTION__,__LINE__,rname);
+ buffer = Safe_calloc(1,strlen(rname)+16);
+ sprintf(buffer, "%s_goto_helper", rname);
+ addpCode2pBlock(pb,newpCode(POC_CALL,newpCodeOp(buffer,PO_STR)));
+ free(buffer);
+ }
+ */
+ emitpcode(POC_CALL,popGetLabel(albl->key));
+ pcop = popGetLabel(blbl->key);
+ emitpcode(POC_PAGESEL,popGetWithString(pcop->name,0)); /* Must restore PCLATH before goto, without destroying W */
+ emitpcode(POC_GOTO,pcop);
+ emitpLabel(albl->key);
+
+ poc = ( (AOP_TYPE(left) == AOP_PCODE) ? POC_MOVLW : POC_MOVFW);
+
+ emitpcode(poc,popGet(AOP(left),1));
+ emitpcode(POC_MOVWF,popCopyReg(&pc_pclath));
+ emitpcode(poc,popGet(AOP(left),0));
+ emitpcode(POC_MOVWF,popCopyReg(&pc_pcl));
+
+ emitpLabel(blbl->key);
+
+ freeAsmop(IC_LEFT(ic),NULL,ic,TRUE);
+
+ /* if we need to assign a result value */
+ if ((IS_ITEMP(IC_RESULT(ic)) &&
+ (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
+ OP_SYMBOL(IC_RESULT(ic))->spildir)) ||
+ IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
+
+ _G.accInUse++;
+ aopOp(IC_RESULT(ic),ic,FALSE);
+ _G.accInUse--;
+
+ assignResultValue(IC_RESULT(ic));
+
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+ }
+
+ /* if register bank was saved then unsave them */
+ if (currFunc && dtype &&
+ (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype)))
+ unsaverbank(FUNC_REGBANK(dtype),ic,TRUE);
+
+ /* if we hade saved some registers then
+ unsave them */
+ if (ic->regsSaved)
+ unsaveRegisters (ic);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* resultRemat - result is rematerializable */
+/*-----------------------------------------------------------------*/
+static int resultRemat (iCode *ic)
+{
+ // DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ if (SKIP_IC(ic) || ic->op == IFX)
+ return 0;
+
+ if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
+ symbol *sym = OP_SYMBOL(IC_RESULT(ic));
+ if (sym->remat && !POINTER_SET(ic))
+ return 1;
+ }
+
+ return 0;
+}
+
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* inExcludeList - return 1 if the string is in exclude Reg list */
+/*-----------------------------------------------------------------*/
+static bool inExcludeList(char *s)
+{
+ DEBUGpic14_emitcode ("; ***","%s %d - WARNING no code generated",__FUNCTION__,__LINE__);
+ int i =0;
+
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ if (options.excludeRegs[i] &&
+ STRCASECMP(options.excludeRegs[i],"none") == 0)
+ return FALSE ;
+
+ for ( i = 0 ; options.excludeRegs[i]; i++) {
+ if (options.excludeRegs[i] &&
+ STRCASECMP(s,options.excludeRegs[i]) == 0)
+ return TRUE;
+ }
+ return FALSE ;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* genFunction - generated code for function entry */
+/*-----------------------------------------------------------------*/
+static void genFunction (iCode *ic)
+{
+ symbol *sym;
+ sym_link *ftype;
+
+ DEBUGpic14_emitcode ("; ***","%s %d curr label offset=%dprevious max_key=%d ",__FUNCTION__,__LINE__,labelOffset,max_key);
+
+ labelOffset += (max_key+4);
+ max_key=0;
+ GpsuedoStkPtr=0;
+ _G.nRegsSaved = 0;
+ /* create the function header */
+ pic14_emitcode(";","-----------------------------------------");
+ pic14_emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
+ pic14_emitcode(";","-----------------------------------------");
+
+ pic14_emitcode("","%s:",sym->rname);
+ addpCode2pBlock(pb,newpCodeFunction(NULL,sym->rname,!IS_STATIC (sym->etype)));
+
+ ftype = operandType(IC_LEFT(ic));
+
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL(ftype))
+ pic14_emitcode("clr","ea");
+
+ /* here we need to generate the equates for the
+ register bank if required */
+#if 0
+ if (FUNC_REGBANK(ftype) != rbank) {
+ int i ;
+
+ rbank = FUNC_REGBANK(ftype);
+ for ( i = 0 ; i < pic14_nRegs ; i++ ) {
+ if (strcmp(regspic14[i].base,"0") == 0)
+ pic14_emitcode("","%s = 0x%02x",
+ regspic14[i].dname,
+ 8*rbank+regspic14[i].offset);
+ else
+ pic14_emitcode ("","%s = %s + 0x%02x",
+ regspic14[i].dname,
+ regspic14[i].base,
+ 8*rbank+regspic14[i].offset);
+ }
+ }
+#endif
+
+ /* if this is an interrupt service routine */
+ if (IFFUNC_ISISR(sym->type)) {
+ /* already done in pic14createInterruptVect() - delete me
+ addpCode2pBlock(pb,newpCode(POC_GOTO,newpCodeOp("END_OF_INTERRUPT+1",PO_STR)));
+ emitpcodeNULLop(POC_NOP);
+ emitpcodeNULLop(POC_NOP);
+ emitpcodeNULLop(POC_NOP);
+ */
+ emitpcode(POC_MOVWF, popCopyReg(&pc_wsave));
+ emitpcode(POC_SWAPFW, popCopyReg(&pc_status));
+ emitpcode(POC_CLRF, popCopyReg(&pc_status));
+ emitpcode(POC_MOVWF, popCopyReg(&pc_ssave));
+ emitpcode(POC_MOVFW, popCopyReg(&pc_pclath));
+ emitpcode(POC_MOVWF, popCopyReg(&pc_psave));
+ emitpcode(POC_CLRF, popCopyReg(&pc_pclath));/* during an interrupt PCLATH must be cleared before a goto or call statement */
+
+ pBlockConvert2ISR(pb);
+#if 0
+ if (!inExcludeList("acc"))
+ pic14_emitcode ("push","acc");
+ if (!inExcludeList("b"))
+ pic14_emitcode ("push","b");
+ if (!inExcludeList("dpl"))
+ pic14_emitcode ("push","dpl");
+ if (!inExcludeList("dph"))
+ pic14_emitcode ("push","dph");
+ if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
+ {
+ pic14_emitcode ("push", "dpx");
+ /* Make sure we're using standard DPTR */
+ pic14_emitcode ("push", "dps");
+ pic14_emitcode ("mov", "dps, #0x00");
+ if (options.stack10bit)
+ {
+ /* This ISR could conceivably use DPTR2. Better save it. */
+ pic14_emitcode ("push", "dpl1");
+ pic14_emitcode ("push", "dph1");
+ pic14_emitcode ("push", "dpx1");
+ }
+ }
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+registers :-) */
+ if (!FUNC_REGBANK(sym->type)) {
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (! IFFUNC_HASFCALL(sym->type)) {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed) {
+ /* save the registers used */
+ for ( i = 0 ; i < sym->regsUsed->size ; i++) {
+ if (bitVectBitValue(sym->regsUsed,i) ||
+ (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
+ pic14_emitcode("push","junk");//"%s",pic14_regWithIdx(i)->dname);
+ }
+ }
+
+ } else {
+ /* this function has a function call cannot
+ determines register usage so we will have the
+ entire bank */
+ saverbank(0,ic,FALSE);
+ }
+ }
+#endif
+ } else {
+ /* if callee-save to be used for this function
+ then save the registers being used in this function */
+ if (IFFUNC_CALLEESAVES(sym->type)) {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed) {
+ /* save the registers used */
+ for ( i = 0 ; i < sym->regsUsed->size ; i++) {
+ if (bitVectBitValue(sym->regsUsed,i) ||
+ (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) {
+ //pic14_emitcode("push","%s",pic14_regWithIdx(i)->dname);
+ _G.nRegsSaved++;
+ }
+ }
+ }
+ }
+ }
+
+ /* set the register bank to the desired value */
+ if (FUNC_REGBANK(sym->type) || FUNC_ISISR(sym->type)) {
+ pic14_emitcode("push","psw");
+ pic14_emitcode("mov","psw,#0x%02x",(FUNC_REGBANK(sym->type) << 3)&0x00ff);
+ }
+
+ if (IFFUNC_ISREENT(sym->type) || options.stackAuto) {
+
+ if (options.useXstack) {
+ pic14_emitcode("mov","r0,%s",spname);
+ pic14_emitcode("mov","a,_bp");
+ pic14_emitcode("movx","@r0,a");
+ pic14_emitcode("inc","%s",spname);
+ }
+ else
+ {
+ /* set up the stack */
+ pic14_emitcode ("push","_bp"); /* save the callers stack */
+ }
+ pic14_emitcode ("mov","_bp,%s",spname);
+ }
+
+ /* adjust the stack for the function */
+ if (sym->stack) {
+
+ int i = sym->stack;
+ if (i > 256 )
+ werror(W_STACK_OVERFLOW,sym->name);
+
+ if (i > 3 && sym->recvSize < 4) {
+
+ pic14_emitcode ("mov","a,sp");
+ pic14_emitcode ("add","a,#0x%02x",((char)sym->stack & 0xff));
+ pic14_emitcode ("mov","sp,a");
+
+ }
+ else
+ while(i--)
+ pic14_emitcode("inc","sp");
+ }
+
+ if (sym->xstack) {
+
+ pic14_emitcode ("mov","a,_spx");
+ pic14_emitcode ("add","a,#0x%02x",((char)sym->xstack & 0xff));
+ pic14_emitcode ("mov","_spx,a");
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndFunction - generates epilogue for functions */
+/*-----------------------------------------------------------------*/
+static void genEndFunction (iCode *ic)
+{
+ symbol *sym = OP_SYMBOL(IC_LEFT(ic));
+
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+
+ if (IFFUNC_ISREENT(sym->type) || options.stackAuto)
+ {
+ pic14_emitcode ("mov","%s,_bp",spname);
+ }
+
+ /* if use external stack but some variables were
+ added to the local stack then decrement the
+ local stack */
+ if (options.useXstack && sym->stack) {
+ pic14_emitcode("mov","a,sp");
+ pic14_emitcode("add","a,#0x%02x",((char)-sym->stack) & 0xff);
+ pic14_emitcode("mov","sp,a");
+ }
+
+
+ if ((IFFUNC_ISREENT(sym->type) || options.stackAuto)) {
+ if (options.useXstack) {
+ pic14_emitcode("mov","r0,%s",spname);
+ pic14_emitcode("movx","a,@r0");
+ pic14_emitcode("mov","_bp,a");
+ pic14_emitcode("dec","%s",spname);
+ }
+ else
+ {
+ pic14_emitcode ("pop","_bp");
+ }
+ }
+
+ /* restore the register bank */
+ if (FUNC_REGBANK(sym->type) || FUNC_ISISR(sym->type))
+ pic14_emitcode ("pop","psw");
+
+ if (IFFUNC_ISISR(sym->type)) {
+
+ /* now we need to restore the registers */
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+registers :-) */
+ if (!FUNC_REGBANK(sym->type)) {
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (! IFFUNC_HASFCALL(sym->type)) {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed) {
+ /* save the registers used */
+ for ( i = sym->regsUsed->size ; i >= 0 ; i--) {
+ if (bitVectBitValue(sym->regsUsed,i) ||
+ (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) )
+ pic14_emitcode("pop","junk");//"%s",pic14_regWithIdx(i)->dname);
+ }
+ }
+
+ } else {
+ /* this function has a function call cannot
+ determines register usage so we will have the
+ entire bank */
+ unsaverbank(0,ic,FALSE);
+ }
+ }
+#if 0
+ if (options.model == MODEL_FLAT24 && !inExcludeList("dpx"))
+ {
+ if (options.stack10bit)
+ {
+ pic14_emitcode ("pop", "dpx1");
+ pic14_emitcode ("pop", "dph1");
+ pic14_emitcode ("pop", "dpl1");
+ }
+ pic14_emitcode ("pop", "dps");
+ pic14_emitcode ("pop", "dpx");
+ }
+ if (!inExcludeList("dph"))
+ pic14_emitcode ("pop","dph");
+ if (!inExcludeList("dpl"))
+ pic14_emitcode ("pop","dpl");
+ if (!inExcludeList("b"))
+ pic14_emitcode ("pop","b");
+ if (!inExcludeList("acc"))
+ pic14_emitcode ("pop","acc");
+
+ if (IFFUNC_ISCRITICAL(sym->type))
+ pic14_emitcode("setb","ea");
+#endif
+
+ /* if debug then send end of function */
+ /* if (options.debug && currFunc) { */
+ if (currFunc) {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+
+ pic14_emitcode ("reti","");
+ emitpcode(POC_MOVFW, popCopyReg(&pc_psave));
+ emitpcode(POC_MOVWF, popCopyReg(&pc_pclath));
+ emitpcode(POC_CLRF, popCopyReg(&pc_status));
+ emitpcode(POC_SWAPFW, popCopyReg(&pc_ssave));
+ emitpcode(POC_MOVWF, popCopyReg(&pc_status));
+ emitpcode(POC_SWAPF, popCopyReg(&pc_wsave));
+ emitpcode(POC_SWAPFW, popCopyReg(&pc_wsave));
+ addpCode2pBlock(pb,newpCodeLabel("END_OF_INTERRUPT",-1));
+ emitpcodeNULLop(POC_RETFIE);
+ }