设为首页收藏本站

ISO/IEC C++ China Unofficial

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
12
返回列表 发新帖
楼主: moecmks

容错率较高的FC模拟器的编写

[复制链接]

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-3-24 01:09:41 | 显示全部楼层
暂时有事,过段时间在更.调试的时候debug PPU有点误差
更新一下CPU, http://codepad.org/t8F2u0vb cpu讲解得错误比较多.以后慢慢拨乱反正吧

点评

= = 我写不动呀,你们为什么这么熟练啊?  发表于 2016-3-28 16:02
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-8 22:27:10 | 显示全部楼层
暂时弃坑~
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-8 22:29:14 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-8 22:31 编辑

@iyzsong 简单的moni不怎么要过脑子@iyzsong

点评

0 0  发表于 2016-4-10 12:41
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 0 反对 1

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 01:37:17 | 显示全部楼层
关于loopy_v与loopy_t
非常重要也是PPU基础的一个难点
如果之前关于0506寄存器的讲解你认真的听了的话
恭喜你,被我坑了!
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 01:43:51 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-10 01:50 编辑

首先是loopy_t,这个对象只有在写00/05/06 IO的时候有用
他的主要作用就是后备电子枪缓冲
在每帧HBLANK过后/每帧开始前都会进行对真实电子枪的更新 行为各异
帧开始的时候会把所有的段位值写进loopy_v对象
HBLANK过后只复位X部分的偏移
大致伪代码如下
  1. /* io write */
  2. DEFINE_PPU_IO_WRITE_(00) // PPU CTRL
  3. {
  4.   ppu->loopy_t = (ppu->loopy_t & 0xF3FF) | ((value & 0x03) << 10);
  5.   ppu->regs[0] = value;
  6. }
  7. DEFINE_PPU_IO_WRITE_(01) // PPU MASK
  8. {
  9.   ppu->regs[1] = value;
  10. }
  11. DEFINE_PPU_IO_WRITE_(03) // OAMADDR
  12. {
  13.   ppu->regs[3] = value;
  14. }
  15. DEFINE_PPU_IO_WRITE_(04) // OAMDATA
  16. {
  17.   ppu->oam[ppu->regs[3]++] = value;
  18. }
  19. DEFINE_PPU_IO_WRITE_(05) // SCROLL/SCREEN ELECTRON GUN
  20. {
  21.   if (!ppu->toggle0506) // first, hori
  22.   {
  23.         ppu->loopy_x = value & 7;
  24.         ppu->loopy_t = (ppu->loopy_t & 0xFFE0) | UINT16_CAST(value >> 3);
  25.   }
  26.   else // second, vert
  27.   {
  28.     ppu->loopy_t &= 0x8C1F;
  29.         ppu->loopy_t |= (UINT16_CAST(value & 0xF8) << 2);
  30.         ppu->loopy_t |= (UINT16_CAST(value & 0x07) << 12);
  31.   }
  32.   ppu->toggle0506 ^= 1;
  33. }
  34. DEFINE_PPU_IO_WRITE_(06) // VRAMADDR/SCREEN ELECTRON GUN
  35. {
  36.   if (!ppu->toggle0506) // first, high 6 bit
  37.   {
  38.         ppu->loopy_t = (ppu->loopy_t & 0x00FF) | (UINT16_CAST(value & 0x3F) << 8);
  39.   }
  40.   else // second, low 8 bit
  41.   {
  42.     ppu->loopy_t = (ppu->loopy_t & 0xFF00) | (UINT16_CAST(value & 0xFF) >> 0);
  43.         ppu->loopy_v = ppu->loopy_t;
  44.   }
  45.   ppu->toggle0506 ^= 1;
  46. }
  47. DEFINE_PPU_IO_WRITE_(07) // VRAMDATA
  48. {
  49.   uint16_t oldv = ppu->loopy_v & 0x3FFF;

  50.   ppu->loopy_v += (ppu->regs[0] & 4) ? 32 : 1;
  51.    
  52.   if (oldv > 0x2FFF)
  53.     if (oldv > 0x3EFF)
  54.            if (!(oldv & 0x000F))
  55.                   ppu->internal_pal[0] = ppu->internal_pal[16] = value & 0x3F;
  56.            else
  57.           ppu->internal_pal[oldv & 0x1F] = value & 0x3F;
  58.     else
  59.           ppu->mem_page[(oldv - 0x1000) >> 10][(oldv - 0x1000) & 0x3FF] = value;
  60.   else
  61.         ppu->mem_page[oldv >> 10][oldv & 0x3FF] = value;
  62. }
  63. DEFINE_PPU_IO_WRITE_(02){/* error write */}
