chenxiao07 发表于 2010-5-3 10:36:07

基于FPGA的NES游戏机系统,附带超级玛丽,坦克大战,吃豆等11个游戏

上次上传的源代码好像因为签名档的缘故出了点问题,这次代码重新整理上传,有一定更新,并且附带了游戏文件

首先先大致解释一下NES游戏机(即我们俗称的“小霸王”)的构成以,NES使用6502的CPU以及一块专门负责显示的PPU,两者均可寻址16K的内存,但实际内存没有这么多。CPU能访问的两块内存分别为程序段ROM,以及运行时所需的RAM。PPU能够访问三块内存,分别为图案表VROM,命名表SRAM,和精灵表PRAM。

然后这里贴一份别人总结的NES资料,比较容易看懂,相信对理解有帮助


----------------------------开始----------------------------------

(来自屎王NES资料)

引言(Introduction)
========================

      首先感谢你阅读这份文档!
      这并不是一份非常详尽的文档,但它绝对是带你进入 NES 编
      程领域的最好教材!
      同时,我本人也为自己能写出这样一份文档而自豪(grin)

      这是一份技术文档,介绍了 NES 游戏机的硬件信息。但是在
      阅读它之前,请保证你懂汇编语言(ASM),最基础的 80x86
      要懂嘛……否则本文可能不适合你——如果你不信邪,可以
      试试!

      需要注意的是,这只是一份基础性的文档,并不涵盖太多太繁
      杂的内容,我的目的只是让你对 NES 的硬件体系有个大体的
      了解。如果你想更深入地了解 NES,访问下面的网站:
               http://nesdev.parodius.com

      这份文档的信息是基于 Y0SHi 的 nestech.txt 和 Marat
      Fayzullin 的 nes.doc 的,同时也加入了一些我个人的开发
      经验,不过不要指望它 100% 精确,现在没有 100% 精确的
      NES 资料。

      同时,我也要大大地感谢 Y0SHi 和 Marat Fayzullin 两位达
      人,没有他们精辟的文章,小的绝不可能写出这份文件,虽然
      达人们并不知道小的是谁。

      这份文档目前的版本是 0.01 版,只对 NES 的 CPU、内存、
      系统概况和 PPU 进行了初步介绍(没时间啊……),不过我
      算写得比较详细了……配合已有的资料,相信对大家掌握 NES
      应该会有所帮助吧……
      后面的部分我有空的时候再继续写……累死了~~~~~~~~~ >_<
      大家就把这文章当作连载吧……


      如果你对这份文档有什么改进的建议,或者发现什么错误,或
      者你想提供新的资料,请联系我!以便我在未来的版本中更新。

      如果你要传播我的文档,请保证它的完整性。



关于作者(About The Author...)
===================================

      我叫做 Necrosaro,中文名字叫屎王皮萨罗,人称屎王。
      年方 18,身高 ≈ 1.72m,体重 > 40kg,黑头发,黄皮肤,
      中国人。。。。
      我爱好广泛,听音乐,玩游戏,写程序(小工具、模拟器、
      小游戏……),看漫画,画漫画,看动画,吃饭,睡觉,等等。
      我穷人一个,目前打算找一份工作,挣钱读书!我希望找到一份
      程序员的工作,尤其向往游戏机软件的程序开发(最好能上GBA,嘿嘿嘿)。
      PC 的话……也可,不过我不懂 VC,DirectX,恐怕出不上什么力。。。
      我的程序水平决不亚于老外!!!
      另外我希望交一些朋友,有实力的(不管哪个方面,不过最好是
      和游戏开发有关的……),我欣赏有真才实干的人!!
      请大家和我联系!!

      [联系方法:]
      我的主页:http://necrosaro.yeah.net
      我的邮箱:necrosaro@ynmail.com(首选)
      我的QQ:18177243
                (note: 我一般晚上 8:00 ~ 10:00 在线)

                                                - Necrosaro
                                        PM 23:70 - 2002/7/31


NES 系统概述(NES Technical Overview)
==========================================

      NES 是日本任天堂(Nintendo)公司于上个世纪 80 年代开发的
      一款游戏主机,它同时也是此后 10 年里最受欢迎的游戏主机。
      NES 在日本/亚洲的名称叫做 FC(famicom,或 family comput-
      er),在欧洲叫做 Dandy,在美国叫做 NES(Nintendo Entert-
      ainment System,任天堂娱乐系统),在中国,通常被称作红白
      机或8位机。它的技术参数如下:
          CPU:6502 NMOS 芯片。
               直接寻址能力为 64KB,数据处理能力为 8位。
               内建一块特殊的音频处理器。
          RAM:NES 本体预留 8KB 的 RAM 空间,
               但实际的物理 RAM 仅 2KB。
          PPU:NES 特有的图形处理芯片,内建 10KB 显示内存。
               支持垂直/平行镜像、垂直/平行滚屏,最大发色数
               64 色。同屏最大发色数 26 色(也有说法是 25 色,
               去掉了透明色)。支持 8x8 tile,最多支持 64 个
               8x8 或 8x16 精灵。显示分辨率 = 256x240。
         pAPU:NES 的音频处理器。因为是设计在 CPU 内部,所以
               叫做 pAPU(pseudo Audio Processing Unit)。包
               含 2 个方块波声道,1 个三角波声道,1 个杂音声
               道以及 1 个数字声道。
      Input:输入设备。主要是手柄,后来也出现了激光枪(Za-
               pper)以及各种形形色色的新设备。
       Mapper:内存映射设备。这并非 NES 本体所有,而是包含在
               许多游戏卡内部,以扩充 NES 的性能。
         SRAM:Save RAM,也叫 Battery-Backed RAM,即电池储存
               RAM。固化在某些游戏卡上的芯片,关机后由电池供
               电,信息不会丢失。多用来保存 RPG 类游戏的档案
               资料。NES 本体为 SRAM 预留了 8KB 的地址空间(
               实际多数游戏的 SRAM 大小也是 8KB)。




