参考博客:v3S移植NES游戏
参考博客二:V3S移植nes游戏模拟器(附带游戏合集)
下载启动器源码:https://github.com/nejidev/arm-NES-linux
下载游戏合集:链接:https://pan.baidu.com/s/16hIWwYQQEX9aOBDG1dVa0A 提取码:asdf
步骤是这样的:
1、Ubuntu上进行交叉编译出启动器:InfoNES,USB手柄xxx.ko
2、下载并解压出游戏合集(需要改名字xxxx.nes)
3、以上都拷贝到目标板上去,安装xxx.ko
4、运行:./InfoNES xxx.nes
这里要基于自己的buildroot制作根文件系统的文件夹
下载启动器源码:https://github.com/nejidev/arm-NES-linux
$ unzip arm-NES-linux-master.zip
1、在linux目录下新建一个work文件夹
$ mkdir /linux/work
2、修改linux目录下的Makefile文件:vim Makefile
全部内容
CC = /home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/host/bin/arm-linux-gnueabihf-gcc
TARBALL = InfoNES08J
# InfoNES
.CFILES = ./../K6502.cpp \
./../InfoNES.cpp \
./../InfoNES_Mapper.cpp \
./../InfoNES_pAPU.cpp \
./InfoNES_System_Linux.cpp joypad_input.cpp
.OFILES = $(.CFILES:.cpp=.o)
CCFLAGS = -O2 -fsigned-char -I/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/include
LDFILGS = -lstdc++ -L/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/lib # gcc3.x.x
all: InfoNES
InfoNES: $(.OFILES)
$(CC) $(INCLUDES) -o $@ $(.OFILES) $(LDFILGS) -lm -lz -lpthread -lasound
.cpp.o:
$(CC) $(INCLUDES) -c $(CCFLAGS) $*.cpp -o $@
clean:
rm -f $(.OFILES) ../*~ ../*/*~ core
cleanall:
rm -f $(.OFILES) ../*~ ../*/*~ core InfoNES
release: clean all
tar:
( cd ..; \
tar cvf $(TARBALL).tar ./*; \
gzip $(TARBALL).tar \
)
install:
install ./InfoNES /home/liefyuan/Liefyuan/Nes/arm-nes-linux/linux/work
1.在CCFLAGS 后面增加alsa的头文件目录(该目录在bulidroot/output那里例如)
-I/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/include
2.在LDFILGS 增加alsa的lib文件目录(和上面一样)
-L/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/lib
3.修改最上面的CC为bulidroot里面的gcc
/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/host/bin/arm-linux-gnueabihf-gcc
4.更改最后的install那里为前面建立的work目录
install ./InfoNES /home/liefyuan/Liefyuan/Nes/arm-nes-linux/linux/work
5.修改linux/InfoNES_System_Linux.cpp文件中的static int lcd_fb_display_px函数(调整spi屏幕的颜色):
static int lcd_fb_display_px(WORD color, int x, int y)
{
unsigned char *pen8;
unsigned short *pen16;
pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
pen16 = (unsigned short *)pen8;
*pen16 = color;
return 0;
}
修改为:
static int lcd_fb_display_px(WORD color, int x, int y)
{
unsigned char *pen8;
unsigned short *pen16;
unsigned char r, g, b;
r = ((color >> 10) & 0x1f);
g = ((color >> 5) & 0x3f);
b = (color & 0x1f);
color = r<<11|g<<6|b;
pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
pen16 = (unsigned short *)pen8;
*pen16 = color;
return 0;
}
make
make install
生成的文件在work文件夹下:
liefyuan@ubuntu:~/Liefyuan/Nes/arm-nes-linux/linux/work$ ls
InfoNES
然后把这个InfoNES拷贝到开板上就可以了。
打开声音:
tinymix set 1 63
tinymix set 2 1
打开游戏
./InfoNES hdl-chinese.nes
来源:https://whycan.com/t_5139.html#p52283
linux kernel 里面编译:
linux menuconfig
> Device Drivers > Input device support
<*> Joystick interface
[x] Joysticks/Gamepads --->
> Device Drivers > HID support > Special HID drivers
<*> DragonRise Inc. game controller
重新烧录内核后,插上游戏手柄:/dev/input
下出现了js0
设备节点
# ls /dev/input
event0 event1 js0
设备节点出来了,但是游戏手柄按键按着没有反应!
写一个用户空间代码测试一下手柄键值:
#include
#include
#include
typedef unsigned int __u32;
typedef short __s16;
typedef unsigned char __u8;
struct js_event {
__u32 time; /* event timestamp in milliseconds */
__s16 value; /* value */
__u8 type; /* event type */
__u8 number; /* axis/button number */
};
#define JS_EVENT_BUTTON 0x01 /* button pressed/released */
#define JS_EVENT_AXIS 0x02 /* joystick moved */
#define JS_EVENT_INIT 0x80 /* initial state of device */
int main() {
int fd = open("/dev/input/js0", O_RDONLY);
struct js_event e;
while(1) {
read(fd, &e, sizeof(e));
int type = JS_EVENT_BUTTON | JS_EVENT_INIT;
switch(e.type) {
case JS_EVENT_AXIS:
printf("axis number: %d, value: %d, time: %d\n", e.number, e.value, e.time);
break;
case JS_EVENT_BUTTON:
printf("btn: number: %d, value: %d, time: %d\n", e.number, e.value, e.time);
break;
}
}
close(fd);
return 0;
}
编译:
arm-linux-gnueabihf-gcc test.c -o joytest
拷贝到开发板上:
sudo cp joytest /media/liefyuan/rootfs/opt/
游戏手柄按键 | 读出的键值 |
---|---|
L1 | btn: number: 4, value: 1, time: 198640 btn: number: 4, value: 0, time: 198850 |
L2 | btn: number: 6, value: 1, time: 221840 btn: number: 6, value: 0, time: 222000 |
R1 | btn: number: 5, value: 1, time: 255670 btn: number: 5, value: 0, time: 255840 |
R2 | btn: number: 7, value: 1, time: 257390 btn: number: 7, value: 0, time: 257470 |
左方向键上 | axis number: 1, value: -32767, time: 51680 axis number: 1, value: 0, time: 51840 |
左方向键下 | axis number: 1, value: 32767, time: 99770 axis number: 1, value: 0, time: 99900 |
左方向键左 | axis number: 0, value: -32767, time: 132060 axis number: 0, value: 0, time: 132150 |
左方向键右 | axis number: 0, value: 32767, time: 156420 axis number: 0, value: 0, time: 156510 |
SELECT键 | btn: number: 8, value: 1, time: 312440 btn: number: 8, value: 0, time: 312600 |
START键 | btn: number: 9, value: 1, time: 313560 btn: number: 9, value: 0, time: 313730 |
右边数字键1 | btn: number: 0, value: 1, time: 460600 btn: number: 0, value: 0, time: 460770 |
右边数字键2 | btn: number: 1, value: 1, time: 461560 btn: number: 1, value: 0, time: 461730 |
右边数字键3 | btn: number: 2, value: 1, time: 463040 btn: number: 2, value: 0, time: 463200 |
右边数字键4 | btn: number: 3, value: 1, time: 463790 btn: number: 3, value: 0, time: 463920 |
查看一下它的写法:
/linux/joypad_input.cpp
...
static int USBjoypadGet(void)
{
/**
* FC手柄 bit 键位对应关系 真实手柄中有一个定时器,处理 连A 连B
* 0 1 2 3 4 5 6 7
* A B Select Start Up Down Left Right
*/
//因为 USB 手柄每次只能读到一位键值 所以要有静态变量保存上一次的值
static unsigned char joypad = 0;
struct js_event e;
if(0 < read (USBjoypad_fd, &e, sizeof(e)))
{
if(0x2 == e.type)
{
/*
上:
value:0x8001 type:0x2 number:0x5
value:0x0 type:0x2 number:0x5
*/
if(0x8001 == e.value && 0x5 == e.number)
{
joypad |= 1<<4;
}
/*下:
value:0x7fff type:0x2 number:0x5
value:0x0 type:0x2 number:0x5
*/
if(0x7fff == e.value && 0x5 == e.number)
{
joypad |= 1<<5;
}
//松开
if(0x0 == e.value && 0x5 == e.number)
{
joypad &= ~(1<<4 | 1<<5);
}
/*左:
value:0x8001 type:0x2 number:0x4
value:0x0 type:0x2 number:0x4
*/
if(0x8001 == e.value && 0x4 == e.number)
{
joypad |= 1<<6;
}
/*右:
value:0x7fff type:0x2 number:0x4
value:0x0 type:0x2 number:0x4
*/
if(0x7fff == e.value && 0x4 == e.number)
{
joypad |= 1<<7;
}
//松开
if(0x0 == e.value && 0x4 == e.number)
{
joypad &= ~(1<<6 | 1<<7);
}
}
if(0x1 == e.type)
{
/*选择:
value:0x1 type:0x1 number:0xa
value:0x0 type:0x1 number:0xa
*/
if(0x1 == e.value && 0xa == e.number)
{
joypad |= 1<<2;
}
if(0x0 == e.value && 0xa == e.number)
{
joypad &= ~(1<<2);
}
/*开始:
value:0x1 type:0x1 number:0xb
value:0x0 type:0x1 number:0xb
*/
if(0x1 == e.value && 0xb == e.number)
{
joypad |= 1<<3;
}
if(0x0 == e.value && 0xb == e.number)
{
joypad &= ~(1<<3);
}
/*A
value:0x1 type:0x1 number:0x0
value:0x0 type:0x1 number:0x0
*/
if(0x1 == e.value && 0x0 == e.number)
{
joypad |= 1<<0;
}
if(0x0 == e.value && 0x0 == e.number)
{
joypad &= ~(1<<0);
}
/*B
value:0x1 type:0x1 number:0x1
value:0x0 type:0x1 number:0x1
*/
if(0x1 == e.value && 0x1 == e.number)
{
joypad |= 1<<1;
}
if(0x0 == e.value && 0x1 == e.number)
{
joypad &= ~(1<<1);
}
/*X
value:0x1 type:0x1 number:0x3
value:0x0 type:0x1 number:0x3
*/
if(0x1 == e.value && 0x3 == e.number)
{
joypad |= 1<<0;
}
if(0x0 == e.value && 0x3 == e.number)
{
joypad &= ~(1<<0);
}
/*Y
value:0x1 type:0x1 number:0x4
value:0x0 type:0x1 number:0x4
*/
if(0x1 == e.value && 0x4 == e.number)
{
joypad |= 1<<1;
}
if(0x0 == e.value && 0x4 == e.number)
{
joypad &= ~(1<<1);
}
}
return joypad;
}
return -1;
}
调试了一下:
# ./InfoNES Tankwar.nes
/dev/input/js0 dev node ok!
fb width:800 height:480
type: 129, axis number: 0, value: 0, time: -214620
type: 129, axis number: 1, value: 0, time: -214620
type: 129, axis number: 2, value: 0, time: -214620
type: 129, axis number: 3, value: 0, time: -214620
type: 129, axis number: 4, value: 0, time: -214620
type: 129, axis number: 5, value: 0, time: -214620
type: 129, axis number: 6, value: 0, time: -214620
type: 129, axis number: 7, value: 0, time: -214620
type: 129, axis number: 8, value: 0, time: -214620
type: 129, axis number: 9, value: 0, time: -214620
type: 129, axis number: 10, value: 0, time: -214620
type: 129, axis number: 11, value: 0, time: -214620
type: 130, axis number: 0, value: 0, time: -214620
type: 130, axis number: 1, value: 0, time: -214620
type: 130, axis number: 2, value: 0, time: -214620
type: 130, axis number: 3, value: 0, time: -214620
type: 130, axis number: 4, value: 0, time: -214620
type: 130, axis number: 5, value: 0, time: -214620
type: 2, axis number: 1, value: 32767, time: -209470
type: 2, axis number: 1, value: 0, time: -209300
type: 2, axis number: 1, value: 32767, time: -209090
type: 2, axis number: 1, value: 0, time: -208960
type: 2, axis number: 1, value: 32767, time: -208840
type: 2, axis number: 1, value: 0, time: -208710
type: 2, axis number: 1, value: 32769, time: -208380
type: 2, axis number: 1, value: 0, time: -208210
type: 1, axis number: 7, value: 1, time: -206910
type: 1, axis number: 7, value: 0, time: -206780
type: 1, axis number: 7, value: 1, time: -206610
type: 1, axis number: 7, value: 0, time: -206570
type: 1, axis number: 7, value: 1, time: -206400
type: 1, axis number: 7, value: 0, time: -206320
type: 1, axis number: 6, value: 1, time: -206280
type: 1, axis number: 6, value: 0, time: -206070
type: 1, axis number: 6, value: 1, time: -205990
type: 1, axis number: 6, value: 0, time: -205860
type: 1, axis number: 4, value: 1, time: -205610
type: 1, axis number: 4, value: 0, time: -205480
type: 1, axis number: 4, value: 1, time: -205350
type: 1, axis number: 4, value: 0, time: -205230
按键是可以获得键值的!!
看了一下逻辑,是键值没有对上
改一下:/linux/joypad_input.cpp文件的这个函数就可以适配我的游戏手柄了
static int USBjoypadGet(void)
{
/**
* FC joypad bitmap 1Byte==8bits
* 0 1 2 3 4 5 6 7
* A B Select Start Up Down Left Right
*/
//USB joypad every time can read 1 bit, so,need static var save last time value
static unsigned char joypad = 0;
struct js_event e;
if(0 < read (USBjoypad_fd, &e, sizeof(e)))
{
//printf("type: %d, axis number: %d, value: %d, time: %d\n", e.type, e.number, e.value, e.time);
if(0x2 == e.type) // axis
{
/*
up:
value:0x8001 type:0x2 number:0x1
value:0x0 type:0x2 number:0x1
*/
if(0x8001 == e.value && 0x1 == e.number)
{
joypad |= 1<<4;
}
/*down
value:0x7fff type:0x2 number:0x1
value:0x0 type:0x2 number:0x1
*/
if(0x7fff == e.value && 0x1 == e.number)
{
joypad |= 1<<5;
}
//release
if(0x0 == e.value && 0x1 == e.number)
{
joypad &= ~(1<<4 | 1<<5);
}
/*left
value:0x8001 type:0x2 number:0x0
value:0x0 type:0x2 number:0x0
*/
if(0x8001 == e.value && 0x0 == e.number)
{
joypad |= 1<<6;
}
/*right
value:0x7fff type:0x2 number:0x0
value:0x0 type:0x2 number:0x0
*/
if(0x7fff == e.value && 0x0 == e.number)
{
joypad |= 1<<7;
}
//release
if(0x0 == e.value && 0x0 == e.number)
{
joypad &= ~(1<<6 | 1<<7);
}
}
if(0x1 == e.type) // btn
{
/*select
value:0x1 type:0x1 number:0x8
value:0x0 type:0x1 number:0x8
*/
if(0x1 == e.value && 0x8 == e.number)
{
joypad |= 1<<2;
}
if(0x0 == e.value && 0x8 == e.number)
{
joypad &= ~(1<<2);
}
/*start
value:0x1 type:0x1 number:0x9
value:0x0 type:0x1 number:0x9
*/
if(0x1 == e.value && 0x9 == e.number)
{
joypad |= 1<<3;
}
if(0x0 == e.value && 0x9 == e.number)
{
joypad &= ~(1<<3);
}
/*A
value:0x1 type:0x1 number:0x0
value:0x0 type:0x1 number:0x0
*/
if(0x1 == e.value && 0x0 == e.number)
{
joypad |= 1<<0;
}
if(0x0 == e.value && 0x0 == e.number)
{
joypad &= ~(1<<0);
}
/*B
value:0x1 type:0x1 number:0x1
value:0x0 type:0x1 number:0x1
*/
if(0x1 == e.value && 0x1 == e.number)
{
joypad |= 1<<1;
}
if(0x0 == e.value && 0x1 == e.number)
{
joypad &= ~(1<<1);
}
/*X
value:0x1 type:0x1 number:0x2
value:0x0 type:0x1 number:0x2
*/
if(0x1 == e.value && 0x2 == e.number)
{
joypad |= 1<<0;
}
if(0x0 == e.value && 0x2 == e.number)
{
joypad &= ~(1<<0);
}
/*Y
value:0x1 type:0x1 number:0x3
value:0x0 type:0x1 number:0x3
*/
if(0x1 == e.value && 0x3 == e.number)
{
joypad |= 1<<1;
}
if(0x0 == e.value && 0x3 == e.number)
{
joypad &= ~(1<<1);
}
}
//printf("joypad-value: 0x%02x\n", joypad);
return joypad;
}
return -1;
}
Nice,手柄可以了!完成!