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 | |
31 | static void DoSQV1(void); |
32 | static void DoSQV2(void); |
33 | static void DoSawV(void); |
34 | |
35 | static int swaparoo; |
36 | static int32 inc; |
37 | static DECLFW(VRC6PSGW90) |
38 | { |
39 | DoSQV1();VPSG[0]=V; |
40 | } |
41 | static DECLFW(VRC6PSGW91) |
42 | { |
43 | DoSQV1();VPSG[2]=V; |
44 | } |
45 | static DECLFW(VRC6PSGW92) |
46 | { |
47 | DoSQV1();VPSG[3]=V; |
48 | } |
49 | static DECLFW(VRC6PSGWA0) |
50 | { |
51 | DoSQV2();VPSG[4]=V; |
52 | } |
53 | static DECLFW(VRC6PSGWA1) |
54 | { |
55 | DoSQV2();VPSG[6]=V; |
56 | } |
57 | static DECLFW(VRC6PSGWA2) |
58 | { |
59 | DoSQV2();VPSG[7]=V; |
60 | } |
61 | static DECLFW(VRC6PSGWB0) |
62 | { |
63 | DoSawV();VPSG2[0]=V; |
64 | } |
65 | static DECLFW(VRC6PSGWB1) |
66 | { |
67 | DoSawV();VPSG2[1]=V; |
68 | } |
69 | static DECLFW(VRC6PSGWB2) |
70 | { |
71 | DoSawV();VPSG2[2]=V; |
72 | } |
73 | |
74 | static int acount=0; |
75 | |
76 | static 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 | |
91 | DECLFW(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 | |
128 | static int CVBC[3]={0,0,0}; |
129 | static int32 vcount[2]; |
130 | |
131 | static 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 | } |
178 | static 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 | |
226 | static 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 | |
272 | void 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 | |
283 | static int satype=0; |
284 | |
285 | void 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 | |
302 | void 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 | |
332 | void 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 | |
342 | void 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 | |