+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ emit2 ("scf");
+ }
+ while (sizel--)
+ {
+ if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ if (bytelit != 0x0FFL)
+ {
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ /* For the flags */
+ emit2 ("or a,a");
+ }
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+ offset++;
+ }
+ // bit = left & literal
+ if (size)
+ {
+ emit2 ("clr c");
+ emit2 ("!tlabeldef", tlbl->key + 100);
+ }
+ // if(left & literal)
+ else
+ {
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ goto release;
+ }
+ outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+ continue;
+ else
+ {
+ if (bytelit == 0)
+ aopPut (AOP (result), "!zero", offset);
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (left), "a", offset);
+ }
+ }
+
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
+ }
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (left), "a", offset);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Tried to AND where the result is in carry");
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ else if (bytelit == 0)
+ {
+ aopPut (AOP (result), "!zero", offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genOr - code for or */
+/*-----------------------------------------------------------------*/
+static void
+genOr (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
+ AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY &&
+ AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ wassertl (0, "Tried to OR where left is a bit");
+ goto release;
+ }
+
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ wassertl (0, "Result is assigned to a bit");
+ }
+ /* PENDING: Modeled after the AND code which is inefficent. */
+ while (sizel--)
+ {
+ bytelit = (lit >> (offset * 8)) & 0x0FFL;
+
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* OR with any literal is the same as OR with itself. */
+ emit2 ("or a,a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Result of OR is in a bit");
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+ else
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
+ aopGet (AOP (right), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ /* PENDING: something weird is going on here. Add exception. */
+ if (AOP_TYPE (result) == AOP_ACC)
+ break;
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genXor - code for xclusive or */
+/*-----------------------------------------------------------------*/
+static void
+genXor (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
+ AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY &&
+ AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ wassertl (0, "Tried to XOR a bit");
+ goto release;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) &&
+ (AOP_TYPE (result) == AOP_CRY) &&
+ (AOP_TYPE (left) != AOP_CRY))
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
+ }
+ while (sizel--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ {
+ wassertl (0, "Result of XOR was destined for a bit");
+ }
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (sameRegs (AOP (result), AOP (left)))
+ {
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ continue;
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ aopPut (AOP (result), "a", 0);
+ }
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Result of XOR is in a bit");
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+ {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset, FALSE),
+ offset);
+ continue;
+ }
+ }
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
+ aopGet (AOP (left), offset, FALSE));
+ }
+ aopPut (AOP (result), "a", offset);
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic);
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+static void
+genInline (iCode * ic)
+{
+ char *buffer, *bp, *bp1;
+
+ _G.lines.isInline += (!options.asmpeep);
+
+ buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
+ strcpy (buffer, IC_INLINE (ic));
+
+ /* emit each line as a code */
+ while (*bp)
+ {
+ if (*bp == '\n')
+ {
+ *bp++ = '\0';
+ emit2 (bp1);
+ bp1 = bp;
+ }
+ else
+ {
+ if (*bp == ':')
+ {
+ bp++;
+ *bp = '\0';
+ bp++;
+ emit2 (bp1);
+ bp1 = bp;
+ }
+ else
+ bp++;
+ }
+ }
+ if (bp1 != bp)
+ emit2 (bp1);
+ _G.lines.isInline -= (!options.asmpeep);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRRC (iCode * ic)
+{
+ wassert (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRLC - generate code for rotate left with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRLC (iCode * ic)
+{
+ wassert (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetHbit - generates code get highest order bit */
+/*-----------------------------------------------------------------*/
+static void
+genGetHbit (iCode * ic)
+{
+ operand *left, *result;
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* get the highest order byte into a */
+ emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ emit2 ("rl a");
+ outBitC (result);
+ }
+ else
+ {
+ emit2 ("rlc a");
+ emit2 ("and a,!one");
+ outAcc (result);
+ }
+
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+static void
+emitRsh2 (asmop *aop, int size, int is_signed)
+{
+ int offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (aop, size, FALSE);
+ if (offset == 0)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ }
+ else
+ {
+ emit2 ("rr %s", l);
+ }
+ offset++;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR2Left2Result - shift right two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR2Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int is_signed)
+{
+ int size = 2;
+ symbol *tlbl, *tlbl1;
+
+ movLeft2Result (left, offl, result, offr, 0);
+ movLeft2Result (left, offl + 1, result, offr + 1, 0);
+
+ /* if (AOP(result)->type == AOP_REG) { */
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ /* Left is already in result - so now do the shift */
+ if (shCount <= 4)
+ {
+ while (shCount--)
+ {
+ emitRsh2 (AOP (result), size, is_signed);
+ }
+ }
+ else
+ {
+ emit2 ("ld a,!immedbyte+1", shCount);
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+
+ emitRsh2 (AOP (result), size, is_signed);
+
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL2Left2Result - shift left two bytes from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL2Left2Result (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ if (sameRegs (AOP (result), AOP (left)) &&
+ ((offl + MSB16) == offr))
+ {
+ wassert (0);
+ }
+ else
+ {
+ /* Copy left into result */
+ movLeft2Result (left, offl, result, offr, 0);
+ movLeft2Result (left, offl + 1, result, offr + 1, 0);
+ }
+ /* PENDING: for now just see if it'll work. */
+ /*if (AOP(result)->type == AOP_REG) { */
+ {
+ int size = 2;
+ int offset = 0;
+ symbol *tlbl, *tlbl1;
+ const char *l;
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+
+ /* Left is already in result - so now do the shift */
+ if (shCount > 1)
+ {
+ emit2 ("ld a,!immedbyte+1", shCount);
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ }
+
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+
+ offset++;
+ }
+ if (shCount > 1)
+ {
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRol - rotate left accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRol (int shCount)
+{
+ shCount &= 0x0007; // shCount : 0..7
+
+ switch (shCount)
+ {
+ case 0:
+ break;
+ case 1:
+ emit2 ("sla a");
+ break;
+ case 2:
+ emit2 ("sla a");
+ emit2 ("rl a");
+ break;
+ case 3:
+ emit2 ("sla a");
+ emit2 ("rl a");
+ emit2 ("rl a");
+ break;
+ case 4:
+ emit2 ("sla a");
+ emit2 ("rl a");
+ emit2 ("rl a");
+ emit2 ("rl a");
+ break;
+ case 5:
+ emit2 ("srl a");
+ emit2 ("rr a");
+ emit2 ("rr a");
+ break;
+ case 6:
+ emit2 ("srl a");
+ emit2 ("rr a");
+ break;
+ case 7:
+ emit2 ("srl a");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccLsh - left shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccLsh (int shCount)
+{
+ static const unsigned char SLMask[] =
+ {
+ 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
+ };
+
+ if (shCount != 0)
+ {
+ if (shCount == 1)
+ {
+ emit2 ("add a,a");
+ }
+ else if (shCount == 2)
+ {
+ emit2 ("add a,a");
+ emit2 ("add a,a");
+ }
+ else
+ {
+ /* rotate left accumulator */
+ AccRol (shCount);
+ /* and kill the lower order bits */
+ emit2 ("and a,!immedbyte", SLMask[shCount]);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftL1Left2Result - shift left one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftL1Left2Result (operand * left, int offl,
+ operand * result, int offr, int shCount)
+{
+ const char *l;
+ l = aopGet (AOP (left), offl, FALSE);
+ _moveA (l);
+ /* shift left accumulator */
+ AccLsh (shCount);
+ aopPut (AOP (result), "a", offr);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genlshTwo - left shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genlshTwo (operand * result, operand * left, int shCount)
+{
+ int size = AOP_SIZE (result);
+
+ wassert (size == 2);
+
+ /* if shCount >= 8 */
+ if (shCount >= 8)
+ {
+ shCount -= 8;
+ if (size > 1)
+ {
+ if (shCount)
+ {
+ movLeft2Result (left, LSB, result, MSB16, 0);
+ aopPut (AOP (result), "!zero", 0);
+ shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+ }
+ else
+ {
+ movLeft2Result (left, LSB, result, MSB16, 0);
+ aopPut (AOP (result), "!zero", 0);
+ }
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", LSB);
+ }
+ }
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ if (size == 1)
+ {
+ wassert (0);
+ }
+ else
+ {
+ shiftL2Left2Result (left, LSB, result, LSB, shCount);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genlshOne - left shift a one byte quantity by known count */
+/*-----------------------------------------------------------------*/
+static void
+genlshOne (operand * result, operand * left, int shCount)
+{
+ shiftL1Left2Result (left, LSB, result, LSB, shCount);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShiftLiteral - left shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShiftLiteral (operand * left,
+ operand * right,
+ operand * result,
+ iCode * ic)
+{
+ int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ freeAsmop (right, NULL, ic);
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ size = getSize (operandType (result));
+
+ /* I suppose that the left size >= result size */
+ if (shCount == 0)
+ {
+ wassert (0);
+ }
+
+ else if (shCount >= (size * 8))
+ {
+ while (size--)
+ {
+ aopPut (AOP (result), "!zero", size);
+ }
+ }
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genlshOne (result, left, shCount);
+ break;
+ case 2:
+ genlshTwo (result, left, shCount);
+ break;
+ case 4:
+ wassertl (0, "Shifting of longs is currently unsupported");
+ break;
+ default:
+ wassert (0);
+ }
+ }
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLeftShift - generates code for left shifting */
+/*-----------------------------------------------------------------*/
+static void
+genLeftShift (iCode * ic)
+{
+ int size, offset;
+ const char *l;
+ symbol *tlbl, *tlbl1;
+ operand *left, *right, *result;
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genLeftShiftLiteral (left, right, result, ic);
+ return;
+ }
+
+ /* shift count is unknown then we have to form a loop get the loop
+ count in B : Note: we take only the lower order byte since
+ shifting more that 32 bits make no sense anyway, ( the largest
+ size of an object can be only 32 bits ) */
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
+ freeAsmop (right, NULL, ic);
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+
+ if (!sameRegs (AOP (left), AOP (result)))
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ l = aopGet (AOP (left), offset, FALSE);
+ aopPut (AOP (result), l, offset);
+ offset++;
+ }
+ }
+
+ tlbl = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = 0;
+ tlbl1 = newiTempLabel (NULL);
+
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ l = aopGet (AOP (result), offset, FALSE);
+
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+ offset++;
+ }
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshOne - left shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshOne (operand * result, operand * left, int shCount, int is_signed)
+{
+ /* Errk */
+ int size = AOP_SIZE (result);
+ const char *l;
+
+ wassert (size == 1);
+ wassert (shCount < 8);
+
+ l = aopGet (AOP (left), 0, FALSE);
+
+ if (AOP (result)->type == AOP_REG)
+ {
+ aopPut (AOP (result), l, 0);
+ l = aopGet (AOP (result), 0, FALSE);
+ while (shCount--)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ }
+ }
+ else
+ {
+ _moveA (l);
+ while (shCount--)
+ {
+ emit2 ("%s a", is_signed ? "sra" : "srl");
+ }
+ aopPut (AOP (result), "a", 0);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - right shift accumulator by known count */
+/*-----------------------------------------------------------------*/
+static void
+AccRsh (int shCount)
+{
+ static const unsigned char SRMask[] =
+ {
+ 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
+ };
+
+ if (shCount != 0)
+ {
+ /* rotate right accumulator */
+ AccRol (8 - shCount);
+ /* and kill the higher order bits */
+ emit2 ("and a,!immedbyte", SRMask[shCount]);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftR1Left2Result - shift right one byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+shiftR1Left2Result (operand * left, int offl,
+ operand * result, int offr,
+ int shCount, int sign)
+{
+ _moveA (aopGet (AOP (left), offl, FALSE));
+ if (sign)
+ {
+ while (shCount--)
+ {
+ emit2 ("%s a", sign ? "sra" : "srl");
+ }
+ }
+ else
+ {
+ AccRsh (shCount);
+ }
+ aopPut (AOP (result), "a", offr);
+}
+
+/*-----------------------------------------------------------------*/
+/* genrshTwo - right shift two bytes by known amount != 0 */
+/*-----------------------------------------------------------------*/
+static void
+genrshTwo (operand * result, operand * left,
+ int shCount, int sign)
+{
+ /* if shCount >= 8 */
+ if (shCount >= 8)
+ {
+ shCount -= 8;
+ if (shCount)
+ {
+ shiftR1Left2Result (left, MSB16, result, LSB,
+ shCount, sign);
+ }
+ else
+ {
+ movLeft2Result (left, MSB16, result, LSB, sign);
+ }
+ if (sign)
+ {
+ /* Sign extend the result */
+ _moveA(aopGet (AOP (result), 0, FALSE));
+ emit2 ("rlc a");
+ emit2 ("sbc a,a");
+
+ aopPut (AOP (result), ACC_NAME, MSB16);
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", 1);
+ }
+ }
+ /* 1 <= shCount <= 7 */
+ else
+ {
+ shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShiftLiteral - left shifting by known count */
+/*-----------------------------------------------------------------*/
+static void
+genRightShiftLiteral (operand * left,
+ operand * right,
+ operand * result,
+ iCode * ic,
+ int sign)
+{
+ int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+ int size;
+
+ freeAsmop (right, NULL, ic);
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ size = getSize (operandType (result));
+
+ /* I suppose that the left size >= result size */
+ if (shCount == 0)
+ {
+ wassert (0);
+ }
+
+ else if (shCount >= (size * 8))
+ while (size--)
+ aopPut (AOP (result), "!zero", size);
+ else
+ {
+ switch (size)
+ {
+ case 1:
+ genrshOne (result, left, shCount, sign);
+ break;
+ case 2:
+ genrshTwo (result, left, shCount, sign);
+ break;
+ case 4:
+ wassertl (0, "Asked to shift right a long which should be a function call");
+ break;
+ default:
+ wassertl (0, "Entered default case in right shift delegate");
+ }
+ }
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShift - generate code for right shifting */
+/*-----------------------------------------------------------------*/
+static void
+genRightShift (iCode * ic)
+{
+ operand *right, *left, *result;
+ sym_link *retype;
+ int size, offset, first = 1;
+ const char *l;
+ bool is_signed;
+
+ symbol *tlbl, *tlbl1;
+
+ /* if signed then we do it the hard way preserve the
+ sign bit moving it inwards */
+ retype = getSpec (operandType (IC_RESULT (ic)));
+
+ is_signed = !SPEC_USIGN (retype);
+
+ /* signed & unsigned types are treated the same : i.e. the
+ signed is NOT propagated inwards : quoting from the
+ ANSI - standard : "for E1 >> E2, is equivalent to division
+ by 2**E2 if unsigned or if it has a non-negative value,
+ otherwise the result is implementation defined ", MY definition
+ is that the sign does not get propagated */
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ genRightShiftLiteral (left, right, result, ic, is_signed);
+ return;
+ }
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!sameRegs (AOP (left), AOP (result)) &&
+ AOP_SIZE (result) > 1)
+ {
+
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ l = aopGet (AOP (left), offset, FALSE);
+ aopPut (AOP (result), l, offset);
+ offset++;
+ }
+ }
+
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
+ freeAsmop (right, NULL, ic);
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+ size = AOP_SIZE (result);
+ offset = size - 1;
+
+ emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+ emitLabel (tlbl->key + 100);
+ while (size--)
+ {
+ l = aopGet (AOP (result), offset--, FALSE);
+ if (first)
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ first = 0;
+ }
+ else
+ {
+ emit2 ("rr %s", l);
+ }
+ }
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ freeAsmop (left, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerGet - get value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerGet (operand * left,
+ operand * result, iCode * ic)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (result));
+ int pair = PAIR_HL;
+
+ if (IS_GB)
+ pair = PAIR_DE;
+
+ aopOp (left, ic, FALSE, FALSE);
+ aopOp (result, ic, FALSE, FALSE);
+
+ size = AOP_SIZE (result);
+
+ if (isPair (AOP (left)) && size == 1)
+ {
+ /* Just do it */
+ if (isPtrPair (AOP (left)))
+ {
+ tsprintf (buffer, "!*pair", getPairName (AOP (left)));
+ aopPut (AOP (result), buffer, 0);
+ }
+ else
+ {
+ emit2 ("ld a,!*pair", getPairName (AOP (left)));
+ aopPut (AOP (result), "a", 0);
+ }
+ freeAsmop (left, NULL, ic);
+ goto release;
+ }
+
+ if ( getPairId( AOP (left)) == PAIR_IY)
+ {
+ /* Just do it */
+ offset = 0;
+ while (size--)
+ {
+ char at[20];
+ tsprintf (at, "!*iyx", offset);
+ aopPut (AOP (result), at, offset);
+ offset++;
+ }
+
+ freeAsmop (left, NULL, ic);
+ goto release;
+ }
+
+ /* For now we always load into IY */
+ /* if this is remateriazable */
+ fetchPair (pair, AOP (left));
+
+ freeAsmop (left, NULL, ic);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ {
+ wassert (0);
+ }
+ else if ( getPairId( AOP (result)) == PAIR_HL)
+ {
+ wassertl (size == 2, "HL must be of size 2");
+ emit2 ("ld a,!*hl");
+ emit2 ("inc hl");
+ emit2 ("ld h,!*hl");
+ emit2 ("ld l,a");
+ }
+ else
+ {
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ while (size--)
+ {
+ /* PENDING: make this better */
+ if (!IS_GB && AOP (result)->type == AOP_REG)
+ {
+ aopPut (AOP (result), "!*hl", offset++);
+ }
+ else
+ {
+ emit2 ("ld a,!*pair", _pairs[pair].name);
+ aopPut (AOP (result), "a", offset++);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[pair].name);
+ _G.pairs[pair].offset++;
+ }
+ }
+ }
+
+release:
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void
+genPointerGet (iCode * ic)
+{
+ operand *left, *result;
+ sym_link *type, *etype;
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (left);
+ etype = getSpec (type);
+
+ genGenPointerGet (left, result, ic);
+}
+
+bool
+isRegOrLit (asmop * aop)
+{
+ if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
+ return TRUE;
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerSet (operand * right,
+ operand * result, iCode * ic)
+{
+ int size, offset;
+ sym_link *retype = getSpec (operandType (right));
+ PAIR_ID pairId = PAIR_HL;
+
+ aopOp (result, ic, FALSE, FALSE);
+ aopOp (right, ic, FALSE, FALSE);
+
+ if (IS_GB)
+ pairId = PAIR_DE;
+
+ size = AOP_SIZE (right);
+
+ /* Handle the exceptions first */
+ if (isPair (AOP (result)) && size == 1)
+ {
+ /* Just do it */
+ const char *l = aopGet (AOP (right), 0, FALSE);
+ const char *pair = getPairName (AOP (result));
+ if (canAssignToPtr (l) && isPtr (pair))
+ {
+ emit2 ("ld !*pair,%s", pair, l);
+ }
+ else
+ {
+ _moveA (l);
+ emit2 ("ld !*pair,a", pair);
+ }
+ goto release;
+ }
+
+ if ( getPairId( AOP (result)) == PAIR_IY)
+ {
+ /* Just do it */
+ const char *l = aopGet (AOP (right), 0, FALSE);
+
+ offset = 0;
+ while (size--)
+ {
+ if (canAssignToPtr (l))
+ {
+ emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("ld !*iyx,a", offset);
+ }
+ offset++;
+ }
+ goto release;
+ }
+
+ /* if the operand is already in dptr
+ then we do nothing else we move the value to dptr */
+ if (AOP_TYPE (result) != AOP_STR)
+ {
+ fetchPair (pairId, AOP (result));
+ }
+ /* so hl know contains the address */
+ freeAsmop (result, NULL, ic);
+
+ /* if bit then unpack */
+ if (IS_BITVAR (retype))
+ {
+ wassert (0);
+ }
+ else
+ {
+ offset = 0;
+
+ while (size--)
+ {
+ const char *l = aopGet (AOP (right), offset, FALSE);
+ if (isRegOrLit (AOP (right)) && !IS_GB)
+ {
+ emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
+ }
+ else
+ {
+ _moveA (l);
+ emit2 ("ld !*pair,a", _pairs[pairId].name);
+ }
+ if (size)
+ {
+ emit2 ("inc %s", _pairs[pairId].name);
+ _G.pairs[pairId].offset++;
+ }
+ offset++;
+ }
+ }
+release:
+ freeAsmop (right, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genPointerSet (iCode * ic)
+{
+ operand *right, *result;
+ sym_link *type, *etype;
+
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (result);
+ etype = getSpec (type);
+
+ genGenPointerSet (right, result, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfx - generate code for Ifx statement */
+/*-----------------------------------------------------------------*/
+static void
+genIfx (iCode * ic, iCode * popIc)
+{
+ operand *cond = IC_COND (ic);
+ int isbit = 0;
+
+ aopOp (cond, ic, FALSE, TRUE);
+
+ /* get the value into acc */
+ if (AOP_TYPE (cond) != AOP_CRY)
+ _toBoolean (cond);
+ else
+ isbit = 1;
+ /* the result is now in the accumulator */
+ freeAsmop (cond, NULL, ic);
+
+ /* if there was something to be popped then do it */
+ if (popIc)
+ genIpop (popIc);
+
+ /* if the condition is a bit variable */
+ if (isbit && IS_ITEMP (cond) &&
+ SPIL_LOC (cond))
+ genIfxJump (ic, SPIL_LOC (cond)->rname);
+ else if (isbit && !IS_ITEMP (cond))
+ genIfxJump (ic, OP_SYMBOL (cond)->rname);
+ else
+ genIfxJump (ic, "a");
+
+ ic->generated = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAddrOf - generates code for address of */
+/*-----------------------------------------------------------------*/
+static void
+genAddrOf (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+
+ aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+
+ /* if the operand is on the stack then we
+ need to get the stack offset of this
+ variable */
+ if (IS_GB)
+ {
+ if (sym->onStack)
+ {
+ spillCached ();
+ if (sym->stack <= 0)
+ {
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
+ }
+ else
+ {
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+ }
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ }
+ else
+ {
+ emit2 ("ld de,!hashedstr", sym->rname);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
+ }
+ }
+ else
+ {
+ spillCached ();
+ if (sym->onStack)
+ {
+ /* if it has an offset then we need to compute it */
+ if (sym->stack > 0)
+ emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
+ else
+ emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+ emit2 ("add hl,sp");
+ }
+ else
+ {
+ emit2 ("ld hl,#%s", sym->rname);
+ }
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ }
+ freeAsmop (IC_RESULT (ic), NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genAssign - generate code for assignment */
+/*-----------------------------------------------------------------*/
+static void
+genAssign (iCode * ic)
+{
+ operand *result, *right;
+ int size, offset;
+ unsigned long lit = 0L;
+
+ result = IC_RESULT (ic);
+ right = IC_RIGHT (ic);
+
+ /* Dont bother assigning if they are the same */
+ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
+ {
+ emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
+ return;
+ }
+
+ aopOp (right, ic, FALSE, FALSE);
+ aopOp (result, ic, TRUE, FALSE);
+
+ /* if they are the same registers */
+ if (sameRegs (AOP (right), AOP (result)))
+ {
+ emitDebug ("; (registers are the same)");
+ goto release;
+ }
+
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ wassertl (0, "Tried to assign to a bit");
+ }
+
+ /* general case */
+ size = AOP_SIZE (result);
+ offset = 0;
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ }
+
+ if (isPair (AOP (result)))
+ {
+ fetchPair (getPairId (AOP (result)), AOP (right));
+ }
+ else if ((size > 1) &&
+ (AOP_TYPE (result) != AOP_REG) &&
+ (AOP_TYPE (right) == AOP_LIT) &&
+ !IS_FLOAT (operandType (right)) &&
+ (lit < 256L))
+ {
+ bool fXored = FALSE;
+ offset = 0;
+ /* Work from the top down.
+ Done this way so that we can use the cached copy of 0
+ in A for a fast clear */
+ while (size--)
+ {
+ if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
+ {
+ if (!fXored && size > 1)
+ {
+ emit2 ("xor a,a");
+ fXored = TRUE;
+ }
+ if (fXored)
+ {
+ aopPut (AOP (result), "a", offset);
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", offset);
+ }
+ }
+ else
+ aopPut (AOP (result),
+ aopGet (AOP (right), offset, FALSE),
+ offset);
+ offset++;
+ }
+ }
+ else if (size == 2 && AOP_TYPE (right) == AOP_IY)
+ {
+ emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
+ aopPut (AOP (result), "l", LSB);
+ aopPut (AOP (result), "h", MSB16);
+ }
+ else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+ {
+ /* Special case. Load into a and d, then load out. */
+ _moveA (aopGet (AOP (right), 0, FALSE));
+ emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
+ aopPut (AOP (result), "a", 0);
+ aopPut (AOP (result), "e", 1);
+ }
+ else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+ {
+ /* Special case - simple memcpy */
+ aopGet (AOP (right), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP (result), LSB, FALSE);
+
+ while (size--)
+ {
+ emit2 ("ld a,(de)");
+ /* Peephole will optimise this. */
+ emit2 ("ld (hl),a");
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ }
+ spillPair (PAIR_HL);
+ }
+ else
+ {
+ while (size--)
+ {
+ /* PENDING: do this check better */
+ if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ aopPut (AOP (result), "a", offset);
+ }
+ else
+ aopPut (AOP (result),
+ aopGet (AOP (right), offset, FALSE),
+ offset);
+ offset++;
+ }
+ }
+
+release:
+ freeAsmop (right, NULL, ic);
+ freeAsmop (result, NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/