Volver a la página principal.GUÍA DE ASM
Capítulo 5: Programación en ASM (mostrar un texto por pantalla)
Ley Nº 1 de la programación en ASM:
“Las Tiles o Fuentes a mostrar por Pantalla se deben meter en ROM o RAM y luego pasarla a la VRAM, ya que así y solo así se podrá ver en pantalla. No hay otra forma.” Magno.
Introducción:Nuevo V1.1:
Compilando el fuente en el fabuloso X86.
Más términos como Tile y sprite.
Aclaraciones y cambios que hay que hacerle al fuente para que se compile con X86 y el fuente sea ejecutable en el ZSNES.
El fuente .asm completo para X86.
Después de mucho tiempo, por fin he entendido como mostrar algo por pantalla, usando puro ASM, lo que muchos esperaban…¡por fin todo explicado!
Lo que pretendo es mostrar el mensaje “hola mundo”, clásico en el mundo de la programación, por la pantalla, que responda al Joystick, y todo esto verlo en el emulador.
Esto nos servirá para entender como se hace un juego en ASM, y servirá para entender mucho mejor los famosos LOG del Trace del SNES9X. Es el documento con más contenido de programación ASM que he hecho hasta ahora.
¡Quizás este es el documente MAS esperado por los verdaderos Rom-hackers de la SNES!
¿Que se espera?Simplemente hacer una ROM sencilla que muestra un texto por pantalla y que responda al Joypad de manera que al presionar START se baya oscureciendo la pantalla.
Esta es la ROM que ustedes harán, claro que con texto que quieran (:
Antes que TodoPara realizar a programar en ASM de la SNES, hay que tener en cuenta varias cosas (muchas cosas están ya explicadas con detalle en los capítulos anteriores, así que iré rápido):
La SNES corre sobre un procesador 65816, similar al 6502 (procesador donde corre la NES) pero con nuevas instrucciones disponibles.
El 65816 es un procesador de 16 bits, pero también de 8 bits. Soporta direccionamiento de 24 bits. A diferencia con el direccionamiento de 16 bits, ahora puedes agregar el byte de BANCO. Puedes hacer en 24 bits, por ejemplo una instrucción LDA $C01234, donde el banco es C0.
La memoria total esta dividida en BLOQUES de 32K cada uno.
NO se puede escribir en la ROM, solo en la RAM. Es decir no se puede hacer un:
LDA $20 luego hacer STA $C01234 ya que estamos escribiendo en la ROM (el Banco C0 es de la ROM). En cambio SI se puede hacer un LDA $20 y luego STA $7E0154 ya que escribimos en la RAM.
Las direcciones de la ROM varían según una HiRom o LoROM. La RAM es la misma para ambos.
HiROM -> RAM: 7E-7F: 0000-FFFF
Aquí hay 64K en cada banco (7E y 7F) lo que suma 128K de RAM, el tamaño total de memoria RAM de la SNES.
ROM: C0-FF: 0000-FFFF
En la ROM las Direcciones son de 0000-FFFF para CADA banco.
LoROM -> RAM: 7E-7F: 0000-FFFF
Aquí hay 64K en cada banco (7E y 7F) lo que suma 128K de RAM.
ROM: 80-FF: 8000-FFFF
En la ROM las Direcciones son de 8000-FFFF para CADA banco.
La CPU tiene registros internos: A, X, Y, D, S, PBR, DBR, PC y P. Todos se usan de alguna forma al momento de programar. A, X e Y son los que mas se usan directamente.
El Registro P - Registro de Banderas (Flag Register)
n: Negative
v: Overflow (desbordamiento)
m: Memory/Accumulator Select (acumulador)
x: Index Register select (registros X e Y)
d: Decimal
i: Interrupt
z: Zero
c: Carry (acarreo)
e: Emulation (0 = Modo Nativo)
Un REP #$30 deja X,Y, A en modo de 16 bit ya que 30 hex = 110000, deja en 0 (R[reset]EP) el Bit 4 de X (indices X e Y ) y bit 5 M (acumulador).
Un SEP #$30 deja X,Y, A en modo de 8 bit ya que 30 hex = 110000, deja en 1 (S[set]EP) el Bit 4 de X (indices X e Y ) y bit 5 M (acumulador).
Términos usadosPuerto: es una dirección de memoria en la que al escribir en ella, no escribes dentro de un chip, sino que estas escribiendo en otro dispositivo. Así las direcciones $2116 y $2117 son puertos ya que no escribimos directamente a los chips de RAM si no que en el controlador de video de la SNES.
PPU: Picture processing unit (unidad de imagen de procesamiento). Esta el la cosa que la toma datos gráficos de la SNES y las tira a una imagen en la pantalla de TV. En detalle: La PPU es un hardware interno a la SNES que viene en un chip diferente a la CPU y que se encarga de controlar el video y la salida a formato NTSC o PAL. Esta PPU es un procesador que funciona de forma independiente y automática según los valores que contengan sus registros y es el que genera la famosa interrupción NMI cuando se inicia el tiempo de VBlank.
VBlank o Blanking: Es el tiempo que tarda el haz de electrones de la TV en retornar desde la última línea de pantalla, abajo a la derecha, hasta la primera, arriba a la izquierda, para dibujar otro frame. El tiempo exactamente es de 65 microsegundos en el sistema europeo PAL y otro tiempo diferente en NTSC y en este tiempo se debe copiar lo que está en los planos a VRAM.
Registros: Puertos de Memoria-mapeados de Input/Output usados para enviar datos y comandos a PPU.
OAM : El Plano/tabla de Sprites se copia aquí y se mantiene información de ellos. OAM significa "Object Attribute Memory", es decir “Atributos de los Objetos en Memoria”.
CG: Color palette data (Datos de la paleta de Colores), o datos de la memoria que la almacena. Hay 256 paletas que contiene los niveles color en un valor de 16-bit.
SC: Screen (Pantalla). Usualmente nos referimos a Tile Map (o simplemente MAP) para un BG, el cual esta guardado en VRAM. Una pantalla esta formada por 32x32 tiles.
BG: Background (Fondo). Hay 4 BGs, o Planos o "layers", para cada Tile. Esos BGs pueden ser deslizados (scrolled), y en especial tipo de BG, en "Mode 7", puede ser ESCALADO y ROTADO en una sorprendente vista 3-D. A veces el termino "plano" es usado como BG pero con indice menor (BG1=Plane 0, BG2=Plane 1, GB3=Plano2, BG4=Plano 3).
Tile: Objetos gráficos que forman una pantalla (tile map). Un tile esta formado por 4 Planos de 8x8 pixels y estos planos por bits (1bpp=1 bit por píxel, 2bpp=bit por píxel, 2bpp, u 8bpp). La cantidad de colores posibles del tile lo da la cantidad de bits del bitplane que forma un plano, así 4 colores = 2 bitplanes, 16 colores = 4 bitplanes, 256 colores = 8 bitplanes, 256 colores = modo 7 (caso especial que lo veremos mas adelante). Varios Tiles forman un sprite.
Sprite: Objeto grafico que le podemos dar movimiento. Esta formada por tiles. La tabla de sprites se carga en OAM.
DMA: Conjunto de Registros que permiten copiar datos a VRAM extremadamente rápido sin usar mucho el procesador.
De la Fuente al ObjetoVamos a realizar un Código Fuente, que será Compilado por un Compilador o Traductor para generar un OBJETO de salida, que es en este caso, un ROM que es EJECUTABLE para un emulador de SNES.
Herramientas de programaciónPara programar: Un editor de Texto cualquiera, recomiendo EditPad Lite (Tip: con Shift + F11 se ven el numero de línea). A todo esto ¿alguien conoce un editor ASM con colores y todo lo demás que sirva para ASM 65816??? Si alguien sabe, que me mande un correo please, si no tendré que hacer yo mismo un editor

.
Para Compilar y Crear un SMC: Aquí hay una variedad mayor:
X86: usado por Magno, yo lo estoy aprendiendo a usar. Muy bueno y completo, quizás el mejor.
SNESASM de ThE INqUISITIoN of BLW (ojo que hay otro que se llama SNESASM Cross Assembler 1.05, pero NO me refiero a este). Muy sencillo de usar, pero incompleto en algunas aspectos. Este use para hacer la rom que trabajaremos en este capitulo. Es para compilar programas sencillos. No se esperen una maravilla de compilador, esta hecho a base de comandos en lenguaje C.
Para compilar fácilmente con SNESASM: Crear un acceso directo del SNESASM y en las propiedades, al final le agregas: [fuente] [archivo.smc] por ejemplo:
…..\SNESASM.EXE demo1.asm demo1.smc
Así como se ve en la imagen:
En la pestaña “Memoria” ponle todo Automático. Ahora edita el archivo fuente (en este caso demo1.asm) y ejecuta el acceso directo, así generaras el .smc mas rápidamente (.
Para compilar fácilmente con X86. Tenemos que aprender desde ya a compilar con este gran compilador ya que es el que usaremos de aquí en adelante. Crear un acceso directo del x86 y en las propiedades, al final le agregas: –s(ese) –l(ele) [fuente.asm] por ejemplo:
…..\X816.exe -s -l DEMO1.ASM
El –S es para que cree el ejecutable .SMC y el –L para que cree un archivo .LST con los códigos hex de cada opcode y la lista de errores posibles del fuente. Esto es muy útil al momento de depurar tu programa.
Etapas de Desarrollo del ProgramaAl programar la frase “Hola mundo” no es llegar y ponerse a escribir código print “hola mundo” como en C. Para nada, aquí es mas largo, casi 100 líneas de código. Pero tranquilos ya que lo entenderemos de a poco.
Para hacer un buen programa hay que aplicar Ingeniería, y para esto cumplimos una serie de etapas para cumplir un objetivo final. Las etapas básicas para escribir cualquier programa de ASM que hagas, son:
1. Declaración de Directivas de EnsambladorAlgunos copiladores exigen que tu código ASM de SNES tiene un código inicial que configura (no inicializa) los registros, índices, compilador etc., antes del programa principal. Ese conjunto de instrucciones en ingles le llaman Directivas de Ensamblador (Assembler Directives).
X86 y otros compiladores tienen estas directivas Opcionales, que van comienzo del código asm. En general si usas X86 van siempre. En el ASMSNES que yo uso, NO necesariamente deben estar.
El conjunto de Directivas es variado, dependiendo del compilador. El compilador X86 en el readme.txt entrega una larga lista, he aquí todos:
.EQU
.ORG
.DCB o .DB
.DCD or .DD
.DCL or .DL
.DCW or .DW
.DSB
.DSD
.DSL
.DSW
.PAD
.INCSRC (.SRC)
.INCBIN (.BIN)
.BASE
.MEM
.INDEX
.DETECT
.DASM
.OPTIMIZE (.OPT)
.HROM
.LROM
.HIROM
.SMC
.LIST
.SYMBOL
.PARENTHESIS (.PAR)
.ECHO
.COMMENT
.INTERRUPTS (.INT)
.CARTRIDGE (.CART)
.IF
.ELSE
.ENDIF
.IFDEF
.IFNDEF
.MACRO
.MODULE (.MOD)
.LOCALSYMBOLCHAR (.LOCCHAR)
.ASCTABLE
.ASC
.TABLE (.TAB)
No explicare todos, solo los más importantes (quizás en futuras versiones explicare uno a uno), estos son:
.ORG
Lo que hace es definir la dirección de inicio donde se empezara a escribir el código que le persigue. Recuerda que esto va al principio del código del juego. Pero existen 2 tipos de ROMs: Hi-roms y Lo-roms, ambos tienen sus direcciones específicas donde se puede empezar a escribir código. Lo-rom desde banco 80 dirección 8000 (dirección 808000) y las Hi-rom desde banco C0 dirección 0000 (dirección C00000).
Se usa así si el código que se hace es para una Lo-Rom :
.org $808000
Y para una Hi-Rom :
.org $C00000
.HIROM
Seteamaos el modo de la ROM, por defecto está en modo de Low ROM. Esta directiva es parecida a .HROM o .LROM. Usando ON o OFF en el operando se deja en modo de Hi ROM o Lo ROM. Si no va este modo, X86 envía un mensaje al compilarlo, ya que es necesario ponerlo.
Ejemplos:
.hirom ; reporta el status de la high ROM
.hirom on ; usa modo high ROM
.hirom off ; usa modo low ROM
.MEM
Define el ancho de bits del acumulador de 8 o 16 bits (por defecto es 16 bit). X86 envía un mensaje si no se define un .mem 8 o .mem 16.
Ejemplos:
.mem ; reporta el ancho de bits de A
.mem 8 ; setea A a 8 bit
.mem 16 ; setea A a 16 bit
.INDEX
Define el ancho de bits del Registro Indice X o Y a 8 o 16 bits (por defecto es 16 bit). X86 envía un mensaje si no se define un .index 8 o .index 16.
Ejemplos:
.index ; reporta el ancho de bit X/Y
.index 8 ; setea X/Y a 8 bit
.index 16 ; setea X/Y to 16 bit
.DETECT
Detecta el ancho de bits (por defecto esta en off), con esto X86 detecta si hay un cambio de ancho de Bits al realizar una instrucción REP/SEP (cambia de ancho de bits de acumulador o índices) y automáticamente X86 cambia el ancho de bits del acumulador
Ejemplos:
.detect ; reporta si detect esta on o off
.detect on ; activa autodetection
.detect off ; disactiva autodetection
.EQU
Puede ser .EQU o simplemente EQU o un signo igual =. Asigna un valor a un símbolo (como el la instrucción Define de C++).
Ejemplo:
space equ 32
letter_a = 65
LDA $space ;es lo mismo que LDA $32.
.OPTIMIZE (.OPT)
Activa o desactiva la optimización de dirección (por defecto esta en off).
X816 es capaz de detectar si una dirección está en un mismo Banco que la dirección actual. Si es así la dirección si es de 24-bit pasa a ser de 16-bit, esto eliminas las referencias de 24 bits cuando solo hablamos de direcciones de 16 bits y estamos en el mismo banco. X816 genera errores cuando hay una referencia a una dirección de 24 y el modo de direccionamiento es de 16 bits, pero el código resultante solo toma para la operación los 16 bits menores y no los 24 bits completos.
Ejemplos:
.optimize ; reporta el estatus de optimize
.optimize on ; activa optimize
.optimize off ; desactiva optimize
Código Ejemplo Directiva de CompilaciónAl crear un fuente para X86 debes poner al comienzo de tu archivo esto (no se si para otro es igual, ASMSNES no lo requiere):
.org $808000
.hirom off
.mem 16
.index 16
.detect on
.optimize off
Es fácil ahora interpretar lo que queremos hacer: una Lo-rom, con acumulador de 16 bits, índices de 16 bits, que detecte cambios de anchos de bits y que no optimice las direcciones.
Insisto que si haces fuente para SNESASM esto NO es obligatorio.
2. Declaración de ConstantesEsta declaración es muy simple, y se hace mediante la palabra reservada EQU que la tienen casi todos los compiladores, también funciona como directiva. Podemos definir constantes que usaremos en el programa reiteradamente, por ejemplo ciertas direcciones de la RAM a que se accesará mas de una vez, etc. No es obligatorio definir constantes, es solo para tu facilidad.
El uso es:
CONTANTE equ <num o hex>
Código Ejemplo Declaración de ConstantesEjemplo sacado del archivo WWF_v50.asm de Magno, donde él pone a disposición un código que muestra algo en pantalla con las fuentes extraídas y modificada del juego Chrono Trigger. Esta en su página, sección Documentos (
http://www.nekein.com/magno).
font equ $0A ;en general se ocupa esta dirección
charset equ $81E4
INI_X equ 32 ; es la posición de la pantalla
; en píxeles donde queremos que empiece el texto
INI_Y equ 64 ; es preferible que estos valores decimales
; sean múltiplos de 8
POS_X equ $4D
POS_Y equ $4A
FUENTE equ $44
NUM_TILES equ $7E807E
….
….
3. Instrucciones de PartidaSe inicializan ahora los registros básicos como el Carry y el de Interrupción, y se deja activado el Modo Nativo de la SNES, sin emulación de la 6502. SIEMPRE son el mismo conjunto de instrucciones, donde sea que lo quieras compilar tu fuente, si en X86 o en SNESASM.
En general aquí se hacen 3 pasos:
Activar interrupciones.
START SEI ; SEI: Set Interrupt Flag. El Label o Etiqueta “start” indica que comienza el código, puede ser “inicio” o “comienzo”, etc. SEI deja en 1 el flag de interrupción, es decir, que vamos a permitir que se produzcan interrupciones durante la ejecución. En general siempre se usa “Start y sei” en la misma línea.
El Data Bank Register (DB) debe partir igual al Program Bank Register (PB).
PHK ; PHK: Push Program Bank Register. El banco actual del
Program Bank se guarda en la Pila, de manera de pasarlo al Data Bank.
PLB ; PLB: Pull Data Bank Register. Sacamos el valor de la pila y la pasamos al Data Bank.
Cuando la SNES se inicia, en el registro PB se carga el byte del banco donde se están leyendo las instrucciones (esto es “interno” no hay código), pero el DB queda vacío, por lo que se llena con el valor de PB. En estas 2 líneas hacemos que el registro DB (Data bank) valga lo mismo que el PB (Program bank)
Dejar en 0 el bit de Emulación para actuar en modo de Nativo de 16 bit.
CLC ;limpiamos el Bit de CARRY (Carry=0)
XCE ;Dejamos Modo nativo de 16 BIT (No hay emulación del 6502). XCE lo que hace es poner a '0' el bit de emulación, que por defecto siempre está a '1', si no se pone a '1' el 65C816 se comportaría exactamente igual que el 6500 de la NES; para poner ese bit al valor que queramos siempre se ha de hacer a través del bit de Carry C.
4. Inicialización de los registrosEsta es una parte vital para todo el desarrollo del programa. Hablamos de registros de video, dma, Joystick, interrupción, que ahora se deben inicializar. Esto te ayudará a entender mejor cuando suceden rutinas complicadas que se repiten en todos los juegos, como “inicializar VRAM para mostrar gráficos”, “meter el texto en RAM”, etc.
Antes, una explicación de la grafica de la Snes y términos usados de aquí en adelante.
Una pantalla de SNES (en 1 frame) esta formada por 4 capas fijas llamadas BG o Planos, que no tienen porque estar activas las 4 a la vez. También esta formada por una Capa de Sprites, en la que los gráficos de allí dentro se mueven según unas tablas. Toda esta información se mete en la VRAM.
Cada capa de estas es independiente entre sí, por tanto, esto que explico ahora vale para cada una de las capas fijas por igual (que nombrar desde BG1 a BG4). Si solo quieres activar las capas BG2 y BG3, deberás escribir en VRAM para cada una de ellas un Mapa de Tiles.
Cada capa BG ocupa toda la pantalla y esta formada por una rejilla 32x32 de Tiles 8x8 (es decir, cada celdilla es una tile 8x8 píxeles) es decir, que tenemos una resolución de 256x256 píxeles.
Por tanto, lo lógico es pensar que hay que decirle a la SNES que tile 8x8 tiene que dibujar en cada celdilla. Para ello está el mapa de tiles, que tiene 2 bytes para indicar en que posición de la VRAM esta la tile que hay que sacar en esa celda. Como hay 32 celdas en cada una de las 32 filas, tenemos
-> 32 * 32 * 2 = 2kbytes de información para cada BG (recuerda que hay 4 BG's). Así que de VRAM necesitas un mínimo de 8 Kbytes para meter la información de las BG. El resto, 56Kbytes (así hacer los 64 Kbytes totales) es para que metas las tiles en sí de los gráficos que forman cada una de las BGs, así como de la capa de sprites.
Como ves, esto es espacio de sobra para meter gráficos. Además, estos gráficos se copian en VRAM SOLO y UNICAMENTE cuando se produce el Blanking del TV (ver Definiciones de sección “Términos Usados” para saber que es Blanking).
Esto es completamente lógico y lo hacen todas las consolas, puesto que mientras que el haz de electrones de la TV esta dibujando un frame en pantalla, éste no puede variar y por tanto no se puede producir ningún movimiento en la pantalla.
A parte está la Capa de Sprites. La SNES sólo puede mover 128 sprites a la vez, y la tabla de cada sprite es de 220 bytes, así que haces la multiplicación y ya tienes cuanto ocupa esta tabla completa. La capa de Sprites NO SE COPIA EN VRAM, SINO EN OAM, que es otro trozo de memoria que queda a parte de RAM y VRAM, que también se accede en modo puerto como la VRAM. Esta es más complicada de entender, así que la veremos quizás mas adelante.
La SNES utiliza uno de los 8 Modos Gráficos para mostrar algo en pantalla (del 0 al 7, ¿han escuchados del Mode 7 del Mario World 2 ?). El modo 0 es el mas sencillo ya que muestra 4 colores por tile, y se pueden usar los 4 planos. El Mode 7 es el más complejo, pero puedes hacer efectos en 3D.
El modo 1 es el más fácil y es el mas se usa para enseñar programación asm.
MODO Numero de BGs Máximos colores/Tile Paletas BitPlanes Colores 0 4 4 8 4 bpp 32 1 3 16/16/4 8 4 bpp 128
Como se ve, ya con modo 1 tenemos 128 colores. En Modo 1 tenemos el BG 1 y 2 con 16 colores y el BG 3 con 4 colores.
4.2 Como se fabrica un Tile y se muestra en Pantalla
Al programar podemos hacer un tile a base de códigos Hex, esos códigos representan en Binario una figura o fuente (una letra o símbolo).
Así tenemos por ejemplo 2 caracteres Char1 y Char2:
Char1 = $00, $00, $00, $00, $00, $00, $00, $00 -> 8 hex
Char2 = $00, $3C, $4E, $5E, $5E, $40, $3C, $00 -> 8 hex
No se ven pero si los pasas por un programa que yo hice SNES_FONT_MAKER V1.0 podrás ver que fuentes son.
En ASM quedaría:
Char1 dcb $00, $00, $00, $00, $00, $00, $00, $00
Char2 dcb $00, $3C, $4E, $5E, $5E, $40, $3C, $00
Y si pasamos a Binario (%) y escribimos hacia abajo cada uno, nos quedaría la versión que se ve en pantalla:
% 00000000 = $00
% 00000000 = $00
% 00000000 = $00
% 00000000 = $00 Este es Char1 (de 8 x 8 pixels)
% 00000000 = $00
% 00000000 = $00
% 00000000 = $00
% 00000000 = $00
% 00000000 = $00
% 00111100 = $3C
% 01001110 = $4E
% 01011110 = $5E Este es Char2 (es un carácter e) =
% 01011110 = $5E $00,$3C,$4E,$5E,$5E,$40,$3C,$00
% 01000000 = $40
% 00111100 = $3C
% 00000000 = $00
Esto ve se con mi programa SNES_FONT_MAKER V1.0 que hice:
Ahora bien como saber que color tienen los pixels que forman el carácter e.
4.3 Los Colores [ registros $2121 y $2122 ]
Los colores de los pixels se ven gracias a los BipPlanes, la SNES usa 4 bpp (bit plane font), es decir Fuente en Planos de 4 Bit.
0 0 0 0 = Color #0
bitplane 0 bitplane 1 bitplane 2 bitplane 3
0 1 1 0 = Color #6
bitplane 0 bitplane 1 bitplane 2 bitplane 3
Ahora Tabla completa de Modos:
MODO Numero de BGs Máximos colores/Tile Paletas BitPlanes Colores 0 4 4 8 4 bpp 32 1 3 16/16/4 8 4 bpp 128 2 ? ?? ? 4 bpp ?? 3 2 256 y 16 1 y 8 4 bpp 256 y 32 4 2 256 y 4 1 y 8 4 bpp 256 y 32 5 ? ?? ? 4 bpp ?? 6 ? 16 8 4 bpp 128 7 ? 256 1 4 bpp 256
El color de fondo que se ve en pantalla es algo mas complicado. Los colores de la SNES son 15 bit; 5 bits para azul, 5 para verde, y 5 para rojo. El orden aquí no es como VB u otro (clásico RGB), sino que es BGR (es invertido!!)
El formato es:
?aaaaavv vvv rrrrr = 16 bits
a : azul
v : verde
r : rojo
? : no se usa
Ejemplo se uso:
0111 1100 0000 0000 = #$7C00 Azul brillante
0000 0000 0001 1111 = #$001F Rojo brillante
0111 1100 0001 1111 = #$7C1F Púrpura
0000 0000 0000 0000 = #$0000 Negro
0111 1111 1111 1111 = #$7FFF Blanco
La implementación en ASM se ve detalladamente en la Inicialización de la VRAM.
4.4 La VRAM [ registros $2116, $2117, $2118, $2119, $2139, $213A ]
Si queremos mostrar una fuente por pantalla la única forma es pasando las fuentes de ROM/RAM a VRAM, ya que así y solo así se podrá ver en pantalla. Esto se hace mediante un “pasadizo”, los registros $2118 y $2119.
Recuerda los Bancos de los registros son $00 al $3F o $80 al $BF, ya que aquí estás escribiendo en lo que se llama PPU (Picture Processing Unit).
Estos registros son de la VRAM, al usarlos (escribir, leer) estas no escribiendo o leyendo en la Memoria principal, sino lo haces en la VRAM. Por eso a este tipo de registros (al igual que los otros 5 listados arriba) se les conoce por Registros de Hardware y precisamente a los de la VRAM se les llama Video Port Address.
La Super Nes tiene su propia RAM para video, por eso le llamamos VRAM. Es requerido para escribir datos gráficos (muy pocas veces se lee), y puede ser accesado por ciertos registros establecidos. Me refiero a la Video RAM (VRAM), que es un bloque de 64K de memoria esta dentro del controlador de video y donde las se guardan las Tiles y los Tile Map (La pantalla final que se ve).
En la VRAM usualmente se escribe en ella y no lee.
Registros $2116, $2117: VRAM Address (2 bytes en total)
Al escribir en $2116 le estamos pasando un dato a un dispositivo a parte que está dentro de la SNES pero fuera de la CPU principal (es como el puerto serie del ordenador, que cada vez que quisieras enviar un dato por él, tuvieras que escribir en una dirección de memoria concreta, esto es lo mismo). En este caso, al escribir en $2116 en cualquiera de los bancos $00 al $3F o $80 al $BF, estás escribiendo en lo que se llama PPU (Picture Processing Unit, ver terminología).
El registro $2116 indica a la PPU donde comenzamos a escribir o leer.
Si quieres decirle a la SNES que escribiras/leeras de la VRAM en la posición $4000 de esta. Deberás escribir en una dirección de memoria normal del mapa de la SNES que es $2116 y $2117, entonces al escribir cada byte de la dirección destino en VRAM debes poner en estos registros $2116= #$00 y $2117= #$40. O simplemente puedes hacer $2116 = #40000. Con esto se pone apuntando a su memoria RAM interna de la VRAM a la posición $4000, ya que se leerá o escribirá.
Ejemplo:
LDX #$2000
STX $2116
Registros $2118, $2119: VRAM Data Write (2 bytes en total)
Ahora si queremos “meter” algo en la VRAM, es decir escribir, debes meter los valores que quieras en las posiciones del $2118 y $2119. Este es el “pasadizo” de datos de la RAM a VRAM.
Si quieres meter AABB en VRAM hay que hacer $2118=$AA y $2119=$BB. Tu ya sabes, con LDA $AA, luego STA $2118, después LDA $BB, STA $2119. Este registro es incrementado automáticamente según el bit 7 del registro $2115.
Registros $2139, $213A: VRAM Data Read (2 bytes en total)
Si queremos leer de la VRAM, consultamos los registros $2139 y $213A. Este registro es incrementado automáticamente según el bit 7 del registro $2115.
4.5 Los Registros de Video
Todos los registros Externos a la CPU tienen una dirección fija en la MEMORIA, ya que así esta memoria actúa como puente entre el hardware y el código. En Memoria tenemos dirección para saber si la pantalla esta con Brillo o no, si estamos leyendo un joytick o no, etc. Y podemos setear estos registros para que por ejemplo NO se lea el joystick al empezar el juego, o esconda ciertos planos gráficos en algunos instantes del juego, etc.
Existe un lista muy completa en un archivo txt, llamado all_register.txt en mi pagina, esta escrito por un tal Yoshi que ha hecho muchos documentos Técnicos de la SNES. Aquí solo listare y explicare los fundamentales que se requieren saber. Explicaré lo que pueda ya que aún no domino el tema de los registros muy bien

En el campo Tamaño de la siguiente Tabla se muestran:
?: No se que estadísticas tiene este registro
2: El largo es de 2 byte (1 palabra o word)
d: Es requerido un Doble-byte para escribir en este registro. Es de 16 bit pero se llena con 2 STA seguidos.
w: En el Registro es posible Grabar
r: En el Registro es posible Leer
Tamaño/ Grabable Dirección Nombre(s) y Explicación de Registro (no todos)
Si el mismo Registro tiene varios nombres, se separan por / W
$2100 Screen Display
x000bbbb x: 0 = Screen on
1 = Screen off.
bbbb: Brillo o Brightness ($0-$F).
Ejemplo: si hacemos:
LDA $8F
STA $2100
estamos haciendo que este registro se carge con 8F h = 10001111 bin => x =1 y bb.=1111, es decir lo seteamos con; Screen OFF y con Brillo de 1111 bin = F hex => Full Brightness, es decir Brillo de pantalla al Máximo. ¿Fácil no? W $2101 OAM size /Tamaño de OAM (Plano de Strites se copia en OAM)
sssnnbbb s: 000 = 8x8 or 16x16.
001 = 8x8 or 32x32.
010 = 8x8 or 64x64.
011 = 16x16 or 32x32.
100 = 16x16 or 64x64.
101 = 32x32 or 64x64.
n: Name selection (upper 4k word addr).
b: Base selection (8k word seg. addr). W 2 $2102 / $2103 OAM address /Dirección de Sprite memory OAM /Registros de Sprite
aaaaaaaa r000000m a: dirección OAM.
r: Rotación prioridad de OAM.
m: Bit menos significativo. W $2104 OAM data
dddddddd d: byte a escribir en VRAM W $2105 Screen mode
abcdefff a: BG4 tile size (0=8x8, 1=16x16).
b: BG3 tile size (0=8x8, 1=16x16).
c: BG2 tile size (0=8x8, 1=16x16).
d: BG1 tile size (0=8x8, 1=16x16).
e: Highest priority for BG3 in MODE 1.
f: MODE definition. W $2106 Screen pixelation / Pixelación de Pantalla
xxxxabcd x: Pixel size (0=Smallest, $F=Largest).
a: Affect BG4.
b: Affect BG3.
c: Affect BG2.
d: Affect BG1. W $2107 BG1 VRAM location / Ubicación de BG1 (Plano0) en la VRAM
xxxx xxab x: Base address
ab: SC size
Ejemplo:
lda #$10
sta $2107 ; 10 hex = 0001 0000 => X = 000100 y AB = 00, X al revez sería 001000 = 1000. El mapa de gráficos BG1 estará en $1000 de VRAM.
....
....
......... ver documento de Yoshi ….. W $210B BG1 & BG2 Ubicación de Tiles en VRAM
aaaabbbb a: dirección de BG2 (plano 1).
b: dirección de BG1(plano 0).
Ejemplo:
lda #$01
sta $210B ;Seteamos BG1para tiles en VRAM en la dirección $1000.
Sip, se lee al revés. LDA #$01 = 0000 0001 => a = 0000 y b = 0001 => al revés es 1000. W $210C BG3 & BG4 Ubicación de Tiles en VRAM
aaaabbbb a: dirección de BG4 (plano 3).
b: dirección de BG3(plano 2). W D (16 bits de largo, se llena con 2 STA) $210D BG1 horizontal scroll / Plane 0 scroll x
mmmmmaaa aaaaaaaa a: Horizontal offset.
m: Only set with MODE 7.
Ejemplo:
LDA #$00
STA $210D ; llenamos Plane 0 scroll x (las aaaaaaaa)
STA $210D ; llenamos Plane 0 scroll x (llenamos aaa ) W D $210E BG1 vertical scroll / Plane 0 scroll y
mmmmmaaa aaaaaaaa a: Horizontal offset.
mayor menor m: Only set with MODE 7.
Ejemplo:
LDA #$00
STA $210E ; llenamos Plane 0 scroll Y (las aaaaaaaa)
STA $210E ; llenamos Plane 0 scroll Y (llenamos aaa )
....
....
......... ver documento de Yoshi …..
W $2115 Video port control / Control del Puerto de video / VRAM Adress Increment Register
i000abcd i: 0 = Se incrementa después de escribir en $2118
o leer de $2139.
1 = Se incrementa al escribir en $2119
o leer de $213A.
ab: Full graphic (ver tabla de abajo).
cd: SC increment (ver tabla de abajo).
abcd
0100 Increment by 8 for 32 times (2-bit formation).
1000 Increment by 8 for 64 times (4-bit formation).
1100 Increment by 8 for 128 times (8-bit formation).
0000 Address increments 1x1.
0001 Address increments 32x32.
0010 Address increments 64x64.
0011 Address increments 128x128.
Ej:
LDA #$80 ; 80 hex = 1000 0000 bin
STA $2115 ; Controlamos el Puerto de video diciendo que incrementaremos 1x1 cada vez que se escriba en $2118 o lea en $2139. W 2 $2116 / $2117 Video port address / VRAM Address
aaaaaaaa aaaaaaaa a: direccion para accesar a la VRAM
Ejemplo: Si quieres escribir en la posición de VRAM $4000 el valor $AABB, hago $2116=$00 y $2117=$40. (primero el byte MENOR luego el MAYOR) W 2 $2118 / $2119 Video port data
dddddddd dddddddd d: data to write to VRAM
$2119 $2118
Se incrementa según el Bit 7 el registro $2115.
Si el Bit 7 (aparece i en esta tabla, mas arriba) es:
0 y se Escribe solo en $2118, por lo que los 8-bits menores son escritos, entonces la dirección es incrementada.
0 y se Escribe $2119 y luego en $2118, entonces la dirección se incrementa.
1 y se Escribe solo en $2119, por lo que los 8-bits mayores son escritos, entonces la dirección es incrementada.
1 y se Escribe $2118 y luego en $2119, entonces la dirección se incrementa.
Ejemplo: Si quieres escribir en la posición de VRAM $4000 el valor $AABB, es decir hago $2118=$AA y $2119=$BB.
W $211A MODE7 settings
ab0000yx ab: (see table below).
y: Vertical screen flip (1=flip).
x: Horizontal screen flip (1=flip).
Si ab es:
00: Se repite la pantalla si se sale del área de pantalla.
10: Carácter 0x00 se repite se sale del área de pantalla.
11: Salir de la pantalla pone la pantalla a 1 color. W $211B COS (COSINE) rotate angle / X Expansion
Aquí va el Angulo que quieres rotar
....
....
......... ver documento de Yoshi …..
W $2121 Colour # (or pallete) selection / Registro Numero de Color
xxxxxxxx x: Dirección (color #). WD (se llenan con varios STA, del menor byte al mayor) $2122 Colour data
?aaaaavv vvvrrrrr a: Valor del color azul.
v: Valor del color verde.
r: Valor del color rojo.
Este registro es de 15 bits: 5 bit para azul, 5 para verde y 5 para rojo.
....
....
......... ver documento de Yoshi …..
W
$4200 Counter enable / Registro de Joypad
a0yx000b a: interrupción NMI/VBlank
y: Contador Vertical.
x: contador Horizontal.
b: Activa Lectura de Joypad.
Ejemplo: si hacemos al comienzo del código de un programa:
lda #$01 ; 01 hex = 00000001 bin
sta $4200 ; Activamos Lectura de JOYPAD
....
....
......... ver documento de Yoshi …..
R $4210 NMI
x000vvvv x: Disable/enable NMI.
v: Version # ($5A22 (???)) RW $4211 Video IRQ
i0000000 i: 0 = IRQ is not enabled.
1 = IRQ is enabled. RW $4212 Status register
xy00000a x: 0 = Not in VBlank state.
1 = In VBlank state.
y: 0 = Not in HBlank state.
1 = In HBlank state.
a: 0 = Joypad not ready.
1 = Joypad ready.
....
....
......... ver documento de Yoshi …..
R $4218 Joypad #1 status / Registro de Estado Botones joypad #1
abcd0000 a: A button (1=pressed).
b: X button (1=pressed).
c: Top-Left (1=pressed). [L Button]
d: Top-Rght (1=pressed). [R button] R $4219 Joypad #1 status / Registro de Estado Botones joypad #1
abcdefgh a: B button (1=pressed).
b: Y button (1=pressed).
c: Select (1=pressed).
d: Start (1=pressed).
e: Up (1=pressed).
f: Down (1=pressed).
g: Left (1=pressed).
h: Right (1=pressed).
....
....
......... ver documento de Yoshi …..
4.6 ¿Que registros específicos Inicializar?
Diré cual son los registros que se deben inicializar y su implementación en ASM.
Inicializar el Direct Page.
REP 30 ; X,Y en 16 bits
LDA #$0000 ; cargamos A con el VALOR 0x0000 (0000 hex)
TCD ; lo de A pasa al DP, es decir que la DP lo dejamos con valor 0.
Guardar las Fuentes en la RAM.
Esto se DEBE hacer aquí, por obligación y no en otra. Aquí se cargan TODAS las fuentes posibles a dibujar y deben estar en el orden que se muestra en Charset, es un orden establecido por el compilador.
Las fuentes de color azul son las que se usaron en la creación de la ROM y representan la letra en cuestión, en cambio, las de color roja hay que hacerlas si quieres usarlas (por eso están con el valor $00 que es símbolo de nulo o vació, es decir que si muestras un @ se verá solo en fondo ya que la letra será transparente) con el programa SNES_FONT_MAKER V1.0 que hice yo mismo.
LDA #CHARSET
STA $0A
CHARSET
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'@'
DC.B $00,$3C,$66,$7E,$66,$66,$66,$00 ;'A'
DC.B $00,$7C,$66,$7C,$66,$66,$7C,$00 ;'B'
DC.B $00,$3C,$66,$60,$60,$66,$3C,$00 ;'C'
DC.B $00,$78,$6C,$66,$66,$6C,$78,$00 ;'D'
DC.B $00,$7E,$60,$78,$60,$60,$7E,$00 ;'E'
DC.B $00,$7E,$60,$78,$60,$60,$60,$00 ;'F'
DC.B $00,$3C,$66,$60,$6E,$66,$3C,$00 ;'G'
DC.B $00,$66,$66,$7E,$66,$66,$66,$00 ;'H'
DC.B $00,$3C,$18,$18,$18,$18,$3C,$00 ;'I'
DC.B $00,$1E,$0C,$0C,$0C,$6C,$38,$00 ;'J'
DC.B $00,$6C,$78,$70,$78,$6C,$66,$00 ;'K'
DC.B $00,$60,$60,$60,$60,$60,$7E,$00 ;'L'
DC.B $00,$63,$77,$7F,$6B,$63,$63,$00 ;'M'
DC.B $00,$66,$76,$7E,$7E,$6E,$66,$00 ;'N'
DC.B $00,$3C,$66,$66,$66,$66,$3C,$00 ;'O'
DC.B $00,$7C,$66,$66,$7C,$60,$60,$00 ;'P'
DC.B $00,$3C,$66,$66,$66,$3C,$0E,$00 ;'Q'
DC.B $00,$7C,$66,$66,$7C,$6C,$66,$00 ;'R'
DC.B $00,$3E,$60,$3C,$06,$66,$3C,$00 ;'S'
DC.B $00,$7E,$18,$18,$18,$18,$18,$00 ;'T'
DC.B $00,$66,$66,$66,$66,$66,$3C,$00 ;'U'
DC.B $00,$66,$66,$66,$66,$3C,$18,$00 ;'V'
DC.B $00,$63,$63,$6B,$7F,$77,$63,$00 ;'W'
DC.B $00,$66,$3C,$18,$3C,$66,$66,$00 ;'X'
DC.B $00,$66,$66,$3C,$18,$18,$18,$00 ;'Y'
DC.B $00,$7E,$0C,$18,$30,$60,$7E,$00 ;'Z'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'['
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'\'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;']'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'^'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'_'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;' ' espacio
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'!'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'"'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'#'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'$'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'%'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'&'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'''
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'('
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;')'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'*'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'+'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;','
DC.B $F0,$E0,$E0,$C0,$C0,$E0,$F0,$00 ;'-'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'.'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'/'
DC.B $00,$3C,$66,$6E,$76,$66,$3C,$00 ;'0'
DC.B $00,$18,$38,$18,$18,$18,$7E,$00 ;'1'
DC.B $00,$7C,$06,$0C,$30,$60,$7E,$00 ;'2'
DC.B $00,$7E,$06,$1C,$06,$66,$3C,$00 ;'3'
DC.B $00,$0E,$1E,$36,$7F,$06,$06,$00 ;'4'
DC.B $00,$7E,$60,$7C,$06,$66,$3C,$00 ;'5'
DC.B $00,$3E,$60,$7C,$66,$66,$3C,$00 ;'6'
DC.B $00,$7E,$06,$0C,$0C,$0C,$0C,$00 ;'7'
DC.B $00,$3C,$66,$3C,$66,$66,$3C,$00 ;'8'
DC.B $00,$3C,$66,$3E,$06,$66,$3C,$00 ;'9'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;':'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;';'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'<'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'='
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'>'
DC.B $00,$00,$00,$00,$00,$00,$00,$00 ;'?'
Ahora tenemos disponibles TODOS los caracteres para ocuparlos después (son 64 caracteres).
NOTA: si compilas con X86 el comando es .DBC así:
.DCB $00,$00,$00,$00,$00,$00,$00,$00 ;'<'
Lo que se hace aquí es cargar en A el offset (el byte bajo) de la dirección de memoria donde empiezan los caracteres y la guarda en $7E:000A. En $7E:000B se guarda el byte alto y en $7E:000C el byte del banco, que SÓLO hace falta si se direcciona (en la parte del programa principal) esa zona de memoria donde están las letras de la forma LDA [$0A],Y, y no hace falta el byte de banco si se direcciona así LDX ($0A). Luego veremos que se hace de la forma LDX ($0A). Como ves, pasamos las fuentes a RAM (solo decía STA $0A y si no se indica banco entonces se pasa al banco 7E de la RAM).
Setear el registro Screen display, dirección en la memoria: $2100
LDA $8F
STA $2100
Estamos haciendo que este registro se cargue con 8F hex = 10001111 bin y recuerda el formato: x000bbbb en la tabla de registros. Entonces aquí tenemos x =1 y bb.=1111, es decir lo seteamos con Screen OFF y con Brillo de 1111 bin = F hex => Full Brightness, es decir Brillo de pantalla al Máximo.
Setear el registro OAM size, $2101
LDA #$00
STA $2101
Setear el registros de Sprite, $2102, $2103
LDA #$00
STA $2102
STA $2103 ;no es necesario hacer otra vez LDA #$00
Setear el registro Screen Mode, $2105
LDA #$00
STA $2105
Setear el registro Screen pixelation, $2106
LDA #$00
STA $2106
Setear el registro Ubicación de BG1 (Plano 0) en VRAM, $2107
LDA #$00
STA $2107
Setear el registro Ubicación de BG2 (Plano 1) en VRAM, $2108
LDA #$00
STA $2108
Setear el registro Ubicación de BG3 (Plano 2) en VRAM, $2109
LDA #$00
STA $2109
Setear el registro Ubicación de BG4 (Plano 3) en VRAM, $210A
LDA #$00
STA $210A
Setear el registro Ubicación de tiles en BG1 y BG2 (Plano 0 + 1) en VRAM, $210B
LDA #$00
STA $210B
Setear el registro Ubicación de tiles en BG3 y BG4 (Plano 2 + 3) en VRAM, $210C
LDA #$00
STA $210C
Setear el registro BG1 horizontal scroll (Plano 0, Scroll X), $210D
LDA #$00
STA $210D ;es de 16 bits de largo, primero cargamos de ceros la parte chica
STA $210D ;luego la mayor, OJO que no se puede hacer LDA #$0000 y luego STA, ya que se debe llenar en “tiradas” de 8 bits.
Setear el registro BG1 vertical scroll (Plano 0, Scroll Y), $210E
LDA #$00
STA $210E
STA $210E
Setear el registro BG2 horizontal scroll (Plano 1, Scroll Y), $210F
LDA #$00
STA $210F
STA $210F
Setear el registro BG2 vertical scroll (Plano 1, Scroll Y), $2110
LDA #$00
STA $2110
STA $2110
Setear el registro BG3 horizontal scroll (Plano 2, Scroll Y), $2111
LDA #$00
STA $2111
STA $2111
Setear el registro BG3 vertical scroll (Plano 2, Scroll Y), $2112
LDA #$00
STA $2112
STA $2112
Setear el registro BG4 horizontal scroll (Plano 3, Scroll Y), $2113
LDA #$00
STA $2113
STA $2113
Setear el registro BG4 vertical scroll (Plano 3, Scroll Y), $2114
LDA #$00
STA $2114
STA $2114
Setear el registro VRAM address increment, $2115
LDA #$80 ; 80 hex = 1000 0000 bin -> ver formato en tabla de registros.
STA $2115 ; La inicialización al Controlamos el Puerto de video diciendo que incrementaremos 1x1 cada vez que se escriba en $2118 o lea en $2139.
Setear el registro VRAM Address, $2116, $2117
LDA #$00
STA $2116 ; Zona baja de la dirección de VRAM
STA $2117 ; Zona alta
Setear el registro MODE7 settings, $211A
LDA #$00
STA $211A
Setear el registro MODE7 matrix parametros A,B,C,D, $211B,$211C,$211D,$211E.
LDA #$01 ; Parámetro A: Coseno parte X (ver libros de Matemática, dentro de sección Trigonometría para que sepan que es Seno, Coseno, etc…)
STA $211B ; Registro de COS (COSENO) rotación de ángulo en Modo 7.
LDA #$00
STA $211B ; necesita que se guarde un 0000 0000 0000 0001 dentro del registro ya que por Regla Matemática Coseno de 1 es 0 (COS (1) =0)
LDA #$00 ; Parámetro B: SENO parte X
STA $211C
STA $211C
LDA #$00 ; Parámetro C: SENO parte Y
STA $211D
STA $211D
LDA #$01 ; Parámetro D: COSENO parte Y
STA $211E
LDA #$00
STA $211E
Setear el registro MODE7 Posición Centrada X e Y, $211F, $2120
LDA #$00
STA $211F
STA $211F
STA $2120
STA $2120
Setear el registro Numero de Color, $2121
LDA #$00
STA $2121
Setear el registro Window mask setting BG1 y BG2, $2123
LDA #$00
STA $2123
Setear el registro Window mask setting BG3 y BG4, $2124
LDA #$00
STA $2124
Setear el registro Window mask setting Objeto y Color, $2125
LDA #$00
STA $2125
Setear el registro Window 1 Posición Izquierda, $2126
LDA #$00
STA $2126
Setear el registro Window 1 Posición Derecha, $2127
LDA #$00
STA $2127
Setear el registro Window 2 Posición Izquierda, $2128
LDA #$00
STA $2128
Setear el registro Window 2 Posición Derecha, $2129
LDA #$00
STA $2129
Setear el registro Logica de Window de BG1, BG2, BG3, BG4, $212A
LDA #$00
STA $212A
Setear el registro Logica de Mask Objeto Windows y color Window, $212B
LDA #$00
STA $212B
Setear el registro Main screen designation, $212C
LDA #$01
STA $212C ; el formato es 000abcde donde e: 1 o 0; y maneja el GB1 activado/desactivado. En este caso es BG1 activado.
Setear el registro Sub-screen designation, $212D
LDA #$00
STA $212D
Setear el registro Window mask main screen designation, $212E
LDA #$00
STA $212E
Setear el registro Window mask sub screen designation, $212F
LDA #$00
STA $212F
Setear el registro Fixed color addition or screen addition, $2130
LDA #$30 ; 30 hex = 0011 0000 bin le damos Fixed Color a Sub Screen y activamos
STA $212F ; suma y resta para fixed color.
Setear el registro Addition/subtraction for screens, BGs, & OBJs, $2131
LDA #$00
STA $2131
Setear el registro Fixed colour data para addition/subtraction, $2132
LDA #$E0 ; E0 hex = 11100000 bin
STA $2132 ; esto quiere decir que se permite un cambio de color Azul, Verde o Rojo.
; ver tabla de registros completa de Yoshi para mas detalles.
Setear el registro Screen mode/video select, $2133
LDA #$00
STA $2133
Setear el registro Counter enable / Enable V-blan, Interrupt, JoyPad, $4200
LDA #$00
STA $4200
Setear el registro Programmable I/O port (out-port), $4201
LDA #$FF ; FF hex = 11111111 bin
STA $2131 ; es decir que se activa el puerto de I/O (Joypad, pantalla) para se programado.
Setear el registro Multiplicand 'A', $4202
Este registro permite entregar el primer factor (A) de una multiplicación A*B=C donde A:8 bit, B.8 bit y C: 16bit.
LDA #$00
STA $4202 ;si quieres multiplicar A * B, entonces A debe estar en
$4202 y B en $4203, el resultado se puede leer de $4216/$4217 (el resultado es de 16 bits).
Setear el registro Multiplier 'B', $4203
Este registro permite entregar el segundo factor (B) de una multiplicación A*B=C.
LDA #$00
STA $4203
Setear el registro Dividend ‘C’, $4204
Este registro permite entregar el dividendo (C) de una división C*D=E, donde C: 16 bit, D: bit y E: 16 bit.
LDA #$00
STA $4204 ;si quieres dividir X/Y, X debe estar en $4204/$4205, e Y en
;$4206, el resultado puede ser leído desde $2114 y el resto
LDA #$00 ;se lee de $4216/4217.
STA $4205
Setear el registro Divisor 'D', $4205, $4206
LDA #$00
STA $4206
Setear el registro Horizontal Count Timer / Video horizontal IRQ, $4207
LDA #$00
STA $4207
Setear el registro Horizontal Count Timer MSB (bit mas significante) / Video horizontal IRQ MSB, $4208
LDA #$00
STA $4208
Setear el registro Vertical Count Timer / Video vertical IRQ, $4209
LDA #$00
STA $4209
Setear el registro Vertical Count Timer MSB (bit mas significante) / Video vertical IRQ MSB, $420A
LDA #$00
STA $420A
Setear el registro DMA Enable (bits 0-7), $420B
LDA #$00
STA $420B
Setear el registro Horizontal DMA (HDMA) Enable (bits 0-7), $420C
LDA #$00
STA $420C
Setear el registro Access cycle designation / Cycle speed (rom tipo slow/fast), $420D
LDA #$00
STA $420D
5. Inicialización de la VRAMLa VRAM se inicializa gracias a los Registros $2105, $2107, $210B, $212C, $2121, $2122.
Aquí tenemos los siguientes pasos:
Ubicación del Mapa de Gráficos BG1 (también conocido como Screen map data) en VRAM. Recuerda que se usa la dirección de memoria $2107 para indicarle a la SNES la dirección.
REP #$30 ; X,Y,A EN MODO 16 BITS
; 30 hex = 110000 = bit 5( y 6 en 1,
SEP #$20 ; ACUMULADOR EN MODO 8 BITS
LDA #$10
STA $2107 ;EL MAPA DE GRÁFICOS BG1 ESTARÁ EN $1000 DE VRAM. RECUERDA QUE SE LEE AL REVÉS => 10 HEX = 00010000 BIN Y SEGÚN EL FORMATO (VER LISTA DE REGISTROS DE ARRIBA) X = 000100 AL REVÉS SERIA 001000 = 1000.
Ubicación de Tiles en el Mapa de Gráficos BG1 en VRAM. Recuerda que se usa la dirección de memoria $210B para indicarle a la SNES la dirección.
lda #$02
sta $210B ; Las tiles del Plano 0 estarán en dirección $2000 de VRAM, recuerda que se lee al revés, el formato es aaaa bbbb y 02 hex = 0000 0002 bin => b = 0002 al revés 2000.
Setear el registro Screen Mode, usar dirección $2105.
LDA #$00
STA $2105 ; Ya esta seteado, pero se hace igual otra vez. Al estar en 0000 0000 todos los Tiles de los 4 BG se setean en modo 8x8 (ver documento de yoshi para mas detalles).
Setear registro Main screen designation con el registro $212C.
LDA #$01
STA $212C ; Ya esta seteado. El formato es 000abcde donde e: 1 o 0; y maneja el GB1 activado o desactivado. En este caso es BG1 activado. (ver documento de yoshi para mas detalles).
Inicialización de Colores con el registro $2121 y $2122.
Los colores de Fondo y Tiles se manejan a través del registro $2121 y $2122.
$2121 debe estar en 0 siempre.
$2122 maneja el color de las fuentes y fondo
Se inserta con LDA y luego con STA. Como es registro es de 16 bits (15 se ocupan) se inserta primero los 8 byte MENORES y luego los 7 MAYORES restantes. Así si queremos poner el color AZUL Brillante ponemos primero el #$00 y luego el #$7C.
Primero dejaremos el registro $2121 (Registro Número de Selección de Color) en 0.
LDA #$00
STA $2121
Ahora veamos el color del Fondo, así que si hacemos un:
LDA #$FF
STA $2122
LDA #$FF
STA $2122
Aquí estamos dejando el fondo de color Blanco. Si hubiésemos puesto en ves de #$FF y #$FF, los valores $00 y $00 nos da un fondo Negro. Y si hacemos #$00 y #$7C nos da Azul Brillante.
Luego si queremos mostrar las Fuentes Rojas de nuestro texto que luego pondremos (mas abajo explico este siguiente paso):
LDA #$1F
STA $2122
LDA #$00
STA $2122
Así deberíamos mostrar el texto que queremos con ASM.
Activar lectura de JoyPad
LDA #$01
STA $4200 ; El formato es a0yx000b y si b = 1
; => Se activa Lectura de Joypad.
6. Programa principalEl programa principal es la parte que más interviene el programador de asm, ya que toda la lógica de la ROM. Para este ejemplo lo dividiré en sucesiones con letras a,b,etc...
Pasar las Fuentes de RAM a VRAM
Ya tenemos todo el set de fuentes en RAM, ahora hay que pasarlas a VRAM para que se vean en pantalla.
Para esto se utilizan los registros $2116, $2117, $2118 y $2119.
Aquí hay que copiar de la RAM a la VRAM todas las fonts almacenadas alli.
Pasos:
Asignar la Dirección de VRAM utilizando el registro $2116, $2117 donde copiaremos la lista de fuentes posibles a utilizar.
LDX #$2000 ; usaremos la dirección $2000 de VRAM por lo que cargamos X con el VALOR 0x2000
STX $2116 ; #$2000 es de 16 bits por lo que se guarda #$00 en $2116 y automáticamente en $2117 el #$20, formando #$2000.
LDY #$0000
COPYCHAR LDA ($0A),Y
Cargamos en A el Offset que guardamos en $0A (sección Registros de Videos, punto 2), que es donde empieza la lista de fuentes. El (offset), Y es que sacamos el contenido que hay en $0A + Y (direccionamiento indexado Y, ¿recuerdas?), e Y lo inicializamos en 0 así sacamos primero lo que hay en $0A + 0 = $0A, luego podemos hacer un incremento Y para sacar lo que hay en $0A + 1 = $0B, y así sacando lo que hay dentro de cada dirección a partir de $0A (no es infinito, luego verás que hay un tope). Por eso a $0A se le conoce como “puntero” ya que es parecido a los punteros del lenguaje C.
Almacenar cada fuente por medio de registros $2118 y $2119.
Las Direcciones $2118 y $2119 son el “pasadizo” que une la RAM con VRAM, así podemos pasar datos a través de ellos. Si almacenas en $2118 o $2119 estas almacenando en VRAM.
STA $2118
guardamos en VRAM lo que esta guardado en A, es decir el offset de donde comienzan las fuentes, parte el offset de la letra @.
STZ $2119
Siempre cero en este registro para no hacer volteo H/V (esto lo dice Magno, lo consultare..¿?).
Por cada byte leído desde RAM se copia ese mismo byte en VRAM (STA $2118) más un byte a cero (STZ $2119), es decir que en VRAM tenemos el doble de bytes que en RAM para las mismas fuentes.
Hacer ciclo (también conocido como “bucle”) que copie todas las fuentes
INY ; incremento Y
CPY #$0200 ; comparo si Y = 200
BNE COPYCHAR ; si es NO es así, salta al Label COPYCHAR , es decir sigue copiando las demás fuentes. Copiamos 200 bytes (0x200) de RAM y pasan a ser 400 Bytes en VRAM y cada fuente ocupa 8 bytes de memoria, es decir que en VRAM sacamos 0x200/0x8 = 0x40 = 64 decimal. Es decir que en 200 bytes tenemos 64 fuentes (es decir todo el pack de caracteres) copiadas a VRAM. En VRAM se guarda después de cada fuente un espacio de 8 bytes con valor 0, por eso ocupamos 400 bytes.
NOTA: cuando tienes un CPX/CPY y luego un BNE, entonces Salta si no es igual la comparación, pero si tienes un AND y luego un BNE Salta si es igual la comparación. Ojo que se invierten.
Pasar la Pantalla ASCII a VRAM usando registros $2116, $2117, $2118 y $2119.
Si no pones esta parte, entonces solo se verá el fondo de color y ninguna letra. En esta parte debemos guardar la pantalla en VRAM, para eso debemos definirla, así que al final del código pon esto (Si te fijas bien, el texto esta en ASCII puro):
TEXTPAN
DC.B " "
DC.B " "
DC.B " "
DC.B " "
DC.B " "
DC.B " DARK-N "
DC.B " "
DC.B " "
DC.B " "
DC.B " "
DC.B " "
DC.B " PRESENTA "
DC.B " "
DC.B " ESTE SIMPLE "
DC.B " CODIGO "
DC.B " "
DC.B " HOLA "
DC.B " "
DC.B " MUNDO "
DC.B " "
DC.B " "
DC.B " PRESIONA BOTON START "
DC.B " "
DC.B " "
DC.B " "
DC.B " 2004 "
DC.B " "
DC.B " "
DC.B " "
DC.B " "
Luego seguimos con el código:
LDX #$1000 ; Asignamos una nueva dirección de VRAM
STX $2116 ; esta vez la $1000, se hace como siempre por
; el registro $2116
LDX #$0000 ; x = valor 0000
TEXTINFO LDA TEXTPAN,X ; Obtenemos la datos que conforman la
; pantalla que esta en ASCII
AND #$3F ; 3F = 63 dec = 0-63 = 64 caracteres
STA $2118 ; como siempre por este pasadizo tiramos
STZ $2119 ; datos a la VRAM.
; dejamos en cero el registro $2119
; (NO H/V FLIPPING)
INX
CPX #$0400 ; Trasferimos la pantalla completa
; $20*$20=$0400 (1024 BYTES)
; comparo si X = 400
BNE TEXTINFO ; si es NO es así, salta al Label TEXTINFO, es decir sigue copiando las demás datos de la pantalla.
NOTA: Los Labels (como TEXTINFO) debe in pegados a la izquierda de la pantalla.
Leer Joypad y botones con registro $4210 y $4219.
LDA #$0F
STA $2100 ; screen enabled, brillo al máximo
CLI ; CLEAR INTERRUPT BIT (lo dejamos en 0)
RUNAROUND LDA $4210 ; chequeamos el VERTICAL BLANK
AND #$80 ; 80 hex = 10000000 bin
BEQ RUNAROUND ; si son iguales entonces aun no se ejecutó
; el VBlanck, entonces salta de nuevo atrás.
; solo se ejecutara si pasa un refresco de
; pantalla.
Ahora para leer el Joypad, así que les muestro un ejemplo. Preguntaremos si esta presionado el Botón Start, si es así, que baya a una subrutina llamada RESET.
LDA $4219 ; se carga los que hay aquí, pongamos que A sale cargado
; el valor 1000 0000 , el botón B presionado
AND #$10 ; compara 10 hex = 0001 0000 bin con lo de A
; 10000000
; and 00010000 no son iguales
BNE RESET ; salta SI SON IGUALES (el AND funciona al revés que el CPX/CPY)
; por lo que no ejecuta y sigue lo que sigue debajo de BNE.
Siguiendo con nuestro programa:
JOYPAD LDA $4212 ; registro de dispositivo Joypad
AND #$01 ; se esta leyendo el Joypad, si esta activado
; $4212 = xxxxxxx1 y si no $4212 = xxxxxxx0
BNE JOYPAD ; si no esta activado que vuelva e intente de
; nuevo, si esta activo que siga.
LDA $4219 ; Leemos registro de botones
AND #$10 ; 10 hex = 00010000 bin = boton start
BNE RESET ; Presionado "START"? salte a RESET
JMP RUNAROUND ; sino que vuelva en un loop.
Oscurecer la Pantalla
Ahora la pantalla se oscurecerá poco a poco. A cada refresco de pantalla de bajara la luz.
RESET SEP #$30 ; X,Y,A en modo de 16 bit
LDY #$0F ; Y = F hex
LUS1 LDX #$06 ; X = 6 hex => es el tiempo que demora en un brillo
; antes de cambiar a otro, se le quita 1 a cada vuelta.
DEY ; y = y – 1 = E
STY $2100 ; $2100 = E => $2100 brillo de pantalla, 0F es máximo
; y 0E un poco menos, hasta llegar a 00, oscuro.
WAIT LDA $4210 ;
AND #$80
BEQ WAIT ; que pase un refresco de pantalla y luego siga.
; tendrá que ir a Wait en Loop hasta que suceda.
DEX ; X = X – 1 (primero valdrá 5, luego 4, luego 3,…0)
CPX #$00 ; X = 0?
BNE WAIT ; si no equivale (x=0) que vuelva a WAIT. Esto es
; para hacer tiempo en cada brillo.
CPY #$00 ; X = 0? (Y parte con F, luego E, ...0)
BNE LUS1 ; si no es así que vuelva a LUS1. Cuando se espero lo
; suficiente que se baya a LUS1
REP #$10 ; 10 hex = 10000 bin = bit 5 (X) índices en modo 16 bit
LDX #$0FFF ; cargamos un valor de 16 bits en X: 0FFF
DARK LDA $4210 ;
AND #$80
BEQ DARK ; esperamos un refresco y seguimos
DEX ; X = X – 1 (partió con 0FFF, luego 0FFE,....,0000)
CPX #$0000 ; X = 0000?
BNE DARK ; si no es así que baya a DARK y haga otro refresco.
Dejar el Program Bank vacío
SEP #$30 ; X, Y, A en modo de 8 bits
LDA #$00 ; A = 00
PHA ; Metemos #$00 al STACK
PLB ; Sacamos #$00 del stack y lo metemos en el Banco
; de Programa ($00: ZZZZ)
JMP.l START ; salto largo a $008000
7. Programa Completo.7.1 Fuente .asm para ensamblador SNESASM
NOTA: No recomiendo usar este fuente ya que corre solo con SNESASM y este compilador es muy básico.
font equ $0A
START sei
phk
plb
clc
xce
;==========================================================================
; INITIALIZACION DE REGISTROS
;==========================================================================
;
rep #$30
lda #$0000
tcd
lda #charset
sta font
SEP #$30 ; X,Y,A are 8 bit numbers
LDA #$8F ; screen off, full brightness
STA $2100 ; brightness + screen enable register
LDA #$00 ;
STA $2101 ; Sprite register (size + address in VRAM)
LDA #$00
STA $2102 ; Sprite registers (address of sprite memory [OAM])
STA $2103 ; "" ""
LDA #$00 ; Mode 0
STA $2105 ; Graphic mode register
LDA #$00 ; no planes, no mosaic
STA $2106 ; Mosaic register
LDA #$00 ;
STA $2107 ; Plane 0 map VRAM location
LDA #$00
STA $2108 ; Plane 1 map VRAM location
LDA #$00
STA $2109 ; Plane 2 map VRAM location
LDA #$00
STA $210A ; Plane 3 map VRAM location
LDA #$00
STA $210B ; Plane 0+1 Tile data location
LDA #$00
STA $210C ; Plane 2+3 Tile data location
LDA #$00
STA $210D ; Plane 0 scroll x (first 8 bits)
STA $210D ; Plane 0 scroll x (last 3 bits) #$0 - #$07ff
STA $210E ; Plane 0 scroll y (first 8 bits)
STA $210E ; Plane 0 scroll y (last 3 bits) #$0 - #$07ff
STA $210F ; Plane 1 scroll x (first 8 bits)
STA $210F ; Plane 1 scroll x (last 3 bits) #$0 - #$07ff
STA $2110 ; Plane 1 scroll y (first 8 bits)
STA $2110 ; Plane 1 scroll y (last 3 bits) #$0 - #$07ff
STA $2111 ; Plane 2 scroll x (first 8 bits)
STA $2111 ; Plane 2 scroll x (last 3 bits) #$0 - #$07ff
STA $2112 ; Plane 2 scroll y (first 8 bits)
STA $2112 ; Plane 2 scroll y (last 3 bits) #$0 - #$07ff
STA $2113 ; Plane 3 scroll x (first 8 bits)
STA $2113 ; Plane 3 scroll x (last 3 bits) #$0 - #$07ff
STA $2114 ; Plane 3 scroll y (first 8 bits)
STA $2114 ; Plane 3 scroll y (last 3 bits) #$0 - #$07ff
LDA #$80 ; increase VRAM address after writing to $2119
STA $2115 ; VRAM address increment register
LDA #$00
STA $2116 ; VRAM address low
STA $2117 ; VRAM address high
STA $211A ; Initial Mode 7 setting register
STA $211B ; Mode 7 matrix parameter A register (low)
LDA #$01
STA $211B ; Mode 7 matrix parameter A register (high)
LDA #$00
STA $211C ; Mode 7 matrix parameter B register (low)
STA $211C ; Mode 7 matrix parameter B register (high)
STA $211D ; Mode 7 matrix parameter C register (low)
STA $211D ; Mode 7 matrix parameter C register (high)
STA $211E ; Mode 7 matrix parameter D register (low)
LDA #$01
STA $211E ; Mode 7 matrix parameter D register (high)
LDA #$00
STA $211F ; Mode 7 center position X register (low)
STA $211F ; Mode 7 center position X register (high)
STA $2120 ; Mode 7 center position Y register (low)
STA $2120 ; Mode 7 center position Y register (high)
STA $2121 ; Color number register ($0-ff)
STA $2123 ; BG1 & BG2 Window mask setting register
STA $2124 ; BG3 & BG4 Window mask setting register
STA $2125 ; OBJ & Color Window mask setting register
STA $2126 ; Window 1 left position register
STA $2127 ; Window 2 left position register
STA $2128 ; Window 3 left position register
STA $2129 ; Window 4 left position register
STA $212A ; BG1, BG2, BG3, BG4 Window Logic register
STA $212B ; OBJ, Color Window Logic Register (or,and,xor,xnor)
LDA #$01
STA $212C ; Main Screen designation (planes, sprites enable)
LDA #$00
STA $212D ; Sub Screen designation
LDA #$00
STA $212E ; Window mask for Main Screen
STA $212F ; Window mask for Sub Screen
LDA #$30
STA $2130 ; Color addition & screen addition init setting
LDA #$00
STA $2131 ; Add/Sub sub designation for screen, sprite, color
LDA #$E0
STA $2132 ; color data for addition/subtraction
LDA #$00
STA $2133 ; Screen setting (interlace x,y/enable SFX data)
LDA #$00
STA $4200 ; Enable V-blank, interrupt, Joypad register
LDA #$FF
STA $4201 ; Programmable I/O port
LDA #$00
STA $4202 ; Multiplicand A
STA $4203 ; Multiplier B
STA $4204 ; Multiplier C
STA $4205 ; Multiplicand C
STA $4206 ; Divisor B
STA $4207 ; Horizontal Count Timer
STA $4208 ; Horizontal Count Timer MSB (most significant bit)
STA $4209 ; Vertical Count Timer
STA $420A ; Vertical Count Timer MSB
STA $420B ; General DMA enable (bits 0-7)
STA $420C ; Horizontal DMA (HDMA) enable (bits 0-7)
STA $420D ; Access cycle designation (slow/fast rom)
;===========================================================================
; I. DE VRAM
;===========================================================================
rep #$30
sep #$20
lda #$10
sta $2107
lda #$02
sta $210b
lda #$00
sta $2105
lda #$01
sta $212c
lda #$00
sta $2121
lda #$FF ; fondo blanco
sta $2122 ;
lda #$FF ;
sta $2122 ;
lda #$1F ; letras rojas
sta $2122 ;
lda #$00
sta $2122 ;
lda #$01
sta $4200 ; ENABLE JOYPAD READ (bit one)
;==========================================================================
; MOVIENDO GRAFICAS A VRAM
;==========================================================================
ldx #$2000 ;fuentes de ram a VRAM
stx $2116
ldy #$0000
copychar lda (font),y
sta $2118
stz $2119
iny
cpy #$0200
bne copychar
ldx #$1000 ;texto en ASCII a VRAM
stx $2116
ldx #$0000
textinfo lda TEXTPAN,x
and #$3f
sta $2118
stz $2119
inx
cpx #$0400
bne textinfo
lda #$0f
sta $2100
cli
runaround lda $4210
and #$80
beq runaround
joypad lda $4212 ; lectura de joypad
and #$01
bne joypad
lda $4219 ; lectura de boton start
and #$10
bne reset
jmp runaround
reset sep #$30 ; oscurecimiento
ldy #$0f
lus1 ldx #$06
dey
sty $2100
wait lda $4210
and #$80
beq wait
dex
cpx #$00
bne wait
cpy #$00
bne lus1
rep #$10
ldx #$0fff
dark lda $4210
and #$80
beq dark
dex
cpx #$0000
bne dark
sep #$30
lda #$00
pha
plb
jmp.l START ;salto largo a $008000
;============================================================================
; FUENTES
;============================================================================
charset
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ;'@'
dc.b $00,$3C,$66,$7E,$66,$66,$66,$00 ;'A'
dc.b $00,$7C,$66,$7C,$66,$66,$7C,$00 ;'B'
dc.b $00,$3C,$66,$60,$60,$66,$3C,$00 ;'C'
dc.b $00,$78,$6C,$66,$66,$6C,$78,$00 ;'D'
dc.b $00,$7E,$60,$78,$60,$60,$7E,$00 ;'E'
dc.b $00,$7E,$60,$78,$60,$60,$60,$00 ;'F'
dc.b $00,$3C,$66,$60,$6E,$66,$3C,$00 ;'G'
dc.b $00,$66,$66,$7E,$66,$66,$66,$00 ;'H'
dc.b $00,$3C,$18,$18,$18,$18,$3C,$00 ;'I'
dc.b $00,$1E,$0C,$0C,$0C,$6C,$38,$00 ;'J'
dc.b $00,$6C,$78,$70,$78,$6C,$66,$00 ;'K'
dc.b $00,$60,$60,$60,$60,$60,$7E,$00 ;'L'
dc.b $00,$63,$77,$7F,$6B,$63,$63,$00 ;'M'
dc.b $00,$66,$76,$7E,$7E,$6E,$66,$00 ;'N'
dc.b $00,$3C,$66,$66,$66,$66,$3C,$00 ;'O'
dc.b $00,$7C,$66,$66,$7C,$60,$60,$00 ;'P'
dc.b $00,$3C,$66,$66,$66,$3C,$0E,$00 ;'Q'
dc.b $00,$7C,$66,$66,$7C,$6C,$66,$00 ;'R'
dc.b $00,$3E,$60,$3C,$06,$66,$3C,$00 ;'S'
dc.b $00,$7E,$18,$18,$18,$18,$18,$00 ;'T'
dc.b $00,$66,$66,$66,$66,$66,$3C,$00 ;'U'
dc.b $00,$66,$66,$66,$66,$3C,$18,$00 ;'V'
dc.b $00,$63,$63,$6B,$7F,$77,$63,$00 ;'W'
dc.b $00,$66,$3C,$18,$3C,$66,$66,$00 ;'X'
dc.b $00,$66,$66,$3C,$18,$18,$18,$00 ;'Y'
dc.b $00,$7E,$0C,$18,$30,$60,$7E,$00 ;'Z'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '['
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '\'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; ']'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '^'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '_'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ;' ' espacio
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '!'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '"'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '#'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '$'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '%'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '&'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '''
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '('
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; ')'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '*'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '+'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; ','
dc.b $00,$00,$00,$3c,$3C,$00,$00,$00 ;'-'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '.'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '/'
dc.b $00,$3C,$66,$6E,$76,$66,$3C,$00 ;'0'
dc.b $00,$18,$38,$18,$18,$18,$7E,$00 ;'1'
dc.b $00,$7C,$06,$0C,$30,$60,$7E,$00 ;'2'
dc.b $00,$7E,$06,$1C,$06,$66,$3C,$00 ;'3'
dc.b $00,$0E,$1E,$36,$7F,$06,$06,$00 ;'4'
dc.b $00,$7E,$60,$7C,$06,$66,$3C,$00 ;'5'
dc.b $00,$3E,$60,$7C,$66,$66,$3C,$00 ;'6'
dc.b $00,$7E,$06,$0C,$0C,$0C,$0C,$00 ;'7'
dc.b $00,$3C,$66,$3C,$66,$66,$3C,$00 ;'8'
dc.b $00,$3C,$66,$3E,$06,$66,$3C,$00 ;'9'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; ':'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; ';'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '<'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '='
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '>'
dc.b $00,$00,$00,$00,$00,$00,$00,$00 ; '?'
;============================================================================
; PANTALLA EN ASCII
;============================================================================
; 12345678901234567890123456789012 => 32
TEXTPAN
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b " DARK-N "
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b " "
dc.b " PRESENTA "
dc.b " "
dc.b " ESTE SIMPLE "
dc.b " CODIGO "
dc.b " "
dc.b " HOLA "
dc.b " "
dc.b " MUNDO "
dc.b " "
dc.B " "
dc.b " PRESIONA BOTON START "
dc.b " "
dc.b " "
dc.b " "
dc.b " 2004 "
dc.b " "
dc.b " "
dc.b " "
dc.b " "
7.2 Fuente .asm para ensamblador X86
NOTA: Recomendado desde aquí en adelante el uso de compilador x86. Es el más completo y más profesional que hay.
.org $808000
.hirom off
.mem 16
.index 16
.detect on
.optimize off
font equ $0A
START sei
phk
plb
clc
xce
;==========================================================================
; INITIALIZACION DE REGISTROS
;==========================================================================
;
rep #$30
lda #$0000
tcd
lda #charset
sta font
SEP #$30 ; X,Y,A are 8 bit numbers
LDA #$8F ; screen off, full brightness
STA $2100 ; brightness + screen enable register
LDA #$00 ;
STA $2101 ; Sprite register (size + address in VRAM)
LDA #$00
STA $2102 ; Sprite registers (address of sprite memory [OAM])
STA $2103 ; "" ""
LDA #$00 ; Mode 0
STA $2105 ; Graphic mode register
LDA #$00 ; no planes, no mosaic
STA $2106 ; Mosaic register
LDA #$00 ;
STA $2107 ; Plane 0 map VRAM location
LDA #$00
STA $2108 ; Plane 1 map VRAM location
LDA #$00
STA $2109 ; Plane 2 map VRAM location
LDA #$00
STA $210A ; Plane 3 map VRAM location
LDA #$00
STA $210B ; Plane 0+1 Tile data location
LDA #$00
STA $210C ; Plane 2+3 Tile data location
LDA #$00
STA $210D ; Plane 0 scroll x (first 8 bits)
STA $210D ; Plane 0 scroll x (last 3 bits) #$0 - #$07ff
STA $210E ; Plane 0 scroll y (first 8 bits)
STA $210E ; Plane 0 scroll y (last 3 bits) #$0 - #$07ff
STA $210F ; Plane 1 scroll x (first 8 bits)
STA $210F ; Plane 1 scroll x (last 3 bits) #$0 - #$07ff
STA $2110 ; Plane 1 scroll y (first 8 bits)
STA $2110 ; Plane 1 scroll y (last 3 bits) #$0 - #$07ff
STA $2111 ; Plane 2 scroll x (first 8 bits)
STA $2111 ; Plane 2 scroll x (last 3 bits) #$0 - #$07ff
STA $2112 ; Plane 2 scroll y (first 8 bits)
STA $2112 ; Plane 2 scroll y (last 3 bits) #$0 - #$07ff
STA $2113 ; Plane 3 scroll x (first 8 bits)
STA $2113 ; Plane 3 scroll x (last 3 bits) #$0 - #$07ff
STA $2114 ; Plane 3 scroll y (first 8 bits)
STA $2114 ; Plane 3 scroll y (last 3 bits) #$0 - #$07ff
LDA #$80 ; increase VRAM address after writing to $2119
STA $2115 ; VRAM address increment register
LDA #$00
STA $2116 ; VRAM address low
STA $2117 ; VRAM address high
STA $211A ; Initial Mode 7 setting register
STA $211B ; Mode 7 matrix parameter A register (low)
LDA #$01
STA $211B ; Mode 7 matrix parameter A register (high)
LDA #$00
STA $211C ; Mode 7 matrix parameter B register (low)
STA $211C ; Mode 7 matrix parameter B register (high)
STA $211D ; Mode 7 matrix parameter C register (low)
STA $211D ; Mode 7 matrix parameter C register (high)
STA $211E ; Mode 7 matrix parameter D register (low)
LDA #$01
STA $211E ; Mode 7 matrix parameter D register (high)
LDA #$00
STA $211F ; Mode 7 center position X register (low)
STA $211F ; Mode 7 center position X register (high)
STA $2120 ; Mode 7 center position Y register (low)
STA $2120 ; Mode 7 center position Y register (high)
STA $2121 ; Color number register ($0-ff)
STA $2123 ; BG1 & BG2 Window mask setting register
STA $2124 ; BG3 & BG4 Window mask setting register
STA $2125 ; OBJ & Color Window mask setting register
STA $2126 ; Window 1 left position register
STA $2127 ; Window 2 left position register
STA $2128 ; Window 3 left position register
STA $2129 ; Window 4 left position register
STA $212A ; BG1, BG2, BG3, BG4 Window Logic register
STA $212B ; OBJ, Color Window Logic Register (or,and,xor,xnor)
LDA #$01
STA $212C ; Main Screen designation (planes, sprites enable)
LDA #$00
STA $212D ; Sub Screen designation
LDA #$00
STA $212E ; Window mask for Main Screen
STA $212F ; Window mask for Sub Screen
LDA #$30
STA $2130 ; Color addition & screen addition init setting
LDA #$00
STA $2131 ; Add/Sub sub designation for screen, sprite, color
LDA #$E0
STA $2132 ; color data for addition/subtraction
LDA #$00
STA $2133 ; Screen setting (interlace x,y/enable SFX data)
LDA #$00
STA $4200 ; Enable V-blank, interrupt, Joypad register
LDA #$FF
STA $4201 ; Programmable I/O port
LDA #$00
STA $4202 ; Multiplicand A
STA $4203 ; Multiplier B
STA $4204 ; Multiplier C
STA $4205 ; Multiplicand C
STA $4206 ; Divisor B
STA $4207 ; Horizontal Count Timer
STA $4208 ; Horizontal Count Timer MSB (most significant bit)
STA $4209 ; Vertical Count Timer
STA $420A ; Vertical Count Timer MSB
STA $420B ; General DMA enable (bits 0-7)
STA $420C ; Horizontal DMA (HDMA) enable (bits 0-7)
STA $420D ; Access cycle designation (slow/fast rom)
;===========================================================================
; I. DE VRAM
;===========================================================================
rep #$30
sep #$20
lda #$10
sta $2107
lda #$02
sta $210b
lda #$00
sta $2105
lda #$01
sta $212c
lda #$00
sta $2121
lda #$FF ; fondo blanco
sta $2122 ;
lda #$FF ;
sta $2122 ;
lda #$1F ; letras rojas
sta $2122 ;
lda #$00
sta $2122 ;
lda #$01
sta $4200 ; ENABLE JOYPAD READ (bit one)
;==========================================================================
; MOVIENDO GRAFICAS A VRAM
;==========================================================================
ldx #$2000 ;fuentes de ram a VRAM
stx $2116
ldy #$0000
copychar lda (font),y
sta $2118
stz $2119
iny
cpy #$0200
bne copychar
ldx #$1000 ;texto en ASCII a VRAM
stx $2116
ldx #$0000
textinfo lda TEXTPAN,x
and #$3f
sta $2118
stz $2119
inx
cpx #$0400
bne textinfo
lda #$0f
sta $2100
cli
runaround lda $4210
and #$80
beq runaround
joypad lda $4212 ; lectura de joypad
and #$01
bne joypad
lda $4219 ; lectura de boton start
and #$10
bne reset
jmp runaround
reset sep #$30 ; oscurecimiento
ldy #$0f
lus1 ldx #$06
dey
sty $2100
wait lda $4210
and #$80
beq wait
dex
cpx #$00
bne wait
cpy #$00
bne lus1
rep #$10
ldx #$0fff
dark lda $4210
and #$80
beq dark
dex
cpx #$0000
bne dark
sep #$30
lda #$00
pha
plb
jmp.l START ;salto largo a $008000
;============================================================================
; FUENTES
;============================================================================
charset
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ;'@'
.dcb $00,$3C,$66,$7E,$66,$66,$66,$00 ;'A'
.dcb $00,$7C,$66,$7C,$66,$66,$7C,$00 ;'B'
.dcb $00,$3C,$66,$60,$60,$66,$3C,$00 ;'C'
.dcb $00,$78,$6C,$66,$66,$6C,$78,$00 ;'D'
.dcb $00,$7E,$60,$78,$60,$60,$7E,$00 ;'E'
.dcb $00,$7E,$60,$78,$60,$60,$60,$00 ;'F'
.dcb $00,$3C,$66,$60,$6E,$66,$3C,$00 ;'G'
.dcb $00,$66,$66,$7E,$66,$66,$66,$00 ;'H'
.dcb $00,$3C,$18,$18,$18,$18,$3C,$00 ;'I'
.dcb $00,$1E,$0C,$0C,$0C,$6C,$38,$00 ;'J'
.dcb $00,$6C,$78,$70,$78,$6C,$66,$00 ;'K'
.dcb $00,$60,$60,$60,$60,$60,$7E,$00 ;'L'
.dcb $00,$63,$77,$7F,$6B,$63,$63,$00 ;'M'
.dcb $00,$66,$76,$7E,$7E,$6E,$66,$00 ;'N'
.dcb $00,$3C,$66,$66,$66,$66,$3C,$00 ;'O'
.dcb $00,$7C,$66,$66,$7C,$60,$60,$00 ;'P'
.dcb $00,$3C,$66,$66,$66,$3C,$0E,$00 ;'Q'
.dcb $00,$7C,$66,$66,$7C,$6C,$66,$00 ;'R'
.dcb $00,$3E,$60,$3C,$06,$66,$3C,$00 ;'S'
.dcb $00,$7E,$18,$18,$18,$18,$18,$00 ;'T'
.dcb $00,$66,$66,$66,$66,$66,$3C,$00 ;'U'
.dcb $00,$66,$66,$66,$66,$3C,$18,$00 ;'V'
.dcb $00,$63,$63,$6B,$7F,$77,$63,$00 ;'W'
.dcb $00,$66,$3C,$18,$3C,$66,$66,$00 ;'X'
.dcb $00,$66,$66,$3C,$18,$18,$18,$00 ;'Y'
.dcb $00,$7E,$0C,$18,$30,$60,$7E,$00 ;'Z'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '['
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '\'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; ']'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '^'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '_'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ;' ' espacio
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '!'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '"'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '#'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '$'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '%'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '&'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '''
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '('
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; ')'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '*'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '+'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; ','
.dcb $00,$00,$00,$3c,$3C,$00,$00,$00 ;'-'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '.'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '/'
.dcb $00,$3C,$66,$6E,$76,$66,$3C,$00 ;'0'
.dcb $00,$18,$38,$18,$18,$18,$7E,$00 ;'1'
.dcb $00,$7C,$06,$0C,$30,$60,$7E,$00 ;'2'
.dcb $00,$7E,$06,$1C,$06,$66,$3C,$00 ;'3'
.dcb $00,$0E,$1E,$36,$7F,$06,$06,$00 ;'4'
.dcb $00,$7E,$60,$7C,$06,$66,$3C,$00 ;'5'
.dcb $00,$3E,$60,$7C,$66,$66,$3C,$00 ;'6'
.dcb $00,$7E,$06,$0C,$0C,$0C,$0C,$00 ;'7'
.dcb $00,$3C,$66,$3C,$66,$66,$3C,$00 ;'8'
.dcb $00,$3C,$66,$3E,$06,$66,$3C,$00 ;'9'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; ':'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; ';'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '<'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '='
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '>'
.dcb $00,$00,$00,$00,$00,$00,$00,$00 ; '?'
;============================================================================
; PANTALLA EN ASCII
;============================================================================
; 12345678901234567890123456789012 => 32
TEXTPAN
.dcb " "
.dcb " "
.dcb " "
.dcb " "
.dcb " "
.dcb " DARK-N "
.dcb " "
.dcb " "
.dcb " "
.dcb " "
.dcb " "
.dcb " PRESENTA "
.dcb " "
.dcb " ESTE SIMPLE "
.dcb " CODIGO "
.dcb " "
.dcb " HOLA MUNDO "
.dcb " "
.dcb " - CODIGO PARA X86 - "
.dcb " "
.dcb " "
.dcb " PRESIONA BOTON START "
.dcb " "
.dcb " "
.dcb " "
.dcb " 2004 "
.dcb " "
.dcb " "
.dcb " "
.dcb " "
Desde aquí en adelante empiezan los Registros Hardware, que tiene una dirección de memoria fija asignada. Los Bancos son 00-3F y $80-$BF y las direcciones 2000-5FFF.
7 6 5 4 3 2 1 0 => 8 bits => 1 byte
____________________
E
| n | v | m | x | d | i | z | c |
-------------------------------
Volver a la página principal.