frameskip, cleanups
[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 {
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
128static int CVBC[3]={0,0,0};
129static int32 vcount[2];
130
131static 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}
178static 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
226static 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
272void 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
283static int satype=0;
284
285void 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
302void 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
332void 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
342void 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