WindowsPhone-GameBoy模拟器开发四--Gameboy显示系统分析
这次说一下GB的显示系统,先从一幅Gb的内存分布图说起,请看图:
图中红色框框起来的部分就是这篇文章关注的部分,这一部分的内存地址从8000-9Fff,共8KB,这一部分是从来存储背景和游戏“精灵”的数据的。通常我们认为Gb只能显示黑、白两种颜色,但其实,Gb还能显示明、暗灰度,总共是4种颜色。这样,显示出来的每个像素点需要占用两个bit的空间。对于Gb的显示系统来说,屏幕会缓存256*256大小的图片,其中160*144大小的某个区域会显示在液晶屏上,我们算一下,要缓存的图片的大小为256*256*2=16KB。但是我们的显存只有从8000-9Fff的8KB,显然是放不下的。所以Gameboy使用了某种机制,使不够16KB的显存也能够显示出16KB大小的内容,这种机制就是再显存中一部分用来存放图片数据,一部分用来存放映射数据。图片被划分为每个8*8大小的块(tile),每个块有一个编号,而在映射数据的部分存的只是每个块的编号,这样子,每个块就有可能会被重复使用,从而达到在不足16KB显存的情况下显示16KB数据的目的。这就解释了为什么在上一篇文中,我直接把任天堂的logo数据加载成图片,显示出来的东西确怎么看都不像是一个logo,其实加载进来的数据只是一个映射数据,而不是真正的图片数据。
好,我们继续。知道了gameboy的显示机制之后再重新看一下显存中的数据分布情况,请看下表:
区域 |
作用 |
8000-87FF |
图块集1: 图块编号0-127 |
8800-8FFF |
图块集1: 图块编号128-255 |
9000-97FF |
图块集0: 图块编号0-127 |
9800-9BFF |
图块集0的映射区域 |
9C00-9FFF |
图块集1的映射区域 |
图块集1可以用来显示背景、窗口和精灵,图块集0用来显示背景和窗口。这里的窗口指的就是160*144大小的在液晶屏上显示的区域。
精灵
Gameboy可以控制40个精灵的显示,每个精灵的大小为8*8或者8*16的图片块,同时,受硬件能力限制,每个扫描线(scan line,对这个概念理解得不是很好,希望有人能帮助解释一下)只能显示10个精灵。每个精灵的图片数据存放在8000-8Fff的区域中,就是上面说的图块集1所在的区域。而精灵自身的属性数据(x和y坐标等数据)则存放在专门的精灵属性表中(Sprite Attribute Table),也叫对象属性内存OAM(Object Attribute Memory),该区域位于内存FE00-FE9F中,OAM被划分成40个4字节的块,每个块代表一个精灵。
对于精灵对象,x坐标越小则它的显示优先级越高,对于拥有同样x坐标的精灵对象,则通过它在OAM中的顺序来区分显示优先级(FE00的最高,FE04的次之,然后依次往下)。
由于最多只能有10个精灵在同一行上显示,所以,在一行有超过10个精灵的时候,显示优先级低的将会被隐藏。为了避免不使用的精灵影响正常精灵的显示,应该把这些精灵的位置设为y=0 or y>=144+16或者x=0 or x>=160+8.
下面说一下OAM中每个精灵属性数据的含义:
Byte0: y坐标值
Byte1: x坐标值
Byte2: 精灵的图块编号,对于8*16模式大小的精灵,LSB(最低有效位?)被忽略
Byte3:标志位:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
值0 |
显示在背景和窗口的顶端 |
从OBJ0PAL取色 |
||||||
值1 |
如果背景和窗口关的颜色为1,2,3则隐藏 |
垂直跳动 |
水平跳动 |
从OBJ1PAL取色 |
颜色表:
值 |
模拟的颜色 |
0 |
[255, 255, 255] |
1 |
[192, 192, 192] |
2 |
[96, 96, 96] |
3 |
[0, 0, 0] |
好了,再了解完gameboy的显示机制之后接下来就要看一下在程序上是怎么来完成从内存到液晶屏上的显示过程了:
下表列出并说明了显示中用到的一些特殊的寄存器,特殊是因为这些寄存器是对内存中特定地址的称呼,而不是在Cpu中的寄存器:
FF40 - LCDC – 液晶屏控制器 (R/W)
Bit 7 – 是否开启液晶屏显示 (0=Off, 1=On) Bit 6 – 窗口图块映射范围选择 (0=9800-9BFF, 1=9C00-9FFF) Bit 5 – 是否开启窗口显示 (0=Off, 1=On) Bit 4 – 背景和窗口图块数据范围选择 (0=8800-97FF, 1=8000-8FFF) Bit 3 – 背景图块映射范围选择 (0=9800-9BFF, 1=9C00-9FFF) Bit 2 – 精灵尺寸选择 (0=8x8, 1=8x16) Bit 1 – 是否允许显示精灵 (0=Off, 1=On) Bit 0 – (对于黑白的GB和SGB)背景显示开关 (0=Off, 1=On) 对于CGB在CGB模式下,0=背景和窗口会失去他们的优先级,精灵们还是会显示在背景和窗口的顶端。 对于CGB在非CGB模式下,0=背景和窗口变白,只有精灵任能继续显示 |
注:对于Bit7停止LCD操作只能在v-blank中断中进行,否则会毁坏硬件(我们做模拟器开发的就不需要担心这个了J)
FF41 - STAT - LCDC Status (R/W)
Bit 6 - LYC=LY Coincidence 中断 (1=Enable) (Read/Write) Bit 5 - 模式 2 OAM 中断 (1=Enable) (Read/Write) Bit 4 - 模式 1 V-Blank 中断 (1=Enable) (Read/Write) Bit 3 - 模式 0 H-Blank 中断 (1=Enable) (Read/Write) Bit 2 - Coincidence Flag (0:LYC<>LY, 1:LYC=LY) (Read Only) Bit 1-0 - 模式标志 (模式 0-3) (Read Only) 0: 处于H-Blank中断中,Cpu能访问8000-9FFF和FE00-FE9F 1: 处于V-Blank中断中,Cpu访问同上 2: 正在搜索OAM-RAM,Cpu不能访问8000-9FFF和FE00-FE9F 3: 正在传输数据到 LCD 驱动,Cpu不能访问8000-9FFF和FE00-FE9F。CGB模式下,不能访问调色板数据FF69,FF6B. |
以下是一些典型的数值切换的过程中各个模式的值:
Mode 2 2_____2_____2_____2_____2_____2___________________2____
Mode 3 _33____33____33____33____33____33__________________3___
Mode 0 ___000___000___000___000___000___000________________000
Mode 1 ____________________________________11111111111111_____
模式标志每个周期的切换顺序为0,2,3,一个周期的时间大约为109uS,0大约停留48.6uS,2大约19uS,3大约41uS,这由vblank中断没16.6ms触发一次,模式标志被设为1的持续时间大约为1.08ms.
用时钟周期表示的话模式0大概201-207个周期,模式2大概77-83个周期,模式3大约169-175个周期,一个完整的模式切换大约456个周期,vblank持续4560个周期,一个完整的屏幕刷新大约每70224个周期发生一次
FF42 - SCY – 滚动Y坐标 (R/W)
FF43 - SCX – 滚动X坐标 (R/W)
制定256*256的背景中,哪一点作为液晶屏幕的左上角原点。两坐标的范围为0—255.
the video controller automatically wraps back to the upper (left) position in BG map when drawing exceeds the lower (right) border of the BG map area.
FF44 - LY – LCDC的Y坐标 (R)
LY指示当前那一条水平线上的显示数据被传送给LCD驱动,LY的值可能为0—153,当值为144—153之间时,GB处于vblank中断之中,当写入值时,会重置计数器
FF45 - LYC - LY 比较 (R/W)
GB不停地比较Lyc和Ly寄存器的值,当两个值完全一样时STAT寄存器的Coincidence Flag位会被设为1,然后如果开启了STAT中断的话,会请求该中断
FF4A - WY – 窗口Y坐标 (R/W)
FF4B - WX – 窗口X坐标 (R/W)
指定左上角的窗口位置,当Wx=0—166,Wy=0—143时,窗口可见
下面通过一张图来说明Scy,SCX和Wy,Wx之间的关系:
FF47 - BGP – 背景调色板数据 (R/W) – 非CGB模式,即黑白模式
该寄存器用来给背景和窗口的图块的颜色编号赋上灰度值
Bit 7-6 -Color Number 3 Bit 5-4 - Color Number 2 Bit 3-2 - Color Number 1 Bit 1-0 - Color Number 0 |
颜色值参考上面的颜色值表
FF48 - OBP0PAL – 0号对象调色板数据(R/W) -非CGB模式,即黑白模式
FF49 - OBP1PAL - 1号对象调色板数据(R/W) -非CGB模式,即黑白模式
这两个寄存器分别给0号和1号精灵调色板赋上灰度值,每个位代表的意思和BGP寄存器一样,但最低的两位是不使用的,因为00代表精灵是透明的
好,寄存器的介绍暂告一段落,现在来计算一下。不管是使用图块0还是图块1,GB的映射空间的大小都是3FFF=1024,然后GB的背景是256*256,同时背景是由8*8的图块拼起来的,所以总共需要32*32个图块。而32*32正好等于1024,由此可知通过解析图块映射区内的所有图块的编号就能够得到要显示的背景的像素数据了。
由今天的分析可知每个图块的大小是8*8个像素,占用的空间是8*8*2个bit,共16个字节。下面通过一副图来说明:
由上图,其实每个像素点的信息表示的是一个索引值,用来索引在调试版的颜色,调色板才是用来实际存放颜色信息的地方。
好了,今天的笔记的就到这吧,本来想先完成模拟Cpu部分的指令的代码再来学习显示的,不过在写代码的时候发现,如果没有显示的话都不知道实际模拟的对不对,所以就只能先学习显示部分的知识然后再去写代码了,有了输出差不多就可以判断自己的代码是不是正确了。
下一回将会对今天的知识用代码来进行实现,就是模拟gameboy的显示系统了,希望不要太难,呼,老天保佑。
WindowsPhone-GameBoy模拟器开发四--Gameboy显示系统分析的更多相关文章
- C#的百度地图开发(四)前端显示与定位
原文:C#的百度地图开发(四)前端显示与定位 有了这些定位信息,那要如何在前端的页面上显示出来呢?这需要用到百度地图的JavaScript的API.下面是示例代码. 前端代码 <%@ Page ...
- 一个可以在多平台运行的任天堂GameBoy模拟器
今天为大家带来一个很有趣的游戏模拟器GoBoy GoBoy GoBoy是一个可以在多平台运行的任天堂GameBoy和GameBoy Color的模拟器,目前这个模拟器可以运行大多数的GameBoy游戏 ...
- 【JAVA EE企业级开发四步走完全攻略】
本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划,单个发blog比较零散,所以整理此索引,决定以后每发一季JAVA EE blog后会 ...
- CozyRSS开发记录16-RssContentView显示
CozyRSS开发记录16-RssContentView显示 1.RssContentView的布局和绑定 继续参照原型图来写xaml: 然后在RSSContentFrameViewModel里提供绑 ...
- [C++][操作符]四种显示转换操作符
整理了C++ Primer中提到的四种显示转换,用思维导图写出来,是不是很清晰O(∩_∩)O.
- PyCharm 教程(四)显示行号
PyCharm 教程(四)显示行号 在PyCharm 里,显示行号有两种办法: 1,临时设置.右键单击行号处,选择 Show Line Numbers. 但是这种方法,只对一个文件有效,并且,重启Py ...
- JAVA EE企业级开发四步走完全攻略 [转]
http://bbs.51cto.com/thread-550558-1.html 本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划, ...
- emWin -- 模拟器系列1 - 如何建立模拟器开发环境
面对如此强大的emWin,大家是否都有跃跃欲试的冲动呢?但是没有硬件可以调试的童鞋,难道只能望洋兴叹?非也.非也.Segger公司早就考虑到了.Segger推出模拟器的目的不仅仅是为了解决没有硬件的烦 ...
- 如何在WindowsPhone Bing Map控件中显示必应中国中文地图、谷歌中国中文地图。
原文:如何在WindowsPhone Bing Map控件中显示必应中国中文地图.谷歌中国中文地图. 最近正好有点业余时间,所以在做做各种地图.Bing Map控件本身就能显示必应地图,但是很遗憾微软 ...
随机推荐
- js 图片预览
图片预览 $('#pac_recipe').change(function() { var imgsrc = ''; ]) { //chrome firefox imgsrc = window.URL ...
- JS-定时器管理实例函数封装
/** * Created by 12461 on 2016/11/6. */window.onload = function () { var oBtn1 = document.getElement ...
- git -- 如何解决冲突
遇到冲突,首先要编辑冲突文件,可以使用vim或者其他工具,冲突文件变现为: <<<<HEAD 到 ==== :代表本地分支的修改内容 ==== 到 >>>&g ...
- Oracle实例和Oracle数据库(Oracle体系结构)
--========================================== --Oracle实例和Oracle数据库(Oracle体系结构) --==================== ...
- ASP.NET MVC学习之模型模板篇
一.前言 如果你使用ASP.NET MVC制作后台一定会爱上它的EditorForModal.DisplayForModal和LabelForModal方法,因为这些方法可以将模型直接变成对应的标签, ...
- 设计模式之美:Chain of Responsibility(职责链)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现后继者链. 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链,并沿着这条 ...
- .net 获取当前周及根据年和周获取起始结束时间
获取当前日期周数 int str = new System.Globalization.GregorianCalendar().GetWeekOfYear(System.DateTime.Now, S ...
- SharePoint 基于 REST API使用简介
之前已经介绍了SP2010中支持CSOM的API进行远程访问SharePoint,但是CSOM的API仍然有一定的局限性,首先使用CSOM类库是基于.Net的,因此也将使用CSOM限制在了.Net平台 ...
- ComponentOne Xuni助力Xamarin开发者突破百万,快速开发Android、IOS Apps
在微软Build 2015上,随着VS 2015的预览版发布,Xamrine免费版已经作为VS 2015跨平台移动解决方案的核心.与此同时,Xamarin官方也宣布其用户量达到百万之多.2011年7月 ...
- atitit.提升开发效率---MDA 软件开发方式的革命(4)----编辑表单建模
)----编辑表单建模 1. 建模语言的选型anno+html...不是uml 1 2. 指定显示模板 @BeanEditForm(tmplt="c:/edit.html") 1 ...