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