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