#include "texture.hpp"

#include "memorymap.hpp"

#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"

#include "systembus.hpp"

#include "holly/texture_memory_alloc9.hpp"

namespace texture {

  struct texture textures[] = {
    {
      .start = reinterpret_cast<void *>(&_binary_font_tandy1k_data_start),
      .size = reinterpret_cast<int>(&_binary_font_tandy1k_data_size),
      .offset = offset::tandy1k,
    },
    {
      .start = reinterpret_cast<void *>(&_binary_model_32bitlogo_colors_data_start),
      .size = reinterpret_cast<int>(&_binary_model_32bitlogo_colors_data_size),
      .offset = offset::logo,
    }
  };

  const int textures_length = (sizeof (textures)) / (sizeof (textures[0]));

  static inline void transfer_ta_fifo_texture_memory_32byte(void * dst, void * src, int length)
  {
    uint32_t out_addr = (uint32_t)dst;
    sh7091.CCN.QACR0 = ((reinterpret_cast<uint32_t>(out_addr) >> 24) & 0b11100);
    sh7091.CCN.QACR1 = ((reinterpret_cast<uint32_t>(out_addr) >> 24) & 0b11100);

    volatile uint32_t * base = &store_queue[(out_addr & 0x03ffffe0) / 4];
    uint32_t * src32 = reinterpret_cast<uint32_t *>(src);

    length = (length + 31) & ~31; // round up to nearest multiple of 32
    while (length > 0) {
      base[0] = src32[0];
      base[1] = src32[1];
      base[2] = src32[2];
      base[3] = src32[3];
      base[4] = src32[4];
      base[5] = src32[5];
      base[6] = src32[6];
      base[7] = src32[7];
      asm volatile ("pref @%0"
                    :                // output
                    : "r" (&base[0]) // input
                    : "memory");
      length -= 32;
      base += 8;
      src32 += 8;
    }
  }

  void transfer_texture_memory()
  {
    system.LMMODE0 = 0; // 64-bit address space
    system.LMMODE1 = 0; // 64-bit address space

    for (int i = 0; i < textures_length; i++) {
      uint32_t offset = texture_memory_alloc.texture.start + textures[i].offset;
      void * dst = reinterpret_cast<void *>(&ta_fifo_texture_memory[offset / 4]);
      void * src = textures[i].start;
      int size = textures[i].size;
      transfer_ta_fifo_texture_memory_32byte(dst, src, size);
    }
  }

}
