逆向工程 - FCEUX - 支援振動功能 - 移植FCEUX(支援振動)



目前司徒先移植FCEUX模擬器,讓其可以支援振動功能,思路相當簡單,只要在模擬器開始執行時,Remap Memory並且初始化馬達的狀態,接著判斷是否有對0x4009 CPU Register做設定,藉此控制馬達的狀態,如下程式:

diff -Naur old/src/drivers/dingux-sdl/dingoo.cpp new/src/drivers/dingux-sdl/dingoo.cpp
--- old/src/drivers/dingux-sdl/dingoo.cpp  2019-05-07 16:32:59.613981947 +0800
+++ new/src/drivers/dingux-sdl/dingoo.cpp  2019-07-21 14:36:09.526862599 +0800
@@ -3,6 +3,7 @@
 #include <signal.h>
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
 #include <string.h>
 #include <strings.h>
 #include <errno.h>
@@ -12,6 +13,10 @@
 #include <fstream>
 #include <limits.h>
 #include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
 
 #include "main.h"
 #include "throttle.h"
@@ -533,6 +538,8 @@
 #ifdef WIN32
 #undef main
 #endif
+int motordev=-1;
+volatile unsigned char* motorreg=NULL;
 int main(int argc, char *argv[]) {
 
   int error;
@@ -552,12 +559,19 @@
 
   // Initialize the configuration system
   g_config = InitConfig();
-
   if (!g_config) {
     SDL_Quit();
     return -1;
   }
 
+  motordev = open("/dev/mem", O_RDWR);
+  if(motordev < 0){ 
+    printf("failed to open /dev/mem\n");
+    return -1; 
+  }
+  motorreg  = (volatile unsigned char*)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, motordev, 0x10010000);
+  printf("mem ptr: 0x%x\n", motorreg);
+
   // Initialize the fceu320 gui
   FCEUGUI_Init(NULL);
 
@@ -812,10 +826,16 @@
   DoFun(frameskip);
 
   CloseGame();
+  
+  if(motordev > 0){
+    motorreg[0x418]|= 4;
+    munmap((void*)motorreg, 4096);
+    close(motordev);
+  }
 
   // exit the infrastructure
   FCEUI_Kill();
   return 0;
 }
  
 static int save_screenshot() {
diff -Naur old/src/drivers/dingux-sdl/input.cpp new/src/drivers/dingux-sdl/input.cpp
--- old/src/drivers/dingux-sdl/input.cpp  2019-05-07 16:32:59.613981947 +0800
+++ new/src/drivers/dingux-sdl/input.cpp  2019-07-21 14:34:09.506770980 +0800
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <sys/ioctl.h>
 #include <string.h>
 #include <stdio.h>
 
@@ -56,6 +57,7 @@
 static int InputType[NUM_INPUT_DEVICES];
 static int cspec = 0;
 
+extern volatile unsigned char* motorreg;
 extern int gametype;
 
 static bool MenuRequested = false;
@@ -651,11 +653,13 @@
             }
             break;
         case SDL_KEYDOWN:
-            if (event.key.keysym.sym == DINGOO_MENU)
+            if (event.key.keysym.sym == DINGOO_MENU) {
                 // Because a KEYUP is sent straight after the KEYDOWN for the
                 // Power switch, SDL_GetKeyState will not ever see this.
                 // Keep a record of it.
                 MenuRequested = true;
+                motorreg[0x418]|= 4;
+             }
             break;
         default:
             // do nothing
diff -Naur old/src/x6502.cpp new/src/x6502.cpp
--- old/src/x6502.cpp  2019-05-07 16:32:59.657981754 +0800
+++ new/src/x6502.cpp  2019-07-21 14:32:16.186684476 +0800
@@ -17,7 +17,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
-
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include "types.h"
 #include "x6502.h"
 #include "fceu.h"
@@ -325,10 +327,21 @@
 #define LD_IX(op)  {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
 #define LD_IY(op)  {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
 
+extern volatile unsigned char* motorreg;
+void do_rumble(unsigned char val)
+{
+  if(val){
+    motorreg[0x414]|= 4;
+  }
+  else{
+    motorreg[0x418]|= 4;
+  }
+}
+
 #define ST_ZP(r)  {uint8 A; GetZP(A); WrRAM(A,r); break;}
 #define ST_ZPX(r)  {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
 #define ST_ZPY(r)  {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
-#define ST_AB(r)  {unsigned int A; GetAB(A); WrMem(A,r); break;}
+#define ST_AB(r)  {unsigned int A; GetAB(A); if(A == 0x4009){do_rumble(r); }else{WrMem(A,r);}  break;}
 #define ST_ABI(reg,r)  {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
 #define ST_ABX(r)  ST_ABI(_X,r)
 #define ST_ABY(r)  ST_ABI(_Y,r)