NES 内存布局(NES Memory Map)
==================================

      NES 包含 3 种内存。
      1 种是系统内存,可被 CPU 直接访问。
      1 种是显示内存,存在于 PPU 内部,CPU 只能通过操作 PPU
      寄存器间接访问这块内存。
      1 种是 OAM 内存(精灵属性内存),同样存在于 PPU 内部,
      CPU 可通过操作 PPU 寄存器或者利用 DMA 间接访问它。


      NES 系统内存布局:
      ------------------

      +----------+----------+---------------------------+
      | 起始地址 | 结束地址 |         说明            |
      +----------+----------+---------------------------+
      |$0000   |$07FF   | NES 本体所包含的 2KB RAM。|(2 KB)
      +----------+----------+---------------------------+
      |$0800   |$0FFF   | 这 3 个区域都是 $0000 -   |(2 KB)
      +----------+----------+ $07FF 的镜像。换句话说,|
      |$1000   |$17FF   | 对它们的操作(读/写)实际 |(2 KB)
      +----------+----------+ 就是对 $0000 - $07FF 的操 |
      |$1800   |$1FFF   | 作。比如:读取 $08AB 的内 |(2 KB)
      |          |          | 容实际等于读取 $00AB 的内 |
      |          |          | 容。而向 $15CC 写数据实际 |
      |          |          | 等于向 $05CC 写数据。   |
      |          |          | 这 3 块不是物理的 RAM,   |
      |          |          | 它们都是镜像(Mirror)!|
      +----------+----------+---------------------------+
      |$2000   |$2007   | PPU 寄存器。CPU 通过对这|(8 字节)
      |          |          | 片区域的操作来实现对 PPU|
      |          |          | 的控制。                  |
      +----------+----------+---------------------------+
      |$2008   |$3FFF   | PPU 寄存器的镜像。      |(上面 8 字节)
      |          |          | $2008 = $2000,         |(的 1024 次镜像)
      |          |          | $2009 = $2001,         |(连同上面 8 字节)
      |          |          | ....                      |(共 8 KB)
      |          |          | $200F = $2007,         |
      |          |          | $2010 = $2000,         |
      |          |          | $2011 = $2001,         |
      |          |          | ....                      |
      +----------+----------+---------------------------+
      |$4000   |$4013   | pAPU 寄存器。CPU 通过对这 |(20 字节)
      |          |          | 片区域的操作来实现对 pAPU |
      |          |          | 的控制。                  |
      +----------+----------+---------------------------+
      |$4014   |$4014   | OAM DMA 寄存器。          |(1 字节)
      |          |          | 通过操作这个字节,可将    |
      |          |          | OAM(精灵属性内存)的内容 |
      |          |          | 传送到指定的系统内存中。|
      +----------+----------+---------------------------+
      |$4015   |$4015   | pAPU 状态寄存器。         |(1 字节)
      |          |          | 各声道的状态,etc....   |
      +----------+----------+---------------------------+
      |$4016   |$4017   | 输入设备状态寄存器。      |(2 字节)
      |          |          | 游戏机的输入设备(例如手柄|
      |          |          | 就通过这两个寄存器访问。|
      +----------+----------+---------------------------+
      |$4018   |$401F   | 未用??(未知)          |(8 字节)
      +----------+----------+---------------------------+
      |$4020   |$5FFF   | 扩展 ROM。                |(8 KB - 32 字节)
      |          |          | 某些有特殊处理芯片的游戏|
      |          |          | 卡利用了这块空间。      |
      +----------+----------+---------------------------+
      |$6000   |$7FFF   | SRAM(电池储存 RAM)。    |(4 KB)
      |          |          | 注意这块 RAM 不存在于 NES |
      |          |          | 本体,而是在某些游戏卡(|
      |          |          | 如 RPG 游戏卡)内部。   |
      +----------+----------+---------------------------+
      |$8000   |$FFFF   | 32K 程序代码 ROM。      |(32 KB)
      |          |          | 存在于游戏卡内部的 ROM,|
      |          |          | 内容为游戏程序代码。      |
      +----------+----------+---------------------------+


      NES 显示内存布局:
      ------------------

      +----------+----------+---------------------------+
      | 起始地址 | 结束地址 |         说明            |
      +----------+----------+---------------------------+
      |$0000   |$0FFF   | Pattern 表 #0             |(4 KB)
      +----------+----------+---------------------------+
      |$1000   |$1FFF   | Pattern 表 #1             |(4 KB)
      +----------+----------+---------------------------+
      |$2000   |$23BF   | Name 表 #0                |(960 字节)
      +----------+----------+---------------------------+
      |$23C0   |$23FF   | Attribute 表 #0         |(64 字节)
      +----------+----------+---------------------------+
      |$2400   |$27BF   | Name 表 #1                |(960 字节)
      +----------+----------+---------------------------+
      |$27C0   |$27FF   | Attribute 表 #1         |(64 字节)
      +----------+----------+---------------------------+
      |$2800   |$2BBF   | Name 表 #2                |(960 字节)
      +----------+----------+---------------------------+
      |$2BC0   |$2BFF   | Attribute 表 #2         |(64 字节)
      +----------+----------+---------------------------+
      |$2C00   |$2FBF   | Name 表 #3                |(960 字节)
      +----------+----------+---------------------------+
      |$2FC0   |$2FFF   | Attribute 表 #3         |(64 字节)
      +----------+----------+---------------------------+
      |$3000   |$3EFF   | $2000 - $2EFF 的镜像      |(4 KB)
      +----------+----------+---------------------------+
      |$3F00   |$3F0F   | 背景调色板                |(16 字节)
      +----------+----------+---------------------------+
      |$3F10   |$3F1F   | 精灵调色板                |(16 字节)
      +----------+----------+---------------------------+
      |$3F20   |$3FFF   | 调色板镜像。            |(上面的)
      |          |          |                           |(背景调色板)
      |          |          | $3F20 - $3F2F:背景调色板 |(精灵调色板)
      |          |          |                的镜像。   |(的 7 次镜像)
      |          |          | $3F30 - $3F3F:精灵调色板 |(共 224 字节)
      |          |          |                的镜像。   |
      |          |          | $3F40 - $3F4F:背景调色板 |(若连同上面本身的)
      |          |          |                的镜像。   |(两个调色板)
      |          |          | $3F50 - $3F5F:精灵调色板 |(共 256 字节)
      |          |          |                的镜像。   |
      |          |          | ......                  |
      +----------+----------+---------------------------+
      |$4000   |$FFFF   | $0000 - $3FFF 的镜像。    |
      |          |          |                           |
      |          |          | $4000 - $7FFF =         |
      |          |          | $0000 - $3FFF。         |
      |          |          |                           |
      |          |          | $8000 - $BFFF =         |
      |          |          | $0000 - $3FFF。         |
      |          |          |                           |
      |          |          | $C000 - $FFFF =         |
      |          |          | $0000 - $3FFF。         |
      +----------+----------+---------------------------+



NES CPU 信息(NES CPU Description)
=======================================

      NES 使用一块定制的 6502 CPU,主要在原 6502 的基础上加入
      了音频处理能力。NES 的 6502 芯片 *只有* 151 个操作码,
      换句话说,很多文档中介绍的所谓非公布(Undocumented)操
      作码都是不正确的,那么如果 NES 执行到不支持的操作码时会
      发生什么事呢?hmmm.....谁知道?:-)

      NTSC 制式的 NES,其 CPU 的运行频率为 1.7897725MHz;
      PAL 制式的 NES,其 CPU 的运行频率为 1.773447MHz。

      NES 的 6502 不支持十进制模式(Decimal Mode),也就是说,
      即使 CPU 的“D”标志被设定为 1,在执行加/减指令后结果仍
      不会被调整为二进制编码的十进制(BCD)。

      NES 的 6502 在对于操作码 6C(JMP Indirect)的处理上有一
      个 bug:如果操作数的低字节 = $FF,这个指令就无法正常执
      行,比如:
                           $AB00: $12
                           $ABFF: $34
                           $AC00: $56
                     指令:JMP ($ABFF)
      理论上,这条指令被执行后,程序流程将跳转到 $5634。
      但是 NES 的 6502 在执行这条指令时,无法正常地读取操作
      数,它在读取高字节时,页面不会进行处理。换句话说,如果
      高低字节所在的页面不同(比如上面:1 个在 $AB,1 个在
      $AC),它将在低字节所在的页面($AB)读取高字节,那么,
      本来应该到 $AC00 读取高字节的,结果就变成了 $AB00,最
      后的跳转地址就成了 $1234 而不是 $5634。

      NES 有 3 个中断:NMI,Reset,BRK/IRQ。
      NMI 发生在屏幕刷新期间。
      当 PPU 完成一帧画面的显示后,产生该中断。
      注意这个中断可通过修改 PPU 控制寄存器屏蔽掉。
      (纳闷~那为什么叫做 NMI:Non-Maskable-Interrupt >_<)
      Reset 发生在接通电源或按下游戏机 RESET 按钮时。
      Reset 的中断向量实际上就是游戏程序的入口。
      BRK/IRQ 是程序中断。在执行 BRK 指令后产生该中断。
      另外 pAPU 和一些具有特殊功能的游戏卡也能产生该中断。
      它们的 16 位中断向量储存在(低字节在前,高字节在后):
                         NMI:    $FFFA,$FFFB
                         Reset:$FFFC,$FFFD
                         BRK/IRQ:$FFFE,$FFFF
      其中,Reset 的中断优先级最高,NMI 其次,BRK/IRQ 最低。

      产生 BRK/IRQ 中断的情况有两种:执行 BRK 指令;硬件调用。
      那么,中断处理程序如何判断是谁调用中断呢?
      如果是执行 BRK 产生该中断,那么压入堆栈的状态寄存器值,
      其 B 标志 = 1;如果是硬件调用而产生该中断,那么压入堆
      栈的状态寄存器值,其 B 标志 = 0。
      因此可通过下面的代码进行判断:
            C134: PLA               ; 将堆栈中状态寄存器的值
                                    ; 读入累加器。
            C135: PHA               ; 还原堆栈指针。
            C136: AND #$10            ; 检查状态寄存器的第4位
                                        (B 标志位)。
            C138: BNE is_BRK_opcode   ; 如果 = 1,表示是由 BRK
                                    ; 指令所产生的。

      什么?操作码资料?well...well.....自己学吧,我并不打算
      在这份文档中教你怎么写 6502 汇编程序……anyway, 如果你
      懂 PC 汇编,这个应该难不倒你:so, learn it yourself!


