merge mapper code from FCEUX
[fceu.git] / boards / n106.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
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
d97315ac 19 */
20
21#include "mapinc.h"
22
23static uint16 IRQCount;
24static uint8 IRQa;
25
386f5371 26static uint8 WRAM[8192];
27static uint8 IRAM[128];
d97315ac 28
29static DECLFR(AWRAM)
30{
31 return(WRAM[A-0x6000]);
32}
33
34static DECLFW(BWRAM)
35{
36 WRAM[A-0x6000]=V;
37}
38
39void Mapper19_ESI(void);
40
41static uint8 NTAPage[4];
42
43static uint8 dopol;
44static uint8 gorfus;
45static uint8 gorko;
46
47static void NamcoSound(int Count);
48static void NamcoSoundHack(void);
49static void DoNamcoSound(int32 *Wave, int Count);
386f5371 50static void DoNamcoSoundHQ(void);
d97315ac 51static void SyncHQ(int32 ts);
52
53static int is210; /* Lesser mapper. */
54
55static uint8 PRG[3];
56static uint8 CHR[8];
57
58static SFORMAT N106_StateRegs[]={
59 {PRG,3,"PRG"},
60 {CHR,8,"CHR"},
61 {NTAPage,4,"NTA"},
62 {0}
63};
64
65static void SyncPRG(void)
66{
67 setprg8(0x8000,PRG[0]);
68 setprg8(0xa000,PRG[1]);
69 setprg8(0xc000,PRG[2]);
70 setprg8(0xe000,0x3F);
71}
72
386f5371 73static void NamcoIRQHook(int a)
d97315ac 74{
75 if(IRQa)
76 {
77 IRQCount+=a;
78 if(IRQCount>=0x7FFF)
79 {
80 X6502_IRQBegin(FCEU_IQEXT);
81 IRQa=0;
82 IRQCount=0x7FFF; //7FFF;
83 }
84 }
85}
86
87static DECLFR(Namco_Read4800)
88{
89 uint8 ret=IRAM[dopol&0x7f];
90 /* Maybe I should call NamcoSoundHack() here? */
91 if(!fceuindbg)
92 if(dopol&0x80)
93 dopol=(dopol&0x80)|((dopol+1)&0x7f);
94 return ret;
95}
96
97static DECLFR(Namco_Read5000)
98{
99 return(IRQCount);
100}
101
102static DECLFR(Namco_Read5800)
103{
104 return(IRQCount>>8);
105}
106
386f5371 107static void DoNTARAMROM(int w, uint8 V)
d97315ac 108{
109 NTAPage[w]=V;
110 if(V>=0xE0)
111 setntamem(NTARAM+((V&1)<<10), 1, w);
112 else
113 {
114 V&=CHRmask1[0];
115 setntamem(CHRptr[0]+(V<<10), 0, w);
116 }
117}
118
119static void FixNTAR(void)
120{
121 int x;
122 for(x=0;x<4;x++)
123 DoNTARAMROM(x,NTAPage[x]);
124}
125
386f5371 126static void DoCHRRAMROM(int x, uint8 V)
d97315ac 127{
128 CHR[x]=V;
129 if(!is210 && !((gorfus>>((x>>2)+6))&1) && (V>=0xE0))
130 {
131 // printf("BLAHAHA: %d, %02x\n",x,V);
132 //setchr1r(0x10,x<<10,V&7);
133 }
134 else
135 setchr1(x<<10,V);
136}
137
138static void FixCRR(void)
139{
140 int x;
141 for(x=0;x<8;x++)
142 DoCHRRAMROM(x,CHR[x]);
143}
144
145static DECLFW(Mapper19C0D8_write)
146{
147 DoNTARAMROM((A-0xC000)>>11,V);
148}
149
150static uint32 FreqCache[8];
151static uint32 EnvCache[8];
152static uint32 LengthCache[8];
153
154static void FixCache(int a,int V)
155{
156 int w=(a>>3)&0x7;
157 switch(a&0x07)
158 {
159 case 0x00:FreqCache[w]&=~0x000000FF;FreqCache[w]|=V;break;
160 case 0x02:FreqCache[w]&=~0x0000FF00;FreqCache[w]|=V<<8;break;
161 case 0x04:FreqCache[w]&=~0x00030000;FreqCache[w]|=(V&3)<<16;
162 LengthCache[w]=(8-((V>>2)&7))<<2;
163 break;
164 case 0x07:EnvCache[w]=(double)(V&0xF)*576716;break;
165 }
166}
167
168static DECLFW(Mapper19_write)
169{
170 A&=0xF800;
171 if(A>=0x8000 && A<=0xb800)
172 DoCHRRAMROM((A-0x8000)>>11,V);
173 else switch(A)
174 {
175 case 0x4800:
176 if(dopol&0x40)
177 {
178 if(FSettings.SndRate)
179 {
180 NamcoSoundHack();
181 GameExpSound.Fill=NamcoSound;
386f5371 182 GameExpSound.HiFill=DoNamcoSoundHQ;
d97315ac 183 GameExpSound.HiSync=SyncHQ;
184 }
185 FixCache(dopol,V);
186 }
187 IRAM[dopol&0x7f]=V;
188 if(dopol&0x80)
189 dopol=(dopol&0x80)|((dopol+1)&0x7f);
190 break;
191 case 0xf800:
192 dopol=V;break;
193 case 0x5000:
194 IRQCount&=0xFF00;IRQCount|=V;X6502_IRQEnd(FCEU_IQEXT);break;
195 case 0x5800:
196 IRQCount&=0x00ff;IRQCount|=(V&0x7F)<<8;
197 IRQa=V&0x80;
198 X6502_IRQEnd(FCEU_IQEXT);
199 break;
200 case 0xE000:
201 gorko=V&0xC0;
202 PRG[0]=V&0x3F;
203 SyncPRG();
204 break;
205 case 0xE800:
206 gorfus=V&0xC0;
207 FixCRR();
208 PRG[1]=V&0x3F;
209 SyncPRG();
210 break;
211 case 0xF000:
212 PRG[2]=V&0x3F;
213 SyncPRG();
214 break;
215 }
216}
217
218static int dwave=0;
219
220static void NamcoSoundHack(void)
221{
222 int32 z,a;
d97315ac 223 if(FSettings.soundq>=1)
224 {
225 DoNamcoSoundHQ();
226 return;
227 }
d97315ac 228 z=((SOUNDTS<<16)/soundtsinc)>>4;
229 a=z-dwave;
386f5371 230 if(a) DoNamcoSound(&Wave[dwave], a);
d97315ac 231 dwave+=a;
232}
233
234static void NamcoSound(int Count)
235{
236 int32 z,a;
237 z=((SOUNDTS<<16)/soundtsinc)>>4;
238 a=z-dwave;
386f5371 239 if(a) DoNamcoSound(&Wave[dwave], a);
d97315ac 240 dwave=0;
241}
242
243static uint32 PlayIndex[8];
244static int32 vcount[8];
245static int32 CVBC;
246
247#define TOINDEX (16+1)
248
249// 16:15
250static void SyncHQ(int32 ts)
251{
252 CVBC=ts;
253}
254
255
256/* Things to do:
257 1 Read freq low
258 2 Read freq mid
259 3 Read freq high
260 4 Read envelope
261 ...?
262*/
263
264static INLINE uint32 FetchDuff(uint32 P, uint32 envelope)
265{
266 uint32 duff;
267 duff=IRAM[((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&0xFF)>>1];
268 if((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&1)
269 duff>>=4;
270 duff&=0xF;
271 duff=(duff*envelope)>>16;
272 return(duff);
273}
274
d97315ac 275static void DoNamcoSoundHQ(void)
276{
386f5371 277 uint32 V; //mbg merge 7/17/06 made uint32
278 int32 P;
d97315ac 279 int32 cyclesuck=(((IRAM[0x7F]>>4)&7)+1)*15;
280
281 for(P=7;P>=(7-((IRAM[0x7F]>>4)&7));P--)
282 {
283 if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
284 {
285 uint32 freq;
286 int32 vco;
287 uint32 duff2,lengo,envelope;
288
289 vco=vcount[P];
290 freq=FreqCache[P];
291 envelope=EnvCache[P];
292 lengo=LengthCache[P];
293
294 duff2=FetchDuff(P,envelope);
295 for(V=CVBC<<1;V<SOUNDTS<<1;V++)
296 {
297 WaveHi[V>>1]+=duff2;
298 if(!vco)
299 {
300 PlayIndex[P]+=freq;
301 while((PlayIndex[P]>>TOINDEX)>=lengo) PlayIndex[P]-=lengo<<TOINDEX;
302 duff2=FetchDuff(P,envelope);
303 vco=cyclesuck;
304 }
305 vco--;
306 }
307 vcount[P]=vco;
308 }
309 }
310 CVBC=SOUNDTS;
311}
386f5371 312
d97315ac 313
314static void DoNamcoSound(int32 *Wave, int Count)
315{
316 int P,V;
317 for(P=7;P>=7-((IRAM[0x7F]>>4)&7);P--)
318 {
319 if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
320 {
321 int32 inc;
322 uint32 freq;
323 int32 vco;
324 uint32 duff,duff2,lengo,envelope;
325
326 vco=vcount[P];
327 freq=FreqCache[P];
328 envelope=EnvCache[P];
329 lengo=LengthCache[P];
330
331 if(!freq) {/*printf("Ack");*/ continue;}
332
333 {
334 int c=((IRAM[0x7F]>>4)&7)+1;
335 inc=(long double)(FSettings.SndRate<<15)/((long double)freq*21477272/((long double)0x400000*c*45));
336 }
337
338 duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
339 if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
340 duff>>=4;
341 duff&=0xF;
342 duff2=(duff*envelope)>>19;
343 for(V=0;V<Count*16;V++)
344 {
345 if(vco>=inc)
346 {
347 PlayIndex[P]++;
348 if(PlayIndex[P]>=lengo)
349 PlayIndex[P]=0;
350 vco-=inc;
351 duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
352 if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
353 duff>>=4;
354 duff&=0xF;
355 duff2=(duff*envelope)>>19;
356 }
357 Wave[V>>4]+=duff2;
358 vco+=0x8000;
359 }
360 vcount[P]=vco;
361 }
362 }
363}
364
365static void Mapper19_StateRestore(int version)
366{
386f5371 367 int x;
d97315ac 368 SyncPRG();
369 FixNTAR();
370 FixCRR();
d97315ac 371 for(x=0x40;x<0x80;x++)
372 FixCache(x,IRAM[x]);
373}
374
375static void M19SC(void)
376{
377 if(FSettings.SndRate)
378 Mapper19_ESI();
379}
380
381void Mapper19_ESI(void)
382{
383 GameExpSound.RChange=M19SC;
384 memset(vcount,0,sizeof(vcount));
385 memset(PlayIndex,0,sizeof(PlayIndex));
386 CVBC=0;
387}
388
389void NSFN106_Init(void)
390{
391 SetWriteHandler(0xf800,0xffff,Mapper19_write);
392 SetWriteHandler(0x4800,0x4fff,Mapper19_write);
393 SetReadHandler(0x4800,0x4fff,Namco_Read4800);
394 Mapper19_ESI();
395}
396
397static int battery=0;
398
399static void N106_Power(void)
400{
401 int x;
402 SetReadHandler(0x8000,0xFFFF,CartBR);
403 SetWriteHandler(0x8000,0xffff,Mapper19_write);
404 SetWriteHandler(0x4020,0x5fff,Mapper19_write);
405 if(!is210)
406 {
407 SetWriteHandler(0xc000,0xdfff,Mapper19C0D8_write);
408 SetReadHandler(0x4800,0x4fff,Namco_Read4800);
409 SetReadHandler(0x5000,0x57ff,Namco_Read5000);
410 SetReadHandler(0x5800,0x5fff,Namco_Read5800);
411 NTAPage[0]=NTAPage[1]=NTAPage[2]=NTAPage[3]=0xFF;
412 FixNTAR();
413 }
414
415 SetReadHandler(0x6000,0x7FFF,AWRAM);
416 SetWriteHandler(0x6000,0x7FFF,BWRAM);
417 FCEU_CheatAddRAM(8,0x6000,WRAM);
418
419 gorfus=0xFF;
420 SyncPRG();
421 FixCRR();
422
423 if(!battery)
424 {
425 FCEU_dwmemset(WRAM,0,8192);
426 FCEU_dwmemset(IRAM,0,128);
427 }
428 for(x=0x40;x<0x80;x++)
429 FixCache(x,IRAM[x]);
430}
431
432void Mapper19_Init(CartInfo *info)
433{
434 is210=0;
435 battery=info->battery;
436 info->Power=N106_Power;
437
438 MapIRQHook=NamcoIRQHook;
439 GameStateRestore=Mapper19_StateRestore;
440 GameExpSound.RChange=M19SC;
441
442 if(FSettings.SndRate)
443 Mapper19_ESI();
444
445 AddExState(WRAM, 8192, 0, "WRAM");
386f5371 446 AddExState(IRAM, 128, 0, "IRAM");
d97315ac 447 AddExState(N106_StateRegs, ~0, 0, 0);
448
449 if(info->battery)
450 {
451 info->SaveGame[0]=WRAM;
452 info->SaveGameLen[0]=8192;
453 info->SaveGame[1]=IRAM;
454 info->SaveGameLen[1]=128;
455 }
456}
457
458static void Mapper210_StateRestore(int version)
459{
460 SyncPRG();
461 FixCRR();
462}
463
464void Mapper210_Init(CartInfo *info)
465{
466 is210=1;
467 GameStateRestore=Mapper210_StateRestore;
468 info->Power=N106_Power;
469 AddExState(WRAM, 8192, 0, "WRAM");
386f5371 470 AddExState(N106_StateRegs, ~0, 0, 0);
d97315ac 471}