Some simplification
This commit is contained in:
parent
361b42be9c
commit
d8b904f53f
|
@ -5,17 +5,95 @@
|
|||
// Nes_Snd_Emu 0.1.7
|
||||
|
||||
#include <cstdint>
|
||||
#include "blargg_source.h"
|
||||
#include "blargg_endian.h"
|
||||
|
||||
typedef long nes_time_t; // CPU clock cycle count
|
||||
typedef unsigned nes_addr_t; // 16-bit memory address
|
||||
|
||||
#include "Nes_Oscs.h"
|
||||
|
||||
struct apu_state_t;
|
||||
class Nes_Buffer;
|
||||
|
||||
class Nes_Apu {
|
||||
public:
|
||||
|
||||
typedef uint8_t env_t [3];
|
||||
/*struct env_t {
|
||||
uint8_t delay;
|
||||
uint8_t env;
|
||||
uint8_t written;
|
||||
};*/
|
||||
|
||||
struct apu_t {
|
||||
uint8_t w40xx [0x14]; // $4000-$4013
|
||||
uint8_t w4015; // enables
|
||||
uint8_t w4017; // mode
|
||||
uint16_t frame_delay;
|
||||
uint8_t frame_step;
|
||||
uint8_t irq_flag;
|
||||
};
|
||||
|
||||
struct square_t {
|
||||
uint16_t delay;
|
||||
env_t env;
|
||||
uint8_t length_counter;
|
||||
uint8_t phase;
|
||||
uint8_t swp_delay;
|
||||
uint8_t swp_reset;
|
||||
uint8_t unused2 [1];
|
||||
};
|
||||
|
||||
struct triangle_t {
|
||||
uint16_t delay;
|
||||
uint8_t length_counter;
|
||||
uint8_t phase;
|
||||
uint8_t linear_counter;
|
||||
uint8_t linear_mode;
|
||||
};
|
||||
|
||||
struct noise_t {
|
||||
uint16_t delay;
|
||||
env_t env;
|
||||
uint8_t length_counter;
|
||||
uint16_t shift_reg;
|
||||
};
|
||||
|
||||
struct dmc_t {
|
||||
uint16_t delay;
|
||||
uint16_t remain;
|
||||
uint16_t addr;
|
||||
uint8_t buf;
|
||||
uint8_t bits_remain;
|
||||
uint8_t bits;
|
||||
uint8_t buf_full;
|
||||
uint8_t silence;
|
||||
uint8_t irq_flag;
|
||||
};
|
||||
|
||||
struct apu_state_t
|
||||
{
|
||||
apu_t apu;
|
||||
square_t square1;
|
||||
square_t square2;
|
||||
triangle_t triangle;
|
||||
noise_t noise;
|
||||
dmc_t dmc;
|
||||
|
||||
enum { tag = 0x41505552 }; // 'APUR'
|
||||
void swap()
|
||||
{
|
||||
SWAP_LE( apu.frame_delay );
|
||||
SWAP_LE( square1.delay );
|
||||
SWAP_LE( square2.delay );
|
||||
SWAP_LE( triangle.delay );
|
||||
SWAP_LE( noise.delay );
|
||||
SWAP_LE( noise.shift_reg );
|
||||
SWAP_LE( dmc.delay );
|
||||
SWAP_LE( dmc.remain );
|
||||
SWAP_LE( dmc.addr );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (apu_state_t) == 72 );
|
||||
|
||||
Nes_Apu();
|
||||
~Nes_Apu();
|
||||
|
||||
|
@ -172,3 +250,125 @@ inline nes_time_t Nes_Dmc::next_read_time() const
|
|||
|
||||
inline nes_time_t Nes_Apu::next_dmc_read_time() const { return dmc.next_read_time(); }
|
||||
|
||||
|
||||
template<int mode>
|
||||
struct apu_reflection
|
||||
{
|
||||
#define REFLECT( apu, state ) (mode ? void (apu = state) : void (state = apu))
|
||||
|
||||
static void reflect_env( Nes_Apu::env_t* state, Nes_Envelope& osc )
|
||||
{
|
||||
REFLECT( (*state) [0], osc.env_delay );
|
||||
REFLECT( (*state) [1], osc.envelope );
|
||||
REFLECT( (*state) [2], osc.reg_written [3] );
|
||||
}
|
||||
|
||||
static void reflect_square( Nes_Apu::square_t& state, Nes_Square& osc )
|
||||
{
|
||||
reflect_env( &state.env, osc );
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.phase, osc.phase );
|
||||
REFLECT( state.swp_delay, osc.sweep_delay );
|
||||
REFLECT( state.swp_reset, osc.reg_written [1] );
|
||||
}
|
||||
|
||||
static void reflect_triangle( Nes_Apu::triangle_t& state, Nes_Triangle& osc )
|
||||
{
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.linear_counter, osc.linear_counter );
|
||||
REFLECT( state.phase, osc.phase );
|
||||
REFLECT( state.linear_mode, osc.reg_written [3] );
|
||||
}
|
||||
|
||||
static void reflect_noise( Nes_Apu::noise_t& state, Nes_Noise& osc )
|
||||
{
|
||||
reflect_env( &state.env, osc );
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.shift_reg, osc.noise );
|
||||
}
|
||||
|
||||
static void reflect_dmc( Nes_Apu::dmc_t& state, Nes_Dmc& osc )
|
||||
{
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.remain, osc.length_counter );
|
||||
REFLECT( state.buf, osc.buf );
|
||||
REFLECT( state.bits_remain, osc.bits_remain );
|
||||
REFLECT( state.bits, osc.bits );
|
||||
REFLECT( state.buf_full, osc.buf_full );
|
||||
REFLECT( state.silence, osc.silence );
|
||||
REFLECT( state.irq_flag, osc.irq_flag );
|
||||
if ( mode )
|
||||
state.addr = osc.address | 0x8000;
|
||||
else
|
||||
osc.address = state.addr & 0x7fff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline void Nes_Apu::save_state( apu_state_t* state ) const
|
||||
{
|
||||
for ( int i = 0; i < osc_count * 4; i++ )
|
||||
{
|
||||
int index = i >> 2;
|
||||
state->apu.w40xx [i] = oscs [index]->regs [i & 3];
|
||||
//if ( index < 4 )
|
||||
// state->length_counters [index] = oscs [index]->length_counter;
|
||||
}
|
||||
state->apu.w40xx [0x11] = dmc.dac;
|
||||
|
||||
state->apu.w4015 = osc_enables;
|
||||
state->apu.w4017 = frame_mode;
|
||||
state->apu.frame_delay = frame_delay;
|
||||
state->apu.frame_step = frame;
|
||||
state->apu.irq_flag = irq_flag;
|
||||
|
||||
typedef apu_reflection<1> refl;
|
||||
Nes_Apu& apu = *(Nes_Apu*) this; // const_cast
|
||||
refl::reflect_square ( state->square1, apu.square1 );
|
||||
refl::reflect_square ( state->square2, apu.square2 );
|
||||
refl::reflect_triangle( state->triangle, apu.triangle );
|
||||
refl::reflect_noise ( state->noise, apu.noise );
|
||||
refl::reflect_dmc ( state->dmc, apu.dmc );
|
||||
}
|
||||
|
||||
inline void Nes_Apu::load_state( apu_state_t const& state )
|
||||
{
|
||||
reset();
|
||||
|
||||
write_register( 0, 0x4017, state.apu.w4017 );
|
||||
write_register( 0, 0x4015, state.apu.w4015 );
|
||||
osc_enables = state.apu.w4015; // DMC clears bit 4
|
||||
|
||||
for ( int i = 0; i < osc_count * 4; i++ )
|
||||
{
|
||||
int n = state.apu.w40xx [i];
|
||||
int index = i >> 2;
|
||||
oscs [index]->regs [i & 3] = n;
|
||||
write_register( 0, 0x4000 + i, n );
|
||||
//if ( index < 4 )
|
||||
// oscs [index]->length_counter = state.length_counters [index];
|
||||
}
|
||||
|
||||
frame_delay = state.apu.frame_delay;
|
||||
frame = state.apu.frame_step;
|
||||
irq_flag = state.apu.irq_flag;
|
||||
|
||||
typedef apu_reflection<0> refl;
|
||||
apu_state_t& st = (apu_state_t&) state; // const_cast
|
||||
refl::reflect_square ( st.square1, square1 );
|
||||
refl::reflect_square ( st.square2, square2 );
|
||||
refl::reflect_triangle( st.triangle, triangle );
|
||||
refl::reflect_noise ( st.noise, noise );
|
||||
refl::reflect_dmc ( st.dmc, dmc );
|
||||
dmc.recalc_irq();
|
||||
|
||||
//force channels to have correct last_amp levels after load state
|
||||
square1.run(last_time, last_time);
|
||||
square2.run(last_time, last_time);
|
||||
triangle.run(last_time, last_time);
|
||||
noise.run(last_time, last_time);
|
||||
dmc.run(last_time, last_time);
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Nes_File.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
#include "blargg_source.h"
|
||||
|
||||
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
|
@ -16,7 +16,6 @@ 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 */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
// Nes_File_Writer
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "blargg_endian.h"
|
||||
#include "Nes_Apu.h"
|
||||
#include "Nes_Emu.h"
|
||||
#include "Nes_Mapper.h"
|
||||
|
||||
|
@ -121,7 +122,7 @@ const char * Nes_State_::write_blocks( Nes_File_Writer& out ) const
|
|||
|
||||
if ( apu_valid )
|
||||
{
|
||||
apu_state_t s = *apu;
|
||||
Nes_Apu::apu_state_t s = *apu;
|
||||
RETURN_ERR( write_nes_state( out, s ) );
|
||||
}
|
||||
|
||||
|
@ -232,7 +233,7 @@ const char * Nes_State_::read_blocks( Nes_File_Reader& in )
|
|||
ppu_valid = true;
|
||||
break;
|
||||
|
||||
case apu_state_t::tag:
|
||||
case FOUR_CHAR('APUR'):
|
||||
memset( apu, 0, sizeof *apu );
|
||||
RETURN_ERR( read_nes_state( in, apu ) );
|
||||
apu_valid = true;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "Nes_File.h"
|
||||
#include "Nes_Cpu.h"
|
||||
#include "Nes_Apu.h"
|
||||
class Nes_Emu;
|
||||
class Nes_State;
|
||||
|
||||
|
@ -63,7 +64,7 @@ public:
|
|||
nes_state_t nes;
|
||||
Nes_Cpu::registers_t* cpu;
|
||||
joypad_state_t* joypad;
|
||||
apu_state_t* apu;
|
||||
Nes_Apu::apu_state_t* apu;
|
||||
ppu_state_t* ppu;
|
||||
mapper_state_t* mapper;
|
||||
|
||||
|
@ -96,7 +97,7 @@ public:
|
|||
private:
|
||||
Nes_Cpu::registers_t cpu;
|
||||
joypad_state_t joypad;
|
||||
apu_state_t apu;
|
||||
Nes_Apu::apu_state_t apu;
|
||||
ppu_state_t ppu;
|
||||
mapper_state_t mapper;
|
||||
uint8_t ram [ram_size];
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
|
||||
#include "abstract_file.h"
|
||||
|
||||
#include "blargg_config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Copyright (C) 2005-2006 Shay Green. Permission is hereby granted, free of
|
||||
charge, to any person obtaining a copy of this software module and associated
|
||||
documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions: The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions of the Software. THE
|
||||
SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
const char *Data_Writer::write( const void*, long ) { return 0; }
|
||||
|
||||
// Mem_Writer
|
||||
|
||||
Mem_Writer::Mem_Writer( void* p, long s, int b )
|
||||
{
|
||||
data_ = (char*) p;
|
||||
size_ = 0;
|
||||
allocated = s;
|
||||
mode = b ? ignore_excess : fixed;
|
||||
}
|
||||
|
||||
Mem_Writer::Mem_Writer()
|
||||
{
|
||||
data_ = 0;
|
||||
size_ = 0;
|
||||
allocated = 0;
|
||||
mode = expanding;
|
||||
}
|
||||
|
||||
Mem_Writer::~Mem_Writer()
|
||||
{
|
||||
if ( ( mode == expanding ) && data_ )
|
||||
free( data_ );
|
||||
}
|
||||
|
||||
const char *Mem_Writer::write( const void* p, long s )
|
||||
{
|
||||
long remain = allocated - size_;
|
||||
if ( s > remain )
|
||||
{
|
||||
if ( mode == fixed )
|
||||
return "Tried to write more data than expected";
|
||||
|
||||
if ( mode == ignore_excess )
|
||||
{
|
||||
s = remain;
|
||||
}
|
||||
else // expanding
|
||||
{
|
||||
long new_allocated = size_ + s;
|
||||
new_allocated += (new_allocated >> 1) + 2048;
|
||||
void* p = realloc( data_, new_allocated );
|
||||
if ( !p )
|
||||
return "Out of memory";
|
||||
data_ = (char*) p;
|
||||
allocated = new_allocated;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy( data_ + size_, p, s );
|
||||
size_ += s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dry_Writer for determining size
|
||||
|
||||
Dry_Writer::Dry_Writer()
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
Dry_Writer::~Dry_Writer()
|
||||
{
|
||||
}
|
||||
|
||||
const char *Dry_Writer::write( const void* p, long s )
|
||||
{
|
||||
size_ += s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Auto_File_Reader
|
||||
|
||||
const char* Auto_File_Reader::open()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Auto_File_Reader::~Auto_File_Reader()
|
||||
{
|
||||
if ( path )
|
||||
delete data;
|
||||
}
|
||||
|
||||
// Auto_File_Writer
|
||||
|
||||
const char* Auto_File_Writer::open()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* Auto_File_Writer::open_comp( int level )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Auto_File_Writer::~Auto_File_Writer()
|
||||
{
|
||||
}
|
|
@ -1,12 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
/* Copyright (C) 2005-2006 Shay Green. Permission is hereby granted, free of
|
||||
charge, to any person obtaining a copy of this software module and associated
|
||||
documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions: The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions of the Software. THE
|
||||
SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
// Abstract file access interfaces
|
||||
|
||||
#ifndef ABSTRACT_FILE_H
|
||||
#define ABSTRACT_FILE_H
|
||||
|
||||
#undef BLARGG_CONFIG_H
|
||||
|
||||
#include "Data_Reader.h"
|
||||
#include <cstring>
|
||||
|
||||
// Supports writing
|
||||
class Data_Writer {
|
||||
|
@ -15,8 +27,8 @@ public:
|
|||
virtual ~Data_Writer() { }
|
||||
|
||||
// Write 'n' bytes. NULL on success, otherwise error string.
|
||||
virtual const char *write( const void*, long n ) = 0;
|
||||
|
||||
virtual const char *write( const void*, long ) { return 0; }
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Data_Writer( const Data_Writer& );
|
||||
|
@ -31,39 +43,93 @@ class Mem_Writer : public Data_Writer {
|
|||
enum { expanding, fixed, ignore_excess } mode;
|
||||
public:
|
||||
// Keep all written data in expanding block of memory
|
||||
Mem_Writer();
|
||||
|
||||
Mem_Writer()
|
||||
{
|
||||
data_ = 0;
|
||||
size_ = 0;
|
||||
allocated = 0;
|
||||
mode = expanding;
|
||||
}
|
||||
|
||||
// Write to fixed-size block of memory. If ignore_excess is false, returns
|
||||
// error if more than 'size' data is written, otherwise ignores any excess.
|
||||
Mem_Writer( void*, long size, int ignore_excess = 0 );
|
||||
|
||||
const char *write( const void*, long );
|
||||
|
||||
Mem_Writer( void* p, long s, int b )
|
||||
{
|
||||
data_ = (char*) p;
|
||||
size_ = 0;
|
||||
allocated = s;
|
||||
mode = b ? ignore_excess : fixed;
|
||||
}
|
||||
|
||||
const char * write( const void* p, long s )
|
||||
{
|
||||
long remain = allocated - size_;
|
||||
if ( s > remain )
|
||||
{
|
||||
if ( mode == fixed )
|
||||
return "Tried to write more data than expected";
|
||||
|
||||
if ( mode == ignore_excess )
|
||||
{
|
||||
s = remain;
|
||||
}
|
||||
else // expanding
|
||||
{
|
||||
long new_allocated = size_ + s;
|
||||
new_allocated += (new_allocated >> 1) + 2048;
|
||||
void* p = realloc( data_, new_allocated );
|
||||
if ( !p )
|
||||
return "Out of memory";
|
||||
data_ = (char*) p;
|
||||
allocated = new_allocated;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy( data_ + size_, p, s );
|
||||
size_ += s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pointer to beginning of written data
|
||||
char* data() { return data_; }
|
||||
|
||||
// Number of bytes written
|
||||
size_t size() const { return size_; }
|
||||
|
||||
~Mem_Writer();
|
||||
~Mem_Writer()
|
||||
{
|
||||
if ( ( mode == expanding ) && data_ ) free( data_ );
|
||||
}
|
||||
};
|
||||
|
||||
// Dry writer to get the state size
|
||||
class Dry_Writer : public Data_Writer {
|
||||
long size_;
|
||||
|
||||
public:
|
||||
// Keep all written data in expanding block of memory
|
||||
Dry_Writer();
|
||||
|
||||
const char *write( const void*, long );
|
||||
|
||||
Dry_Writer()
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
~Dry_Writer()
|
||||
{
|
||||
}
|
||||
|
||||
const char *write( const void* p, long s )
|
||||
{
|
||||
size_ += s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Pointer to beginning of written data
|
||||
char* data() { return NULL; }
|
||||
|
||||
// Number of bytes written
|
||||
long size() const { return size_; }
|
||||
|
||||
~Dry_Writer();
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,9 +142,18 @@ public:
|
|||
Auto_File_Reader( Data_Reader& r ) : data( &r ), path( 0 ) { }
|
||||
Auto_File_Reader( Auto_File_Reader const& );
|
||||
Auto_File_Reader& operator = ( Auto_File_Reader const& );
|
||||
~Auto_File_Reader();
|
||||
const char* open();
|
||||
|
||||
|
||||
const char* open()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
~Auto_File_Reader()
|
||||
{
|
||||
if ( path )
|
||||
delete data;
|
||||
}
|
||||
|
||||
int operator ! () const { return !data; }
|
||||
Data_Reader* operator -> () const { return data; }
|
||||
Data_Reader& operator * () const { return *data; }
|
||||
|
@ -93,9 +168,20 @@ public:
|
|||
Auto_File_Writer( Data_Writer& r ) : data( &r ), path( 0 ) { }
|
||||
Auto_File_Writer( Auto_File_Writer const& );
|
||||
Auto_File_Writer& operator = ( Auto_File_Writer const& );
|
||||
~Auto_File_Writer();
|
||||
const char* open();
|
||||
const char* open_comp( int level = -1 ); // compress output if possible
|
||||
|
||||
~Auto_File_Writer()
|
||||
{
|
||||
}
|
||||
|
||||
const char* open()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* open_comp( int level = -1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int operator ! () const { return !data; }
|
||||
Data_Writer* operator -> () const { return data; }
|
||||
|
@ -122,5 +208,3 @@ inline Auto_File_Writer& Auto_File_Writer::operator = ( Auto_File_Writer const&
|
|||
return *this;
|
||||
}
|
||||
inline Auto_File_Writer::Auto_File_Writer( Auto_File_Writer const& r ) { *this = r; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
|
||||
// Nes_Snd_Emu 0.1.7. http://www.slack.net/~ant/libs/
|
||||
|
||||
#include "apu_state.h"
|
||||
#include "Nes_Apu.h"
|
||||
|
||||
/* Copyright (C) 2003-2006 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 */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
template<int mode>
|
||||
struct apu_reflection
|
||||
{
|
||||
#define REFLECT( apu, state ) (mode ? void (apu = state) : void (state = apu))
|
||||
|
||||
static void reflect_env( apu_state_t::env_t* state, Nes_Envelope& osc )
|
||||
{
|
||||
REFLECT( (*state) [0], osc.env_delay );
|
||||
REFLECT( (*state) [1], osc.envelope );
|
||||
REFLECT( (*state) [2], osc.reg_written [3] );
|
||||
}
|
||||
|
||||
static void reflect_square( apu_state_t::square_t& state, Nes_Square& osc )
|
||||
{
|
||||
reflect_env( &state.env, osc );
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.phase, osc.phase );
|
||||
REFLECT( state.swp_delay, osc.sweep_delay );
|
||||
REFLECT( state.swp_reset, osc.reg_written [1] );
|
||||
}
|
||||
|
||||
static void reflect_triangle( apu_state_t::triangle_t& state, Nes_Triangle& osc )
|
||||
{
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.linear_counter, osc.linear_counter );
|
||||
REFLECT( state.phase, osc.phase );
|
||||
REFLECT( state.linear_mode, osc.reg_written [3] );
|
||||
}
|
||||
|
||||
static void reflect_noise( apu_state_t::noise_t& state, Nes_Noise& osc )
|
||||
{
|
||||
reflect_env( &state.env, osc );
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.length_counter, osc.length_counter );
|
||||
REFLECT( state.shift_reg, osc.noise );
|
||||
}
|
||||
|
||||
static void reflect_dmc( apu_state_t::dmc_t& state, Nes_Dmc& osc )
|
||||
{
|
||||
REFLECT( state.delay, osc.delay );
|
||||
REFLECT( state.remain, osc.length_counter );
|
||||
REFLECT( state.buf, osc.buf );
|
||||
REFLECT( state.bits_remain, osc.bits_remain );
|
||||
REFLECT( state.bits, osc.bits );
|
||||
REFLECT( state.buf_full, osc.buf_full );
|
||||
REFLECT( state.silence, osc.silence );
|
||||
REFLECT( state.irq_flag, osc.irq_flag );
|
||||
if ( mode )
|
||||
state.addr = osc.address | 0x8000;
|
||||
else
|
||||
osc.address = state.addr & 0x7fff;
|
||||
}
|
||||
};
|
||||
|
||||
void Nes_Apu::save_state( apu_state_t* state ) const
|
||||
{
|
||||
for ( int i = 0; i < osc_count * 4; i++ )
|
||||
{
|
||||
int index = i >> 2;
|
||||
state->apu.w40xx [i] = oscs [index]->regs [i & 3];
|
||||
//if ( index < 4 )
|
||||
// state->length_counters [index] = oscs [index]->length_counter;
|
||||
}
|
||||
state->apu.w40xx [0x11] = dmc.dac;
|
||||
|
||||
state->apu.w4015 = osc_enables;
|
||||
state->apu.w4017 = frame_mode;
|
||||
state->apu.frame_delay = frame_delay;
|
||||
state->apu.frame_step = frame;
|
||||
state->apu.irq_flag = irq_flag;
|
||||
|
||||
typedef apu_reflection<1> refl;
|
||||
Nes_Apu& apu = *(Nes_Apu*) this; // const_cast
|
||||
refl::reflect_square ( state->square1, apu.square1 );
|
||||
refl::reflect_square ( state->square2, apu.square2 );
|
||||
refl::reflect_triangle( state->triangle, apu.triangle );
|
||||
refl::reflect_noise ( state->noise, apu.noise );
|
||||
refl::reflect_dmc ( state->dmc, apu.dmc );
|
||||
}
|
||||
|
||||
void Nes_Apu::load_state( apu_state_t const& state )
|
||||
{
|
||||
reset();
|
||||
|
||||
write_register( 0, 0x4017, state.apu.w4017 );
|
||||
write_register( 0, 0x4015, state.apu.w4015 );
|
||||
osc_enables = state.apu.w4015; // DMC clears bit 4
|
||||
|
||||
for ( int i = 0; i < osc_count * 4; i++ )
|
||||
{
|
||||
int n = state.apu.w40xx [i];
|
||||
int index = i >> 2;
|
||||
oscs [index]->regs [i & 3] = n;
|
||||
write_register( 0, 0x4000 + i, n );
|
||||
//if ( index < 4 )
|
||||
// oscs [index]->length_counter = state.length_counters [index];
|
||||
}
|
||||
|
||||
frame_delay = state.apu.frame_delay;
|
||||
frame = state.apu.frame_step;
|
||||
irq_flag = state.apu.irq_flag;
|
||||
|
||||
typedef apu_reflection<0> refl;
|
||||
apu_state_t& st = (apu_state_t&) state; // const_cast
|
||||
refl::reflect_square ( st.square1, square1 );
|
||||
refl::reflect_square ( st.square2, square2 );
|
||||
refl::reflect_triangle( st.triangle, triangle );
|
||||
refl::reflect_noise ( st.noise, noise );
|
||||
refl::reflect_dmc ( st.dmc, dmc );
|
||||
dmc.recalc_irq();
|
||||
|
||||
//force channels to have correct last_amp levels after load state
|
||||
square1.run(last_time, last_time);
|
||||
square2.run(last_time, last_time);
|
||||
triangle.run(last_time, last_time);
|
||||
noise.run(last_time, last_time);
|
||||
dmc.run(last_time, last_time);
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
|
||||
// NES APU state snapshot support
|
||||
|
||||
// Nes_Snd_Emu 0.1.7
|
||||
|
||||
#ifndef APU_STATE_H
|
||||
#define APU_STATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "blargg_common.h"
|
||||
|
||||
struct apu_state_t
|
||||
{
|
||||
typedef uint8_t env_t [3];
|
||||
/*struct env_t {
|
||||
uint8_t delay;
|
||||
uint8_t env;
|
||||
uint8_t written;
|
||||
};*/
|
||||
|
||||
struct apu_t {
|
||||
uint8_t w40xx [0x14]; // $4000-$4013
|
||||
uint8_t w4015; // enables
|
||||
uint8_t w4017; // mode
|
||||
uint16_t frame_delay;
|
||||
uint8_t frame_step;
|
||||
uint8_t irq_flag;
|
||||
} apu;
|
||||
|
||||
struct square_t {
|
||||
uint16_t delay;
|
||||
env_t env;
|
||||
uint8_t length_counter;
|
||||
uint8_t phase;
|
||||
uint8_t swp_delay;
|
||||
uint8_t swp_reset;
|
||||
uint8_t unused2 [1];
|
||||
};
|
||||
|
||||
square_t square1;
|
||||
square_t square2;
|
||||
|
||||
struct triangle_t {
|
||||
uint16_t delay;
|
||||
uint8_t length_counter;
|
||||
uint8_t phase;
|
||||
uint8_t linear_counter;
|
||||
uint8_t linear_mode;
|
||||
} triangle;
|
||||
|
||||
struct noise_t {
|
||||
uint16_t delay;
|
||||
env_t env;
|
||||
uint8_t length_counter;
|
||||
uint16_t shift_reg;
|
||||
} noise;
|
||||
|
||||
struct dmc_t {
|
||||
uint16_t delay;
|
||||
uint16_t remain;
|
||||
uint16_t addr;
|
||||
uint8_t buf;
|
||||
uint8_t bits_remain;
|
||||
uint8_t bits;
|
||||
uint8_t buf_full;
|
||||
uint8_t silence;
|
||||
uint8_t irq_flag;
|
||||
} dmc;
|
||||
|
||||
//uint8_t length_counters [4];
|
||||
|
||||
enum { tag = 0x41505552 }; // 'APUR'
|
||||
void swap();
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (apu_state_t) == 72 );
|
||||
|
||||
#endif
|
|
@ -34,9 +34,6 @@ arithmetic on smaller types. */
|
|||
// In case compiler doesn't support these properly. Used rarely.
|
||||
#define STATIC_CAST(T,expr) static_cast<T> (expr)
|
||||
|
||||
// User configuration can override the above macros if necessary
|
||||
#include "blargg_config.h"
|
||||
|
||||
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||
#ifndef BOOST_STATIC_ASSERT
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// Library configuration. Modify this file as necessary.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
#ifndef HAVE_STDINT_H
|
||||
#define HAVE_STDINT_H
|
||||
#endif
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -1,11 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
// CPU Byte Order Utilities
|
||||
|
||||
// Nes_Emu 0.7.0
|
||||
|
||||
#ifndef BLARGG_ENDIAN
|
||||
#define BLARGG_ENDIAN
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
|
||||
|
@ -105,4 +103,5 @@ inline void set_be( uint32_t* p, unsigned long n ) { SET_BE32( p, n ); }
|
|||
inline unsigned get_be( uint16_t* p ) { return GET_BE16( p ); }
|
||||
inline unsigned long get_be( uint32_t* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
||||
#define SWAP_BE( n ) (void) (set_be( &(n), (n) ))
|
||||
#define SWAP_LE( n ) (void) (set_le( &(n), (n) ))
|
|
@ -1,23 +1,18 @@
|
|||
# quickerNES Core sources
|
||||
|
||||
quickerNESCoreSrc = [
|
||||
'abstract_file.cpp',
|
||||
'Nes_Apu.cpp',
|
||||
'Nes_File.cpp',
|
||||
'Nes_Oscs.cpp',
|
||||
'apu_state.cpp',
|
||||
'Nes_Buffer.cpp',
|
||||
'Nes_Fme7_Apu.cpp',
|
||||
'Nes_Ppu.cpp',
|
||||
'Blip_Buffer.cpp',
|
||||
'Nes_Cart.cpp',
|
||||
'Nes_Mapper.cpp',
|
||||
'Nes_Ppu_Impl.cpp',
|
||||
'Data_Reader.cpp',
|
||||
'Nes_Core.cpp',
|
||||
'Nes_Ppu_Rendering.cpp',
|
||||
'Effects_Buffer.cpp',
|
||||
'Nes_Cpu.cpp',
|
||||
'Nes_State.cpp',
|
||||
'emu2413.cpp',
|
||||
'nes_data.cpp',
|
||||
|
@ -30,6 +25,9 @@ quickerNESCoreSrc = [
|
|||
'Nes_Emu.cpp',
|
||||
'nes_ntsc.cpp',
|
||||
'Nes_Vrc7.cpp',
|
||||
'Nes_Mapper.cpp',
|
||||
'Nes_Core.cpp',
|
||||
'Nes_Cpu.cpp',
|
||||
]
|
||||
|
||||
# quickerNES Core Configuration
|
||||
|
|
|
@ -3,64 +3,8 @@
|
|||
|
||||
#include "nes_data.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
||||
/* Copyright (C) 2004-2006 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 */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
#define SWAP_BE( n ) (void) (set_be( &(n), (n) ))
|
||||
#define SWAP_LE( n ) (void) (set_le( &(n), (n) ))
|
||||
|
||||
void nes_block_t::swap()
|
||||
{
|
||||
SWAP_BE( tag );
|
||||
SWAP_LE( size );
|
||||
}
|
||||
|
||||
void nes_state_t::swap()
|
||||
{
|
||||
SWAP_LE( timestamp );
|
||||
SWAP_LE( frame_count );
|
||||
}
|
||||
|
||||
void cpu_state_t::swap()
|
||||
{
|
||||
SWAP_LE( pc );
|
||||
}
|
||||
|
||||
void ppu_state_t::swap()
|
||||
{
|
||||
SWAP_LE( vram_addr );
|
||||
SWAP_LE( vram_temp );
|
||||
SWAP_LE( decay_low );
|
||||
SWAP_LE( decay_high );
|
||||
}
|
||||
|
||||
void apu_state_t::swap()
|
||||
{
|
||||
SWAP_LE( apu.frame_delay );
|
||||
SWAP_LE( square1.delay );
|
||||
SWAP_LE( square2.delay );
|
||||
SWAP_LE( triangle.delay );
|
||||
SWAP_LE( noise.delay );
|
||||
SWAP_LE( noise.shift_reg );
|
||||
SWAP_LE( dmc.delay );
|
||||
SWAP_LE( dmc.remain );
|
||||
SWAP_LE( dmc.addr );
|
||||
}
|
||||
|
||||
void joypad_state_t::swap()
|
||||
{
|
||||
SWAP_LE( joypad_latches [0] );
|
||||
SWAP_LE( joypad_latches [1] );
|
||||
}
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
// NES data file block formats
|
||||
/* Copyright (C) 2004-2006 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 */
|
||||
|
||||
// Nes_Emu 0.7.0
|
||||
|
||||
#ifndef NES_DATA_H
|
||||
#define NES_DATA_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "apu_state.h"
|
||||
#include "blargg_endian.h"
|
||||
|
||||
typedef long nes_tag_t;
|
||||
|
||||
|
@ -48,7 +56,11 @@ struct nes_block_t
|
|||
uint32_t tag; // ** stored in big-endian
|
||||
uint32_t size;
|
||||
|
||||
void swap();
|
||||
void swap()
|
||||
{
|
||||
SWAP_BE( tag );
|
||||
SWAP_LE( size );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (nes_block_t) == 8 );
|
||||
|
||||
|
@ -63,7 +75,11 @@ struct nes_state_t
|
|||
uint32_t frame_count; // number of frames emulated since power-up
|
||||
|
||||
enum { tag = FOUR_CHAR('TIME') };
|
||||
void swap();
|
||||
void swap()
|
||||
{
|
||||
SWAP_LE( timestamp );
|
||||
SWAP_LE( frame_count );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (nes_state_t) == 8 );
|
||||
|
||||
|
@ -74,7 +90,11 @@ struct joypad_state_t
|
|||
uint8_t unused [3];
|
||||
|
||||
enum { tag = FOUR_CHAR('CTRL') };
|
||||
void swap();
|
||||
void swap()
|
||||
{
|
||||
SWAP_LE( joypad_latches [0] );
|
||||
SWAP_LE( joypad_latches [1] );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (joypad_state_t) == 12 );
|
||||
|
||||
|
@ -104,7 +124,10 @@ struct cpu_state_t
|
|||
uint8_t unused [1];
|
||||
|
||||
enum { tag = FOUR_CHAR('CPUR') };
|
||||
void swap();
|
||||
void swap()
|
||||
{
|
||||
SWAP_LE( pc );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (cpu_state_t) == 8 );
|
||||
|
||||
|
@ -127,7 +150,13 @@ struct ppu_state_t
|
|||
uint8_t unused2[3];
|
||||
|
||||
enum { tag = FOUR_CHAR('PPUR') };
|
||||
void swap();
|
||||
void swap()
|
||||
{
|
||||
SWAP_LE( vram_addr );
|
||||
SWAP_LE( vram_temp );
|
||||
SWAP_LE( decay_low );
|
||||
SWAP_LE( decay_high );
|
||||
}
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (ppu_state_t) == 20 + 0x20 );
|
||||
|
||||
|
@ -151,5 +180,3 @@ struct mmc3_state_t
|
|||
uint8_t irq_flag;
|
||||
};
|
||||
BOOST_STATIC_ASSERT( sizeof (mmc3_state_t) == 15 );
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue