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