always fill on blanking
[fceu.git] / vsuni.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2003 Xodnizel\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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
19 */\r
20\r
21#include <string.h>\r
22#include <stdio.h>\r
23\r
24#include "types.h"\r
25#include "x6502.h"\r
26#include "fce.h"\r
27#include "input.h"\r
28#include "netplay.h"\r
29#include "vsuni.h"\r
30#include "state.h"\r
31\r
32#include "svga.h"\r
33\r
34#define IOPTION_GUN 0x1\r
35#define IOPTION_SWAPDIRAB 0x2\r
36\r
37#define IOPTION_PREDIP 0x10\r
38typedef struct\r
39{\r
40 char *name;\r
41 uint64 md5partial;\r
42 int mapper;\r
43 int mirroring;\r
44 int ppu;\r
45 int ioption;\r
46 int predip;\r
47} VSUNIENTRY;\r
48\r
49VSUNIENTRY *curvs;\r
50\r
51static uint8 DIPS=0;\r
52uint8 vsdip=0;\r
53\r
54void FCEUI_VSUniToggleDIPView(void)\r
55{\r
56 DIPS=!DIPS;\r
57}\r
58\r
59void FCEU_VSUniToggleDIP(int w)\r
60{\r
61 vsdip^=1<<w;\r
62}\r
63\r
64void FCEUI_VSUniSetDIP(int w, int state)\r
65{\r
66 if(((vsdip >> w) & 1) != state)\r
67 FCEUI_VSUniToggleDIP(w);\r
68}\r
69\r
70uint8 FCEUI_VSUniGetDIPs(void)\r
71{\r
72 return(vsdip);\r
73}\r
74\r
75static uint8 secdata[2][32]=\r
76{\r
77 {\r
78 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,\r
79 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,\r
80 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,\r
81 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00\r
82 },\r
83 {\r
84 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,\r
85 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,\r
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
88 }\r
89};\r
90\r
91static uint8 *secptr;\r
92\r
93static uint8 VSindex;\r
94\r
95static DECLFR(VSSecRead)\r
96{\r
97 switch(A)\r
98 {\r
99 case 0x5e00: VSindex=0;return X.DB;\r
100 case 0x5e01: return(secptr[(VSindex++)&0x1F]);\r
101 }\r
102 return(0x00);\r
103}\r
104uint8 coinon=0;\r
105\r
106void FCEU_VSUniCoin(void)\r
107{\r
108 coinon=6;\r
109}\r
110\r
111static int curppu;\r
112static int64 curmd5;\r
113\r
114#define RP2C04_001 1\r
115#define RP2C04_002 2\r
116#define RP2C04_003 3\r
117#define RP2C05_004 4\r
118#define RCP2C03B 5\r
119#define RC2C05_01 6\r
120#define RC2C05_02 7\r
121#define RC2C05_03 8\r
122#define RC2C05_04 9\r
123\r
124static readfunc OldReadPPU;\r
125static writefunc OldWritePPU[2];\r
126\r
127static DECLFR(A2002_Gumshoe)\r
128{\r
129 return( (OldReadPPU(A)&~0x3F) | 0x1C);\r
130}\r
131\r
132static DECLFR(A2002_Topgun)\r
133{\r
134 return( (OldReadPPU(A)&~0x3F) | 0x1B);\r
135}\r
136\r
137static DECLFR(A2002_MBJ) // Mighty Bomb Jack\r
138{\r
139 return( (OldReadPPU(A)&~0x3F) | 0x3D);\r
140}\r
141\r
142static DECLFW(B2000_2001_2C05)\r
143{\r
144 OldWritePPU[(A&1)^1](A ^ 1, V);\r
145}\r
146static uint8 xevselect = 0;\r
147static DECLFR(XevRead)\r
148{\r
149 //printf("%04x\n",A);\r
150 if(A == 0x54FF)\r
151 {\r
152 return(0x5);\r
153 }\r
154 else if(A == 0x5678)\r
155 {\r
156 return(xevselect?0:1);\r
157 }\r
158 else if(A == 0x578F)\r
159 {\r
160 return(xevselect?0xd1:0x89);\r
161 }\r
162 else if(A == 0x5567)\r
163 {\r
164 xevselect ^=1;\r
165 return(xevselect?0x37:0x3E);\r
166 }\r
167 return(X.DB);\r
168}\r
169\r
170void FCEU_VSUniSwap(uint8 *j0, uint8 *j1)\r
171{\r
172 if(curvs->ioption & IOPTION_SWAPDIRAB)\r
173 {\r
174 uint16 t=*j0;\r
175 *j0=(*j0&0xC)|(*j1&0xF3);\r
176 *j1=(*j1&0xC)|(t&0xF3);\r
177 }\r
178}\r
179\r
180void FCEU_VSUniPower(void)\r
181{\r
182 coinon = 0;\r
183 VSindex = 0;\r
184\r
185 if(secptr)\r
186 SetReadHandler(0x5e00,0x5e01,VSSecRead);\r
187\r
188 if(curppu == RC2C05_04)\r
189 {\r
190 OldReadPPU = GetReadHandler(0x2002);\r
191 SetReadHandler(0x2002, 0x2002, A2002_Topgun);\r
192 }\r
193 else if(curppu == RC2C05_03)\r
194 {\r
195 OldReadPPU = GetReadHandler(0x2002);\r
196 SetReadHandler(0x2002, 0x2002, A2002_Gumshoe);\r
197 }\r
198 else if(curppu == RC2C05_02)\r
199 {\r
200 OldReadPPU = GetReadHandler(0x2002);\r
201 SetReadHandler(0x2002, 0x2002, A2002_MBJ);\r
202 }\r
203 if(curppu == RC2C05_04 || curppu == RC2C05_01 || curppu == RC2C05_03 || curppu == RC2C05_02)\r
204 {\r
205 OldWritePPU[0] = GetWriteHandler(0x2000);\r
206 OldWritePPU[1] = GetWriteHandler(0x2001);\r
207 SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05);\r
208 }\r
209 if(curmd5 == 0x2d396247cf58f9faLL) /* Super Xevious */\r
210 {\r
211 SetReadHandler(0x5400,0x57FF,XevRead);\r
212 }\r
213}\r
214\r
215/* Games that will probably not be supported ever(or for a long time), since they require\r
216 dual-system:\r
217\r
218 Balloon Fight\r
219 VS Mahjong\r
220 VS Tennis\r
221 Wrecking Crew\r
222*/\r
223\r
224/* Games/PPU list. Information copied from MAME. ROMs are exchangable, so don't take\r
225 this list as "this game must use this PPU".\r
226\r
227RP2C04-001:\r
228- Baseball\r
229- Freedom Force\r
230- Gradius\r
231- Hogan's Alley\r
232- Mach Rider (Japan, Fighting Course)\r
233- Pinball\r
234- Platoon\r
235- Super Xevious\r
236\r
237RP2C04-002:\r
238- Castlevania\r
239- Ladies golf\r
240- Mach Rider (Endurance Course)\r
241- Raid on Bungeling Bay (Japan)\r
242- Slalom\r
243- Stroke N' Match Golf\r
244- Wrecking Crew\r
245\r
246RP2C04-003:\r
247- Dr mario\r
248- Excite Bike\r
249- Goonies\r
250- Soccer\r
251- TKO Boxing\r
252\r
253RP2c05-004:\r
254- Clu Clu Land\r
255- Excite Bike (Japan)\r
256- Ice Climber\r
257- Ice Climber Dual (Japan)\r
258- Super Mario Bros.\r
259\r
260Rcp2c03b:\r
261- Battle City\r
262- Duck Hunt\r
263- Mahjang\r
264- Pinball (Japan)\r
265- Rbi Baseball\r
266- Star Luster\r
267- Stroke and Match Golf (Japan)\r
268- Super Skykid\r
269- Tennis\r
270- Tetris\r
271\r
272RC2C05-01:\r
273- Ninja Jajamaru Kun (Japan)\r
274\r
275RC2C05-02:\r
276- Mighty Bomb Jack (Japan)\r
277\r
278RC2C05-03:\r
279- Gumshoe\r
280\r
281RC2C05-04:\r
282- Top Gun\r
283*/\r
284\r
285VSUNIENTRY VSUniGames[] =\r
286{\r
287 {"Baseball", 0x691d4200ea42be45LL, 99, 2,RP2C04_001,0},\r
288 {"Battle City", 0x8540949d74c4d0ebLL, 99, 2,RP2C04_001,0},\r
289 {"Battle City(Bootleg)",0x8093cbe7137ac031LL, 99, 2,RP2C04_001,0},\r
290\r
291 {"Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2,RP2C05_004,IOPTION_SWAPDIRAB},\r
292 {"Dr Mario", 0xe1af09c477dc0081LL, 1, 0,RP2C04_003,IOPTION_SWAPDIRAB},\r
293 {"Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2,RCP2C03B ,IOPTION_GUN},\r
294 {"Excitebike", 0x3dcd1401bcafde77LL, 99, 2,RP2C04_003,0},\r
295 {"Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2,RP2C05_004,0},\r
296 {"Freedom Force", 0xed96436bd1b5e688LL, 4, 0,RP2C04_001,IOPTION_GUN}, /* Wrong color in game select screen? */\r
297 {"Stroke and Match Golf",0x612325606e82bc66LL, 99, 2,RP2C04_002,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x01},\r
298\r
299 {"Goonies", 0x3b0085c4ff29098eLL, 151,1,RP2C04_003,0},\r
300 {"Gradius", 0x50687ae63bdad976LL,151, 1,RP2C04_001,IOPTION_SWAPDIRAB},\r
301 {"Gumshoe", 0xb8500780bf69ce29LL, 99, 2,RC2C05_03,IOPTION_GUN},\r
302 {"Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2,RP2C04_001,IOPTION_GUN},\r
303 {"Ice Climber", 0xd21e999513435e2aLL, 99, 2,RP2C05_004,IOPTION_SWAPDIRAB},\r
304 {"Ladies Golf", 0x781b24be57ef6785LL, 99, 2,RP2C04_002,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x1},\r
305\r
306 {"Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_002,0},\r
307 {"Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_001,0},\r
308 {"Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02,0},\r
309 {"Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2,RC2C05_01 ,IOPTION_SWAPDIRAB},\r
310 {"Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2,RP2C04_001,IOPTION_PREDIP,0x01},\r
311 {"Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2,RCP2C03B,IOPTION_PREDIP,0x1},\r
312 {"Platoon", 0x160f237351c19f1fLL, 68, 1,RP2C04_001,0},\r
313 {"RBI Baseball", 0x6a02d345812938afLL, 4, 1,RP2C04_001 ,IOPTION_SWAPDIRAB},\r
314 {"Soccer", 0xd4e7a9058780eda3LL, 99, 2,RP2C04_003,IOPTION_SWAPDIRAB},\r
315 {"Star Luster", 0x8360e134b316d94cLL, 99, 2,RCP2C03B ,0},\r
316 {"Stroke and Match Golf (J)",0x869bb83e02509747LL, 99, 2,RCP2C03B,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x1},\r
317 {"Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1,RCP2C03B ,IOPTION_SWAPDIRAB | IOPTION_PREDIP,0x20},\r
318\r
319 {"Super Xevious", 0x2d396247cf58f9faLL, 206, 0,RP2C04_001,0},\r
320 {"Tetris", 0x531a5e8eea4ce157LL, 99, 2,RCP2C03B ,IOPTION_PREDIP,0x20},\r
321 {"Top Gun", 0xf1dea36e6a7b531dLL, 2, 0,RC2C05_04 ,0},\r
322 {"VS Castlevania", 0x92fd6909c81305b9LL, 2, 1,RP2C04_002,0},\r
323 {"VS Slalom", 0x4889b5a50a623215LL, 0, 1,RP2C04_002,0},\r
324 {"VS Super Mario Bros",0x39d8cfa788e20b6cLL, 99, 2,RP2C05_004,0},\r
325 {"VS TKO Boxing", 0x6e1ee06171d8ce3aLL,4, 1,RP2C04_003,IOPTION_PREDIP,0x00},\r
326 {0}\r
327};\r
328\r
329void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring)\r
330{\r
331 VSUNIENTRY *vs = VSUniGames;\r
332\r
333 while(vs->name)\r
334 {\r
335 if(md5partial == vs->md5partial)\r
336 {\r
337\r
338 if(vs->ppu < RCP2C03B) pale = vs->ppu;\r
339 //puts(vs->name);\r
340 *MapperNo = vs->mapper;\r
341 *Mirroring = vs->mirroring;\r
342 FCEUGameInfo.type = GIT_VSUNI;\r
343 FCEUGameInfo.cspecial = SIS_VSUNISYSTEM;\r
344 FCEUGameInfo.inputfc = SIFC_NONE;\r
345 curppu = vs->ppu;\r
346 curmd5 = md5partial;\r
347\r
348 secptr = 0;\r
349\r
350 {\r
351 static int64 tko=0x6e1ee06171d8ce3aULL, rbi=0x6a02d345812938afULL;\r
352 if(md5partial == tko)\r
353 secptr=secdata[0];\r
354 if(md5partial == rbi)\r
355 secptr = secdata[1];\r
356 }\r
357\r
358 vsdip = 0x0;\r
359 if(vs->ioption & IOPTION_PREDIP)\r
360 {\r
361 vsdip= vs->predip;\r
362 }\r
363 if(vs->ioption & IOPTION_GUN)\r
364 {\r
365 FCEUGameInfo.input[0] = SI_ZAPPER;\r
366 FCEUGameInfo.input[1] = SI_NONE;\r
367 }\r
368 else\r
369 {\r
370 FCEUGameInfo.input[0] = FCEUGameInfo.input[1] = SI_GAMEPAD;\r
371 }\r
372 curvs = vs;\r
373 return;\r
374 }\r
375 vs++;\r
376 }\r
377}\r
378\r
e328100e 379#define SCREEN_WIDTH 320\r
380#define SCREEN_OFFS 32\r
381\r
d97315ac 382void FCEU_VSUniDraw(uint8 *XBuf)\r
383{\r
384 uint32 *dest;\r
385 int y,x;\r
386\r
387 if(!DIPS) return;\r
388\r
e328100e 389 dest=(uint32 *)(XBuf+SCREEN_WIDTH*12+164+SCREEN_OFFS);\r
390 for(y=24;y;y--,dest+=(SCREEN_WIDTH-72)>>2)\r
d97315ac 391 {\r
392 for(x=72>>2;x;x--,dest++)\r
393 *dest=0;\r
394 }\r
395\r
e328100e 396 dest=(uint32 *)(XBuf+SCREEN_WIDTH*(12+4)+164+6+SCREEN_OFFS );\r
397 for(y=16;y;y--,dest+=(SCREEN_WIDTH>>2)-16)\r
d97315ac 398 for(x=8;x;x--)\r
399 {\r
400 *dest=0x01010101;\r
401 dest+=2;\r
402 }\r
403\r
e328100e 404 dest=(uint32 *)(XBuf+SCREEN_WIDTH*(12+4)+164+6+SCREEN_OFFS );\r
d97315ac 405 for(x=0;x<8;x++,dest+=2)\r
406 {\r
e328100e 407 uint32 *da=dest+(SCREEN_WIDTH>>2);\r
d97315ac 408\r
409 if(!((vsdip>>x)&1))\r
e328100e 410 da+=(SCREEN_WIDTH>>2)*10;\r
411 for(y=4;y;y--,da+=SCREEN_WIDTH>>2)\r
d97315ac 412 *da=0;\r
413 }\r
414}\r
415\r
416\r
417SFORMAT FCEUVSUNI_STATEINFO[]={\r
418 { &vsdip, 1, "vsdp"},\r
419 { &coinon, 1, "vscn"},\r
420 { &VSindex, 1, "vsin"},\r
421 { 0}\r
422};\r