nes 红白机模拟器 第1篇
对比了很多种,开源的 NES 模拟器 VirtuaNES , nestopia , FakeNES , FCEUX , InfoNES , LiteNES
最后决定使用 LiteNES 进行移值,它是由 mynes 移值而来。LiteNES 对 mynes 代码进行整理兼容了 C99 标准,编译时无警告。
https://github.com/NJUOS/LiteNES
https://github.com/yaglo/mynes
LiteNES , mynes 基于 Allegro ,Allegro 是一种提供底层画图,输入,定时器等支持的库。
LiteNES 全部抽象提取代码到 一个 hal.c 文件里面,修改移值十分方便。下面是修改后的样子,替换这个文件。
在修改下 Makefile 中的 gcc 改为 arm-linux-gcc 编译 即可在板子上出现 Game 画面了(经过测试,发现支持的游戏不多,有的载加不出来)
NES 移值第1篇,仅能出现画面。以后会更新添加声音,多线程,输入等。现在只为能显示出画面。
hal.c :
/*
This file present all abstraction needed to port LiteNES.
(The current working implementation uses allegro library.) To port this project, replace the following functions by your own:
1) nes_hal_init()
Do essential initialization work, including starting a FPS HZ timer. 2) nes_set_bg_color(c)
Set the back ground color to be the NES internal color code c. 3) nes_flush_buf(*buf)
Flush the entire pixel buf's data to frame buffer. 4) nes_flip_display()
Fill the screen with previously set background color, and
display all contents in the frame buffer. 5) wait_for_frame()
Implement it to make the following code is executed FPS times a second:
while (1) {
wait_for_frame();
do_something();
} 6) int nes_key_state(int b)
Query button b's state (1 to be pressed, otherwise 0).
The correspondence of b and the buttons:
0 - Power
1 - A
2 - B
3 - SELECT
4 - START
5 - UP
6 - DOWN
7 - LEFT
8 - RIGHT
*/
#include "hal.h"
#include "fce.h"
#include "common.h" /**
* allegro API 不明白的看文档
* https://www.allegro.cc/manual/5/index.html
*/
/* lcd 操作相关 头文件 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h> static int fb_fd;
static unsigned char *fb_mem;
static int px_width;
static int line_width;
static int screen_width;
static struct fb_var_screeninfo var; static int lcd_fb_display_px(int color, int x, int y)
{
unsigned char *pen8;
unsigned short *pen16; unsigned char r,g,b; pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
pen16 = (unsigned short *)pen8; //合并为 565 格式 16bbp
r = (color>>) & 0xff;
g = (color>>) & 0xff;
b = (color>>) & 0xff;
*pen16 = (r>>)<< | (g>>)<< | (b>>); return ;
} //调色板转16进行32位颜色
static int pal2color(pal pal)
{
int color = ;
color = pal.r << | pal.g << | pal.b;
return color;
} static int lcd_fb_init()
{
//如果使用 mmap 打开方式 必须是 读写方式
fb_fd = open("/dev/fb0", O_RDWR);
if(- == fb_fd)
{
printf("cat't open /dev/fb0 \n");
return -;
}
//获取屏幕参数
if(- == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var))
{
close(fb_fd);
printf("cat't ioctl /dev/fb0 \n");
return -;
}
//计算参数
px_width = var.bits_per_pixel / ;
line_width = var.xres * px_width;
screen_width = var.yres * line_width; fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, );
if(fb_mem == (void *)-)
{
close(fb_fd);
printf("cat't mmap /dev/fb0 \n");
return -;
}
//清屏
memset(fb_mem, , screen_width);
return ;
} /* Wait until next allegro timer event is fired. */
void wait_for_frame()
{
//休眠 FPS = 60 * 1000 毫秒
usleep(/FPS*);
} /* Set background color. RGB value of c is defined in fce.h */
void nes_set_bg_color(int c)
{
//画背景颜色
int i,j;
for(i=; i<SCREEN_WIDTH; i++)
{
for(j=; j<SCREEN_HEIGHT; j++)
{
lcd_fb_display_px(pal2color(palette[c]), i, j);
}
}
} /* Flush the pixel buffer */
void nes_flush_buf(PixelBuf *buf)
{
Pixel *p;
int i,x,y,color;
for (i = ; i < buf->size; i++)
{
p = &buf->buf[i];
x = p->x;
y = p->y; color = pal2color(palette[p->c]);
lcd_fb_display_px(color, x, y);
lcd_fb_display_px(color, x+, y);
lcd_fb_display_px(color, x, y+);
lcd_fb_display_px(color, x+, y+);
}
} /* Initialization:
(1) start a 1/FPS Hz timer.
(2) register fce_timer handle on each timer event */
void nes_hal_init()
{
/**
* 需要完成的事情
* 1,初始化 lcd
* 2,初始化 定时器 先做简单的直接用系统延时
*/
if(- == lcd_fb_init())
{
printf("lcd fb init error \n");
return ;
}
} /* Update screen at FPS rate by allegro's drawing function.
Timer ensures this function is called FPS times a second. */
void nes_flip_display()
{
//设置64种颜色值 不必设置
} /* Query a button's state.
Returns 1 if button #b is pressed. */
int nes_key_state(int b)
{
switch (b)
{
case : // On / Off
return ;
case : // A
return ;
case : // B
return ;
case : // SELECT
return ;
case : // START
return ;
case : // UP
return ;
case : // DOWN
return ;
case : // LEFT
return ;
case : // RIGHT
return ;
default:
return ;
}
}
nes 红白机模拟器 第1篇的更多相关文章
- nes 红白机模拟器 第7篇 编译使用方法
模拟器,基于 InfoNES ,作者添加修改以下功能: 1, joypad 真实手柄驱动程序(字符型设备驱动) 2,原始图像只有256*240 ,添加 图像放大算法,这里实现了2种,a, 最近邻插值 ...
- arm 2440 linux 应用程序 nes 红白机模拟器 第1篇
对比了很多种,开源的 NES 模拟器 VirtuaNES , nestopia , FakeNES , FCEUX , InfoNES , LiteNES 最后决定使用 LiteNES 进行移值,它是 ...
- arm 2440 linux 应用程序 nes 红白机模拟器 第4篇 linux 手柄驱动支持
小霸王学习机的真实手柄,实测CPU 占用 80% 接线图: 手柄读时序: joypad.c 驱动: 普通的字符设备驱动. #include <linux/module.h> #includ ...
- arm 2440 linux 应用程序 nes 红白机模拟器 第2篇 InfoNES
InfoNES 支持 map ,声音,代码比较少,方便 移值. 在上个 LiteNES 的基础上,其实不到半小时就移值好了这个,但问题是,一直是黑屏.InfoNES_LoadFrame () Wo ...
- nes 红白机模拟器 第6篇 声音支持
InfoNES 源码中并没有包含 linux 的声音支持. 但提供 wince 和 win 的工程,文件,通过分析,win 的 DirectSound 发声,在使用 linux ALSA 实现. 先使 ...
- nes 红白机模拟器 第5篇 全屏显示
先看一下效果图 放大的原理是使用最初级的算法,直接取对应像素法. /*================================================================= ...
- nes 红白机模拟器 第4篇 linux 手柄驱动支持
小霸王学习机的真实手柄,实测CPU 占用 80% 接线图: 手柄读时序: joypad.c 驱动: 普通的字符设备驱动. #include <linux/module.h> #includ ...
- nes 红白机模拟器 第2篇 InfoNES
InfoNES 支持 map ,声音,代码比较少,方便 移值. 在上个 LiteNES 的基础上,其实不到半小时就移值好了这个,但问题是,一直是黑屏.InfoNES_LoadFrame () Wo ...
- nes 红白机模拟器 第3篇 游戏手柄测试 51 STM32
手柄使用的是 CD4021 ,datasheet 上说支持 3V - 15V . 因为手柄是 5V 供电,2440 开发板上是GPIO 3.3V 电平,STM32 GPIO 也是 3.3V (也兼容5 ...
随机推荐
- 1)session总结
(1)session的由来: HTTP协议是一种无状态协议,服务器响应完之后就失去了与浏览器的联系,最早,Netscape将cookie引入浏览器,使得数据可以客户端跨页面交换,那么服务器是如何记住众 ...
- iOS高仿微信悬浮窗、忍者小猪游戏、音乐播放器、支付宝、今日头条布局滚动效果等源码
iOS精选源码 iOS WKWebView的使用源码 模仿apple music 小播放器的交互实现 高仿微信的悬浮小窗口 iOS仿支付宝首页效果 [swift]仿微信悬浮窗 类似于今日头条,网易新闻 ...
- android高仿抖音、点餐界面、天气项目、自定义view指示、爬取美女图片等源码
Android精选源码 一个爬取美女图片的app Android高仿抖音 android一个可以上拉下滑的Ui效果 android用shape方式实现样式源码 一款Android上的新浪微博第三方轻量 ...
- STL中map的使用
知识点 C++中map提供的是一种键值对容器,里面的数据都是成对出现的.map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的. ...
- VS2010发布,IIS实际目录,无法修改只读状态解难决办法
VS2010发布网站后,无法修改只读状态 CMS简单的主页生成失败,其他的修改操错也应该无法执行 只在常规里修改无效. 网上得答案 1.鼠标右键点击文件夹 2.点击属性 3.在“常规”标签页中,取消“ ...
- ES6的模块暴露与模块引入
ES6的模块暴露和引入可以让我们实现模块化编程,以下列出ES6的几种模块暴露与引入的方式与区别. 1.ES6一共有三种模块暴露方法 多行暴露 模块1:module1.js //多行暴露 export ...
- Python时间操作所相关
相关模块:time,datetime,calendar(日历模块) 获取当前时间: # 获取当前10位时间戳,默认返回为float类型 print int(time.time()) # output: ...
- Java遍历文件夹的两种方法(非递归和递归)
import java.io.File; import java.util.LinkedList; public class FileSystem { public static int num ...
- 猫头鹰的深夜翻译:核心JAVA并发一
简介 从创建以来,JAVA就支持核心的并发概念如线程和锁.这篇文章会帮助从事多线程编程的JAVA开发人员理解核心的并发概念以及如何使用它们. (博主将在其中加上自己的理解以及自己想出的例子作为补充) ...
- 你每天跑这么多自动化用例,能发现BUG吗?
阿里QA导读:为什么要度量测试有效性?这么多的CASE,花了大量时间和资源去运行,真能发现bug吗?CI做到90%的行覆盖率了,能发现问题吗?测试用例越来越多,删一些,会不会就发现不了问题了?怎么找出 ...