1
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
5
#include "blargg_endian.h"
8
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9
can redistribute it and/or modify it under the terms of the GNU Lesser
10
General Public License as published by the Free Software Foundation; either
11
version 2.1 of the License, or (at your option) any later version. This
12
module is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15
details. You should have received a copy of the GNU Lesser General Public
16
License along with this module; if not, write to the Free Software Foundation,
17
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
19
#include "blargg_source.h"
21
Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000 };
22
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 300 };
26
set_type( gme_gbs_type );
28
static const char* const names [Gb_Apu::osc_count] = {
29
"Square 1", "Square 2", "Wave", "Noise"
31
set_voice_names( names );
33
static int const types [Gb_Apu::osc_count] = {
34
wave_type | 1, wave_type | 2, wave_type | 0, mixed_type | 0
36
set_voice_types( types );
38
set_silence_lookahead( 6 );
39
set_max_initial_silence( 21 );
42
static equalizer_t const eq = { -1.0, 120 };
46
Gbs_Emu::~Gbs_Emu() { }
48
void Gbs_Emu::unload()
56
static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out )
58
GME_COPY_FIELD( h, out, game );
59
GME_COPY_FIELD( h, out, author );
60
GME_COPY_FIELD( h, out, copyright );
63
blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const
65
copy_gbs_fields( header_, out );
69
static blargg_err_t check_gbs_header( void const* header )
71
if ( memcmp( header, "GBS", 3 ) )
72
return gme_wrong_file_type;
76
struct Gbs_File : Gme_Info_
80
Gbs_File() { set_type( gme_gbs_type ); }
82
blargg_err_t load_( Data_Reader& in )
84
blargg_err_t err = in.read( &h, Gbs_Emu::header_size );
86
return (err == in.eof_error ? gme_wrong_file_type : err);
88
set_track_count( h.track_count );
89
return check_gbs_header( &h );
92
blargg_err_t track_info_( track_info_t* out, int ) const
94
copy_gbs_fields( h, out );
99
static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; }
100
static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
102
gme_type_t_ const gme_gbs_type [1] = { "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 };
106
blargg_err_t Gbs_Emu::load_( Data_Reader& in )
108
assert( offsetof (header_t,copyright [32]) == header_size );
109
RETURN_ERR( rom.load( in, header_size, &header_, 0 ) );
111
set_track_count( header_.track_count );
112
RETURN_ERR( check_gbs_header( &header_ ) );
114
if ( header_.vers != 1 )
115
set_warning( "Unknown file version" );
117
if ( header_.timer_mode & 0x78 )
118
set_warning( "Invalid timer mode" );
120
unsigned load_addr = get_le16( header_.load_addr );
121
if ( (header_.load_addr [1] | header_.init_addr [1] | header_.play_addr [1]) > 0x7F ||
123
set_warning( "Invalid load/init/play address" );
125
set_voice_count( Gb_Apu::osc_count );
127
apu.volume( gain() );
129
return setup_buffer( 4194304 );
132
void Gbs_Emu::update_eq( blip_eq_t const& eq )
137
void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
139
apu.osc_output( i, c, l, r );
144
// see gb_cpu_io.h for read/write functions
146
void Gbs_Emu::set_bank( int n )
148
blargg_long addr = rom.mask_addr( n * (blargg_long) bank_size );
149
if ( addr == 0 && rom.size() > bank_size )
151
// TODO: what is the correct behavior? Current Game & Watch Gallery
152
// rip requires that this have no effect or set to bank 1.
153
//dprintf( "Selected ROM bank 0\n" );
157
cpu::map_code( bank_size, bank_size, rom.at_addr( addr ) );
160
void Gbs_Emu::update_timer()
162
if ( header_.timer_mode & 0x04 )
164
static byte const rates [4] = { 10, 4, 6, 8 };
165
int shift = rates [ram [hi_page + 7] & 3] - (header_.timer_mode >> 7);
166
play_period = (256L - ram [hi_page + 6]) << shift;
170
play_period = 70224; // 59.73 Hz
172
if ( tempo() != 1.0 )
173
play_period = blip_time_t (play_period / tempo());
176
static BOOST::uint8_t const sound_data [Gb_Apu::register_count] = {
177
0x80, 0xBF, 0x00, 0x00, 0xBF, // square 1
178
0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2
179
0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave
180
0x00, 0xFF, 0x00, 0x00, 0xBF, // noise
181
0x77, 0xF3, 0xF1, // vin/volume, status, power mode
182
0, 0, 0, 0, 0, 0, 0, 0, 0, // unused
183
0xAC, 0xDD, 0xDA, 0x48, 0x36, 0x02, 0xCF, 0x16, // waveform data
184
0x2C, 0x04, 0xE5, 0x2C, 0xAC, 0xDD, 0xDA, 0x48
187
void Gbs_Emu::cpu_jsr( gb_addr_t addr )
189
check( cpu::r.sp == get_le16( header_.stack_ptr ) );
191
cpu_write( --cpu::r.sp, idle_addr >> 8 );
192
cpu_write( --cpu::r.sp, idle_addr&0xFF );
195
void Gbs_Emu::set_tempo_( double t )
201
blargg_err_t Gbs_Emu::start_track_( int track )
203
RETURN_ERR( Classic_Emu::start_track_( track ) );
205
memset( ram, 0, 0x4000 );
206
memset( ram + 0x4000, 0xFF, 0x1F80 );
207
memset( ram + 0x5F80, 0, sizeof ram - 0x5F80 );
208
ram [hi_page] = 0; // joypad reads back as 0
211
for ( int i = 0; i < (int) sizeof sound_data; i++ )
212
apu.write_register( 0, i + apu.start_addr, sound_data [i] );
214
cpu::reset( rom.unmapped() );
216
unsigned load_addr = get_le16( header_.load_addr );
217
cpu::rst_base = load_addr;
218
rom.set_addr( load_addr );
220
cpu::map_code( ram_addr, 0x10000 - ram_addr, ram );
221
cpu::map_code( 0, bank_size, rom.at_addr( 0 ) );
222
set_bank( rom.size() > bank_size );
224
ram [hi_page + 6] = header_.timer_modulo;
225
ram [hi_page + 7] = header_.timer_mode;
227
next_play = play_period;
230
cpu::r.pc = idle_addr;
231
cpu::r.sp = get_le16( header_.stack_ptr );
233
cpu_jsr( get_le16( header_.init_addr ) );
238
blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int )
241
while ( cpu_time < duration )
243
long count = duration - cpu_time;
245
bool result = cpu::run( count );
246
cpu_time -= cpu::remain();
250
if ( cpu::r.pc == idle_addr )
252
if ( next_play > duration )
258
if ( cpu_time < next_play )
259
cpu_time = next_play;
260
next_play += play_period;
261
cpu_jsr( get_le16( header_.play_addr ) );
262
GME_FRAME_HOOK( this );
263
// TODO: handle timer rates different than 60 Hz
265
else if ( cpu::r.pc > 0xFFFF )
267
dprintf( "PC wrapped around\n" );
272
set_warning( "Emulation error (illegal/unsupported instruction)" );
273
dprintf( "Bad opcode $%.2x at $%.4x\n",
274
(int) *cpu::get_code( cpu::r.pc ), (int) cpu::r.pc );
275
cpu::r.pc = (cpu::r.pc + 1) & 0xFFFF;
282
next_play -= cpu_time;
283
if ( next_play < 0 ) // could go negative if routine is taking too long to return
285
apu.end_frame( cpu_time );