//
// ri/controller.c: RAM interface controller.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//

#include "common.h"
#include "bus/address.h"
#include "bus/controller.h"
#include "ri/controller.h"

#ifdef DEBUG_MMIO_REGISTER_ACCESS
const char *rdram_register_mnemonics[NUM_RDRAM_REGISTERS] = {
#define X(reg) #reg,
#include "ri/rdram_registers.md"
#undef X
};
#endif

#ifdef DEBUG_MMIO_REGISTER_ACCESS
const char *ri_register_mnemonics[NUM_RI_REGISTERS] = {
#define X(reg) #reg,
#include "ri/registers.md"
#undef X
};
#endif

// Initializes the RI.
int ri_init(struct ri_controller *ri, struct bus_controller *bus) {
  ri->bus = bus;

  // MESS uses these, so we will too?
  ri->regs[RI_MODE_REG] = 0xE;
  ri->regs[RI_CONFIG_REG] = 0x40;
  ri->regs[RI_SELECT_REG] = 0x14;
  ri->regs[RI_REFRESH_REG] = 0x63634;

  return 0;
}

// Reads a word from RDRAM.
int read_rdram(void *opaque, uint32_t address, uint32_t *word) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RDRAM_BASE_ADDRESS;

  memcpy(word, ri->ram + offset, sizeof(*word));
  *word = byteswap_32(*word);
  return 0;
}

// Reads a word from the RDRAM MMIO register space.
int read_rdram_regs(void *opaque, uint32_t address, uint32_t *word) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RDRAM_REGS_BASE_ADDRESS;
  enum rdram_register reg = (offset >> 2);

  *word = ri->rdram_regs[reg];
  debug_mmio_read(rdram, rdram_register_mnemonics[reg], *word);
  return 0;
}

// Reads a word from the RI MMIO register space.
int read_ri_regs(void *opaque, uint32_t address, uint32_t *word) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RI_REGS_BASE_ADDRESS;
  enum ri_register reg = (offset >> 2);

  *word = ri->regs[reg];
  debug_mmio_read(ri, ri_register_mnemonics[reg], *word);
  return 0;
}

// Writes a word to RDRAM.
int write_rdram(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RDRAM_BASE_ADDRESS;
  uint32_t orig_word;

  memcpy(&orig_word, ri->ram + offset, sizeof(orig_word));
  orig_word = byteswap_32(orig_word) & ~dqm;
  word = byteswap_32(orig_word | word);
  memcpy(ri->ram + offset, &word, sizeof(word));
  return 0;
}

// Writes a word to the RDRAM MMIO register space.
int write_rdram_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RDRAM_REGS_BASE_ADDRESS;
  enum rdram_register reg = (offset >> 2);

  debug_mmio_write(rdram, rdram_register_mnemonics[reg], word, dqm);
  ri->rdram_regs[reg] &= ~dqm;
  ri->rdram_regs[reg] |= word;
  return 0;
}

// Writes a word to the RI MMIO register space.
int write_ri_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
  struct ri_controller *ri = (struct ri_controller *) opaque;
  unsigned offset = address - RI_REGS_BASE_ADDRESS;
  enum ri_register reg = (offset >> 2);

  debug_mmio_write(ri, ri_register_mnemonics[reg], word, dqm);
  ri->regs[reg] &= ~dqm;
  ri->regs[reg] |= word;
  return 0;
}

