summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6pre/gme/Nsf_Impl.h
diff options
context:
space:
mode:
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.h189
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