quickerNES/core/mappers/mapper085.hpp

225 lines
4.9 KiB
C++
Raw Normal View History

2024-01-08 19:11:49 +00:00
// Nes_Emu 0.5.4. http://www.slack.net/~ant/
#include "Nes_Mapper.h"
#include "Nes_Vrc7.h"
#include "blargg_endian.h"
#include <string.h>
#pragma once
/* Copyright (C) 2004-2005 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
struct vrc7_state_t
{
// written registers
uint8_t mirroring;
uint8_t prg_banks [3];
uint8_t chr_banks [8];
uint8_t irq_reload;
uint8_t irq_mode;
// internal state
uint16_t next_time;
uint8_t irq_pending;
uint8_t unused;
vrc7_snapshot_t sound_state;
};
BOOST_STATIC_ASSERT( sizeof (vrc7_state_t) == 20 + sizeof (vrc7_snapshot_t) );
// Vrc7
class Mapper085 : public Nes_Mapper, vrc7_state_t {
public:
Mapper085()
{
vrc7_state_t* state = this;
register_state( state, sizeof *state );
}
virtual int channel_count() const { return sound.osc_count; }
virtual void set_channel_buf( int i, Blip_Buffer* b ) { sound.osc_output( i, b ); }
virtual void set_treble( blip_eq_t const& eq ) { sound.treble_eq( eq ); }
virtual void save_state( mapper_state_t & out )
{
sound.save_snapshot( &sound_state );
set_le16( &next_time, next_time );
Nes_Mapper::save_state( out );
}
virtual void load_state( mapper_state_t const& in )
{
Nes_Mapper::load_state( in );
next_time = get_le16( &next_time );
sound.load_snapshot( sound_state, in.size );
}
virtual void reset_state()
{
mirroring = 0;
memset( prg_banks, 0, sizeof prg_banks );
memset( chr_banks, 0, sizeof chr_banks );
memset( &sound_state, 0, sizeof sound_state );
irq_reload = 0;
irq_mode = 0;
irq_pending = false;
next_time = 0;
sound.reset();
set_prg_bank( 0xE000, bank_8k, last_bank );
apply_mapping();
}
void write_prg_bank( int bank, int data )
{
prg_banks [bank] = data;
set_prg_bank( 0x8000 | ( bank << bank_8k ), bank_8k, data );
}
void write_chr_bank( int bank, int data )
{
//dprintf( "change chr bank %d\n", bank );
chr_banks [bank] = data;
set_chr_bank( bank * 0x400, bank_1k, data );
}
void write_mirroring( int data )
{
mirroring = data;
//dprintf( "Change mirroring %d\n", data );
enable_sram( data & 128, data & 64 );
if ( data & 2 )
mirror_single( data & 1 );
else if ( data & 1 )
mirror_horiz();
else
mirror_vert();
}
void apply_mapping()
{
size_t i;
for ( i = 0; i < sizeof prg_banks; i++ )
write_prg_bank( i, prg_banks [i] );
for ( i = 0; i < sizeof chr_banks; i++ )
write_chr_bank( i, chr_banks [i] );
write_mirroring( mirroring );
}
void reset_timer( nes_time_t present )
{
next_time = present + unsigned ((0x100 - irq_reload) * timer_period) / 4;
}
virtual void run_until( nes_time_t end_time )
{
if ( irq_mode & 2 )
{
while ( next_time < end_time )
{
//dprintf( "%d timer expired\n", next_time );
irq_pending = true;
reset_timer( next_time );
}
}
}
virtual void end_frame( nes_time_t end_time )
{
run_until( end_time );
next_time -= end_time;
sound.end_frame( end_time );
}
virtual nes_time_t next_irq( nes_time_t present )
{
if ( irq_pending )
return present;
if ( irq_mode & 2 )
return next_time + 1;
return no_irq;
}
virtual void write( nes_time_t time, nes_addr_t addr, int data )
{
addr |= ( addr & 8 ) << 1;
if ( addr >= 0xe010 )
{
// IRQ
run_until( time );
//dprintf( "%d VRC6 IRQ [%d] = %02X\n", time, addr & 3, data );
switch ( addr & 0xf010 )
{
case 0xe010:
irq_reload = data;
break;
case 0xf000:
irq_pending = false;
irq_mode = data;
if ( data & 2 )
reset_timer( time );
break;
case 0xf010:
irq_pending = false;
irq_mode = (irq_mode & ~2) | ((irq_mode << 1) & 2);
break;
}
irq_changed();
}
else if ( ( unsigned ) ( addr - 0xa000 ) < 0x4000 )
{
write_chr_bank( ((addr >> 4) & 1) | (((addr - 0xa000) >> 11)&~1), data );
}
else switch ( addr & 0xf010 )
{
case 0x8000: write_prg_bank( 0, data ); break;
case 0x8010: write_prg_bank( 1, data ); break;
case 0x9000: write_prg_bank( 2, data ); break;
case 0xe000:
write_mirroring( data );
break;
case 0x9010:
if ( addr & 0x20 ) sound.write_data( time, data );
else sound.write_reg( data );
break;
}
}
Nes_Vrc7 sound;
enum { timer_period = 113 * 4 + 3 };
};