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