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 | static void AYSound(int Count); |
23 | static void DoAYSQ(int x); |
24 | static void DoAYNoise(void); |
25 | |
26 | #define sunselect mapbyte1[0] |
27 | #define sungah mapbyte1[1] |
28 | #define sunindex mapbyte1[2] |
29 | |
30 | static uint16 znreg; |
31 | static int32 inc; |
32 | |
33 | DECLFW(SUN5BWRAM) |
34 | { |
35 | if((sungah&0xC0)==0xC0) |
36 | (WRAM-0x6000)[A]=V; |
37 | } |
38 | |
39 | DECLFR(SUN5AWRAM) |
40 | { |
41 | if((sungah&0xC0)==0x40) |
c0bf6f9f |
42 | return X.DB; |
c62d2810 |
43 | return CartBR(A); |
44 | } |
45 | |
46 | DECLFW(Mapper69_SWL) |
47 | { |
48 | sunindex=V%14; |
49 | } |
50 | DECLFW(Mapper69_SWH) |
51 | { |
52 | GameExpSound.Fill=AYSound; |
53 | switch(sunindex) |
54 | { |
55 | case 0: |
56 | case 1: |
57 | case 8:DoAYSQ(0);break; |
58 | case 2: |
59 | case 3: |
60 | case 9:DoAYSQ(1);break; |
61 | case 4: |
62 | case 5: |
63 | case 10:DoAYSQ(2);break; |
64 | case 6:DoAYNoise();znreg=0xFFFF;break; |
65 | case 7:DoAYNoise(); |
66 | DoAYSQ(0); |
67 | DoAYSQ(1); |
68 | DoAYSQ(2);break; |
69 | } |
c0bf6f9f |
70 | MapperExRAM[sunindex]=V; |
c62d2810 |
71 | } |
72 | |
73 | DECLFW(Mapper69_write) |
74 | { |
75 | switch(A&0xE000) |
76 | { |
77 | case 0x8000:sunselect=V;break; |
78 | case 0xa000: |
79 | sunselect&=0xF; |
80 | if(sunselect<=7) |
81 | VROM_BANK1(sunselect<<10,V); |
82 | else |
83 | switch(sunselect&0x0f) |
84 | { |
85 | case 8: |
86 | sungah=V; |
87 | if(V&0x40) |
88 | { |
89 | if(V&0x80) // Select WRAM |
90 | setprg8r(0x10,0x6000,0); |
91 | } |
92 | else |
93 | setprg8(0x6000,V); |
c0bf6f9f |
94 | X6502_Rebase(); |
c62d2810 |
95 | break; |
c0bf6f9f |
96 | case 9:ROM_BANK8(0x8000,V); |
97 | X6502_Rebase();break; |
98 | case 0xa:ROM_BANK8(0xa000,V); |
99 | X6502_Rebase();break; |
100 | case 0xb:ROM_BANK8(0xc000,V); |
101 | X6502_Rebase();break; |
c62d2810 |
102 | case 0xc: |
103 | switch(V&3) |
104 | { |
105 | case 0:MIRROR_SET2(1);break; |
106 | case 1:MIRROR_SET2(0);break; |
107 | case 2:onemir(0);break; |
108 | case 3:onemir(1);break; |
109 | } |
110 | break; |
111 | case 0xd:IRQa=V;break; |
112 | case 0xe:IRQCount&=0xFF00;IRQCount|=V;break; |
113 | case 0xf:IRQCount&=0x00FF;IRQCount|=V<<8;break; |
114 | } |
115 | break; |
116 | } |
117 | } |
118 | |
119 | static int32 vcount[4]; |
120 | static int CAYBC[4]={0,0,0,0}; |
121 | static void DoAYSQ(int x) |
122 | { |
123 | int V; |
124 | uint32 freq; |
125 | unsigned char amp; |
126 | int32 start,end; |
127 | |
c0bf6f9f |
128 | start=CAYBC[x]; |
4fdfab07 |
129 | end=(SOUNDTS<<16)/soundtsinc; |
c62d2810 |
130 | if(end<=start) return; |
131 | CAYBC[x]=end; |
132 | |
133 | if(!(MapperExRAM[0x7]&(1<<x))) |
134 | { |
135 | long vcoo; |
136 | freq=(MapperExRAM[x<<1]|((MapperExRAM[(x<<1)+1]&15)<<8))+1; |
137 | inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/ |
138 | ((long double)PSG_base/freq); |
139 | amp=MapperExRAM[0x8+x]&15; |
140 | amp<<=3; |
141 | vcoo=vcount[x]; |
142 | if(amp) |
143 | for(V=start;V<end;V++) |
144 | { |
145 | if(vcoo<(inc>>1)) |
146 | Wave[V>>4]+=amp; |
147 | vcoo+=0x1000; |
148 | if(vcoo>=inc) vcoo-=inc; |
149 | } |
150 | vcount[x]=vcoo; |
151 | } |
152 | } |
153 | static void DoAYNoise(void) |
154 | { |
155 | int V; |
156 | uint32 freq; |
157 | unsigned char amp; |
158 | int32 start,end; |
159 | |
c0bf6f9f |
160 | start=CAYBC[3]; |
4fdfab07 |
161 | end=(SOUNDTS<<16)/soundtsinc; |
c62d2810 |
162 | if(end<=start) return; |
163 | CAYBC[3]=end; |
164 | |
165 | amp=0; |
166 | for(V=0;V<3;V++) |
167 | { |
168 | if(!(MapperExRAM[0x7]&(8<<V))) |
169 | { |
170 | //if(MapperExRAM[0x8+V]&0x10) amp+=MapperExRAM[0x20]&15; |
171 | //else |
172 | amp+=MapperExRAM[0x8+V]&15; |
173 | } |
174 | } |
175 | amp<<=3; |
176 | |
177 | if(amp) |
178 | { |
179 | freq=PSG_base/(MapperExRAM[0x6]+1); |
180 | if(freq>44100) |
181 | inc=((freq<<11)/(FSettings.SndRate OVERSAMPLE))<<4; |
182 | else |
183 | inc=(freq<<15)/(FSettings.SndRate OVERSAMPLE); |
184 | |
185 | for(V=start;V<end;V++) |
186 | { |
187 | static uint32 mixer; |
188 | |
189 | if(vcount[3]>=32768) |
190 | { |
191 | unsigned char feedback; |
192 | mixer=0; |
193 | if(znreg&1) mixer+=amp; |
194 | feedback=((znreg>>13)&1)^((znreg>>14)&1); |
195 | znreg=(znreg<<1)+(feedback); |
196 | vcount[3]-=32768; |
197 | } |
198 | Wave[V>>4]+=mixer; |
199 | vcount[3]+=inc; |
200 | } |
201 | } |
202 | |
203 | |
204 | } |
205 | static void AYSound(int Count) |
206 | { |
207 | int x; |
208 | DoAYSQ(0); |
209 | DoAYSQ(1); |
210 | DoAYSQ(2); |
211 | DoAYNoise(); |
212 | for(x=0;x<4;x++) |
213 | CAYBC[x]=Count; |
214 | } |
215 | |
216 | static void FP_FASTAPASS(1) SunIRQHook(int a) |
217 | { |
218 | if(IRQa) |
219 | { |
220 | IRQCount-=a; |
221 | if(IRQCount<=0) |
222 | {TriggerIRQ();IRQa=0;IRQCount=0xFFFF;} |
223 | } |
224 | } |
225 | |
226 | void Mapper69_StateRestore(int version) |
227 | { |
228 | if(version>=19) |
229 | { |
230 | if(mapbyte1[1]&0x40) |
231 | { |
232 | if(mapbyte1[1]&0x80) // Select WRAM |
233 | setprg8r(0x10,0x6000,0); |
234 | } |
235 | else |
236 | setprg8(0x6000,mapbyte1[1]); |
237 | } |
238 | else |
239 | mapbyte1[1]=0xC0; |
240 | } |
241 | |
242 | static void M69SC(void) |
243 | { |
244 | if(FSettings.SndRate) |
245 | Mapper69_ESI(); |
c0bf6f9f |
246 | else |
c62d2810 |
247 | SetWriteHandler(0xc000,0xffff,(writefunc)0); |
248 | } |
249 | |
250 | void Mapper69_ESI(void) |
251 | { |
c0bf6f9f |
252 | GameExpSound.RChange=M69SC; |
c62d2810 |
253 | if(FSettings.SndRate) |
254 | { |
255 | SetWriteHandler(0xc000,0xdfff,Mapper69_SWL); |
256 | SetWriteHandler(0xe000,0xffff,Mapper69_SWH); |
257 | } |
258 | } |
259 | |
260 | void Mapper69_init(void) |
261 | { |
262 | SetupCartPRGMapping(0x10,WRAM,8192,1); |
263 | |
264 | SetWriteHandler(0x8000,0xbfff,Mapper69_write); |
265 | SetWriteHandler(0x6000,0x7fff,SUN5BWRAM); |
266 | SetReadHandler(0x6000,0x7fff,SUN5AWRAM); |
267 | Mapper69_ESI(); |
268 | MapIRQHook=SunIRQHook; |
269 | MapStateRestore=Mapper69_StateRestore; |
270 | znreg=0; |
271 | } |
272 | |