OSDN Git Service

[VM][FMTOWNS][MOUSE][JOYSTICK] Split MOUSE to separate class.
authorK.Ohta <whatisthis.sowhat@gmail.com>
Wed, 16 Jun 2021 18:30:40 +0000 (03:30 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Wed, 16 Jun 2021 18:30:40 +0000 (03:30 +0900)
source/src/vm/fmtowns/CMakeLists.txt
source/src/vm/fmtowns/fmtowns.cpp
source/src/vm/fmtowns/fmtowns.h
source/src/vm/fmtowns/joystick.cpp
source/src/vm/fmtowns/joystick.h
source/src/vm/fmtowns/mouse.cpp [new file with mode: 0644]
source/src/vm/fmtowns/mouse.h [new file with mode: 0644]

index 3dccb4f..6e07bc9 100644 (file)
@@ -19,6 +19,8 @@ set(VM_FMTOWNS_DEV_SRCS
        iccard.cpp
        joystick.cpp
        joypad.cpp
+       mouse.cpp
+       
        msdosrom.cpp
        serialrom.cpp
        dictionary.cpp
index d5912db..d7c8487 100644 (file)
@@ -63,6 +63,7 @@
 #include "./joystick.h"
 #include "./joypad.h"
 #include "./keyboard.h"
+#include "./mouse.h"
 #include "./msdosrom.h"
 #include "./scsi.h"
 #include "./serialrom.h"
@@ -82,6 +83,7 @@ using FMTOWNS::FONT_ROMS;
 using FMTOWNS::JOYSTICK;
 using FMTOWNS::JOYPAD;
 using FMTOWNS::KEYBOARD;
+using FMTOWNS::MOUSE;
 using FMTOWNS::MSDOSROM;
 using FMTOWNS::SCSI;
 using FMTOWNS::SERIAL_ROM;
@@ -214,6 +216,7 @@ VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
 #endif
        joypad[0] = new JOYPAD(this, emu);
        joypad[1] = new JOYPAD(this, emu);
+       mouse = new MOUSE(this, emu);
 
        uint16_t machine_id = 0x0100; // FM-Towns1
        uint16_t cpu_id = 0x0001;     // i386DX
@@ -417,6 +420,8 @@ VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
        timer->set_context_rtc(rtc);
        timer->set_context_halt_line(cpu, SIG_CPU_HALTREQ, 0xffffffff);
 
+       joystick->set_context_mouse(mouse, SIG_MOUSE_STROBE, 0xff);
+       
        joystick->set_context_enable0(joypad[0], SIG_JOYPAD_ENABLE, 0xffffffff);
        joystick->set_context_enable1(joypad[1], SIG_JOYPAD_ENABLE, 0xffffffff);
        joystick->set_context_mask(joypad[0], SIG_JOYPAD_SELECT_BUS, 0x10); // Mouse0 or joypad0
index 12446e1..e78fc68 100644 (file)
@@ -381,7 +381,7 @@ namespace FMTOWNS {
        class TOWNS_VRAM;
        class PLANEVRAM;
        class JOYPAD;
-       class JOYSTICK; // Mouse and Joystick.
+       class MOUSE;
 }
 
 class VM : public VM_TEMPLATE
@@ -417,6 +417,7 @@ protected:
        FMTOWNS::FLOPPY*         floppy;
        FMTOWNS::JOYSTICK*       joystick;
        FMTOWNS::JOYPAD*             joypad[2];
+       FMTOWNS::MOUSE*                  mouse;
        FMTOWNS::KEYBOARD*       keyboard;
        FMTOWNS::TIMER*          timer;
        FMTOWNS::TOWNS_VRAM*     vram;
index 5a6bb55..61daa40 100644 (file)
@@ -9,43 +9,28 @@
 */
 
 #include "./joystick.h"
+#include "./mouse.h"
 
 namespace FMTOWNS {
-#define EVENT_MOUSE_TIMEOUT 1
-#define EVENT_MOUSE_SAMPLING 2
        
 void JOYSTICK::reset()
 {
-       dx = dy = 0;
-       lx = ly = 0;
-       mouse_state = emu->get_mouse_buffer();
-       mouse_mask = 0x00;
-       mouse_type = -1; // Force update data.
-       mouse_phase = 0;
-       mouse_strobe = false;
-       mouse_data = 0x00;
+       mouse_mask = 0xff;
        update_config(); // Update MOUSE PORT.
-
 }
 
 void JOYSTICK::initialize()
 {
        rawdata = emu->get_joy_buffer();
-       mouse_state = emu->get_mouse_buffer();
        joydata[0] = joydata[1] = 0x00;
-       dx = dy = 0;
-       lx = ly = 0;
-       mouse_button = 0x00;
-       mouse_timeout_event = -1;
-       mouse_sampling_event = -1;
-       set_emulate_mouse();
-       mouse_type = config.mouse_type;
+
        // Force reset pads.
        connected_type[0] = 0xffffffff;
        connected_type[1] = 0xffffffff;
        stat_com[0] = stat_com[1] = false;
 
 //     register_frame_event(this);
+       register_frame_event(this);
 }
 
 void JOYSTICK::release()
@@ -54,20 +39,21 @@ void JOYSTICK::release()
        
 void JOYSTICK::event_pre_frame()
 {
-       event_callback(EVENT_MOUSE_SAMPLING, 0);
+       for(int i = 0; i < 2; i++) {
+               if(connected_type[i] == SIG_JOYPORT_TYPE_2BUTTONS) {
+                       write_signals(&outputs_query, 1 << i);
+               }
+       }
 }
-
+       
 void JOYSTICK::write_io8(uint32_t address, uint32_t data)
 {
        // ToDo: Mouse
        if(address == 0x04d6) {
-               if(emulate_mouse[0]) {
-                       update_strobe(((data & 0x10) != 0));
-               } else if(emulate_mouse[1]) {
-                       update_strobe(((data & 0x20) != 0));
+               if(mouse_mask != data) {
+                       mouse_mask = data;
+                       write_signals(&outputs_mask, data);
                }
-               mouse_mask = data;
-               write_signals(&outputs_mask, data);
        }
 }
 
@@ -79,74 +65,51 @@ uint32_t JOYSTICK::read_io8(uint32_t address)
        switch(address) {
        case 0x04d0:
        case 0x04d2:
-               if(emulate_mouse[port_num]) {
-                       uint8_t trig = (mouse_mask >> (port_num << 1)) & 0x03;
-                       uint8_t mask2 = (mouse_mask >> (port_num + 4)) & 0x01;
-                       uint8_t rval = 0x70;
-                       rval |= (update_mouse() & 0x0f);
-                       mouse_state = emu->get_mouse_buffer();
-                       if(mouse_state != NULL) {
-                               uint32_t stat = mouse_state[2];
-                               mouse_button = 0x00;
-                               if((stat & 0x01) == 0) mouse_button |= 0x10; // left
-                               if((stat & 0x02) == 0) mouse_button |= 0x20; // right
-                       }
-                       if((mask2 & 0x01) == 0) { // COM
-                               rval = rval & ~0x40;
-                       }
-                       if((trig & 0x02) == 0) { // TRIG2
-                               rval = rval & ~0x20;
-                       }
-                       if((trig & 0x01) == 0) { // TRIG1
-                               rval = rval & ~0x10;
-                       }                               
-                       if((mouse_button & 0x10) != 0) {
-                               rval &= ~0x10; // Button LEFT
-                       }
-                       if((mouse_button & 0x20) != 0) {
-                               rval &= ~0x20; // Button RIGHT
-                       }
-                       retval = rval;
-               } else {
-                       write_signals(&outputs_query, 1 << (port_num + 0));
-                       uint8_t trig = (mouse_mask >> (port_num << 1)) & 0x03;
+               {
+                       retval = 0xff;
                        uint8_t mask2 = (mouse_mask >> (port_num + 4)) & 0x01;
-                       retval = 0x7f;
                        if((mask2 & 0x01) == 0) { // COM
                                retval = retval & ~0x40;
                        }
-                       if((trig & 0x02) == 0) { // TRIG2
-                               retval = retval & ~0x20;
-                       }
-                       if((trig & 0x01) == 0) { // TRIG1
-                               retval = retval & ~0x10;
-                       }                               
-                       if(connected_type[port_num] == SIG_JOYPORT_TYPE_NULL) {
-                               // None Connected
-                               return retval;
-                       }
-                       // Trigger independents from direction keys.
-                       if((joydata[port_num] & LINE_JOYPORT_B) != 0) {
-                               retval = retval & ~0x20;
-                       }
-                       if((joydata[port_num] & LINE_JOYPORT_A) != 0) {
-                               retval = retval & ~0x10;
-                       }
-                       //if((mask & (0x10 << port_num)) == 0) {
-                       if((joydata[port_num] & LINE_JOYPORT_LEFT) != 0) { // LEFT
-                               retval = retval & ~0x04; // LEFT
-                       }
-                       if((joydata[port_num] & LINE_JOYPORT_RIGHT) != 0) { // RIGHT
-                               retval = retval & ~0x08; // RIGHT
-                       }                               
-                       if((joydata[port_num] & LINE_JOYPORT_UP) != 0) { // UP
-                               retval = retval & ~0x01; // FWD
-                       }
-                       if((joydata[port_num] & LINE_JOYPORT_DOWN) != 0) { // DOWN
-                               retval = retval & ~0x02; // BACK
+                       if(emulate_mouse[port_num]) {
+                               if(d_mouse != nullptr) {
+                                       retval &= d_mouse->read_signal(SIG_MOUSE_DATA);
+                               }
+                       } else {
+                               uint8_t trig = (mouse_mask >> (port_num << 1)) & 0x03;
+                               if(connected_type[port_num] == SIG_JOYPORT_TYPE_NULL) {
+                                       // None Connected
+                                       return retval;
+                               }
+                               // Trigger independents from direction keys.
+                               if((joydata[port_num] & LINE_JOYPORT_B) != 0) {
+                                       if((trig & 0x02) != 0) { // TRIG2
+                                               retval = retval & ~0x20;
+                                       }
+                               }
+                               if((joydata[port_num] & LINE_JOYPORT_A) != 0) {
+                                       if((trig & 0x01) != 0) { // TRIG1
+                                               retval = retval & ~0x10;
+                                       }
+                               }
+                               //if((mask & (0x10 << port_num)) == 0) {
+//                             if((mask2 & 0x01) == 0) { // COM
+                                       if((joydata[port_num] & LINE_JOYPORT_LEFT) != 0) { // LEFT
+                                               retval = retval & ~0x04; // LEFT
+                                       }
+                                       if((joydata[port_num] & LINE_JOYPORT_RIGHT) != 0) { // RIGHT
+                                               retval = retval & ~0x08; // RIGHT
+                                       }                               
+                                       if((joydata[port_num] & LINE_JOYPORT_UP) != 0) { // UP
+                                               retval = retval & ~0x01; // FWD
+                                       }
+                                       if((joydata[port_num] & LINE_JOYPORT_DOWN) != 0) { // DOWN
+                                               retval = retval & ~0x02; // BACK
+                                       }
+//                             }
                        }
+                       return retval;
                }
-               return retval;
                break;
        default:
                break;
@@ -154,37 +117,6 @@ uint32_t JOYSTICK::read_io8(uint32_t address)
        return 0xff;
 }
 
-void JOYSTICK::event_callback(int event_id, int err)
-{
-       switch(event_id) {
-       case EVENT_MOUSE_TIMEOUT:
-               mouse_phase = 0;
-               mouse_timeout_event = -1;
-               dx = dy = 0;
-               lx = ly = 0;
-               mouse_data = 0x00;
-               break;
-       case EVENT_MOUSE_SAMPLING:
-               if((emulate_mouse[0]) || (emulate_mouse[1])) {
-                       mouse_state = emu->get_mouse_buffer();
-                       if(mouse_state != NULL) {
-                               dx += mouse_state[0];
-                               dy += mouse_state[1];
-                               if(dx < -127) {
-                                       dx += 128;
-                               } else if(dx > 127) {
-                                       dx -= 128;
-                               }
-                               if(dy < -127) {
-                                       dy += 128;
-                               } else if(dy > 127) {
-                                       dy -= 128;
-                               }
-                       }
-               }
-               break;
-       }
-}
 
 void JOYSTICK::write_signal(int id, uint32_t data, uint32_t mask)
 {
@@ -228,11 +160,8 @@ void JOYSTICK::update_config(void)
        if(emulate_mouse[1]) {
                ntype[1] = SIG_JOYPORT_TYPE_MOUSE;
        }
-       if((emulate_mouse[0]) || (emulate_mouse[1])) {
-               force_register_event(this, EVENT_MOUSE_SAMPLING, 8.0e3, true, mouse_sampling_event);
-       } else {
-               clear_event(this, mouse_sampling_event);
-       }
+       
+       write_signals(&outputs_mask, mouse_mask);
        for(int i = 0; i < 2; i++) {
 //             if(connected_type[i] != ntype[i]) {
                        write_signals(&outputs_enable[i], 1 << ntype[i]);
@@ -247,7 +176,7 @@ void JOYSTICK::update_config(void)
                        break;
                }
        }
-       mouse_type = config.mouse_type;
+       
 }
 
 void JOYSTICK::set_emulate_mouse()
@@ -256,71 +185,28 @@ void JOYSTICK::set_emulate_mouse()
        case 1:
                emulate_mouse[0] = true;
                emulate_mouse[1] = false;
+               if(d_mouse != nullptr) {
+                       d_mouse->write_signal(SIG_MOUSE_ENABLE, 0xfffffffe, 0xffffffff);
+               }
                break;
        case 2:
                emulate_mouse[0] = false;
                emulate_mouse[1] = true;
+               if(d_mouse != nullptr) {
+                       d_mouse->write_signal(SIG_MOUSE_ENABLE, 0xffffffff, 0xffffffff);
+               }
                break;
        default:
                emulate_mouse[0] = false;
                emulate_mouse[1] = false;
-               break;
-       }
-}
-
-void JOYSTICK::update_strobe(bool flag)
-{
-       bool _bak = mouse_strobe;
-       mouse_strobe = flag;
-       if((_bak != mouse_strobe)/* && (flag)*/) {
-               if((mouse_phase == 0)) {
-                       // Sample data from MOUSE to registers.
-                       lx = -dx;
-                       ly = -dy;
-                       dx = 0;
-                       dy = 0;
-                       clear_event(this, mouse_timeout_event);
-                       register_event(this, EVENT_MOUSE_TIMEOUT, 600.0, false, &mouse_timeout_event);
-                       if(mouse_strobe) {
-                               mouse_phase = 1; // SYNC from MAME 0.225. 20201126 K.O
-                       }
+               if(d_mouse != nullptr) {
+                       d_mouse->write_signal(SIG_MOUSE_ENABLE, 0x00000000, 0xffffffff);
                }
-               mouse_phase++;
-//             if(mouse_phase > 5) {
-//                     mouse_phase = 0;
-//                     mouse_strobe = false;
-//                     clear_event(this, mouse_timeout_event);
-//             }
-       }
-}
-
-uint32_t JOYSTICK::update_mouse()
-{
-       switch(mouse_phase) {
-//     case 1: // SYNC
-//             mouse_data = 0x0f;
-//             break;
-       case 2: // X_HIGH
-               mouse_data = (lx >> 0) & 0x0f;
-               break;
-       case 3: // X_LOW
-               mouse_data = (lx >> 4) & 0x0f;
-               break;
-       case 4: // Y_HIGH
-               mouse_data = (ly >> 0) & 0x0f;
-               break;
-       case 5: // Y_LOW
-               mouse_data = (ly >> 4) & 0x0f;
-               break;
-       default:
-               mouse_data = 0x0f;
                break;
        }
-//     out_debug_log(_T("READ MOUSE DATA=%01X PHASE=%d STROBE=%d"), mouse_data, mouse_phase, (mouse_strobe) ? 1 : 0);
-       return mouse_data;
 }
 
-#define STATE_VERSION 5
+#define STATE_VERSION 6
 
 bool JOYSTICK::process_state(FILEIO *state_fio, bool loading)
 {
@@ -336,17 +222,6 @@ bool JOYSTICK::process_state(FILEIO *state_fio, bool loading)
        
        state_fio->StateArray(emulate_mouse, sizeof(emulate_mouse), 1);
        state_fio->StateArray(stat_com, sizeof(stat_com), 1);
-       state_fio->StateValue(dx);
-       state_fio->StateValue(dy);
-       state_fio->StateValue(lx);
-       state_fio->StateValue(ly);
-       state_fio->StateValue(mouse_button);
-       state_fio->StateValue(mouse_type);
-       state_fio->StateValue(mouse_strobe);
-       state_fio->StateValue(mouse_phase);
-       state_fio->StateValue(mouse_data);
-       state_fio->StateValue(mouse_timeout_event);
-       state_fio->StateValue(mouse_sampling_event);
 
        return true;
 }
index 6c0e7f7..611f3ef 100644 (file)
@@ -44,57 +44,45 @@ namespace FMTOWNS {
 class JOYSTICK : public DEVICE
 {
 private:
+       DEVICE* d_mouse;
+       
        outputs_t outputs_mask;
        outputs_t outputs_query;
        outputs_t outputs_enable[2];
+       
        bool emulate_mouse[2];
        uint32_t joydata[2];
        bool stat_com[2];
        
        const uint32_t *rawdata;
-       const int32_t *mouse_state;
-       int dx, dy;
-       int lx, ly;
-       uint32_t mouse_button;
-       int mouse_phase;
-       bool mouse_strobe;
-       uint8_t mouse_data;
-       
-       int mouse_timeout_event;
-       int mouse_sampling_event;
-       int mouse_type;
+
        uint8_t mouse_mask;
        uint32_t connected_type[2];
        
        void set_emulate_mouse();
-       virtual void update_strobe(bool flag);
-       uint32_t update_mouse();
-
 public:
        JOYSTICK(VM_TEMPLATE* parent_vm, EMU_TEMPLATE* parent_emu) : DEVICE(parent_vm, parent_emu)
        {
-               mouse_timeout_event = -1;
-               mouse_sampling_event = -1;
+               d_mouse = NULL;
                initialize_output_signals(&outputs_query);
                initialize_output_signals(&outputs_mask);
                initialize_output_signals(&outputs_enable[0]);
                initialize_output_signals(&outputs_enable[1]);
                connected_type[0] = SIG_JOYPORT_CH0 | SIG_JOYPORT_TYPE_NULL;
                connected_type[1] = SIG_JOYPORT_CH1 | SIG_JOYPORT_TYPE_NULL;
-               set_device_name(_T("FM-Towns PAD Port and MOUSE (JIS)"));
+               set_device_name(_T("FM-Towns PAD Port"));
        }
        ~JOYSTICK() {}
        
        // common functions
        void initialize(void);
-       void event_pre_frame(void);
        void release();
        void reset();
+       void event_pre_frame();
        
        void __FASTCALL write_io8(uint32_t addr, uint32_t data);
        uint32_t __FASTCALL read_io8(uint32_t addr);
        void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask);
-       void __FASTCALL event_callback(int event_id, int err);
        void update_config();
        
        bool process_state(FILEIO* state_fio, bool loading);
@@ -116,6 +104,13 @@ public:
        {
                register_output_signal(&outputs_query, dev, id, mask);
        }
+       void set_context_mouse(DEVICE* dev, int id, uint32_t mask)
+       {
+               if((d_mouse == nullptr) && (dev != nullptr)) {
+                       d_mouse = dev;
+                       register_output_signal(&outputs_mask, dev, id, mask);
+               }
+       }
 
                        
 };
diff --git a/source/src/vm/fmtowns/mouse.cpp b/source/src/vm/fmtowns/mouse.cpp
new file mode 100644 (file)
index 0000000..8a34d18
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+       FUJITSU FM Towns Emulator 'eFMTowns'
+
+       Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
+       Date   : 2021.06.16 -
+    History : 2021.06.16 Initial
+       [ Towns Mouse]
+
+*/
+
+#include "./mouse.h"
+
+namespace FMTOWNS {
+
+#define EVENT_MOUSE_TIMEOUT            1
+#define EVENT_MOUSE_SAMPLING   2
+#define EVENT_MOUSE_RESET              3
+       
+void MOUSE::initialize()
+{
+       phase = 0;
+       strobe = false;
+       mouse_state = NULL;
+       mouse_connected = false;
+       port_num = 0;
+       
+       dx = dy = 0;
+       lx = ly = 0;
+       event_timeout = -1;
+       event_sampling = -1;
+
+       register_frame_event(this);
+}
+
+void MOUSE::release()
+{
+}
+
+void MOUSE::event_pre_frame()
+{
+       event_callback(EVENT_MOUSE_SAMPLING, 0);
+}
+       
+void MOUSE::reset()
+{
+       // Values around mouse aren't initialized on reset.
+//     mouse_state = emu->get_mouse_buffer();
+//     update_config(); // Update MOUSE PORT.
+}
+
+void MOUSE::update_strobe()
+{
+       bool _bak = strobe;
+       uint8_t _mask = ((port_num & 1) != 0) ? 0x20 : 0x10;
+       strobe = ((mouse_mask & _mask) != 0) ? true : false;
+       if((_bak != strobe)/* && (flag)*/) {
+               if(phase == 0) {
+                       if(strobe) {
+                               // Sample data from MOUSE to registers.
+                               lx = -dx;
+                               ly = -dy;
+                               dx = 0;
+                               dy = 0;
+                               // From FM Towns Technical book, Sec.1-7, P.241.
+                               // (Ta + Tj * 3 + Ti) <= 920.0uS 
+                               //force_register_event(this, EVENT_MOUSE_TIMEOUT, 920.0, false, event_timeout);
+                               force_register_event(this, EVENT_MOUSE_TIMEOUT, 2000.0, false, event_timeout);
+                               phase = 2; // SYNC from MAME 0.225. 20201126 K.O
+                       }
+                       return;
+               }
+               phase++;
+       }
+}
+
+
+uint32_t MOUSE::update_mouse()
+{
+       uint32_t mouse_data = 0x0f;
+       switch(phase) {
+//     case 1: // SYNC
+//             mouse_data = 0x0f;
+//             break;
+       case 2: // X_HIGH
+               mouse_data = (lx >> 0) & 0x0f;
+               break;
+       case 3: // X_LOW
+               mouse_data = (lx >> 4) & 0x0f;
+               break;
+       case 4: // Y_HIGH
+               mouse_data = (ly >> 0) & 0x0f;
+               break;
+       case 5: // Y_LOW
+               mouse_data = (ly >> 4) & 0x0f;
+               // From FM Towns Technical book, Sec.1-7, P.241.
+               // Ti(min)
+               force_register_event(this, EVENT_MOUSE_TIMEOUT, 150.0, false, event_timeout);
+               break;
+       }
+
+//     out_debug_log(_T("READ MOUSE DATA=%01X PHASE=%d STROBE=%d"), mouse_data, mouse_phase, (mouse_strobe) ? 1 : 0);
+       return mouse_data;
+}
+
+uint32_t MOUSE::read_signal(int ch)
+{
+       switch(ch) {
+       case SIG_MOUSE_DATA:
+               if(mouse_connected) {
+                       uint8_t trig = (mouse_mask >> (port_num << 1)) & 0x03;
+                       uint8_t rval = 0xf0;
+                       
+                       rval |= (update_mouse() & 0x0f);
+                       mouse_state = emu->get_mouse_buffer();
+                       if(mouse_state != NULL) {
+                               uint32_t stat = mouse_state[2];
+                               if((trig & 0x01) != 0) {
+                                       if((stat & 0x01) == 0) {
+                                               rval &= ~0x10; // Button LEFT
+                                       }
+                               }
+                               if((trig & 0x02) != 0) {
+                                       if((stat & 0x02) == 0) {
+                                               rval &= ~0x20; // Button LEFT
+                                       }
+                               }
+                       }
+                       if(!(strobe)) { // COM
+                               rval = rval & ~0x40;
+                       }
+                       return rval;
+               }
+               break;
+       case SIG_MOUSE_ENABLE:
+               return ((mouse_connected) ? 0xffffffff : 0);
+               break;
+       case SIG_MOUSE_NUM:
+               return port_num & 1;
+               break;
+       }
+       return 0xffffffff;
+}
+       
+void MOUSE::write_signal(int id, uint32_t data, uint32_t mask)
+{
+       switch(id) {
+       case SIG_MOUSE_ENABLE:
+               {
+                       bool _bak = mouse_connected;
+                       mouse_connected = (((data & mask) & 0xfffffffe) != 0) ? true : false;
+                       port_num = (data & mask) & 0x01;
+                       if(_bak != mouse_connected) {
+                               if(!(_bak)) { // off -> on
+                                       phase = 0;
+                                       dx = dy = 0;
+                                       lx = ly = 0;
+                                       strobe = false;
+                                       clear_event(this, event_timeout);
+//                                     force_register_event(this, EVENT_MOUSE_SAMPLING,
+//                                                                              4.0e3, true, event_sampling);
+                               } else { // on -> off
+                                       clear_event(this, event_timeout);
+//                                     clear_event(this, event_sampling);
+                               }
+                       }
+               }
+               break;
+       case SIG_MOUSE_STROBE:
+               mouse_mask = data;
+               if(mouse_connected) {
+                       update_strobe();
+               }
+               break;
+       }
+}
+
+void MOUSE::event_callback(int event_id, int err)
+{
+       switch(event_id) {
+       case EVENT_MOUSE_RESET:
+               event_timeout = -1;
+               phase = 0;
+               break;
+       case EVENT_MOUSE_TIMEOUT:
+               phase = 0;
+               event_timeout = -1;
+               dx = dy = 0;
+               lx = ly = 0;
+               break;
+       case EVENT_MOUSE_SAMPLING:
+               mouse_state = emu->get_mouse_buffer();
+               if(mouse_state != NULL) {
+                       dx += mouse_state[0];
+                       dy += mouse_state[1];
+                       if(dx < -127) {
+                               dx += 128;
+                       } else if(dx > 127) {
+                               dx -= 128;
+                       }
+                       if(dy < -127) {
+                               dy += 128;
+                       } else if(dy > 127) {
+                               dy -= 128;
+                       }
+               }
+               break;
+       }
+}
+       
+#define STATE_VERSION 1
+
+bool MOUSE::process_state(FILEIO *state_fio, bool loading)
+{
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+       
+       state_fio->StateValue(mouse_connected);
+       state_fio->StateValue(port_num);
+       
+       state_fio->StateValue(phase);
+       state_fio->StateValue(strobe);
+       state_fio->StateValue(dx);
+       state_fio->StateValue(dy);
+       state_fio->StateValue(lx);
+       state_fio->StateValue(ly);
+       
+       state_fio->StateValue(mouse_mask);
+       state_fio->StateValue(event_timeout);
+       state_fio->StateValue(event_sampling);
+
+       return true;
+}
+}
diff --git a/source/src/vm/fmtowns/mouse.h b/source/src/vm/fmtowns/mouse.h
new file mode 100644 (file)
index 0000000..b24f9fb
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+       FUJITSU FM Towns Emulator 'eFMTowns'
+
+       Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
+       Date   : 2021.06.16 -
+    History : 2020.06.16 Initial.
+       [ Towns Mouse]
+
+*/
+
+#pragma once
+
+#include "../device.h"
+
+#define SIG_MOUSE_ENABLE       1
+#define SIG_MOUSE_STROBE       2
+#define SIG_MOUSE_NUM          3
+#define SIG_MOUSE_DATA         4
+
+namespace FMTOWNS {
+       
+class MOUSE : public DEVICE
+{
+private:
+       const int32_t* mouse_state;
+       
+       int phase;
+       bool strobe;
+       int dx, dy;
+       int lx, ly;
+       
+       bool mouse_connected;
+       int port_num;
+
+       uint8_t mouse_mask;
+       
+       int event_timeout;
+       int event_sampling;
+
+       void update_strobe();
+       uint32_t update_mouse();
+       
+public:
+       MOUSE(VM_TEMPLATE* parent_vm, EMU_TEMPLATE* parent_emu) : DEVICE(parent_vm, parent_emu)
+       {
+               set_device_name(_T("FM-Towns MOUSE"));
+       }
+       ~MOUSE() {}
+       
+       void initialize();
+       void release();
+
+       void reset();
+       void __FASTCALL event_callback(int event_id, int err);
+       void event_pre_frame();
+       
+       uint32_t __FASTCALL read_signal(int ch);
+       void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask);
+
+       bool process_state(FILEIO* state_fio, bool loading);
+};
+
+}
+