1 /* Copyright 2006-2007 Theo Berkau
2
3 This file is part of Yabause.
4
5 Yabause is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 Yabause is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Yabause; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*! \file bios.c
21 \brief Emulated bios functions required for running games and saving backup ram.
22 */
23
24 #include "memory.h"
25 #include "cs0.h"
26 #include "debug.h"
27 #include "sh2core.h"
28 #include "bios.h"
29 #include "smpc.h"
30 #include "yabause.h"
31 #include "error.h"
32
33 static u8 sh2masklist[0x20] = {
34 0xF0, 0xE0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80,
35 0x80, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
36 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
37 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70
38 };
39
40 static u32 scumasklist[0x20] = {
41 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,
42 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,
43 0xFFFFFF80, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00,
44 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00,
45 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00,
46 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00,
47 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00,
48 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00
49 };
50
51 u32 interruptlist[2][0x80];
52
53 //////////////////////////////////////////////////////////////////////////////
54
BiosInit(void)55 void BiosInit(void)
56 {
57 int i;
58
59 // Setup vectors
60 MappedMemoryWriteLongNocache(MSH2, 0x06000600, 0x002B0009); // rte, nop
61 MappedMemoryWriteLongNocache(MSH2, 0x06000604, 0xE0F0600C); // mov #0xF0, r0; extu.b r0, r0
62 MappedMemoryWriteLongNocache(MSH2, 0x06000608, 0x400E8BFE); // ldc r0, sr; bf
63 MappedMemoryWriteLongNocache(MSH2, 0x0600060C, 0x00090009); // nop
64 MappedMemoryWriteLongNocache(MSH2, 0x06000610, 0x000B0009); // rts, nop
65
66 for (i = 0; i < 0x200; i+=4)
67 {
68 MappedMemoryWriteLongNocache(MSH2, 0x06000000+i, 0x06000600);
69 MappedMemoryWriteLongNocache(MSH2, 0x06000400+i, 0x06000600);
70 interruptlist[0][i >> 2] = 0x06000600;
71 interruptlist[1][i >> 2] = 0x06000600;
72 }
73
74 MappedMemoryWriteLongNocache(MSH2, 0x06000010, 0x06000604);
75 MappedMemoryWriteLongNocache(MSH2, 0x06000018, 0x06000604);
76 MappedMemoryWriteLongNocache(MSH2, 0x06000024, 0x06000604);
77 MappedMemoryWriteLongNocache(MSH2, 0x06000028, 0x06000604);
78 interruptlist[0][4] = 0x06000604;
79 interruptlist[0][6] = 0x06000604;
80 interruptlist[0][9] = 0x06000604;
81 interruptlist[0][10] = 0x06000604;
82
83 MappedMemoryWriteLongNocache(MSH2, 0x06000410, 0x06000604);
84 MappedMemoryWriteLongNocache(MSH2, 0x06000418, 0x06000604);
85 MappedMemoryWriteLongNocache(MSH2, 0x06000424, 0x06000604);
86 MappedMemoryWriteLongNocache(MSH2, 0x06000428, 0x06000604);
87 interruptlist[1][4] = 0x06000604;
88 interruptlist[1][6] = 0x06000604;
89 interruptlist[1][9] = 0x06000604;
90 interruptlist[1][10] = 0x06000604;
91
92 // Scu Interrupts
93 for (i = 0; i < 0x38; i+=4)
94 {
95 MappedMemoryWriteLongNocache(MSH2, 0x06000100+i, 0x00000400+i);
96 interruptlist[0][0x40+(i >> 2)] = 0x00000400+i;
97 }
98
99 for (i = 0; i < 0x40; i+=4)
100 {
101 MappedMemoryWriteLongNocache(MSH2, 0x06000140+i, 0x00000440+i);
102 interruptlist[0][0x50+(i >> 2)] = 0x00000440+i;
103 }
104
105 for (i = 0; i < 0x100; i+=4)
106 MappedMemoryWriteLongNocache(MSH2, 0x06000A00+i, 0x06000610);
107
108 // Setup Bios Functions
109 MappedMemoryWriteLongNocache(MSH2, 0x06000210, 0x00000210);
110 MappedMemoryWriteLongNocache(MSH2, 0x0600026C, 0x0000026C);
111 MappedMemoryWriteLongNocache(MSH2, 0x06000274, 0x00000274);
112 MappedMemoryWriteLongNocache(MSH2, 0x06000280, 0x00000280);
113 MappedMemoryWriteLongNocache(MSH2, 0x0600029C, 0x0000029C);
114 MappedMemoryWriteLongNocache(MSH2, 0x060002DC, 0x000002DC);
115 MappedMemoryWriteLongNocache(MSH2, 0x06000300, 0x00000300);
116 MappedMemoryWriteLongNocache(MSH2, 0x06000304, 0x00000304);
117 MappedMemoryWriteLongNocache(MSH2, 0x06000310, 0x00000310);
118 MappedMemoryWriteLongNocache(MSH2, 0x06000314, 0x00000314);
119 MappedMemoryWriteLongNocache(MSH2, 0x06000320, 0x00000320);
120 MappedMemoryWriteLongNocache(MSH2, 0x06000324, 0x00000000);
121 MappedMemoryWriteLongNocache(MSH2, 0x06000330, 0x00000330);
122 MappedMemoryWriteLongNocache(MSH2, 0x06000334, 0x00000334);
123 MappedMemoryWriteLongNocache(MSH2, 0x06000340, 0x00000340);
124 MappedMemoryWriteLongNocache(MSH2, 0x06000344, 0x00000344);
125 MappedMemoryWriteLongNocache(MSH2, 0x06000348, 0xFFFFFFFF);
126 MappedMemoryWriteLongNocache(MSH2, 0x06000354, 0x00000000);
127 MappedMemoryWriteLongNocache(MSH2, 0x06000358, 0x00000358);
128 }
129
130 //////////////////////////////////////////////////////////////////////////////
131
BiosSetScuInterrupt(SH2_struct * sh)132 static void FASTCALL BiosSetScuInterrupt(SH2_struct * sh)
133 {
134 SH2GetRegisters(sh, &sh->regs);
135
136 // LOG("BiosSetScuInterrupt. vector = %02X, func = %08X\n", sh->regs.R[4], sh->regs.R[5]);
137
138 if (sh->regs.R[5] == 0)
139 {
140 sh->MappedMemoryWriteLong(sh, 0x06000900+(sh->regs.R[4] << 2), 0x06000610);
141 sh->cycles += 8;
142 }
143 else
144 {
145 sh->MappedMemoryWriteLong(sh, 0x06000900+(sh->regs.R[4] << 2), sh->regs.R[5]);
146 sh->cycles += 9;
147 }
148
149 sh->regs.PC = sh->regs.PR;
150 SH2SetRegisters(sh, &sh->regs);
151 }
152
153 //////////////////////////////////////////////////////////////////////////////
154
BiosGetScuInterrupt(SH2_struct * sh)155 static void FASTCALL BiosGetScuInterrupt(SH2_struct * sh)
156 {
157 SH2GetRegisters(sh, &sh->regs);
158
159 // check me
160 // LOG("BiosGetScuInterrupt\n");
161
162 sh->regs.R[0] = sh->MappedMemoryReadLong(sh, 0x06000900+(sh->regs.R[4] << 2));
163 sh->cycles += 5;
164
165 sh->regs.PC = sh->regs.PR;
166 SH2SetRegisters(sh, &sh->regs);
167 }
168
169 //////////////////////////////////////////////////////////////////////////////
170
BiosSetSh2Interrupt(SH2_struct * sh)171 static void FASTCALL BiosSetSh2Interrupt(SH2_struct * sh)
172 {
173 SH2GetRegisters(sh, &sh->regs);
174
175 // LOG("BiosSetSh2Interrupt\n");
176
177 if (sh->regs.R[5] == 0)
178 {
179 sh->MappedMemoryWriteLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2), interruptlist[sh->isslave][sh->regs.R[4]]);
180 sh->cycles += 8;
181 }
182 else
183 {
184 sh->MappedMemoryWriteLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2), sh->regs.R[5]);
185 sh->cycles += 9;
186 }
187
188 sh->regs.PC = sh->regs.PR;
189 SH2SetRegisters(sh, &sh->regs);
190 }
191
192 //////////////////////////////////////////////////////////////////////////////
193
BiosGetSh2Interrupt(SH2_struct * sh)194 static void FASTCALL BiosGetSh2Interrupt(SH2_struct * sh)
195 {
196 SH2GetRegisters(sh, &sh->regs);
197
198 // check me
199 // LOG("BiosGetSh2Interrupt\n");
200
201 sh->regs.R[0] = sh->MappedMemoryReadLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2));
202 sh->cycles += 5;
203
204 sh->regs.PC = sh->regs.PR;
205 SH2SetRegisters(sh, &sh->regs);
206 }
207
208 //////////////////////////////////////////////////////////////////////////////
209
BiosSetScuInterruptMask(SH2_struct * sh)210 static void FASTCALL BiosSetScuInterruptMask(SH2_struct * sh)
211 {
212 SH2GetRegisters(sh, &sh->regs);
213
214 // check me
215 LOG("BiosSetScuInterruptMask\n");
216
217 if (!sh->isslave)
218 {
219 sh->MappedMemoryWriteLong(sh, 0x06000348, sh->regs.R[4]);
220 sh->MappedMemoryWriteLong(sh, 0x25FE00A0, sh->regs.R[4]); // Interrupt Mask Register
221 }
222
223 if (!(sh->regs.R[4] & 0x8000)) // double check this
224 sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge
225
226 sh->cycles += 17;
227
228 sh->regs.PC = sh->regs.PR;
229 SH2SetRegisters(sh, &sh->regs);
230 }
231
232 //////////////////////////////////////////////////////////////////////////////
233
BiosChangeScuInterruptMask(SH2_struct * sh)234 static void FASTCALL BiosChangeScuInterruptMask(SH2_struct * sh)
235 {
236 u32 newmask;
237
238 SH2GetRegisters(sh, &sh->regs);
239
240 // LOG("BiosChangeScuInterruptMask\n");
241
242 // Read Stored Scu Interrupt Mask, AND it by R4, OR it by R5, then put it back
243 newmask = (sh->MappedMemoryReadLong(sh, 0x06000348) & sh->regs.R[4]) | sh->regs.R[5];
244 if (!sh->isslave)
245 {
246 sh->MappedMemoryWriteLong(sh, 0x06000348, newmask);
247 sh->MappedMemoryWriteLong(sh, 0x25FE00A0, newmask); // Interrupt Mask Register
248 sh->MappedMemoryWriteLong(sh, 0x25FE00A4, (u32)(s16)sh->regs.R[4]); // Interrupt Status Register
249 }
250
251 if (!(sh->regs.R[4] & 0x8000)) // double check this
252 sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge
253
254 sh->cycles += 20;
255
256 sh->regs.PC = sh->regs.PR;
257 SH2SetRegisters(sh, &sh->regs);
258 }
259
260 //////////////////////////////////////////////////////////////////////////////
261
BiosCDINIT2(SH2_struct * sh)262 static void FASTCALL BiosCDINIT2(SH2_struct * sh)
263 {
264 SH2GetRegisters(sh, &sh->regs);
265 sh->regs.PC = sh->regs.PR;
266 SH2SetRegisters(sh, &sh->regs);
267 }
268
269 //////////////////////////////////////////////////////////////////////////////
270
BiosCDINIT1(SH2_struct * sh)271 static void FASTCALL BiosCDINIT1(SH2_struct * sh)
272 {
273 SH2GetRegisters(sh, &sh->regs);
274 sh->regs.PC = sh->regs.PR;
275 SH2SetRegisters(sh, &sh->regs);
276 }
277
278 //////////////////////////////////////////////////////////////////////////////
279
BiosGetSemaphore(SH2_struct * sh)280 static void FASTCALL BiosGetSemaphore(SH2_struct * sh)
281 {
282 u8 temp;
283
284 SH2GetRegisters(sh, &sh->regs);
285
286 // check me
287 LOG("BiosGetSemaphore\n");
288
289 if ((temp = sh->MappedMemoryReadByte(sh, 0x06000B00 + sh->regs.R[4])) == 0)
290 sh->regs.R[0] = 1;
291 else
292 sh->regs.R[0] = 0;
293
294 temp |= 0x80;
295 sh->MappedMemoryWriteByte(sh, 0x06000B00 + sh->regs.R[4], temp);
296
297 sh->cycles += 11;
298 sh->regs.PC = sh->regs.PR;
299 SH2SetRegisters(sh, &sh->regs);
300 }
301
302 //////////////////////////////////////////////////////////////////////////////
303
BiosClearSemaphore(SH2_struct * sh)304 static void FASTCALL BiosClearSemaphore(SH2_struct * sh)
305 {
306 SH2GetRegisters(sh, &sh->regs);
307
308 // check me
309 LOG("BiosClearSemaphore\n");
310
311 sh->MappedMemoryWriteByte(sh, 0x06000B00 + sh->regs.R[4], 0);
312
313 sh->cycles += 5;
314 sh->regs.PC = sh->regs.PR;
315 SH2SetRegisters(sh, &sh->regs);
316 }
317
318 //////////////////////////////////////////////////////////////////////////////
319
BiosChangeSystemClock(SH2_struct * sh)320 static void FASTCALL BiosChangeSystemClock(SH2_struct * sh)
321 {
322 int i, j;
323 u32 mask;
324 SH2GetRegisters(sh, &sh->regs);
325
326 LOG("BiosChangeSystemClock\n");
327
328 // Set new system clock speed
329 sh->MappedMemoryWriteLong(sh, 0x06000324, sh->regs.R[4]);
330
331 sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 0); // Clear A-bus Interrupt ACK
332 sh->MappedMemoryWriteLong(sh, 0x25FE00B8, 0); // Clear A-Bus Refresh
333
334 sh->MappedMemoryWriteByte(sh, 0xFFFFFE91, 0x80); // Transition to standby mode
335 sh->MappedMemoryWriteWord(sh, 0xFFFFFE80, 0xA51D); // Set WDT counter
336 sh->MappedMemoryWriteWord(sh, 0xFFFFFEE0, 0x8000); // Set NMI edge select to high
337
338 if (sh->regs.R[4] == 0)
339 SmpcCKCHG320();
340 else
341 SmpcCKCHG352();
342
343 // Clear SCU DMA Regs
344 for (j = 0; j < 3; j++)
345 {
346 for (i = 0; i < 7; i++)
347 sh->MappedMemoryWriteLong(sh, 0x25FE0000+(j*0xC)+(i*4), 0);
348 }
349
350 sh->MappedMemoryWriteLong(sh, 0x25FE0060, 0); // Clear DMA force stop
351 sh->MappedMemoryWriteLong(sh, 0x25FE0080, 0); // Clear DSP Control Port
352 sh->MappedMemoryWriteLong(sh, 0x25FE00B0, 0x1FF01FF0); // Reset A-Bus Set
353 sh->MappedMemoryWriteLong(sh, 0x25FE00B4, 0x1FF01FF0);
354 sh->MappedMemoryWriteLong(sh, 0x25FE00B8, 0x1F); // Reset A-Bus Refresh
355 sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 0x1); // Reset A-bus Interrupt ACK
356 sh->MappedMemoryWriteLong(sh, 0x25FE0090, 0x3FF); // Reset Timer 0 Compare
357 sh->MappedMemoryWriteLong(sh, 0x25FE0094, 0x1FF); // Reset Timer 1 Set Data
358 sh->MappedMemoryWriteLong(sh, 0x25FE0098, 0); // Reset Timer 1 Mode
359
360 mask = sh->MappedMemoryReadLong(sh, 0x06000348);
361 sh->MappedMemoryWriteLong(sh, 0x25FE00A0, mask); // Interrupt Mask Register
362
363 if (!(mask & 0x8000))
364 sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge
365
366 sh->regs.PC = sh->regs.PR;
367 SH2SetRegisters(sh, &sh->regs);
368 }
369
370 //////////////////////////////////////////////////////////////////////////////
371
BiosChangeScuInterruptPriority(SH2_struct * sh)372 static void FASTCALL BiosChangeScuInterruptPriority(SH2_struct * sh)
373 {
374 int i;
375
376 SH2GetRegisters(sh, &sh->regs);
377
378 // check me
379 // LOG("BiosChangeScuInterruptPriority\n");
380
381 for (i = 0; i < 0x20; i++)
382 {
383 scumasklist[i] = sh->MappedMemoryReadLong(sh, sh->regs.R[4]+(i << 2));
384 sh2masklist[i] = (scumasklist[i] >> 16);
385 if (scumasklist[i] & 0x8000)
386 scumasklist[i] |= 0xFFFF0000;
387 else
388 scumasklist[i] &= 0x0000FFFF;
389 }
390
391 sh->cycles += 186;
392 sh->regs.PC = sh->regs.PR;
393 SH2SetRegisters(sh, &sh->regs);
394 }
395
396 //////////////////////////////////////////////////////////////////////////////
397
BiosExecuteCDPlayer(SH2_struct * sh)398 static void FASTCALL BiosExecuteCDPlayer(SH2_struct * sh)
399 {
400 SH2GetRegisters(sh, &sh->regs);
401
402 LOG("BiosExecuteCDPlayer\n");
403
404 sh->regs.PC = sh->regs.PR;
405 SH2SetRegisters(sh, &sh->regs);
406 }
407
408 //////////////////////////////////////////////////////////////////////////////
409
BiosPowerOnMemoryClear(SH2_struct * sh)410 static void FASTCALL BiosPowerOnMemoryClear(SH2_struct * sh)
411 {
412 SH2GetRegisters(sh, &sh->regs);
413
414 LOG("BiosPowerOnMemoryClear\n");
415
416 sh->regs.PC = sh->regs.PR;
417 SH2SetRegisters(sh, &sh->regs);
418 }
419
420 //////////////////////////////////////////////////////////////////////////////
421
BiosCheckMPEGCard(SH2_struct * sh)422 static void FASTCALL BiosCheckMPEGCard(SH2_struct * sh)
423 {
424 SH2GetRegisters(sh, &sh->regs);
425
426 LOG("BiosCheckMPEGCard\n");
427
428 sh->regs.PC = sh->regs.PR;
429 SH2SetRegisters(sh, &sh->regs);
430 }
431
432 //////////////////////////////////////////////////////////////////////////////
433
GetDeviceStats(u32 device,u32 * size,u32 * addr,u32 * blocksize)434 static u32 GetDeviceStats(u32 device, u32 *size, u32 *addr, u32 *blocksize)
435 {
436 switch(device)
437 {
438 case 0:
439 *addr = 0x00180000;
440 *size = 0x8000;
441 *blocksize = 0x40;
442 return 0;
443 case 1:
444 if ((CartridgeArea->cartid & 0xF0) == 0x20)
445 {
446 *addr = 0x04000000;
447 *size = 0x40000 << (CartridgeArea->cartid & 0x0F);
448 if (CartridgeArea->cartid == 0x24)
449 *blocksize = 0x400;
450 else
451 *blocksize = 0x200;
452
453 return 0;
454 }
455 else
456 return 1;
457 default:
458 *addr = 0;
459 *size = 0;
460 *blocksize = 0;
461 return 1;
462 }
463
464 return 1;
465 }
466
467 //////////////////////////////////////////////////////////////////////////////
468
CheckHeader(UNUSED u32 device)469 static int CheckHeader(UNUSED u32 device)
470 {
471 return 0;
472 }
473
474 //////////////////////////////////////////////////////////////////////////////
475
CalcSaveSize(SH2_struct * sh,u32 tableaddr,int blocksize)476 static int CalcSaveSize(SH2_struct *sh, u32 tableaddr, int blocksize)
477 {
478 int numblocks=0;
479
480 // Now figure out how many blocks this save is
481 for(;;)
482 {
483 u16 block;
484 if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0)
485 tableaddr += 8;
486 block = (sh->MappedMemoryReadByte(sh, tableaddr) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 2);
487 if (block == 0)
488 break;
489 tableaddr += 4;
490 numblocks++;
491 }
492
493 return numblocks;
494 }
495
496 //////////////////////////////////////////////////////////////////////////////
497
GetFreeSpace(SH2_struct * sh,UNUSED u32 device,u32 size,u32 addr,u32 blocksize)498 static u32 GetFreeSpace(SH2_struct *sh, UNUSED u32 device, u32 size, u32 addr, u32 blocksize)
499 {
500 u32 i;
501 u32 usedblocks=0;
502
503 for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
504 {
505 // Find a block with the start of a save
506 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
507 {
508 // Now figure out how many blocks this save is
509 usedblocks += (CalcSaveSize(sh, addr+i+0x45, blocksize) + 1);
510 }
511 }
512
513 return ((size / blocksize) - 2 - usedblocks);
514 }
515
516 //////////////////////////////////////////////////////////////////////////////
517
FindSave(SH2_struct * sh,UNUSED u32 device,u32 stringaddr,u32 blockoffset,u32 size,u32 addr,u32 blocksize)518 static u32 FindSave(SH2_struct *sh, UNUSED u32 device, u32 stringaddr, u32 blockoffset, u32 size, u32 addr, u32 blocksize)
519 {
520 u32 i;
521
522 for (i = ((blockoffset * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
523 {
524 // Find a block with the start of a save
525 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
526 {
527 int i3;
528
529 // See if string matches, or if there's no string to check, just copy
530 // the data over
531 for (i3 = 0; i3 < 11; i3++)
532 {
533 u8 data = sh->MappedMemoryReadByte(sh, stringaddr+i3);
534
535 if (sh->MappedMemoryReadByte(sh, addr+i+0x9+(i3*2)) != data)
536 {
537 if (data == 0)
538 // There's no string to match
539 return ((i / blocksize) >> 1);
540 else
541 // No Match, move onto the next block
542 i3 = 12;
543 }
544 else
545 {
546 // Match
547 if (i3 == 10 || data == 0)
548 return ((i / blocksize) >> 1);
549 }
550 }
551 }
552 }
553
554 return 0;
555 }
556
557 //////////////////////////////////////////////////////////////////////////////
558
FindSave2(SH2_struct * sh,UNUSED u32 device,const char * string,u32 blockoffset,u32 size,u32 addr,u32 blocksize)559 static u32 FindSave2(SH2_struct *sh, UNUSED u32 device, const char *string, u32 blockoffset, u32 size, u32 addr, u32 blocksize)
560 {
561 u32 i;
562
563 for (i = ((blockoffset * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
564 {
565 // Find a block with the start of a save
566 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
567 {
568 int i3;
569
570 // See if string matches, or if there's no string to check, just copy
571 // the data over
572 for (i3 = 0; i3 < 11; i3++)
573 {
574 if (sh->MappedMemoryReadByte(sh, addr+i+0x9+(i3*2)) != string[i3])
575 {
576 if (string[i3] == 0)
577 // There's no string to match
578 return ((i / blocksize) >> 1);
579 else
580 // No Match, move onto the next block
581 i3 = 12;
582 }
583 else
584 {
585 // Match
586 if (i3 == 10 || string[i3] == 0)
587 return ((i / blocksize) >> 1);
588 }
589 }
590 }
591 }
592
593 return 0;
594 }
595
596 //////////////////////////////////////////////////////////////////////////////
597
DeleteSave(SH2_struct * sh,u32 addr,u32 blockoffset,u32 blocksize)598 static void DeleteSave(SH2_struct *sh, u32 addr, u32 blockoffset, u32 blocksize)
599 {
600 sh->MappedMemoryWriteByte(sh, addr + (blockoffset * blocksize * 2) + 0x1, 0x00);
601 }
602
603 //////////////////////////////////////////////////////////////////////////////
604
GetFreeBlocks(SH2_struct * sh,u32 addr,u32 blocksize,u32 numblocks,u32 size)605 static u16 *GetFreeBlocks(SH2_struct *sh, u32 addr, u32 blocksize, u32 numblocks, u32 size)
606 {
607 u8 *blocktbl;
608 u16 *freetbl;
609 u32 tableaddr;
610 u32 i;
611 u32 blockcount=0;
612
613 // Create a table that tells us which blocks are free and used
614 if ((blocktbl = (u8 *)malloc(sizeof(u8) * (size / blocksize))) == NULL)
615 return NULL;
616
617 memset(blocktbl, 0, (size / blocksize));
618
619 for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
620 {
621 // Find a block with the start of a save
622 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
623 {
624 tableaddr = addr+i+0x45;
625 blocktbl[i / (blocksize << 1)] = 1;
626
627 // Now let's figure out which blocks are used
628 for(;;)
629 {
630 u16 block;
631 if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0)
632 tableaddr += 8;
633 block = (sh->MappedMemoryReadByte(sh, tableaddr) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 2);
634 if (block == 0)
635 break;
636 tableaddr += 4;
637 // block is used
638 blocktbl[block] = 1;
639 }
640 }
641 }
642
643 if ((freetbl = (u16 *)malloc(sizeof(u16) * numblocks)) == NULL)
644 {
645 free(blocktbl);
646 return NULL;
647 }
648
649 // Find some free blocks for us to use
650 for (i = 2; i < (size / blocksize); i++)
651 {
652 if (blocktbl[i] == 0)
653 {
654 freetbl[blockcount] = (u16)i;
655 blockcount++;
656
657 if (blockcount >= numblocks)
658 break;
659 }
660 }
661
662 // Ok, we're all done
663 free(blocktbl);
664
665 return freetbl;
666 }
667
668 //////////////////////////////////////////////////////////////////////////////
669
ReadBlockTable(SH2_struct * sh,u32 addr,u32 * tableaddr,int block,int blocksize,int * numblocks,int * blocksread)670 static u16 *ReadBlockTable(SH2_struct *sh, u32 addr, u32 *tableaddr, int block, int blocksize, int *numblocks, int *blocksread)
671 {
672 u16 *blocktbl = NULL;
673 int i=0;
674
675 tableaddr[0] = addr + (block * blocksize * 2) + 0x45;
676 blocksread[0]=0;
677
678 // First of all figure out how large of buffer we need
679 numblocks[0] = CalcSaveSize(sh, tableaddr[0], blocksize);
680
681 // Allocate buffer
682 if ((blocktbl = (u16 *)malloc(sizeof(u16) * numblocks[0])) == NULL)
683 return NULL;
684
685 // Now read in the table
686 for(i = 0; i < numblocks[0]; i++)
687 {
688 u16 block;
689 block = (sh->MappedMemoryReadByte(sh, tableaddr[0]) << 8) | sh->MappedMemoryReadByte(sh, tableaddr[0] + 2);
690 tableaddr[0] += 4;
691
692 if (((tableaddr[0]-1) & ((blocksize << 1) - 1)) == 0)
693 {
694 tableaddr[0] = addr + (blocktbl[blocksread[0]] * blocksize * 2) + 9;
695 blocksread[0]++;
696 }
697 blocktbl[i] = block;
698 }
699
700 tableaddr[0] += 4;
701
702 return blocktbl;
703 }
704
705 //////////////////////////////////////////////////////////////////////////////
706
BiosBUPInit(SH2_struct * sh)707 static void FASTCALL BiosBUPInit(SH2_struct * sh)
708 {
709 SH2GetRegisters(sh, &sh->regs);
710
711 // LOG("BiosBUPInit. arg1 = %08X, arg2 = %08X, arg3 = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6]);
712
713 // Setup Function table
714 sh->MappedMemoryWriteLong(sh, 0x06000354, sh->regs.R[5]);
715 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x00, 0x00000380);
716 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x04, 0x00000384);
717 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x08, 0x00000388);
718 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x0C, 0x0000038C);
719 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x10, 0x00000390);
720 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x14, 0x00000394);
721 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x18, 0x00000398);
722 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x1C, 0x0000039C);
723 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x20, 0x000003A0);
724 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x24, 0x000003A4);
725 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x28, 0x000003A8);
726 sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x2C, 0x000003AC);
727
728 // Setup Device list
729
730 // First Device
731 sh->MappedMemoryWriteWord(sh, sh->regs.R[6], 1); // ID
732 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x2, 1); // Number of partitions
733
734 // Second Device
735 if ((CartridgeArea->cartid & 0xF0) == 0x20)
736 {
737 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x4, 2); // ID
738 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x6, 1); // Number of partitions
739 }
740 else
741 {
742 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x4, 0); // ID
743 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x6, 0); // Number of partitions
744 }
745
746 // Third Device
747 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x08, 0); // ID
748 sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x0A, 0); // Number of partitions
749
750 // cycles need to be incremented
751
752 sh->regs.PC = sh->regs.PR;
753 SH2SetRegisters(sh, &sh->regs);
754 }
755
756 //////////////////////////////////////////////////////////////////////////////
757
BiosBUPSelectPartition(SH2_struct * sh)758 static void FASTCALL BiosBUPSelectPartition(SH2_struct * sh)
759 {
760 SH2GetRegisters(sh, &sh->regs);
761
762 LOG("BiosBUPSelectPartition. PR = %08X\n", sh->regs.PR);
763
764 sh->regs.R[0] = 0; // returns 0 if there's no error
765 sh->regs.PC = sh->regs.PR;
766 SH2SetRegisters(sh, &sh->regs);
767 }
768
769 //////////////////////////////////////////////////////////////////////////////
770
BiosBUPFormat(SH2_struct * sh)771 static void FASTCALL BiosBUPFormat(SH2_struct * sh)
772 {
773 SH2GetRegisters(sh, &sh->regs);
774
775 // LOG("BiosBUPFormat. PR = %08X\n", sh->regs.PR);
776
777 BupFormat(sh->regs.R[4]);
778
779 sh->regs.R[0] = 0; // returns 0 if there's no error
780 sh->regs.PC = sh->regs.PR;
781 SH2SetRegisters(sh, &sh->regs);
782 }
783
784 //////////////////////////////////////////////////////////////////////////////
785
BiosBUPStatus(SH2_struct * sh)786 static void FASTCALL BiosBUPStatus(SH2_struct * sh)
787 {
788 u32 size;
789 u32 addr;
790 u32 blocksize;
791 u32 ret;
792 u32 freeblocks=0;
793 u32 needsize;
794 int aftersize;
795
796 SH2GetRegisters(sh, &sh->regs);
797
798 // LOG("BiosBUPStatus. arg1 = %d, arg2 = %d, arg3 = %08X, PR = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6], sh->regs.PR);
799
800 // Fill in status variables
801 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
802
803 // Make sure there's a proper header, and return if there's any other errors
804 if (ret == 1 || CheckHeader(sh->regs.R[4]) != 0)
805 {
806 // Error
807 sh->regs.R[0] = ret;
808 sh->regs.PC = sh->regs.PR;
809 SH2SetRegisters(sh, &sh->regs);
810 return;
811 }
812
813 freeblocks = GetFreeSpace(sh, sh->regs.R[4], size, addr, blocksize);
814
815 needsize = sh->regs.R[5];
816 aftersize = (((blocksize - 6) * freeblocks) - 30) - needsize;
817 if (aftersize < 0) aftersize = 0;
818
819 sh->MappedMemoryWriteLong(sh, sh->regs.R[6], size); // Size of Backup Ram (in bytes)
820 sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x4, size / blocksize); // Size of Backup Ram (in blocks)
821 sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x8, blocksize); // Size of block
822 sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0xC, ((blocksize - 6) * freeblocks) - 30); // Free space(in bytes)
823 sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x10, freeblocks); // Free space(in blocks)
824 sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x14, aftersize / blocksize); // writable block size
825
826 // cycles need to be incremented
827
828 sh->regs.R[0] = ret; // returns 0 if there's no error
829 sh->regs.PC = sh->regs.PR;
830 SH2SetRegisters(sh, &sh->regs);
831 }
832
833 //////////////////////////////////////////////////////////////////////////////
834
BiosBUPWrite(SH2_struct * sh)835 static void FASTCALL BiosBUPWrite(SH2_struct * sh)
836 {
837 u32 size;
838 u32 addr;
839 u32 blocksize;
840 u32 block;
841 u32 ret;
842 u32 savesize;
843 u16 *blocktbl;
844 u32 workaddr;
845 u32 blockswritten=0;
846 u32 datasize;
847 u32 i;
848
849 SH2GetRegisters(sh, &sh->regs);
850
851 LOG("BiosBUPWrite. arg1 = %d, arg2 = %08X, arg3 = %08X, arg4 = %d, PR = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6], sh->regs.R[7], sh->regs.PR);
852
853 // Fill in status variables
854 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
855 if (ret == 1)
856 {
857 // Error
858 sh->regs.R[0] = ret;
859 sh->regs.PC = sh->regs.PR;
860 SH2SetRegisters(sh, &sh->regs);
861 return;
862 }
863
864 // See if save exists already
865 if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) != 0)
866 {
867 // save exists
868
869 // Should we be overwriting it?
870 if (sh->regs.R[7] != 0)
871 {
872 // Nope, let's bail instead
873 sh->regs.R[0] = 6;
874 sh->regs.PC = sh->regs.PR;
875 SH2SetRegisters(sh, &sh->regs);
876 return;
877 }
878
879 // Delete old save
880 DeleteSave(sh, addr, block, blocksize);
881 }
882
883 // Let's figure out how many blocks will be needed for the save
884 // Consider available size of a block as "blocksize - 6",
885 // because 4 bytes at the beginning of each headers are
886 // reserved to save file system, and because each blocks
887 // require 2 bytes in allocation table.
888 // First block doesn't requires its entry in allocation
889 // table, but since allocation table ends with dummy zero
890 // block ID, we can consider that data available in first
891 // block is the same as in the other blocks.
892 //
893 // Memo when used with internal memory :
894 // - Block size is 64 bytes
895 // - datasize= 1; -> savesize: 1 block
896 // - datasize= 28; -> savesize: 1 block
897 // - datasize= 29; -> savesize: 2 blocks
898 // - datasize= 86; -> savesize: 2 blocks
899 // - datasize= 87; -> savesize: 3 blocks
900 datasize = sh->MappedMemoryReadLong(sh, sh->regs.R[5]+0x1C);
901 savesize = 1 + ((datasize + 0x1D) / (blocksize - 6));
902
903 // Will it blend? Err... fit
904 if (savesize > GetFreeSpace(sh, sh->regs.R[4], size, addr, blocksize))
905 {
906 // Nope, time to bail
907 sh->regs.R[0] = 4;
908 sh->regs.PC = sh->regs.PR;
909 SH2SetRegisters(sh, &sh->regs);
910 return;
911 }
912
913 // Find free blocks for the save
914 if ((blocktbl = GetFreeBlocks(sh, addr, blocksize, savesize, size)) == NULL)
915 {
916 // Just return an error that might make sense
917 sh->regs.R[0] = 8;
918 sh->regs.PC = sh->regs.PR;
919 SH2SetRegisters(sh, &sh->regs);
920 return;
921 }
922
923 // Create save
924 workaddr = addr + (blocktbl[0] * blocksize * 2);
925
926 sh->MappedMemoryWriteByte(sh, workaddr+0x1, 0x80);
927
928 // Copy over filename
929 for (i = workaddr+0x9; i < ((workaddr+0x9) + (11 * 2)); i+=2)
930 {
931 sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5]));
932 sh->regs.R[5]++;
933 }
934
935 sh->regs.R[5]++;
936
937 // Copy over comment
938 for (i = workaddr+0x21; i < ((workaddr+0x21) + (10 * 2)); i+=2)
939 {
940 sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5]));
941 sh->regs.R[5]++;
942 }
943
944 // Copy over language
945 sh->MappedMemoryWriteByte(sh, workaddr+0x1F, sh->MappedMemoryReadByte(sh, sh->regs.R[5]));
946 sh->regs.R[5]++;
947
948 sh->regs.R[5]++;
949
950 // Copy over date
951 for (i = workaddr+0x35; i < ((workaddr+0x35) + (4 * 2)); i+=2)
952 {
953 sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5]));
954 sh->regs.R[5]++;
955 }
956
957 // Copy over data size
958 for (i = workaddr+0x3D; i < ((workaddr+0x3D) + (4 * 2)); i+=2)
959 {
960 sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5]));
961 sh->regs.R[5]++;
962 }
963
964 // write the block table
965 workaddr += 0x45;
966
967 for (i = 1; i < savesize; i++)
968 {
969 sh->MappedMemoryWriteByte(sh, workaddr, (u8)(blocktbl[i] >> 8));
970 workaddr+=2;
971 sh->MappedMemoryWriteByte(sh, workaddr, (u8)blocktbl[i]);
972 workaddr+=2;
973
974 if (((workaddr-1) & ((blocksize << 1) - 1)) == 0)
975 {
976 // Next block
977 blockswritten++;
978 workaddr = addr + (blocktbl[blockswritten] * blocksize * 2) + 9;
979 }
980 }
981
982 // Write 2 blank bytes so we now how large the table size is next time
983 sh->MappedMemoryWriteByte(sh, workaddr, 0);
984 workaddr+=2;
985 sh->MappedMemoryWriteByte(sh, workaddr, 0);
986 workaddr+=2;
987
988 // Lastly, write the actual save data
989 while (datasize > 0)
990 {
991 if (((workaddr-1) & ((blocksize << 1) - 1)) == 0)
992 {
993 // Next block
994 blockswritten++;
995 workaddr = addr + (blocktbl[blockswritten] * blocksize * 2) + 9;
996 }
997
998 sh->MappedMemoryWriteByte(sh, workaddr, sh->MappedMemoryReadByte(sh, sh->regs.R[6]));
999 datasize--;
1000 sh->regs.R[6]++;
1001 workaddr+=2;
1002 }
1003
1004 free(blocktbl);
1005
1006 YabFlushBackups();
1007
1008 sh->regs.R[0] = 0; // returns 0 if there's no error
1009 sh->regs.PC = sh->regs.PR;
1010 SH2SetRegisters(sh, &sh->regs);
1011 }
1012
1013 //////////////////////////////////////////////////////////////////////////////
1014
BiosBUPRead(SH2_struct * sh)1015 static void FASTCALL BiosBUPRead(SH2_struct * sh)
1016 {
1017 u32 size;
1018 u32 addr;
1019 u32 blocksize;
1020 u32 block;
1021 u32 ret;
1022 u32 tableaddr;
1023 u16 *blocktbl;
1024 int numblocks;
1025 int blocksread;
1026 u32 datasize;
1027
1028 SH2GetRegisters(sh, &sh->regs);
1029
1030 LOG("BiosBUPRead\n", sh->regs.PR);
1031
1032 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
1033
1034 if (ret == 1)
1035 {
1036 // Error
1037 sh->regs.R[0] = ret;
1038 sh->regs.PC = sh->regs.PR;
1039 SH2SetRegisters(sh, &sh->regs);
1040 return;
1041 }
1042
1043 // See if save exists
1044 if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0)
1045 {
1046 // save doesn't exist
1047 sh->regs.R[0] = 5;
1048 sh->regs.PC = sh->regs.PR;
1049 SH2SetRegisters(sh, &sh->regs);
1050 return;
1051 }
1052
1053 tableaddr = addr + (block * blocksize * 2) + 0x3D;
1054 datasize = (sh->MappedMemoryReadByte(sh, tableaddr) << 24) | (sh->MappedMemoryReadByte(sh, tableaddr + 2) << 16) |
1055 (sh->MappedMemoryReadByte(sh, tableaddr+4) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 6);
1056
1057 // Read in Block Table
1058 if ((blocktbl = ReadBlockTable(sh, addr, &tableaddr, block, blocksize, &numblocks, &blocksread)) == NULL)
1059 {
1060 // Just return an error that might make sense
1061 sh->regs.R[0] = 8;
1062 sh->regs.PC = sh->regs.PR;
1063 SH2SetRegisters(sh, &sh->regs);
1064 return;
1065 }
1066
1067 // Now let's read in the data
1068 while (datasize > 0)
1069 {
1070 if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0)
1071 {
1072 // Load up the next block
1073 tableaddr = addr + (blocktbl[blocksread] * blocksize * 2) + 9;
1074 blocksread++;
1075 }
1076
1077 sh->MappedMemoryWriteByte(sh, sh->regs.R[6], sh->MappedMemoryReadByte(sh, tableaddr));
1078 datasize--;
1079 sh->regs.R[6]++;
1080 tableaddr+=2;
1081 }
1082
1083 free(blocktbl);
1084
1085 sh->regs.R[0] = 0; // returns 0 if there's no error
1086 sh->regs.PC = sh->regs.PR;
1087 SH2SetRegisters(sh, &sh->regs);
1088 }
1089
1090 //////////////////////////////////////////////////////////////////////////////
1091
BiosBUPDelete(SH2_struct * sh)1092 static void FASTCALL BiosBUPDelete(SH2_struct * sh)
1093 {
1094 u32 size;
1095 u32 addr;
1096 u32 blocksize;
1097 u32 block;
1098 u32 ret;
1099
1100 SH2GetRegisters(sh, &sh->regs);
1101
1102 LOG("BiosBUPDelete. PR = %08X\n", sh->regs.PR);
1103
1104 // Fill in status variables
1105 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
1106 if (ret == 1)
1107 {
1108 // Error
1109 sh->regs.R[0] = ret;
1110 sh->regs.PC = sh->regs.PR;
1111 SH2SetRegisters(sh, &sh->regs);
1112 return;
1113 }
1114
1115 // See if save exists
1116 if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0)
1117 {
1118 // Since the save doesn't exist, let's bail with an error
1119
1120 sh->regs.R[0] = 5;
1121 sh->regs.PC = sh->regs.PR;
1122 SH2SetRegisters(sh, &sh->regs);
1123 return;
1124 }
1125
1126 DeleteSave(sh, addr, block, blocksize);
1127
1128 sh->regs.R[0] = 0; // returns 0 if there's no error
1129 sh->regs.PC = sh->regs.PR;
1130 SH2SetRegisters(sh, &sh->regs);
1131 }
1132
1133 //////////////////////////////////////////////////////////////////////////////
1134
BiosBUPDirectory(SH2_struct * sh)1135 static void FASTCALL BiosBUPDirectory(SH2_struct * sh)
1136 {
1137 u32 size;
1138 u32 addr;
1139 u32 blocksize;
1140 u32 ret;
1141 u32 i;
1142 char filename[12];
1143 u32 blockoffset=2;
1144
1145 SH2GetRegisters(sh, &sh->regs);
1146
1147 // int findmatch = MappedMemoryReadByte(sh->regs.R[5]);
1148
1149 for (i = 0; i < 12; i++)
1150 filename[i] = sh->MappedMemoryReadByte(sh, sh->regs.R[5]+i);
1151
1152 LOG("BiosBUPDirectory. arg1 = %d, arg2 = %s, arg3 = %08X, arg4 = %08X, PR = %08X\n", sh->regs.R[4], filename, sh->regs.R[6], sh->regs.R[7], sh->regs.PR);
1153
1154 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
1155
1156 if (ret == 1)
1157 {
1158 // Error
1159 sh->regs.R[0] = ret;
1160 sh->regs.PC = sh->regs.PR;
1161 SH2SetRegisters(sh, &sh->regs);
1162 return;
1163 }
1164
1165 // Count Max size
1166 for (i = 0; i < 256; i++)
1167 {
1168 u32 block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], blockoffset, size, addr, blocksize);
1169
1170 if (block == 0)
1171 break;
1172
1173 blockoffset = block + 1;
1174 block = addr + (blocksize * block * 2);
1175 }
1176
1177 if (sh->regs.R[6] < i)
1178 {
1179 sh->regs.R[0] = -(s32)i; // returns the number of successfully read dir entries
1180 sh->regs.PC = sh->regs.PR;
1181 SH2SetRegisters(sh, &sh->regs);
1182 return;
1183 }
1184
1185 // reset offet
1186 blockoffset = 2;
1187
1188 for (i = 0; i < sh->regs.R[6]; i++)
1189 {
1190 u32 i4;
1191 u32 datasize=0;
1192 u32 block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], blockoffset, size, addr, blocksize);
1193
1194 if (block == 0)
1195 break;
1196
1197 blockoffset = block+1;
1198
1199 // Alright, we found a match :) Time to copy over some data
1200 block = addr + (blocksize * block * 2);
1201
1202 // Copy over filename
1203 for (i4 = block+0x9; i4 < ((block+0x9) + (11 * 2)); i4+=2)
1204 {
1205 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4));
1206 sh->regs.R[7]++;
1207 }
1208 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], 0);
1209 sh->regs.R[7]++;
1210
1211 // Copy over comment
1212 for (i4 = block+0x21; i4 < ((block+0x21) + (10 * 2)); i4+=2)
1213 {
1214 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4));
1215 sh->regs.R[7]++;
1216 }
1217
1218 // Copy over language
1219 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, block+0x1F));
1220 sh->regs.R[7]++;
1221
1222 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], 0);
1223 sh->regs.R[7]++;
1224
1225 // Copy over date
1226 for (i4 = block+0x35; i4 < ((block+0x35) + (4 * 2)); i4+=2)
1227 {
1228 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4));
1229 sh->regs.R[7]++;
1230 }
1231
1232 // Copy over data size
1233 for (i4 = block+0x3D; i4 < ((block+0x3D) + (4 * 2)); i4+=2)
1234 {
1235 u8 data;
1236 datasize <<= 8;
1237 data = sh->MappedMemoryReadByte(sh, i4);
1238 sh->MappedMemoryWriteByte(sh, sh->regs.R[7], data);
1239 datasize |= data;
1240 sh->regs.R[7]++;
1241 }
1242
1243 // Calculate block size from the data size, and then copy it over
1244 sh->MappedMemoryWriteWord(sh, sh->regs.R[7], (u16)(((datasize + 0x1D) / (blocksize - 6)) + 1));
1245 sh->regs.R[7] += 4;
1246 }
1247
1248 sh->regs.R[0] = i; // returns the number of successfully read dir entries
1249 sh->regs.PC = sh->regs.PR;
1250 SH2SetRegisters(sh, &sh->regs);
1251 }
1252
1253 //////////////////////////////////////////////////////////////////////////////
1254
BiosBUPVerify(SH2_struct * sh)1255 static void FASTCALL BiosBUPVerify(SH2_struct * sh)
1256 {
1257 u32 size;
1258 u32 addr;
1259 u32 blocksize;
1260 u32 block;
1261 u32 ret;
1262 u32 tableaddr;
1263 u32 datasize;
1264 u16 *blocktbl;
1265 int numblocks;
1266 int blocksread;
1267
1268 SH2GetRegisters(sh, &sh->regs);
1269
1270 LOG("BiosBUPVerify. PR = %08X\n", sh->regs.PR);
1271
1272 ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize);
1273
1274 if (ret == 1)
1275 {
1276 // Error
1277 sh->regs.R[0] = ret;
1278 sh->regs.PC = sh->regs.PR;
1279 SH2SetRegisters(sh, &sh->regs);
1280 return;
1281 }
1282
1283 // See if save exists
1284 if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0)
1285 {
1286 // Since the save doesn't exist, let's bail with an error
1287 sh->regs.R[0] = 5; // Not found
1288 sh->regs.PC = sh->regs.PR;
1289 SH2SetRegisters(sh, &sh->regs);
1290 return;
1291 }
1292
1293 tableaddr = addr + (block * blocksize * 2) + 0x3D;
1294 datasize = (sh->MappedMemoryReadByte(sh, tableaddr) << 24) | (sh->MappedMemoryReadByte(sh, tableaddr + 2) << 16) |
1295 (sh->MappedMemoryReadByte(sh, tableaddr+4) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 6);
1296
1297 // Read in Block Table
1298 if ((blocktbl = ReadBlockTable(sh, addr, &tableaddr, block, blocksize, &numblocks, &blocksread)) == NULL)
1299 {
1300 // Just return an error that might make sense
1301 sh->regs.R[0] = 8; // Broken
1302 sh->regs.PC = sh->regs.PR;
1303 SH2SetRegisters(sh, &sh->regs);
1304 return;
1305 }
1306
1307 // Now let's read in the data, and check to see if it matches
1308 while (datasize > 0)
1309 {
1310 if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0)
1311 {
1312 // Load up the next block
1313 tableaddr = addr + (blocktbl[blocksread] * blocksize * 2) + 9;
1314 blocksread++;
1315 }
1316
1317 if (sh->MappedMemoryReadByte(sh, sh->regs.R[6]) != sh->MappedMemoryReadByte(sh, tableaddr))
1318 {
1319 free(blocktbl);
1320 // Ok, the data doesn't match
1321 sh->regs.R[0] = 7; // No match
1322 sh->regs.PC = sh->regs.PR;
1323 SH2SetRegisters(sh, &sh->regs);
1324 return;
1325 }
1326
1327 datasize--;
1328 sh->regs.R[6]++;
1329 tableaddr+=2;
1330 }
1331
1332 free(blocktbl);
1333
1334 sh->regs.R[0] = 0; // returns 0 if there's no error
1335 sh->regs.PC = sh->regs.PR;
1336 SH2SetRegisters(sh, &sh->regs);
1337 }
1338
1339 //////////////////////////////////////////////////////////////////////////////
1340
ConvertMonthAndDay(SH2_struct * sh,u32 data,u32 monthaddr,u32 dayaddr,int type)1341 static void ConvertMonthAndDay(SH2_struct *sh, u32 data, u32 monthaddr, u32 dayaddr, int type)
1342 {
1343 int i;
1344 u16 monthtbl[11] = { 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31,
1345 31+28+31+30+31+30, 31+28+31+30+31+30+31,
1346 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30,
1347 31+28+31+30+31+30+31+31+30+31,
1348 31+28+31+30+31+30+31+31+30+31+30 };
1349
1350 if (data < monthtbl[0])
1351 {
1352 // Month
1353 sh->MappedMemoryWriteByte(sh, monthaddr, 1);
1354
1355 // Day
1356 sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data + 1));
1357 return;
1358 }
1359
1360 for (i = 1; i < 11; i++)
1361 {
1362 if (data <= monthtbl[i])
1363 break;
1364 }
1365
1366 if (type == 1)
1367 {
1368 // Month
1369 sh->MappedMemoryWriteByte(sh, monthaddr, (u8)(i + 1));
1370
1371 // Day
1372 if ((i + 1) == 2)
1373 sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)] + 1));
1374 else
1375 sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)]));
1376 }
1377 else
1378 {
1379 // Month
1380 sh->MappedMemoryWriteByte(sh, monthaddr, (u8)(i + 1));
1381
1382 // Day
1383 sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)] + 1));
1384 }
1385 }
1386
1387 //////////////////////////////////////////////////////////////////////////////
1388
BiosBUPGetDate(SH2_struct * sh)1389 static void FASTCALL BiosBUPGetDate(SH2_struct * sh)
1390 {
1391 u32 date;
1392 u32 div;
1393 u32 yearoffset;
1394 u32 yearremainder;
1395
1396 SH2GetRegisters(sh, &sh->regs);
1397
1398 LOG("BiosBUPGetDate. PR = %08X\n", sh->regs.PR);
1399
1400 date = sh->regs.R[4];
1401
1402 // Time
1403 sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+3, (u8)((date % 0x5A0) / 0x3C));
1404
1405 // Minute
1406 sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+4, (u8)(date % 0x3C));
1407
1408 div = date / 0x5A0;
1409
1410 // Week
1411 if (div > 0xAB71)
1412 sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+5, (u8)((div + 1) % 7));
1413 else
1414 sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+5, (u8)((div + 2) % 7));
1415
1416 yearremainder = div % 0x5B5;
1417
1418 if (yearremainder > 0x16E)
1419 {
1420 yearoffset = (yearremainder - 1) / 0x16D;
1421 ConvertMonthAndDay(sh, (yearremainder - 1) % 0x16D, sh->regs.R[5]+1, sh->regs.R[5]+2, 0);
1422 }
1423 else
1424 {
1425 yearoffset = 0;
1426 ConvertMonthAndDay(sh, 0, sh->regs.R[5]+1, sh->regs.R[5]+2, 1);
1427 }
1428
1429 // Year
1430 sh->MappedMemoryWriteByte(sh, sh->regs.R[5], (u8)(((div / 0x5B5) * 4) + yearoffset));
1431
1432 sh->regs.PC = sh->regs.PR;
1433 SH2SetRegisters(sh, &sh->regs);
1434 }
1435
1436 //////////////////////////////////////////////////////////////////////////////
1437
BiosBUPSetDate(SH2_struct * sh)1438 static void FASTCALL BiosBUPSetDate(SH2_struct * sh)
1439 {
1440 u32 date;
1441 u8 data;
1442 u32 remainder;
1443 u16 monthtbl[11] = { 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31,
1444 31+28+31+30+31+30, 31+28+31+30+31+30+31,
1445 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30,
1446 31+28+31+30+31+30+31+31+30+31,
1447 31+28+31+30+31+30+31+31+30+31+30 };
1448
1449 SH2GetRegisters(sh, &sh->regs);
1450
1451 LOG("BiosBUPSetDate. PR = %08X\n", sh->regs.PR);
1452
1453 // Year
1454 data = sh->MappedMemoryReadByte(sh, sh->regs.R[4]);
1455 date = (data / 4) * 0x5B5;
1456 remainder = data % 4;
1457 if (remainder)
1458 date += (remainder * 0x16D) + 1;
1459
1460 // Month
1461 data = sh->MappedMemoryReadByte(sh, sh->regs.R[4]+1);
1462 if (data != 1 && data < 13)
1463 {
1464 date += monthtbl[data - 2];
1465 if (date > 2 && remainder == 0)
1466 date++;
1467 }
1468
1469 // Day
1470 date += sh->MappedMemoryReadByte(sh, sh->regs.R[4]+2) - 1;
1471 date *= 0x5A0;
1472
1473 // Hour
1474 date += (sh->MappedMemoryReadByte(sh, sh->regs.R[4]+3) * 0x3C);
1475
1476 // Minute
1477 date += sh->MappedMemoryReadByte(sh, sh->regs.R[4]+4);
1478
1479 sh->regs.R[0] = date;
1480 sh->regs.PC = sh->regs.PR;
1481 SH2SetRegisters(sh, &sh->regs);
1482 }
1483
1484 //////////////////////////////////////////////////////////////////////////////
1485
BiosHandleScuInterrupt(SH2_struct * sh,int vector)1486 static void FASTCALL BiosHandleScuInterrupt(SH2_struct * sh, int vector)
1487 {
1488 SH2GetRegisters(sh, &sh->regs);
1489
1490 // Save R0-R7, PR, GBR, and old Interrupt mask to stack
1491 sh->regs.R[15] -= 4;
1492 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[0]);
1493 sh->regs.R[15] -= 4;
1494 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[1]);
1495 sh->regs.R[15] -= 4;
1496 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[2]);
1497 sh->regs.R[15] -= 4;
1498 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[3]);
1499 sh->regs.R[15] -= 4;
1500 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->MappedMemoryReadLong(sh, 0x06000348));
1501 sh->regs.R[15] -= 4;
1502 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[4]);
1503 sh->regs.R[15] -= 4;
1504 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[5]);
1505 sh->regs.R[15] -= 4;
1506 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[6]);
1507 sh->regs.R[15] -= 4;
1508 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[7]);
1509 sh->regs.R[15] -= 4;
1510 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.PR);
1511 sh->regs.R[15] -= 4;
1512 sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.GBR);
1513
1514 // Set SR according to vector
1515 sh->regs.SR.all = (u32)sh2masklist[vector - 0x40];
1516
1517 // Write new Interrupt mask value
1518 sh->MappedMemoryWriteLong(sh, 0x06000348, sh->MappedMemoryReadLong(sh, 0x06000348) | scumasklist[vector - 0x40]);
1519 sh->MappedMemoryWriteLong(sh, 0x25FE00A0, sh->MappedMemoryReadLong(sh, 0x06000348) | scumasklist[vector - 0x40]);
1520
1521 // Set PR to our Interrupt Return handler
1522 sh->regs.PR = 0x00000480;
1523
1524 // Now execute the interrupt
1525 sh->regs.PC = sh->MappedMemoryReadLong(sh, 0x06000900+(vector << 2));
1526 // LOG("Interrupt PC = %08X. Read from %08X\n", sh->regs.PC, 0x06000900+(vector << 2));
1527
1528 sh->cycles += 33;
1529 SH2SetRegisters(sh, &sh->regs);
1530 }
1531
1532 //////////////////////////////////////////////////////////////////////////////
1533
BiosHandleScuInterruptReturn(SH2_struct * sh)1534 static void FASTCALL BiosHandleScuInterruptReturn(SH2_struct * sh)
1535 {
1536 u32 oldmask;
1537
1538 SH2GetRegisters(sh, &sh->regs);
1539
1540 // Restore R0-R7, PR, GBR, and old Interrupt mask from stack
1541 sh->regs.GBR = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1542 sh->regs.R[15] += 4;
1543 sh->regs.PR = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1544 sh->regs.R[15] += 4;
1545 sh->regs.R[7] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1546 sh->regs.R[15] += 4;
1547 sh->regs.R[6] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1548 sh->regs.R[15] += 4;
1549 sh->regs.R[5] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1550 sh->regs.R[15] += 4;
1551 sh->regs.R[4] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1552 sh->regs.R[15] += 4;
1553 // Return SR back to normal
1554 sh->regs.SR.all = 0xF0;
1555 oldmask = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1556 sh->MappedMemoryWriteLong(sh, 0x06000348, oldmask);
1557 sh->MappedMemoryWriteLong(sh, 0x25FE00A0, oldmask);
1558 sh->regs.R[15] += 4;
1559 sh->regs.R[3] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1560 sh->regs.R[15] += 4;
1561 sh->regs.R[2] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1562 sh->regs.R[15] += 4;
1563 sh->regs.R[1] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1564 sh->regs.R[15] += 4;
1565 sh->regs.R[0] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1566 sh->regs.R[15] += 4;
1567
1568 sh->regs.PC = sh->MappedMemoryReadLong(sh, sh->regs.R[15]);
1569 sh->regs.R[15] += 4;
1570 sh->regs.SR.all = sh->MappedMemoryReadLong(sh, sh->regs.R[15]) & 0x000003F3;
1571 sh->regs.R[15] += 4;
1572
1573 sh->cycles += 24;
1574 SH2SetRegisters(sh, &sh->regs);
1575 }
1576
1577 //////////////////////////////////////////////////////////////////////////////
1578
BiosHandleFunc(SH2_struct * sh)1579 int FASTCALL BiosHandleFunc(SH2_struct * sh)
1580 {
1581 SH2GetRegisters(sh, &sh->regs);
1582
1583 // Let's see if it's a bios function
1584 switch((sh->regs.PC - 0x200) >> 2)
1585 {
1586 case 0x04: // 0x06000210
1587 BiosPowerOnMemoryClear(sh);
1588 break;
1589 case 0x1B: // 0x0600026C
1590 BiosExecuteCDPlayer(sh);
1591 break;
1592 case 0x1D: // 0x06000274
1593 BiosCheckMPEGCard(sh);
1594 break;
1595 case 0x20: // 0x06000280
1596 BiosChangeScuInterruptPriority(sh);
1597 break;
1598 case 0x27: // 0x0600029C
1599 BiosCDINIT2(sh);
1600 break;
1601 case 0x37: // 0x060002DC
1602 BiosCDINIT1(sh);
1603 break;
1604 case 0x40: // 0x06000300
1605 BiosSetScuInterrupt(sh);
1606 break;
1607 case 0x41: // 0x06000304
1608 BiosGetScuInterrupt(sh);
1609 break;
1610 case 0x44: // 0x06000310
1611 BiosSetSh2Interrupt(sh);
1612 break;
1613 case 0x45: // 0x06000314
1614 BiosGetSh2Interrupt(sh);
1615 break;
1616 case 0x48: // 0x06000320
1617 BiosChangeSystemClock(sh);
1618 break;
1619 case 0x4C: // 0x06000330
1620 BiosGetSemaphore(sh);
1621 break;
1622 case 0x4D: // 0x06000334
1623 BiosClearSemaphore(sh);
1624 break;
1625 case 0x50: // 0x06000340
1626 BiosSetScuInterruptMask(sh);
1627 break;
1628 case 0x51: // 0x06000344
1629 BiosChangeScuInterruptMask(sh);
1630 break;
1631 case 0x56: // 0x06000358
1632 BiosBUPInit(sh);
1633 break;
1634 case 0x60: // 0x06000380
1635 break;
1636 case 0x61: // 0x06000384
1637 BiosBUPSelectPartition(sh);
1638 break;
1639 case 0x62: // 0x06000388
1640 BiosBUPFormat(sh);
1641 break;
1642 case 0x63: // 0x0600038C
1643 BiosBUPStatus(sh);
1644 break;
1645 case 0x64: // 0x06000390
1646 BiosBUPWrite(sh);
1647 break;
1648 case 0x65: // 0x06000394
1649 BiosBUPRead(sh);
1650 break;
1651 case 0x66: // 0x06000398
1652 BiosBUPDelete(sh);
1653 break;
1654 case 0x67: // 0x0600039C
1655 BiosBUPDirectory(sh);
1656 break;
1657 case 0x68: // 0x060003A0
1658 BiosBUPVerify(sh);
1659 break;
1660 case 0x69: // 0x060003A4
1661 BiosBUPGetDate(sh);
1662 break;
1663 case 0x6A: // 0x060003A8
1664 BiosBUPSetDate(sh);
1665 break;
1666 case 0x6B: // 0x060003AC
1667 break;
1668 case 0x80: // Interrupt Handler
1669 case 0x81:
1670 case 0x82:
1671 case 0x83:
1672 case 0x84:
1673 case 0x85:
1674 case 0x86:
1675 case 0x87:
1676 case 0x88:
1677 case 0x89:
1678 case 0x8A:
1679 case 0x8B:
1680 case 0x8C:
1681 case 0x8D:
1682 case 0x90:
1683 case 0x91:
1684 case 0x92:
1685 case 0x93:
1686 case 0x94:
1687 case 0x95:
1688 case 0x96:
1689 case 0x97:
1690 case 0x98:
1691 case 0x99:
1692 case 0x9A:
1693 case 0x9B:
1694 case 0x9C:
1695 case 0x9D:
1696 case 0x9E:
1697 case 0x9F:
1698 BiosHandleScuInterrupt(sh, (sh->regs.PC - 0x300) >> 2);
1699 break;
1700 case 0xA0: // Interrupt Handler Return
1701 BiosHandleScuInterruptReturn(sh);
1702 break;
1703 default:
1704 return 0;
1705 }
1706
1707 return 1;
1708 }
1709
1710 //////////////////////////////////////////////////////////////////////////////
1711
BupGetDeviceList(int * numdevices)1712 deviceinfo_struct *BupGetDeviceList(int *numdevices)
1713 {
1714 deviceinfo_struct *device;
1715 int devicecount=1;
1716
1717 if ((CartridgeArea->cartid & 0xF0) == 0x20)
1718 devicecount++;
1719
1720 if ((device = (deviceinfo_struct *)malloc(devicecount * sizeof(deviceinfo_struct))) == NULL)
1721 {
1722 *numdevices = 0;
1723 return NULL;
1724 }
1725
1726 *numdevices = devicecount;
1727
1728 device[0].id = 0;
1729 sprintf(device[0].name, "Internal Backup RAM");
1730
1731 if ((CartridgeArea->cartid & 0xF0) == 0x20)
1732 {
1733 device[1].id = 1;
1734 sprintf(device[1].name, "%d Mbit Backup RAM Cartridge", 1 << ((CartridgeArea->cartid & 0xF)+1));
1735 }
1736
1737 // For now it's only internal backup ram and cartridge, no floppy :(
1738 // device[2].id = 2;
1739 // sprintf(device[1].name, "Floppy Disk Drive");
1740
1741 return device;
1742 }
1743
1744 //////////////////////////////////////////////////////////////////////////////
1745
BupGetStats(SH2_struct * sh,u32 device,u32 * freespace,u32 * maxspace)1746 int BupGetStats(SH2_struct *sh, u32 device, u32 *freespace, u32 *maxspace)
1747 {
1748 u32 ret;
1749 u32 size;
1750 u32 addr;
1751 u32 blocksize;
1752
1753 ret = GetDeviceStats(device, &size, &addr, &blocksize);
1754
1755 // Make sure there's a proper header, and return if there's any other errors
1756 if (ret == 1 || CheckHeader(device) != 0)
1757 return 0;
1758
1759 *maxspace = size / blocksize;
1760 *freespace = GetFreeSpace(sh, device, size, addr, blocksize);
1761
1762 return 1;
1763 }
1764
1765 //////////////////////////////////////////////////////////////////////////////
1766
BupGetSaveList(SH2_struct * sh,u32 device,int * numsaves)1767 saveinfo_struct *BupGetSaveList(SH2_struct *sh, u32 device, int *numsaves)
1768 {
1769 u32 ret;
1770 u32 size;
1771 u32 addr;
1772 u32 blocksize;
1773 saveinfo_struct *save;
1774 int savecount=0;
1775 u32 i, j;
1776 u32 workaddr;
1777
1778 ret = GetDeviceStats(device, &size, &addr, &blocksize);
1779
1780 // Make sure there's a proper header, and return if there's any other errors
1781 if (ret == 1 || CheckHeader(device) != 0)
1782 {
1783 *numsaves = 0;
1784 return NULL;
1785 }
1786
1787 for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
1788 {
1789 // Find a block with the start of a save
1790 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
1791 savecount++;
1792 }
1793
1794 if ((save = (saveinfo_struct *)malloc(savecount * sizeof(saveinfo_struct))) == NULL)
1795 {
1796 *numsaves = 0;
1797 return NULL;
1798 }
1799
1800 *numsaves = savecount;
1801
1802 savecount = 0;
1803
1804 for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1))
1805 {
1806 // Find a block with the start of a save
1807 if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0)
1808 {
1809 workaddr = addr + i;
1810
1811 // Copy over filename
1812 for (j = 0; j < 11; j++)
1813 save[savecount].filename[j] = sh->MappedMemoryReadByte(sh, workaddr+0x9+(j * 2));
1814 save[savecount].filename[11] = '\0';
1815
1816 // Copy over comment
1817 for (j = 0; j < 10; j++)
1818 save[savecount].comment[j] = sh->MappedMemoryReadByte(sh, workaddr+0x21+(j * 2));
1819 save[savecount].comment[10] = '\0';
1820
1821 // Copy over language
1822 save[savecount].language = sh->MappedMemoryReadByte(sh, workaddr+0x1F);
1823
1824 // Copy over Date(fix me)
1825 save[savecount].year = 0;
1826 save[savecount].month = 0;
1827 save[savecount].day = 0;
1828 save[savecount].hour = 0;
1829 save[savecount].minute = 0;
1830 save[savecount].week = 0;
1831
1832 // Copy over data size
1833 save[savecount].datasize = (sh->MappedMemoryReadByte(sh, workaddr+0x3D) << 24) |
1834 (sh->MappedMemoryReadByte(sh, workaddr+0x3F) << 16) |
1835 (sh->MappedMemoryReadByte(sh, workaddr+0x41) << 8) |
1836 sh->MappedMemoryReadByte(sh, workaddr+0x43);
1837
1838 // Calculate size in blocks
1839 save[savecount].blocksize = CalcSaveSize(sh, workaddr+0x45, blocksize) + 1;
1840 savecount++;
1841 }
1842 }
1843
1844 return save;
1845 }
1846
1847 //////////////////////////////////////////////////////////////////////////////
1848
BupDeleteSave(SH2_struct * sh,u32 device,const char * savename)1849 int BupDeleteSave(SH2_struct *sh, u32 device, const char *savename)
1850 {
1851 u32 ret;
1852 u32 size;
1853 u32 addr;
1854 u32 blocksize;
1855 u32 block;
1856
1857 ret = GetDeviceStats(device, &size, &addr, &blocksize);
1858
1859 // Make sure there's a proper header, and return if there's any other errors
1860 if (ret == 1 || CheckHeader(device) != 0)
1861 return -1;
1862
1863 // Let's find and delete the save game
1864 if ((block = FindSave2(sh, device, savename, 2, size, addr, blocksize)) != 0)
1865 {
1866 // Delete old save
1867 DeleteSave(sh, addr, block, blocksize);
1868 return 0;
1869 }
1870
1871 return -2;
1872 }
1873
1874 //////////////////////////////////////////////////////////////////////////////
1875
BupFormat(u32 device)1876 void BupFormat(u32 device)
1877 {
1878 switch (device)
1879 {
1880 case 0:
1881 FormatBackupRam(BupRam, 0x10000);
1882 break;
1883 case 1:
1884 if ((CartridgeArea->cartid & 0xF0) == 0x20)
1885 {
1886 switch (CartridgeArea->cartid & 0xF)
1887 {
1888 case 1:
1889 FormatBackupRam(CartridgeArea->bupram, 0x100000);
1890 break;
1891 case 2:
1892 FormatBackupRam(CartridgeArea->bupram, 0x200000);
1893 break;
1894 case 3:
1895 FormatBackupRam(CartridgeArea->bupram, 0x400000);
1896 break;
1897 case 4:
1898 FormatBackupRam(CartridgeArea->bupram, 0x800000);
1899 break;
1900 default: break;
1901 }
1902 }
1903 break;
1904 case 2:
1905 LOG("Formatting FDD not supported\n");
1906 default: break;
1907 }
1908 }
1909
1910 //////////////////////////////////////////////////////////////////////////////
1911
BupCopySave(UNUSED u32 srcdevice,UNUSED u32 dstdevice,UNUSED const char * savename)1912 int BupCopySave(UNUSED u32 srcdevice, UNUSED u32 dstdevice, UNUSED const char *savename)
1913 {
1914 return 0;
1915 }
1916
1917 //////////////////////////////////////////////////////////////////////////////
1918
BupImportSave(UNUSED u32 device,const char * filename)1919 int BupImportSave(UNUSED u32 device, const char *filename)
1920 {
1921 FILE *fp;
1922 long filesize;
1923 u8 *buffer;
1924 size_t num_read = 0;
1925
1926 if (!filename)
1927 return -1;
1928
1929 if ((fp = fopen(filename, "rb")) == NULL)
1930 return -1;
1931
1932 // Calculate file size
1933 fseek(fp, 0, SEEK_END);
1934 filesize = ftell(fp);
1935
1936 if (filesize <= 0)
1937 {
1938 YabSetError(YAB_ERR_FILEREAD, filename);
1939 fclose(fp);
1940 return -1;
1941 }
1942
1943 fseek(fp, 0, SEEK_SET);
1944
1945 if ((buffer = (u8 *)malloc(filesize)) == NULL)
1946 {
1947 fclose(fp);
1948 return -2;
1949 }
1950
1951 num_read = fread((void *)buffer, 1, filesize, fp);
1952 fclose(fp);
1953
1954 // Write save here
1955
1956 free(buffer);
1957 return 0;
1958 }
1959
1960 //////////////////////////////////////////////////////////////////////////////
1961
BupExportSave(UNUSED u32 device,UNUSED const char * savename,UNUSED const char * filename)1962 int BupExportSave(UNUSED u32 device, UNUSED const char *savename, UNUSED const char *filename)
1963 {
1964 return 0;
1965 }
1966
1967 //////////////////////////////////////////////////////////////////////////////
1968
1969