def thumb_multiple_load_store(cpu: CPU, instr: int):
    """Execute a THUMB.15 instruction (multiple load/store)"""
    reg_list = get_bits(instr, 0, 7)
    base_reg = get_bits(instr, 8, 10)
    address = cpu.regs.get(base_reg)
    cpu.advance_pc_thumb()
    load = get_bit(instr, 11)
    if reg_list == 0:
        if load:
            cpu.regs.set_pc(cpu.memory.read_32(cpu.regs.get(base_reg), MemoryAccess.NON_SEQUENTIAL))
            cpu.flush_pipeline()
        else:
            cpu.memory.write_32(cpu.regs.get(base_reg), cpu.regs.get_pc(), MemoryAccess.NON_SEQUENTIAL)
        cpu.regs.set(base_reg, add_32(cpu.regs.get(base_reg), 64))
        return
    count = 0
    for reg in range(8):
        count += get_bit(instr, reg)
    count *= 4
    access_type = MemoryAccess.NON_SEQUENTIAL
    if load:
        cpu.regs.set(base_reg, add_32(cpu.regs.get(base_reg), count))
        cpu.scheduler.idle(1)
        for reg in range(8):
            if get_bit(reg_list, reg):
                cpu.regs.set(reg, cpu.memory.read_32(address, access_type))
                address = add_32(address, 4)
                access_type = MemoryAccess.SEQUENTIAL
    else:
        first = True
        for reg in range(8):
            if get_bit(reg_list, reg):
                cpu.memory.write_32(address, cpu.regs.get(reg), access_type)
                address = add_32(address, 4)
                access_type = MemoryAccess.SEQUENTIAL
                if first:
                    cpu.regs.set(base_reg, add_32(cpu.regs.get(base_reg), count))
                    first = False

def thumb_push_pop_registers(cpu: CPU, instr: int):
    """Execute a THUMB.14 instruction (push/pop registers to the stack)"""
    reg_list = get_bits(instr, 0, 8)
    opcode = get_bit(instr, 11)
    cpu.advance_pc_thumb()
    if opcode:
        thumb_pop_registers(cpu, reg_list)
    else:
        thumb_push_registers(cpu, reg_list)

def thumb_push_registers(cpu: CPU, reg_list: int):
    """
    Push the specified registers to the stack.

    :param cpu:      The CPU executing this instruction.
    :param reg_list: A 9-bit wide bitfield specifying which registers to push.
                     Bits 0-7 correspond to registers R0-R7 and bit 8 corresponds
                     to LR (R14).
    """
    if reg_list == 0:
        cpu.regs.set_sp(add_32(cpu.regs.get_sp(), -64))
        cpu.memory.write_32(cpu.regs.get_sp(), cpu.regs.get_pc(), MemoryAccess.NON_SEQUENTIAL)
        return
    push_lr = get_bit(reg_list, 8)
    if push_lr:
        cpu.regs.set_sp(add_32(cpu.regs.get_sp(), -4))
        cpu.memory.write_32(cpu.regs.get_sp(), cpu.regs.get_lr(), MemoryAccess.NON_SEQUENTIAL)
    for reg in range(7, -1, -1):
        if get_bit(reg_list, reg):
            cpu.regs.set_sp(add_32(cpu.regs.get_sp(), -4))
            cpu.memory.write_32(cpu.regs.get_sp(), cpu.regs.get(reg), MemoryAccess.SEQUENTIAL)

def thumb_pop_registers(cpu: CPU, reg_list: int):
    """
    Pop the specified registers off the stack.

    :param cpu:      The CPU executing this instruction.
    :param reg_list: A 9-bit wide bitfield specifying which registers to pop.
                     Bits 0-7 correspond to registers R0-R7 and bit 8 corresponds
                     to PC (R15).
    """
    if reg_list == 0:
        cpu.regs.set_pc(cpu.memory.read_32(cpu.regs.get_sp(), MemoryAccess.NON_SEQUENTIAL))
        cpu.regs.set_sp(add_32(cpu.regs.get_sp(), 64))
        cpu.flush_pipeline()
        return
    access_type = MemoryAccess.NON_SEQUENTIAL
    for reg in range(8):
        if get_bit(reg_list, reg):
            cpu.regs.set(reg, cpu.memory.read_32(cpu.regs.get_sp(), access_type))
            cpu.regs.set_sp(add_32(cpu.regs.get_sp(), 4))
            access_type = MemoryAccess.SEQUENTIAL
    pop_pc = get_bit(reg_list, 8)
    if pop_pc:
        cpu.regs.set_pc(cpu.memory.read_32(cpu.regs.get_sp(), access_type))
        cpu.regs.set_sp(add_32(cpu.regs.get_sp(), 4))
        cpu.flush_pipeline()
    cpu.scheduler.idle(1)