UNIVERSIDAD DE CASTILLA-LA MANCHA

Transcripción

UNIVERSIDAD DE CASTILLA-LA MANCHA
UNIVERSIDAD DE CASTILLA-LA MANCHA
ESCUELA SUPERIOR DE INFORMÁTICA
INGENIERÍA
EN INFORMÁTICA
PROYECTO FIN DE CARRERA
Entorno de programación para videoconsola Nintendo
DS con fines docentes
Manuel Rodrigo Gómez
Septiembre, 2009
UNIVERSIDAD DE CASTILLA-LA MANCHA
ESCUELA SUPERIOR DE INFORMÁTICA
Departamento de Informática
PROYECTO FIN DE CARRERA
Entorno de programación para videoconsola Nintendo
DS con fines docentes
Autor: Manuel Rodrigo Gómez
Director: Francisco Moya Fernández
Septiembre, 2009
TRIBUNAL:
Presidente:
Vocal 1:
Vocal 2:
Secretario:
FECHA DE DEFENSA:
CALIFICACIÓN:
PRESIDENTE
Fdo.:
VOCAL 1
Fdo.:
VOCAL 2
Fdo.:
SECRETARIO
Fdo.:
c Manuel Rodrigo Gómez. Se permite la copia, distribución y/o modificación de este docu
mento bajo los términos de la licencia de documentación libre GNU, versión 1.1 o cualquier versión
posterior publicada por la Free Software Foundation, sin secciones invariantes. Puede consultar esta
licencia en http://www.gnu.org.
Este documento fue compuesto con LATEX. Imágenes generadas con OpenOffice.
RESUMEN
ABSTRACT
Portable video game systems are not only a multibillion-dollar computer industry,
but also an attractive platform to enable people with knowledge of computer organization
and architecture to develop innovative software applications. The authors show how socalled ”homebrewçomputing has led to significant innovations in computer science, and,
by explaining the organization and architecture of the Nintendo DS, show how this game
system is, in many ways, an ideal homebrew computing device. In addition, readers with an
interest in homebrew computing are provided a guide to getting started with programming
for the DS platform.
AGRADECIMIENTOS
Índice general
Lista de figuras
V
Lista de tablas
IX
1. INTRODUCCIÓN
1
1.1. Motivación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2. Justificación del trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3. Estructura del documento . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2. OBJETIVOS DEL PROYECTO
5
2.1. Objetivos generales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2. Objetivos especı́ficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
9
3.1. La videoconsola Nintendo DS . . . . . . . . . . . . . . . . . . . . . . . .
10
3.1.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
3.1.2. Familia de la Nintendo DS . . . . . . . . . . . . . . . . . . . . . .
10
3.1.3. El hardware de la Nintendo DS . . . . . . . . . . . . . . . . . . .
11
3.2. Desarrollo de software casero para Nintendo DS . . . . . . . . . . . . . . .
16
3.2.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.2.2. DevkitPro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.2.3. DevkitARM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.2.4. GNU Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.2.5. Entornos cruzados de desarrollo . . . . . . . . . . . . . . . . . . .
20
3.2.6. Emuladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.3. Compilando para Nintendo DS . . . . . . . . . . . . . . . . . . . . . . . .
26
3.3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.3.2. ABI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3.3.3. EABI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
I
ÍNDICE GENERAL
II
3.3.4. AAPCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
3.3.5. Explorando el ABI con GDB y DeSmuME . . . . . . . . . . . . . .
37
3.4. Gráficos con Nintendo DS . . . . . . . . . . . . . . . . . . . . . . . . . .
40
3.4.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
3.4.2. Interacción con los periféricos . . . . . . . . . . . . . . . . . . . .
42
3.4.3. Modo framebuffer . . . . . . . . . . . . . . . . . . . . . . . . . .
44
3.4.4. Modo extended rotoscale . . . . . . . . . . . . . . . . . . . . . . .
54
3.4.5. Modo teselado . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
4. MÉTODO DE TRABAJO
83
4.1. Adaptación del problema al Proceso Unificado . . . . . . . . . . . . . . . .
84
4.2. Construcción del entorno cruzado de desarrollo . . . . . . . . . . . . . . .
84
4.2.1. Comprensión del software . . . . . . . . . . . . . . . . . . . . . .
84
4.2.2. Construcción del diagrama de casos de uso . . . . . . . . . . . . .
88
4.2.3. Fase de análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . .
88
4.2.4. Fase de diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
4.2.5. Fase de implementación . . . . . . . . . . . . . . . . . . . . . . .
93
4.2.6. Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
4.3. Construcción del editor de fondos . . . . . . . . . . . . . . . . . . . . . .
95
4.3.1. Construcción del diagrama de casos de uso . . . . . . . . . . . . .
95
4.3.2. Priorización de casos de uso . . . . . . . . . . . . . . . . . . . . .
97
4.3.3. Iteración 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
4.3.4. Iteración 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.3.5. Iteración 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
4.3.6. Iteración 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
4.3.7. Iteración 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
4.3.8. Iteración 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
4.3.9. Iteración 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
4.3.10. Iteración 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
4.3.11. Iteración 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
5. RESULTADOS
153
5.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
6. CONCLUSIONES Y PROPUESTAS
155
6.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
6.2. Propuestas y lı́neas de investigación futuras . . . . . . . . . . . . . . . . . 156
ÍNDICE GENERAL
III
6.2.1. Entorno cruzado de desarrollo . . . . . . . . . . . . . . . . . . . . 157
6.2.2. Editor de fondos . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
A.1. Entorno cruzado de desarrollo . . . . . . . . . . . .
A.1.1. Instalación en Debian GNU/Linux . . . . . .
A.1.2. Creación de un proyecto para NDS . . . . .
A.1.3. Configuración del proyecto . . . . . . . . . .
A.1.4. Edición del archivo fuente . . . . . . . . . .
A.1.5. Depuración del proyecto . . . . . . . . . . .
A.1.6. Sesión de depuración . . . . . . . . . . . . .
A.2. Editor de fondos . . . . . . . . . . . . . . . . . . . .
A.2.1. Ejecución . . . . . . . . . . . . . . . . . . .
A.2.2. Abrir imagen . . . . . . . . . . . . . . . . .
A.2.3. Reorganizar paleta . . . . . . . . . . . . . .
A.2.4. Convertir fondo . . . . . . . . . . . . . . . .
A.2.5. Personalización del fondo . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
159
159
159
160
160
163
165
166
167
167
168
170
170
171
B. FIGURAS
175
B.1. Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Bibliografı́a
183
ÍNDICE GENERAL
IV
Lista de figuras
3.1. Nintendo DS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.2. Nintendo DS Lite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.3. Nintendo DSi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.4. Esquema del mapa de memoria de la NDS [21] . . . . . . . . . . . . . . .
14
3.5. Asignación de bancos de VRAM [18] . . . . . . . . . . . . . . . . . . . .
15
3.6. Arquitectura de la plataforma Eclipse [14] . . . . . . . . . . . . . . . . . .
22
3.7. Entorno conectado a un dispositivo remoto vı́a JTAG/BDM [12] . . . . . .
24
3.8. ABI para la arquitectura ARM [5] . . . . . . . . . . . . . . . . . . . . . .
28
3.9. Orden de los bytes en big-endian y en little-endian [8] . . . . . . . . . . .
30
3.10. Alineamiento del tipo compuesto MyData [28] . . . . . . . . . . . . . . .
32
3.11. Alineamiento de una estructura equivalente a MyData [28] . . . . . . . . .
33
3.12. La ejecución alcanza el punto de interrupción establecido . . . . . . . . . .
40
3.13. Exploración del ABI con KDbg . . . . . . . . . . . . . . . . . . . . . . .
41
3.14. Conexión de los periféricos de entrada-salida con el computador [26] . . . .
43
3.15. Esquema de la memoria destinada a los fondos de mapas de bits [24] . . . .
55
3.16. Ejemplo de paleta de colores [24] . . . . . . . . . . . . . . . . . . . . . .
58
3.17. Ejemplos de transformaciones afines . . . . . . . . . . . . . . . . . . . . .
61
3.18. Elementos básicos de los fondos teselados [25] . . . . . . . . . . . . . . .
65
3.19. Direcciones base para un mapa de 32×32 y de 64×64 [25] . . . . . . . . .
67
3.20. Desplazamientos en la memoria de fondos [25] . . . . . . . . . . . . . . .
68
3.21. Ejemplo de tesela [25] . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
3.22. Tesela en forma de flecha [25] . . . . . . . . . . . . . . . . . . . . . . . .
72
3.23. Misma tesela con diferente paleta [25] . . . . . . . . . . . . . . . . . . . .
73
3.24. Ejemplo de fondo del juego Yoshi Island [1] . . . . . . . . . . . . . . . . .
75
3.25. Ejemplo de fondo del juego Super Nenas [1] . . . . . . . . . . . . . . . . .
75
3.26. Tesela que representa la letra L [25] . . . . . . . . . . . . . . . . . . . . .
76
3.27. 16 bits que componen la entrada de un mapa [25] . . . . . . . . . . . . . .
78
3.28. Resultado final [25] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
V
LISTA DE FIGURAS
VI
3.29. Generando mapas, teselas y paletas [25] . . . . . . . . . . . . . . . . . . .
81
4.1. Interfaz gráfica de Zylin Embedded CDT . . . . . . . . . . . . . . . . . .
85
4.2. Diagrama de clases de una parte del plug-in Zylin Embedded CDT . . . . .
87
4.3. Vista funcional del entorno cruzado de desarrollo . . . . . . . . . . . . . .
89
4.4. Clases de análisis involucradas en el caso de uso Depurar mediante emulador 90
4.5. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . .
91
4.6. Diagrama de clases modificado del plug-in Zylin Embedded CDT . . . . .
92
4.7. Vista funcional del editor de fondos . . . . . . . . . . . . . . . . . . . . .
96
4.8. Clases de análisis involucradas en el caso de uso Abrir imagen . . . . . . .
99
4.9. Clases de análisis involucradas en el caso de uso Crear fondo . . . . . . . . 100
4.10. Clases de análisis involucradas en el caso de uso Crear extended rotoscale . 103
4.11. Diagrama de secuencia del patrón MVP [13] . . . . . . . . . . . . . . . . . 104
4.12. Diagrama de clases del patrón MVP [13] . . . . . . . . . . . . . . . . . . . 105
4.13. Construcción del diagrama de clases del sistema utilizando el patrón MVP . 106
4.14. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 106
4.15. Diagrama de secuencia correspondiente al flujo alternativo . . . . . . . . . 107
4.16. Diagrama de clases utilizando el patrón Builder . . . . . . . . . . . . . . . 108
4.17. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 108
4.18. Diagrama de clases utilizando el patrón Proxy . . . . . . . . . . . . . . . . 109
4.19. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 110
4.20. Diálogo de selección del tipo de fondo . . . . . . . . . . . . . . . . . . . . 111
4.21. Clases de análisis involucradas en el caso de uso Crear teselado . . . . . . 118
4.22. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 120
4.23. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 123
4.24. Clases de análisis involucradas en el caso de uso Modificar paleta . . . . . 125
4.25. Clases de análisis involucradas en el caso de uso Cambiar color . . . . . . 127
4.26. Clases de análisis involucradas en el caso de uso Modificar tesela . . . . . . 128
4.27. Clases de análisis involucradas en el caso de uso Agregar color nuevo . . . 129
4.28. Clases de análisis involucradas en el caso de uso Intercambiar colores . . . 129
4.29. Clases de análisis involucradas en el caso de uso Modificar fondo . . . . . . 130
4.30. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 133
4.31. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 134
4.32. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 135
4.33. Diálogo Reorganizar paleta . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.34. Diálogo de selección de color . . . . . . . . . . . . . . . . . . . . . . . . . 137
4.35. Diagrama de secuencia correspondiente al flujo normal . . . . . . . . . . . 140
LISTA DE FIGURAS
4.36.
4.37.
4.38.
4.39.
4.40.
4.41.
4.42.
VII
Diagrama de secuencia correspondiente al flujo alternativo . . . . .
Diagrama de secuencia correspondiente al flujo normal . . . . . . .
Diagrama de secuencia correspondiente al flujo normal . . . . . . .
Clases de análisis involucradas en el caso de uso Generar datos NDS
Diagrama de secuencia correspondiente al flujo normal . . . . . . .
Diagrama de clases del editor de fondos . . . . . . . . . . . . . . .
Diagrama de secuencia correspondiente al flujo normal . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
141
141
142
148
149
150
151
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
161
162
165
166
167
168
169
169
170
171
172
173
B.1. Fondo framebuffer a partir de una imagen de 192×256 pixels . . . . . .
B.2. Fondo de rotación extendida a partir de una imagen de 128×128 pixels .
B.3. Fondo de rotación extendida a partir de una imagen de 256×256 pixels .
B.4. Fondo de rotación extendida a partir de una imagen de 512×256 pixels .
B.5. Fondo de rotación extendida a partir de una imagen de 512×512 pixels .
B.6. Fondo de rotación extendida a partir de una imagen de 512×1024 pixels
B.7. Fondo de rotación extendida a partir de una imagen de 1024×512 pixels
B.8. Fondo teselado de 256 colores a partir de una imagen de 32×32 teselas
B.9. Fondo teselado de 256 colores a partir de una imagen de 32×64 teselas
B.10. Fondo teselado de 16 colores a partir de una imagen de 64×32 teselas .
B.11. Fondo teselado de 16 colores a partir de una imagen de 64×64 teselas .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
175
176
176
177
177
178
178
179
180
181
182
A.1. Diálogo de creación de un proyecto C . . . . . . .
A.2. Propiedades del proyecto . . . . . . . . . . . . . .
A.3. Crear la configuración de depuración . . . . . . . .
A.4. Punto de ruptura en el programa . . . . . . . . . .
A.5. Salida del programa . . . . . . . . . . . . . . . . .
A.6. Interfaz del editor de fondos . . . . . . . . . . . .
A.7. Diálogo Nuevo fondo . . . . . . . . . . . . . . . .
A.8. Abrir una imagen en modo teselado de 256 colores
A.9. Diálogo Reorganizar paleta . . . . . . . . . . . . .
A.10.Diálogo Convertir fondo . . . . . . . . . . . . . .
A.11.Sustitución de un conjunto de teselas del fondo . .
A.12.Espejos disponibles para una tesela . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
LISTA DE FIGURAS
VIII
Lista de tablas
3.1. Bancos de memoria de video . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.2. Tamaño de los tipos de datos básicos . . . . . . . . . . . . . . . . . . . . .
30
3.3. Registros de ARM y su uso en AAPCS . . . . . . . . . . . . . . . . . . . .
34
3.4. Modos gráficos para el núcleo principal y el secundario [21] . . . . . . . .
42
3.5. Registro de control de energı́a REG POWERCNT . . . . . . . . . . . . . .
44
3.6. Colores en formato RGB de 16 bits . . . . . . . . . . . . . . . . . . . . . .
45
3.7. Posibles configuraciones del modo framebuffer . . . . . . . . . . . . . . .
45
3.8. Registro de control de pantalla REG DISPCNT [15] . . . . . . . . . . . .
46
3.9. Entrada de un mapa teselado . . . . . . . . . . . . . . . . . . . . . . . . .
74
4.1. Descripción textual del caso de uso Depurar mediante emulador . . . . . .
91
4.2. Caso de prueba 1, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . .
95
4.3. Plan de iteraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
4.4. Descripción textual del caso de uso Abrir imagen . . . . . . . . . . . . . . 100
4.5. Descripción textual del caso de uso Crear fondo . . . . . . . . . . . . . . . 101
4.6. Descripción textual del caso de uso Crear framebuffer . . . . . . . . . . . . 102
4.7. Descripción textual del caso de uso Crear extended rotoscale . . . . . . . . 103
4.8. Caso de prueba 1, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . . 117
4.9. Caso de prueba 2, “en negativo” . . . . . . . . . . . . . . . . . . . . . . . 117
4.10. Caso de prueba 3, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . . 117
4.11. Caso de prueba 4, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . . 118
4.12. Descripción textual del caso de uso Crear teselado . . . . . . . . . . . . . 119
4.13. Caso de prueba 5, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . . 122
4.14. Caso de prueba 6, “en positivo” . . . . . . . . . . . . . . . . . . . . . . . . 125
4.15. Descripción textual del caso de uso Modificar paleta . . . . . . . . . . . . 126
4.16. Descripción textual del caso de uso Cambiar color . . . . . . . . . . . . . 127
4.17. Descripción textual del caso de uso Modificar tesela . . . . . . . . . . . . . 128
4.18. Descripción textual del caso de uso Agregar color nuevo . . . . . . . . . . 130
IX
LISTA DE TABLAS
4.19. Descripción textual del caso de uso Intecambiar colores .
4.20. Descripción textual del caso de uso Modificar fondo . . .
4.21. Caso de prueba 7, “en positivo” . . . . . . . . . . . . . .
4.22. Caso de prueba 8, “en positivo” . . . . . . . . . . . . . .
4.23. Caso de prueba 9, “en positivo” . . . . . . . . . . . . . .
4.24. Caso de prueba 10, “en positivo” . . . . . . . . . . . . .
4.25. Caso de prueba 11, “en positivo” . . . . . . . . . . . . .
4.26. Caso de prueba 12, “en positivo” . . . . . . . . . . . . .
4.27. Caso de prueba 13, “en positivo” . . . . . . . . . . . . .
4.28. Caso de prueba 14, “en positivo” . . . . . . . . . . . . .
4.29. Caso de prueba 15, “en positivo” . . . . . . . . . . . . .
4.30. Descripción textual del caso de uso Generar datos NDS .
4.31. Caso de prueba 16, “en positivo” . . . . . . . . . . . . .
X
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
131
132
138
138
139
139
145
145
146
146
147
148
152
5.1. Resultados para cada tamaño aceptado por los tipos de fondo . . . . . . . . 153
Capı́tulo 1
INTRODUCCIÓN
1.1. Motivación
1.2. Justificación del trabajo
1.3. Estructura del documento
1.1.
Motivación
Durante el curso 2007-2008 y el curso actual, 2008-2009, se puso en práctica en
la Escuela Superior de Informática de Ciudad Real una nueva experiencia docente en el
Área de Arquitectura y Tecnologı́a de Computadores. Dicha experiencia consistı́a en la
utilización de la consola de videojuegos Nintendo DS como plataforma para el aprendizaje
de los conceptos básicos de arquitectura de computadores. En concreto, la Nintendo DS
sustituyó al microcontrolador Microchip PIC16F84 en las prácticas de laboratorio de la
asignatura Estructura de Computadores.
En la industria de los videojuegos, las consolas portátiles están viviendo en las fechas
actuales su máximo auge. Los principales culpables de este auge son tanto Nintendo, con la
Game Boy Advance y con la Nintendo DS, como Sony, con la Sony PlayStation Portable.
Dichas compañı́as han logrado que estas consolas hayan entrado en millones de hogares de
todo el mundo. En concreto, según datos oficiales de Nintendo, el número total de unidades
vendidas en todo el mundo de cualquiera de los tipos de Nintendo DS alcanzó la cifra de
101 millones en el pasado mes de junio1 .
Debido a la amplia difusión de la videoconsola Nintendo DS, existe una amplia
comunidad de usuarios que se dedican al desarrollo de software casero. La tendencia de
1 Fuente:
http://www.nintendo.co.jp/ir/library/historical_data/pdf/consolidated_
sales_e0903.pdf
1
CAPÍTULO 1. INTRODUCCIÓN
2
desarrollar este tipo de software para una videoconsola, se hizo popular por primera vez
con la Game Boy Advance.
El desarrollo de software para una videoconsola requiere de un conocimiento exhaustivo tanto del hardware del dispositivo como de sus especificaciones técnicas. Gracias
a la extensa comunidad de desarrollo casero existente en Internet, cualquier persona puede tener acceso a la amplia documentación disponible para construir aplicaciones para la
Nintendo DS.
Por tanto, a causa de la amplia difusión de la videoconsola Nintendo DS y de su
comunidad de desarrollo existente en Internet, cualquier alumno tiene la posibilidad de
estudiar y profundizar en los conceptos de la asignatura Estructura de Computadores en su
propia casa. Una de las ventajas de emplear una videoconsola como la Nintendo DS reside
en que el alumno utilizará un dispositivo real con el cual esté familiarizado para abordar los
objetivos de la asignatura.
1.2.
Justificación del trabajo
Como se ha comentado, una videconsola tan extendida como la Nintendo DS ofrece
al alumno la posibilidad de estudiar y profundizar en los conceptos de la asignatura Estructura de Computadores en su propia casa. En concreto, cualquier alumno podrá realizar o
terminar de realizar cualquier práctica de dicha asignatura fuera de un laboratorio docente
de la escuela.
Para la realización de las diversas prácticas, el alumno debe emplear una serie de
herramientas desconocidas para la gran mayorı́a. La instalación, configuración y familiarización con estas herramientas supone un gran esfuerzo en tiempo para los alumnos de
primer curso. Esta situación provoca que gran parte del tiempo disponible para las sesiones
de prácticas se dediquen a temas que no entran dentro del ámbito de la asignatura. Por tanto,
las sesiones de exploración de la arquitectura de la DS se reducen de forma considerable
por falta de tiempo.
Este proyecto pretende desarrollar un entorno amigable de programación apto para
la docencia de Estructura de Computadores, el cual permita destinar gran parte del esfuerzo
de los alumnos a tareas relacionadas con la exploración de la arquitectura de la Nintendo
DS.
Con este proyecto se intentará disminuir, en la mayor medida de lo posible, algunas
tareas que no entran dentro del ámbito de estudio de la asignatura y que conciernen a materias de cursos superiores. Y, por otro lado, se intentará que las posibles dificultades que
aparezcan en los alumnos, estén relacionadas con la arquitectura de la videoconsola y no
CAPÍTULO 1. INTRODUCCIÓN
3
sean consecuencia de un software demasiado complejo, el cual requiera una gran curva de
aprendizaje para los estudiantes de primer curso.
1.3.
Estructura del documento
Este documento está estructurado en site capı́tulos y en 2 anexos. El capı́tulo actual,
relativo a la introducción, pretende ser una presentación, comentando el marco bajo el que
se elabora este proyecto.
En el segundo capı́tulo se concretará y expondrá el problema a resolver describiendo
el entorno de trabajo, la situación y, además, se detallará lo que se pretende conseguir.
Asimismo, se señalarán las limitaciones y condicionantes a considerar para la resolución
del problema.
En el tercer capı́tulo se mostrarán los conocimientos obtenidos en la búsqueda bibliográfica. Se articulará este capı́tulo en diversas secciones que permitan la exposición
estructurada y didáctica de las distintas tecnologı́as y herramientas que se han utilizado
para realizar el presente proyecto.
En el cuarto capı́tulo se explicará el procedimiento empleado para conseguir los
objetivos propuestos. En el quinto capı́tulo se muestran los resultados obtenidos, que darán
paso al capı́tulo de conclusiones y propuestas expuestas.
En el último capı́tulo se incluye la bibliografı́a consultada para la realización del
proyecto.
En el primer anexo se ilustrará con un tutorial del entorno de programación construido. Por último, en el segundo anexo se presentarán las figuras relacionadas con el capı́tulo
de resultados.
CAPÍTULO 1. INTRODUCCIÓN
4
Capı́tulo 2
OBJETIVOS DEL PROYECTO
2.1. Objetivos generales
2.2. Objetivos especı́ficos
2.1.
Objetivos generales
El objetivo principal de este proyecto es el desarrollo de un entorno de programación
apto para ser utilizado en la docencia de la asignatura Estructura de Computadores. El
producto software final permitirá a los alumnos, en primer lugar, reducir el tiempo empleado
en tareas de instalación, configuración y aprendizaje del software empleado en las prácticas
de laboratorio. En segundo lugar, permitirá una mayor dedicación del esfuerzo a labores de
exploración de la arquitectura de la Nintendo DS.
Con este proyecto se intentará disminuir, en la mayor medida de lo posible, algunas
tareas que no entran dentro del ámbito de estudio de la asignatura y que conciernen a materias de cursos superiores. Y, por otro lado, se intentará que las posibles dificultades que
aparezcan en los alumnos, estén relacionadas con la arquitectura de la videoconsola y no
sean consecuencia de un software demasiado complejo, el cual requiera una gran curva de
aprendizaje para los estudiantes de primer curso.
2.2.
Objetivos especı́ficos
A continuación se ofrece en una serie de puntos especı́ficos una visión más clara de
los objetivos que se abordarán en el proyecto:
5
CAPÍTULO 2. OBJETIVOS DEL PROYECTO
6
Desarrollo del sistema utilizando como base Eclipse: El entorno de programación
se construirá utilizando como base Eclipse. De manera más precisa, se utilizarán los
plugin de Eclipse siguientes:
1. NDS Managedbuilder
2. Zylin Embedded CDT
Bajo acoplamiento y alta cohesión: Se prestará un énfasis especial en la facilidad
de actualización del sistema y la minimización del acoplamiento entre componentes.
Depuración utilizando un emulador: El sistema proporcionará al alumno la posibilidad de poder utilizar un simulador de Nintendo DS durante el proceso de depuración
de aplicaciones. En concreto, se utilizará el simulador libre de Nintendo DS DeSmuME.
Múltiples vistas: El sistema debe tener la capacidad de ofrecer tres vistas diferentes
de cada tesela de un fondo teselado, ya sea de 16 o 256 colores. Estas tres vistas serán
las siguintes:
1. Vista del fondo
2. Vista del conjunto de teselas del fondo en edición
3. Vista individual de cada tesela para su edición
Modos gráficos 2D: El sistema debe soportar el trabajo con los tres tipos diferentes
de fondos 2D de la Nintendo DS. Estos son los siguientes:
1. Modo Framebuffer
2. Modo Extended Rotoscale
3. Modo Gráficos Teselados
Fondos teselados de 16 y 256 colores: Se debe poder trabajar tanto con teselas de
256 colores como con teselas de 16 colores. Además, el sistema debe ofrecer la posibilidad de crear mapas teselados para la Nintendo DS partiendo desde cero, ası́ como
trabajar con un mapa teselado existente.
Edición de la paletas de colores: Tanto en el modo extended rotoscale como en el
modo teselado de 256 colores y 16 colores, se debe permitir la edición de la paleta de
colores asociada al fondo con el que se esté trabajando en ese momento.
CAPÍTULO 2. OBJETIVOS DEL PROYECTO
7
El sistema generará datos entendibles por la videoconsola: Las entradas del sistema serán imágenes, a partir de los cuales se generarán los datos con los que la
Nintendo DS es capaz de trabajar. Las imágenes de entrada se ajustarán al formato
gráfico PNG (Portable Network Graphics).
Desarrollo de un sistema multiplataforma: Se buscará el desarrollo de un sistema
software que pueda funcionar en diversas plataformas. En concreto, se pretende que
el sistema final pueda funcionar tanto en plataformas Microsoft Windows como en
plataformas GNU/Linux.
Desarrollo de un sistema viable desde el punto de vista docente: Se demostrará la
viabilidad docente del sistema, mediante la preparación de un tutorial adaptado a asignaturas donde este tipo de plataforma tenga sentido, como por ejemplo, Estructura de
Computadores, Interfaces y Periféricos, Sistemas Empotrados o Diseño de Sistemas
Crı́ticos.
Sencilla instalación y configuración del software: Es de gran importancia desvincular al usuario de las dependencias del sistema, ası́ como minimizar en la mayor
medida de lo posible las configuraciones que el alumno tenga que realizar.
Desarrollo del sistema utilizando software libre: Todo el desarrollo del proyecto se
llevará a cabo mediante el empleo de tecnologı́as libres.
CAPÍTULO 2. OBJETIVOS DEL PROYECTO
8
Capı́tulo 3
ANTECEDENTES, ESTADO DE LA
CUESTIÓN
3.1. La videoconsola Nintendo DS
3.1.1. Introducción
3.1.2. Familia de la Nintendo DS
3.1.3. El hardware de la Nintendo DS
3.2. Desarrollo de software casero para Nintendo DS
3.2.1. Introducción
3.2.2. DevkitPro
3.2.3. DevkitARM
3.2.4. GNU Debugger
3.2.5. Entornos cruzados de desarrollo
3.2.6. Emuladores
3.3. Compilando para Nintendo DS
3.3.1. Introducción
3.3.2. ABI
3.3.3. EABI
3.3.4. AAPCS
3.3.5. Explorando el ABI con GDB y DeSmuME
3.4. Gráficos con Nintendo DS
3.4.1. Introducción
9
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
10
3.4.2. Interacción con los periféricos
3.4.3. Modo framebuffer
3.4.4. Modo extended rotoscale
3.4.5. Modo teselado
3.1.
La videoconsola Nintendo DS
3.1.1.
Introducción
Desarrollar para Nintendo DS supone desarrollar para un microprocesador ARM,
más concretamente, para microprocesadores ARM9 y ARM7, a 67 y 33 MHz respectivamente. El procesador ARM9 se encarga de la lógica principal del programa, mientras que
el ARM7, como procesador secundario, se encargará básicamente de gestionar el audio y la
Wi-Fi. El hecho de que la consola NDS cuente con dos procesadores implica la generación
de dos ejecutables distintos, uno para cada procesador. El ejecutable del ARM7 actuará como esclavo del ARM9, atendiendo peticiones de reproducción de sonido o comunicaciones
vı́a Wi-Fi [27].
Los microprocesadores ARM1 tienen una gran importancia en el campo de los dispositivos portátiles, como teléfonos móviles o reproductores de mp3, gracias a su bajo consumo energético, entre otras razones. Cerca del 70 % de los procesadores de 32 bits del
mercado poseen este chip en su núcleo [3].
3.1.2.
Familia de la Nintendo DS
La familia de la Nintendo DS consta de tres miembros hasta la fecha actual. Por
orden de lanzamiento en el mercado, estas tres videoconsolas son las siguientes:
Nintendo DS (NDS): Sustituyó el procesador Z80 de la GameBoy Advance (GBA)
por un ARM9 a 33Mhz, y mejoró el conjunto de aceleradores para gráficos de la GBA
(véase la figura 3.1).
Nintendo DS Lite: Sólo se diferencia de la NDS normal, aparte de por su aspecto
más estilizado, en mejoras de consumo y diferentes niveles de control de brillo de la
pantalla (véase la figura 3.2).
1 Sitio
web oficial de ARM: http://www.arm.com
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
11
Nintendo DSi: Incorpora dos cámaras de baja resolución, las dos pantallas son algo
mayores, un mejor sonido, más memoria (16 MiB RAM y 256 MiB Flash) e incorpora una nueva ranura para tarjetas SD. Además, la frecuencia del procesador ARM9
aumenta hasta 133 MHz. En cuanto a aspectos negativos, se debe señalar que pierde
la ranura Slot2 de compatibilidad con los cartuchos de Game Boy Advance (véase la
figura 3.3).
Figura 3.1: Nintendo DS
3.1.3.
El hardware de la Nintendo DS
3.1.3.1.
Microprocesadores
Como se ha comentado anteriormente, la consola cuenta con dos procesadores, un
ARM9 y un ARM7, a 67 y 33 MHz respectivamente, ambos integrados en un único procesador especı́ficamente diseñado para Nintendo [7]. Esto supone una mejora significativa del
hardware en comparación con su predecesora, la Game Boy Advance. Dicha videoconsola
tenı́a un único procesador, el ARM7TDI a 16.8 MHz. Obviamente, se debe subrayar que el
procesador ARM7 de la Nintendo DS trabaja a 16 MHz cuando funciona en modo Game
Boy Advance.
El nombre completo del procesador ARM7 es ARM7TDMI [4]. No tiene ni caché de
instrucciones ni caché de datos, pero esto se ve compensando ligeramente por la rápida memoria que posee. El ARM7 es la única CPU que puede utilizarse para controlar la pantalla
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Figura 3.2: Nintendo DS Lite
Figura 3.3: Nintendo DSi
12
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
13
táctil. Además, también es el encargado de controlar el micrófono, el sonido, las comunicaciones inalámbricas y el reloj de tiempo real.
Debido a su mayor potencia en comparación con el ARM7, el ARM9 es el principal
procesador y, como tal, se encargará de la mayorı́a del trabajo. La mayorı́a de las aplicaciones son ejecutadas en este proceador. Su nombre completo es ARM946E-S[6].
3.1.3.2.
Memoria Principal
La memoria RAM principal de la Nintendo DS tiene un tamaño de 4 MiB. Dicha
memoria almacena el ejecutable para el ARM9, ası́ como la gran mayorı́a de datos del
ejecutable. Ambos procesadores pueden acceder a esta memoria en cualquier momento.
Si ambos intentaran acceder a la vez, serı́a el que tenga mayor prioridad el que accederı́a,
quedando el otro a la espera.
En adición a estos 4 MiB de RAM, existen 656 KiB para memoria de video (VRAM),
las pseudo-cachés WRAM e IWRAM de 96Kb, una memoria RAM adicional para la BIOS
y una memoria virtual para video (Virtual Video RAM). En la figura 3.4 se puede observar
el esquema del mapa de memoria de la consola.
3.1.3.3.
Gráficos
El hardware de video de la Nintendo DS se compone de dos núcleos gráficos 2D, uno
principal (main) y otro secundario (sub). Dichos núcleos se diferencian únicamente en que
el motor principal puede renderizar tanto la memoria de video virtual sin utilizar el motor
2D, como mapas de bits de 256 colores, ası́ como utilizar el motor 3D para el renderizado
de alguno de sus fondos[26].
Además, la videoconsola cuenta con un motor gráfico 3D, el cual puede representar
gráficos superiores a los de Nintendo 64.
3.1.3.4.
Memoria de video VRAM
La Nintendo DS tiene 9 bancos de memoria de video, los cuales se pueden usar con
diferentes propósitos (véase la figura [21] 3.5). Cada de uno de estos bancos de memoria
están etiquetado desde VRAM A hasta VRAM I y se pueden utilizar para almacenar los
datos de sprites, de teselas, de texturas o de un mapa de pı́xeles. Asimismo, cada banco
de memoria tiene un registro asociado, el cual se utiliza para activar su banco de memoria
correspondiente. En la tabla 3.1 se muestra cada uno de los bancos de memoria de video
existentes junto con su tamaño.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Figura 3.4: Esquema del mapa de memoria de la NDS [21]
14
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
15
Figura 3.5: Asignación de bancos de VRAM [18]
La cantidad total de memoria de video es de 656 KiB. Se debe prestar un esfuerzo
especial en cómo utilizar de manera eficiente esta cantidad de memoria flexible, pero muy
limitada.
Banco de memoria
VRAM A
VRAM B
VRAM C
VRAM D
VRAM E
VRAM F
VRAM G
VRAM H
VRAM I
Tamaño del banco (KiB)
128
128
128
128
64
16
16
32
16
Tabla 3.1: Bancos de memoria de video
3.1.3.5.
Sonido
Nintendo DS dispone de altavoces estéreo y cuenta con 16 canales de audio independientes [7].
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.1.3.6.
16
Comunicación inalámbrica
La Nintendo DS soporta el estándar de protocolo de comunicaciones IEEE 802.11.
El rango de comunicación inalámbrica varı́a de 10 a 30 metros, dependiendo de las circunstancias. En muchos casos, varios jugadores pueden participar en la misma partida multijugador utilizando una única tarjeta de juego [7].
3.1.3.7.
Entrada/Salida
La videoconsola tiene un puerto para cartuchos de juegos de Nintendo DS y otro para
juegos de Game Boy Advance2 . La NDS cuenta con una entrada para auriculares estéreo y
otra entrada para micrófono [7].
3.1.3.8.
Doble pantalla
Las dos pantallas LCD de Nintendo DS ofrecen un enfoque absolutamente innovador
en lo que a videojuegos portátiles se refiere. Las dos pantallas, ambas de 3 pulgadas, son
capaces de reproducir auténticos gráficos en tres dimensiones, incluso más avanzados que
los de la Nintendo 64. La pantalla inferior de la DS emplea tecnologı́a táctil, siendo ésta la
primera vez en la historia que una consola portátil utiliza este tipo de caracterı́sticas [7].
3.1.3.9.
Temporizador
La Nintendo DS cuenta con un reloj de tiempo de real, el cual puede ser utilizado
por una aplicación o juego para definir diferentes respuestas dependiendo de la hora del dı́a
[7].
3.2.
Desarrollo de software casero para Nintendo DS
3.2.1.
Introducción
Según [9], se denomina homebrew al software casero no oficial realizado por programadores, ya sean aficionados o expertos, para cualquier plataforma. Generalmente, esta
plataforma suele ser una videoconsola propietaria. No obstante, en la última década se han
desarrollado algunas consolas diseñadas especı́ficamente para la ejecución de software casero como, por ejemplo, GP32 de GamePark o GP2X de GamePark Holdings.
2 La
Nintendo DSi no cuenta con puerto para cartuchos de Game Boy Advance
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
17
El desarrollo de software casero está permitido en cualquiera de las consolas de
Nintendo, siempre y cuando sea sin ánimo de lucro. En cualquier caso, se debe señalar que
no todas las plataformas permiten el homebrew.
El desarrollo de software para la Nintendo DS se puede realizar de dos maneras
diferentes:
1. Utilizando el kit comercial de desarrollo de software (SDK) de Nintendo.
2. Utilizando DevkitPro, que es un conjunto de librerı́as, compiladores y utilidades para
desarrollar software para varias plataformas. Además, es libre y de descarga gratuita.
En los apartados siguientes de este capı́tulo se analizarán las principales herramientas existentes que ayudan al desarrollo de aplicaciones para Nintendo DS.
3.2.2.
DevkitPro
DevkitPro3 es un conjunto de librerı́as, compiladores y utilidades que permiten
el desarrollo de aplicaciones para las consolas Game Boy Advance (GBA), GP32, GP2X,
Playstation Portable (PSP), Nintendo DS y GameCube. Actualmente, DekvitPro cuenta con
cuatro toolchains4 que permiten escribir aplicaciones y juegos para las consolas citadas:
DevkitARM: es la toolchain utilizada para el desarrollo de aplicaciones para GBA,
GP32 y Nintendo DS.
DevkitGP2X: es la toolchain utilizada para el desarrollo de aplicaciones para la GamePark GP2X.
DevkitPPC: es la toolchain utilizada para el desarrollo de aplicaciones para la Nintendo GameCube.
DevkitPSP: es la toolchain utilizada para el desarrollo de aplicaciones para la Sony
PSP.
3.2.3.
DevkitARM
DevkitARM es una toolchain de C y C++, basada en la colección de compiladores
GNU (GCC), que permite crear binarios para la arquitectura ARM. Incluye todo lo necesario para crear software para la Nintendo DS, GBA y GP32. Las librerı́as que incluye
DevkitARM son las siguientes:
3 Sitio
web de devkitPro: http://www.devkitpro.org
término toolchain se refiere a un conjunto de programas informáticos (tools) que se usan para crear un
determinado producto.
4 El
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
18
LibNDS [22]: anteriormente conocida como NDSLIB, es una librerı́a que fue creada
por Michael Noland y Jason Rogers. Esta librerı́a sirve como base para el desarrollo
de programas para la Nintendo DS. Supone una alternativa libre frente al kit comercial de desarrollo de software (SDK) de Nintendo. LibNDS soporta casi todas las
caracterı́sticas de la DS, incluyendo la pantalla táctil, el micrófono, el hardware 2D,
el hardware 3D y las comunicaciones inalámbricas.
LibFAT: esta librerı́a contiene una serie de rutinas para leer y escribir en sistemas de
ficheros FAT como los de las tarjetas Secure Digital (SD), MultimediaCard (MMC) o
CompactFlash (CF).
DSWifi: esta librerı́a permite a los desarrolladores usar la Wi-Fi de la DS de una
manera similar a cómo los ordenadores usan la tarjeta de red inalámbrica.
LibGBA: esta librerı́a contiene las funciones necesarias para controlar el hardware
de la Game Boy Advance.
En Informática, es una tradición que el primer ejercicio a la hora de aprender o enseñar un nuevo lenguaje sea imprimir en pantalla “Hello World”. En este caso, para mostrar
el funcionamiento de LibNDS se realizará un pequeño programa de ejemplo que imprima
en la pantalla de arriba de la DS “Hello Mario”.
1
# include < nds .h >
2
# include < stdio .h >
3
int main ( int argc , char * argv [])
4
{
5
consoleDemoInit () ;
6
printf ( ‘ ‘ Hello Mario \ n ’ ’) ;
7
while (1) {};
8
return 0;
9
}
Algunas de las herramientas más destacadas de devkitArm son las siguientes [29]:
Grit (GBA Image Transmogrifier) [34]: es un conversor de imágenes para la Game
Boy Advance y la Nintendo DS. Grit acepta multitud de formatos de archivos (bmp,
pcx, png, gif, jpeg, etc. . . ) con cualquier profundidad de bits y obtiene los datos que
pueden ser usados directamente en el código de un programa para GBA o NDS. Los
datos que genera Grit pueden ser datos de una paleta, datos de teselas, datos de un mapa o datos de un gráfico. Los formatos de salida disponibles son, entre otros, archivo
C, archivo binario, archivo GNU Assembly o archivo RIFF.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
19
arm-eabi-gcc: es un compilador cruzado que genera código objeto para el ARM7 y
el ARM9 a partir de código escrito en C o C++.
arm-eabi-ld: es un enlazador que genera un archivo ejecutable en el formato estándar
ELF para el entorno de ejecución ARM7 y ARM9 a partir del código objeto generado
por el arm-eabi-gcc.
arm-eabi-objcopy: es una herramienta que genera los archivos ejecutables reducidos
.arm7 y .arm9 a partir del archivo ejecutable con formato ELF. Esta herramienta
reduce al mı́nimo las necesidades de memoria de la videoconsola. Para ello, extra
exclusivamente lo necesario para poder ejecutar el programa (instrucciones y datos).
ndstool: la herramienta ndstool combina los archivos ejectuables .arm7 y .arm9 en
un único archivo con extensión .nds añadiendo una cabecera descriptiva al comienzo.
Opcionalmente, puede combinar junto con los archivos ejecutables otros datos como,
por ejemplo, datos de gráficos.
dsbuild: la herramienta dsbuild genera un archivo con extensión .ds.gba, el cual permite arrancar el programa desde el Slot2 (compatible con Game Boy Advance).
3.2.4.
GNU Debugger
El depurador de GNU, abreviado GDB [31], es un depurador simbólico avanzado
con soporte de múltiples de arquitecturas, formatos de ejecutable y lenguajes de programación. Es utilizado en una amplı́sima variedad de productos comerciales en todo el mundo.
GDB es un poderoso depurador que permite “ver” que está sucediendo dentro de
otro programa mientras se ejecuta o lo que otro programa estaba haciendo en el momento
que terminó inesperadamente su ejecución. Entre las capacidades más notorias que este
depurador posee están:
Depurar programas complejos con múltiples archivos.
Detener el programa en una posición de la memoria del programa (breakpoints), detener el programa según una condición (watchpoints) o al emitirse una señal (catchpoints).
Examinar las variables locales de la función que se está ejecutando en un momento
determinado.
Mostrar valores de expresiones arbitrariamente complejas cuando el programa se detiene.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
20
Examinar los registros del procesador.
Modificar cualquier valor de registros o posición de memoria para estudiar el comportamiento del programa sin necesidad de recompilar.
Mostrar la traza de llamadas del programa, es decir, las funciones que han sido invocadas y desde dónde.
Ir avanzando la ejecución paso a paso hasta encontrar el punto exacto en el que ocurre
el fallo inespiradamente del programa.
El uso de los depuradores no se limita únicamente al campo de la localización y
resolución de errores, sino que también se emplean para explorar la arquitectura sobre la
que está ejecutando un programa.
Para que GDB pueda ser aprovechado al máximo en la depuración de un programa, será necesario que éste haya sido compilado con soporte para depuración, lo cual se
especifica al compilador GCC mediante la opción -g.
3.2.4.1.
Front-ends para GDB
Un front-end [23] no es más que una interfaz gráfica entre la aplicación y los usuarios. Por lo tanto, los front-ends para GDB realmente no son depuradores en sı́ mismos, sino
que son sólo interfaces gráficas que redirigen las peticiones en forma de órdenes a GDB.
Dentro del amplio abanico de front-ends que existen para GDB, se presentarán las
propuestas más relevantes de entre aquellos que dan soporte a la depuración remota, ya
que es esencial cuando se desarrolla para plataformas mediante compilación cruzada, como
es el caso de la compilación y depuración de código para la consola Nintendo DS. Las
principales propuestas son las siguientes:
KDbg [30]: es un front-end desarrollado utilizando la arquitectura de componentes
KDE.
DDD [16]: son las siglas de Data Display Debugger. Lo más caracterı́stico de este
front-end es que permite explorar los datos mediante interacción con la representación
gráfica de los mismos, pues las estructuras de datos se representan como grafos.
3.2.5.
Entornos cruzados de desarrollo
Según [11], se puede definir un IDE (Integrated Development Environment) como
un programa compuesto por un conjunto de herramientas útiles para un desarrollador de
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
21
software. Como elementos básicos, un IDE cuenta con un editor de código, un compilador/intérprete y un depurador. También puede dar soporte a más de un lenguaje de programación.
Para desarrollar aplicaciones para Nintendo DS no es suficiente con utilizar un entorno de desarrollo integrado. Se necesita un entorno cruzado de desarrollo que soporte los
lenguajes de programación C y C++. En un entorno cruzado de desarrollo se ven involucrados dos sistemas diferentes:
Sistema Host: las actividades de desarrollo software tipı́camente se realizan en este
sistema, el cual aporta facilidades para el desarrollo (editores, compiladores, montadores, etc. . . ).
Sistema Target: el resultado de las actividades de desarrollo software se ejecutan en
este sistema, distinto al anterior.
Gracias al uso de herramientas cruzadas en Sistemas Host, es posible desarrollar
y depurar aplicaciones para Sistemas Target. Dado que los requerimientos del Target son
incompatibles con los del Host (el hardware del Target suele diseñarse de modo especı́fico
para un proyecto), las herramientas de desarrollo y depuración cruzada deben permitir al
desarrollador ajustarse lo máximo posible a los requerimientos del Target.
Dentro del desarrollo de sistemas, una de las labores más importantes es la depuración del sistema. Esta labor puede realizarse de dos modos distintos:
Utilizando emuladores: de este modo la labor de depuración puede realizarse en el
Sistema Host de modo independiente del Sistema Target. Sin embargo de este modo
se tiene una visión reducida del sistema, ya que este no está en su entorno real. También posee la desventaja de que para cada sistema particular se necesita un emulador.
Utilizando el propio Sistema Target: de esta manera se tiene una visión más real
de la forma de operar del sistema. Este modo exige incluir dentro del código de la
aplicación código para poder realizar la depuración. Además, no todo sistema puede
depurarse de este modo, ya que exige la parada del mismo, lo cual no siempre puede
ser conveniente.
3.2.5.1.
Eclipse
La plataforma Eclipse5 consiste en un entorno de desarrollo integrado abierto y extensible. Eclipse sirve como IDE de Java y dispone de numerosas herramientas de desarrollo
5 Sitio
web oficial de Eclipse: http://www.eclipse.org
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
22
de software. También da soporte a otros lenguajes de programación, como C/C++, Cobol,
Fortran, PHP o Python. A la plataforma base de Eclipse se le pueden añadir extensiones
(plug-in) para extender la funcionalidad (véase la figura 3.6).
Figura 3.6: Arquitectura de la plataforma Eclipse [14]
Además, el término Eclipse identifica a la comunidad de usuarios que constantemente están ampliando esta plataforma. Eclipse se divide en proyectos que tienen el objetivo de
proporcionar una plataforma robusta, escalable y de calidad para el desarrollo de software. Está coordinado por la Eclipse Foundation, que es una organización sin ánimo de lucro
creada para la promoción y la evolución de la plataforma Eclipse, Asimismo, la mencionada
fundación da soporte tanto a la comunidad como al ecosistema Eclipse.
CDT
Eclipse fue creado originalmente en Java y para Java. Sin embargo, La mayorı́a
de proyectos de desarrollo cruzado de software están escritos en C, C++ o en lenguaje
ensamblador. Para que Eclipse fuera compatible con C y C++, se creó un plug-in llamado
CDT6 (C/C++ Development Tools).
Con Eclipse y CDT trabajando conjuntamente (Eclipse CDT), el entorno es capaz
de soportar el desarrollo de código en C y C++. Sin embargo, el entorno que forman sólo
es útil para el desarrollo de aplicaciones nativas.
6 Sitio
web del plug-in CDT: http://www.eclipse.org/cdt/
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
23
NDS Managedbuilder
NDS Managedbuilder7 es un plug-in para Eclipse CDT. Se utiliza exclusivamente
para el desarrollo de aplicaciones para Nintendo DS. Las principales caracterı́sticas de este
plug-in son:
Permite el desarrollo cruzado de software basado en las herramientas de programación producidas por el proyecto GNU (GNU toolchain.
Soporta el desarrollo de proyectos en C y C++. También permite la programación en
lenguaje ensamblador (ASM).
Entre las herramientas que incluye se encuentran ObjCopy y NDS-Tool.
Integra el depurador GDB de ARM.
Permite la creación de proyectos para el ARM7 y el ARM9 de NDS
Permite la creación de ROMs para NDS.
Permite la creación de liberı́as para el ARM7 y el ARM9 de NDS.
Con Eclipse y NDS Managedbuilder trabajando conjuntamente, Eclipse adquiere la
forma de entorno cruzado de desarrollo de software para Nintendo DS. Sin embargo, el
entorno creado no es un buen entorno de depuración cruzado para NDS, ya que no permite
ni depurar remotamente en la propia consola, ni depurar utilizando un emulador de DS en
la máquina host.
Zylin Embedded CDT
Zylin Embedded CDT8 es un plug-in de código abierto creado por Zylin AS Consulting que permite al depurador de Eclipse conectarse a un dispositivo remoto vı́a JTAG,
BDM, Ethernet o usando una conexión en serie (véase la figura 3.7).
Este plugin no es especı́ficamente para ARM. Puede ser usado con cualquier microprocesador empotrado que GDB sea capaz de soportar como MIPS, PowerPC o XScale,
entre otros.
Para que el depurador sea capaz de controlar el programa que se está depurando es
necesaria la colaboración de unas rutinas auxiliares, los cabos del depurador (gdb stubs).
Normalmente, estos cabos se ejecutan en la consola, combinados con el propio programa en
7 Sitio
8 Sitio
web de NDS Managedbuilder: http://snipah.com/
web de Zylin AS Consulting: http://opensource.zylin.com/embeddedcdt.html
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
24
Figura 3.7: Entorno conectado a un dispositivo remoto vı́a JTAG/BDM [12]
un único ejecutable. Sin embargo, esto suele imponer severas limitaciones a las capacidades
de depuración. Ası́, por ejemplo, en la Nintendo DS no se tendrı́a la capacidad de parar el
programa cuando se desee [27].
Para solucionar este problema de la depuración directa en la consola, se debe utilizar
un emulador de Nintendo DS que incorpore directamente los cabos del depurador.
En el entorno cruzado de desarrollo construido hasta este punto, no tiene integrado
ningún emulador de Nintendo DS. Por tanto, cada vez que se pretenda depurar un programa
utilizando un emulador, tal emulador tiene que ser arrancado y detenido manualmente. Es
decir, el entorno y el emulador son totalmente independientes entre sı́.
3.2.5.2.
VisualHAM
VisualHAM9 es un entorno de desarrollo integrado creado para el SDK de Game
Boy Advance llamado HAM. Esta disponible sólo para la plataforma Windows. En concreto, para Windows 2000 y para Windows XP. Alguna de las caracterı́sticas más destacadas
de VisualHAM son:
Sintaxis resaltada para código fuente escrito en C/C++, en lenguaje ensamblador o en
GNU Makefiles.
Función autocompletar en el código fuente.
9 Sitio
web de VisualHAM: http://www.console-dev.de/projects/page_visualham/
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
25
Salida de las herramientas redirigidas hacia la consola.
Sugerencias durante la escritura de código fuente.
3.2.6.
Emuladores
El término emulación se refiere a la capacidad que tiene un hardware o software
de reproducir el comportamiento de otro hardware o software diferente. Es posible utilizar
hardware para emular hardware o usar software para emular software. En este documento
se utilizará la palabra emulador para referirse a una aplicación software que emula a otro
hardware. En [20] se define el término emulador como:
“Un emulador es un programa que se ejecuta en un computador (sistema anfitrión del
emulador) y, allı́, se encarga de recrear el comportamiento de un computador diferente
(sistema objetivo del emulador)”
La ventaja de utilizar un emulador de Nintendo DS es que no se necesita tener ni
videoconsola ni cartuchos especiales. Sin embargo, las funcionalidades de la NDS que se
soportarán dependerá del emulador utilizado.
Existen multitud de emuladores heterogéneos de Nintendo DS. En las siguientes
secciones se comentarán los más relevantes.
3.2.6.1.
DeSmumE
DeSmuME10 es uno de los pocos emuladores de Nintendo DS libres, con disponibilidad del código fuente. Aunque tiene sus limitaciones, implementa un respetable número
de caracterı́sticas de la NDS, incluyendo el motor de gráficos 3D. Además, está disponible
para un amplio rango de plataformas.
Desde el punto de vista docente la caracterı́stica más sobresaliente de DeSmuME
es que implementa la interfaz con el depurador GDB (cabos del depurador o gdb stubs)
directamente en el propio emulador, sin necesidad de añadir ningún código adicional a los
programas [27].
Además estos cabos pueden habilitarse de manera independiente en cada uno de
los procesadores de la Nintendo DS. Para activar la interfaz con el depurador para el procesador ARM9 se empleará la opción –arm9gdb=puerto y para activar la interfaz con el
depurador para el procesador ARM7 se utilizará la opción –arm7gdb=puerto. En ambos
casos el puerto debe ser un número comprendido entre 1024 y 65535. Si se activan ambas
opciones será necesario utilizar puertos diferentes para cada procesador.
10 Sitio
web de DeSmuME: http://desmume.org/
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
26
Para plataformas GNU/Linux, DeSmuME se puede ejecutar con tres interfaces diferentes (desmume, desmume-cli y desmume-glade), cada una de las cuales proporciona
distintas funcionalidades.
3.2.6.2.
No$GBA
No$GBA (Nocash Game Boy Advance)11 es un emulador para GBA. También emula
la NDS con unos resultados muy aceptables. Sin duda se trata del simulador más fiable de
cuantos están disponibles libremente. Sin embargo, su principal carencia desde el punto de
visa docente es que no tiene soporte integrado para el depurador GDB, por lo que no es útil
para la depuración remota.
3.3.
Compilando para Nintendo DS
3.3.1.
Introducción
El software de la consola está preparado para leer un cartucho de memoria en la
memoria RAM principal y darle el control. Los cartuchos para ejecutar software casero
(R4, M3, CycloDS, SuperCard, etc. . . ) tienen un programa interno (navegador o browser)
que se comporta a su vez como cargador para otros programas. El proceso de carga se
produce de forma muy similar a como lo hace el firmware, pero esta vez el programa se
lee de una tarjeta de memoria Flash (SD, microSD, miniSD o CompactFlash) utilizando un
protocolo propio de cada fabricante a través del mismo bus serie SPI por el que se leen los
cartuchos comerciales. Es decir, a todos los efectos se comporta como si estuviera leyendo
un cartucho comercial, pero esta vez de un simple archivo escrito en una tarjeta de memoria
Flash. Por tanto, para poder programar la consola nuestro objetivo va a ser el de crear uno
de esos archivos (de extensión .nds) que emulan el contenido de la memoria ROM de un
cartucho comercial.
Para generar el ejecutable para la NDS partiendo del código escrito en C, se comienza con la generación de código objeto para el ARM7 y ARM9, con la ayuda del compilador
cruzado (arm-eabi-gcc). El código objeto generado tras la compilación será utilizado por
el montador (arm-eabi-ld aunque frecuentemente se utiliza desde el propio arm-eabi-gcc)
creando un archivo ejecutable para cada entorno de ejecución concreto, en este caso para el
ARM7 y ARM9.
Los archivos ejecutables responden a un formato estándar (denominado ELF) que
facilita la interacción con un sistema operativo o con herramientas de depuración. Sin em11 Sitio
web de No$GBA http://nocash.emubase.de/gba.htm
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
27
bargo, estos ejecutables contienen mucha más información aparte de las instrucciones y
datos del programa. Para reducir al mı́nimo las necesidades de memoria de la consola, se
extrae exclusivamente lo necesario para poder ejecutar el programa (instrucciones y datos)
utilizando la herramienta arm-eabi-objcopy para generar los archivos ejecutables reducidos .arm7 y .arm9. La herramienta ndstool combinará estos dos archivos ejecutables, y
opcionalmente otros datos (e.g. gráficos) en un único archivo con extensión .nds añadiendo
una cabecera descriptiva al comienzo. La herramienta dsbuild generará un archivo similar con extensión .ds.gba que permite arrancar el programa desde el Slot2 (compatible con
Game Boy Advance). Para ello añadirá una cabecerá distinta a la que se genera para DS,
además de añadir un programa cargador al principio.
En todo este proceso solo los archivos en lenguaje C (código fuente) podrı́an ser
reutilizables para otra plataforma distinta. El código fuente es portable siempre que utilice
un lenguaje y unas bibliotecas estándar. Sin embargo, no ocurre lo mismo con el código
objeto, que sı́ será dependiente de la arquitectura y del compilador empleado. En general
no es posible reutilizar código objeto ni siquiera entre dos compiladores distintos para la
misma arquitectura. Esto es debido a que frecuentemente difieren en la forma en que se
usan las caracterı́sticas del procesador para implementar las caracterı́sticas del lenguaje C.
3.3.2.
ABI
El ABI (Application Binary Interface) [5] para la arquitectura ARM es una colección
de estándares, algunos generales y otros especı́ficos de la arquitectura ARM, que regulan
la interacción entre archivos objeto o binarios, ası́ como con las herramientas de desarrollo
para el espectro de entornos de ejecución basados en ARM. El concepto de ABI se refiere
a:
Las especificaciones que un ejecutable debe satisfacer para poder ser ejecutado en un
entorno de ejecución especı́fico. Por ejemplo, el ABI de Linux para la Arquitectura
ARM.
Un aspecto particular de las especificaciones a las que se deben ajustar los archivos
objeto reubicables, producidos independientemente para que éstos puedan ser enlazados y ejecutados estáticamente. Por ejemplo, el ABI de C++ para la Arquitectura
ARM, el ABI de tiempo de ejecución para la Arquitectura ARM, el ABI de la Librerı́a
C para la Arquitectura ARM.
Esto permite que el código objeto generado tras la compilación sea portable a otros
sistemas que implementen el mismo ABI. Por lo tanto, si los compiladores siguen unas
determinadas reglas establecidas por el ABI se podrá garantizar la interoperabilidad.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.3.3.
28
EABI
Todos los fabricantes de microprocesadores publican documentos que describen el
convenio de paso de argumentos en las llamadas a procedimientos. ARM no es una excepción. En la figura 3.8 se muestra la estructura del ABI dominante en la arquitectura ARM,
el EABI:
Figura 3.8: ABI para la arquitectura ARM [5]
Las siglas EABI provienen de Embedded ABI, el ABI especı́ficamente diseñado para
sistemas empotrados. Se compone de un conjunto de documentos que especifica aspectos
especı́ficos del EABI:
El soporte básico de depuración.
El ABI para las llamadas a procedimientos (AAPCS).
El ABI para el manejo de excepciones.
El ABI genérico de C++ (definido por Intel), y su especialización para la arquitectura
ARM.
El formato estándar de ejecutables ELF, y su especialización para la arquitectura
ARM.
El formato genérico de datos para la depuración DWARF, y su especialización para la arquitectura ARM. Formato de las secciones del ejecutable que proporcionan
información al depurador.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
29
Formato y convenios utilizados en las bibliotecas estáticas y dinámicas, ası́ como el
soporte de ejecución.
Los convenios de la biblioteca estándar de C.
Todos estos documentos están accesibles en [2]. En general, se trata de documentos
cortos que definen de forma muy precisa los convenios del EABI. El siguiente apartado se
centra en el estudio del mecanismo de paso de parámetros, especificado en el AAPCS.
3.3.4.
AAPCS
El convenio empleado para el paso de parámetros entre funciones conforme al EABI
se recogen en [8]. Fundamentalmente contiene:
Restricciones impuestas al programa que llama a una función para pueda comenzar
la ejecución de dicha función.
Restricciones impuestas al código de la función respecto al estado que debe preservar
a lo largo de la ejecución (e.g. registros cuyo valor debe preservarse).
Convenios utilizados para transmitir los argumentos y recoger el valor de retorno.
Como todos los convenios de llamadas a procedimiento, el AAPCS tiene como principal criterio de diseño la eficiencia [28]. Además, el AAPCS está diseñado para soportar
los dos repertorios de instrucciones de los microprocesadores ARM: el modo ARM y el
modo Thumb. De hecho está especialmente diseñado para permitir la interoperabilidad de
funciones en modo ARM y funciones en modo Thumb.
3.3.4.1.
Alineamiento de datos
El AAPCS determina un conjunto de tipos básicos que corresponden más o menos a
los tipos básicos de C. En la tabla 3.2 se muestran los tamaños de cada tipo básico, ası́ como
los requisitos de alineamiento en bytes:
Que el alineamiento de un tipo de datos sea de N bytes quiere decir que las variables
de ese tipo solo pueden almacenarse comenzando en direcciones de memoria múltiplo de N.
Como se puede observar en la tabla 3.2, no es difı́cil recordar los alineamientos impuestos
por el EABI porque coinciden con el tamaño del tipo básico. Un char puede almacenarse en
cualquier posición de memoria, mientras que un short sólo puede almacenarse comenzando
en direcciones pares, y un int debe comenzar en direcciones múltiplo de 4.
Estos requisitos de alineamiento garantizan un buen compromiso entre velocidad
y consumo de memoria, e impiden tener que leer o escribir más palabras de las necesarias
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Categorı́a
Enteros
Coma flotante
Punteros
Tipo C
unsigned char
signed char
unsigned short
signed short
unsigned int
signed int
unsigned long long
signed long long
float
double
a datos
a código
Tamaño
1
1
2
2
4
4
8
8
4
8
4
4
30
Alineamiento
1
1
2
2
4
4
8
8
4
8
4
4
Tabla 3.2: Tamaño de los tipos de datos básicos
cuando se accede a una variable. Por ejemplo, si una variable de tipo int pudiera almacenarse
en cualquier dirección par serı́a posible almacenar un entero repartido entre dos palabras de
4 bytes. Por tanto cualquier acceso a esa variable requerirı́a acceder a ambas palabras.
El EABI permite que el orden de los bytes sea big-endian o little-endian. Esto se
debe a que la mayorı́a de los procesadores ARM pueden configurarse en cualquiera de los
dos modos. En el caso de la consola Nintendo DS, se limitará al estudio del orden littleendian, que es el seleccionado por defecto por DevkitPro, y el dominante en el mercado de
microprocesadores actual. La figura 3.9 muestra la disposición de las palabras en memoria
para cada una de estas ordenaciones:
Figura 3.9: Orden de los bytes en big-endian y en little-endian [8]
Se puede comprobar con un simple programa en C si un procesador está configurado
en modo little-endian o en big-endian.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
31
# i n c l u d e < s t d i o . h>
i n t main ( v o i d )
{
int i = 1;
char ∗p = ( char ∗ ) &i ;
i f ( p [ 0 ] == 1 )
p r i n t f ( "Little Endian\n" ) ;
else
p r i n t f ( "Big Endian\n" ) ;
return 0;
}
3.3.4.2.
Tipos compuestos
El AAPCS también define las reglas de alineamiento para los tipos compuestos. En
C hay tres tipos de tipos compuestos:
Las estructuras struct o agregados inhomogéneos. Permite agrupar diferentes componentes de tipos básicos o compuestos en un mismo tipo.
El alineamiento de las estructuras es el máximo de los alineamientos de sus componentes. El tamaño de las estructuras se redondea al múltiplo de su alineamiento más
pequeño que pueda contener todos sus componentes.
Los vectores o arrays, son una secuencia de objetos de un mismo tipo (agregación
homogénea).
El alineamiento de los vectores es el mismo que el de su tipo base. El tamaño es N
veces el de su tipo base, siendo N el número de elementos del vector.
Los tipos union, que tienen una sintaxis similar a las estructuras, pero en ellas todos
los elementos se almacenan en la misma dirección de memoria.
El alineamiento de las uniones es el máximo de los alineamientos de sus componentes. El tamaño de las uniones se redondea al múltiplo de su alineamiento más pequeño
que pueda contener el mayor de sus componentes.
La importancia de conocer estas reglas no debe subestimarse, pues influye significativamente en el consumo de memoria. Se pondrá como ejemplo la siguiente declaración
simple en C:
1
struct MyData {
2
char c ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3
double d ;
4
int s ;
5
32
};
6
7
int main ( void ) {
8
char c ;
9
struct MyData data [5];
10
...
Aplicando las reglas del EABI, el alineamiento del vector data es el de su tipo base
(struct MyData). El alineamiento del tipo struct MyData es el máximo de los alineamientos
de sus componentes. Esto es 8, el alineamiento correspondiente al elemento double d.
Por otro lado, el tamaño de struct MyData tiene que ser un múltiplo de 8 que sea
capaz de contener los tres elementos con sus respectivas condiciones de alineamiento. Ya
sabemos que la estructura comienza en una posición de memoria múltiplo de 8. Por tanto,
el caracter c se puede situar inmediatamente al comienzo. Sin embargo, el elemento d debe
comenzar en una posición múltiplo de 8. Si c está ya en una posición múltiplo de 8 tendremos que introducir 7 bytes de relleno (padding) para poder situar el elemento d cumpliendo
las reglas de alineamiento.
El entero s puede situarse inmediatamente a continuación, puesto que d está alineado
a 8 y ocupa 8 bytes. Eso indica que la siguiente posición disponible está alineada a 8 y, por
tanto, también está alineada a 4. Finalmente, para que la estructura tenga un tamaño múltiplo
de 8 se tiene que añadir otros 4 bytes de relleno (padding).
El resultado se muestra en la figura 3.10:
Figura 3.10: Alineamiento del tipo compuesto MyData [28]
Conociendo las reglas de alineamiento del EABI, se pueden almacenar los mismos
datos en una estructura equivalente que solo ocupe el 50 % de la memoria. En la figura 3.11
se muestra como quedarı́a la memoria:
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
33
Figura 3.11: Alineamiento de una estructura equivalente a MyData [28]
Se puede compobar de una manera sencilla cómo el compilador de C fuerza el alineamiento impuesto por el EABI. Basta con crear un pequeño programa en C que defina
variables consecutivas de distintos tipos, e imprima las direcciones y los tamaños de cada
una.
3.3.4.3.
Paso de argumentos
Los procesadores ARM disponen de 16 registros (r0 a r15) que son visibles tanto
en el modo ARM como en el modo Thumb. La mayorı́a de ellos son de propósito general,
aunque los 2 superiores cumplen funciones especiales dentro de la arquitectura: el registro
r15 es el contador de programa (PC), y el registro r14 se utiliza en la implementación de las
llamadas a subrutinas para almacenar temporalmente la dirección de retorno (LR). Además,
dispone de un registro de estado (CPSR).
El resto de registros son de propósito general, pero el ABI restringe su uso de acuerdo
con la tabla 3.3:
3.3.4.3.1.
LLamadas a función y registro IP
Los procesadores ARM disponen de una instrucción bl (branch and link, saltar y
enlazar) para realizar los saltos a subrutinas. Esta instrucción salta a la dirección que se
indica como único operando pero antes de alterar el contador de programa preserva su valor
en el registro de enlace (lr, link register). El bit menos significativo del lr se utiliza para
almacenar el repertorio de instrucciones en el que se encuentra el procesador en el momento
del salto (1 si está en modo Thumb y 0 si está en modo ARM).
La instrucción bl no tiene acceso a todo el rango de direcciones. Esto implica que en
algunos casos el montador (linker) deberá introducir instrucciones de puente para permitir
los saltos más allá del espacio que puede direccionar bl. El EABI da libertad al montador
para introducir las instrucciones que sean necesarias, siempre que se se preserve el estado
del procesador (incluyendo el CPSR) salvo el registro r12 (intra-procedure call register,
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Registro
r15
r14
r13
r12
r11
r10
Sinónimo
r9
v6
r8
r7
r6
r5
r4
r3
r2
r1
r0
v5
v4
v3
v2
v1
a4
a3
a2
a1
Especial
PC
LR
SP
IP
v8
v7
SB
TR
34
Rol en AAPCS
Contador de programa
Registro de enlace
Puntero de pila
Registro temporal intra-llamada
Registro de variable 8
Registro de variable 7
Platform register
Registro de variable 5
Registro de variable 4
Registro de variable 3
Registro de variable 2
Registro de variable 1
Argumento/registro temporal 4
Argumento/registro temporal 3
Argumento/registro temporal 2
Argumento/registro temporal 1
Tabla 3.3: Registros de ARM y su uso en AAPCS
IP). Dicho de otro modo, el compilador debe ser consciente de que el registro r12 puede
ser modificado en cualquier instrucción de salto a funciones externas, o en los retornos de
subrutinas. Con frecuencia en la práctica significa que este registro no está disponible para
uso general salvo para cálculos temporales. No hay garantı́as de que se preserve su valor al
realizar una llamada a función.
El AAPCS reserva los primeros cuatro registros (r0 a r3) para el convenio de paso
de argumentos, incluyendo el paso de los valores de retorno. El resto, entre r4 y r11, se
pueden emplear para almacenar variables.
Los registros reservados para el paso de argumentos pueden utilizarse para cualquier
otro fin una vez han cumplido con su propósito. Es decir, no hay garantı́as de que se preserve
su valor tras una llamada a función. En cambio, los registros r4 a r11 pueden contener
variables del programa que llama, por lo que deben preservarse.
Es importante señalar que esto no supone en modo alguno una limitación en el número de registros que pueden utilizarse en una función. Por ejemplo, si una función quisiera
almacenar en el registro r4 una variable determinada12 lo único que exige el AAPCS es que
primero debe preservar el contenido del registro en la pila y restaurarlo antes de volver de
la función.
12 Las variables automáticas suelen asignarse a registros cuando se utilizan con mucha frecuencia para evitar
excesivos accesos a la memoria. Por ejemplo, un contador de un bucle.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.3.4.3.2.
35
Restricciones de la pila
El registro r13 se utiliza como puntero de pila (SP), es decir, contiene la dirección de
la primera posición libre de la pila. Además, el EABI especifica que la pila crece hacia posiciones de memoria más bajas (full-descending). Asimismo, el compilador debe garantizar
que:
En todo momento el puntero de pila debe estar alineado al lı́mite de palabra de 4
bytes.
En un interfaz público. Por ejemplo, cuando se llama a una función externa o se
retorna de una función externa, el puntero de pila debe alinearse al lı́mite de doble
palabra (8 bytes).
El alineamiento extra en un interfaz público es conveniente, puesto que de esta forma
el compilador puede asignar el marco de pila (stack frame) de la función sin preocuparse
de ningún detalle de alineamiento previo. Es conveniente mencionar que 8 es el máximo
requisito de alineamiento que puede tener cualquier tipo de datos en el EABI.
3.3.4.3.3.
Valor de retorno
Justo antes de realizar la llamada a función, el compilador debe generar las instrucciones necesarias para preparar el valor de retorno. En principio, como ocurre en muchas
otras arquitecturas, el AAPCS intenta que el valor de retorno se devuelva en el registro r0,
que una vez que ha cumplido su misión en el paso de argumentos puede reutilizarse para
este fin. Sin embargo no siempre va a ser posible:
Si el valor de retorno es de un tipo básico o compuesto de tamaño menor o igual a 4
bytes (char, short, int, long, float) entonces se retorna en r0.
Si es necesario se expande a 4 bytes manteniendo el valor. Por ejemplo, un char con
el valor −19 (0xED, en hexadecimal) pasará de ocupar un byte a ocupar los 4 bytes
de r0 (0xFFFFFFED, en hexadecimal). Para ello, el compilador deberá utilizar la
operación de extensión de signo.
Los tipos compuestos pequeños se retornan en r0 sin extensión de ningún tipo. La
disposición de los datos es la misma que tendrı́a en memoria.
Si el valor de retorno es de un tipo básico de 8 bytes (double, long long) entonces se
retorna en r0 y r1.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
36
Si el valor de retorno es de un tipo compuesto de más de 4 bytes o de tamaño indeterminado, entonces el resultado se devolverá en un área de memoria (pila) determinada
por el que llama. La dirección de esta área de memoria se pasa a la función como un
argumento extra.
El compilador debe comprobar, antes de nada, el valor de retorno, porque es posible
que encaje en el último caso contemplado. En ese caso, debe pasar un argumento extra a la
función.
3.3.4.3.4.
Paso de argumentos
El AAPCS permite pasar argumentos a funciones en los registros r0 a r3 y en la
pila. Si la función tiene pocos argumentos podrá utilizar solo los registros y no tendrá que
realizar ningún acceso a la memoria, lo que incrementa notablemente el rendimiento.
La asignación de parámetros a registros y pila se realiza aplicando un algoritmo en
tres etapas. Se trata de un algoritmo que ejecuta el compilador en cada llamada a función.
A pesar de su relativa complejidad, el resultado es un puñado de lı́neas de código muy
eficientes.
La etapa de inicialización se realiza una sola vez antes de procesar los argumentos.
Se utilizan un par de contadores que llevan la cuenta de cuál es el primer registro libre
para la asignación de un argumento (SiguienteRegistro, que se inicializa a r0) y cuál
es la siguiente posición de la pila libre para asignar argumentos (SiguienteArgEnPila,
que se inicializa a SP).
Si la función devuelve un resultado en memoria, la dirección del resultado se escribe
en r0 y SiguienteRegistro pasa a ser r1.
La etapa de pre-padding y extensión de argumentos se ejecuta por cada argumento
después de la inicialización. Básicamente, el objetivo de esta etapa es hacer que los
argumentos ocupen un número entero de palabras.
• Si se trata de un argumento compuesto y no se puede determinar el tamaño por
la función, se copia en memoria y se reemplaza por un puntero a esta copia.
• Si es de un tipo básico de menos de 4 bytes, se extiende a 4 bytes.
• Si es de un tipo compuesto cuyo tamaño no es múltiplo de 4 bytes, se redondea
a múltiplo de 4 bytes más cercano.
Por último, la etapa de asignación de argumentos a registros y pila también se ejecuta
iterativamente por cada argumento.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
37
• Si el argumento requiere 8 bytes asigna a SiguienteRegistro el siguiente registro
par. Es decir, los argumentos de 8 bytes se pueden asignar a r0 y r1, o a r2 y r3,
pero no a r1 y r2.
• Si el tamaño del argumento no supera el tamaño de los registros disponibles para
paso de argumentos, entonces se copia a registros empezando en SiguienteRegistro, y se incrementa SiguienteRegistro hasta el siguiente registro libre.
• Si no cabe en los registros disponibles pero SiguienteArgEnPila contiene SP, es
decir, todavı́a no se ha asignado ningún argumento a la pila, entonces se divide
el argumento entre registros (primera parte) y pila e incrementa SiguienteArgEnPila a la siguiente posición libre.
• En cualquier otro caso copia el argumento a SiguienteArgEnPila e incrementa
SiguienteArgEnPila a la siguiente posición libre.
3.3.5.
Explorando el ABI con GDB y DeSmuME
El depurador GDB es una excelente herramienta para explorar el ABI y para analizar
las instrucciones que genera el compilador para llamar a una función. De modo ilustrativo,
en esta sección se mostrará el uso de la interfaz gráfica KDbg.
Para evitar optimizaciones inesperadas que eliminen completamente las llamadas a
función, es muy conveniente poner la definición de las funciones en unidades de compilación separadas.
Se utilizará la plantilla de programa para el ARM9 incluida con DevkitPro:
1
2
3
$ cp -r / opt / devkitPro / examples / nds / templates / arm9 prueba
$ cd prueba
$ rm source /*
Ahora se añaden los archivos fuente para este ejemplo en el directorio source. El
programa principal simplemente llama a la función prueba.
1
// Archio source / main . c
2
void prueba () ;
3
int main () {
4
prueba () ;
5
return 0;
6
}
La función prueba está definida en otro archivo independiente y simplemente realiza
dos llamadas a función diferentes.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
1
// Archivo source / prueba . c
2
# include ‘‘ fn . h ’ ’
38
3
4
void prueba () {
5
MyData ret = fnA (1.5 , ‘‘ Hola ’ ’) ;
6
fnB ( ret ) ;
7
}
Las funciones están declaradas en un archivo de cabecera junto a los tipos que utilizan.
1
// Archivo source / fn . h
2
typedef struct Mydata_ {
3
double d ;
4
char s [10];
5
} MyData ;
6
7
MyData
fnA ( double d , char data []) ;
8
void
fnB ( MyData md ) ;
Por último la implementación de las funciones se realiza en un archivo C independiente para que el compilador no pueda optimizar las llamadas a función.
1
// Archivo source / fn . c
2
# include ‘‘ fn . h ’ ’
3
# include < string .h >
4
5
MyData fnA ( double d , char data []) {
6
MyData md ;
7
md . d = d ;
8
strcpy ( md .s , data ) ;
9
return md ;
10
}
11
12
void fnB ( MyData md ) {
13
md . d = 1.0;
14
md . s [0] = ’ \0 ’;
15
}
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
39
En este ejemplo se utilizará el reperterio de instrucciones ARM, dejando a un lado
el repertorio de instrucciones Thumb. Por este motivo se deberá comentar la siguiente lı́nea
en el archivo Makefile:
1
$ ARCH := - mthumb - mthumb - interwork
Para comentar la lı́nea basta con añadir el carácter al comienzo. Lo siguiente será crear
las dos variables de entorno siguientes, sin las cuales la compilación no podrı́a realizarse.
1
2
$ export DEVKITPRO =/ opt / devkitPro
$ export DEVKITARM =/ opt / devkitPro / devkitARM
Una vez realizado estos cambios, ya se puede compilar.
1
$ make
En otro terminal se ejecuta el depurador. En este caso se utilizará kdbg:
1
$ kdbg prueba . elf
La primera vez que se ejecute KDbg, se debe configurar de tal modo que se cambie
el GDB a la versión de DevkitPro. Para ello, en el menú Settings ⇒ Opciones globales se
debe cambiar la opción Cómo iniciar GDB a arm-eabi-gdb -fullname -nx.
Inmediatamente después, se abre el archivo main.c y se establece un punto de interrupción en la sentencia “prueba();”.
A continuación, se cierrar KDbg y se vuelve a arrancar, pero esta vez conectando
con el emulador DeSmuME:
1
2
$ desmume -- arm9gdb =7777 prueba . nds &
$ kdbg -r :7777 prueba . elf
A continuación, se pulsa el botón Ejecutar. En la figura 3.12 se muestra el resultado que se deberı́a obtener. Se puede observar que la ejecución ha alcanzado el punto de
interrupción establecido anteriormente.
Con el botón de ejecución paso a paso (step into by instruction) se puede entrar en
cualquier función. En el menú View ⇒ Registros puede analizarse el valor de los registros
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
40
Figura 3.12: La ejecución alcanza el punto de interrupción establecido
del procesador. En la ventana superior derecha están disponibles las variables del marco de
pila actual.
KDbg es especialmente aconsejable para aprender cómo funciona el ABI, ya que
tiene la capacidad de ver el código ensamblador equivalente a cada sentencia C. Para ello,
se debe pulsar simplemente sobre los signos + que preceden cada lı́nea. En la figura 3.13 se
muestra el código ensamblador equivalente a la sentencia alcanzada durante el proceso de
depuración.
Con un conocimiento superficial de las instrucciones y viendo su efecto sobre los
registros y sobre la pila, es posible entender perfectamente el EABI.
3.4.
Gráficos con Nintendo DS
3.4.1.
Introducción
Experimentar con gráficos en la consola Nintendo DS proporciona la posibilidad de
obtener una visión más concreta de cómo el procesador interactúa con dispositivos hardware
como, por ejemplo, el hardware de video. La representación de gráficos plantea el reto de
poner en práctica los conocimientos adquiridos sobre la organización de la memoria, para
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
41
Figura 3.13: Exploración del ABI con KDbg
que se pueda ası́ hacer un uso eficiente de la misma en base a las reglas establecidas por el
ABI [26].
El hardware de video de la Nintendo DS se compone de dos núcleos gráficos 2D,
uno principal o main y otro secundario o sub, diferenciados en que el motor principal puede
renderizar tanto la memoria de video virtual sin utilizar el motor 2D, como mapas de bits
de 256 colores, ası́ como utilizar el motor 3D para el renderizado de alguno de sus fondos.
Pero, ¿qué es un fondo? El concepto de fondo es básico para comprender cómo funcionan
los modos de video de la Nintendo DS. Se puede entender como un concepto equivalente
al de capa o layer, utilizado por algunas aplicaciones de diseño gráfico para facilitar la
composición de una imagen a partir de la superposición del contenido de las capas. Los
núcleos gráficos de la Nintendo DS disponen de cuatro fondos, etiquetados como BG0,
BG1, BG2 y BG3, cuya configuración dependerá del tipo de gráfico que se represente.
Un modo gráfico básicamente agrupa un conjunto de configuraciones para cada uno
de los fondos. En la tabla 3.4 se resumen los modos disponibles para el núcleo principal y el
secundario. Los seis primeros modos, Mode 0 a Mode 5, son comunes para los dos núcleos.
Además, el núcleo principal cuenta con el Mode 6 y con el modo framebuffer.
La tabla se compone básicamente de tres tipos diferentes de configuraciones para
los fondos 2D, que son Text, Rotation y Extended Rotation y el modo framebuffer que pinta
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
42
Main 2D Engine
Mode
Mode 0
Mode 1
Mode 2
Mode 3
Mode 4
Mode 5
Mode 6
Framebuffer
BG0
BG1
BG2
BG3
Text/3D Text
Text
Text
Text/3D Text
Text
Rotation
Text/3D Text
Rotation
Rotation
Text/3D Text
Text
Extended
Text/3D Text
Rotation
Extended
Text/3D Text
Extended
Extended
3D
Large Bitmap
Direct VRAM display as a bitmap
Sub 2D Engine
Mode
Mode 0
Mode 1
Mode 2
Mode 3
Mode 4
Mode 5
BG0
Text
Text
Text
Text
Text
Text
BG1
Text
Text
Text
Text
Text
Text
BG2
Text
Text
Rotation
Text
Rotation
Extended
BG3
Text
Rotation
Rotation
Extended
Extended
Extended
Tabla 3.4: Modos gráficos para el núcleo principal y el secundario [21]
la imagen directamente sin utilizar fondos. A los modos Text también se les llama modos
teselados, y a los modos Rotation también se les conoce como modos Rotoscale.
3.4.2.
Interacción con los periféricos
Como ya se sabe de apartados anteriores, la consola Nintendo DS dispone de una
amplia variedad de periféricos. Estos periféricos se engloban dentro del sistema de entrada
y salida, que constituye junto al procesador y la memoria uno de los elementos básicos
de la estructura de un computador. La comunicación con el mundo exterior y la interacción
computador-usuario es posible gracias al sistema de entrada-salida. Si se vuelve al programa
“Hello Mario” que se realizó anteriormente, se puede ver que ese programa ya era capaz de
interactuar con el usuario a través de la pantalla de la Nintendo DS, mostrando el mensaje
“Hello Mario”. La pantalla es un claro ejemplo de periférico de salida. Mostrar un mensaje
a través de ella es posible gracias al empleo de la función “printf()”, que pertenece a la
biblioteca de entrada-salida estándar (stdio.h) del lenguaje C y que se incluı́a al comienzo
del fichero fuente.
Los periféricos de entrada-salida se comunican con el procesador y la memoria a
través de los buses del sistema (direcciones, datos y control). Debido a la gran variedad de
periféricos existente, estos suelen comunicarse con el procesador y la memoria a través de
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
43
controladores de entrada-salida. De esta forma, los controladores actúan de interfaz, y la comunicación y el control del periférico es posible gracias a una serie de registros accesibles
para el procesador. Ası́, cada periférico se controla mediante el uso de un conjunto de registros de control, datos y estado13 . Tı́picamente, se debe configurar el periférico escribiendo
en uno o varios registros de control, y se puede conocer su estado simplemente leyendo un
registro de estado. En la figura 3.14 se puede ver gráficamente el funcionamiento de todo
este sistema de entrada-salida.
Figura 3.14: Conexión de los periféricos de entrada-salida con el computador [26]
Los registros de datos permiten transferir datos a los periféricos, aunque, como se
verá, es mucho más frecuente transmitir datos a través de una zona de memoria compartida
entre el periférico y el procesador.
Escribir y leer de estos registros en la Nintendo DS es muy sencillo. Esta consola
utiliza la técnica de correspondencia en memoria para comunicación con los dispositivos
(memory mapped devices). Esta técnica se basa en tratar los registros de los dispositivos como si se tratara de direcciones de memoria convencionales. Por ejemplo, la dirección 0x4000304 corresponde con el registro de control de alimentación de los periféricos
(REG POWERCNT). Cada vez que el procesador escribe en esa dirección de memoria,
está escribiendo en el registro de control, y cada vez que lee esa posición de memoria,
está realmente leyendo el registro. Desde el punto de vista del procesador, no es posible
distinguir si lee o escribe de memoria o de registros de dispositivos. En el caso de la Nintendo DS, para el procesador ARM9 los dispositivos de entrada y salida están mapeados en
13 No se deben confundir estos registros, que controlan los periféricos, con los registros de propósito general
que contiene el procesador. Los registros del procesador actúan como almacenamiento ultra-rápido mientras
que los registros de los periféricos simplemente actúan como interfaz con el procesador.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
44
memoria en la zona de direcciones comprendida entre la posición 0x04000000 y la posición
0x04FFFFFF.
El registro de control de energı́a REG POWERCNT, mencionado anteriormente, es
de 16 bits. Se puede observar en la tabla 3.5 para qué sirven y cómo se utilizan sus principales bits.
Bit
Sı́mbolo
Descripción
0
1
2
3
9
15
POWER LCD
POWER 2D A
POWER MATRIX
POWER 3D CORE
POWER 2D B
POWER SWAP LCDS
Encender las pantallas LCD
Activar procesador 2D principal
Matriz de transformación 3D
Activar procesador 3D
Activar procesador 2D secundario
Intercambia pantallas
Tabla 3.5: Registro de control de energı́a REG POWERCNT
De esta forma, si se quisiera encender las pantallas LCD y activar el procesador 2D
principal de la consola, bastarı́a con utilizar la siguiente instrucción:
1
REG_POWERCNT = POWER_LCD | POWER_2D_A ;
3.4.3.
Modo framebuffer
La principal peculiaridad de este modo de representación es que la pantalla se mapea directamente a la memoria, sin utilizar el motor de renderizado. De forma que lo que
se escribe en memoria es lo que se muestra. La pantalla se compone de 49152 pixels, organizados en 192 lı́neas de 256 pixels cada una, donde a su vez, el contenido de cada pixel
representa un color en formato RGB de 16 bits.
El formato RGB de 16 bits para especificar el color se representa como una mezcla
de una cantidad determinada del color rojo (R), verde (G) y azul (B), dedicando 5 bits
para determinar esa cantidad: 0 (ausencia de color) y 31 (máximo color). La librerı́a libnds
proporciona la macro RBG15 para facilitar la definición de colores. Es suficiente con indicar
la cantidad de cada uno de ellos, en un rango de 0 a 31, para obtener el color en formato
RGB de 16 bits. En la tabla 3.6 se muestran algunos ejemplos de colores en este formato.
El uso de esta macro simplifica la tarea de dibujado en la pantalla, ya que únicamente hay que asignar pixel a pixel el valor correspondiente al color que se desea pintar. Sin
embargo, también puede ocurrir que lo que se desee pintar en pantalla sea una imagen existente, en cuyo caso la imagen debe venir descrita como un mapa de bits, con profundidad de
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
RGB15
RGB15(31,0,0)
RGB15(0,31,0)
RGB15(0,0,31)
RGB15(0,0,0)
RGB15(31,31,31)
RGB15(31,31,0)
RGB15(0,31,31)
RGB15(31,0,31)
45
Color
Rojo
Verde
Azul
Negro
Blanco
Amarillo
Cyan
Magenta
Tabla 3.6: Colores en formato RGB de 16 bits
16 bits, para adaptarse a la configuración del modo framebuffer. A continuación, se describen de manera más detallada estas dos formas de representación para el modo framebuffer,
ası́ como otras cuestiones a tener cuenta a la hora de utilizar este modo.
3.4.3.1.
Preparando el modo framebuffer
El modo framebuffer admite cuatro tipos de configuración, que reciben el nombre de
FB0, FB1, FB2 o FB2 y que básicamente establecen la zona de memoria cuyo contenido se
va a volcar en la pantalla (véase tabla 3.7).
Modo
FB0
FB1
FB2
FB3
Memoria
VRAM A
VRAM B
VRAM C
VRAM D
Tabla 3.7: Posibles configuraciones del modo framebuffer
Antes de poder cargar los datos en memoria, se tiene que especificar el modo seleccionado, para lo cual se utiliza el registro REG DISPCNT. Este registro, de 31 bits, controla
los modos y fondos activos en la pantalla de la consola. En la tabla 3.8 se explica cuál es la
utilidad de los bits más importantes de este registro.
Los primeros 15 bits actúan de la misma manera que lo hacı́an en la GBA. A continuación, se muestra un ejemplo de funcionamiento de este registro.
1
REG_DISPCNT = MODE_FB0 ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Bit
0-2
Sı́mbolo
MODE x 2D
3
ENABLE 3D
8
9
10
11
12
13
14
15
DISPLAY BG0 ACTIVE
DISPLAY BG1 ACTIVE
DISPLAY BG2 ACTIVE
DISPLAY BG3 ACTIVE
DISPLAY SPR ACTIVE
DISPLAY WIN0 ON
DISPLAY WIN1 ON
DISPLAY SPR WIN ON
17 - 19
MODE FBx
46
Descripción
Especifica el modo gráfico. 0 ≤ x ≥ 5
Especifica el modo 3D o 2D para BG0.
(0 = 2D; 1 = 3D)
Activa el renderizado de BG0
Activa el renderizado de BG1
Activa el renderizado de BG2
Activa el renderizado de BG3
Permite el uso de sprites
Activa el uso de Window0
Activa el uso de Window1
Activa el uso de Sprite Window
Activa el modo de video FB0, FB1, FB2
o FB3. 0 ≤ x ≥ 3
Tabla 3.8: Registro de control de pantalla REG DISPCNT [15]
En este ejemplo, al especificar el modo de video, indirectamente se está especificando la zona de memoria donde se deberán escribir los datos que se van a mostrar en la
pantalla. En base a la lı́nea anterior, que selecciona el modo FB0, el motor gráfico trabajará con los datos del banco de memoria VRAM A. Sin embargo, para poder utilizar los
bancos de memoria es necesario que éstos estén habilitados y configurados según su finalidad. Como se muestra en la siguiente lı́nea de código, el banco A mapea directamente su
contenido a la pantalla:
1
VRAM_A_CR = VRAM_A_ENABLE | VRAM_A_LCD ;
Una vez se ha especificado el modo y se ha habilitado la zona de memoria donde
se escribirán los datos, el siguiente paso consiste en escribir en la memoria el valor que se
asignará a cada uno de los pixels de la pantalla, bien mediante una asignación manual, utilizando la macro RGB15, o escribiendo los datos correspondientes a una imagen especı́fica.
3.4.3.2.
Mostrando imágenes de archivo
Una vez que ya se ha configurado el modo de vı́deo, el siguiente paso consiste en
transferir los datos que se van a mostrar. Dado que el modo framebuffer no utiliza fondos ni
motor de renderizado, la tarea de representación quedará reducida a transferir al banco de
memoria correspondiente los datos del gráfico a mostrar. Como se describirá a continuación,
será necesario convertir esa imagen en un mapa de bits.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
47
La conversión de imágenes se realiza con la herramienta grit, que ya viene integrada en devkitPro. Por cada imagen a convertir existirá un archivo con extensión .grit, que
contendrá las opciones especı́ficas para la generación de los datos convertidos. Para más
información sobre las diferentes opciones disponibles se puede ejecutar en un terminal:
1
$ grit -- help
Suponiendo que el nombre de la imagen a mostrar es wallpaper.png, se tendrá que
editar un archivo de texto, con el mismo nombre que la imagen y con extensión .grit. Las
opciones de conversión del modo framebuffer que se deben añadir son -gb y -gB16. Se debe
escribir una opción por lı́nea. La primera opción indica que el formato de la conversión es
un mapa de bits y la segunda opción, que tiene una profundidad de 16 bits por pixel.
Una vez se ha ejecutado grit, se generan los datos de la conversión en un archivo que
contiene el vector de datos correspondiente al mapa de bits de la imagen especificada. El
formato del archivo de salida se puede ajustar a múltiples formatos y puede ser escogido por
el usuario. La opción por defecto es generar los datos en un archivo en lenguaje ensamblador
para ARM (archivo .s) y declarar estos datos en un archivo de cabecera (archivo .h) .
Una vez que se dispone de la imagen, en el formato adecuado, el siguiente paso
consiste en trasnferir los datos correspondientes a la memoria. Para ello, será necesario
haber incluido el archivo de cabecera que contiene la declaración del vector de datos de la
imagen. El código para cargar una imagen de archivo en la pantalla quedarı́a de la siguiente
manera:
1
# include < nds .h >
2
# include " wallpaper . h "
3
4
int main ( void ) {
5
REG_DISPCNT = MODE_FB0 ;
6
VRAM_A_CR = VRAM_ENABLE | VRAM_A_LCD ;
7
dmaCopy ( wallpaperBitmap , VRAM_A , 256*192*2) ;
8
for (;;)
swiWaitForVBlank () ;
9
return 0;
10
11
}
Como se puede observar, mediante la función dmaCopy el vector de datos se copia al banco de memoria que está mapeado a la pantalla. En apartados posteriores de este
documento se explica más detalladamente el proceso de transferencia de datos.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.4.3.3.
48
Dibujando pixels
Otra forma alternativa de representar gráficos en modo framebuffer consiste en componer una imagen a partir de la asignación de colores a cada uno de los pixels que componen
la pantalla.
Al igual que en el caso anterior, el primer paso consistirá en especificar el modo
de video utilizado, que para el caso del framebuffer, puede variar entre cualquiera de los
cuatro disponibles, FB0, FB1, FB2 o FB3. A cada uno de los modos le corresponde un
banco de memoria especı́fico. Para el ejemplo siguiente, se utilizará el modo FB0 al que
le corresponde el banco VRAM A, cuyo contenido se pintará directamente en la pantalla
LCD.
1
REG_DISPCNT = MODE_FB0 ;
2
VRAM_A_CR = VRAM_ENABLE | VRAM_A_LCD ;
El siguiente paso difiere del apartado anterior, donde se hacı́a una transferencia directa de un vector de datos, correspondiente a la imagen a dibujar. En este caso, habrá que
utilizar un bucle que recorra la región de memoria correspondiente, para escribir uno por
uno el valor del color que se desee asignar a cada uno de los pixels que componen la pantalla. La macro RGB15 permite obtener ese valor, indicando la cantidad de color rojo, verde
y azul de la que se compone el color que se pintará en cada pixel.
Si se desea mostar un gradado vertical de color negro a azul, que ocupe toda la
pantalla, se deberá ir incrementando la cantidad de azul a medida que se vaya descendiendo
en la pantalla. El color negro se obtiene mediante la ausencia de color de las tres tonalidades.
Por lo tanto, mediante RGB15(0,0,0) se obtiene el valor correspondiente.
Dicho de otra forma, el nivel de color azul depende exclusivamente de la lı́nea que
se esté pintando. Por tanto, basta con recorrer todos los puntos de la pantalla y pintarlos con
el color correspondiente a la lı́nea.
1
# include < nds .h >
2
# include < stdio .h >
3
4
int main ( void )
5
{
6
consoleDemoInit () ;
7
printf ( " Ejemplo de frame buffer " ) ;
8
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
49
// Configuracion de pantalla principal
9
REG_DISPCNT = MODE_FB0 ;
10
// Framebuffer
11
12
// Configuracion de bloque A de la VRAM
13
VRAM_A_CR = VRAM_ENABLE | VRAM_A_LCD ;
14
15
int lin , col ;
16
unsigned short * fb = VRAM_A ;
17
for ( lin = 0; lin < 192; lin ++)
18
for ( col = 0; col < 256; col ++)
19
fb [ lin *256 + col ] = RGB15 (0 ,0 , lin
20
*32/192) ;
21
return 0;
22
23
}
En la lı́nea 17, se define un puntero de tipo entero sin signo de 16 bits y que apunta a
la dirección 0x6800000, que es el valor de la macro VRAM A, el comienzo de la memoria
del framebuffer FB0. El hecho de definir el puntero a la memoria como unsigned short, es
porque en este modo se necesita direccionar la memoria pixel a pixel de la pantalla. Cada
pixel ocupa 16 bits (5 bits por componente y el bit más significativo sin usar).
En la lı́nea 21, se utiliza el puntero fb para acceder al pixel correspondiente a la
lı́nea lin y a la columna col. Dado que los pixels se almacenan por lı́neas y cada lı́nea tiene
256 puntos, se tendrá que multiplicar el número de lı́nea por 256 para ir al comienzo de la
fila y sumar el número de columna para llegar al pixel correspondiente de la pantalla. La
asignación del color a cada pixel consiste en obtener el valor del color en formato RGB15,
y asignarlo a la posición de memoria del pixel correspondiente.
3.4.3.4.
Limitaciones de la pila
Una de las limitaciones más importantes de la consola Nintendo DS, en comparación
con los ordenadores personales, es que la memoria se convierte en un recurso mucho más
limitado. Se requiere un uso más restrictivo para que esta no se agote de manera prematura
o inesperada. La pila, al ser una zona de la memoria, tampoco será un recurso ilimitado. No
hacer un uso eficiente de la misma, puede llevar a situaciones de desbordamiento cuando se
intenta mantener en la misma una cantidad de datos superior al espacio fı́sico disponible.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
50
Una vez más, conocer el ABI resulta fundamental para poder llevar a cabo una gestión eficiente de la pila. El ABI, en relación con la pila, establece que las variables automáticas se almacenan en la pila, por lo que habrá que hacer un uso razonable de las variables
automáticas si no se desea desbordar la pila. El primer paso será determinar la cantidad de
espacio reservado para la pila, con el objetivo de evitar que ese espacio se desborde.
El linker o montador no sólo está encargado de combinar el código objeto generado
tras la compilación de cada uno de los archivos de código fuente, sino que también se encarga de determinar la localización fı́sica en el hardware del código y datos de una aplicación.
En cuanto a la localización fı́sica de la pila, la consola Nintendo DS la ubica en una región
especial de memoria conocida como DTCM.
La DTCM (Data Tightly Coupled Memory) es un tipo de memoria de datos muy
rápida, de 16 KiB de tamaño, que se encuentra dentro del procesador ARM9. El tamaño de
esta memoria se debe tener en cuenta, ya que este es el lı́mite fı́sico para la pila. Por lo tanto,
se debe prestar especial atención cuando se trabaje con variables automáticas para que estas
no superen los 16KiB disponibles, como es el caso del código que se lista a continuación:
1
# include < nds .h >
2
# include < stdio .h >
3
4
int main ( void )
5
{
6
consoleDemoInit () ;
7
printf ( " Ejemplo de frame buffer " ) ;
8
9
// Configuracion de pantalla principal
10
REG_DISPCNT = MODE_FB0 ;
// Framebuffer
11
// Configuracion de bloque A de la VRAM
12
VRAM_A_CR = VRAM_ENABLE | VRAM_A_LCD ;
13
14
int i =0 , j =0;
15
uint16 * color = VRAM_A ;
16
uint16 triangulo [192][256];
17
18
19
for ( i =1; i <256; i ++) {
if ( i ==127)
triangulo [0][127] = 1;
20
21
22
else
triangulo [0][ i ] = 0;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
23
}
24
for ( i =1; i <192; i ++)
51
for ( j =0; j <256; j ++) {
25
triangulo [ i ][ j ] = triangulo [i -1][ j -1] +
26
triangulo [i -1][ j +1];
if ( triangulo [ i ][ j ] % 2)
27
color [ i *256+ j ] = RGB15 (31 ,0 ,0) ;
28
}
29
30
return 0;
31
32
}
La compilación de este código no dará ningún error. Sin embargo, la ejecución del
binario mostrará un fallo. La causa de este fallo radica en una gestión deficiente de la memoria de la pila. Se debe tener presente que el ABI establece la localización de las variables
automáticas en la pila, como es el caso de la variable triangulo, definida como una matriz
de 192x256 elementos. Como el vector es de tipo entero sin signo de 16 bits (2 bytes),
ocupará un tamaño de 192x256x2 o lo que es lo mismo, 96KiB. Estos 96KiB superan por
mucho los 16KiB disponibles en la memoria DTCM, donde se encuentra pila.
La solución es declarar triangulo como una variable global (fuera de cualquier función) o indicar explı́citamente que se desea almacenar en la zona de variables estáticas:
1
static uint16 triangulo [192][256];
3.4.3.5.
Transferencia de datos
La transferencia de datos juega un papel esencial en la representación gráfica, no
sólo en el modo framebuffer. De ahı́ la necesidad de conocer las distintas formas existentes
para cargar datos en memoria, más allá del direccionamiento básico mediante punteros.
A lo largo de este apartado se describirán los fundamentos teóricos del acceso directo a
memoria, ası́ como algunas de las funciones más comunes de la librerı́a libnds que le dan
soporte y otros tipos de transferia de datos usando la CPU.
3.4.3.5.1.
DMA (Direct Memory Access)
La comunicación entre el procesador y un periférico de entrada y salida se realiza en
dos pasos: un primer paso de sincronización entre ambos y un segundo paso de transferencia
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
52
de datos. Este proceso se puede realizar mediante el uso de las siguientes técnicas: sondeo
o consulta (polling), interrupción, y acceso directo a memoria (DMA). En los dos primeros
casos, la transferencia de datos se hace a través del procesador, mientras que mediante DMA
la información pasa directamente entre los periféricos y la memoria.
La técnica de sondeo resulta la más sencilla, ya que es el procesador el que se encarga de interrogar al periférico para iniciar la transferencia de datos. Esto hace que las
entradas y salidas estén controladas por el programa, mientras el procesador está ocupado
con esta tarea no pueda realizar otras. Por todo ello, se trata de una técnica poco eficiente
para transferir grandes cantidades de información, especialmente si la transferencia es lenta.
En la técnica basada en interrupciones, es el controlador del periférico el encargado
de notificar al procesador cuándo se debe hacer una transferencia. Esto permite al procesador trabajar en paralelo, mientras no reciba interrupciones.
Finalmente, la técnica basada en acceso directo a memoria deja en manos del controlador de DMA la operación de transferencia de datos entre periféricos y memoria. En
este caso, la información ya no debe pasar por el procesador, permitiéndole poder realizar
otras tareas simultáneamente. La única limitación que impone, es que el procesador y el
controlador no pueden emplear los buses al mismo tiempo con el fin de evitar un conflicto.
Esta técnica es, sin duda, la más eficiente para transferir grandes cantidades de datos entre
periféricos y memoria de forma frecuente.
Para las transferencias tipo DMA se emplea el controlador de DMA (CDMA) del
sistema. Generalmente este controlador es más sofisticado que los controladores de entrada
salida de los periféricos. La estructura interna del CDMA consta de los siguientes registros
mapeados en memoria y accesibles para el procesador:
Registros de dirección: contienen las direcciones de origen y destino de la transferencia a realizar. Se autoincrementan de forma automática.
Contador de palabras: contiene el número de palabras a transferir; se decrementa
después de transferir una palabra y cuando llega a 0 genera una señal para notificar la
finalización de la transferencia.
Registro de datos: Buffer intermedio contiene el dato a transferir.
Lógica auxiliar de control: es la circuiterı́a encargada de notificar al procesador cuando se solicita el uso de los buses y cuando se ha terminado la transferencia.
En el caso de la Nintendo DS, existen 4 canales DMA para cada procesador (ARM9
y ARM7) que permiten la transferencia de bloques de datos entre diferentes tipos de memoria y periféricos de entrada-salida.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.4.3.5.2.
53
Algunas funciones para transferencia de datos
La librerı́a libnds proporciona una serie de funciones que soportan el proceso de
transferencia de datos utilizando controladores de DMA. Anteriormente, se ha utilizado la
función dmaCopy. El primer argumento de esta función se corresponde con la dirección
de memoria donde se encuentran los datos a transferir, el segundo argumento indica la
dirección de memoria donde se van a transferir y, finalmente, el tercer agumento indica el
tamaño de esos datos en bytes.
Es preferible utilizar funciones de transferencia sobre DMA, ya que al no intervenir
la CPU, el proceso es más rápido y eficiente. Sin embargo, como la memoria DTCM no
está conectada al bus accesible por el controlador de DMA, este no tiene acceso a la misma.
Esto obliga a utilizar funciones de transferencia que utilicen la CPU como, por ejemplo,
memcpy o swiCopy.
La función dmaCopy tampoco permite la transferencia de un bloque de datos de tamaño superior a 128KiB. Por eso, si se quisiere cargar en memoria una imagen de 512x512
(256KiB, 512x512x2), también se tendrı́a que recurrir a una función de transferencia que
utilizara la CPU, o hacer dos transferencia de 128KiB cada una, utilizando DMA.
El código que se lista a continuación, utiliza el modo de video extended rotoscale, el
cual se comentará más adelante. Para la transferencia de datos se utiliza la función memcpy,
que como primer argumento recibe la dirección de memoria donde se transferirán los datos,
como segundo argumento la dirección de memoria donde se encuentran los datos a transferir
y, finalmente, el tamaño de los datos a transferir.
1
# include < nds .h >
2
# include < stdio .h >
3
# include " wallpaper . h "
4
5
int main ( void )
6
{
7
consoleDemoInit () ;
8
// Configuracion de pantalla principal
9
REG_DISPCNT = MODE_5_2D | D IS PL AY _B G2_ AC TI VE ;
10
// Configuracion de bloque A de la VRAM
11
VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG ;
12
// Configuracion de bloque B de la VRAM
13
VRAM_B_CR = VRAM_ENABLE | VRAM_B_MAIN_BG ;
14
// Configuracion del fondo 2
15
BGCTRL [2] = BG_MAP_BASE (0) | Bg Size_B 8_512x 512 ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
54
16
17
// Copia del fondo
18
memcpy ( BG_GFX , wallpaperBitmap , 512*512) ;
19
}
La otra opción para la transferencia de datos, es utilizar la función swiCopy. Esta
función es una rutina de la BIOS que soporta la transferencia en bloques de 2 bytes. La
definición de esta función establece, como primer argumento la dirección de memoria de
la localización de los datos a transferir, como segundo argumento la dirección de memoria
donde se transferirán los datos y, finalmente, el tamaño de los mismos, en cantidad de 2
bytes. Se puede utilizar el mismo código listado anteriormente, pero cambiando swiCopy
por memcpy. Ambas funciones se diferencian en el orden de los argumentos de la función.
1
// Copia del fondo
2
// dmaCopy ( wallpaperBitmap , BG_GFX , 512*512) ;
3
swiCopy ( wallpaperBitmap , BG_GFX , 512*512) ;
3.4.4.
Modo extended rotoscale
3.4.4.1.
Introducción
Los fondos extended rotoscale [24] se pueden componer a partir de un mapa de
bits, como hace el modo framebuffer, o a partir de un mapa de teselas, concepto que se
explicará cuando se describan los fondos teselados.
Excepto el modo framebuffer, el resto de modos hacen uso de fondos (backgrounds).
Existen cuatro fondos, BG0,BG1,BG2 y BG3, dispuestos de forma superpuesta. Normalmente, el BG0 es el más exterior y el BG3 el más interior, aunque se puede cambiar (prioridad de fondos). Cada uno de los fondos admite una configuración determinada, ası́ se
hablará de fondos de rotación, de rotación extendida o teselados.
Los modos etiquetados como Mode 3, Mode 4 y Mode 5 soportan una configuración
en la que interviene al menos un fondo de tipo rotación extendida (extended rotoscale, ER.
Sin embargo, es el Mode 5 el único que permite una configuración con dos fondos de este
tipo, el fondo 2 o BG2 y el fondo 3 o BG3. Este es el modo que se utilizará en los apartados
relativos al modo ER, tal y como se indica en la siguiente lı́nea de código:
1
REG_DISPCNT = MODE_5_2D | D IS PL AY _B G2_ AC TI VE ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
55
Como se puede observar, se especifica el modo 5, aunque únicamente se habilita el
fondo 2, que es un fondo de tipo ER. Este tipo de fondo puede ser utilizado para representar
mapas de bits, al igual que hacı́a el modo framebuffer, pero además con la funcionalidad
añadida para rotar, escalar y desplazar el fondo a lo largo y ancho de la pantalla.
3.4.4.2.
Mapeando bancos de memoria VRAM a los fondos extended rotoscale
En lo referente a la gestión de memoria, la principal novedad que los fondos ER
presentan con respecto al modo framebuffer, es que ahora el motor 2D espera encontrar los
datos relativos a los gráficos en una zona de memoria especı́fica, referida como memoria de
fondos (background memory). El motor 2D, por defecto, no tiene más memoria asignada
que la de sprites y la de paletas. De ahı́ la necesidad de mapear bancos de la memoria de
video VRAM a aquellas zonas donde el motor espera encontrar los datos a dibujar.
La figura 3.15 describe el esquema de la memoria de fondos para el motor principal,
organizada en bloques de 16KiB cada uno, etiquetados con nombres que van de BMP BASE
0 a BMP BASE 31. Esta región de memoria contiene el mapa de datos de la imagen que el
motor 2D va a renderizar en la pantalla.
Figura 3.15: Esquema de la memoria destinada a los fondos de mapas de bits [24]
Un fondo ER se puede configurar de forma análoga al framebuffer, en la que cada
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
56
pixel se representa con el color de dicho pixel en formato RGB15 y ocupa 16 bits14 . Asimismo, se puede configurar en un modo especial de mapa de bits, en el que cada pixel se
representa por un número de 8 bits que corresponde a su color dentro de la paleta de colores
del sistema. Este es el modo que se empleará en los apartados dedicados al modo ER.
En función del tamaño de los datos correspondientes a la imagen, se habilitarán
los bancos de VRAM que se necesiten, teniendo en cuenta que el máximo se establece a
512KiB. Ası́, en el ejemplo que se muestra a continuación, el cual representa una imagen
de 256 × 256, bastará con habilitar el banco A de la VRAM y comenzar la escritura de los
datos del mapa a patir del BMP BASE 0, es decir, desde el principio de la memoria de video
asignada.
1
VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG ;
2
BGCTRL [2] = BG_BMP_BASE (0) | Bg Size_B 8_256x 256 ;
La primera lı́nea habilita el banco A de la VRAM y lo asigna a la memoria de fondos
del motor principal, mapeando por lo tanto 256KiB, suficientes para contener los datos del
mapa de una imagen de 256 × 25615 . La segunda lı́nea configura el fondo 2, indicando
al motor 2D que los datos del mapa se encuentran desplazados 0 bytes en la memoria
de fondos, indicado mediante la macro BG BMP BASE(0). Los datos del mapa para esta
imagen ocupan los primeros 64KiB (256 × 256). Si se quisiera representar otro fondo con
otra imagen, podrı́a estar contenida en la memoria de fondos, justo a continuación de la
anterior imagen. Es decir, este segundo fondo comenzarı́a en el bloque 4 (cada bloque es de
16KiB), que se especifica en la configuración del fondo como BG BMP BASE(4).
El motor secundario sólo admite un máximo de 128KiB para la memoria de fondos,
mapeada en los bancos C, H e I de la VRAM.
3.4.4.3.
Configuración de los fondos extended rotoscale
La configuración de un fondo en modo ER conlleva la configuración de tres aspectos:
Desplazamiento en la VRAM.
Especificación del tamaño de la imagen y de cada pixel.
La paleta de colores.
14 El bit más significativo se utiliza para indicar la opacidad. Si vale 1 el pixel es opaco y no deja ver el color
de los fondos inferiores. Si vale 0 el pixel es transparente.
15 Puesto que cada pixel ocupará un byte (8 bits), la imagen ocupará 256 × 256 bytes, es decir, 64KiB.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
57
En el apartado anterior, se describió la configuración de los dos primeros aspectos.
El desplazamiento en la VRAM se especifica en múltiplos de 16KiB, de manera que parece
organizada en bloques lógicos. No hay ningún mecanismo que impida que se sobrepasen
los lı́mites de estos bloques lógicos o BMP BASEs. Dado que la máxima memoria disponible para fondos es de 512KiB el rango posible de desplazamientos va entre 0 y 31,
correspondientes a los deplazamientos de 0 bytes y 31 × 16KiB respectivamente.
El tamaño que ocupa el mapa de bits dependerá del tamaño de la imagen a representar y del tamaño de cada pixel. La configuración del tamaño sólo permite la elección entre
una lista preestablecida de valores, especificados como una enumeración en el fichero de
cabecera. El tamaño de cada pixel solo puede ser 8 bits o 16 bits. En el siguiente fragmento
de código se configura un fondo de mapa de bits de 16 bits por pixel para representar un
gradado de negro a azul, suponiendo un tamaño de 256 × 256:
1
BGCTRL [2] = BG_BMP_BASE (0) | BgS iz e_ B1 6_ 25 6x 25 6 ;
2
uint16 * memoria = BG_GFX ;
3
4
int i , j ;
5
6
7
8
for ( i =0; i <192; i ++)
for ( j =0; j <256; j ++)
memoria [ i *256 + j ]= RGB15 (0 ,0 , i /(192/32) ) | BIT (15)
;
En este caso, al tratarse de un mapa de bits de 16 bits por pixel, no existe paleta de
colores. Een memoria se escriben los 16 bits correspondientes al color de cada pixel. Se debe
puntualizar que el bit 15 debe estar habilitado para que el pixel no sea considerado como
transparente, para lo cual se utiliza la macro BIT(15). Por defecto, la macro RGB15 deja el
bit 15 a 0. Alternativamente, se podrı́a utilizar la macro ARGB16(1,r,g,b) que directamente
pone el bit más significativo al valor indicado por el primer argumento.
Las configuraciones del fondo que utilicen 8 bits por cada pixel no representan cada
pixel por un color, sino por el número de color dentro de la paleta de colores del sistema.
Una paleta es simplemente una colección de todos aquellos colores que se utilizan en la
imagen a representar. En La figura 3.16 se muestra un ejemplo de paleta. Las paletas de la
consola NDS están limitadas a un máximo de 256 colores diferentes.
Para dibujar un gradado de negro a azul utilizando la paleta de colores, se requiere
disponer de un vector de datos para contener el valor de los 16 bits correspondientes a cada
una de las 32 tonalidades de azul. Este vector, al igual que ocurre con los datos de la imagen,
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
58
Figura 3.16: Ejemplo de paleta de colores [24]
se debe escribir en aquella zona de memoria donde el motor gráfico 2D busca este tipo de
datos. La dirección de comienzo de esa región es la contenida en la macro BG PALETTE.
De esa manera, una vez se haya generado la paleta y se haya copiado en la memoria, el
siguiente paso será escribir el mapa de datos. Este mapa contiene el número de la posición
que ocupa el color que se representará en cada pixel, quedando el código para el ejemplo
de gradado de la siguiente manera:
1
BGCTRL [2] = BG_BMP_BASE (0) | Bg Size_B 8_256x 256 ;
2
3
uint16 * paleta = BG_PALETTE ;
4
uint8 linea [256];
5
uint8 * memoria = ( uint8 *) BG_GFX ;
6
7
int i , j ;
8
for ( i =0; i <32; i ++)
paleta [ i ] = RGB15 (0 , 0 , i ) ;
9
10
11
for ( i =0; i <192; i ++) {
for ( j =0; j <256; j ++) {
12
linea [ j ]= i /(192/32) ;
13
14
}
15
memcpy (& memoria [256* i ] , linea , 256) ;
16
}
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
59
La lı́nea número 1 se corresponde con la configuración del fondo, que en este caso
es un fondo de 8 bits por pixel y tamaño de 256 × 256. La lı́nea 3 define un puntero de
tipo entero corto sin signo al comienzo de la región de memoria donde el motor 2D espera
encontrar los datos de la paleta. La paleta se rellena con todos los azules posibles en el bucle
for de las lı́neas 8 y 9. La lı́nea 13, asigna posiciones de la paleta a cada uno de los pixeles
de la lı́nea en curso, que se almacena en el vector linea. Finalmente, la lı́nea 15 copia la
lı́nea en curso a la posición correspondiente de la memoria de video.
3.4.4.4.
La matriz de transformación
El código de ejemplo que se ha presentando en los apartados anteriores está incompleto, ya que el último paso para la representación de un gráfico en modo ER requiere la
especificación de una matriz de transformaciones afines [35].
Los fondos de rotación extendida admiten rotaciones, desplazamientos y escalados.
Incluso en el caso de que no se desee que la representación de la imagen sea objeto de alguna
de estas modificaciones, es necesario que se especifique la matriz de transformación.
Una transformación cambia la posición de los puntos del plano. Al aplicar una transformación sobre una imagen se obtiene otra imagen. Las transformaciones afines transforman rectas en rectas y preservan la propiedad de paralelismo. Matemáticamente son muy
sencillas:
~v = A · (~u − u~0 )
(3.1)
Donde u~o es el vector que determina el punto origen de coordenadas de la transformación, es decir, el punto de la imagen original que se transforma en el origen de coordenadas en el plano transformado. O bien, expresada por componentes:
" #
x0
=
y0
! "
#
a b
x − x0
·
c d
y − y0
(3.2)
Los motores gráficos de la consola, sin embargo, están más interesados en la operación contraria, obtener el punto de la imagen original dado un punto de la imagen transformada. Esto se debe a que su función es precisamente recorrer punto a punto de la pantalla
(espacio transformado), pintándolo del color que corresponda (punto equivalente de la imagen original). Desde el punto de vista matemático serı́a:
" #
" # " #
x
x0
x0
= A−1 · 0 +
y
y
y0
(3.3)
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
60
Si se desea poner todo en una única matriz P, la ecuación quedarı́a de la siguiente
manera:


h
i h
i xdx xdy


x y = x0 y0 1 · ydx ydy
dx dy
(3.4)
En la biblioteca libnds se proporciona una estructura de datos que facilita el manejo
de la matriz de transformación, de nombre bg transform. Esta estructura se compone de los
siguientes campos de datos:
1
typedef struct {
2
s16 xdx ;
3
s16 ydx ;
4
s16 xdy ;
5
s16 ydy ;
6
s32 dx ;
7
s32 dy ;
8
} bg_transform ;
Cada campo se corresponde exactamente con la componente del mismo nombre en
la matriz P de la ecuación 3.4. Dependiendo de los valores que se utilicen, se pueden conseguir un amplio conjunto de efectos. En la figura 3.17 se muestran algunos ejemplos que
se pueden conseguir mediante transformaciones afines.
3.4.4.5.
Valores reales en punto fijo
En la consola NDS se tiene que programar la matriz P para obtener la transformación
deseada. Aunque no se desee ninguna transformación de la imagen, se tiene que indicar la
matriz P correspondiente a la transformación identidad.
Nótese que los coeficientes de esta matriz son, en general, números reales. Los
números reales se pueden representar en C mediante los tipos float o double, los cuales emplean un formato conocido como representación en coma flotante. Sin embargo, ninguno de
estos tipos valen para especificar los coeficientes de la matriz de transformación. Para que
la consola NDS los entienda, se deben especificar como números reales en representación
de coma fija con 8 bits decimales.
La representación en coma fija no es dificil de entender ni de manipular empleando números enteros convencionales. Basta con transformar el número real en una fracción
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
61
Figura 3.17: Ejemplos de transformaciones afines
entera en la que el denominador es la base elevada al número de dı́gitos decimales considerados. El numerador de esa fracción serı́a su representación en coma fija. Por ejemplo, para
representar el número 0, 25 en coma fija con dos dı́gitos de parte decimal, se transformarı́a
en la fracción 25/100 y se tomarı́a el numerador 25.
Lo único que cambia en un computador es que la base de numeración empleada es
la binaria. Ası́, el número 0, 25(10 en binario serı́a 0, 01(2 . Para que se represente en coma
fija de 2 dı́gitos binarios de parte decimal, se multiplicarı́a por 22 , es decir, se desplazarı́a
el punto dos posiciones hacia la derecha, obteniendose 001.
En el caso de la consola NDS, la matriz de transformación utiliza números de coma
fija con 8 dı́gitos binarios de parte decimal. Por tanto el número 1, 0 serı́a un 1 seguido de 8
ceros de la parte decimal, es decir, 100000000(2 . O, lo que es lo mismo, 256.
En el primer ejemplo de la figura 3.17, la matriz P equivalente a la transformación
identidad (no transformación) serı́a:


1, 0 0


P =  0 1, 0
0
0
(3.5)
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
62
Que expresado en coma fija en los elementos de la estructura bg transform, se escribirı́a:
1
bg_transform [2] - > xdx = 256;
2
bg_transform [2] - > ydx = 0;
3
bg_transform [2] - > xdy = 0;
4
bg_transform [2] - > ydy = 256;
5
bg_transform [2] - > dx
= 0;
6
bg_transform [2] - > dy
= 0;
El ı́ndice 2 significa que se está definiendo la matriz para el fondo BG2.
Los desplazamientos dx y dy también se expresan en coma fija. A continuación se
analizará el caso del efecto de espejo horizontal. La matriz P es:


−1 0


P =  0 1
256 0
(3.6)
Que expresado en coma fija en los elementos de la estructura bg transform, se escribirı́a:
1
bg_transform [2] - > xdx = - (1 << 8) ;
2
bg_transform [2] - > ydx = 0;
3
bg_transform [2] - > xdy = 0;
4
bg_transform [2] - > ydy = (1 << 8) ;
5
bg_transform [2] - > dx
6
bg_transform [2] - > dy = 0;
= 256 << 8;
En este caso, se ha utilizado el hecho de que el desplazamiento hacia la izquierda
es equivalente a multiplicar por la base (en este caso 2). Por tanto, 8 desplazamientos es
equivalente a multiplicar por 256.
Por último, se verá un ejemplo más complejo. El caso de la rotación de 30 grados en
sentido horario serı́a:


cos π6 sen π6


P = − sen π6 cos π6 
0
0
(3.7)
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
63
Que expresado en coma fija en los elementos de la estructura bg transform, se escribirı́a:
1
# include < math .h >
2
...
3
bg_transform [2] - > xdx = cos ( M_PI /6.0) * 256.0;
4
bg_transform [2] - > ydx = sin ( M_PI /6.0) * 256.0;
5
bg_transform [2] - > xdy = - sin ( M_PI /6.0) * 256.0;
6
bg_transform [2] - > ydy = cos ( M_PI /6.0) * 256.0;
7
bg_transform [2] - > dx
= 0;
8
bg_transform [2] - > dy
= 0;
En este caso se han realizado las operaciones en coma flotante y, posteriormente, se
ha convertido implı́citamente el número resultante a un entero.
Este último caso se ha escrito con efectos puramente ilustrativos, aunque no es ni
mucho menos óptimo. Los procesadores de la NDS no tienen unidad aritmética de coma
flotante, por lo que todas estas operaciones intermedias se simularán por el compilador,
generando un código muy ineficiente.
3.4.5.
Modo teselado
3.4.5.1.
Introducción
El nivel de complejidad de los modos gráficos de la NDS se ha ido incrementando
durante las últimas secciones, pero también las posibilidades de representación que ofrecen.
El framebuffer es el más sencillo y directo de manejar de los tres, mientras que el modo
teselado representa el más versátil y flexible en cuanto a la utilización de recursos. Ası́, en
el modo framebuffer se limitaba el tamaño de la imagen al de la pantalla de la consola,
permitiendo únicamente la representación de un gráfico, ya que no soporta la utilización
de fondos o capas. En los fondos de rotación extendida se introducen mejoras relevantes
en cuanto al tipo de gráficos, el tamaño y número de gráficos que se pueden representar,
ya que entra en juego el uso de fondos. Además, en los fondos ER se da soporte a una
serie de transformaciones que ofrecen una mayor versatilidad a los fondos. En el siguiente
escalón creciente de funcionalidad se encuentran los fondos teselados (tiled backgrounds),
que, además, se pueden utilizar como fondos de rotación extendida.
Un fondo teselado [25] se compone de dos partes:
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
64
Colección de teselas o tile set: es un conjunto de hasta 1024 teselas diferentes, donde
cada tesela se identifica según la posición que ocupa dentro de la colección de teselas,
de 0 a 1023.
Mapa de teselas: es una matriz de tamaño 32×32, 32×64, 64×32 o 64×64 (dependiendo del tamaño del fondo), que especifica qué tesela se colocará en cada uno de
las posiciones de esa matriz imaginaria de teselas en la que se ha divido el fondo.
El concepto de mapa ya apareció en el contexto de los fondos de rotación extendida,
pero, en este caso, las entradas del mapa no especificaban teselas, sino el ı́ndice de la paleta
de colores asignado a cada uno de los pixeles que componı́a el fondo. De alguna manera,
se puede concebir que la unidad mı́nima para el mapa de los fondos de rotación extendida
era el pixel, mientras que para los fondos teselados es la tesela. La realidad es algo más
compleja, ya que además de considerar la tesela como unidad mı́nima, en el contexto de los
fondos teselados, el gráfico se va a describir en función de tres elementos básicos:
La tesela: es la unidad mı́nima de composición de los fondos teselados.
La transformación: Toda tesela puede admitir una transformación de entre tres diferentes, espejo con respecto al eje Y (espejo vertical), con respecto al eje X (espejo
horizontal) o ambos.
La paleta de colores: Existe un modo especial de gráficos teselados que divide la
paleta de colores en 16 subpaletas de 16 colores. Sólo para este caso, en cada componente del mapa se tendrá que especificar la subpaleta utilizada de entre las 16 disponibles.
Antes de que se estudien de manera más detallada los fundamentos de los fondos
teselados, se hará un especial énfasis en aclarar la dinámica general de este tipo de fondos,
utilizando para ello la figura 3.18.
Como se puede observar, parte de la memoria de video VRAM puede configurarse para albergar la memoria de fondos, y dentro de esta, los datos de mapas y teselas que
compondrán los fondos teselados. Simplificando al máximo los fundamentos de la representación de gráficos teselados, el mapa de un fondo teselado se compone de referencias
a teselas y, cuando se utilicen paletas de 16 colores, también de referencias a la subpaleta
utilizada por cada tesela.
Por otro lado, en la zona de la memoria de fondos destinada a albergar los datos
de las teselas, cada entrada se corresponderá con una tesela de 8×8 pixels. Cada pixel se
representa mediante el ı́ndice del color correspondiente en la paleta de colores, de forma
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
65
Figura 3.18: Elementos básicos de los fondos teselados [25]
similar a los modos rotoscale de 8 bits por pixel, o en un modo más compacto que sólo
utiliza 4 bits por pixel al usar paletas de 16 colores.
Finalmente, el último eslabón de esta cadena es la paleta o paletas de colores, que ya
se conoce de secciones anteriores. Como principal novedad, la paleta de 256 colores puede
utilizarse como un grupo de 16 paletas de 16 colores.
3.4.5.2.
Fondos teselados
En cualquiera de los modos disponibles para los dos motores gráficos (el secundario y el principal), hay al menos uno de los fondos configurado para trabajar como fondo
teselado. Por ejemplo, el modo 5 elegido para la representación de fondos de rotación extendida, se puede utilizar también para representar fondos teselados, utilizando en este caso
los fondos 0 ó 1.
La configuración de los fondos teselados debe incluir tres elementos:
Desplazamiento en la VRAM: especifica dónde se ubicarán los datos, tanto del mapa
como de las teselas que compondrán el fondo.
Tamaño: conjunto limitado de posibles tamaños, especificado en teselas.
Tipo de paleta: existe la posibilidad de utilizar hasta 16 paletas de 16 colores o
simplemente utilizar una de 256.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
66
El desplazamiento en la VRAM se explicará más detalladamente en el siguiente
apartado. El tamaño del fondo vendrá especificado en teselas, siempre teniendo presente
que cada tesela tiene unas dimensiones de 8×8 pixels. Además, el tamaño del fondo estará limitado a una de las posibles combinaciones de {32 ó 64} x {32 ó 64}.
En cuanto a la paleta de colores, este tipo de fondos considera o bien una paleta de
256 colores o subpaletas de 16 colores cada una (hasta un máximo de 16 subpaletas), es
decir, hay dos modos de colores para las teselas:
Modo de 256 colores: A cada pixel se le asigna un ı́ndice de la paleta de colores. El
ı́ndice será un entero de 8 bits, con un valor comprendido entre 0 y 255.
Modo de 16 colores: En este caso un pixel es un ı́ndice a una paleta de 16 colores.
Por lo tanto, el ı́ndice será un entero de 4 bits, con un valor comprendido entre 0 y
15. Aunque este modo requiere menos memoria, dejando ası́ más espacio para teselas
y otros elementos en la VRAM, la calidad de la imagen renderizada puede verse
comprometida al disponer de solo 16 colores diferentes en cada tesela.
3.4.5.2.1.
Desplazamientos en la VRAM
El motor gráfico renderiza los fondos teselados a partir de las entradas del mapa y el
conjunto de teselas a las que hace referencia. Estos datos están contenidos en la memoria de
fondos de la VRAM. Teniendo en cuenta que cada motor gráfico puede manejar un máximo
de cuatro fondos, es necesario que cada fondo activado configure la localización de sus
datos de mapas y teselas. Para ello, se utiliza el mismo registro de configuración del fondo,
el registro REG BGnCNT o BGCTRL[n], donde la n se sustituye por el ı́ndice del fondo,
tomando valores de 0 a 3. Este registro reserva 4 bits para especificar el desplazamiento de
las teselas (en múltiplos de 16 KiB) y 5 bits para el mapa (en múltiplos de 2 KiB), de tal
forma que las teselas admiten 24 = 16 posibles valores del desplazamiento base y los mapas
admiten 25 = 32.
Un mapa puede empezar en cualquier dirección múltiplo de 2KiB entre 0 × 2KiB y
31 × 2KiB. Expresado en hexadecimal, serı́a desde 0×0x800 hasta 31×0x800.
El tamaño de un mapa depende del tamaño del fondo. Un mapa de 32 × 32 teselas
será una sucesión de 32 × 32 entradas de 16 bits (esto se explicará con más detalle en las
siguientes páginas), por lo que el tamaño total será de 2 × 32 × 32 = 2KiB. Es decir, en este
caso el mapa entero cabe antes de la siguiente dirección base de otro mapa. Sin embargo,
para un fondo de 64 × 64 teselas, los datos del mapa requieren 2 × 64 × 64 = 8KiB, es decir,
las siguientes 3 posibles direcciones base no estarı́an disponibles para otro mapa (véase
figura 3.19).
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
67
Figura 3.19: Direcciones base para un mapa de 32×32 y de 64×64 [25]
Para que se facilite la configuración de las direcciones base, la liberı́a libnds incluye
la macro BG MAP BASE(n) (donde esa n se corresponde con el múltiplo de 2KiB seleccionado, entre 0 y 31). Indicar en el registro de configuración del fondo que los datos del
mapa se encuentran ubicados a partir de BG MAP BASE(1), significa que comenzarán en
la posición de memoria 0x0800 a partir del principio de la memoria de fondos. Análogamente, decir que lo hacen en BG MAP BASE(31) significa que empiezan en la posición
0xf800, tal y como se puede comprobar en la figura 3.20. Una técnica similar a ésta ya se
utilizó en los fondos de rotación extendida, para especificar la ubicación de los datos del
mapa. Sin embargo, en este caso el desplazamiento base se indicaba como un múltiplo de
16KiB y los datos incluı́an directamente el mapa de bits a mostrar. En libnds se incluye
la macro BG BMP BASE(n), que empleábamos en los modos rotoscale para indicar el comienzo del fondo en múltiplos de de 16KiB. Realmente tanto la macro BG MAP BASE(n)
como la macro BG BMP BASE(n) hacen exactamente lo mismo, configuran los 5 bits reservados en los registros de configuración de los fondos para especificar el comienzo del
mapa, aunque en este caso el desplazamiento es múltiplo de 16 KiB. Usar dos nombres
distintos simplemente sirve para hacer explı́cito que se trata de direcciones diferentes.
Como ya se ha comentado en algún momento, el motor de video no tiene memoria
fı́sica dedicada. Parte de la memoria de video (VRAM) debe configurarse para ser utilizada
como memoria de fondos. El coprocesador gráfico principal utiliza como memoria fondos
el rango de memoria de 0x06000000 a 0x0607ffff (512KiB máximo) mientras que el secundario emplea el rango de 0x06200000 a 0x0621ffff (128KiB máximo). Gran parte de los
bancos de la memoria de video pueden configurarse para ser accesibles en estos rangos de
memoria, como ya hemos visto en el capı́tulo anterior. Todos los desplazamientos base de
mapas y teselas son referidos al comienzo de estos rangos de memoria.
En cuanto a las teselas, ocurre lo mismo que para los mapas, ya que ambos comparten la misma memoria de fondos y al igual que los mapas, utilizarán los desplazamientos para gestionar esa memoria como si estuviera organizada en bloques, sólo que en este caso, de
tamaño 16KiB. La macro utilizada para especificar la dirección base es BG TILE BASE(n),
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Figura 3.20: Desplazamientos en la memoria de fondos [25]
68
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
69
donde n que toma valores entre 0 y 15. El número corresponde al múltiplo de 16KiB correspondiente, empezando en 0x0000, desplazándose en múltiplos de 0x4000 hasta el valor
0x3c000.
Ya se sabe que una tesela es una colección de 64 pixeles, ¿pero cuál es el tamaño
de un pixel? La NDS soporta dos modos de color para las teselas de un fondo teselado,
el modo de 256 colores utiliza 8 bits para identificar un color de la paleta, de tal forma
que cada pixel tendrá un tamaño de 1 byte. En cambio, si se usa 16 paletas de 16 colores
cada una, el ı́ndice de paleta podrá especificarse con sólo 4 bits, lo que supone un ahorro
de memoria en VRAM, aunque también supone al mismo tiempo una pérdida en cuanto al
número de colores disponibles. Teniendo en cuenta que el desplazamiento en la memoria de
fondos para las teselas es múltiplo 16KiB, cada bloque lógico puede almacenar 256 teselas
en modo de 256 colores y 512 en modo de 16 colores:
256 teselas × 64 pixeles/tesela × 1 byte/pixel = 16KiB
512 teselas × 64 pixeles/tesela × 1/2 byte/pixel = 16KiB
En la figura 3.20 se puede comprobar muy fácilmente por qué el primer listado de
código es correcto, mientras que el segundo mostrará unos resultados que no son los esperados. Se debe ser muy cuidadoso a la hora de utilizar los desplazamientos en la memoria
de fondos, ya que ésta es la misma para mapas y teselas, lo que significa que una incorrecta
utilización de esos desplazamientos lleva a escribir unos datos sobre otros. Dadas las unidades de desplazamiento, cada unidad base de teselas se componen de 8 unidades base de
mapas:
1
BGCTRL [0] = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE (0) |
BG_TILE_BASE (1) ;
Esta configuración especifica que los datos del mapa están contenidos a partir de la
dirección 0x0000 mientras que los datos de la tesela se encuentran a partir de la dirección
0x04000 (el múltiplo 1 de 16KiB). Como se puede observar, no existe superposición de los
datos. Sin embargo, el siguiente fragmento de código es incorrecto, ya que los datos del
mapa y los de las teselas están configurados a partir de la misma dirección:
1
BGCTRL [0] = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE (0) |
BG_TILE_BASE (0) ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3.4.5.3.
70
Teselas
Los gráficos teselados vienen descritos mediante una matriz de teselas, en lugar de
una matriz de pixeles, donde cada tesela representa un pequeño mapa de bits de 8x8 pixeles.
Para entender mejor el concepto de gráfico teselado, se puede imaginar la pantalla de la
consola dividida en celdas de dimensiones 8x8 pixeles, donde cada cuadrado se corresponde
con una tesela, quedando la pantalla dividida en 32 teselas de ancho y 24 de largo.
Creando teselas de 16 y 256 colores
Aunque el concepto de paleta de colores para los fondos de rotación extendida no
difiere para el caso de los fondos teselados, sı́ que en este último caso caben dos posibilidades, en lugar de considerar una única paleta de 256 colores, considerar 16 paletas de 16
colores cada una. La principal ventaja que se obtiene al disponer de 16 paletas de colores
estriba básicamente en la capacidad de representar los pixels de una misma tesela con colores diferentes, dependiendo de la paleta elegida, pues cada pixel se especifica mediante el
ı́ndice que el color ocupa en la paleta. De esta manera, si el color 1 es rojo en una paleta,
verde en otra y ası́ sucesivamente en las 16 paletas disponibles, será posible representar un
pixel de una misma tesela de 16 colores diferentes.
El hecho de utilizar una paleta de 256 ó de 16 colores va a determinar el número de
bits necesarios para referenciar las entradas de la paleta. Naturalmente, como para el caso
de los fondos de rotación extendida, que utilizaban una paleta de 256 colores, cada pixel
se especifica mediante 8 bits. Sin embargo, para el caso de utilizar paletas de 16 colores,
4 bits son suficientes para identificar cada una de las 16 entradas disponibles. Por lo tanto,
las entradas para cada uno de los 64 pixels que componen una tesela, serán de 4 u 8 bits,
dependiendo del modo de color utilizado (16 ó 256).
Como ya se ha introducido brevemente, los gráficos teselados son aquéllos que vienen descritos mediante una matriz de teselas, en lugar de una matriz de pixels, como ocurrı́a
en el modo framebuffer o de rotación extendida. Cada tesela es equivalente a un pequeño
mapa de bits, de 8x8 pixels. Por lo tanto la definición de una tesela no difiere demasiado de
la definición de un fondo de rotación extendida, con la diferencia de que la tesela tiene un
tamaño fijo de 8x8 y además, dependiendo del tipo del modo de color utilizado (16 ó 256
colores) se compondrá de entradas de 4 u 8 bits.
El siguiente código se corresponde con la defición de una tesela que utiliza una paleta
de 16 colores. Como se puede comprobar, cada elemento del vector de tipo unsigned char
(de 8 bits de tamaño) especifica el color de dos pixels, dedicando los 4 bits correspondientes
a cada uno de los dı́gitos de la notación hexadecimal utilizada a expresar el ı́ndice de la
paleta para cada pixel. Debido al orden de bytes (endianness) de la máquina, los bits menos
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
71
significativos ocupan las posiciones más bajas, de tal forma, que por ejemplo, el valor 0x10,
para los dos primeros pixels de la tesela, asignan al pixel 0 (el menos significativo) el ı́ndice
0 de la paleta y el pixel 1 (el más significativo) el ı́ndice 1 de la paleta. La figura 3.21
representa la tesela definida por el siguiente código.
1
unsigned char A16 [] = {
2
0 x00 ,0 x10 ,0 x01 ,0 x00 ,
3
0 x00 ,0 x11 ,0 x11 ,0 x00 ,
4
0 x00 ,0 x01 ,0 x10 ,0 x00 ,
5
0 x10 ,0 x01 ,0 x10 ,0 x01 ,
6
0 x10 ,0 x11 ,0 x11 ,0 x01 ,
7
0 x10 ,0 x01 ,0 x10 ,0 x01 ,
8
0 x10 ,0 x01 ,0 x10 ,0 x01 ,
9
0 x00 ,0 x00 ,0 x00 ,0 x00 ,
10
};
Figura 3.21: Ejemplo de tesela [25]
Sin embargo, la forma más cómoda de definir teselas que utilizan paletas de 16 colores es utilizar un vector de tipo unsigned long, ya que como tal, cada elemento de este
vector tiene un tamaño de 32 bits, de tal forma que adoptando una notación hexadecimal
de 8 dı́gitos, cada uno de ellos se corresponde con la especificación del color de los pixels
de la tesela. El siguiente código se corresponde con la definición de la misma tesela de la
figura 3.21 utilizando un vector de unsigned long. Por la simetrı́a de la imagen representada en la tesela, no se aprecia el endianess utilizado, sin emabargo, en la definición de la
segunda tesela (representa una flecha) sı́ que se aprecia, tal como se puede observar en la
representación de la tesela en la figura 3.22.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
1
unsigned long A16 [] = {
2
0 x00011000
3
0 x00111100 ,
4
0 x00100100 ,
5
0 x01100110 ,
6
0 x01111110 ,
7
0 x01100110 ,
8
0 x01100110 ,
9
0 x00000000 ,
10
72
};
Figura 3.22: Tesela en forma de flecha [25]
Una de las principales ventajas derivadas del uso de paletas de 16 colores es que
simplemente cambiando de paleta cambia el color de la tesela. Por ejemplo, para el mismo
código la misma tesela representada en la figura 3.21, suponiendo ahora que se cambia la
paleta y el color que ocupa la posicion 1 es el color verde, figura 6, la tesela asignará el
color verdes a los pixels que apunten a la posición 1, como muestra la figura 5. Si se vuelve
a cambiar de paleta, ahora por una paleta cuya elemento de ı́ndice 1 sea el color azul, la
tesela también cambiará de aspecto, dibujando en azul los pixels que apunten contengan el
ı́ndice 1.
Cuando la paleta utilizada sea de 256 colores, el número de bits necesarios para
especificar un pı́xel será de 8 (28 = 256) como ya se ha comentado anteriormente, de tal
forma, que la misma tesela para representar la letra A, utilizando en este caso 8 bits por pixel
se puede definir mediante un vector de unsigned char, quedando de la siguiente manera:
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
73
Figura 3.23: Misma tesela con diferente paleta [25]
1
unsigned char A256 [] = {
2
0 ,0 ,0 ,1 ,1 ,0 ,0 ,0 ,
3
0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,
4
0 ,0 ,1 ,0 ,0 ,1 ,0 ,0 ,
5
0 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,
6
0 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,
7
0 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,
8
0 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,
9
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
10
};
El uso de una notación decimal, en lugar de la hexadecimal, en este caso es más
cómoda, pues cada pixel se corresponde con un elemento del vector de 64 elementos que
describen los pixels de la tesela.
Copiando las teselas en memoria
La configuración especificada para el fondo teselado será determinante para obtener
la dirección de memoria donde se escribirán los datos del mismo. Los ı́ndices empleado en
la configuración en las macros BG TILE BASE(n) y BG MAP BASE(n), serán los mismos
que se especifiquen en las macros utilizadas para obtener la dirección de memoria donde escribir los datos de mapas y teselas. La macro BG TILE RAM(n) se define como un puntero
que apunta a la dirección de memoria 0x06000000 más el desplazamiento (n por 0x4000).
Análogamente, la macro BG MAP RAM(n) se define como un puntero que apunta a la
dirección de memoria 0x06000000 más el desplazamiento (n por 0x800).
Suponiendo que se desear cargar en memoria las teselas generadas por Grit, para
una imagen de archivo y dada una configuración inicial para el fondo como la que se indica
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
74
en el siguiente listado, en la lı́nea 1, que especifica un desplazamiento en memoria para
las teselas de 16KiB. La lı́nea 2 muestra cómo utilizar la macro BG TILE RAM(1), con el
mı́smo número empleado en BG TILE BASE(1):
1
BGCTRL [0] = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE (0) |
BG_TILE_BASE (1) ;
2
memcpy ( BG_TILE_RAM (1) , gnuTiles , gnuTilesLen ) ;
Como se puede observar, la función utilizada para escribir los datos de las teselas
es una función ya conocida, la memcpy. Sin embargo, también se podrı́a haber utilizado la
función dmaCopy o swiCopy como ya se ha descrito en el capı́tulo anterior.
Es importante discernir entre lo que es el desplazamiento en la memoria que se especifica mediante la macro BG TILE BASE(n) y la dirección de memoria, especificada con la
macro BG TILE RAM(n), donde se escribirán los datos. Los desplazamientos en memoria
se especifican en el momento de la configuración del fondo, mientras que la dirección de
memoria se utiliza para acceder desde el programa a la zona donde está.
3.4.5.4.
Mapas
Como ya se ha adelantado, cada una de las entradas del mapa se representa mediante
un conjunto de 16 bits, donde los 10 bits menos significativos especifican la tesela. De
ahı́ que el conjunto máximo de teselas esté limitado a 1024, las máximas referenciables con
10 bits. Los dos bits siguientes se utilizan para especificar el efecto de espejo en la tesela,
es decir, si tiene una reflexión horizontal, vertical o ambas. Finalmente, para teselas que
utilizan paletas de 16 colores, se utilizan los 4 últimos bits para identificar la subpaleta de
colores utilizada por esa tesela.
Bits
15 14 13 12
Propósito
Paleta
11
Espejo
Vertical
10
Espejo
Horizontal
9876543210
Índice
Tabla 3.9: Entrada de un mapa teselado
Se puede comprobar el uso eficiente de la memoria que se deriva del uso de los
fondos teselados, cuando se observa un fondo como el representado en las figuras 3.24 y
3.25. El mapa para representar este fondo teselado estará compuesto de un gran número de
entradas repetidas, apuntando a la misma tesela, ya que gran parte del fondo se compone de
las mismas teselas, como la que se resalta en la figura 3.24. Además de repetir teselas, este
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
75
fondo también se compondrá de teselas representadas con algún tipo de reflexión, como es
el caso de las dos teselas que se extraen del fondo de la figura 3.25, y cuyo reflejo horizontal
permite representar parte del tejado de las casas.
Figura 3.24: Ejemplo de fondo del juego Yoshi Island [1]
Figura 3.25: Ejemplo de fondo del juego Super Nenas [1]
3.4.5.5.
Generando las entradas del mapa
La copia de los datos del mapa generados automáticamente con el grit no supone
ninguna dificultad. Es bastante más interesante estudiar el proceso de composición de las
entradas de un mapa a partir de las teselas que se quieren representar en el mismo. A lo
largo de esta sección se detallará el proceso de creación de un mapa, para un fondo de
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
76
32x32 teselas, compuesto únicamente a partir de una única tesela, repetida a lo largo de
todo el fondo y a la que se le aplicarán rotaciones verticales y horizontales. Veamos el
siguiente código se corresponde con una tesela que representa la forma de la letra L:
1
const unsiged long myTiles [] = {
2
0 x10000000 ,
3
0 x10000000 ,
4
0 x10000000 ,
5
0 x10000000 ,
6
0 x10000000 ,
7
0 x10000000 ,
8
0 x10000000 ,
9
0 x11111111 ,
10
};
Figura 3.26: Tesela que representa la letra L [25]
Con esta única tesela, el objetivo será crear un fondo que represente una rejilla, donde cada celda tenga unas dimensiones de 4x4 teselas, utilizando para ello únicamente esta
tesela. Aplicando reflexiones horizontales, verticales y en ambas direcciones a la vez, se
puede conseguir que esta misma tesela aparezca de cuatro maneras diferentes, cuya combinación nos permitirá obtener celdas de tamaño 4x4. A continuación, se verá el código
necesario para cargar la tesela en la memoria de fondos y ver cómo se compone cada una
de las entradas del mapa para este fondo:
1
REG_POWERCNT = POWER_ALL_2D ;
2
REG_DISPCNT = MODE_0_2D | D IS PL AY _B G0_ AC TI VE ;
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
3
VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG ;
4
BGCTRL [0] = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE (0) |
77
BG_TILE_BASE (1) ;
5
6
memcpy (( void *) BG_TILE_RAM (1) , myTiles , sizeof ( myTiles ) ) ;
7
8
BG_PALETTE [0 xf1 ] = RGB15 (31 ,0 ,0) ;
9
10
int i , j ;
11
u16 * reja = ( u16 *) BG_MAP_RAM (0) ;
12
13
for ( i = 0; i < 32; ++ i ) {
for ( j = 0; j < 32; ++ j ) {
14
reja [ i + 32* j ] = 0 xf000 | ( j %2 ? 0 x0800 : 0) |
15
( i %2 ? 0 x0400 : 0) ;
}
16
17
}
En este ejemplo, el conjunto de tesela se limita a la tesela que se ha descrito anteriormente, de nombre myTiles, que en la lı́nea 7 del código se copia a la memoria de fondos, a
partir de un desplazamiento inicial de 16KiB, ya que en la configuración del fondo se especificó un desplazamiento base de 1 unidad. Además, el fondo está configurado para utilizar
una paleta de 16 colores. Se utilizará la paleta número 15, tal y como se puede deducir de
la lı́nea 9, donde al segundo elemento de la paleta 15 se le asigna el color rojo16 , aunque
no será hasta el momento de crear las entradas del mapa cuando se especificará el ı́ndice
de la paleta utilizada. Seguidamente, la lı́nea 12 define un puntero de tipo entero sin signo,
de 16 bits, apuntando a la memoria de fondos donde se almacenan los datos del mapa. Este
puntero se utilizará para ir recorriendo esa región de la memoria de fondos e ir escribiendo
a lo largo de la misma las entradas del mapa.
En este ejemplo las entradas del mapa se componen a mano, en la lı́nea 16, que dentro de dos bucles for, recorre esa memoria de fondos para determinar las 32 × 32 teselas que
van a componer el fondo. Analizando más detenidamente esta lı́nea y teniendo presente que
cada entrada del mapa se compone de 16 bits, se puede utilizar una notación hexadecimal
como forma abreviada de la representación binaria, de tal forma que cada dı́gito hexade16 Cuando
se utilizan paletas de 16 colores, el uso de la notación hexadecimal para el ı́ndice de color en la
paleta simplifica bastante su manejo, ya que el primer dı́gito hace referencia a la paleta, en este caso al ser f
serı́a la paleta 15 (empieza en la paleta 0) y el segundo ı́ndice especifica la posición dentro de la paleta, en
este caso el 1, indica la segunda posición de la paleta.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
78
cimal se corresponde con 4 bits. Por ejemplo 0xf000 equivale a 1111 0000 0000 0000. La
entrada del mapa, es decir, el valor que se escribe en la memoria de fondos apuntada por
el puntero reja tendrá una parte común y fija para todas las entradas, como es la referencia
a la misma paleta (todas utilizan la misma paleta, la número 15) ası́ como la tesela, que
también es única, y por lo tanto tendrá asignado el ı́ndice 0. La única variación reside en la
reflexión aplicada a la tesela, vertical si la fila es impar y horizontal si la columna es impar
y en ambas direcciones si tanto fila como columna son impares.
La operación lógica OR a nivel de bit, habilita el bit cuando al menos uno está habilitado. Suponiendo la iteración i = 1 y j = 0, la situación es la siguiente: reja[1] = 0xf000
— 0x0000 — 0x0400, veamos cuál será el resultado de esta operación OR, que será el
valor correspondiente con la entrada del mapa para la tesela que ocupa el segundo lugar,
empezando por la esquina superior izquierda de la pantalla (fila 0, columna 1):
1111 0000 0000 0000
0000 0000 0000 0000
0000 0100 0000 0000
——————————–
1111 0100 0000 0000
Como se puede observar, la única diferencia entre cada una de las entradas que componen el mapa para este fondo teselado, recae en los bits 10 y 11, que vendrán determinados
por la paridad de fila y columna que dicha entrada representa en el fondo.
El resultado final es el que aparece en la figura 11, donde cada celda tiene unas
dimensiones de 4x4 teselas, la rejilla es de color rojo, tal y como se especificó en el código,
quedando el interior de la celda en color transparente, ya que salvo que se especifique lo
contrario, el ı́ndice 0 de cada paleta de colores se corresponde con el color transparente.
Figura 3.27: 16 bits que componen la entrada de un mapa [25]
3.4.5.6.
Copiando las entradas del mapa en memoria
En el apartado anterior ya se ha adelantado la posibilidad de utilizar un puntero para
recorrer y escribir en la memoria de fondos las entradas del mapa. Al estar compuestas por
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
79
Figura 3.28: Resultado final [25]
un conjunto de 16 bits, evitan ası́ la limitación del bus a la hora de recorrer la memoria de
video en unidades menores de 16 bits. No es necesario por tanto utilizar arrays intermedios
como ocurrı́a en los mapas de los fondos de rotación extendida de 8 bits por pixel.
En cualquier caso, si las entradas del mapa no se componen de manera manual,
sino que se generan automáticamente a partir de una imagen del archivo se podrá utilizar
cualquiera de las funciones de copia para transferirlos.
Al igual que para el caso de las teselas, la zona de memoria donde se escribirán los
datos del mapa vendrá determinada por la configuración del fondo. Las siguientes lı́neas de
código presentan un ejemplo en el que el fondo se ha configurado con un desplazamiento
inicial de 0 unidades para los mapas, especificado mediante la macro BG MAP BASE(0).
La dirección de memoria de fondos, para escribir las entradas del mapa se obtiene utilizando
la macro BG MAP RAM(0).
1
BGCTRL [0] = BG_32x32 | BG_COLOR_16 | BG_MAP_BASE (0) |
BG_TILE_BASE (1) ;
2
memcpy ( BG_MAP_RAM (0) , fondoTiles , fondoTilesLen ) ;
3.4.5.7.
Conversión de imágenes con grit
Aunque no es la primera vez que se utiliza la aplicación Grit para la generación de
los datos necesarios para mostrar en la pantalla de la consola una imagen de archivo, sı́ que
es cierto que la generación de datos para cargar la imagen como un fondo teselado requiere
una lista de opciones mayor que las vistas hasta el momento.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
80
Al igual que ocurrı́a para el framebuffer y para los fondos de rotación extendida, si
se desea automatizar la generación de los datos de la imagen o imágenes, éstas deben estar
ubicadas en el directorio de nombre data, que cuelga al mismo nivel que el directorio source
(que a su vez contiene el código fuente). Por cada imagen que se desea convertir debe haber
un fichero de texto, con el mismo nombre que la imagen, pero con extensión .grit.
Cualquiera de los Makefile que se pueden encontrar con en los ejemplos de gráficos
para la NDS que se han puesto a disposición del alumno, contiene las instrucciones necesarias para generar los datos en función de las opciones que se especifiquen en los archivos
con extensión .grit, que para el caso de los fondos teselados, un ejemplo de las opciones
más comunes son las siguientes:
-p: Incluye los datos de la paleta de colores.
-pe2: Especifica que el fin de la paleta, en este caso, el 2 ı́ndica que el fin de la paleta
está en el segundo color, para imágenes en blanco y negro. Este valor se ajustará a los
colores de la imagen.
-gt: Indica que el formato de los datos del gráfico es teselado.
-g: Incluye los datos del gráfico (en este caso las teselas).
-gB4: 4 bits por pixel.
-m: Incluye los datos del mapa.
-mR4: Optimizar para 4bpp.
-gT000000: Color transparente de la paleta, en este caso el negro.
La figura 3.29 presenta de manera esquemática el proceso de obtención de los datos
necesarios para mostrar una imagen de archivo en un fondo teselado. La aplicación grit
genera automáticamente los datos correspondientes al mapa, teselas y paleta de colores,
especificando las opciones de generación adecuadas para ello, aunque ésto se comentará de
manera a lo largo de este documento.
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
Figura 3.29: Generando mapas, teselas y paletas [25]
81
CAPÍTULO 3. ANTECEDENTES, ESTADO DE LA CUESTIÓN
82
Capı́tulo 4
MÉTODO DE TRABAJO
4.1. Adaptación del problema al Proceso Unificado
4.2. Construcción del entorno cruzado de desarrollo
4.2.1. Comprensión del software
4.2.2. Construcción del diagrama de casos de uso
4.2.3. Fase de análisis
4.2.4. Fase de diseño
4.2.5. Fase de implementación
4.2.6. Pruebas
4.3. Construcción del editor de fondos
4.3.1. Construcción del diagrama de casos de uso
4.3.2. Priorización de casos de uso
4.3.3. Iteración 1
4.3.4. Iteración 2
4.3.5. Iteración 3
4.3.6. Iteración 4
4.3.7. Iteración 5
4.3.8. Iteración 6
4.3.9. Iteración 7
4.3.10. Iteración 8
4.3.11. Iteración 9
83
CAPÍTULO 4. MÉTODO DE TRABAJO
4.1.
84
Adaptación del problema al Proceso Unificado
El presente proyecto se ha desarrollado utilizando la metodologı́a PUD. El Proceso
Unificado de Desarrollo (PUD) [19] es una metodologı́a de desarrollo de software que se
autodenomina “dirigida por casos de uso, iterativa e incremental”.
Este trabajo se ha dividido en dos partes completamente independientes. Por un lado,
se construirá un entorno cruzado de programación para el desarrollo de aplicaciones para la
NDS. Con este entorno se podrá realizar la depuración de aplicaciones mediante el empleo
de un emulador. Por otro lado, se desarrollará una aplicación que permita la edición de
fondos para la Nintendo DS. La aplicación se podrá utilizar para trabajar tanto con fondos
framebuffer, extended rotoscale, ası́ como fondos teselados.
Este capı́tulo se dividirá en dos apartados princiaples:
Construcción del entorno cruzado de desarrollo que permita la depuración de aplicaciones por medio de un emulador.
Construcción de un editor de fondos para la Nintendo DS, el cual soporte el trabajo
con los tres tipos de fondos disponibles en la videoconsola.
En ambos apartados se comentarán los pasos necesario para resolver los problemas
propuestos. Asimismo, se hará un énfasis especial en los mecanismos empleados, en lugar
de incluir grandes cantidades de código.
4.2.
Construcción del entorno cruzado de desarrollo
4.2.1.
Comprensión del software
En el apartado 3.2.5.1 del capı́tulo anterior se explicó cómo construir el entorno cruzado de desarrollo de software para la Nintendo DS, utilizando como base Eclipse. Dicho
entorno permite la depuración directa en la consola. La depuración por medio de la consola impone bastantes limitaciones como, por ejemplo, no tener la capacidad de parar el
programa que se está depurando cuando se desee.
Para solucionar los problemas de la depuración directa en la consola, se debe utilizar
un emulador de Nintendo DS. Sin embargo, este entorno no tiene integrado la opción de
depurar un programa mediante el empleo de un emulador. En el caso de que se necesite utilizar un emulador para depurar un programa de NDS, dicho emulador debe ser gestionado
de forma manual. Es decir, antes del comienzo de cada proceso de depuración se debe arrancar el emulador manualmente. Por lo tanto, el funcionamiento del entorno y del emulador
son totalmente independientes entre sı́.
CAPÍTULO 4. MÉTODO DE TRABAJO
85
Para que el entorno sea capaz de soportar la depuración mediante el empleo de un
emulador, se deberá modificar el entorno. En concreto, se debe añadir está nueva funcionalidad al plug-in Zylin Embedded CDT. DeSmuME será el emulador que se integre dentro
del entorno. El motivo de esta elección se debe a que DeSmuME es el único que implementa la interfaz con el depurador GDB (gdb stubs) directamente en el propio emulador, sin
necesidad de añadir ningún código adicional a los programas de la Nintendo DS.
4.2.1.1.
Análisis del código fuente
Cuando un usuario se plantea depurar una aplicación con el plug-in Zylin Embedded
CDT, el primer paso que debe realizar es configurar las opciones de depuración. La interfaz
gráfica que proporciona este plug-in para configurar las opciones de depuración de una
aplicación se muestra en la figura 4.1. En la figura se puede ver que el plug-in tiene cinco
pestañas distintas: Main, Debugger, Commands, Source y Common.
Figura 4.1: Interfaz gráfica de Zylin Embedded CDT
Si se observa detenidamente el código del plug-in, se puede apreciar que para crear
una pestaña en la interfaz se necesita crear una clase que cumpla un requisito. El requisito
es que la clase implemente la interfaz ILaunchConfigurationTab, o bien, que esta clase
herede de alguna clase que implemente dicha interfaz. El método createTabs de la clase
LaunchConfigurationTabGroup es el encargado de la creación de las pestañas de la interfaz.
CAPÍTULO 4. MÉTODO DE TRABAJO
1
86
public void createTabs ( I L a u n c h C o n f i g u r a t i o n D i a l o g dialog ,
String mode ) {
2
MainTab main = new MainTab () ;
3
I L a u n c h C o n f i g u r a t i o n T a b [] tabs = new
I L a u n c h C o n f i g u r a t i o n T a b [] {
4
main ,
5
new E m be d d ed D e bu g g er T a b ( false ) ,
6
new CommandTab () ,
7
new SourceLookupTab () ,
8
new CommonTab ()
};
9
setTabs ( tabs ) ;
10
}
11
12
}
Cuando se ha escogido una configuración para la depuración, el usuario pulsa el
botón de depurar y se inicia el el proceso de depuración. Ası́ bien, se debe prestar atención
a la parte del código que realiza todo este proceso.
Analizando el código fuente del plug-in, se observa que la clase EmbeddedMIProcessAdapter es la encargada de crear el proceso del depurador GDB. En concreto, se realiza
en la función getGDBProcess, la cual devuelve el proceso que ha creaodo.
1
Process getGDBProcess ( String [] args , int launchTimeout ,
IProgressMonitor monitor )
El significado de los parámetros de esta función son los siguientes:
args: representa los argumentos que se le pasan a GDB en el momento de su ejecución.
launchTimeout: representa el tiempo máximo que necesita el proceso para lanzarse.
monitor: este objeto se utiliza para monitorizar el progreso de una actividad.
El problema ahora consiste en saber cómo obtiene el proceso de depuración la configuración seleccionada por el usuario. La solución se encuentra en las interfaces ILaunchConfiguration y LaunchConfigurationConstants. La primera de las interfaces se utiliza para
guardar y recuperar una configuración escogida. Una configuración no es ni más ni menos
CAPÍTULO 4. MÉTODO DE TRABAJO
87
que una serie de atributos definidos en la interfaz LaunchConfigurationConstants. La interfaz ILaunchConfiguration es la encargada de obtener los valores de estos atributos o de
establecer nuevos valores para dichos atributos. Por ejemplo, las funciones para un atributo
entero son las siguientes:
1
public void setAttribute ( String attributeName , int value )
2
public int getAttribute ( String attributeName , int defaultValue )
La clase Launch se ocupa de recuperar la configuración escogida antes de que se
inicie el proceso del depurador GDB. Dicha configuración serán los argumentos con los
que se ejecute GDB.
En la figura 4.2 se muestra el diagrama de clases de la parte del plug-in que se acaba
de analizar.
Figura 4.2: Diagrama de clases de una parte del plug-in Zylin Embedded CDT
CAPÍTULO 4. MÉTODO DE TRABAJO
4.2.2.
88
Construcción del diagrama de casos de uso
Una vez se ha identificado el alcance del entorno cruzado de desarrollo, se procederá a la construcción de la vista funcional del sistema (véase figura 4.3, que se implementará en la forma de un diagrama de casos de uso.
Se puede deducir la presencia del actor Alumno, que será la persona que utilice el
entorno. Puesto que el sistema permite la depuración remota, se puede identificar el actor
Otro dispositivo. Además, el sistema también permite la depuración mediante el uso de un
emulador, por lo que también se puede identificar el actor DeSmuME.
Se ha añadido el caso de uso Depurar mediante emulador para completar las funcionalidades ya existentes. Este nuevo caso de uso está incluido dentro de Depurar remotamente. En general, las funcionalidades o casos de uso que se han identificado en el sistema
son las siguientes:
Editar texto
Compilar aplicación
Compilar para ARM7
Compilar para ARM9
Depurar aplicación
Depurar remotamente
Depurar mediante emulador
El caso de uso Depurar mediante emulador es el único que no se ha desarrollado.
Por tanto, en los próximos apartados se llevarán a cabo las fases n
4.2.3.
Fase de análisis
Descripción textual de casos de uso
Además de gráficamente, los casos de uso se especificarán textualmente, en documentos que expliquen de manera clara el requisito funcional que están representando. Se va
a utilizar una plantilla en forma de tabla, diseñada para contener la información significativa
de cada caso de uso [19].
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.3: Vista funcional del entorno cruzado de desarrollo
89
CAPÍTULO 4. MÉTODO DE TRABAJO
90
Descripción del caso de uso Depurar mediante emulador
En la figura 4.4 se muestran las posibles clases de análisis identificadas para este
caso de uso. En este caso de uso intervienen dos entidades. Una se encarga de guardar
la configuración de la depuración elegida por el usuario (entidad DesmumeTab). La otra
entidad (Lanzador) se encarga de obtener la configuración de la depuración antes de que
se ejecute el emulador DeSmuME. El controlador Proceso es el responsable de arrancar el
emulador.
Figura 4.4: Clases de análisis involucradas en el caso de uso Depurar mediante emulador
La descripción textual se muestra en la tabla 4.1. En este caso de uso existe sólo un
flujo de eventos.
4.2.4.
Fase de diseño
Desarrollo del caso de uso Depurar mediante emulador
Una vez se ha realizado la descripción textual del caso de uso, lo siguiente será proceder a su desarrollo. Para ello, se construirá el diagrama de secuencia de análisis del flujo
de eventos normal, representando ası́ el escenario de ejecución del caso de uso (véase la
figura 4.5.
El diálogo de configuración del proceso de depuración original del plug-in, no es
suficiente para soportar el empleo de un emulador. Ası́, se debe modificar dicho diálogo
agregando una nueva pestaña con opciones exclusivas para DeSmuME. Además, se deberán
retocar algunas pestañas existentes para no perder ninguna funcionalidad original del plugin. En la figura 4.6 se muestra el diagrama de clases de la parte del plug-in una vez que se
han realizado todos los cambios.
CAPÍTULO 4. MÉTODO DE TRABAJO
Nombre: Depurar mediante emulador
Abstracto: No
Precondiciones:
No existe un proceso de depuración con DeSmuME iniciado.
Postcondiciones:
Se inicia un proceso de depuración con el emulador DeSmuME.
Rango: 1
Flujo normal:
1. El alumno seleciona las opciones que se utilizarán para la depuración mediante
DeSmuME en el diálogo Configurar depuración y pulsa el botón Depurar. Las
opciones elegidas se guardan en la entidad DesmumeTab.
2. El controlador Proceso crea la entidad Lanzador, que se encarga de recuperar la
configuración escogida.
3. El controlador arranca el emulador DeSmuME en un nuevo proceso.
Descripción:
Este caso de uso se ocupa de gestionar la depuración de una aplicación utilizando el
emulador DeSmuME.
Tabla 4.1: Descripción textual del caso de uso Depurar mediante emulador
Figura 4.5: Diagrama de secuencia correspondiente al flujo normal
91
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.6: Diagrama de clases modificado del plug-in Zylin Embedded CDT
92
CAPÍTULO 4. MÉTODO DE TRABAJO
4.2.5.
93
Fase de implementación
Depurar mediante emulador
En primer lugar, se necesita modificar la interfaz gráfica. En concreto, se deben
modificar algunos aspectos de varias pestañas y agregar una nueva. En esta nueva pestaña
se mostrarán las opciones que acepta DeSmuME para la depuración.
Para crear la nueva pestaña se creará una nueva clase DesmumeTab, la cual herederá de la clase CLaunchConfigurationTab. El constructor de esta clase tiene un parámetro
de tipo MainTab. Este parámetro será utilizado para obtener el nombre del proyecto que se
va a depurar. La definición de las principales operaciones utilizadas de esta clase se muestran a continuación:
1
public DesmumeTab ( MainTab main )
2
public void createControl ( Composite parent )
3
public void c re a t eO p t io n D es m u me ( Composite parent , int i )
4
public void createArm9Option ( Composite comp , int i )
5
public void createArm7Option ( Composite comp , int i )
6
public void setDefaults ( I L a u n c h C o n f i g u r a t i o n W o r k i n g C o p y
configuration )
7
public void initializeFrom ( I L a u n c h C o n f i g u r a t i o n configuration )
8
public void performApply ( I L a u n c h C o n f i g u r a t i o n W o r k i n g C o p y
configuration )
9
public String getNDSFileName ( String projectpath )
10
public String getName ()
11
public String getProjectName ()
La utilidad de estas funciones se explica a continuación:
DesmumeTab: es el contructor de la clase.
createControl: esta función crea los controles de alto nivel para la pestaña DeSmuME
a partir de la clase Composite pasado como parámetro. Las instancia de dicha clase
son controles capaces de contener otros controles. Dentro de esta función se llama
a otras especı́ficas, las cuales construyen partes especı́ficas de la pestaña: createOptionDesmume, createArm9Option y createArm7Option.
setDefaults: inicializa la configuración de la pestaña con valores por defecto.
initializeFrom: inicializa los controles de la pestaña con los valores obtenidos de la
configuración por defecto.
CAPÍTULO 4. MÉTODO DE TRABAJO
94
performApply: copia los valores de los controles de la pestaña en la configuración del
lanzador.
getNDSFileName: obtiene el nombre del archivo .nds que será pasado a DeSmuME
como argumento.
getName: devuelve el nombre de la pestaña.
getProjectName: obtiene el nombre del proyecto que se depurará a partir de la instancia de tipo MainTab.
Cuando se inicie el proceso de depuración, deberá estar arrancado DeSmuME. Para
ello, se deberá modificar la clase EmbeddedMIProcessAdapter. Ası́, antes de que se cree
el proceso del depurador GDB, se creará el proceso que inicie DeSmuME. Con el fin de
realizar esta tarea se ha agregado la función desmumeProcess a dicha clase.
1
Process desmumeProcess ( String [] args , int launchTimeout ,
IProgressMonitor monitor )
La utilidad de cada uno de los parámetros de la función es la siguiente:
args: son los argumentos con los que se ejecutará DeSmuME.
launchTimeout: tiempo que necesita el proceso para lanzarse.
monitor: representa un objeto que monitoriza el progreso de una actividad.
Además, la función destroy EmbeddedMIProcessAdapter se ha modificado para que
destruya tanto el proceso del depurador GDB como el proceso del emulador DeSmuME
cuando se el usuario detenga la depuración.
La clase Launch es la encargada de obtener la configuración del depurador GDB y
del emulador DeSmuME. Para obtener la configuración de DeSmuME ha sido necesario
agregar a esta clase las siguientes funciones:
1
public String [] getDesmumeArgs ( I L a u n c h C o n f i g u r a t i o n
configuration ) ;
2
public String [] getDesmumeArgs () ;
3
public boolean getOptionDesmume () ;
La primera y la segunda función se utilizan para obtener los argumentos con los que
se ejecutará DeSmuME. La tercera función indica si se desea utilizar el emulador durante
el proceso de depuración.
CAPÍTULO 4. MÉTODO DE TRABAJO
4.2.6.
95
Pruebas
A partir de los diagramas de secuencia, se pueden definir casos de prueba. Para ello,
se utilizará una plantilla en forma de tabla como la siguiente:
Identificación del caso de prueba: 1
Caso de uso / Flujo de eventos: Depurar mediante emulador / Flujo normal
Condiciones de ejecución:
El depurador no debe estar arrancado.
Descripción:
Se inicia el proceso de depuración utilizando el emulador DeSmuME.
Resultado esperado:
Se inicia DeSmueME antes de inciarse el proceso del depurador GDB.
Resultado obtenido:
Correcto
Tabla 4.2: Caso de prueba 1, “en positivo”
4.3.
Construcción del editor de fondos
4.3.1.
Construcción del diagrama de casos de uso
Una vez se ha identificado el alcance de la aplicación de edición de fondos, se procederá a la construcción de la vista funcional del sistema (véase figura 4.7), que se implementará en la forma de un diagrama de casos de uso.
Se puede deducir la existencia del actor Alumno, que será la persona que utilice la
aplicación. Dado que el sistema permite crear un fondo a partir de una imagen, se puede
deducir la presencia del actor Imagen. Para que el sistema pueda crear un fondo a partir de
una imagen, se necesita realizar un conversión de dicha imagen en datos “entendibles”. De
ahı́ la necesidad del actor Grit, el cual genera estos datos a partir de una imagen. Además, en
el sistema se permite la generación de ficheros a partir de un fondo pintado en la aplicación.
Estos ficheros serán archivos de texto, los cuales pueden ajustarse al formato que el alumno
elija.
Respecto de los casos de uso, se han identificado las siguientes funcionalidades en
el sistema:
Abrir imagen
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.7: Vista funcional del editor de fondos
96
CAPÍTULO 4. MÉTODO DE TRABAJO
97
Crear fondo
Crear teselado
Crear extended rotoscale
Crear framebuffer
Modificar paleta
Cambiar color
Agregar color nuevo
Intercambiar colores
Modificar tesela
Modificar fondo
Generar datos NDS
4.3.2.
Priorización de casos de uso
Se ha establecido un orden de priorización de los casos de uso del sistema. Dicho
orden atiende a la necesidad de un caso de uso para implementar otro. Con este criterio, se
ha programado la siguiente ordenación:
1. Abrir imagen
2. Crear fondo
3. Crear framebuffer
4. Crear extended rotoscale
5. Crear teselado
6. Modificar paleta
7. Cambiar color
8. Agregar color nuevo
9. Intercambiar colores
CAPÍTULO 4. MÉTODO DE TRABAJO
98
10. Modificar tesela
11. Modificar fondo
12. Generar datos NDS
Una vez se ha realizado la ordenación de los casos de uso, se debe planificar un conjunto de iteraciones, y ubicar en cada una de ellas un conjunto de casos de uso. Asimismo,
se intentará colocar los casos de uso más o menos similares en cada iteración, de manera
que el fragmento de sistema que se lleve construido sea funcionalmente correcto.
Con estas consideraciones, la primera versión del plan de iteraciones se muestra en
la tabla 4.3:
Fase
Iteración
Caso de uso
Comienzo
1
Elaboración
2
Abrir imagen
Crear fondo
Crear framebuffer
Crear extended rotoscale
Abrir imagen
Crear fondo
Crear framebuffer
Crear teselado
Crear extended rotoscale
Crear teselado
Modificar paleta
Cambiar color
Modificar tesela
Agregar color nuevo
Intercambiar colores
Modificar fondo
Modificar paleta
Cambiar color
Modificar tesela
Agregar color nuevo
Intercambiar colores
Modificar fondo
Generar datos NDS
Modificar fondo
Generar datos NDS
3
4
5
6
Construcción
7
8
Transición
9
10
Tabla 4.3: Plan de iteraciones
Flujos de trabajo
R A D I P
X X
X X
X X
X X
X X X X
X X X X
X X X X
X X
X X X X
X X X X
X X
X X
X X
X X
X X
X X
X X X X
X X X X
X X X X
X X X X
X X X X
X X X X
X X X X X
X X
X X
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.3.
99
Iteración 1
De acuerdo con el plan de iteraciones, en esta iteración se realizará el análisis de requisitos de los casos de uso Abrir imagen, Crear fondo, Crear framebuffer y Crear extended
rotoscale. Esta iteración constituye la fase de comienzo del proyecto.
4.3.3.1.
Fase de análisis
Descripción del caso de uso Abrir imagen
La figura 4.8 muestra las posibles clases de análisis identificadas para este caso de
uso. El elemento más importantes que interviene en la ejecución de este caso de uso es el
controlador, que es el encargado de comprobar que el tamaño de la imagen es adecuado
para el fondo que se ha seleccionado. Si la anchura o la altura, o ambas, no cumple con los
requisitos del fondo, entonces se mostrará en un diálogo un mensaje de error. Este caso de
uso tiene relación con el caso de uso Crear fondo.
Figura 4.8: Clases de análisis involucradas en el caso de uso Abrir imagen
La descripción textual se muestra en la tabla 4.4. En este caso de uso existe un flujo
normal y otro alternativo. El flujo alternativo corresponde al caso en que la imagen no se
ajusta con los requisitos de tamaño del fondo seleccionado.
Descripción del caso de uso Crear fondo
Este caso de uso es abstracto y se encarga de mostrar en la ventana un fondo de
cualquiera de los tipos posibles. En este caso de uso interviene la entidad Proxy, la cual se
explicará con detalle en la siguiente iteración. La figura 4.9 muestra las posibles clases de
análisis identificadas para este caso de uso abstracto.
La descripción textual de este caso de uso se muestra en la tabla 4.5.
Descripción del caso de uso Crear framebuffer
Este caso de uso no añade ninguna clase propia de análisis, pero hereda todas las
clases de análisis identificadas en el caso de uso Crear fondo.
La descripción textual de este caso de uso se muestra en la tabla 4.6.
CAPÍTULO 4. MÉTODO DE TRABAJO
100
Nombre: Abrir imagen
Abstracto: No
Precondiciones:
Postcondiciones:
Rango: 1
Flujo normal:
1. El alumno selecciona en el diálogo una imagen y el tipo de fondo que quiere crear.
2. El diálogo le pasa al controlador del caso de uso los datos introducidos.
3. El controlador comprueba que el tamaño de la imagen es válido para el fondo
seleccionado.
4. El controlador le envı́a los datos introducidos al caso de uso Crear fondo, el cual se
ejecuta a continuación.
Flujo alternativo 1:
1. El alumno selecciona en el diálogo una imagen y el tipo de fondo que quiere crear.
2. El diálogo le pasa al controlador del caso de uso los datos introducidos.
3. El controlador comprueba que el tamaño de la imagen no es válido para el fondo
seleccionado.
4. Se muestra un mensaje de error en el diálogo.
Descripción:
Tabla 4.4: Descripción textual del caso de uso Abrir imagen
Figura 4.9: Clases de análisis involucradas en el caso de uso Crear fondo
CAPÍTULO 4. MÉTODO DE TRABAJO
Nombre: Crear fondo
Abstracto: Sı́
Precondiciones:
Existe una imagen y un fondo seleccionados. Dicha imagen tiene la altura y la
anchura acorde con el tipo de fondo elegido.
Postcondiciones:
1. Se muestra en la ventana los datos del fondo según el tipo elegido.
Rango: 2
Flujo normal:
1. El controlador recibe la ruta de la imagen y el tipo de fondo del controlador del
caso de uso Abrir imagen.
2. El controlador envı́a al proxy el tipo de fondo y la ruta de la imagen.
3. El controlador solicita al proxy los datos del fondo.
4. El proxy le dice a la herramienta Grit que se ejecute con las opciones que ha
recibido del controlador.
5. El proxy envı́a los datos al controlador.
6. El controlador crea las instancias necesarios según el fondo.
7. El controlador le pasa a la ventana los datos del fondo.
8. Se muestran en la ventana los datos del fondo.
Descripción:
Este caso de uso se encarga de mostrar los datos del fondo en la ventana. Estos datos
se mostrarán de una manera u otra dependiendo del tipo de fondo.
Tabla 4.5: Descripción textual del caso de uso Crear fondo
101
CAPÍTULO 4. MÉTODO DE TRABAJO
102
Nombre: Crear framebuffer
Abstracto: No
Precondiciones:
Existe una imagen y un fondo seleccionados. Dicha imagen tiene la
altura y la anchura acorde con fondo de tipo framebuffer.
Postcondiciones:
1. Se muestra en la ventana un fondo de tipo framebuffer.
Rango: 3
Flujo normal:
1. El controlador recibe la ruta de la imagen y el tipo de fondo igual a framebuffer del
controlador del caso de uso Abrir imagen.
2. El controlador envı́a al proxy el tipo de fondo y la ruta de la imagen.
3. El controlador solicita al proxy los datos del fondo.
4. El proxy le dice a la herramienta Grit que se ejecute con las opciones que ha
recibido del controlador.
5. El proxy envı́a los datos al controlador.
6. El controlador le pasa a la ventana los datos del fondo.
7. Se muestran en la ventana los datos del fondo framebuffer.
Descripción:
Este caso de uso se encarga de mostrar los datos del fondo framebuffer en la ventana.
Tabla 4.6: Descripción textual del caso de uso Crear framebuffer
CAPÍTULO 4. MÉTODO DE TRABAJO
103
Descripción del caso de uso Crear extended rotoscale
Este caso de uso además de heredar las clases de análisis identificadas en el caso de
uso Crear fondo, se utiliza la entidad Paleta (véase figura 4.10).
Figura 4.10: Clases de análisis involucradas en el caso de uso Crear extended rotoscale
La descripción textual se muestra en la tabla 4.7.
Nombre: Crear extended rotoscale
Abstracto: No
Precondiciones:
Existe una imagen y un fondo seleccionados. Dicha imagen tiene la altura y la
anchura acorde con el fondo de tipo extended rotoscale.
Postcondiciones:
1. Se muestra en la ventana un fondo de tipo extended rotoscale.
Rango: 4
Flujo normal:
1. El controlador recibe la ruta de la imagen y el tipo de fondo igual a extended
rotoscale del controlador del caso de uso Abrir imagen.
2. El controlador envı́a al proxy el tipo de fondo y la ruta de la imagen.
3. El controlador solicita al proxy los datos de la paleta y del fondo.
4. El proxy le dice a la herramienta Grit que se ejecute con las opciones que ha
recibido del controlador.
5. El proxy envı́a los datos al controlador.
6. El controlador crea una instancia de Paleta.
7. El controlador le pasa a la ventana los datos del fondo y de la paleta.
8. Se muestran en la ventana los datos y la paleta del fondo.
Descripción:
Este caso de uso se encarga de mostrar los datos y la paleta del fondo extended
rotoscale en la ventana.
Tabla 4.7: Descripción textual del caso de uso Crear extended rotoscale
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.4.
104
Iteración 2
La fase de elaboración comienza con esta iteración. Según el plan de iteraciones, en
esta iteración se realizará la fase de diseño, implementación y pruebas de los casos de uso
Abrir imagen, Crear fondo y Crear framebuffer.
4.3.4.1.
Fase de Diseño
Utilización del patrón Modelo Vista Presentador
El patrón Modelo Vista Presentador (MVP) [13] es un patrón orientado a la construccion de interfaces usuario que realiza la separacion de la logica de negocios de la logica
de presentacion. En el MVP, el objetivo de la vista es capturar y manejar las eventos lanzados por el usuario, los cuales se envı́an directamente al presentador, el cual sabe qué hacer
con cada uno de ellos. El presentador se comunica con el modelo y se coordina con los
controles de la vista para la presentación de los datos (véase figura 4.11 y 4.12).
Figura 4.11: Diagrama de secuencia del patrón MVP [13]
Es importante mencionar que el MVP facilita la realización de pruebas de la lógica
de presentación sin la necesidad de que el usuario intervenga en los tests.
El sistema actual constará de cuatro tipos de vistas diferentes, una para la presentación de la paleta, una para la presentación de todas las teselas, otra para la presentación del
mapa y otra para la presentación de la tesela en edición. Cada una de las vistas tendrá una relación de generalización con la clase abstracta IVista. En cuanto al número de presentadores
existentes en el sistema, habrá un presentador diferente por cada vista. Por tanto, existirán
CAPÍTULO 4. MÉTODO DE TRABAJO
105
Figura 4.12: Diagrama de clases del patrón MVP [13]
4 presentadores, cada uno de los cuales heredará de la clase abstracta IPresenter. En la capa de dominio se incluirán las clases Paleta y Tesela, las cuales implementan la interfaz
Objeto (véase la figura 4.13). El presente patrón es de gran utilidad para el actual sistema
en desarrollo, ya que cada vez que se modifique algún elemento de la capa de dominio
inmediatamente se actualizarán las vistas que se vean afectadas por dicha modificación.
Se debe señalar que el presentador PresenterMap tiene una relación de asociación
no navegable con la interfaz Objeto. Dependiendo del modo gráfico con el que se trabaje,
dicho presentador puede trabajar con paletas (modo extended rotoscale) o con teselas (modo
teselado).
Desarrollo del caso de uso Abrir imagen
Una vez se ha realizado la descripción textual del primer caso de uso del plan de
iteraciones, lo siguiente será proceder a su desarrollo. Para ello, se construirá un diagrama de
secuencia de análisis por cada flujo de eventos, representando ası́ los diferentes escenarios
de ejecución del caso de uso.
En la figura 4.14 se puede observar el diagrama de secuencia del flujo normal del
caso de uso Abrir imagen. Nótese que en este escenario, una vez se ha comprobado que la
altura y la anchura de la imagen son correctas para el fondo elegido, se pasan los datos al
CAPÍTULO 4. MÉTODO DE TRABAJO
106
Figura 4.13: Construcción del diagrama de clases del sistema utilizando el patrón MVP
Figura 4.14: Diagrama de secuencia correspondiente al flujo normal
CAPÍTULO 4. MÉTODO DE TRABAJO
107
controlador del caso de uso Crear fondo.
Figura 4.15: Diagrama de secuencia correspondiente al flujo alternativo
En la figura 4.15 se muestra el diagrama de secuencia correspondiente al flujo alternativo del presente caso de uso. Una vez que el diálogo comprueba que la imagen tiene
el tamaño incorrecto para el tipo de fondo elegido, se muestra un mensaje de error en otro
diálogo.
Desarrollo del caso de uso Crear fondo con un Builder
El patrón Builder (Constructor) [10] se utiliza cuando existe un conjunto de varias
jerarquı́as de herencia y debe crearse un “lote” de objetos, formado por un conjunto de
especializaciones de estas clases de la jeraquı́a.
Tal conjunto de jerarquı́as existe en este caso, ya que se dispone de dos clases abstractas (IModo y IVista) con varias especializaciones cada una. En función del subtipo de
la clase IModo, se deben crear unas instancias u otras de la otra clase (IVista), también con
el subtipo adecuado. Con este patrón, se asigna a uno de los objetos del lote la responsabilidad de crear el resto de objetos, que serán instancias de alguno de los subtipos del resto de
jerarquı́as de herencia (véase la figura 4.16).
Al utilizar este patrón se incluye habitualmente una clase (a la que se conoce con el
nombre de Director) que se encarga de la creación del builder. Antes de dicha creación, el
builder se debe instanciar al subtipo concreto. Esta tarea se lleva a cabo en la clase Cliente.
Para este caso de uso sólo será preciso crear un diagrama de secuencia. En concreto,
se creará para el flujo normal del caso de uso (véase la figura 4.17). En el diagrama de clases de análisis de este caso de uso se identificó una clase Controller, la cual era demasiado
general. Para mantener la coherencia con los patrones utilizados, dicha clase se ha descompuesto en nuevas clases de análisis, las cuales forman un diagrama algo más complejo que
el identificado en un primer término en la fase de análisis de requisitos.
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.16: Diagrama de clases utilizando el patrón Builder
Figura 4.17: Diagrama de secuencia correspondiente al flujo normal
108
CAPÍTULO 4. MÉTODO DE TRABAJO
109
En el diagrama de secuencia anterior se puede observar que existe una entidad llamada Proxy. El Proxy [10] es aplicable en bastantes situaciones comunes. Una de las más
habituales es utilizar este patrón como intermediario para acceder a un dispositivo externo,
permitiendo controlar el acceso a él. Sin embargo, en este caso, se utilizará cómo un proxy
virtual, el cual se encarga de crear objetos costosos bajo demanda. En este caso los objetos
costosos podrán ser, según el tipo de fondo, los datos del mapa, los datos de la paleta y
los datos de las teselas. Dichos datos serán generados por Grit. En la figura 4.18 se puede
observar como serı́a la parte del sistema diseñada utilizando el patrón Proxy.
Figura 4.18: Diagrama de clases utilizando el patrón Proxy
Desarrollo del caso de uso Crear framebuffer
Este caso de uso no tiene ningún flujo de eventos alternativo. Por tanto, sólo se
creará un diagrama de secuencia de análisis, el correspondiente al flujo normal de eventos
(véase figura 4.19). Al igual que en el caso de uso Crear fondo, el controlador se ha dividido
en otras clases de análisis más especı́ficas con el objetivo de adaptarse a los patrones que se
están utilizando.
En este tipo de fondo los datos que se obtienen del proxy son únicamente los correspondientes al fondo, ya que en el fondo framebuffer no intervienen ni paletas ni teselas.
4.3.4.2.
Fase de implementación
La implementación se ha realizado utilizando el lenguaje de programación C++,
entre otras razones, por su eficiencia, rapidez y por las liberı́as que permite utilizar para
el trabajo con imágenes. Sin duda, las más importantes para este sistema son GooCanvas,
GdkPixbuf, y GModule.
La liberı́a GdkPixbuf [17] trabaja con “buffer de pixels” (pixbuf) y permite almacenar en memoria la información de una imagen. Ası́, las principales posibilidades que proporciona son: cargar una imagen en memoria, guardar un pixbuf en un archivo de imagen y
trabajar con subgrupos de pixels de un pixbuf.
CAPÍTULO 4. MÉTODO DE TRABAJO
110
Figura 4.19: Diagrama de secuencia correspondiente al flujo normal
GooCanvas [32] es un canvas para GTK+ que usa la librerı́a 2D Cairo para dibujar.
Entre sus caracterı́sticas destacan el manejo de eventos, los elementos básicos de los que
consta y la posibilidad de utilizar el “zoom” sobre sus elementos.
La liberı́a GModule [33] proporciona las funciones necesarias para la carga de objetos (también conocidos como “plug-ins”) dinámicamente. Esta liberı́a es sumamente útil
para este sistema porque es la que permite la carga en memoria de los datos generados por
Grit.
En esta fase se explicará cómo se han implementado las partes más importantes de
los casos de uso.
Abrir imagen
Este caso de uso se ejecuta cuando el alumno pulsa el botón Abrir en la ventana principal de la aplicación. En ese preciso momento se emite la señal siguiente y es capturada:
1
static void o n _ a b r i r B u t t o n _ c l i c k e d ( GtkToolButton * toolbutton ,
gpointer data ) ;
Una vez que la señal se ha capturado, se realizan cuatro acciones principalmente:
CAPÍTULO 4. MÉTODO DE TRABAJO
111
Se muestra un diálogo de selección de imágenes.
Se muestra un diálogo de selección del tipo de fondo (véase la figura 4.20).
Se comprueba si tamaño de la imagen es adecuado con el fondo elegido. En caso de
ser incorrecto se muestra un mensaje de error. En otro caso se creará un nuevo fondo.
Figura 4.20: Diálogo de selección del tipo de fondo
Cuando se crea un nuevo fondo, el controlador de este caso de uso (clase Cliente)
se deberá comunicar con el controlador del caso de uso Crear fondo (clase Director). Todo
esto se realiza creando un objeto de la clase Cliente, cuyo constructor tiene la siguiente
forma:
1
Cliente ( Parametros & args ) ;
El constructor recibe como único argumento una estructura llamada Parametros.
Esta estructura se ha definido de la siguiente forma:
1
typedef struct {
2
std :: string filename ;
3
std :: string modo ;
4
} Parametros ;
La estructura Parametros tiene dos campos: uno que se utiliza para almacenar la ruta
una la imagen y otro que guarda el tipo de fondo que se quiere crear.
El código del constructor de la clase Cliente es muy simple y es siguiente:
CAPÍTULO 4. MÉTODO DE TRABAJO
1
Cliente :: Cliente ( Parametros & args )
2
{
3
this - > director = new Director ;
4
new_window ( args ) ;
5
112
}
La función new window es la responsable de crear una nueva ventana, la cual será de
un tipo u otro dependiendo del valor del argumento que se le pasa como parámetro.
1
void new_window ( Parametros & args ) ;
Crear fondo
Como se ha comentado anteriormente, este caso de uso se ha construido utilizando
el patrón Builder. La construcción del builder tiene lugar en la operación new window de
la clase Cliente, la cual tiene como argumento único la dirección de una estructura de tipo
Parametros:
1
void new_window ( Parametros & args ) ;
En esta operación se instancia el builder al subtipo concreto y, posteriormente, la clase Director se encarga de su creación. La parte del código que se encarga de la instanciación
al subtipo concreto es la siguiente:
1
...
2
if ( ! args . modo . compare ( " teselado16 " ) ) { // teselado 16
colores
builder = new ModoTeselado ( args . filename , 16) ;
3
4
}
5
else if ( ! args . modo . compare ( " teselado256 " ) ) { // teselado
256 colores
builder = new ModoTeselado ( args . filename , 256) ;
6
7
}
8
else if ( ! args . modo . compare ( " framebuffer " ) ) { // framebuffer
9
builder = new ModoFramebuffer ( args . filename ) ;
CAPÍTULO 4. MÉTODO DE TRABAJO
10
}
11
else if ( ! args . modo . compare ( " rotoscale " ) ) { // extended
113
rotoscale
builder = new ModoRotoscale ( args . filename ) ;
12
13
} else {
g_error ( " Error : modo %s desconocido \ n " , args . filename .
14
c_str () ) ;
15
}
16
...
Todos los subtipos de la clase IModo tienen como primer argumento una cadena
(std::string) en la que se especifica la ruta de una imagen. Además, el modo teselado especifica un segundo argumento de tipo entero en el cual se indica el número de colores
utilizados para dibujar cada tesela (16 o 256).
La operación de creación se encarga de la construcción de cada una de las vistas y
se ha implementado de la siguiente forma:
1
void Director :: construir ()
2
{
3
this - > builder - > build_vpaleta () ;
4
this - > builder - > build_vteselas () ;
5
this - > builder - > build_vmapa () ;
6
this - > builder - > build_veditar () ;
7
}
Se debe señalar que cada una de las funciones de creación de las vistas (build vpaleta,
build vteselas, build vmapa y build veditar), se redefine en cada uno de los subtipos de la
clase IModo.
Todo este proceso que se ha descrito, se realiza durante la creación de cualquier tipo
de fondo. Las diferencias surgen en la creación de cada una de las vistas, ya que cada modo
tiene su propia idiosincrasia. La explicación de estas diferencias se realizarán durante la
implementación de cada uno los tipos de fondo existentes.
1
void PresenterMap :: d ib u j ar _ f ra m e bu f f er ()
2
{
vistas [ " map " ] - > update (0 , 0 , this - > pixbuf ) ;
3
4
}
CAPÍTULO 4. MÉTODO DE TRABAJO
114
La función update se ha sobrecargado en la clase IVista. En concreto, la función del
código anterior se utiliza para mostrar el pixbuf pasado como argumento en la posición
(x,y) del mapa. Su definición es la siguiente:
1
void update ( int x , int y , GdkPixbuf * pixbuf ) ;
Crear framebuffer
Este caso de uso hereda la implementación del builder del caso de uso Crear fondo. Por la propia naturaleza de este tipo de fondo, sólo se necesita redefinir el método
build vmapa, el cual se muestra a continuación:
1
void ModoFramebuffer :: build_vmapa ()
2
{
IPresenter * pres = new PresenterMap ( filename , "
3
framebuffer " ) ;
VistaMapa * vmapa = new VistaMapa ( pres , xml , filename , "
4
framebuffer " ) ;
pres - > subscribe ( " map " , vmapa ) ;
5
6
if ( filename . size () ) {
7
vmapa - > cargar ( proxy - > get_datos_mapa () ) ;
8
}
9
10
11
presenter [ " map " ] = pres ;
12
vistas [ " map " ] = vmapa ;
13
}
Los métodos de construcción de vistas (build vpaleta, build vteselas, build vmapa y
build veditar) que son redefinidos por cada tipo de fondo, tienen la misma estructura. Cada
uno de estos métodos realiza las tres acciones siguientes:
En primer lugar, se crea el presentador y la vista con el subtipo adecuado de IPresenter y de IVista, respectivamente. Una vez construidos, el presentador se encarga de
registrar (subscribe) la vista o vistas que quieren ser informadas cuando haya algún
cambio en el modelo.
CAPÍTULO 4. MÉTODO DE TRABAJO
115
En segundo lugar, el proxy se encarga de obtener los datos del mapa (get datos mapa),
los cuales han sido generados por Grit.
En tercer lugar, la vista se ocupa de iniciar la carga de los datos que obtiene del proxy.
El proxy se comporta como un intermediario entre la vista y grit. Su funcionamiento,
básicamente, consiste en solicitar datos a grit e ir devolviéndoselos a la vista. Tanto el proxy
(clase GritProxy) como grit (clase Grit) heredan la misma interfaz (IProxy), la cual publica
las principales operaciones siguientes:
1
std :: vector < unsigned int > get_datos_paleta () ;
2
std :: vector < unsigned int > get_datos_mapa () ;
3
std :: vector < unsigned int > g et_dat os_tes elas () ;
4
void convertir ( std :: string imagen , std :: string optn ,
std :: string output , std :: string header )
5
;
Las tres primeras operaciones se encargan de solicitar datos, mientras que la última
se utiliza para la conversión de un fondo en archivos de texto. Se explicará con detalle esta
última operación durante la implementación del caso de uso Generar datos NDS.
El proceso de solicitud de los datos del mapa (get datos mapa) es muy sencillo. En
primer lugar, se comprueba si se ha instanciado el objeto grit. En caso negativo, se instancia
llamando al constructor apropiado. Por último, se llama a la operación get datos mapa de
dicho objeto.
1
std :: vector < unsigned int > GritProxy :: get_datos_mapa ()
2
{
if (! grit ) {
3
if (! modo . compare ( " framebuffer " ) )
4
grit = new Grit ( filename , modo ) ;
5
else if (! modo . compare ( " rotoscale " ) )
6
grit = new Grit ( filename , modo , 256) ;
7
else
8
grit = new Grit ( filename , modo ,
9
n_colores ) ;
10
}
11
return grit - > get_datos_mapa () ;
12
}
CAPÍTULO 4. MÉTODO DE TRABAJO
116
La clase Grit es la encargada de realizar la ejecución de la herramienta Grit y de cargar en memoria los datos de los archivos que se generan tras la ejecución (liberı́a GModule).
Estos datos son simplemente vectores de enteros sin signo (unsigned int).
En cuanto a la carga de datos por parte de la vista, se debe aclarar que la vista en
sı́ misma no carga los datos. El proceso es algo más complejo. Como se está utilizando el
patrón MVP, la vista únicamente se encarga de lo relacionado con la interfaz gráfica. Para
tratar con el modelo ya está el presentador (clase IPresenter). De este modo, la vista se
ocupa de realizar las llamadas al presentador, que es quien creará o modificará los objetos
del modelo (teselas o paletas).
1
void VistaMapa :: cargar ( std :: vector < unsigned int > datos )
2
{
3
...
4
this - > pres - > cargar ( datos ) ;
5
}
La función cargar del presentador no crea ninguna instancia del modelo, ya que no
se utilizan ni paletas ni teselas. La definición de esta función de la clase IPresenter es la
siguiente:
1
void cargar ( std :: vector < unsigned int > datos ) ;
En esta función se crea una variable de tipo GdkPixbuf a partir del archivo de la
imagen y le indica a la vista del mapa que se actualice por medio de la función:
1
void update ( int x , int y , GdkPixbuf * pixbuf ) ;
4.3.4.3.
Pruebas
A partir de los diagrama de secuencias, se puede definir casos de prueba. Para ello,
se utilizará una plantilla en forma de tabla como la siguiente:
4.3.5.
Iteración 3
En esta iteración se realizará la fase de análisis de requisitos del caso de uso Crear
teselado. De acuerdo con el plan de iteraciones, también se realizará la fase de diseño, la
fase de implementación y la fase de pruebas del caso de uso Crear extended rotoscale.
CAPÍTULO 4. MÉTODO DE TRABAJO
Identificación del caso de prueba: 1
Caso de uso / Flujo de eventos: Abrir imagen / Flujo normal
Condiciones de ejecución:
Descripción:
El alumno indica en la ventana la ruta de una imagen y el tipo de fondo que se creará
a partir de la imagen.
Resultado esperado:
La altura y la anchura de la imagen son aceptados por el tipo de fondo seleccionado.
Resultado obtenido:
Correcto
Tabla 4.8: Caso de prueba 1, “en positivo”
Identificación del caso de prueba: 2
Caso de uso / Flujo de eventos: Abrir imagen / Flujo alternativo
Condiciones de ejecución:
Descripción:
El alumno indica en la ventana la ruta de una imagen y el tipo de fondo que se creará
a partir de la imagen.
Resultado esperado:
Se muestra un diálogo de error en el que se indica que el tamaño
de la imagen no es correcto para el tipo de fondo seleccionado.
Resultado obtenido:
Correcto
Tabla 4.9: Caso de prueba 2, “en negativo”
Identificación del caso de prueba: 3
Caso de uso / Flujo de eventos: Crear fondo / Flujo normal
Condiciones de ejecución:
El alumno ha seleccionado una imagen y un tipo de fondo adecuados.
Descripción:
Se crean los datos de un fondo a partir de la imagen y el tipo elegidos.
Resultado esperado:
Se muestran los datos de un fondo en la ventana.
Resultado obtenido:
Correcto
Tabla 4.10: Caso de prueba 3, “en positivo”
117
CAPÍTULO 4. MÉTODO DE TRABAJO
118
Identificación del caso de prueba: 4
Caso de uso / Flujo de eventos: Crear framebuffer / Flujo normal
Condiciones de ejecución:
El alumno ha seleccionado una imagen con un tamaño adecuado para un
fondo de tipo framebuffer.
Descripción:
Se crean los datos de un fondo framebuffer a partir de la imagen y el tipo
elegidos.
Resultado esperado:
Se muestran los datos de un fondo framebuffer en la ventana.
Resultado obtenido:
Correcto
Tabla 4.11: Caso de prueba 4, “en positivo”
4.3.5.1.
Fase de análisis
Descripción del caso de uso Crear teselado
Este caso de uso hereda las clases de análisis identificados en el caso de uso Crear
fondo y, además, agrega las entidades Tesela y Paleta (véase figura 4.21).
Figura 4.21: Clases de análisis involucradas en el caso de uso Crear teselado
La descripción textual se muestra en la tabla 4.12.
4.3.5.2.
Fase de diseño
Desarrollo del caso de uso Crear extended rotoscale
En este caso de uso sólo se contempla un único flujo de eventos. Por tanto, sólo
habrá un diagrama de secuencia de análisis para este caso de uso (véase figura 4.22). Al
igual que en el caso de uso Crear fondo, el controlador se ha dividido en otras clases de
análisis más especı́ficas con el objetivo de adaptarse a los patrones que se están utilizando.
En el diagrama de secuencia anterior se ha representado un bucle que realiza dos
iteraciones. Esto es debido a que en primer lugar se recogen los datos de la paleta que se han
generado y, posteriormente, se obtienen los datos correspondientes al fondo. Cada iteración
CAPÍTULO 4. MÉTODO DE TRABAJO
Nombre: Crear teselado
Abstracto: No
Precondiciones:
Existe una imagen y un fondo seleccionados. Dicha imagen tiene la altura y la
anchura acorde con el fondo de tipo teselado.
Postcondiciones:
1. Se muestra en la ventana un fondo de tipo teselado.
Rango: 5
Flujo normal:
1. El controlador recibe la ruta de la imagen y el tipo de fondo igual a teselado del
controlador del caso de uso Abrir imagen.
2. El controlador envı́a al proxy el tipo de fondo y la ruta de la imagen.
3. El controlador solicita al proxy los datos de la paleta y del fondo.
4. El proxy le dice a la herramienta Grit que se ejecute con las opciones que ha
recibido del controlador.
5. El proxy envı́a los datos al controlador.
6. El controlador crea una instancia de Paleta y crea un conjunto de instancias de
Tesela.
7. El controlador le pasa a la ventana los datos del fondo, de la paleta y de las teselas.
8. Se muestran en la ventana los datos, la paleta y las teselas del fondo.
Descripción:
Este caso de uso se encarga de mostrar la paleta, las teselas
y los datos del fondo teselado en la ventana.
Tabla 4.12: Descripción textual del caso de uso Crear teselado
119
CAPÍTULO 4. MÉTODO DE TRABAJO
120
Figura 4.22: Diagrama de secuencia correspondiente al flujo normal
del bucle empieza con la obtención de los datos y concluye cuando la vista correspondiente
le indica a la ventana que se actualice.
4.3.5.3.
Fase de implementación
Crear extended rotoscale
En los fondos de rotación extendida se empieza a utilizar la paleta de colores. Por
este motivo, el proceso de construcción se complica ligeramente en comparación con los
fondos framebuffer. En el subtipo de la clase IModo correspondiente a los fondos de rotación extendida (clase ModoRotoscale), se deben redefinir los métodos encargados de construir la vista del mapa y la vista de la paleta (build vmapa y build vpaleta). Ambos métodos
tienen la misma estructura, aunque obviamente cada uno se instancia con un subtipo distinto. En primer lugar, se construye la vista de la paleta y, posteriormente, la vista del fondo.
La estructura es la siguiente:
Primero se crea el presentador y la vista con el subtipo adecuado de IPresenter y
de IVista, respectivamente. Una vez creados, el presentador se encarga de registrar
(subscribe) las vistas que quieren ser informadas cuando haya algún cambio en el
modelo (en la paleta, en este caso).
CAPÍTULO 4. MÉTODO DE TRABAJO
121
El proxy se encarga de obtener los datos que se le soliciten. En este caso, se deben
obtener los datos de la paleta y del fondo (get datos paleta y get datos mapa). Estos
datos son generados por la herramienta Grit y se almacenan en memoria como un
vector de enteros sin signo.
La vista utiliza estos datos para transmitirlos al presentador, el cual crea aquellos
objetos del modelo que correspondan. Una vez definidos los objetos del modelo, el
presentador emite una actualización a cada una de las vistas que se hayan suscrito al
servicio de actualizaciones.
La novedad de este tipo de fondos con respecto a un fondo framebuffer reside en la
paleta de colores. La vista se encarga de decirle al presentador que cargue la paleta. Para
ello, se utiliza la función cargar. Esta función se ha sobrecargado en la clase IPresenter. El
código de esta función es el siguiente:
1
void PresenterPal :: cargar ( std :: vector < unsigned int > datos , int
ncolores )
2
{
3
this - > paleta = new Paleta ( ncolores ) ;
4
this - > paleta - > crear ( datos ) ;
5
for ( unsigned int i = 0; i < this - > paleta - > get_data () .
6
size () ; i ++) {
7
int x = i % 8;
8
int y = (i - x ) /8;
9
this - > vistas [ " pal " ] - > update (x , y , this - > paleta
- > get_data () . at ( i ) ) ;
}
10
11
}
El primer argumento corresponde a los datos de la paleta, mientras que el segundo
argumento indica si la paleta es de 16 o de 256 colores. Una paleta en el sistema no es ni
más ni menos que un vector de enteros sin signo, donde cada elemento corresponde a un
color de la misma en formato RGB de 32 bits.
CAPÍTULO 4. MÉTODO DE TRABAJO
122
Identificación del caso de prueba: 5
Caso de uso / Flujo de eventos: Crear extended rotoscale / Flujo normal
Condiciones de ejecución:
El alumno ha seleccionado una imagen con un tamaño adecuado para un fondo
de tipo extended rotoscale.
Descripción:
Se crean los datos del fondo y de la paleta a partir de la imagen y el
tipo elegidos.
Resultado esperado:
Se muestran el fondo y la paleta de un fondo extended rotoscale en la ventana.
Resultado obtenido:
Correcto
Tabla 4.13: Caso de prueba 5, “en positivo”
4.3.5.4.
Pruebas
4.3.6.
Iteración 4
En esta iteración se realizará la fase de diseño, la fase de implementación y la fase
de pruebas del caso de uso Crear teselado, según se indica en el plan de iteraciones.
4.3.6.1.
Fase de diseño
Desarrollo del caso de uso Crear teselado
Este caso de uso tiene un único flujo de eventos y, por lo tanto, se realizará sólo un
diagrama de secuencia de análisis (véase la figura 4.23). En el diagrama se puede observar
que se ha utilizado un bucle, el cual se repite 3 veces. Ası́ bien, en cada iteración del bucle
se pretende representar la obtención de los datos correspondientes a cada uno de los 3
elementos del fondo teselado. Estos elementos son, en orden de obtención, la paleta, el
conjunto de teselas y el fondo o mapa. Por tanto, la primera iteración comienza con la
recogida de los datos de la paleta y termina con la presentación de los mismos en la ventana.
La segunda iteración empieza con la obtención de los datos del conjunto de teselas del
fondo y termina cuando la vista le indica a la ventana que se actualice. La tercera y última
iteración se inicia con la obtención de los datos del fondo y finaliza cuando la vista le pasa
a la ventana el fondo que debe mostrar.
Al igual que en el caso de uso Crear fondo, el controlador se ha dividido en otras
clases de análisis más especı́ficas con el objetivo de adaptarse a los patrones que se están
utilizando.
CAPÍTULO 4. MÉTODO DE TRABAJO
123
Figura 4.23: Diagrama de secuencia correspondiente al flujo normal
4.3.6.2.
Fase de implementación
Crear teselado
El proceso de construcción de un fondo teselado es más complicado que el proceso
de construcción de un fondo framebuffer o de un fondo de rotación extendida. El modelo
de este tipo de fondo lo constituyen tanto la paleta de colores como un conjunto de teselas.
Ası́, en el subtipo de la clase IModo correspondiente a los fondos teselados (clase ModoTeselado), se deben redefinir todos los métodos de construcción de las vistas, es decir, el
método de construcción de la vista de la paleta (build vpaleta), el de la vista de las teselas
(build vteselas), el de la vista del mapa (build vmapa) y el de la vista de edición de cada
tesela (build veditar). Todos estos métodos tienen la misma estructura, aunque obviamente
cada uno se instancia con un subtipo distinto. La estructura es la siguiente:
Primero se crea el presentador y la vista con el subtipo adecuado de IPresenter y
de IVista, respectivamente. Una vez creados, el presentador se encarga de registrar
(subscribe) las vistas que quieren ser informadas cuando haya algún cambio en el
modelo (en la paleta, en este caso).
El proxy se encarga de obtener los datos que se le soliciten. En este caso, se deben
obtener los datos de la paleta, del conjunto de teselas y del fondo (get datos paleta,
CAPÍTULO 4. MÉTODO DE TRABAJO
124
get datos teselas y get datos mapa). Estos datos son generados por la herramienta
Grit y se almacenan en memoria como un vector de enteros sin signo.
La vista utiliza estos datos para transmitirlos al presentador, el cual crea aquellos
objetos del modelo que correspondan. Una vez definidos los objetos del modelo, el
presentador emite una actualización a cada una de las vistas que se hayan suscrito al
servicio de actualizaciones.
La novedad de este tipo de fondo es la introducción de las teselas. Esto introduce la
vista y el presentador de teselas. La vista llama a la función cargar del presentador, la cual
crea las teselas del fondo a partir de un vector de enteros sin signo. La definición de esta
función, sobrecargada en la clase IPresenter, es la siguiente:
1
void cargar ( std :: vector < unsigned int > datos ) ;
A la hora de mostrar el fondo teselado, la vista del mapa llama al método cargar
del presentador, el cual tiene un vector de enteros sin signo como único argumento que representa los datos del mapa. Este método llama a la función crear teselado del presentador
se encarga de comunicar a la vista la tesela que tiene ir dibujando en cada posición. Ası́,
para cada elemento del mapa se obtiene el número de tesela, si la tesela se dibuja utilizando algún tipo de espejo y el número de paleta. Esto último sólo es necesario para saber el
número de la subpaleta que utiliza una tesela de 16 colores, ya que en las teselas de 256
colores la subpaleta siempre será la número 0.
4.3.6.3.
Pruebas
4.3.7.
Iteración 5
Según el plan de iteraciones, en la iteración 5 se realizará la fase de análisis de los
casos de uso siguientes: Modificar paleta, Cambiar color y Modificar tesela.
4.3.7.1.
Fase de análisis
Descripción del caso de uso Modificar paleta
La ejecución de este caso de uso supone la modificación de la paleta del fondo actual,
ya sea un fondo teselado o un fondo extended rotoscale. Las posibles clases de análisis
identificadas en este caso de uso abstracto se pueden ver en la figura 4.24.
La descripción textual se muestra en la tabla 4.15.
CAPÍTULO 4. MÉTODO DE TRABAJO
125
Identificación del caso de prueba: 6
Caso de uso / Flujo de eventos: Crear teselado / Flujo normal
Condiciones de ejecución:
El alumno ha seleccionado una imagen con un tamaño adecuado para un fondo de tipo
teselado.
Descripción:
Se crean la paleta, las teselas y los datos de un fondo teselado a partir de la imagen y
el tipo elegidos.
Resultado esperado:
Se muestran la paleta, las teselas y los datos de un fondo teselado en la ventana.
Resultado obtenido:
Correcto
Tabla 4.14: Caso de prueba 6, “en positivo”
Figura 4.24: Clases de análisis involucradas en el caso de uso Modificar paleta
CAPÍTULO 4. MÉTODO DE TRABAJO
Nombre: Modificar paleta
Abstracto: Sı́
Precondiciones:
En el sistema se debe haber creado un fondo que soporte el trabajo con paletas, es
decir, cualquier tipo de fondo excepto el framebuffer.
Postcondiciones:
La paleta de colores del fondo se ha modificado.
Rango: 6
Flujo normal:
1. El alumno pulsa el botón reorganizar paleta en la ventana, la cual muestra el
diálogo de reorganizar la paleta.
2. El alumno selecciona una operación a realizar sobre la paleta.
3. El diálogo le envı́a a la vista la operación seleccionada y los datos necesarios para
llevarla a cabo.
4. La vista le pasa al presentador los datos y le indica que se actualice.
5. El presentador actualiza la paleta y le pide a todas las vistas afectadas que se
actualicen.
Descripción:
En este caso de uso se modifica la paleta de colores de un fondo existente.
Tabla 4.15: Descripción textual del caso de uso Modificar paleta
126
CAPÍTULO 4. MÉTODO DE TRABAJO
127
Descripción del caso de uso Cambiar color
Este caso de uso modifica un color de la paleta por el color que seleccione el alumno.
Las posibles clases de análisis identificadas en este caso de uso abstracto se pueden ver en
la figura 4.25.
Figura 4.25: Clases de análisis involucradas en el caso de uso Cambiar color
La descripción textual se muestra en la tabla 4.16.
Nombre: Cambiar color
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo que soporte el trabajo con paletas, es
decir, cualquier tipo de fondo excepto el framebuffer.
Postcondiciones:
Se ha cambiado el color de un elemento de la paleta de colores.
Rango: 7
Flujo normal:
1. El alumno pulsa el botón reorganizar paleta en la ventana, la cual muestra el
diálogo de reorganizar la paleta.
2. El alumno selecciona un color de la paleta y pulsa el botón editar color en el
diálogo, el cual muestra un diálogo de selección de color.
3. El alumno selecciona un color en el diálogo de selección de color.
4. La vista obtiene el nuevo color seleccionado.
5. La vista le pasa al presentador la posición que ocupa en la paleta el color afectado y
el nuevo color, y le indica que se actualice.
6. El presentador actualiza la paleta y le pide a todas las vistas afectadas que se
actualicen.
Descripción:
En este caso de uso se cambia el color de un elemento de la paleta de colores.
Tabla 4.16: Descripción textual del caso de uso Cambiar color
CAPÍTULO 4. MÉTODO DE TRABAJO
128
Descripción del caso de uso Modificar tesela
Este caso de uso modifica una tesela de un fondo teselado. El alumno selecciona una
tesela, un pixel de la misma y el color de la paleta que quiere que aparezca en la tesela. Las
posibles clases de análisis identificadas se pueden ver en la figura 4.26.
Figura 4.26: Clases de análisis involucradas en el caso de uso Modificar tesela
Este caso de uso presenta un sólo flujo de eventos. La descripción textual se muestra
en la tabla 4.17.
Nombre: Modificar tesela
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo teselado.
Postcondiciones:
Rango: 8
Flujo normal:
1. El alumno selecciona en la ventana una tesela del conjunto de teselas, un color de la
paleta y un pixel de la tesela.
2. La ventana le pasa a la vista los datos seleccionados.
3. La vista le indica al presentador que se actualice.
4. El presentador actualiza la tesela seleccionada del conjunto y propaga a las vistas
afectadas la actualización.
Descripción:
Tabla 4.17: Descripción textual del caso de uso Modificar tesela
4.3.8.
Iteración 6
En la presente iteración se realizará la fase de análisis de los casos de uso Agregar
color nuevo, Intercambiar colores y Modificar fondo.
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.8.1.
129
Fase de análisis
Descripción del caso de uso Agregar color nuevo
Este caso de uso presenta un flujo normal y un flujo alternativo. El flujo normal
corresponde a la situación en la que se añade un color a la paleta, mientras que el flujo
alternativo ocurre cuando ya no se pueden agregar más colores a la paleta. Las posibles
clases de análisis identificadas se pueden ver en la figura 4.27.
Figura 4.27: Clases de análisis involucradas en el caso de uso Agregar color nuevo
La descripción textual del caso de uso se muestra en la tabla 4.18.
Descripción del caso de uso Intercambiar colores
Este caso de uso intercambia la posición de dos colores de la misma paleta. Será especialmente útlil cuando se desee cambiar el elemento de la paleta que ocupa la posición
del color transparente (el primer color de la paleta es transparente). Las posibles clases de
análisis identificadas se pueden ver en la figura 4.28.
Figura 4.28: Clases de análisis involucradas en el caso de uso Intercambiar colores
La descripción textual del caso de uso se muestra en la tabla 4.19.
Descripción del caso de uso Modificar fondo
Este caso de uso se ejecuta cuando el alumno personaliza un fondo teselado de 16 o
256 colores, mediante la sustitución de una o varias teselas del fondo. Las posibles clases
de análisis identificadas se pueden ver en la figura 4.29.
La descripción textual del caso de uso se muestra en la tabla 4.20.
CAPÍTULO 4. MÉTODO DE TRABAJO
130
Nombre: Agregar color nuevo
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo teselado o extended rotoscale.
Postcondiciones:
Rango: 9
Flujo normal:
1. El alumno pulsa el botón reorganizar paleta en la ventana, la cual muestra el
diálogo de reorganizar la paleta.
2. El alumno pulsa el botón agregar color en el diálogo.
3. La vista comprueba que existe suficente espacio en la paleta para agregar un nuevo
color.
4. La vista muestra un diálogo de selección de color.
5. El alumno selecciona un color en el diálogo.
6. La vista recoge el color seleccionado.
7. La vista le pasa al presentador el nuevo color de la paleta.
8. El presentador actualiza la paleta y propaga las actualizaciones por las vistas
afectadas.
Flujo alternativo:
1. El alumno pulsa el botón reorganizar paleta en la ventana, la cual muestra el
diálogo de reorganizar la paleta.
2. El alumno pulsa el botón agregar color en el diálogo. 3. La vista comprueba que no
existe suficente espacio en la paleta para agregar un nuevo color.
4. La vista muestra un mensaje de error en un nuevo diálogo.
Descripción:
Tabla 4.18: Descripción textual del caso de uso Agregar color nuevo
Figura 4.29: Clases de análisis involucradas en el caso de uso Modificar fondo
CAPÍTULO 4. MÉTODO DE TRABAJO
Nombre: Intercambiar colores
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo teselado o extended rotoscale.
Postcondiciones:
En la paleta de colores del fondo se han intercambiado dos colores.
Rango: 10
Flujo normal:
1. El alumno pulsa el botón reorganizar paleta en la ventana, la cual muestra el
diálogo de reorganizar la paleta.
2. El alumno mueve el color seleccionado hasta la posición de otro color de la paleta,
los cuales serán los elementos que se intercambien.
3. El diálogo envı́a a la vista la posición y el color de cada uno de los dos elementos.
4. La vista le pasa al presentador los datos de los colores involucrados en el
intercambio.
5. El presentador comprueba si alguno de los dos elementos ocupa la posición del
color transparente. En caso afirmativo, se actualiza la paleta. Por último, el
presentador propaga las actualizaciones a las vistas interesadas.
Descripción:
En este caso de uso se intercambia la posición de dos colores de la paleta del fondo.
Tabla 4.19: Descripción textual del caso de uso Intecambiar colores
131
CAPÍTULO 4. MÉTODO DE TRABAJO
132
Nombre: Modificar fondo
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo teselado.
Postcondiciones:
El fondo se ha modificado por medio de la sustitución de una o varias teselas.
Rango: 11
Flujo normal:
1. El alumno selecciona una tesela del conjunto de teselas en la ventana. Previamente,
el alumno habrá elegido si quiere utilizar un tipo de espejo para la tesela.
2. El alumno hace click en una posición del fondo en la ventana y selecciona un
conjunto de teselas.
3. La ventana le dice a la vista la posición de inicio y final que se ha seleccionado.
4. La vista le pide al presentador que le envı́e la tesela seleccionada, el cual cumple
con la petición.
5. La vista le pasa al presentador la tesela y las posiciones del mapa en las que se debe
colocar a dicha tesela.
6. El presentador actualiza los datos del fondo y le indica a la vista del mapa que se
actualice.
Descripción:
En este caso de uso se reemplazan una o varias teselas del fondo.
Tabla 4.20: Descripción textual del caso de uso Modificar fondo
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.9.
133
Iteración 7
En esta iteración se inicia la fase de construcción del sistema. Durante el transcurso
de la iteración se realizará la fase de diseño, la fase de implementación y la fase de pruebas
de los casos de uso Modificar paleta, Cambiar color y Modificar tesela.
4.3.9.1.
Fase de diseño
Desarrollo del caso de uso Modificar paleta
En este caso de uso sólo se contempla un único flujo de eventos. Por tanto, sólo
habrá un diagrama de secuencia de análisis para este caso de uso (véase figura 4.30). En el
diagrama se puede observar que cuando se produce cualquier operación que modifique la
paleta, la vista le indica al presentador la actualización que debe realizar. Dicho presentador
se encarga de actualizar la paleta (modelo) y de pedirle a todas las vistas con las que tenga
relación que se actualicen. Esto se representa en el diagrama con un bucle, el cual se repite
un número de veces igual al número de elementos del vector v (IVista).
Figura 4.30: Diagrama de secuencia correspondiente al flujo normal
Desarrollo del caso de uso Cambiar color
En este caso de uso sólo se contempla un único flujo de eventos. Por tanto, sólo
habrá un diagrama de secuencia de análisis para este caso de uso (véase figura 4.31).
CAPÍTULO 4. MÉTODO DE TRABAJO
134
Figura 4.31: Diagrama de secuencia correspondiente al flujo normal
Desarrollo del caso de uso Modificar tesela
En este caso de uso contempla un flujo de eventos normal y, por tanto, habrá un diagrama de secuencia de análisis para este caso de uso (véase la figura 4.32). En el diagrama
se puede observar que el presentador primero actualiza la tesela y, posteriormente, le indica
a cada una de las cuatro vistas (la vista de la paleta, la vista del conjunto de teselas, la vista
del mapa y la vista de edición de la tesela) que se actualicen.
4.3.9.2.
Fase de implementación
Modificar paleta
Cuando se pulse el botón Reorganizar paleta de la ventana, se emite una señal que es
capturada por la vista de la paleta. La función reorganizar button clicked captura esta señal
y se encarga de mostrar el diálogo que permite la modificación de la paleta (véase la figura
4.33). Pero sin duda, la tarea más importante de esta función es detectar el botón del diálogo
que se pulsa y, en función del botón pulsado, llamará a la función update con unos valores
u otros. Se debe recordar que en este diálogo tendrán lugar las operaciones que pueden
modificar una paleta de colores: editar un color, agregar un color nuevo o intercambiar dos
colores.
El código de la función update del presentador de la paleta utilizada para actualizar
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.32: Diagrama de secuencia correspondiente al flujo normal
Figura 4.33: Diálogo Reorganizar paleta
135
CAPÍTULO 4. MÉTODO DE TRABAJO
136
la misma es el siguiente:
1
void PresenterPal :: update ( int pos_paleta , unsigned int color )
2
{
3
int x = pos_paleta % 8;
4
int y = ( pos_paleta - x ) /8;
5
this - > paleta - > update ( pos_paleta , color ) ;
6
this - > vistas [ " pal " ] - > update (x , y , color ) ;
7
if ( this - > vistas [ " tiles " ]) {
8
this - > vistas [ " tiles " ] - > update ( pos_paleta ,
9
color ) ;
10
}
11
if ( this - > vistas [ " edit " ]) {
this - > vistas [ " edit " ] - > update ( pos_paleta , color
12
);
13
}
14
this - > vistas [ " map " ] - > update ( pos_paleta ) ;
15
}
Esta función realiza en primer lugar la modificación de la paleta. Tras realizar el
cambio, se desencadena una propagación de llamadas a cada una de las vistas suscritas al
servicio de actualizaciones para que se actualicen.
Cambiar color
La función reorganizar button clicked se ocupa de detectar si se ha pulsado el botón
Editar color en el diálogo Reorganizar paleta. Cuando esto sucede, la función pick color
de la vista de la paleta muestra un diálogo de selección de color (véase la figura 4.34). En
este diálogo se selecciona el color que reemplazará al color seleccionado existente.
Una vez elegido el nuevo color, el presentador realiza en primer lugar la modificación
de la paleta. Para ello, llama al método update de la paleta, el cual cambia el color de la
posición pos paleta por el color color. Este método se ha implementado ası́:
1
void Paleta :: update ( int pos_paleta , unsigned int color )
2
{
3
4
if ( pos_paleta < ( int ) this - > data . size () )
this - > data . at ( pos_paleta ) = color ;
CAPÍTULO 4. MÉTODO DE TRABAJO
137
Figura 4.34: Diálogo de selección de color
else
5
this - > data . push_back ( color ) ;
6
7
}
Como se ha explicado en la implementación del caso de uso Modificar paleta, tras
realizar un cambio en la paleta, se desencadena una propagación de llamadas a cada una de
las vistas suscritas al servicio de actualizaciones para que se actualicen.
Modificar tesela
Cuando se selecciona un pixel de una tesela en la vista de edición, se emite una señal
que es capturada por la función change pixel.
4.3.9.3.
4.3.10.
Pruebas
Iteración 8
Durante esta iteración se realizará la fase de diseño, la fase de implementación y la
fase de pruebas de los casos de uso Agregar color nuevo, Intercambiar colores y Modificar
fondo, según el plan de iteraciones.
CAPÍTULO 4. MÉTODO DE TRABAJO
138
Identificación del caso de prueba: 7
Caso de uso / Flujo de eventos: Modificar paleta / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que soporte el trabajo con paletas.
Descripción:
Se realiza un cambio en la paleta de colores del fondo actual.
Resultado esperado:
Se muestra en la ventana el cambio realizado en la paleta.
Resultado obtenido:
Correcto
Tabla 4.21: Caso de prueba 7, “en positivo”
Identificación del caso de prueba: 8
Caso de uso / Flujo de eventos: Cambiar color / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que soporte el trabajo con paletas.
Descripción:
Se realiza el cambio de color de un elemento de la paleta de colores del fondo actual.
Resultado esperado:
Se muestra en la ventana el nuevo color elegido para el elemento afectado de la paleta.
Resultado obtenido:
Correcto
Tabla 4.22: Caso de prueba 8, “en positivo”
CAPÍTULO 4. MÉTODO DE TRABAJO
139
Identificación del caso de prueba: 9
Caso de uso / Flujo de eventos: Modificar tesela / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo teselado de 16 o 256 colores.
Descripción:
El alumno modifica un pixel de una tesela.
Resultado esperado:
Se muestra en la ventana la tesela con el cambio efectuado.
Resultado obtenido:
Correcto
Tabla 4.23: Caso de prueba 9, “en positivo”
Identificación del caso de prueba: 10
Caso de uso / Flujo de eventos: Modificar tesela / Flujo alternativo
Condiciones de ejecución:
En el sistema se debe haber creado un fondo teselado de 16 o 256 colores.
Descripción:
Se modifican los pixels de una tesela como consecuencia de un cambio en la paleta de
colores.
Resultado esperado:
Se muestra en la ventana la tesela actualizada.
Resultado obtenido:
Correcto
Tabla 4.24: Caso de prueba 10, “en positivo”
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.10.1.
140
Fase de diseño
Desarrollo del caso de uso Agregar color nuevo
En este caso de uso se contemplan un flujo normal y un flujo de eventos alternativo.
Por tanto, habrá un diagrama de secuencia de análisis para cada flujo de eventos (véase
figura 4.35).
Figura 4.35: Diagrama de secuencia correspondiente al flujo normal
El diagrama de flujo de eventos alternativos se puede ver en la figura 4.36.
Desarrollo del caso de uso Intercambiar colores
En este caso de uso sólo se contempla un flujo de eventos. Por tanto, habrá un diagrama de secuencia de análisis para este flujo de eventos (véase figura 4.37).
Desarrollo del caso de uso Modificar fondo
Para este caso de uso se deberá construir un sólo diagrama de secuencia de análisis
(véase la figura 4.38).
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.36: Diagrama de secuencia correspondiente al flujo alternativo
Figura 4.37: Diagrama de secuencia correspondiente al flujo normal
141
CAPÍTULO 4. MÉTODO DE TRABAJO
142
Figura 4.38: Diagrama de secuencia correspondiente al flujo normal
4.3.10.2.
Fase de implementación
Agregar color nuevo
La función reorganizar button clicked se ocupa de detectar si se ha pulsado el botón
Añadir color en el diálogo Reorganizar paleta. Cuando esto sucede, dicha función comprueba si hay espacio suficiente en la paleta para agregar otro color. En caso afirmativo, la
función pick color de la vista de la paleta muestra el diálogo de selección de color. En este
diálogo se selecciona el nuevo color que se agregará a la paleta.
Una vez elegido el nuevo color, el presentador realiza la modificación de la paleta.
Para ello, llama al método update de la paleta (explicado en la implementación del caso
de uso Cambiar color), el cual agrega el color color en la posición igual al número de
elementos de la paleta más 1. Es decir, se agrega a continuación del último elemento de la
paleta.
Como se ha explicado en la implementación del caso de uso Modificar paleta, tras
realizar un cambio en la paleta, se desencadena una propagación de llamadas a cada una de
las vistas suscritas al servicio de actualizaciones para que se actualicen.
Intercambiar colores
Para implementar este caso de uso se ha utilizado la técnica de arrastrar y soltar
(drag and drop). Ası́, para intercambiar dos colores se agarra un color de la paleta, el cual
CAPÍTULO 4. MÉTODO DE TRABAJO
143
se mueve hasta la posición de otro color de la paleta y, finalmente, se suelta. El resultado es
el intercambio de los colores de los dos elementos que intervienen en la acción.
Para implementar esta técnica se han necesitado las tres funciones siguientes, definidas en la clase VistaPaleta:
press color paleta: esta función captura la señal emitida cuando se pulsa un color de
la paleta en el diálogo Reorganizar paleta. Lo que se realiza en este método es almacenar el elemento pulsado junto con las coordenadas de su posición en el momento
de pulsarse.
motion notify color paleta: esta función captura la señal que se emite cada vez que
se mueve el ratón. Lo que realiza este método es pintar el elemento de la paleta en la
posición que se mueva el ratón. Esto provoca la sensación de que el color de la paleta
pulsado se está moviendo.
release color paleta: esta función captura la señal que se emite cuando se suelta el
botón del ratón una vez que se ha presionado. Cuando se ejecuta este método se obtiene el color de los dos elementos que intervienen en la operación. Después, el método
llama a la función intercambiar colores del presentador. Esta función comprueba si
alguno de los dos colores ocupa la posición del color transparente en la paleta. En caso afirmativo, se modifica la paleta y se propaga una actualización por aquellas vistas
que estén interesadas.
Modificar fondo
Este caso de uso también se ha implementado utilizando la técnica de arrastrar y soltar. En concreto, dicha técnica se ha utilizado para realizar la selección de aquellas teselas
del fondo que se desean reemplazar. Para la técnica de arrastrar y soltar se han implementado las tres funciones siguientes en la clase VistaMapa:
on press tesela: esta función captura la señal que se emite cuando se pulsa una tesela
del fondo. Asimismo, es la encargada de guardar la posición de dicha tesela.
on motion notify: esta función simplemente se encarga de ir redimensionando el rectángulo rojo utilizado en la interfaz para simular la selección de un conjunto de teselas.
on release tesela: esta función captura la señal que se emite cuando se suelta el botón
del ratón. La primera tarea que se realiza es pedirle al presentador que le envı́e la
tesela que se ha seleccionado (get tesela seleccionada). Posteriormente, se llama a la
función update del presentador para cada una de las posiciones de las teselas que se
hayan seleccionado.
CAPÍTULO 4. MÉTODO DE TRABAJO
144
La función update del presentador es, sin duda, la más importante de este caso uso.
Esta función tiene dos tareas bien diferenciadas: la primera es notificar a la vista que se
actualice y, la segunda, consiste en actualizar la entrada del mapa para que se mantenga la
coherencia entre la vista y los datos del fondo. Su implementación se puede ver a continuación:
1
void PresenterMap :: update ( int x , int y , int tesela )
2
{
3
int i = y /8 , j = x /8;
4
unsigned int entrada_mapa = this - > mapa . at ( i *( height /8)
+ j);
unsigned int paleta = ( entrada_mapa & 0 xF000 ) >> 12; //
5
obtener numero de paleta ;
unsigned int new_flip = ( int ) this - > datos . at ( tesela ) ->
6
get_flip () ;
7
if ( new_flip == 0) { // no utilizar espejo
8
vistas [ " map " ] - > update (j , i , this - > datos . at (
9
tesela ) -> get_data ( " " ) ) ;
} else if ( new_flip == 1) { // espejo horizontal
10
vistas [ " map " ] - > update (j , i , this - > datos . at (
11
tesela ) -> get_data ( " horizontal " ) ) ;
} else if ( new_flip == 2) { // espejo vertical
12
vistas [ " map " ] - > update (j , i , this - > datos . at (
13
tesela ) -> get_data ( " vertical " ) ) ;
} else { // espejo horizontal y vertical
14
vistas [ " map " ] - > update (j , i , this - > datos . at (
15
tesela ) -> get_data ( " horizontal and vertical "
));
}
16
17
this - > mapa . at ( i *( height /8) + j ) = tesela + ( new_flip <<
18
10) + ( paleta << 12) ;
19
}
CAPÍTULO 4. MÉTODO DE TRABAJO
Identificación del caso de prueba: 11
Caso de uso / Flujo de eventos: Agregar color nuevo / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que trabaje con paletas de colores.
Descripción:
El alumno agrega un nuevo elemento a la paleta de colores.
Resultado esperado:
Se muestra en la ventana y en el diálogo de reorganización de la paleta el cambio
realizado sobre la paleta de colores.
Resultado obtenido:
Correcto
Tabla 4.25: Caso de prueba 11, “en positivo”
Identificación del caso de prueba: 12
Caso de uso / Flujo de eventos: Agregar color nuevo / Flujo alternativo
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que trabaje con paletas de colores.
Descripción:
El alumno agrega un nuevo elemento a la paleta de colores, la cual tiene 256 colores.
Resultado esperado:
Se muestra un diálogo de error en el que se indica que la paleta ya tiene el número
máximo de colores posibles.
Resultado obtenido:
Correcto
Tabla 4.26: Caso de prueba 12, “en positivo”
145
CAPÍTULO 4. MÉTODO DE TRABAJO
146
Identificación del caso de prueba: 13
Caso de uso / Flujo de eventos: Intercambiar colores / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que trabaje con paletas de colores.
Descripción:
El alumno intercambia dos elementos de la paleta.
Resultado esperado:
Se muestra en el diálogo de reorganización de la paleta y en la ventana los colores de
dos elementos de la paleta intercambiados.
Resultado obtenido:
Correcto
Tabla 4.27: Caso de prueba 13, “en positivo”
Identificación del caso de prueba: 14
Caso de uso / Flujo de eventos: Intercambiar colores / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo que trabaje con paletas de colores.
Descripción:
El alumno intercambia dos elementos de la paleta.
Resultado esperado:
Se muestra en el diálogo de reorganización de la paleta y en la ventana los colores de
dos elementos de la paleta intercambiados.
Resultado obtenido:
Correcto
Tabla 4.28: Caso de prueba 14, “en positivo”
CAPÍTULO 4. MÉTODO DE TRABAJO
147
Identificación del caso de prueba: 15
Caso de uso / Flujo de eventos: Modificar fondo / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo teselado o extended rotoscale.
Descripción:
Se sustituyen una serie de teselas del fondo por otras en las posiciones que se han
elegido.
Resultado esperado:
En primer lugar, la vista debe mostrar la tesela elegida en las posiciones que se
seleccionaron. Y en segundo lugar se debe comprobar la coherencia de las entradas
del mapa que se hayan visto afectadas.
Resultado obtenido:
Correcto
Tabla 4.29: Caso de prueba 15, “en positivo”
4.3.10.3.
Pruebas
4.3.11.
Iteración 9
En esta iteración se realizará la fase de análisis, la fase de diseño, la fase de implementación y la fase de pruebas del caso de uso Generar datos NDS, según el plan de
iteraciones.
4.3.11.1.
Fase de análisis
Descripción del caso de uso Generar datos NDS
Este caso de uso se encarga de convertir la imagen del fondo que actualmente se
muestra en la ventana, en ficheros de texto en el formato que elija el alumno. Estos ficheros
generados son perfectamente utilizables en la programación de aplicaciones para Nintendo
DS. Las posibles clases de análisis identificadas en este caso de uso se muestran en la figura
4.39.
La descripción textual del caso de uso se muestra en la tabla 4.30.
CAPÍTULO 4. MÉTODO DE TRABAJO
148
Figura 4.39: Clases de análisis involucradas en el caso de uso Generar datos NDS
Nombre: Generar datos NDS
Abstracto: No
Precondiciones:
En el sistema se debe haber creado un fondo teselado, extended rotoscale o
framebuffer.
Postcondiciones:
Se han generado archivos de texto para la NDS a partir del fondo mostrado en la
ventana. El formato de los archivos de texto es elegido por el alumno.
Rango: 12
Flujo normal:
1. El alumno pulsa el botón convertir fondo en la ventana, la cual muestra un diálogo
con opciones para la generaración del fondo para la NDS.
2. El alumno selecciona las opciones de salida para los ficheros de texto en el diálogo.
3. EL diálogo pasa las opciones al controlador.
4. El controlador guarda el fondo que se muestra en la pantalla en un archivo de tipo
imagen. Para ello, solicita al presentador que le envı́e el fondo.
5. El controlador le pasa al proxy la ruta del archivo que ha creado.
6. El proxy le dice a Grit que se ejecute de acuerdo con los datos que ha recibido.
Descripción:
En este caso de uso se generan los archivos de texto que se utilizarán para la
programación de la NDS a partir del fondo mostrado en la ventana.
Tabla 4.30: Descripción textual del caso de uso Generar datos NDS
CAPÍTULO 4. MÉTODO DE TRABAJO
4.3.11.2.
149
Fase de diseño
Desarrollo del caso de uso Generar datos NDS
En este caso de uso sólo se contempla un único flujo de eventos. Por tanto, sólo
habrá un diagrama de secuencia de análisis para este caso de uso (véase figura 4.40).
Figura 4.40: Diagrama de secuencia correspondiente al flujo normal
Como se puede comprobar, este es el último que caso de uso que se tiene que desarrollar de acuerdo con el plan de iteraciones. Por tanto, se está en disposición de mostrar el
diagrama de clases del editor de fondos completado. Dicho diagrama se puede observar en
la figura 4.41.
4.3.11.3.
Fase de implementación
Generar datos NDS
La función convert item de la clase IModo se encarga de capturar la señal que se
emite cuando se pulsa el botón Convertir imagen. Cuando se ejecuta esta función, se muestra un diálogo con las opciones para convertir el fondo (véase la figura 4.42). Cuando se
pulsa el botón Aceptar del diálogo, esta función ejecuta el método save de su misma clase,
el cual se ha definido de la siguiente manera:
1
void save ( std :: string filename , IPresenter * presenter )
CAPÍTULO 4. MÉTODO DE TRABAJO
Figura 4.41: Diagrama de clases del editor de fondos
150
CAPÍTULO 4. MÉTODO DE TRABAJO
151
Figura 4.42: Diagrama de secuencia correspondiente al flujo normal
El primer parámetro de este método representa el nombre del archivo de la imagen
que se creará para que sea utilizado por Grit. El segundo parámtetro es el presentador del
mapa, que será utilizado para obtener los datos actuales del fondo que se muestra en la
pantalla mediante la llamada a su función get mapa. Esta última función no tiene ningún
argumento y devuelve un puntero a un elemento del tipo GdkPixbuf.
Una vez que ha terminado de ejecutarse el método save, se recogen las opciones que
se han introducido en el diálogo y, posteriormente, se ejecuta la función convertir del proxy.
El código de esta última función es el siguiente:
1
void GritProxy :: convertir ( std :: string imagen , std :: string optn
, std :: string output , std :: string header )
2
{
if (! grit ) {
3
grit = new Grit ( this - > filename , modo , n_colores
4
);
5
}
6
grit - > convertir ( imagen , optn , output , header ) ;
7
}
CAPÍTULO 4. MÉTODO DE TRABAJO
152
El significado de cada uno de los cuatro argumentos de la función se explica a continuación:
imagen: representa la ruta del nombre del archivo de la imagen.
optn: representa la opción elegida en el diálogo para el formato de salida de los archivos que generará Grit.
ouput: representa el nombre de salida de los archivos que generará Grit.
header: indica si se prefiere que Grit genere un fichero de encabezado.
La función convertir instancia el objeto grit (clase Grit) si no estuviera instanciado
y llama a su método convertir. En esta última función es realmente donde se realiza la
ejecución de Grit (herramienta) con las opciones escogidas en un nuevo proceso.
4.3.11.4.
Pruebas
Identificación del caso de prueba: 16
Caso de uso / Flujo de eventos: Generar datos NDS / Flujo normal
Condiciones de ejecución:
En el sistema se debe haber creado un fondo framebuffer, teselado o extended
rotoscale.
Descripción:
Se convierte el fondo mostrado en la ventana en los archivos de texto que se utilizarán
para la programación de la NDS.
Resultado esperado:
Se generan el archivo o los archivos de texto en el formato que indique el alumno.
Resultado obtenido:
Correcto
Tabla 4.31: Caso de prueba 16, “en positivo”
Capı́tulo 5
RESULTADOS
5.1. Introducción
5.1.
Introducción
Este capı́tulo está dedicado a mostrar los resultados obtenidos al ejecutar el entorno
de programación. En primer lugar, se ilustrará al lector con la presentación de los resultados
del editor de fondos para cada uno de los distintos tipos de fondos junto con los tamaños
que soportan (véase la tabla 5.1).
Tipo de fondo
Framebuffer
Rotación extendida
Teselado
Tamaño
192×256 pixels
128×128 pixels
256×256 pixels
512×256.pixels
512×512 pixels
512×1024 pixels
1024×512 pixels
32×32 teselas
32×64 teselas
64×32 teselas
64×64 teselas
Resultado (Anexo)
Véase la figura B.1
Véase la figura B.2
Véase la figura B.3
Véase la figura B.4
Véase la figura B.5
Véase la figura B.6
Véase la figura B.7
Véase la figura B.8
Véase la figura B.9
Véase la figura B.10
Véase la figura B.11
Tabla 5.1: Resultados para cada tamaño aceptado por los tipos de fondo
153
CAPÍTULO 5. RESULTADOS
154
Capı́tulo 6
CONCLUSIONES Y PROPUESTAS
6.1.
Conclusiones
En el segundo capı́tulo se expusieron los objetivos que se pretendı́an conseguir para
este proyecto. Ası́, los objetivos que se han alcanzado finalmente han sido los siguientes:
Eclipse como base: El entorno de programación se ha construido utilizando como
base Eclipse, al cual se han unido el plug-in NDS Managedbuilder y la nueva versión
realizada del plug-in Zylin Embedded CDT. T
Depuración utilizando un emulador: El emulador de Nintendo DS, DeSmuME, se
ha integrado en el entorno para poder ser utilizado durante el proceso de depuración
de aplicaciones.
Bajo acoplamiento y alta cohesión: La minimización del acoplamiento entre componentes se ha logrado gracias al empleo de los patrones de diseño de software Modelo Vista Presentador, Builder y Proxy.
Múltiples vistas: El editor de fondos se ha construido para que soporte múltiples
vistas. Gracias al empleo del patrón Modelo Vista Presentador, cualquier cambio que
se produzca en un elemento del modelo se verá reflejado en cada una de las vistas en
las que intervenga el elemento afectado.
Modos gráficos 2D: El editor de fondos ofrece la posibilidad de trabajar con los tres
modos gráficos 2D de la Nintendo DS: modo framebuffer, modo extended rotoscale
y modo teselado.
El sistema generará datos entendibles por la videoconsola: A partir de una imagen
indexada en formato PNG, el editor puede generar los archivos de texto que pue155
CAPÍTULO 6. CONCLUSIONES Y PROPUESTAS
156
den ser utilizados directamente para la programación de la Nintendo DS. Gracias al
empleo de la herramienta Grit, se ha superado este objetivo.
Fondos teselados de 16 y 256 colores: El editor es capaz de trabajar tanto con fondos
teselados de 256 colores como con fondos teselados de 16 colores.
Edición de la paletas de colores: Durante el trabajo con fondos teselados y con fondos de rotación extendida, el editor ofrece la posibilidad de personalizar la paleta de
colores. En concreto, se pueden agregar colores a la paleta, editar los colores existentes e intercambiar colores de posición.
Sencilla instalación y configuración del software: El entorno de programación ha
reducido en gran medida el tiempo que el alumno tiene que dedicar a tareas de instalación, configuración y aprendizaje. Como consecuencia de la cobertura de este objetivo, se consigue que el alumno dedique gran parte de su esfuerzo a la exploración de
la arquitectura de la Nintendo DS.
Desarrollo de un sistema multiplataforma: Tanto las tecnologı́as utilizadas, como
Eclipse, como los lenguajes de programación utilizados permiten que el sistema sea
multiplataforma. El sistema ha sido probado en equipos que utilizan el sistema operativo Debian GNU/Linux, obteniéndose buenos resultados. Sin embargo, en plataformas Microsoft Windows no se ha probado el entorno de programación. Por tanto,
este objetivo no se ha logrado del todo.
Desarrollo del sistema utilizando software libre: Este objetivo se ha cumplido, ya
que tanto Eclipse como los plug-ins utilizados son tecnologı́as libres. Asimismo, las
tecnologı́as utilizadas para el desarrollo del editor, como GooCanvas o devkitPro,
también son libres.
Desarrollo de un sistema viable desde el punto de vista docente: Para demostrar
la viabilidad se ha elaborado un tutorial del entorno de programación (véase el anexo
A.1).
6.2.
Propuestas y lı́neas de investigación futuras
Existen varios aspectos del sistema que son susceptibles de ser mejorados en profundidad. A continuación se aportarán una serie de ideas para la realización de futuras mejoras
sobre el entorno de programación. Estas ideas se han organizado en dos apartados diferentes.
CAPÍTULO 6. CONCLUSIONES Y PROPUESTAS
6.2.1.
157
Entorno cruzado de desarrollo
El hecho de que se haya integrado en el sistema el emulador DeSmuME durante el
proceso de depuración de aplicaciones para Nintendo DS, abre una nueva posibilidad. Esta
posibilidad serı́a la utilización del emulador durante el proceso de ejecución de cualquier
aplicación para NDS que se esté desarrollando. Es decir, se podrı́a conseguir algo parecido
a lo que hace el plug-in de Eclipse para el desarrollo de aplicaciones para móviles EclipseME. Este plug-in utiliza durante el proceso de ejecución y de depuración una especie de
emulador en forma de teléfono móvil.
Uno de los objetivos que no ha sido cubierto en su totalidad es el desarrollo de un
sistema multiplataforma. En concreto, no se ha probado el correcto funcionamiento del entorno de programación en plataformas Microsoft Windows. La introducción de esta mejora
ofrecerı́a al alumno un amplio abanico de posibilidades a la hora de realizar su trabajo.
6.2.2.
Editor de fondos
El editor de fondos es capaz de crear archivos, los cuales pueden ser utilizados para
la programación de la Nintendo DS, a partir de una imagen en formato PNG. Una mejora
que se podrı́a realizar es aumentar la compatibilidad con otros formatos de imagen, teniendo
en cuenta que cada modo gráfico 2D tiene unas caracterı́sticas propias y no todos los modos
gráficos pueden soportar el mismo formato.
Otra mejora que se podrı́a estudiar serı́a ofrecer la posibilidad de crear un fondo teselado a partir de un fondo en blanco, es decir, partiendo de un conjunto vacı́o de teselas.
Obviamente, se podrı́a pensar en ampliar esta mejora para fondos framebuffer y fondos de
rotación extendida, pero no tendrı́a mucho sentido, ya que se estarı́a imitando las funcionalidades de cualquier programa de dibujo existente como, por ejemplo, GIMP. De cualquier
modo, la introducción de esta mejora para los fondos teselados abre un amplio número de
posibilidades a la hora de continuar con el desarrollo del editor de fondos:
Integrar la posibilidad de crear una nueva tesela para un fondo teselado en el editor.
La tesela deberı́a poder crearse tanto con 256 colores como con 16 colores.
Implementación de un mecanismo que permita copiar o mover una o varias teselas de
un fondo a otro.
Integrar en el editor la posibilidad de copiar colores de una paleta a otra entre fondos
distintos.
Otra posibilidad que se podrı́a estudiar serı́a la compartición de las paletas de colores
entre fondos teselados.
CAPÍTULO 6. CONCLUSIONES Y PROPUESTAS
158
También se podrı́a estudiar la posibilidad de ampliar la funcionalidad del editor de
fondos mediante la incorporación de sprites. Si los fondos constituyen los objetos estáticos
de la videoconsola, los sprites forman la parte dinámica. Ası́, los personajes, los enemigos,
las armas o items, entre otros, son sprites. No obstante, los sprites y los fondos son bastantes similares en muchos aspectos. La integración de sprites ampliarı́a en gran medida las
funcionalidades que actualmente ofrece el editor.
Anexo A
TUTORIAL DEL ENTORNO DE
PROGRAMACIÓN
A.1. Entorno cruzado de desarrollo
A.1.1. Instalación en Debian GNU/Linux
A.1.2. Creación de un proyecto para NDS
A.1.3. Configuración del proyecto
A.1.4. Edición del archivo fuente
A.1.5. Depuración del proyecto
A.1.6. Sesión de depuración
A.2. Editor de fondos
A.2.1. Ejecución
A.2.2. Abrir imagen
A.2.3. Reorganizar paleta
A.2.4. Convertir fondo
A.2.5. Personalización del fondo
A.1.
Entorno cruzado de desarrollo
A.1.1.
Instalación en Debian GNU/Linux
Este tutorial está dirigido a todos aquellos usuarios que utilicen como sistema operativo Debian GNU/Linux o cualquier distribución GNU/Linux basada en Debian.
159
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
160
En primer lugar se debe añadir a las fuentes de paquetes una adicional. Para ello, se
tiene que agregar al archivo /etc/apt/sources.list las dos lı́neas siguientes:
1
2
deb http :// arco . esi . uclm . es /~ francisco . moya / debian / ./
deb - src http :// arco . esi . uclm . es /~ francisco . moya / debian / ./
Se necesitan una serie de herramientas para el desarrollo de aplicaciones para Nintendo DS. La instalación de dichas herramientas se puede realizar instalando el paquete
siguiente:
1
$ sudo aptitude install devkitpro - arm - eabi
Para poder utilizar el entorno se necesita tener instalado previamente Eclipse C/C++
Development Tooling - CDT 1 junto con el plug-in NDS Managedbuilder2 .
La nueva versión del plug-in Zylin Embedded CDT se puede instalar agregando la
dirección http://arco.esi.uclm.es/~manuel.rodrigo/update/ en el centro de actualizaciones de Eclipse.
A.1.2.
Creación de un proyecto para NDS
Para crear un nuevo proyecto se debe pulsar en la ventana principal de Eclipse en
File / New / C project. En el diálogo (véase la figura A.1) que aparece se debe configurar lo
siguiente:
Introducir un nombre y una ubicación para el proyecto.
En Project types seleccionar Nintendo DS Rom / Empty Project (libnds).
Click en Next y en Finish.
A.1.3.
Configuración del proyecto
Existen ligeras diferencias entre crear un proyecto para ARM9 y crear uno para
ARM7. Las diferencias afectan principalmente al modo de configuración de uno y de otro.
En este manual se ha creado un proyecto para el procesador ARM9 y, por tanto, se deberá configurar como tal.
Para iniciar la configuración del proyecto, se debe pulsar en la ventana principal de
Eclipse en Project Properties. En el diálogo nuevo que aparece (véase la figura A.2), se
deberá desplegar la pestaña C/C++ Build.
1 Disponible
2 Disponible
en http://www.eclipse.org .
en http://snipah.com .
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
Figura A.1: Diálogo de creación de un proyecto C
161
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
Figura A.2: Propiedades del proyecto
162
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
163
La sección Discovery Options se deberá configurar del siguiente modo:
1. Seleccionar GCC per project scanner info profile en Discovery profile.
2. Desmarcar la opción Report path detection problems.
3. En Compiler invocation command introducir: /usr/bin/arm-eabi-gcc y, finalmente,
aplicar los cambios.
En la sección Environment:
1. Cambiar el valor de DEVKITARM DIR por /opt/devkitPro/devkitARM
2. Cambiar el valor de DEVKITPRO DIR por /opt/devkitPro
En la sección Settings se deberán realizar varios cambios en la pestaña Tool Settings.
En concreto, el apartado devkitARM C Compiler se debe configurar del siguiente modo:
1. Click en Directories. Añadir la ruta /usr/include.
2. Click en Debugging. En Debug level seleccionar Default (-g).
3. Click en Miscellaneous. Agregar -march=armv5te en Other flags.
4. Click en ARM. Desmarcar la opción Omit Frame Pointer. Dejar en blanco el campo
CPU y cambiar el valor del campo Tune por arm946e-s.
En el apartado NDS Tool configurar lo siguiente:
1. Click en ARM7.
2. Introducir /opt/devkitPro/libnds/default.arm7 en el campo Code y, por último, aplicar
los cambios.
A.1.4.
Edición del archivo fuente
Para familiarizarse con el entorno de desarrollo de aplicaciones para Nintendo DS,
se va a utilizar como ejemplo una aplicación que utilice el algoritmo de Euclides para el
cálculo del máximo común divisor.
En primer lugar, se debe crear un fichero fuente en C dentro del proyecto actual. Para
ello se debe realizar lo siguiente:
1. Click en File / New / Source File.
2. En Source File introducir main.c.
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
164
3. En Template seleccionar ¡None¿.
4. Click en Finish.
A continuación se edita el nuevo fichero para que contenga el siguiente código:
1
# include < nds .h >
2
# include < stdio .h >
3
4
int mcd ( signed char a , signed char b )
5
{
6
if ( b == 0) {
7
return a ;
8
}
9
else {
return mcd (b , a % b ) ;
10
}
11
12
}
13
14
int main ()
15
{
consoleDemoInit () ;
16
17
18
int i = 12 , j = 99;
19
int div = mcd (i , j ) ;
20
21
printf ( " El mcd de %d y %d es %d \ n " , i , j , div ) ;
22
return 0;
23
}
Si no se han producido errores de compilación, aparecerán varios archivos:
mcd.elf
mcd.arm9
mcd.nds
De los tres archivos el único que preserva la información de depuración es el ejecutable mcd.elf. Por tanto, el depurador tendrá que trabajar necesariamente con él. Sin embargo
la consola (o el simulador) sólo será capaz de ejecutar la imagen del cartucho mcd.nds.
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
A.1.5.
165
Depuración del proyecto
Para iniciar la depuración del proyecto lo primero que se debe realizar es cambiar la
perspectiva de Eclipse. Se debe utilizar la perspectiva llamada Debug. Para ello:
1. Click en Window / Open Perspective / Other ...
2. Seleccionar Debug.
3. Click en Ok.
A continuación, se debe crear la configuración de depuración para el proyecto (véase
la figura A.3). Para ello:
1. Click en Run / Debug Configurations...
2. Doble click en Zylin Embedded debug (Native).
Figura A.3: Crear la configuración de depuración
En la pestaña Main:
1. En Project (Optional) indicar el nombre del proyecto.
2. Click en Search Project... Seleccionar el archivo .elf.
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
166
En la pestaña Debugger cambiar el valor de GDB debugger por arm-eabi-gdb.
En la pestaña Commands seleccionar la opción I will use DeSmuME for remote debugging on the next TCP Port.
En la pestaña DeSmuME:
1. Seleccionar la opción I will use DeSmuME for remote debugging.
2. Localizar la ubicación exacta de DeSmuME y aplicar los cambios.
Para iniciar el proceso de depuración se debe pulsar el botón Debug.
A.1.6.
Sesión de depuración
El programa, como todos los programas escritos en C, empieza en la función main.
Por tanto, ese puede ser un buen punto para empezar a ver las caracterı́sticas de GDB. Con
objeto de parar el programa justo cuando llegue a main, se pondrá un punto de ruptura3 .
Para ello se debe hacer doble click en la barra gris justo al lado del código del programa.
En Eclipse los puntos de ruptura se simbolizan con un circulo pequeño de color azul (véase
la figura A.4).
Figura A.4: Punto de ruptura en el programa
Para iniciar la depuración se debe pulsar el botón Resume. Este botón se utiliza para
reanudar o continuar la ejecución de un hilo actualmente suspendido. Para terminar la sesión
de depuración en cualquier momento, se debe pulsar el botón Terminate, próximo al botón
Resume. Este botón tiene forma de cuadrado y es de color rojo.
Se puede examinar el valor de las variables locales de la función que se está ejecutando en este momento en la pestaña Variables. También, se pueden ver los registros del
procesador en la pestaña Registers.
3 Breakpoint
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
167
Como únicamente se ha situado un punto de ruptura, al reanudar la depuración el
programa terminará su ejecución, salvo que exista algún error en tiempo de ejecución. Si
no se ha producido ninguna anomalı́a en la depuración, la salida del programa se puede ver
en el simulador DeSmuME (véase la figura A.5).
Figura A.5: Salida del programa
A.2.
Editor de fondos
A.2.1.
Ejecución
Para ejecutar el editor simplemente hay que situarse en la carpeta de la aplicación y
teclear:
1
$ ./ editor - ds
En la figura A.6 se puede ver la interfaz de la aplicación.
Los elementos principales de la interfaz son los siguientes:
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
168
Figura A.6: Interfaz del editor de fondos
Paleta: en esta vista se muestran los colores de la paleta del fondo.
Color actual: se muestra el color de la paleta que se ha seleccionado.
Teselas: en esta vista se muestra el conjunto de teselas de un fondo teselado.
Tesela actual: se muestra la tesela que actualmente ha sido seleccionada de entre el
conjunto de teselas.
La parte central de la interfaz se utiliza para mostrar el fondo.
Botón Abrir: se utiliza para crear un nuevo fondo a partir de un archivo de imagen.
Botón Ampliar y Reducir: se utilizan para realizar operaciones de zoom sobre el fondo.
A.2.2.
Abrir imagen
Cuando se pulsa el botón Abrir y se selecciona un archivo de imagen, la interfaz
muestra un diálogo (véase la figura A.7) en el que se debe seleccionar el tipo de fondo que
se desea crear.
En la figura A.8 se muestra el resultado de crear un fondo teselado de 256 colores a
partir de una imagen existente.
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
Figura A.7: Diálogo Nuevo fondo
Figura A.8: Abrir una imagen en modo teselado de 256 colores
169
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
A.2.3.
170
Reorganizar paleta
Al pulsar el botón Reorganizar paleta en la barra de herramientas de la interfaz
aparecerá un diálogo (véase la figura A.9) en el cual se puede modificar una paleta. En este
diálogo se pueden realizar tres operaciones sobre la paleta:
Editar un color de la paleta.
Agregar un nuevo color a la paleta.
Intercambiar dos colores moviendo un color de la paleta encima de otro.
Figura A.9: Diálogo Reorganizar paleta
A.2.4.
Convertir fondo
Al pulsar el botón Reorganizar paleta en la barra de herramientas de la interfaz
aparecerá un diálogo (véase la figura A.10) en el cual se muestran las opciones para la
creación de los ficheros de salida a partir del fondo mostrado en la ventana. Las opciones
del diálogo se explican a continuación:
Nombre del archivo: nombre que se desea para los archivos de salida.
Directorio de salida: directorio donde se crearán los archivos de salida.
Formato de salida: indica el tipo de archivo o archivos de salida que se desean obtener.
Archivo de encabezado: en caso de activarse se crea un fichero de encabezado.
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
171
Figura A.10: Diálogo Convertir fondo
A.2.5.
Personalización del fondo
Un fondo teselado puede ser personalizado de dos formas distintas. La primera opción consiste en editar manualmente una tesela del fondo. La segunda opción consiste en
sustituir unas teselas del fondo por otras.
El proceso para editar manualmente una tesela del fondo es el siguiente:
Pulsar en la tesela que se desee seleccionar del conjunto de teselas del fondo.
Pulsar en el color de la paleta que se desee utilizar. El color seleccionado se puede
ver en la parte de la interfaz llamada Color actual.
Hacer click en el pixel de la tesela que se desee modificar. Recordar que esta acción
se tiene que realizar en la vista de edición de teselas (Tesela actual).
Para reemplazar unas teselas del fondo por otras se debe proceder del siguiente modo:
Pulsar en la tesela que se desee seleccionar del conjunto de teselas del fondo.
Hacer click en la tesela del fondo que desee sustituir. Si se desea reemplazar un conjunto extenso de teselas, simplemente se debe pulsar en una parte del fondo con el
botón izquierdo del ratón y mantener presionado dicho botón mientras se mueve el
ratón (véase la figura A.11).
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
Figura A.11: Sustitución de un conjunto de teselas del fondo
172
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
173
Cada tesela de un fondo puede ser configurada mediante la aplicación de un tipo
de espejo (véase la figura A.12). Para ello, se debe pulsar con el botón derecho del ratón
encima de una tesela y seleccionar el tipo de espejo que se desee. A continuación se citan
las configuraciones posibles para una tesela:
No utilizar ningún tipo de espejo (Do not flip).
Utilizar espejo horizontal (Horizontal flip).
Utilizar espejo vertical (Vertical flip).
Utilizar espejo horizontal y espejo vertical (Horizontal and vertical flip).
Figura A.12: Espejos disponibles para una tesela
ANEXO A. TUTORIAL DEL ENTORNO DE PROGRAMACIÓN
174
Anexo B
FIGURAS
B.1. Resultados
B.1.
Resultados
Figura B.1: Fondo framebuffer a partir de una imagen de 192×256 pixels
175
ANEXO B. FIGURAS
Figura B.2: Fondo de rotación extendida a partir de una imagen de 128×128 pixels
Figura B.3: Fondo de rotación extendida a partir de una imagen de 256×256 pixels
176
ANEXO B. FIGURAS
Figura B.4: Fondo de rotación extendida a partir de una imagen de 512×256 pixels
Figura B.5: Fondo de rotación extendida a partir de una imagen de 512×512 pixels
177
ANEXO B. FIGURAS
178
Figura B.6: Fondo de rotación extendida a partir de una imagen de 512×1024 pixels
Figura B.7: Fondo de rotación extendida a partir de una imagen de 1024×512 pixels
ANEXO B. FIGURAS
Figura B.8: Fondo teselado de 256 colores a partir de una imagen de 32×32 teselas
179
ANEXO B. FIGURAS
Figura B.9: Fondo teselado de 256 colores a partir de una imagen de 32×64 teselas
180
ANEXO B. FIGURAS
Figura B.10: Fondo teselado de 16 colores a partir de una imagen de 64×32 teselas
181
ANEXO B. FIGURAS
Figura B.11: Fondo teselado de 16 colores a partir de una imagen de 64×64 teselas
182
Bibliografı́a
[1] The Video Game Museum. http://www.vgmuseum.com/.
R
[2] ARMLimited.
The Official ARM site. http://www.arm.com.
R
[3] ARMLimited.
ARM Architecture Reference Manual, 2000. Disponible en lı́nea
en http://infocenter.arm.com/help/index.jsp. Accedido por última vez el
15/02/2009.
R
[4] ARMLimited.
ARM7TDMI Technical Reference Manual, 2004. Disponible en
lı́nea en http://infocenter.arm.com/help/index.jsp. Accedido por última vez
el 15/02/2009.
R
R
[5] ARMLimited.
Application Binary Interface for the ARMArchitecture.
The Base Standard, 2007. Disponible en lı́nea en http://infocenter.arm.com/help/
index.jsp. Accedido por última vez el 15/02/2009.
R
[6] ARMLimited.
ARM946E-S Technical Reference Manual, 2007. Disponible en
lı́nea en http://infocenter.arm.com/help/index.jsp. Accedido por última vez
el 15/02/2009.
R
[7] ARMLimited.
Nintendo DS Lite. ARM Powered Product, 2007. Disponible en lı́nea
en http://www.arm.com/markets/home_solutions/armpp/11961.html. Accedido por última vez el 15/02/2009.
R
R
[8] ARMLimited.
Procedure Call Standard for the ARMArchitecture,
2007. Disponible en lı́nea en http://infocenter.arm.com/help/index.jsp. Accedido por
última vez el 15/02/2009.
[9] ESTEBAN, Daniel. Programación de videojuegos - Nintendo DS, 2007. Disponible
en lı́nea en http://www.theninjabunny.com/libro-nds/. Accedido por última
vez el 11/03/2009.
183
BIBLIOGRAFÍA
184
[10] GAMMA, Erich, HELM, Richard, JOHNSON, Ralph, and VLISSIDES, John. Design
Patterns. Elements of Reusable Object-Oriented Software. Addison Wesley, 1998.
[11] GONZÁLEZ, Jesús M., SEOANE, Joaquı́n, and ROBLES, Gregorio. Software Libre.
Universitat Oberta de Catalunya, 2003. Disponible en lı́nea en cv.uoc.es/cdocent/
6IP_5KXJ8EBO2FY26CJE.pdf. Accedido por última vez el 18/07/2009.
[12] HANDLEY, Brian. Building an embedded cross-development environment with
Eclipse. Macraigor Systems LLC, 2007. Disponible en lı́nea en http://www.
embedded-control-europe.com/c_ece_knowhow/90/ecejul07p24.pdf. Accedido por última vez el 20/07/2009.
[13] HUNTER, Martin. Tidying the House: The MVPC Software Design Pattern, 2006.
[14] IBM Corporation. Eclipse Platform Technical Overview, 2003. Disponible en lı́nea en
http://eclipse.org/whitepapers/eclipse-overview.pdf. Accedido por última vez el 18/07/2009.
[15] LIPINSKI, Michael. Feasibility of the Nintendo DS for Teaching Problem-Based
Learning in Kindergarten through Twelfth Grade Students. Faculty of the Graduate
School at the University of Missouri-Columbia, 2008. Disponible en lı́nea en
http://edt.missouri.edu/Summer2008/Thesis/LipinskiM-072508-T11610/
research.pdf. Accedido por última vez el 23/02/2009.
[16] LÜTKEHAUS, Dorothea, ZELLER, Andreus, and et al. Debugging with DDD.
Free Software Foundation, 2004. Disponible en lı́nea en http://www.gnu.org/
software/ddd/. Accedido por última vez el 17/07/2009.
[17] MENA, Federico. GDK-PixBuf Reference Manual. The Free Software Foundation,
2000. Disponible en lı́nea en http://library.gnome.org/devel/gdk-pixbuf/
stable/. Accedido por última vez el 19/08/2009.
[18] MOYA, Francisco. Introducción a los modos gráficos 2D de la Nintendo DS. Escuela
Superior de Informática de Ciudad Real. Universidad de Castilla-La Mancha, 2008.
[19] POLO, Macario. Manual de Ingenierı́a del Software II. Escuela Superior de Informática de Ciudad Real. Universidad de Castilla-La Mancha.
[20] RAUBER, Andreas and BECKER, Christoph. Digital Preservation of Console Video
Games. Vienna University of Technology, 2007. Disponible en lı́nea en www.ifs.
tuwien.ac.at/~becker/pubs/guttenbrunner_games2007.pdf. Accedido por
última vez el 17/07/2009.
BIBLIOGRAFÍA
185
[21] ROGERS, Jason. Day 2: NDS Introduction. Disponible en lı́nea en http://www.
dev-scene.com/NDS/Tutorials_Day_2. Accedido por última vez el 12/07/2009.
[22] ROGERS, Jason, NOLAND, Michael, and MURPHY, Dave. LibNDS Reference
Documentation, 2009. Disponible en lı́nea en http://libnds.devkitpro.org/
index.html. Accedido por última vez el 15/07/2009.
[23] SANTOFIMIA, Maria José and MOYA, Francisco. Familiarización con el entorno de
desarrollo. Escuela Superior de Informática de Ciudad Real. Universidad de CastillaLa Mancha, 2009.
[24] SANTOFIMIA, Maria José and MOYA, Francisco. Gráficos en modo extended rotoscale con la NDS. Escuela Superior de Informática de Ciudad Real. Universidad de
Castilla-La Mancha, 2009.
[25] SANTOFIMIA, Maria José and MOYA, Francisco. Gráficos en modo teselado con
la NDS. Escuela Superior de Informática de Ciudad Real. Universidad de Castilla-La
Mancha, 2009.
[26] SANTOFIMIA, Maria José and MOYA, Francisco. Gráficos en modo framebuffer con
la NDS. Escuela Superior de Informática de Ciudad Real. Universidad de Castilla-La
Mancha, 2009.
[27] SANTOFIMIA, Maria José and MOYA, Francisco. Introducción a la consola Nintendo DS y al EABI. Escuela Superior de Informática de Ciudad Real. Universidad de
Castilla-La Mancha, 2009.
[28] SANTOFIMIA, Maria José and MOYA, Francisco. Introducción al EABI y al AAPCS.
Escuela Superior de Informática de Ciudad Real. Universidad de Castilla-La Mancha,
2009.
[29] SIVIANES, Francisco, BARROS, José, and MARTÍN, Antonio. Entorno de Desarrollo para NDS. Departamento de Tecnologı́a Electrónica. Escuela Universitaria Politécnica. Universidad de Sevilla, 2008.
[30] SIXT, Johannes. KDbg. A Graphical Debugger Interface, 2008. Disponible en lı́nea
en http://www.kdbg.org/. Accedido por última vez el 17/07/2009.
[31] STALLMAN, Richard, PESCH, Roland, SHEBS, Stan, and et al. Debugging with
GDB, the GNU Source-Level Debugger. Free Software Foundation, 2008. Disponible
en lı́nea en http://www.gnu.org/software/gdb/documentation/. Accedido por
última vez el 14/04/2009.
BIBLIOGRAFÍA
186
[32] TAGLIARETTI, GianMario. GooCanvas Reference Manual. The GNOME Project,
2007. Disponible en lı́nea en http://library.gnome.org/devel/goocanvas/
unstable/. Accedido por última vez el 19/08/2009.
[33] The GNOME Project. GLib Reference Manual. Dynamic Loading of Modules. Disponible en lı́nea en http://library.gnome.org/devel/glib/stable/. Accedido
por última vez el 19/08/2009.
[34] VIJN, Jasper. The Grit project site. http://www.coranac.com/category/proj/
grit/.
[35] VIJN, Jasper. TONC. The Affine Transformation Matrix, 2008. Disponible en lı́nea
en http://www.coranac.com/tonc/text/affine.htm. Accedido por última vez
el 23/07/2009.

Documentos relacionados