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