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