01、第一个程序
我们可以做的最简单的事是在屏幕关闭时向背景中写入数据。
ppu_off();
vram_adr(address);
vram_put(tile);
ppu_on_all();
我们来过一下这些方法的功能
ppu_off();
关闭屏幕(将PPU屏蔽寄存器2001的xxx1 1xxx位复位为零。)这样可以使PPU自由地执行任何操作。
然后,设置地址以设置写入的起始位置。
vram_adr(NTADR_A(x,y));
这将2个字节推送到ppu地址寄存器2006,首先是高字节,然后是低字节。它在屏幕上设置一个用于写入的位置。
我们想要写入#0名称表,在PPU RAM中介于 $2000和 $23ff之间。Nametable是指tilemap或称作背景屏幕。
这个宏将在编译时生成正确的地址。
#define NTADR_A(x,y) (NAMETABLE_A|(((y)<<5)|(x)))
X和Y是贴图的坐标,X从0到31,Y从0到29。
然后我们就可以向PPU DATA寄存器 $2007发送数据了,每次1 byte。
最明显的方法是使用vram_put(tile)函数。只需循环到所有数据都已发送完毕。
如果要使用相同的图块填充屏幕的大部分区域,可以使用vram_fill(tile,length)方法。
发送数据字节后,NES PPU的地址会自动递增。因此,每个数据字节将在最后一个数据的右边1,填充到下一行。
然后打开屏幕(寄存器2001中将xxx1 1xxx位翻转为ON状态)。
ppu_on_all();
我们正在做的是在瓷砖地图上放置值,告诉NES在屏幕上绘制哪些瓷砖。就像在网格上安排拼图一样。
我让瓷砖看起来像字母。我将它们定位为与ASCII地图相同,所以我可以将它们称为“A”或“ABC”,它与图形匹配。
该文件名为Alpha.chr。我有“incbin” - 在crt0.s末尾的图形并放入一个“CHR”段,链接器指向该段放在文件的末尾。
我们的链接器配置是nrom_32k_vert.cfg,它确保文件的拼接方式能使模拟器知道如何运行。
https://github.com/nesdoug/01_Hello/blob/master/hello.c
https://github.com/nesdoug/01_Hello
安装CC65,配置compile.bat文件中的cc65 home路径,将源码直接放到CC65目录下 /cc65/01_Hello/
或者将代码放到其他地方,通过修改路径的方式指向到cc65目录
PS:当我第一次用ASM编写NES游戏时,我试图写入屏幕,但感到困惑,因为我写的内容只会出现在屏幕的左上角。
由于PPU奇怪的工作方式,写地址(2006)会覆盖滚动寄存器(2005)。
写入屏幕后,重要的是写入2000 1次,2005 2次(或2006 2次,2005 2次)以重新调整屏幕。
在许多商业游戏中,你会看到写完PPU后执行的代码...
lda #0
sta $2006
sta $2006
sta $2005
sta $2005
neslib在后台自动执行此操作。如果你在neslib.s中看到nmi代码的底部附近,你会看到它完全正如我所描述的那样,就在屏幕重新显示之前。
lda #0
sta PPU_ADDR ;2006
sta PPU_ADDR ;2006
lda
sta PPU_SCROLL ;2005
lda
sta PPU_SCROLL ;2005
lda
sta PPU_CTRL ;2000
(暂时不知道怎么翻译这个)
The 2000 write sets the proper nametable.