+ goto release;
+ }
+
+ /* push right operand */
+ if (IS_VALOP(right)) {
+ if (rightVal < 0) {
+ pic16_pushpCodeOp( pic16_popGetLit(-rightVal) );
+ negated++;
+ } else {
+ pushaop(AOP(right), 0);
+ }
+ } else if (!IS_UNSIGNED(operandType(right))) {
+ pic16_mov2w(AOP(right), 0);
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(right), 0, 7));
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(pic16_stack_postdec));
+ negated++;
+ } else {
+ pushaop(AOP(right), 0);
+ }
+
+ /* push left operand */
+ if (IS_VALOP(left)) {
+ if (leftVal < 0) {
+ pic16_pushpCodeOp(pic16_popGetLit(-leftVal));
+ negated++;
+ } else {
+ pushaop(AOP(left), 0);
+ }
+ } else if (!IS_UNSIGNED(operandType(left))) {
+ pic16_mov2w(AOP(left),0);
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(left), 0, 7));
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(pic16_stack_postdec));
+ negated++;
+ } else {
+ pushaop(AOP(left), 0);
+ }
+
+ /* call _divuchar */
+ pic16_emitpcode(POC_CALL, pic16_popGetWithString(functions[op][1]));
+
+ {
+ symbol *sym;
+ sym = newSymbol( functions[op][1], 0 );
+ sym->used++;
+ strcpy(sym->rname, functions[op][1]);
+ checkAddSym(&externs, sym);
+ }
+
+ /* Revert negation(s) from above.
+ * This is inefficient: if both operands are negative, this
+ * should not touch WREG. However, determining that exactly
+ * one operand was negated costs at least 3 instructions,
+ * so there is nothing to be gained here, is there?
+ *
+ * I negate WREG because either operand might share registers with
+ * result, so assigning first might destroy an operand. */
+
+ /* For the modulus operator, (a/b)*b == a shall hold.
+ * Thus: a>0, b>0 --> a/b >= 0 and a%b >= 0
+ * a>0, b<0 --> a/b <= 0 and a%b >= 0 (e.g. 128 / -5 = -25, -25*(-5) = 125 and +3 remaining)
+ * a<0, b>0 --> a/b <= 0 and a%b < 0 (e.g. -128 / 5 = -25, -25* 5 = -125 and -3 remaining)
+ * a<0, b<0 --> a/b >= 0 and a%b < 0 (e.g. -128 / -5 = 25, 25*(-5) = -125 and -3 remaining)
+ * Only invert the result if the left operand is negative (sigh).
+ */
+ if (AOP_SIZE(result) <= 1 || !negated)
+ {
+ if (ic->op == '/')
+ {
+ if (IS_VALOP(right)) {
+ if (rightVal < 0) {
+ /* we negated this operand above */
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ }
+ } else if (!IS_UNSIGNED(operandType(right))) {
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(right), 0, 7));
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ }
+ }
+
+ if (IS_VALOP(left)) {
+ if (leftVal < 0) {
+ /* we negated this operand above */
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ }
+ } else if (!IS_UNSIGNED(operandType(left))) {
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(left), 0, 7));
+ pic16_emitpcode(POC_NEGF, pic16_popCopyReg(&pic16_pc_wreg));
+ }
+
+ /* Move result to destination. */
+ pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), 0));
+
+ /* Zero-extend: no operand was signed (or result is just a byte). */
+ pic16_addSign(result, 1, 0);
+ } else {
+ assert( AOP_SIZE(result) > 1 );
+ pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result), 1));
+ if (ic->op == '/')
+ {
+ if (IS_VALOP(right)) {
+ if (rightVal < 0) {
+ /* we negated this operand above */
+ pic16_emitpcode(POC_COMF, pic16_popGet(AOP(result), 1));
+ }
+ } else if (!IS_UNSIGNED(operandType(right))) {
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(right), 0, 7));
+ pic16_emitpcode(POC_COMF, pic16_popGet(AOP(result), 1));
+ }
+ }
+
+ if (IS_VALOP(left)) {
+ if (leftVal < 0) {
+ /* we negated this operand above */
+ pic16_emitpcode(POC_COMF, pic16_popGet(AOP(result), 1));
+ }
+ } else if (!IS_UNSIGNED(operandType(left))) {
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(left), 0, 7));
+ pic16_emitpcode(POC_COMF, pic16_popGet(AOP(result), 1));
+ }
+
+ /* Move result to destination. */
+ pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), 0));
+
+ /* Negate result if required. */
+ pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(result), 1, 7));
+ pic16_emitpcode(POC_NEGF, pic16_popGet(AOP(result), 0));
+
+ /* Sign-extend. */
+ pic16_addSign(result, 2, 1);
+ }
+
+ /* clean up stack */
+ pic16_emitpcode(POC_MOVFW, pic16_popCopyReg(pic16_stack_preinc));
+ pic16_emitpcode(POC_MOVFW, pic16_popCopyReg(pic16_stack_preinc));
+ goto release;
+ }
+
+#if 0
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE(left) == AOP_CRY &&
+ AOP_TYPE(right)== AOP_CRY) {
+ genDivbits(left,right,result);
+ goto release ;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE(left) == 1 &&
+ AOP_SIZE(right) == 1 ) {
+ genDivOneByte(left,right,result);
+ goto release ;
+ }
+#endif
+
+ /* should have been converted to function call */
+ assert(0);
+release :
+ pic16_freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ pic16_freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ pic16_freeAsmop(result,NULL,ic,TRUE);
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* genModbits :- modulus of bits */
+/*-----------------------------------------------------------------*/
+static void genModbits (operand *left,
+ operand *right,
+ operand *result)
+{
+ char *l;
+
+ FENTRY;
+
+ werror(W_POSSBUG2, __FILE__, __LINE__);
+ /* the result must be bit */
+ pic16_emitcode("mov","b,%s",pic16_aopGet(AOP(right),0,FALSE,FALSE));
+ l = pic16_aopGet(AOP(left),0,FALSE,FALSE);
+
+ MOVA(l);