From: K.Ohta Date: Sun, 25 Jul 2021 18:48:12 +0000 (+0900) Subject: [VM][JOYSTICK][FMTOWNS] Add template class of JOYSTICK DEVICES. X-Git-Url: http://git.sourceforge.jp/view?a=commitdiff_plain;h=243867904ad9a090723260ef5412c095e0da651d;p=csp-qt%2Fcommon_source_project-fm7.git [VM][JOYSTICK][FMTOWNS] Add template class of JOYSTICK DEVICES. --- diff --git a/source/src/vm/fmtowns/js_template.h b/source/src/vm/fmtowns/js_template.h new file mode 100644 index 000000000..d411054aa --- /dev/null +++ b/source/src/vm/fmtowns/js_template.h @@ -0,0 +1,430 @@ +/* + FUJITSU FM Towns Emulator 'eFMTowns' + + Author : Kyuma.Ohta + Date : 2020.07.26 - + History : 2020.07.26 Initial. + [ Towns Joystick devices: Template class] + +*/ + +#pragma once + +#include "../device.h" + +namespace FMTOWNS { + +// OUTPUT TO PARENT PORT (SOME JOYSTICK DEVICES -> JOYSTICK PORT) +#define SIG_JSPORT_COM 0x01001 +#define SIG_JSPORT_DATA 0x01002 + +#define SIG_JSPORT_PORT1 0x00000000 +#define SIG_JSPORT_PORT2 0x00010000 +#define SIG_JSPORT_PORT3 0x00020000 +#define SIG_JSPORT_PORT4 0x00030000 +#define SIG_JSPORT_PORT5 0x00040000 +#define SIG_JSPORT_PORT6 0x00050000 +#define SIG_JSPORT_PORT7 0x00060000 +#define SIG_JSPORT_PORT8 0x00070000 + + +// DEVICE CONTROL SIGNALS (MOSTLY PORT -> THIS) +#define SIG_JS_COM 1 +#define SIG_JS_TRIG_A 2 +#define SIG_JS_TRIG_B 3 + +// SPECIAL DEVICE CONTROL SIGNAL(S) (PORT -> THIS) +#define SIG_JS_DEVICE_RESET 0x80 + +// INPUT SIGNALS FROM PARENT PORT. (THIS -> PORT) +#define SIG_JS_COM_OUTPUT 0x11 +#define SIG_JS_TRIG_A_OUTPUT 0x12 +#define SIG_JS_TRIG_B_OUTPUT 0x13 +#define SIOG_JS_DATA 0x14 + +// PEEK STATUS OF THIS FROM ANY DEVICES. +#define SIG_JS_PORT_NUM 0x15 +#define SIG_JS_CONNECTED 0x16 +#define SIG_JS_DATASHIFT 0x17 +#define SIG_JS_DATAMASK 0x18 +#define SIG_JS_NAGATIVE_LOGIC 0x19 + +#define JSPORT_MASK_DATA 0x0f +#define JSPORT_MASK_TRIG_A 0x10 +#define JSPORT_MASK_TRIG_B 0x20 +#define JSPORT_MASK_COM 0x40 +#define JSPORT_MASK_RESERVE 0x80 + +class JSDEV_TEMPLATE : public DEVICE +{ +protected: + DEVICE* d_parent_device; // Normally FMTOWNS::JOYSTICK + + bool is_connected; + bool is_negative_logic; // DATA VALUES IS NAGATIVE LOGIC. + bool force_output_on_change; + int parent_port_num; + + uint32_t signal_mask; + int signal_shift; + + // INPUT (Received) Values + bool sig_trig_a; // INPUT: trig_a + bool sig_trig_b; // INPUT: trig_a + bool sig_com; // INPUT: com (or strobe). + + bool val_trig_a; // OUTPUT: trig_a + bool val_trig_b; // OUTPUT: trig_b + bool val_com; + + uint8_t portval_data; // May 4bit space. + + bool need_unlock; + + void lock_vm() + { + if((emu != nullptr) && (need_unlock)){ + emu->lock_vm(); + } + } + + void unlock_vm() + { + if((emu != nullptr) && (need_unlock)){ + emu->unlock_vm(); + } + } + + // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device(). + virtual void reset_device() + { + initialize_status(); + + output_port_status(false); + output_port_com(val_com, false); + } + virtual void initialize_status() + { + sig_trig_a = false; + sig_trig_b = false; + sig_com = false; + + val_trig_a = true; + val_trig_b = true; + val_com = true; + + portval_data = 0x00; + + } + virtual void output_port_com(bool val, bool force = false) + { + val_com = val; + if(!(force)) { + val = val & sig_com; + } + if((d_parent_device != nullptr) && (is_connected)) { + if((parent_port_num >= 0) && (parent_port_num < 8)) { + uint32_t r_data = (val) ? 0x40 : 0x0; + int signum = (parent_port_num << 16) & 0x70000; + signum = signum | SIG_JSPORT_COM; + lock_vm(); + write_signal(signum, r_data << signal_shift, signal_mask); + unlock_vm(); + } + } + } + virtual void output_port_signals(bool force = false) + { + if((d_parent_device != nullptr) && (is_connected)) { + if((parent_port_num >= 0) && (parent_port_num < 8)) { + uint32_t r_data; + r_data = (uint32_t)(portval_data & 0x0f); + if(force) { + r_data |= (val_trig_a == true) ? 0x10 : 0x00; + r_data |= (val_trig_b == true) ? 0x20 : 0x00; + } else {p + r_data |= (((val_trig_a) && (sig_trig_a)) == true) ? 0x10 : 0x00; + r_data |= (((val_trig_b) && (sig_trig_b)) == true) ? 0x20 : 0x00; + } + int signum = (parent_port_num << 16) & 0x70000; + signum = signum | SIG_JSPORT_DATA; + lock_vm(); + write_signal(signum, r_data << signal_shift, signal_mask); + unlock_vm(); + } + } + } + void output_port_data(uint8_t data, bool later = true, bool force = false) + { + if(is_negative_logic) { + data = ~data; + } + port_val = data & 0x0f; + + if(!(later)) { + output_port_signals(force); + } + } + + void output_trig_a(bool val, bool later = true, bool force = false) + { + val_trig_a = val; + if(!(later)) { + output_port_signals(force); + } + } + void output_trig_b(bool val, bool later = true, bool force = false) + { + val_trig_b = val; + if(!(later)) { + output_port_signals(force); + } + } + + virtual void hook_changes_trig_a(bool changed) + { + if(changed) { + // Please write sequences. + output_port_signals(force_output_on_change); + } + } + virtual void hook_change_trig_b(bool changed) + { + if(changed) { + // Please write sequences. + output_port_signals(force_output_on_change); + } + } + virtual void hook_changed_data(bool changed) + { + if(changed) { + // Please write sequences. + output_port_signals(force_output_on_change); + } + } + + virtual void hook_changed_com(bool changed) + { + if(changed) { + // Please write sequences. + output_port_com(val_com, force_output_on_change); + } + } + +public: + JSDEV_TEMPLATE(VM_TEMPLATE* parent_vm, EMU_TEMPLATE* parent_emu) : DEVICE(parent_vm, parent_emu) + { + d_parent_device = NULL; + + parent_port_num = -1; + signal_shift = 0; + signal_mask = 0xffffffff; + + is_connected = false; + is_nagative_logic = false; + force_output_on_change = false; + need_unlock = false; + initialize_status(); + } + // common functions + virtual void initialize(void) + { + need_unlock = true; // Available to lock_vm() / unlick_vm() on VM/EMU. + reset_device(); + } + + virtual void release() + { + } + + // @note: DEVICE MUST NOT RESET WITHIN reset(), must reset within reset_device(). + virtual void reset() + { + } + + virtual void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask) + { + // id_structure + // Bit 0 - 15: PERSONAL SIGNAL NUMBER. + // Bit 16 - 18: PORT NUMBER (0 - 7) + int sig_num = id & 0xffff; + int port_num = (id & 0x70000) >> 16; + + if(port_num != parent_port_num) return; + switch(sig_num) { + case SIG_JS_TRIG_A: + if(is_connected) { + bool bak = sig_trig_a; + sig_trig_a = ((data & mask) != 0) ? true : false; + hook_changed_trig_a((bak != sig_trig_a) ? true : false); + } + break; + case SIG_JS_TRIG_B: + if(is_connected) { + bool bak = sig_trig_b; + sig_trig_b = ((data & mask) != 0) ? true : false; + hook_changed_trig_b((bak != sig_trig_b) ? true : false); + } + break; + case SIG_JS_COM: + if(is_connected) { + bool bak = sig_com; + sig_com = ((data & mask) != 0) ? true : false; + hook_changed_com((bak != sig_com) ? true : false); + } + break; + case SIG_JS_DEVICE_RESET: + if((data & mask) != 0) { + reset_device(); + } + break; + } + } + + virtual uint32_t __FASTCALL read_signal(int id) + { + switch(id) { + case SIG_JS_TRIG_A_OUTPUT: + return (val_trig_a == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_TRIG_B_OUTPUT: + return (val_trig_b == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_COM_OUTPUT: + return (val_com == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_DATA: + return ((uint32_t)portval_data) & 0x0f; + break; + case SIG_JS_TRIG_A: + return (sig_trig_a == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_TRIG_B: + return (sig_trig_b == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_COM: + return (sig_com == true) ? 0xffffffff : 0x00000000; + break; + case SIG_JS_PORT_NUM: + if((parent_port_num >= 0) && (parent_port_num < 8)) { + return (uint32_t)parent_port_num; + } else { + return 0xffffffff; + } + break; + case SIG_JS_CONNECTED: + return (is_connected == true) ? 0xffffffff : 0; + break; + case SIG_JS_DATASHIFT: + return (uint32_t)signal_shift; + break; + case SIG_JS_DATAMASK: + return signal_mask; + break; + case SIG_JS_NAGATIVE_LOGIC: + return (is_nagative_logic == true) ? 0xffffffff : 0; + break; + } + return 0; + } + + virtual void update_config() + { + } + +#define TOWNS_JS_TEMPLATE_STATE_VERSION 1 + virtual bool process_state(FILEIO* state_fio, bool loading) + { + if(!state_fio->StateCheckUint32(TOWNS_JS_TEMPLATE_STATE_VERSION)) { + return false; + } + if(!state_fio->StateCheckInt32(this_device_id)) { + return false; + } + state_fio->StateValue(is_connected); + state_fio->StateValue(is_nagative_logic); + + state_fio->StateValue(parent_port_num); + state_fio->StateValue(portval_data); + + + state_fio->StateValue(sig_trig_a); + state_fio->StateValue(sig_trig_b); + state_fio->StateValue(sig_com); + + state_fio->StateValue(val_trig_a); + state_fio->StateValue(val_trig_b); + state_fio->StateValue(val_com); + + state_fio->StateValue(portval_data); + + state_fio->StateValue(signal_shift); + state_fio->StateValue(signal_mask); + + return true; + } +#undef TOWNS_JS_TEMPLATE_STATE_VERSION + + // unique functions + // Set parent port + void set_context_parent_port(int num, DEVICE* dev, int shift, uint32_t mask) + { + lock_vm(); + parent_port_num = num; + d_parent_device = dev; + + signal_shift = shift; + signal_mask = mask; + unlock_vm(); + + force_output_on_change = false; + reset_device() + } + + virtual void remove_from_parent_port() + { + // You should make all events cancel here. + lock_vm(); + parent_port_num = -1; + signal_shift = 0; + signal_mask = 0xffffffff; + + d_parent_device = NULL; + is_connected = false; + is_nagative_logic = false; + force_output_on_change = false; + + initialize_status(); + + unlock_vm(); + } + virtual void set_force_output_on_change(bool is_enable) + { + lock_vm(); + force_output_on_change = val; + unlock_vm(); + } + virtual void set_enable(bool is_enable) + { + lock_vm(); + if(is_enable) { + // You may implement initialize sequence. + } else { + // You may implement removing sequence. + } + is_connected = is_enable; + unlock_vm(); + } + virtual void set_negative_logic(bool val) + { + lock_vm(); + is_negative_logic = val; + unlock_vm(); + } + virtual bool is_enabled() + { + return is_connected; + } +}; +} +