NES PPU 信息(NES PPU Description)
=======================================

      PPU(屁屁油),也就是 Picture Processing Unit,NES 的
      图形处理芯片。这是 NES 中最重要的设备之一,同时也是个
      挺复杂的东西。
      PPU 包含一块 10KB 左右的 RAM,叫做 VRAM(Video RAM),
      即显示内存。以及一块 256 字节的 OAM(精灵属性内存)。
      这两块 RAM 基本上描述了显示在屏幕上的一切图像信息。
      CPU 不能直接访问 PPU 内部的 RAM,只能通过 PPU 映射在系
      统内存特别位置的寄存器间接访问它们。
      同时,CPU 要想控制 PPU,也只能通过这些寄存器实现。
      在 PPU 中,有 3 个很重要的表,描述了当前显示的图像:
      Pattern 表、Name 表、以及 Attribute 表。
      在说明这些表的用途前,我们先来看看 PPU 储存图形元素的
      方式。
      在 PC 中,通常最基本的图形元素是“像素”(pixel),说
      白了就是屏幕上的一个小点。而在 NES 的 PPU 中,最基本的
      图形元素是“Tile”。
      Tile 是什么?
      它是一个由 8x8 像素组成的方块。当然每个 Tile 也就描述
      了一块 8x8 的图像。而整个屏幕又由 32x30 个 Tile 组成。
      由此也可计算出 NES 的屏幕分辨率 = 256x240 像素。
      NES 一共支持 512 个 Tile,它们的图像(点阵)信息储存在
      Pattern 表中。而 Name 表用来描述显示在屏幕上的图像,在
      这个表中储存的实际上是 Tile 号。PPU 从 Name 表中读取
      Tile 号,然后根据 Tile 号到 Pattern 表中获取图像的点阵
      信息,再根据这些点阵信息综合 Attribute 表在屏幕上画图。
      (很复杂?well...可能是我说得不太清楚,read on!)
      简单来说,把整个屏幕比作一面墙,而 Tile 就是组成这面墙
      的大小相等的砖块。
      为什么要使用 Tile?
      由于电子游戏画面中,通常会出现很多重复的部分,如果一一
      描述它们的点阵信息,实际上是一种空间上的浪费,而如果用
      Tile,就可以有效地避免这个问题。

      (不管你看没看懂,read on! ;-))

      -=[ Pattern 表 ]=-
      NES 的 PPU 一共有 2 个 Pattern 表:
      Pattern 表 #0:位于显示内存 $0000 - $0FFF,共 $1000 字节。(4 KB)
      Pattern 表 #1:位于显示内存 $1000 - $1FFF,共 $1000 字节。(4 KB)

      Pattern 表中,储存着 Tile 的点阵信息(如果你是
      romhacker,那么我告诉你:Pattern 表中,储存着字库)。
      每个 Tile 占用 16 字节,它的格式如下:
      前 8 个字节:
      每个字节由 8 个二进制位组成,每个位描述一个像素颜色值的
      第 0 位。一个字节(8个位)恰好描述一行像素颜色值的第 0
      位。8个字节描述一个 Tile 所有像素的颜色值第 0 位。
      后 8 个字节:
      每个字节由 8 个二进制位组成,每个位描述一个像素颜色值的
      第 1 位。一个字节(8个位)恰好描述一行像素颜色值的第 1
      位。8个字节描述一个 Tile 所有像素的颜色值第 1 位。
      由此可见,每个 Tile 所表现的色彩范围是 2 位。
      实际上,这只是最终显示在屏幕上图像色彩的 *低 2 位*。
      (BTW:高 2 位在 Attribute 表中,后面讲)。
      具体的储存方式,我们用一个例子来说明:

         地址      Pattern表内容
      -------   ---------------
      字节 1:   %00010000 = $10 --+
      字节 2:   %00000000 = $00   |
      字节 3:   %01000100 = $44   |
      字节 4:   %00000000 = $00   +-- 第 0 位
      字节 5:   %11111110 = $FE   |
      字节 6:   %00000000 = $00   |
      字节 7:   %10000010 = $82   |
      字节 8:   %00000000 = $00 --+
      字节 9:   %00000000 = $00 --+
      字节10:   %00101000 = $28   |
      字节11:   %01000100 = $44   |
      字节12:   %10000010 = $82   +-- 第 1 位
      字节13:   %00000000 = $00   |
      字节14:   %10000010 = $82   |
      字节15:   %10000010 = $82   |
      字节16:   %00000000 = $00 --+


      实际图像
      --------
      ...1....   注:为便于观察,这里用 . 代表 0。
      ..2.2...         数字表示图像相应位置的颜色值。
      .3...3..
      2.....2.
      1111111.
      2.....2.
      3.....3.
      ........

      可见,这个 Tile 所描述的图像是一个“A”字。每个像素
      的颜色值如上图所示。
      它储存在 Pattern 表中的 16 字节点阵信息按顺序依次是:
      $10,$00,$44,$00,$FE,$00,$82,$00,
      $00,$28,$44,$82,$00,$82,$82,$00。

      在 Pattern 表中,每个 Tile 占 16 字节,由于每个 Pattern
      表的大小是 $1000 字节,所以,每个 Pattern 表可储存
      $1000 / 16 = 256 个 Tile 的点阵信息。两个 Pattern 表
      一共可储存 512 个 Tile 的点阵信息。


      -=[ Name 表 ]=-
      Name 表描述的是实际显示在屏幕上的图像。但和 PC 的显存不
      同的是,PC 显存中保存的是屏幕上每个像素的颜色信息,而
      Name 表中保存的是 Tile 号。(如果你是 romhacker,那么我
      告诉你:Name 表中,储存着脚本)
      PPU 一共支持 4 个 Name 表,但 PPU 本体的显存空间实际上只
      允许存在 2 个 Name 表。多数情况下,另外 2 个是前 2 个的
      镜像(这个比较复杂,后面讲)。
      每个 Name 表将屏幕定义为一块 32x30 个 Tile 的区域。其中
      用一个字节描述一个 Tile 号,所以,每个 Name 表的大小就是
      32x30 = $3C0 字节。
      由于用一个字节描述一个 Tile 号,所以 Tile 号的取值范围可
      以是 0 - 255 共 256 个。PPU 在画图时,首先读取 Tile 号,
      然后按照 Tile 号到指定的 Pattern 表中读取点阵信息。
      注意每个 Pattern 表包含 256 个 Tile,位于 $0000 - $000F
      的是 0 号 Tile,$0010 - $001F 为 1 号 Tile,$0020 -
      $002F 为 2 号 Tile,以此类推……
      由于 Pattern 表一共有 2 个,所以具体到哪个 Pattern 表中
      读取点阵信息,这取决于 PPU 寄存器的设置,后面将有介绍。


      -=[ Attribute 表 ]=-
      前面曾提到,Attribute 表保存着屏幕图像颜色信息的高 2 位。
      是的,综合 Name 表和 Pattern 表所输出的图像,其颜色是 2
      位的。而真正显示在屏幕上的颜色,还应该综合 Attribute 表
      中所描述的高 2 位。
      Attribute 表也有 4 个,同样由于显存空间,允许存在的仅有
      2 个。说白了,它和 Name 表一一对应。
      每个 Attribute 表的大小是 $40 字节。
      Attribute 表中,每个字节(姑且称为 Attribute 字节)描述
      了屏幕上 4x4 个 Tile (姑且把这个 4x4 的 Tile 区域称为
      “描述区”)的高 2 位,具体定义如下:

      Attribute 字节位                   定义
      ----------------------------------------------------
             0 - 1      描述区中左上角 2x2 个 Tile 的高 2 位。
             2 - 3      描述区中右上角 2x2 个 Tile 的高 2 位。
             4 - 5      描述区中左下角 2x2 个 Tile 的高 2 位。
             6 - 7      描述区中右上角 2x2 个 Tile 的高 2 位。

      举个例子,Attribute 表中的第一个字节描述的就是屏幕上最
      左上角 4x4 Tile(相当于一个 32x32 像素的方块区)的颜色
      信息的高 2 位。
      屏幕上一共有 8x8 个“描述区”(分辨率相当于 256x256,不
      过由于 NES 的分辨率只有 256x240,所以最下方的 16 行像素
      相当于是浪费了)。


      -=[ Name 表和 Attribute 表镜像 ]=-
      前面说到,PPU 一共支持 4 个 Name/Attribute 表(位于显存
      $2000 - $2FFF 共 $1000 字节),但显存空间实际只够容下 2
      个 Name/Attribute 表(只有 $800 字节的实际空间)。这 4
      个 Name/Attribute 表每 2 个共享一块空间($400 字节)。
      那么到底哪 2 个共享哪一块空间呢?分两种情况,“垂直镜像”
      和“平行镜像”。但也有例外的情况,比如“单屏镜像”和
      “四屏布局”。

      具体是怎样的呢?总的来说,有 4 种情况:
      1、垂直镜像(Vertical Mirror)
      2、平行镜像(Horizontal Mirror)
      3、单屏镜像(Single Screen)
      4、四屏布局(4-Screen layout)

      1 - 垂直镜像
      ------------
      在这种情况下,
      Name/Attribute 表 #0 和 Name/Attribute 表 #2 使用
      PPU 内部前 $400 字节的空间。
      Name/Attribute 表 #1 和 Name/Attribute 表 #3 使用
      PPU 内部后 $400 字节的空间。

      2 - 平行镜像
      ------------
      在这种情况下,
      Name/Attribute 表 #0 和 Name/Attribute 表 #1 使用
      PPU 内部前 $400 字节的空间。
      Name/Attribute 表 #2 和 Name/Attribute 表 #3 使用
      PPU 内部后 $400 字节的空间。

      3 - 单屏镜像
      ------------
      在这种情况下,4 个 Name/Attribute 表都共享同一个空间,
      具体是哪个呢?这要视情况而定。

      4 - 四屏布局
      ------------
      在这种情况下,4 个 Name/Attribute 表每个都拥有物理的
      空间,也就是说每个都是实际存在的。你也许会问:前面不
      是说显存中没有空间容下另外 2 个 Name/Attribute 表吗?
      当然,所以,这另外 2 个 Name/Attribute 表的空间一般
      来自特殊的游戏卡带内部(当然由于这个原因,这种游戏卡
      的售价比一般的游戏卡都要贵一些啰 ^o^ )。
      Name/Attribute 表 #0:使用 PPU 内部空间前 $400 字节。
      Name/Attribute 表 #1:使用 PPU 内部空间后 $400 字节。
      Name/Attribute 表 #2:使用游戏卡提供的空间。
      Name/Attribute 表 #3:使用游戏卡提供的空间。


      前面说到的 3 个表所描述的图像,实际上仅仅是 NES 的背
      景层,NES 一共有 2 个层,除了背景层,还有一个是“精灵
      层”(Sprite Layer)。
      So WHAT is a sprite? 精灵是什么东西?
      所谓精灵,就是屏幕上自由活动的图块。例如:游戏中玩家所
      操纵的角色。

      NES 的 PPU 拥有一块 256 字节的精灵属性内存(OAM,Object
      Attributes Memory,也叫 SRAM,Sprite RAM)。
      NES 的 PPU 一共可处理 64 个 8x8 或 8x16 大小的精灵。
      这 64 个精灵的属性(坐标,标志,Tile 号)被均匀地储存
      在 256 字节的 OAM 中,每个精灵占用 256 / 64 = 4 个字节。
      每个精灵的 4 字节属性内容解释如下:
      +--------+-------------------------------------------+
      | 字节 # |                   说明                  |
      +--------+-------------------------------------------+
      | 字节 1 | 精灵的 Y 坐标 - 1。                     |
      |      |                                           |
      |      | 这个字节 = 精灵所在屏幕位置的 Y 坐标 - 1|
      |      | 注意坐标是以像素为基准而不是 Tile。       |
      +--------+-------------------------------------------+
      | 字节 2 | 精灵的 Tile 号。                        |
      |      |                                           |
      |      | 精灵的图像也是用 Tile 表示的。这个字节表|
      |      | 示该精灵使用哪个 Tile,注意 Tile 所对应的 |
      |      | 实际图像储存在 Pattern 表中。             |
      +--------+-------------------------------------------+
      | 字节 3 | 精灵的标志。                              |
      |      |                                           |
      |      | 第 0-1 位:精灵色彩值的高 2 位。          |
      |      |            注意背景是通过 Attribute 表储|
      |      |            存高 2 位的。                  |
      |      |                                           |
      |      | 第 2-4 位:未用。                         |
      |      |                                           |
      |      | 第 5 位:精灵优先级。如果 = 0,则将精灵显 |
      |      |          示在背景层前面,如果 = 1,则将精 |
      |      |          灵显示在背景层后面。             |
      |      |                                           |
      |      | 第 6 位:平行翻转。如果 = 0,则精灵按正常 |
      |      |          显示。如果 = 1,则将精灵的 Tile|
      |      |          平行翻转后显示。就好像一块透明玻 |
      |      |          璃,你到背面看写在正面的字一样。 |
      |      |                                           |
      |      | 第 7 位:垂直翻转。如果 = 0,则精灵按正常 |
      |      |          显示。如果 = 1,则将精灵的 Tile|
      |      |          垂直翻转后显示。也就是说,第 1   |
      |      |          行像素显示在第 8 行,第 8 行显示 |
      |      |          在第 1 行,第 2 行像素显示在第 7 |
      |      |          行……                           |
      +--------+-------------------------------------------+
      | 字节 4 | 精灵的 X 坐标。                           |
      +--------+-------------------------------------------+
      注意在 OAM 中,每 4 个字节就是一个精灵的属性,$00 - $03
      是 0 号精灵,$04 - $07 是 1 号精灵,$08 - $0B 是 2 号精
      灵……每个精灵的 4 字节属性均是按照上面的格式储存的。
      同背景层一样,精灵的图像信息也是以 Tile 的形式来体现的。
      同背景层一样,精灵也通过 PPU 的寄存器来决定从哪个 Pattern
      表中读取 Tile 的点阵信息。
      NES 的 PPU 支持两种尺寸的精灵,8x8 和 8x16。
      8x8 精灵非常简单,它只包含一个 Tile,精灵属性中明确说明
      了这个 Tile 的实际图像到底从何而来。
      而 8x16 精灵就有所不同了,8x16 的精灵,由上下两部分组成,
      每个部分均是一个 Tile,换句话说,8x16 的精灵一共包含两
      个 Tile,一个在上一个在下。可是,精灵属性中只有一个 Tile
      字节,那么另一个 Tile 号到底是多少呢?
      PPU 做出这样的规定:对于 8x16 的精灵,将 Tile 号第 0 位
      作为标志位,表示 Tile 来自哪个 Pattern 表,如果 = 0,则
      来自 Pattern 表 #0,如果 = 1,则来自 Pattern 表 #1。换
      句话说,PPU 寄存器则无法决定 8x16 精灵的 Tile 来自哪个
      Pattern 表。而精灵属性中的 Tile 号,其 1 - 7 位则表示精
      灵两个 Tile 的 Tile 号的 1 - 7 位,对于第 1 位,上方
      Tile = 0,下方 Tile = 1。
      举个例子,比如一个 8x16 精灵,其 Tile 号 = $B9,那么:
      $B9 = %10111001
               |   ||
               |   |+-- 第 0 位 = 1,Tile 来自 Pattern 表 #1。
               |   |
               |   +--- 上方 Tile = %10111000 = $B8。
               |
               +--------- 下方 Tile = %10111001 = $B9。


      PPU 规定:如果某个像素的低 2 位 = 0,则这个像素透明。
      这是怎么回事呢?前面已经说过,每个 Tile 包含一块 8x8
      像素区域的颜色值低 2 位,换句话说,每个 Tile 包含 8x8
      个像素的低 2 位。那么,如果其中某一个像素的低 2 位值
      = 0,那么 PPU 在绘制这个 Tile 时,这个像素就不会被画
      在屏幕上。
      举个例子,比方说上面出现的 A:
                              ...1....
                              ..2.2...
                              .3...3..
                              2.....2.
                              1111111.
                              2.....2.
                              3.....3.
                              ........
      图中用“.”表示的像素,就是透明像素,因为其颜色值的低
      2 位 = 0。

