mapper fixes for ncpu, debug is broken atm
[fceu.git] / input.c
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  */
21 #include <string.h>
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 #include "movie.h"
32
33 #ifdef DEBUG_ASM_6502
34 extern int cpu_repeat;
35 extern int cpu_lastval;
36 #endif
37
38 extern INPUTC *FCEU_InitZapper(int w);
39 extern INPUTC *FCEU_InitPowerpad(int w);
40 extern INPUTC *FCEU_InitArkanoid(int w);
41
42 extern INPUTCFC *FCEU_InitArkanoidFC(void);
43 extern INPUTCFC *FCEU_InitSpaceShadow(void);
44 extern INPUTCFC *FCEU_InitFKB(void);
45 static uint8 joy_readbit[2];
46 static uint16 joy[4]={0,0,0,0};
47
48 extern int coinon;
49
50 static int FSDisable=0; /* Set to 1 if NES-style four-player adapter is disabled. */
51 static int JPAttrib[2]={0,0};
52 static int JPType[2]={0,0};
53 static void *InputDataPtr[2];
54
55 static int JPAttribFC=0;
56 static int JPTypeFC=0;
57 static void *InputDataPtrFC;
58
59 void (*InputScanlineHook)(uint8 *buf, int line);
60
61 static INPUTC DummyJPort={0,0,0,0,0};
62 static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
63 static INPUTCFC *FCExp=0;
64
65 static 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
79 static uint8 FP_FASTAPASS(1) ReadGP(int w)
80 {
81                 uint8 ret;
82                 //if(JoyMulti)
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
101 static DECLFR(JPRead)
102 {
103         uint8 ret=0;
104
105 #ifdef DEBUG_ASM_6502
106         if (cpu_repeat) return cpu_lastval;
107 #endif
108         if(JPorts[A&1]->Read)
109          ret|=JPorts[A&1]->Read(A&1);
110
111         if(FCExp)
112          if(FCExp->Read)
113           ret=FCExp->Read(A&1,ret);
114
115         ret|=X.DB&0xC0;
116 #ifdef DEBUG_ASM_6502
117 //      cpu_lastval=ret;
118 #endif
119         return(ret);
120 }
121
122 static 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
151 static void FP_FASTAPASS(1) StrobeGP(int w)
152 {
153         joy_readbit[w]=0;
154 }
155
156 static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
157 static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
158
159 void 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
171 void 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
203         if (current < 0) FCEUMOV_AddJoy(joy);
204         FlushCommandQueue();
205 }
206
207 static 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
220 static 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
230 static 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);
237  if(FCExp)
238   if(FCExp->SLHook)
239    FCExp->SLHook(buf,line);
240 }
241
242 static 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
252 static 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
271 static uint8 F4ReadBit[2];
272 static void StrobeFami4(void)
273 {
274  F4ReadBit[0]=F4ReadBit[1]=0;
275 }
276
277 static 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
288 static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
289 static 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
305 void InitializeInput(void)
306 {
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
324 void 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
332 void FCEUI_DisableFourScore(int s)
333 {
334  FSDisable=s;
335 }
336
337 void FCEUI_SetInputFC(int type, void *ptr, int attrib)
338 {
339  JPAttribFC=attrib;
340  JPTypeFC=type;
341  InputDataPtrFC=ptr;
342  SetInputStuffFC();
343 }