merge mappers from FCEU-mm
[fceu.git] / mappers / 24and26.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  * VRC-6
21  *
22  */
23
24 #include "mapinc.h"
25
26 static void (*sfun[3])(void);
27
28 #define vrctemp mapbyte1[0]
29 #define VPSG2 mapbyte3
30 #define VPSG mapbyte2
31
32 static void DoSQV1(void);
33 static void DoSQV2(void);
34 static void DoSawV(void);
35
36 static int swaparoo;
37
38 static int acount=0;
39
40 static void FP_FASTAPASS(1) KonamiIRQHook(int a)
41 {
42   #define LCYCS 341
43 //  #define LCYCS ((227*2)+1)
44   if(IRQa)
45   {
46    acount+=a*3;
47    if(acount>=LCYCS)
48    {
49     doagainbub:acount-=LCYCS;IRQCount++;
50     if(IRQCount==0x100)
51     {
52      X6502_IRQBegin(FCEU_IQEXT);
53      IRQCount=IRQLatch;
54     }
55     if(acount>=LCYCS) goto doagainbub;
56    }
57  }
58 }
59
60 static DECLFW(VRC6SW)
61 {
62         A&=0xF003;
63         if(A>=0x9000 && A<=0x9002)
64         {
65          VPSG[A&3]=V;
66          if(sfun[0]) sfun[0]();
67         }
68         else if(A>=0xa000 && A<=0xa002)
69         {
70          VPSG[4|(A&3)]=V;
71          if(sfun[1]) sfun[1]();
72         }
73         else if(A>=0xb000 && A<=0xb002)
74         {
75          VPSG2[A&3]=V;
76          if(sfun[2]) sfun[2]();
77         }
78
79 }
80
81 static DECLFW(Mapper24_write)
82 {
83         if(swaparoo)
84          A=(A&0xFFFC)|((A>>1)&1)|((A<<1)&2);
85         if(A>=0x9000 && A<=0xb002)
86         {
87          VRC6SW(A,V);
88          return;
89         }
90         A&=0xF003;
91 //        if(A>=0xF000) printf("%d, %d, $%04x:$%02x\n",scanline,timestamp,A,V);
92         switch(A&0xF003)
93         {
94          case 0x8000:ROM_BANK16(0x8000,V);break;
95          case 0xB003:
96                     switch(V&0xF)
97                  {
98                   case 0x0:MIRROR_SET2(1);break;
99                   case 0x4:MIRROR_SET2(0);break;
100                   case 0x8:onemir(0);break;
101                   case 0xC:onemir(1);break;
102                  }
103                  break;
104          case 0xC000:ROM_BANK8(0xC000,V);break;
105          case 0xD000:VROM_BANK1(0x0000,V);break;
106          case 0xD001:VROM_BANK1(0x0400,V);break;
107          case 0xD002:VROM_BANK1(0x0800,V);break;
108          case 0xD003:VROM_BANK1(0x0c00,V);break;
109          case 0xE000:VROM_BANK1(0x1000,V);break;
110          case 0xE001:VROM_BANK1(0x1400,V);break;
111          case 0xE002:VROM_BANK1(0x1800,V);break;
112          case 0xE003:VROM_BANK1(0x1c00,V);break;
113          case 0xF000:IRQLatch=V;
114                         //acount=0;
115                         break;
116          case 0xF001:IRQa=V&2;
117                      vrctemp=V&1;
118                      if(V&2)
119                      {
120                       IRQCount=IRQLatch;
121                       acount=0;
122                      }
123                      X6502_IRQEnd(FCEU_IQEXT);
124                      break;
125          case 0xf002:IRQa=vrctemp;
126                      X6502_IRQEnd(FCEU_IQEXT);break;
127          case 0xF003:break;
128   }
129 }
130
131 static int32 CVBC[3];
132 static int32 vcount[3];
133 static int32 dcount[2];
134
135 static INLINE void DoSQV(int x)
136 {
137  int32 V;
138  int32 amp=(((VPSG[x<<2]&15)<<8)*6/8)>>4;
139  int32 start,end;
140
141  start=CVBC[x];
142  end=(SOUNDTS<<16)/soundtsinc;
143  if(end<=start) return;
144  CVBC[x]=end;
145
146  if(VPSG[(x<<2)|0x2]&0x80)
147  {
148   if(VPSG[x<<2]&0x80)
149   {
150    for(V=start;V<end;V++)
151     Wave[V>>4]+=amp;
152   }
153   else
154   {
155    int32 thresh=(VPSG[x<<2]>>4)&7;
156    int32 freq=((VPSG[(x<<2)|0x1]|((VPSG[(x<<2)|0x2]&15)<<8))+1)<<17;
157    for(V=start;V<end;V++)
158    {
159     if(dcount[x]>thresh)        /* Greater than, not >=.  Important. */
160      Wave[V>>4]+=amp;
161     vcount[x]-=nesincsize;
162     while(vcount[x]<=0)            /* Should only be <0 in a few circumstances. */
163     {
164      vcount[x]+=freq;
165      dcount[x]=(dcount[x]+1)&15;
166     }
167    }
168   }
169  }
170 }
171
172 static void DoSQV1(void)
173 {
174  DoSQV(0);
175 }
176
177 static void DoSQV2(void)
178 {
179  DoSQV(1);
180 }
181
182 static void DoSawV(void)
183 {
184     int V;
185     int32 start,end;
186
187     start=CVBC[2];
188     end=(SOUNDTS<<16)/soundtsinc;
189     if(end<=start) return;
190     CVBC[2]=end;
191
192    if(VPSG2[2]&0x80)
193    {
194     static int32 saw1phaseacc=0;
195     uint32 freq3;
196     static uint8 b3=0;
197     static int32 phaseacc=0;
198     static uint32 duff=0;
199
200     freq3=(VPSG2[1]+((VPSG2[2]&15)<<8)+1);
201
202     for(V=start;V<end;V++)
203     {
204      saw1phaseacc-=nesincsize;
205      if(saw1phaseacc<=0)
206      {
207       int32 t;
208       rea:
209       t=freq3;
210       t<<=18;
211       saw1phaseacc+=t;
212       phaseacc+=VPSG2[0]&0x3f;
213       b3++;
214       if(b3==7)
215       {
216        b3=0;
217        phaseacc=0;
218       }
219       if(saw1phaseacc<=0)
220        goto rea;
221       duff=(((phaseacc>>3)&0x1f)<<4)*6/8;
222       }
223      Wave[V>>4]+=duff;
224     }
225    }
226 }
227
228 static INLINE void DoSQVHQ(int x)
229 {
230  int32 V;
231  int32 amp=((VPSG[x<<2]&15)<<8)*6/8;
232
233  if(VPSG[(x<<2)|0x2]&0x80)
234  {
235   if(VPSG[x<<2]&0x80)
236   {
237    for(V=CVBC[x];V<SOUNDTS;V++)
238     WaveHi[V]+=amp;
239   }
240   else
241   {
242    int32 thresh=(VPSG[x<<2]>>4)&7;
243    for(V=CVBC[x];V<SOUNDTS;V++)
244    {
245     if(dcount[x]>thresh)        /* Greater than, not >=.  Important. */
246      WaveHi[V]+=amp;
247     vcount[x]--;
248     if(vcount[x]<=0)            /* Should only be <0 in a few circumstances. */
249     {
250      vcount[x]=(VPSG[(x<<2)|0x1]|((VPSG[(x<<2)|0x2]&15)<<8))+1;
251      dcount[x]=(dcount[x]+1)&15;
252     }
253    }
254   }
255  }
256  CVBC[x]=SOUNDTS;
257 }
258
259 static void DoSQV1HQ(void)
260 {
261  DoSQVHQ(0);
262 }
263
264 static void DoSQV2HQ(void)
265 {
266  DoSQVHQ(1);
267 }
268
269 static void DoSawVHQ(void)
270 {
271  static uint8 b3=0;
272  static int32 phaseacc=0;
273  int32 V;
274
275  if(VPSG2[2]&0x80)
276  {
277   for(V=CVBC[2];V<SOUNDTS;V++)
278   {
279    WaveHi[V]+=(((phaseacc>>3)&0x1f)<<8)*6/8;
280    vcount[2]--;
281    if(vcount[2]<=0)
282    {
283     vcount[2]=(VPSG2[1]+((VPSG2[2]&15)<<8)+1)<<1;
284     phaseacc+=VPSG2[0]&0x3f;
285     b3++;
286     if(b3==7)
287     {
288      b3=0;
289      phaseacc=0;
290    }
291
292    }
293   }
294  }
295  CVBC[2]=SOUNDTS;
296 }
297
298
299 void VRC6Sound(int Count)
300 {
301     int x;
302
303     DoSQV1();
304     DoSQV2();
305     DoSawV();
306     for(x=0;x<3;x++)
307      CVBC[x]=Count;
308 }
309
310 void VRC6SoundHQ(void)
311 {
312     DoSQV1HQ();
313     DoSQV2HQ();
314     DoSawVHQ();
315 }
316
317 void VRC6SyncHQ(int32 ts)
318 {
319  int x;
320  for(x=0;x<3;x++) CVBC[x]=ts;
321 }
322
323 static void VRC6_ESI(void)
324 {
325         GameExpSound.RChange=VRC6_ESI;
326         GameExpSound.Fill=VRC6Sound;
327         GameExpSound.HiFill=VRC6SoundHQ;
328         GameExpSound.HiSync=VRC6SyncHQ;
329
330         memset(CVBC,0,sizeof(CVBC));
331         memset(vcount,0,sizeof(vcount));
332         memset(dcount,0,sizeof(dcount));
333         if(FSettings.SndRate)
334         {
335          if(FSettings.soundq>=1)
336          {
337           sfun[0]=DoSQV1HQ;
338           sfun[1]=DoSQV2HQ;
339           sfun[2]=DoSawVHQ;
340          }
341          else
342          {
343           sfun[0]=DoSQV1;
344           sfun[1]=DoSQV2;
345           sfun[2]=DoSawV;
346          }
347         }
348         else
349          memset(sfun,0,sizeof(sfun));
350 }
351
352 void Mapper24_init(void)
353 {
354         SetWriteHandler(0x8000,0xffff,Mapper24_write);
355         VRC6_ESI();
356         MapIRQHook=KonamiIRQHook;
357         swaparoo=0;
358 }
359
360 void Mapper26_init(void)
361 {
362         SetWriteHandler(0x8000,0xffff,Mapper24_write);
363         VRC6_ESI();
364         MapIRQHook=KonamiIRQHook;
365         swaparoo=1;
366 }
367
368 void NSFVRC6_Init(void)
369 {
370         VRC6_ESI();
371         SetWriteHandler(0x8000,0xbfff,VRC6SW);
372 }