超级任天堂编程/超级FX教程
超级FX是一款为SNES设计的定制16位RISC处理器,具有特殊的位图模拟功能。它旨在为SNES带来基本的3D功能。它的编程是用特殊的超级FX汇编语言完成的。每个超级FX游戏都结合了标准的SNES汇编代码和专门编译的超级FX汇编例程,这些例程以二进制数据的形式编码在游戏卡中。它可以在某些条件下与SNES并行运行。每个超级FX游戏卡都有板载RAM,超级FX芯片使用它作为帧缓冲区以及用于它可以与SNES共享的通用操作。
超级FX芯片被用于8款已发布的SNES游戏中,在《星际火狐2》(未发布)以及多个技术演示中;其中有2款的二进制文件可供使用。
标题 | 超级FX版本 | ROM大小 | 游戏卡RAM大小 | 存档RAM大小 |
---|---|---|---|---|
《星际火狐》(PAL: 《星际之翼》) | 马里奥芯片 | 8 MBit | 256 KBit | 无 |
越野赛车 | GSU-1 | 4 MBit | 256 KBit | 无 |
尘土飞扬FX | GSU-1 | 4 MBit | 512 KBit | 无 |
《特技赛车FX》(JP: 《狂野赛道》) | GSU-1 | 8 MBit | 512 KBit | 64KBit |
星际火狐2 | GSU-1 | 8 MBit | 512 KBit | 64KBit |
漩涡 | GSU-1 | 4 MBit | 256 KBit | 无 |
SNES体素景观演示 | GSU-1 | 3 MBit | 512 KBit | 无 |
飘移(演示) | GSU-1 | 3 MBit | 512 KBit | 无 |
DOOM | GSU-2 | 16 MBit | 512 KBit | 无 |
耀西岛 | GSU-2-SP1 | 16 MBit | 256 KBit | 64KBit |
冬日黄金 | GSU-2 | 16 MBit | 512 KBit | 64KBit |
超级FX是SNES CPU的协处理器。超级FX的任务是执行比SNES快得多的复杂数学计算,并为超级FX游戏的简单3D渲染生成位图。超级FX和SNES处理器共享对公共游戏卡RAM和ROM总线的访问。在任何时候,只有一个处理器,超级FX或SNES CPU,可以访问游戏卡RAM和/或ROM,由特殊寄存器控制。SNES和超级FX访问数据总线的流程是优化程序效率的一门艺术。
游戏卡RAM主要用于存储计算结果、超级FX程序、批量数据或超级FX正在生成的PLOT图像。可以有256 Kib(32KiB)或512 Kib(64 KiB)的RAM。一些超级FX游戏还使用此RAM来存储存档数据。
超级FX可以以3种方式处理指令:从游戏卡RAM中读取、从游戏卡ROM中读取(直接从ROM芯片读取),或通过特殊的512字节指令缓存读取。
当使用512字节指令缓存时,超级FX可以与SNES CPU并行运行。这涉及加载程序,然后设置超级FX以开始工作。与在游戏卡RAM或ROM中运行程序相比,512字节缓存通常快3倍。超级FX可以在处理完成后中断SNES CPU。
当使用超级FX的特殊位图功能时,可以快速将位图从游戏卡RAM加载到SNES视频RAM并显示在屏幕上。SNES默认是一个基于瓷砖和精灵的控制台 - 3D渲染游戏中使用的基于像素的场景构建对于库存的SNES硬件来说非常低效。在超级FX游戏中,例如DOOM、星际火狐/星际之翼等,超级FX快速将基于像素的场景位图绘制到游戏卡RAM上,然后将其扔到SNES VRAM中,以便每秒多次显示图形。
超级FX有3个不同的硬件版本。所有版本在指令集方面功能上都是兼容的,但支持不同的ROM大小。
- MARIO芯片 - 代表“数学阿格诺特旋转输入输出”。超级FX芯片的第一个版本,仅与星际火狐/星际之翼一起使用。芯片有两个版本 - 一个是直接PCB裸片粘合/环氧树脂设置,另一个是标准芯片载体封装。
- GSU-1 - 用于大多数超级FX游戏的版本,采用标准芯片载体封装。在功能上与MARIO芯片相同。支持最大8兆位(1兆字节)的ROM大小。
- GSU-2 - 用于最后3款超级FX游戏,支持完整的16兆位(2兆字节)ROM大小。
-
MARIO芯片(封装)
-
MARIO芯片(环氧树脂)
-
GSU-1
-
GSU-2
-
GSU-2 SP1
超级FX芯片有16个通用16位寄存器,标记为R0
到R15
,以及11个控制寄存器。此外,从$3100-$32FF
的内存空间构成指令缓存。
通用寄存器
寄存器 | 地址 | 描述 | 从SNES访问 |
R0 |
$3000 |
默认源/目标寄存器 | R/W |
R1 |
$3002 |
像素绘图X位置寄存器 | R/W |
R2 |
$3004 |
像素绘图Y位置寄存器 | R/W |
R3 |
$3006 |
用于一般用途 | R/W |
R4 |
$3008 |
lmult 的低16位结果 | R/W |
R5 |
$300A |
用于一般用途 | R/W |
R6 |
$300C |
fmult 和 lmult 的乘数 | R/W |
R7 |
$300E |
用于合并的定点纹素X位置 | R/W |
R8 |
$3010 |
用于合并的定点纹素Y位置 | R/W |
R9 |
$3012 |
用于一般用途 | R/W |
R10 |
$3014 |
用于一般用途 | R/W |
R11 |
$3016 |
由 link 设置的返回地址 | R/W |
R12 |
$3018 |
循环计数器 | R/W |
R13 |
$301A |
循环点地址 | R/W |
R14 |
$301C |
用于GETB 、GETBH 、GETBL 、GETBS 的rom地址 |
R/W |
R15 |
$301E |
程序计数器 | R/W |
控制寄存器
名称 | 地址 | 描述 | 大小 | 从SNES访问 |
SFR |
$3030 |
状态标志寄存器 | 16位 | R/W |
$3032 |
未使用 | |||
BRAMR |
$3033 |
备份RAM寄存器 | 8位 | W |
PBR |
$3034 |
程序库寄存器 | 8位 | R/W |
$3035 |
未使用 | |||
ROMBR |
$3036 |
rom库寄存器 | 8位 | R |
CFGR |
$3037 |
控制标志寄存器 | 8位 | W |
SCBR |
$3038 |
屏幕基址寄存器 | 8位 | W |
CLSR |
$3039 |
时钟速度寄存器 | 8位 | W |
SCMR |
$303A |
屏幕模式寄存器 | 8位 | W |
VCR |
$303B |
版本代码寄存器(只读) | 8位 | R |
RAMBR |
$303C |
RAM库寄存器 | 8位 | R |
$303D |
未使用 | |||
CBR |
$303E |
缓存基址寄存器 | 16位 | R |
指令缓存
名称 | 地址 | 描述 | 大小 | 从SNES访问 |
1 |
$3100 |
指令缓存的第一个字节 | 8位 | R/W |
2 |
$3101 |
指令缓存的第二个字节 | 8位 | R/W |
... | ... | ... | 8位 | R/W |
... | ... | ... | 8位 | R/W |
512 |
$32FF |
指令缓存的第512个字节 | 8位 | R/W |
SFR
是一个非常重要的寄存器。它在评估计算后控制 Super FX 内部的分支,并且可以在从 SNES CPU 访问时确定 Super FX 的状态。
位 | 描述 |
---|---|
0 | - |
1 | Z 零标志 |
2 | CY 进位标志 |
3 | S 符号标志 |
4 | OV 溢出标志 |
5 | G Go 标志(当 GSU 运行时设置为 1) |
6 | R 使用 R14 地址读取 ROM 时设置为 1 |
7 | - |
8 | ALT1 下一条指令的模式设置标志 |
9 | ALT2 下一条指令的模式设置标志 |
10 | IL 立即较低 8 位标志 |
11 | IH 立即较高 8 位标志 |
12 | B 当执行 WITH 指令时设置为 1 |
13 | - |
14 | - |
15 | IRQ 当 GSU 引起中断时设置为 1。当被 658c16 读取时设置为 0 |
用于允许保护游戏卡内备份 RAM(不要与游戏卡 RAM 混淆)。位 0 可以设置为 0 以禁用写入备份 RAM,设置为 1 以启用写入。
位 | 描述 |
---|---|
0 | BRAM 标志(0 = 写入禁用,1 = 写入启用) |
1 | 未使用 |
2 | 未使用 |
3 | 未使用 |
4 | 未使用 |
5 | 未使用 |
6 | 未使用 |
7 | 未使用 |
当 Super FX 加载代码时,它引用 PBR
寄存器来指定正在使用的库。LJMP
指令是用于更改此寄存器的常用方法。
位 | 描述 |
---|---|
0 | A16 地址选择 |
1 | A17 地址选择 |
2 | A18 地址选择 |
3 | A19 地址选择 |
4 | A20 地址选择 |
5 | A21 地址选择 |
6 | A22 地址选择 |
7 | A23 地址选择 |
当使用 ROM 缓冲系统时,此寄存器指定要复制到缓冲区的游戏卡 ROM 的库。ROMB
指令是用于更改此寄存器的常用方法。
位 | 描述 |
---|---|
0 | A16 ROM 地址选择 |
1 | A17 ROM 地址选择 |
2 | A18 ROM 地址选择 |
3 | A19 ROM 地址选择 |
4 | A20 ROM 地址选择 |
5 | A21 ROM 地址选择 |
6 | A22 ROM 地址选择 |
7 | A23 ROM 地址选择 |
控制时钟倍频器和中断屏蔽。
位 | 描述 |
---|---|
0 | 未使用 |
1 | 未使用 |
2 | 未使用 |
3 | 未使用 |
4 | 未使用 |
5 | MS0 (0 = 标准,1 = 高速) |
6 | 未使用 |
7 | IRQ (0 = 正常,1 = 屏蔽) |
注意:如果通过 CLSR
标志(1)设置为以 21.477 MHz 运行,MS0
标志应设置为 0。
此寄存器设置图形存储区域的起始地址。它直接写入,而不是通过特定的指令。
位 | 描述 |
---|---|
0 | A10 屏幕基址选择 |
1 | A11 屏幕基址选择 |
2 | A12 屏幕基址选择 |
3 | A13 屏幕基址选择 |
4 | A14 屏幕基址选择 |
5 | A15 屏幕基址选择 |
6 | A16 屏幕基址选择 |
7 | A17 屏幕基址选择 |
控制 Super FX 芯片的时钟频率。
位 | 描述 |
---|---|
0 | CLSR ,0 = 10.738 MHz,1 = 21.477 MHz |
1 | 未使用 |
2 | 未使用 |
3 | 未使用 |
4 | 未使用 |
5 | 未使用 |
6 | 未使用 |
7 | 未使用 |
此寄存器为 PLOT
图形加速例程设置颜色数量和屏幕高度,并另外控制 Super FX 或 SNES 是否控制游戏卡 RAM 和 ROM。
位 | 描述 |
---|---|
0 | 颜色模式 MD0 |
1 | 颜色模式 MD1 |
2 | 屏幕高度 HT0 |
3 | 游戏卡 RAM 访问 - RAN (0 = SNES,1 = Super FX) |
4 | 游戏卡 ROM 访问 - RON (0 = SNES,1 = Super FX) |
5 | 屏幕高度 HT1 |
6 | 未使用 |
7 | 未使用 |
屏幕高度真值表
HT1 | HT0 | 模式 |
---|---|---|
0 | 0 | 128 像素 |
0 | 1 | 160 像素 |
1 | 0 | 192 像素 |
1 | 1 | OBJ 模式 |
颜色模式真值表
MD1 | MD0 | 模式 |
---|---|---|
0 | 0 | 4 色 |
0 | 1 | 16 色 |
1 | 0 | 未使用 |
1 | 1 | 256 色 |
可以使用此寄存器读取正在使用的 Super FX 芯片的版本。
位 | 描述 |
---|---|
0 | VC0 |
1 | VC1 |
2 | VC2 |
3 | VC3 |
4 | VC4 |
5 | VC5 |
6 | VC6 |
7 | VC7 |
在游戏卡 RAM 和 Super FX 寄存器之间写入时,此寄存器指定正在使用的游戏卡 RAM 的库。RAMB
指令是用于更改此寄存器的常用方法。位 0 用于将 RAM 库设置为 $70
或 $71
位 | 描述 |
---|---|
0 | A16(当为 0 时为 $70 ,当为 1 时为 $71 ) |
1 | 未使用 |
2 | 未使用 |
3 | 未使用 |
4 | 未使用 |
5 | 未使用 |
6 | 未使用 |
7 | 未使用 |
此寄存器指定游戏卡 RAM 或 ROM 的地址,数据将从该地址加载到缓存中。LJMP
和 CACHE
指令都是更改此寄存器的可接受方法。
位 | 描述 |
---|---|
0 | -(读取时始终为 0) |
1 | -(读取时始终为 0) |
2 | -(读取时始终为 0) |
3 | -(读取时始终为 0) |
4 | A4 |
5 | A5 |
6 | A6 |
7 | A7 |
8 | A8 |
9 | A9 |
10 | A10 |
11 | A11 |
12 | A12 |
13 | A13 |
14 | A14 |
15 | A15 |
Super FX 接口:映射到 $3000-$32FF
,在库 $00-$3F
和 $80-$BF
中
游戏 ROM:映射到 2 MiB,在库 $00-$3F
中从 $8000-$FFFF
开始。从库 $40-$5F
开始的 2 MiB 镜像映射。
游戏卡 RAM:映射到 128 KiB,从库 $70:$0000
开始。前 8 KiB 镜像到库 $00-$3F
和 $80-$BF
中的每个 $6000
。
游戏备份 RAM:映射到 128 KiB,从库 $78:$0000
开始
SNES CPU ROM:可以使用一个额外的 6 MiB ROM,该 ROM 仅对 SNES CPU 可访问,但没有 Super FX 游戏超过 2 MiB。额外的 ROM 将映射在库 $80-$BF
中从 $8000-$FFFF
开始,以及在库 $C0-$FF
中从 $0000-$FFFF
开始
游戏 ROM:映射到 2 MiB,在库 $00-$3F
中从 $8000-$FFFF
开始。从库 $40-$5F
开始的 2 MiB 镜像映射。
游戏卡 RAM:映射到 128 KiB,从库 $70:$0000
开始。不应访问 SNES 可以看到的其他内存位置。
注意:Super FX 通过三个库控制寄存器访问内存:程序库寄存器 (PBR
)、ROM 库寄存器 (ROMBR
) 和 RAM 库寄存器 (RAMBR
)
Super FX 指令集不同于 Super Nintendo 的原生指令集。它允许更快的、更复杂的 16 位数学运算,并包含一些特定的图形操作功能。
一些指令可以组装成单个字节。这是指令(半字节)和参数(半字节)合并到同一个存储字节中的地方。这使得执行速度更快,指令密度也更高。这些是在设计协处理器时要考虑的重要目标。其中一个指令是 ADC
,它以 $5
开头,并接收 16 个通用 Super FX 寄存器之一($0-$F
)的参数。
相当多的指令需要在执行操作码之前执行 ALT
指令。这会修改相同操作码的行为,使其执行略微不同的操作。有 3 种可能的 ALT
代码——ALT1
($3D
)、ALT2
($3E
)和 ALT1
+ALT2
($3F
)。在下表中,每个指令都列出了具体的 ALT
代码。
大多数指令依赖于预定义的指针来定位计算变量。这些是 FROM
、TO
和 WITH
指令。TO
和 FROM
命令分别指定作为变量的通用寄存器和计算结果。WITH
在同一个命令中定义了变量和结果。变量和结果分别被称为源和目标寄存器。
指令 | 描述 | ALT(十六进制) | CODE(十六进制) | ARG | 长度(字节) | 字节 | ATL1 | ALT2 | O/V | S | CY | Z | ROM | RAM | 缓存 | 分类 | 备注 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ADC |
带进位的加法 | 3D | 0x5 | Rn | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
ADC |
带进位的加法 | 3F | 0x5 | #n | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
ADD |
加法 | 无 | 0x5 | Rn | 1 | 0 | 0 | 0 | * | * | * | * | 3 | 3 | 1 | 算术运算指令 | |
ADD |
加法 | 3E | 0x5 | #n | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
ALT1 |
设置 ALT1 模式 | 无 | 0x3D | / | 1 | / | 1 | / | / | / | / | / | 3 | 3 | 1 | 前缀标志指令 | |
ALT2 |
设置 ALT2 模式 | 无 | 0x3E | / | 1 | / | / | 1 | / | / | / | / | 3 | 3 | 1 | 前缀标志指令 | |
ALT3 |
设置 ALT3 模式 | 无 | 0x3F | / | 1 | / | 1 | 1 | / | / | / | / | 3 | 3 | 1 | 前缀标志指令 | |
AND |
逻辑与 | 无 | 0x7 | Rn | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 逻辑运算指令 | |
AND |
逻辑与 | 3E | 0x7 | #n | 2 | 0 | 0 | 0 | / | * | / | * | 6 | 6 | 2 | 逻辑运算指令 | |
ASR |
算术右移 | 无 | 0x96 | / | 1 | 0 | 0 | 0 | / | * | * | * | 3 | 3 | 1 | 移位指令 | |
BCC |
进位清零时跳转 | 无 | 0x0C | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BCS |
进位置位时跳转 | 无 | 0x0D | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BEQ |
相等时跳转 | 无 | 0x09 | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BGE |
大于等于零时跳转 | 无 | 0x06 | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BIC |
位清零掩码 | 3D | 0x7 | Rn | 2 | 0 | 0 | 0 | / | * | / | * | 6 | 6 | 2 | 逻辑运算指令 | |
BIC |
位清零掩码 | 3F | 0x7 | #n | 2 | 0 | 0 | 0 | / | * | / | * | 6 | 6 | 2 | 逻辑运算指令 | |
BLT |
小于零时跳转 | 无 | 0x07 | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BMI |
负数时跳转 | 无 | 0x0B | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BNE |
不相等时跳转 | 无 | 0x08 | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BPL |
正数时跳转 | 无 | 0x0A | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BRA |
始终跳转 | 无 | 0x05 | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BVC |
溢出清零时跳转 | 无 | 0x0E | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
BVS |
溢出置位时跳转 | 无 | 0x0F | e | 2 | / | / | / | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
CACHE |
设置缓存基址寄存器 | 无 | 0x02 | / | 1 | 0 | 0 | 0 | / | / | / | / | 3-4 | 3-4 | 1 | GSU 控制指令 | |
CMODE |
设置绘图模式 | 3D | 0x4E | / | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 绘图/相关指令 | |
CMP |
比较 | 3F | 0x6 | Rn | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
COLOR |
设置绘图颜色 | 无 | 0x4E | / | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | 绘图/相关指令 | |
DEC |
递减 | 无 | 0xE | Rn | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 算术运算指令 | |
DIV2 |
除以 2 | 3D | 0x96 | / | 2 | 0 | 0 | 0 | / | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
FMULT |
分数有符号乘法 | 无 | 0x9F | / | 1 | 0 | 0 | 0 | / | * | * | * | 11 或 7 | 11 或 7 | 8 或 4 | 算术运算指令 | 周期取决于 CFGR 寄存器 |
FROM |
设置 Sreg | 无 | 0xB | Rn | 1 | / | / | / | / | / | / | / | 3 | 3 | 1 | 前缀寄存器指令 | |
GETB |
从 ROM 缓冲区获取字节 | 无 | 0xEF | / | 1 | 0 | 0 | 0 | / | / | / | / | 3-8 | 3-8 | 1-6 | 数据从游戏卡 ROM 传输到寄存器 | 周期因 ROM 缓冲区而异 |
GETBH |
从 ROM 缓冲区获取高字节 | 3D | 0xEF | / | 2 | 0 | 0 | 0 | / | / | / | / | 6-10 | 6-9 | 2-6 | 数据从游戏卡 ROM 传输到寄存器 | 周期因 ROM 缓冲区而异 |
GETBL |
从 ROM 缓冲区获取低字节 | 3E | 0xEF | / | 2 | 0 | 0 | 0 | / | / | / | / | 6-10 | 6-9 | 2-6 | 数据从游戏卡 ROM 传输到寄存器 | 周期因 ROM 缓冲区而异 |
GETBS |
从 ROM 缓冲区获取有符号字节 | 3F | 0xEF | / | 2 | 0 | 0 | 0 | / | / | / | / | 6-10 | 6-9 | 2-6 | 数据从游戏卡 ROM 传输到寄存器 | 周期因 ROM 缓冲区而异 |
GETC |
从 ROM 获取字节到颜色寄存器 | 无 | 0xDF | / | 1 | 0 | 0 | 0 | / | / | / | / | 3-10 | 3-9 | 1-6 | 数据从游戏卡 ROM 传输到寄存器 | 周期因 ROM 缓冲区而异 |
HIB |
寄存器高字节的值 | 无 | 0xC0 | / | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 字节传输指令 | |
IBT |
加载立即字节数据 | 无 | 0xA | "Rn, #pp" | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 数据传输/立即数据到寄存器 | |
INC |
递增 | 无 | 0xD | Rn | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 算术运算指令 | |
IWT |
加载立即字数据 | 无 | 0xF | "Rn, #xx" | 3 | 0 | 0 | 0 | / | / | / | / | 9 | 9 | 3 | 数据传输/立即数据到寄存器 | |
JMP |
跳转 | 无 | 0x9 | Rn | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | "跳转、分支和循环指令" | |
LDB |
从 RAM 加载字节数据 | 3D | 0x4 | Rm | 1 | 0 | 0 | 0 | / | / | / | / | 11 | 13 | 6 | 数据从游戏卡 RAM 传输到寄存器 | |
LDW |
从 RAM 加载字数据 | 无 | 0x4 | Rm | 1 | 0 | 0 | 0 | / | / | / | / | 10 | 12 | 7 | 数据从游戏卡 RAM 传输到寄存器 | |
LEA |
加载有效地址 | 无 | 0xF | "Rn, xx" | 3 | 0 | 0 | 0 | / | / | / | / | 9 | 9 | 3 | 宏指令 | |
LINK |
链接返回地址 | 无 | 0x9 | #n | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | "跳转、分支和循环指令" | |
LJMP |
长跳转 | 3D | 0x9 | Rn | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | "跳转、分支和循环指令" | |
LM |
"从 RAM 加载字数据,使用 16 位" | 3D | 0xF | "Rn, (xx)" | 2 | 0 | 0 | 0 | / | / | / | / | 20 | 21 | 11 | 数据从游戏卡 RAM 传输到寄存器 | |
LMS |
"从 RAM 加载字数据,短地址" | 3D | 0xA | "Rn, (yy)" | 2 | 0 | 0 | 0 | / | / | / | / | 17 | 17 | 10 | 数据从游戏卡 RAM 传输到寄存器 | |
LMULT |
16x16 有符号乘法 | 3D | 0x9F | / | 2 | 0 | 0 | 0 | / | * | * | * | 10 或 14 | 10 或 14 | 5 或 9 | 算术运算指令 | 周期取决于 CFGR 寄存器 |
LOB |
寄存器低字节的值 | 无 | 0x9E | / | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 字节传输指令 | |
LOOP |
循环 | 无 | 0x3C | / | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | "跳转、分支和循环指令" | |
LSR |
逻辑右移 | 无 | 0x03 | / | 1 | 0 | 0 | 0 | / | 0 | * | * | 3 | 3 | 1 | 移位指令 | |
MERGE |
合并 R8 和 R7 的高字节 |
无 | 0x70 | / | 1 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 字节传输指令 | |
MOVE |
将字数据从 Rn' 移动到 Rn |
无 | 0x2n1n' | "Rn, Rn'" | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 数据从寄存器到寄存器的传输 | |
MOVES |
将字数据从 Rn' 移动到 Rn 并设置标志 |
无 | 0x2nBn' | "Rn, Rn'" | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 数据从寄存器到寄存器的传输 | |
MULT |
有符号乘法 | 无 | 0x8 | Rn | 1 | 0 | 0 | 0 | / | * | / | * | 3 或 5 | 3 或 5 | 1 或 2 | 算术运算指令 | 周期取决于 CFGR 寄存器 |
MULT |
有符号乘法 | 3E | 0x8 | #n | 2 | 0 | 0 | 0 | / | * | / | * | 6 或 8 | 6 或 8 | 2 或 3 | 算术运算指令 | 周期取决于 CFGR 寄存器 |
NOP |
无操作 | 无 | 0x01 | / | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | GSU 控制指令 | |
NOT |
反转所有位 | 无 | 0x4F | / | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | 位操作指令 | |
OR |
位或 | 无 | 0xC | Rn | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | 位操作指令 | |
OR |
位或 | 3E | 0xC | #n | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 位操作指令 | |
PLOT |
绘制像素 | 无 | 0x4C | / | 1 | 0 | 0 | 0 | / | / | / | / | 3-48 | 3-51 | 1-48 | 绘图/相关指令 | 周期因 RAM 缓冲区和程序而异 |
RAMB |
设置 RAM 数据库 | 3E | 0xDF | / | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 库设置指令 | |
ROL |
带进位的左旋 | 无 | 0x04 | / | 1 | 0 | 0 | 0 | / | * | * | * | 3 | 3 | 1 | 移位指令 | |
ROMB |
设置 ROM 数据库 | 3F | 0xDF | / | 2 | 0 | 0 | 0 | / | / | / | / | 6 | 6 | 2 | 库设置指令 | |
ROR |
带进位的右旋 | 无 | 0x97 | / | 1 | 0 | 0 | 0 | / | * | * | * | 3 | 3 | 1 | 移位指令 | |
RPIX |
读取像素颜色 | 3D | 0x4C | / | 2 | 0 | 0 | 0 | / | * | / | * | 24-80 | 24-78 | 20-74 | 绘图/相关指令 | |
SBC |
带进位的减法 | 3D | 0x6 | Rn | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
SBK |
"存储字数据,上次使用的 RAM 地址" | 无 | 0x9 | / | 1 | 0 | 0 | 0 | / | / | / | / | 3-8 | 7-11 | 1-6 | 数据从寄存器传输到游戏卡 RAM | |
SEX |
符号扩展寄存器 | 无 | 0x95 | / | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 字节传输指令 | |
SM |
使用 16 位将字数据存储到 RAM | 3E | 0xF | "Rn, (xx)" | 3 | 0 | 0 | 0 | / | / | / | / | 12-17 | 16-20 | 4-9 | 数据从寄存器传输到游戏卡 RAM | 周期因 RAM 缓冲区和程序而异 |
SMS |
"将字数据存储到 RAM,短地址" | 3E | 0xA | "Rn, (yy)" | 3 | 0 | 0 | 0 | / | / | / | / | 9-14 | 13-17 | 3-8 | 数据从寄存器传输到游戏卡 RAM | 周期因 RAM 缓冲区和程序而异 |
STB |
将字节数据存储到 RAM | 3D | 0x3 | Rm | 2 | 0 | 0 | 0 | / | / | / | / | 6-9 | 8-14 | 2-5 | 数据从寄存器传输到游戏卡 RAM | 周期因 RAM 缓冲区和程序而异 |
STOP |
停止处理器 | 无 | 0x00 | / | 1 | 0 | 0 | 0 | / | / | / | / | 3 | 3 | 1 | GSU 控制指令 | |
STW |
将字数据存储到 RAM | 无 | 0x3 | Rm | 1 | 0 | 0 | 0 | / | / | / | / | 3-8 | 7-11 | 1-6 | 数据从寄存器传输到游戏卡 RAM | 周期因 RAM 缓冲区和程序而异 |
SUB |
减法 | 无 | 0x6 | Rn | 1 | 0 | 0 | 0 | * | * | * | * | 3 | 3 | 1 | 算术运算指令 | |
SUB |
减法 | 3E | 0x6 | #n | 2 | 0 | 0 | 0 | * | * | * | * | 6 | 6 | 2 | 算术运算指令 | |
SWAP |
交换低字节和高字节 | 无 | 0x4D | / | 1 | 0 | 0 | 0 | / | * | / | * | 3 | 3 | 1 | 字节传输指令 | |
TO |
设置 Dreg | 无 | 0x1 | Rn | 1 | / | / | / | / | / | / | / | 3 | 3 | 1 | 前缀寄存器指令 | |
UMULT |
无符号乘法 | 3D | 0x8 | Rn | 2 | 0 | 0 | 0 | / | * | / | * | 6 或 8 | 6 或 8 | 2 或 3 | 算术运算指令 | 周期数取决于 CONFIG 寄存器 |
UMULT |
无符号乘法 | 3F | 0x8 | #n | 2 | 0 | 0 | 0 | / | * | / | * | 6 或 8 | 6 或 8 | 2 或 3 | 算术运算指令 | ? |
WITH |
设置 Sreg 和 Dreg | 无 | 0x2 | "Rn, ?" | ? | 1 | ? | ? | ? | ? | ? | ? | ? | ? | ? | 前缀寄存器指令 | ? |
XOR |
位异或 | 3D | 0xC | Rn | 2 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | 位操作指令 | ? |
XOR |
位异或 | 3F | 0xC | #n | 2 | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | 位操作指令 | ? |
对于某些指令,必须在运行指令之前指定 Sreg 和 Dreg。Sreg 是“源寄存器”,Dreg 是“目标寄存器”,每个都指定为 16 个通用寄存器之一。使用 TO
、FROM
和 WITH
指令指定 Sreg 和 Dreg。
位图模拟功能是 Super FX 的主要加速功能之一。它允许在帧缓冲区中使用基于像素的着色方法,而不是 SNES VRAM 中基于图块的方法。对于 3D 渲染操作,需要一个快速的逐像素着色器。Super FX 提供了框架,可以快速将单个像素绘制到帧缓冲区,然后将绘制的图像传输到 SNES VRAM。
Super FX 有 4 个乘法指令。
MULT
- 有符号 8 位 x 有符号 8 位,结果为有符号 16 位,存储在 Dreg 中。UMULT
- 无符号 8 位 x 无符号 8 位,结果为无符号 16 位,存储在 Dreg 中。LMULT
- 有符号 16 位 x 有符号 16 位,结果为有符号 32 位,MSB 存储在 Dreg 中,LSB 存储在 R4 中FMULT
- 有符号 16 位 x 有符号 16 位,结果为有符号 32 位。
MULT
/UMULT
指令比 LMULT
/FMULT
指令更快。
虽然 SNES 汇编语言程序可以使用常规的 65c816 编译器进行编译,但 Super FX 汇编语言需要自定义编译器。现有的 Super FX 游戏中使用的原始编译器没有在封闭的开发社区之外发布。
一个名为 sfxasm 的开源编译器可用于编译 Super FX 程序。
编译后,Super FX 程序将作为二进制库包含在 SNES 汇编语言程序中。然后,SNES 程序指示 Super FX 使用打包在 ROM 中的预编译程序。
当 SNES 启动带有 Super FX 游戏时,Super FX 芯片处于闲置状态,您无需执行任何操作即可启动正常的 SNES 加载 ROM 和执行代码的程序。当 SNES 启动并执行了一些启动例程,并且通常已准备好后,您可以在程序中激活 Super FX。注意,为了使模拟器支持 Super FX 指令,标题中的 $FFD6
字节必须为 $13
、$14
、$15
或 $1A
。$FFD5
字节应为 $20
。
在运行代码之前应初始化 Super FX 芯片。这包括设置基本配置寄存器。
SCBR
SCMR
CFGR
CLSR
如前所述,代码可以通过三种不同的方式加载到 Super FX 中 - 来自游戏卡 ROM、RAM 和 512 字节缓存。根据您想要使用哪种方式,程序略有不同。
- ROM 模式的好处是简单,但代价是 Super FX 处理时会停止 SNES CPU。
- RAM 模式的优势是能够在 SNES CPU 已经忙碌的情况下运行一个大型 Super FX 程序,但代价是必须在运行之前将程序写入游戏卡 RAM 中。
- 缓存模式的优势是在 SNES 同时忙于游戏卡 ROM 和 RAM 的情况下,运行一个小程序的速度比 ROM 或 RAM 模式快三倍,但代价是必须在执行过程之前将程序加载到缓存内存中。
1. 设置程序库寄存器 (PBR
) 用于 SFX 程序开始的位置。
2. 编程 Super FX 中的程序计数器 (R15
)。
3. 通过在 SFR 寄存器中设置 RON
标志,使 Super FX 独占访问 ROM。
1. 使用复制例程将程序从 ROM 传输到游戏卡 RAM 中。
2. 设置程序基址寄存器 (PBR
) 用于 SFX 程序开始的位置。
3. 写入 Super FX 程序计数器 (R15
)。
1. 使用复制例程将程序从 ROM 传输到缓存 RAM ($3100-$31FF
) 及以后。程序需要以每 16 字节为一个块的方式排列,否则 Super FX 将不会执行超出 16 字节段的指令。这对小于 16 字节的小程序也适用 - 要解决这个问题,请在第 16 个字节 ($310F
) 中写入一些内容。
2. 写入 Super FX 程序计数器 (R15
),这通常为 0。
3. Super FX 程序将独立于 SNES 执行,直到它遇到 STOP
指令。当它完成时,根据 SFR
配置中断是否设置,它将在 SNES 上生成一个中断 (RTI
指令)。如果中断被屏蔽,则 Super FX 将进入空闲模式,并等待 SNES 的下一个命令开始执行。
当 Super FX 发现 SNES 已经写入其程序计数器寄存器 (R15
) 时,处理开始。
Super FX 可以通过两种方式之一停止 - 通过在 Super FX 的程序中执行 STOP
指令,或者通过 SNES 将 "0" 写入 Super FX 的 SFR
寄存器中的 GO
标志。
当 Super FX 读取 Super FX STOP
指令时,它会调用 RTI
指令。可以通过在 SFR 寄存器中设置 IRQ
位来屏蔽中断。如果中断没有被屏蔽,要确定它是屏幕消隐中断还是 Super FX,请检查 SFR
寄存器中的 IRQ
标志位。