-----------------------结束-------------------------------------------






回到正题,这次整理代码时把NES作为一个元件剖离了出来,使得移植比较方便,而不仅仅限于DE系列的开发板
entity nestop is
    port (
                cpuclk : in std_logic;   ---usually 1/6 of ppuclk
                ppuclk : in std_logic;   --- expect 25Mhz
                memclk : in std_logic;   --- expect 50Mhz
                reset : in std_logic;
                hs : out std_logic;
                vs : out std_logic;
                r : out std_logic_vector(3 downto 0);
                g : out std_logic_vector(3 downto 0);
                b : out std_logic_vector(3 downto 0);
                joy1        :        in std_logic_vector(7 downto 0);
                joy2        :        in std_logic_vector(7 downto 0);
                sram_mapper : in std_logic_vector(3 downto 0);
                isdouble : in std_logic   ---256x240 or 512x480 ?
                );
end nestop;


其中joy1和joy2参照下面的图片,可以直接使用FC手柄,也可以通过其他方式实现
http://cache.ourdev.cn/bbs_upload489681/files_9/ourdev_241140.jpg


cpuclk的话通过ppuclk分频得到,在一个时序严格的NES游戏机里面他们有下面的时序关系
        NTSC制式        PAL制式
基频(Base clock)        21477270.0Hz        21281364.0Hz
CPU主频(Cpu clock)        1789772.5Hz        1773447.0Hz
总扫描线数(Total scanlines)        262        312
扫描线总周期(Scanline total cycles)        1364(15.75KHz)        1362(15.625KHz)
水平扫描周期(H-Draw cycles)        1024        1024
水平空白周期(H-Blank cycles)        340        338
结束周期(End cycles)        4        2
帧周期(Frame cycles)        1364*262        1362*312
帧IRQ周期(FrameIRQ cycles)        29830        35469
帧率(Frame rate)        60(59.94Hz)        50Hz
帧时间(Frame period)        1000.0/60.0(ms)        1000.0/50.0(ms)

