arm linux 应用程序 nes 红白机模拟器 第1篇

Posted 宁次

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了arm linux 应用程序 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 :

  1 /*
  2 This file present all abstraction needed to port LiteNES.
  3   (The current working implementation uses allegro library.)
  4 
  5 To port this project, replace the following functions by your own:
  6 1) nes_hal_init()
  7     Do essential initialization work, including starting a FPS HZ timer.
  8 
  9 2) nes_set_bg_color(c)
 10     Set the back ground color to be the NES internal color code c.
 11 
 12 3) nes_flush_buf(*buf)
 13     Flush the entire pixel buf\'s data to frame buffer.
 14 
 15 4) nes_flip_display()
 16     Fill the screen with previously set background color, and
 17     display all contents in the frame buffer.
 18 
 19 5) wait_for_frame()
 20     Implement it to make the following code is executed FPS times a second:
 21         while (1) {
 22             wait_for_frame();
 23             do_something();
 24         }
 25 
 26 6) int nes_key_state(int b) 
 27     Query button b\'s state (1 to be pressed, otherwise 0).
 28     The correspondence of b and the buttons:
 29       0 - Power
 30       1 - A
 31       2 - B
 32       3 - SELECT
 33       4 - START
 34       5 - UP
 35       6 - DOWN
 36       7 - LEFT
 37       8 - RIGHT
 38 */
 39 #include "hal.h"
 40 #include "fce.h"
 41 #include "common.h"
 42 
 43 /**
 44  * allegro API 不明白的看文档 
 45  * https://www.allegro.cc/manual/5/index.html
 46  */
 47 /* lcd 操作相关 头文件 */
 48 #include <sys/types.h>
 49 #include <sys/stat.h>
 50 #include <fcntl.h>
 51 #include <linux/fb.h>
 52 #include <sys/ioctl.h>
 53 #include <unistd.h>
 54 #include <string.h>
 55 #include <sys/mman.h>
 56 
 57 static int fb_fd;
 58 static unsigned char *fb_mem;
 59 static int px_width;
 60 static int line_width;
 61 static int screen_width;
 62 static struct fb_var_screeninfo var;
 63 
 64 static int lcd_fb_display_px(int color, int x, int y)
 65 {
 66     unsigned char  *pen8;
 67     unsigned short *pen16;
 68     
 69     unsigned char r,g,b;
 70     
 71     pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
 72     pen16 = (unsigned short *)pen8;
 73     
 74     //合并为 565 格式 16bbp
 75     r = (color>>16) & 0xff;
 76     g = (color>>8) & 0xff;
 77     b = (color>>0) & 0xff;
 78     *pen16 = (r>>3)<<11 | (g>>2)<<5 | (b>>3);
 79     
 80     return 0;
 81 }
 82 
 83 //调色板转16进行32位颜色
 84 static int pal2color(pal pal)
 85 {
 86     int color = 0;
 87     color = pal.r << 16 | pal.g <<8 | pal.b;
 88     return color;
 89 }
 90 
 91 static int lcd_fb_init()
 92 {
 93     //如果使用 mmap 打开方式 必须是 读写方式
 94     fb_fd = open("/dev/fb0", O_RDWR);
 95     if(-1 == fb_fd)
 96     {
 97         printf("cat\'t open /dev/fb0 \\n");
 98         return -1;
 99     }
100     //获取屏幕参数
101     if(-1 == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var))
102     {
103         close(fb_fd);
104         printf("cat\'t ioctl /dev/fb0 \\n");
105         return -1;
106     }
107     //计算参数
108     px_width = var.bits_per_pixel / 8;
109     line_width = var.xres * px_width;
110     screen_width = var.yres * line_width;
111     
112     fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
113     if(fb_mem == (void *)-1)
114     {
115         close(fb_fd);
116         printf("cat\'t mmap /dev/fb0 \\n");
117         return -1;
118     }
119     //清屏
120     memset(fb_mem, 0 , screen_width);
121     return 0;
122 }
123   
124 /* Wait until next allegro timer event is fired. */
125 void wait_for_frame()
126 {
127     //休眠 FPS = 60 * 1000 毫秒
128     usleep(1/FPS*1000);
129 }
130 
131 /* Set background color. RGB value of c is defined in fce.h */
132 void nes_set_bg_color(int c)
133 {
134     //画背景颜色
135     int i,j;
136     for(i=0; i<SCREEN_WIDTH; i++)
137     {
138         for(j=0; j<SCREEN_HEIGHT; j++)
139         {
140             lcd_fb_display_px(pal2color(palette[c]), i, j);
141         }
142     }    
143 }
144 
145 /* Flush the pixel buffer */
146 void nes_flush_buf(PixelBuf *buf)
147 {
148     Pixel *p;
149     int i,x,y,color;
150     for (i = 0; i < buf->size; i++) 
151     {
152            p = &buf->buf[i];
153            x = p->x;
154         y = p->y;
155 
156         color = pal2color(palette[p->c]);
157         lcd_fb_display_px(color, x, y);    
158         lcd_fb_display_px(color, x+1, y);
159         lcd_fb_display_px(color, x, y+1);
160         lcd_fb_display_px(color, x+1, y+1);
161         }
162 }
163 
164 /* Initialization:
165    (1) start a 1/FPS Hz timer. 
166    (2) register fce_timer handle on each timer event */
167 void nes_hal_init()
168 {
169     /**
170      * 需要完成的事情
171      * 1,初始化 lcd 
172      * 2,初始化 定时器 先做简单的直接用系统延时
173      */
174     if(-1 == lcd_fb_init())
175     {
176         printf("lcd fb init error \\n");
177         return ;
178     }    
179 }
180 
181 /* Update screen at FPS rate by allegro\'s drawing function. 
182    Timer ensures this function is called FPS times a second. */
183 void nes_flip_display()
184 {
185     //设置64种颜色值 不必设置
186 }
187 
188 /* Query a button\'s state.
189    Returns 1 if button #b is pressed. */
190 int nes_key_state(int b)
191 {
192     switch (b)
193     {
194         case 0: // On / Off
195             return 1;
196         case 1: // A
197             return 1;
198         case 2: // B
199             return 1;
200         case 3: // SELECT
201             return 1;
202         case 4: // START
203             return 1;
204         case 5: // UP
205             return 1;
206         case 6: // DOWN
207             return 1;
208         case 7: // LEFT
209             return 1;
210         case 8: // RIGHT
211             return 1;
212         default:
213             return 1;
214     }
215 }

 

以上是关于arm linux 应用程序 nes 红白机模拟器 第1篇的主要内容,如果未能解决你的问题,请参考以下文章

arm 2440 linux 应用程序 nes 红白机模拟器 第4篇 linux 手柄驱动支持

nes 红白机模拟器 第6篇 声音支持

nes 红白机模拟器 第7篇 编译使用方法

nes 红白机模拟器 第5篇 全屏显示

nes 红白机模拟器 第3篇 游戏手柄测试 51 STM32

NES 系统架构