merge mappers from FCEU-mm
[fceu.git] / boards / 116.c
CommitLineData
386f5371 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2011 CaH4e3\r
5 *\r
6 * This program is free software; you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation; either version 2 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * This program is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with this program; if not, write to the Free Software\r
43725da7 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
19 *\r
386f5371 20 * SL12 Protected 3-in-1 mapper hardware (VRC2, MMC3, MMC1)\r
21 * the same as 603-5052 board (TODO: add reading registers, merge)\r
22 * SL1632 2-in-1 protected board, similar to SL12 (TODO: find difference)\r
23 *\r
24 * Known PCB:\r
25 *\r
26 * Garou Densetsu Special (G0904.PCB, Huang-1, GAL dip: W conf.)\r
27 * Kart Fighter (008, Huang-1, GAL dip: W conf.)\r
28 * Somari (008, C5052-13, GAL dip: P conf., GK2-P/GK2-V maskroms)\r
29 * Somari (008, Huang-1, GAL dip: W conf., GK1-P/GK1-V maskroms)\r
43725da7 30 * AV Mei Shao Nv Zhan Shi (aka AV Pretty Girl Fighting) (SL-12 PCB, Hunag-1, GAL dip: unk conf. SL-11A/SL-11B maskroms)\r
386f5371 31 * Samurai Spirits (Full version) (Huang-1, GAL dip: unk conf. GS-2A/GS-4A maskroms)\r
43725da7 32 * Contra Fighter (603-5052 PCB, C5052-3, GAL dip: unk conf. SC603-A/SCB603-B maskroms)\r
386f5371 33 *\r
34 */\r
35\r
36#include "mapinc.h"\r
386f5371 37\r
38static uint8 mode;\r
39static uint8 vrc2_chr[8], vrc2_prg[2], vrc2_mirr;\r
40static uint8 mmc3_regs[10], mmc3_ctrl, mmc3_mirr;\r
43725da7 41static uint8 IRQCount,IRQLatch,IRQa;\r
42static uint8 IRQReload;\r
386f5371 43static uint8 mmc1_regs[4], mmc1_buffer, mmc1_shift;\r
44\r
45static SFORMAT StateRegs[]=\r
46{\r
47 {&mode, 1, "MODE"},\r
43725da7 48 {vrc2_chr, 8, "VRCC"},\r
49 {vrc2_prg, 2, "VRCP"},\r
50 {&vrc2_mirr, 1, "VRCM"},\r
51 {mmc3_regs, 10, "M3RG"},\r
52 {&mmc3_ctrl, 1, "M3CT"},\r
53 {&mmc3_mirr, 1, "M3MR"},\r
386f5371 54 {&IRQReload, 1, "IRQR"},\r
55 {&IRQCount, 1, "IRQC"},\r
56 {&IRQLatch, 1, "IRQL"},\r
57 {&IRQa, 1, "IRQA"},\r
43725da7 58 {mmc1_regs, 4, "M1RG"},\r
59 {&mmc1_buffer, 1, "M1BF"},\r
60 {&mmc1_shift, 1, "M1MR"},\r
386f5371 61 {0}\r
62};\r
63\r
64static void SyncPRG(void)\r
65{\r
66 switch(mode & 3) {\r
67 case 0:\r
68 setprg8(0x8000, vrc2_prg[0]);\r
69 setprg8(0xA000, vrc2_prg[1]);\r
70 setprg8(0xC000, ~1);\r
71 setprg8(0xE000, ~0);\r
72 break;\r
73 case 1: {\r
74 uint32 swap = (mmc3_ctrl >> 5) & 2;\r
75 setprg8(0x8000, mmc3_regs[6 + swap]);\r
76 setprg8(0xA000, mmc3_regs[7]);\r
77 setprg8(0xC000, mmc3_regs[6 + (swap ^ 2)]);\r
78 setprg8(0xE000, mmc3_regs[9]);\r
79 break;\r
80 }\r
81 case 2:\r
82 case 3: {\r
83 uint8 bank = mmc1_regs[3] & 0xF;\r
84 if(mmc1_regs[0] & 8)\r
85 {\r
86 if(mmc1_regs[0] & 4)\r
87 {\r
88 setprg16(0x8000, bank);\r
89 setprg16(0xC000, 0x0F);\r
90 }\r
91 else\r
92 {\r
93 setprg16(0x8000, 0);\r
94 setprg16(0xC000, bank);\r
95 }\r
96 }\r
97 else\r
98 setprg32(0x8000, bank >> 1);\r
99 break;\r
100 }\r
101 }\r
102}\r
103\r
104static void SyncCHR(void)\r
105{\r
106 uint32 base = (mode & 4) << 6;\r
107 switch(mode & 3) {\r
108 case 0:\r
109 setchr1(0x0000, base|vrc2_chr[0]);\r
110 setchr1(0x0400, base|vrc2_chr[1]);\r
111 setchr1(0x0800, base|vrc2_chr[2]);\r
112 setchr1(0x0c00, base|vrc2_chr[3]);\r
113 setchr1(0x1000, base|vrc2_chr[4]);\r
114 setchr1(0x1400, base|vrc2_chr[5]);\r
115 setchr1(0x1800, base|vrc2_chr[6]);\r
116 setchr1(0x1c00, base|vrc2_chr[7]);\r
117 break;\r
118 case 1: {\r
119 uint32 swap = (mmc3_ctrl & 0x80) << 5;\r
120 setchr1(0x0000 ^ swap, base|((mmc3_regs[0])&0xFE));\r
121 setchr1(0x0400 ^ swap, base|(mmc3_regs[0]|1));\r
122 setchr1(0x0800 ^ swap, base|((mmc3_regs[1])&0xFE));\r
123 setchr1(0x0c00 ^ swap, base|(mmc3_regs[1]|1));\r
124 setchr1(0x1000 ^ swap, base|mmc3_regs[2]);\r
125 setchr1(0x1400 ^ swap, base|mmc3_regs[3]);\r
126 setchr1(0x1800 ^ swap, base|mmc3_regs[4]);\r
127 setchr1(0x1c00 ^ swap, base|mmc3_regs[5]);\r
128 break;\r
129 }\r
130 case 2:\r
131 case 3:\r
132 if(mmc1_regs[0]&0x10)\r
133 {\r
134 setchr4(0x0000, mmc1_regs[1]);\r
135 setchr4(0x1000, mmc1_regs[2]);\r
136 }\r
137 else\r
138 setchr8(mmc1_regs[1] >> 1);\r
139 break;\r
140 }\r
141}\r
142\r
143static void SyncMIR(void)\r
144{\r
145 switch(mode & 3) {\r
146 case 0: {\r
147 setmirror((vrc2_mirr&1)^1);\r
148 break;\r
149 }\r
150 case 1: {\r
151 setmirror((mmc3_mirr&1)^1);\r
152 break;\r
153 }\r
154 case 2:\r
155 case 3: {\r
156 switch(mmc1_regs[0]&3) {\r
157 case 0: setmirror(MI_0); break;\r
158 case 1: setmirror(MI_1); break;\r
159 case 2: setmirror(MI_V); break;\r
160 case 3: setmirror(MI_H); break;\r
161 }\r
162 break;\r
163 }\r
164 }\r
165}\r
166\r
167static void Sync(void)\r
168{\r
169 SyncPRG();\r
170 SyncCHR();\r
171 SyncMIR();\r
172}\r
173\r
174static DECLFW(UNLSL12ModeWrite)\r
175{\r
43725da7 176// FCEU_printf("%04X:%02X\n",A,V);\r
386f5371 177 if((A & 0x4100) == 0x4100) {\r
178 mode = V;\r
179 if(A&1) { // hacky hacky, there are two configuration modes on SOMARI HUANG-1 PCBs\r
180 // Solder pads with P1/P2 shorted called SOMARI P,\r
181 // Solder pads with W1/W2 shorted called SOMARI W\r
182 // Both identical 3-in-1 but W wanted MMC1 registers\r
183 // to be reset when switch to MMC1 mode P one - doesn't\r
184 // There is issue with W version of Somari at starting copyrights\r
185 mmc1_regs[0] = 0xc;\r
186 mmc1_regs[3] = 0;\r
187 mmc1_buffer = 0;\r
188 mmc1_shift = 0;\r
189 }\r
190 Sync();\r
191 }\r
192}\r
193\r
194static DECLFW(UNLSL12Write)\r
195{\r
43725da7 196// FCEU_printf("%04X:%02X\n",A,V);\r
386f5371 197 switch(mode & 3) {\r
198 case 0: {\r
199 if((A>=0xB000)&&(A<=0xE003))\r
200 {\r
201 int32 ind=((((A&2)|(A>>10))>>1)+2)&7;\r
202 int32 sar=((A&1)<<2);\r
203 vrc2_chr[ind]=(vrc2_chr[ind]&(0xF0>>sar))|((V&0x0F)<<sar);\r
204 SyncCHR();\r
205 }\r
206 else\r
207 switch(A&0xF000) {\r
208 case 0x8000: vrc2_prg[0] = V; SyncPRG(); break;\r
209 case 0xA000: vrc2_prg[1] = V; SyncPRG(); break;\r
210 case 0x9000: vrc2_mirr = V; SyncMIR(); break;\r
211 }\r
212 break;\r
213 }\r
214 case 1: {\r
215 switch(A & 0xE001) {\r
216 case 0x8000: {\r
217 uint8 old_ctrl = mmc3_ctrl;\r
218 mmc3_ctrl = V;\r
219 if((old_ctrl&0x40) != (mmc3_ctrl&0x40))\r
220 SyncPRG();\r
221 if((old_ctrl&0x80) != (mmc3_ctrl&0x80))\r
222 SyncCHR();\r
223 break;\r
224 }\r
225 case 0x8001:\r
226 mmc3_regs[mmc3_ctrl & 7] = V;\r
227 if((mmc3_ctrl & 7) < 6)\r
228 SyncCHR();\r
229 else\r
230 SyncPRG();\r
231 break;\r
232 case 0xA000:\r
233 mmc3_mirr = V;\r
234 SyncMIR();\r
235 break;\r
236 case 0xC000:\r
237 IRQLatch = V;\r
238 break;\r
239 case 0xC001:\r
240 IRQReload = 1;\r
241 break;\r
242 case 0xE000:\r
243 X6502_IRQEnd(FCEU_IQEXT);\r
244 IRQa=0;\r
245 break;\r
246 case 0xE001:\r
247 IRQa=1;\r
248 break;\r
249 }\r
250 break;\r
251 }\r
252 case 2:\r
253 case 3: {\r
254 if(V & 0x80)\r
255 {\r
256 mmc1_regs[0] |= 0xc;\r
257 mmc1_buffer = mmc1_shift = 0;\r
258 SyncPRG();\r
259 }\r
260 else\r
261 {\r
262 uint8 n = (A >> 13) - 4;\r
263 mmc1_buffer |= (V & 1) << (mmc1_shift++);\r
264 if(mmc1_shift == 5)\r
265 {\r
266 mmc1_regs[n] = mmc1_buffer;\r
267 mmc1_buffer = mmc1_shift = 0;\r
268 switch(n) {\r
269 case 0: SyncMIR();\r
43725da7 270 case 2: SyncCHR();\r
386f5371 271 case 3:\r
272 case 1: SyncPRG();\r
273 }\r
274 }\r
275 }\r
276 break;\r
277 }\r
278 }\r
279}\r
280\r
281static void UNLSL12HBIRQ(void)\r
282{\r
283 if((mode & 3) == 1)\r
284 {\r
285 int32 count = IRQCount;\r
286 if(!count || IRQReload)\r
287 {\r
288 IRQCount = IRQLatch;\r
289 IRQReload = 0;\r
290 }\r
291 else\r
292 IRQCount--;\r
293 if(!IRQCount)\r
294 {\r
295 if(IRQa)\r
296 X6502_IRQBegin(FCEU_IQEXT);\r
297 }\r
298 }\r
299}\r
300\r
301static void StateRestore(int version)\r
302{\r
303 Sync();\r
304}\r
305\r
306static void UNLSL12Power(void)\r
307{\r
308 mode = 0;\r
309 vrc2_chr[0] = ~0;\r
310 vrc2_chr[1] = ~0;\r
311 vrc2_chr[2] = ~0;\r
312 vrc2_chr[3] = ~0; // W conf. of Somari wanted CHR3 has to be set to BB bank (or similar), but doesn't do that directly\r
313 vrc2_chr[4] = 4;\r
314 vrc2_chr[5] = 5;\r
315 vrc2_chr[6] = 6;\r
316 vrc2_chr[7] = 7;\r
317 vrc2_prg[0] = 0;\r
318 vrc2_prg[1] = 1;\r
319 vrc2_mirr = 0;\r
320 mmc3_regs[0] = 0;\r
321 mmc3_regs[1] = 2;\r
322 mmc3_regs[2] = 4;\r
323 mmc3_regs[3] = 5;\r
324 mmc3_regs[4] = 6;\r
325 mmc3_regs[5] = 7;\r
326 mmc3_regs[6] = ~3;\r
327 mmc3_regs[7] = ~2;\r
328 mmc3_regs[8] = ~1;\r
329 mmc3_regs[9] = ~0;\r
330 mmc3_ctrl = mmc3_mirr = IRQCount = IRQLatch = IRQa = 0;\r
331 mmc1_regs[0] = 0xc;\r
332 mmc1_regs[1] = 0;\r
333 mmc1_regs[2] = 0;\r
334 mmc1_regs[3] = 0;\r
335 mmc1_buffer = 0;\r
336 mmc1_shift = 0;\r
337 Sync();\r
338 SetReadHandler(0x8000,0xFFFF,CartBR);\r
339 SetWriteHandler(0x4100,0x7FFF,UNLSL12ModeWrite);\r
340 SetWriteHandler(0x8000,0xFFFF,UNLSL12Write);\r
341}\r
342\r
343void UNLSL12_Init(CartInfo *info)\r
344{\r
345 info->Power = UNLSL12Power;\r
346 GameHBIRQHook = UNLSL12HBIRQ;\r
347 GameStateRestore = StateRestore;\r
348 AddExState(&StateRegs, ~0, 0, 0);\r
349}\r