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