更新说明
介绍
此仓库来源于 nesasm , 并对其功能进行完善
功能 | 描述 |
相对路径逻辑修改 | 使用include incbin等命令时相对路径基于使用命令的文件, 不再是基于程序当前工作目录 |
绝对寻址优化 | 增加绝对寻址可转变为零页寻址时使用零页寻址(不用显示指定零页寻址) |
增加STR指令 | STR指令增加长度限制(可选范围0-255) |
标签长度优化 | 标签长度从32扩展到256 |
命令行增加 -fill | 指定填充内存 |
命令行增加 -fns | 指定生成fns函数地址列表文件(原来默认生成且不能控制) |
命令行增加 -out | 指定输出文件名 |
命令行增加 -bank 指定bank大小 | |
预处理指令增加 .HEX | 用于指定十六进制编写的字节数据 |
预处理指令增加 .RDW | 用于指定大头序双字节数据 |
预处理指令增加 .BASE | 用于指定编译结果放置位置 |
支持中文标签 | |
兼容65s指令语法 | 兼容65s () 间接寻址 <取低位 >取高位 |
文件头增加 电池备份指令 | INESBAT |
文件头增加 INES2.0 支持 | INESTIM INESSUBMAP INESPRGRAM INESPRGNVRAM INESCHRRAM INESCHRNVRAM |
NESASM v3.2 使用手册
命令行用法
nesasm_3_2.exe [-选项] [-? (帮助)] 输入文件, 例如
nesasm_3_2.exe demo.asm
nesasm_3_2.exe demo.asm -out demo.nes
汇编程序只接受一个输入文件 “输入文件”,该文件将是组装成ROM文件(.NES扩展)可由模拟器直接使用。
还可以生成列表文件 (.LST 扩展名)如果在输入文件中遇到 LIST 指令。
以下是不同选项的说明:
选项 | 说明 |
-s | 显示区段使用情况。 如果指定了其中一个选项,汇编程序将显示有关 ROM 库使用情况的信息。 使用 “-s” 显示基本信息,“-s” 显示更详细的信息 |
-l # | 控制列表文件的输出: 0 - 完全禁用列表文件,即使LIST 指令用于输入文件 1 - 最低水平;DB、DW 和 DEFCHR 生成的代码不会被倾倒 2 - 正常水平;只有 DEFCHR 生成的代码不会被倾倒 3 - 最大水平;所有代码都转储在列表文件中 默认级别为 2 级. |
-m | 在列表文件中强制展开宏,即使在输入文件中看不到 MLIST 指令. |
-raw | 不会生成 ROM 标头 |
-bank | 指定编译时bank大小 0: 8KB 1: 16KB 2: 32KB 默认为0 |
-fill | 内存填充 (00-FF) |
-out | 指定输出文件名 |
-fns | 输出函数地址列表文件 |
包含路径
默认情况下,汇编程序在以下情况下查看当前目录加载包含文件,但当它找不到该文件时, 然后使用环境变量“NES_INCLUDE”获取列表包含路径。理想情况下,您需要将此变量设置为您的 'AUTOEXEC.BAT“文件,并让它指向”NES”MagicKit 的目录。
例如:set NES_INCLUDE=c:\magickit\nes
符号
支持两种类型的符号:全局符号和局部符号。局部符号前面有一个点“.”,并且仅在两个全局符号之间有效。符号后面可以跟冒号“:”,但这不是必需的。
表达式
汇编程序支持非常复杂的表达式。您可以根据需要使用任意数量的括号级别,并且可以在运算符和数字之间使用空格。
数字可以用三个基数写成:十六进制($7F)、二进制(x0101)和十进制(48)。还支持(‘A’)字符值。
所有常用的运算符都存在:
+, -, *, /, %, ^, &, |, ~, <<, >>
以及比较运算符:
=, !=, !, <, >, <=, >=
对于优先级,适用与 C 相同的规则。
您还可以在表达式中使用预定义或用户定义的函数。
预定义函数 | 描述 |
HIGH() | 返回值的高字节。 |
LOW() | 返回值的低字节。 |
BANK() | 返回符号的bank索引。如果没有给出符号,或者给出了多个符号,函数将返回错误。 |
PAGE() | 返回标签的页面索引。请参见上方的错误。 |
SIZEOF() | 返回数据元素的大小。 |
用户定义的函数
用户定义的函数使用FUNC指令声明,例如:
SCR_ADDR .func (\1) + ((\2) << 5)
最多可以使用 9 个参数,即 1 到 9。
要调用函数,只需将参数括在括号内并用逗号分隔即可:
stw #SCR_ADDR(10,4)+$2000,<$20
用户定义的函数可能非常有用,人们经常需要在表达式中一次又一次地使用相同的计算。定义函数将为您节省大量工作,并减少拼写错误。😃
请注意,函数调用可以嵌套,您可以毫无问题地从一个函数调用另一个函数,但是,递归调用将产生错误。
宏
虽然函数对于仅通过函数调用替换常用表达式非常有用,但宏用于用单行代码替换常用指令组。
使用以下命令启动宏定义:
label .macro
或者您也可以将标签放在“.macro”关键字之后,如下所示:
.macro label
之后跟随宏的主体,该主体由“.endm”指令终止。
例如,让我们定义一个“neg”宏来否定累加器。
neg .macro
eor #$FF
inc A
.endm
宏也可以有参数。在宏体中,您可以通过使用反斜杠字符(‘’)后跟一个数字来引用参数。可以使用9个参数,从1到9。
这是另一个例子:
add .macro ; 添加一个值到寄存器A
clc ; (处理进位标志)
adc
.endm
可以使用其他“特殊”参数,以下是您可以在宏中使用的所有可能参数的列表:
参数 | 描述 |
\1 - \9 | 输入参数 - 最多可以在宏调用中使用9个 |
# | 输入参数的数量 |
?1 - ?9 | 输入参数的“类型”: ARG_NONE (= 0) = 无参数 ARG_REG (= 1) = 寄存器 -> A, X, Y ARG_IMMEDIATE (= 2) = 立即数类型 -> #xx ARG_ABSOLUTE (= 3) = 绝对寻址 -> 标签, $xxxx ARG_INDIRECT (= 4) = 间接寻址 -> [标签] ARG_STRING (= 5) = 字符串参数 -> “…” ARG_LABEL (= 6) = 标签参数 -> 标签 |
@ | 特殊参数,每个宏返回不同的数字;可用于在宏内定义局部符号。 abs .macro lda \1 bpl .x@ eor #$FF inc A sta \1 .x@: .endm |
指令
指令 | 描述 |
LIST | 启用列表文件生成。您可以稍后使用NOLIST指令暂时停止输出,然后再用LIST重新启动。 |
NOLIST | 停止列出输出。 |
MLIST | 允许在清单文件中进行宏展开。 |
OPT | 请停止在清单文件中扩展宏。 如果您使用“-m”命令行选项,此指令将不会产生任何效果。 |
EQU | 给一个符号赋值。字符 ‘=’ 也有相同的功能。 |
BANK | 选择一个8KB / 16KB / 32KB 的ROM bank,并将位置计数器重置为该bank中最新已知的位置。 当bank大小为 8KB时, 有效值范围为0-7663 当bank大小为 16KB时, 有效值范围为0-3831 当bank大小为 32KB时, 有效值范围为0-1915 |
ORG | 设置程序计数器的位置。 地址的最低13位通知汇编器ROM bank中的偏移量,而最高的3位表示页面索引。 |
BASE | 将程序输出的位置设置在银行尺寸范围内。 |
DB BYTE | 在当前位置存储一个或多个数据字节。 |
DW WORD | 存储数据字(小端)。 例如,DW $6502 编译为字节 02 65。 |
RDW RWORD | 存储数据字(大端)。 例如,RDW $6502 编译为字节 65 02。 |
STR | 存储字符串,第一个字节是字符串的长度。 例如 STR “FlameCyclone” 编译为 0C 46 6C 61 6D 65 43 79 63 6C 6F 6E 65 |
HEX | 存储以十六进制格式编写的二进制文件。 |
DS | 在当前位置保留空间。如果在CODE或DATA组中使用此指令,该空间将填充为零。 |
RSSET | 将RS指令的内部计数器设置为指定值。 |
RS | 给一个符号分配一个值;有点像EQU,但这里分配的值来自内部计数器,分配后,该计数器会增加RS指令中指定的数量。这是一种非常方便的定义结构成员偏移量的方法,以下是一个小例子: ; C: ; – ; struct { ; short p_x; ; short p_y; ; byte p_color; ; } pixel; ; ; ASM: ; ---- .rsset $0 ; 设置RS计数器的初始值 P_X .rs 2 P_Y .rs 2 P_COLOR .rs 1 你可以随后在“像素”结构中使用这些符号作为偏移量。 ldy #P_COLOR lda [pixel_ptr],Y |
MACRO | 开始一个宏定义。 |
ENDM | 结束宏定义。 |
PROC | |
ENDP | |
PROCGROUP | |
ENDPROCGROUP | |
INCBIN | 将二进制文件包含在当前位置。如果文件大于ROM存储器,将使用尽可能多的连续存储器。 |
INCLUDE | 请在当前位置包含一个源文件。最多可以有7个级别。 |
INCCHR | 从PCX文件中提取一部分并将其转换为NES 4色8x8图形字符。有三种语法可用: INCCHR picpcx 不带任何附加参数,该命令将转换整个PCX文件。 INCCHR picpcx,32,4 告诉汇编器仅转换32个字符的4行(一个字符大小为8x8)。 INCCHR picpcx,48,16,32,4 与上述相同,但从坐标48,16(以像素为单位)开始提取字符。 |
DEFCHR | 定义一个字符块(8x8像素)。 该指令接受8个参数(每个参数都存储为8个nybble的32位值),每个参数对应一个像素数据行。 此指令还会重新组织像素数据以符合NES所需的位格式。 请注意,只能使用颜色索引0到3,因为NES瓷砖只有4种颜色。 如果尝试使用更多颜色,将会生成错误。 zero: .defchr $00111110,\ $01000011,\ $01000101,\ $01001001,\ $01010001,\ $01100001,\ $00111110,\ $00000000 |
ZP | 选择零页部分($0000-$00FF)。 |
BSS | 选择RAM部分($0200-$07FF)。 |
CODE | 选择程序代码部分。 |
DATA | 选择程序数据部分 在ZP和BSS部分,您只能分配存储空间,不能存储初始值。 |
IF | 条件汇编指令。 此指令将评估所提供的表达式,然后根据结果打开或关闭条件汇编。 如果结果为空,则关闭条件汇编;如果结果非空,则打开条件汇编。 |
IFDEF IFNDEF | 这些指令允许条件组装,具体取决于是否定义了标签 |
ELSE | 将条件程序集打开、关闭或反之亦然 |
ENDIF | 终止条件程序集的当前级别。 如果 IF 和 ENDIF 的数量不匹配,则报告错误. |
FAIL | 当汇编程序遇到此指令时,它将中止编译。 可在宏中用于参数错误检测. |
INESPRG | 指定 16k prg bank 的数量 (1-3832, 即16-61312 KB). |
INESCHR | 指定 8k chr bank 的数量 (0-3832, 即0-30656 KB). |
INESMAP | 指定使用的 NES 映射器 (0-4095). |
INESMIR | 指定 bank 的 VRAM 镜像。(0: 水平 1: 垂直 2: 四屏) |
INESBAT | 指定 存在电池备份 (0: 不存在 1: 存在)。 |
INESTIM | 指定 CPU/PPU 时序 (0: NTSC, 1: PAL, 2: 多区域, 3: Dendy)。 |
INESSUBMAP | 指定子映射器号 (0-15) |
INESPRGRAM | 指定 PRG RAM 大小 (0: 不存在, 1-15: 存在且大小 = 64字节 左移 1-15 次, 即128字节 - 2048KB) |
INESPRGNVRAM | 指定 PRG NVRAM 大小 (0: 不存在, 1-15: 存在且大小 = 64字节 左移 1-15 次, 即128字节 - 2048KB) |
INESCHRRAM | 指定 CHR RAM 大小 (0: 不存在, 1-15: 存在且大小 = 64字节 左移 1-15 次, 即128字节 - 2048KB) |
INESCHRNVRAM | 指定 CHR NVRAM 大小 (0: 不存在, 1-15: 存在且大小 = 64字节 左移 1-15 次, 即128字节 - 2048KB) |
例子
;======================================================================
;文件头
NES_16KB_PRG_SIZE = 1 ;16KB PRG大小数量
NES_8KB_CHR_SIZE = 0 ;8KB CHR大小数量
BANK_DATA_MASK = NES_16KB_PRG_SIZE * 2 - 1 ;bank号掩码
;======================================================================
PRG_DATA_BANK_C000 = NES_16KB_PRG_SIZE * 2 - 2
PRG_DATA_BANK_E000 = NES_16KB_PRG_SIZE * 2 - 1
MAPPER_MIRRORING = 1 ;命名表镜像 0水平 1垂直
;======================================================================
RESET_BANK = NES_16KB_PRG_SIZE * 2 - 1
RESET_ADDR = $E000 ;主程序起始地址
;======================================================================
;======================================================================
.INESPRG NES_16KB_PRG_SIZE ;16KB PRG 数量, $01-$EF8(1-3832),即16-61,312 KB
.INESCHR NES_8KB_CHR_SIZE ;8KB CHR 数量,$01-$EF8(1-3832),即0-30,656 KB
.INESMAP 4 ;Mapper号 (0-4095)
.INESSUBMAP 0 ;子Mapper号 (0-15)
.INESMIR 0 ;命名表镜像 (0: 水平 1: 垂直 2: 四屏)
.INESBAT 0 ;指定是否存在电池备份 (0: 不存在 1: 存在)
.INESPRGRAM 0 ;指定 PRG RAM 大小 (大小 = 64字节 << 计数)
.INESPRGNVRAM 0 ;指定 PRG NVRAM 大小(大小 = 64字节 << 计数)
.INESCHRRAM 0 ;指定 CHR RAM 大小(大小 = 64字节 << 计数)
.INESCHRNVRAM 0 ;指定 CHR NVRAM 大小(大小 = 64字节 << 计数)
.INESTIM 0 ;指定时序 (0: NTSC, 1: PAL, 2: 多区域, 3: Dendy)
.RSSET $40;内部计数器设置为指定值
FC_Data_L .RS 1;此符号分配后内部计数器 + 1
FC_Data_H .RS 1;此符号分配后内部计数器 + 1
FC_Palette .RS $20;此符号分配后内部计数器 + $20
;======================================================================
.BANK 0;设置程序所在Bank (限制: 8KB模式 0-7663 16KB模式 3831 32KB模式: 1915)
.ORG $8200;设置程序编译地址位置
.BASE $0000;设置程序在中Bank中输出的位置
.INCLUDE "sub.asm" ;引用其他源文件
.INCBIN "sub.bin",$10,$40 ;引用其他文件, 从$10开始, 共$20字节
.STR "FlameCyclone" ;定义一个字符串, 编译结果: 0C 46 6C 61 6D 65 43 79 63 6C 6F 6E 65
.HEX 4E 45 53 1A ;定义HEX数据, 编译结果: 4E 45 53 1A
.DW $6502 ;定义双字节数据(小头序), 编译结果: 02 65
.RDW $6502 ;定义双字节数据(大头序), 编译结果: 65 02
.DB $65,$02 ;定义双字节数据编译结果: 65 02
.DS $32;保留32字节数据(用零填充)
.RDW $6502 ;定义双字节数据(大头序), 编译结果: 65 02
;======================================================================
;测试程序
Test_Proc
LDA #$65
STA FC_Data_L
LDA #$02
STA FC_Data_H
RTS
;======================================================================
.BANK PRG_DATA_BANK_E000;设置程序所在Bank
.ORG RESET_ADDR
;不可屏蔽中断处理
Nmi_Program
PHA
TXA
PHA
TYA
PHA
PLA
TAY
PLA
TAX
PLA
RTI
;======================================================================
;重启处理
Reset_Program
SEI
CLD
STA $00
LDA #$00
STA $2000
STA $2001
LDA #$80
STA $2000
LDA #$1E
STA $2001
.Loop
JMP .Loop
;======================================================================
;请求中断处理
Irq_Program
RTI
;======================================================================
;中断向量表
.ORG $FFFA
.DW Nmi_Program
.DW Reset_Program
.DW Irq_Program