merge mapper code from FCEUX
[fceu.git] / mappers / 24and26.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
d97315ac 4 * Copyright (C) 2002 Xodnizel
c62d2810 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
386f5371 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c62d2810 19 */
20
21#include "mapinc.h"
22
d97315ac 23static void (*sfun[3])(void);
24
c62d2810 25#define vrctemp mapbyte1[0]
c62d2810 26#define VPSG2 mapbyte3
27#define VPSG mapbyte2
28
29static void DoSQV1(void);
30static void DoSQV2(void);
31static void DoSawV(void);
32
33static int swaparoo;
c62d2810 34
35static int acount=0;
36
386f5371 37static void KonamiIRQHook(int a)
c62d2810 38{
d97315ac 39 #define LCYCS 341
40// #define LCYCS ((227*2)+1)
c62d2810 41 if(IRQa)
42 {
d97315ac 43 acount+=a*3;
c62d2810 44 if(acount>=LCYCS)
45 {
46 doagainbub:acount-=LCYCS;IRQCount++;
d97315ac 47 if(IRQCount==0x100)
48 {
49 X6502_IRQBegin(FCEU_IQEXT);
50 IRQCount=IRQLatch;
51 }
c62d2810 52 if(acount>=LCYCS) goto doagainbub;
53 }
54 }
55}
56
d97315ac 57static DECLFW(VRC6SW)
c62d2810 58{
d97315ac 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 }
c62d2810 75
d97315ac 76}
77
78static 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);
c62d2810 89 switch(A&0xF003)
d97315ac 90 {
91 case 0x8000:ROM_BANK16(0x8000,V);break;
c62d2810 92 case 0xB003:
d97315ac 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;
c62d2810 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;
d97315ac 110 case 0xF000:IRQLatch=V;
111 //acount=0;
112 break;
c62d2810 113 case 0xF001:IRQa=V&2;
114 vrctemp=V&1;
d97315ac 115 if(V&2)
116 {
117 IRQCount=IRQLatch;
118 acount=0;
119 }
120 X6502_IRQEnd(FCEU_IQEXT);
c62d2810 121 break;
d97315ac 122 case 0xf002:IRQa=vrctemp;
123 X6502_IRQEnd(FCEU_IQEXT);break;
c62d2810 124 case 0xF003:break;
125 }
126}
127
d97315ac 128static int32 CVBC[3];
129static int32 vcount[3];
130static int32 dcount[2];
c62d2810 131
d97315ac 132static INLINE void DoSQV(int x)
c62d2810 133{
d97315ac 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. */
c62d2810 160 {
d97315ac 161 vcount[x]+=freq;
162 dcount[x]=(dcount[x]+1)&15;
c62d2810 163 }
d97315ac 164 }
165 }
166 }
c62d2810 167}
c62d2810 168
d97315ac 169static void DoSQV1(void)
170{
171 DoSQV(0);
172}
c62d2810 173
d97315ac 174static void DoSQV2(void)
175{
176 DoSQV(1);
c62d2810 177}
178
179static void DoSawV(void)
180{
181 int V;
182 int32 start,end;
183
184 start=CVBC[2];
4fdfab07 185 end=(SOUNDTS<<16)/soundtsinc;
c62d2810 186 if(end<=start) return;
187 CVBC[2]=end;
188
189 if(VPSG2[2]&0x80)
190 {
d97315ac 191 static int32 saw1phaseacc=0;
c62d2810 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 {
d97315ac 201 saw1phaseacc-=nesincsize;
c62d2810 202 if(saw1phaseacc<=0)
203 {
d97315ac 204 int32 t;
c62d2810 205 rea:
206 t=freq3;
d97315ac 207 t<<=18;
c62d2810 208 saw1phaseacc+=t;
209 phaseacc+=VPSG2[0]&0x3f;
210 b3++;
211 if(b3==7)
212 {
213 b3=0;
214 phaseacc=0;
215 }
c0bf6f9f 216 if(saw1phaseacc<=0)
c62d2810 217 goto rea;
d97315ac 218 duff=(((phaseacc>>3)&0x1f)<<4)*6/8;
c62d2810 219 }
220 Wave[V>>4]+=duff;
221 }
222 }
223}
224
d97315ac 225static INLINE void DoSQVHQ(int x)
c62d2810 226{
386f5371 227 uint32 V; //mbg merge 7/17/06 made uint
d97315ac 228 int32 amp=((VPSG[x<<2]&15)<<8)*6/8;
c62d2810 229
d97315ac 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;
c62d2810 254}
255
d97315ac 256static void DoSQV1HQ(void)
257{
258 DoSQVHQ(0);
259}
c62d2810 260
d97315ac 261static void DoSQV2HQ(void)
c62d2810 262{
d97315ac 263 DoSQVHQ(1);
264}
c62d2810 265
d97315ac 266static void DoSawVHQ(void)
267{
268 static uint8 b3=0;
269 static int32 phaseacc=0;
386f5371 270 uint32 V; //mbg merge 7/17/06 made uint32
d97315ac 271
272 if(VPSG2[2]&0x80)
273 {
274 for(V=CVBC[2];V<SOUNDTS;V++)
c62d2810 275 {
d97315ac 276 WaveHi[V]+=(((phaseacc>>3)&0x1f)<<8)*6/8;
277 vcount[2]--;
278 if(vcount[2]<=0)
c62d2810 279 {
d97315ac 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
c62d2810 289 }
290 }
d97315ac 291 }
292 CVBC[2]=SOUNDTS;
c62d2810 293}
d97315ac 294
c62d2810 295
d97315ac 296void VRC6Sound(int Count)
c62d2810 297{
d97315ac 298 int x;
c62d2810 299
d97315ac 300 DoSQV1();
301 DoSQV2();
302 DoSawV();
303 for(x=0;x<3;x++)
304 CVBC[x]=Count;
305}
c62d2810 306
d97315ac 307void VRC6SoundHQ(void)
308{
309 DoSQV1HQ();
310 DoSQV2HQ();
311 DoSawVHQ();
312}
313
314void VRC6SyncHQ(int32 ts)
315{
316 int x;
317 for(x=0;x<3;x++) CVBC[x]=ts;
318}
d97315ac 319
320static void VRC6_ESI(void)
321{
322 GameExpSound.RChange=VRC6_ESI;
c62d2810 323 GameExpSound.Fill=VRC6Sound;
386f5371 324 GameExpSound.HiFill=VRC6SoundHQ;
325 GameExpSound.HiSync=VRC6SyncHQ;
d97315ac 326
327 memset(CVBC,0,sizeof(CVBC));
328 memset(vcount,0,sizeof(vcount));
329 memset(dcount,0,sizeof(dcount));
c62d2810 330 if(FSettings.SndRate)
d97315ac 331 {
d97315ac 332 if(FSettings.soundq>=1)
333 {
334 sfun[0]=DoSQV1HQ;
335 sfun[1]=DoSQV2HQ;
336 sfun[2]=DoSawVHQ;
337 }
338 else
c62d2810 339 {
d97315ac 340 sfun[0]=DoSQV1;
341 sfun[1]=DoSQV2;
342 sfun[2]=DoSawV;
c62d2810 343 }
d97315ac 344 }
345 else
346 memset(sfun,0,sizeof(sfun));
c62d2810 347}
348
349void Mapper24_init(void)
350{
351 SetWriteHandler(0x8000,0xffff,Mapper24_write);
d97315ac 352 VRC6_ESI();
c62d2810 353 MapIRQHook=KonamiIRQHook;
d97315ac 354 swaparoo=0;
c62d2810 355}
356
357void Mapper26_init(void)
358{
359 SetWriteHandler(0x8000,0xffff,Mapper24_write);
d97315ac 360 VRC6_ESI();
c62d2810 361 MapIRQHook=KonamiIRQHook;
d97315ac 362 swaparoo=1;
c62d2810 363}
364
d97315ac 365void NSFVRC6_Init(void)
366{
367 VRC6_ESI();
368 SetWriteHandler(0x8000,0xbfff,VRC6SW);
369}