# nesasm_3_2_vs
**Repository Path**: flame_cyclone/nesasm_3_2_vs
## Basic Information
- **Project Name**: nesasm_3_2_vs
- **Description**: 基于nesasm汇编工具, 完善功能
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-08-07
- **Last Updated**: 2025-12-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 更新说明
## 介绍
此仓库基于 [nesasm](http://www.nespowerpak.com/nesasm) 进行功能上的完善与更新.
| 功能 | 描述 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| 相对路径逻辑修改 | 使用include incbin等命令时相对路径基于使用命令的文件, 不再是基于程序当前工作目录 |
| 绝对寻址优化 | 增加绝对寻址可转变为零页寻址时使用零页寻址(不用显示指定零页寻址) |
| 增加STR指令 | STR指令增加长度限制(可选范围0-255) |
| 增加FILL指令 | 添加指定填充指定字节和长度 |
| 标签长度优化 | 标签长度从32扩展到256 |
| 命令行增加 -fill | 指定填充内存 |
| 命令行增加 -fns | 指定生成fns函数地址列表文件(原来默认生成且不能控制) |
| 命令行增加 -out | 指定输出文件名 |
| 命令行增加 -bank 指定全局bank大小 | |
| 预处理指令增加 .HEX | 用于指定十六进制编写的字节数据 |
| 预处理指令增加 .RDW | 用于指定大头序双字节数据 |
| 预处理指令增加 .BASE | 用于指定编译结果放置位置 |
| 预处理指令增加 .CHAR_MAP | 用于将字符串宏的字符映射为另一个字符 |
| 预处理指令增加
.BANK8
.BANK16
.BANK32 | 用于灵活指定当前Bank块大小 |
| 支持中文标签 | |
| 兼容65s指令语法 | 兼容65s
() 间接寻址
<取低位
>取高位 |
| 文件头增加 电池备份指令 | INESBAT |
| 文件头增加 INES2.0 支持 | INESTIM
INESSUBMAP
INESPRGRAM
INESPRGNVRAM
INESCHRRAM
INESCHRNVRAM
|
| | |
# NESASM v3.2 使用手册
## 命令行用法
nesasm_3_2.exe [-选项] [-? (帮助)] 输入文件, 例如
```bat
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 |
| BANK8 | 选择一个8KB 的ROM bank, 有效值范围为0-7663 |
| BANK16 | 选择一个16KB 的ROM bank, 有效值范围为0-3831 |
| BANK32 | 选择一个32KB 的ROM bank, 有效值范围为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 |
| USTR | 存储大写字符串,第一个字节是字符串的长度。
例如: USTR "FlameCyclone" 等同于 STR "FLAMECYCLONE" |
| LSTR | 存储小写字符串,第一个字节是字符串的长度。
例如: LSTR"FlameCyclone" 等同于 STR "flamecyclone" |
| HEX | 存储以十六进制格式编写的二进制文件。
例如: HEX 78 D8 A9 20 8D 00 20 |
| FILL | 填充指定字节并指定长度
例如: FILL $FF,64;在当前位置填充64个内容为$FF的字节数据 |
| CHAR_MAP | 指定字符串相关字符映射, 首个参数指定映射起始位置
例如: .CHAR_MAP 'A', $01,$02; 编译 .STR "AB" 将生成 02 01 02 |
| 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存储器,将使用尽可能多的连续存储器。
例如: INCBIN, 起始位置, 大小 |
| 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 | 当汇编程序遇到此指令时,它将中止编译。
可在宏中用于参数错误检测. |
## NES 文件头指令
| 指令 | 描述 |
| ------------ | ------------------------------------------------------------ |
| 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) |
INES 详见: [INES - NESdev Wiki](https://www.nesdev.org/wiki/INES)
NES2.0 详见: [NES 2.0 - NESdev Wiki](https://www.nesdev.org/wiki/NES_2.0)
## NSF文件头指令
| 指令 | 描述 |
| -------------- | ------------------------------------------------- |
| INSFVERSION | 版本, 如 1 |
| INSFTOTALSONGS | 总曲目 |
| INSFSTARTSONG | 起始播放曲目, 从 1 开始 |
| INSFLOAD | 数据加载地址, 如: $8000 |
| INSFINIT | 音乐初始化地址, 如: $BF00 |
| INSFPLAY | 音乐播放地址, 如: $80D5 |
| INSFNAME | 音乐名, 如: "Contra" |
| INSFARTIST | 作者, 如: "H. Maezawa, K. Sada" |
| INSFCOPYRIGHT | 版权信息, 如: "1988 Konami" |
| INSFSPEEDNTSC | NTSC 制式播放速率(每1/1000000秒滴答数), 如: 16666 |
| INSFBANKSWITCH | 初始数据块分布, 如: 0,1,2,3,4,5,6,7 |
| INSFSPEE | PAL 制式播放速率(每1/1000000秒滴答数), 如: 16666 |
| INSFSTANDARD | 制式标准 |
| INSFEXTRASOUND | 扩展音源 |
NSF 格式详见: [NSF - NESdev Wiki](https://www.nesdev.org/wiki/NSF)
## 例子
```asm
;======================================================================
;文件头
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
```