<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-12890134</id><updated>2011-12-24T00:08:05.974+01:00</updated><title type='text'>Programando la Gameboy Advance</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-12890134.post-112760488299688712</id><published>2005-09-25T01:02:00.000+02:00</published><updated>2005-09-25T02:35:48.216+02:00</updated><title type='text'>Sprites. Un ejemplo práctico</title><content type='html'>En la última entrega vimos un poco por encima los recursos que tiene la Gameboy Advance para manejar &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;. No obstante, la mejor forma de aprender suele ser practicando, así que vamos a poner en marcha un pequeño ejemplo en el que se dé uso a los conceptos vistos.&lt;br /&gt;&lt;br /&gt;Vamos a hacer un programa que sea capaz de mover por pantalla un par de &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;. Los que he usado en mi ejemplo son Head y Heels, los dos protagonistas de un clásico de los 8 bits programado por &lt;a href="http://www.ritman.co.uk/"&gt;Jon Ritman&lt;/a&gt;: &lt;a href="http://www.headoverheels.net/"&gt;Head Over Heels&lt;/a&gt;, y versionados por todo un crack del dibujo que es &lt;a href="http://remakesgraph.speccy.org/"&gt;Matriax&lt;/a&gt;. Son dos gráficos de 32x32 &lt;span style="font-style: italic;"&gt;pixels&lt;/span&gt;. Al importarlos a nuestro código sólo hemos tenido que tener la precaución de hacer que compartan la misma paleta de 256 colores.&lt;br /&gt;&lt;br /&gt;Mediante la cruceta moveremos a uno de ellos. Si mantenemos pulsado el botón R moveremos al otro, mientras que si mantenemos pulsado L moveremos a ambos. Por último, el botón START intercambia la prioridad de los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;, esto es, cuál se debe pintar encima del otro.&lt;br /&gt;&lt;br /&gt;Por último, en la parte inferior mostraremos las coordenadas de Heels y Head.&lt;br /&gt;&lt;br /&gt;El programa es muy sencillo. No obstante, vamos a comentarlo por partes.&lt;br /&gt;&lt;br /&gt;Para gestionar los &lt;span style="font-style: italic;"&gt;sprites &lt;/span&gt;podemos usar una estructura como la siguiente:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;typedef struct&lt;br /&gt;{&lt;br /&gt;int x,y;&lt;br /&gt;OAMEntry* oam;&lt;br /&gt;int gfxID;&lt;br /&gt;}Sprite;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Guardamos las coordenadas x e y, la entrada en la tabla OAM y un identificador del gráfico.&lt;br /&gt;&lt;br /&gt;En la función &lt;span style="font-style: italic;"&gt;main&lt;span style="font-style: italic;"&gt;()&lt;/span&gt;&lt;/span&gt; simplemente inicializamos ambos sprites y, a continuación, definimos el modo de vídeo, activamos el fondo, los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; e indicamos que el mapeado de los mismos lo haremos en modo 1D.&lt;br /&gt;&lt;br /&gt;Borramos el fondo, activamos los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; y entramos en un bucle sin fin:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Leemos los botones&lt;/li&gt;   &lt;li&gt;Según las pulsaciones, moveremos los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; convenientemente&lt;/li&gt;   &lt;li&gt;Esperamos al retrazado vertical y, justo después, copiamos la información desde el &lt;span style="font-style: italic;"&gt;buffer&lt;/span&gt; a la OAM (evitando así parpadeos).&lt;/li&gt; &lt;/ul&gt; El resto de funciones están comentadas en el código fuente. No obstante, si tenéis alguna duda no dudéis en consultarme.&lt;br /&gt;&lt;br /&gt;Recordad que si vuestra instalación del compilador difiere de la mía deberéis editar el &lt;span style="font-style: italic;"&gt;Makefile&lt;/span&gt; para que la compilación se efectúe correctamente.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;a href="http://falvarez.dyndns.org/gba/src/sprites.zip"&gt;Código fuente&lt;/a&gt;.&lt;br /&gt;&lt;a href="http://falvarez.dyndns.org/gba/bin/sprites.gba"&gt;ROM&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-112760488299688712?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/112760488299688712/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=112760488299688712' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112760488299688712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112760488299688712'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/09/sprites-un-ejemplo-prctico.html' title='Sprites. Un ejemplo práctico'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-112708317855052254</id><published>2005-09-19T00:39:00.000+02:00</published><updated>2005-09-19T23:46:30.440+02:00</updated><title type='text'>Sprites. Introducción</title><content type='html'>Una de las ventajas que tiene programar para la Gameboy Advance es que incorpora control de &lt;span style="font-style: italic;"&gt;sprites &lt;/span&gt;por &lt;span style="font-style: italic;"&gt;hardware&lt;/span&gt;. Este hecho simplificará sobremanera nuestras rutinas, ya que únicamente tenemos que indicarle a la consola cómo dibujar nuestro &lt;span style="font-style: italic;"&gt;sprite &lt;/span&gt;y cuáles son sus coordenadas, y ella se encargará de todo. Además, también nos permite aplicar transformaciones afines sobre los mismos, pero eso lo veremos más adelante.&lt;br /&gt;&lt;br /&gt;Para empezar vamos a ver cómo se almacenan los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; en la memoria y cómo podemos manejarlos.&lt;br /&gt;&lt;br /&gt;Los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; en la GBA pueden ser de tamaño 8x8 hasta 64x64 &lt;span style="font-style: italic;"&gt;pixeles&lt;/span&gt;, y se pueden manejar hasta 128 de ellos. Cada &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt; estará formado por bloques o &lt;span style="font-style: italic;"&gt;tiles&lt;/span&gt; de 8x8. Los datos de los 128 &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; se almacenan en una zona de memoria llamada OAM (&lt;span style="font-style: italic;"&gt;Object Attribute Memory&lt;/span&gt; o Memoria de Atributos de Objetos). La OAM consta de 1KB, donde se encuadran las 128 entradas de atributos de los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; intercaladas con las 32 entradas disponibles para transformaciones afines.&lt;br /&gt;&lt;br /&gt;En lenguaje C podríamos definir ambas estructuras de la siguiente forma:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;typedef struct tipo_OAM_ENTRY&lt;br /&gt;{&lt;br /&gt;   u16 attr0;&lt;br /&gt;   u16 attr1;&lt;br /&gt;   u16 attr2;&lt;br /&gt;   s16 fill;&lt;br /&gt;}   OAM_ENTRY;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;typedef struct tipo_OAM_AFF_ENTRY&lt;br /&gt;{&lt;br /&gt;   u16 fill0[3];&lt;br /&gt;   s16 pa;&lt;br /&gt;   u16 fill1[3];&lt;br /&gt;   s16 pb;&lt;br /&gt;   u16 fill2[3];&lt;br /&gt;   s16 pc;&lt;br /&gt;   u16 fill3[3];&lt;br /&gt;   s16 pd;&lt;br /&gt;}   OAM_AFF_ENTRY;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;de forma que se entrelazarían de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;table style="border: 1px solid rgb(0, 0, 0);" border="1" cellpadding="0" cellspacing="0"&gt; &lt;tbody&gt;&lt;tr align="left"&gt;&lt;th&gt;mem (u16)&lt;/th&gt;&lt;th&gt;0&lt;/th&gt;&lt;th&gt;3&lt;/th&gt;&lt;th&gt;4&lt;/th&gt;&lt;th&gt;7&lt;/th&gt;&lt;th&gt;8&lt;/th&gt;&lt;th&gt;B&lt;/th&gt;&lt;th&gt;C&lt;/th&gt;&lt;th&gt;F&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;OAM_ENTRY  &lt;/th&gt;&lt;td&gt;0 1 2&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;0 1 2&lt;/td&gt;&lt;td&gt;   &lt;/td&gt;&lt;td&gt;0 1 2&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;0 1 2&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;OAM_AFF_ENTRY  &lt;/th&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;pa&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;pb  &lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;pc&lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;pd&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Cada entrada de la OAM consta de 3 atributos de 16 bits, en los que se almacena la siguiente información:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ATRIBUTO 0&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;bits 0..7: Coordenada Y de la esquina superior izquierda del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;.&lt;br /&gt;bits 8..9: usados para configurar las transformaciones afines u ocultar el &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;00 - dibujado normal&lt;br /&gt;01 - el &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt; se dibuja según la transformación afin descrita por el atributo 1, bits 9..13&lt;br /&gt;10 - desactiva el dibujado (oculta el sprite)&lt;br /&gt;11 - transformación afín usando el doble del área de dibujado (lo veremos más adelante)&lt;br /&gt;&lt;br /&gt;bits 10..11: modo gráfico (efectos especiales)&lt;br /&gt;&lt;br /&gt;00 - dibujado normal&lt;br /&gt;01 - habilita el canal &lt;span style="font-style: italic;"&gt;alpha&lt;/span&gt;&lt;br /&gt;10 - el sprite hace de máscara&lt;br /&gt;11 - prohibido&lt;br /&gt;&lt;br /&gt;bit 12: habilita/deshabilita el efecto mosaico&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;bit 13: modo de color, 16 colores por &lt;span style="font-style: italic;"&gt;pixel&lt;/span&gt; si vale 0 y 256 si vale 1&lt;br /&gt;bits 14..15: forma del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;, junto con el tamaño del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt; (atributo 1, bits 14..15) conforma el tamaño real del mismo&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ATRIBUTO 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;bits 0..8: coordenada X de la esquina superior izquierda del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;.&lt;br /&gt;bits 9..13: índice de la transformación afín, sólo se usa si el bit 8 del atributo 0 vale 1&lt;br /&gt;bit 12: volteado horizontal, sólo si el bit 8 del atributo 0 vale 0&lt;br /&gt;bit 13: volteado vertical, sólo si el bit 8 del atributo 0 vale 1&lt;br /&gt;bits 14..15: tamaño, junto con la forma indicada en el atributo 0 conforma el tamaño real del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;, según la siguiente tabla:&lt;br /&gt;&lt;br /&gt;&lt;table style="border: 1px solid rgb(0, 0, 0);" border="1" cellpadding="0" cellspacing="0"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;forma\tamaño &lt;/td&gt;&lt;th&gt;00    &lt;/th&gt;&lt;th&gt;01    &lt;/th&gt;&lt;th&gt;10    &lt;/th&gt;&lt;th&gt;11&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;00&lt;/th&gt;&lt;td&gt; 8x 8 &lt;/td&gt;&lt;td&gt;16x16 &lt;/td&gt;&lt;td&gt;32x32 &lt;/td&gt;&lt;td&gt;64x64&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;01&lt;/th&gt;&lt;td&gt;16x 8 &lt;/td&gt;&lt;td&gt;32x 8 &lt;/td&gt;&lt;td&gt;32x16 &lt;/td&gt;&lt;td&gt;64x32&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;10&lt;/th&gt;&lt;td&gt;8 x16 &lt;/td&gt;&lt;td&gt; 8x32 &lt;/td&gt;&lt;td&gt;16x32 &lt;/td&gt;&lt;td&gt;32x64&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt; Tamaño del &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ATRIBUTO 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;bits 0..9: índice del primer bloque de los que componen el &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt;. Si estamos trabajando en modo &lt;span style="font-style: italic;"&gt;bitmap&lt;/span&gt;, el índice debe valer 512 o más&lt;br /&gt;bits 10..11: indican la prioridad, cuanto más alta, se dibuja primero (y quedará por debajo si luego se dibujan más &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;). Un &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt; se dibuja por encima de un fondo de la misma prioridad y, por otro lado, para dos &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; de la misma prioridad, se dibuja primero aquél que tenga la entrada en la tabla OAM con el índice más alto.&lt;br /&gt;bits 12..15: subpaleta que se usará para el &lt;span style="font-style: italic;"&gt;sprite&lt;/span&gt; cuando estemos trabajando en el modo de 16 colores, sólo si el bit 12 del atributo 0 vale 1&lt;br /&gt;&lt;br /&gt;No hay un cuarto atributo, pero para completar el alineamiento en memoria a una doble palabra de 32 bits se suele declarar un relleno (que se usa en las tablas de transformaciones afines, que estudiaremos más adelante).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;DOBLE BÚFER&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cuando trabajemos con &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;, se suele usar con la OAM una técnica de doble búfer. Esto es, trabajamos sobre una copia de la OAM y cuando se produzca el retrazado vertical en el redibujado de la pantalla aprovechamos para volcar la copia en la OAM real. De esta forma evitaremos modificar los valores de los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; justo mientras están siendo dibujados por el hardware de la Gameboy Advance.&lt;br /&gt;&lt;br /&gt;En la próxima entrega veremos un ejemplo práctico. Vamos a crear dos &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; de 256 colores (por tanto, compartirán paleta) y podremos moverlos con el &lt;span style="font-style: italic;"&gt;keypad&lt;/span&gt; y ver cómo se superpone el uno sobre el otro.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-112708317855052254?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/112708317855052254/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=112708317855052254' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112708317855052254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112708317855052254'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/09/sprites-introduccin.html' title='Sprites. Introducción'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-112198339068997318</id><published>2005-07-21T23:59:00.000+02:00</published><updated>2005-07-22T00:03:10.696+02:00</updated><title type='text'>(Aviso, no me he ido)</title><content type='html'>Ni me he ido ni he abandonado la programación de la GBA.&lt;br /&gt;&lt;br /&gt;Simplemente, se han juntado 2 semanas de vacaciones con una vuelta al trabajo muy ajetreada y, la verdad, llego a casa con poco tiempo y ganas de seguir investigando. Pero tengo claros cuáles serán los próximos pasos que seguiré:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Investigar el tema de &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;. Ya estuve mirando algo por encima antes de marchar de vacaciones. Seguramente que le dedique varios artículos, porque el tema es bastante extenso.&lt;/li&gt;   &lt;li&gt;Instalarme un buen entorno de desarrollo, haciendo uso de la herramienta &lt;a href="http://www.gnu.org/software/make/"&gt;&lt;span style="font-style: italic;"&gt;Make&lt;/span&gt;&lt;/a&gt; y de algún software de control de versiones como &lt;a href="http://subversion.tigris.org/"&gt;&lt;span style="font-style: italic;"&gt;Subversion&lt;/span&gt;&lt;/a&gt;.&lt;/li&gt; &lt;/ol&gt; Igual permuto el orden, pero acometeré esas dos etapas próximamente (espero que no tardando demasiado).&lt;br /&gt;&lt;br /&gt;Para los que vayan de vacaciones, buen viaje y a disfrutar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-112198339068997318?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/112198339068997318/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=112198339068997318' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112198339068997318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/112198339068997318'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/07/aviso-no-me-he-ido.html' title='(Aviso, no me he ido)'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111766670305591039</id><published>2005-06-01T21:55:00.000+02:00</published><updated>2005-06-02T01:42:23.870+02:00</updated><title type='text'>Interrupciones. Un ejemplo práctico</title><content type='html'>En el anterior artículo vimos qué son las interrupciones y la necesidad de tener un gestor de interrupciones que detecte cuál se ha producido y ceda el control a la función que se vaya a encargar de su manejo.&lt;br /&gt;&lt;br /&gt;Lo primero que debemos hacer es codificar ese gestor de interrupciones. Debe ser algo sumamente rápido, así que, anticipando acontecimientos, he tomado el siguiente código ensamblador del tutorial de &lt;a href="http://www.thepernproject.com/tutorials/GBA/day_4.html"&gt;Drunken Coders&lt;/a&gt;. De momento no nos preocuparemos en entenderlo. Simplemente responde al esquema que habíamos planteado y funciona. Más adelante quizás ahondemos en conceptos de ensamblador.&lt;br /&gt;&lt;br /&gt;El ensamblador no va a ser el único concepto que vamos a avanzar en este ejemplo y que retomaremos más adelante para estudiarlo en profundidad. Por un lado, para entender el funcionamiento de las interrupciones vamos a implementar un contador, que imprimiremos en pantalla y que se incrementará en una unidad cada segundo. Para ello, haremos uso de los temporizadores con que nos provee el &lt;span style="font-style: italic;"&gt;hardware&lt;/span&gt; de la Gameboy Advance.&lt;br /&gt;&lt;br /&gt;Por otro lado, este proyecto ya consta de más de un archivo de código fuente (en este caso, uno en C y otro en ensamblador). De momento efectuaremos una compilación &lt;span style="font-style: italic;"&gt;ad hoc&lt;/span&gt;. Anticipo que en breve estudiaremos el uso de la herramienta &lt;span style="font-style: italic;"&gt;make&lt;/span&gt;, que nos permitirá gestionar proyectos con múltiples archivos fuente de forma sencilla.&lt;br /&gt;&lt;br /&gt;Pues bien, ya tenemos claro lo que vamos a hacer. En primer lugar, haremos uso de nuestro sencillo-pero-efectivo juego de caracteres numéricos para imprimir en pantalla el contador, así como la función PintaCaracter() y la función ActualizaContadorPantalla(), adaptada del marcador del gbasnake y que nos permite imprimir un número en pantalla. Por otro lado, la lógica del programa es bien sencilla.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Habilitar el modo 3 en la pantalla de la Gameboy Advance.&lt;/li&gt;   &lt;li&gt;Habilitar uno de los temporizadores, configurándolo para que se genere una interrupción cada segundo.&lt;/li&gt;   &lt;li&gt;Definir la función que gestionará las interrupciones generadas por el temporizador.&lt;/li&gt;   &lt;li&gt;Habilitar las interrupciones.&lt;/li&gt; &lt;/ol&gt; El paso 1 ya es conocido del ejemplo del gbasnake. Vamos con el resto de pasos.&lt;br /&gt;&lt;br /&gt;2. Vamos a usar el temporizador 0. Primero escribiremos el valor inicial del temporizador en su registro de datos correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;REG_TM0D = 0xC000;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En el registro de control del temporizador, REG_T0CNT, tenemos que activar los bits 0 y 1 (para usar un conteo cada 1024 ciclos, lo que nos da una frecuencia de conteo de 16384Hz), el bit 6 (para que se genere una interrupción en cuando se produzca desbordamiento) y el bit 7 (que activa el temporizador).&lt;br /&gt;&lt;br /&gt;¿Qué conseguimos con esto? Que cada 16384 (0x4000) ciclos el contador produzca desbordamiento y, por lo tanto, genere una interrupción. Como la frecuencia a la que trabajamos es precisamente de 16384Hz, el temporizador 0 generará una interrupción cada segundo. Ya tenemos la primera parte del problema resuelta.&lt;br /&gt;&lt;br /&gt;3. Ahora tenemos que declarar e implementar una función que maneje dicha interrupción. Lo primero que haremos será definir un tipo de datos que represente a dicha función:&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;typedef void (*fp)(void);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Declaramos la tabla de vectores de interrupción (con ese nombre, que es la etiqueta que maneja el gestor de interrupciones que previamente hemos presentado en ensamblador):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;fp IntrTable[14];&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Declaramos la función que gestiona las interrupciones (que es la que hemos codificado en ensamblador). El nombre es importante, si no luego no podremos enlazar el código objeto y la generación del binario fallará:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;extern void IrqHandler(void);&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Por último nos construiremos, por comodidad, dos funciones. La primera nos servirá para habilitar las interrupciones y asignar los manejadores correspondientes. La segunda, nos servirá para deshabilitar las interrupciones.&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void IRQ_Set(int irq, fp irq_handle)&lt;br /&gt;{&lt;br /&gt;int i;&lt;br /&gt;&lt;br /&gt;for(i = 0; i &amp;lt; 14; i++)&lt;br /&gt;{&lt;br /&gt;   if(irq &amp;amp; BIT(i))&lt;br /&gt;      IntrTable[i] = irq_handle;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;REG_IRQ_HANDLER = IrqHandler;&lt;br /&gt;REG_IME  = 0;&lt;br /&gt;REG_IE |= irq;&lt;br /&gt;REG_IME = 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void IRQ_Disable(int irqs)&lt;br /&gt;{&lt;br /&gt;REG_IME = 0;&lt;br /&gt;REG_IE &amp;= ~irqs;&lt;br /&gt;REG_IME = 1;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;4. Activar las interrupciones es tan sencillo ahora como: &lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;br /&gt;&lt;br /&gt;IRQ_Set(IRQ_TIMER_0,GestionaTimer);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y ya está. Terminamos el código con un bucle infinito en el que no se haga nada, y veremos en efecto como aparece un contador en la esquina inferior derecha de la pantalla que se va incrementando cada segundo.&lt;br /&gt;&lt;hr /&gt;&lt;a href="http://falvarez.dyndns.org/gba/src/interrup.zip"&gt;Código fuente&lt;/a&gt;.&lt;br /&gt;&lt;a href="http://falvarez.dyndns.org/gba/bin/interrup.gba"&gt;ROM&lt;/a&gt;.&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;Gestor de interrupciones (irq_handler.asm).&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;"&gt;&lt;br /&gt;&lt;pre&gt;@ arm-elf-as -mthumb-interwork -o irq_handler.o irq_handler.asm&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    .SECTION    .iwram,"ax",%progbits&lt;br /&gt; &lt;br /&gt;    .EXTERN     IntrTable&lt;br /&gt;    .GLOBAL  IrqHandler&lt;br /&gt;    .ALIGN&lt;br /&gt;    .ARM&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;IrqHandler:&lt;br /&gt;                                         @ Multiple interrupts support&lt;br /&gt;        mov     r2, #0x4000000           @ REG_BASE&lt;br /&gt;        ldr     r3, [r2,#0x200]!         @ r2 = IE : r3 = IF|IE&lt;br /&gt;        ldrh    r1, [r2, #0x8]           @ r1 = IME&lt;br /&gt;        mrs     r0, spsr&lt;br /&gt;        stmfd   sp!, {r0-r2,lr}          @ {spsr, IME, REG_IE, lr}  // IF|IE&lt;br /&gt;&lt;br /&gt;        mov     r0, #1                   @ IME = 1 (To permit multiple interrupts if&lt;br /&gt;                                         @ an interrupt occurs)&lt;br /&gt;        strh    r0, [r2, #0x8]&lt;br /&gt;        and     r1, r3, r3, lsr #16      @ r1 = IE &amp; IF&lt;br /&gt;        ldr     r12, =IntrTable&lt;br /&gt;&lt;br /&gt;        ands    r0, r1, #1               @ V-blank interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #2               @ H-blank interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #4               @ V-counter interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #8               @ Timer 0 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x10            @ Timer 1 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x20            @ Timer 2 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x40            @ Timer 3 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x80            @ Serial Communication Interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x100           @ DMA 0 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x200           @ DMA 1 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x400           @ DMA 2 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x800           @ DMA 3 interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x1000          @ Key interrupt&lt;br /&gt;        bne     jump_intr&lt;br /&gt;        add     r12,r12, #4&lt;br /&gt;        ands    r0, r1, #0x2000          @ Cart interrupt&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;jump_intr:&lt;br /&gt;        strh    r0, [r2, #2]             @ Clear IF&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        mrs     r3, cpsr&lt;br /&gt;        bic     r3, r3, #0xdf            @ \__&lt;br /&gt;        orr     r3, r3, #0x1f            @ /  --&gt; Enable IRQ &amp; FIQ. Set CPU mode to System.&lt;br /&gt;        msr     cpsr, r3&lt;br /&gt;&lt;br /&gt;        ldr     r0, [r12]&lt;br /&gt;&lt;br /&gt;        stmfd   sp!, {lr}&lt;br /&gt;        adr     lr, IntrRet&lt;br /&gt;        bx      r0&lt;br /&gt;&lt;br /&gt;IntrRet:&lt;br /&gt;        ldmfd   sp!, {lr}&lt;br /&gt;&lt;br /&gt;        mrs     r3, cpsr&lt;br /&gt;        bic     r3, r3, #0xdf            @ \__&lt;br /&gt;        orr     r3, r3, #0x92            @ /  --&gt; Disable IRQ. Enable FIQ. Set CPU mode to IRQ.&lt;br /&gt;        msr     cpsr, r3&lt;br /&gt;&lt;br /&gt;        ldmfd   sp!, {r0-r2,lr}          @ {spsr, IME, REG_IE, lr}  //IF|IE&lt;br /&gt;        strh    r1,  [r2, #0x8]          @ restore REG_IME&lt;br /&gt;        msr     spsr, r0                 @ restore spsr&lt;br /&gt;        bx      lr&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    .ALIGN&lt;br /&gt;    .POOL          &lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111766670305591039?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111766670305591039/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111766670305591039' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111766670305591039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111766670305591039'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/06/interrupciones-un-ejemplo-prctico.html' title='Interrupciones. Un ejemplo práctico'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111723670942308288</id><published>2005-05-28T01:28:00.000+02:00</published><updated>2005-05-28T02:19:09.550+02:00</updated><title type='text'>Interrupciones. Primera aproximación.</title><content type='html'>No, no se trata de un nuevo inciso en nuestro proceso de aprendizaje. Es más, el tema que vamos a tratar no es sencillo, pero es crucial a la hora de programar. Se trata del manejo de interrupciones.&lt;br /&gt;&lt;br /&gt;Una interrupción, como su propio nombre indica, es un evento que provoca que la CPU deje de ejecutar el código que estaba ejecutando y salte a una zona de código predefinida, que hará una tarea determinada (normalmente rápida) y vuelva a donde estaba en el preciso instante en que se produjo la interrupción.&lt;br /&gt;&lt;br /&gt;Hay dos tipos de interrupciones: las generadas por la circuitería interna de la consola (interrupciones &lt;span style="font-style: italic;"&gt;hardware&lt;/span&gt;) y aquéllas generadas por los programas (interrupciones &lt;span style="font-style: italic;"&gt;software&lt;/span&gt;). Comenzaremos hablando de las primeras.&lt;br /&gt;&lt;br /&gt;Para poder manejar las interrupciones, tendremos que acceder a una serie de registros. Son los siguientes:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;REG_IME&lt;/span&gt; (0x0400:0208) es el registro maestro de interrupciones. Si queremos habilitar las interrupciones, deberemos poner este registro a 1.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;REG_IE&lt;/span&gt; (0x400:0200) nos permite habilitar o deshabilitar cada uno de los 14 tipos de interrupción, a saber:&lt;br /&gt;&lt;br /&gt;REG_IE[0] - INT_VBLANK (Vertical Blank - generada en la zona de retrazado vertical)&lt;br /&gt;REG_IE[1] - INT_HBLANK (Horizontal Blank - generada en la zona de retrazado horizontal)&lt;br /&gt;REG_IE[2] - INT_VCOUNT (Vertical Count - generada al principio de cada &lt;span style="font-style: italic;"&gt;scanline&lt;/span&gt;)&lt;br /&gt;REG_IE[3] - INT_TM0 (Timer 0 - temporizador 0)&lt;br /&gt;REG_IE[4] - INT_TM1 (Timer 1 - temporizador 1)&lt;br /&gt;REG_IE[5] - INT_TM2 (Timer 2 - temporizador 2)&lt;br /&gt;REG_IE[6] - INT_TM3 (Timer 3 - temporizador 3)&lt;br /&gt;REG_IE[7] - INT_COM (Communications - generada al finalizar una transmisión por el puerto de comunicaciones)&lt;br /&gt;REG_IE[8] - INT_DMA0 (DMA - Acceso directo a memoria, canal 0)&lt;br /&gt;REG_IE[9] - INT_DMA1 (DMA - Acceso directo a memoria, canal 1)&lt;br /&gt;REG_IE[10] - INT_DMA2 (DMA - Acceso directo a memoria, canal 2)&lt;br /&gt;REG_IE[11] - INT_DMA3 (DMA - Acceso directo a memoria, canal 3)&lt;br /&gt;REG_IE[12] - INT_KEYS ( generada cuando alguno de los botones indicados en el registro REG_P1CNT se ha pulsado)&lt;br /&gt;REG_IE[13] - INT_CART (generada cuando se extrae el cartucho de la consola)&lt;br /&gt;&lt;br /&gt;Para habilitar un tipo de interrupción deberemos poner a 1 el bit correspondiente. Adicionalmente, algunos tipos necesitan de registros adicionales, como en el caso de INT_KEYS, o INT_VBLANK, INT_HBLANK e INT_VCOUNT, que hacen uso del registro REG_DISPSTAT.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;REG_IF&lt;/span&gt; (0x400:0202) tiene la misma disposición que REG_IE y su misión es indicarnos qué interrupción se ha generado, poniendo a uno el bit correspondiente. Una vez que hemos tratado la interrupción, debemos escribir un 1 en este mismo registro en el bit que corresponda.&lt;br /&gt;&lt;br /&gt;¿Cómo funciona el mecanismo de interrupciones? Una vez habilitadas, se da el siguiente proceso:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Ocurre una interrupción. El procesador pasa a modo ARM (importante) y se guarda información del estado actual en la pila.&lt;/li&gt;   &lt;li&gt;La BIOS lee la dirección de memoria contenida en 0x0300:7FFC y el procesador salta a esa dirección.&lt;/li&gt;   &lt;li&gt;El código al que apuntaba el valor contenido en 0x0300:7FFC comienza a ejecutarse. Como hemos indicado anteriormente, se trata de código en modo ARM.&lt;/li&gt;   &lt;li&gt;Una vez finalizado el tratamiento, debemos indicar que la interrupción ha sido tratada, escribiendo un 1 en el bit correspondiente del registro REG_IF, y volver de la interrupción con la instrucción: bx lr&lt;/li&gt;   &lt;li&gt;Se recupera el estado que se almacenó en la pila y continúa la ejecución donde se dejó en el momento de "levantarse" la interrupción.&lt;/li&gt; &lt;/ol&gt; En principio, los pasos 1, 2 y 5 son automáticos (gestionados por la BIOS). Sólo tenemos que preocuparnos de poner en la dirección 0x0300:7FFC la dirección en la que se almacenará nuestro código gestor de interrupciones. Por comodidad, podemos definir un registro al efecto:&lt;br /&gt;&lt;pre&gt;typedef void (*fp)(void);  //un puntero a una función de tipo void que no recibe parámetros&lt;br /&gt;#define REG_IRQ_HANDLER        (*(fp*)0x3007FFC)&lt;br /&gt;&lt;/pre&gt;Y una primera aproximación sería:&lt;br /&gt;&lt;pre&gt;void gestor_interrupciones()&lt;br /&gt;{&lt;br /&gt;   ... tratamos la interrupción ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;REG_IRQ_HANDLER = gestor_interrupciones;&lt;br /&gt;&lt;br /&gt;REG_IE = INT_CART;&lt;br /&gt;REG_IME = 1;&lt;br /&gt;&lt;/pre&gt;De esta forma, cada vez que se genere una interrupción de las indicadas (en el ejemplo, la extracción del cartucho), se ejecutará la función 'gestor_interrupciones'.&lt;br /&gt;&lt;br /&gt;Como vemos, en la Gameboy Advance no existe una tabla de vectores de interrupción. Por tanto, el módulo gestor de interrupciones debería discriminar qué interrupción se ha producido y llamar a la rutina de tratamiento correspondiente. También aprovecharemos para que, una vez ejecutada la rutina de control, escribiremos un 1 en el bit de REG_IF correspondiente, para dar por tratada la interrupción.&lt;br /&gt;&lt;br /&gt;El módulo gestor de interrupciones debe ser extremadamente rápido, como todo código que se ejecute al levantarse una interrupción. Por tanto, lo escribiremos en ensamblador del ARM. Todo ello, y un ejemplo práctico de uso de los temporizadores, en la siguiente entrega.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;&lt;code&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111723670942308288?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111723670942308288/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111723670942308288' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111723670942308288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111723670942308288'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/interrupciones-primera-aproximacin.html' title='Interrupciones. Primera aproximación.'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111714843592208045</id><published>2005-05-27T01:00:00.000+02:00</published><updated>2005-05-27T01:30:10.663+02:00</updated><title type='text'>Inciso: Instalación del entorno de desarrollo</title><content type='html'>Manuel, un amable lector, me ha comentado por correo electrónico que no era capaz de instalar el compilador en su Linux. Quizás di algunas cosas por sentadas al comentar las herramientas que íbamos a utilizar, así que voy a detallar todo el proceso de descarga, instalación y compilación del gbasnake.&lt;br /&gt;&lt;br /&gt;No voy a realizar una exposición muy detallada de momento del uso de herramientas auxiliares como Make, que ayudan en la compilación de proyectos complejos, ya que cada cual se monta el entorno de desarrollo un poco a su medida y según sus preferencias. Quizás más adelante aborde ese tema. Tras este inciso me gustaría seguir profundizando en el conocimiento del hardware de la consola y cómo manejarlo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Entorno Windows&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Entramos en la página devkit.tk y clicamos en la sección "Downloads". Aquí encontraremos un enlace al DevkitPro en Sourceforge. Descargamos el devkitARM en su versión para Windows. Una vez lo tengamos en nuestra máquina, procederemos a instalarlo. Para ello, basta con hacer doble clic en el ejecutable que acabamos de descargar. Nos solicitará un directorio donde descomprimirse (por ejemplo, c:\devkitarm\) y copiará todos los ficheros necesarios bajo ese directorio.&lt;br /&gt;&lt;br /&gt;En la página devkit.tk, nos recomiendan un árbol de instalación, que sería algo parecido a:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;span style="font-weight: bold;"&gt;c:\devkitPro&lt;/span&gt;   &lt;/li&gt;   &lt;ul&gt;     &lt;li&gt;&lt;span style="font-weight: bold;"&gt;devkitARM&lt;/span&gt;  &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;devkitPPC  &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;msys  &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libgba  &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libmirko  &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libnds   &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;&lt;span style="font-weight: bold;"&gt;proyectos&lt;/span&gt;   &lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;ul&gt;       &lt;li&gt;&lt;span style="font-weight: bold;"&gt;gba&lt;/span&gt;&lt;/li&gt;     &lt;/ul&gt;   &lt;/ul&gt; &lt;/ul&gt; He marcado en negrita lo que necesitamos mínimamente pare empezar. &lt;a href="http://www.mingw.org/"&gt;Msys&lt;/a&gt; es recomendable, pero no imprescindible. Msys es un sistema mínimo GNU para Windows, lo más parecido a trabajar con la &lt;span style="font-style: italic;"&gt;shell&lt;/span&gt; de UNIX pero en el sistema de Microsoft.&lt;br /&gt;&lt;br /&gt;Tan solo queda poner el directorio c:\devkitPro\devkitARM\bin\ en el PATH (para que el sistema pueda encontrar el compilador y ejecutarlo). Para compilar programas y generar los ficheros de ROMs (.gba) uso el siguiente script, que es el que usan en Drunken Coders en todos sus ejemplos. Pongo tanto la versión para consola de Windows como la "traducción" que he hecho a lenguaje de &lt;span style="font-style: italic;"&gt;script&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;CONSOLA WINDOWS&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;@echo off&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM just add  .c file and  .o file to the next two lines &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set CFILES= gbasnake.c &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set OFILES= gbasnake.o &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set GAME= gbasnake&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set SPECS=gba_mb.specs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set DEVDIR=C:\devkitPro\devkitARM&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set DEVKITPRO=C:\devkitPro&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set DEVKITARM=C:\devkitPro\devkitARM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;PATH=%DEVDIR%\bin;%path%&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM set our paths so the linker knows were to look for the libs&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set LIBDIR= %DEVDIR%\arm-elf\lib\interwork&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set LIBDIR2= %DEVDIR%\libgba\lib&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM set our include directories so the compiler can find our include files&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set INCDIR= %DEVDIR%\arm-elf\include&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set INCDIR2= ..\..\..\include&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM the compiler and linker flags&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set CFLAGS= -I. -I%INCDIR% -I%INCDIR2% -c -g -O2 -Wall -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set LDFLAGS=  -mthumb -mthumb-interwork -specs=%SPECS% -L%LIBDIR% -L%LIBDIR2%  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM Compile the cfiles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;arm-elf-gcc  %CFILES% %CFLAGS%&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM link the o files&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;arm-elf-gcc -o %GAME%.elf  %OFILES% %LDFLAGS% &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM gcc produces .elf exicutables...objcopy to .gba&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;arm-elf-objcopy -v -O binary %game%.elf %game%.gba&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;gbafix %game%.gba&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;REM remove all the ofiles&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;del %OFILES%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;del %game%.elf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;pause&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;SHELL SCRIPT&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;GCC="arm-elf-gcc"&lt;br /&gt;&lt;br /&gt;DEVDIR="/c/devkitPro/devkitARM"&lt;br /&gt;DEVIKITPRO=/c/devkitPro/&lt;br /&gt;DEVKITARM=$DEVDIR&lt;br /&gt;&lt;br /&gt;PATH=$PATH:$DEVDIR/bin&lt;br /&gt;&lt;br /&gt;CFILES=gbasnake&lt;br /&gt;OFILES=gbasnake&lt;br /&gt;&lt;br /&gt;GAME=gbasnake&lt;br /&gt;SPECS="$DEVDIR/arm-elf/lib/gba_mb.specs"&lt;br /&gt;&lt;br /&gt;LIBDIR=$DEVDIR/arm-elf/lib/interwork&lt;br /&gt;LIBDIR2=$DEVDIR/lib&lt;br /&gt;&lt;br /&gt;INCDIR=$DEVDIR/arm-elf/include&lt;br /&gt;INCDIR2=$DEVDIR/include&lt;br /&gt;&lt;br /&gt;CFLAGS="-I. -I$INCDIR -I$INCDIR2 -c -g -O2 -Wall -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork "&lt;br /&gt;&lt;br /&gt;LDFLAGS="-mthumb -mthumb-interwork -specs=$SPECS -L$LIBDIR -L$LIBDIR2"&lt;br /&gt;&lt;br /&gt;# Compilar el fuente&lt;br /&gt;$GCC  $CFILES $CFLAGS&lt;br /&gt;&lt;br /&gt;# Enlazar el objeto&lt;br /&gt;$GCC -o $GAME.elf $OFILES $LDFLAGS&lt;br /&gt;&lt;br /&gt;# Generar el .gba&lt;br /&gt;arm-elf-objcopy -v -O binary $GAME.elf $GAME.gba&lt;br /&gt;&lt;br /&gt;gbafix $GAME.gba&lt;br /&gt;&lt;br /&gt;# Limpiar los archivos intermedios&lt;br /&gt;rm $OFILES&lt;br /&gt;rm $GAME.elf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Obviamente, el resultado de ambas soluciones es el mismo, ya que el compilador es el mismo, sólo cambiaría el entorno de desarrollo en el que estamos trabajando.&lt;br /&gt;&lt;br /&gt;Ahora ya podemos descargar los fuentes completos de &lt;a href="http://falvarez.dyndns.org/gba/src/gbasnake.zip"&gt;GBASnake &lt;/a&gt;(incluyendo algunos archivos de cabecera extra) y probar que nuestra instalación del compilador funciona.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Entorno Linux&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El procedimiento es exacto al descrito anteriormente (salvo la parte de consola de Windows, que no es aplicable en este caso).&lt;br /&gt;&lt;br /&gt;Entramos en la página devkit.tk y clicamos en la sección "Downloads". Aquí encontraremos un enlace al DevkitPro en Sourceforge. Descargamos el devkitARM en su versión para Linux. Una vez lo tengamos en nuestra máquina, procederemos a instalarlo. Para ello, basta descomprimir el fichero que nos hemos bajado. En mi caso ha sido algo como:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;p2:/c/devkitPro# wget http://kent.dl.sourceforge.net/sourceforge/devkitpro/devkitARM_r12-linux.tar.bz2&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span style="font-family: courier new;"&gt;p2:/c/devkitPro# tar xjvf devkitARM_r12-linux.tar.bz2&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;He respetado la misma estructura de directorios que se usa en Windows con Msys&lt;br /&gt;&lt;br /&gt;Nos solicitará un directorio donde descomprimirse (por ejemplo, c:\devkitarm\) y copiará todos los ficheros necesarios bajo ese directorio.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;span style="font-weight: bold;"&gt;/c/devkitPro&lt;/span&gt;&lt;/li&gt;   &lt;ul&gt;     &lt;li&gt;&lt;span style="font-weight: bold;"&gt;    devkitARM&lt;/span&gt;&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;devkitPPC&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;msys&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libgba&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libmirko&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;libnds&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;li&gt;&lt;span style="font-weight: bold;"&gt;    proyectos&lt;/span&gt;&lt;/li&gt;   &lt;/ul&gt;   &lt;ul&gt;     &lt;ul&gt;       &lt;li&gt;&lt;span style="font-weight: bold;"&gt;        gba&lt;/span&gt;&lt;/li&gt;     &lt;/ul&gt;   &lt;/ul&gt; &lt;/ul&gt; Lo he hecho por comodidad, para no tener que escribir el script de compilación dos veces. En cualquier caso, las rutas de instalación son totalmente modificables. Probamos el script y vemos que todo funciona correctamente.&lt;br /&gt;&lt;br /&gt;No olvidéis añadir la ruta de los binarios del compilador al PATH, en nuestro caso:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;export PATH=PATH:/c/devkitPro/devkitARM/bin&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTA IMPORTANTE: &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La versión actual del compilador para Linux tiene un BUG (que explican en este &lt;a href="http://forum.gbadev.org/viewtopic.php?t=5790"&gt;enlace&lt;/a&gt; y que me ha hecho volverme loco durante un par de noches). Básicamente, hay que parchear el fichero arm-elf/lib/gba_crt0.s añadiendo la línea que falta en la función SkipEWRAMClear (la marco en negrita)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;@--------------------------------------------------------------------------------- &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  SkipEWRAMClear:                                 @ Clear Internal WRAM to 0x00 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;@--------------------------------------------------------------------------------- &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;           mov     r0, #3 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;          lsl     r0, #24                         @ r0 = 0x3000000 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;           ldr     r1, =__iwram_end &lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;           sub    r1, r0 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;           bl      ClearMem &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;y recompilando esa parte con:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;make CRT=gba&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;¡¡¡Felices compilaciones!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111714843592208045?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111714843592208045/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111714843592208045' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111714843592208045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111714843592208045'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/inciso-instalacin-del-entorno-de_27.html' title='Inciso: Instalación del entorno de desarrollo'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111645547707598273</id><published>2005-05-18T23:45:00.000+02:00</published><updated>2005-05-19T00:31:17.080+02:00</updated><title type='text'>Leyendo los botones</title><content type='html'>Cuando hicimos el &lt;span style="font-style: italic;"&gt;port&lt;/span&gt; del juego Snake, ya tuvimos que implementar la lectura de los botones para poder manejar la serpiente y reiniciar la partida. Ahora vamos a entrar un poco más en profundidad en este tema.&lt;br /&gt;&lt;br /&gt;La Gameboy Advance posee 10 botones, como ya se ha comentado. El manejo de estas entradas se hace mediante dos registros de Entrada/Salida, que son los siguientes:&lt;br /&gt;&lt;br /&gt;REG_KEYS (0x0400:0130)&lt;br /&gt;&lt;br /&gt;Cada bit del 0 al 9 hace referencia a cada uno de los botones:&lt;br /&gt;&lt;br /&gt;REG_KEYS[0] -&gt; A&lt;br /&gt;REG_KEYS[1] -&gt; B&lt;br /&gt;REG_KEYS[2] -&gt; Select&lt;br /&gt;REG_KEYS[3] -&gt; Start&lt;br /&gt;REG_KEYS[4] -&gt; Derecha&lt;br /&gt;REG_KEYS[5] -&gt; Izquierda&lt;br /&gt;REG_KEYS[6] -&gt; Arriba&lt;br /&gt;REG_KEYS[7] -&gt; Abajo&lt;br /&gt;REG_KEYS[8] -&gt; R&lt;br /&gt;REG_KEYS[9] -&gt; L&lt;br /&gt;&lt;br /&gt;El valor de cada bit es 1 si el botón no está pulsado y 0 si lo está, de forma que REG_KEYS = 0x03FF en estado de "reposo".&lt;br /&gt;&lt;br /&gt;REG_KEYCNT (0x0400:0132)&lt;br /&gt;&lt;br /&gt;Este registro se usa para controlar las "interrupciones del teclado". Tiene la misma configuración que REG_KEYS pero añadiendo dos bits:&lt;br /&gt;&lt;br /&gt;REG_KEYCNT[0] -&gt; A&lt;br /&gt;REG_KEYCNT[1] -&gt; B&lt;br /&gt;REG_KEYCNT[2] -&gt; Select&lt;br /&gt;REG_KEYCNT[3] -&gt; Start&lt;br /&gt;REG_KEYCNT[4] -&gt; Derecha&lt;br /&gt;REG_KEYCNT[5] -&gt; Izquierda&lt;br /&gt;REG_KEYCNT[6] -&gt; Arriba&lt;br /&gt;REG_KEYCNT[7] -&gt; Abajo&lt;br /&gt;REG_KEYCNT[8] -&gt; R&lt;br /&gt;REG_KEYCNT[9] -&gt; L&lt;br /&gt;REG_KEYCNT[E] -&gt; I&lt;br /&gt;REG_KEYCNT[F] -&gt; Op&lt;br /&gt;&lt;br /&gt;I activa o desactiva las interrupciones del teclado. Op determina la forma de calcular si lanzar la interrupción o no. Si vale 0, se aplicará una operación OR a los botones indicados, mientras que si vale 1, aplicará una operación AND.&lt;br /&gt;&lt;br /&gt;Ejemplo: si cargamos en este registro el valor binario 1100000000001111 (0xC00F), conseguiremos que se genere una interrupción cuando los botones A, B, Select y Start se presionen simultáneamente.&lt;br /&gt;&lt;br /&gt;Bien, ya tenemos todo para leer las pulsaciones de los botones, pero nos falta algo muy importante. Hasta ahora sabemos cuándo un botón está pulsado o no. Realmente esta no es la información que necesitamos, sino que lo lógico es saber si un botón ha cambiado de estado. ¿Por qué? Imaginemos el botón Start con su función típica de activar la pausa del juego. Leemos el estado de los botones y detectamos que Start fue pulsado. Entramos en el estado "pausa", del que saldremos cuando detectemos nuevamente que Start está pulsado. El problema es que el microprocesador de la Gameboy Advance ejecuta código mucho más rápido de lo que imaginamos. Por tanto, una pequeña pulsación de Start por nuestra parte puede implicar muchas pausas/continuaciones. De hecho, podemos considerar que el estado en el que quedará el juego tras soltar el botón es totalmente aleatorio.&lt;br /&gt;&lt;br /&gt;Resumiendo, lo que nos interesan son los cambios de estado de los botones. Y podemos conseguir esa información mediante estas funciones:&lt;br /&gt;&lt;pre class="proglist"&gt;&lt;span class="keyw"&gt;void&lt;/span&gt; LeerBotones()&lt;br /&gt;{   bot_ant= bot_act; bot_act= REG_KEYS; }&lt;br /&gt;&lt;br /&gt;u16 BotonCambio(u16 boton)&lt;br /&gt;{   &lt;span class="keyw"&gt;return&lt;/span&gt;  (bot_act^bot_ant) &amp; boton; }&lt;br /&gt;&lt;br /&gt;u16 BotonMantiene(u16 boton)&lt;br /&gt;{   &lt;span class="keyw"&gt;return&lt;/span&gt; ~(bot_act|bot_ant) &amp; boton; }&lt;br /&gt;&lt;br /&gt;u16 BotonPulsado(u16 boton)&lt;br /&gt;{   &lt;span class="keyw"&gt;return&lt;/span&gt; (~bot_act&amp;bot_ant) &amp;amp; boton; }&lt;br /&gt;&lt;br /&gt;u16 BotonSoltado(u16 key)&lt;br /&gt;{   &lt;span class="keyw"&gt;return&lt;/span&gt; (bot_act&amp;~bot_ant) &amp;amp; boton; }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Lo que haremos será llamar a LeerBotones() cada ciclo de nuestro programa, y de esa forma podremos saber si un botón en concreto ha cambiado de estado.&lt;br /&gt;&lt;br /&gt;Por ejemplo, BotonPulsado(KEY_START) devolverá 1 si se pulsó el botón Start, y 0 en caso contrario. Este valor lo devolverá una única vez. Hasta que no soltemos y volvamos a pulsar el botón, la función no volverá a devolver 1.&lt;br /&gt;&lt;br /&gt;Con estos conocimientos podemos hacer prácticamente todo en cuanto a lectura de botones. Hemos aprovechado para añadir a nuestra serpiente el clásico botón de pausa (Start).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://falvarez.dyndns.org/gba/src/gbasnake_2.c"&gt;Código fuente&lt;/a&gt;.&lt;br /&gt;&lt;a href="http://falvarez.dyndns.org/gba/bin/gbasnake_2.gba"&gt;ROM&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111645547707598273?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111645547707598273/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111645547707598273' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111645547707598273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111645547707598273'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/leyendo-los-botones.html' title='Leyendo los botones'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111644999573926291</id><published>2005-05-18T22:14:00.000+02:00</published><updated>2005-05-18T22:59:55.746+02:00</updated><title type='text'>Un acercamiento superficial al hardware</title><content type='html'>Como todos sabréis, Gameboy Advance es un sistema portátil de videojuegos creado por Nintendo. Las características más importantes de su &lt;span style="font-style: italic;"&gt;hardware&lt;/span&gt; son:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Procesador ARM de 32 bits, corriendo a 16,78 MHz.&lt;/li&gt;   &lt;li&gt;Pantalla LCD de 240x160 pixels, capaz de visualizar 32768 colores (15 bits).&lt;/li&gt;   &lt;li&gt;Memoria dividida en diferentes zonas. La Entrada/Salida está mapeada en memoria.&lt;/li&gt;   &lt;li&gt;10 botones (cruceta de 4 direcciones, A, B, L, R, Select y Start).&lt;/li&gt;   &lt;li&gt;Sonido estéreo, con 6 canales disponibles, 4 de ellos ya presentes en la Gameboy original y dos conversores Digital-Analógico.&lt;/li&gt; &lt;/ul&gt; La CPU puede ejecutar dos juegos de instrucciones: el ARM, que es un juego de instrucciones de 32 bits, y el THUMB, que usa instrucciones de 16 bits. THUMB es un subconjunto de instrucciones del juego ARM. El procesador cuenta además con 16 registros de 32 bits, si bien los tres últimos no son de propósito general (r13 = SP, r14 = LR y r15 = PC). Además, en modo THUMB sólo están disponibles los 8 primeros.&lt;br /&gt;&lt;br /&gt;Cuando trabajemos en zonas de memoria con tamaño de palabra de 32 bits, usaremos código ARM, mientras que preferiremos usar THUMB para las zonas con palabra de 16 bits.&lt;br /&gt;&lt;br /&gt;La memoria está dividida en diferentes áreas:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ROM del sistema&lt;/span&gt; (0x0000:0000 - 0x0000:3FFF [16KB] palabras de 32 bits).&lt;br /&gt;Es la BIOS del sistema. No se puede leer su contenido, sólo ejecutarse.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;EWRAM&lt;/span&gt; (0x0200:0000 - 0x0203:FFFF [256KB] palabras de 16 bits).&lt;br /&gt;RAM externa de trabajo (External Work RAM). Disponible para código y datos. En caso de usar un cable &lt;span style="font-style: italic;"&gt;multiboot&lt;/span&gt;, aquí se almacenaría el código descargado y empezaría la ejecución.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;IWRAM&lt;/span&gt; (0x0300:0000 - 0x0300:7FFF [32KB] palabras de 32 bits).&lt;br /&gt;RAM interna de trabajo (Internal Work RAM). También disponible para código y datos. Es la memoria más rápida, de hecho se encuentra embebida dentro del procesador.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;IORAM &lt;/span&gt;(0x0400:0000 - 0x0401:03FF [1KB] palabras de 16 bits).&lt;br /&gt;Zona de Entrada/Salida mapeada en memoria. En esta zona se encuentran mapeados los registros de Entrada/Salida, que nos servirán para prácticamente controlar todo el hardware.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;PALRAM &lt;/span&gt;(0x0500:0000 - 0x0500:03FF [1KB] palabras de 16 bits).&lt;br /&gt;Zona de almacenamiento de paletas de vídeo. Cada una contiene 256 entradas de 15 bits. La primera de ellas para fondos, la segunda para &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VRAM &lt;/span&gt;(0x0600:0000 - 0x0601:7FFF [96KB] palabras de 16 bits).&lt;br /&gt;Memoria de vídeo. La estructura de los datos almacenados dependerá del modo de vídeo en que estemos trabajando.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;OAM &lt;/span&gt;(0x0700:0000 - 0x0700:03FF [1KB] palabras de 32 bits).&lt;br /&gt;Memoria de atributos de objetos (Object Attribute Memory). En esta zona se controlan los &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;PAKROM &lt;/span&gt;(0x0800:0000 - variable [variable] palabras de 16 bits).&lt;br /&gt;En esta zona se mapea la ROM de los cartuchos de software. Normalmente será la zona donde comience la ejecución, salvo que hayamos arrancado mediante un cable &lt;span style="font-style: italic;"&gt;multiboot&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CartRAM &lt;/span&gt;(0x0E00:0000 - variable [variable] palabras de 8 bits).&lt;br /&gt;Esta es la RAM usada en los cartuchos para guardar partidas, datos de configuración, etc. Su longitud es variable. Puede ser de tipo SRAM, FlashROM o EEPROM. En cualquier caso, su comportamiento será el mismo.&lt;br /&gt;&lt;br /&gt;La pantalla de la GBA, como hemos comentado antes, consta de 240x160 pixeles. Se refresca cada 280,896 ciclos de CPU, o sea, alrededor de los 59,73 Hz. Soporta 6 modos de funcionamiento, algunos basados en &lt;span style="font-style: italic;"&gt;pixeles&lt;/span&gt; y otros en bloques (&lt;span style="font-style: italic;"&gt;tiles&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;La consola da soporte a 128 &lt;span style="font-style: italic;"&gt;sprites&lt;/span&gt; simultáneos, de hasta 64x64 &lt;span style="font-style: italic;"&gt;pixeles&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Como vemos, el &lt;span style="font-style: italic;"&gt;hardware&lt;/span&gt; de la Gameboy Advance es lo suficientemente complejo como para no intentar abarcarlo todo en una primera aproximación. Iremos profundizando juntos en su conocimiento a medida que vayamos programando y vayamos necesitando afinar más para conseguir aquellos efectos que nos propongamos.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;Enlaces:&lt;a href="http://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm"&gt;&lt;br /&gt;&lt;/a&gt; &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm"&gt;Cowbite Virtual Hardware Specifications&lt;/a&gt;.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://user.chem.tue.nl/jakvijn/tonc/hardware.htm"&gt;TONC: GBA Hardware&lt;/a&gt;.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://www.gbadev.org/"&gt;GBADev&lt;/a&gt;.&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111644999573926291?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111644999573926291/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111644999573926291' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111644999573926291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111644999573926291'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/un-acercamiento-superficial-al.html' title='Un acercamiento superficial al hardware'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111615804481798294</id><published>2005-05-15T13:17:00.000+02:00</published><updated>2005-05-15T14:02:03.946+02:00</updated><title type='text'>Primer proyecto rápido</title><content type='html'>Cuando uno empieza a programar, está ávido de ver resultados. En este caso, la sensación es la misma, así que tras un vistazo rápido a la documentación para aprender a generar gráficos en la pantalla de la consola y a detectar la pulsación de sus botones nos lanzamos a la tarea.&lt;br /&gt;&lt;br /&gt;Lo que se me ha ocurrido ha sido hacer una conversión directa del juego de la serpiente (snake) que realicé para la competición de juegos en BASIC para Spectrum organizada por Bytemaniacos. Es una versión muy sencilla, sin incrementos de velocidad, ni gráficos. Tan solo una serpiente recogiendo frutas por la pantalla. Así que procedemos a descargar el &lt;a href="http://www.redeya.com/bytemaniacos/concurso2003/zxsnake.zip"&gt;código fuente en BASIC&lt;/a&gt; para proceder a la conversión.&lt;br /&gt;&lt;br /&gt;Si miráis el código es muy sencillo. Se trata de un bucle en el que se mueve la serpiente, se comprueba si ha chocado con algo o si ha comido una fruta y se lee el teclado para ver si hay que cambiar de dirección. Este esquema ha sido adaptado de forma &lt;span style="font-style: italic;"&gt;cutre salchichera&lt;/span&gt; a lenguaje C en 10 minutos, para poder ver resultados rápidamente.&lt;br /&gt;&lt;br /&gt;La consola tiene registros mapeados en memoria. Pero para acceder a la mayoría de ellos se han definido constantes y macros en los archivos de cabecera, de forma que no tengamos que recordar las direcciones de memoria.&lt;br /&gt;&lt;br /&gt;Los principales problemas que he encontrado han sido:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Cómo dibujar objetos en pantalla?&lt;/span&gt;&lt;ul&gt; &lt;/ul&gt;La consola tiene varios modos de vídeo. Más adelante estudiaremos todos. De momento basta con saber que el Modo 3 nos permite un acceso lineal a la memoria de vídeo, donde el color de cada &lt;span style="font-style: italic;"&gt;pixel&lt;/span&gt; vendrá determinado por un valor de 16 bits. Para acceder a este modo de vídeo, lo haremos de la siguiente manera:&lt;br /&gt;&lt;pre&gt;SetMode(MODE_3 | BG2_ENABLE);&lt;/pre&gt;Tanto la función como las constantes están definidas en los archivos de cabecera.&lt;br /&gt;&lt;br /&gt;Para colorear un punto de la pantalla accederemos a la siguiente variable (definida en los archivos de cabecera):&lt;br /&gt;&lt;pre&gt;VideoBuffer[x + y * SCREEN_WIDTH] = color;&lt;/pre&gt;donde SCREEN_WIDTH está definida en los archivos de cabecera (la pantalla en Modo 3 es de 240x160) y color, como hemos comentado anteriormente, es un valor entero de 16 bits, que podemos generar de la siguiente forma:&lt;br /&gt;&lt;pre&gt;color = RGB16(componente_roja, componente_verde, componente_azul);&lt;/pre&gt;donde los valores de cada componente son enteros de 5 bits (o sea, entre 0 y 31).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Cómo leer la pulsación de los botones de la consola?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Podemos consultar el valor del registro REG_KEYS de la siguiente forma:&lt;br /&gt;&lt;pre&gt;!(REG_KEYS &amp; botón)&lt;/pre&gt;de forma que obtendremos 1 (true) si el botón indicado ha sido pulsado. Las constantes para los botones son las siguientes:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;KEY_LEFT (pad izquierda)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_RIGHT (pad derecha)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_UP (pad arriba)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_DOWN (pad abajo)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_A (botón A)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_B (botón B)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_L (gatillo L)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_R (gatillo R)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_SELECT (botón Select)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;KEY_START (botón Start)&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt; ¿Cómo "imprimir caracteres" en la pantalla?&lt;br /&gt;&lt;br /&gt;Aquí no vale usar &lt;span style="font-style: italic;"&gt;printf&lt;/span&gt; e imprimir una cadena en pantalla. Así que necesitaremos definirnos un juego de caracteres y construirnos las rutinas de escritura en pantalla. De momento sólo necesitamos números para el marcador, así que lo hemos hecho "a las bravas", definiendo un array de 8x8 para cada carácter numérico, poniendo un 1 en los &lt;span style="font-style: italic;"&gt;pixels&lt;/span&gt; que deben ir iluminados. Por ejemplo, para el número cero (0):&lt;br /&gt;&lt;pre&gt;    {&lt;br /&gt;     {0,0,0,0,0,0,0,0},&lt;br /&gt;     {0,0,1,1,1,0,0,0},&lt;br /&gt;     {0,1,0,0,0,1,0,0},&lt;br /&gt;     {1,0,0,0,0,0,1,0},&lt;br /&gt;     {1,0,1,1,1,0,1,0},&lt;br /&gt;     {1,0,0,0,0,0,1,0},&lt;br /&gt;     {0,1,0,0,0,1,0,0},&lt;br /&gt;     {0,0,1,1,1,0,0,0}&lt;br /&gt; },&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Por tanto, definimos una variable global llamada caracteres en la que almacenamos nuestro rudimentario juego de caracteres numéricos, del 0 al 9. La rutina de impresión es tan sencilla como:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void PintaCaracter(caracter,x,y,color,color_fondo)&lt;br /&gt;{&lt;br /&gt; unsigned char tx, ty;&lt;br /&gt; for(tx = 0; tx &lt; 8; tx ++)&lt;br /&gt; {&lt;br /&gt;  for(ty = 0; ty &lt; 8; ty ++)&lt;br /&gt;  {&lt;br /&gt;   if(caracteres[caracter][ty][tx] == 1)&lt;br /&gt;   {&lt;br /&gt;    VideoBuffer[(x+tx) + (y+ty) * SCREEN_WIDTH] = color;  &lt;br /&gt;   } &lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;    VideoBuffer[(x+tx) + (y+ty) * SCREEN_WIDTH] = color_fondo;  &lt;br /&gt;   }    &lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;} &lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;El juego va muy rápido, ¿cómo lo ralentizamos?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La solución buena y elegante es efectuar la sincronización del movimiento mediante interrupciones. En este primer ejemplo no lo vamos a hacer así, así que emplearemos métodos de espera activa, tanto para ralentizar cada iteración (mediante un bucle for vacío), como para esperar a la pulsación de una tecla (mediante un while del que no se sale hasta que se pulsa dicha tecla). Tampoco esperamos al redibujado de la pantalla para escribir en la memoria de vídeo y así evitar molestos parpadeos. Todas estas técnicas las iremos viendo más adelante, conforme vayamos profundizando en nuestro conocimiento del hardware de la Gameboy Advance.&lt;br /&gt;&lt;br /&gt;Y con estas salvedades y un &lt;a href="http://falvarez.dyndns.org/gba/src/gbasnake.c"&gt;código muy chapucero&lt;/a&gt;, tenemos en pantalla la primera versión de nuestro juego de la serpiente. Cuando choquemos, hay que pulsar Start para volver a empezar la partida. Aquí tenéis la &lt;a href="http://falvarez.dyndns.org/gba/bin/gbasnake.gba"&gt;ROM&lt;/a&gt; con el juego listo para ser ejecutado.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img style="border: 1px solid rgb(170, 170, 170); padding: 2px;" src="http://photos11.flickr.com/13899332_221a8f1ff3_m.jpg" /&gt;&lt;br /&gt;&lt;span style="font-size:80%;"&gt;Ver mi primer código corriendo en la GBA no tiene precio&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111615804481798294?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111615804481798294/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111615804481798294' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111615804481798294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111615804481798294'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/primer-proyecto-rpido.html' title='Primer proyecto rápido'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111615525747403601</id><published>2005-05-15T13:01:00.000+02:00</published><updated>2005-05-15T13:57:20.256+02:00</updated><title type='text'>Preparando las herramientas</title><content type='html'>Para comenzar a trabajar con la consola necesitamos urgentemente un compilador y algo de documentación. Aclarar que yo voy a trabajar bajo Windows, pero no creo que haya ningún inconveniente en usar las herramientas para Linux.&lt;br /&gt;&lt;br /&gt;El compilador se puede descargar &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=114505&amp;package_id=124207&amp;amp;release_id=304886"&gt;de este enlace&lt;/a&gt;, así como algo de información en la página &lt;a href="http://www.devkit.tk/"&gt;devkit.tk&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;También se puede descargar un kit de desarrollo como &lt;a href="http://devkitadv.sourceforge.net/"&gt;DevKit Advance&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Por supuesto, probar el código generado en la consola se hace muy pesado, así que no está de más instalarnos un emulador de Gameboy Advance, como &lt;a href="http://vba.ngemu.com/"&gt;Visualboy Advance&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Para conseguir documentación, de momento he echado mano de estos enlaces:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;&lt;a href="http://www.gbadev.org/"&gt;Gameboy Advance Development&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.thepernproject.com/index.php?system_id=2&amp;amp;page=Tutorials"&gt;Drunken Coders Tutorials&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.loirak.com/gameboy/gbatutor.php"&gt;GBA Programming for beginners&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt; Una vez instalado el compilador, ya podemos empezar a juguetear. Lo primero que he hecho ha sido descargar los tutoriales de Drunken Coders y probar a ver que se compilan perfectamente y se genera el archivo .gba correspondiente.&lt;br /&gt;&lt;br /&gt;Pues bien, ya tenemos nuestro entorno de trabajo listo. Se da por hecho el uso de un editor de texto para generar el código fuente en C o ensamblador (de momento comenzaremos por usar C). Ya podemos comenzar a crear nuestro software para la Gameboy Advance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111615525747403601?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111615525747403601/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111615525747403601' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111615525747403601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111615525747403601'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/preparando-las-herramientas.html' title='Preparando las herramientas'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12890134.post-111608723694385051</id><published>2005-05-14T17:58:00.000+02:00</published><updated>2005-05-14T18:13:56.946+02:00</updated><title type='text'>Presentación y propósito</title><content type='html'>Hace casi 20 años, mi abuelo, Andrés Valero, me hizo un regalo que posiblemente cambió el resto de mi vida: un ordenador ZX Spectrum +.&lt;br /&gt;&lt;br /&gt;Desde aquella época, siempre me llamó mucho la atención llegar a ser un programador de juegos, trabajar en los estudios españoles de aquella época (Dinamic, Topo, Opera...). No obstante, quizás porque me pilló demasiado joven, no lo conseguí y, aunque estudié la carrera, trabajo y vivo de la informática, siempre quedó aquella espinita clavada de no haber programado ningún juego para aquel entrañable ordenador.&lt;br /&gt;&lt;br /&gt;Estas navidades recibí un nuevo regalo. Esta vez, mi novia me obsequió con una Gameboy Advance SP. He adquirido un cartucho Flash y este fin de semana, cinco meses después, comienzo a quitarme la espinita. Quizás programar juegos para ZX Spectrum hoy en día sea un poco anacrónico (aunque hay gente que lo sigue haciendo y con excelentes resultados). Pero el principal problema es que no tiene un público "mayoritario". Así que la idea es programar algunas cosillas para la Gameboy Advance. Nuevamente llego un poco tarde, con su hermana mayor (Nintendo DS) ya en el mercado. Pero puedo asegurar una cosa: ver ejecutándose un trocito de código propio en la consola es una experiencia incomparable.&lt;br /&gt;&lt;br /&gt;Como decía, este fin de semana me he puesto manos a la obra. He instalado el compilador y he empezado a trastear. El resultado de todas esas investigaciones, presentes y futuras, serán la fuente de alimentación de este blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12890134-111608723694385051?l=gbadvance.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gbadvance.blogspot.com/feeds/111608723694385051/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12890134&amp;postID=111608723694385051' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111608723694385051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12890134/posts/default/111608723694385051'/><link rel='alternate' type='text/html' href='http://gbadvance.blogspot.com/2005/05/presentacin-y-propsito.html' title='Presentación y propósito'/><author><name>Federico J. Álvarez Valero</name><uri>https://profiles.google.com/101937542419678652849</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-W8HYDBH15qY/AAAAAAAAAAI/AAAAAAAABZI/TECD9ndLSr0/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry></feed>
