/*===================================================================*/
/*                                                                   */
/*                    Mapper 19 (Namcot 106)                         */
/*                                                                   */
/*===================================================================*/

BYTE  Map19_Chr_Ram[ 0x2000 ];
BYTE  Map19_Regs[ 2 ];

BYTE  Map19_IRQ_Enable;
DWORD Map19_IRQ_Cnt;

/*-------------------------------------------------------------------*/
/*  Initialize Mapper 19                                             */
/*-------------------------------------------------------------------*/
void Map19_Init()
{
  /* Initialize Mapper */
  MapperInit = Map19_Init;

  /* Write to Mapper */
  MapperWrite = Map19_Write;

  /* Write to SRAM */
  MapperSram = Map0_Sram;

  /* Write to APU */
  MapperApu = Map19_Apu;

  /* Read from APU */
  MapperReadApu = Map19_ReadApu;

  /* Callback at VSync */
  MapperVSync = Map0_VSync;

  /* Callback at HSync */
  MapperHSync = Map19_HSync;

  /* Callback at PPU */
  MapperPPU = Map0_PPU;

  /* Callback at Rendering Screen ( 1:BG, 0:Sprite ) */
  MapperRenderScreen = Map0_RenderScreen;

  /* Set SRAM Banks */
  SRAMBANK = SRAM;

  /* Set ROM Banks */
  ROMBANK0 = ROMPAGE( 0 );
  ROMBANK1 = ROMPAGE( 1 );
  ROMBANK2 = ROMLASTPAGE( 1 );
  ROMBANK3 = ROMLASTPAGE( 0 );

  /* Set PPU Banks */
  if ( NesHeader.byVRomSize > 0 )
  {
    DWORD dwLastPage = (DWORD)NesHeader.byVRomSize << 3;
    PPUBANK[ 0 ] = VROMPAGE( dwLastPage - 8 );
    PPUBANK[ 1 ] = VROMPAGE( dwLastPage - 7 );
    PPUBANK[ 2 ] = VROMPAGE( dwLastPage - 6 );
    PPUBANK[ 3 ] = VROMPAGE( dwLastPage - 5 );
    PPUBANK[ 4 ] = VROMPAGE( dwLastPage - 4 );
    PPUBANK[ 5 ] = VROMPAGE( dwLastPage - 3 );
    PPUBANK[ 6 ] = VROMPAGE( dwLastPage - 2 );
    PPUBANK[ 7 ] = VROMPAGE( dwLastPage - 1 );
    InfoNES_SetupChr();
  }

  /* Initialize State Register */
  Map19_Regs[ 0 ] = 0x00;
  Map19_Regs[ 1 ] = 0x00;
  Map19_Regs[ 2 ] = 0x00;

  /* Set up wiring of the interrupt pin */
  K6502_Set_Int_Wiring( 1, 1 ); 
}

