Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Mapper_Fme7.cpp
2 views
1
2
// Sunsoft FME-7 mapper
3
4
// Nes_Emu 0.7.0. http://www.slack.net/~ant/libs/
5
6
#include "Nes_Mapper.h"
7
8
#include "blargg_endian.h"
9
#include "Nes_Fme7_Apu.h"
10
11
/* Copyright (C) 2005 Chris Moeller */
12
/* Copyright (C) 2005-2006 Shay Green. This module is free software; you
13
can redistribute it and/or modify it under the terms of the GNU Lesser
14
General Public License as published by the Free Software Foundation; either
15
version 2.1 of the License, or (at your option) any later version. This
16
module is distributed in the hope that it will be useful, but WITHOUT ANY
17
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
19
more details. You should have received a copy of the GNU Lesser General
20
Public License along with this module; if not, write to the Free Software
21
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22
23
#include "blargg_source.h"
24
25
struct fme7_state_t
26
{
27
// first 16 bytes in register order
28
BOOST::uint8_t regs [13];
29
BOOST::uint8_t irq_mode;
30
BOOST::uint16_t irq_count;
31
32
BOOST::uint8_t command;
33
BOOST::uint8_t irq_pending;
34
fme7_apu_state_t sound_state; // only used when saving/restoring state
35
36
void swap();
37
};
38
BOOST_STATIC_ASSERT( sizeof (fme7_state_t) == 18 + sizeof (fme7_apu_state_t) );
39
40
void fme7_state_t::swap()
41
{
42
set_le16( &irq_count, irq_count );
43
for ( unsigned i = 0; i < sizeof sound_state.delays / sizeof sound_state.delays [0]; i++ )
44
set_le16( &sound_state.delays [i], sound_state.delays [i] );
45
}
46
47
class Mapper_Fme7 : public Nes_Mapper, fme7_state_t {
48
nes_time_t last_time;
49
Nes_Fme7_Apu sound;
50
public:
51
Mapper_Fme7()
52
{
53
fme7_state_t* state = this;
54
register_state( state, sizeof *state );
55
}
56
57
virtual int channel_count() const { return sound.osc_count; }
58
59
virtual void set_channel_buf( int i, Blip_Buffer* b ) { sound.osc_output( i, b ); }
60
61
virtual void set_treble( blip_eq_t const& eq ) { sound.treble_eq( eq ); }
62
63
virtual void reset_state()
64
{
65
regs [8] = 0x40; // wram disabled
66
irq_count = 0xFFFF;
67
sound.reset();
68
}
69
70
virtual void save_state( mapper_state_t& out )
71
{
72
sound.save_state( &sound_state );
73
fme7_state_t::swap();
74
Nes_Mapper::save_state( out );
75
fme7_state_t::swap(); // to do: kind of hacky to swap in place
76
}
77
78
virtual void read_state( mapper_state_t const& in )
79
{
80
Nes_Mapper::read_state( in );
81
fme7_state_t::swap();
82
sound.load_state( sound_state );
83
}
84
85
void write_register( int index, int data );
86
87
virtual void apply_mapping()
88
{
89
last_time = 0;
90
for ( int i = 0; i < (int) sizeof regs; i++ )
91
write_register( i, regs [i] );
92
}
93
94
virtual void run_until( nes_time_t end_time )
95
{
96
int new_count = irq_count - (end_time - last_time);
97
last_time = end_time;
98
99
if ( new_count <= 0 && (irq_mode & 0x81) == 0x81 )
100
irq_pending = true;
101
102
if ( irq_mode & 0x01 )
103
irq_count = new_count & 0xFFFF;
104
}
105
106
virtual nes_time_t next_irq( nes_time_t )
107
{
108
if ( irq_pending )
109
return 0;
110
111
if ( (irq_mode & 0x81) == 0x81 )
112
return last_time + irq_count + 1;
113
114
return no_irq;
115
}
116
117
virtual void end_frame( nes_time_t end_time )
118
{
119
if ( end_time > last_time )
120
run_until( end_time );
121
122
last_time -= end_time;
123
assert( last_time >= 0 );
124
125
sound.end_frame( end_time );
126
}
127
128
void write_irq( nes_time_t, int index, int data );
129
130
virtual void write( nes_time_t time, nes_addr_t addr, int data )
131
{
132
switch ( addr & 0xE000 )
133
{
134
case 0x8000:
135
command = data & 0x0F;
136
break;
137
138
case 0xA000:
139
if ( command < 0x0D )
140
write_register( command, data );
141
else
142
write_irq( time, command, data );
143
break;
144
145
case 0xC000:
146
sound.write_latch( data );
147
break;
148
149
case 0xE000:
150
sound.write_data( time, data );
151
break;
152
}
153
}
154
};
155
156
void Mapper_Fme7::write_irq( nes_time_t time, int index, int data )
157
{
158
run_until( time );
159
switch ( index )
160
{
161
case 0x0D:
162
irq_mode = data;
163
irq_pending = false;
164
irq_changed();
165
break;
166
167
case 0x0E:
168
irq_count = (irq_count & 0xFF00) | data;
169
break;
170
171
case 0x0F:
172
irq_count = data << 8 | (irq_count & 0xFF);
173
break;
174
}
175
176
}
177
178
void Mapper_Fme7::write_register( int index, int data )
179
{
180
regs [index] = data;
181
int prg_bank = index - 0x09;
182
if ( (unsigned) prg_bank < 3 ) // most common
183
{
184
set_prg_bank( 0x8000 | (prg_bank << bank_8k), bank_8k, data );
185
}
186
else if ( index == 0x08 )
187
{
188
enable_sram( (data & 0xC0) == 0xC0 );
189
if ( !(data & 0xC0) )
190
set_prg_bank( 0x6000, bank_8k, data & 0x3F );
191
}
192
else if ( index < 0x08 )
193
{
194
set_chr_bank( index * 0x400, bank_1k, data );
195
}
196
else
197
{
198
assert( index == 0x0C );
199
if ( data & 2 )
200
mirror_single( data & 1 );
201
else if ( data & 1 )
202
mirror_horiz();
203
else
204
mirror_vert();
205
}
206
}
207
208
void register_fme7_mapper();
209
void register_fme7_mapper()
210
{
211
register_mapper<Mapper_Fme7>( 69 );
212
}
213
214
215