不过由于设计的困难,目前还没有实现严格的时序,因此这里的cpuclk可能得随着游戏的不同在3分频,4分频,。。。7分频,8分频等之间变动,可以把分频大小用开关引出,对于不同的游戏调整即可。

压缩包里面包含的游戏有:
坦克大战
超级玛丽
水管玛丽
大金刚3
吃豆
弹射球
猫捉老鼠
三只小猪
中国象棋
以及两个专门用于NES测试的游戏

游戏可以自己从NES ROM中提取,目前支持的卡带大小为24K和40K的,24K游戏提取的时候请将ROM取重复一遍即可(什么,你问我魂斗罗能不能玩??我也想玩啊,但遗憾的是它是个128K的游戏,目前还不支持)


http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_551213.JPG
(原文件名:1.JPG)

http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_551214.JPG
(原文件名:2.JPG)

点击此处下载 ourdev_551215.rar(文件大小:1.35M) (原文件名:nestop.rar)

tear086 发表于 2010-5-3 10:37:40

顶楼主;谢谢分享。
正好,手上有个DE2。

Yan.hong.yu 发表于 2010-5-3 10:47:13

这是不是要嵌入软核?

zlei 发表于 2010-5-3 10:49:42

感兴趣!

chenxiao07 发表于 2010-5-3 10:53:23

