Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx/core/cart_hw/sram.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* Backup RAM support
4
*
5
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
6
*
7
* Redistribution and use of this code or any derivative works are permitted
8
* provided that the following conditions are met:
9
*
10
* - Redistributions may not be sold, nor may they be used in a commercial
11
* product or activity.
12
*
13
* - Redistributions that are modified from the original source must include the
14
* complete source code, including the source code for all components used by a
15
* binary built from the modified sources. However, as a special exception, the
16
* source code distributed need not include anything that is normally distributed
17
* (in either source or binary form) with the major components (compiler, kernel,
18
* and so on) of the operating system on which the executable runs, unless that
19
* component itself accompanies the executable.
20
*
21
* - Redistributions must reproduce the above copyright notice, this list of
22
* conditions and the following disclaimer in the documentation and/or other
23
* materials provided with the distribution.
24
*
25
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGE.
36
*
37
****************************************************************************************/
38
39
#include "shared.h"
40
#include "eeprom_i2c.h"
41
#include "eeprom_spi.h"
42
#include "eeprom_93c.h"
43
44
T_SRAM sram;
45
46
/****************************************************************************
47
* A quick guide to external RAM on the Genesis
48
*
49
* The external RAM definition is held at offset 0x1b0 of the ROM header.
50
*
51
* 1B0h: dc.b 'RA', %1x1yz000, %abc00000
52
* 1B4h: dc.l RAM start address
53
* 1B8h: dc.l RAM end address
54
* x 1 for BACKUP (not volatile), 0 for volatile RAM
55
* yz 10 if even address only
56
* 11 if odd address only
57
* 00 if both even and odd address
58
* 01 others (serial EEPROM, RAM with 4-bit data bus, etc)
59
* abc 001 if SRAM
60
* 010 if EEPROM (serial or parallel)
61
* other values unused
62
*
63
* Assuming max. 64k backup RAM throughout
64
****************************************************************************/
65
void sram_init()
66
{
67
memset(&sram, 0, sizeof (T_SRAM));
68
69
/* backup RAM data is stored above cartridge ROM area, at $800000-$80FFFF (max. 64K) */
70
if (cart.romsize > 0x800000) return;
71
sram.sram = cart.rom + 0x800000;
72
73
/* initialize Backup RAM */
74
memset(sram.sram, 0xFF, 0x10000);
75
//sram.crc = crc32(0, sram.sram, 0x10000);
76
77
/* retrieve informations from header */
78
if ((READ_BYTE(cart.rom,0x1b0) == 0x52) && (READ_BYTE(cart.rom,0x1b1) == 0x41))
79
{
80
/* backup RAM detected */
81
sram.detected = 1;
82
83
/* enable backup RAM */
84
sram.on = 1;
85
86
/* retrieve backup RAM start & end addresses */
87
sram.start = READ_WORD_LONG(cart.rom, 0x1b4);
88
sram.end = READ_WORD_LONG(cart.rom, 0x1b8);
89
90
/* autodetect games with wrong header infos */
91
if (strstr(rominfo.product,"T-26013") != NULL)
92
{
93
/* Psy-O-Blade (wrong header) */
94
sram.start = 0x200001;
95
sram.end = 0x203fff;
96
}
97
98
/* fixe games indicating internal RAM as volatile external RAM (Feng Kuang Tao Hua Yuan) */
99
else if (sram.start == 0xff0000)
100
{
101
/* backup RAM should be disabled */
102
sram.on = 0;
103
}
104
105
/* fixe other bad header informations */
106
else if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000))
107
{
108
sram.end = sram.start + 0xffff;
109
}
110
}
111
else
112
{
113
/* autodetect games with missing header infos */
114
if (strstr(rominfo.product,"T-50086") != NULL)
115
{
116
/* PGA Tour Golf */
117
sram.on = 1;
118
sram.start = 0x200001;
119
sram.end = 0x203fff;
120
}
121
else if (strstr(rominfo.product,"ACLD007") != NULL)
122
{
123
/* Winter Challenge */
124
sram.on = 1;
125
sram.start = 0x200001;
126
sram.end = 0x200fff;
127
}
128
else if (strstr(rominfo.product,"T-50286") != NULL)
129
{
130
/* Buck Rogers - Countdown to Doomsday */
131
sram.on = 1;
132
sram.start = 0x200001;
133
sram.end = 0x203fff;
134
}
135
else if (((rominfo.realchecksum == 0xaeaa) || (rominfo.realchecksum == 0x8dba)) &&
136
(rominfo.checksum == 0x8104))
137
{
138
/* Xin Qigai Wangzi (use uncommon area) */
139
sram.on = 1;
140
sram.start = 0x400001;
141
sram.end = 0x40ffff;
142
}
143
else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"001") != NULL))
144
{
145
/* SF-001 */
146
sram.on = 1;
147
if (rominfo.checksum == 0x3e08)
148
{
149
/* last revision (use bankswitching) */
150
sram.start = 0x3c0001;
151
sram.end = 0x3cffff;
152
}
153
else
154
{
155
/* older revisions (use uncommon area) */
156
sram.start = 0x400001;
157
sram.end = 0x40ffff;
158
}
159
}
160
else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"004") != NULL))
161
{
162
/* SF-004 (use bankswitching) */
163
sram.on = 1;
164
sram.start = 0x200001;
165
sram.end = 0x203fff;
166
}
167
else if (strstr(rominfo.international,"SONIC & KNUCKLES") != NULL)
168
{
169
/* Sonic 3 & Knuckles combined ROM */
170
if (cart.romsize == 0x400000)
171
{
172
/* Sonic & Knuckle does not have backup RAM but can access FRAM from Sonic 3 cartridge */
173
sram.on = 1;
174
sram.start = 0x200001;
175
sram.end = 0x203fff;
176
}
177
}
178
179
/* auto-detect games which need disabled backup RAM */
180
else if (strstr(rominfo.product,"T-113016") != NULL)
181
{
182
/* Pugsy (does not have backup RAM but tries writing outside ROM area as copy protection) */
183
sram.on = 0;
184
}
185
else if (strstr(rominfo.international,"SONIC THE HEDGEHOG 2") != NULL)
186
{
187
/* Sonic the Hedgehog 2 (does not have backup RAM) */
188
/* this prevents backup RAM from being mapped in place of mirrored ROM when using S&K LOCK-ON feature */
189
sram.on = 0;
190
}
191
192
// by default, enable backup RAM for ROM smaller than 2MB
193
/*
194
else if (cart.romsize <= 0x200000)
195
{
196
// 64KB static RAM mapped to $200000-$20ffff
197
sram.start = 0x200000;
198
sram.end = 0x20ffff;
199
sram.on = 1;
200
}
201
*/
202
}
203
}
204
205
unsigned int sram_read_byte(unsigned int address)
206
{
207
return sram.sram[address & 0xffff];
208
}
209
210
unsigned int sram_read_word(unsigned int address)
211
{
212
address &= 0xfffe;
213
return (sram.sram[address + 1] | (sram.sram[address] << 8));
214
}
215
216
void sram_write_byte(unsigned int address, unsigned int data)
217
{
218
sram.sram[address & 0xffff] = data;
219
}
220
221
void sram_write_word(unsigned int address, unsigned int data)
222
{
223
address &= 0xfffe;
224
sram.sram[address] = data >> 8;
225
sram.sram[address + 1] = data & 0xff;
226
}
227
228
// the variables in SRAM_T are all part of "configuration", so we don't have to save those.
229
// the only thing that needs to be saved is the SRAM itself and the SEEPROM struct (if applicable)
230
231
int sram_context_save(uint8 *state)
232
{
233
int bufferptr = 0;
234
if (!sram.on)
235
return 0;
236
save_param(sram.sram, sram_get_actual_size());
237
switch (sram.custom)
238
{
239
case 1:
240
save_param(&eeprom_i2c, sizeof(eeprom_i2c));
241
break;
242
case 2:
243
save_param(&spi_eeprom, sizeof(spi_eeprom));
244
break;
245
case 3:
246
save_param(&eeprom_93c, sizeof(eeprom_93c));
247
break;
248
}
249
return bufferptr;
250
}
251
252
int sram_context_load(uint8 *state)
253
{
254
int bufferptr = 0;
255
if (!sram.on)
256
return 0;
257
load_param(sram.sram, sram_get_actual_size());
258
switch (sram.custom)
259
{
260
case 1:
261
load_param(&eeprom_i2c, sizeof(eeprom_i2c));
262
break;
263
case 2:
264
load_param(&spi_eeprom, sizeof(spi_eeprom));
265
break;
266
case 3:
267
load_param(&eeprom_93c, sizeof(eeprom_93c));
268
break;
269
}
270
return bufferptr;
271
}
272
273
int sram_get_actual_size()
274
{
275
if (!sram.on)
276
return 0;
277
switch (sram.custom)
278
{
279
case 0: // plain bus access saveram
280
break;
281
case 1: // i2c
282
return eeprom_i2c.config.size_mask + 1;
283
case 2: // spi
284
return 0x10000; // it doesn't appear to mask anything internally
285
case 3: // 93c
286
return 0x10000; // SMS only and i don't have time to look into it
287
default:
288
return 0x10000; // who knows
289
}
290
// figure size for plain bus access saverams
291
{
292
int startaddr = sram.start / 8192;
293
int endaddr = sram.end / 8192 + 1;
294
int size = (endaddr - startaddr) * 8192;
295
return size;
296
}
297
}
298
299