2 FUJITSU FM Towns Emulator 'eFMTowns'
4 Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
6 History : 2020.07.26 Initial.
7 [ Towns Joystick devices: Template class]
13 #include "../device.h"
17 // OUTPUT TO PARENT PORT (SOME JOYSTICK DEVICES -> JOYSTICK PORT)
18 #define SIG_JSPORT_COM 0x01001
19 #define SIG_JSPORT_DATA 0x01002
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
31 // DEVICE CONTROL SIGNALS (MOSTLY PORT -> THIS)
33 #define SIG_JS_TRIG_A 2
34 #define SIG_JS_TRIG_B 3
36 // SPECIAL DEVICE CONTROL SIGNAL(S) (PORT -> THIS)
37 #define SIG_JS_DEVICE_RESET 0x80
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
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
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
58 class JSDEV_TEMPLATE : public DEVICE
61 DEVICE* d_parent_device; // Normally FMTOWNS::JOYSTICK
64 bool is_negative_logic; // DATA VALUES IS NAGATIVE LOGIC.
65 bool force_output_on_change;
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).
76 bool val_trig_a; // OUTPUT: trig_a
77 bool val_trig_b; // OUTPUT: trig_b
80 uint8_t portval_data; // May 4bit space.
86 if((emu != nullptr) && (need_unlock)){
93 if((emu != nullptr) && (need_unlock)){
98 // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device().
99 virtual void reset_device()
103 output_port_status(false);
104 output_port_com(val_com, false);
106 virtual void initialize_status()
119 virtual void output_port_com(bool val, bool force = false)
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;
131 write_signal(signum, r_data << signal_shift, signal_mask);
136 virtual void output_port_signals(bool force = false)
138 if((d_parent_device != nullptr) && (is_connected)) {
139 if((parent_port_num >= 0) && (parent_port_num < 8)) {
141 r_data = (uint32_t)(portval_data & 0x0f);
143 r_data |= (val_trig_a == true) ? 0x10 : 0x00;
144 r_data |= (val_trig_b == true) ? 0x20 : 0x00;
146 r_data |= (((val_trig_a) && (sig_trig_a)) == true) ? 0x10 : 0x00;
147 r_data |= (((val_trig_b) && (sig_trig_b)) == true) ? 0x20 : 0x00;
149 int signum = (parent_port_num << 16) & 0x70000;
150 signum = signum | SIG_JSPORT_DATA;
152 write_signal(signum, r_data << signal_shift, signal_mask);
157 void output_port_data(uint8_t data, bool later = true, bool force = false)
159 if(is_negative_logic) {
162 port_val = data & 0x0f;
165 output_port_signals(force);
169 void output_trig_a(bool val, bool later = true, bool force = false)
173 output_port_signals(force);
176 void output_trig_b(bool val, bool later = true, bool force = false)
180 output_port_signals(force);
184 virtual void hook_changes_trig_a(bool changed)
187 // Please write sequences.
188 output_port_signals(force_output_on_change);
191 virtual void hook_change_trig_b(bool changed)
194 // Please write sequences.
195 output_port_signals(force_output_on_change);
198 virtual void hook_changed_data(bool changed)
201 // Please write sequences.
202 output_port_signals(force_output_on_change);
206 virtual void hook_changed_com(bool changed)
209 // Please write sequences.
210 output_port_com(val_com, force_output_on_change);
215 JSDEV_TEMPLATE(VM_TEMPLATE* parent_vm, EMU_TEMPLATE* parent_emu) : DEVICE(parent_vm, parent_emu)
217 d_parent_device = NULL;
219 parent_port_num = -1;
221 signal_mask = 0xffffffff;
223 is_connected = false;
224 is_nagative_logic = false;
225 force_output_on_change = false;
230 virtual void initialize(void)
232 need_unlock = true; // Available to lock_vm() / unlick_vm() on VM/EMU.
236 virtual void release()
240 // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device().
245 virtual void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask)
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;
253 if(port_num != parent_port_num) return;
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);
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);
272 sig_com = ((data & mask) != 0) ? true : false;
273 hook_changed_com((bak != sig_com) ? true : false);
276 case SIG_JS_DEVICE_RESET:
277 if((data & mask) != 0) {
284 virtual uint32_t __FASTCALL read_signal(int id)
287 case SIG_JS_TRIG_A_OUTPUT:
288 return (val_trig_a == true) ? 0xffffffff : 0x00000000;
290 case SIG_JS_TRIG_B_OUTPUT:
291 return (val_trig_b == true) ? 0xffffffff : 0x00000000;
293 case SIG_JS_COM_OUTPUT:
294 return (val_com == true) ? 0xffffffff : 0x00000000;
297 return ((uint32_t)portval_data) & 0x0f;
300 return (sig_trig_a == true) ? 0xffffffff : 0x00000000;
303 return (sig_trig_b == true) ? 0xffffffff : 0x00000000;
306 return (sig_com == true) ? 0xffffffff : 0x00000000;
308 case SIG_JS_PORT_NUM:
309 if((parent_port_num >= 0) && (parent_port_num < 8)) {
310 return (uint32_t)parent_port_num;
315 case SIG_JS_CONNECTED:
316 return (is_connected == true) ? 0xffffffff : 0;
318 case SIG_JS_DATASHIFT:
319 return (uint32_t)signal_shift;
321 case SIG_JS_DATAMASK:
324 case SIG_JS_NAGATIVE_LOGIC:
325 return (is_nagative_logic == true) ? 0xffffffff : 0;
331 virtual void update_config()
335 #define TOWNS_JS_TEMPLATE_STATE_VERSION 1
336 virtual bool process_state(FILEIO* state_fio, bool loading)
338 if(!state_fio->StateCheckUint32(TOWNS_JS_TEMPLATE_STATE_VERSION)) {
341 if(!state_fio->StateCheckInt32(this_device_id)) {
344 state_fio->StateValue(is_connected);
345 state_fio->StateValue(is_nagative_logic);
347 state_fio->StateValue(parent_port_num);
348 state_fio->StateValue(portval_data);
351 state_fio->StateValue(sig_trig_a);
352 state_fio->StateValue(sig_trig_b);
353 state_fio->StateValue(sig_com);
355 state_fio->StateValue(val_trig_a);
356 state_fio->StateValue(val_trig_b);
357 state_fio->StateValue(val_com);
359 state_fio->StateValue(portval_data);
361 state_fio->StateValue(signal_shift);
362 state_fio->StateValue(signal_mask);
366 #undef TOWNS_JS_TEMPLATE_STATE_VERSION
370 void set_context_parent_port(int num, DEVICE* dev, int shift, uint32_t mask)
373 parent_port_num = num;
374 d_parent_device = dev;
376 signal_shift = shift;
380 force_output_on_change = false;
384 virtual void remove_from_parent_port()
386 // You should make all events cancel here.
388 parent_port_num = -1;
390 signal_mask = 0xffffffff;
392 d_parent_device = NULL;
393 is_connected = false;
394 is_nagative_logic = false;
395 force_output_on_change = false;
401 virtual void set_force_output_on_change(bool is_enable)
404 force_output_on_change = val;
407 virtual void set_enable(bool is_enable)
411 // You may implement initialize sequence.
413 // You may implement removing sequence.
415 is_connected = is_enable;
418 virtual void set_negative_logic(bool val)
421 is_negative_logic = val;
424 virtual bool is_enabled()