release r2, update credits
[fceu.git] / mappers / 85.c
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
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * VRC-7
21  *
22  */
23
24 #include "mapinc.h"
25
26 #define vrctemp mapbyte1[0]
27 static uint8 indox;
28
29 #include "emu2413.h"
30
31 static int acount=0;
32
33 static OPLL *VRC7Sound=NULL;
34 static int dwave=0;
35
36 void DoVRC7Sound(void)
37 {
38  int32 z,a;
39
40  if(FSettings.soundq>=1) return;
41  z=((SOUNDTS<<16)/soundtsinc)>>4;
42  a=z-dwave;
43
44  moocow(VRC7Sound, &Wave[dwave], a, 1);
45
46  dwave+=a;
47 }
48
49 void UpdateOPLNEO(int32 *Wave, int Count)
50 {
51  moocow(VRC7Sound, Wave, Count, 4);
52 }
53
54 void UpdateOPL(int Count)
55 {
56  int32 z,a;
57
58   z=((SOUNDTS<<16)/soundtsinc)>>4;
59  a=z-dwave;
60
61  if(VRC7Sound && a)
62   moocow(VRC7Sound, &Wave[dwave], a, 1);
63
64  dwave=0;
65 }
66
67 static INLINE void DaMirror(int V)
68 {
69  int salpo[4]={MI_V,MI_H,MI_0,MI_1};
70  setmirror(salpo[V&3]);
71 }
72
73 DECLFW(Mapper85_write)
74 {
75         A|=(A&8)<<1;
76
77         if(A>=0xa000 && A<=0xDFFF)
78         {
79         // printf("$%04x, $%04x\n",X.PC,A);
80          A&=0xF010;
81          {
82           int x=((A>>4)&1)|((A-0xA000)>>11);
83            mapbyte3[x]=V;
84           setchr1(x<<10,V);
85          }
86         }
87         else if(A==0x9030)
88         {
89          if(FSettings.SndRate)
90          {
91           OPLL_writeReg(VRC7Sound, indox, V);
92           GameExpSound.Fill=UpdateOPL;
93           GameExpSound.NeoFill=UpdateOPLNEO;
94          }
95         }
96         else switch(A&0xF010)
97         {
98          case 0x8000:mapbyte2[0]=V;setprg8(0x8000,V);break;
99          case 0x8010:mapbyte2[1]=V;setprg8(0xa000,V);break;
100          case 0x9000:mapbyte2[2]=V;setprg8(0xc000,V);break;
101          case 0x9010:indox=V;break;
102          case 0xe000:mapbyte2[3]=V;DaMirror(V);break;
103          case 0xE010:IRQLatch=V;
104                      X6502_IRQEnd(FCEU_IQEXT);
105                      break;
106          case 0xF000:IRQa=V&2;
107                      vrctemp=V&1;
108                      if(V&2) {IRQCount=IRQLatch;}
109                      acount=0;
110                      X6502_IRQEnd(FCEU_IQEXT);
111                      break;
112          case 0xf010:if(vrctemp) IRQa=1;
113                      else IRQa=0;
114                      X6502_IRQEnd(FCEU_IQEXT);
115                      break;
116         }
117 }
118
119 static void FP_FASTAPASS(1) KonamiIRQHook(int a)
120 {
121   #define ACBOO 341
122 //  #define ACBOO ((227*2)+1)
123   if(IRQa)
124    {
125     acount+=a*3;
126
127     if(acount>=ACBOO)
128     {
129      doagainbub:acount-=ACBOO;
130      IRQCount++;
131      if(IRQCount&0x100) {X6502_IRQBegin(FCEU_IQEXT);IRQCount=IRQLatch;}
132      if(acount>=ACBOO) goto doagainbub;
133     }
134  }
135 }
136
137 void Mapper85_StateRestore(int version)
138 {
139  int x;
140
141  if(version<7200)
142  {
143   for(x=0;x<8;x++)
144    mapbyte3[x]=CHRBankList[x];
145   for(x=0;x<3;x++)
146    mapbyte2[x]=PRGBankList[x];
147   mapbyte2[3]=(Mirroring<0x10)?Mirroring:Mirroring-0xE;
148  }
149
150  for(x=0;x<8;x++)
151   setchr1(x*0x400,mapbyte3[x]);
152  for(x=0;x<3;x++)
153   setprg8(0x8000+x*8192,mapbyte2[x]);
154  DaMirror(mapbyte2[3]);
155  //LoadOPL();
156 }
157
158 static void M85SC(void)
159 {
160  if(VRC7Sound)
161   OPLL_set_rate(VRC7Sound, FSettings.SndRate);
162 }
163
164 static void M85SKill(void)
165 {
166  if(VRC7Sound)
167   OPLL_delete(VRC7Sound);
168  VRC7Sound=NULL;
169 }
170
171 static void VRC7SI(void)
172 {
173   GameExpSound.RChange=M85SC;
174   GameExpSound.Kill=M85SKill;
175
176   VRC7Sound=OPLL_new(3579545, FSettings.SndRate?FSettings.SndRate:44100);
177   OPLL_reset(VRC7Sound);
178   OPLL_reset(VRC7Sound);
179 }
180
181 void NSFVRC7_Init(void)
182 {
183     SetWriteHandler(0x9010,0x901F,Mapper85_write);
184     SetWriteHandler(0x9030,0x903F,Mapper85_write);
185     VRC7SI();
186 }
187
188 void Mapper85_init(void)
189 {
190   MapIRQHook=KonamiIRQHook;
191   SetWriteHandler(0x8000,0xffff,Mapper85_write);
192   GameStateRestore=Mapper85_StateRestore;
193   if(!VROM_size)
194    SetupCartCHRMapping(0, CHRRAM, 8192, 1);
195   //AddExState(VRC7Instrument, 16, 0, "VC7I");
196   //AddExState(VRC7Chan, sizeof(VRC7Chan), 0, "V7CH");
197   VRC7SI();
198 }