FDS fixed for asm core
[fceu.git] / input.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
5a2aa426 4 * Copyright (C) 1998 BERO
c62d2810 5 * Copyright (C) 2002 Ben Parnell
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
5232c20c 21#include <string.h>
c62d2810 22#include "types.h"
23#include "x6502.h"
24
25#include "fce.h"
26#include "sound.h"
27#include "netplay.h"
28#include "svga.h"
29
30#include "input.h"
890e37ba 31#include "state.h"
5a2aa426 32#include "movie.h"
c62d2810 33
d97315ac 34#include "fds.h"
35#include "vsuni.h"
4fdfab07 36#include "dprintf.h"
37
c62d2810 38extern INPUTC *FCEU_InitZapper(int w);
39extern INPUTC *FCEU_InitPowerpad(int w);
40extern INPUTC *FCEU_InitArkanoid(int w);
41
42extern INPUTCFC *FCEU_InitArkanoidFC(void);
43extern INPUTCFC *FCEU_InitSpaceShadow(void);
44extern INPUTCFC *FCEU_InitFKB(void);
45static uint8 joy_readbit[2];
890e37ba 46static uint8 joy[4]={0,0,0,0};
47static uint8 LastStrobe;
c62d2810 48
49extern int coinon;
50
51static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
52static int JPAttrib[2]={0,0};
53static int JPType[2]={0,0};
54static void *InputDataPtr[2];
55
56static int JPAttribFC=0;
57static int JPTypeFC=0;
58static void *InputDataPtrFC;
59
60void (*InputScanlineHook)(uint8 *buf, int line);
61
62static INPUTC DummyJPort={0,0,0,0,0};
63static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
64static INPUTCFC *FCExp=0;
65
d97315ac 66/* This function is a quick hack to get the NSF player to use emulated gamepad
67 input.
68*/
69uint8 FCEU_GetJoyJoy(void)
70{
71 return(joy[0]|joy[1]|joy[2]|joy[3]);
72}
73
c62d2810 74static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
75{
76 uint8 ret=0;
77
78 if(joy_readbit[w]>=8)
79 ret=1;
80 else
81 {
82 ret = ((joy[w]>>(joy_readbit[w]))&1);
83 joy_readbit[w]++;
84 }
85 return ret;
86}
87
88static uint8 FP_FASTAPASS(1) ReadGP(int w)
89{
90 uint8 ret;
5a2aa426 91 //if(JoyMulti)
c62d2810 92 //{
93 //ret = ((joy[w]>>(joy_readbit[w]))&1)|
94 //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
95 //if(joy_readbit[w]>8) ret=0;
96 //}
97 ret = ((joy[w]>>(joy_readbit[w]))&1);
98 if(FSDisable)
99 {
100 if(joy_readbit[w]>=8) ret|=1;
101 }
102 else
103 {
104 if(joy_readbit[w]==19-w) ret|=1;
105 }
106 joy_readbit[w]++;
107 return ret;
108}
109
110static DECLFR(JPRead)
111{
112 uint8 ret=0;
113
114 if(JPorts[A&1]->Read)
115 ret|=JPorts[A&1]->Read(A&1);
5a2aa426 116
c62d2810 117 if(FCExp)
118 if(FCExp->Read)
119 ret=FCExp->Read(A&1,ret);
120
121 ret|=X.DB&0xC0;
4fdfab07 122 dprintf("JPRead %02x", ret);
c62d2810 123 return(ret);
124}
125
126static DECLFW(B4016)
127{
128 if(FCExp)
129 if(FCExp->Write)
130 FCExp->Write(V&7);
131
132 if(JPorts[0]->Write)
133 JPorts[0]->Write(V&1);
134 if(JPorts[1]->Write)
135 JPorts[1]->Write(V&1);
136
890e37ba 137 if((LastStrobe&1) && (!(V&1)))
c62d2810 138 {
139 /* This strobe code is just for convenience. If it were
140 with the code in input / *.c, it would more accurately represent
141 what's really going on. But who wants accuracy? ;)
142 Seriously, though, this shouldn't be a problem.
143 */
144 if(JPorts[0]->Strobe)
145 JPorts[0]->Strobe(0);
146 if(JPorts[1]->Strobe)
147 JPorts[1]->Strobe(1);
148 if(FCExp)
149 if(FCExp->Strobe)
150 FCExp->Strobe();
151 }
890e37ba 152 LastStrobe=V&1;
c62d2810 153}
154
155static void FP_FASTAPASS(1) StrobeGP(int w)
156{
157 joy_readbit[w]=0;
158}
159
160static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
161static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
162
163void DrawInput(uint8 *buf)
164{
165 int x;
166
167 for(x=0;x<2;x++)
168 if(JPorts[x]->Draw)
169 JPorts[x]->Draw(x,buf,JPAttrib[x]);
170 if(FCExp)
171 if(FCExp->Draw)
172 FCExp->Draw(buf,JPAttribFC);
173}
174
175void UpdateInput(void)
176{
177 int x;
178
179 for(x=0;x<2;x++)
180 {
181 switch(JPType[x])
182 {
183 case SI_GAMEPAD:
184 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
185 else joy[1]=*(uint16 *)InputDataPtr[1];
186 break;
187 default:
188 if(JPorts[x]->Update)
189 JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
190 break;
191 }
192 }
193 if(FCExp)
194 if(FCExp->Update)
195 FCExp->Update(InputDataPtrFC,JPAttribFC);
196
197 if(FCEUGameInfo.type==GIT_VSUNI)
198 {
199 uint16 t=joy[0];
200 joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
201 joy[1]=(joy[1]&0xC)|(t&0xF3);
202 if(coinon) coinon--;
203 }
204 #ifdef NETWORK
205 if(netplay) NetplayUpdate(&joy[0],&joy[1]);
206 #endif
5a2aa426 207 if (current < 0) FCEUMOV_AddJoy(joy);
ea80a45b 208 else framecount++; // for debug
d97315ac 209 //FlushCommandQueue();
c62d2810 210}
211
212static DECLFR(VSUNIRead0)
213{
214 uint8 ret=0;
215
216 if(JPorts[0]->Read)
217 ret|=(JPorts[0]->Read(0))&1;
218
219 ret|=(vsdip&3)<<3;
220 if(coinon)
221 ret|=0x4;
222 return ret;
223}
224
225static DECLFR(VSUNIRead1)
226{
227 uint8 ret=0;
228
229 if(JPorts[1]->Read)
230 ret|=(JPorts[1]->Read(1))&1;
231 ret|=vsdip&0xFC;
232 return ret;
233}
234
235static void SLHLHook(uint8 *buf, int line)
236{
237 int x;
238
239 for(x=0;x<2;x++)
240 if(JPorts[x]->SLHook)
241 JPorts[x]->SLHook(x,buf,line);
5a2aa426 242 if(FCExp)
c62d2810 243 if(FCExp->SLHook)
244 FCExp->SLHook(buf,line);
245}
246
247static void CheckSLHook(void)
248{
249 InputScanlineHook=0;
250 if(JPorts[0]->SLHook || JPorts[1]->SLHook)
251 InputScanlineHook=SLHLHook;
252 if(FCExp)
253 if(FCExp->SLHook)
254 InputScanlineHook=SLHLHook;
255}
256
257static void FASTAPASS(1) SetInputStuff(int x)
258{
259 switch(JPType[x])
260 {
261 case SI_GAMEPAD:
262 if(FCEUGameInfo.type==GIT_VSUNI)
263 JPorts[x]=&GPCVS;
264 else
265 JPorts[x]=&GPC;
266 break;
267 case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
268 case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
d97315ac 269 case SI_POWERPADA:JPorts[x]=FCEU_InitPowerpad(x);break;
c62d2810 270 case SI_NONE:JPorts[x]=&DummyJPort;break;
271 }
272
273 CheckSLHook();
274}
275
276static uint8 F4ReadBit[2];
277static void StrobeFami4(void)
278{
279 F4ReadBit[0]=F4ReadBit[1]=0;
280}
281
282static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
283{
284 ret&=1;
285
286 ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
287 if(F4ReadBit[w]>=8) ret|=2;
288 else F4ReadBit[w]++;
289
290 return(ret);
291}
292
293static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
294static void SetInputStuffFC(void)
295{
296 switch(JPTypeFC)
297 {
298 case SIFC_NONE:FCExp=0;break;
299 case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
300 case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
301 case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
302 case SIFC_FKB:FCExp=FCEU_InitFKB();break;
303 }
304 CheckSLHook();
305}
306
307// VS Unisystem code called after SetInputMap() hooks B4016. Need to
308// rewrite code to make this more sane?
309
310void InitializeInput(void)
5a2aa426 311{
c62d2810 312 memset(joy_readbit,0,sizeof(joy_readbit));
313 memset(joy,0,sizeof(joy));
890e37ba 314 LastStrobe=0;
c62d2810 315
316 if(FCEUGameInfo.type==GIT_VSUNI)
317 {
318 SetReadHandler(0x4016,0x4016,VSUNIRead0);
319 SetReadHandler(0x4017,0x4017,VSUNIRead1);
320 }
321 else
322 SetReadHandler(0x4016,0x4017,JPRead);
323 SetWriteHandler(0x4016,0x4016,B4016);
324
325 SetInputStuff(0);
326 SetInputStuff(1);
327 SetInputStuffFC();
328}
329
330void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
331{
332 JPAttrib[port]=attrib;
333 JPType[port]=type;
334 InputDataPtr[port]=ptr;
335 SetInputStuff(port);
336}
337
338void FCEUI_DisableFourScore(int s)
339{
340 FSDisable=s;
341}
342
343void FCEUI_SetInputFC(int type, void *ptr, int attrib)
344{
345 JPAttribFC=attrib;
346 JPTypeFC=type;
347 InputDataPtrFC=ptr;
348 SetInputStuffFC();
349}
890e37ba 350
351// quick paste
352#define FCEUNPCMD_RESET 0x01
353#define FCEUNPCMD_POWER 0x02
354
355#define FCEUNPCMD_VSUNICOIN 0x07
356#define FCEUNPCMD_VSUNIDIP0 0x08
357#define FCEUNPCMD_FDSINSERT 0x18
358#define FCEUNPCMD_FDSSELECT 0x1A
359
360
361void FCEU_DoSimpleCommand(int cmd)
362{
363 switch(cmd)
364 {
d97315ac 365 case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
366 case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
890e37ba 367// case FCEUNPCMD_FDSEJECT: FCEU_FDSEject();break;
d97315ac 368 case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
369 case FCEUNPCMD_VSUNIDIP0 ... (FCEUNPCMD_VSUNIDIP0 + 7): FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);break;
890e37ba 370 case FCEUNPCMD_POWER: PowerNES();break;
371 case FCEUNPCMD_RESET: ResetNES();break;
372 default: printf("FCEU_DoSimpleCommand: can't handle cmd %i\n", cmd); break;
373 }
374}
375
d97315ac 376void FCEU_QSimpleCommand(int cmd)
377{
378// if(FCEUnetplay)
379// FCEUNET_SendCommand(cmd, 0);
380// else
381 {
382 // totally wrong:
383// if(!FCEUMOV_IsPlaying())
384// FCEU_DoSimpleCommand(cmd);
385// else
386// FCEUMOV_AddCommand(cmd);
387
388 FCEU_DoSimpleCommand(cmd);
389// if(FCEUMOV_IsRecording())
390// FCEUMOV_AddCommand(cmd);
391 }
392}
393
394void FCEUI_FDSSelect(void)
395{
396 FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
397}
398
399int FCEUI_FDSInsert(void)
400{
401 FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
402 return(1);
403}
404
405/*
406int FCEUI_FDSEject(void)
407{
408 FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
409 return(1);
410}
411*/
412void FCEUI_VSUniToggleDIP(int w)
413{
414 FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
415}
416
417void FCEUI_VSUniCoin(void)
418{
419 FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
420}
421
422void FCEUI_ResetNES(void)
423{
424 FCEU_QSimpleCommand(FCEUNPCMD_RESET);
425}
426
427void FCEUI_PowerNES(void)
428{
429 FCEU_QSimpleCommand(FCEUNPCMD_POWER);
430}
431
432
890e37ba 433
434SFORMAT FCEUCTRL_STATEINFO[]={
435 { joy_readbit, 2, "JYRB"},
436 { joy, 4, "JOYS"},
437 { &LastStrobe, 1, "LSTS"},
438 { 0 }
439};
440
441