复制代码
// =====================================================================
// method:ppu_electron_gun_adjust_hori
// arg0:this
// return:n/a
// =====================================================================
static void ppu_electron_gun_adjust_hori (struct ppu_s *ppu)
{
  ppu->loopy_v = (ppu->loopy_v & 0xFBE0) | (ppu->loopy_t & 0x041F);
}
// =====================================================================
// method:ppu_electron_gun_adjust_vert
// arg0:this
// return:n/a
// =====================================================================
static void ppu_electron_gun_adjust_vert (struct ppu_s *ppu)
{
  if ((ppu->loopy_v & 0x7000) == 0x7000)
  {
    ppu->loopy_v &= 0x8FFF; // clear mini y offset

    if ((ppu->loopy_v & 0x03E0) == 0x03A0) // nametable's y is 29 ?
    {
      ppu->loopy_v ^= 0x0800; // switch vert nametable
      ppu->loopy_v &= 0xFC1F; // reset y pos
    }
    else
    {
      // for "negative scroll"
      if((ppu->loopy_v & 0x03E0) == 0x03E0) // nametable's y is 31 ?
      {
        ppu->loopy_v &= 0xFC1F;
      }
      else
      {
        ppu->loopy_v += 0x0020;
      }
    }
  }
  else
  {
    ppu->loopy_v += 0x1000;
  }
}
// =====================================================================
// method:ppu_frame_scan_start
// arg0:this
// return:n/a
// =====================================================================
void ppu_frame_scan_start (struct ppu_s *ppu)
{
  if ((ppu->regs[1] & 0x08) || (ppu->regs[1] & 0x10))
  {
    // open sp/bg render enable, set electron gun init pos
    ppu->loopy_v = ppu->loopy_t;
  }
  ppu->scanline_lines = 0; // reset scanlines
}
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 01:59:58 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-10 02:08 编辑

loopy_v古怪点,这个实际是使用的屏幕电子枪对象, 控制着屏幕的刷新.2006负责更新此对象
在每帧HBLANK过后/每帧开始前都会进行对loopy_v的更新
在屏幕刷新期间被写入新的值得话会撕裂屏幕.这个效果配合着0号精灵可以用来
分隔光栅.最典型的就是马里奥的Tile字模同步.此游戏字模不是使用精灵来记录的所以想要随心所欲的具体的控制位置就必须要用上述方法,或者使用IRQ分割光栅
当测试到0号精灵被击中写05滚动重新设置loop_t的X部分相应位置为新的滚动位置[可能是写06复位也说不定.不过后者感觉可行性不高]
[0号精灵即附着在计分金币后面的一个后备精灵(一个斜45度角的2个像素自己开一个带PPU调试器的模拟器运行一下超级玛丽游戏就知道了)]


#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 02:11:36 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-10 02:22 编辑

复制代码
  1. 偏移 字节数 内容

  2. 0-3 4 字符串“NES^Z”用来识别.NES文件

  3. 4    1  16kB ROM的数目

  4. 5    1   8kB VROM的数目

  5. 6    1
  6.                 D0:1=垂直镜像,0=水平镜像
  7.                 D1:1=有电池记忆,SRAM地址$6000-$7FFF
  8.                 D2:1=在$7000-$71FF有一个512字节的trainer
  9.                 D3:1=4屏幕VRAM布局
  10.                 D4-D7:ROM Mapper的低4位

  11. 7          1  D0-D3:保留,必须是0(准备作为副Mapper号^_^)
  12.                 D4-D7:ROM Mapper的高4位

  13. 8-F 8 保留,必须是0

  14. 16-  16KxM ROM段升序排列,如果存在trainer,它的512字节摆在ROM段之前

  15. -EOF  8KxN VROM段, 升序排列
复制代码


好了狗屁差不多放完了80%。让我们试着来写点实际的能看得出来的东西.至于INES文件头自己去看nesdev的文档吧也就是固定的16个字节的东西简单的说就是上面的表,这里我们假设平台是windows_x86.使用的是directx的api.开发环境为vs2005+directx sdk
注意一下以下代码可能会写的非常粗糙/糟糕。这种平台相关的东西不保证能看得懂了。码风也会变得更加糟糕。请谅解[其实主要是懒...hhh]
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 02:23:03 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-10 02:25 编辑

