背景
自己开发nes模拟器已经成功跑起来了打砖块,其实代码没有多少,只是很多其中细节搞了好久才明白,之前没有没有按照line-by-line实现渲染,后面用line-by-line 渲染了,才能够明白其中细节。
目的
开发nes模拟器,相当于开始一个虚拟机,但你如果要写一个intel 虚拟机用来跑windows,需要资料点太多,同时要花很多精力,感觉对于我难度太高,但nes就不一样了,他的模拟官方指令并不多,同时要模拟的硬件也不多,同时可以学习之前怎么在那么有限的内存写出那么多好玩的游戏,同时小时候也非常喜欢玩,所以我也想知道其中技术点,同时也会对Intel 汇编理解更深。
需要模拟模块
- cpu 指令:运行的代码
- rom的解析
- PPU 渲染:本质渲染name table 和 精灵(可以动的元素),还要考虑滚动
- 控制实现(前3个就可以实现了就可以玩了)
- 声音(我暂时没有实现)
- mapper (默认用mapper0 就是没有mapper,这个地址映射关系,目前我也没有实现)
cpu 指令
这个最基本同时也是最重要,这个看文档按照思路写就可以了,一些标志位设置,直接问AI就可以了,对于溢出我写完了,就忘记判断逻辑了,这些标志不能错,一旦错,那么程序逻辑就错,我开始写错了,发现图案表等是错误,我一条条指令排查,通过其他模拟器调试进行对比,找到错误的指令,所以实现指令时候最好用nes dev 中测试rom进行验证,难度算是比较简单
rom 解析
这个看官方文档
ppu 模拟
这个实现可以按照一帧一帧的渲染,直接获取每一帧的数据,然后统一渲染这一帧的数据,这个实现非常简单,写一个循环就可以遍历所有 tile(nes内部最小图案元素),按照x y 保存起来,统一渲染,不用管那么多细节
line-by-line:按照8个周期渲染,同时要预读2个tile,这块好多逻辑文档写的不清楚,貌似是错误的,这块模拟不一定要按照原来硬件实现方式实现,反而代码不好写,我发现目前主流模拟器都没有i按照line-by-line 实现,因为我测试打砖块渲染速度就不对,快了很多,我自己用2种方案实现发现,line-by-line 会慢一些,感觉游戏代码控制帧率,这样子更加接近以前玩的感觉。
这个难点:图案表和name table 数据结构、滚动细节,这些东西第一次看文档不知道它们说什么,我跟AI讨论好多就是这些细节,AI 生成的代码,基本不能用,因为它们自己很多点都是错误的,同时前后矛盾,只能借鉴一下,但进入复杂的逻辑无论AI还是人逻辑都可能混乱,后面还是我自己反复思考结合AI,总结出一些自己理解。
控制实现
如果只是模拟,只要知道几个寄存器是干什么,然后读取按键,写对应值就可以了。
其他我暂时没有实现,所以不写了,等后续自己再弄。
总结
- 我发现目前好多NES 和 开源的代码,都没有按照硬件思路实现,所以搞不懂为什么 nes为什么那设计,只有自己按照类似实现,才能明白,我目前也没有完全模拟,因为内存足够大,直接读写就可以了,根本不用考虑那么多,所以现在人写代码多么简单。
- 目前网上文章,感觉其中细节根本没有那么扣
- 写一个demo模拟器可能没有很多代码,但要扣其中细节挺多
教程计划
- 每一步实现写清楚,同时把难点写出来,尽可能清楚,主要提高自己理解
- 细节足够多,但这个感觉无法保证
- 每个模块单独写出来,代码全部分开
- 不知道声音教程会不会出,因为我觉得只要把界面渲染出来后,后面都非常简单了
- 代码足够简单,不要加过多抽象,导致看代码痛苦
因为自己平时很忙,所以进度可能特别慢,但会按照计划进去下去
效果图
说明:因为gif ,导致一些帧数减少了,滚动起来没有丝滑,同时当时实现没有处理精灵不显示情况,导致一些精灵显示出来
