#include "assert.h"
#include "interrupt.hpp"
#include "aica/aica.hpp"

#include "platform/graphics.hpp"
#include "platform/input.hpp"
#include "platform/texture.hpp"
#include "platform/detect_emulator.hpp"
#include "xm_player/sound.hpp"
#include "xm_player/interpreter.hpp"
#include "printf/printf.h"

#include "platform/emulator_detected.hpp"

bool emulator_detected;

void vbr100()
{
  if (sh7091.CCN.EXPEVT == 0xe0) {
    serial::string("vbr100 expevt == 0xe0\n");
    return;
  }
  serial::string("vbr100\n");
  interrupt_exception();
}

void vbr400()
{
  serial::string("vbr400\n");
  interrupt_exception();
}

static bool inside_interrupt = false;

void vbr600()
{
  assert(inside_interrupt == false);
  inside_interrupt = true;
  uint32_t sr;
  asm volatile ("stc sr,%0" : "=r" (sr));
  sr |= sh::sr::imask(15);
  asm volatile ("ldc %0,sr" : : "r" (sr));

  if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x320) { // Holly
    uint32_t istnrm = system.ISTNRM;
    uint32_t isterr = system.ISTERR;

    if (isterr) {
      serial::string("isterr: ");
      serial::integer<uint32_t>(system.ISTERR);
    }

    graphics::interrupt(istnrm);
  } else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x360) { // AICA
    wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A

    wait(); aica_sound.common.tactl_tima
              = aica::tactl_tima::TACTL(0)  // increment once every sample
              | aica::tactl_tima::TIMA(0xfffd) // interrupt after 3 counts
              ;

    interpreter::interrupt();
  } else {
    serial::string("vbr600\n");
    interrupt_exception();
  }

  sr &= ~sh::sr::imask(15);
  asm volatile ("ldc %0,sr" : : "r" (sr));
  inside_interrupt = false;
}

void main()
{
  serial::init(0);

  emulator_detected = detect_emulator();

  input::init();
  graphics::init();
  texture::init();
  sound::init();

  interrupt_init();
  system.IML6NRM = istnrm::end_of_render_tsp
                 | istnrm::v_blank_in
                 | istnrm::end_of_transferring_opaque_list;

  system.IML4EXT = istext::aica;

  while (1) {
    input::update();
    graphics::step();
  }
}
