merge mapper code from FCEUX
[fceu.git] / boards / datalatch.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "mapinc.h"
22 #include "../ines.h"
23
24 static uint8 latche, latcheinit, bus_conflict;
25 static uint16 addrreg0, addrreg1;
26 static uint8 *WRAM=NULL;
27 static uint32 WRAMSIZE;
28 static void(*WSync)(void);
29
30 static DECLFW(LatchWrite)
31 {
32 //  FCEU_printf("bs %04x %02x\n",A,V);
33   if(bus_conflict)
34     latche=V&CartBR(A);
35   else
36   latche=V;
37   WSync();
38 }
39
40 static void LatchPower(void)
41 {
42   latche=latcheinit;
43   WSync();
44         if(WRAM)
45         {
46                 SetReadHandler(0x6000,0xFFFF,CartBR);
47                 SetWriteHandler(0x6000,0x7FFF,CartBW);
48         }
49         else
50         {
51                 SetReadHandler(0x8000,0xFFFF,CartBR);
52         }
53   SetWriteHandler(addrreg0,addrreg1,LatchWrite);
54 }
55
56 static void LatchClose(void)
57 {
58   if(WRAM)
59     FCEU_gfree(WRAM);
60   WRAM=NULL;
61 }
62
63 static void StateRestore(int version)
64 {
65   WSync();
66 }
67
68 static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 adr0, uint16 adr1, uint8 wram, uint8 busc)
69 {
70   bus_conflict = busc;
71   latcheinit=init;
72   addrreg0=adr0;
73   addrreg1=adr1;
74   WSync=proc;
75   info->Power=LatchPower;
76   info->Close=LatchClose;
77   GameStateRestore=StateRestore;
78   if(wram)
79   {
80     WRAMSIZE=8192;
81     WRAM=(uint8*)FCEU_gmalloc(WRAMSIZE);
82     SetupCartPRGMapping(0x10,WRAM,WRAMSIZE,1);
83     if(info->battery)
84     {
85       info->SaveGame[0]=WRAM;
86       info->SaveGameLen[0]=WRAMSIZE;
87     }
88     AddExState(WRAM, WRAMSIZE, 0, "WRAM");
89   }
90   AddExState(&latche, 1, 0, "LATC");
91 }
92
93 //------------------ CPROM ---------------------------
94
95 static void CPROMSync(void)
96 {
97   setchr4(0x0000,0);
98   setchr4(0x1000,latche&3);
99   setprg16(0x8000,0);
100   setprg16(0xC000,1);
101 }
102
103 void CPROM_Init(CartInfo *info)
104 {
105   Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0);
106 }
107
108 //------------------ Map 184 ---------------------------
109
110 static void M184Sync(void)
111 {
112   setchr4(0x0000,latche);
113   setchr4(0x1000,latche>>4);
114   setprg16(0x8000,0);
115   setprg16(0xC000,1);
116 }
117
118 void Mapper184_Init(CartInfo *info)
119 {
120   Latch_Init(info, M184Sync, 0, 0x6000, 0x7FFF, 0, 0);
121 }
122
123 //------------------ CNROM ---------------------------
124
125 static void CNROMSync(void)
126 {
127         //mbg 8/10/08 - fixed this so that large homebrew roms would work.
128         //setchr8(latche&3);
129         setchr8(latche);
130         setprg16(0x8000,0);
131         setprg16(0xC000,1);
132   setprg8r(0x10,0x6000,0); // Hayauchy IGO uses 2Kb or RAM
133 }
134
135 void CNROM_Init(CartInfo *info)
136 {
137         bool busc = MasterRomInfoParams.ContainsKey("busc");
138         Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, busc?1:0);
139 }
140
141 //------------------ ANROM ---------------------------
142
143 static void ANROMSync()
144 {
145   setprg32(0x8000,latche&0xf);
146   setmirror(MI_0+((latche>>4)&1));
147   setchr8(0);
148 }
149
150 void ANROM_Init(CartInfo *info)
151 {
152   Latch_Init(info, ANROMSync, 0, 0x8000, 0xFFFF, 0, 0);
153 }
154
155 //------------------ Map 70 ---------------------------
156
157 static void M70Sync()
158 {
159   setprg16(0x8000,latche>>4);
160   setprg16(0xc000,~0);
161   setchr8(latche&0xf);
162 }
163
164 void Mapper70_Init(CartInfo *info)
165 {
166   Latch_Init(info, M70Sync, 0, 0x8000, 0xFFFF, 0, 0);
167 }
168
169 //------------------ Map 152 ---------------------------
170
171 static void M152Sync()
172 {
173   setprg16(0x8000,(latche>>4)&7);
174   setprg16(0xc000,~0);
175   setchr8(latche&0xf);
176   setmirror(MI_0+((latche>>7)&1));         /* Saint Seiya...hmm. */
177 }
178
179 void Mapper152_Init(CartInfo *info)
180 {
181   Latch_Init(info, M152Sync, 0, 0x8000, 0xFFFF, 0, 0);
182 }
183
184 //------------------ Map 78 ---------------------------
185 /* Should be two separate emulation functions for this "mapper".  Sigh.  URGE TO KILL RISING. */
186 static void M78Sync()
187 {
188   setprg16(0x8000,(latche&7));
189   setprg16(0xc000,~0);
190   setchr8(latche>>4);
191   setmirror(MI_0+((latche>>3)&1));
192 }
193
194 void Mapper78_Init(CartInfo *info)
195 {
196   Latch_Init(info, M78Sync, 0, 0x8000, 0xFFFF, 0, 0);
197 }
198
199 //------------------ MHROM ---------------------------
200
201 static void MHROMSync(void)
202 {
203   setprg32(0x8000,latche>>4);
204   setchr8(latche&0xf);
205 }
206
207 void MHROM_Init(CartInfo *info)
208 {
209   Latch_Init(info, MHROMSync, 0, 0x8000, 0xFFFF, 0, 0);
210 }
211
212 void Mapper140_Init(CartInfo *info)
213 {
214   Latch_Init(info, MHROMSync, 0, 0x6000, 0x7FFF, 0, 0);
215 }
216
217 void Mapper240_Init(CartInfo *info)
218 {
219   Latch_Init(info, MHROMSync, 0, 0x4020, 0x5FFF, 0, 0);
220   // need SRAM.
221 }
222
223 //------------------ Map 87 ---------------------------
224
225 static void M87Sync(void)
226 {
227   setprg16(0x8000,0);
228   setprg16(0xC000,1);
229   setchr8(((latche>>1)&1)|((latche<<1)&2));
230 //  setchr8(latche);
231 }
232
233 void Mapper87_Init(CartInfo *info)
234 {
235   Latch_Init(info, M87Sync, ~0, 0x6000, 0xFFFF, 0, 0);
236 }
237
238 //------------------ Map 101 ---------------------------
239
240 static void M101Sync(void)
241 {
242   setprg16(0x8000,0);
243   setprg16(0xC000,1);
244   setchr8(latche);
245 }
246
247 void Mapper101_Init(CartInfo *info)
248 {
249   Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0);
250 }
251
252 //------------------ Map 11 ---------------------------
253
254 static void M11Sync(void)
255 {
256   setprg32(0x8000,latche&0xf);
257   setchr8(latche>>4);
258 }
259
260 void Mapper11_Init(CartInfo *info)
261 {
262   Latch_Init(info, M11Sync, 0, 0x8000, 0xFFFF, 0, 0);
263 }
264
265 void Mapper144_Init(CartInfo *info)
266 {
267   Latch_Init(info, M11Sync, 0, 0x8001, 0xFFFF, 0, 0);
268 }
269
270 //------------------ Map 38 ---------------------------
271
272 static void M38Sync(void)
273 {
274   setprg32(0x8000,latche&3);
275   setchr8(latche>>2);
276 }
277
278 void Mapper38_Init(CartInfo *info)
279 {
280   Latch_Init(info, M38Sync, 0, 0x7000, 0x7FFF, 0, 0);
281 }
282
283 //------------------ Map 36 ---------------------------
284
285 static void M36Sync(void)
286 {
287   setprg32(0x8000,latche>>4);
288   setchr8((latche)&0xF);
289 }
290
291 void Mapper36_Init(CartInfo *info)
292 {
293   Latch_Init(info, M36Sync, 0, 0x8400, 0xfffe, 0, 0);
294 }
295 //------------------ UNROM ---------------------------
296
297 static void UNROMSync(void)
298 {
299   setprg16(0x8000,latche);
300   setprg16(0xc000,~0);
301   setchr8(0);
302 }
303
304 void UNROM_Init(CartInfo *info)
305 {
306   Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, 1);
307 }
308
309 //------------------ Map 93 ---------------------------
310
311 static void SSUNROMSync(void)
312 {
313   setprg16(0x8000,latche>>4);
314   setprg16(0xc000,~0);
315   setchr8(0);
316 }
317
318 void SUNSOFT_UNROM_Init(CartInfo *info)
319 {
320   Latch_Init(info, SSUNROMSync, 0, 0x8000, 0xFFFF, 0, 0);
321 }
322
323 //------------------ Map 94 ---------------------------
324
325 static void M94Sync(void)
326 {
327   setprg16(0x8000,latche>>2);
328   setprg16(0xc000,~0);
329   setchr8(0);
330 }
331
332 void Mapper94_Init(CartInfo *info)
333 {
334   Latch_Init(info, M94Sync, 0, 0x8000, 0xFFFF, 0, 0);
335 }
336
337 //------------------ Map 180 ---------------------------
338
339 static void M180Sync(void)
340 {
341   setprg16(0x8000,0);
342   setprg16(0xc000,latche);
343   setchr8(0);
344 }
345
346 void Mapper180_Init(CartInfo *info)
347 {
348   Latch_Init(info, M180Sync, 0, 0x8000, 0xFFFF, 0, 0);
349 }
350
351 //------------------ Map 107 ---------------------------
352
353 static void M107Sync(void)
354 {
355   setprg32(0x8000,(latche>>1)&3);
356   setchr8(latche&7);
357 }
358
359 void Mapper107_Init(CartInfo *info)
360 {
361   Latch_Init(info, M107Sync, ~0, 0x8000, 0xFFFF, 0, 0);
362 }
363
364 //------------------ Map 113 ---------------------------
365
366 static void M113Sync(void)
367 {
368   setprg32(0x8000,(latche>>3)&7);
369   setchr8(((latche>>3)&8)|(latche&7));
370 //  setmirror(latche>>7); // only for HES 6in1
371 }
372
373 void Mapper113_Init(CartInfo *info)
374 {
375   Latch_Init(info, M113Sync, 0, 0x4100, 0x7FFF, 0, 0);
376 }
377
378 //------------------ A65AS ---------------------------
379
380 // actually, there is two cart in one... First have extra mirroring
381 // mode (one screen) and 32K bankswitching, second one have only
382 // 16 bankswitching mode and normal mirroring... But there is no any
383 // correlations between modes and they can be used in one mapper code.
384
385 static void BMCA65ASSync(void)
386 {
387   if(latche&0x40)
388     setprg32(0x8000,(latche>>1)&0x0F);
389   else
390   {
391     setprg16(0x8000,((latche&0x30)>>1)|(latche&7));
392     setprg16(0xC000,((latche&0x30)>>1)|7);
393   }
394   setchr8(0);
395   if(latche&0x80)
396     setmirror(MI_0+(((latche>>5)&1)));
397   else
398     setmirror(((latche>>3)&1)^1);
399 }
400
401 void BMCA65AS_Init(CartInfo *info)
402 {
403   Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0);
404 }
405
406 //------------------ NROM ---------------------------
407
408 #ifdef DEBUG_MAPPER
409 static DECLFW(WriteHandler)
410 {
411  FCEU_printf("bs %04x %02x\n",A,V);
412  CartBW(A,V);
413 }
414 #endif
415
416 static void NROMPower(void)
417 {
418   setprg8r(0x10,0x6000,0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB
419   setprg16(0x8000,0);
420   setprg16(0xC000,~0);
421   setchr8(0);
422
423   SetReadHandler(0x6000,0x7FFF,CartBR);
424   SetWriteHandler(0x6000,0x7FFF,CartBW);
425   SetReadHandler(0x8000,0xFFFF,CartBR);
426
427   #ifdef DEBUG_MAPPER
428   SetWriteHandler(0x4020,0xFFFF,WriteHandler);
429   #endif
430 }
431
432 void NROM_Init(CartInfo *info)
433 {
434   info->Power=NROMPower;
435   info->Close=LatchClose;
436
437   WRAMSIZE=8192;
438   WRAM=(uint8*)FCEU_gmalloc(WRAMSIZE);
439   SetupCartPRGMapping(0x10,WRAM,WRAMSIZE,1);
440   if(info->battery)
441   {
442     info->SaveGame[0]=WRAM;
443     info->SaveGameLen[0]=WRAMSIZE;
444   }
445   AddExState(WRAM, WRAMSIZE, 0, "WRAM");
446 }