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.