ec6336f461ce0e72082b7c03ce6300058d5f84bb
[fceu.git] / mappers / 69.c
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)
42   return X.DB; 
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              }
70              MapperExRAM[sunindex]=V; 
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);
94                         break;
95                 case 9:ROM_BANK8(0x8000,V);break;
96                 case 0xa:ROM_BANK8(0xa000,V);break;
97                 case 0xb:ROM_BANK8(0xc000,V);break;
98                 case 0xc:
99                          switch(V&3)
100                          {
101                           case 0:MIRROR_SET2(1);break;
102                           case 1:MIRROR_SET2(0);break;
103                           case 2:onemir(0);break;
104                           case 3:onemir(1);break;
105                          }
106                          break;
107              case 0xd:IRQa=V;break;
108              case 0xe:IRQCount&=0xFF00;IRQCount|=V;break;
109              case 0xf:IRQCount&=0x00FF;IRQCount|=V<<8;break;
110              }
111              break;
112  }
113 }
114
115 static int32 vcount[4];
116 static int CAYBC[4]={0,0,0,0};
117 static void DoAYSQ(int x)
118 {
119     int V;
120     uint32 freq;
121     unsigned char amp;
122     int32 start,end;
123
124     start=CAYBC[x];    
125     end=(timestamp<<16)/soundtsinc;
126     if(end<=start) return;
127     CAYBC[x]=end;
128
129     if(!(MapperExRAM[0x7]&(1<<x)))
130     {
131       long vcoo;
132       freq=(MapperExRAM[x<<1]|((MapperExRAM[(x<<1)+1]&15)<<8))+1;
133       inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/
134         ((long double)PSG_base/freq);
135                             amp=MapperExRAM[0x8+x]&15;
136               amp<<=3;
137               vcoo=vcount[x];
138              if(amp)
139               for(V=start;V<end;V++)
140                {
141                 if(vcoo<(inc>>1))
142                   Wave[V>>4]+=amp;
143                 vcoo+=0x1000;
144                 if(vcoo>=inc) vcoo-=inc;
145                 }
146               vcount[x]=vcoo;
147      }
148 }
149 static void DoAYNoise(void)
150 {
151     int V;
152     uint32 freq;
153     unsigned char amp;
154     int32 start,end;
155
156     start=CAYBC[3];    
157     end=(timestamp<<16)/soundtsinc;
158     if(end<=start) return;
159     CAYBC[3]=end;
160
161         amp=0;
162         for(V=0;V<3;V++)
163          {
164           if(!(MapperExRAM[0x7]&(8<<V)))
165           {
166           //if(MapperExRAM[0x8+V]&0x10) amp+=MapperExRAM[0x20]&15;
167                                 //else
168                                 amp+=MapperExRAM[0x8+V]&15;
169           }
170          }
171      amp<<=3;
172
173      if(amp)
174        {
175         freq=PSG_base/(MapperExRAM[0x6]+1);
176         if(freq>44100)
177          inc=((freq<<11)/(FSettings.SndRate OVERSAMPLE))<<4;
178         else
179          inc=(freq<<15)/(FSettings.SndRate OVERSAMPLE);
180
181          for(V=start;V<end;V++)
182           {
183              static uint32 mixer;
184
185              if(vcount[3]>=32768)
186              {
187                unsigned char feedback;
188                mixer=0;
189                if(znreg&1) mixer+=amp;
190                feedback=((znreg>>13)&1)^((znreg>>14)&1);
191                znreg=(znreg<<1)+(feedback);
192                vcount[3]-=32768;
193              }
194              Wave[V>>4]+=mixer;
195              vcount[3]+=inc;
196            }
197        }
198
199
200 }
201 static void AYSound(int Count)
202 {
203     int x;
204     DoAYSQ(0);
205     DoAYSQ(1);
206     DoAYSQ(2);
207     DoAYNoise();
208     for(x=0;x<4;x++)
209      CAYBC[x]=Count;
210 }
211
212 static void FP_FASTAPASS(1) SunIRQHook(int a)
213 {
214   if(IRQa)
215   {
216    IRQCount-=a;
217    if(IRQCount<=0)
218    {TriggerIRQ();IRQa=0;IRQCount=0xFFFF;}
219   }
220 }
221
222 void Mapper69_StateRestore(int version)
223 {
224    if(version>=19)
225    {
226     if(mapbyte1[1]&0x40)
227     {
228      if(mapbyte1[1]&0x80) // Select WRAM
229       setprg8r(0x10,0x6000,0);
230     }
231     else
232      setprg8(0x6000,mapbyte1[1]);
233    }
234    else
235     mapbyte1[1]=0xC0;
236 }
237
238 static void M69SC(void)
239 {
240  if(FSettings.SndRate)
241   Mapper69_ESI();
242  else 
243   SetWriteHandler(0xc000,0xffff,(writefunc)0);
244 }
245
246 void Mapper69_ESI(void)
247 {
248  GameExpSound.RChange=M69SC; 
249  if(FSettings.SndRate)
250  {
251   SetWriteHandler(0xc000,0xdfff,Mapper69_SWL);
252   SetWriteHandler(0xe000,0xffff,Mapper69_SWH);
253  }
254 }
255
256 void Mapper69_init(void)
257 {
258  SetupCartPRGMapping(0x10,WRAM,8192,1);
259
260  SetWriteHandler(0x8000,0xbfff,Mapper69_write);
261  SetWriteHandler(0x6000,0x7fff,SUN5BWRAM);
262  SetReadHandler(0x6000,0x7fff,SUN5AWRAM);
263  Mapper69_ESI();
264  MapIRQHook=SunIRQHook;
265  MapStateRestore=Mapper69_StateRestore;
266  znreg=0;
267 }
268