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 
");
 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 
");
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 
");
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 
");
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 }
原文地址:https://www.cnblogs.com/ningci/p/5618351.html