/*-------------------------------------------------------------------*/
/*  Mapper 19 Write Function                                         */
/*-------------------------------------------------------------------*/
void Map19_Write( WORD wAddr, BYTE byData )
{
  /* Set PPU Banks */
  switch ( wAddr & 0xf800 )
  {
    case 0x8000:  /* $8000-87ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 0 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 0 ] = Map19_VROMPAGE( 0 );
      }
      InfoNES_SetupChr();
      break;

    case 0x8800:  /* $8800-8fff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 1 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 1 ] = Map19_VROMPAGE( 1 );
      }
      InfoNES_SetupChr();
      break;

    case 0x9000:  /* $9000-97ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 2 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 2 ] = Map19_VROMPAGE( 2 );
      }
      InfoNES_SetupChr();
      break;

    case 0x9800:  /* $9800-9fff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 3 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 3 ] = Map19_VROMPAGE( 3 );
      }
      InfoNES_SetupChr();
      break;

    case 0xa000:  /* $a000-a7ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 4 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 4 ] = Map19_VROMPAGE( 4 );
      }
      InfoNES_SetupChr();
      break;

    case 0xa800:  /* $a800-afff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 5 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 5 ] = Map19_VROMPAGE( 5 );
      }
      InfoNES_SetupChr();
      break;

    case 0xb000:  /* $b000-b7ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 6 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 6 ] = Map19_VROMPAGE( 6 );
      }
      InfoNES_SetupChr();
      break;

    case 0xb800:  /* $b800-bfff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ 7 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ 7 ] = Map19_VROMPAGE( 7 );
      }
      InfoNES_SetupChr();
      break;

    case 0xc000:  /* $c000-c7ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ NAME_TABLE0 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ NAME_TABLE0 ] = VRAMPAGE( byData & 0x01 );
      }
      break;

    case 0xc800:  /* $c800-cfff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ NAME_TABLE1 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ NAME_TABLE1 ] = VRAMPAGE( byData & 0x01 );
      }
      break;

    case 0xd000:  /* $d000-d7ff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ NAME_TABLE2 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ NAME_TABLE2 ] = VRAMPAGE( byData & 0x01 );
      }
      break;

    case 0xd800:  /* $d800-dfff */
      if ( byData < 0xe0 || Map19_Regs[ 0 ] == 1 )
      {
        byData %= ( NesHeader.byVRomSize << 3 );
        PPUBANK[ NAME_TABLE3 ] = VROMPAGE( byData );
      } else {
        PPUBANK[ NAME_TABLE3 ] = VRAMPAGE( byData & 0x01 );
      }
      break;

    case 0xe000:  /* $e000-e7ff */
      byData &= 0x3f;
      byData %= ( NesHeader.byRomSize << 1 );
      ROMBANK0 = ROMPAGE( byData );
      break;

    case 0xe800:  /* $e800-efff */
      Map19_Regs[ 0 ] = ( byData & 0x40 ) >> 6;
      Map19_Regs[ 1 ] = ( byData & 0x80 ) >> 7;

      byData &= 0x3f;
      byData %= ( NesHeader.byRomSize << 1 );
      ROMBANK1 = ROMPAGE( byData );
      break;

    case 0xf000:  /* $f000-f7ff */
      byData &= 0x3f;
      byData %= ( NesHeader.byRomSize << 1 );
      ROMBANK2 = ROMPAGE( byData );
      break;

    case 0xf800:  /* $e800-efff */
      if ( wAddr == 0xf800 )
      {
        // Extra Sound
      }
      break;    
  }
}

/*-------------------------------------------------------------------*/
/*  Mapper 19 Write to APU Function                                  */
/*-------------------------------------------------------------------*/
void Map19_Apu( WORD wAddr, BYTE byData )
{
  switch ( wAddr & 0xf800 )
  {
    case 0x4800:
      if ( wAddr == 0x4800 )
      {
        // Extra Sound
      }
      break;

    case 0x5000:  /* $5000-57ff */
      Map19_IRQ_Cnt = ( Map19_IRQ_Cnt & 0xff00 ) | byData;
      break;

    case 0x5800:  /* $5800-5fff */
      Map19_IRQ_Cnt = ( Map19_IRQ_Cnt & 0x00ff ) | ( (DWORD)( byData & 0x7f ) << 8 );
      Map19_IRQ_Enable = ( byData & 0x80 ) >> 7;
      break;
  }
}

/*-------------------------------------------------------------------*/
/*  Mapper 19 Read from APU Function                                 */
/*-------------------------------------------------------------------*/
BYTE Map19_ReadApu( WORD wAddr )
{
  switch ( wAddr & 0xf800 )
  {
    case 0x4800:
      if ( wAddr == 0x4800 )
      {
        // Extra Sound
      }
      return (BYTE)( wAddr >> 8 );

    case 0x5000:  /* $5000-57ff */
      return (BYTE)(Map19_IRQ_Cnt & 0x00ff );

    case 0x5800:  /* $5800-5fff */
      return (BYTE)( (Map19_IRQ_Cnt & 0x7f00) >> 8 );

    default:
      return (BYTE)( wAddr >> 8 );
  }
}

/*-------------------------------------------------------------------*/
/*  Mapper 19 H-Sync Function                                        */
/*-------------------------------------------------------------------*/
void Map19_HSync()
{
/*
 *  Callback at HSync
 *
 */
  BYTE Map19_IRQ_Timing = 113;

  if ( Map19_IRQ_Enable )
  {
    if ( Map19_IRQ_Cnt >= (DWORD)(0x7fff - Map19_IRQ_Timing) )
    {
      Map19_IRQ_Cnt = 0x7fff;
      IRQ_REQ;
    } else {
      Map19_IRQ_Cnt += Map19_IRQ_Timing;
    }
  }
}
