RG300
移植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)