// (c)1998, Carl Burch. This may not be redistributed
public class Register {
	public static final int BITS = 32;
	public static final int BYTES = 4;

	public static final int SIGNED_MAX = 0x7FFFFFFF;
	public static final int UNSIGNED_MAX = 0x80000000;

	// the bits are stored in this array, with the lowest-order
	// bit at data[0]
	protected byte[] bit;
	boolean altered = false;

	public Register() {
		bit = new byte[BITS];
		for(int i = 0; i < BITS; i++) bit[i] = 0;
	}

	public Register(int val) {
		bit = new byte[BITS];
		setToSignedInt(val);
	}

	public boolean isChanged() { return altered; }
	public void setChanged(boolean what) { altered = what; }

	public int getSignedInt() {
		int ret = 0;

		for(int i = BITS - 2; i >= 0; i--) {
			ret = (ret << 1) + bit[i];
		}
		if(bit[BITS - 1] == 1) {
			// it is important to parenthesize this expression so;
			// otherwise we could get overflow.
			return (ret - SIGNED_MAX) - 1;
		} else {
			return ret;
		}
	}
	public byte[] getBits() {
		byte[] ret = new byte[BITS];
		for(int i = 0; i < BITS; i++) ret[i] = bit[i];
		return ret;
	}

	public boolean isZero() {
		for(int i = 0; i < BITS; i++) if(bit[i] != 0) return false;
		return true;
	}

	public void setToSignedInt(int set) {
		int mask = 0x1;
		for(int i = 0; i < BITS; i++) {
			bit[i] = (byte) ((set & mask) != 0 ? 1 : 0);
			mask <<= 1;
		}
		altered = true;
	}
	public void setToBits(byte[] set) {
		for(int i = 0; i < BITS; i++) bit[i] = set[i];
		altered = true;
	}

	public void signExtend(int num) {
		for(int i = num; i < BITS; i++) bit[i] = bit[num - 1];
	}

	public void setToSum(Register ri, Register rj) {
		byte carry = 0;
		for(int i = 0; i < BITS; i++) {
			bit[i] = (byte) (ri.bit[i] + rj.bit[i] + carry);
			if(bit[i] >= 2) {
				bit[i] -= 2;
				carry = 1;
			} else {
				carry = 0;
			}
		}
		altered = true;
	}
	public void setToDifference(Register ri, Register rj) {
		byte carry = 1;
		for(int i = 0; i < BITS; i++) {
			bit[i] = (byte) (carry + ri.bit[i] + 1 - rj.bit[i]);
			if(bit[i] >= 2) {
				bit[i] -= 2;
				carry = 1;
			} else {
				carry = 0;
			}
		}
		altered = true;
	}

	public void setToProduct(Register ri, Register rj) {
		byte[] x = ri.getBits();
		byte[] y = rj.getBits();
		boolean negate = false; // whether answer should be negated

		// zero out answer
		for(int i = 0; i < BITS; i++) bit[i] = 0;

		// find the absolute value of x and y
		if(x[BITS - 1] == 1) {
			negate = !negate;

			int x_pos = 0;
			while(x[x_pos] == 0) x_pos++;
			for(x_pos++; x_pos < BITS; x_pos++) x[x_pos] = (byte) (1 - x[x_pos]);
		}
		if(y[BITS - 1] == 1) {
			negate = !negate;

			int y_pos = 0;
			while(y[y_pos] == 0) y_pos++;
			for(y_pos++; y_pos < BITS; y_pos++) y[y_pos] = (byte) (1 - y[y_pos]);
		}

		// find the product
		for(int y_pos = 0; y_pos < BITS; y_pos++) {
			if(y[y_pos] == 1) {
				byte carry = 0;
				for(int i = y_pos; i < BITS; i++) {
					bit[i] = (byte) (bit[i] + x[i - y_pos] + carry);
					if(bit[i] >= 2) {
						bit[i] -= 2;
						carry = 1;
					} else {
						carry = 0;
					}
				}
				// overflow if carry > 0 || any bits in x set beyond
			}
		}

		// negate result if appropriate
		if(negate) {
			int i = 0;
			while(bit[i] == 0) i++;
			for(i++; i < BITS; i++) bit[i] = (byte) (1 - bit[i]);
		}

		altered = true;
	}

	public void setToQuotient(Register ri, Register rj) {
		this.setToSignedInt(ri.getSignedInt() / rj.getSignedInt());
	}

	public void setToModulo(Register ri, Register rj) {
		this.setToSignedInt(ri.getSignedInt() % rj.getSignedInt());
	}

	public void setToNot(Register ri) {
		for(int i = 0; i < BITS; i++) bit[i] = (byte) (1 - ri.bit[i]);
		altered = true;
	}
	public void setToAnd(Register ri, Register rj) {
		for(int i = 0; i < BITS; i++) bit[i] = (byte) (ri.bit[i] & rj.bit[i]);
		altered = true;
	}
	public void setToOr(Register ri, Register rj) {
		for(int i = 0; i < BITS; i++) bit[i] = (byte) (ri.bit[i] | rj.bit[i]);
		altered = true;
	}
	public void setToXor(Register ri, Register rj) {
		for(int i = 0; i < BITS; i++) bit[i] = (byte) (ri.bit[i] ^ rj.bit[i]);
		altered = true;
	}

	public void setToShiftLeft(Register ri, int distance) {
		if(distance < 0 || distance > BITS) {
			System.err.println("Register.setToShiftRightArithmetic: "
				+ Integer.toString(distance) + " too far");
		}
		if(distance == 0) return;
		for(int i = BITS - 1; i >= distance; i--) {
			bit[i] = ri.bit[i - distance];
		}
		for(int i = distance - 1; i >= 0; i--) {
			bit[i] = 0;
		}
		altered = true;
	}
	public void setToShiftRightLogical(Register ri, int distance) {
		if(distance < 0 || distance > BITS) {
			System.err.println("Register.setToShiftRightArithmetic: "
				+ Integer.toString(distance) + " too far");
		}
		if(distance == 0) return;
		for(int i = 0; i < BITS - distance; i++) {
			bit[i] = ri.bit[i + distance];
		}
		for(int i = BITS - distance; i < BITS; i++) {
			bit[i] = 0;
		}
		altered = true;
	}
	public void setToShiftRightArithmetic(Register ri, int distance) {
		if(distance < 0 || distance > BITS) {
			System.err.println("Register.setToShiftRightArithmetic: "
				+ Integer.toString(distance) + " too far");
		}
		if(distance == 0) return;
		for(int i = 0; i < BITS - distance; i++) {
			bit[i] = ri.bit[i + distance];
		}
		for(int i = BITS - distance; i < BITS; i++) {
			bit[i] = ri.bit[BITS - 1 - distance];
		}
		altered = true;
	}

	public int compare(Register ri) {
		return this.getSignedInt() - ri.getSignedInt();
	}
}
