Consola de juegos stm32

Algunos tiradores para stm32; cómo, por qué, qué pasó.



Prefacio


Siendo fanático de la "vieja" escuela de tiradores por un lado y desarrollador integrado por el otro, siempre me pregunté cómo y por qué los autores de esa época lograron implementar un nuevo género que requería enfoques completamente nuevos en un hardware muy "modesto". Y decidí intentar lanzar algo similar usando soluciones basadas en MK moderno: aquí hay recursos básicos y recursos "modestos" y una herramienta de depuración bastante poderosa (stm32, en mi humilde opinión). Y así, mi elección recayó en la placa de desarrollo de descubrimiento stm32f769i.

Notas


Por el momento, el ensamblaje solo es posible desde el entorno Keil MDK (gestor de arranque, juegos) o utilizando arm-gcc + make (solo gestor de arranque). Puertos actualmente disponibles para: Quake I (+ mods), Doom (+ mods), Duke Nukem (+ mods), Hexen, Heretic. Con todas las modificaciones, la lista se puede ampliar significativamente.

Empecemos


En este artículo intentaré describir brevemente las ideas y principios principales de su implementación en el camino hacia la creación de una consola de juegos, en particular para el descubrimiento de stm32f769i. Además, intentaré evitar detalles técnicos detallados, prefiero perseguir el objetivo de presentar al lector otra opción para usar MK moderno. Por "consola de juegos", me refiero a un dispositivo independiente con la capacidad de ejecutar aplicaciones de "usuario" sin actualizar el software principal.

Arquitectura


Dado que la implementación final requiere la capacidad de lanzar varios juegos de forma independiente sin actualizar el firmware de MK, surgió la necesidad de alguna versión del "cargador de arranque", por lo que:

  1. Cargador; trabajar con memoria: "instalación" de una aplicación (juego), iniciar.
  2. Conductor; Servicio de nivel de sistema HAL y funciones relacionadas, transferencia de API a la aplicación.
  3. Solicitud; El programa final no devuelve el control al gestor de arranque.

1. Cargador de arranque


Se basa en el modelo IAP (Programación en aplicación): controladores que utilizan un ejemplo de ST-microelectronics.

La peculiaridad de este enfoque es que no es necesario cambiar la configuración del arranque MK.
Todo el "cuerpo" del gestor de arranque está en la memoria principal, y esto a su vez permite el uso del descubrimiento stm32f769i "listo para usar".

La funcionalidad principal de este nivel es leer el archivo .bin, escribir su contenido en la memoria MK y transferir el control. En esta etapa, el punto clave es leer la dirección del punto de entrada y la dirección del puntero de la pila, el segundo no es necesario, porque la aplicación no devuelve el control
la pila se comparte y no hay necesidad de reescribir el puntero. También se puede hacer una llamada a través de un puntero a una función. Por lo tanto, el resultado será un cargador "híbrido": su parte "controlador" continúa sirviendo a la aplicación, mientras que los recursos del cargador en sí se descargan.

2. Conductor


El controlador se realiza en forma de "envoltorio" por encima del nivel HAL, proporcionando acceso a los recursos necesarios: sistema de archivos, pantalla \ monitor, sonido, controlador de juego \ sensor de pantalla. Para un uso posterior, la API del controlador se transmite en forma de estructura de puntero a través de la "memoria compartida", una pieza de memoria reservada tanto para el gestor de arranque como para el lado de retorno. Dicha manipulación requiere costos de memoria, y quizás la mejor solución sería usar SWI (interrupción suave, llamada svc), pero para esto, a su vez, debe poder cambiar el contexto, porque No todas las llamadas se pueden manejar en una interrupción. Además, la memoria "compartida" se usa para pasar argumentos del usuario (por ejemplo, a través de la consola), un requisito previo es agregar el atributo no-init para esta sección,esto evitará sobrescribirlo con runtime-library en el momento de la inicialización de la aplicación del usuario.

3. Solicitud


Como resultado, lo único que necesita saber al momento de crear la aplicación es la arquitectura del núcleo del procesador, no hay dependencias del HAL, tampoco hay una tabla de vectores de interrupción, todas las interrupciones son procesadas por el cargador. Como resultado, la aplicación utiliza mucho menos espacio en la memoria del programa, debido al hecho de que parte de la funcionalidad está "protegida" junto con el gestor de arranque / controlador, lo que le permite instalarlo en el área de datos SRAM (RAM interna). Esto a su vez puede reducir significativamente la cantidad de ciclos de escritura de la memoria Flash y también acelerar el proceso de depuración y ejecución en general. De los inconvenientes: en el momento de la depuración, es posible llamar a la aplicación solo desde el exterior, por ejemplo, usando un comando desde la consola (puerto COM a través de ST-Link, VCOM), para esto se usa una versión muy simplificada de la línea de comando.

Recursos:

cargador , hal , conductor

Características de desarrollo


Memoria


