+ sregs->psr = add_cc(sregs->psr, operand1, operand2, *rdd);
+ break;
+ case DIVScc:
+ {
+ int sign;
+ uint32 result, remainder;
+ int c0, y31;
+
+ if (!sparclite) {
+ sregs->trap = TRAP_UNIMP;
+ break;
+ }
+
+ sign = ((sregs->psr & PSR_V) != 0) ^ ((sregs->psr & PSR_N) != 0);
+
+ remainder = (sregs->y << 1) | (rs1 >> 31);
+
+ /* If true sign is positive, calculate remainder - divisor.
+ Otherwise, calculate remainder + divisor. */
+ if (sign == 0)
+ operand2 = ~operand2 + 1;
+ result = remainder + operand2;
+
+ /* The SPARClite User's Manual is not clear on how
+ the "carry out" of the above ALU operation is to
+ be calculated. From trial and error tests
+ on the the chip itself, it appears that it is
+ a normal addition carry, and not a subtraction borrow,
+ even in cases where the divisor is subtracted
+ from the remainder. FIXME: get the true story
+ from Fujitsu. */
+ c0 = result < (uint32) remainder
+ || result < (uint32) operand2;
+
+ if (result & 0x80000000)
+ sregs->psr |= PSR_N;
+ else
+ sregs->psr &= ~PSR_N;
+
+ y31 = (sregs->y & 0x80000000) == 0x80000000;
+
+ if (result == 0 && sign == y31)
+ sregs->psr |= PSR_Z;
+ else
+ sregs->psr &= ~PSR_Z;
+
+ sign = (sign && !y31) || (!c0 && (sign || !y31));
+
+ if (sign ^ (result >> 31))
+ sregs->psr |= PSR_V;
+ else
+ sregs->psr &= ~PSR_V;
+
+ if (!sign)
+ sregs->psr |= PSR_C;
+ else
+ sregs->psr &= ~PSR_C;
+
+ sregs->y = result;
+
+ if (rd != 0)
+ *rdd = (rs1 << 1) | !sign;
+ }
+ break;
+ case SMUL:
+ {
+ mul64 (rs1, operand2, &sregs->y, rdd, 1);
+ }
+ break;
+ case SMULCC:
+ {
+ uint32 result;
+
+ mul64 (rs1, operand2, &sregs->y, &result, 1);
+
+ if (result & 0x80000000)
+ sregs->psr |= PSR_N;
+ else
+ sregs->psr &= ~PSR_N;
+
+ if (result == 0)
+ sregs->psr |= PSR_Z;
+ else
+ sregs->psr &= ~PSR_Z;
+
+ *rdd = result;
+ }
+ break;
+ case UMUL:
+ {
+ mul64 (rs1, operand2, &sregs->y, rdd, 0);
+ }
+ break;
+ case UMULCC:
+ {
+ uint32 result;
+
+ mul64 (rs1, operand2, &sregs->y, &result, 0);
+
+ if (result & 0x80000000)
+ sregs->psr |= PSR_N;
+ else
+ sregs->psr &= ~PSR_N;
+
+ if (result == 0)
+ sregs->psr |= PSR_Z;
+ else
+ sregs->psr &= ~PSR_Z;
+
+ *rdd = result;
+ }
+ break;
+ case SDIV:
+ {
+ if (sparclite) {
+ sregs->trap = TRAP_UNIMP;
+ break;
+ }
+
+ if (operand2 == 0) {
+ sregs->trap = TRAP_DIV0;
+ break;
+ }
+
+ div64 (sregs->y, rs1, operand2, rdd, 1);
+ }
+ break;
+ case SDIVCC:
+ {
+ uint32 result;
+
+ if (sparclite) {
+ sregs->trap = TRAP_UNIMP;
+ break;
+ }
+
+ if (operand2 == 0) {
+ sregs->trap = TRAP_DIV0;
+ break;
+ }
+
+ div64 (sregs->y, rs1, operand2, &result, 1);
+
+ if (result & 0x80000000)
+ sregs->psr |= PSR_N;
+ else
+ sregs->psr &= ~PSR_N;
+
+ if (result == 0)
+ sregs->psr |= PSR_Z;
+ else
+ sregs->psr &= ~PSR_Z;
+
+ /* FIXME: should set overflow flag correctly. */
+ sregs->psr &= ~(PSR_C | PSR_V);
+
+ *rdd = result;
+ }
+ break;
+ case UDIV:
+ {
+ if (sparclite) {
+ sregs->trap = TRAP_UNIMP;
+ break;
+ }
+
+ if (operand2 == 0) {
+ sregs->trap = TRAP_DIV0;
+ break;
+ }
+
+ div64 (sregs->y, rs1, operand2, rdd, 0);
+ }
+ break;
+ case UDIVCC:
+ {
+ uint32 result;
+
+ if (sparclite) {
+ sregs->trap = TRAP_UNIMP;
+ break;
+ }
+
+ if (operand2 == 0) {
+ sregs->trap = TRAP_DIV0;
+ break;
+ }
+
+ div64 (sregs->y, rs1, operand2, &result, 0);
+
+ if (result & 0x80000000)
+ sregs->psr |= PSR_N;
+ else
+ sregs->psr &= ~PSR_N;
+
+ if (result == 0)
+ sregs->psr |= PSR_Z;
+ else
+ sregs->psr &= ~PSR_Z;
+
+ /* FIXME: should set overflow flag correctly. */
+ sregs->psr &= ~(PSR_C | PSR_V);
+
+ *rdd = result;
+ }