1
2 // NES mapper interface
3
4 // Nes_Emu 0.7.0
5
6 #ifndef NES_MAPPER
7 #define NES_MAPPER
8
9 #include "Nes_Cart.h"
10 #include "Nes_Cpu.h"
11 #include "nes_data.h"
12 #include "Nes_Core.h"
13 class Blip_Buffer;
14 class blip_eq_t;
15 class Nes_Core;
16
17 class Nes_Mapper {
18 public:
19 // Register function that creates mapper for given code.
20 typedef Nes_Mapper* (*creator_func_t)();
21 static void register_mapper( int code, creator_func_t );
22
23 // Register optional mappers included with Nes_Emu
24 void register_optional_mappers();
25
26 // Create mapper appropriate for cartridge. Returns NULL if it uses unsupported mapper.
27 static Nes_Mapper* create( Nes_Cart const*, Nes_Core* );
28
29 virtual ~Nes_Mapper();
30
31 // Reset mapper to power-up state.
32 virtual void reset();
33
34 // Save snapshot of mapper state. Default saves registered state.
35 virtual void save_state( mapper_state_t& );
36
37 // Resets mapper, loads state, then applies it
38 virtual void load_state( mapper_state_t const& );
39
40 // I/O
41
42 // Read from memory
43 virtual int read( nes_time_t, nes_addr_t );
44
45 // Write to memory
46 virtual void write( nes_time_t, nes_addr_t, int data ) = 0;
47
48 // Write to memory below 0x8000 (returns false if mapper didn't handle write)
49 virtual bool write_intercepted( nes_time_t, nes_addr_t, int data );
50
51 // Timing
52
53 // Time returned when current mapper state won't ever cause an IRQ
54 enum { no_irq = LONG_MAX / 2 };
55
56 // Time next IRQ will occur at
57 virtual nes_time_t next_irq( nes_time_t present );
58
59 // Run mapper until given time
60 virtual void run_until( nes_time_t );
61
62 // End video frame of given length
63 virtual void end_frame( nes_time_t length );
64
65 // Sound
66
67 // Number of sound channels
68 virtual int channel_count() const;
69
70 // Set sound buffer for channel to output to, or NULL to silence channel.
71 virtual void set_channel_buf( int index, Blip_Buffer* );
72
73 // Set treble equalization
74 virtual void set_treble( blip_eq_t const& );
75
76 // Misc
77
78 // Called when bit 12 of PPU's VRAM address changes from 0 to 1 due to
79 // $2006 and $2007 accesses (but not due to PPU scanline rendering).
80 virtual void a12_clocked();
81
82 protected:
83 // Services provided for derived mapper classes
84 Nes_Mapper();
85
86 // Register state data to automatically save and load. Be sure the binary
87 // layout is suitable for use in a file, including any byte-order issues.
88 // Automatically cleared to zero by default reset().
89 void register_state( void*, unsigned );
90
91 // Enable 8K of RAM at 0x6000-0x7FFF, optionally read-only.
92 void enable_sram( bool enabled = true, bool read_only = false );
93
94 // Cause CPU writes within given address range to call mapper's write() function.
95 // Might map a larger address range, which the mapper can ignore and pass to
96 // Nes_Mapper::write(). The range 0x8000-0xffff is always intercepted by the mapper.
97 void intercept_writes( nes_addr_t addr, unsigned size );
98
99 // Cause CPU reads within given address range to call mapper's read() function.
100 // Might map a larger address range, which the mapper can ignore and pass to
101 // Nes_Mapper::read(). CPU opcode/operand reads and low-memory reads always
102 // go directly to memory and cannot be intercepted.
103 void intercept_reads( nes_addr_t addr, unsigned size );
104
105 // Bank sizes for mapping
106 enum bank_size_t { // 1 << bank_Xk = X * 1024
107 bank_1k = 10,
108 bank_2k = 11,
109 bank_4k = 12,
110 bank_8k = 13,
111 bank_16k = 14,
112 bank_32k = 15
113 };
114
115 // Index of last PRG/CHR bank. Last_bank selects last bank, last_bank - 1
116 // selects next-to-last bank, etc.
117 enum { last_bank = -1 };
118
119 // Map 'size' bytes from 'PRG + bank * size' to CPU address space starting at 'addr'
120 void set_prg_bank( nes_addr_t addr, bank_size_t size, int bank );
121
122 // Map 'size' bytes from 'CHR + bank * size' to PPU address space starting at 'addr'
123 void set_chr_bank( nes_addr_t addr, bank_size_t size, int bank );
124 void set_chr_bank_ex( nes_addr_t addr, bank_size_t size, int bank );
125
126 // Set PPU mirroring. All mappings implemented using mirror_manual().
127 void mirror_manual( int page0, int page1, int page2, int page3 );
128 void mirror_single( int page );
129 void mirror_horiz( int page = 0 );
130 void mirror_vert( int page = 0 );
131 void mirror_full();
132
133 // True if PPU rendering is enabled. Some mappers watch PPU memory accesses to determine
134 // when scanlines occur, and can only do this when rendering is enabled.
135 bool ppu_enabled() const;
136
137 // Cartridge being emulated
cart()138 Nes_Cart const& cart() const { return *cart_; }
139
140 // Must be called when next_irq()'s return value is earlier than previous,
141 // current CPU run can be stopped earlier. Best to call whenever time may
142 // have changed (no performance impact if called even when time didn't change).
143 void irq_changed();
144
145 // Handle data written to mapper that doesn't handle bus conflict arising due to
146 // PRG also reading data. Returns data that mapper should act as if were
147 // written. Currently always returns 'data' and just checks that data written is
148 // the same as byte in PRG at same address and writes debug message if it doesn't.
149 int handle_bus_conflict( nes_addr_t addr, int data );
150
151 // Reference to emulator that uses this mapper.
emu()152 Nes_Core& emu() const { return *emu_; }
153
154 protected:
155 // Services derived classes provide
156
157 // Read state from snapshot. Default reads data into registered state, then calls
158 // apply_mapping().
159 virtual void read_state( mapper_state_t const& );
160
161 // Apply current mapping state to hardware. Called after reading mapper state
162 // from a snapshot.
163 virtual void apply_mapping() = 0;
164
165 // Called by default reset() before apply_mapping() is called.
reset_state()166 virtual void reset_state() { }
167
168 // End of general interface
169 private:
170 Nes_Core* emu_;
171 void* state;
172 unsigned state_size;
173 Nes_Cart const* cart_;
174
175 void default_reset_state();
176
177 struct mapping_t {
178 int code;
179 Nes_Mapper::creator_func_t func;
180 };
181 static mapping_t mappers [];
182 static creator_func_t get_mapper_creator( int code );
183
184 // built-in mappers
185 static Nes_Mapper* make_nrom();
186 static Nes_Mapper* make_unrom();
187 static Nes_Mapper* make_aorom();
188 static Nes_Mapper* make_cnrom();
189 static Nes_Mapper* make_mmc1();
190 static Nes_Mapper* make_mmc3();
191 };
192
193 template<class T>
194 struct register_mapper {
register_mapperregister_mapper195 /*void*/ register_mapper( int code ) { Nes_Mapper::register_mapper( code, create ); }
createregister_mapper196 static Nes_Mapper* create() { return BLARGG_NEW T; }
197 };
198
199 #ifdef NDEBUG
handle_bus_conflict(nes_addr_t addr,int data)200 inline int Nes_Mapper::handle_bus_conflict( nes_addr_t addr, int data ) { return data; }
201 #endif
202
mirror_horiz(int p)203 inline void Nes_Mapper::mirror_horiz( int p ) { mirror_manual( p, p, p ^ 1, p ^ 1 ); }
mirror_vert(int p)204 inline void Nes_Mapper::mirror_vert( int p ) { mirror_manual( p, p ^ 1, p, p ^ 1 ); }
mirror_single(int p)205 inline void Nes_Mapper::mirror_single( int p ) { mirror_manual( p, p, p, p ); }
mirror_full()206 inline void Nes_Mapper::mirror_full() { mirror_manual( 0, 1, 2, 3 ); }
207
register_state(void * p,unsigned s)208 inline void Nes_Mapper::register_state( void* p, unsigned s )
209 {
210 state = p;
211 state_size = s;
212 }
213
write_intercepted(nes_time_t,nes_addr_t,int)214 inline bool Nes_Mapper::write_intercepted( nes_time_t, nes_addr_t, int ) { return false; }
215
read(nes_time_t,nes_addr_t)216 inline int Nes_Mapper::read( nes_time_t, nes_addr_t ) { return -1; } // signal to caller
217
intercept_reads(nes_addr_t addr,unsigned size)218 inline void Nes_Mapper::intercept_reads( nes_addr_t addr, unsigned size )
219 {
220 emu().add_mapper_intercept( addr, size, true, false );
221 }
222
intercept_writes(nes_addr_t addr,unsigned size)223 inline void Nes_Mapper::intercept_writes( nes_addr_t addr, unsigned size )
224 {
225 emu().add_mapper_intercept( addr, size, false, true );
226 }
227
enable_sram(bool enabled,bool read_only)228 inline void Nes_Mapper::enable_sram( bool enabled, bool read_only )
229 {
230 emu_->enable_sram( enabled, read_only );
231 }
232
233 #endif
234