呵呵,顺便把关于NES的更详细的资料一块上传了吧,方便大家更详细的了解其原理。这些东西比较冷门,不是很好找。

小霸王游戏机.rarourdev_551216.rar(文件大小:1.29M) (原文件名:小霸王游戏机.rar)

chenxiao07 发表于 2010-5-3 10:54:51

回复【2楼】Yan.hong.yu
这是不是要嵌入软核?
-----------------------------------------------------------------------

里面用到的6502CPu和NES专用的PPU就可以说是软核

这个不是模拟的,是直接硬件实现

kinoko 发表于 2010-5-3 11:03:34

学习了,ppu显示方式。

elecfun 发表于 2010-5-3 12:28:33

很好的资料啊

kk67696248 发表于 2010-5-3 13:18:08

标记一下,谢谢楼主

eworker 发表于 2010-5-3 16:28:05

学习

PaulDE 发表于 2010-5-3 16:31:26

mark

cqfeiyu 发表于 2010-5-3 16:44:05

强帖

zengyi703 发表于 2010-5-3 16:53:14

mark

AIHHLI 发表于 2010-5-3 17:08:31

不懂,但资料确实很好。

youki1234 发表于 2010-5-3 17:34:26

mark

xlwxdl1 发表于 2010-5-3 17:50:30