首先是绘图,简单起见用的是dxsurface/建立摧毁很容易理解.bitblt buffer要求的是256*240的像素
  1. #include <windows.h>
  2. #include <d3d9.h>
  3. #include <dinput.h>
  4. #include <xaudio2.h>

  5. static IDirect3D9 *base=0;
  6. struct ddraw_warps {D3DLOCKED_RECT    vinfo;
  7. IDirect3DDevice9  *device;         /* device object */
  8.                 IDirect3DSurface9 *surface; /* vram object */
  9. };

  10. // ==< get_surface >==========================
  11. void *get_surface (HWND window_handle)
  12. {
  13.         D3DLOCKED_RECT vinfo = {0};         

  14.         D3DPRESENT_PARAMETERS d3dpp = {0};         

  15.         static _init_base = 0;
  16. struct ddraw_warps *ddw;
  17.         if (!base)
  18.         {base = Direct3DCreate9 (D3D_SDK_VERSION);
  19.         if (!base) return NULL;}

  20.         ddw = malloc                    (sizeof(struct ddraw_warps));
  21.         if (!ddw)
  22.                 return NULL;      memset (ddw, 0x00, sizeof(struct ddraw_warps));

  23.         /* set d3dpp struct */
  24.         d3dpp.BackBufferFormat      = D3DFMT_X8R8G8B8;
  25.         d3dpp.SwapEffect            = D3DSWAPEFFECT_DISCARD;
  26.         d3dpp.Flags                 = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  27.         d3dpp.hDeviceWindow         = window_handle;
  28.         d3dpp.Windowed              = TRUE;
  29.         d3dpp.PresentationInterval  = D3DPRESENT_INTERVAL_IMMEDIATE; /* Disable VSync */

  30.         /* check, init d3d object */
  31.         if (S_OK == IDirect3D9_CreateDevice (base, 0, D3DDEVTYPE_HAL, window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &ddw->device))
  32.                 if (S_OK == IDirect3DDevice9_GetBackBuffer (ddw->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &ddw->surface))
  33.                         if (S_OK == IDirect3DSurface9_LockRect (ddw->surface, &ddw->vinfo, NULL, D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE))
  34.                                 if (S_OK == IDirect3DSurface9_UnlockRect (ddw->surface)) {
  35.                                         return ddw;
  36.                                 }

  37.                                 if (ddw->surface) IDirect3DSurface9_Release (ddw->surface);
  38.                                 if (ddw->device) IDirect3DDevice9_Release (ddw->device);
  39.                                 if (ddw) free (ddw);

  40.                                 return NULL;   
  41. }
  42. void simple_bitblt256_240 (struct ddraw_warps *ddw, void *buffer)
  43. {
  44.         int x;
  45.         DWORD *d = ddw->vinfo.pBits;
  46.         DWORD *s = buffer;
  47.         DWORD n = ddw->vinfo.Pitch >> 2;
  48.         for (x = 0; x != 240; x++)
  49.                 memcpy (&d[n*x], &s[x*256], 1024);
  50.         IDirect3DDevice9_Present (ddw->device,0,0,0,0);
  51. }
  52. void destroy_surface(struct ddraw_warps *ddw)
  53. {
  54.         if (ddw->surface) IDirect3DSurface9_Release (ddw->surface);
  55.         if (ddw->device) IDirect3DDevice9_Release (ddw->device);
  56.         if (ddw) free (ddw);
  57.         if (base) { IDirect3D9_Release(base) , base = 0;};
  58. }
