fc开发:cc65的准备 nmi支持编译(2)

上次简单介绍了使用cc65开发的信息,这次把cc65的环境准备详细说明一下

上一篇中我使用的是cc65 2.13.3

现在最新版本已经是2.18了,所以我打算从下载开始讲起,并讲解编译,nmi的配置等内容,将开发环境基本部署到位,以后不再赘述。

首先,官网地址 https://www.cc65.org/

可以看到老的版本和资源还有,不过最新的在github上https://github.com/cc65/cc65

打开ftserver,看到只有2.13的版本提供下载,那就转去github

当然,用2.13也足够用,嫌麻烦就直接用2.13就可以了。

在github看到windows下载,https://sourceforge.net/projects/cc65/files/cc65-snapshot-win32.zip

下载下来,放到d:\cc65-2.18

当然,要记得在全局系统参数里加上设置

现在拿上一篇的代码试一下 0.c文件

#include <conio.h>

void main()
{
	while(1){
		gotoxy(10,10);
		cprintf("string:%s ","123456");
	}
}

编译

cl65 -t nes -o 0.nes 0.c

然后用模拟器运行

在这里,基本环境就搭建好了, 可以参考手册进行编程开发,

使用CHR查看编辑工具YY-CHR查看编译好的0.nes文件

可以看到cc65使用的CHR文件里都是文本内容,基本就是ascii码的对应内容,如何替换和使用图形以后再说

现在说说nmi,也是以后的重点内容,

现在来看没有开启nmi的代码演示

1.c文件

#include <conio.h>

void main()
{
	
	while(1){
		clrscr();//清屏
		gotoxy(10,10);
		cprintf("string:%s ","123456");
		clrscr();//清屏
		gotoxy(20,20);
		cprintf("string:%s ","123456");
	}
}

编译好后执行效果

可以看到在闪啊闪,

扩展开, 在nes开发过程中, 如果不做任何处理, 在全屏背景图, 几十个spring,配合手柄,音乐和各种判定代码的情况下,

屏幕会闪花眼,这个时候,就要引入nmi概念。

nmi的解释:

     NMI的意思是 Non-Maskable Interrupt (不可屏蔽中断--译注),发生在每次刷新时
     (VBlank). 这些刷新的间隔依赖于所用的系统 (PAL/NTSC).
     NMI在NTSC控制下刷新次数为 60次/秒, PAL为50次/秒. 6502的中断潜伏期为七 (7) 个周
     期; 这也就是说需要需要七 (7) 个周期来移入和移出一个中断.

其实说白了就是屏幕刷新,而一般的建议是在nmi中断过程中处理和图形显示相关的代码,在这些代码里更新VRAM,移动spring,更改调色盘,或其它任何与显示有关的操作,这样就可以避免产生不必要的闪烁。

而cc65默认情况下是没有开启nmi支持的,看过我第一篇文章的,会注意到代码里有mynmi函数,那就是我进行修改重新编译后增加的nmi中断函数(在编译的时候名称随意定义,但在代码中一定要严格使用定义的函数名字),也就是系统每次产生nmi中断,就会自动调用mynmi函数

#include <conio.h>

//mynmi申明
void mynmi(void);

//mynmi实现
void mynmi(void)
{

}

void main()
{
	while(1){
		waitvblank();
		gotoxy(10,10);
		cprintf("string:%s ","123456");
	}
}

mynmi函数是没有参数传递的,也没有返回值,而这就设计到另一个概念, 在fc/nes开发过程中,尽量使用全局变量,在定义的各个函数或其它操作中尽量使用全局变量, 可以加快代码速度5倍左右,而直接使用全局变量,不如使用指针操作,会更快。在我以前的学习过程中,指针操作感觉比变量操作要快几倍,我操作精灵移动,使用变量和指针的速度差异非常大。第三点就是使用无符号变量类型,更可以加快速度,这些记住即可,不进坑就好。

(fc是8位机,所以尽量所有数据用8位数据)

下面我来修改一下代码,在之前编译好的2.13环境下测试一下效果

#include <conio.h>

short xx=10;
short zz=0;
//mynmi申明
void mynmi(void);

