超级任天堂编程/超级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 芯片。这包括设置基本配置寄存器。
SCBRSCMRCFGRCLSR
如前所述,代码可以通过三种不同的方式加载到 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 标志位。