哈哈,正有兴趣研究下。谢谢楼主啊。

wajlh 发表于 2010-5-3 20:50:15

楼主强

aleyn 发表于 2010-5-4 08:26:44

收藏

lsw0136 发表于 2010-5-4 08:46:22

mark

huwenhui 发表于 2010-5-4 09:02:10

收藏!

liangbmw 发表于 2010-5-4 09:03:33

收藏

geniusjia 发表于 2010-5-4 09:18:55

很好的资料!谢谢!

sun_gan 发表于 2010-5-4 09:19:40

回复【4楼】chenxiao07
呵呵,顺便把关于nes的更详细的资料一块上传了吧,方便大家更详细的了解其原理。这些东西比较冷门,不是很好找。
小霸王游戏机.rar (原文件名:小霸王游戏机.rar)

-----------------------------------------------------------------------

一直在关注你这个项目,从你上回发布我也默默的在搞这个,不过我的目标是使用LCD作为显示输出,而整体资源能限定在EP2C5或EP2C8中
因为我手里只有EP2C8的板子,没有DE2那么多的资源那
现在LCD功能已经做好,在你的程序稍作修改的基础上也能运行起来了,但是还有不少问题
我的下一目标是做一个硬件总线操作和时序上尽量与6528接近的PPU,不使用双端口的RAM,ROM实现ram,vram,vrom
在查找精确的PPU时序说明的时候,发现了一篇好文档,看了之后有醍醐灌顶的感觉啊,绝对不可多得
尤其是PPU部分,绝对是最精确的描述,不敢独享啊
点击此处下载 ourdev_551332.pdf(文件大小:615K) (原文件名:NES Specifications.pdf)

avrwoo 发表于 2010-5-4 10:49:52

mark

vermon 发表于 2010-5-4 10:50:48

楼主你很牛皮

loveghb 发表于 2010-5-4 11:09:35

mark

xiaoniu 发表于 2010-5-4 12:10:10

mark

hecat 发表于 2010-5-4 12:43:45

儿时的梦想啊。

guke 发表于 2010-5-4 13:17:11

不错不错。。。

bad_fpga 发表于 2010-5-4 13:58:28

MARK

chenxiao07 发表于 2010-5-4 14:20:37

回复【23楼】sun_gan
回复【4楼】chenxiao07   
呵呵,顺便把关于nes的更详细的资料一块上传了吧,方便大家更详细的了解其原理。这些东西比较冷门,不是很好找。
小霸王游戏机.rar (原文件名:小霸王游戏机.rar)
-----------------------------------------------------------------------
一直在关注你这个项目,从你上回发布我也默默的在搞这个,不过我的目标是使用lcd作为显示输出,而整体资源能限定在ep2c5或ep2c8中
因为我手里只有ep2c8的板子,没有de2那么多的资源那
现在lcd功能已经做好,在你的程序稍作修改的基础上也能运行起来了,但是还有不少问题
我的下一目标是做一个硬件总线操作和时序上尽量与6528接近的ppu,不使用双端口的ram,rom实现ram......
-----------------------------------------------------------------------

你太厉害了~~我觉得我写的代码糟糕得自己都不想去碰它了,没想到你居然还成功移植了。。。。

呵呵,话说回来,要弄到ep2c8上问题应该不大,LE够用,只要把rom以及vrom换成外部sdram就可以了,不过vrom需要改成单端口
但2c5就够呛了,据说那上面跑个nios都难。
至于时序的问题你那篇文章相当详细啊,可惜写之前没看过,现在又懒得去改了。呵呵,如果你做出来了,那么不妨也开源分享,那会是一件非常赞的事~~~

dickhou 发表于 2010-5-4 14:30:36

ppu 部分是楼主写的吗?想了解一下颜色是怎么得出来的,你那个r/g/b的表是怎么回事?

dickhou 发表于 2010-5-4 14:34:28

Port 2001h/Bit7-5 allow to adjust the palette, eg. with setting 001b the whole picture becomes more green.
000b Normal
001b Green
010b Brown
100b Blue

另外,上面这三位好像没有实现,是不是没有游戏用这三位?

ksniper 发表于 2010-5-4 14:39:59

mark、

loveghb 发表于 2010-5-4 16:09:30

我这里有块3C40的板子估计是够了

sun_gan 发表于 2010-5-4 16:20:36

回复【31楼】chenxiao07
-----------------------------------------------------------------------
你太厉害了~~我觉得我写的代码糟糕得自己都不想去碰它了,没想到你居然还成功移植了。。。。

呵呵,话说回来,要弄到ep2c8上问题应该不大,LE够用,只要把rom以及vrom换成外部sdram就可以了,不过vrom需要改成单端口
但2c5就够呛了,据说那上面跑个nios都难。
至于时序的问题你那篇文章相当详细啊,可惜写之前没看过,现在又懒得去改了。呵呵,如果你做出来了,那么不妨也开源分享,那会是一件非常赞的事~~~
-----------------------------------------------------------------------
你太谦虚了,正因为有你的代码在,我才得以用我的想法一部分一部分的替换改造,否则我的想法根本无从着手啊
我把原来VGA用的LineBuf给去掉之后,基本上资源占用可以到6000~7000LE的水平
至于rom,vrom么肯定是不够了,我弄了个小蜜蜂的游戏,它需要8K的程序rom和8K的vrom,但是ep2c8的M4K块已经不够了
所以我只留了8k的程序rom和vrom的背景页,卡通页用的是背景页的镜像才勉强装下,一个M4K都不剩了,当然执行时一部分的卡通是花的
后面如果调试通过后我是准备用外部的sdram的,但是这就涉及到还要搞一个游戏rom动态载入了,唉,莫非还要加个nios?
现在ppu部分正在努力的搞,搞好一定分享

sun_gan 发表于 2010-5-4 17:07:02

