def get_bit(num: int, i: int) -> bint:
    return num >> i & 1

def get_bits(num: int, start: int, end: int) -> int:
    num_bits = end - start + 1
    mask = (1 << num_bits) - 1
    return num >> start & mask

def set_bit(num: int, i: int, bit: bint) -> int:
    return num & ~(1 << i) | bit << i

def sign_32(num: int) -> bint:
    return get_bit(num, 31)

def sign_24(num: int) -> bint:
    return get_bit(num, 23)

def sign_23(num: int) -> bint:
    return get_bit(num, 22)

def sign_16(num: int) -> bint:
    return get_bit(num, 15)

def sign_12(num: int) -> bint:
    return get_bit(num, 11)

def sign_9(num: int) -> bint:
    return get_bit(num, 8)

def sign_8(num: int) -> bint:
    return get_bit(num, 7)

def extend_sign_32(num: int) -> int:
    extension = 18446744069414584320
    return num | extension if sign_32(num) else num

def extend_sign_24(num: int) -> int:
    extension = 4278190080
    return num | extension if sign_24(num) else num

def extend_sign_23(num: int) -> int:
    extension = 4286578688
    return num | extension if sign_23(num) else num

def extend_sign_16(num: int) -> int:
    extension = 4294901760
    return num | extension if sign_16(num) else num

def extend_sign_12(num: int) -> int:
    extension = 4294963200
    return num | extension if sign_12(num) else num

def extend_sign_9(num: int) -> int:
    extension = 4294966784
    return num | extension if sign_9(num) else num

def extend_sign_8(num: int) -> int:
    extension = 4294967040
    return num | extension if sign_8(num) else num

def add_32(op1: int, op2: int) -> int:
    mask = 4294967295
    return op1 + op2 & mask

def ror_32(num: int, amount: int) -> int:
    """
    Rotate right (ROR)

    :param num: 32-bit unsigned integer to rotate
    :param amount: number of bits to rotate to the right (must be <= 32)
    :return: num rotated right by amount bits
    """
    mask = 4294967295
    return (num >> amount | num << 32 - amount) & mask

def array_read_32(arr: array, address: int) -> int:
    """Read a little-endian 32-bit value from an array of bytes"""
    b0 = arr[address]
    b1 = arr[address + 1]
    b2 = arr[address + 2]
    b3 = arr[address + 3]
    return b0 | b1 << 8 | b2 << 16 | b3 << 24

def array_read_16(arr: array, address: int) -> int:
    """Read a little-endian 16-bit value from an array of bytes"""
    b0 = arr[address]
    b1 = arr[address + 1]
    return b0 | b1 << 8

def array_write_32(arr: array, address: int, value: int):
    """Write a 32-bit value to the given array of bytes in little-endian format"""
    arr[address] = value & 255
    arr[address + 1] = value >> 8 & 255
    arr[address + 2] = value >> 16 & 255
    arr[address + 3] = value >> 24 & 255

def array_write_16(arr: array, address: int, value: int):
    """Write a 16-bit value to the given array of bytes in little-endian format"""
    arr[address] = value & 255
    arr[address + 1] = value >> 8 & 255