OSDN Git Service

[VM][JOYSTICK][FMTOWNS] Add template class of JOYSTICK DEVICES.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / js_template.h
1 /*
2         FUJITSU FM Towns Emulator 'eFMTowns'
3
4         Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2020.07.26 -
6     History : 2020.07.26 Initial.
7         [ Towns Joystick devices: Template class]
8
9 */
10
11 #pragma once
12
13 #include "../device.h"
14
15 namespace FMTOWNS {
16
17 // OUTPUT TO PARENT PORT (SOME JOYSTICK DEVICES -> JOYSTICK PORT)
18 #define SIG_JSPORT_COM          0x01001
19 #define SIG_JSPORT_DATA         0x01002
20
21 #define SIG_JSPORT_PORT1        0x00000000
22 #define SIG_JSPORT_PORT2        0x00010000
23 #define SIG_JSPORT_PORT3        0x00020000
24 #define SIG_JSPORT_PORT4        0x00030000
25 #define SIG_JSPORT_PORT5        0x00040000
26 #define SIG_JSPORT_PORT6        0x00050000
27 #define SIG_JSPORT_PORT7        0x00060000
28 #define SIG_JSPORT_PORT8        0x00070000
29
30         
31 // DEVICE CONTROL SIGNALS (MOSTLY PORT -> THIS)
32 #define SIG_JS_COM                              1
33 #define SIG_JS_TRIG_A                   2
34 #define SIG_JS_TRIG_B                   3
35
36 // SPECIAL DEVICE CONTROL SIGNAL(S) (PORT -> THIS)
37 #define SIG_JS_DEVICE_RESET             0x80
38         
39 // INPUT SIGNALS FROM PARENT PORT. (THIS -> PORT)       
40 #define SIG_JS_COM_OUTPUT               0x11
41 #define SIG_JS_TRIG_A_OUTPUT    0x12
42 #define SIG_JS_TRIG_B_OUTPUT    0x13
43 #define SIOG_JS_DATA                    0x14
44
45 // PEEK STATUS OF THIS FROM ANY DEVICES.        
46 #define SIG_JS_PORT_NUM                 0x15
47 #define SIG_JS_CONNECTED                0x16
48 #define SIG_JS_DATASHIFT                0x17
49 #define SIG_JS_DATAMASK                 0x18
50 #define SIG_JS_NAGATIVE_LOGIC   0x19
51
52 #define JSPORT_MASK_DATA                0x0f
53 #define JSPORT_MASK_TRIG_A              0x10
54 #define JSPORT_MASK_TRIG_B              0x20
55 #define JSPORT_MASK_COM                 0x40
56 #define JSPORT_MASK_RESERVE             0x80
57         
58 class JSDEV_TEMPLATE : public DEVICE
59 {
60 protected:
61         DEVICE* d_parent_device; // Normally FMTOWNS::JOYSTICK
62         
63         bool is_connected;
64         bool is_negative_logic; // DATA VALUES IS NAGATIVE LOGIC.
65         bool force_output_on_change;
66         int parent_port_num;
67         
68         uint32_t signal_mask;
69         int signal_shift;
70         
71         // INPUT (Received) Values
72         bool sig_trig_a; // INPUT: trig_a
73         bool sig_trig_b; // INPUT: trig_a
74         bool sig_com;  // INPUT: com (or strobe).
75
76         bool val_trig_a; // OUTPUT: trig_a
77         bool val_trig_b; // OUTPUT: trig_b
78         bool val_com;
79
80         uint8_t portval_data; // May 4bit space.
81
82         bool need_unlock;
83         
84         void lock_vm()
85         {
86                 if((emu != nullptr) && (need_unlock)){
87                         emu->lock_vm();
88                 }
89         }
90         
91         void unlock_vm()
92         {
93                 if((emu != nullptr) && (need_unlock)){
94                         emu->unlock_vm();
95                 }
96         }
97
98         // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device().
99         virtual void reset_device()
100         {
101                 initialize_status();
102                 
103                 output_port_status(false);
104                 output_port_com(val_com, false);
105         }
106         virtual void initialize_status()
107         {
108                 sig_trig_a = false;
109                 sig_trig_b = false;
110                 sig_com = false;
111
112                 val_trig_a = true;
113                 val_trig_b = true;
114                 val_com = true;
115
116                 portval_data = 0x00;
117
118         }
119         virtual void output_port_com(bool val, bool force = false)
120         {
121                 val_com = val;
122                 if(!(force)) {
123                         val = val & sig_com;
124                 }
125                 if((d_parent_device != nullptr) && (is_connected)) {
126                         if((parent_port_num >= 0) && (parent_port_num < 8)) {
127                                 uint32_t r_data = (val) ? 0x40 : 0x0;
128                                 int signum = (parent_port_num << 16) & 0x70000;
129                                 signum = signum | SIG_JSPORT_COM;
130                                 lock_vm();
131                                 write_signal(signum, r_data << signal_shift, signal_mask);
132                                 unlock_vm();
133                         }
134                 }
135         }
136         virtual void output_port_signals(bool force = false)
137         {
138                 if((d_parent_device != nullptr) && (is_connected)) {
139                         if((parent_port_num >= 0) && (parent_port_num < 8)) {
140                                 uint32_t r_data;
141                                 r_data =  (uint32_t)(portval_data & 0x0f);
142                                 if(force) {
143                                         r_data |= (val_trig_a == true) ? 0x10 : 0x00;
144                                         r_data |= (val_trig_b == true) ? 0x20 : 0x00;
145                                 } else {p
146                                         r_data |= (((val_trig_a) && (sig_trig_a)) == true) ? 0x10 : 0x00;
147                                         r_data |= (((val_trig_b) && (sig_trig_b)) == true) ? 0x20 : 0x00;
148                                 }
149                                 int signum = (parent_port_num << 16) & 0x70000;
150                                 signum = signum | SIG_JSPORT_DATA;
151                                 lock_vm();
152                                 write_signal(signum, r_data << signal_shift, signal_mask);
153                                 unlock_vm();
154                         }
155                 }
156         }
157         void output_port_data(uint8_t data, bool later = true, bool force = false)
158         {
159                 if(is_negative_logic) {
160                         data = ~data;
161                 }
162                 port_val = data & 0x0f;
163                 
164                 if(!(later)) {
165                         output_port_signals(force);
166                 }
167         }
168         
169         void output_trig_a(bool val,  bool later = true, bool force = false)
170         {
171                 val_trig_a = val;
172                 if(!(later)) {
173                         output_port_signals(force);
174                 }
175         }
176         void output_trig_b(bool val,  bool later = true, bool force = false)
177         {
178                 val_trig_b = val;
179                 if(!(later)) {
180                         output_port_signals(force);
181                 }
182         }
183
184         virtual void hook_changes_trig_a(bool changed)
185         {
186                 if(changed) {
187                         // Please write sequences.
188                         output_port_signals(force_output_on_change);
189                 }
190         }
191         virtual void hook_change_trig_b(bool changed)
192         {
193                 if(changed) {
194                         // Please write sequences.
195                         output_port_signals(force_output_on_change);
196                 }
197         }
198         virtual void hook_changed_data(bool changed)
199         {
200                 if(changed) {
201                         // Please write sequences.
202                         output_port_signals(force_output_on_change);
203                 }
204         }
205         
206         virtual void hook_changed_com(bool changed)
207         {
208                 if(changed) {
209                         // Please write sequences.
210                         output_port_com(val_com, force_output_on_change);
211                 }
212         }
213
214 public:
215         JSDEV_TEMPLATE(VM_TEMPLATE* parent_vm, EMU_TEMPLATE* parent_emu) : DEVICE(parent_vm, parent_emu)
216         {
217                 d_parent_device = NULL;
218
219                 parent_port_num = -1;
220                 signal_shift = 0;
221                 signal_mask = 0xffffffff;
222                 
223                 is_connected = false;
224                 is_nagative_logic = false;
225                 force_output_on_change = false;
226                 need_unlock = false;
227                 initialize_status();
228         }
229         // common functions
230         virtual void initialize(void)
231         {
232                 need_unlock = true; // Available to lock_vm() / unlick_vm() on VM/EMU.
233                 reset_device();
234         }
235         
236         virtual void release()
237         {
238         }
239         
240         // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device().
241         virtual void reset()
242         {
243         }
244
245         virtual void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask)
246         {
247                 // id_structure
248                 // Bit 0  - 15:  PERSONAL SIGNAL NUMBER.
249                 // Bit 16 - 18:  PORT NUMBER (0 - 7)
250                 int sig_num = id & 0xffff;
251                 int port_num = (id & 0x70000) >> 16;
252
253                 if(port_num != parent_port_num) return; 
254                 switch(sig_num) {
255                 case SIG_JS_TRIG_A:
256                         if(is_connected) {
257                                 bool bak = sig_trig_a;
258                                 sig_trig_a = ((data & mask) != 0) ? true : false;
259                                 hook_changed_trig_a((bak != sig_trig_a) ? true : false);
260                         }
261                         break;
262                 case SIG_JS_TRIG_B:
263                         if(is_connected) {
264                                 bool bak = sig_trig_b;
265                                 sig_trig_b = ((data & mask) != 0) ? true : false;
266                                 hook_changed_trig_b((bak != sig_trig_b) ? true : false);
267                         }
268                         break;
269                 case SIG_JS_COM:
270                         if(is_connected) {
271                                 bool bak = sig_com;
272                                 sig_com = ((data & mask) != 0) ? true : false;
273                                 hook_changed_com((bak != sig_com) ? true : false);
274                         }
275                         break;
276                 case SIG_JS_DEVICE_RESET:
277                         if((data & mask) != 0) {
278                                 reset_device();
279                         }
280                         break;
281                 }
282         }
283         
284         virtual uint32_t __FASTCALL read_signal(int id)
285         {
286                 switch(id) {
287                 case SIG_JS_TRIG_A_OUTPUT:
288                         return (val_trig_a == true) ? 0xffffffff : 0x00000000;
289                         break;
290                 case SIG_JS_TRIG_B_OUTPUT:
291                         return (val_trig_b == true) ? 0xffffffff : 0x00000000;
292                         break;
293                 case SIG_JS_COM_OUTPUT:
294                         return (val_com == true) ? 0xffffffff : 0x00000000;
295                         break;
296                 case SIG_JS_DATA:
297                         return ((uint32_t)portval_data) & 0x0f;
298                         break;
299                 case SIG_JS_TRIG_A:
300                         return (sig_trig_a == true) ? 0xffffffff : 0x00000000;
301                         break;
302                 case SIG_JS_TRIG_B:
303                         return (sig_trig_b == true) ? 0xffffffff : 0x00000000;
304                         break;
305                 case SIG_JS_COM:
306                         return (sig_com == true) ? 0xffffffff : 0x00000000;
307                         break;
308                 case SIG_JS_PORT_NUM:
309                         if((parent_port_num >= 0) && (parent_port_num < 8)) {
310                                 return (uint32_t)parent_port_num;
311                         } else {
312                                 return 0xffffffff;
313                         }
314                         break;
315                 case SIG_JS_CONNECTED:
316                         return (is_connected == true) ? 0xffffffff : 0;
317                         break;
318                 case SIG_JS_DATASHIFT:
319                         return (uint32_t)signal_shift;
320                         break;
321                 case SIG_JS_DATAMASK:
322                         return signal_mask;
323                         break;
324                 case SIG_JS_NAGATIVE_LOGIC:
325                         return (is_nagative_logic == true) ? 0xffffffff : 0;
326                         break;
327                 }
328                 return 0;
329         }
330
331         virtual void update_config()
332         {
333         }
334
335 #define TOWNS_JS_TEMPLATE_STATE_VERSION 1       
336         virtual bool process_state(FILEIO* state_fio, bool loading)
337         {
338                 if(!state_fio->StateCheckUint32(TOWNS_JS_TEMPLATE_STATE_VERSION)) {
339                         return false;
340                 }
341                 if(!state_fio->StateCheckInt32(this_device_id)) {
342                         return false;
343                 }
344                 state_fio->StateValue(is_connected);
345                 state_fio->StateValue(is_nagative_logic);
346                 
347                 state_fio->StateValue(parent_port_num);
348                 state_fio->StateValue(portval_data);
349
350                 
351                 state_fio->StateValue(sig_trig_a);
352                 state_fio->StateValue(sig_trig_b);
353                 state_fio->StateValue(sig_com);
354
355                 state_fio->StateValue(val_trig_a);
356                 state_fio->StateValue(val_trig_b);
357                 state_fio->StateValue(val_com);
358                 
359                 state_fio->StateValue(portval_data);
360
361                 state_fio->StateValue(signal_shift);
362                 state_fio->StateValue(signal_mask);
363                 
364                 return true;
365         }
366 #undef TOWNS_JS_TEMPLATE_STATE_VERSION
367         
368         // unique functions
369         // Set parent port
370         void set_context_parent_port(int num, DEVICE* dev, int shift, uint32_t mask)
371         {
372                 lock_vm();
373                 parent_port_num = num;
374                 d_parent_device = dev;
375                 
376                 signal_shift = shift;
377                 signal_mask = mask;
378                 unlock_vm();
379
380                 force_output_on_change  = false;
381                 reset_device()
382         }
383
384         virtual void remove_from_parent_port()
385         {
386                 // You should make all events cancel here.
387                 lock_vm();
388                 parent_port_num = -1;
389                 signal_shift = 0;
390                 signal_mask = 0xffffffff;
391                 
392                 d_parent_device = NULL;
393                 is_connected = false;
394                 is_nagative_logic = false;
395                 force_output_on_change  = false;
396                 
397                 initialize_status();
398                 
399                 unlock_vm();
400         }
401         virtual void set_force_output_on_change(bool is_enable)
402         {
403                 lock_vm();
404                 force_output_on_change = val;
405                 unlock_vm();
406         }
407         virtual void set_enable(bool is_enable)
408         {
409                 lock_vm();
410                 if(is_enable) {
411                         // You may implement initialize sequence.
412                 } else {
413                         // You may implement removing sequence.
414                 }
415                 is_connected = is_enable;
416                 unlock_vm();
417         }
418         virtual void set_negative_logic(bool val)
419         {
420                 lock_vm();
421                 is_negative_logic = val;
422                 unlock_vm();
423         }
424         virtual bool is_enabled()
425         {
426                 return is_connected;
427         }
428 };
429 }
430