//mynmi实现
void mynmi(void)
{
	++zz;
	if(zz==10){
		//clrscr();//清屏
		if(xx == 10){
			xx=15;
			gotoxy(10,10);
		}else{
			xx=10;
			gotoxy(15,15);
		}
		cprintf("%s ","            ");
		gotoxy(xx,xx);
		cprintf("string:%s ","123456");
		zz = 0;
	}
}

void main()
{
	while(1){
	}
}

使用打开nmi支持的2.13编译后效果

可以看到不再闪烁。

而应用全屏背景和spring之后,意义更大,不会闪瞎眼,

以上两张图是以前用cc65 2.13 nmi环境下写的迷宫,里边有背景、音乐、碰撞判断、倒计时显示数字等

吃个饭去,回来讲编译打开nmi

 

=====================================================================================

下边开始cc65 nmi的修改和编译

下载源代码

https://github.com/cc65/cc65

并下载好了windows版本的可执行版本

cc65-master.zip

cc65-snapshot-win32.zip

两个全部解压, 并分开两个目录

在源代码“ libsrc\nes”文件夹找到 crt0.s 文件,

默认 nes 库怎么指明 nmi 中断入口的,找到一段代码:

.segment "VECTORS"

        .word   nmi         ; $fffa vblank nmi
        .word   start       ; $fffc reset
        .word   irq         ; $fffe irq / brk

这里就是知道的 nmi、 start、 irq 三个中断,只看nmi相关的

然后看到$fffa 位置使用了标签(或者叫地址) nmi 去填充,这样最后生成的 nes 中 nmi 中断向量就为 nmi 了,

看看它在 nmi 里面写了写什么,找到 nmi 标签:

nmi:    pha
        tya
        pha
        txa
        pha
......

省略号后边自己看

我们想让程序在nmi 中断的时候调用我们自己用 C写的中断服务程序,假设我们的中服务程序的声明为 void mynmi(void);
因为 mynmi 是之后自己写的,所以我们在 crt0.s 中的开头需要用.import_mynmi 导入,之所以有下划线是因为 C 函数编译之后编译器会在函数前面加上下划线,所以通过汇编方式访问的时候需要加下划线。这样就把mynmi()导入了。
然后调用,为了不破坏它原来的库,我们在它完成原来 nmi 中断的工作之后增加一条去执行我们外部用 C 写的中断服务程序的语句吧。一条 jsr19_mynmi 句足够了。(本段摘录自Trbbadboy的cc65高级玩法(1-7))

在nmi: 这一段找到

        sta     PPU_VRAM_ADDR1
        sta     PPU_VRAM_ADDR1

在下边添加一行

jsr _mynmi;

这个是在系统自己的代码执行完后,去执行自定义函数

mynmi这个函数需要在crt0.s文件的最前部分添加

.import _mynmi;
        .import         __CODE_LOAD__,__CODE_RUN__, __CODE_SIZE__
        .import         __RODATA_LOAD__,__RODATA_RUN__, __RODATA_SIZE__

        .import _mynmi;

        .include        "zeropage.inc"
        .include        "nes.inc"

以上完成了源代码的修改,下边开始编译和替换文件里的部分

del *.o
ar65 d nes.lib crt0.o

ca65 -t nes crt0.s
ar65 a nes.lib crt0.o

pause

可以看到,使用cc65自己的编译工具,不用其它编译环境即可

nes.lib是cc65环境中lib目录里nes.lib文件

过程就是先删除所有编译好的  .o 文件,然后从nes.lib里删除crt0.o部分

然后编译crt0.s ,再然后向nes.lib文件里添加crt0.o部分,

这样编译和替换完成后,就实现了mynmi函数,也就是实现了nmi中断。

(在编译的时候需要把neschar.inc也拷贝过来)

编译过程

然后把修改好的nes.lib剪切回lib目录,即可进行相关编程开发操作,要记得,把刚才拷贝过去的inc文件, lib文件和.s文件删掉,

下边是2.18版本nmi支持示例代码和模拟器效果

使用上边的例子,也就是2.13环境nmi的那个代码

至此,cc65 2.18 就实现了对nmi的支持。

下一次,将继续进行cc65环境的准备,会进行自定义库的使用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值