Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/waterbox/gpgx/core/cart_hw/areplay.c
2 views
1
/****************************************************************************
2
* Genesis Plus
3
* Action Replay / Pro Action Replay emulation
4
*
5
* Copyright (C) 2009-2011 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
41
#define TYPE_PRO1 0x12
42
#define TYPE_PRO2 0x22
43
44
struct
45
{
46
uint8 enabled;
47
uint8 status;
48
uint8 *rom;
49
uint8 *ram;
50
uint16 regs[13];
51
uint16 old[4];
52
uint16 data[4];
53
uint32 addr[4];
54
} action_replay;
55
56
static void ar_write_regs(uint32 address, uint32 data);
57
static void ar_write_regs_2(uint32 address, uint32 data);
58
static void ar_write_ram_8(uint32 address, uint32 data);
59
60
void areplay_init(void)
61
{
62
int size;
63
FILE *f;
64
65
memset(&action_replay,0,sizeof(action_replay));
66
67
/* store Action replay ROM (max. 128k) & RAM (64k) above cartridge ROM + SRAM area */
68
if (cart.romsize > 0x810000) return;
69
action_replay.rom = cart.rom + 0x810000;
70
action_replay.ram = cart.rom + 0x830000;
71
72
/* Open Action Replay ROM */
73
f = fopen(AR_ROM,"rb");
74
if (f == NULL) return;
75
76
/* ROM size */
77
fseek(f, 0, SEEK_END);
78
size = ftell(f);
79
fseek(f, 0, SEEK_SET);
80
81
/* detect Action Replay board type */
82
switch (size)
83
{
84
case 0x8000:
85
{
86
/* normal Action Replay (32K) */
87
action_replay.enabled = TYPE_AR;
88
89
/* internal registers mapped at $010000-$01ffff */
90
m68k.memory_map[0x01].write16 = ar_write_regs;
91
break;
92
}
93
94
case 0x10000:
95
case 0x20000:
96
{
97
/* read Stack Pointer */
98
uint8 sp[4];
99
fread(&sp, 4, 1, f);
100
fseek(f, 0, SEEK_SET);
101
102
/* Detect board version */
103
if (sp[1] == 0x42)
104
{
105
/* PRO Action Replay 1 (64/128K) */
106
action_replay.enabled = TYPE_PRO1;
107
108
/* internal registers mapped at $010000-$01ffff */
109
m68k.memory_map[0x01].write16 = ar_write_regs;
110
}
111
else if (sp[1] == 0x60)
112
{
113
/* PRO Action Replay 2 (64K) */
114
action_replay.enabled = TYPE_PRO2;
115
116
/* internal registers mapped at $100000-$10ffff */
117
m68k.memory_map[0x10].write16 = ar_write_regs_2;
118
}
119
120
/* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */
121
if (action_replay.enabled)
122
{
123
m68k.memory_map[sp[1]].base = action_replay.ram;
124
m68k.memory_map[sp[1]].read8 = NULL;
125
m68k.memory_map[sp[1]].read16 = NULL;
126
m68k.memory_map[sp[1]].write8 = ar_write_ram_8;
127
m68k.memory_map[sp[1]].write16 = NULL;
128
}
129
break;
130
}
131
132
default:
133
{
134
break;
135
}
136
}
137
138
if (action_replay.enabled)
139
{
140
/* Load ROM */
141
int i = 0;
142
for (i=0; i<size; i+=0x1000)
143
{
144
fread(action_replay.rom + i, 0x1000, 1, f);
145
}
146
147
#ifdef LSB_FIRST
148
for (i= 0; i<size; i+=2)
149
{
150
/* Byteswap ROM */
151
uint8 temp = action_replay.rom[i];
152
action_replay.rom[i] = action_replay.rom[i+1];
153
action_replay.rom[i+1] = temp;
154
}
155
#endif
156
}
157
158
/* Close ROM file */
159
fclose(f);
160
}
161
162
void areplay_shutdown(void)
163
{
164
/* clear existing patches */
165
areplay_set_status(AR_SWITCH_OFF);
166
167
/* disable device by default */
168
action_replay.enabled = 0;
169
}
170
171
void areplay_reset(int hard)
172
{
173
if (action_replay.enabled)
174
{
175
if (hard || (action_replay.status == AR_SWITCH_TRAINER))
176
{
177
/* reset internal registers */
178
memset(action_replay.regs, 0, sizeof(action_replay.regs));
179
memset(action_replay.old, 0, sizeof(action_replay.old));
180
memset(action_replay.data, 0, sizeof(action_replay.data));
181
memset(action_replay.addr, 0, sizeof(action_replay.addr));
182
183
/* by default, internal ROM is mapped at $000000-$00FFFF */
184
m68k.memory_map[0].base = action_replay.rom;
185
186
/* reset internal RAM on power-on */
187
if (hard)
188
{
189
memset(action_replay.ram,0xff,0x10000);
190
}
191
}
192
}
193
}
194
195
int areplay_get_status(void)
196
{
197
if (action_replay.enabled)
198
{
199
return action_replay.status;
200
}
201
202
return -1;
203
}
204
205
void areplay_set_status(int status)
206
{
207
if (action_replay.enabled)
208
{
209
/* no Trainer mode for normal Action Replay */
210
if ((action_replay.enabled == TYPE_AR) && (status == AR_SWITCH_TRAINER))
211
{
212
status = AR_SWITCH_OFF;
213
}
214
215
/* check status changes */
216
switch (status)
217
{
218
case AR_SWITCH_OFF:
219
case AR_SWITCH_TRAINER:
220
{
221
/* check that patches were previously enabled */
222
if (action_replay.status == AR_SWITCH_ON)
223
{
224
/* restore original data */
225
*(uint16 *)(cart.rom + action_replay.addr[0]) = action_replay.old[0];
226
*(uint16 *)(cart.rom + action_replay.addr[1]) = action_replay.old[1];
227
*(uint16 *)(cart.rom + action_replay.addr[2]) = action_replay.old[2];
228
*(uint16 *)(cart.rom + action_replay.addr[3]) = action_replay.old[3];
229
}
230
break;
231
}
232
233
case AR_SWITCH_ON:
234
{
235
/* check that patches were previously disabled */
236
if (action_replay.status != AR_SWITCH_ON)
237
{
238
/* decode patch data */
239
action_replay.data[0] = action_replay.regs[0];
240
action_replay.data[1] = action_replay.regs[4];
241
action_replay.data[2] = action_replay.regs[7];
242
action_replay.data[3] = action_replay.regs[10];
243
244
/* decode patch address ($000000-$7fffff) */
245
action_replay.addr[0] = (action_replay.regs[1] | ((action_replay.regs[2] & 0x3f00) << 8)) << 1;
246
action_replay.addr[1] = (action_replay.regs[5] | ((action_replay.regs[6] & 0x3f00) << 8)) << 1;
247
action_replay.addr[2] = (action_replay.regs[8] | ((action_replay.regs[9] & 0x3f00) << 8)) << 1;
248
action_replay.addr[3] = (action_replay.regs[11] | ((action_replay.regs[12] & 0x3f00) << 8)) << 1;
249
250
/* save original data */
251
action_replay.old[0] = *(uint16 *)(cart.rom + action_replay.addr[0]);
252
action_replay.old[1] = *(uint16 *)(cart.rom + action_replay.addr[1]);
253
action_replay.old[2] = *(uint16 *)(cart.rom + action_replay.addr[2]);
254
action_replay.old[3] = *(uint16 *)(cart.rom + action_replay.addr[3]);
255
256
/* patch new data */
257
*(uint16 *)(cart.rom + action_replay.addr[0]) = action_replay.data[0];
258
*(uint16 *)(cart.rom + action_replay.addr[1]) = action_replay.data[1];
259
*(uint16 *)(cart.rom + action_replay.addr[2]) = action_replay.data[2];
260
*(uint16 *)(cart.rom + action_replay.addr[3]) = action_replay.data[3];
261
}
262
break;
263
}
264
265
default:
266
{
267
return;
268
}
269
}
270
271
/* update status */
272
action_replay.status = status;
273
}
274
}
275
276
static void ar_write_regs(uint32 address, uint32 data)
277
{
278
/* register offset */
279
int offset = (address & 0xffff) >> 1;
280
if (offset > 12)
281
{
282
m68k_unused_16_w(address,data);
283
return;
284
}
285
286
/* update internal register */
287
action_replay.regs[offset] = data;
288
289
/* MODE register */
290
if (action_replay.regs[3] == 0xffff)
291
{
292
/* check switch status */
293
if (action_replay.status == AR_SWITCH_ON)
294
{
295
/* reset existing patches */
296
areplay_set_status(AR_SWITCH_OFF);
297
areplay_set_status(AR_SWITCH_ON);
298
}
299
300
/* enable Cartridge ROM */
301
m68k.memory_map[0].base = cart.rom;
302
}
303
}
304
305
static void ar_write_regs_2(uint32 address, uint32 data)
306
{
307
/* enable Cartridge ROM */
308
if (((address & 0xff) == 0x78) && (data == 0xffff))
309
{
310
m68k.memory_map[0].base = cart.rom;
311
}
312
}
313
314
static void ar_write_ram_8(uint32 address, uint32 data)
315
{
316
/* byte writes are handled as word writes, with LSB duplicated in MSB (/LWR is not used) */
317
*(uint16 *)(action_replay.ram + (address & 0xfffe)) = (data | (data << 8));
318
}
319
320
321