diff options
Diffstat (limited to 'plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h')
-rw-r--r-- | plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h b/plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h new file mode 100644 index 00000000..d7c5ad4f --- /dev/null +++ b/plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h @@ -0,0 +1,189 @@ +// Loads NSF file and emulates CPU and RAM, no sound chips + +// Game_Music_Emu 0.6-pre +#ifndef NSF_IMPL_H +#define NSF_IMPL_H + +#include "Gme_Loader.h" +#include "Nes_Cpu.h" +#include "Rom_Data.h" +#include "Nes_Apu.h" + +// NSF file header +struct nsf_header_t +{ + typedef unsigned char byte; + enum { size = 0x80 }; + + char tag [ 5]; + byte vers; + byte track_count; + byte first_track; + byte load_addr [ 2]; + byte init_addr [ 2]; + byte play_addr [ 2]; + char game [32]; // NOT null-terminated if 32 chars in length + char author [32]; + char copyright [32]; + byte ntsc_speed [ 2]; + byte banks [ 8]; + byte pal_speed [ 2]; + byte speed_flags; + byte chip_flags; + byte unused [ 4]; + + // Sound chip masks + enum { + vrc6_mask = 1 << 0, + vrc7_mask = 1 << 1, + fds_mask = 1 << 2, + mmc5_mask = 1 << 3, + namco_mask = 1 << 4, + fme7_mask = 1 << 5, + all_mask = (1 << 6) - 1 + }; + + // True if header has proper NSF file signature + bool valid_tag() const; + + // True if file supports only PAL speed + bool pal_only() const { return (speed_flags & 3) == 1; } + + // Clocks per second + double clock_rate() const; + + // Clocks between calls to play routine + int play_period() const; +}; + +/* Loads NSF file into memory, then emulates CPU, RAM, and ROM. +Non-memory accesses are routed through cpu_read() and cpu_write(). */ +class Nsf_Impl : public Gme_Loader { +public: + + // Sound chip + Nes_Apu* nes_apu() { return &apu; } + + // Starts track, where 0 is the first + virtual blargg_err_t start_track( int ); + + // Emulates to at least time t, then begins new time frame at + // time t. Might emulate a few clocks extra, so after returning, + // time() may not be zero. + typedef int time_t; // clock count + virtual void end_frame( time_t n ); + +// Finer control + + // Header for currently loaded file + typedef nsf_header_t header_t; + header_t const& header() const { return header_; } + + // Sets clocks between calls to play routine to p + 1/2 clock + void set_play_period( int p ) { play_period = p; } + + // Time play routine will next be called + time_t play_time() const { return next_play; } + + // Emulates to at least time t. Might emulate a few clocks extra. + virtual void run_until( time_t t ); + + // Time emulated to + time_t time() const { return cpu.time(); } + +protected: +// Nsf_Core use + + typedef int addr_t; + + // Called for unmapped accesses. Default just prints info if debugging. + virtual void unmapped_write( addr_t, int data ); + virtual int unmapped_read( addr_t ); + + // Override in derived class + // Bank writes and RAM at 0-$7FF and $6000-$7FFF are handled internally + virtual int cpu_read( addr_t a ) { return unmapped_read( a ); } + virtual void cpu_write( addr_t a, int data ){ unmapped_write( a, data ); } + + // Reads byte as CPU would when executing code. Only works for RAM/ROM, + // NOT I/O like sound chips. + int read_code( addr_t addr ) const; + +// Debugger services + + enum { mem_size = 0x10000 }; + + // CPU sits here when waiting for next call to play routine + enum { idle_addr = 0x5FF6 }; + + Nes_Cpu cpu; + + // Runs CPU to at least time t and returns false, or returns true + // if it encounters illegal instruction (halt). + virtual bool run_cpu_until( time_t t ); + + // CPU calls through to these to access memory (except instructions) + int read_mem( addr_t ); + void write_mem( addr_t, int ); + + // Address of play routine + addr_t play_addr() const { return get_addr( header_.play_addr ); } + + // Same as run_until, except emulation stops for any event (routine returned, + // play routine called, illegal instruction). + void run_once( time_t ); + + // Make a note of event + virtual void special_event( const char str [] ); + + +// Implementation +public: + Nsf_Impl(); + ~Nsf_Impl(); + +protected: + virtual blargg_err_t load_( Data_Reader& ); + virtual void unload(); + +private: + enum { low_ram_size = 0x800 }; + enum { fdsram_size = 0x6000 }; + enum { sram_size = 0x2000 }; + enum { unmapped_size= Nes_Cpu::page_size + 8 }; + enum { fds_banks = 2 }; + enum { bank_count = fds_banks + 8 }; + enum { banks_addr = idle_addr }; + enum { sram_addr = 0x6000 }; + + blargg_vector<byte> high_ram; + Rom_Data rom; + + // Play routine timing + time_t next_play; + time_t play_period; + int play_extra; + int play_delay; + Nes_Cpu::registers_t saved_state; // of interrupted init routine + + // Large objects after others + header_t header_; + Nes_Apu apu; + byte low_ram [low_ram_size]; + + // Larger RAM areas allocated separately + enum { fdsram_offset = sram_size + unmapped_size }; + byte* sram() { return high_ram.begin(); } + byte* unmapped_code() { return &high_ram [sram_size]; } + byte* fdsram() { return &high_ram [fdsram_offset]; } + int fds_enabled() const { return header_.chip_flags & header_t::fds_mask; } + + void map_memory(); + void write_bank( int index, int data ); + void jsr_then_stop( byte const addr [] ); + void push_byte( int ); + static addr_t get_addr( byte const [] ); + static int pcm_read( void*, int ); +}; + +#endif |