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