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