int a = 1 - Universidad de Castilla
Transcripción
int a = 1 - Universidad de Castilla
Laboratorio de Estructura de Computadores Empleando videoconsolas Nintendo DS María José Santofimia Romero Francisco Moya Fernández Escuela Superior de Informática Universidad de Castilla-La Mancha Contenidos BLOQUE I 1. Lenguaje C 2. Arquitectura de la Nintendo DS 3. ABI e ISA BLOQUE II 4. Tipos de representación gráfica 2D BLOQUE III 5. Temporizadores e interrupciones BLOQUE IV 6. Ejemplos de proyectos de prácticas 2 BLOQUE I – TEMA 1 Antes de empezar, configuremos el entorno 3 Configuración del entorno ● Editamos el archivo de fuentes de paquetes: $ sudo gedit /etc/apt/sources.list ● Añadimos a las fuentes de paquetes la siguiente: deb http://arco.esi.uclm.es/~francisco.moya/debian/ ./ deb−src http://arco.esi.uclm.es/~francisco.moya/debian/ ./ ● Actualizamos la lista de paquetes: $ sudo aptitude update 4 Configuración del entorno ● Exportamos las variables de entorno: $ gedit ~/.bashrc export DEVKITPRO=/opt/devkitPro export DEVKITARM=/opt/devkitPro/devkitARM ● Instalamos los emuladores: $ sudo aptitude install desmume nocasgba ● Instalamos los depuradores: $ sudo aptitude install kdbg gdb 5 Configuración del entorno ● Instalación del paquete DevkitPro: $ sudo aptitude install devkitpro-arm-eabi ● Primera prueba: $ $ $ $ cp -r /opt/devkitPro/examples/nds/templates/arm9 /tmp/hello cd /tmp/hello make desmume hello.nds 6 BLOQUE I – TEMA 1 BLOQUE I Lenguaje Máquina y Ensamblador 7 Correspondencia con contenidos teóricos ● ● ● BLOQUE I Arquitectura y repertorio de instrucciones (Instruction Set Architecture, ISA). Formato Instrucciones. Modos de direccionamiento. Tipos de instrucción. Formato y repertorio de instrucciones del ARM (Advanced RISC Machines) ● Ensamblador, montador y cargador. ● Formato de una sentencia en lenguaje ensamblador. ● Instrucciones y directivas. ● Macros y subrutinas. 8 BLOQUE I – TEMA 1 Tema 1 Introducción al Lenguaje C 9 BLOQUE I – TEMA 1 ¿Por qué el lenguaje C? 1. Reducimos la barrera de aprendizaje (la traducción de algoritmos a lenguaje C es más directa que a ensamblador) 2. Valor profesional que aporta conocer C frente al ensamblador (ARM, PIC, etc.) 3. Lenguaje de “alto nivel” con capacidades de “bajo nivel”, ya que permite acceso a detalles de la arquitectura como: ABI, modos de direccionamiento, gestión de memoria, entrada/salida, aritmética binaria, etc. 10 Características de C ¿Qué lo hace tan atractivo para este laboratorio? ● ● ● ● Los punteros son un mecanismo de direccionamiento indirecto. Los arrays son un mecanismo de direccionamiento indexado. Número muy reducido de palabras reservadas (inferior al de cualquier lenguaje ensamblador). La complejidad de hacer programas en C se puede mantener al mínimo. 11 BLOQUE I – TEMA 1 Un tutorial clásico Ejemplos tomados de: Programming in C – A Tutorial Brian Kernighan, Bell Labs http://www.lysator.liu.se/c/bwk-tutor.html 12 BLOQUE I – TEMA 2 Tema 2 Arquitectura de la Nintendo DS 13 BLOQUE I – TEMA 2 Contenido ● Elementos de la plataforma NDS ● El proceso de compilación ● El interfaz binario de aplicaciones (ABI) ● – Relación entre ABI e ISA – Principios básicos de gestión de memoria – Reglas de alineamiento Explorando el ABI y la ISA 14 BLOQUE I – TEMA 2 El hardware de la NDS ● 2 procesadores – – ● ARM946E-S a 66 MHz ARM7TDMI a 33 MHz (a 16 MHz en modo GBA) 4 MB de RAM principal – ● Todo integrado en un único procesador específico para Nintendo PSRAM (pseudo-SRAM) Dinámica con circuitería de refresco Variedad de periféricos – – – – – – 2 motores gráficos 2D 1 motor gráfico 3D 1 touch screen 16 canales de sonido (6 gen. ondas, 2 gen. ruido) Altavoces y micrófono estéreo ... 15 BLOQUE I – TEMA 2 Compilando para NDS archivos.c archivos.c ARM9 código fuente ARM7 código fuente ARM7 compilador ARM9 compilador archivo.ds.gba archivos.o ARM7 código objeto AMR7 montador dsbuild ARM9 código objeto archivos.o ARM9 montador archivo.nds archivo.arm7.elf ARM7 ejecutable ndstool archivo.arm9.elf ARM9 ejecutable 16 BLOQUE I – TEMA 2 El proceso de empaquetado ● ndstool – Mismo formato de los cartuchos NDS ● ● ● Cabecera Junta ejecutables dsbuild – Permite ejecución desde cartucho GBA ● ● ejecutables Cabecera distinta Añade un cargador (loader) al principio ndstool archivo.nds Field Game title Game code Maker code Unit code Device code Card size Card info Flags ARM9 source (ROM) ARM9 execute addr ARM9 copy to addr ARM9 binary size ARM7 source (ROM) ARM7 execute addr ARM7 copy to addr ARM7 binary size Filename table offset (ROM) Filename table size FAT offset (ROM) FAT size ... dsbuild Start 0x000 0x00C 0x010 0x012 0x013 0x014 0x015 0x01F 0x020 0x024 0x028 0x02C 0x030 0x034 0x038 0x03C 0x040 0x044 0x048 0x04C End 0x00B 0x00F 0x011 0x012 0x013 0x014 0x01E 0x01F 0x023 0x027 0x02B 0x02F 0x033 0x037 0x03B 0x03F 0x043 0x047 0x04B 0x04F Size 12 4 2 1 1 1 10 1 4 4 4 4 4 4 4 4 4 4 4 4 archivo.ds.gba 17 BLOQUE I – TEMA 2 Hola, mundo ● Uso de la plantilla base que viene con devKitPro $ cp -r /opt/devkitPro/examples/nds/templates/arm9 /tmp/hola $ cd /tmp/hola $ gedit source/main.c #include <nds.h> #include <stdio.h> int main(void) { ConsoleDemoInit(); printf(“Hola, mundo\n”); while(1) { swiWaitForVBlank(); } } $ make $ desmume hola.nds 18 BLOQUE I – TEMA 3 Tema 3 Application Bynary Interface (ABI) 19 BLOQUE I – TEMA 3 Contenido 1. Reglas de alineamiento 2. Alineamiento de la pila 3. Llamadas a procedimientos a) Utilización de registros b) Repaso: Uso del link register c) Paso de parámetros 20 BLOQUE I – TEMA 3 Application Binary Interface ● La arquitectura impone restricciones – – Orden de bytes en una palabra (endianness) Restricciones de alineamiento ● ● E.g.Palabras no alineadas implican una doble lectura Algunos coprocesadores exigen alineación El compilador mantiene cierta libertad – – Utilización de los registros, método de paso de parámetros, promoción de tipos, nombres de símbolos internos... Para garantizar la interoperabilidad es preciso ceñirse a reglas comunes: ABI 21 BLOQUE I – TEMA 3 Embedded ABI for ARM (EABI) ● ● Definición de ABI acordado por múltiples empresas de compiladores (ARM, CodeSourcery, IAR, ...) Disponible públicamente – – ● http://infocenter.arm.com/help/index.jsp También disponible en moodle.uclm.es Especificado a varios niveles – – – – – Llamadas a procedimientos Biblioteca C estándar Excepciones y C++ ABI específico de plataforma (e.g. Linux) ... 22 BLOQUE I – TEMA 3 ISA y ABI ● El ABI siempre está estrechamente relacionado con la arquitectura del repertorio de instrucciones de la máquina (ISA) – Pensado para máxima eficiencia ● – E.g. Orden de bytes = el de la arquitectura Limitado por la arquitectura ● E.g. Idealmente todo se guardaría en registros 23 BLOQUE I – TEMA 3 La gestión de la memoria ● Un programa en ejecución tiene tres regiones fundamentales – ● Contiene instrucciones Puede tener textos fijos Datos ● ● – Pila (stack) Código ● – Variables de entorno Contiene datos globales BSS es inicializado a 0 Pila ● ● Variables automáticas El heap se gestiona explícitamente Stack frame Montículo (heap) BSS Datos (data) Código (text) Memoria principal 24 BLOQUE I – TEMA 3 Variables automáticas y estáticas ● ● Estáticas inicializadas y estáticas sin inicializar en secciones separadas Automáticas en una única sección int si = 0xbadbeef; int su; int main() { consoleDemoInit(); int ai = 0xdadbebad; int au; printf(“%p\n%p\n%p\n%p\n”, &si, &su, &ai, &au); return 0; } ¿Por qué? 25 BLOQUE I – TEMA 3 Variables automáticas ● Las variables automáticas se crean en la pila – – ● Definición = push Final = pop Excepciones – Optimización (registros) ① ② ③ SP SP SP void f() { ① ... int a = 1; ② ... int b; ③ ... }④ 1 a ④ ? b 1 a SP 26 BLOQUE I – TEMA 3 Variables estáticas ● Las variables estáticas se reservan en el ejecutable – Las inicializadas deben ser copiadas al principio – Las no inicializadas basta reservarlas ... int a = 1; ... int b; ... int main() { ... 0 b 1 a bss bss data cargador sz 1 a Ejecutable data Memoria principal 27 BLOQUE I – TEMA 3 ¿Estáticas o automáticas? Depende del tamaño ARM9 DTCM (16KiB) Tiene que ser estática porque de lo contrario desbordaría la pila PILA int main() { [...] static uint16 pixel[256*256]; [...] } 28 BLOQUE I – TEMA 3 Reglas de alineamiento Palabras se alinean al borde de palabra ● c – Relleno si es necesario – Pila crece hacia direcciones más bajas ? ? int main() { consoleDemoInit(); char c; int i; printf(“%p\n%p\n”, &c, &i); return 0; } Relleno (padding) ? i3 i2 c ? ? ? i i1 i0 SP 29 BLOQUE I – TEMA 3 Reglas de alineamiento Tipos básicos ● El ABI indica las reglas de alineamiento para cada tipo básico Type Integral Floating Point Pointer Machine unsigned char signed char unsigned short signed short unsigned int signed int unsigned long long signed long long float Double Data Code Size Alignment 1 1 1 1 2 2 2 2 4 4 4 4 8 8 8 8 4 4 8 8 4 4 4 4 30 BLOQUE I – TEMA 3 Reglas de alineamiento Tipos compuestos ● struct – – ● Alineamiento es el máximo de sus componentes Tamaño es múltiplo del alineamiento arrays – Alineamiento es el de su tipo base – Tamaño es N veces el del tipo base Optimiza la definición de struct MyData struct MyData { char c; double d; int s; }; int main() { char c; struct MyData data; struct MyData v[5]; ... 31 BLOQUE I – TEMA 3 Alineamiento de la pila El registro sp siempre debe alinearse al límite de palabra (4 bytes) ● En un interfaz público (e.g. al llamar a una función) debe alinearse al límite de doble palabra (8 bytes) ● 32 BLOQUE I – TEMA 3 Llamadas a procedimientos Utilización de registros Register Synonym Special Role r15 pc Program counter r14 lr Link register r13 sp Stack pointer r12 ip Intra procedure call scratch register r11 v8 Variable register 8 r10 v7 Variable register 7 r9 v6 sb/tr Platform register r8 v5 Variable register 5 r7 v4 Variable register 4 r6 v3 Variable register 3 r5 v2 Variable register 2 r4 v1 Variable register 1 r3 a4 Argument/scratch register 4 r2 a3 Argument/scratch register 3 r1 a2 Argument/scratch register 2 r0 a1 Argument/scratch register 1 33 BLOQUE I – TEMA 3 Llamadas a procedimientos Link register ● Para llamar se usa la instrucción bl – – – ● Usa lr para guardar dirección de retorno Permite ir a código ARM o Thumb Permite volver a la ISA correcta Retorna saltando a lr – bx lr int main() { ... func(3, 'c'); ... main: ... bl func ... lr[31:1] ← pc lr[0] ← ISA (0=ARM, 1=Thumb) pc ← func 34 BLOQUE I – TEMA 3 Llamadas a procedimientos Llamadas anidadas ● Si hay llamadas anidadas hay que preservar el lr en la pila void func2(int i, char c) { ... } void func() { ... func2(3, 'c'); ... } Antes del bl debe guardar en int main() { la pila el lr ... func(); 35 BLOQUE I – TEMA 3 Valor de retorno Si tiene signo se extiende el bit de signo ● Tipo básico o compuesto de tamaño ≤ 4 bytes (char, short, int, long, float, ...) – ● Tipo básico de 8 bytes (long long, double) – ● Se expande a 4 bytes y se retorna en r0 Se retorna en r0 y en r1 Tipo compuesto > 4 bytes o tamaño indeterminado – Se almacena en memoria – Dirección pasada como argumento extra 36 BLOQUE I – TEMA 3 Paso de parámetros ● Tres etapas: – A. Inicialización ● – B. Pre-padding y extensión de argumentos ● – Solo una vez antes de procesar argumentos Para cada argumento C. Asignación de argumentos a registros y pila ● Para cada argumento 37 Paso de parámetros BLOQUE I – TEMA 3 Inicialización ● ● ● Contador SiguienteReg se inicializa a r0 La dirección SiguienteArgEnPila se inicializa al valor del sp Si la función devuelve un resultado en memoria – La dirección del resultado se escribe en r0 – SiguienteReg pasa a ser r1 38 BLOQUE I – TEMA 3 Paso de parámetros Pre-padding y extensión de argumentos ● Argumento compuesto y no se puede determinar el tamaño por la función – ● Tipo básico de menos de 4 bytes – ● Se copia en memoria y se reemplaza por un puntero a esta copia Se extiende a 4 bytes Tipo compuesto cuyo tamaño no es múltiplo de 4 bytes – Se redondea a múltiplo de 4 bytes más cercano 39 Paso de parámetros BLOQUE I – TEMA 3 Asignación de argumentos a reg y pila ● Se requieren 8 bytes – ● Tamaño en palabras no supera r4 – SiguienteReg – – ● Se copia a registros empezando en SiguienteReg Se incrementa SiguienteReg al siguiente libre Supera pero SiguienteArgEnPila == sp – ● SiguienteReg = siguiente registro par Se divide entre registros (primera parte) y pila En otro caso – – Copiar argumento a SiguienteArgEnPila Incrementar SiguienteArgEnPila 40 Ejemplo1 BLOQUE I – TEMA 3 MCD, Algoritmo de Euclides #include #include <nds.h> <nds.h> #include #include <stdio.h> <stdio.h> int int mcd(int mcd(int a, a, int int b) b) {{ return return bb == == 00 ?? aa :: mcd(b, mcd(b, aa %% b); b); }} Llamadas a función int main() { int main() { consoleDemoInit(); consoleDemoInit(); int int ii == 12, 12, jj == 99; 99; int int div div == mcd(i, mcd(i, j); j); printf("El mcd de printf("El mcd de %d %d yy %d %d es es %d\n", %d\n", i, i, j, j, div); div); return 0; return 0; }} 41 Utilizando kdbg BLOQUE I – TEMA 3 Paso de argumentos y retorno de valores #include <nds.h> int sum(int, int); int main(){ consoleDemoInit(); int a, b, res; a = 4; b = 5; res = sum(a, b); printf("Suma: %d\n", res); return 0; } int sum(int v1, int v2){ return v1+v2; } 42 Utilizando kdbg BLOQUE I – TEMA 3 Compilación y ejecución $ cp -r /opt/devkitPro/examples/nds/templates/arm9 prueba $ cd prueba $ rm source/* Editar source/main.c source/prueba.c source/fn.h source/fn.c ● Editar Makefile para quitar optimización -O0 y comentar: #ARCH := -mthumb -mthumb-interwork ● Se comenta con # $ make $ desmume --arm9gdb=7777 prueba.nds & $ kdbg prueba.elf Poner un punto de interrupción en main ● Salir de kdbg ● $ kdbg -r :7777 prueba.elf 43 BLOQUE I – TEMA 2 Kdbg y DeSmuME step 44 BLOQUE I – TEMA 2 Stack frame y registros Stack frame Call trace Registros View → Registros 45 BLOQUE I – TEMA 2 Código ensamblador Código ensamblador 46 Utilizando kdbg BLOQUE I – TEMA 3 Paso de argumentos y retorno de valores 47 BLOQUE I – TEMA 1 BLOQUE II Memorias 48 Correspondencia con contenidos teóricos BLOQUE II ● Tecnología y características de la memoria. ● Jerarquía de memorias ● Mapa de memoria: diseño 49 BLOQUE II – TEMA 4 Tema 4 Gráficos 2D con Nintendo DS 50 BLOQUE II – TEMA 4 Contenidos ● Jerarquía y mapa de memoria. ● Modos gráficos 2D – Framebuffer – Extended Rotoscale – Tiles 51 BLOQUE II – TEMA 4 JERARQUÍA DE MEMORIA a ad d i d i c c ste apa o l o C C Ve d CPU Memoria Interna E/S BLOQUE I – TEMA 2 Mapa de memoria M ain BIOS ITC M DTCM WRAM0 WRAM1 M ain BIOS IWRAM WRAM0 WRAM1 ARM 9 0x02000000 0x023FFFFF 0xFFFF0000 0xFFFF7FFF 0x00000000 0x00007FFF 0x0B000000 0x0B003FFF 0x03000000 0x03003FFF 0x03004000 0x03007FFF ARM 7 0x02000000 0x023FFFFF 0x00000000 0x00003FFF 0x03800000 0x0380FFFF 0x03000000 0x03003FFF 0x03004000 0x03007FFF 4MB 32KB 32KB 16KB 16KB 16KB 4MB 16KB 64KB 16KB 16KB Video RAM M ain OAM 0x 07000000 0x070003FF Sub OA M 0x 07000400 0x070007FF M ain Palette 0x 05000000 0x050003FF Sub Palette 0x 05000400 0x050007FF Bank A 0x 06800000 0x0681FFFF Bank B 0x 06820000 0x0683FFFF Bank C 0x 06840000 0x0685FFFF Bank D 0x 06860000 0x0687FFFF Bank E 0x 06880000 0x0688FFFF Bank F 0x 06890000 0x06983FFF Bank G 0x 06894000 0x06897FFF Bank H 0x 06898000 0x0689FFFF Bank I 0x 068A0000 0x068A3FFF Virtual Video RAM M ain BG 0x 06000000 0x0607FFFF Sub BG 0x 06200000 0x0621FFFF M ain Sprite 0x 06400000 0x0643FFFF Sub Sprite 0x 06600000 0x0661FFFF 1KB 1KB 1KB 1KB 128KB 128KB 128KB 128KB 64KB 16KB 16KB 32KB 16KB 512KB 128KB 256KB 128KB Tomado de http://dev-scene.com/NDS/Tutorials_Day_2#Memory_Layout 53 BLOQUE I – TEMA 2 Arquitectura de memoria ARM9 DCache WRAM0 (16 KiB) ICache WRAM1 (16 KiB) DTCM (16 KiB) ITCM (32 KiB) BIOS ARM9 (32 KiB) IWRAM (64 KiB) Main RAM (4MiB) VRAM (656 KiB) OAM (2 KiB) Palette (2 KiB) ARM7 BIOS ARM7 (32 KiB) 3D Graphics (no accesible) GBA RAM (32MiB) 54 BLOQUE II – TEMA 4 La memoria de video (VRAM) ● 9 bancos asignables a distintos propósitos – – – – – – – – – VRAM_A VRAM_B VRAM_C VRAM_D VRAM_E VRAM_F VRAM_G VRAM_H VRAM_I (128KiB) (128KiB) (128KiB) (128KiB) (64KiB) (16KiB) (16KiB) (32KiB) (16KiB) ● Ejemplo: activar el bloque A y asociarlo a la representación de fondos con el procesador 2D principal VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG; Bloque VRAM_A asignado a fondos del 2D MAIN. Equivale a: vramSetBankA(VRAM_A_MAIN_BG); 55 Asignación de bancos de VRAM VRAM A Main Framebuffer Sprites Sub VRAM B VRAM C VRAM D Fondos BLOQUE II – TEMA 4 VRAM E VRAM F Fondos Sprites Paletas extendidas VRAM G Paletas extendidas Texturas VRAM H VRAM I Paletas texturas 56 BLOQUE II – TEMA 4 Activando coprocesadores ● El registro REG_POWERCNT controla el encendido de hardware Activar LCD y 2D principal REG_POWERCNT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 REG_POWERCNT = POWER_LCD | POWER_2D_A; POWER_LCD Pantallas LCD POWER_2D_A Procesador 2D principal POWER_MATRIX Matriz de transformación 3D POWER_3D_CORE Procesador 3D POWER_2D_B Procesador 2D secundario POWER_SWAP_LCDS Intercambia pantallas 57 Asignación de bancos de VRAM ● BLOQUE II – TEMA 4 Cada banco tiene un registro VRAM_?_CR para activarlo y seleccionar su función Activar VRAM_A y asignarla a fondos del motor 2D principal VRAM_?_CR 7 6 5 4 3 2 1 0 VRAM_A_CR = VRAM_A_ENABLE | VRAM_A_MAIN_BG; Modo Desplazamiento VRAM_?_ENABLE Más información en ${DEVKITPRO}/libnds/include/nds/arm9/video.h 58 BLOQUE II – TEMA 4 Modo de representación Modos de direccionamiento ● ● ● ● Cada modo de representación se distingue por una organización diferente de los datos en memoria. Conocer la jerarquía de memoria es indispensable para poder representar en cada uno de los modos 2D. Es necesario conocer las peculiaridades de cada tipo de memoria (tamaño, restricciones de acceso, buses, etc.) Excelente mecanismo para la práctica de los modos de direccionamiento. 59 BLOQUE II – TEMA 4 Modo de representación ● El registro REG_DISPCNT controla modos y fondos activos Activar modo 0 y BG0 REG_DISPCNT = MODE_0_2D | DISPLAY_BG0_ACTIVE; REG_DISPCNT 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 MODE_{0..6}_2D ENABLE_3D DISPLAY_{BG0,BG1,BG2,BG3,SPR}_ACTIVE DISPLAY_{WIN0,WIN1,SPR_WIN}_ON 2D mode MODE_FB{0..3} 60 BLOQUE II – TEMA 4 Modos de representación Configuración de los motores 2D ● Al usar MODE_0_2D todos los fondos son teselados – Hay otras posibilidades ● Modos Rotoscale permiten transformaciones afines Solo el coprocesador 2D principal Modo 0 1 2 3 4 5 6 BG0 Teselado Teselado Teselado Teselado Teselado Teselado Teselado BG1 BG2 BG3 Teselado Teselado Teselado Teselado Teselado Rotoscale Teselado Rotoscale Rotoscale Teselado Teselado Ext. Rotoscale Teselado Rotoscale Ext. Rotoscale Teselado Ext. Rotoscale Ext. Rotoscale N/A Large BMP 61 BLOQUE II – TEMA 4 Gráficos con Nintendo DS Modos framebuffer de la Nintendo DS 62 BLOQUE II – TEMA 4 Modos framebuffer ● ● Modo framebuffer – Pantalla mapeada en memoria – Al escribir en memoria aparece en pantalla 4 posibles framebuffers – Asociados a los bancos de VRAM de 128KiB – Permite implementar double buffering Modo FB0 FB1 FB2 FB3 Mem VRAM_A VRAM_B VRAM_C VRAM_D REG_DISPCNT = MODE_FB0; VRAM_A_CR = VRAM_A_ENABLE | VRAM_A_LCD; // El framebuffer está en VRAM_A 63 BLOQUE II – TEMA 4 Formato de representación ● Un framebuffer se caracteriza por – Posición de memoria donde se mapea ● – Longitud de cada línea ● – FB0 en VRAM_A, FB1 en VRAM_B, ... En la NDS 256 pixels por línea Formato de cada pixel ● RGB15(r,g,b) – – – R, G, B 5 bits por componente (0..31) Ocupa 2 bytes (bit15 no se usa) 64 BLOQUE II – TEMA 4 Ejemplo ● Archivos gráficos – data/wallpaper.png – data/wallpaper.grit -gB16 -gb #include <nds.h> #include "wallpaper.h" Cada pixel int main(void) { ocupa 2 bytes REG_DISPCNT = MODE_FB0; VRAM_A_CR = VRAM_ENABLE | VRAM_A_LCD; dmaCopy(wallpaperBitmap, VRAM_A, 256*192*2); for(;;) Copiar los 256x192 pixels swiWaitForVBlank(); de la imagen en VRAM_A return 0; } 65 BLOQUE II – TEMA 4 Ejemplo 66 BLOQUE II – TEMA 4 Gráficos con grit ● Grit genera automáticamente datos de pixels a partir de archivos gráficos $ grit help ● DevkitPro utiliza automáticamente grit – Añadir gráficos en carpeta data data/dibujo.png – Añadir opciones de grit data/dibujo.grit 67 BLOQUE II – TEMA 4 Ejercicio Mostrar un gradado vertical ocupando toda la pantalla desde el color negro RGB15(0,0,0) hasta el color azul RGB15(0,0,31) 68 BLOQUE II – TEMA 4 Gráficos con Nintendo DS Modos extended rotoscale 69 BLOQUE II – TEMA 4 Extended rotoscale ● Utilizar el modo 5 – Los fondos 2 y 3 son ext. Rotoscale ● Mapear algún banco de VRAM a fondos ● Configurar el fondo – – Desplazamiento en VRAM del dibujo Tamaño ● – ● 128x128, 256x256, 512x256, 512x512, 1024x512, 512x1024 Paleta Configurar matriz de transformación 70 BLOQUE II – TEMA 4 Ejemplo ● Archivos gráficos – – data/wallpaper.png data/wallpaper.grit -gB8 -gB8 -gb -gb #include <nds.h> #include "wallpaper.h" int main(void) { REG_DISPCNT = MODE_5_2D | DISPLAY_BG2_ACTIVE; VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG; BGCTRL[2] = BG_BMP_BASE(0) | BgSize_B8_256x256; dmaCopy(wallpaperBitmap, BG_GFX, 256*192); dmaCopy(wallpaperPal, BG_PALETTE, 256*2); bgTransform[2]>xdx = 256; bgTransform[2]>ydx = 0; bgTransform[2]>xdy = 0; bgTransform[2]>ydy = 256; bgTransform[2]>dx = 0; bgTransform[2]>dy = 0; } 71 BLOQUE II – TEMA 4 Paleta de colores ● ● Cada punto de la imagen es un número de color dentro de una paleta de 256 colores Cada color de la paleta es RGB de 15 bits – 0 1 2 3 4 5 6 7 8 5 bits por componente RGB15(0,0,0) RGB15(31,0,0) RGB15(31,15,0) RGB15(31,31,0) RGB15(0,31,0) RGB15(0,31,31) RGB15(31,0,31) RGB15(31,31,31) RGB15(7,7,7) Paleta 72 BLOQUE II – TEMA 4 Imágenes en la VRAM ● La imagen puede empezar en dirección múltiplo de 16KiB (0x4000) BGCTRL[2] = BG_BMP_BASE(0) | BgSize_B8_256x256; BMP_BASE 0 0x04000 BMP_BASE 1 0x08000 512KiB Puede ocupar más de 16KiB ¡Uno de 256x256 ocupa 64KiB! 0x00000 ... 0x78000 BMP_BASE 30 0x7c000 BMP_BASE 31 VRAM 73 BLOQUE II – TEMA 4 La matriz de transformación ● bgTransform[fondo] contiene una matriz de tranformación afín, que se aplica a la imagen – Ver http://www.coranac.com/tonc/text/affine.htm typedef struct { s16 xdx; s16 ydx; s16 xdy; s16 ydy; s32 dx; s32 dy; } bg_transform; bgTransform[2]>xdx = 256; bgTransform[2]>ydx = 0; bgTransform[2]>xdy = 0; bgTransform[2]>ydy = 256; bgTransform[2]>dx = 0; bgTransform[2]>dy = 0; Escala 1:1 y sin rotación 74 BLOQUE II – TEMA 4 Ejemplo 75 BLOQUE II – TEMA 4 Transformaciones afines con libnds ● Inicializar un fondo con libnds int bg = bgInit(2, BgType_Bmp8, BgSize_B8_256x256, 0, 0); ● Obtener la dirección de memoria u16* ptr = bgGetGfxPtr(bg); ● Transformaciones afines bgSetCenter(bg, x, y); bgSetScroll(bg, x, y); bgSetRotateScale(bg, angulo, escalaX, escalaY); bgUpdate(); BgUpdate actualiza la imagen 76 BLOQUE II – TEMA 4 Características del modo ER ● ● ● ● Introduce el concepto de “paleta de colores” que supone una representación indirecta del color de cada píxel. Práctica los modos de direccionamiento. La matriz de transformaciones requiere representación en punto fijo con 8 bits decimales. La VRAM no es accesible byte a byte (unidad mínima es de 2 bytes). 77 BLOQUE II – TEMA 4 Ejercicio ● Utilizando el modo 5 dibujar un gradado vertical ocupando toda la pantalla desde negro RGB15(0,0,0) hasta azul RGB15(0,0,31). 78 BLOQUE II – TEMA 4 Gráficos con Nintendo DS Modos gráficos teselados 79 BLOQUE II – TEMA 4 Mapas, teselas, paletas Mapas teselados ● Cada fondo se divide en teselas de 8x8 pixels – Cuatro posibilidades ● – Parte visible del mapa 32x32, 32x64, 64x32 y 64x64 La parte visible puede ajustarse (efecto scroll) 32X32 64X32 32X64 64X64 80 BLOQUE II – TEMA 4 Configuración de fondo teselado REG_BG0CNT = BG_32x32 | BG_16_COLOR | BG_MAP_BASE(0) | BG_TILE_BASE(1); ● – – También BGCTRL[n] REG_BG<n>CNT Fondo configurable – {32 o 64}x{32 o 64} 16 o 256 colores Posiciones de memoria ● 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ● Para mapa Para teselas Prioridad del fondo Posición de teselas (TILE_BASE) Modo mosaico 0=16 colores, 1=256 colores Posición del mapa (MAP_BASE) Conectar extremos (wrap) Tamaño de mapa (32x32, 64x32, 32x64, 64x64) 81 BLOQUE II – TEMA 4 Mapas, teselas, paletas 82 BLOQUE II – TEMA 4 Mapas, teselas, paletas Teselas de 16 y 256 colores ● Cada tesela es un dibujo de 8x8 pixels – Dos posibilidades ● 16 colores – ● 4 bits por pixel 256 colores – ¡Ojo! El nibble menos significativo es del pixel más a la izquierda 8 bits por pixel unsigned char A16[] = { 0x00,0x10,0x01,0x00, 0x00,0x11,0x11,0x00, 0x00,0x01,0x10,0x00, 0x10,0x01,0x10,0x01, 0x10,0x11,0x11,0x01, 0x10,0x01,0x10,0x01, 0x10,0x01,0x10,0x01, 0x00,0x00,0x00,0x00, }; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 5956 60 61 62 63 unsigned char A256[] = { 0,0,0,1,1,0,0,0, 0,0,1,1,1,1,0,0, 0,0,1,0,0,1,0,0, 0,1,1,0,0,1,1,0, 0,1,1,1,1,1,1,0, 0,1,1,0,0,1,1,0, 0,1,1,0,0,1,1,0, 0,0,0,0,0,0,0,0, }; 83 BLOQUE II – TEMA 4 Mapas, teselas, paletas Teselas de 16 colores (cont) ● En las teselas de 16 colores es más legible si usamos unsigned long – ¡Cuidado! Los nibbles menos significativos son pixels más a la izquierda unsigned long A16[] = { 0x00001111, 0x00000011, 0x00000101, 0x00001001, 0x00010000, 0x00000000, 0x00000000, }; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 ¡Ojo! La representación real se invierte respecto al eje Y 84 BLOQUE II – TEMA 4 Mapas, teselas, paletas Paleta de colores para fondos ● La paleta de fondos tiene 256 colores – 0x00 Paleta 0 1 paleta de 256 colores 0x10 Paleta 1 Color de 0x00 a 0xff 0x20 ● – 16 paletas de 16 colores ● ● Paleta de 0x0 a 0xf Color de 0x0 a 0xf BG_PALETE[0x25] es el color 0x25 de la paleta de 256 colores o el color 5 de la paleta 2 de 16 colores ... 0xe0 Paleta 14 0xf0 Paleta 15 Paleta de fondos BG_PALETTE 85 BLOQUE II – TEMA 4 Mapas, teselas, paletas Paleta de colores ● ● 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Un punto es un número de color dentro de una paleta 16 17 18 19 20 21 22 23 Cada color de la paleta es RGB de 0 15 bits 56 57 58 59 60 61 62 63 – 5 bits por componente unsigned long tesela[] = { 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, }; 1 2 3 4 5 6 7 8 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 Tesela RGB15(0,0,0) RGB15(31,0,0) RGB15(31,15,0) El color 0 es transparente RGB15(31,31,0) RGB15(0,31,0) RGB15(0,31,31) RGB15(31,0,31) RGB15(31,31,31) RGB15(7,7,7) Paleta 86 BLOQUE II – TEMA 4 Mapas, teselas, paletas Almacenamiento de teselas ● Las teselas se guardan a partir de una dirección base (TILE_BASE) – El procesador de gráficos 2D no permite cualquier dirección base BASE Tesela 0 BASE + 32 Tesela 1 BASE + 64 BASE + 32∙(n1) BASE + 32∙n Tesela n-1 Tesela n 87 BLOQUE II – TEMA 4 Mapas, teselas, paletas Formato de mapas ● Cada tesela del mapa se representa con 16 bits – Número de tesela entre 0 y 1023 – Espejo horizontal y/o vertical – Paleta (solo para teselas de 16 colores por pixel) Espejo vertical Espejo horizontal 15 14 13 Paleta 12 11 10 9 8 7 6 5 4 3 2 1 0 Número de tesela 88 BLOQUE II – TEMA 4 Teselas y mapas con grit ● Grit genera automáticamente datos de paletas, teselas y mapas a partir de archivos gráficos $ grit help ● DevkitPro utiliza automáticamente grit – Añadir gráficos en carpeta data data/dibujo.bmp – Añadir opciones de grit data/dibujo.grit 89 BLOQUE II – TEMA 4 Ejemplo ● Archivos gráficos – – data/wallpaper.png data/wallpaper.grit -g -m -p -gB8 -pe256 -gb -gB8 -gt #include <nds.h> #include "wallpaper.h" int main() { consoleDemoInit(); REG_DISPCNT = MODE_0_2D | DISPLAY_BG0_ACTIVE; VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG; BGCTRL[0] = BG_32x32 | BG_COLOR_256 | BG_WRAP_ON | BG_MAP_BASE(0) | BG_TILE_BASE(1); memcpy(BG_PALETTE, wallpaperPal, wallpaperPalLen); memcpy((void*)BG_TILE_RAM(1), wallpaperTiles, wallpaperTilesLen); memcpy((void*)BG_MAP_RAM(0), wallpaperMap, wallpaperMapLen); int i; for (i=0; ; ++i) { swiWaitForVBlank(); } } 90 BLOQUE II – TEMA 4 Teselas y mapas con grit Ejemplo: Fuente de texto ● Con programa de dibujo multicapa – Fondo: damero de cuadritos 8x8 – Primer plano: alfabeto y caracteres especiales ● ● – Elegir fuente monoespaciada Elegir tamaño múltiplo de 8 bits El interlineado también Grabar en gfx/texto.bmp solo la capa de primer plano Cada carácter son 2x4 teselas 91 BLOQUE II – TEMA 4 Teselas y mapas con grit Ejemplo: Fuente de texto (2) ● Creamos un archivo de opciones para grit gfx/texto.grit El primer color suele ser el negro. Con esto forzamos transparente el segundo color ● Por supuesto tu caso puede ser diferente – g # Generar teselas m # Generar mapas pe2 # Solo 2 colores pT1 # Color transparente gt # Modo teselas gB4 # 4 bits por pixel mR4 # Optimizar para 4bpp $ grit texto.bmp fts $ cat texto.h ¡Experimenta! 92 BLOQUE II – TEMA 4 Teselas y mapas con grit Ejemplo: Fuente de texto (3) ● El carácter de la columna i y la fila j empieza en unsigned short* pos = textoMap + i*2 + 26*2*4*j ● Todas las teselas del carácter son pos[0], pos[1], pos[26*2], pos[26*2+1], pos[26*4], pos[26*4+1], pos[26*6], pos[26*6+1] 0 5 10 15 20 25 0 1 2 93 BLOQUE II – TEMA 4 Guardar mapas en la VRAM ● Un mapa puede empezar en dirección múltiplo de 2KiB (0x800) MAP_BASE 0 0x0800 MAP_BASE 1 0x1000 64KiB Puede ocupar más de 2KiB ¡Uno de 64x64 ocupa 8KiB! 0x0000 ... 0xf000 MAP_BASE 30 0xf800 MAP_BASE 31 VRAM 94 BLOQUE II – TEMA 4 Guardar teselas en la VRAM ● Un mismo conjunto de teselas puede ocupar más de 16KiB ¡Como máximo un mismo mapa puede usar 1024 teselas de 256 colores (64KiB)! TILE_BASE 0 0x04000 TILE_BASE 1 0x08000 256KiB Un conjunto de teselas puede empezar en dirección múltiplo de 16KiB (0x4000) 0x00000 ... 0x38000 TILE_BASE 14 0x3c000 TILE_BASE 15 256KiB VRAM 95 BLOQUE II – TEMA 4 Características del modo Teselado ● ● ● ● Determinar el color de un píxel requiere un direccionamiento más complejo (mapa de teselas y la paleta de colores) Es necesario “dimensionar” el tamaño de los datos que componen el fondo. Distintas memorias para distintos tipos de datos (mapas, teselas o colores). Conocer el color de un determinado píxel plantea un excelente ejercicio de direccionamiento. 96 BLOQUE I – TEMA 1 BLOQUE III Sistema de Entrada-Salida 97 BLOQUE III – TEMA 5 Contenidos ● Temporizadores ● Interrupciones ● Funciones de entrada y salida ● DMA 98 BLOQUE III – TEMA 5 Tema 5 Temporizadores y Interrupciones 99 BLOQUE III – TEMA 5 Temporizadores Hardware disponible en la NDS ● 8 temporizadores (timers) de 16 bits – – ● ● Funcionan como un contador de eventos Frecuencia maestra de 33.554 MHz – ● 4 divisores (1, 64, 256, 1024) 0x2000000 Soportan configuración en cascada – ● 4 en el ARM9 4 en el ARM7 Incrementa cuando desborda el anterior Pueden generar interrupciones 100 BLOQUE III – TEMA 5 Programación de temporizadores ● Dos registros por temporizador – – ● TIMER_DATA(n) TIMER_CR(n) Valor del contador Registro de control Funcionamiento básico: – – Escribir en TIMER_DATA(n) el valor donde empezará la cuenta Escribir en TIMER_CR(n) ● ● ● ● El divisor de frecuencia TIMER_DIV_{1,64,256,1024} Si se configura en cascada TIMER_CASCADE Habilitar el temporizador con TIMER_ENABLE Si se habilitan interrupciones con TIMER_IRQ_REQ 101 BLOQUE III – TEMA 5 Registro de control TIMER_CR(n) n ∈ {0,1,2,3} TIMER_DATA(0) = TIMER_FREQ(1000); TIMER_CR(0) = TIMER_DIV_1 | TIMER_ENABLE; TIMER_CR(n) 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Divisor de frecuencia 0 TIMER_DIV_1 1 TIMER_DIV_64 2 TIMER_DIV_256 3 TIMER_DIV_1024 TIMER_CASCADE Habilita modo cascada TIMER_IRQ_REQ Habilita interrupción TIMER_ENABLE Habilita el temporizador 102 BLOQUE III – TEMA 5 Registro de datos TIMER_DATA(n) ● Para facilitar su programación se proporcionan macros que calculan el valor para desbordar a cierta frecuencia – TIMER_FREQ(n) para TIMER_DIV_1 – TIMER_FREQ_64(n) para TIMER_DIV_64 – TIMER_FREQ_256(n) para TIMER_DIV_256 – TIMER_FREQ_1024(n) para TIMER_DIV_1024 103 BLOQUE III – TEMA 5 Ejemplo: medir tiempo con precisión de 30 ns ● Si la función supera 0x10000 / 0x2000000 segundos habrá que usar varios en cascada TIMER_DATA(0) = 0; TIMER_CR(0) = TIMER_DIV_1 | TIMER_ENABLE; funcion_a_medir(); unsigned short t = TIMER_DATA(0); printf(¨tarda %g segundos\n¨, (double)t/(double)0x2000000); 104 BLOQUE III – TEMA 5 Ejemplo: usando interrupciones ● Procesado completamente asíncrono – ¡Cuidado! La RSI debe ser async-safe ● Cuando se invoca, el procesador puede estar ejecutando cualquier fragmento void desbordaTemporizador() { ... } int main() { TIMER_DATA(0) = 0; TIMER_CR(0) = TIMER_DIV_64 \ | TIMER_IRQ_REQ | TIMER_ENABLE; irqSet(IRQ_TIMER0, &desbordaTemporizador); irqEnable(IRQ_TIMER0); ... } 105 BLOQUE III – TEMA 5 Funciones de entrada y salida Cooperación ARM7-ARM9 Pantalla tactil Teclas X, Y Teclas A, B, L, R Teclas ←, ↑, →, ↓ Cierre de la tapa ARM7 ARM9 Teclas Select, Start REG_KEYXY REG_KEYINPUT Comunicación entre ARM7 y ARM9 scanKeys libnds keysCurrent keysUp keysDown keysHeld touchRead 106 BLOQUE III – TEMA 5 Funciones de libnds ● void scanKeys() – ● uint32 keysHeld() – ● Teclas que se acaban de pulsar uint32 keysUp() – ● Teclas que se mantienen pulsadas uint32 keysDown() – ● Descubre y almacena las teclas pulsadas Teclas que se acaban de dejar de pulsar void touchRead(touchPosition* pos) – Dónde se ha pulsado en la pantalla táctil 107 BLOQUE III – TEMA 5 El teclado de la NDS keysCurrent, keysUp, keysDown, keysHeld, ... 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 KEY_A KEY_B KEY_SELECT KEY_START KEY_RIGHT KEY_LEFT KEY_UP KEY_DOWN KEY_R KEY_L KEY_X KEY_Y KEY_TOUCH KEY_LID Añadidos por libnds a partir de información del ARM7 108 BLOQUE III – TEMA 5 Ejemplo 1: pulsación teclas #include <nds.h> #include <stdio.h> int main(void) Modifica keysHeld por { keysDown o keysUp consoleDemoInit(); para ver qué sucede for(;;) { scanKeys(); unsigned keys = keysHeld(); swiWaitForVBlank(); if(keys==KEY_A) printf("A"); } return 0; } 109 BLOQUE III – TEMA 5 Ejemplo 2: pulsación teclas #include <nds.h> #include <stdio.h> int main(void) { consoleDemoInit(); for(;;) { scanKeys(); unsigned keys = keysHeld(); swiWaitForVBlank(); printf("\x1b[23;0f%c%c%c%c %c%c%c%c %c%c", (keys & KEY_DOWN ? 'v': ''), (keys & KEY_UP ? '^': ''), (keys & KEY_LEFT ? '<': ''), (keys & KEY_RIGHT? '>': ''), (keys & KEY_A ? 'A': ''), (keys & KEY_B ? 'B': ''), (keys & KEY_X ? 'X': ''), (keys & KEY_Y ? 'Y': ''), (keys & KEY_L ? 'L': ''), (keys & KEY_R ? 'R': '')); } } 110 BLOQUE III – TEMA 5 Ejemplo 3: pantalla táctil #include <nds.h> int main(void) { consoleDemoInit(); for(;;) { swiWaitForVBlank(); scanKeys(); unsigned held = keysHeld(); if(held & KEY_TOUCH) { touchPosition touch; touchRead(&touch); printf("\x1b[6;5HTouch x = %04X, %04X\n", touch.rawx, touch.px); printf("\x1b[7;5HTouch y = %04X, %04X\n", touch.rawy, touch.py); } } } 111 BLOQUE III – TEMA 5 Acceso directo a memoria (DMA) ARM RAM DTCM VRAM DMA 112 BLOQUE III – TEMA 5 Transferencias con DMA ● ● La librería libnds proporciona funciones para la transferencia de datos utilizando controladores de DMA Algunas consideraciones – Diferencia entre variables estáticas y dinámicas – Bloques de no más de 128KiB – Mayor eficiencia que otras funciones de transferencia en las que interviene la CPU dmaCopy(wallpaperBitmap, VRAM_A, 256*192*2); 113 BLOQUE I – TEMA 1 BLOQUE IV Proyectos 114 BLOQUE IV – TEMA 6 Tema 6 Ejemplos de proyectos de prácticas 115 Autómatas regulares y Fractal del Pascal 116 ¿Qué ponen en práctica? ● ● Modos de direccionamiento. – Recorrer el fractal – Selección de colores Matrices de transformación (punto fijo) – ● Ampliar y reducir el tamaño del fractal Conocer los distintos tipos de memoria que intervienen en la representación gráfica – Bancos de la VRAM – Cada fondo debe tener su banco de memoria asignado ● Limitaciones de la caché (DTCM que contiene la pila de 16 KiB) ● DMA y sus restricciones de uso 117 BLOQUE I – TEMA 1 Filtros de imagen 118 BLOQUE I – TEMA 1 Filtros de imagen 119 BLOQUE I – TEMA 1 Filtros de imagen 120 BLOQUE I – TEMA 1 Piano 121 Conclusiones ● ● ● ● La arquitectura NDS puede ser explorada con un lenguaje de alto nivel como C. Todos los experimentos se realizan con un sistema “real”. La gestión de memoria para la representación de gráficos pone en práctica los conceptos de aritmética binaria entera y de punto fijo. La peculiar jerarquía de memoria plantea un excelente recurso para poner en práctica cómo la arquitectura de memoria interfiere con la entrada/salida (DTCM, caché y DMA). 122 Conclusiones ● ● Se experimenta con los distintos tipos de E/S – Por consulta (teclado de la NDS) – Por DMA (uso de la función dmaCopy) – Por interrupciones (utilizando temporizadores) Subsistema de memoria que nos permite realizar numerosos ejemplos prácticos sobre – Direccionamiento – Alineamiento – Optimización – Interacción con otros otros subsistemas 123 Conclusiones ● ¿Qué conseguimos con los proyectos planteados? – El proyecto se divide en sub-proyectos para permitir un aprendizaje gradual de lo más simple a lo más complejo. – Cada sub-proyecto explora cuestiones modulares de la arquitectura (memoria, interrupciones, optimización, etc). – La complejidad algorítmica se reduce al mínimo ofreciendo la implementación de aquellas partes no triviales y que no son objeto de la asignatura. 124