Este manual cubre desde lo más básico hasta conceptos avanzados para programar ROMs de Super Nintendo Entertainment System (SNES).
El SNES utiliza una CPU basada en el procesador WDC 65C816:
Rango de memoria | Descripción
-------------------|-------------------------------
$0000-$1FFF | WRAM (Work RAM, 128KB)
$2100-$21FF | Registros PPU
$4200-$44FF | Registros de CPU y DMA
$7E0000-$7FFFFF | WRAM mapeada (128KB)
$8000-$FFFF | ROM del cartucho (banco 0)
Responsable de los gráficos:
Un ROM de SNES típico tiene esta estructura:
; Cabecera del ROM (Header)
.org $FFB0
ROMHeader:
.db "TITLE OF GAME " ; Título de 21 caracteres
.db $30 ; Map mode (SlowROM)
.db $02 ; Tipo de cartucho (ROM+RAM+Battery)
.db $0A ; Tamaño del ROM (4MB)
.db $03 ; Tamaño de la SRAM (64KB)
.db $00 ; País (Japón)
.db $00 ; Licencia code
.db $00 ; Versión
.dw $0000 ; Checksum complement
.dw $FFFF ; Checksum
; ... más campos de cabecera
; Ejemplo de archivo .cfg para WLA-DX
[OBJECT]
OUTPUT = game.smc
NAME = GAMEPROJECT
[MEMORY]
ROM0: start=$008000 size=$8000 fill=yes
ROM1: start=$018000 size=$8000 fill=yes
; ... más bancos según sea necesario
[BANKS]
0: start=$008000 size=$8000
1: start=$018000 size=$8000
[PATHS]
.
[SYMBOLS]
; Registros principales
A = Acumulador (8/16 bits)
X = Registro índice X (8/16 bits)
Y = Registro índice Y (8/16 bits)
D = Registro direct page (16 bits)
DB = Registro data bank (8 bits)
P = Registro de estado (8 bits)
S = Stack pointer (16 bits)
PC = Program counter (24 bits)
; Ejemplos de modos de direccionamiento
LDA #$42 ; Inmediato
LDA $00 ; Direct page
LDA $00,X ; Indexado por X
LDA [$00],Y ; Indirecto indexado largo
LDA $123456 ; Absoluto largo
; Inicialización básica del sistema
.include "header.inc"
.bank 0
.org $8000
Reset:
SEI ; Deshabilitar interrupciones
CLC ; Limpiar carry
XCE ; Cambiar a modo nativo (65816)
REP #$30 ; Registros A/X/Y de 16 bits
LDA #$0000
TCD ; Establecer direct page a $0000
LDX #$1FFF
TXS ; Establecer stack pointer
; Limpiar WRAM
LDA #$0000
LDX #$0000
.ClearWRAM:
STA $7E0000,X
INX
INX
CPX #$8000
BNE .ClearWRAM
; Inicialización del PPU
JSR InitPPU
; Habilitar pantalla
LDA #$0F
STA $2100 ; Brightness = 15, pantalla habilitada
; Bucle principal
.MainLoop:
WAI ; Esperar interrupción VBlank
JSR ReadControllers
JSR UpdateGame
BRA .MainLoop
El SNES tiene 8 modos gráficos principales (0-7):
; Configurar modo gráfico (registro $2105)
LDA #$01 ; Modo 1, 16 colores por tile
STA $2105
; Modos comunes:
; $00: 4 capas de 4 colores
; $01: Capa 1/2: 16 colores, Capa 3: 4 colores
; $07: Modo 7 (para efectos de rotación/escala)
; Cargar tiles en VRAM
; Asumimos que los tiles están en ROM en $018000
LDA #$1801 ; DMA: Transferencia de CPU a PPU, incremento de 1
STA $4300
LDA #.loword(Tiles)
STA $4302
LDX #^Tiles ; Banco de los datos
STX $4304
LDA #$1000 ; VRAM destino: $1000
STA $2116
LDA #$2000 ; Tamaño: $2000 bytes (64 tiles de 8x8 4bpp)
STA $4305
LDX #$01
STX $420B ; Iniciar DMA canal 0
Tiles:
.incbin "tiles.bin"
; Configurar sprites
LDA #$01
STA $2101 ; Tamaño de sprite: 8x8 y 16x16
; Estructura de OAM (Object Attribute Memory)
; Cada sprite usa 4 bytes:
; Byte 0: Posición X (bit 0-7)
; Byte 1: Posición Y
; Byte 2: Tile number
; Byte 3: Atributos (prioridad, paleta, flip, etc.)
; Ejemplo: Configurar sprite 0
STZ $2102 ; Resetear OAM address
STZ $2103
LDA #$50 ; Posición Y = 80
STA $2104
LDA #$60 ; Posición X = 96 (bit 0-7)
STA $2104
LDA #$00 ; Tile 0
STA $2104
LDA #%00110000 ; Prioridad 3, paleta 0, no flip
STA $2104
LDA #$00 ; Posición X bit 8 (para X > 255)
STA $2104
ReadControllers:
LDA #$01
STA $4016 ; Iniciar lectura
STZ $4016
; Leer controles del jugador 1
LDX #$00
.ReadLoop:
LDA $4016
LSR A
ROL $00 ; Almacenar en $00 (botones bajos)
LDA $4017
LSR A
ROL $02 ; Almacenar en $02 (botones altos)
INX
CPX #$10
BNE .ReadLoop
; Combinar resultados
LDA $00
STA Controller1
LDA $02
STA Controller1+1
RTS
Controller1: .dw $0000 ; 16 bits para los botones
; Bits en Controller1:
; Bit 0: B
; Bit 1: Y
; Bit 2: Select
; Bit 3: Start
; Bit 4: Up
; Bit 5: Down
; Bit 6: Left
; Bit 7: Right
; Bit 8: A
; Bit 9: X
; Bit 10: L
; Bit 11: R
; Ejemplo de carga de música
LoadMusic:
; Esperar a que el SPC esté listo
.WaitReady:
LDA $2140
CMP #$AA
BNE .WaitReady
; Iniciar transferencia
LDA #$01
STA $2141 ; Comando: cargar música
; Transferir datos del DSP
; (código omitido por brevedad)
; Ejecutar código en SPC
LDA #$CC
STA $2140 ; Señal de ejecución
RTS
; Ejemplo de transferencia DMA
DoDMA:
; Configurar DMA
LDA #$01 ; DMA control: transferir de CPU a PPU
STA $4300
LDA #$18 ; PPU destino: $2118 (VRAM data)
STA $4301
LDA #.loword(SourceData)
STA $4302 ; Dirección baja
LDA #^SourceData
STA $4304 ; Banco
LDA #$1000 ; Tamaño: $1000 bytes
STA $4305
LDA #$01 ; Habilitar DMA canal 0
STA $420B
RTS
SourceData: .incbin "graphics.bin"
; Ejemplo de HDMA para efectos de parallax
SetupHDMA:
; Tabla HDMA para scroll horizontal
LDA #$42 ; HDMA control: 1 registro, write twice
STA $4300
LDA #$0D ; PPU destino: $210D (BG1HOFS)
STA $4301
LDA #.loword(HDMATable)
STA $4302
LDA #^HDMATable
STA $4304
LDA #$01 ; Habilitar HDMA canal 0
STA $420C
RTS
HDMATable:
.db $20 : .dw $0100 ; 32 líneas, scroll = $0100
.db $30 : .dw $0110 ; 48 líneas, scroll = $0110
.db $00 ; Fin de tabla
; Configurar modo 7
SetupMode7:
LDA #$07
STA $2105 ; Modo gráfico 7
; Matriz de transformación
LDA #$00
STA $211B ; Matriz A baja
LDA #$01
STA $211B ; Matriz A alta
STA $211C ; Matriz B = 1
LDA #$00
STA $211D ; Matriz C = 0
STA $211E ; Matriz D baja
LDA #$01
STA $211E ; Matriz D alta
; Centro de rotación
LDA #$80
STA $211F ; Centro X
STA $2120 ; Centro Y
RTS
; Ejemplo de optimización de bucle
; Versión no optimizada:
LDX #$00
.LoopSlow:
LDA Data,X
STA $7E0000,X
INX
CPX #$80
BNE .LoopSlow
; Versión optimizada:
LDX #$7F ; Contador descendente
.LoopFast:
LDA Data,X
STA $7E0000,X
DEX
BPL .LoopFast ; Repetir hasta X = $FF
Programar para SNES es un desafío gratificante que combina conocimientos de hardware de bajo nivel con creatividad. Este manual cubre los conceptos fundamentales, pero la mejor manera de aprender es experimentar y estudiar ROMs existentes.
Nota: Este documento es una introducción. La programación real de SNES requiere estudio profundo de la documentación técnica y mucha práctica.