+ if (ic->op == '/')
+ op = 0;
+ else if (ic->op == '%')
+ op = 1;
+ else
+ assert( !"invalid operation requested in genDivMod" );
+
+ /* get literal values */
+ if (IS_VALOP(left)) {
+ leftVal = (int)floatFromVal( OP_VALUE(left) );
+ assert( leftVal >= -128 && leftVal < 256 );
+ if (leftVal < 0) { signedLits++; }
+ }
+ if (IS_VALOP(right)) {
+ rightVal = (int)floatFromVal( OP_VALUE(right) );
+ assert( rightVal >= -128 && rightVal < 256 );
+ if (rightVal < 0) { signedLits++; }
+ }
+
+ /* We should only come here to convert all
+ * / : {u8_t, s8_t} x {u8_t, s8_t} -> {u8_t, s8_t}
+ * with exactly one operand being s8_t into
+ * u8_t x u8_t -> u8_t. All other cases should have been
+ * turned into calls to support routines beforehand... */
+ if ((AOP_SIZE(left) == 1 || IS_VALOP(left))
+ && (AOP_SIZE(right) == 1 || IS_VALOP(right)))
+ {
+ if ((!IS_UNSIGNED(operandType(right)) || rightVal < 0)
+ && (!IS_UNSIGNED(operandType(left)) || leftVal < 0))
+ {
+ /* Both operands are signed or negative, use _divschar
+ * instead of _divuchar */
+ pushaop(AOP(right), 0);
+ pushaop(AOP(left), 0);
+
+ /* call _divschar */
+ pic16_emitpcode(POC_CALL, pic16_popGetWithString(functions[op][0]));
+
+ {
+ symbol *sym;
+ sym = newSymbol( functions[op][0], 0 );
+ sym->used++;
+ strcpy(sym->rname, functions[op][0]);
+ checkAddSym(&externs, sym);
+ }
+
+ /* assign result */
+ pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), 0));
+ if (AOP_SIZE(result) > 1)
+ {
+ pic16_emitpcode(POC_MOVFF,
+ pic16_popGet2p(pic16_popCopyReg(&pic16_pc_prodl),
+ pic16_popGet(AOP(result), 1)));
+ /* 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;
+ }
+
+ /* 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