Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Nes_Mmc3.cpp
2 views
1
2
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
3
4
#include "Nes_Mapper.h"
5
6
#include <string.h>
7
#include "Nes_Core.h"
8
9
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
10
can redistribute it and/or modify it under the terms of the GNU Lesser
11
General Public License as published by the Free Software Foundation; either
12
version 2.1 of the License, or (at your option) any later version. This
13
module is distributed in the hope that it will be useful, but WITHOUT ANY
14
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
16
more details. You should have received a copy of the GNU Lesser General
17
Public License along with this module; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
20
#include "blargg_source.h"
21
22
// 264 or less breaks Gargoyle's Quest II
23
// 267 or less breaks Magician
24
int const irq_fine_tune = 268;
25
nes_time_t const first_scanline = 20 * Nes_Ppu::scanline_len + irq_fine_tune;
26
nes_time_t const last_scanline = first_scanline + 240 * Nes_Ppu::scanline_len;
27
28
class Mapper_Mmc3 : public Nes_Mapper, mmc3_state_t {
29
nes_time_t next_time;
30
int counter_just_clocked; // used only for debugging
31
public:
32
Mapper_Mmc3()
33
{
34
mmc3_state_t* state = this;
35
register_state( state, sizeof *state );
36
}
37
38
virtual void reset_state()
39
{
40
memcpy( banks, "\0\2\4\5\6\7\0\1", sizeof banks );
41
42
counter_just_clocked = 0;
43
next_time = 0;
44
mirror = 1;
45
if ( cart().mirroring() & 1 )
46
{
47
mirror = 0;
48
//dprintf( "cart specified vertical mirroring\n" );
49
}
50
}
51
52
void update_chr_banks();
53
void update_prg_banks();
54
void write_irq( nes_addr_t addr, int data );
55
void write( nes_time_t, nes_addr_t, int );
56
57
void start_frame() { next_time = first_scanline; }
58
59
virtual void apply_mapping()
60
{
61
write( 0, 0xA000, mirror );
62
write( 0, 0xA001, sram_mode );
63
update_chr_banks();
64
update_prg_banks();
65
start_frame();
66
}
67
68
void clock_counter()
69
{
70
if ( counter_just_clocked )
71
counter_just_clocked--;
72
73
if ( !irq_ctr-- )
74
{
75
irq_ctr = irq_latch;
76
//if ( !irq_latch )
77
//dprintf( "MMC3 IRQ counter reloaded with 0\n" );
78
}
79
80
//dprintf( "%6d MMC3 IRQ clocked\n", time / ppu_overclock );
81
if ( irq_ctr == 0 )
82
{
83
//if ( irq_enabled && !irq_flag )
84
//dprintf( "%6d MMC3 IRQ triggered: %f\n", time / ppu_overclock, time / scanline_len.0 - 20 );
85
irq_flag = irq_enabled;
86
}
87
}
88
89
virtual void run_until( nes_time_t );
90
91
virtual void a12_clocked()
92
{
93
clock_counter();
94
if ( irq_enabled )
95
irq_changed();
96
}
97
98
virtual void end_frame( nes_time_t end_time )
99
{
100
run_until( end_time );
101
start_frame();
102
}
103
104
virtual nes_time_t next_irq( nes_time_t present )
105
{
106
run_until( present );
107
108
if ( !irq_enabled )
109
return no_irq;
110
111
if ( irq_flag )
112
return 0;
113
114
if ( !ppu_enabled() )
115
return no_irq;
116
117
int remain = irq_ctr - 1;
118
if ( remain < 0 )
119
remain = irq_latch;
120
121
assert( remain >= 0 );
122
123
long time = remain * 341L + next_time;
124
if ( time > last_scanline )
125
return no_irq;
126
127
return time / ppu_overclock + 1;
128
}
129
};
130
131
void Mapper_Mmc3::run_until( nes_time_t end_time )
132
{
133
bool bg_enabled = ppu_enabled();
134
135
end_time *= ppu_overclock;
136
while ( next_time < end_time && next_time <= last_scanline )
137
{
138
if ( bg_enabled )
139
clock_counter();
140
next_time += Nes_Ppu::scanline_len;
141
}
142
}
143
144
void Mapper_Mmc3::update_chr_banks()
145
{
146
int chr_xor = (mode >> 7 & 1) * 0x1000;
147
set_chr_bank( 0x0000 ^ chr_xor, bank_2k, banks [0] >> 1 );
148
set_chr_bank( 0x0800 ^ chr_xor, bank_2k, banks [1] >> 1 );
149
set_chr_bank( 0x1000 ^ chr_xor, bank_1k, banks [2] );
150
set_chr_bank( 0x1400 ^ chr_xor, bank_1k, banks [3] );
151
set_chr_bank( 0x1800 ^ chr_xor, bank_1k, banks [4] );
152
set_chr_bank( 0x1c00 ^ chr_xor, bank_1k, banks [5] );
153
}
154
155
void Mapper_Mmc3::update_prg_banks()
156
{
157
set_prg_bank( 0xA000, bank_8k, banks [7] );
158
nes_addr_t addr = 0x8000 + 0x4000 * (mode >> 6 & 1);
159
set_prg_bank( addr, bank_8k, banks [6] );
160
set_prg_bank( addr ^ 0x4000, bank_8k, last_bank - 1 );
161
}
162
163
void Mapper_Mmc3::write_irq( nes_addr_t addr, int data )
164
{
165
switch ( addr & 0xE001 )
166
{
167
case 0xC000:
168
irq_latch = data;
169
break;
170
171
case 0xC001:
172
if ( counter_just_clocked == 1 )
173
dprintf( "MMC3 IRQ counter pathological behavior triggered\n" );
174
counter_just_clocked = 2;
175
irq_ctr = 0;
176
break;
177
178
case 0xE000:
179
irq_flag = false;
180
irq_enabled = false;
181
break;
182
183
case 0xE001:
184
irq_enabled = true;
185
break;
186
}
187
if ( irq_enabled )
188
irq_changed();
189
}
190
191
void Mapper_Mmc3::write( nes_time_t time, nes_addr_t addr, int data )
192
{
193
check( !(addr & ~0xe001) ); // writes to mirrored registers are rare
194
//dprintf( "%6d %02X->%04X\n", time, data, addr );
195
196
switch ( addr & 0xE001 )
197
{
198
case 0x8000: {
199
int changed = mode ^ data;
200
mode = data;
201
// avoid unnecessary bank updates
202
if ( changed & 0x80 )
203
update_chr_banks();
204
if ( changed & 0x40 )
205
update_prg_banks();
206
break;
207
}
208
209
case 0x8001: {
210
int bank = mode & 7;
211
banks [bank] = data;
212
if ( bank < 6 )
213
update_chr_banks();
214
else
215
update_prg_banks();
216
break;
217
}
218
219
case 0xA000:
220
mirror = data;
221
if ( !(cart().mirroring() & 0x08) )
222
{
223
if ( mirror & 1 )
224
mirror_horiz();
225
else
226
mirror_vert();
227
}
228
break;
229
230
case 0xA001:
231
sram_mode = data;
232
//dprintf( "%02X->%04X\n", data, addr );
233
234
// Startropics 1 & 2 use MMC6 and always enable low 512 bytes of SRAM
235
if ( (data & 0x3F) == 0x30 )
236
enable_sram( true );
237
else
238
enable_sram( data & 0x80, data & 0x40 );
239
break;
240
241
default:
242
run_until( time );
243
write_irq( addr, data );
244
break;
245
}
246
}
247
248
Nes_Mapper* Nes_Mapper::make_mmc3()
249
{
250
return BLARGG_NEW Mapper_Mmc3;
251
}
252
253
254