cleanup
[fceu.git] / fds.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2002 Xodnizel\r
5 *\r
6 * This program is free software; you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation; either version 2 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * This program is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with this program; if not, write to the Free Software\r
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
19 */\r
20\r
21#include <stdio.h>\r
22#include <stdlib.h>\r
23#include <string.h>\r
24\r
25#include "types.h"\r
26#include "x6502.h"\r
27#include "fce.h"\r
28#include "fds.h"\r
29#include "sound.h"\r
30#include "general.h"\r
31#include "state.h"\r
32#include "file.h"\r
33#include "memory.h"\r
34#include "cart.h"\r
35#include "md5.h"\r
36#include "netplay.h"\r
37\r
38#include "svga.h"\r
39\r
40/* TODO: Add code to put a delay in between the time a disk is inserted\r
41 and the when it can be successfully read/written to. This should\r
42 prevent writes to wrong places OR add code to prevent disk ejects\r
43 when the virtual motor is on(mmm...virtual motor).\r
44*/\r
45\r
46static DECLFR(FDSRead4030);\r
47static DECLFR(FDSRead4031);\r
48static DECLFR(FDSRead4032);\r
49static DECLFR(FDSRead4033);\r
50\r
51static DECLFW(FDSWrite);\r
52\r
53static DECLFW(FDSWaveWrite);\r
54static DECLFR(FDSWaveRead);\r
55\r
56static DECLFR(FDSSRead);\r
57static DECLFW(FDSSWrite);\r
58static DECLFR(FDSBIOSRead);\r
59static DECLFR(FDSRAMRead);\r
60static DECLFW(FDSRAMWrite);\r
61static void FDSInit(void);\r
62static void FP_FASTAPASS(1) FDSFix(int a);\r
63\r
64#define FDSRAM GameMemBlock\r
65#define CHRRAM (GameMemBlock+32768)\r
66\r
67static uint8 FDSRegs[6];\r
68static int32 IRQLatch,IRQCount;\r
69static uint8 IRQa;\r
70static void FDSClose(void);\r
71\r
72static uint8 FDSBIOS[8192];\r
73\r
74/* Original disk data backup, to help in creating save states. */\r
75static uint8 *diskdatao[8]={0,0,0,0,0,0,0,0};\r
76\r
77static uint8 *diskdata[8]={0,0,0,0,0,0,0,0};\r
78\r
79static unsigned int TotalSides;\r
80static uint8 DiskWritten=0; /* Set to 1 if disk was written to. */\r
81static uint8 writeskip;\r
82static uint32 DiskPtr;\r
83static int32 DiskSeekIRQ;\r
84static uint8 SelectDisk,InDisk;\r
85\r
86#define DC_INC 1\r
87\r
88void FDSGI(int h)\r
89{\r
90 switch(h)\r
91 {\r
92 case GI_CLOSE: FDSClose();break;\r
93 case GI_POWER: FDSInit();break;\r
94 }\r
95}\r
96\r
97static void FDSStateRestore(int version)\r
98{\r
99 int x;\r
100\r
101 setmirror(((FDSRegs[5]&8)>>3)^1);\r
102\r
103 if(version >= 9810)\r
104 for(x=0;x<TotalSides;x++)\r
105 {\r
106 int b;\r
107 for(b=0; b<65500; b++)\r
108 diskdata[x][b] ^= diskdatao[x][b];\r
109 }\r
110\r
111}\r
112\r
113void FDSSound();\r
114void FDSSoundReset(void);\r
115void FDSSoundStateAdd(void);\r
116static void RenderSound(void);\r
117//static void RenderSoundHQ(void);\r
118\r
119static void FDSInit(void)\r
120{\r
121 memset(FDSRegs,0,sizeof(FDSRegs));\r
122 writeskip=DiskPtr=DiskSeekIRQ=0;\r
123 setmirror(1);\r
124\r
125 setprg8r(0,0xe000,0); // BIOS\r
126 setprg32r(1,0x6000,0); // 32KB RAM\r
127 setchr8(0); // 8KB CHR RAM\r
128\r
129 MapIRQHook=FDSFix;\r
130 GameStateRestore=FDSStateRestore;\r
131\r
132 SetReadHandler(0x4030,0x4030,FDSRead4030);\r
133 SetReadHandler(0x4031,0x4031,FDSRead4031);\r
134 SetReadHandler(0x4032,0x4032,FDSRead4032);\r
135 SetReadHandler(0x4033,0x4033,FDSRead4033);\r
136\r
137 SetWriteHandler(0x4020,0x4025,FDSWrite);\r
138\r
139 SetWriteHandler(0x6000,0xdfff,FDSRAMWrite);\r
140 SetReadHandler(0x6000,0xdfff,FDSRAMRead);\r
141 SetReadHandler(0xE000,0xFFFF,FDSBIOSRead);\r
142 IRQCount=IRQLatch=IRQa=0;\r
143\r
144 FDSSoundReset();\r
145 InDisk=0;\r
146 SelectDisk=0;\r
147}\r
148\r
149void FCEU_FDSInsert(void)\r
150{\r
151 if(TotalSides==0)\r
152 {\r
153 FCEU_DispMessage("Not FDS; can't eject disk.");\r
154 return;\r
155 }\r
156 if(InDisk==255)\r
157 {\r
158 FCEU_DispMessage("Disk %d Side %s Inserted",SelectDisk>>1,(SelectDisk&1)?"B":"A");\r
159 InDisk=SelectDisk;\r
160 }\r
161 else\r
162 {\r
163 FCEU_DispMessage("Disk %d Side %s Ejected",SelectDisk>>1,(SelectDisk&1)?"B":"A");\r
164 InDisk=255;\r
165 }\r
166}\r
167/*\r
168void FCEU_FDSEject(void)\r
169{\r
170 InDisk=255;\r
171}\r
172*/\r
173void FCEU_FDSSelect(void)\r
174{\r
175 if(TotalSides==0)\r
176 {\r
177 FCEU_DispMessage("Not FDS; can't select disk.");\r
178 return;\r
179 }\r
180 if(InDisk!=255)\r
181 {\r
182 FCEU_DispMessage("Eject disk before selecting.");\r
183 return;\r
184 }\r
185 SelectDisk=((SelectDisk+1)%TotalSides)&3;\r
186 FCEU_DispMessage("Disk %d Side %c Selected",SelectDisk>>1,(SelectDisk&1)?'B':'A');\r
187}\r
188\r
189static void FP_FASTAPASS(1) FDSFix(int a)\r
190{\r
191 if((IRQa&2) && IRQCount)\r
192 {\r
193 IRQCount-=a;\r
194 if(IRQCount<=0)\r
195 {\r
196 if(!(IRQa&1))\r
197 {\r
198 IRQa&=~2;\r
199 IRQCount=IRQLatch=0;\r
200 }\r
201 else\r
202 IRQCount=IRQLatch;\r
203 //IRQCount=IRQLatch; //0xFFFF;\r
204 X6502_IRQBegin(FCEU_IQEXT);\r
205 //printf("IRQ: %d\n",timestamp);\r
206// printf("IRQ: %d\n",scanline);\r
207 }\r
208 }\r
209 if(DiskSeekIRQ>0)\r
210 {\r
211 DiskSeekIRQ-=a;\r
212 if(DiskSeekIRQ<=0)\r
213 {\r
214 if(FDSRegs[5]&0x80)\r
215 {\r
216 X6502_IRQBegin(FCEU_IQEXT2);\r
217 }\r
218 }\r
219 }\r
220}\r
221\r
222static DECLFR(FDSRead4030)\r
223{\r
224 uint8 ret=0;\r
225\r
226 /* Cheap hack. */\r
227 if(X.IRQlow&FCEU_IQEXT) ret|=1;\r
228 if(X.IRQlow&FCEU_IQEXT2) ret|=2;\r
229\r
230 if(!fceuindbg)\r
231 {\r
232 X6502_IRQEnd(FCEU_IQEXT);\r
233 X6502_IRQEnd(FCEU_IQEXT2);\r
234 }\r
235 return ret;\r
236}\r
237\r
238static DECLFR(FDSRead4031)\r
239{\r
240 static uint8 z=0;\r
241 if(InDisk!=255)\r
242 {\r
243 z=diskdata[InDisk][DiskPtr];\r
244 if(!fceuindbg)\r
245 {\r
246 if(DiskPtr<64999) DiskPtr++;\r
247 DiskSeekIRQ=150;\r
248 X6502_IRQEnd(FCEU_IQEXT2);\r
249 }\r
250 }\r
251 return z;\r
252}\r
253static DECLFR(FDSRead4032)\r
254{\r
255 uint8 ret;\r
256\r
257 ret=X.DB&~7;\r
258 if(InDisk==255)\r
259 ret|=5;\r
260\r
261 if(InDisk==255 || !(FDSRegs[5]&1) || (FDSRegs[5]&2))\r
262 ret|=2;\r
263 return ret;\r
264}\r
265\r
266static DECLFR(FDSRead4033)\r
267{\r
268 return 0x80; // battery\r
269}\r
270\r
271static DECLFW(FDSRAMWrite)\r
272{\r
273 (FDSRAM-0x6000)[A]=V;\r
274}\r
275\r
276static DECLFR(FDSBIOSRead)\r
277{\r
278 return (FDSBIOS-0xE000)[A];\r
279}\r
280\r
281static DECLFR(FDSRAMRead)\r
282{\r
283 return (FDSRAM-0x6000)[A];\r
284}\r
285\r
286/* Begin FDS sound */\r
287\r
288#define FDSClock (1789772.7272727272727272/2)\r
289\r
290typedef struct {\r
291 int64 cycles; // Cycles per PCM sample\r
292 int64 count; // Cycle counter\r
293 int64 envcount; // Envelope cycle counter\r
294 uint32 b19shiftreg60;\r
295 uint32 b24adder66;\r
296 uint32 b24latch68;\r
297 uint32 b17latch76;\r
298 int32 clockcount; // Counter to divide frequency by 8.\r
299 uint8 b8shiftreg88; // Modulation register.\r
300 uint8 amplitude[2]; // Current amplitudes.\r
301 uint8 speedo[2];\r
302 uint8 mwcount;\r
303 uint8 mwstart;\r
304 uint8 mwave[0x20]; // Modulation waveform\r
305 uint8 cwave[0x40]; // Game-defined waveform(carrier)\r
306 uint8 SPSG[0xB];\r
307} FDSSOUND;\r
308\r
309static FDSSOUND fdso;\r
310\r
311#define SPSG fdso.SPSG\r
312#define b19shiftreg60 fdso.b19shiftreg60\r
313#define b24adder66 fdso.b24adder66\r
314#define b24latch68 fdso.b24latch68\r
315#define b17latch76 fdso.b17latch76\r
316#define b8shiftreg88 fdso.b8shiftreg88\r
317#define clockcount fdso.clockcount\r
318#define amplitude fdso.amplitude\r
319#define speedo fdso.speedo\r
320\r
321void FDSSoundStateAdd(void)\r
322{\r
323 AddExState(fdso.cwave,64,0,"WAVE");\r
324 AddExState(fdso.mwave,32,0,"MWAV");\r
325 AddExState(amplitude,2,0,"AMPL");\r
326 AddExState(SPSG,0xB,0,"SPSG");\r
327\r
328 AddExState(&b8shiftreg88,1,0,"B88");\r
329\r
330 AddExState(&clockcount, 4, 1, "CLOC");\r
331 AddExState(&b19shiftreg60,4,1,"B60");\r
332 AddExState(&b24adder66,4,1,"B66");\r
333 AddExState(&b24latch68,4,1,"B68");\r
334 AddExState(&b17latch76,4,1,"B76");\r
335\r
336}\r
337\r
338static DECLFR(FDSSRead)\r
339{\r
340 switch(A&0xF)\r
341 {\r
342 case 0x0:return(amplitude[0]|(X.DB&0xC0));\r
343 case 0x2:return(amplitude[1]|(X.DB&0xC0));\r
344 }\r
345 return(X.DB);\r
346}\r
347\r
348static DECLFW(FDSSWrite)\r
349{\r
350 if(FSettings.SndRate)\r
351 {\r
352#if 0\r
353 if(FSettings.soundq>=1)\r
354 RenderSoundHQ();\r
355 else\r
356#endif\r
357 RenderSound();\r
358 }\r
359 A-=0x4080;\r
360 switch(A)\r
361 {\r
362 case 0x0:\r
363 case 0x4: if(V&0x80)\r
364 amplitude[(A&0xF)>>2]=V&0x3F; //)>0x20?0x20:(V&0x3F);\r
365 break;\r
366 case 0x5://printf("$%04x:$%02x\n",A,V);\r
367 break;\r
368 case 0x7: b17latch76=0;SPSG[0x5]=0;//printf("$%04x:$%02x\n",A,V);\r
369 break;\r
370 case 0x8:\r
371 b17latch76=0;\r
372 // printf("%d:$%02x, $%02x\n",SPSG[0x5],V,b17latch76);\r
373 fdso.mwave[SPSG[0x5]&0x1F]=V&0x7;\r
374 SPSG[0x5]=(SPSG[0x5]+1)&0x1F;\r
375 break;\r
376 }\r
377 //if(A>=0x7 && A!=0x8 && A<=0xF)\r
378 //if(A==0xA || A==0x9)\r
379 //printf("$%04x:$%02x\n",A,V);\r
380 SPSG[A]=V;\r
381}\r
382\r
383// $4080 - Fundamental wave amplitude data register 92\r
384// $4082 - Fundamental wave frequency data register 58\r
385// $4083 - Same as $4082($4083 is the upper 4 bits).\r
386\r
387// $4084 - Modulation amplitude data register 78\r
388// $4086 - Modulation frequency data register 72\r
389// $4087 - Same as $4086($4087 is the upper 4 bits)\r
390\r
391\r
392static void DoEnv()\r
393{\r
394 int x;\r
395\r
396 for(x=0;x<2;x++)\r
397 if(!(SPSG[x<<2]&0x80) && !(SPSG[0x3]&0x40))\r
398 {\r
399 static int counto[2]={0,0};\r
400\r
401 if(counto[x]<=0)\r
402 {\r
403 if(!(SPSG[x<<2]&0x80))\r
404 {\r
405 if(SPSG[x<<2]&0x40)\r
406 {\r
407 if(amplitude[x]<0x3F)\r
408 amplitude[x]++;\r
409 }\r
410 else\r
411 {\r
412 if(amplitude[x]>0)\r
413 amplitude[x]--;\r
414 }\r
415 }\r
416 counto[x]=(SPSG[x<<2]&0x3F);\r
417 }\r
418 else\r
419 counto[x]--;\r
420 }\r
421}\r
422\r
423static DECLFR(FDSWaveRead)\r
424{\r
425 return(fdso.cwave[A&0x3f]|(X.DB&0xC0));\r
426}\r
427\r
428static DECLFW(FDSWaveWrite)\r
429{\r
430 //printf("$%04x:$%02x, %d\n",A,V,SPSG[0x9]&0x80);\r
431 if(SPSG[0x9]&0x80)\r
432 fdso.cwave[A&0x3f]=V&0x3F;\r
433}\r
434\r
435static int ta;\r
436static INLINE void ClockRise(void)\r
437{\r
438 if(!clockcount)\r
439 {\r
440 ta++;\r
441\r
442 b19shiftreg60=(SPSG[0x2]|((SPSG[0x3]&0xF)<<8));\r
443 b17latch76=(SPSG[0x6]|((SPSG[0x07]&0xF)<<8))+b17latch76;\r
444\r
445 if(!(SPSG[0x7]&0x80))\r
446 {\r
447 int t=fdso.mwave[(b17latch76>>13)&0x1F]&7;\r
448 int t2=amplitude[1];\r
449 int adj = 0;\r
450\r
451 if((t&3))\r
452 {\r
453 if((t&4))\r
454 adj -= (t2 * ((4 - (t&3) ) ));\r
455 else\r
456 adj += (t2 * ( (t&3) ));\r
457 }\r
458 adj *= 2;\r
459 if(adj > 0x7F) adj = 0x7F;\r
460 if(adj < -0x80) adj = -0x80;\r
461 //if(adj) printf("%d ",adj);\r
462 b8shiftreg88=0x80 + adj;\r
463 }\r
464 else\r
465 {\r
466 b8shiftreg88=0x80;\r
467 }\r
468 }\r
469 else\r
470 {\r
471 b19shiftreg60<<=1;\r
472 b8shiftreg88>>=1;\r
473 }\r
474// b24adder66=(b24latch68+b19shiftreg60)&0x3FFFFFF;\r
475 b24adder66=(b24latch68+b19shiftreg60)&0x1FFFFFF;\r
476}\r
477\r
478static INLINE void ClockFall(void)\r
479{\r
480 //if(!(SPSG[0x7]&0x80))\r
481 {\r
482 if((b8shiftreg88&1)) // || clockcount==7)\r
483 b24latch68=b24adder66;\r
484 }\r
485 clockcount=(clockcount+1)&7;\r
486}\r
487\r
488static INLINE int32 FDSDoSound(void)\r
489{\r
490 fdso.count+=fdso.cycles;\r
491 if(fdso.count>=((int64)1<<40))\r
492 {\r
493 dogk:\r
494 fdso.count-=(int64)1<<40;\r
495 ClockRise();\r
496 ClockFall();\r
497 fdso.envcount--;\r
498 if(fdso.envcount<=0)\r
499 {\r
500 fdso.envcount+=SPSG[0xA]*3;\r
501 DoEnv();\r
502 }\r
503 }\r
504 if(fdso.count>=32768) goto dogk;\r
505\r
506 // Might need to emulate applying the amplitude to the waveform a bit better...\r
507 {\r
508 int k=amplitude[0];\r
509 if(k>0x20) k=0x20;\r
510 return (fdso.cwave[b24latch68>>19]*k)*4/((SPSG[0x9]&0x3)+2);\r
511 }\r
512}\r
513\r
514static int32 FBC=0;\r
515\r
516static void RenderSound(void)\r
517{\r
518 int32 end, start;\r
519 int32 x;\r
520\r
521 start=FBC;\r
522 end=(SOUNDTS<<16)/soundtsinc;\r
523 if(end<=start)\r
524 return;\r
525 FBC=end;\r
526\r
527 if(!(SPSG[0x9]&0x80))\r
528 for(x=start;x<end;x++)\r
529 {\r
530 uint32 t=FDSDoSound();\r
531 t+=t>>1;\r
532 t>>=4;\r
533 Wave[x>>4]+=t; //(t>>2)-(t>>3); //>>3;\r
534 }\r
535}\r
536\r
537#if 0\r
538static void RenderSoundHQ(void)\r
539{\r
540 int32 x;\r
541\r
542 if(!(SPSG[0x9]&0x80))\r
543 for(x=FBC;x<SOUNDTS;x++)\r
544 {\r
545 uint32 t=FDSDoSound();\r
546 t+=t>>1;\r
547 WaveHi[x]+=t; //(t<<2)-(t<<1);\r
548 }\r
549 FBC=SOUNDTS;\r
550}\r
551#endif\r
552\r
553static void HQSync(int32 ts)\r
554{\r
555 FBC=ts;\r
556}\r
557\r
558void FDSSound(int c)\r
559{\r
560 RenderSound();\r
561 FBC=c;\r
562}\r
563\r
564/*\r
565static DECLFR(FDSBIOSPatch)\r
566{\r
567 if(FDSRegs[5]&0x4)\r
568 {\r
569 X.X=FDSRead4031(0x4031);\r
570 FDSWrite(0x4024,X.A);\r
571 X.A=X.X;\r
572 return(0x60);\r
573 }\r
574 else\r
575 {\r
576 return(0x58);\r
577 //puts("Write");\r
578 }\r
579}\r
580*/\r
581\r
582static void FDS_ESI(void)\r
583{\r
584 if(FSettings.SndRate)\r
585 {\r
586#if 0\r
587 if(FSettings.soundq>=1)\r
588 {\r
589 fdso.cycles=(int64)1<<39;\r
590 }\r
591 else\r
592#endif\r
593 {\r
594 fdso.cycles=((int64)1<<40)*FDSClock;\r
595 fdso.cycles/=FSettings.SndRate *16;\r
596 }\r
597 }\r
598// fdso.cycles=(int64)32768*FDSClock/(FSettings.SndRate *16);\r
599 SetReadHandler(0x4040,0x407f,FDSWaveRead);\r
600 SetWriteHandler(0x4040,0x407f,FDSWaveWrite);\r
601 SetWriteHandler(0x4080,0x408A,FDSSWrite);\r
602 SetReadHandler(0x4090,0x4092,FDSSRead);\r
603\r
604 //SetReadHandler(0xE7A3,0xE7A3,FDSBIOSPatch);\r
605}\r
606\r
607void FDSSoundReset(void)\r
608{\r
609 memset(&fdso,0,sizeof(fdso));\r
610 FDS_ESI();\r
611 GameExpSound.HiSync=HQSync;\r
612 GameExpSound.HiFill=0;//RenderSoundHQ;\r
613 GameExpSound.Fill=FDSSound;\r
614 GameExpSound.RChange=FDS_ESI;\r
615}\r
616\r
617static DECLFW(FDSWrite)\r
618{\r
619 //extern int scanline;\r
620 //FCEU_printf("$%04x:$%02x, %d\n",A,V,scanline);\r
621 switch(A)\r
622 {\r
623 case 0x4020:\r
624 X6502_IRQEnd(FCEU_IQEXT);\r
625 IRQLatch&=0xFF00;\r
626 IRQLatch|=V;\r
627// printf("$%04x:$%02x\n",A,V);\r
628 break;\r
629 case 0x4021:\r
630 X6502_IRQEnd(FCEU_IQEXT);\r
631 IRQLatch&=0xFF;\r
632 IRQLatch|=V<<8;\r
633// printf("$%04x:$%02x\n",A,V);\r
634 break;\r
635 case 0x4022:\r
636 X6502_IRQEnd(FCEU_IQEXT);\r
637 IRQCount=IRQLatch;\r
638 IRQa=V&3;\r
639// printf("$%04x:$%02x\n",A,V);\r
640 break;\r
641 case 0x4023:break;\r
642 case 0x4024:\r
643 if(InDisk!=255 && !(FDSRegs[5]&0x4) && (FDSRegs[3]&0x1))\r
644 {\r
645 if(DiskPtr>=0 && DiskPtr<65500)\r
646 {\r
647 if(writeskip) writeskip--;\r
648 else if(DiskPtr>=2)\r
649 {\r
650 DiskWritten=1;\r
651 diskdata[InDisk][DiskPtr-2]=V;\r
652 }\r
653 }\r
654 }\r
655 break;\r
656 case 0x4025:\r
657 X6502_IRQEnd(FCEU_IQEXT2);\r
658 if(InDisk!=255)\r
659 {\r
660 if(!(V&0x40))\r
661 {\r
662 if(FDSRegs[5]&0x40 && !(V&0x10))\r
663 {\r
664 DiskSeekIRQ=200;\r
665 DiskPtr-=2;\r
666 }\r
667 if(DiskPtr<0) DiskPtr=0;\r
668 }\r
669 if(!(V&0x4)) writeskip=2;\r
670 if(V&2) {DiskPtr=0;DiskSeekIRQ=200;}\r
671 if(V&0x40) DiskSeekIRQ=200;\r
672 }\r
673 setmirror(((V>>3)&1)^1);\r
674 break;\r
675 }\r
676 FDSRegs[A&7]=V;\r
677}\r
678\r
679static void FreeFDSMemory(void)\r
680{\r
681 int x;\r
682\r
683 for(x=0;x<TotalSides;x++)\r
684 if(diskdata[x])\r
685 {\r
686 free(diskdata[x]);\r
687 diskdata[x]=0;\r
688 }\r
689}\r
690\r
691static int SubLoad(int fp)\r
692{\r
693 struct md5_context md5;\r
694 uint8 header[16];\r
695 int x;\r
696\r
697 FCEU_fread(header,16,1,fp);\r
698\r
699 if(memcmp(header,"FDS\x1a",4))\r
700 {\r
701 if(!(memcmp(header+1,"*NINTENDO-HVC*",14)))\r
702 {\r
703 long t;\r
704 t=FCEU_fgetsize(fp);\r
705 if(t<65500)\r
706 t=65500;\r
707 TotalSides=t/65500;\r
708 FCEU_fseek(fp,0,SEEK_SET);\r
709 }\r
710 else\r
711 return(0);\r
712 }\r
713 else\r
714 TotalSides=header[4];\r
715\r
716 md5_starts(&md5);\r
717\r
718 if(TotalSides>8) TotalSides=8;\r
719 if(TotalSides<1) TotalSides=1;\r
720\r
721 for(x=0;x<TotalSides;x++)\r
722 {\r
723 diskdata[x]=(uint8 *)FCEU_malloc(65500);\r
724 if(!diskdata[x])\r
725 {\r
726 int zol;\r
727 for(zol=0;zol<x;zol++)\r
728 free(diskdata[zol]);\r
729 return 0;\r
730 }\r
731 FCEU_fread(diskdata[x],1,65500,fp);\r
732 md5_update(&md5,diskdata[x],65500);\r
733 }\r
734 md5_finish(&md5,FCEUGameInfo.MD5);\r
735 return(1);\r
736}\r
737\r
738static void PreSave(void)\r
739{\r
740 int x;\r
741\r
742 //if(DiskWritten)\r
743 for(x=0;x<TotalSides;x++)\r
744 {\r
745 int b;\r
746 for(b=0; b<65500; b++)\r
747 diskdata[x][b] ^= diskdatao[x][b];\r
748 }\r
749}\r
750\r
751static void PostSave(void)\r
752{\r
753 int x;\r
754\r
755 //if(DiskWritten)\r
756 for(x=0;x<TotalSides;x++)\r
757 {\r
758 int b;\r
759\r
760 for(b=0; b<65500; b++)\r
761 diskdata[x][b] ^= diskdatao[x][b];\r
762 }\r
763\r
764}\r
765\r
766int FDSLoad(const char *name, int fp)\r
767{\r
768 FILE *zp;\r
769 int x;\r
770 char *fn;\r
771\r
772 FCEU_fseek(fp,0,SEEK_SET);\r
773\r
774 if(!SubLoad(fp))\r
775 return(0);\r
776\r
777\r
778 fn = FCEU_MakeFName(FCEUMKF_FDSROM,0,0);\r
779\r
780 if(!(zp=FCEUD_UTF8fopen(fn,"rb")))\r
781 {\r
782 FCEU_PrintError("FDS BIOS ROM image missing!");\r
783 FreeFDSMemory();\r
784 free(fn);\r
785 return 0;\r
786 }\r
787\r
788 free(fn);\r
789\r
790 if(fread(FDSBIOS,1,8192,zp)!=8192)\r
791 {\r
792 fclose(zp);\r
793 FreeFDSMemory();\r
794 FCEU_PrintError("Error reading FDS BIOS ROM image.");\r
795 return 0;\r
796 }\r
797\r
798 fclose(zp);\r
799\r
800\r
801 {\r
802 int tp;\r
803 char *fn=FCEU_MakeFName(FCEUMKF_FDS,0,0);\r
804\r
805 int x;\r
806 for(x=0;x<TotalSides;x++)\r
807 {\r
808 diskdatao[x]=(uint8 *)FCEU_malloc(65500);\r
809 memcpy(diskdatao[x],diskdata[x],65500);\r
810 }\r
811\r
812 if((tp=FCEU_fopen(fn,"rb")))\r
813 {\r
814 FreeFDSMemory();\r
815 if(!SubLoad(tp))\r
816 {\r
817 FCEU_PrintError("Error reading auxillary FDS file.");\r
818 free(fn);\r
819 return(0);\r
820 }\r
821 FCEU_fclose(tp);\r
822 DiskWritten=1; /* For save state handling. */\r
823 }\r
824 free(fn);\r
825 }\r
826\r
827 FCEUGameInfo.type=GIT_FDS;\r
828 GameInterface=FDSGI;\r
829\r
830 SelectDisk=0;\r
831 InDisk=255;\r
832\r
833 ResetExState(PreSave,PostSave);\r
834 FDSSoundStateAdd();\r
835\r
836 for(x=0;x<TotalSides;x++)\r
837 {\r
838 char temp[5];\r
839 sprintf(temp,"DDT%d",x);\r
840 AddExState(diskdata[x],65500,0,temp);\r
841 }\r
842\r
843 AddExState(FDSRAM,32768,0,"FDSR");\r
844 AddExState(FDSRegs,sizeof(FDSRegs),0,"FREG");\r
845 AddExState(CHRRAM,8192,0,"CHRR");\r
846 AddExState(&IRQCount, 4, 1, "IRQC");\r
847 AddExState(&IRQLatch, 4, 1, "IQL1");\r
848 AddExState(&IRQa, 1, 0, "IRQA");\r
849 AddExState(&writeskip,1,0,"WSKI");\r
850 AddExState(&DiskPtr,4,1,"DPTR");\r
851 AddExState(&DiskSeekIRQ,4,1,"DSIR");\r
852 AddExState(&SelectDisk,1,0,"SELD");\r
853 AddExState(&InDisk,1,0,"INDI");\r
854 AddExState(&DiskWritten,1,0,"DSKW");\r
855\r
856 ResetCartMapping();\r
857 SetupCartCHRMapping(0,CHRRAM,8192,1);\r
858 SetupCartMirroring(0,0,0);\r
859 memset(CHRRAM,0,8192);\r
860 memset(FDSRAM,0,32768);\r
861\r
862 FCEU_printf(" Sides: %d\n\n",TotalSides);\r
863\r
864 FCEUI_SetVidSystem(0);\r
865\r
866 return 1;\r
867}\r
868\r
869void FDSClose(void)\r
870{\r
871 FILE *fp;\r
872 int x;\r
873 char *fn=FCEU_MakeFName(FCEUMKF_FDS,0,0);\r
874\r
875 if(!DiskWritten) return;\r
876\r
877 if(!(fp=FCEUD_UTF8fopen(fn,"wb")))\r
878 {\r
879 free(fn);\r
880 return;\r
881 }\r
882 free(fn);\r
883\r
884 for(x=0;x<TotalSides;x++)\r
885 {\r
886 if(fwrite(diskdata[x],1,65500,fp)!=65500)\r
887 {\r
888 FCEU_PrintError("Error saving FDS image!");\r
889 fclose(fp);\r
890 return;\r
891 }\r
892 }\r
893 FreeFDSMemory();\r
894 fclose(fp);\r
895}\r