mapper fixes for ncpu, debug is broken atm
[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"
5a2aa426 31#include "movie.h"
c62d2810 32
c0bf6f9f 33#ifdef DEBUG_ASM_6502
34extern int cpu_repeat;
35extern int cpu_lastval;
36#endif
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];
5a2aa426 46static uint16 joy[4]={0,0,0,0};
c62d2810 47
48extern int coinon;
49
50static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
51static int JPAttrib[2]={0,0};
52static int JPType[2]={0,0};
53static void *InputDataPtr[2];
54
55static int JPAttribFC=0;
56static int JPTypeFC=0;
57static void *InputDataPtrFC;
58
59void (*InputScanlineHook)(uint8 *buf, int line);
60
61static INPUTC DummyJPort={0,0,0,0,0};
62static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
63static INPUTCFC *FCExp=0;
64
65static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
66{
67 uint8 ret=0;
68
69 if(joy_readbit[w]>=8)
70 ret=1;
71 else
72 {
73 ret = ((joy[w]>>(joy_readbit[w]))&1);
74 joy_readbit[w]++;
75 }
76 return ret;
77}
78
79static uint8 FP_FASTAPASS(1) ReadGP(int w)
80{
81 uint8 ret;
5a2aa426 82 //if(JoyMulti)
c62d2810 83 //{
84 //ret = ((joy[w]>>(joy_readbit[w]))&1)|
85 //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
86 //if(joy_readbit[w]>8) ret=0;
87 //}
88 ret = ((joy[w]>>(joy_readbit[w]))&1);
89 if(FSDisable)
90 {
91 if(joy_readbit[w]>=8) ret|=1;
92 }
93 else
94 {
95 if(joy_readbit[w]==19-w) ret|=1;
96 }
97 joy_readbit[w]++;
98 return ret;
99}
100
101static DECLFR(JPRead)
102{
103 uint8 ret=0;
104
c0bf6f9f 105#ifdef DEBUG_ASM_6502
106 if (cpu_repeat) return cpu_lastval;
107#endif
c62d2810 108 if(JPorts[A&1]->Read)
109 ret|=JPorts[A&1]->Read(A&1);
5a2aa426 110
c62d2810 111 if(FCExp)
112 if(FCExp->Read)
113 ret=FCExp->Read(A&1,ret);
114
115 ret|=X.DB&0xC0;
c0bf6f9f 116#ifdef DEBUG_ASM_6502
117// cpu_lastval=ret;
118#endif
c62d2810 119 return(ret);
120}
121
122static DECLFW(B4016)
123{
124 if(FCExp)
125 if(FCExp->Write)
126 FCExp->Write(V&7);
127
128 if(JPorts[0]->Write)
129 JPorts[0]->Write(V&1);
130 if(JPorts[1]->Write)
131 JPorts[1]->Write(V&1);
132
133 if((PSG[0x16]&1) && (!(V&1)))
134 {
135 /* This strobe code is just for convenience. If it were
136 with the code in input / *.c, it would more accurately represent
137 what's really going on. But who wants accuracy? ;)
138 Seriously, though, this shouldn't be a problem.
139 */
140 if(JPorts[0]->Strobe)
141 JPorts[0]->Strobe(0);
142 if(JPorts[1]->Strobe)
143 JPorts[1]->Strobe(1);
144 if(FCExp)
145 if(FCExp->Strobe)
146 FCExp->Strobe();
147 }
148 PSG[0x16]=V;
149}
150
151static void FP_FASTAPASS(1) StrobeGP(int w)
152{
153 joy_readbit[w]=0;
154}
155
156static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
157static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
158
159void DrawInput(uint8 *buf)
160{
161 int x;
162
163 for(x=0;x<2;x++)
164 if(JPorts[x]->Draw)
165 JPorts[x]->Draw(x,buf,JPAttrib[x]);
166 if(FCExp)
167 if(FCExp->Draw)
168 FCExp->Draw(buf,JPAttribFC);
169}
170
171void UpdateInput(void)
172{
173 int x;
174
175 for(x=0;x<2;x++)
176 {
177 switch(JPType[x])
178 {
179 case SI_GAMEPAD:
180 if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
181 else joy[1]=*(uint16 *)InputDataPtr[1];
182 break;
183 default:
184 if(JPorts[x]->Update)
185 JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
186 break;
187 }
188 }
189 if(FCExp)
190 if(FCExp->Update)
191 FCExp->Update(InputDataPtrFC,JPAttribFC);
192
193 if(FCEUGameInfo.type==GIT_VSUNI)
194 {
195 uint16 t=joy[0];
196 joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
197 joy[1]=(joy[1]&0xC)|(t&0xF3);
198 if(coinon) coinon--;
199 }
200 #ifdef NETWORK
201 if(netplay) NetplayUpdate(&joy[0],&joy[1]);
202 #endif
5a2aa426 203 if (current < 0) FCEUMOV_AddJoy(joy);
c62d2810 204 FlushCommandQueue();
205}
206
207static DECLFR(VSUNIRead0)
208{
209 uint8 ret=0;
210
211 if(JPorts[0]->Read)
212 ret|=(JPorts[0]->Read(0))&1;
213
214 ret|=(vsdip&3)<<3;
215 if(coinon)
216 ret|=0x4;
217 return ret;
218}
219
220static DECLFR(VSUNIRead1)
221{
222 uint8 ret=0;
223
224 if(JPorts[1]->Read)
225 ret|=(JPorts[1]->Read(1))&1;
226 ret|=vsdip&0xFC;
227 return ret;
228}
229
230static void SLHLHook(uint8 *buf, int line)
231{
232 int x;
233
234 for(x=0;x<2;x++)
235 if(JPorts[x]->SLHook)
236 JPorts[x]->SLHook(x,buf,line);
5a2aa426 237 if(FCExp)
c62d2810 238 if(FCExp->SLHook)
239 FCExp->SLHook(buf,line);
240}
241
242static void CheckSLHook(void)
243{
244 InputScanlineHook=0;
245 if(JPorts[0]->SLHook || JPorts[1]->SLHook)
246 InputScanlineHook=SLHLHook;
247 if(FCExp)
248 if(FCExp->SLHook)
249 InputScanlineHook=SLHLHook;
250}
251
252static void FASTAPASS(1) SetInputStuff(int x)
253{
254 switch(JPType[x])
255 {
256 case SI_GAMEPAD:
257 if(FCEUGameInfo.type==GIT_VSUNI)
258 JPorts[x]=&GPCVS;
259 else
260 JPorts[x]=&GPC;
261 break;
262 case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
263 case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
264 case SI_POWERPAD:JPorts[x]=FCEU_InitPowerpad(x);break;
265 case SI_NONE:JPorts[x]=&DummyJPort;break;
266 }
267
268 CheckSLHook();
269}
270
271static uint8 F4ReadBit[2];
272static void StrobeFami4(void)
273{
274 F4ReadBit[0]=F4ReadBit[1]=0;
275}
276
277static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
278{
279 ret&=1;
280
281 ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
282 if(F4ReadBit[w]>=8) ret|=2;
283 else F4ReadBit[w]++;
284
285 return(ret);
286}
287
288static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
289static void SetInputStuffFC(void)
290{
291 switch(JPTypeFC)
292 {
293 case SIFC_NONE:FCExp=0;break;
294 case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
295 case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
296 case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
297 case SIFC_FKB:FCExp=FCEU_InitFKB();break;
298 }
299 CheckSLHook();
300}
301
302// VS Unisystem code called after SetInputMap() hooks B4016. Need to
303// rewrite code to make this more sane?
304
305void InitializeInput(void)
5a2aa426 306{
c62d2810 307 memset(joy_readbit,0,sizeof(joy_readbit));
308 memset(joy,0,sizeof(joy));
309
310 if(FCEUGameInfo.type==GIT_VSUNI)
311 {
312 SetReadHandler(0x4016,0x4016,VSUNIRead0);
313 SetReadHandler(0x4017,0x4017,VSUNIRead1);
314 }
315 else
316 SetReadHandler(0x4016,0x4017,JPRead);
317 SetWriteHandler(0x4016,0x4016,B4016);
318
319 SetInputStuff(0);
320 SetInputStuff(1);
321 SetInputStuffFC();
322}
323
324void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
325{
326 JPAttrib[port]=attrib;
327 JPType[port]=type;
328 InputDataPtr[port]=ptr;
329 SetInputStuff(port);
330}
331
332void FCEUI_DisableFourScore(int s)
333{
334 FSDisable=s;
335}
336
337void FCEUI_SetInputFC(int type, void *ptr, int attrib)
338{
339 JPAttribFC=attrib;
340 JPTypeFC=type;
341 InputDataPtrFC=ptr;
342 SetInputStuffFC();
343}