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 | { |
c0bf6f9f |
98 | case 0x8000:ROM_BANK16(0x8000,V); |
99 | X6502_Rebase();break; |
c62d2810 |
100 | case 0xB003: |
101 | switch(V&0xF) |
102 | { |
103 | case 0x0:MIRROR_SET2(1);break; |
104 | case 0x4:MIRROR_SET2(0);break; |
105 | case 0x8:onemir(0);break; |
106 | case 0xC:onemir(1);break; |
107 | } |
108 | break; |
c0bf6f9f |
109 | case 0xC000:ROM_BANK8(0xC000,V); |
110 | X6502_Rebase();break; |
c62d2810 |
111 | case 0xD000:VROM_BANK1(0x0000,V);break; |
112 | case 0xD001:VROM_BANK1(0x0400,V);break; |
113 | case 0xD002:VROM_BANK1(0x0800,V);break; |
114 | case 0xD003:VROM_BANK1(0x0c00,V);break; |
115 | case 0xE000:VROM_BANK1(0x1000,V);break; |
116 | case 0xE001:VROM_BANK1(0x1400,V);break; |
117 | case 0xE002:VROM_BANK1(0x1800,V);break; |
118 | case 0xE003:VROM_BANK1(0x1c00,V);break; |
119 | case 0xF000:IRQLatch=V;break; |
120 | case 0xF001:IRQa=V&2; |
121 | vrctemp=V&1; |
122 | if(V&2) {IRQCount=IRQLatch;} |
123 | //acount=0; |
124 | break; |
125 | case 0xf002:IRQa=vrctemp;break; |
126 | case 0xF003:break; |
127 | } |
128 | } |
129 | |
130 | static int CVBC[3]={0,0,0}; |
131 | static int32 vcount[2]; |
132 | |
133 | static void DoSQV1(void) |
134 | { |
135 | uint8 amp; |
136 | int32 freq; |
137 | int V; |
138 | int32 start,end; |
139 | |
c0bf6f9f |
140 | start=CVBC[0]; |
c62d2810 |
141 | end=(timestamp<<16)/soundtsinc; |
142 | if(end<=start) return; |
143 | CVBC[0]=end; |
144 | |
145 | if(VPSG[0x3]&0x80) |
146 | { |
147 | amp=(VPSG[0]&15)<<4; |
148 | if(VPSG[0]&0x80) |
149 | { |
150 | for(V=start;V<end;V++) |
151 | Wave[V>>4]+=amp; |
152 | } |
153 | else |
154 | { |
c0bf6f9f |
155 | unsigned long dcycs; |
c62d2810 |
156 | freq=(((VPSG[0x2]|((VPSG[0x3]&15)<<8))+1)); |
157 | inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq); |
158 | switch(VPSG[0]&0x70) |
159 | { |
160 | default: |
161 | case 0x00:dcycs=inc>>4;break; |
162 | case 0x10:dcycs=inc>>3;break; |
163 | case 0x20:dcycs=(inc*3)>>4;break; |
164 | case 0x30:dcycs=inc>>2;break; |
165 | case 0x40:dcycs=(inc*5)>>4;break; |
166 | case 0x50:dcycs=(inc*6)>>4;break; |
167 | case 0x60:dcycs=(inc*7)>>4;break; |
168 | case 0x70:dcycs=inc>>1;break; |
169 | } |
170 | for(V=start;V<end;V++) |
171 | { |
172 | if(vcount[0]<dcycs) |
173 | Wave[V>>4]+=amp; |
174 | vcount[0]+=0x1000; |
175 | if(vcount[0]>=inc) vcount[0]-=inc; |
176 | } |
177 | } |
178 | } |
179 | } |
180 | static void DoSQV2(void) |
181 | { |
182 | uint8 amp; |
183 | int32 freq; |
184 | int V; |
185 | int32 start,end; |
186 | |
187 | start=CVBC[1]; |
c0bf6f9f |
188 | end=(timestamp<<16)/soundtsinc; |
c62d2810 |
189 | if(end<=start) return; |
190 | CVBC[1]=end; |
191 | |
192 | if(VPSG[0x7]&0x80) |
193 | { |
194 | amp=(VPSG[4]&15)<<4; |
195 | if(VPSG[4]&0x80) |
196 | { |
197 | for(V=start;V<end;V++) |
198 | Wave[V>>4]+=amp; |
199 | } |
200 | else |
201 | { |
202 | unsigned long dcycs; |
203 | freq=(((VPSG[0x6]|((VPSG[0x7]&15)<<8))+1)); |
204 | inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq); |
205 | switch(VPSG[4]&0x70) |
206 | { |
207 | default: |
208 | case 0x00:dcycs=inc>>4;break; |
209 | case 0x10:dcycs=inc>>3;break; |
210 | case 0x20:dcycs=(inc*3)>>4;break; |
211 | case 0x30:dcycs=inc>>2;break; |
212 | case 0x40:dcycs=(inc*5)>>4;break; |
213 | case 0x50:dcycs=(inc*6)>>4;break; |
214 | case 0x60:dcycs=(inc*7)>>4;break; |
215 | case 0x70:dcycs=inc>>1;break; |
216 | } |
217 | for(V=start;V<end;V++) |
218 | { |
219 | if(vcount[1]<dcycs) |
220 | Wave[V>>4]+=amp; |
221 | vcount[1]+=0x1000; |
222 | if(vcount[1]>=inc) vcount[1]-=inc; |
223 | } |
224 | } |
225 | } |
226 | } |
227 | |
228 | static void DoSawV(void) |
229 | { |
230 | int V; |
231 | int32 start,end; |
232 | |
233 | start=CVBC[2]; |
c0bf6f9f |
234 | end=(timestamp<<16)/soundtsinc; |
c62d2810 |
235 | if(end<=start) return; |
236 | CVBC[2]=end; |
237 | |
238 | if(VPSG2[2]&0x80) |
239 | { |
240 | static int64 saw1phaseacc=0; |
241 | uint32 freq3; |
242 | static uint8 b3=0; |
243 | static int32 phaseacc=0; |
244 | static uint32 duff=0; |
245 | |
246 | freq3=(VPSG2[1]+((VPSG2[2]&15)<<8)+1); |
247 | |
248 | for(V=start;V<end;V++) |
249 | { |
250 | saw1phaseacc-=nesincsizeLL; |
251 | if(saw1phaseacc<=0) |
252 | { |
253 | int64 t; |
254 | rea: |
255 | t=freq3; |
256 | t<<=50; // 49 + 1 |
257 | saw1phaseacc+=t; |
258 | phaseacc+=VPSG2[0]&0x3f; |
259 | b3++; |
260 | if(b3==7) |
261 | { |
262 | b3=0; |
263 | phaseacc=0; |
264 | } |
c0bf6f9f |
265 | if(saw1phaseacc<=0) |
c62d2810 |
266 | goto rea; |
267 | duff=(((phaseacc>>3)&0x1f)<<4); |
268 | } |
269 | Wave[V>>4]+=duff; |
270 | } |
271 | } |
272 | } |
273 | |
274 | void VRC6Sound(int Count) |
275 | { |
276 | int x; |
277 | |
278 | DoSQV1(); |
279 | DoSQV2(); |
280 | DoSawV(); |
281 | for(x=0;x<3;x++) |
282 | CVBC[x]=Count; |
283 | } |
284 | |
285 | static int satype=0; |
286 | |
287 | void VRC6SoundC(void) |
288 | { |
289 | int x; |
290 | |
291 | if(FSettings.SndRate) |
292 | VRC6_ESI(satype); |
293 | else |
294 | { |
295 | for(x=000;x<0x1000;x+=4) |
296 | { |
c0bf6f9f |
297 | SetWriteHandler(0x9000+x,0x9002+x,0); |
298 | SetWriteHandler(0xa000+x,0xa002+x,0); |
299 | SetWriteHandler(0xb000+x,0xb002+x,0); |
c62d2810 |
300 | } |
301 | } |
302 | } |
303 | |
304 | void VRC6_ESI(int t) |
305 | { |
306 | int x; |
307 | |
308 | satype=t; |
309 | |
310 | GameExpSound.RChange=VRC6SoundC; |
311 | GameExpSound.Fill=VRC6Sound; |
312 | if(FSettings.SndRate) |
313 | for(x=000;x<0x1000;x+=4) |
314 | { |
315 | uint32 a; |
316 | |
317 | a=0x9000+x; |
318 | SetWriteHandler(a,a,VRC6PSGW90); |
319 | SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGW91); |
320 | SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGW92); |
321 | |
322 | a=0xa000+x; |
323 | SetWriteHandler(a,a,VRC6PSGWA0); |
324 | SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWA1); |
325 | SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWA2); |
326 | |
327 | a=0xb000+x; |
328 | SetWriteHandler(a,a,VRC6PSGWB0); |
329 | SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWB1); |
330 | SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWB2); |
331 | } |
332 | } |
333 | |
334 | void Mapper24_init(void) |
335 | { |
336 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
337 | if(FSettings.SndRate) |
338 | VRC6_ESI(0); |
339 | GameExpSound.RChange=VRC6SoundC; |
340 | MapIRQHook=KonamiIRQHook; |
341 | swaparoo=0; |
342 | } |
343 | |
344 | void Mapper26_init(void) |
345 | { |
346 | SetWriteHandler(0x8000,0xffff,Mapper24_write); |
347 | if(FSettings.SndRate) |
348 | VRC6_ESI(3); |
349 | GameExpSound.RChange=VRC6SoundC; |
350 | MapIRQHook=KonamiIRQHook; |
351 | swaparoo=1; |
352 | } |
353 | |