1 #ifdef SYSTEM_CPP
2 
3 Input input;
4 
port_read(bool portnumber)5 uint8 Input::port_read(bool portnumber) {
6   port_t &p = port[portnumber];
7 
8   switch(p.device) {
9     case DeviceJoypad: {
10       if(p.counter0 >= 16) return 1;
11       return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
12     } //case DeviceJoypad
13 
14     case DeviceMultitap: {
15       if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
16 
17       unsigned deviceidx, deviceindex0, deviceindex1;
18       uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
19 
20       if(cpu.pio() & mask) {
21         deviceidx = p.counter0;
22         if(deviceidx >= 16) return 3;
23         p.counter0++;
24 
25         deviceindex0 = 0;  //controller 1
26         deviceindex1 = 1;  //controller 2
27       } else {
28         deviceidx = p.counter1;
29         if(deviceidx >= 16) return 3;
30         p.counter1++;
31 
32         deviceindex0 = 2;  //controller 3
33         deviceindex1 = 3;  //controller 4
34       }
35 
36       return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
37            | (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
38     } //case DeviceMultitap
39 
40     case DeviceMouse: {
41       if(p.counter0 >= 32) return 1;
42 
43       int position_x = system.interface->input_poll(portnumber, p.device, 0, MouseX);  //-n = left, 0 = center, +n = right
44       int position_y = system.interface->input_poll(portnumber, p.device, 0, MouseY);  //-n = up,   0 = center, +n = right
45 
46       bool direction_x = position_x < 0;  //0 = right, 1 = left
47       bool direction_y = position_y < 0;  //0 = down,  1 = up
48 
49       if(position_x < 0) position_x = -position_x;  //abs(position_x)
50       if(position_y < 0) position_y = -position_y;  //abs(position_x)
51 
52       position_x = min(127, position_x);  //range = 0 - 127
53       position_y = min(127, position_y);  //range = 0 - 127
54 
55       switch(p.counter0++) { default:
56         case  0: return 0;
57         case  1: return 0;
58         case  2: return 0;
59         case  3: return 0;
60         case  4: return 0;
61         case  5: return 0;
62         case  6: return 0;
63         case  7: return 0;
64 
65         case  8: return system.interface->input_poll(portnumber, p.device, 0, MouseRight);
66         case  9: return system.interface->input_poll(portnumber, p.device, 0, MouseLeft);
67         case 10: return 0;  //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
68         case 11: return 0;  // ||
69 
70         case 12: return 0;  //signature
71         case 13: return 0;  // ||
72         case 14: return 0;  // ||
73         case 15: return 1;  // ||
74 
75         case 16: return (direction_y) & 1;
76         case 17: return (position_y >> 6) & 1;
77         case 18: return (position_y >> 5) & 1;
78         case 19: return (position_y >> 4) & 1;
79         case 20: return (position_y >> 3) & 1;
80         case 21: return (position_y >> 2) & 1;
81         case 22: return (position_y >> 1) & 1;
82         case 23: return (position_y >> 0) & 1;
83 
84         case 24: return (direction_x) & 1;
85         case 25: return (position_x >> 6) & 1;
86         case 26: return (position_x >> 5) & 1;
87         case 27: return (position_x >> 4) & 1;
88         case 28: return (position_x >> 3) & 1;
89         case 29: return (position_x >> 2) & 1;
90         case 30: return (position_x >> 1) & 1;
91         case 31: return (position_x >> 0) & 1;
92       }
93     } //case DeviceMouse
94 
95     case DeviceSuperScope: {
96       if(portnumber == 0) break;  //Super Scope in port 1 not supported ...
97       if(p.counter0 >= 8) return 1;
98 
99       if(p.counter0 == 0) {
100         //turbo is a switch; toggle is edge sensitive
101         bool turbo = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTurbo);
102         if(turbo && !p.superscope.turbolock) {
103           p.superscope.turbo = !p.superscope.turbo;  //toggle state
104           p.superscope.turbolock = true;
105         } else if(!turbo) {
106           p.superscope.turbolock = false;
107         }
108 
109         //trigger is a button
110         //if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
111         p.superscope.trigger = false;
112         bool trigger = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTrigger);
113         if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
114           p.superscope.trigger = true;
115           p.superscope.triggerlock = true;
116         } else if(!trigger) {
117           p.superscope.triggerlock = false;
118         }
119 
120         //cursor is a button; it is always level sensitive
121         p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, SuperScopeCursor);
122 
123         //pause is a button; it is always edge sensitive
124         p.superscope.pause = false;
125         bool pause = system.interface->input_poll(portnumber, p.device, 0, SuperScopePause);
126         if(pause && !p.superscope.pauselock) {
127           p.superscope.pause = true;
128           p.superscope.pauselock = true;
129         } else if(!pause) {
130           p.superscope.pauselock = false;
131         }
132 
133         p.superscope.offscreen =
134            p.superscope.x < 0 || p.superscope.x >= 256
135         || p.superscope.y < 0 || p.superscope.y >= (ppu.overscan() ? 240 : 225);
136       }
137 
138       switch(p.counter0++) {
139         case 0: return p.superscope.trigger;
140         case 1: return p.superscope.cursor;
141         case 2: return p.superscope.turbo;
142         case 3: return p.superscope.pause;
143         case 4: return 0;
144         case 5: return 0;
145         case 6: return p.superscope.offscreen;
146         case 7: return 0;  //noise (1 = yes)
147       }
148     } //case DeviceSuperScope
149 
150     case DeviceJustifier:
151     case DeviceJustifiers: {
152       if(portnumber == 0) break;  //Justifier in port 1 not supported ...
153       if(p.counter0 >= 32) return 1;
154 
155       if(p.counter0 == 0) {
156         p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, JustifierTrigger);
157         p.justifier.start1   = system.interface->input_poll(portnumber, p.device, 0, JustifierStart);
158 
159         if(p.device == DeviceJustifiers) {
160           p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, JustifierTrigger);
161           p.justifier.start2   = system.interface->input_poll(portnumber, p.device, 1, JustifierStart);
162         } else {
163           p.justifier.x2 = -1;
164           p.justifier.y2 = -1;
165 
166           p.justifier.trigger2 = false;
167           p.justifier.start2   = false;
168         }
169       }
170 
171       switch(p.counter0++) {
172         case  0: return 0;
173         case  1: return 0;
174         case  2: return 0;
175         case  3: return 0;
176         case  4: return 0;
177         case  5: return 0;
178         case  6: return 0;
179         case  7: return 0;
180         case  8: return 0;
181         case  9: return 0;
182         case 10: return 0;
183         case 11: return 0;
184 
185         case 12: return 1;  //signature
186         case 13: return 1;  // ||
187         case 14: return 1;  // ||
188         case 15: return 0;  // ||
189 
190         case 16: return 0;
191         case 17: return 1;
192         case 18: return 0;
193         case 19: return 1;
194         case 20: return 0;
195         case 21: return 1;
196         case 22: return 0;
197         case 23: return 1;
198 
199         case 24: return p.justifier.trigger1;
200         case 25: return p.justifier.trigger2;
201         case 26: return p.justifier.start1;
202         case 27: return p.justifier.start2;
203         case 28: return p.justifier.active;
204 
205         case 29: return 0;
206         case 30: return 0;
207         case 31: return 0;
208       }
209     } //case DeviceJustifier(s)
210   } //switch(p.device)
211 
212   //no device connected
213   return 0;
214 }
215 
216 //scan all input; update cursor positions if needed
update()217 void Input::update() {
218   system.interface->input_poll();
219   port_t &p = port[1];
220 
221   switch(p.device) {
222     case DeviceSuperScope: {
223       int x = system.interface->input_poll(1, p.device, 0, SuperScopeX);
224       int y = system.interface->input_poll(1, p.device, 0, SuperScopeY);
225       x += p.superscope.x;
226       y += p.superscope.y;
227       p.superscope.x = max(-16, min(256 + 16, x));
228       p.superscope.y = max(-16, min(240 + 16, y));
229 
230       latchx = p.superscope.x;
231       latchy = p.superscope.y;
232     } break;
233 
234     case DeviceJustifier:
235     case DeviceJustifiers: {
236       int x1 = system.interface->input_poll(1, p.device, 0, JustifierX);
237       int y1 = system.interface->input_poll(1, p.device, 0, JustifierY);
238       x1 += p.justifier.x1;
239       y1 += p.justifier.y1;
240       p.justifier.x1 = max(-16, min(256 + 16, x1));
241       p.justifier.y1 = max(-16, min(240 + 16, y1));
242 
243       int x2 = system.interface->input_poll(1, p.device, 1, JustifierX);
244       int y2 = system.interface->input_poll(1, p.device, 1, JustifierY);
245       x2 += p.justifier.x2;
246       y2 += p.justifier.y2;
247       p.justifier.x2 = max(-16, min(256 + 16, x2));
248       p.justifier.y2 = max(-16, min(240 + 16, y2));
249 
250       if(p.justifier.active == 0) {
251         latchx = p.justifier.x1;
252         latchy = p.justifier.y1;
253       } else {
254         latchx = (p.device == DeviceJustifiers ? p.justifier.x2 : -1);
255         latchy = (p.device == DeviceJustifiers ? p.justifier.y2 : -1);
256       }
257     } break;
258   }
259 
260   if(latchy < 0 || latchy >= (ppu.overscan() ? 240 : 225) || latchx < 0 || latchx >= 256) {
261     //cursor is offscreen, set to invalid position so counters are not latched
262     latchx = ~0;
263     latchy = ~0;
264   } else {
265     //cursor is onscreen
266     latchx += 40;  //offset trigger position to simulate hardware latching delay
267     latchx <<= 2;  //dot -> clock conversion
268     latchx +=  2;  //align trigger on half-dot ala interrupts (speed optimization for sCPU::add_clocks)
269   }
270 }
271 
port_set_device(bool portnumber,unsigned device)272 void Input::port_set_device(bool portnumber, unsigned device) {
273   port_t &p = port[portnumber];
274 
275   p.device = device;
276   p.counter0 = 0;
277   p.counter1 = 0;
278 
279   //set iobit to true if device is capable of latching PPU counters
280   iobit = port[1].device == DeviceSuperScope
281        || port[1].device == DeviceJustifier
282        || port[1].device == DeviceJustifiers;
283   latchx = -1;
284   latchy = -1;
285 
286   if(device == DeviceSuperScope) {
287     p.superscope.x = 256 / 2;
288     p.superscope.y = 240 / 2;
289 
290     p.superscope.trigger   = false;
291     p.superscope.cursor    = false;
292     p.superscope.turbo     = false;
293     p.superscope.pause     = false;
294     p.superscope.offscreen = false;
295 
296     p.superscope.turbolock   = false;
297     p.superscope.triggerlock = false;
298     p.superscope.pauselock   = false;
299   } else if(device == DeviceJustifier) {
300     p.justifier.active = 0;
301     p.justifier.x1 = 256 / 2;
302     p.justifier.y1 = 240 / 2;
303     p.justifier.x2 = -1;
304     p.justifier.y2 = -1;
305 
306     p.justifier.trigger1 = false;
307     p.justifier.trigger2 = false;
308     p.justifier.start1 = false;
309     p.justifier.start2 = false;
310   } else if(device == DeviceJustifiers) {
311     p.justifier.active = 0;
312     p.justifier.x1 = 256 / 2 - 16;
313     p.justifier.y1 = 240 / 2;
314     p.justifier.x2 = 256 / 2 + 16;
315     p.justifier.y2 = 240 / 2;
316 
317     p.justifier.trigger1 = false;
318     p.justifier.trigger2 = false;
319     p.justifier.start1 = false;
320     p.justifier.start2 = false;
321   }
322 }
323 
poll()324 void Input::poll() {
325   port[0].counter0 = 0;
326   port[0].counter1 = 0;
327   port[1].counter0 = 0;
328   port[1].counter1 = 0;
329 
330   port[1].justifier.active = !port[1].justifier.active;
331 }
332 
init()333 void Input::init() {
334 }
335 
336 #endif
337