复制代码
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 02:27:16 | 显示全部楼层
键盘输入直接靠wndproc
  1. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {
  3.      switch (message)
  4.      {
  5.                 case WM_KEYDOWN:
  6.                 {
  7.                   switch(wParam)
  8.                   {
  9.                   case 'W': joypad_set_up();     break;
  10.                   case 'S': joypad_set_down();   break;
  11.                   case 'A': joypad_set_left();   break;
  12.                   case 'D': joypad_set_right();  break;
  13.                   case 'J': joypad_set_b();                   break;
  14.                   case 'K': joypad_set_a();          break;
  15.                   case 'Q': joypad_set_select(); break;
  16.                   case 'E': joypad_set_start();  break;
  17.                   }
  18.             }
  19.             return 0;
  20.                
  21.                 case WM_KEYUP:                
  22.                 {
  23.                   switch(wParam)
  24.                   {
  25.                   case 'W': joypad_clr_up();     break;
  26.                   case 'S': joypad_clr_down();   break;
  27.                   case 'A': joypad_clr_left();   break;
  28.                   case 'D': joypad_clr_right();  break;
  29.                   case 'J': joypad_clr_b();             break;
  30.                   case 'K': joypad_clr_a();          break;
  31.                   case 'Q': joypad_clr_select(); break;
  32.                   case 'E': joypad_clr_start();  break;
  33.                   }
  34.             }
  35.             return 0;

  36.      case WM_DESTROY:
  37.         PostQuitMessage (0) ;
  38.         return 0 ;
  39.      }
  40.      return DefWindowProc (hwnd, message, wParam, lParam) ;
  41. }
复制代码

#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-10 12:46:01 | 显示全部楼层
本帖最后由 moecmks 于 2016-4-10 12:50 编辑

直接传代码吧[http://pan.baidu.com/s/1jHQOlRg]Cblock可能要自己设置下,试过在windows x86下cl/gcc都可以编译透过运行【见附件】
少写了很多东西,和一些影响不大的代码最多两千行左右的代码 主要参考了nesterj和virtuanes的代码
写的很乱,码风很渣不过主要地方做了注释了
想写的不显得那么民科发现精力水平都有限[还是干货太少了]至于APU以及少说的INES/精确扫描什么有时间再坑吧好累啊[发现错的好多暂时不管了】

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

1

主题

16

帖子

142

积分

注册会员

Rank: 2

威望
0
经验
126
贡献
0
发表于 2016-4-10 13:10:00 | 显示全部楼层
本帖最后由 iyzsong 于 2016-5-11 16:25 编辑

感谢!

我打算用scheme实现,最近完全没动力,先坑着...

坑了太久,这都是啥来着。现在我是一脸懵逼 = =
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-4-26 18:37:17 | 显示全部楼层
iyzsong 发表于 2016-4-10 13:10
感谢!

我打算用scheme实现,最近完全没动力,先坑着...

真羡慕你们天天能用电脑!!!
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

3

主题

74

帖子

283

积分

中级会员

Rank: 3Rank: 3

威望
9
经验
182
贡献
9
 楼主| 发表于 2016-5-11 01:33:06 | 显示全部楼层
x86-64环境改一下simple_bitblt256_240函数不然屏幕不会更新
复制下面代码即可,x86下可以不锁定缓冲即可更新64位下居然不行了。。。
void simple_bitblt256_240 (struct ddraw_warps *ddw, void *buffer)
{
        int x;
                D3DLOCKED_RECT vinfo = {0};

        DWORD *d;
        DWORD *s;
        DWORD n;

        IDirect3DSurface9_LockRect (ddw->surface, &vinfo, NULL, D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE);

        d = vinfo.pBits;
        s = buffer;
        n =vinfo.Pitch >> 2;


        for (x = 0; x != 240; x++)
                memcpy (&d[n*x], &s[x*256], 1024);

        IDirect3DSurface9_UnlockRect (ddw->surface);

        IDirect3DDevice9_Present (ddw->device,0,0,0,0);
}
#if !idppc
/*
** float q_rsqrt( float number )
*/
float Q_rsqrt( float number )
{
        long i;
        float x2
回复 支持 反对

使用道具 举报

10

主题

108

帖子

461

积分

超级版主

RA2DIY 特别行政区行政长官

Rank: 8Rank: 8

威望
4
经验
342
贡献
3
发表于 2016-5-17 21:40:43 | 显示全部楼层
moecmks 发表于 2016-5-11 01:33
x86-64环境改一下simple_bitblt256_240函数不然屏幕不会更新
复制下面代码即可,x86下可以不锁定缓冲即可更 ...

高中党?不容易呀。

点评

是,不过没什么人发帖子。  发表于 2016-5-21 00:29
搬砖党哈哈哈~~~最近可以歇一阵子  发表于 2016-5-17 23:14
We will prevail!! www.lhmouse.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|ISO/IEC C++ China Unofficial    

GMT+8, 2017-6-24 01:07 , Processed in 0.346627 second(s), 32 queries , Xcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表