* src/pic16/main.c (_pic16_linkEdit,pic16_linkCmd),
[fw/sdcc] / src / pic16 / genutils.c
index 55e5bbe9d3572bf9262d77b7b1b75ad8d4a0529b..46ff7731dc20090a5a924b453bd8f8cddd52262f 100644 (file)
@@ -54,6 +54,7 @@
 #include "SDCCpeeph.h"
 #include "ralloc.h"
 #include "pcode.h"
+#include "device.h"
 #include "gen.h"
 
 #include "genutils.h"
@@ -154,6 +155,8 @@ void pic16_genCpl (iCode *ic)
     } 
 
     size = AOP_SIZE(IC_RESULT(ic));
+    if (size >= AOP_SIZE(IC_LEFT(ic))) size = AOP_SIZE(IC_LEFT(ic));
+    
     while (size--) {
       if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
         pic16_emitpcode(POC_COMF,  pic16_popGet(AOP(IC_LEFT(ic)), offset));
@@ -164,6 +167,34 @@ void pic16_genCpl (iCode *ic)
       offset++;
     }
 
+    /* handle implicit upcast */
+    size = AOP_SIZE(IC_RESULT(ic));
+    if (offset < size)
+    {
+      if (SPEC_USIGN(operandType(IC_LEFT(ic)))) {
+       while (offset < size) {
+         pic16_emitpcode(POC_SETF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
+         offset++;
+       } // while
+      } else {
+       if ((offset + 1) == size) {
+         /* just one byte to fix */
+         pic16_emitpcode(POC_SETF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
+         pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RESULT(ic)),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
+         pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
+       } else {
+         /* two or more byte to adjust */
+         pic16_emitpcode(POC_SETF, pic16_popCopyReg( &pic16_pc_wreg ));
+         pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RESULT(ic)),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
+         pic16_emitpcode(POC_CLRF, pic16_popCopyReg( &pic16_pc_wreg ));
+         while (offset < size) {
+           pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
+           offset++;
+         } // while
+       } // if
+      }
+    } // if
+
 release:
     /* release the aops */
     pic16_freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1));
@@ -417,6 +448,25 @@ void pic16_DumpOp(char *prefix, operand *op)
 
 }
 
+void pic16_DumpOpX(FILE *fp, char *prefix, operand *op)
+{
+  if(!op)return;
+    
+  fprintf(fp, "%s [", prefix);
+  fprintf(fp, "%s", IS_SYMOP(op)?"S":" ");
+  fprintf(fp, "%s", IS_VALOP(op)?"V":" ");
+  fprintf(fp, "%s", IS_TYPOP(op)?"T":" ");
+  fprintf(fp, "] ");
+
+  fprintf(fp, "isaddr:%d,", op->isaddr);
+  fprintf(fp, "isvolatile:%d,", op->isvolatile);
+  fprintf(fp, "isGlobal:%d,", op->isGlobal);
+  fprintf(fp, "isPtr:%d,", op->isPtr);
+  fprintf(fp, "isParm:%d,", op->isParm);
+  fprintf(fp, "isLit:%d\n", op->isLiteral);
+}  
+    
+
 void _debugf(char *f, int l, char *frm, ...)
 {
   va_list ap;
@@ -463,3 +513,128 @@ void gpsimDebug_StackDump(char *fname, int line, char *info)
 
   gpsimio2_lit('\n');
 }
+
+const char *gptr_fns[4][2] = {
+  { "_gptrget1", "_gptrput1" },
+  { "_gptrget2", "_gptrput2" },
+  { "_gptrget3", "_gptrput3" },
+  { "_gptrget4", "_gptrput4" } };
+
+extern set *externs;
+  
+/* generate a call to the generic pointer read/write functions */
+void pic16_callGenericPointerRW(int rw, int size)
+{
+  char buf[32];
+  symbol *sym;
+
+    if(size>4) {
+      werror(W_POSSBUG2, __FILE__, __LINE__);
+      abort();
+    }
+
+    strcpy(buf, port->fun_prefix);
+    strcat(buf, gptr_fns[size-1][rw]);
+    
+    pic16_emitpcode (POC_CALL, pic16_popGetWithString (buf));
+    
+    sym = newSymbol( buf, 0 );
+    sym->used++;
+    strcpy(sym->rname, buf);
+    checkAddSym(&externs, sym);
+}
+
+
+
+/* check all condition and return appropriate instruction, POC_CPFSGT or POC_CPFFSLT */
+static int selectCompareOp(resolvedIfx *rIfx, iCode *ifx,
+        operand *result, int offset, int invert_op)
+{
+  /* add code here */
+  
+  /* check condition, > or < ?? */
+  if(rIfx->condition != 0)invert_op ^= 1;
+  
+  if(ifx && IC_FALSE(ifx))invert_op ^= 1;
+
+  if(!ifx)invert_op ^= 1;
+
+  DEBUGpic16_emitcode("; +++", "%s:%d %s] rIfx->condition= %d, ifx&&IC_FALSE(ifx)= %d, invert_op = %d",
+      __FILE__, __LINE__, __FUNCTION__, rIfx->condition, (ifx && IC_FALSE(ifx)), invert_op);
+  
+  /* do selection */
+  if(!invert_op)return POC_CPFSGT;
+  else return POC_CPFSLT;
+}
+
+/* return 1 if function handles compare, 0 otherwise */
+/* this functions handles special cases like:
+ * reg vs. zero
+ * reg vs. one
+ */
+int pic16_genCmp_special(operand *left, operand *right, operand *result,
+                    iCode *ifx, resolvedIfx *rIfx, int sign)
+{
+  int size;
+  int offs=0;
+  symbol *tmplbl;
+  unsigned long lit;
+  int op, cmp_op=0, cond_pre;
+
+    FENTRY;
+    
+    if(!(pic16_options.opt_flags & OF_OPTIMIZE_CMP))return 0;
+
+    size = max(AOP_SIZE(left), AOP_SIZE(right));
+
+    cond_pre = rIfx->condition; // must restore old value on return with 0!!!
+    
+    if(!isAOP_REGlike(left)) {
+      operand *dummy;
+
+        dummy = left;
+        left = right;
+        right = dummy;
+        
+        /* invert comparing operand */
+//        cmp_op ^= 1;
+        rIfx->condition ^= 1;
+    }
+    
+    
+    if(isAOP_REGlike(left) && isAOP_LIT(right)) {
+      /* comparing register vs. literal */
+      lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
+      
+      
+      if(size == 1) {
+        op = selectCompareOp(rIfx, ifx, result, offs, cmp_op);
+        
+        DEBUGpic16_emitcode("%%", "comparing operand %s, condition: %d", (op==POC_CPFSLT?"POC_CPFSLT":"POC_CPFSGT"), rIfx->condition);
+
+        if(!sign) {
+          /* unsigned compare */
+          switch( lit ) {
+            case 0:
+              if(ifx && IC_FALSE(ifx)) {
+                tmplbl = newiTempLabel( NULL );
+                pic16_emitpcode(POC_TSTFSZ, pic16_popGet(AOP(left), 0));
+                pic16_emitpcode(POC_BRA, pic16_popGetLabel(tmplbl->key));
+                pic16_emitpcode(POC_BRA, pic16_popGetLabel(rIfx->lbl->key));
+                pic16_emitpLabel(tmplbl->key);
+
+                ifx->generated = 1;
+                return 1;
+              }
+              break;
+          }    /* switch */
+
+        }      /* if(!sign) */
+
+      }                /* if(size==1) */
+
+    }          /* */
+      
+  rIfx->condition = cond_pre;
+  return 0;
+}