Lo primero que tuve que enfrentar fue el problema de asignar un recurso de memoria externa (SDRAM). Esto se debe al hecho de que algunos juegos requieren más memoria para la sección .bss (duke nukem ~ 5.5mbytes). Para colocar dicho volumen solo es posible en sdram, pero porque el gestor de arranque utiliza la misma memoria para almacenar datos temporales (imágenes, sonido, contenido de archivos, etc.), necesarios solo antes de que se inicie la aplicación; se decidió dividir la administración de esta parte de la memoria; en cada lado hay un malloc / free. Después de comenzar, el controlador utiliza punteros a las funciones malloc \ free, que, si es necesario, se pasan como un parámetro a la función de llamada. Es decir, después de comenzar el juego, el controlador no puede realizar directamente la asignación desde sdram.Un hecho interesante sobre D-Cache e I-Cache, debido a las peculiaridades del manejo de la memoria externa, debe apagar ambas líneas antes de comenzar, porque sdram se reinicia, todo estaría bien, pero hay un "pero": siempre debe invalidar la memoria caché; de lo contrario, de forma predeterminada conserva el estado válido de todas las líneas, mientras que se sobrescribieron en el intervalo cuando se apagó la memoria caché.
Otra característica: todos los datos del gestor de arranque se colocan en la sección DTCM, esto permite no usar el caché al acceder a la memoria (la MPU permite lo mismo) y, como resultado, se resuelven problemas de coherencia al trabajar con DMA;
En conjunción - CPU -> D-Cache -> Memoria <- DMA

Artes graficas


En su mayor parte, estas son varias funciones de escala de imagen (2x2, 3x3),
la función de inicialización y la carga de la paleta. El punto clave es la indicación correcta de los atributos de memoria de trama (realizada a través de la configuración de MPU): para el gestor de arranque, esto será "Reescritura, sin asignación de escritura", para eliminar el efecto de parpadeo, como se utiliza el modo de búfer único, mientras que la aplicación usa "Escribir a través, sin asignación de escritura", que logra el FPS más alto (Doom ~ 28-40).

Todos los puertos de juegos existentes funcionan con gráficos de 8 bits, pero también es posible cambiar al modo de color verdadero de 16 bits (requiere modificación desde el lado del juego).
Es posible escalar una imagen de 8 bits con DMA2D, pero este enfoque no ha dado resultado: cuesta ~ 1000 interrupciones necesarias para procesar una imagen con una resolución final de 640x480 píxeles, también genera muchos artefactos en los juegos: imágenes individuales (sprites, polígonos) no se representarán completamente, porque en este caso, todo el proceso de renderizado en el juego ocurrirá en paralelo con el boceto de la pantalla.

Sonido


Esta parte está hecha en forma de un simple mezclador de 16 canales y 16 bits basado en ejemplos de microelectrónica ST, también se utiliza el controlador I2S. Por el momento, no hay forma de convertir formatos de audio entre ellos: esta parte se implementa a nivel de juego según los requisitos. Duke Nukem, en mi opinión, tiene el conjunto más rico de utilidades para trabajar con sonido, incluyendo y reverberación.

Entrar


El controlador de joystick también se realiza utilizando la clase usb-hid (de hecho, el gamepad se definirá como un mouse de computadora ...). El sensor de pantalla, como un gamepad, usa el mismo canal para transmitir eventos, y es algo extremadamente inconveniente.

Juegos


Condenar


El stm32doom puerto fue tomado como base ,
el soporte de sonido añadido, parcheadas con las últimas Chocolate doom cambios , algunas correcciones debidas a Killough, desde PrBoom, se añadieron. El juego te permite usar todas las modificaciones y mapas disponibles para chocolate doom, incluidos Se agregaron escenarios y sonido de las versiones 3DO y PS1 del juego. Se ha agregado la optimización de gráficos: la resolución de la representación de texturas depende de la distancia, la solución es regular, en diferentes lugares, una ganancia de + 3-7 cuadros por segundo. disponible. La última versión también agrega soporte para sprites "transparentes" - todo se basa en la tabla generada de combinaciones de elementos de paleta - algo similar se usa en Quake II y juegos basados ​​en el motor Build. Juego incl. las modificaciones se pueden completar por completo.

Recursos:

stm32doom , 3DO doom , chocolate doom , Versión actual

Duke Nukem


Basado en el puerto duque de chocolate . No hubo tiempo para comprender completamente el código fuente del juego, por lo que todo permaneció "tal cual", solo se solucionaron defectos menores. El puerto también te permite ejecutar modificaciones oficiales y no del todo: edición atómica, invierno nuclear, etc.
Nota: por el momento, ninguno de los episodios del juego se puede completar por completo debido a defectos existentes.

Recursos:

duque de chocolate , versión actual

Terremoto i


Desafortunadamente, el enlace al repositorio original no se conservó y no puedo encontrarlo, el
puerto se ejecutó con el nombre sdl quake. De las características, vale la pena señalar la presencia de una arquitectura cliente-servidor, una pila muy "glotona" (~ 700kb) debido a la cual surgieron muchas situaciones interesantes por primera vez (armcc realmente no monitorea su uso), problemas generalizados con la alineación, tal vez esto concierne solo el armcc del compilador, pero casi en todas partes donde hay un atractivo para un elemento de la estructura de más de un byte de tamaño; de lo contrario, debe usar la función de envoltura para leer / escribir byte, excepción de falla dura. El juego es bastante bueno, con un promedio de fps ~ 15. También se pueden completar varios episodios, más o menos cómodos solo en el primer nivel de dificultad :)

Recursos:

versión actual

Hexen, Hereje


En su mayor parte, heredan el motor Doom, por lo que desde el punto de vista de la portabilidad, son casi idénticos (en mi humilde opinión). En hexen se agregó la capacidad de comenzar el juego en la ubicación seleccionada, los juegos no se pueden completar por completo.

Recursos:

hexen stm32 , heretic stm32

Resultado


Doom , Duke Nukem , Quake

Gracias por su atención.

All Articles