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 |
386f5371 |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
c62d2810 |
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 | |
386f5371 |
37 | static void KonamiIRQHook(int a) |
c62d2810 |
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 | static INLINE void DoSQVHQ(int x) |
c62d2810 |
226 | { |
386f5371 |
227 | uint32 V; //mbg merge 7/17/06 made uint |
d97315ac |
228 | int32 amp=((VPSG[x<<2]&15)<<8)*6/8; |
c62d2810 |
229 | |
d97315ac |
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; |
c62d2810 |
254 | } |
255 | |
d97315ac |
256 | static void DoSQV1HQ(void) |
257 | { |
258 | DoSQVHQ(0); |
259 | } |
c62d2810 |
260 | |
d97315ac |
261 | static void DoSQV2HQ(void) |
c62d2810 |
262 | { |
d97315ac |
263 | DoSQVHQ(1); |
264 | } |
c62d2810 |
265 | |
d97315ac |
266 | static void DoSawVHQ(void) |
267 | { |
268 | static uint8 b3=0; |
269 | static int32 phaseacc=0; |
386f5371 |
270 | uint32 V; //mbg merge 7/17/06 made uint32 |
d97315ac |
271 | |
272 | if(VPSG2[2]&0x80) |
273 | { |
274 | for(V=CVBC[2];V<SOUNDTS;V++) |
c62d2810 |
275 | { |
d97315ac |
276 | WaveHi[V]+=(((phaseacc>>3)&0x1f)<<8)*6/8; |
277 | vcount[2]--; |
278 | if(vcount[2]<=0) |
c62d2810 |
279 | { |
d97315ac |
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 | |
c62d2810 |
289 | } |
290 | } |
d97315ac |
291 | } |
292 | CVBC[2]=SOUNDTS; |
c62d2810 |
293 | } |
d97315ac |
294 | |
c62d2810 |
295 | |
d97315ac |
296 | void VRC6Sound(int Count) |
c62d2810 |
297 | { |
d97315ac |
298 | int x; |
c62d2810 |
299 | |
d97315ac |
300 | DoSQV1(); |
301 | DoSQV2(); |
302 | DoSawV(); |
303 | for(x=0;x<3;x++) |
304 | CVBC[x]=Count; |
305 | } |
c62d2810 |
306 | |
d97315ac |
307 | void VRC6SoundHQ(void) |
308 | { |
309 | DoSQV1HQ(); |
310 | DoSQV2HQ(); |
311 | DoSawVHQ(); |
312 | } |
313 | |
314 | void VRC6SyncHQ(int32 ts) |
315 | { |
316 | int x; |
317 | for(x=0;x<3;x++) CVBC[x]=ts; |
318 | } |
d97315ac |
319 | |
320 | static void VRC6_ESI(void) |
321 | { |
322 | GameExpSound.RChange=VRC6_ESI; |
c62d2810 |
323 | GameExpSound.Fill=VRC6Sound; |
386f5371 |
324 | GameExpSound.HiFill=VRC6SoundHQ; |
325 | GameExpSound.HiSync=VRC6SyncHQ; |
d97315ac |
326 | |
327 | memset(CVBC,0,sizeof(CVBC)); |
328 | memset(vcount,0,sizeof(vcount)); |
329 | memset(dcount,0,sizeof(dcount)); |
c62d2810 |
330 | if(FSettings.SndRate) |
d97315ac |
331 | { |
d97315ac |
332 | if(FSettings.soundq>=1) |
333 | { |
334 | sfun[0]=DoSQV1HQ; |
335 | sfun[1]=DoSQV2HQ; |
336 | sfun[2]=DoSawVHQ; |
337 | } |
338 | else |
c62d2810 |
339 | { |
d97315ac |
340 | sfun[0]=DoSQV1; |
341 | sfun[1]=DoSQV2; |
342 | sfun[2]=DoSawV; |
c62d2810 |
343 | } |
d97315ac |
344 | } |
345 | else |
346 | memset(sfun,0,sizeof(sfun)); |
c62d2810 |
347 | } |
348 | |
349 | void Mapper24_init(void) |
350 | { |
351 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
d97315ac |
352 | VRC6_ESI(); |
c62d2810 |
353 | MapIRQHook=KonamiIRQHook; |
d97315ac |
354 | swaparoo=0; |
c62d2810 |
355 | } |
356 | |
357 | void Mapper26_init(void) |
358 | { |
359 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
d97315ac |
360 | VRC6_ESI(); |
c62d2810 |
361 | MapIRQHook=KonamiIRQHook; |
d97315ac |
362 | swaparoo=1; |
c62d2810 |
363 | } |
364 | |
d97315ac |
365 | void NSFVRC6_Init(void) |
366 | { |
367 | VRC6_ESI(); |
368 | SetWriteHandler(0x8000,0xbfff,VRC6SW); |
369 | } |