Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/quicknes/nes_emu/Nes_State.cpp
2 views
1
2
// Nes_Emu 0.7.0. http://www.slack.net/~ant/
3
4
#include "Nes_State.h"
5
6
#include <stdlib.h>
7
#include <string.h>
8
9
#include "blargg_endian.h"
10
#include "Nes_Emu.h"
11
#include "Nes_Mapper.h"
12
13
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
14
can redistribute it and/or modify it under the terms of the GNU Lesser
15
General Public License as published by the Free Software Foundation; either
16
version 2.1 of the License, or (at your option) any later version. This
17
module is distributed in the hope that it will be useful, but WITHOUT ANY
18
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
20
more details. You should have received a copy of the GNU Lesser General
21
Public License along with this module; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
23
24
#include "blargg_source.h"
25
26
int mem_differs( void const* p, int cmp, unsigned long s )
27
{
28
unsigned char const* cp = (unsigned char*) p;
29
while ( s-- )
30
{
31
if ( *cp++ != cmp )
32
return 1;
33
}
34
return 0;
35
}
36
37
Nes_State::Nes_State()
38
{
39
Nes_State_::cpu = &this->cpu;
40
Nes_State_::joypad = &this->joypad;
41
Nes_State_::apu = &this->apu;
42
Nes_State_::ppu = &this->ppu;
43
Nes_State_::mapper = &this->mapper;
44
Nes_State_::ram = this->ram;
45
Nes_State_::sram = this->sram;
46
Nes_State_::spr_ram = this->spr_ram;
47
Nes_State_::nametable = this->nametable;
48
Nes_State_::chr = this->chr;
49
}
50
51
void Nes_State_::clear()
52
{
53
memset( &nes, 0, sizeof nes );
54
nes.frame_count = static_cast<unsigned>(invalid_frame_count);
55
56
nes_valid = false;
57
cpu_valid = false;
58
joypad_valid = false;
59
apu_valid = false;
60
ppu_valid = false;
61
mapper_valid = false;
62
ram_valid = false;
63
sram_size = 0;
64
spr_ram_valid = false;
65
nametable_size = 0;
66
chr_size = 0;
67
}
68
69
// write
70
71
blargg_err_t Nes_State_Writer::end( Nes_Emu const& emu )
72
{
73
Nes_State* state = BLARGG_NEW Nes_State;
74
CHECK_ALLOC( state );
75
emu.save_state( state );
76
blargg_err_t err = end( *state );
77
delete state;
78
return err;
79
}
80
81
blargg_err_t Nes_State_Writer::end( Nes_State const& ss )
82
{
83
RETURN_ERR( ss.write_blocks( *this ) );
84
return Nes_File_Writer::end();
85
}
86
87
blargg_err_t Nes_State::write( Auto_File_Writer out ) const
88
{
89
Nes_State_Writer writer;
90
RETURN_ERR( writer.begin( out ) );
91
return writer.end( *this );
92
}
93
94
blargg_err_t Nes_State_::write_blocks( Nes_File_Writer& out ) const
95
{
96
if ( nes_valid )
97
{
98
nes_state_t s = nes;
99
s.timestamp *= 5;
100
RETURN_ERR( write_nes_state( out, s ) );
101
}
102
103
if ( cpu_valid )
104
{
105
cpu_state_t s;
106
memset( &s, 0, sizeof s );
107
s.pc = cpu->pc;
108
s.s = cpu->sp;
109
s.a = cpu->a;
110
s.x = cpu->x;
111
s.y = cpu->y;
112
s.p = cpu->status;
113
RETURN_ERR( write_nes_state( out, s ) );
114
}
115
116
if ( ppu_valid )
117
{
118
ppu_state_t s = *ppu;
119
RETURN_ERR( write_nes_state( out, s ) );
120
}
121
122
if ( apu_valid )
123
{
124
apu_state_t s = *apu;
125
RETURN_ERR( write_nes_state( out, s ) );
126
}
127
128
if ( joypad_valid )
129
{
130
joypad_state_t s = *joypad;
131
RETURN_ERR( write_nes_state( out, s ) );
132
}
133
134
if ( mapper_valid )
135
RETURN_ERR( out.write_block( FOUR_CHAR('MAPR'), mapper->data, mapper->size ) );
136
137
if ( ram_valid )
138
RETURN_ERR( out.write_block( FOUR_CHAR('LRAM'), ram, ram_size ) );
139
140
if ( spr_ram_valid )
141
RETURN_ERR( out.write_block( FOUR_CHAR('SPRT'), spr_ram, spr_ram_size ) );
142
143
if ( nametable_size )
144
{
145
check( nametable_size == 0x800 || nametable_size == 0x1000 );
146
RETURN_ERR( out.write_block_header( FOUR_CHAR('NTAB'), nametable_size ) );
147
RETURN_ERR( out.write( nametable, 0x800 ) );
148
if ( nametable_size > 0x800 )
149
RETURN_ERR( out.write( chr, 0x800 ) );
150
}
151
152
if ( chr_size )
153
RETURN_ERR( out.write_block( FOUR_CHAR('CHRR'), chr, chr_size ) );
154
155
#ifdef __LIBRETRO__ // Maintain constant save state size.
156
if ( sram_size )
157
RETURN_ERR( out.write_block( FOUR_CHAR('SRAM'), sram, sram_size ) );
158
#else
159
// only save sram if it's been modified
160
if ( sram_size && mem_differs( sram, 0xff, sram_size ) )
161
RETURN_ERR( out.write_block( FOUR_CHAR('SRAM'), sram, sram_size ) );
162
#endif
163
164
return 0;
165
}
166
167
// read
168
169
Nes_State_Reader::Nes_State_Reader() { state_ = 0; owned = 0; }
170
171
Nes_State_Reader::~Nes_State_Reader() { delete owned; }
172
173
blargg_err_t Nes_State_Reader::begin( Auto_File_Reader dr, Nes_State* out )
174
{
175
state_ = out;
176
if ( !out )
177
CHECK_ALLOC( state_ = owned = BLARGG_NEW Nes_State );
178
179
RETURN_ERR( Nes_File_Reader::begin( dr ) );
180
if ( block_tag() != state_file_tag )
181
return "Not a state snapshot file";
182
return 0;
183
}
184
185
blargg_err_t Nes_State::read( Auto_File_Reader in )
186
{
187
Nes_State_Reader reader;
188
RETURN_ERR( reader.begin( in, this ) );
189
while ( !reader.done() )
190
RETURN_ERR( reader.next_block() );
191
192
return 0;
193
}
194
195
blargg_err_t Nes_State_Reader::next_block()
196
{
197
if ( depth() != 0 )
198
return Nes_File_Reader::next_block();
199
return state_->read_blocks( *this );
200
}
201
202
void Nes_State_::set_nes_state( nes_state_t const& s )
203
{
204
nes = s;
205
nes.timestamp /= 5;
206
nes_valid = true;
207
}
208
209
blargg_err_t Nes_State_::read_blocks( Nes_File_Reader& in )
210
{
211
while ( true )
212
{
213
RETURN_ERR( in.next_block() );
214
switch ( in.block_tag() )
215
{
216
case nes_state_t::tag:
217
memset( &nes, 0, sizeof nes );
218
RETURN_ERR( read_nes_state( in, &nes ) );
219
set_nes_state( nes );
220
break;
221
222
case cpu_state_t::tag: {
223
cpu_state_t s;
224
memset( &s, 0, sizeof s );
225
RETURN_ERR( read_nes_state( in, &s ) );
226
cpu->pc = s.pc;
227
cpu->sp = s.s;
228
cpu->a = s.a;
229
cpu->x = s.x;
230
cpu->y = s.y;
231
cpu->status = s.p;
232
cpu_valid = true;
233
break;
234
}
235
236
case ppu_state_t::tag:
237
memset( ppu, 0, sizeof *ppu );
238
RETURN_ERR( read_nes_state( in, ppu ) );
239
ppu_valid = true;
240
break;
241
242
case apu_state_t::tag:
243
memset( apu, 0, sizeof *apu );
244
RETURN_ERR( read_nes_state( in, apu ) );
245
apu_valid = true;
246
break;
247
248
case joypad_state_t::tag:
249
memset( joypad, 0, sizeof *joypad );
250
RETURN_ERR( read_nes_state( in, joypad ) );
251
joypad_valid = true;
252
break;
253
254
case FOUR_CHAR('MAPR'):
255
mapper->size = in.remain();
256
RETURN_ERR( in.read_block_data( mapper->data, sizeof mapper->data ) );
257
mapper_valid = true;
258
break;
259
260
case FOUR_CHAR('SPRT'):
261
spr_ram_valid = true;
262
RETURN_ERR( in.read_block_data( spr_ram, spr_ram_size ) );
263
break;
264
265
case FOUR_CHAR('NTAB'):
266
nametable_size = in.remain();
267
check( nametable_size == 0x800 || nametable_size == 0x1000 );
268
RETURN_ERR( in.read( nametable, 0x800 ) );
269
if ( nametable_size > 0x800 )
270
RETURN_ERR( in.read( chr, 0x800 ) );
271
break;
272
273
case FOUR_CHAR('LRAM'):
274
ram_valid = true;
275
RETURN_ERR( in.read_block_data( ram, ram_size ) );
276
break;
277
278
case FOUR_CHAR('CHRR'):
279
chr_size = in.remain();
280
RETURN_ERR( in.read_block_data( chr, chr_max ) );
281
break;
282
283
case FOUR_CHAR('SRAM'):
284
sram_size = in.remain();
285
RETURN_ERR( in.read_block_data( sram, sram_max ) );
286
break;
287
288
default:
289
return 0;
290
}
291
}
292
}
293
294
295