回复【33楼】dickhou
port 2001h/bit7-5 allow to adjust the palette, eg. with setting 001b the whole picture becomes more green.
000b normal
001b green
010b brown
100b blue
另外,上面这三位好像没有实现,是不是没有游戏用这三位?
-----------------------------------------------------------------------

应该不是没有游戏用到这几位吧,不过这个并不是什么很要紧的功能,完全可以以后再实现吧

jd.warlock 发表于 2010-5-4 17:15:29

学习,楼主强人

dickhou 发表于 2010-5-4 17:35:19

port 2001h/bit7-5 allow to adjust the palette, eg. with setting 001b the whole picture becomes more green.
000b normal
001b green
010b brown
100b blue
另外,上面这三位好像没有实现,是不是没有游戏用这三位?
-----------------------------------------------------------------------

应该不是没有游戏用到这几位吧,不过这个并不是什么很要紧的功能,完全可以以后再实现吧



我想了解一下具体应该怎么实现?例如值为001,使图像更绿一些,难道是整个颜色上加上一定比例的绿色?

sun_gan 发表于 2010-5-4 19:27:21

应该只是控制底背景色,也就是颜色编码为0时的底背景色
彩色模式和黑白模式时的操作有些差别,具体可以参照下面文档的23页
点击此处下载 ourdev_551497.pdf(文件大小:210K) (原文件名:任天堂产品系统文件.pdf)
你也可以下一个开源的nes模拟器,看看他的源代码中是怎样实现的

aureole 发表于 2010-5-4 20:43:38

真牛比

andriy 发表于 2010-5-6 11:21:10

楼主真是强悍!

bodyopq 发表于 2010-5-6 13:58:03

占位置!

zbjzxc 发表于 2010-5-6 15:26:03

佩服~~

Bromi 发表于 2010-5-7 12:31:05

学习了

jackzh 发表于 2010-5-7 16:52:20

关注中!

zxl2431 发表于 2010-5-7 21:08:37

顶顶

zxl2431 发表于 2010-5-7 21:09:12

顶顶

ZZL520 发表于 2010-5-12 08:38:04

好东西哟~!!!!!!!!!!!1

catzl7 发表于 2010-5-12 08:48:35

顶啊,值得学习

tedden 发表于 2010-5-29 20:53:30

好资料,mark

bobqq 发表于 2010-5-29 23:13:39

好东西..记号!

luan_dahai 发表于 2010-6-16 13:28:28

mark

tmpond 发表于 2010-6-16 21:19:18

记录

motion_ctrl 发表于 2010-6-18 14:55:03

mark

wang110 发表于 2010-6-19 00:49:53

我移植的NES,基于qq2440,求助
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4104963&bbs_page_no=1&bbs_id=1032

ldqmoon 发表于 2010-6-19 16:19:11

mark

ljt8015 发表于 2010-6-19 16:48:02

mark!~

zucc30702088 发表于 2010-6-19 17:46:28

DE1能实现吗

sdmmqy 发表于 2010-6-19 18:12:20

值得学习

wangqishao 发表于 2010-6-19 18:19:06

mark

glass356 发表于 2010-6-21 22:47:42

有没可能实现 玩记录卡ROM??

wang110 发表于 2010-6-24 21:58:50

http://cache.amobbs.com/bbs_upload782111/files_30/ourdev_563651V2C0GX.JPG
(原文件名:5401.JPG)

litop 发表于 2010-6-24 23:29:42

..经典,小时候经常玩的游戏

gahang 发表于 2010-6-25 09:45:00

2层楼上,这是你做的板子?用什么器件实现的?

wang110 发表于 2010-6-25 12:43:26

回复【66楼】gahang
-----------------------------------------------------------------------

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4104963&bbs_page_no=1&bbs_id=1032

QQ2440

cancerlock 发表于 2010-6-26 14:47:58

收藏

santi7009 发表于 2010-8-31 21:01:00

MARK

kingreat 发表于 2010-8-31 21:27:19

赞一个,楼主很强大!!

wanwzy 发表于 2010-8-31 22:52:10

mark

liangtao 发表于 2010-9-1 08:18:00

mark

barryyan2007 发表于 2010-9-1 08:41:50

学习了哦

maidong 发表于 2010-9-4 23:57:25

很感兴趣,mark

catzl7 发表于 2010-9-5 01:35:39

强大的楼主!

tt20085223 发表于 2010-9-13 14:18:59

强大的楼主啊

bd4sad 发表于 2010-9-13 15:08:51

mark

xiaoniu 发表于 2010-9-13 19:33:05

mark

wso75839840 发表于 2010-9-13 22:18:32

mark

esdart 发表于 2010-9-14 09:24:02

太猛了,是不是也必须要这么猛的硬件才能跑起来。

qzx0907 发表于 2010-9-14 11:57:50

mark

avic 发表于 2010-9-20 23:10:20

mark

sunjie718 发表于 2010-9-21 08:35:06

mark

obit 发表于 2010-9-21 10:22:22

整个任天堂系统中就属PPU和APU这两快最难懂

yl604922959 发表于 2010-9-21 21:33:58

厉害啊

ye_song 发表于 2010-9-24 09:43:19

厉害啊

Forest_liu 发表于 2010-9-24 10:51:10

强人啊!

dzq112358 发表于 2010-9-24 11:01:17

强人,顶…………

relotus 发表于 2010-10-9 08:27:12

mark

252177861 发表于 2010-10-9 17:28:31

标记下

zxcvb110 发表于 2010-10-10 21:46:31

好强啊!!!

heibaogame 发表于 2010-10-13 16:25:21

MARK

AG17 发表于 2010-10-13 18:59:13

强人

cuikai12345 发表于 2010-10-13 19:24:43

mark

Spunky 发表于 2010-10-14 13:29:17

mark

wo_LKH 发表于 2010-10-14 19:18:54

学习了

jack_yu 发表于 2010-10-14 23:57:30

mark!

howmoney 发表于 2010-11-30 22:20:00

mark!!!

swong 发表于 2010-11-30 23:37:43

mark

wwwdege 发表于 2010-11-30 23:58:46

厉害

bone 发表于 2010-12-1 01:22:26

mark
页: [1] 2 3 4
查看完整版本: 基于FPGA的NES游戏机系统,附带超级玛丽,坦克大战,吃豆等11个游戏