random warning fixes
[fceu.git] / boards / n106.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "mapinc.h"
22
23 static uint16 IRQCount;
24 static uint8 IRQa;
25
26 static uint8 WRAM[8192];
27 static uint8 IRAM[128];
28
29 static DECLFR(AWRAM)
30 {
31   return(WRAM[A-0x6000]);
32 }
33
34 static DECLFW(BWRAM)
35 {
36   WRAM[A-0x6000]=V;
37 }
38
39 void Mapper19_ESI(void);
40
41 static uint8 NTAPage[4];
42
43 static uint8 dopol;
44 static uint8 gorfus;
45 static uint8 gorko;
46
47 static void NamcoSound(int Count);
48 static void NamcoSoundHack(void);
49 static void DoNamcoSound(int32 *Wave, int Count);
50 static void DoNamcoSoundHQ(void);
51 static void SyncHQ(int32 ts);
52
53 static int is210;        /* Lesser mapper. */
54
55 static uint8 PRG[3];
56 static uint8 CHR[8];
57
58 static SFORMAT N106_StateRegs[]={
59   {PRG,3,"PRG"},
60   {CHR,8,"CHR"},
61   {NTAPage,4,"NTA"},
62   {0}
63 };
64
65 static void SyncPRG(void)
66 {
67   setprg8(0x8000,PRG[0]);
68   setprg8(0xa000,PRG[1]);
69   setprg8(0xc000,PRG[2]);
70   setprg8(0xe000,0x3F);
71 }
72
73 static void FP_FASTAPASS(1) NamcoIRQHook(int a)
74 {
75   if(IRQa)
76   {
77     IRQCount+=a;
78     if(IRQCount>=0x7FFF)
79     {
80       X6502_IRQBegin(FCEU_IQEXT);
81       IRQa=0;
82       IRQCount=0x7FFF; //7FFF;
83     }
84   }
85 }
86
87 static DECLFR(Namco_Read4800)
88 {
89   uint8 ret=IRAM[dopol&0x7f];
90   /* Maybe I should call NamcoSoundHack() here? */
91   #ifdef FCEUDEF_DEBUGGER
92   if(!fceuindbg)
93   #endif
94     if(dopol&0x80)
95       dopol=(dopol&0x80)|((dopol+1)&0x7f);
96   return ret;
97 }
98
99 static DECLFR(Namco_Read5000)
100 {
101   return(IRQCount);
102 }
103
104 static DECLFR(Namco_Read5800)
105 {
106   return(IRQCount>>8);
107 }
108
109 static void FASTAPASS(2) DoNTARAMROM(int w, uint8 V)
110 {
111   NTAPage[w]=V;
112   if(V>=0xE0)
113     setntamem(NTARAM+((V&1)<<10), 1, w);
114   else
115   {
116     V&=CHRmask1[0];
117     setntamem(CHRptr[0]+(V<<10), 0, w);
118   }
119 }
120
121 static void FixNTAR(void)
122 {
123   int x;
124   for(x=0;x<4;x++)
125      DoNTARAMROM(x,NTAPage[x]);
126 }
127
128 static void FASTAPASS(2) DoCHRRAMROM(int x, uint8 V)
129 {
130   CHR[x]=V;
131   if(!is210 && !((gorfus>>((x>>2)+6))&1) && (V>=0xE0))
132   {
133     // printf("BLAHAHA: %d, %02x\n",x,V);
134     //setchr1r(0x10,x<<10,V&7);
135   }
136   else
137     setchr1(x<<10,V);
138 }
139
140 static void FixCRR(void)
141 {
142   int x;
143   for(x=0;x<8;x++)
144      DoCHRRAMROM(x,CHR[x]);
145 }
146
147 static DECLFW(Mapper19C0D8_write)
148 {
149   DoNTARAMROM((A-0xC000)>>11,V);
150 }
151
152 static uint32 FreqCache[8];
153 static uint32 EnvCache[8];
154 static uint32 LengthCache[8];
155
156 static void FixCache(int a,int V)
157 {
158   int w=(a>>3)&0x7;
159   switch(a&0x07)
160   {
161     case 0x00:FreqCache[w]&=~0x000000FF;FreqCache[w]|=V;break;
162     case 0x02:FreqCache[w]&=~0x0000FF00;FreqCache[w]|=V<<8;break;
163     case 0x04:FreqCache[w]&=~0x00030000;FreqCache[w]|=(V&3)<<16;
164               LengthCache[w]=(8-((V>>2)&7))<<2;
165               break;
166     case 0x07:EnvCache[w]=(double)(V&0xF)*576716;break;
167   }
168 }
169
170 static DECLFW(Mapper19_write)
171 {
172   A&=0xF800;
173   if(A>=0x8000 && A<=0xb800)
174     DoCHRRAMROM((A-0x8000)>>11,V);
175   else switch(A)
176   {
177     case 0x4800:
178          if(dopol&0x40)
179          {
180            if(FSettings.SndRate)
181            {
182              NamcoSoundHack();
183              GameExpSound.Fill=NamcoSound;
184              GameExpSound.HiFill=DoNamcoSoundHQ;
185              GameExpSound.HiSync=SyncHQ;
186            }
187            FixCache(dopol,V);
188          }
189          IRAM[dopol&0x7f]=V;
190          if(dopol&0x80)
191            dopol=(dopol&0x80)|((dopol+1)&0x7f);
192          break;
193     case 0xf800:
194          dopol=V;break;
195     case 0x5000:
196          IRQCount&=0xFF00;IRQCount|=V;X6502_IRQEnd(FCEU_IQEXT);break;
197     case 0x5800:
198          IRQCount&=0x00ff;IRQCount|=(V&0x7F)<<8;
199          IRQa=V&0x80;
200          X6502_IRQEnd(FCEU_IQEXT);
201          break;
202     case 0xE000:
203          gorko=V&0xC0;
204          PRG[0]=V&0x3F;
205          SyncPRG();
206          break;
207     case 0xE800:
208          gorfus=V&0xC0;
209          FixCRR();
210          PRG[1]=V&0x3F;
211          SyncPRG();
212          break;
213     case 0xF000:
214          PRG[2]=V&0x3F;
215          SyncPRG();
216          break;
217   }
218 }
219
220 static int dwave=0;
221
222 static void NamcoSoundHack(void)
223 {
224   int32 z,a;
225   if(FSettings.soundq>=1)
226   {
227     DoNamcoSoundHQ();
228     return;
229   }
230   z=((SOUNDTS<<16)/soundtsinc)>>4;
231   a=z-dwave;
232   if(a) DoNamcoSound(&Wave[dwave], a);
233   dwave+=a;
234 }
235
236 static void NamcoSound(int Count)
237 {
238   int32 z,a;
239   z=((SOUNDTS<<16)/soundtsinc)>>4;
240   a=z-dwave;
241   if(a) DoNamcoSound(&Wave[dwave], a);
242   dwave=0;
243 }
244
245 static uint32 PlayIndex[8];
246 static int32 vcount[8];
247 static int32 CVBC;
248
249 #define TOINDEX        (16+1)
250
251 // 16:15
252 static void SyncHQ(int32 ts)
253 {
254   CVBC=ts;
255 }
256
257
258 /* Things to do:
259         1        Read freq low
260         2        Read freq mid
261         3        Read freq high
262         4        Read envelope
263         ...?
264 */
265
266 static INLINE uint32 FetchDuff(uint32 P, uint32 envelope)
267 {
268   uint32 duff;
269   duff=IRAM[((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&0xFF)>>1];
270   if((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&1)
271     duff>>=4;
272   duff&=0xF;
273   duff=(duff*envelope)>>16;
274   return(duff);
275 }
276
277 static void DoNamcoSoundHQ(void)
278 {
279   int32 P,V;
280   int32 cyclesuck=(((IRAM[0x7F]>>4)&7)+1)*15;
281
282   for(P=7;P>=(7-((IRAM[0x7F]>>4)&7));P--)
283   {
284     if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
285     {
286       uint32 freq;
287       int32 vco;
288       uint32 duff2,lengo,envelope;
289
290       vco=vcount[P];
291       freq=FreqCache[P];
292       envelope=EnvCache[P];
293       lengo=LengthCache[P];
294
295       duff2=FetchDuff(P,envelope);
296       for(V=CVBC<<1;V<SOUNDTS<<1;V++)
297       {
298         WaveHi[V>>1]+=duff2;
299         if(!vco)
300         {
301           PlayIndex[P]+=freq;
302           while((PlayIndex[P]>>TOINDEX)>=lengo) PlayIndex[P]-=lengo<<TOINDEX;
303           duff2=FetchDuff(P,envelope);
304           vco=cyclesuck;
305         }
306         vco--;
307       }
308       vcount[P]=vco;
309     }
310   }
311   CVBC=SOUNDTS;
312 }
313
314
315 static void DoNamcoSound(int32 *Wave, int Count)
316 {
317   int P,V;
318   for(P=7;P>=7-((IRAM[0x7F]>>4)&7);P--)
319   {
320     if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
321     {
322       int32 inc;
323       uint32 freq;
324       int32 vco;
325       uint32 duff,duff2,lengo,envelope;
326
327       vco=vcount[P];
328       freq=FreqCache[P];
329       envelope=EnvCache[P];
330       lengo=LengthCache[P];
331
332       if(!freq) {/*printf("Ack");*/  continue;}
333
334       {
335         int c=((IRAM[0x7F]>>4)&7)+1;
336         inc=(long double)(FSettings.SndRate<<15)/((long double)freq*21477272/((long double)0x400000*c*45));
337       }
338
339       duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
340       if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
341         duff>>=4;
342       duff&=0xF;
343       duff2=(duff*envelope)>>19;
344       for(V=0;V<Count*16;V++)
345       {
346         if(vco>=inc)
347         {
348           PlayIndex[P]++;
349           if(PlayIndex[P]>=lengo)
350             PlayIndex[P]=0;
351           vco-=inc;
352           duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
353           if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
354             duff>>=4;
355           duff&=0xF;
356           duff2=(duff*envelope)>>19;
357         }
358         Wave[V>>4]+=duff2;
359         vco+=0x8000;
360       }
361       vcount[P]=vco;
362     }
363   }
364 }
365
366 static void Mapper19_StateRestore(int version)
367 {
368   SyncPRG();
369   FixNTAR();
370   FixCRR();
371   int x;
372   for(x=0x40;x<0x80;x++)
373      FixCache(x,IRAM[x]);
374 }
375
376 static void M19SC(void)
377 {
378   if(FSettings.SndRate)
379     Mapper19_ESI();
380 }
381
382 void Mapper19_ESI(void)
383 {
384   GameExpSound.RChange=M19SC;
385   memset(vcount,0,sizeof(vcount));
386   memset(PlayIndex,0,sizeof(PlayIndex));
387   CVBC=0;
388 }
389
390 void NSFN106_Init(void)
391 {
392   SetWriteHandler(0xf800,0xffff,Mapper19_write);
393   SetWriteHandler(0x4800,0x4fff,Mapper19_write);
394   SetReadHandler(0x4800,0x4fff,Namco_Read4800);
395   Mapper19_ESI();
396 }
397
398 static int battery=0;
399
400 static void N106_Power(void)
401 {
402   int x;
403   SetReadHandler(0x8000,0xFFFF,CartBR);
404   SetWriteHandler(0x8000,0xffff,Mapper19_write);
405   SetWriteHandler(0x4020,0x5fff,Mapper19_write);
406   if(!is210)
407   {
408     SetWriteHandler(0xc000,0xdfff,Mapper19C0D8_write);
409     SetReadHandler(0x4800,0x4fff,Namco_Read4800);
410     SetReadHandler(0x5000,0x57ff,Namco_Read5000);
411     SetReadHandler(0x5800,0x5fff,Namco_Read5800);
412     NTAPage[0]=NTAPage[1]=NTAPage[2]=NTAPage[3]=0xFF;
413     FixNTAR();
414   }
415
416   SetReadHandler(0x6000,0x7FFF,AWRAM);
417   SetWriteHandler(0x6000,0x7FFF,BWRAM);
418   FCEU_CheatAddRAM(8,0x6000,WRAM);
419
420   gorfus=0xFF;
421   SyncPRG();
422   FixCRR();
423
424   if(!battery)
425   {
426     FCEU_dwmemset(WRAM,0,8192);
427     FCEU_dwmemset(IRAM,0,128);
428   }
429   for(x=0x40;x<0x80;x++)
430      FixCache(x,IRAM[x]);
431 }
432
433 void Mapper19_Init(CartInfo *info)
434 {
435   is210=0;
436   battery=info->battery;
437   info->Power=N106_Power;
438
439   MapIRQHook=NamcoIRQHook;
440   GameStateRestore=Mapper19_StateRestore;
441   GameExpSound.RChange=M19SC;
442
443   if(FSettings.SndRate)
444     Mapper19_ESI();
445
446   AddExState(WRAM, 8192, 0, "WRAM");
447   AddExState(IRAM, 128, 0, "IRAM");
448   AddExState(N106_StateRegs, ~0, 0, 0);
449
450   if(info->battery)
451   {
452     info->SaveGame[0]=WRAM;
453     info->SaveGameLen[0]=8192;
454     info->SaveGame[1]=IRAM;
455     info->SaveGameLen[1]=128;
456   }
457 }
458
459 static void Mapper210_StateRestore(int version)
460 {
461   SyncPRG();
462   FixCRR();
463 }
464
465 void Mapper210_Init(CartInfo *info)
466 {
467   is210=1;
468   GameStateRestore=Mapper210_StateRestore;
469   info->Power=N106_Power;
470   AddExState(WRAM, 8192, 0, "WRAM");
471   AddExState(N106_StateRegs, ~0, 0, 0);
472 }