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