more opt. in sound.c, vol incresed
[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
e1591a12 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
d97315ac 158}\r
159\r
160void 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
179void FCEU_FDSEject(void)\r
180{\r
181 InDisk=255;\r
182}\r
183*/\r
184void 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
200static void FP_FASTAPASS(1) FDSFix(int a)\r
201{\r
e1591a12 202 if(IRQCount && (IRQa&2))\r
d97315ac 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
233static DECLFR(FDSRead4030)\r
234{\r
235 uint8 ret=0;\r
236\r
237 /* Cheap hack. */\r
e1591a12 238#ifndef ASM_6502\r
d97315ac 239 if(X.IRQlow&FCEU_IQEXT) ret|=1;\r
240 if(X.IRQlow&FCEU_IQEXT2) ret|=2;\r
e1591a12 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
d97315ac 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
254static 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
269static 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
282static DECLFR(FDSRead4033)\r
283{\r
284 return 0x80; // battery\r
285}\r
286\r
287static DECLFW(FDSRAMWrite)\r
288{\r
289 (FDSRAM-0x6000)[A]=V;\r
290}\r
291\r
292static DECLFR(FDSBIOSRead)\r
293{\r
294 return (FDSBIOS-0xE000)[A];\r
295}\r
296\r
297static 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
306typedef 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
325static 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
337void 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
354static 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
364static 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
408static 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
439static DECLFR(FDSWaveRead)\r
440{\r
441 return(fdso.cwave[A&0x3f]|(X.DB&0xC0));\r
442}\r
443\r
444static 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
451static int ta;\r
452static 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
494static 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
e1591a12 504static INLINE int32 FDSDoSound(int32 mul)\r
d97315ac 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
e1591a12 523/*\r
d97315ac 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
e1591a12 529*/\r
530 return (fdso.cwave[b24latch68>>19]*mul)>>16;\r
d97315ac 531}\r
532\r
533static int32 FBC=0;\r
534\r
535static void RenderSound(void)\r
536{\r
537 int32 end, start;\r
538 int32 x;\r
e1591a12 539 int32 mul;\r
d97315ac 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
e1591a12 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
d97315ac 564 if(!(SPSG[0x9]&0x80))\r
565 for(x=start;x<end;x++)\r
566 {\r
e1591a12 567 uint32 t=FDSDoSound(mul);\r
d97315ac 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
575static 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
590static void HQSync(int32 ts)\r
591{\r
592 FBC=ts;\r
593}\r
594\r
595void FDSSound(int c)\r
596{\r
597 RenderSound();\r
598 FBC=c;\r
599}\r
600\r
601/*\r
602static 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
619static 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
644void 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
654static 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
716static 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
728static 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
775static 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
788static 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
803int 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
989672f4 822 LoadGameLastError = 10;\r
d97315ac 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
989672f4 833 LoadGameLastError = 10;\r
d97315ac 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
989672f4 858 LoadGameLastError = 11;\r
d97315ac 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
909void 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