merge mapper code from FCEUX
[fceu.git] / boards / onebus.c
CommitLineData
386f5371 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2007-2010 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
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
19 *\r
20 * OneBus system\r
21 * Street Dance (Dance pad) (Unl)\r
22 * 101-in-1 Arcade Action II\r
23 * DreamGEAR 75-in-1\r
24 */\r
25\r
26#include "mapinc.h"\r
27\r
28static uint8 isDance;\r
29static uint8 regs[16],regc[6];\r
30static uint8 IRQCount,IRQLatch,IRQa, IRQReload, pcm_enable = 0, pcm_irq = 0;\r
31static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xF6;\r
32static writefunc old4011write, old4012write, old4013write, old4015write;\r
33static readfunc old4015read;\r
34\r
35static SFORMAT StateRegs[]=\r
36{\r
37 {regc, 6, "REGC"},\r
38 {regs, 16, "REGS"},\r
39 {&IRQReload, 1, "IRQR"},\r
40 {&IRQCount, 1, "IRQC"},\r
41 {&IRQLatch, 1, "IRQL"},\r
42 {&IRQa, 1, "IRQA"},\r
43 {&pcm_enable, 1, "PCME"},\r
44 {&pcm_irq, 1, "PCMIRQ"},\r
45 {&pcm_addr, 2, "PCMADDR"},\r
46 {&pcm_size, 2, "PCMSIZE"},\r
47 {&pcm_latch, 2, "PCMLATCH"},\r
48 {&pcm_clock, 2, "PCMCLOCK"},\r
49 {0}\r
50};\r
51\r
52static void Sync(void)\r
53{\r
54 uint16 cswap = (regs[0xf] & 0x80) << 5;\r
55 uint16 pswap = (regs[0xd]&1)?((regs[0xf] & 0x40) << 8):0;\r
56 uint16 pbase = (regs[0]&0xf0)<<4;\r
57 uint16 cbase = (((regs[0]&0x0f)<<8)|(regs[0xc]<<1)|((regs[0xd]&0xf8)>>3))<<3;\r
58 uint16 pmask = 0x3f>>(regs[0xb]&0xf);\r
59\r
60 setchr1(cswap^0x0000,cbase|(regc[0]&(~1)));\r
61 setchr1(cswap^0x0400,cbase|(regc[0]|1));\r
62 setchr1(cswap^0x0800,cbase|(regc[1]&(-1)));\r
63 setchr1(cswap^0x0c00,cbase|(regc[1]|1));\r
64 setchr1(cswap^0x1000,cbase|(regc[2]));\r
65 setchr1(cswap^0x1400,cbase|(regc[3]));\r
66 setchr1(cswap^0x1800,cbase|(regc[4]));\r
67 setchr1(cswap^0x1c00,cbase|(regc[5]));\r
68\r
69 if(regs[0xd]&2)\r
70 {\r
71 setprg8(pswap^0x8000, pbase|(regs[0x7]&pmask)|(regs[0xa]&(~pmask)));\r
72 setprg8( 0xA000, pbase|(regs[0x8]&pmask)|(regs[0xa]&(~pmask)));\r
73 setprg8(pswap^0xC000, pbase|(regs[0x9]&pmask)|(regs[0xa]&(~pmask)));\r
74 setprg8( 0xE000, pbase|regs[0xa]);\r
75 }\r
76 else\r
77 {\r
78 setprg8(pswap^0x8000, pbase|(regs[0x7]&pmask)|(regs[0xa]&(~pmask)));\r
79 setprg8( 0xA000, pbase|(regs[0x8]&pmask)|(regs[0xa]&(~pmask)));\r
80 setprg8(pswap^0xC000, pbase|((~1)&pmask)|(regs[0xa]&(~pmask)));\r
81 setprg8( 0xE000, pbase|((~0)&pmask)|(regs[0xa]&(~pmask)));\r
82 }\r
83\r
84 setmirror(regs[0xe]);\r
85}\r
86\r
87static DECLFW(UNLOneBusWrite20XX)\r
88{\r
89// FCEU_printf("PPU %04x:%04x\n",A,V);\r
90 if(A == 0x201A)\r
91 regs[0xd] = V;\r
92 else if(A == 0x2018)\r
93 regs[0xc] = V;\r
94 Sync();\r
95}\r
96\r
97static DECLFW(UNLOneBusWriteExp)\r
98{\r
99// FCEU_printf("EXP %04x:%04x\n",A,V);\r
100// switch(A & 0x0F)\r
101// {\r
102// case 2: pcm_latch = pcm_clock; FCEU_printf("write %04x:%04x\n",A,V); break;\r
103// case 3: pcm_irqa = 0; X6502_IRQEnd(FCEU_IQEXT); pcm_irq = 0; FCEU_printf("write %04x:%04x\n",A,V); break;\r
104// case 4: pcm_irqa = 1; FCEU_printf("write %04x:%04x\n",A,V); break;\r
105// default:\r
106 regs[A & 0x0F] = V;\r
107 Sync();\r
108// }\r
109}\r
110\r
111static DECLFW(UNLOneBusWriteDebug)\r
112{\r
113// FCEU_printf("write %04x:%04x\n",A,V);\r
114}\r
115\r
116static DECLFW(UNLOneBusWriteMMC)\r
117{\r
118// FCEU_printf("MMC %04x:%04x\n",A,V);\r
119 switch(A&0xE001)\r
120 {\r
121 case 0x8000: regs[0xf] = V; Sync(); break;\r
122 case 0x8001:\r
123 {\r
124 uint8 mask = 0xff, mmc3cmd = regs[0xf]&7;\r
125 switch(mmc3cmd)\r
126 {\r
127 case 0:\r
128 case 1:\r
129 case 2:\r
130 case 3:\r
131 case 4:\r
132 case 5:\r
133 if(regs[0xd]&4)\r
134 mask = 0x0f;\r
135 else\r
136 mask >>= ((regs[0xb]&0xf0)>>4);\r
137 regc[mmc3cmd] = V&mask;\r
138 break;\r
139 case 6:\r
140 case 7:\r
141 mask = (mask&0x3f)>>(regs[0xb]&0xf);\r
142 regs[mmc3cmd+1] = (regs[mmc3cmd+1]&(~mask))|(V&mask);\r
143 break;\r
144 }\r
145\r
146 Sync();\r
147 break;\r
148 }\r
149 case 0xA000: regs[0xe] = (V & 1)^1; Sync(); break;\r
150 case 0xC000: IRQLatch = V&0xfe; break;\r
151 case 0xC001: IRQReload = 1; break;\r
152 case 0xE000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break;\r
153 case 0xE001: IRQa = 1; break;\r
154 }\r
155}\r
156\r
157static void UNLOneBusIRQHook(void)\r
158{\r
159 int count = IRQCount;\r
160 if(!count || IRQReload)\r
161 {\r
162 IRQCount = IRQLatch;\r
163 IRQReload = 0;\r
164 }\r
165 else\r
166 IRQCount--;\r
167 if(count && !IRQCount)\r
168 {\r
169 if(IRQa)\r
170 X6502_IRQBegin(FCEU_IQEXT);\r
171 }\r
172}\r
173\r
174static DECLFW(UNLOneBusWriteAPU2)\r
175{\r
176// FCEU_printf("APU2 %04x:%04x\n",A,V);\r
177 CartBW(A&0xffdf,V);\r
178}\r
179\r
180static DECLFW(UNLOneBusWrite4012)\r
181{\r
182// FCEU_printf("write %04x:%04x\n",A,V);\r
183 pcm_addr = V << 6;\r
184 old4012write(A,V);\r
185}\r
186\r
187static DECLFW(UNLOneBusWrite4013)\r
188{\r
189// FCEU_printf("write %04x:%04x\n",A,V);\r
190 pcm_size = (V << 4) + 1;\r
191 old4013write(A,V);\r
192}\r
193\r
194static DECLFW(UNLOneBusWrite4015)\r
195{\r
196// FCEU_printf("write %04x:%04x\n",A,V);\r
197 pcm_enable = V&0x10;\r
198 if(pcm_irq)\r
199 {\r
200 X6502_IRQEnd(FCEU_IQEXT);\r
201 pcm_irq = 0;\r
202 }\r
203 if(pcm_enable)\r
204 pcm_latch = pcm_clock;\r
205 old4015write(A,V&0xEF);\r
206}\r
207\r
208static DECLFR(UNLOneBusRead4015)\r
209{\r
210 uint8 result = (old4015read(A) & 0x7F)|pcm_irq;\r
211// FCEU_printf("read %04x, %02x\n",A,result);\r
212 return result;\r
213}\r
214\r
215static void UNLOneBusCpuHook(int a)\r
216{\r
217 if(pcm_enable)\r
218 {\r
219 pcm_latch-=a;\r
220 if(pcm_latch<=0)\r
221 {\r
222 pcm_latch+=pcm_clock;\r
223 pcm_size--;\r
224 if(pcm_size<0)\r
225 {\r
226 pcm_irq = 0x80;\r
227 pcm_enable = 0;\r
228 X6502_IRQBegin(FCEU_IQEXT);\r
229 }\r
230 else\r
231 {\r
232 uint8 raw_pcm = ARead[pcm_addr](pcm_addr) >> 1;\r
233 old4011write(0x4011,raw_pcm);\r
234 pcm_addr++;\r
235 pcm_addr&=0x7FFF;\r
236 }\r
237 }\r
238 }\r
239}\r
240\r
241static void UNLOneBusPower(void)\r
242{\r
243 IRQCount=IRQLatch=IRQa==0;\r
244 regs[0]=regs[1]=regs[1]=regs[2]=regs[3]=regs[4]=regs[5]=regs[6]=0;\r
245 regs[7]=regs[8]=regs[11]=regs[12]=regs[13]=regs[14]=regs[15]=0;\r
246 regs[0x09]=0x3E;\r
247 regs[0x0A]=0x3F;\r
248\r
249 SetupCartCHRMapping(0,PRGptr[0],4096 * 1024,0);\r
250\r
251 if(isDance) // quick workaround, TODO: figure out how it works together\r
252 {\r
253 old4015read=GetReadHandler(0x4015);\r
254 SetReadHandler(0x4015,0x4015,UNLOneBusRead4015);\r
255 old4011write=GetWriteHandler(0x4011);\r
256 old4012write=GetWriteHandler(0x4012);\r
257 SetWriteHandler(0x4012,0x4012,UNLOneBusWrite4012);\r
258 old4013write=GetWriteHandler(0x4013);\r
259 SetWriteHandler(0x4013,0x4013,UNLOneBusWrite4013);\r
260 old4015write=GetWriteHandler(0x4015);\r
261 SetWriteHandler(0x4015,0x4015,UNLOneBusWrite4015);\r
262 }\r
263\r
264 SetReadHandler(0x8000,0xFFFF,CartBR);\r
265 SetWriteHandler(0x2009,0x2fff,UNLOneBusWrite20XX);\r
266// SetWriteHandler(0x4020,0xffff,UNLOneBusWriteDebug);\r
267// SetWriteHandler(0x4020,0x4040,UNLOneBusWriteAPU2);\r
268 SetWriteHandler(0x4100,0x410f,UNLOneBusWriteExp);\r
269 SetWriteHandler(0x8000,0xefff,UNLOneBusWriteMMC);\r
270 Sync();\r
271}\r
272\r
273static void UNLOneBusReset(void)\r
274{\r
275 IRQCount=IRQLatch=IRQa=0;\r
276 regs[0]=regs[1]=regs[1]=regs[2]=regs[3]=regs[4]=regs[5]=regs[6]=0;\r
277 regs[7]=regs[8]=regs[11]=regs[12]=regs[13]=regs[14]=regs[15]=0;\r
278 regs[0x09]=0x3E;\r
279 regs[0x0A]=0x3F;\r
280 Sync();\r
281}\r
282\r
283static void StateRestore(int version)\r
284{\r
285 Sync();\r
286}\r
287\r
288void UNLOneBus_Init(CartInfo *info)\r
289{\r
290 isDance = 0;\r
291 info->Power=UNLOneBusPower;\r
292 info->Reset=UNLOneBusReset;\r
293 GameHBIRQHook=UNLOneBusIRQHook;\r
294// MapIRQHook=UNLOneBusCpuHook;\r
295 GameStateRestore=StateRestore;\r
296 AddExState(&StateRegs, ~0, 0, 0);\r
297}\r
298\r
299void UNLDANCE_Init(CartInfo *info)\r
300{\r
301 isDance = 1;\r
302 info->Power=UNLOneBusPower;\r
303 info->Reset=UNLOneBusReset;\r
304 GameHBIRQHook=UNLOneBusIRQHook;\r
305 MapIRQHook=UNLOneBusCpuHook;\r
306 GameStateRestore=StateRestore;\r
307 AddExState(&StateRegs, ~0, 0, 0);\r
308}\r