#include "aica/aica.hpp"

#include "interrupt.hpp"
#include "graphics.hpp"
#include "interpreter.hpp"
#include "sound.hpp"
#include "scene/scene.hpp"
#include "scene/logo/sound.hpp"
#include "cursor.hpp"
#include "input.hpp"

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

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

void vbr600()
{
  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(0xffff) // interrupt after 1 counts
      ;

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

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

#include "memorymap.hpp"
#include "holly/texture_memory_alloc9.hpp"
#include "holly/holly.hpp"

static inline uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b)
{
  int r5 = r & 31;
  int g6 = g & 63;
  int b5 = b & 31;
  return (r5 << 11) | (g6 << 5) | (b5 << 0);
}

void test_pattern()
{
  uint16_t * framebuffer = (uint16_t *)&texture_memory32[texture_memory_alloc.framebuffer[0].start / 4];

  for (int y = 0; y < 480; y++) {
    for (int x = 0; x < 720; x++) {
      if (x == 0 || y == 0 || y == 479)
        framebuffer[y * 720 + x] = rgb565(31, 0, 0);
      else if (x == 719)
        framebuffer[y * 720 + x] = rgb565(0, 0, 31);
      else
        framebuffer[y * 720 + x] = rgb565(0, 31 * (x & 1), 0);
    }
  }

  holly.FB_R_SOF1 = texture_memory_alloc.framebuffer[0].start;
}

void main()
{
  printf("main\n");
  serial::init(0);

  printf("main\n");
  sound::init();
  graphics_init();
  scene::scene_init();
  input::state_init();
  cursor::init();

  //test_pattern();

  interrupt_init();

  system.IML6NRM = istnrm::end_of_render_tsp
                 | istnrm::v_blank_in
                 | istnrm::end_of_transferring_opaque_list;

  system.IML4EXT = istext::aica;

  static uint8_t op_buf[1024 * 1024 / 2] __attribute__((aligned(32)));
  static uint8_t pt_buf[1024 * 1024 / 2] __attribute__((aligned(32)));
  ta_multiwriter multi(ta_parameter_writer(op_buf, (sizeof (op_buf))),
                       ta_parameter_writer(pt_buf, (sizeof (pt_buf))));

  static uint8_t send_buf[1024] __attribute__((aligned(32)));
  static uint8_t recv_buf[1024] __attribute__((aligned(32)));

  input::state_update(send_buf, recv_buf);
  while (1) {
    cursor::update();
    input::state_update(send_buf, recv_buf);

    graphics_event(multi);
  }
}
