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 |
28 | static uint8 isDance;\r |
29 | static uint8 regs[16],regc[6];\r |
30 | static uint8 IRQCount,IRQLatch,IRQa, IRQReload, pcm_enable = 0, pcm_irq = 0;\r |
31 | static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xF6;\r |
32 | static writefunc old4011write, old4012write, old4013write, old4015write;\r |
33 | static readfunc old4015read;\r |
34 | \r |
35 | static 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 |
52 | static 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 |
87 | static 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 |
97 | static 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 |
111 | static DECLFW(UNLOneBusWriteDebug)\r |
112 | {\r |
113 | // FCEU_printf("write %04x:%04x\n",A,V);\r |
114 | }\r |
115 | \r |
116 | static 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 |
157 | static 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 |
174 | static 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 |
180 | static 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 |
187 | static 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 |
194 | static 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 |
208 | static 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 |
215 | static 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 |
241 | static 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 |
273 | static 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 |
283 | static void StateRestore(int version)\r |
284 | {\r |
285 | Sync();\r |
286 | }\r |
287 | \r |
288 | void 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 |
299 | void 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 |