initial fce ultra 0.81 import
[fceu.git] / mappers / 24and26.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
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 #define vrctemp mapbyte1[0]
24 #define regb000 mapbyte3[0]
25 #define regb001 mapbyte3[1]
26 #define regb002 mapbyte3[2]
27 #define exchstat mapbyte4[0]
28 #define VPSG2 mapbyte3
29 #define VPSG mapbyte2
30
31 static void DoSQV1(void);
32 static void DoSQV2(void);
33 static void DoSawV(void);
34
35 static int swaparoo;
36 static int32 inc;
37 static DECLFW(VRC6PSGW90)
38 {
39  DoSQV1();VPSG[0]=V;
40 }
41 static DECLFW(VRC6PSGW91)
42 {
43  DoSQV1();VPSG[2]=V;
44 }
45 static DECLFW(VRC6PSGW92)
46 {
47  DoSQV1();VPSG[3]=V;
48 }
49 static DECLFW(VRC6PSGWA0)
50 {
51  DoSQV2();VPSG[4]=V;
52 }
53 static DECLFW(VRC6PSGWA1)
54 {
55  DoSQV2();VPSG[6]=V;
56 }
57 static DECLFW(VRC6PSGWA2)
58 {
59  DoSQV2();VPSG[7]=V;
60 }
61 static DECLFW(VRC6PSGWB0)
62 {
63  DoSawV();VPSG2[0]=V;
64 }
65 static DECLFW(VRC6PSGWB1)
66 {
67  DoSawV();VPSG2[1]=V;
68 }
69 static DECLFW(VRC6PSGWB2)
70 {
71  DoSawV();VPSG2[2]=V;
72 }
73
74 static int acount=0;
75
76 static void FP_FASTAPASS(1) KonamiIRQHook(int a)
77 {
78   #define LCYCS 114
79   if(IRQa)
80   {
81    acount+=a;
82    if(acount>=LCYCS)
83    {
84     doagainbub:acount-=LCYCS;IRQCount++;
85     if(IRQCount==0x100) {TriggerIRQ();IRQCount=IRQLatch;}
86     if(acount>=LCYCS) goto doagainbub;
87    }
88  }
89 }
90
91 DECLFW(Mapper24_write)
92 {
93         if(swaparoo)
94          A=(A&0xFFFC)|((A>>1)&1)|((A<<1)&2);
95
96         switch(A&0xF003)
97         {
98          case 0x8000:ROM_BANK16(0x8000,V);break;
99          case 0xB003:
100                  switch(V&0xF)
101                  {
102                   case 0x0:MIRROR_SET2(1);break;
103                   case 0x4:MIRROR_SET2(0);break;
104                   case 0x8:onemir(0);break;
105                   case 0xC:onemir(1);break;
106                  }
107                  break;
108          case 0xC000:ROM_BANK8(0xC000,V);break;
109          case 0xD000:VROM_BANK1(0x0000,V);break;
110          case 0xD001:VROM_BANK1(0x0400,V);break;
111          case 0xD002:VROM_BANK1(0x0800,V);break;
112          case 0xD003:VROM_BANK1(0x0c00,V);break;
113          case 0xE000:VROM_BANK1(0x1000,V);break;
114          case 0xE001:VROM_BANK1(0x1400,V);break;
115          case 0xE002:VROM_BANK1(0x1800,V);break;
116          case 0xE003:VROM_BANK1(0x1c00,V);break;
117          case 0xF000:IRQLatch=V;break;
118          case 0xF001:IRQa=V&2;
119                      vrctemp=V&1;
120                      if(V&2) {IRQCount=IRQLatch;}
121                      //acount=0;
122                      break;
123          case 0xf002:IRQa=vrctemp;break;
124          case 0xF003:break;
125   }
126 }
127
128 static int CVBC[3]={0,0,0};
129 static int32 vcount[2];
130
131 static void DoSQV1(void)
132 {
133     uint8 amp;
134     int32 freq;
135     int V;
136     int32 start,end;
137
138     start=CVBC[0];    
139     end=(timestamp<<16)/soundtsinc;
140     if(end<=start) return;
141     CVBC[0]=end;
142
143     if(VPSG[0x3]&0x80)
144     {
145      amp=(VPSG[0]&15)<<4;
146      if(VPSG[0]&0x80)
147      {
148       for(V=start;V<end;V++)
149        Wave[V>>4]+=amp;
150      }
151      else
152      {
153       unsigned long dcycs;      
154       freq=(((VPSG[0x2]|((VPSG[0x3]&15)<<8))+1));
155       inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
156       switch(VPSG[0]&0x70)
157       {
158        default:
159        case 0x00:dcycs=inc>>4;break;
160        case 0x10:dcycs=inc>>3;break;
161        case 0x20:dcycs=(inc*3)>>4;break;
162        case 0x30:dcycs=inc>>2;break;
163        case 0x40:dcycs=(inc*5)>>4;break;
164        case 0x50:dcycs=(inc*6)>>4;break;
165        case 0x60:dcycs=(inc*7)>>4;break;
166        case 0x70:dcycs=inc>>1;break;
167       }
168              for(V=start;V<end;V++)
169               {
170                if(vcount[0]<dcycs)
171                  Wave[V>>4]+=amp;
172                vcount[0]+=0x1000;
173                if(vcount[0]>=inc) vcount[0]-=inc;
174                }
175      }
176     }
177 }
178 static void DoSQV2(void)
179 {
180     uint8 amp;
181     int32 freq;
182     int V;
183     int32 start,end;
184
185     start=CVBC[1];
186     end=(timestamp<<16)/soundtsinc;   
187     if(end<=start) return;
188     CVBC[1]=end;
189
190     if(VPSG[0x7]&0x80)
191     {
192      amp=(VPSG[4]&15)<<4;
193      if(VPSG[4]&0x80)
194      {
195       for(V=start;V<end;V++)
196        Wave[V>>4]+=amp;
197      }
198      else
199      {
200       unsigned long dcycs;
201       freq=(((VPSG[0x6]|((VPSG[0x7]&15)<<8))+1));
202       inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
203       switch(VPSG[4]&0x70)
204       {
205        default:
206        case 0x00:dcycs=inc>>4;break;
207        case 0x10:dcycs=inc>>3;break;
208        case 0x20:dcycs=(inc*3)>>4;break;
209        case 0x30:dcycs=inc>>2;break;
210        case 0x40:dcycs=(inc*5)>>4;break;
211        case 0x50:dcycs=(inc*6)>>4;break;
212        case 0x60:dcycs=(inc*7)>>4;break;
213        case 0x70:dcycs=inc>>1;break;
214       }
215              for(V=start;V<end;V++)
216               {
217                if(vcount[1]<dcycs)
218                  Wave[V>>4]+=amp;
219                vcount[1]+=0x1000;
220                if(vcount[1]>=inc) vcount[1]-=inc;
221                }
222      }
223     }
224 }
225
226 static void DoSawV(void)
227 {
228     int V;
229     int32 start,end;
230
231     start=CVBC[2];
232     end=(timestamp<<16)/soundtsinc;   
233     if(end<=start) return;
234     CVBC[2]=end;
235
236    if(VPSG2[2]&0x80)
237    {
238     static int64 saw1phaseacc=0;
239     uint32 freq3;
240     static uint8 b3=0;
241     static int32 phaseacc=0;
242     static uint32 duff=0;
243
244     freq3=(VPSG2[1]+((VPSG2[2]&15)<<8)+1);
245
246     for(V=start;V<end;V++)
247     {
248      saw1phaseacc-=nesincsizeLL;
249      if(saw1phaseacc<=0)
250      {
251       int64 t;
252       rea:
253       t=freq3;
254       t<<=50;   // 49 + 1
255       saw1phaseacc+=t;
256       phaseacc+=VPSG2[0]&0x3f;
257       b3++;
258       if(b3==7)
259       {
260        b3=0;
261        phaseacc=0;
262       }
263       if(saw1phaseacc<=0) 
264        goto rea;
265       duff=(((phaseacc>>3)&0x1f)<<4);
266       }
267      Wave[V>>4]+=duff;
268     }
269    }
270 }
271
272 void VRC6Sound(int Count)
273 {
274     int x;
275
276     DoSQV1();
277     DoSQV2();
278     DoSawV();
279     for(x=0;x<3;x++)
280      CVBC[x]=Count;
281 }
282
283 static int satype=0;
284
285 void VRC6SoundC(void)
286 {
287   int x;
288
289   if(FSettings.SndRate)
290    VRC6_ESI(satype);
291   else
292   {
293    for(x=000;x<0x1000;x+=4)
294    {
295           SetWriteHandler(0x9000+x,0x9002+x,0); 
296           SetWriteHandler(0xa000+x,0xa002+x,0); 
297           SetWriteHandler(0xb000+x,0xb002+x,0); 
298    }
299   }
300 }
301
302 void VRC6_ESI(int t)
303 {
304         int x;
305
306         satype=t;
307
308         GameExpSound.RChange=VRC6SoundC;
309         GameExpSound.Fill=VRC6Sound;
310         if(FSettings.SndRate)
311          for(x=000;x<0x1000;x+=4)
312          {
313           uint32 a;
314
315           a=0x9000+x;
316           SetWriteHandler(a,a,VRC6PSGW90);
317           SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGW91);
318           SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGW92);
319
320           a=0xa000+x;
321           SetWriteHandler(a,a,VRC6PSGWA0);
322           SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWA1);
323           SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWA2);
324
325           a=0xb000+x;
326           SetWriteHandler(a,a,VRC6PSGWB0);
327           SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWB1);
328           SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWB2);
329          }
330 }
331
332 void Mapper24_init(void)
333 {
334         SetWriteHandler(0x8000,0xffff,Mapper24_write);
335         if(FSettings.SndRate)
336          VRC6_ESI(0);
337         GameExpSound.RChange=VRC6SoundC;
338         MapIRQHook=KonamiIRQHook;
339         swaparoo=0;
340 }
341
342 void Mapper26_init(void)
343 {
344         SetWriteHandler(0x8000,0xffff,Mapper24_write);
345         if(FSettings.SndRate)
346          VRC6_ESI(3);
347         GameExpSound.RChange=VRC6SoundC;
348         MapIRQHook=KonamiIRQHook;
349         swaparoo=1;
350 }
351