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