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 |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | #include "mapinc.h" |
22 | |
d97315ac |
23 | static void (*sfun[3])(void); |
24 | |
c62d2810 |
25 | #define vrctemp mapbyte1[0] |
c62d2810 |
26 | #define VPSG2 mapbyte3 |
27 | #define VPSG mapbyte2 |
28 | |
29 | static void DoSQV1(void); |
30 | static void DoSQV2(void); |
31 | static void DoSawV(void); |
32 | |
33 | static int swaparoo; |
c62d2810 |
34 | |
35 | static int acount=0; |
36 | |
37 | static void FP_FASTAPASS(1) KonamiIRQHook(int a) |
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 |
57 | static 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 | |
78 | static 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 |
128 | static int32 CVBC[3]; |
129 | static int32 vcount[3]; |
130 | static int32 dcount[2]; |
c62d2810 |
131 | |
d97315ac |
132 | static 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 |
169 | static void DoSQV1(void) |
170 | { |
171 | DoSQV(0); |
172 | } |
c62d2810 |
173 | |
d97315ac |
174 | static void DoSQV2(void) |
175 | { |
176 | DoSQV(1); |
c62d2810 |
177 | } |
178 | |
179 | static 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 |
225 | #if 0 |
226 | static INLINE void DoSQVHQ(int x) |
c62d2810 |
227 | { |
d97315ac |
228 | int32 V; |
229 | int32 amp=((VPSG[x<<2]&15)<<8)*6/8; |
c62d2810 |
230 | |
d97315ac |
231 | if(VPSG[(x<<2)|0x2]&0x80) |
232 | { |
233 | if(VPSG[x<<2]&0x80) |
234 | { |
235 | for(V=CVBC[x];V<SOUNDTS;V++) |
236 | WaveHi[V]+=amp; |
237 | } |
238 | else |
239 | { |
240 | int32 thresh=(VPSG[x<<2]>>4)&7; |
241 | for(V=CVBC[x];V<SOUNDTS;V++) |
242 | { |
243 | if(dcount[x]>thresh) /* Greater than, not >=. Important. */ |
244 | WaveHi[V]+=amp; |
245 | vcount[x]--; |
246 | if(vcount[x]<=0) /* Should only be <0 in a few circumstances. */ |
247 | { |
248 | vcount[x]=(VPSG[(x<<2)|0x1]|((VPSG[(x<<2)|0x2]&15)<<8))+1; |
249 | dcount[x]=(dcount[x]+1)&15; |
250 | } |
251 | } |
252 | } |
253 | } |
254 | CVBC[x]=SOUNDTS; |
c62d2810 |
255 | } |
256 | |
d97315ac |
257 | static void DoSQV1HQ(void) |
258 | { |
259 | DoSQVHQ(0); |
260 | } |
c62d2810 |
261 | |
d97315ac |
262 | static void DoSQV2HQ(void) |
c62d2810 |
263 | { |
d97315ac |
264 | DoSQVHQ(1); |
265 | } |
c62d2810 |
266 | |
d97315ac |
267 | static void DoSawVHQ(void) |
268 | { |
269 | static uint8 b3=0; |
270 | static int32 phaseacc=0; |
271 | int32 V; |
272 | |
273 | if(VPSG2[2]&0x80) |
274 | { |
275 | for(V=CVBC[2];V<SOUNDTS;V++) |
c62d2810 |
276 | { |
d97315ac |
277 | WaveHi[V]+=(((phaseacc>>3)&0x1f)<<8)*6/8; |
278 | vcount[2]--; |
279 | if(vcount[2]<=0) |
c62d2810 |
280 | { |
d97315ac |
281 | vcount[2]=(VPSG2[1]+((VPSG2[2]&15)<<8)+1)<<1; |
282 | phaseacc+=VPSG2[0]&0x3f; |
283 | b3++; |
284 | if(b3==7) |
285 | { |
286 | b3=0; |
287 | phaseacc=0; |
288 | } |
289 | |
c62d2810 |
290 | } |
291 | } |
d97315ac |
292 | } |
293 | CVBC[2]=SOUNDTS; |
c62d2810 |
294 | } |
d97315ac |
295 | #endif |
296 | |
c62d2810 |
297 | |
d97315ac |
298 | void VRC6Sound(int Count) |
c62d2810 |
299 | { |
d97315ac |
300 | int x; |
c62d2810 |
301 | |
d97315ac |
302 | DoSQV1(); |
303 | DoSQV2(); |
304 | DoSawV(); |
305 | for(x=0;x<3;x++) |
306 | CVBC[x]=Count; |
307 | } |
c62d2810 |
308 | |
d97315ac |
309 | #if 0 |
310 | void VRC6SoundHQ(void) |
311 | { |
312 | DoSQV1HQ(); |
313 | DoSQV2HQ(); |
314 | DoSawVHQ(); |
315 | } |
316 | |
317 | void VRC6SyncHQ(int32 ts) |
318 | { |
319 | int x; |
320 | for(x=0;x<3;x++) CVBC[x]=ts; |
321 | } |
322 | #endif |
323 | |
324 | static void VRC6_ESI(void) |
325 | { |
326 | GameExpSound.RChange=VRC6_ESI; |
c62d2810 |
327 | GameExpSound.Fill=VRC6Sound; |
d97315ac |
328 | GameExpSound.HiFill=0;//VRC6SoundHQ; |
329 | GameExpSound.HiSync=0;//VRC6SyncHQ; |
330 | |
331 | memset(CVBC,0,sizeof(CVBC)); |
332 | memset(vcount,0,sizeof(vcount)); |
333 | memset(dcount,0,sizeof(dcount)); |
c62d2810 |
334 | if(FSettings.SndRate) |
d97315ac |
335 | { |
336 | #if 0 |
337 | if(FSettings.soundq>=1) |
338 | { |
339 | sfun[0]=DoSQV1HQ; |
340 | sfun[1]=DoSQV2HQ; |
341 | sfun[2]=DoSawVHQ; |
342 | } |
343 | else |
344 | #endif |
c62d2810 |
345 | { |
d97315ac |
346 | sfun[0]=DoSQV1; |
347 | sfun[1]=DoSQV2; |
348 | sfun[2]=DoSawV; |
c62d2810 |
349 | } |
d97315ac |
350 | } |
351 | else |
352 | memset(sfun,0,sizeof(sfun)); |
c62d2810 |
353 | } |
354 | |
355 | void Mapper24_init(void) |
356 | { |
357 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
d97315ac |
358 | VRC6_ESI(); |
c62d2810 |
359 | MapIRQHook=KonamiIRQHook; |
d97315ac |
360 | swaparoo=0; |
c62d2810 |
361 | } |
362 | |
363 | void Mapper26_init(void) |
364 | { |
365 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
d97315ac |
366 | VRC6_ESI(); |
c62d2810 |
367 | MapIRQHook=KonamiIRQHook; |
d97315ac |
368 | swaparoo=1; |
c62d2810 |
369 | } |
370 | |
d97315ac |
371 | void NSFVRC6_Init(void) |
372 | { |
373 | VRC6_ESI(); |
374 | SetWriteHandler(0x8000,0xbfff,VRC6SW); |
375 | } |