1// NES video game console emulator with snapshot support23// Nes_Emu 0.7.045#ifndef NES_EMU_H6#define NES_EMU_H78#include "blargg_common.h"9#include "Multi_Buffer.h"10#include "Nes_Cart.h"11#include "Nes_Core.h"12class Nes_State;1314// Register optional mappers included with Nes_Emu15void register_optional_mappers();1617extern const char unsupported_mapper []; // returned when cartridge uses unsupported mapper1819class Nes_Emu {20public:21Nes_Emu();22virtual ~Nes_Emu();2324// Basic setup2526// Load iNES file into emulator and clear recording27blargg_err_t load_ines( Auto_File_Reader );2829// Set sample rate for sound generation30blargg_err_t set_sample_rate( long );3132// Size and depth of graphics buffer required for rendering. Note that this33// is larger than the actual image, with a temporary area around the edge34// that gets filled with junk. Its height is many times larger in Nes_Recorder35// to allow caching of multiple images.36enum { buffer_width = Nes_Ppu::buffer_width };37int buffer_height() const { return buffer_height_; }38enum { bits_per_pixel = 8 };3940private:41// Set graphics buffer to render pixels to. Pixels points to top-left pixel and42// row_bytes is the number of bytes to get to the next line (positive or negative).43void set_pixels( void* pixels, long row_bytes );44public:4546// Size of image generated in graphics buffer47enum { image_width = 256 };48enum { image_height = 240 };4950// Basic emulation5152// Emulate one video frame using joypad1 and joypad2 as input. Afterwards, image53// and sound are available for output using the accessors below.54// A connected controller should have 0xffffff** in the high bits, or 0x000000**55// if emulating an incorrectly made third party controller. A disconnected controller56// should be 0x00000000 exactly.57virtual blargg_err_t emulate_frame( uint32_t joypad1, uint32_t joypad2 );5859// Maximum size of palette that can be generated60enum { max_palette_size = 256 };6162// Result of current frame63struct frame_t64{65int joypad_read_count; // number of times joypads were strobed (read)66int burst_phase; // NTSC burst phase for frame (0, 1, or 2)6768int sample_count; // number of samples (always a multiple of chan_count)69int chan_count; // 1: mono, 2: stereo7071int top; // top-left position of image in graphics buffer72enum { left = 8 };73unsigned char* pixels; // pointer to top-left pixel of image74long pitch; // number of bytes to get to next row of image7576int palette_begin; // first host palette entry, as set by set_palette_range()77int palette_size; // number of entries used for current frame78short palette [max_palette_size]; // [palette_begin to palette_begin+palette_size-1]79};80frame_t const& frame() const { return *frame_; }8182// Read samples for the current frame. Returns number of samples read into buffer.83// Currently all samples must be read in one call.84virtual long read_samples( short* out, long max_samples );8586// Additional features8788// Use already-loaded cartridge. Retains pointer, so it must be kept around until89// closed. A cartridge can be shared among multiple emulators. After opening,90// cartridge's CHR data shouldn't be modified since a copy is cached internally.91blargg_err_t set_cart( Nes_Cart const* );9293// Pointer to current cartridge, or NULL if none is loaded94Nes_Cart const* cart() const { return emu.cart; }9596// Free any memory and close cartridge, if one was currently open. A new cartridge97// must be opened before further emulation can take place.98void close();99100// Emulate powering NES off and then back on. If full_reset is false, emulates101// pressing the reset button only, which doesn't affect memory, otherwise102// emulates powering system off then on.103virtual void reset( bool full_reset = true, bool erase_battery_ram = false );104105// Number of undefined CPU instructions encountered. Cleared after reset() and106// load_state(). A non-zero value indicates that cartridge is probably107// incompatible.108unsigned long error_count() const { return emu.error_count; }109110// Sound111112// Set sample rate and use a custom sound buffer instead of the default113// mono buffer, i.e. Nes_Buffer, Effects_Buffer, etc..114blargg_err_t set_sample_rate( long rate, Multi_Buffer* );115116// Adjust effective frame rate by changing how many samples are generated each frame.117// Allows fine tuning of frame rate to improve synchronization.118void set_frame_rate( double rate );119120// Number of sound channels for current cartridge121int channel_count() const { return channel_count_; }122123// Frequency equalizer parameters124struct equalizer_t {125double treble; // 5.0 = extra-crisp, -200.0 = muffled126long bass; // 0 = deep, 20000 = tinny127};128129// Current frequency equalization130equalizer_t const& equalizer() const { return equalizer_; }131132// Change frequency equalization133void set_equalizer( equalizer_t const& );134135// Equalizer presets136static equalizer_t const nes_eq; // NES137static equalizer_t const famicom_eq; // Famicom138static equalizer_t const tv_eq; // TV speaker139140// File save/load141142// Save emulator state143void save_state( Nes_State* s ) const { emu.save_state( s ); }144blargg_err_t save_state( Auto_File_Writer ) const;145146// Load state into emulator147void load_state( Nes_State const& );148blargg_err_t load_state( Auto_File_Reader );149150// True if current cartridge claims it uses battery-backed memory151bool has_battery_ram() const { return cart()->has_battery_ram(); }152153// Save current battery RAM154blargg_err_t save_battery_ram( Auto_File_Writer );155156// Load battery RAM from file. Best called just after reset() or loading cartridge.157blargg_err_t load_battery_ram( Auto_File_Reader );158159// Graphics160161// Number of frames generated per second162enum { frame_rate = 60 };163164// Size of fixed NES color table (including the 8 color emphasis modes)165enum { color_table_size = 8 * 64 };166167// NES color lookup table based on standard NTSC TV decoder. Use nes_ntsc.h to168// generate a palette with custom parameters.169struct rgb_t { unsigned char red, green, blue; };170static rgb_t const nes_colors [color_table_size];171172// Hide/show/enhance sprites. Sprite mode does not affect emulation accuracy.173enum sprite_mode_t {174sprites_hidden = 0,175sprites_visible = 8, // limit of 8 sprites per scanline as on NES (default)176sprites_enhanced = 64 // unlimited sprites per scanline (no flickering)177};178void set_sprite_mode( sprite_mode_t n ) { emu.ppu.sprite_limit = n; }179180// Set range of host palette entries to use in graphics buffer; default uses181// all of them. Begin will be rounded up to next multiple of palette_alignment.182// Use frame().palette_begin to find the adjusted beginning entry used.183enum { palette_alignment = 64 };184void set_palette_range( int begin, int end = 256 );185186// Access to emulated memory, for viewer/cheater/debugger187188// CHR189byte const* chr_mem();190long chr_size() const;191void write_chr( void const*, long count, long offset );192193// Nametable194byte* nametable_mem() { return emu.ppu.impl->nt_ram; }195long nametable_size() const { return 0x1000; }196197// Built-in 2K memory198enum { low_mem_size = 0x800 };199byte* low_mem() { return emu.low_mem; }200201// Optional 8K memory202enum { high_mem_size = 0x2000 };203byte* high_mem() { return emu.impl->sram; }204205// Prg peek/poke for debuggin206byte peek_prg(nes_addr_t addr) const { return *static_cast<Nes_Cpu>(emu).get_code(addr); }207void poke_prg(nes_addr_t addr, byte value) { *static_cast<Nes_Cpu>(emu).get_code(addr) = value; }208byte peek_ppu(int addr) { return emu.ppu.peekaddr(addr); }209210void get_regs(unsigned int *dest) const;211212byte get_ppu2000() const { return emu.ppu.w2000; }213byte* pal_mem() { return emu.ppu.palette; }214byte* oam_mem() { return emu.ppu.spr_ram; }215216void set_tracecb(void (*cb)(unsigned int *dest)) { emu.set_tracecb(cb); }217218// End of public interface219public:220blargg_err_t set_sample_rate( long rate, class Nes_Buffer* );221blargg_err_t set_sample_rate( long rate, class Nes_Effects_Buffer* );222void irq_changed() { emu.irq_changed(); }223private:224friend class Nes_Recorder;225226frame_t* frame_;227int buffer_height_;228bool fade_sound_in;229bool fade_sound_out;230virtual blargg_err_t init_();231232virtual void loading_state( Nes_State const& ) { }233void load_state( Nes_State_ const& );234void save_state( Nes_State_* s ) const { emu.save_state( s ); }235int joypad_read_count() const { return emu.joypad_read_count; }236long timestamp() const { return emu.nes.frame_count; }237void set_timestamp( long t ) { emu.nes.frame_count = t; }238239private:240// noncopyable241Nes_Emu( const Nes_Emu& );242Nes_Emu& operator = ( const Nes_Emu& );243244// sound245Multi_Buffer* default_sound_buf;246Multi_Buffer* sound_buf;247unsigned sound_buf_changed_count;248Silent_Buffer silent_buffer;249equalizer_t equalizer_;250int channel_count_;251bool sound_enabled;252void enable_sound( bool );253void clear_sound_buf();254void fade_samples( blip_sample_t*, int size, int step );255256char* host_pixel_buff;257char* host_pixels;258int host_palette_size;259frame_t single_frame;260Nes_Cart private_cart;261Nes_Core emu; // large; keep at end262263bool init_called;264blargg_err_t auto_init();265};266267inline void Nes_Emu::set_pixels( void* p, long n )268{269host_pixels = (char*) p + n;270emu.ppu.host_row_bytes = n;271}272273inline byte const* Nes_Emu::chr_mem()274{275return cart()->chr_size() ? (byte*) cart()->chr() : emu.ppu.impl->chr_ram;276}277278inline long Nes_Emu::chr_size() const279{280return cart()->chr_size() ? cart()->chr_size() : emu.ppu.chr_addr_size;281}282283#endif284285286