auto ARM::pipeline_step() -> void {
  pipeline.execute = pipeline.decode;
  pipeline.decode = pipeline.fetch;

  unsigned sequential = Sequential;
  if(pipeline.nonsequential) {
    pipeline.nonsequential = false;
    sequential = Nonsequential;
  }

  if(cpsr().t == 0) {
    r(15).data += 4;
    pipeline.fetch.address = r(15) & ~3;
    pipeline.fetch.instruction = read(Prefetch | Word | sequential, pipeline.fetch.address);
  } else {
    r(15).data += 2;
    pipeline.fetch.address = r(15) & ~1;
    pipeline.fetch.instruction = read(Prefetch | Half | sequential, pipeline.fetch.address);
  }
}

auto ARM::arm_step() -> void {
  if(pipeline.reload) {
    pipeline.reload = false;
    r(15).data &= ~3;

    pipeline.fetch.address = r(15) & ~3;
    pipeline.fetch.instruction = read(Prefetch | Word | Nonsequential, pipeline.fetch.address);

    pipeline_step();
  }

  pipeline_step();

  if(processor.irqline && cpsr().i == 0) {
    vector(0x00000018, Processor::Mode::IRQ);
    return;
  }

  instructions++;
  if(trace) {
    print(disassemble_registers(), "\n");
    print(disassemble_arm_instruction(pipeline.execute.address), "\n");
    usleep(100000);
  }

  if(condition(instruction() >> 28) == false) return;

  #define decode(pattern, execute) if( \
    (instruction() & std::integral_constant<uint32_t, bit::mask(pattern)>::value) \
    == std::integral_constant<uint32_t, bit::test(pattern)>::value \
  ) return arm_op_ ## execute()

  decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register);
  decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply);
  decode("???? 0000 1??? ???? ???? ???? 1001 ????", multiply_long);
  decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
  decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
  decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register);
  decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate);
  decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register);
  decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate);
  decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
  decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
  decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift);
  decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift);
  decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate);
  decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset);
  decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset);
  decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple);
  decode("???? 101? ???? ???? ???? ???? ???? ????", branch);
  decode("???? 1111 ???? ???? ???? ???? ???? ????", software_interrupt);

  #undef decode

  crash = true;
}

auto ARM::thumb_step() -> void {
  if(pipeline.reload) {
    pipeline.reload = false;
    r(15).data &= ~1;

    pipeline.fetch.address = r(15) & ~1;
    pipeline.fetch.instruction = read(Prefetch | Half | Nonsequential, pipeline.fetch.address);

    pipeline_step();
  }

  pipeline_step();

  if(processor.irqline && cpsr().i == 0) {
    vector(0x00000018, Processor::Mode::IRQ);
    r(14) += 2;
    return;
  }

  instructions++;
  if(trace) {
    print(disassemble_registers(), "\n");
    print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
  }

  #define decode(pattern, execute) if( \
    (instruction() & std::integral_constant<uint32_t, bit::mask(pattern)>::value) \
    == std::integral_constant<uint32_t, bit::test(pattern)>::value \
  ) return thumb_op_ ## execute()

  decode("0001 10?? ???? ????", adjust_register);
  decode("0001 11?? ???? ????", adjust_immediate);
  decode("000? ???? ???? ????", shift_immediate);
  decode("001? ???? ???? ????", immediate);
  decode("0100 00?? ???? ????", alu);
  decode("0100 0111 0??? ?---", branch_exchange);
  decode("0100 01?? ???? ????", alu_hi);
  decode("0100 1??? ???? ????", load_literal);
  decode("0101 ???? ???? ????", move_register_offset);
  decode("0110 ???? ???? ????", move_word_immediate);
  decode("0111 ???? ???? ????", move_byte_immediate);
  decode("1000 ???? ???? ????", move_half_immediate);
  decode("1001 ???? ???? ????", move_stack);
  decode("1010 ???? ???? ????", add_register_hi);
  decode("1011 0000 ???? ????", adjust_stack);
  decode("1011 ?10? ???? ????", stack_multiple);
  decode("1100 ???? ???? ????", move_multiple);
  decode("1101 1111 ???? ????", software_interrupt);
  decode("1101 ???? ???? ????", branch_conditional);
  decode("1110 0??? ???? ????", branch_short);
  decode("1111 0??? ???? ????", branch_long_prefix);
  decode("1111 1??? ???? ????", branch_long_suffix);

  #undef decode

  crash = true;
}
