tutorial_sms
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorial_sms [2009/11/29 16:26] – xzakox | tutorial_sms [2013/11/10 18:36] (current) – [Explicación] zako | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Tutorial de programación de la Sega Master System ====== | ====== Tutorial de programación de la Sega Master System ====== | ||
- | No pretendo con esto hacer un tutorial paso a paso de programación de la SMS, sino partir de un programa de ejemplo e ir explicando sobre la marcha el programa y las características de la SMS. | + | No pretendo con esto hacer un tutorial paso a paso de programación de la SMS, sino partir de un programa de ejemplo e ir explicando sobre la marcha el programa y las características de la SMS, explicando además la programación del z80 que se va viendo en el ejemplo. |
- | + | ||
- | Empezamos con el código fuente de un pequeño programa de ejemplo: | + | |
+ | Empezamos con el código fuente de nuestro pequeño programa de ejemplo: | ||
+ | {{: | ||
Que muestra por pantalla el logo de vieju.net, espera que pulsemos el boton 1 del pad y borra la pantalla. | Que muestra por pantalla el logo de vieju.net, espera que pulsemos el boton 1 del pad y borra la pantalla. | ||
+ | |||
+ | Para generar una rom binaria a partir de este código, con el wla-dx: | ||
+ | |||
+ | < | ||
+ | wla-z80 -oi prueba.asm | ||
+ | wlalink prueba.link prueba.sms | ||
+ | </ | ||
+ | |||
+ | Necesitaremos un archivo prueba.link con el siguiente contenido: | ||
+ | < | ||
+ | [objects] | ||
+ | prueba.o | ||
+ | </ | ||
+ | |||
+ | Además necesitaremos los archivos de tiles, mapa y paleta: {{: | ||
===== Explicación ===== | ===== Explicación ===== | ||
Vamos diseccionando el programa parte por parte. | Vamos diseccionando el programa parte por parte. | ||
- | Para empezar comentar que en ensamblador, los numeros decimales se escriben tal cual, los hexadecimales precedidos por $ ($12he) y los binarios precedidos por % (%10011011). | + | Para empezar, comentar que en ensamblador los numeros decimales se escriben tal cual, los hexadecimales precedidos por $ ($12fe) y los binarios precedidos por % (%10011011). |
<code asm> | <code asm> | ||
Line 29: | Line 44: | ||
</ | </ | ||
- | Primero las directivas .MEMORYMAP y .ROMBANKMAP. Estas son directivas del ensamblador wla-dx que nos permiten definir cuestiones relacionadas con la rom que estamos creando. No es código z80, simplemente le dicen al ensamblador como crear el mapa de memoria y los bancos que vamos a usar en nuestro programa. En este caso, le decimos que solo tenemos un slot, de 0h a 8000h (32K) y solo un banco de memoria, tambien | + | Primero las directivas .MEMORYMAP y .ROMBANKMAP. Estas son directivas del ensamblador wla-dx que nos permiten definir cuestiones relacionadas con la rom que estamos creando. No es código z80, simplemente le dicen al ensamblador como crear el mapa de memoria y los bancos que vamos a usar en nuestro programa. En este caso, le decimos que solo tenemos un slot, de $0 a $8000 (32K) y solo un banco de memoria, tambien |
Luego el tag .sdsctag nos permite definir una versión un nombre, descripción y autor del programa. Sencillo. | Luego el tag .sdsctag nos permite definir una versión un nombre, descripción y autor del programa. Sencillo. | ||
Line 35: | Line 50: | ||
; Boot | ; Boot | ||
.bank 0 slot 0 | .bank 0 slot 0 | ||
- | .org $0001 | + | .org $0000 |
di | di | ||
Line 42: | Line 57: | ||
</ | </ | ||
- | Empezamos, usamos la directiva .bank del compilador para decirle que empezamos a definir el primer banco y el primer slot de memoria. Solo tenemos este, asi que solo nos hará falta definirlo aqui. | + | Empezamos, usamos la directiva .bank del compilador para decirle que empezamos a definir el primer banco y el primer slot de memoria. Solo tenemos este, asi que solamente |
- | Luego con .org le decimos que el programa comienza en 0000h, el primer banco de ROM. | + | Luego con .org le decimos que el programa comienza en $0000, el primer banco de ROM. |
- | Vamos con las primeras instrucciones de código. di deshabilita las interrupciones, | + | Vamos con las primeras instrucciones de código; //di// deshabilita las interrupciones, |
- | Y para terminar con jp main, saltamos al inicio del programa, dejando espacio entre aqui y nuestro | + | Y para terminar con //jp main//, saltamos al inicio del programa, dejando espacio entre aquí y nuestro |
<code asm> | <code asm> | ||
Line 55: | Line 70: | ||
</ | </ | ||
- | Aqui definimos el origen $0066, que es el lugar normal para poner la rutina de interrupción del botón de pausa. De momento no hacemos nada y solo retornamos de la funcion con retn | + | Aquí definimos el origen $0066, que es el lugar normal para poner la rutina de interrupción del botón de pausa. De momento no hacemos nada y solo retornamos de la funcion con //retn// |
<code asm> | <code asm> | ||
Line 71: | Line 86: | ||
</ | </ | ||
- | Ya empieza lo interesante. Para empezar, apuntamos la pila a una de las ultimas | + | Ya empieza lo interesante. Para comenzar, apuntamos la pila a una de las últimas |
- | Como la pila es decreciente (cuando insertas un valor, SP decrece), no tendremos problemas en que se desborde (a no ser que metamos mas de 8192-8 bytes en ella!). | + | Como la pila es decreciente (cuando insertas un valor, SP decrece), no tendremos problemas en que se desborde (a no ser que metamos mas de 8192-16 bytes en ella!). |
- | Ahora vamos con algo más complicado. Inicializar el VDP, el chip gráfico de la SMS. Al final del programa tenemos una tabla con los valores de configuración del VDP, de momento vamos a asumir que tenemos que usar estos para iniciarlo. Bien, entonces empezamos, cargamos el registro de 16 bit hl, con la dirección del primero de los datos a cargar. Cargamos en el registro b (8 bits) el numero | + | Ahora vamos con algo más complicado. Inicializar el VDP, el chip gráfico de la SMS. Al final del programa tenemos una tabla con los valores de configuración del VDP entre dos etiquetas, vdp_data y vdp_data_end, de momento vamos a asumir que tenemos que usar estos datos para iniciarlo. Bien, entonces empezamos; cargamos el registro de 16 bit //hl//, con la dirección del primero de los datos a cargar. Cargamos en el registro |
- | Y ahora vamos con una compleja instrucción del z80, otir. otir es una instrucción de salida de bloque con incremento. | + | Y ahora vamos con una compleja instrucción del z80, //otir//. //otir// es una instrucción de salida de bloque con incremento. |
Cuando termina esta instrucción ya hemos enviado todos los datos de configuración al VDP, vamos a por acción. | Cuando termina esta instrucción ya hemos enviado todos los datos de configuración al VDP, vamos a por acción. | ||
+ | <code asm> | ||
+ | ; borramos la vram | ||
+ | ld hl, | ||
+ | call vram_to_hl | ||
+ | call clear_vram | ||
+ | </ | ||
+ | |||
+ | Bueno, aqui lo que hacemos es poner toda la vram a cero. La ram puede tener valores arbitrarios al encender la consola, asi que no podemos asumir que siempre es cero, muchos emuladores lo hacen y esto es incorrecto, de hecho hay juegos que usan esto para obtener datos aleatorios o cosas asi. | ||
+ | Entonces lo primero que hacemos es limpiarla | ||
+ | Para ello vamos a usar dos rutinas que están definidias más adelante, asi que tocará explicarlas también. | ||
+ | Por lo que se ve en el código, cargamos el registro //hl// con el valor $4000 y luego llamamos a dos rutinas con la instrucción //call//. Las rutinas se invocan asi, tan simple, //call etiqueta//. | ||
+ | |||
+ | Vamos entonces a explicar las subrutinas: | ||
+ | |||
+ | <code asm> | ||
+ | vram_to_hl: | ||
+ | push af | ||
+ | ld a,l | ||
+ | out ($bf),a | ||
+ | ld a,h | ||
+ | out ($bf),a | ||
+ | pop af | ||
+ | ret | ||
+ | </ | ||
+ | |||
+ | Esta rutina es muy útil, como veremos. El VDP no está mapeado en la memoria principal, y como vimos antes, nos comunicamos con él usando los puertos de entrada y salida del z80. Al ser las instrucciones de E/S limitadas (además sólo podemos usar datos de 8 bits), se puede hacer tedioso escribir ciertos bloques de código, como por ejemplo en este caso. Quememos decirle al VDP que vamos a usar la dirección $4000 de la VRAM. Para ello, usando la instrucción normal de salida, //out (puerto), a//, tenemos que cargar en //a//, el valor $00 (el byte menos significativo), | ||
+ | |||
+ | Ahora vamos con la siguiente: | ||
+ | <code asm> | ||
+ | ; limpia la vram | ||
+ | clear_vram: | ||
+ | push af | ||
+ | push bc | ||
+ | ld bc,$4000 ; toda la vram | ||
+ | ld a,$00 ; con ceros | ||
+ | bclrvram: | ||
+ | out ($be),a | ||
+ | dec c | ||
+ | jp nz, | ||
+ | dec b | ||
+ | jp nz, | ||
+ | pop bc | ||
+ | pop af | ||
+ | ret | ||
+ | </ |
tutorial_sms.1259508410.txt.gz · Last modified: 2009/11/29 16:26 by xzakox